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?
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!
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.
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!
Hi! Thank you for the reply. Using a fresh ubuntu:16.04 container it does not work for me. Please check this screenshot where I demonstrate. http://imgur.com/a/j0fwW
Thanks again Ivan.
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!
Thank you for the solution and, equally important, for providing the reason why this happens.
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 ?
did you get any solution?
Thank you so much, it’s perfect. working amazingly.
How to set the time zone to host running the docker in environment variables and then use it in yml?
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!
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.
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!
Great article much appreciated!
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”