From 1bde9b4ac9ed3a3d9e512edfc3ad43aa6c46eb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20N=C3=A4gele?= Date: Sun, 17 Dec 2017 17:07:35 +0100 Subject: [PATCH] [incubator/keycloak] Add high availability and various improvements (#2756) * [incubator/keycloak] Add high availability and various improvements * Add various improvements, such as node selector, tolerations, and pod anti-affinity * Switch to StatefulSet due to length restrictions for WildFly node identifier and for potential advantages for cluster discovery when names pod stable * Add high availability and clustering using JDBC_PING discovery for JGroups * Add customizability via WildFly CLI * Improve ingress configuration * Fix NOTES.txt * Improve external database configuration * Fix typos * Add login test * Fix Postgres conditionals * Automatically enable HA when keycloak.replicas > 1 --- incubator/keycloak/Chart.yaml | 7 +- incubator/keycloak/README.md | 142 +++++++++++- incubator/keycloak/requirements.lock | 4 +- incubator/keycloak/requirements.yaml | 1 + incubator/keycloak/templates/NOTES.txt | 69 +++--- incubator/keycloak/templates/_helpers.tpl | 76 ++++++- incubator/keycloak/templates/configmap.yaml | 71 ++++++ incubator/keycloak/templates/db-secret.yaml | 14 ++ incubator/keycloak/templates/deployment.yaml | 63 ------ .../keycloak/templates/headless-service.yaml | 20 ++ .../keycloak/templates/http-service.yaml | 30 +++ incubator/keycloak/templates/ingress.yaml | 45 ++-- .../keycloak/templates/keycloak-secret.yaml | 16 ++ incubator/keycloak/templates/secrets.yaml | 16 -- incubator/keycloak/templates/service.yaml | 29 --- incubator/keycloak/templates/statefulset.yaml | 124 +++++++++++ .../templates/test/test-configmap.yaml | 48 ++++ .../keycloak/templates/test/test-pod.yaml | 35 +++ incubator/keycloak/templates/tls-secret.yaml | 21 ++ incubator/keycloak/values.yaml | 205 ++++++++++++------ 20 files changed, 799 insertions(+), 237 deletions(-) create mode 100644 incubator/keycloak/templates/configmap.yaml create mode 100644 incubator/keycloak/templates/db-secret.yaml delete mode 100644 incubator/keycloak/templates/deployment.yaml create mode 100644 incubator/keycloak/templates/headless-service.yaml create mode 100644 incubator/keycloak/templates/http-service.yaml create mode 100644 incubator/keycloak/templates/keycloak-secret.yaml delete mode 100644 incubator/keycloak/templates/secrets.yaml delete mode 100644 incubator/keycloak/templates/service.yaml create mode 100644 incubator/keycloak/templates/statefulset.yaml create mode 100644 incubator/keycloak/templates/test/test-configmap.yaml create mode 100644 incubator/keycloak/templates/test/test-pod.yaml create mode 100644 incubator/keycloak/templates/tls-secret.yaml diff --git a/incubator/keycloak/Chart.yaml b/incubator/keycloak/Chart.yaml index d2a2252474..812a1a0b03 100644 --- a/incubator/keycloak/Chart.yaml +++ b/incubator/keycloak/Chart.yaml @@ -1,6 +1,6 @@ name: keycloak -version: 0.1.0 -appVersion: 3.3.0.Final +version: 0.2.0 +appVersion: 3.4.0.Final description: Open Source Identity and Access Management For Modern Applications and Services keywords: - authentication @@ -11,4 +11,5 @@ sources: maintainers: - name: nexeck email: marcel@beck.im -engine: gotpl + - name: unguiculus + email: unguiculus@gmail.com diff --git a/incubator/keycloak/README.md b/incubator/keycloak/README.md index c7cb4ff0b7..6f3db5489b 100644 --- a/incubator/keycloak/README.md +++ b/incubator/keycloak/README.md @@ -11,18 +11,21 @@ $ helm install incubator/keycloak ## Introduction -This chart bootstraps a [Keycloak](http://www.keycloak.org/) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. +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 it's [documentation](http://www.keycloak.org/documentation.html). ## Prerequisites Details -* PV support on underlying infrastructure (if persistence is required) +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 -To install the chart with the release name `keycloak` into the namespace keycloak-system: +To install the chart with the release name `keycloak`: ```console -$ helm install --name keycloak incubator/keycloak --namespace keycloak-system +$ helm install --name keycloak incubator/keycloak ``` ## Uninstalling the Chart @@ -33,13 +36,59 @@ To uninstall/delete the `keycloak` deployment: $ helm delete keycloak ``` -## Chart Details -This chart will provision a fully functional and fully featured Keycloak installation. -For more information on Keycloak and its capabilities, see it's [documentation](http://www.keycloak.org/documentation.html). - ## Configuration -Configurable values are documented in the `values.yaml`. +The following tables lists the configurable parameters of the Keycloak chart and their default values. + +Parameter | Description | Default +--- | --- | --- +`hyperkube.image.repository` | Hyperkube image repository | `quay.io/coreos/hyperkube` +`hyperkube.image.tag` | Hyperkube image tag | `v1.8.1_coreos.0` +`hyperkube.image.pullPolicy` | Hyperkube image pull policy | `IfNotPresent` +`keycloak.replicas` | The number of Keycloak replicas | `1` +`keycloak.image.repository` | The Keycloak image repository | `jboss/keycloak` +`keycloak.image.tag` | The Keycloak image tag | `3.4.0.Final` +`keycloak.image.pullPolicy` | The Keycloak image pull policy | `IfNotPresent` +`keycloak.username` | Username for the initial Keycloak admin user | `keycloak` +`keycloak.password` | Password for the initial Keycloak admin user. If not set, a random 10 characters password is created | `""` +`keycloak.additionalEnv` | Allows the specification of additional environment variables for Keycloak | `[]` +`keycloak.resources` | Pod resource requests and limits | `{}` +`keycloak.podAntiAffinity` | Pod anti-affinity (`soft` or `hard`) | `soft` +`keycloak.nodeSelector` | Node labels for pod assignment | `{}` +`keycloak.tolerations` | Node taints to tolerate | `[]` +`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.reverseProxy` | WildFly CLI script for reverse proxy configuration | See `values.yaml` +`keycloak.cli.discovery` | WildFly CLI script for cluster discovery | See `values.yaml` +`keycloak.cli.custom` | Additional custom WildFly CLI script | `""` +`keycloak.service.annotations` | Annotations for the Keycloak service | `{}` +`keycloak.service.labels` | Additional labels for ther Keycloak service | `{}` +`keycloak.service.type` | The service type | `ClusterIP` +`keycloak.service.port` | The service port | `80` +`keycloak.service.nodePort` | The node port used if the service is of type `NodePort` | `""` +`keycloak.ingress.enabled` | If true, an ingress is be created | `false` +`keycloak.ingress.path` | The ingress path | `/` +`keycloak.ingress.annotations` | Annotations for the ingress | `{}` +`keycloak.ingress.hosts` | A list of hosts for the ingress | `[keycloak.example.com]` +`keycloak.ingress.tls.enabled` | If true, tls is enabled for the ingress | `false` +`keycloak.ingress.tls.existingSecret` | If tls is enabled, uses an existing secret with this name; otherwise a secret is created | `false` +`keycloak.ingress.tls.secretContents` | Contents for the tls secret | `{}` +`keycloak.ingress.tls.secretAnnotations` | Annotations for the newly created tls secret | `{}` +`keycloak.persistence.deployPostgres` | If true, the PostgreSQL chart is installed | `true` +`keycloak.persistence.existingSecret` | Name of an existing secret to be used for the database password (if `keycloak.persistence.deployPostgres=false`). Otherwise a new secret is created | `""` +`keycloak.persistence.existingSecretKey` | The key for the database password in the existing secret (if `keycloak.persistence.deployPostgres=false`) | `password` +`keycloak.persistence.dbVendor` | One of `H2`, `POSTGRES`, or `MYSQL` (if `deployPostgres=false`) | `H2` +`keycloak.persistence.dbName` | The name of the database to connect to (if `deployPostgres=false`) | `keycloak` +`keycloak.persistence.dbHost` | The database host name (if `deployPostgres=false`) | `mykeycloak` +`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`) | `keycloak` +`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` +`test.image.repository` | Test image repository | `unguiculus/docker-python3-phantomjs-selenium` +`test.image.tag` | Test image tag | `v1` +`test.image.pullPolicy` | Test image pull policy | `IfNotPresent` Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. @@ -49,4 +98,77 @@ Alternatively, a YAML file that specifies the values for the parameters can be p $ helm install --name keycloak -f values.yaml incubator/keycloak ``` -> **Tip**: You can use the default [values.yaml](values.yaml) +### Database Setup + +By default, the [PostgreSQL](https://github.com/kubernetes/charts/tree/master/stable/postgresql) chart is deployed and used as database. +Please refer to this chart for additional PostgreSQL configuration options. If PostgreSQL is disabled, Keycloak uses an embedded H2 +database which is only suitable for testing with a single replica. + +#### Using an External Database + +The Keycloak Docker image supports PostgreSQL and MySQL. 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: + persistence: + + # Disable deployment of the PostgreSQL chart + deployPostgres: false + + # Optionally specify an existing secret + existingSecret: "my-database-password-secret" + existingSecretKey: "password-key in-my-database-secret" + + dbVendor: POSTGRES # for MySQL use "MYSQL" + + dbName: keycloak + dbHost: mykeycloak + dbPort: 5432 # 5432 is PostgreSQL's default port. For MySQL it would be 3306 + dbUser: keycloak + + # Only used if no existing secret is specified. In this case a new secret is created + dbPassword: keycloak +``` + +See also: +* https://github.com/jboss-dockerfiles/keycloak/blob/master/server/cli/databases/postgres/change-database.cli +* https://github.com/jboss-dockerfiles/keycloak/blob/master/server/cli/databases/mysql/change-database.cli + +### Configuring additional environment variables: + +```yaml +keycloak: + additionalEnv: + - name: KEYCLOAK_LOGLEVEL + value: : DEBUG + - name: WILDFLY_LOGLEVEL + value: DEBUG + - name: CACHE_OWNERS: + value"3" +``` + +### WildFly Configuration + +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. + +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. + +### 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. If `keycloak.replicas > 1`, the +WildFly CLI script `keycloak.cli.discovery` adds JGroups' [JDBC_PING](http://www.jgroups.org/javadoc/org/jgroups/protocols/JDBC_PING.html) +for cluster discovery and Keycloak is started with `--server-config standalone-ha.xml`. + +## Why StatefulSet? + +The chart sets node identifiers to the system property `jboss.node.name` which is in fact the pod name. Node identifiers +must not be longer than 23 characters. This can be problematic because pod names are quite long. We would have to truncate +the chart's fullname to six characters because pods get a 17-character suffix (e. g. `-697f8b7655-mf5ht`). 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. diff --git a/incubator/keycloak/requirements.lock b/incubator/keycloak/requirements.lock index 94747dc828..014420bce0 100644 --- a/incubator/keycloak/requirements.lock +++ b/incubator/keycloak/requirements.lock @@ -2,5 +2,5 @@ dependencies: - name: postgresql repository: https://kubernetes-charts.storage.googleapis.com/ version: 0.8.3 -digest: sha256:b67c843d95aa0a2e7684abb787b22913e54baa92f45a450a3c3bcb7f3e068748 -generated: 2017-10-28T10:01:56.578879+02:00 +digest: sha256:cb2fd7e1ac6001bc8f963a39acb2af903e1e0f684535b9790631c9db59787ada +generated: 2017-11-29T09:01:49.898438236+01:00 diff --git a/incubator/keycloak/requirements.yaml b/incubator/keycloak/requirements.yaml index 98765c61de..a9804aa3af 100644 --- a/incubator/keycloak/requirements.yaml +++ b/incubator/keycloak/requirements.yaml @@ -2,3 +2,4 @@ dependencies: - name: postgresql version: 0.8.3 repository: https://kubernetes-charts.storage.googleapis.com/ + condition: keycloak.persistence.deployPostgres diff --git a/incubator/keycloak/templates/NOTES.txt b/incubator/keycloak/templates/NOTES.txt index 7153a73f28..353a952ecf 100644 --- a/incubator/keycloak/templates/NOTES.txt +++ b/incubator/keycloak/templates/NOTES.txt @@ -1,44 +1,49 @@ 1. Keycloak can be accessed: - * Within your cluster, at the following DNS name at port {{ .Values.keycloak.service.port }}: + * Within your cluster, at the following DNS name at port {{ .Values.keycloak.service.port }}: - {{ template "keycloak.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + {{ template "keycloak.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local - {{- if .Values.keycloak.ingress.enabled }} +{{- if .Values.keycloak.ingress.enabled }} - * From outside the cluster, the URL is: -{{- if .Values.keycloak.ingress.tls }} - https://{{ .Values.keycloak.ingress.hostname }} -{{- else }} - http://{{ .Values.keycloak.ingress.hostname }} -{{- end }} - {{- else }} + * From outside the cluster: - * From outside the cluster, run these commands in the same shell: - {{- 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_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" . }}' - - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "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}") - echo "Visit http://127.0.0.1:8080 to use Keycloak" - kubectl port-forward --namespace {{ .Release.Namespace }} $POD_NAME 8080:{{ .Values.keycloak.service.port }} + {{- range .Values.keycloak.ingress.hosts }} + - http{{ if $.Values.keycloak.ingress.tls.enabled }}s{{ end }}://{{ . }} {{- end }} + +{{- else }} + + * From outside the cluster, run these commands in the same shell: + + {{- 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_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" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "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}") + echo "Visit http://127.0.0.1:8080 to use Keycloak" + kubectl port-forward --namespace {{ .Release.Namespace }} $POD_NAME 8080 + {{- end }} -2. Login with the following credentials +{{- end }} - To get your user password run: - kubectl get secret --namespace {{ .Release.Namespace }} {{ template "keycloak.fullname" . }} -o jsonpath="{.data.keycloak-password}" | base64 --decode; echo +2. Login with the following credentials: - Username: {{ .Values.keycloak.username }} + 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 diff --git a/incubator/keycloak/templates/_helpers.tpl b/incubator/keycloak/templates/_helpers.tpl index 4a54c9ed73..49169cfc29 100644 --- a/incubator/keycloak/templates/_helpers.tpl +++ b/incubator/keycloak/templates/_helpers.tpl @@ -8,11 +8,13 @@ Expand the name of the chart. {{/* Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +We truncate to 20 characters because this is used to set the node identifier in WildFly which is limited to +23 characters. This allows for a replica suffix for up to 99 replicas. */}} {{- define "keycloak.fullname" -}} {{- $name := default .Chart.Name .Values.nameOverride -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- $fullname := printf "%s-%s" $name .Release.Name -}} +{{- default $fullname .Values.fullnameOverride | trunc 20 | trimSuffix "-" -}} {{- end -}} {{/* @@ -23,3 +25,73 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this {{- $name := default "postgresql" .Values.postgresql.nameOverride -}} {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} {{- end -}} + +{{/* +Create the name for the tls secret. +*/}} +{{- define "keycloak.tlsSecret" -}} +{{- if .Values.keycloak.ingress.tls.existingSecret -}} + {{- .Values.keycloak.ingress.tls.existingSecret -}} +{{- else -}} + {{- template "keycloak.fullname" . -}}-tls +{{- end -}} +{{- end -}} + +{{/* +Create the name for the database secret. +*/}} +{{- define "keycloak.externalDbSecret" -}} +{{- if .Values.keycloak.persistence.existingSecret -}} + {{- .Values.keycloak.persistence.existingSecret -}} +{{- else -}} + {{- template "keycloak.fullname" . -}}-db +{{- end -}} +{{- end -}} + +{{/* +Create the name for the password secret key. +*/}} +{{- define "keycloak.dbPasswordKey" -}} +{{- if .Values.keycloak.persistence.existingSecret -}} + {{- .Values.keycloak.persistence.existingSecretKey -}} +{{- else -}} + password +{{- end -}} +{{- end -}} + +{{/* +Create environment variables for database configuration. +*/}} +{{- define "keycloak.externalDbConfig" -}} +- name: DB_VENDOR + value: {{ .Values.keycloak.persistence.dbVendor | quote }} +{{- if eq .Values.keycloak.persistence.dbVendor "POSTGRES" }} +- name: POSTGRES_PORT_5432_TCP_ADDR + value: {{ .Values.keycloak.persistence.dbHost | quote }} +- name: POSTGRES_PORT_5432_TCP_PORT + value: {{ .Values.keycloak.persistence.dbPort | quote }} +- name: POSTGRES_USER + value: {{ .Values.keycloak.persistence.dbUser | quote }} +- name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "keycloak.externalDbSecret" . }} + key: {{ include "keycloak.dbPasswordKey" . | quote }} +- name: POSTGRES_DATABASE + value: {{ .Values.keycloak.persistence.dbName | quote }} +{{- else if eq .Values.keycloak.persistence.dbVendor "MYSQL" }} +- name: MYSQL_PORT_3306_TCP_ADDR + value: {{ .Values.keycloak.persistence.dbHost | quote }} +- name: MYSQL_PORT_3306_TCP_PORT + value: {{ .Values.keycloak.persistence.dbPort | quote }} +- name: MYSQL_USER + value: {{ .Values.keycloak.persistence.dbUser | quote }} +- name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "keycloak.externalDbSecret" . }} + key: {{ include "keycloak.dbPasswordKey" . | quote }} +- name: MYSQL_DATABASE + value: {{ .Values.keycloak.persistence.dbName | quote }} +{{- end }} +{{- end -}} diff --git a/incubator/keycloak/templates/configmap.yaml b/incubator/keycloak/templates/configmap.yaml new file mode 100644 index 0000000000..3a26691449 --- /dev/null +++ b/incubator/keycloak/templates/configmap.yaml @@ -0,0 +1,71 @@ +{{- $highAvailability := gt (int .Values.keycloak.replicas) 1 -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "keycloak.fullname" . }} + labels: + app: {{ template "keycloak.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +data: +{{- if .Values.keycloak.persistence.deployPostgres }} + wait_for_postgresql.sh: | + #!/usr/bin/env bash + + set -eu + + pod_labels="${1?Please specify PostgreSQL labels}" + max_retries=30 + retry_count=0 + sleep_secs=2 + ready_pods= + + echo 'Polling for PostgreSQL readiness...' + + while [ -z "$ready_pods" ] && [ "$retry_count" -lt "$max_retries" ]; do + ready_pods=$(kubectl get pods -l "$pod_labels" -o jsonpath="{.items[*].status.containerStatuses[?(@.ready==true)].name}") + retry_count=$((retry_count + 1)) + sleep "$sleep_secs" + done + + if [ -z "$ready_pods" ]; then + echo "ERROR: Timeout waiting for PostgreSQL to start up." >&2 + exit 1 + fi + + echo "PostgreSQL ready!" +{{- end }} + + keycloak.sh: | + #!/usr/bin/env bash + + set -eu + + /opt/jboss/keycloak/bin/jboss-cli.sh --file=/scripts/keycloak.cli + + args=(-b 0.0.0.0{{ if $highAvailability }} --server-config standalone-ha.xml{{ end }}) + + exec /opt/jboss/docker-entrypoint.sh "${args[@]}" + exit "$?" + + keycloak.cli: | + embed-server{{ if $highAvailability }} --server-config=standalone-ha.xml{{ end }} --std-out=echo + +{{- $cli := .Values.keycloak.cli }} + +{{ $cli.nodeIdentifier | indent 4 }} + +{{ $cli.logging | indent 4 }} + +{{ $cli.reverseProxy | indent 4 }} + +{{- if $highAvailability }} +{{ $cli.discovery | indent 4 }} +{{- end }} + +{{- if $cli.custom }} +{{ $cli.custom | indent 4 }} +{{- end }} + + stop-embedded-server diff --git a/incubator/keycloak/templates/db-secret.yaml b/incubator/keycloak/templates/db-secret.yaml new file mode 100644 index 0000000000..edd91687f7 --- /dev/null +++ b/incubator/keycloak/templates/db-secret.yaml @@ -0,0 +1,14 @@ +{{- if and (not .Values.keycloak.persistence.deployPostgres) (not .Values.keycloak.persistence.existingSecret) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "keycloak.fullname" . }}-db + labels: + app: {{ template "keycloak.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +type: Opaque +data: + {{ template "keycloak.dbPasswordKey" . }}: {{ .Values.keycloak.persistence.dbPassword | b64enc | quote }} +{{- end -}} diff --git a/incubator/keycloak/templates/deployment.yaml b/incubator/keycloak/templates/deployment.yaml deleted file mode 100644 index 3c6e70a5ca..0000000000 --- a/incubator/keycloak/templates/deployment.yaml +++ /dev/null @@ -1,63 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: {{ template "keycloak.fullname" . }} - labels: - app: {{ template "keycloak.name" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -spec: - replicas: 1 - template: - metadata: - labels: - app: {{ template "keycloak.name" . }} - release: "{{ .Release.Name }}" - spec: - containers: - - name: {{ .Chart.Name }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: - - name: PROXY_ADDRESS_FORWARDING - value: "true" - - name: KEYCLOAK_LOGLEVEL - value: {{ .Values.keycloak.loglevel | quote }} - - name: KEYCLOAK_USER - value: {{ .Values.keycloak.username | quote }} - - name: KEYCLOAK_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "keycloak.fullname" . }} - key: keycloak-password - - - name: POSTGRES_PORT_5432_TCP_ADDR - value: {{ template "keycloak.postgresql.fullname" . }} - - name: POSTGRES_PORT_5432_TCP_PORT - value: "5432" - - name: POSTGRES_USER - value: {{ .Values.postgresql.postgresUser | quote }} - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "keycloak.postgresql.fullname" . }} - key: postgres-password - - name: POSTGRES_DATABASE - value: {{ .Values.postgresql.postgresDatabase | quote }} - ports: - - containerPort: 8080 - livenessProbe: - httpGet: - path: / - port: 8080 - initialDelaySeconds: 120 - timeoutSeconds: 5 - readinessProbe: - httpGet: - path: / - port: 8080 - initialDelaySeconds: 5 - timeoutSeconds: 1 - resources: -{{ toYaml .Values.keycloak.resources | indent 10 }} diff --git a/incubator/keycloak/templates/headless-service.yaml b/incubator/keycloak/templates/headless-service.yaml new file mode 100644 index 0000000000..2890cfe3d9 --- /dev/null +++ b/incubator/keycloak/templates/headless-service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "keycloak.fullname" . }}-headless + labels: + app: {{ template "keycloak.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + type: ClusterIP + clusterIP: None + ports: + - name: http + port: {{ .Values.keycloak.service.port }} + targetPort: http + protocol: TCP + selector: + app: {{ template "keycloak.name" . }} + release: "{{ .Release.Name }}" diff --git a/incubator/keycloak/templates/http-service.yaml b/incubator/keycloak/templates/http-service.yaml new file mode 100644 index 0000000000..07d8ce791c --- /dev/null +++ b/incubator/keycloak/templates/http-service.yaml @@ -0,0 +1,30 @@ +{{- $service := .Values.keycloak.service -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "keycloak.fullname" . }}-http +{{- if $service.annotations }} + annotations: +{{ toYaml $service.annotations | indent 4 }} +{{- end }} + labels: + app: {{ template "keycloak.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- if $service.labels }} +{{ toYaml $service.labels | indent 4 }} +{{- end }} +spec: + type: {{ $service.type }} + ports: + - name: http + port: {{ $service.port }} + targetPort: http + {{- if and (eq "NodePort" $service.type) $service.nodePort }} + nodePort: {{ $service.nodePort }} + {{- end }} + protocol: TCP + selector: + app: {{ template "keycloak.name" . }} + release: "{{ .Release.Name }}" diff --git a/incubator/keycloak/templates/ingress.yaml b/incubator/keycloak/templates/ingress.yaml index b4bf8d8bf1..48a9698f5a 100644 --- a/incubator/keycloak/templates/ingress.yaml +++ b/incubator/keycloak/templates/ingress.yaml @@ -1,28 +1,35 @@ -{{- if .Values.keycloak.ingress.enabled -}} +{{- $ingress := .Values.keycloak.ingress -}} +{{- if $ingress.enabled -}} apiVersion: extensions/v1beta1 kind: Ingress metadata: name: {{ template "keycloak.fullname" . }} +{{- if $ingress.annotations }} + annotations: +{{ toYaml $ingress.annotations | indent 4 }} +{{- end }} labels: app: {{ template "keycloak.name" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -{{- if .Values.keycloak.ingress.annotations }} - annotations: -{{ toYaml .Values.keycloak.ingress.annotations | indent 4 }} -{{- end }} + chart: {{ .Chart.Name }}-{{ .Chart.Version }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} spec: - rules: - - host: {{ .Values.keycloak.ingress.hostname }} - http: - paths: - - path: / - backend: - serviceName: {{ template "keycloak.fullname" . }} - servicePort: {{ .Values.keycloak.service.port }} -{{- if .Values.keycloak.ingress.tls }} +{{- if $ingress.tls.enabled }} tls: -{{ toYaml .Values.keycloak.ingress.tls | indent 4 }} -{{- end -}} + - hosts: + {{- range $ingress.hosts }} + - {{ . }} + {{- end }} + secretName: {{ template "keycloak.tlsSecret" . }} +{{- end }} + rules: + {{- range $ingress.hosts }} + - host: {{ . }} + http: + paths: + - path: {{ $ingress.path }} + backend: + serviceName: {{ template "keycloak.fullname" $ }}-http + servicePort: http + {{- end }} {{- end -}} diff --git a/incubator/keycloak/templates/keycloak-secret.yaml b/incubator/keycloak/templates/keycloak-secret.yaml new file mode 100644 index 0000000000..12d5051f4f --- /dev/null +++ b/incubator/keycloak/templates/keycloak-secret.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "keycloak.fullname" . }}-http + labels: + app: {{ template "keycloak.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +type: Opaque +data: +{{- if .Values.keycloak.password }} + password: {{ .Values.keycloak.password | b64enc | quote }} +{{- else }} + password: {{ randAlphaNum 10 | b64enc | quote }} +{{- end }} diff --git a/incubator/keycloak/templates/secrets.yaml b/incubator/keycloak/templates/secrets.yaml deleted file mode 100644 index f45f7dfd08..0000000000 --- a/incubator/keycloak/templates/secrets.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ template "keycloak.fullname" . }} - labels: - app: {{ template "keycloak.name" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -type: Opaque -data: - {{ if .Values.keycloak.password }} - keycloak-password: {{ .Values.keycloak.password | b64enc | quote }} - {{ else }} - keycloak-password: {{ randAlphaNum 10 | b64enc | quote }} - {{ end }} diff --git a/incubator/keycloak/templates/service.yaml b/incubator/keycloak/templates/service.yaml deleted file mode 100644 index ce52632bff..0000000000 --- a/incubator/keycloak/templates/service.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ template "keycloak.fullname" . }} -{{- if .Values.keycloak.service.annotations }} - annotations: -{{ toYaml .Values.keycloak.service.annotations | indent 4 }} -{{- end }} - labels: - app: {{ template "keycloak.name" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -{{- if .Values.keycloak.service.labels }} -{{ toYaml .Values.keycloak.service.labels | indent 4 }} -{{- end }} -spec: - type: {{ .Values.keycloak.service.type }} - ports: - - name: http - port: {{ .Values.keycloak.service.port }} - targetPort: 8080 - {{ if and (eq "NodePort" .Values.keycloak.service.type) .Values.keycloak.service.nodePort }} - nodePort: {{ .Values.keycloak.service.nodePort}} - {{ end }} - protocol: TCP - selector: - app: {{ template "keycloak.name" . }} - release: "{{ .Release.Name }}" diff --git a/incubator/keycloak/templates/statefulset.yaml b/incubator/keycloak/templates/statefulset.yaml new file mode 100644 index 0000000000..dc6d1f4f29 --- /dev/null +++ b/incubator/keycloak/templates/statefulset.yaml @@ -0,0 +1,124 @@ +apiVersion: apps/v1beta1 +kind: StatefulSet +metadata: + name: {{ template "keycloak.fullname" . }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + labels: + app: {{ template "keycloak.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + replicas: {{ .Values.keycloak.replicas }} + serviceName: {{ template "keycloak.fullname" . }}-headless + podManagementPolicy: Parallel + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + app: {{ template "keycloak.name" . }} + release: "{{ .Release.Name }}" + spec: + {{- if .Values.keycloak.persistence.deployPostgres }} + initContainers: + - name: wait-for-postgresql + image: "{{ .Values.hyperkube.image.repository }}:{{ .Values.hyperkube.image.tag }}" + imagePullPolicy: "{{ .Values.hyperkube.image.pullPolicy }}" + command: + - "bash" + - "-c" + - "/scripts/wait_for_postgresql.sh app={{ template "keycloak.postgresql.fullname" . }}" + volumeMounts: + - name: scripts + mountPath: /scripts + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.keycloak.image.repository }}:{{ .Values.keycloak.image.tag }}" + imagePullPolicy: {{ .Values.keycloak.image.pullPolicy }} + command: + - /scripts/keycloak.sh + env: + - name: KEYCLOAK_USER + value: {{ .Values.keycloak.username }} + - name: KEYCLOAK_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "keycloak.fullname" . }}-http + key: password + {{- if .Values.keycloak.persistence.deployPostgres }} + - name: POSTGRES_PORT_5432_TCP_ADDR + value: {{ template "keycloak.postgresql.fullname" . }} + - name: POSTGRES_USER + value: {{ .Values.postgresql.postgresUser | quote }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "keycloak.postgresql.fullname" . }} + key: postgres-password + - name: POSTGRES_DATABASE + value: {{ .Values.postgresql.postgresDatabase | quote }} + {{- else }} +{{ include "keycloak.externalDbConfig" . | indent 12 }} + {{- end }} +{{- if .Values.keycloak.additionalEnv }} +{{ toYaml .Values.keycloak.additionalEnv | indent 12 }} +{{- end }} + volumeMounts: + - name: scripts + mountPath: /scripts + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + httpGet: + path: /auth/ + port: http + initialDelaySeconds: 120 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /auth/ + port: http + initialDelaySeconds: 5 + timeoutSeconds: 1 + resources: +{{ toYaml .Values.keycloak.resources | indent 12 }} + {{- if eq .Values.keycloak.podAntiAffinity "hard" }} + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: "kubernetes.io/hostname" + labelSelector: + matchLabels: + app: "{{ template "keycloak.fullname" . }}" + release: "{{ .Release.Name }}" + {{- else if eq .Values.keycloak.podAntiAffinity "soft" }} + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + app: "{{ template "keycloak.fullname" . }}" + release: "{{ .Release.Name }}" + {{- end }} + {{- if .Values.keycloak.nodeSelector }} + nodeSelector: +{{ toYaml .Values.keycloak.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.keycloak.tolerations }} + tolerations: +{{ toYaml .Values.keycloak.tolerations | indent 8 }} + {{- end }} + terminationGracePeriodSeconds: 60 + volumes: + - name: scripts + configMap: + name: {{ template "keycloak.fullname" . }} + defaultMode: 0755 diff --git a/incubator/keycloak/templates/test/test-configmap.yaml b/incubator/keycloak/templates/test/test-configmap.yaml new file mode 100644 index 0000000000..08d2e02e0a --- /dev/null +++ b/incubator/keycloak/templates/test/test-configmap.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "keycloak.fullname" . }}-test + labels: + app: {{ template "keycloak.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +data: + test.py: | + import os + from selenium import webdriver + from urllib.parse import urlparse + + print('Creating PhantomJS river...') + driver = webdriver.PhantomJS() + + base_url = 'http://{{ template "keycloak.fullname" . }}-http{{ if ne 80 (int .Values.keycloak.service.port) }}{{ .Values.keycloak.service.port }}{{ end }}' + + print('Opening Keycloak...') + driver.get('{0}/auth/admin/'.format(base_url)) + + username = os.environ['KEYCLOAK_USER'] + password = os.environ['KEYCLOAK_PASSWORD'] + + print('Entering username...') + driver.find_element_by_id('username').send_keys(username) + + print('Entering password...') + driver.find_element_by_id('password').send_keys(password) + + print('Clicking login button...') + driver.find_element_by_id('kc-login').click() + + current_url = urlparse(driver.current_url) + expected_url = urlparse('{0}/auth/admin/master/console/'.format(base_url)) + + print('Current URL: {0}'.format(current_url)) + print('Expected URL: {0}'.format(expected_url)) + + if current_url.path != expected_url.path: + print('Login failed. Current url is not expected url') + exit(1) + + print('URLs match. Login successful.') + + driver.quit() diff --git a/incubator/keycloak/templates/test/test-pod.yaml b/incubator/keycloak/templates/test/test-pod.yaml new file mode 100644 index 0000000000..622bb64723 --- /dev/null +++ b/incubator/keycloak/templates/test/test-pod.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "keycloak.fullname" . }}-test + labels: + app: {{ template "keycloak.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: {{ .Chart.Name }}-test + image: "{{ .Values.test.image.repository }}:{{ .Values.test.image.tag }}" + imagePullPolicy: {{ .Values.test.image.pullPolicy }} + command: + - python3 + - /tests/test.py + env: + - name: KEYCLOAK_USER + value: {{ .Values.keycloak.username }} + - name: KEYCLOAK_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "keycloak.fullname" . }}-http + key: password + volumeMounts: + - name: tests + mountPath: /tests + volumes: + - name: tests + configMap: + name: {{ template "keycloak.fullname" . }}-test + restartPolicy: Never diff --git a/incubator/keycloak/templates/tls-secret.yaml b/incubator/keycloak/templates/tls-secret.yaml new file mode 100644 index 0000000000..402ba4259e --- /dev/null +++ b/incubator/keycloak/templates/tls-secret.yaml @@ -0,0 +1,21 @@ +{{- $tls := .Values.keycloak.ingress.tls -}} +{{- if and $tls.enabled (not $tls.existingSecret) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "keycloak.fullname" . }}-tls +{{- if $tls.secretAnnotations }} + annotations: +{{ toYaml $tls.secretAnnotations | indent 4 }} +{{- end }} + labels: + app: {{ template "keycloak.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +type: Opaque +data: +{{- range $key, $value := $tls.secretContents }} + {{ $key }}: {{ $value | b64enc | quote }} +{{- end }} +{{- end -}} diff --git a/incubator/keycloak/values.yaml b/incubator/keycloak/values.yaml index 49b0029286..78da2caa62 100644 --- a/incubator/keycloak/values.yaml +++ b/incubator/keycloak/values.yaml @@ -1,35 +1,36 @@ -image: - ## Keycloak image. - ## - repository: jboss/keycloak - - ## keycloak image version. - ## ref: https://hub.docker.com/r/jboss/keycloak/tags/ - ## - tag: 3.3.0.Final - - ## Specify a imagePullPolicy: 'Always' if imageTag is 'latest', else set to 'IfNotPresent'. - ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-image - ## - pullPolicy: IfNotPresent +## Used to run 'kubectl' in an init container in order to wait for Postgresql to start up. +hyperkube: + image: + repository: quay.io/coreos/hyperkube + tag: v1.8.1_coreos.0 + pullPolicy: IfNotPresent keycloak: - ## First keycloak username - ## This user has full admin access + replicas: 1 + + image: + repository: jboss/keycloak + tag: 3.4.0.Final + pullPolicy: IfNotPresent + + ## Username for the initial Keycloak admin user username: keycloak - ## Keycloak Password for the first user. - ## If not set, a random 10 characters password will be used. - ## - # password: keycloak + ## Password for the initial Keycloak admin user + ## If not set, a random 10 characters password will be used + password: "" - ## Keycloak logging level - loglevel: INFO + ## Allows the specification of additional environment variables for Keycloak + additionalEnv: {} + # KEYCLOAK_LOGLEVEL: DEBUG + # WILDFLY_LOGLEVEL: DEBUG + # CACHE_OWNERS: 2 - ## Configure resource requests and limits. - ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ - ## - resources: + podAntiAffinity: soft + nodeSelector: {} + tolerations: [] + + resources: {} # limits: # cpu: "100m" # memory: "1024Mi" @@ -37,53 +38,129 @@ keycloak: # cpu: "100m" # memory: "1024Mi" - ## Ingress configuration. - ## ref: https://kubernetes.io/docs/user-guide/ingress/ - ## - ingress: - ## Enable Ingress. - ## - enabled: false + ## WildFly CLI configurations. They all end up in the file 'keycloak.cli' configured in the configmap whichn is + ## executed on server startup. + cli: + ## Sets the node identifier to the node name (= pod name). Node identifiers have to be unique. They can have a + ## maximum length of 23 characters. Thus, the chart's fullname template truncates its length accordingly. + nodeIdentifier: | + # Makes node identifier unique getting rid of a warning in the logs + /subsystem=transactions:write-attribute(name=node-identifier, value=${jboss.node.name}) - ## Annotations to be added to the ingress. - ## - # annotations: - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: 'true' + logging: | + # Allow log level to be configured via environment variable + /subsystem=logging/console-handler=CONSOLE:write-attribute(name=level, value=${env.WILDFLY_LOGLEVEL:INFO}) + /subsystem=logging/root-logger=ROOT:write-attribute(name=level, value=${env.WILDFLY_LOGLEVEL:INFO}) + + # Log only to console + /subsystem=logging/root-logger=ROOT:write-attribute(name=handlers, value=[CONSOLE]) + + reverseProxy: | + /socket-binding-group=standard-sockets/socket-binding=proxy-https:add(port=443) + /subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=redirect-socket, value=proxy-https) + /subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding, value=true) + + discovery: | + /subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:2}) + /subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:2}) + /subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions: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=jgroups/stack=tcp:remove() + /subsystem=jgroups/stack=tcp:add() + /subsystem=jgroups/stack=tcp/transport=TCP:add(socket-binding="jgroups-tcp") + /subsystem=jgroups/stack=tcp/protocol=JDBC_PING:add() + /subsystem=jgroups/stack=tcp/protocol=JDBC_PING/property=datasource_jndi_name:add(value=java:jboss/datasources/KeycloakDS) + /subsystem=jgroups/stack=tcp/protocol=JDBC_PING/property=clear_table_on_view_change:add(value=true) + /subsystem=jgroups/stack=tcp/protocol=JDBC_PING/property=break_on_coord_rsp:add(value=true) + + # Statements must be adapted for PostgreSQL. Additionally, we add a 'creation_timestamp' column. + /subsystem=jgroups/stack=tcp/protocol=JDBC_PING/property=initialize_sql:add(value="CREATE TABLE IF NOT EXISTS JGROUPSPING (own_addr varchar(200) NOT NULL, creation_timestamp timestamp NOT NULL, cluster_name varchar(200) NOT NULL, ping_data bytea, constraint PK_JGROUPSPING PRIMARY KEY (own_addr, cluster_name))") + /subsystem=jgroups/stack=tcp/protocol=JDBC_PING/property=insert_single_sql:add(value="INSERT INTO JGROUPSPING (own_addr, creation_timestamp, cluster_name, ping_data) values (?, NOW(), ?, ?)") + + /subsystem=jgroups/stack=tcp/protocol=MERGE3:add() + /subsystem=jgroups/stack=tcp/protocol=FD_SOCK:add(socket-binding="jgroups-tcp-fd") + /subsystem=jgroups/stack=tcp/protocol=FD:add() + /subsystem=jgroups/stack=tcp/protocol=VERIFY_SUSPECT:add() + /subsystem=jgroups/stack=tcp/protocol=pbcast.NAKACK2:add() + /subsystem=jgroups/stack=tcp/protocol=UNICAST3:add() + /subsystem=jgroups/stack=tcp/protocol=pbcast.STABLE:add() + /subsystem=jgroups/stack=tcp/protocol=pbcast.GMS:add() + /subsystem=jgroups/stack=tcp/protocol=pbcast.GMS/property=max_join_attempts:add(value=5) + /subsystem=jgroups/stack=tcp/protocol=MFC:add() + /subsystem=jgroups/stack=tcp/protocol=FRAG2:add() + + /subsystem=jgroups/channel=ee:write-attribute(name=stack, value=tcp) + /subsystem=jgroups/stack=udp:remove() + /socket-binding-group=standard-sockets/socket-binding=jgroups-mping:remove() + /interface=private:write-attribute(name=nic, value=eth0) + /interface=private:undefine-attribute(name=inet-address) + + custom: "" - ## Hostnames. - ## Must be provided if Ingress is enabled. - ## - hostname: keycloak.example.com - ## TLS configuration. - ## Secrets must be manually created in the namespace. - ## - # tls: - # - secretName: keycloak.example.com-tls - # hosts: - # - keycloak.example.com - # - # service: - # annotations: - # service.beta.kubernetes.io/aws-load-balancer-internal: "0.0.0.0/0" - # labels: - # key: value + annotations: {} + # service.beta.kubernetes.io/aws-load-balancer-internal: "0.0.0.0/0" + + labels: {} + # key: value ## ServiceType ## ref: https://kubernetes.io/docs/user-guide/services/#publishing-services---service-types - ## type: ClusterIP - ## nodePort port number - ## Is not required, but allows for static port assignment with - ## serviceType NodePort. - ## Default: nil + ## Optional static port assignment for service type NodePort. # nodePort: 30000 port: 80 + ## Ingress configuration. + ## ref: https://kubernetes.io/docs/user-guide/ingress/ + ingress: + enabled: false + path: / + + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # ingress.kubernetes.io/affinity: cookie + + ## List of hosts for the ingress + hosts: + - keycloak.example.com + + ## TLS configuration + tls: + enabled: false + existingSecret: "" + secretContents: {} + secretAnnotations: {} + + ## Persistence configuration + persistence: + # If true, the Postgres chart is deployed + deployPostgres: true + + ## The following values only apply if "deployPostgres" is set to "false" + + # Specifies an existing secret to be used for the database password + existingSecret: "" + + # The key in the existing secret that stores the password + existingSecretKey: password + + # The database vendor. Can be either "POSTGRES" or "MYSQL" + dbVendor: H2 + + dbName: keycloak + dbHost: mykeycloak + dbPort: 5432 + dbUser: keycloak + + # Only used if no existing secret is specified. In this case a new secret is created + dbPassword: keycloak + postgresql: ### PostgreSQL User to create. ## @@ -92,7 +169,7 @@ postgresql: ## PostgreSQL Password for the new user. ## If not set, a random 10 characters password will be used. ## - # postgresPassword: keycloak + postgresPassword: "" ## PostgreSQL Database to create. ## @@ -105,3 +182,9 @@ postgresql: ## Enable PostgreSQL persistence using Persistent Volume Claims. ## enabled: true + +test: + image: + repository: unguiculus/docker-python3-phantomjs-selenium + tag: v1 + pullPolicy: IfNotPresent