Adrienne Dunham
Adrienne Dunham

Reputation: 101

Stop a Docker container that's been running for a certain amount of time

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

Answers (7)

Rob Weiss
Rob Weiss

Reputation: 1

The below bash function

  • takes the number of days as an input argument,
  • iterates all containers,
  • compares the time the container was started against the current time minus n days, and
  • stops the container if it has been running for more than n 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

Martin
Martin

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

Itiel Olenick
Itiel Olenick

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

BMitch
BMitch

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

Kamil Szymański
Kamil Szymański

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

Siru
Siru

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

VonC
VonC

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

Related Questions