Update standalone.yml
[discourse_docker.git] / scripts / docker-gc
CommitLineData
29a35d1b
S
1#!/bin/bash
2
3# Copyright (c) 2014 Spotify AB.
4#
5# Licensed to the Apache Software Foundation (ASF) under one
6# or more contributor license agreements. See the NOTICE file
7# distributed with this work for additional information
8# regarding copyright ownership. The ASF licenses this file
9# to you under the Apache License, Version 2.0 (the
10# "License"); you may not use this file except in compliance
11# with the License. You may obtain a copy of the License at
12#
13# http://www.apache.org/licenses/LICENSE-2.0
14#
15# Unless required by applicable law or agreed to in writing,
16# software distributed under the License is distributed on an
17# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18# KIND, either express or implied. See the License for the
19# specific language governing permissions and limitations
20# under the License.
21
22# This script attempts to garbage collect docker containers and images.
23# Containers that exited more than an hour ago are removed.
24# Images that have existed more than an hour and are not in use by any
25# containers are removed.
26
27# Note: Although docker normally prevents removal of images that are in use by
28# containers, we take extra care to not remove any image tags (e.g.
29# ubuntu:14.04, busybox, etc) that are used by containers. A naive
30# "docker rmi `docker images -q`" will leave images stripped of all tags,
31# forcing users to re-pull the repositories even though the images
32# themselves are still on disk.
33
34# Note: State is stored in $STATE_DIR, defaulting to /var/lib/docker-gc
35
36set -o nounset
37set -o errexit
38
39GRACE_PERIOD_SECONDS=${GRACE_PERIOD_SECONDS:=3600}
40STATE_DIR=${STATE_DIR:=/var/lib/docker-gc}
41DOCKER=${DOCKER:=docker}
42EXCLUDE_FROM_GC=${EXCLUDE_FROM_GC:=/etc/docker-gc-exclude}
43if [ ! -f "$EXCLUDE_FROM_GC" ]
44then
45 EXCLUDE_FROM_GC=/dev/null
46fi
47
48EXCLUDE_IDS_FILE="exclude_ids"
49
50function date_parse {
51 if date --utc >/dev/null 2>&1; then
52 # GNU/date
53 echo $(date -u --date "${1}" "+%s")
54 else
55 # BSD/date
56 echo $(date -j -u -f "%F %T" "${1}" "+%s")
57 fi
58}
59
60
61# Elapsed time since a docker timestamp, in seconds
62function elapsed_time() {
63 # Docker 1.5.0 datetime format is 2015-07-03T02:39:00.390284991
64 # Docker 1.7.0 datetime format is 2015-07-03 02:39:00.390284991 +0000 UTC
65 utcnow=$(date -u "+%s")
66 without_ms="${1:0:19}"
67 replace_t="${without_ms/T/ }"
68 epoch=$(date_parse "${replace_t}")
69 echo $(($utcnow - $epoch))
70}
71
72function compute_exclude_ids() {
73 # Find images that match patterns in the EXCLUDE_FROM_GC file and put their
74 # id prefixes into $EXCLUDE_IDS_FILE, prefixed with ^
75
76 PROCESSED_EXCLUDES="processed_excludes.tmp"
77 # Take each line and put a space at the beginning and end, so when we
78 # grep for them below, it will effectively be: "match either repo:tag
79 # or imageid". Also delete blank lines or lines that only contain
80 # whitespace
81 sed 's/^\(.*\)$/ \1 /' $EXCLUDE_FROM_GC | sed '/^ *$/d' > $PROCESSED_EXCLUDES
82 # The following looks a bit of a mess, but here's what it does:
83 # 1. Get images
84 # 2. Skip header line
85 # 3. Turn columnar display of 'REPO TAG IMAGEID ....' to 'REPO:TAG IMAGEID'
86 # 4. find lines that contain things mentioned in PROCESSED_EXCLUDES
87 # 5. Grab the image id from the line
88 # 6. Prepend ^ to the beginning of each line
89
90 # What this does is make grep patterns to match image ids mentioned by
91 # either repo:tag or image id for later greppage
92 $DOCKER images \
93 | tail -n+2 \
94 | sed 's/^\([^ ]*\) *\([^ ]*\) *\([^ ]*\).*/ \1:\2 \3 /' \
95 | grep -f $PROCESSED_EXCLUDES 2>/dev/null \
96 | cut -d' ' -f3 \
97 | sed 's/^/^/' > $EXCLUDE_IDS_FILE
98}
99
100# Change into the state directory (and create it if it doesn't exist)
101if [ ! -d "$STATE_DIR" ]
102then
103 mkdir -p $STATE_DIR
104fi
105cd "$STATE_DIR"
106
107# Verify that docker is reachable
108$DOCKER version 1>/dev/null
109
110# List all currently existing containers
111$DOCKER ps -a -q --no-trunc | sort | uniq > containers.all
112
113# List running containers
114$DOCKER ps -q --no-trunc | sort | uniq > containers.running
115
116# compute ids of containers to exclude from GC
117compute_exclude_ids
118
119# List containers that are not running
120comm -23 containers.all containers.running > containers.exited
121
122# Find exited containers that finished at least GRACE_PERIOD_SECONDS ago
123echo -n "" > containers.reap.tmp
124cat containers.exited | while read line
125do
126 EXITED=$(${DOCKER} inspect -f "{{json .State.FinishedAt}}" ${line})
127 ELAPSED=$(elapsed_time $EXITED)
128 if [[ $ELAPSED -gt $GRACE_PERIOD_SECONDS ]]; then
129 echo $line >> containers.reap.tmp
130 fi
131done
132cat containers.reap.tmp | sort | uniq > containers.reap
133
134# List containers that we will keep.
135comm -23 containers.all containers.reap > containers.keep
136
137# List images used by containers that we keep.
138# This may be both image id's and repo/name:tag, so normalize to image id's only
139cat containers.keep |
140xargs -n 1 $DOCKER inspect -f '{{.Config.Image}}' 2>/dev/null |
141sort | uniq |
142xargs -n 1 $DOCKER inspect -f '{{.Id}}' 2>/dev/null |
143sort | uniq > images.used
144
145# List images to reap; images that existed last run and are not in use.
146$DOCKER images -q --no-trunc | sort | uniq > images.all
147comm -23 images.all images.used | grep -v -f $EXCLUDE_IDS_FILE > images.reap || true
148
149# Reap containers.
150xargs -n 1 $DOCKER rm --volumes=true < containers.reap &>/dev/null || true
151
152# Reap images.
153xargs -n 1 $DOCKER rmi < images.reap &>/dev/null || true