This page covers common failures when deploying the Tyk Developer Portal on Kubernetes. For installation steps and configuration, see Install Developer Portal on Kubernetes.
Bootstrap Job Fails: Pod Security Standards Violation
Symptom: helm install completes but the bootstrap job fails with a security policy error, for example:
Error creating: pods "dev-portal-job-..." is forbidden: violates PodSecurity "restricted:latest"
Cause: The bootstrap job runs as root and does not support security context configuration via values.yaml. Clusters enforcing the Kubernetes PSS Restricted or Baseline profiles will reject it.
Fix: Disable the automatic bootstrap job and bootstrap the portal manually:
- Set
global.components.bootstrap: false in your values.yaml and run helm upgrade.
- Wait for the Portal pod to be ready:
kubectl rollout status deployment/tyk-dev-portal -n <namespace>
- Send the bootstrap request to create the bootstrap admin user:
curl -X POST http://<portal-service>:<port>/portal-api/bootstrap \
-H "Content-Type: application/json" \
-d '{
"username": "admin@example.com",
"password": "your-password",
"first_name": "Admin",
"last_name": "User"
}'
Once the call succeeds, the Portal shuts down the temporary bootstrap server and completes startup.
This is a known limitation in the Helm chart. The bootstrap job template does not yet support security context configuration. Use global.components.bootstrap: false and bootstrap manually as described above.
Portal Pod Crash-Looping
Symptom: The Portal pod restarts repeatedly. Inspect the pod state and logs:
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous
Probe Timeouts: Pod Killed Before Startup Completes
Symptom: Kubernetes terminates the pod before it finishes starting. Logs show:
Readiness probe failed: HTTP probe failed with statuscode: 503
Liveness probe failed: HTTP probe failed with statuscode: 503
Cause: The Portal’s /ready endpoint performs a live database ping on every probe check. Short-lived database latency (TLS handshake overhead or connection pool delays) can cause the probe to time out, triggering Kubernetes to restart the pod before it has fully initialized.
Fix: Increase the probe delays and thresholds in your values.yaml:
livenessProbe:
initialDelaySeconds: 120
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
initialDelaySeconds: 120
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
If the Portal connects to a database over a high-latency or TLS-secured link, increase initialDelaySeconds further (e.g., 300).
PostgreSQL Date Format Mismatch
Symptom: The pod enters CrashLoopBackOff immediately after starting, even though the database is reachable. Logs contain:
{"level":"fatal","message":"checking if bootstrapped: recovering config: convert field 1 failed: parsing time \"15-JAN-26 13:58:19.626098 +05:30\" as \"2006-01-02 15:04:05.999999999Z07:00\""}
Cause: The date format returned by the PostgreSQL server does not match the ISO format that the Portal expects. This occurs when the PostgreSQL DateStyle is not set to ISO.
Fix: Append datestyle and lc_time options to your database.connectionString in values.yaml.
For a DSN-format connection string:
host=<host> user=<user> password=<pass> dbname=<db> port=5432 sslmode=disable options=-c datestyle=ISO,MDY -c lc_time=C
For a URL-format connection string:
postgres://<user>:<pass>@<host>:5432/<db>?options=-c%20datestyle%3DISO%2CMDY%20-c%20lc_time%3DC
License Key Not Set
If the Portal is started without a valid Tyk license, it logs the following at startup:
| Log message | Meaning |
|---|
Initializing license: license is empty | license field is missing or empty in values.yaml |
Initializing license: token not valid | License key is set but malformed or expired |
Licensing: license is invalid | Periodic background check; license failed validation |
Fix: Set the license field in your values.yaml. If using a Kubernetes secret, confirm the secret contains a DevPortalLicense key and that useSecretName references it:
kubectl get secret <secret-name> -n <namespace> -o jsonpath='{.data.DevPortalLicense}' | base64 -d
Environment Variables Not Taking Effect
Symptom: Configuration set via extraEnvs (such as PORTAL_STORAGE or PORTAL_DATABASE_DIALECT) is not reflected at runtime. The Portal continues using previous values.
Cause: The Helm chart generates environment variables for certain fields (including storage type and database dialect) from its own templated values. Variables passed through extraEnvs may be overridden by these chart-generated values.
Fix: Use the chart’s native fields in values.yaml instead of extraEnvs for these settings:
Instead of extraEnvs | Use directly in values.yaml |
|---|
PORTAL_STORAGE=db | storage.type: db |
PORTAL_DATABASE_DIALECT=postgres | database.dialect: postgres |
Reserve extraEnvs for configuration options that have no direct Helm chart equivalent.