-
Notifications
You must be signed in to change notification settings - 8000 Fork 7.3k
Multi-stage docker builds fail --optimized validation #38893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multi-stage docker builds fail --optimized validation #38893
Comments
I don't think we've seen this behavior before. But our example shows using ADD, instead of COPY, so that the ownership of the provider jar can also be set - maybe there's a difference between ADD and COPY coming into play here https://www.keycloak.org/server/containers#_writing_your_optimized_keycloak_containerfile
Out of curiosity could you also determine what the actual last-modified time of the provider jar is at runtime? |
I'm not sure this is the cause or not. But I face the same error when I try to build the image on a machine that has |
I'm running one of your "working" versions, which is super weird. docker -v
Docker version 27.5.1, build 9f9e405
I'm not sure of an easy way to inspect the modified time at runtime. But these are the stat keycloak-theme-for-kc-all-other-versions.jar
File: keycloak-theme-for-kc-all-other-versions.jar
Size: 1763566 Blocks: 3448 IO Block: 4096 regular file
Device: 7ch/124d Inode: 33870099 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2025-04-12 00:19:00.000000000 +0000
Modify: 2025-04-12 00:19:00.000000000 +0000
Change: 2025-04-12 00:35:45.753114012 +0000
Birth: 2025-04-12 00:35:45.747114012 +000
I think I have to |
found a jankier but functional workaround: # NEW
RUN touch -m --date=@1744481906 /opt/keycloak/providers/keycloak-theme-for-kc-all-other-versions.jar
RUN /opt/keycloak/bin/kc.sh build --db=postgres --health-enabled=true --metrics-enabled=true --tracing-enabled=true --features=opentelemetry:v1,multi-site:v1
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"] I don't see many drawbacks of this. |
@shawkins changing |
For us this helped in our multi-stage Dockerfile:
Chown is required to be able to modify the jar timestamp, otherwise you get permission denied error. |
It has worked for us but this indicates that somehow it has to be a regression created in 26.2.0.... It doesn't make sense that this has to be done when it was not necessary until now. |
I wouldn't call this a regression as it's working as intended #34665 It seems more like an issue with specific versions of Docker not maintaining file timestamps. |
I did not analyze it too deep but it looks like it is related somehow to the new version of quarkus used in this new release, so 3.17.x (#36501). The reaugmentation process (https://quarkus.io/guides/reaugmentation) which depends on involved files timestamps, I can see in the keycloak sources the flag is used keycloak/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Build.java Line 78 in 4cb4d2d
I mean the image was built just ok for us, only during a keycloak bootstrap we had the message which ended up as error, so it did not start at all because of this. |
Interesting is with 26.1.5 we did not have the issue at all - our Dockerfile was exactly the same with exception to keycloak base image version. |
#34665 was added in 26.2. |
So to summarize (if I understood it well):
|
I guess you may be right, we made those builds in gh runners with docker engine 26.x which was reported with this kind of problems. They plan to upgrade it soon: actions/runner-images#11766 what should solve this problem I guess. We did not have the issue in our local system using one of the latest 28.x docker engine. |
BTW, upgrading Docker Engine to 28.x didn't fix the issue. Here's the output of
|
so my assumption about docker version was wrong in that case - anyway the solution we used shoud not break anything so we will live with it for the moment |
To add more, we tried to build our provider jar and keycloak in the same stage and it also did not help, still the same error. It looks like a docker engine version also has nothing to do with it. So still a kind of puzzle. Anyway timestamp modification for the provider's jar helps. |
We also ran into this issue and are currently working around it by modifying the file timestamp. In any case, IMO file timestamps shouldn't be used for this kind of verification. A hash of the jar would be much better suited, or since it's not security relevant here, even a CRC would be enough and more reliable. |
Looking into to this more there are some references that a plain copy or add operation does indeed have counterintuative affects on the mtime of files - it will be one value at build time, then in the image it will be stored as the image creation time. There are a couple of suggestions for making thing consistent. From https://docs.docker.com/build/ci/github-actions/reproducible-builds/ you can use SOURCE_DATE_EPOCH, it also appears that COPY --link preserves the original file attributes. Seems like we do need to update our example.
I am not sure what motivated the original decision to use timestamps. I believe that it was considered good enough for most most circumstances with out any performance implications. A CRC32 or other fast hash could prevent false positives from changing timestamps, but we'd need to vet the performance. I agree that there aren't security concerns here with a non-cryptographic given that the primary issue would be having something sensitive in the provider jars. However this situation does seem to be more of a nuance of Docker that can be addressed in other ways. |
I'm experiencing the same issue using custom providers in a Docker-based Keycloak deployment. When I run
However, when I later run
This results in a non-reproducible config and causes Keycloak to detect changes and re-trigger updates at runtime, even though no actual change occurred in the JAR. After some investigation, it seems the root cause might be Docker’s image layering or file copy mechanism truncating or altering file timestamps slightly during Would it be possible for Keycloak to:
This would improve reproducibility in CI/CD pipelines and prevent unnecessary reconfiguration or rebuilds when using Docker. |
PS: I used this as a workaround: RUN find /opt/keycloak/providers -name '*.jar' -exec bash -c ' \
for f; do \
epoch_sec=$(stat -c %Y "$f"); \
touch -d @"$epoch_sec" "$f"; \
done' bash {} + |
from a keycloak perspective, would it be possible to use a checksum of the jar instead of a timestamp? This seems to capture the intent of the check better, but comes with some overhead. |
Beyond the workarounds that can be done on the docker side of things, I see a couple of options for Keycloak:
|
closes: keycloak#38893 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
closes: keycloak#38893 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
closes: keycloak#38893 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
closes: #38893 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
* fix: documenting known issues with docker closes: #38801 #38893 * Update docs/guides/server/containers.adoc --------- (cherry picked from commit 68096ee) Signed-off-by: Steve Hawkins <shawkins@redhat.com> Signed-off-by: Steven Hawkins <shawkins@redhat.com> Co-authored-by: Martin Bartoš <mabartos@redhat.com>
…39340) closes: keycloak#38893 Signed-off-by: Steve Hawkins <shawkins@redhat.com> (cherry picked from commit 0ff4cce)
…39340) closes: keycloak#38893 Signed-off-by: Steve Hawkins <shawkins@redhat.com> (cherry picked from commit 0ff4cce)
With the latest Keycloak version, the timestamps of providers is compared to the timestamp of the latest provider build. When starting keycloak with the `--optimized` flag, keycloak will throw an error when the timestamp of the providers is more recent than it was during the build. > A provider JAR was updated since the last build, please rebuild for this to be fully utilized. As we do not preserve the timestamp in the init script, this error is always thrown when starting keycloak as optimized. This is fixed by preserving the timestamp in the initContainer `cp` commands. see: keycloak/keycloak#38893 Signed-off-by: msvechla <m.svechla@gmail.com>
With the latest Keycloak version, the timestamps of providers is compared to the timestamp of the latest provider build. When starting keycloak with the `--optimized` flag, keycloak will throw an error when the timestamp of the providers is more recent than it was during the build. > A provider JAR was updated since the last build, please rebuild for this to be fully utilized. As we do not preserve the timestamp in the init script, this error is always thrown when starting keycloak as optimized. This is fixed by preserving the timestamp in the initContainer `cp` commands. see: keycloak/keycloak#38893 Signed-off-by: msvechla <m.svechla@gmail.com> Signed-off-by: Marius Svechla <m.svechla@gmail.com>
…39340) closes: keycloak#38893 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
We are still getting this with 26.2.4-0 The reason being that the build happens on one server and the provider files get copied to a mount which changes their timestamps. When Keycloak tries to start the timestamps will be different despite the provider files being exactly the same. We cannot "touch" the files at the mount point because it's in cloud storage without that functionality. Is it possible to disable the flakey timestamp check? |
Please start a new issue. As you can see on this one we ultimately decided to document how to touch the files and relaxed the check to be tolerant to ms truncation. |
With the latest Keycloak version, the timestamps of providers is compared to the timestamp of the latest provider build. When starting keycloak with the `--optimized` flag, keycloak will throw an error when the timestamp of the providers is more recent than it was during the build. > A provider JAR was updated since the last build, please rebuild for this to be fully utilized. As we do not preserve the timestamp in the init script, this error is always thrown when starting keycloak as optimized. This is fixed by preserving the timestamp in the initContainer `cp` commands. see: keycloak/keycloak#38893 Signed-off-by: msvechla <m.svechla@gmail.com> Signed-off-by: Marius Svechla <m.svechla@gmail.com>
With the latest Keycloak version, the timestamps of providers is compared to the timestamp of the latest provider build. When starting keycloak with the `--optimized` flag, keycloak will throw an error when the timestamp of the providers is more recent than it was during the build. > A provider JAR was updated since the last build, please rebuild for this to be fully utilized. As we do not preserve the timestamp in the init script, this error is always thrown when starting keycloak as optimized. This is fixed by preserving the timestamp in the initContainer `cp` commands. see: keycloak/keycloak#38893 Signed-off-by: msvechla <m.svechla@gmail.com> Signed-off-by: Marius Svechla <m.svechla@gmail.com>
Before reporting an issue
Area
dist/quarkus
Describe the bug
Running a dockerfile with
--optimized
that works with earlier versions fails on newer ones. I believe the commit is: 332bf12.The error is:
A provider JAR was updated since the last build, please rebuild for this to be fully utilized.
This may be similar to #37770, but they seemed to have resolved the issue.
Version
26.2
Regression
Expected behavior
This docker image can be run fine with --optimized
Actual behavior
It fails with
ERROR: A provider JAR was updated since the last build, please rebuild for this to be fully utilized.
How to Reproduce?
I have the following dockerfile leveraging keycloakify:
After building, running
docker run 24f554b83ada start --optimized
yeilds:ERROR: A provider JAR was updated since the last build, please rebuild for this to be fully utilized.
I am not sure what causes this. I think it may have to do with docker COPY messing with timestamps, but don't know enough to be sure.
For now I can run unoptimized, but this is not ideal.
Anything else?
Running
docker run <image hash> show-config
yeilds:The text was updated successfully, but these errors were encountered: