1
<#import "/templates/guide.adoc" as tmpl>
2
<#import "/templates/kc.adoc" as kc>
3
<#import "/templates/options.adoc" as opts>
4
<#import "/templates/links.adoc" as links>
5
<#import "/templates/profile.adoc" as profile>
8
title="Running {project_name} in a container"
9
summary="Learn how to run {project_name} from a container image"
10
includedOptions="db db-url db-username db-password features hostname https-key-store-file https-key-store-password health-enabled metrics-enabled">
12
This {section} describes how to optimize and run the {project_name} container image to provide the best experience running a {project_name} container.
16
WARNING: This chapter applies only for building an image that you run in a OpenShift environment. Only an OpenShift environment is supported for this image. It is not supported if you run it in other Kubernetes distributions.
20
== Creating a customized and optimized container image
21
The default {project_name} container image ships ready to be configured and optimized.
23
For the best start up of your {project_name} container, build an image by running the `build` step during the container build.
24
This step will save time in every subsequent start phase of the container image.
26
=== Writing your optimized {project_name} Dockerfile
27
The following `Dockerfile` creates a pre-configured {project_name} image that enables the health and metrics endpoints, enables the token exchange feature, and uses a PostgreSQL database.
30
[source,dockerfile,subs="attributes+"]
32
FROM quay.io/keycloak/keycloak:{containerlabel} as builder
34
# Enable health and metrics support
35
ENV KC_HEALTH_ENABLED=true
36
ENV KC_METRICS_ENABLED=true
38
# Configure a database vendor
42
# for demonstration purposes only, please make sure to use proper certificates in production instead
43
RUN keytool -genkeypair -storepass password -storetype PKCS12 -keyalg RSA -keysize 2048 -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore conf/server.keystore
44
RUN /opt/keycloak/bin/kc.sh build
46
FROM quay.io/keycloak/keycloak:{containerlabel}
47
COPY --from=builder /opt/keycloak/ /opt/keycloak/
49
# change these values to point to a running postgres instance
52
ENV KC_DB_USERNAME=<DBUSERNAME>
53
ENV KC_DB_PASSWORD=<DBPASSWORD>
54
ENV KC_HOSTNAME=localhost
55
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
57
The build process includes multiple stages:
59
* Run the `build` command to set server build options to create an optimized image.
60
* The files generated by the `build` stage are copied into a new image.
61
* In the final image, additional configuration options for the hostname and database are set so that you don't need to set them again when running the container.
62
* In the entrypoint, the `kc.sh` enables access to all the distribution sub-commands.
64
To install custom providers, you just need to define a step to include the JAR file(s) into the `/opt/keycloak/providers` directory.
65
This step must be placed before the line that `RUNs` the `build` command, as below:
67
[source,dockerfile,subs="attributes+"]
69
# A example build step that downloads a JAR file from a URL and adds it to the providers directory
70
FROM quay.io/keycloak/keycloak:{containerlabel} as builder
74
# Add the provider JAR file to the providers directory
75
ADD --chown=keycloak:keycloak <MY_PROVIDER_JAR_URL> /opt/keycloak/providers/myprovider.jar
79
# Context: RUN the build command
80
RUN /opt/keycloak/bin/kc.sh build
83
=== Installing additional RPM packages
85
If you try to install new software in a stage `+FROM quay.io/keycloak/keycloak+`, you will notice that `+microdnf+`, `+dnf+`, and even `+rpm+` are not installed. Also, very few packages are available, only enough for a `+bash+` shell, and to run Keycloak itself. This is due to security hardening measures, which reduce the attack surface of the Keycloak container.
87
First, consider if your use case can be implemented in a different way, and so avoid installing new RPMs into the final container:
89
* A `+RUN curl+` instruction in your Dockerfile can be replaced with `+ADD+`, since that instruction natively supports remote URLs.
90
* Some common CLI tools can be replaced by creative use of the Linux filesystem. For example, `+ip addr show tap0+` becomes `+cat /sys/class/net/tap0/address+`
91
* Tasks that need RPMs can be moved to a former stage of an image build, and the results copied across instead.
93
Here is an example. Running `+update-ca-trust+` in a former build stage, then copying the result forward:
97
FROM registry.access.redhat.com/ubi9 AS ubi-micro-build
98
COPY mycertificate.crt /etc/pki/ca-trust/source/anchors/mycertificate.crt
101
FROM quay.io/keycloak/keycloak
102
COPY --from=ubi-micro-build /etc/pki /etc/pki
105
It is possible to install new RPMs if absolutely required, following this two-stage pattern established by ubi-micro:
109
FROM registry.access.redhat.com/ubi9 AS ubi-micro-build
110
RUN mkdir -p /mnt/rootfs
111
RUN dnf install --installroot /mnt/rootfs <package names go here> --releasever 9 --setopt install_weak_deps=false --nodocs -y && \
112
dnf --installroot /mnt/rootfs clean all && \
113
rpm --root /mnt/rootfs -e --nodeps setup
115
FROM quay.io/keycloak/keycloak
116
COPY --from=ubi-micro-build /mnt/rootfs /
119
This approach uses a chroot, `+/mnt/rootfs+`, so that only the packages you specify and their dependencies are installed, and so can be easily copied into the second stage without guesswork.
121
WARNING: Some packages have a large tree of dependencies. By installing new RPMs you may unintentionally increase the container's attack surface. Check the list of installed packages carefully.
123
=== Building the container image
124
To build the actual container image, run the following command from the directory containing your Dockerfile:
128
podman|docker build . -t mykeycloak
131
=== Starting the optimized {project_name} container image
132
To start the image, run:
136
podman|docker run --name mykeycloak -p 8443:8443 \
137
-e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=change_me \
142
{project_name} starts in production mode, using only secured HTTPS communication, and is available on `https://localhost:8443`.
144
Health check endpoints are available at `https://localhost:8443/health`, `https://localhost:8443/health/ready` and `https://localhost:8443/health/live`.
146
Opening up `https://localhost:8443/metrics` leads to a page containing operational metrics that could be used by your monitoring solution.
148
== Exposing the container to a different port
150
By default, the server is listening for `http` and `https` requests using the ports `8080` and `8443`, respectively.
152
If you want to expose the container using a different port, you need to set the `hostname-port` accordingly:
154
. Exposing the container using a port other than the default ports
157
podman|docker run --name mykeycloak -p 3000:8443 \
158
-e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=change_me \
160
start --optimized --hostname-port=3000
163
By setting the `hostname-port` option you can now access the server at `https://localhost:3000`.
165
== Trying {project_name} in development mode
166
The easiest way to try {project_name} from a container for development or testing purposes is to use the Development mode.
167
You use the `start-dev` command:
169
[source,bash,subs="attributes+"]
171
podman|docker run --name mykeycloak -p 8080:8080 \
172
-e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=change_me \
173
quay.io/keycloak/keycloak:{containerlabel} \
177
Invoking this command starts the {project_name} server in development mode.
179
This mode should be strictly avoided in production environments because it has insecure defaults.
180
For more information about running {project_name} in production, see <@links.server id="configuration-production"/>.
182
== Running a standard {project_name} container
183
In keeping with concepts such as immutable infrastructure, containers need to be re-provisioned routinely.
184
In these environments, you need containers that start fast, therefore you need to create an optimized image as described in the preceding section.
185
However, if your environment has different requirements, you can run a standard {project_name} image by just running the `start` command.
188
[source,bash,subs="attributes+"]
190
podman|docker run --name mykeycloak -p 8080:8080 \
191
-e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=change_me \
192
quay.io/keycloak/keycloak:{containerlabel} \
194
--db=postgres --features=token-exchange \
195
--db-url=<JDBC-URL> --db-username=<DB-USER> --db-password=<DB-PASSWORD> \
196
--https-key-store-file=<file> --https-key-store-password=<password>
199
Running this command starts a {project_name} server that detects and applies the build options first.
200
In the example, the line `--db=postgres --features=token-exchange` sets the database vendor to PostgreSQL and enables the token exchange feature.
202
{project_name} then starts up and applies the configuration for the specific environment.
203
This approach significantly increases startup time and creates an image that is mutable, which is not the best practice.
205
== Provide initial admin credentials when running in a container
206
{project_name} only allows to create the initial admin user from a local network connection. This is not the case when running in a container, so you have to provide the following environment variables when you run the image:
210
# setting the admin username
211
-e KEYCLOAK_ADMIN=<admin-user-name>
213
# setting the initial password
214
-e KEYCLOAK_ADMIN_PASSWORD=change_me
217
== Importing A Realm On Startup
219
The {project_name} containers have a directory `/opt/keycloak/data/import`. If you put one or more import files in that directory via a volume mount or other means and add the startup argument `--import-realm`, the Keycloak container will import that data on startup! This may only make sense to do in Dev mode.
221
[source,bash,subs="attributes+"]
223
podman|docker run --name keycloak_unoptimized -p 8080:8080 \
224
-e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=change_me \
225
-v /path/to/realm/data:/opt/keycloak/data/import \
226
quay.io/keycloak/keycloak:{containerlabel} \
227
start-dev --import-realm
230
Feel free to join the open https://github.com/keycloak/keycloak/discussions/8549[GitHub Discussion] around enhancements of the admin bootstrapping process.
232
== Specifying different memory settings
234
The {project_name} container, instead of specifying hardcoded values for the initial and maximum heap size, uses relative values to the total memory of a container.
235
This behavior is achieved by JVM options `-XX:MaxRAMPercentage=70`, and `-XX:InitialRAMPercentage=50`.
237
The `-XX:MaxRAMPercentage` option represents the maximum heap size as 70% of the total container memory.
238
The `-XX:InitialRAMPercentage` option represents the initial heap size as 50% of the total container memory.
239
These values were chosen based on a deeper analysis of Keycloak memory management.
241
The JVM options related to the heap might be overridden by setting the environment variable `JAVA_OPTS_KC_HEAP`.
242
You can find the default values of the `JAVA_OPTS_KC_HEAP` in the source code of the `kc.sh`, or `kc.bat` script.
243
For example, you can specify the environment variable as follows:
245
[source,bash,subs="attributes+"]
247
podman|docker run --name mykeycloak -p 8080:8080 \
248
-e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=change_me \
249
-e JAVA_OPTS_KC_HEAP="-XX:MaxHeapFreeRatio=30 -XX:MaxRAMPercentage=65" \
250
quay.io/keycloak/keycloak:{containerlabel} \