How to limit `docker run` execution time? - docker

I want to run a command inside a docker container. If the command takes more than 3 seconds to finish, the container should be deleted.
I thought I can achieve this goal by using --stop-timeout option in docker run.
But it looks like something goes wrong with my command.
For example, docker run -d --stop-timeout 3 ubuntu:14.04 sleep 100 command creates a docker container that lasts for more than 3 seconds. The container is not stopped or deleted after the 3rd second.
Do I misunderstand the meaning of --stop-timeout?
The document says
--stop-timeout Timeout (in seconds) to stop a container
Here's my docker version:
Client:
Version: 17.12.0-ce
API version: 1.35
Go version: go1.9.2
Git commit: c97c6d6
Built: Wed Dec 27 20:03:51 2017
OS/Arch: darwin/amd64
Server:
Engine:
Version: 17.12.0-ce
API version: 1.35 (minimum version 1.12)
Go version: go1.9.2
Git commit: c97c6d6
Built: Wed Dec 27 20:12:29 2017
OS/Arch: linux/amd64
Experimental: true
The API version is newer than 1.25.

You can try
timeout 3 docker run...
there is a PR on that subject
https://github.com/moby/moby/issues/1905
See also
Docker timeout for container?

The --stop-timeout option is the maximum amount of time docker should wait for your container to stop when using the docker stop command.
A container will stop when it's told to or when the command is running finishes, so if you change you sleep from 100 to 1, you'll see that the container is stopped after a second.
What I'll advice you to do is to change the ENTRYPOINT of your container to a script that you create, that will execute what you want and keep track of the execution time from within and exit when timeout.
After that you can start your container using the --rm option that will delete it once the script finishes.
A small example.
Dockerfile:
FROM ubuntu:16.04
ADD ./script.sh /script.sh
ENTRYPOINT /script.sh
script.sh:
#!/bin/bash
timeout=5
sleep_for=1
sleep 100 &
find_process=$(ps aux | grep -v "grep" | grep "sleep")
while [ ! -z "$find_process" ]; do
find_process=$(ps aux | grep -v "grep" | grep "sleep")
if [ "$timeout" -le "0" ]; then
echo "Timeout"
exit 1
fi
timeout=$(($timeout - $sleep_for))
sleep $sleep_for
done
exit 0
Run it using:
docker build -t testing .
docker run --rm testing
This script will execute sleep 100 in background, check if its still running and if the timeout of 5 seconds is reach then exit.
This might not be the best way to do it, but if you want to do something simple it may help.

docker run --rm ubuntu timeout 2 sh -c 'echo start && sleep 30 && echo finish'
will terminate after 2 seconds and finish will never be output

Depending on what exactly you want to achieve, the --ulimit parameter to docker run may do what you need. For example:
docker run --rm -it --ulimit cpu=1 debian:buster bash -c '(while true; do true; done)'
After about 1s, this will print Killed and return. With the --ulimit option, it would rune forever.
However, note that this only limits the CPU time, not the wall clock time. You can happily run sleep 24h with a --ulimit cpu=1 because sleep does not consume CPU time.

In my case, I had a docker container that started an Express server, and then remained running, and I wanted a simple test on CI to check that the container can start without any immediate error (such as configuration errors).
I made sure my code returned a non-zero exit code if something failed during start, and then ended up with this:
timeout 10 docker run [ container params ]; test $? -eq 124 && echo "Container ran for 10 seconds without failing"
This will send SIGTERM to the docker container after 10 seconds if it has not already died. If it's alive long enough for the timeout to occur, it will return 124, which is what the test is for. In other words, this verifies that the docker ran long enough to reach a timeout, any error (or early exit with code 0!) will be considered an error.

Related

How to disable clock sync in docker-desktop VM for MACOS

Using macos Catalina and docker desktop.
The time of the conteiners perfectly syncs with the time in Vm Docker Desktop.
But I need to test one conteiner with date in the future.
I dont want to advance the clock of my mac because of iCloud services.
So I can achieve this just changing the hour in VM docker-desktop
I run:
docker run --privileged --rm alpine date -s "2023-02-19 11:27"
It changes the time ok. But it last just some seconds. Clearly there is some type of "syncronizer" that keeps changing back the time.
How do I disable this "syncronizer"?
There's only one time in Linux, it's not namespaced, so when Docker runs ntp on the VM to keep it synchronized (in the past it would get out of sync, especially after the parent laptop was put to sleep), that sync applies to the Linux kernel, which applies to every container since it's the same kernel value for everything. Therefore it's impossible to set this on just one container in the Linux kernel.
Instead, I'd recommend going with something like libfaketime that can be used to alter the response applications see when the query that time value. It basically sits as a layer between the kernel and application, and injects an offset based on an environment variable you set.
FROM debian
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y libfaketime \
&& rm -rf /var/lib/apt/lists*
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
And then to run it, set FAKETIME:
$ docker run --rm test-faketime date
Thu Feb 17 14:59:48 UTC 2022
$ docker run -e FAKETIME="+7d" --rm test-faketime date
Thu Feb 24 14:59:55 UTC 2022
$ date
Thu 17 Feb 2022 09:59:57 AM EST
I found that you can kill the NTP service which syncs the VM time to the host's time. Details of how service works.
First, use this guide to get a shell inside the VM.
Then, find the sntpc service:
/ # ps a | grep sntpc
1356 root 0:00 /usr/bin/containerd-shim-runc-v2 -namespace services.linuxkit -id sntpc -address /run/containerd/containerd.sock
1425 root 0:00 /usr/sbin/sntpc -v -i 30 127.0.0.1
3465 root 0:00 grep sntpc
Take the number at the beginning of the /usr/sbin/sntpc line, and use kill to stop the process.
/ # kill 1425
I have found that Docker Desktop does not seem to restart this process if it dies, and you can change the VM time without SNTPC changing it back.

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?
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
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
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

docker logs --details flag showing nothing more

I try to see docker logs with the --details flag
I read the docs but i see no difference with or without the flag : https://docs.docker.com/engine/reference/commandline/logs/
For exemple this command echoes the date every second.
$ docker run --name test -d busybox sh -c "while true; do $(echo date); sleep 1; done"
e9d836000532
This command shows logs :
$ docker logs e9d836000532
Sun Jan 26 16:01:55 UTC 2020
...
This command adds nothing more that a "space on the left" :
$ docker logs --details e9d836000532
...
Sun Jan 26 16:01:55 UTC 2020
From docker documentation:
The docker logs --details command will add on extra attributes, such
as environment variables and labels, provided to --log-opt when
creating the container.
currently you have an extra space on the left when you use docker log --details because you probably do not use --log-opt when you create your container.
For your interest, --log-opt is used to use an another log driver than docker default's one
Try out this one :
https://docs.docker.com/config/containers/logging/fluentd/

GitLab (via Docker) on a QNAP NAS with ARM CPU ("exec format error")

I just bought a QNAP TS-832X NAS (Firmware: 4.3.4.0695 Build 20180830).
This machine comes with an ARM CPU (Annapurna Labs Alpine AL324 Quad-core ARM Cortex-A57 CPU # 1.70GHz).
I bought it only to install GitLab on it, but the official image doesn't seem to work.
When I try to run the image it fails.
[~] # docker run -d --name gitlab-server --hostname build1 -p 10080:10080 -p 10022:22 -p 10443:443 -v /share/GitLab/config:/etc/gitlab -v /share/GitLab/logs:/var/log/gitlab -v /share/GitLab/data:/var/opt/gitlab --restart always gitlab/gitlab-ce:latest
[~] # docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a176158729ad gitlab/gitlab-ce:latest "/assets/wrapper" 5 seconds ago Restarting (1) 1 second ago gitlab-server
[~] # docker logs a1
standard_init_linux.go:185: exec user process caused "exec format error"
standard_init_linux.go:185: exec user process caused "exec format error"
standard_init_linux.go:185: exec user process caused "exec format error"
standard_init_linux.go:185: exec user process caused "exec format error"
standard_init_linux.go:185: exec user process caused "exec format error"
standard_init_linux.go:185: exec user process caused "exec format error"
standard_init_linux.go:185: exec user process caused "exec format error"
After googling I figured it might be caused by the host architecture, so I tried running ulm0/gitlab, but with the same result.
I also tried other images with "ARM" in their tags like arm64v8/ubuntu. This one didn't even give any logs.
[~] # docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2b2b68bc912c arm64v8/ubuntu:latest "/bin/bash" 7 seconds ago Restarting (0) 1 second ago ubuntu-arm
a176158729ad gitlab/gitlab-ce:latest "/assets/wrapper" 2 hours ago Restarting (1) 51 seconds ago gitlab-server
[~] # docker logs 2b
[~] #
uname -a
Linux build1 4.2.8 #2 SMP Thu Aug 30 07:33:01 CST 2018 aarch64 GNU/Linux
docker version
Client:
Version: 17.09.1-ce
API version: 1.32
Go version: go1.8.3
Git commit: a9fd393
Built: Fri Aug 3 04:31:20 2018
OS/Arch: linux/arm64
Server:
Version: 17.09.1-ce
API version: 1.32 (minimum version 1.12)
Go version: go1.8.3
Git commit: a9fd393
Built: Fri Aug 3 04:31:20 2018
OS/Arch: linux/arm64
Experimental: false
Sorry to hear about your problem, unfortunately I don't believe there is any official GitLab Docker image for ARM devices.
From personal experience I've found that most developers will make a Docker image for Intel devices but not work on ARM Devices.
This topic has been discussed on the QNAP Forums already:
My QNAP is Intel based, so I can't corroborate your results, but quoting a few sentences from a page about docker on Raspberry Pi:
"Docker-based apps you use have to be packaged specifically for ARM architecture! Docker-based apps packaged for x86/x64 will not work and will result in an error such as:
FATA[0003] Error response from daemon: Cannot start container 0f0fa3f8e510e53908e6a459e817d600b9649e621e7dede974d6a65761ad39e5: exec format error
Keep this in mind when searching for apps on the Docker Hub - the source for Docker apps/images. If you see the keyword RPI or ARM in the heading or description, this app can usually be used for the Raspberry Pi."
The TS-831X has a "AnnapurnaLabs, an Amazon company Alpine AL-314 Quad-core 1.7 GHz Cortex-A15 processor" CPU, which is an ARM architecture much like the Raspberry Pi..
So, I suspect you may be limited in what Docker images you have access to and unless an official/canonical maintainer of an app also makes an ARM build, you may be stuck with either rolling your own or trusting a 3rd party hobbyist to do so...
I hate to say this but I'd say you should have picked up an Intel one instead.
I have a QNAP TS-251+ (Intel based) with 8GB RAM and 2x8TB in a RAID Configuration and this works perfectly for my Gitlab instance, in addition to running PLEX and using it as a Webserver as well.
I would also suggest when you do finally get it up and running to map the volumes to directories that are easy to access so you can make configuration changes easily.

query.js crash on Hyperledger fabric fabcar example

The fabcar example of the hyperledger tutorial crashes for me at the step of attempting to run query.js.
I have removed all hyperledger related docker images (with docker rmi), so all required content was downloaded automatically when running startFabric.sh. The output on startup looks slightly "clouded" but not very suspicious (I skipped the lengthy output about the images being downloaded):
# wait for Hyperledger Fabric to start
# incase of errors when running later commands, issue export FABRIC_START_TIMEOUT=<larger number>
export FABRIC_START_TIMEOUT=10
#echo ${FABRIC_START_TIMEOUT}
sleep ${FABRIC_START_TIMEOUT}
# Create the channel
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin#org1.example.com/msp" peer0.org1.example.com peer channel create -o orderer.example.com:7050 -c mychannel -f /etc/hyperledger/configtx/channel.tx
flag provided but not defined: -e
See 'docker exec --help'.
The next step as asked is
npm install
It also delivers mostly ok output,just one warning:
npm WARN fabcar#1.0.0 No repository field.
I have verified images are running (also shows that the user is authorized to use the docker, while the user is otherwise not root):
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9acf0dd8a2e2 hyperledger/fabric-peer:x86_64-1.0.0 "peer node start" 20 seconds ago Up 19 seconds 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com
da42dca3cbda hyperledger/fabric-orderer:x86_64-1.0.0 "orderer" 20 seconds ago Up 19 seconds 0.0.0.0:7050->7050/tcp orderer.example.com
0265c3cd86f2 hyperledger/fabric-ca:x86_64-1.0.0 "sh -c 'fabric-ca-ser" 20 seconds ago Up 20 seconds 0.0.0.0:7054->7054/tcp ca.example.com
4f71895a78c0 hyperledger/fabric-couchdb:x86_64-1.0.0 "tini -- /docker-entr" 20 seconds ago Up 19 seconds 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb
When I finally try to run
node query.js
I observe the following errors:
Create a client and set the wallet location
Set wallet path, and associate user PeerAdmin with application
Check user is enrolled, and set a query URL in the network
Make query
Assigning transaction_id: eb03c5e69259b880433861daf57a5ac2d33e41d93cebe80a7a478a1aa2cba711
error: [client-utils.js]: sendPeersProposal - Promise is rejected: Error: Endpoint read failed
at /home/hla/fabric-samples/fabcar/node_modules/grpc/src/node/src/client.js:434:17
returned from query
Query result count = 1
error from query = { Error: Endpoint read failed
at /home/hla/fabric-samples/fabcar/node_modules/grpc/src/node/src/client.js:434:17 code: 14, metadata: Metadata { _internal_repr: {} } }
Response is Error: Endpoint read failed
My OS:
uname -a
Linux uhost 4.4.0-92-generic #115-Ubuntu SMP Thu Aug 10 09:04:33 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
I have checked this but my node.js version is correct:
node --version
v6.11.2
npm -- version
{ fabcar: '1.0.0',
npm: '3.10.10',
ares: '1.10.1-DEV',
http_parser: '2.7.0',
icu: '56.1',
modules: '48',
node: '6.11.2',
openssl: '1.0.2l',
uv: '1.11.0',
v8: '5.1.281.103',
zlib: '1.2.11' }
Also, the error message is completely different. The machine has ports 8080 and 8443 in use, but when I tired to shut down the applications using them, was not helpful.
That's because you didn't follow the steps.. as it says, before query.js u should enroll the admin and register user, then it works properly. And don't pay attention to "npm WARN fabcar#1.0.0 No repository field", it works well. Try the following:
$docker stop $(docker ps -a -q)
$docker ps -qa|xargs docker rm
$./startFabric.sh
$cd fabric-samples/fabcar/javascript
$node enrollAdmin.js
$npm install
$node registerUser.js
$node query.js
[

Resources