Time in Docker Containers

By | October 31, 2015

In this article I will give an example on how to maintain time in a Docker container. The time may be the correct local time or the accurate time of another timezone. Reasons for doing this may be:

  • The container is run on a host which does not maintain correct time information and you cannot modify the host.
  • You want the time in the container to be of a different timezone than the host.
  • You need to assure that the time maintained in different containers is synchronized.

Disclaimer: I am not an expert on Linux or shell script programming. I have merely assembled and applied knowledge I have found.

What time is it?

time-watch-CC0

To learn the time in a running Docker container, execute the date command:

docker exec -it [container id] date

To determine the timezone configured in a running Docker container, execute the following command:

docker exec -it [container id] cat /etc/timezone

Synchronising Time

Since I use Ubuntu as a base for most of my Docker images, I will use NTP to facilitate synchronisation of the time in my Docker containers.
As usual, installation of NTP is done when creating the Docker image.
If you are already installing other software using apt-get in the Dockerfile, just add ntp as in this example:

apt-get install -y wget python python-dev unzip gcc ntp && \

The following lines will install NTP and nothing more without relying on any prerequisites:

RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y ntp

With NTP installed, I use the following commands in the default startup-script that is executed when a new Docker container is run:

ntpd -gq
service ntp start

The first line sets the time while allowing for a larger adjustment. The second line starts the NTP service.

Setting the Timezone

In one case I was running Docker on a host that had the wrong timezone configured and I did not have the privileges to change the host timezone.
In Ubuntu you can set the timezone without requiring any user interaction using the following two commands:

echo Europe/Stockholm >/etc/timezone && \
dpkg-reconfigure -f noninteractive tzdata

If I produce a Docker image for others to use, I want to make the setting of a timezone optional and I also want the user of the image to be able to change which timezone to use.
To accomplish this, I add two environment variables to my Dockerfile:

# Set this environment variable to true to set timezone on container start.
ENV SET_CONTAINER_TIMEZONE false
# Default container timezone as found under the directory /usr/share/zoneinfo/.
ENV CONTAINER_TIMEZONE Europe/Stockholm

Then I add the following lines to the default startup-script that is executed whenever a new Docker container is started:

# Set the timezone.
if [ "$SET_CONTAINER_TIMEZONE" = "true" ]; then
	echo ${CONTAINER_TIMEZONE} >/etc/timezone && \
	dpkg-reconfigure -f noninteractive tzdata
	echo "Container timezone set to: $CONTAINER_TIMEZONE"
else
	echo "Container timezone not modified"
fi

If I start a Docker container without changing any environment variables, the timezone of the Docker container will not be set.
To set the timezone of a Docker container to the default timezone specified in the Dockerfile, I start the container like this:

docker run -e "SET_CONTAINER_TIMEZONE=true" [docker image name]

The -e flag allows us to set or modify environment variables when running a Docker container.
At start of a Docker container, log similar to this then appears:

Current default time zone: 'Europe/Stockholm'
Local time is now:      Sat Oct 31 23:49:38 CET 2015.
Universal Time is now:  Sat Oct 31 22:49:38 UTC 2015.

Container timezone set to: Europe/Stockholm

To use a custom timezone in a Docker container, I start it with an additional environment variable:

docker run -e "SET_CONTAINER_TIMEZONE=true" -e "CONTAINER_TIMEZONE=US/Arizona" [docker image name]

When the Docker container is started, log similar to this is displayed:

Current default time zone: 'America/Phoenix'
Local time is now:      Sat Oct 31 15:55:55 MST 2015.
Universal Time is now:  Sat Oct 31 22:55:55 UTC 2015.

Container timezone set to: US/Arizona

Update October 30, 2016:

As have been pointed out in the comments-section below, the above instructions do not result in the timezone being changed in Ubuntu 16.04.
In such a case, use the following commands to set the timezone:

echo Europe/Stockholm >/etc/timezone && \
ln -sf /usr/share/zoneinfo/Europe/Stockholm /etc/localtime && \
dpkg-reconfigure -f noninteractive tzdata

The reason for the previous instructions not working anymore under Ubuntu 16.04 is that dpkg-reconfigure overwrite the information in /etc/timezone with information based on /etc/localtime.
When I examine /etc/localtime in a freshly started Ubuntu 16.04 container, I see the following:

root@134ba694203a:/# ls -al /etc/localtime 
lrwxrwxrwx 1 root root 27 Oct 10 12:25 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC

Thus /etc/locatime is a symbolic link pointing at a file containing information about the current timezone.

Thus the code-fragment in the startup-script in the Docker container will now look like this:

# Set the timezone.
if [ "$SET_CONTAINER_TIMEZONE" = "true" ]; then
    echo ${CONTAINER_TIMEZONE} >/etc/timezone && \
    ln -sf /usr/share/zoneinfo/${CONTAINER_TIMEZONE} /etc/localtime && \
    dpkg-reconfigure -f noninteractive tzdata
    echo "Container timezone set to: $CONTAINER_TIMEZONE"
else
    echo "Container timezone not modified"
fi

Alpine Linux

Update October 30, 2016:

Ubuntu is no longer the first choice as far as base for my Docker images is concerned. The following example shows how to install the prerequisites and synchronize time in a Docker image based on Alpine Linux:

Install prerequisites:

# Install NTPD for time synchronization and timezone data.
RUN apk --no-cache update && \
    apk --no-cache upgrade && \
apk --no-cache add tzdata openntpd

Setting the timezone and synchronizing time in the startup-script in the Docker image:

# Set the timezone. Base image does not contain the setup-timezone script, so an alternate way is used.
if [ "$SET_CONTAINER_TIMEZONE" = "true" ]; then
    cp /usr/share/zoneinfo/${CONTAINER_TIMEZONE} /etc/localtime && \
	echo "${CONTAINER_TIMEZONE}" >  /etc/timezone && \
	echo "Container timezone set to: $CONTAINER_TIMEZONE"
else
	echo "Container timezone not modified"
fi

# Force immediate synchronisation of the time and start the time-synchronization service.
# In order to be able to use ntpd in the container, it must be run with the SYS_TIME capability.
# In addition you may want to add the SYS_NICE capability, in order for ntpd to be able to modify its priority.
ntpd -s

Unlike Ubuntu 16.04, the file containing the timezone information is copied to, and overwrites the file, /etc/localtime.

Note that a Docker image with an Alpine Linux base using the above technique to synchronize time must be started with the following flags or else time synchronization will fail:

docker run --cap-add=SYS_TIME --cap-add=SYS_NICE [name of docker image]

Docker Compose

The following is an example of how setting the environment variables related to timezones in a Docker Compose configuration file:

elastalert:
    image: ivankrizsan/elastalert:latest
    volumes:
        - ./ElastalertShared/logs:/opt/logs
        - ./ElastalertShared/rules:/opt/rules
    links:
        - elk_stack:elasticsearch_host
    environment:
        - SET_CONTAINER_TIMEZONE=true
        - CONTAINER_TIMEZONE=Europe/Stockholm
    stdin_open: false
    tty: false

Note that I use the equals-character(=) without any whitespace before the value. This is significant in the case of the SET_CONTAINER_TIMEZONE variable, which must contain exactly “true” in order for the timezone to be set in the new Docker container.

Happy coding!

14 thoughts on “Time in Docker Containers

  1. Jim

    The part of setting the Timezone using `/etc/timezone` and `dpkg-reconfigure` does not work on 16.04. Any update on that?

    Thanks for the great post.

    Reply
    1. Ivan Krizsan Post author

      Hello!
      Running dpkg-reconfigure in a Docker container created from the image ubuntu:16.04 poses no problems to me, as you run as root. If you try to execute dpkg-reconfigure with a user that lacks root privileges, you will get a write permission error. To avoid such an error, first execute sudo bash in your terminal window and then the dpkg-reconfigure command.
      Happy coding!

      Reply
        1. Ivan Krizsan Post author

          Hello!
          Thanks for pointing this out and taking the trouble to provide a demonstration!
          The article has been updated as to work with Ubuntu 16.04 too. In addition, I added a section on how to set timezone and synchronize time in a container based on Alpine Linux.
          Happy coding!

          Reply
          1. Jim

            Thank you for the solution and, equally important, for providing the reason why this happens.

  2. Abhijit

    Question : We would like to start the docker with a particular time or would like to provide some offset with System time. You can also call setting some virtual time with docker so that application ruuning will refer to this time as sys time till the time Docker is up and running. How can we achieve this ?

    Reply
  3. Ahmed Wasfy

    Thank you so much, it’s perfect. working amazingly.

    Reply
  4. Jon

    How to set the time zone to host running the docker in environment variables and then use it in yml?

    Reply
    1. Ivan Krizsan Post author

      Hi!
      I have not done this but I imagine that you need to write a script that finds the time zone of the host and then launch your Docker container(s) setting the appropriate environment variable as you do. If you have a Docker Compose configuration, then the script that finds the host time zone will probably need to modify the Docker Compose file – sed is your friend here.
      Happy coding!

      Reply
  5. Prashant Raghav

    Hi Ivan,
    I am using cloud foundry to host docker image and run into the same problem,will the solution also work for me as I do not have the root access to the VM where docker container is running.

    Reply
    1. Ivan Krizsan Post author

      Hi! As long as you are able to give the necessary permissions when starting the Docker container you will be fine.
      I do not know any details about Cloud Foundry, since I have never used it, sorry.
      Happy coding!

      Reply
  6. gregbown

    Very helpful, Thank you! Recently had a micro-service in docker complain that an outside API’s ssl cert was expired, when in fact it was not. The issue was the alpine container being in a different time. Your post provided the crucial pieces to correct the issue.
    Used your RUN syntax for my Dockerfile
    RUN apk –no-cache update && \
    apk –no-cache upgrade && \
    apk –no-cache add tzdata openntpd
    And then, placed the command in my docker-compose.yml to set the timezone to what the other API’s were on.
    command: >
    sh -c “cp /usr/share/zoneinfo/PST8PDT /etc/localtime && echo PST8PDT > /etc/timezone && echo Container timezone set to: PST8PDT”

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *