Try It Out
In this example we will deploy Keycloak on a Kubernetes cluster using the Minimus Keycloak Advanced Helm chart. Keycloak will be configured with authentication, PostgreSQL database, and persistent storage.
Step 1: Start Cluster
If you have a cluster to work with, skip this step. Otherwise, start a Minikube cluster. Deployment instructions
Step 2: Create Namespace
Create a namespace:
kubectl create ns keycloak-advanced
Step 3: Save Values File Locally
Go to the Values tab and save a copy of it locally. You will pass it to Helm with -f values.yaml to use the defaults, then override specific values with --set flags.
Step 4: Deploy PostgreSQL (External)
Deploy PostgreSQL separately using the Minimus PostgreSQL Advanced chart. This is the recommended approach for reliability and flexibility.
First, create the PostgreSQL namespace:
kubectl create namespace postgresql-advanced
Then install PostgreSQL with your required chart version:
helm install my-postgresql-advanced \
oci://helm.mini.dev/postgresql-advanced \
--version 0.1.0 \
-n postgresql-advanced \
--set global.imageRegistry=reg.mini.dev \
--set global.imagePullSecrets[0].name=minimus-registry \
--set postgresql.auth.username=bn_keycloak \
--set postgresql.auth.password=keycloakpass \
--set postgresql.auth.database=bitnami_keycloak
Wait for PostgreSQL to be ready:
kubectl wait --for=condition=ready pod \
-l app.kubernetes.io/name=postgresql \
-n postgresql-advanced \
--timeout=10m
Get the PostgreSQL service name:
kubectl get svc -n postgresql-advanced
You'll see a service like my-postgresql-advanced (note the service name, not the pod name).
Step 5: Deploy Keycloak
Deploy Keycloak using --set flags to configure the external PostgreSQL database. Important: The database password must match exactly what you set in PostgreSQL.
helm install my-keycloak-advanced oci://helm.mini.dev/keycloak-advanced \
--version 0.1.0 \
-f values.yaml \
-n keycloak-advanced \
--set postgresql.enabled=false \
--set keycloak.externalDatabase.host=my-postgresql-advanced.postgresql-advanced.svc.cluster.local \
--set keycloak.externalDatabase.port=5432 \
--set keycloak.externalDatabase.user=bn_keycloak \
--set keycloak.externalDatabase.password=keycloakpass \
--set keycloak.externalDatabase.database=bitnami_keycloak \
--set keycloak.auth.adminPassword=my-admin-pass
Important:
--set postgresql.enabled=false disables the bundled PostgreSQL dependency
- If PostgreSQL is in a different namespace, use the full FQDN:
{service-name}.{namespace}.svc.cluster.local
- If PostgreSQL is in the same namespace, you can use just the service name:
{service-name}
- The database password must match exactly the password you set in PostgreSQL (
keycloakpass in this example)
- The default resource limits (200m CPU, 512Mi memory) are already set in values.yaml for small clusters
Step 6: Verify Keycloak is Running
To check that the pods were successfully created run:
kubectl get pods -n keycloak-advanced
You should see output similar to:
NAME READY STATUS RESTARTS AGE
my-postgresql-advanced-0 1/1 Running 0 5m
my-keycloak-advanced-0 1/1 Running 0 5m
Keycloak pod:
keycloak → main Keycloak container
prepare-write-dirs → init container (if defaultInitContainers.prepareWriteDirs.enabled=true)
Init containers do not appear in the READY count, so 1/1 is correct for each pod.
Note: Keycloak may take 2-5 minutes to fully start and connect to PostgreSQL. If the Keycloak pod shows CrashLoopBackOff, check the logs:
kubectl logs my-keycloak-advanced-0 -n keycloak-advanced -c keycloak
Common issues:
- "cannot resolve host" → Check that
keycloak.externalDatabase.host matches the PostgreSQL service FQDN: {service-name}.{namespace}.svc.cluster.local
- Connection refused → Wait for PostgreSQL to be fully ready (1/1 Running)
- "password authentication failed" → The database password doesn't match. Ensure
--set keycloak.externalDatabase.password=... matches the password you set in PostgreSQL
- Authentication failed → Verify the database user (
bn_keycloak), password, and database name (bitnami_keycloak) all match your PostgreSQL configuration
Step 7: Test Keycloak Connection
This verifies Keycloak is actually working and accepting connections.
Wait for Keycloak to be ready (this may take 2-5 minutes after the pod starts):
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=keycloak -n keycloak-advanced --timeout=10m
Get the Keycloak admin password from the secret:
kubectl get secret my-keycloak-advanced -n keycloak-advanced -o jsonpath='{.data.admin-password}' | base64 -d
Connect to Keycloak using port-forward:
kubectl port-forward svc/my-keycloak-advanced 8080:8080 -n keycloak-advanced
In another terminal or browser, access the Keycloak admin console:
Login with:
- Username:
user (or the value set in keycloak.auth.adminUser, default is user)
- Password:
my-admin-pass (or the value you set with --set keycloak.auth.adminPassword=...)
Or test the health endpoint:
curl http://localhost:8080/health/ready
If you see a successful response, the deployment is fully operational.
Step 8: Using an Existing PostgreSQL Database
If you already have a PostgreSQL database running (from another Helm chart, managed service, etc.), you can point Keycloak to it:
helm install my-keycloak-advanced oci://helm.mini.dev/keycloak-advanced \
--version 0.1.0 \
-f values.yaml \
-n keycloak-advanced \
--set postgresql.enabled=false \
--set keycloak.externalDatabase.host=your-postgres-host.your-namespace.svc.cluster.local \
--set keycloak.externalDatabase.port=5432 \
--set keycloak.externalDatabase.user=your-db-user \
--set keycloak.externalDatabase.password=your-password \
--set keycloak.externalDatabase.database=your-database \
--set keycloak.auth.adminPassword=my-admin-pass
Note:
- If the database is in the same namespace, you can use just the service name:
your-postgres-host
- If the database is in a different namespace, use the full FQDN:
your-postgres-host.your-namespace.svc.cluster.local
- For cloud-managed databases (Cloud SQL, RDS, etc.), use the external hostname and ensure network connectivity
Step 9: Cleanup
To clean up the deployment:
helm uninstall my-keycloak-advanced -n keycloak-advanced
helm uninstall my-postgresql-advanced -n postgresql-advanced
kubectl delete namespace keycloak-advanced
kubectl delete namespace postgresql-advanced
Note: This will remove both Keycloak and PostgreSQL deployments and all their data. Make sure to backup any important data before cleanup.