I’m trying to figure out which way would be better to package an image of Keycloak with my own extensions. I’m targeting a deployment in a Kubernetes cluster so everything needs to be self contained.
I have experimented a little with the server deployments by adding my jar files in standalone/deployments through a multi-stage dockerfile, like this example:
FROM gradle:6.7.0-jdk11 AS builder
WORKDIR /work
ADD . .
RUN gradle jar
FROM quay.io/keycloak/keycloak:11.0.2
COPY --from=builder /work/build/libs/my-module.jar /opt/jboss/keycloak/standalone/deployments/
This works fine for themes, jpa or required actions so far, but it doesn’t seem to work for custom Spi (as stated in this thread: Not able to register a custom SPI)
So another approach could be to package my jars in modules instead and use the module approach, but then I would have to edit something like the standalone.xml file to include my modules. That would probably be achieved by doing some sed magic through Docker, but that’s not very robust: prone to break when I’ll be upgrading Keycloak versions or maybe inserting my XML entry at the wrong place and messing something up.
Is there another approach I’m not thinking of that would be better for my use case?
Out of curiosity, are there any performance or reliability reasons why to choose the module approach rather than the standalone/deployments one when packaging a docker image, apart that some functionalities are not supported by the latter?
Also, the script would be executed when building the Dockerfile, right? Not during the entrypoint.
The script will be executed during startup of keycloak and not during the docker build. The Dockerfile just copies the script to the startup-scripts.
I don’t know why some SPIs require to be a module. I experienced that we would need to use a module when the SPI needs to change the database layout using liquibase. I am not sure if that is true, but it would make sense for me, because liquibase is probably run at the startup of the keycloak context and not during hot-deployments of jars.
Regarding performance or reliability, I think it will not have any differences. Performance is more relevant when the context is up and running and then it is only about the specific SPI and its implementation whether it is performant.
You want to look into jboss-deployment-structure.xml
This is a file very similar to module.xml and it is packaged inside the jar one meta-inf.
So it describes inside-out the modules dependencies and the deployment works fine.
This means you can mount the file from outside the docker container and if it’s being replaced it will be uninstalled and installed including details on the log.
Another option is to use the extraInitContainer parameter, along with mounted volumes parameters, for the Helm chart for a Kubernetes deployment. You can provide a custom image here that contains the theme, which would run as a sidecar with the Keycloak Pod of the Keycloak StatefulSet.
The startup scripts of the extra container could copy the theme from the mounted shared volume to the themes location in the Keycloak container.
You can do this way as well, copy your file into extensions and run the batch before starting the EAP.
Just create a file deploy.cli and use the docker file to copy it and your spi:
FROM jboss/keycloak:11.0.2
COPY ./your-spi.jar /opt/jboss/keycloak/
COPY ./deploy.cli /opt/jboss/extensions/deploy.cli
Batch mode is a suggested approach, to add any external component into the standalone file. Even we do not need to mention the configuration file it will automatically detect. Moreover, extensions will automatically read by the Keycloak startup.