Change TimeZone in Docker and OCI compliant Containers

By default, Docker and Container uses UTC timezone. When container engines like Podman, Docker or CRI-O run containers, they pull down the specified OCI image from a container registry. The container image is usually built with a hardcoded link from /etc/localtime to one timezone. Once the image is pulled, the container engine just launches the container based on the hardcoded time zone. This means that your container running in London could be reporting that it is running in New York or Singapore, depending on where the image was built. Depending on your application and sometimes to meet certain audit requirements, it might be necessary for you to control the timezone in the containers.

Unfortunately, the option to control timezone in the containers / pods can vary, depending upon your container engine, the type of the OS in the container image, the versions of the container engines and platform used to run container engines. We’ll discuss some of these in this post.

With Docker Engine

The timezone of a container can be set using an environment variable in the docker container when it is created. For example:

$ docker run ubuntu:latest date
Sat Feb 27 15:58:32 UTC 2021
$ docker run -e TZ=Asia/Kolkata ubuntu:latest date
Sat Feb 27 15:58:40 Asia 2021

However, above works only if the image is fedora based. For alpine based images, it does not work:

$ docker run alpine:latest date
Sat Feb 27 16:00:05 UTC 2021
$ docker run -e TZ=Asia/Kolkata alpine:latest date
Sat Feb 27 16:00:26 UTC 2021

Do note that, docker engine uses containerd runtime these days, instead of docker runtime. So what said above is true for container engines using containerd.

With Dockerfile

We can also control container timezone using the Dockerfile. For this, we first need to install tzdata package and then specify timezone setting using the environmental variable:

FROM ubuntu:16.04

# tzdata for timzone
RUN apt-get update -y
RUN apt-get install -y tzdata

# timezone env with default
ENV TZ Asia/India

Lets build docker image and run it:

# build docker image
$ docker build -t ubuntu_modified_tz:20210221 .

# run docker container
$ docker run ubuntu_modified_tz:20210221 date
Sat Feb 27 16:58:17 Asia 2021

With Docker Compose

We can control timezone in the container, by setting TZ environment variable as part of docker-compose:

version: "3.9" 
services:
  ubuntu:
    image: ubuntu:latest
    container_name: ubuntu_container
    environment:
        - TZ=Asia/Kolkata

Again, it depends if the underlying OS has tzdata package installed or not, to support this variable. Also, instead of making it a part of docker-compose, you can supply it at runtime with docker-compose.

With Storage Data Volumes

The directory /usr/share/zoneinfo in Docker contains the container time zones available.  The desired time zone from this folder can be copied to /etc/localtime file, to set as default time.

This time zone files of the host machine can be set in Docker volume and shared among the containers by configuring it in the Dockerfile as below:

volumes: 
- "/etc/timezone:/etc/timezone:ro" 
- "/etc/localtime:/etc/localtime:ro"

The containers created out of this Dockerfile will have the same timezone as the host OS (as set in /etc/localtime file).

This method can also be used to set timezone when using docker compose. However as we have noted above, this might not work for all cases.

With Kubernetes Pods

Again, we have to rely here on setting up of the TZ variable:

spec:
      containers:
      - name: demo
        image: docker.io/ubuntu:latest
        imagePullPolicy: Always
        env:
        - name: TZ
          value: Asia/Kolkata

If we are using deployments, we can mention environment variable as part of container spec:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
spec:
  replicas: 3
  selector:
    matchLabels:
        app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: demo
        image: docker.io/ubuntu:latest
        imagePullPolicy: Always
        env:
        - name: TZ
          value: Asia/Kolkata
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      terminationGracePeriodSeconds: 0

If above does not work, you may also choose to use host volumes to map /etc/localtime file with the pods/deployments.

Leave a comment