Skip to content

Commit

Permalink
[keycloak] Create new major chart release (codecentric#20)
Browse files Browse the repository at this point in the history
Signed-off-by: Reinhard Naegele <unguiculus@gmail.com>
  • Loading branch information
unguiculus authored Jul 5, 2019
1 parent 0949597 commit 6a2c027
Show file tree
Hide file tree
Showing 27 changed files with 428 additions and 308 deletions.
5 changes: 3 additions & 2 deletions charts/keycloak/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: keycloak
version: 4.16.0
appVersion: 5.0.0
version: 5.0.0
appVersion: 6.0.1
description: Open Source Identity and Access Management For Modern Applications and Services
keywords:
- sso
Expand All @@ -12,6 +12,7 @@ keywords:
home: https://www.keycloak.org/
icon: https://www.keycloak.org/resources/images/keycloak_logo_480x108.png
sources:
- https://github.com/codecentric/helm-charts
- https://github.com/jboss-dockerfiles/keycloak
maintainers:
- name: unguiculus
Expand Down
103 changes: 88 additions & 15 deletions charts/keycloak/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ $ helm install codecentric/keycloak

## Introduction

This chart bootstraps a [Keycloak](http://www.keycloak.org/) StatefulSet on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. It provisions a fully featured Keycloak installation.
This chart bootstraps a [Keycloak](http://www.keycloak.org/) StatefulSet on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
It provisions a fully featured Keycloak installation.
For more information on Keycloak and its capabilities, see its [documentation](http://www.keycloak.org/documentation.html).

## Prerequisites Details

The chart has an optional dependency on the [PostgreSQL](https://github.com/kubernetes/charts/tree/master/codecentric/postgresql) chart.
The chart has an optional dependency on the [PostgreSQL](https://github.com/kubernetes/charts/tree/master/stable/postgresql) chart.
By default, the PostgreSQL chart requires PV support on underlying infrastructure (may be disabled).

## Installing the Chart
Expand All @@ -41,12 +42,13 @@ The following table lists the configurable parameters of the Keycloak chart and
Parameter | Description | Default
--- | --- | ---
`init.image.repository` | Init image repository | `alpine`
`init.image.tag` | Init image tag | `3.8`
`init.image.tag` | Init image tag | `3.9`
`init.image.pullPolicy` | Init image pull policy | `IfNotPresent`
`init.resources` | Pod resource requests and limits for the init container | `{}`
`clusterDomain` | The internal Kubernetes cluster domain | `cluster.local`
`keycloak.replicas` | The number of Keycloak replicas | `1`
`keycloak.image.repository` | The Keycloak image repository | `jboss/keycloak`
`keycloak.image.tag` | The Keycloak image tag | `5.0.0`
`keycloak.image.tag` | The Keycloak image tag | `6.0.1`
`keycloak.image.pullPolicy` | The Keycloak image pull policy | `IfNotPresent`
`keycloak.image.pullSecrets` | Image pull secrets | `[]`
`keycloak.basepath` | Path keycloak is hosted at | `auth`
Expand Down Expand Up @@ -74,13 +76,14 @@ Parameter | Description | Default
`keycloak.serviceAccount.create` | If `true`, a new service account is created | `false`
`keycloak.securityContext` | Security context for the entire pod. Every container running in the pod will inherit this security context. This might be relevant when other components of the environment inject additional containers into running pods (service meshs are the most prominent example for this) | `{fsGroup: 1000}`
`keycloak.containerSecurityContext` | Security context for containers running in the pod. Will not be inherited by additionally injected containers | `{runAsUser: 1000, runAsNonRoot: true}`
`keycloak.preStartScript` | Custom script to run before Keycloak starts up | ``
`keycloak.startupScripts` | Custom startup scripts to run before Keycloak starts up | `[]`
`keycloak.lifecycleHooks` | Container lifecycle hooks. Passed through the `tpl` function and thus to be configured a string | ``
`keycloak.extraArgs` | Additional arguments to the start command | ``
`keycloak.livenessProbe.initialDelaySeconds` | Liveness Probe `initialDelaySeconds` | `120`
`keycloak.livenessProbe.timeoutSeconds` | Liveness Probe `timeoutSeconds` | `5`
`keycloak.readinessProbe.initialDelaySeconds` | Readiness Probe `initialDelaySeconds` | `30`
`keycloak.readinessProbe.timeoutSeconds` | Readiness Probe `timeoutSeconds` | `1`
`keycloak.cli.enabled` | Set to `false` if no CLI changes should be performed by the chart | `true`
`keycloak.cli.nodeIdentifier` | WildFly CLI script for setting the node identifier | See `values.yaml`
`keycloak.cli.logging` | WildFly CLI script for logging configuration | See `values.yaml`
`keycloak.cli.ha` | Settings for HA setups | See `values.yaml`
Expand Down Expand Up @@ -113,9 +116,9 @@ Parameter | Description | Default
`keycloak.persistence.dbPort` | The database host port (if `deployPostgres=false`) | `5432`
`keycloak.persistence.dbUser` |The database user (if `deployPostgres=false`) | `keycloak`
`keycloak.persistence.dbPassword` |The database password (if `deployPostgres=false`) | `""`
`postgresql.postgresUser` | The PostgreSQL user (if `keycloak.persistence.deployPostgres=true`) | `keycloak`
`postgresql.postgresPassword` | The PostgreSQL password (if `keycloak.persistence.deployPostgres=true`) | `""`
`postgresql.postgresDatabase` | The PostgreSQL database (if `keycloak.persistence.deployPostgres=true`) | `keycloak`
`postgresql.postgresqlUser` | The PostgreSQL user (if `keycloak.persistence.deployPostgres=true`) | `keycloak`
`postgresql.postgresqlPassword` | The PostgreSQL password (if `keycloak.persistence.deployPostgres=true`) | `""`
`postgresql.postgresqlDatabase` | The PostgreSQL database (if `keycloak.persistence.deployPostgres=true`) | `keycloak`
`test.enabled` | If `true`, test pods get scheduled | `true`
`test.image.repository` | Test image repository | `unguiculus/docker-python3-phantomjs-selenium`
`test.image.tag` | Test image tag | `v1`
Expand All @@ -133,7 +136,8 @@ $ helm install --name keycloak -f values.yaml codecentric/keycloak

### Usage of the `tpl` Function

The `tpl` function allows us to pass string values from `values.yaml` through the templating engine. It is used for the following values:
The `tpl` function allows us to pass string values from `values.yaml` through the templating engine.
It is used for the following values:

* `keycloak.extraInitContainers`
* `keycloak.extraContainers`
Expand All @@ -142,7 +146,8 @@ The `tpl` function allows us to pass string values from `values.yaml` through th
* `keycloak.extraVolumeMounts`
* `keycloak.extraVolumes`

It is important that these values be configured as strings. Otherwise, installation will fail. See example for Google Cloud Proxy or default affinity configuration in `values.yaml`.
It is important that these values be configured as strings.
Otherwise, installation will fail. See example for Google Cloud Proxy or default affinity configuration in `values.yaml`.

### Database Setup

Expand All @@ -154,7 +159,10 @@ Please refer to this chart for additional PostgreSQL configuration options.

#### Using an External Database

The Keycloak Docker image supports PostgreSQL, MySQL, MariaDB, and H2. The password for the database user is read from a Kubernetes secret. It is possible to specify an existing secret that is not managed with this chart. The key in the secret the password is read from may be specified as well (defaults to `password`).
The Keycloak Docker image supports PostgreSQL, MySQL, MariaDB, and H2.
The password for the database user is read from a Kubernetes secret.
It is possible to specify an existing secret that is not managed with this chart.
The key in the secret the password is read from may be specified as well (defaults to `password`).

```yaml
keycloak:
Expand Down Expand Up @@ -206,7 +214,8 @@ keycloak:
### Providing a Custom Theme
One option is certainly to provide a custom Keycloak image that includes the theme. However, if you prefer to stick with the official Keycloak image, you can use an init container as theme provider.
One option is certainly to provide a custom Keycloak image that includes the theme.
However, if you prefer to stick with the official Keycloak image, you can use an init container as theme provider.
Create your own theme and package it up into a Docker image.
Expand Down Expand Up @@ -270,7 +279,9 @@ After startup the web admin console for the realm should be available on the pat

### Using Google Cloud SQL Proxy

Depending on your environment you may need a local proxy to connect to the database. This is, e. g., the case for Google Kubernetes Engine when using Google Cloud SQL. Create the secret for the credentials as documented [here](https://cloud.google.com/sql/docs/postgres/connect-kubernetes-engine) and configure the proxy as a sidecar.
Depending on your environment you may need a local proxy to connect to the database.
This is, e. g., the case for Google Kubernetes Engine when using Google Cloud SQL.
Create the secret for the credentials as documented [here](https://cloud.google.com/sql/docs/postgres/connect-kubernetes-engine) and configure the proxy as a sidecar.

Because `keycloak.extraContainers` is a string that is passed through the `tpl` function, it is possible to create custom values and use them in the string.

Expand Down Expand Up @@ -316,13 +327,38 @@ keycloak:
WildFly can be configured via its [command line interface (CLI)](https://docs.jboss.org/author/display/WFLY/Command+Line+Interface).
This chart uses the official Keycloak Docker image and customizes the installation running CLI scripts at server startup.

#### Customizing CLI Scripts

In order to make further customization easier, the CLI commands are separated by their concerns into smaller scripts.
Everything is in `values.yaml` and can be overridden. Additional CLI commands may be added via `keycloak.cli.custom`, which is empty by default.
Everything is in `values.yaml` and can be overridden.
Additional CLI commands may be added via `keycloak.cli.custom`, which is empty by default.

#### Disabling CLI Changes

The CLI changes the chart makes may not be desirable in all cases, especially when a custom Keycloak image is used that already incorporates a complete configuration that doesn't need any adjustments.
In this case, the CLI scripts the chart runs by default can either be disabled en bloc or on and individual basis.

##### Disabling all CLI Changes en Bloc

```yaml
keycloak:
cli:
enabled: false
```

##### Disabling an Individual Script

```yaml
keycloak:
cli:
logging: ""
```

### High Availability and Clustering

For high availability, Keycloak should be run with multiple replicas (`keycloak.replicas > 1`).
WildFly uses Infinispan for caching. These caches can be replicated across all instances forming a cluster.
WildFly uses Infinispan for caching.
These caches can be replicated across all instances forming a cluster.
If `keycloak.replicas > 1`, JGroups' DNS_PING is configured for cluster discovery and Keycloak is started with `--server-config standalone-ha.xml`.

## Why StatefulSet?
Expand All @@ -334,3 +370,40 @@ We would have to truncate the chart's fullname to six characters because pods ge
Using a StatefulSet allows us to truncate to 20 characters leaving room for up to 99 replicas, which is much better.
Additionally, we get stable values for `jboss.node.name` which can be advantageous for cluster discovery.
The headless service that governs the StatefulSet is used for DNS discovery.

## Upgrading

### From chart versions < 5.0.0

Version 5.0.0 is a major update.

* The chart now follows the new Kubernetes label recommendations:
https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
* Several changes to the StatefulSet render an out-of-the-box upgrade impossible because StatefulSets only allow updates to a limited set of fields
* The chart uses the new support for running scripts at startup that has been added to Keycloak's Docker image.
If you use this feature, you will have to adjust your configuration

However, with the following manual steps an automatic upgrade is still possible:

1. Adjust chart configuration as necessary (e. g. startup scripts)
1. Perform a non-cascading deletion of the StatefulSet which keeps the pods running
1. Add the new labels to the pods
1. Run `helm upgrade`

Use a script like the following to add labels and to delete the StatefulSet:

```console
#!/bin/sh
release=<release>
namespace=<release_namespace>
kubectl delete statefulset -n "$namespace" -l app=keycloak -l release="$release" --cascade=false
kubectl label pod -n "$namespace" -l app=keycloak -l release="$release" app.kubernetes.io/name=keycloak
kubectl label pod -n "$namespace" -l app=keycloak -l release="$release" app.kubernetes.io/instance="$release"
```

**NOTE:** Version 5.0.0 also updates the Postgresql dependency which has received a major upgrade as well.
In case you use this dependency, the database must be upgraded first.
Please refer to the Postgresql chart's upgrading section in its README for instructions.
26 changes: 25 additions & 1 deletion charts/keycloak/ci/postgres-ha-values.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
keycloak:
replicas: 2
password: keycloak

podLabels:
test-label: test-label-value
podAnnotations:
test-annotation: test-annotation-value

startupScripts:
hello.sh: |
#!/bin/sh
echo '********************************************************************************'
echo '* *'
echo '* Hello from my startup script! *'
echo '* *'
echo '********************************************************************************'
lifecycleHooks: |
postStart:
exec:
command: ["/bin/sh", "-c", "echo 'Hello from lifecycle hook!'"]
persistence:
deployPostgres: true
dbVendor: postgres

postgresql:
postgresPassword: keycloak
postgresqlPassword: keycloak
persistence:
enabled: true
storageClass: local-path
6 changes: 3 additions & 3 deletions charts/keycloak/requirements.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
dependencies:
- name: postgresql
repository: https://kubernetes-charts.storage.googleapis.com/
version: 0.15.0
digest: sha256:428d8302be9a566a3e77538af30c56b63e0bfc97dd01dd434f303f4434cb8100
generated: 2018-07-06T08:41:15.715456938+02:00
version: 5.3.9
digest: sha256:5f20713cf4f8f03a87b1f78d2a350c3ebde4c500b4c4740c4c7a5655e47db924
generated: "2019-06-21T13:48:56.67213+02:00"
2 changes: 1 addition & 1 deletion charts/keycloak/requirements.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
dependencies:
- name: postgresql
version: 0.15.0
version: 5.3.9
repository: https://kubernetes-charts.storage.googleapis.com/
condition: keycloak.persistence.deployPostgres
1 change: 1 addition & 0 deletions charts/keycloak/scripts/ha.cli
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:2})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:2})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:write-attribute(name=owners, value=${env.CACHE_OWNERS:2})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens:write-attribute(name=owners, value=${env.CACHE_OWNERS:2})

/subsystem=jgroups/channel=ee:write-attribute(name=stack, value=tcp)
1 change: 1 addition & 0 deletions charts/keycloak/scripts/logging.cli
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Add dedicated eventsListener config element to allow configuring elements.
/subsystem=keycloak-server/spi=eventsListener:add()
/subsystem=keycloak-server/spi=eventsListener/provider=jboss-logging:add(enabled=true)

# Propagate success events to INFO instead of DEBUG, to expose successful logins for log analysis
/subsystem=keycloak-server/spi=eventsListener/provider=jboss-logging:write-attribute(name=properties.success-level,value=info)
/subsystem=keycloak-server/spi=eventsListener/provider=jboss-logging:write-attribute(name=properties.error-level,value=warn)
15 changes: 6 additions & 9 deletions charts/keycloak/templates/NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Keycloak can be accessed:

* Within your cluster, at the following DNS name at port {{ .Values.keycloak.service.port }}:

{{ template "keycloak.fullname" . }}-http.{{ .Release.Namespace }}.svc.cluster.local
{{ include "keycloak.fullname" . }}-http.{{ .Release.Namespace }}.svc.cluster.local

{{- if .Values.keycloak.ingress.enabled }}

Expand All @@ -19,34 +19,31 @@ Keycloak can be accessed:

{{- if contains "NodePort" .Values.keycloak.service.type }}

export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "keycloak.fullname" . }})
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "keycloak.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT

{{- else if contains "LoadBalancer" .Values.keycloak.service.type }}

NOTE:
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "keycloak.fullname" . }}'
You can watch the status of by running 'kubectl get svc -w {{ include "keycloak.fullname" . }}'

export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "keycloak.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "keycloak.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.keycloak.service.port }}

{{- else if contains "ClusterIP" .Values.keycloak.service.type }}

export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l app={{ template "keycloak.name" . }},release={{ .Release.Name }} -o jsonpath="{.items[0].metadata.name}")
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l app={{ include "keycloak.name" . }},release={{ .Release.Name }} -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use Keycloak"
kubectl port-forward --namespace {{ .Release.Namespace }} $POD_NAME 8080

{{- end }}

{{- end }}

{{- if .Release.IsInstall }}

Login with the following credentials:
Username: {{ .Values.keycloak.username }}

To retrieve the initial user password run:
kubectl get secret --namespace {{ .Release.Namespace }} {{ template "keycloak.fullname" . }}-http -o jsonpath="{.data.password}" | base64 --decode; echo
{{- end }}
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "keycloak.fullname" . }}-http -o jsonpath="{.data.password}" | base64 --decode; echo
Loading

0 comments on commit 6a2c027

Please sign in to comment.