keycloak: adding package using microdnf no longer works since keycloak version 21
Before reporting an issue
- I have searched existing issues
- I have reproduced the issue with the latest release
Area
ci
Describe the bug
Before keycloak 21.0.0 I could add packages such as jq using the microdnf command:
microdnf install jq
microdnf: command not found
Next to that in keycloak version before 21.0.0 curl was avilable in the container.
I use curl and jq to define a health check on the docker level and make the check part of containers I build.
health check code put in /usr/local/bin/health.sh:
#!/bin/bash
set -euo pipefail
CHECK=`curl --fail -s http://localhost:8080/health | jq 'select((.status == "UP") or (.checks[].status == "UP"))'`
if [[ -z ${CHECK} ]]; then exit 1;fi
Dockerfile:
ARG QUAY_REGISTRY
ARG KC_VER
FROM ${QUAY_REGISTRY}/keycloak/keycloak:${KC_VER} as builder
ENV KC_METRICS_ENABLED=true
ENV KC_DB=mariadb
ENV KC_VAULT=file
ENV KC_HEALTH_ENABLED=true
RUN /opt/keycloak/bin/kc.sh build
FROM ${QUAY_REGISTRY}/keycloak/keycloak:${KC_VER}
COPY --from=builder /opt/keycloak/lib/quarkus/ /opt/keycloak/lib/quarkus/
COPY rootfs /
USER root
RUN microdnf update -y && microdnf install jq && microdnf clean all; \
chmod +x /usr/local/bin/health.sh
USER keycloak
HEALTHCHECK CMD /usr/local/bin/health.sh
WORKDIR /opt/keycloak
ENV KC_METRICS_ENABLED=true
ENV KC_HEALTH_ENABLED=true
ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start", "--optimized"]
Version
21.0.0
Expected behavior
I expect there is an option to install additional packages while the keycloak container is built (or other methods to define a docker health check for keycloak)
Actual behavior
.
How to Reproduce?
.
Anything else?
Info on how I thought to write a health check comes from here: https://www.keycloak.org/server/health and ubi9 also has curl, microdnf onboard: https://hub.docker.com/r/redhat/ubi9-minimal/tags
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 14
- Comments: 68 (29 by maintainers)
Commits related to this issue
- Update the server guide for the RPM-minimized container Closes #17273 — committed to ASzc/keycloak by ASzc a year ago
- Update the server guide for the RPM-minimized container Closes #17273 — committed to ASzc/keycloak by ASzc a year ago
- Update the server guide for the RPM-minimized container Closes #17273 — committed to ASzc/keycloak by ASzc a year ago
- Update the server guide for the RPM-minimized container Closes #17273 — committed to ASzc/keycloak by ASzc a year ago
- Update the server guide for the RPM-minimized container Closes #17273 — committed to keycloak/keycloak by ASzc a year ago
- Update the server guide for the RPM-minimized container Closes #17273 — committed to vmuzikar/keycloak by ASzc a year ago
- Update the server guide for the RPM-minimized container (#17444) * Update the server guide for the RPM-minimized container Closes #17273 Co-authored-by: Alex Szczuczko <aszczucz@redhat.com> Co... — committed to keycloak/keycloak by vmuzikar a year ago
- chore: remove keycloak health check https://github.com/keycloak/keycloak/issues/17273 — committed to janhq/jan by louis-jan 10 months ago
- Resolves #35, resolves #59, resolves #53 (#60) * fix: [#35] - jan containers wont restart * chore: remove keycloak health check https://github.com/keycloak/keycloak/issues/17273 * fix: #53 hasu... — committed to janhq/jan by louis-jan 10 months ago
You can easily find this out by checking the changes in the layers using for example: https://github.com/wagoodman/dive
#16879 is IMO a mistake. This forces users that want to extend the the base image to do super brittle reverse engineered custom images just because they want to augment the system in any small way.
The workaround by @tobhv looks brittle for any changes keycloak will do in the future and already has issues
In the workaround by @3XC1T3D they are already worried that they may have or may not have bulldozed ENV variables and managed to forget the jdk
I can understand why one would lock down the image due to security concerns but I consider this to be overall worse than before.
As context what we do in our dockerfile
update-ca-trustwhich fails because the underlying utilityp11-kitis now gone (probably will have to use a truststore instead from now on)microdnf install iprouteto do some docker swarm required introspection.we are issung the same problem. it is not possible to offer two images? one based on ubi9-minimal and the other based on ubi9-micro?
So that the community dont have to rebuild each Dockerfile or CI/CD step.
HTH, I use another workaround - checking when 8080 port is reserved on the container. It is usually just before container to became healthy.
The healthcheck section is like this:
Explanation is that in
/proc/net/tcpcan be found a list of all ports that are used on the system (for tcp protocol), but in HEX format.00000000:1F90can be read as local address: 0.0.0.0 on port: 1F90 (equal to 8080 in dec)So the check will pass when some process start to use this port inside the container.
Going back to 20, let me know when documentation is up-to-date, just need curl for healthcheck, wasted too much time…
My workaround for missing
curlis to add staticcurl:I would recommend this workaround only if you understand security risks of this approach.
I don’t like an idea of full image build - it will introduces Docker image management problems. Also this is not a for prod deployment, so I’m happy to accept security risks of this workaround.
It’s using the pseudo-device
/dev/tcp(which is a Bash feature) to perform a TCP connection, see https://tldp.org/LDP/abs/html/devref1.html3<>is opening a read/write file descriptor for the socket communication, see https://tldp.org/LDP/abs/html/io-redirection.htmlFinally, grep is used to check if the strings “status” and “UP” appears in the response to exit the script successfully or with a none-zero exit code in case of an error.
@vmuzikar The it’s only kubectl
I tried to copy the export into the new 21.02 container
kubectl cp keycloak-export.json thens/keycloak-754d88f645-54ln7:/tmp/keycloak-export.jsonResult:
I resolved it by creating the export as a configMap and mount it under
/opt/keycloak/data/import/keycloak-export.jsonand appended the start arg--import-realmBased on https://ceh51.blogspot.com/2016/07/how-to-open-tcpudp-sockets-bash-shell.html a
docker-healthcheck.sh:@xoxys yes, it was hard … 😉
As an alternative to a dynamically linked curl i tried a statically linked binary of xh ( https://github.com/ducaale/xh )
My Dockerfile:
In my docker-compose.yml i now have a healthcheck section:
I moved to using ubi9-minimal as a base using the below dockerfile:
Initial testing looks fine with this for new installations, but not for upgrades in my case but that is due to https://github.com/keycloak/keycloak/issues/17285 Reason to use the ubi9-minimal from now on is that I want the option to install packages @runtime in case of troubleshooting.
@Zetanova Thank you for providing more details. I can confirm that
kubectl cpindeed doesn’t work due to missingtarin the container.Apart from the mentioned ConfigMap workaround, another possible solution might be using something as simple as:
Could you please confirm this works for your use case? I guess it depends on how big your Realm is. 😃
@ghenadiibatalski Yes i did it in the end. I updated my last message 1min later.
I tested now
kubectl cp thens/keycloak-754d88f645-54ln7:/opt/keycloak/data/import/keycloak-export.json keycloak-export2.jsonResult:
@t-schuster Your use cases are covered, as detailed in previous comments in this thread.
FROM ubi9, where all the packages you need are available, then copy across/etc/pkiinto the second stage.ADD --chown=keycloak:keycloak. You don’t need curl to access URLs.Both of these use cases are now included in the latest container documentation, but we’re still working on the backport to the KC 21 docs.
To avoid opening a duplicate:
The issue prevents installing custom certificate-authorities reliably into the container and in our build pipeline also stops usage of curl/wget to fetch custom providers in the Dockerfile to provide them for the build.
Allowing p11-kit to be installed would help a lot here instead of having to create a brittle and fragile script to manually put the certificate stores into proper order.
I also stumbled across this method, but at least for me, it did not work reliably, as only unencrypted connections are supported. Depending on the
KC_PROXYconfiguration, port 8080 may or may not work. Personally, I am considering using an approach similar to this https://github.com/parkr/go-curlWe were actually considering this but realized that would probably hurt the performance – creating a new JVM for each health check request. Hence we see installing
curlas a lesser evil.I think removing essential stuff like a package manager is not the best solution when your base idea is to build an individual “own” image.
In the past I just copied our ActiveDirectory root CA into the anchor directory and update-ca-trust. update-ca-trust updates also the java default truststore.
update-ca trust is missing p11-kit -> The option to install it is also gone.
IMHO: This makes everything overcomplicated.
Now we can fight around with keytool instead of the build in tools of RH. And i think also copiing stuff manually for whatever needs to be installed like: executables, libraries etc. will make it even worse
Hi @ASzc ,
thanks that you take a look at the docs and update it.
1.) i think no one wants a static curl binary link in his Dockerfile. The major people wants the package from the based repository to acchive the latest security fixes etc.
2.) in this example you have to know which folders you have to copy from one layer to the other. In the example from me and @tobhv you dont have to worry about the folders to copy.
that’s my opinion 😃
This is due to https://github.com/keycloak/keycloak/pull/16879 and an intended change to minimise image size and attack surface. You can still install your own dependencies by using a multi-layer build i.e. create your own layer with microdnf, install your dependencies, switch to the Keycloak image and copy your installed dependencies from your own layer.