Reputation: 101
I'd like to create a cron job that would stop Docker containers if they've been running for more than, say, 2 hours.
I can get the times they started.
$ docker inspect -f '{{ .State.StartedAt }}' $(docker ps -q)
Just need to compare that with 2 hours ago...
$ date --utc --date="-2 hours" +"%Y-%m-%dT%H:%M:%S.%NZ"
...and if it's earlier stop the container
$ docker stop <<container_id>>
How can I do this with a bash script?
Upvotes: 4
Views: 4229
Reputation: 1
The below bash
function
n
days, andn
days.function docker-stop-running-for-n-days() {
date_threshold=$(date --utc --date="$1 days ago" +"%Y-%m-%dT%H:%M:%S")
for name in $(docker ps --format="{{ .Names }}"); do
start_date=$(docker inspect -f '{{ .State.StartedAt }}' "$name")
printf "Stopping container:\n"
if [[ "$start_date" < "$date_threshold" ]]; then
docker stop "$name"
fi
done
}
Upvotes: 0
Reputation: 2611
I used this simple method (derived from Siru's answer) to stop anything running for more than 24hrs.
docker ps --format="{{.ID}} {{.RunningFor}}" | grep "day\|week\|month" | awk '{print $1}' | xargs docker stop
If you ran this as well as Siru's answer then you can reliably clean up to a specific number of hours, but at that point it's probably be better to use Itiel's solution.
Upvotes: 0
Reputation: 1
@siru's solutions inspired me to look for an option to be persice about the exact time to control for, since the docker ps running for
is a rounded formatted result and not exact:
docker ps -q | xargs docker inspect --format='{{.Id}} {{.State.StartedAt}}' |\
awk '{"date -d " $2 " +%s" | getline startedAt
"date +%s" | getline now
if((now-startedAt)/(60*60) > 5) print $1}' |\
xargs docker rm -f
explination:
The first line will pass a list of container Id's and their started time in ISO 8601 format.
Then we convert each date to UNIX time, calculate the delta from the current time, and pass on to docker rm -f
only the lines where the running time exceeded the time specified.
In this example, all containers that are running more than 6 hours will be removed.
Upvotes: 0
Reputation: 264831
I was hoping to do this within the Go templating of the format string, but I don't think we have any time parsing functions included (might make for a nice PR).
Instead, here's a version that takes advantage of the date command for time parsing:
#!/bin/sh
# adjust threshold as needed
threshold="2 hours"
# cutoff is seconds since epoc of the threshold time
cutoff="$(date --date="-$threshold" "+%s")"
# loop through the running containers by id
docker container ls -q | while read cid; do
# retrieve the start time as a string
startedat="$(docker container inspect "$cid" --format "{{.State.StartedAt}}")"
# convert to seconds since epoc
start="$(date --date="$startedat" "+%s")"
# then we can do a numeric comparison in shell
if [ "$start" -lt "$cutoff" ]; then
docker container stop "$cid"
fi
done
For other examples of using date to calculate offsets, see this post in unix.SE.
Upvotes: 0
Reputation: 51
The one-liner from @Siru is great, however I had to change below part in order to correctly find containers older than two digit number of days:
awk -F " " '{if($1>14)print$0}'
Upvotes: 1
Reputation: 89
It is an old thread but still if someone is searching for an answer. The below command will stop containers running more than 2 hours.
docker ps --format="{{.RunningFor}} {{.Names}}" | grep hours | awk -F: '{if($1>2)print$1}' | awk ' {print $4} ' | xargs docker stop
Explaination:
docker ps --format="{{.RunningFor}} {{.Names}}"
will print the container names and running period.
grep hours
will print the containres running in hours.
awk -F: '{if($1>2)print$1}'
will only print containers running for more than 2 hours.
awk ' {print $4} ' | xargs docker stop
will print the container names obtained from previous output and pass it as argument to stop the containers.
Upvotes: 5
Reputation: 1328152
This was discussed as soon as 2013 in issue 1905
The bash alternative was:
#!/bin/bash
set -e
to=$1
shift
cont=$(docker run -d "$@")
code=$(timeout "$to" docker wait "$cont" || true)
docker kill $cont &> /dev/null
echo -n 'status: '
if [ -z "$code" ]; then
echo timeout
else
echo exited: $code
fi
echo output:
# pipe to sed simply for pretty nice indentation
docker logs $cont | sed 's/^/\t/'
with:
$ docker-run-timeout.sh 10s busybox sh -c 'echo start && sleep 30 && echo finish'
status: timeout
output:
start
Note, with docker 1.13, you could run with --rm -d
(see PR 20848).
Upvotes: 1