Archmede
Archmede

Reputation: 1842

Time in Docker container out of sync with host machine

I'm trying to connect to CosmosDB through my SpringBoot app. I have all of this working if I run the app with Spring or via Intellij. But, when I run the app in Docker I get the following error message:

com.azure.data.cosmos.CosmosClientException: The authorization token is not valid at the current time.
Please create another token and retry
(token start time: Thu, 26 Mar 2020 04:32:10 GMT, 
token expiry time: Thu, 26 Mar 2020 04:47:10 GMT, current server time: Tue, 31 Mar 2020 20:12:42 GMT).

Note that in the above error message the current server time is correct but the other times are 5 days behind.

What I find interesting is that I only ever receive this in the docker container.

FROM {copy of zulu-jdk11}

ARG JAR_FILE

#.crt file in the same folder as your Dockerfile
ARG CERT="cosmos.cer"
ARG ALIAS="cosmos2"

#import cert into java
COPY $CERT /
RUN chmod +x /$CERT
WORKDIR $JAVA_HOME/lib/security
RUN keytool -importcert -file /$CERT -alias $ALIAS -cacerts -storepass changeit -noprompt

WORKDIR /
COPY /target/${JAR_FILE} app.jar
COPY run-java.sh /
RUN chmod +x /run-java.sh

ENV JAVA_OPTIONS "-Duser.timezone=UTC"
ENV JAVA_APP_JAR "/app.jar"

# run as non-root to mitigate some security risks
RUN addgroup -S pcc && adduser -S nonroot -G nonroot
USER nonroot:nonroot

ENTRYPOINT ["/run-java.sh"]

One thing to note is ENV JAVA_OPTIONS "-Duser.timezone=UTC" but removing this didn't help me at all

I basically run the same step from IntelliJ and I have no issues with it but in docker the expiry date seems to be 5 days behind.

version: "3.7"
services:
  orchestration-agent:
    image: {image-name}
    ports:
      - "8080:8080"
    network_mode: host
    environment:
      - COSMOSDB_URI=https://host.docker.internal:8081/
      - COSMOSDB_KEY={key}
      - COSMOSDB_DATABASE={database}
      - COSMOSDB_POPULATEQUERYMETRICS=true
      - COSMOSDB_ITEMLEVELTTL=60

I think it should also be mentioned that I changed the network_mode to host. And I also changed the CosmosDB URI from https://localhost:8081 to https://host.docker.internal:8081/

I would also like to mention that I built my dockerfile with the help of:

Importing self-signed cert into Docker's JRE cacert is not recognized by the service

How to add a SSL self-signed cert to Jenkins for LDAPS within Dockerfile?

Upvotes: 7

Views: 15966

Answers (4)

Seven
Seven

Reputation: 582

If you are in windows using a docker desktop, you can run this command:

wsl -d docker-desktop -e /sbin/hwclock -s.

The command does the following:

wsl: This command invokes the Windows Subsystem for Linux (WSL).

-d docker-desktop: This specifies the distribution to run, in this case, docker-desktop. Docker Desktop uses its own WSL 2 backend, running as a separate WSL distribution named docker-desktop.

-e /sbin/hwclock -s: The -e option runs a specific executable in the specified distribution.

/sbin/hwclock -s runs the hwclock command with the -s flag, which reads the hardware clock (in this case, the Windows system clock) and sets the WSL system time to match it.

Upvotes: 0

Vadzim
Vadzim

Reputation: 26180

There is recent known problem with WSL 2 time shift after sleep which has been fixed in 5.10.16.3 WSL 2 Linux kernel which is still not included in Windows 10 version 21H1 update but can be installed manually.

How to check WSL kernel version:

> wsl uname -r

Temporal workaround for the old kernel that helps until next sleep:

> wsl hwclock -s

Upvotes: 5

Sean McCarthy
Sean McCarthy

Reputation: 5578

Here's an alternative that worked for me on WSL2 with Docker Desktop on Windows:

Since it's not possible to set the date inside a Docker container, I just opened Ubuntu in WSL2 and ran the following command to synchronize the clock:

sudo date -s "$(wget -qSO- --max-redirect=0 google.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z"

It worked well, so I added the following line in my root user's crontab:

# Edit root user's crontab
sudo crontab -e

# Add the following line to run it every minute of every day:
* * * * * sudo date -s "$(wget -qSO- --max-redirect=0 google.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z"

After that, I just restarted my Docker containers, and the dates were correct since they seemed to use the WSL2 Ubuntu dates.

Date before (incorrect):

date
Thu Feb  4 21:50:35 UTC 2021

Date after (correct):

date
Fri Feb  5 19:01:05 UTC 2021

Upvotes: -1

BMitch
BMitch

Reputation: 264156

Docker containers don't maintain a separate clock, it's identical to the Linux host since time is not a namespaced value. This is also why Docker removes the permission to change the time inside the container, since that would impact the host and other containers, breaking the isolation model.

However, on Docker Desktop, docker runs inside of a VM (allowing you to run Linux containers on non-Linux desktops), and that VM's time can get out of sync when the laptop is suspended. This is currently being tracked in an issue over on github which you can follow to see the progress: https://github.com/docker/for-win/issues/4526

Potential solutions include restarting your computer, restarting docker's VM, running NTP as a privileged container, or resetting the time sync in the windows VM with the following PowerShell:

Get-VMIntegrationService -VMName DockerDesktopVM -Name "Time Synchronization" | Disable-VMIntegrationService
Get-VMIntegrationService -VMName DockerDesktopVM -Name "Time Synchronization" | Enable-VMIntegrationService

With WSL 2, restarting the VM involves:

wsl --shutdown
wsl

Upvotes: 15

Related Questions