Kubernetes Pod Timezone Configuration
Standard timezone for Hypera infrastructure: America/Sao_Paulo
Problem
Kubernetes pods run in UTC by default. Logs and application timestamps show +0000 offset instead of local Brazil time (-0300).
Solution
Add the TZ environment variable to container specifications.
Implementation Patterns
1. Helm Values (extraEnv pattern)
For Helm charts that support extraEnv:
# In values.yaml
extraEnv:
- name: TZ
value: America/Sao_Paulo
2. Multiple Containers
When a deployment has multiple containers (e.g., API server + frontend), add TZ to ALL containers:
apiServer:
extraEnv:
- name: TZ
value: America/Sao_Paulo
frontend:
extraEnv:
- name: TZ
value: America/Sao_Paulo
3. Raw Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
env:
- name: TZ
value: America/Sao_Paulo
4. StatefulSet
apiVersion: apps/v1
kind: StatefulSet
spec:
template:
spec:
containers:
- name: app
env:
- name: TZ
value: America/Sao_Paulo
Verification
After deployment, verify timezone is set correctly:
# Check pod logs for timestamp offset
# Before: 2026-01-13T11:37:06 +0000
# After: 2026-01-13T08:37:06 -0300
# Or exec into pod
kubectl exec -it <pod-name> -n <namespace> -- date
# Should show: Mon Jan 13 08:37:06 -03 2026
Common Applications Requiring Timezone
| Application | Config Location | Notes |
|-------------|-----------------|-------|
| Dependency-Track | apiServer.extraEnv + frontend.extraEnv | Both containers need TZ |
| Grafana | env or extraEnvVars | Single container |
| Loki | extraEnv | Affects log timestamps |
| Prometheus | server.env | Affects alert timestamps |
| DefectDojo | extraEnv | Django app |
| PostgreSQL | primary.extraEnvVars | Database timestamps |
Important Notes
- Restart required: Pods must restart for TZ changes to take effect
- All containers: Set TZ on ALL containers in a pod, including sidecars
- Init containers: Also set TZ on init containers if they log timestamps
- Cron jobs: Kubernetes CronJob schedules are always UTC - TZ only affects container-level time
Hypera GitOps Workflow
- Edit values.yaml in
argo-cd-helm-values/kube-addons/<service>/<cluster>/values.yaml - Add TZ environment variable to all containers
- Commit and push (ArgoCD auto-syncs)
- Verify pods restart with new timezone
Reference
- IANA Timezone Database:
America/Sao_Paulo= UTC-3 (no DST since 2019) - Linux TZ variable: Uses
/usr/share/zoneinfo/America/Sao_Paulo
Gotchas
TZenv var only affects app-level timestamps, notkubectl logstimestamps (those come from the container runtime, which stays UTC). The kubelet timestamps stay+0000even after the pod's internal clock is São Paulo.- CronJob
schedule:is always UTC regardless of podTZ. A0 8 * * *schedule fires at 05:00 BRT, not 08:00 BRT. Usespec.timeZone: America/Sao_Pauloon the CronJob itself (K8s 1.27+) or compute the UTC offset manually. - Distroless and scratch images have no
/usr/share/zoneinfo—TZ=America/Sao_Paulosilently falls back to UTC. Either use a base image that ships tzdata or mount it via configMap/volume. - Init containers don't inherit
TZfrom the main container in older charts — set it on the init container spec separately or their migration logs stay UTC. - Java apps need
-Duser.timezone=America/Sao_Pauloin JAVA_OPTS in addition to TZ — the JVM reads its own property, not the env var, on some distributions. - PostgreSQL
TZenv var sets the OS clock, not the databasetimezonesetting. Server timestamps vianow()still use the value inpostgresql.conf— set both.