Skip to content

Commit 1f32d6f

Browse files
authored
Merge pull request #4 from YanziNetworks/users/emmanuel/active-rm
Active removal of containers
2 parents 922c234 + 046714f commit 1f32d6f

3 files changed

Lines changed: 98 additions & 24 deletions

File tree

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ENV NAMES=
2020
ENV EXCLUDE=
2121
ENV RESOURCES=
2222
ENV AGE=
23+
ENV ANCIENT=
2324
ENV TIMEOUT=
2425

2526
# Add dependency and main script

README.md

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ use the `--names` and `--exclude` command-line options to consider only a subset
2929
of the containers.
3030

3131
Exited and dead containers are as reported by Docker. Stale containers are
32-
containers that are created but hasn't moved to any other state after a given
32+
containers that are created but have not moved to any other state after a given
3333
timeout.
3434

35+
In addition, it is possible to forcedly remove ancient, but still running
36+
containers using the `--ancient` option. This might be a dangerous operation,
37+
and it is turned off by default.
38+
39+
[cprune]: https://docs.docker.com/engine/reference/commandline/container_prune/
40+
3541
### Images
3642

3743
All dangling and orphan images will be removed. This also provides filtering
@@ -43,6 +49,8 @@ Dangling images are layers that have no relationship to any tagged images.
4349
Orphan images are images that are not used by any container, whichever state the
4450
container is in (including created or exited state).
4551

52+
[iprune]: https://docs.docker.com/engine/reference/commandline/image_prune/
53+
4654
### Volumes
4755

4856
All "empty" dangling volumes will be removed. The script will count the files
@@ -53,8 +61,6 @@ volumes. Volumes that have a name that was automatically generated are
5361
automatically selected. File count is achieved through mounting the volumes into
5462
a temporary [busybox] container.
5563

56-
[cprune]: https://docs.docker.com/engine/reference/commandline/container_prune/
57-
[iprune]: https://docs.docker.com/engine/reference/commandline/image_prune/
5864
[busybox]: https://hub.docker.com/_/busybox
5965

6066
## Command-Line Options
@@ -70,10 +76,17 @@ dash, `--`.
7076

7177
### `-v` or `--verbose`
7278

73-
This will increase the verbosity of the script, output will be sent to the
74-
`stderr` and lines will contain the name of the script, together with the
75-
timestamp. When used in interactive mode, the script will automatically colour
76-
the log.
79+
This will select the verbosity of the script (default: `info`), output will be
80+
sent to the `stderr` and lines will contain the name of the script, together
81+
with the timestamp. When used in interactive mode, the script will automatically
82+
colour the log. Available levels are: `error`, `warn`, `notice`, `info`,
83+
`debug`.
84+
85+
### `--non-interactive`, `--no-colour` or `--no-color`
86+
87+
Forcedly remove colouring from logs. Otherwise, logs will be coloured in
88+
interactive mode, but kept without colouring when invoked within pipes or
89+
without a (pseudo-)tty.
7790

7891
### `-h` or `--help`
7992

@@ -83,7 +96,7 @@ Print out help and exit.
8396

8497
Just print out what would be perform, do not remove anything at all. This option
8598
can be used to assess what the script would do when experimenting with options
86-
such as `--names`, `--exclude` or `--age`.
99+
such as `--names`, `--exclude`, `--age` or `--ancient`.
87100

88101
### `-r` or `--resources`
89102

@@ -112,7 +125,17 @@ that should be kept.
112125
### `-a` or `--age`
113126

114127
Age of dangling images to consider for removal (default: `6m`). The age can be
115-
expressed in human-readable format, e.g. `6m` (for 6 months), `3 days`, etc.
128+
expressed in human-readable format, e.g. `6m` (for 6 months), `3 days`, etc. Set
129+
this to an empty string to skip removal of named dangling images totally.
130+
131+
### `--ancient`
132+
133+
Age of running containers to consider for removal (default: empty). The age can
134+
be expressed in human-readable format, e.g. `6m` (for 6 months), `3 days`, etc.
135+
Unnamed containers or containers that match the `--names` and `--exclude` filter
136+
and exclusion will be forced removed. This operation cannot be undone! The
137+
default is an empty sting, in which case no running container will ever be
138+
stopped and removed.
116139

117140
### `-t` or `--timeout`
118141

@@ -142,6 +165,21 @@ parsed at run-time to detect if containers are "unnamed" containers.
142165
[source]: https://raw.githubusercontent.com/moby/moby/master/pkg/namesgenerator/names-generator.go
143166
[golang]: https://golang.org/
144167

168+
## Environment Variables
169+
170+
This script also recognises a number of environment variables, these can be used
171+
instead of (some of) the command-line options. Command-line options always have
172+
precedence over the environment variables. Recognised variables are:
173+
174+
- `BUSYBOX`: same as `--busybox`
175+
- `MAXFILES`: same as `--limit`
176+
- `NAMES`: same as `--names`
177+
- `EXCLUDE`: same as `--exclude`
178+
- `RESOURCES`: same as `--resources`
179+
- `AGE`: same as `--age`
180+
- `ANCIENT`: same as `--ancient`
181+
- `TIMEOUT`: same as `--timeout`
182+
145183
## Docker
146184

147185
This script also comes as a Docker [image]. To be able to run it from a
@@ -163,7 +201,7 @@ to double check what the command would do...
163201
```shell
164202
./prune.sh \
165203
--verbose debug \
166-
--names '^runner-[[:alnum:]]+-project-[0-9]+-.*' \
204+
--names '^runner-[[:alnum:]_]+-project-[0-9]+-.*' \
167205
--age 2d
168206
```
169207

prune.sh

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ NAMES=${NAMES:-}
3535
EXCLUDE=${EXCLUDE:-}
3636
RESOURCES=${RESOURCES:-"images volumes containers"}
3737
AGE=${AGE:-"6m"}
38+
ANCIENT=${ANCIENT:-}
3839
NAMESGEN=https://raw.githubusercontent.com/moby/moby/master/pkg/namesgenerator/names-generator.go
3940
TIMEOUT=${TIMEOUT:-"30s"}
4041
INTERMEDIATE=0
@@ -66,12 +67,15 @@ Usage:
6667
-x | --exclude Regular expression to exclude from names selected above,
6768
this eases selecting away important containers/volumes.
6869
-a | --age Age of dangling image to consider it for removal (default:
69-
6m). The age can be expressed in yush_human_period-readable format, e.g.
70-
6m (== 6 months), 3 days, etc.
70+
6m). The age can be expressed in yush_human_period-readable
71+
format, e.g. 6m (== 6 months), 3 days, etc.
72+
--ancient Age of ancient container. Matching or unnamed containers
73+
at least this old will be forced removed. Default is empty,
74+
no removal at all!
7175
-t | --timeout Timeout to wait for created containers to change status,
72-
they will be consideyush_red as stale and removed if status has
73-
not changed. This can be expressed in yush_human_period-readable format.
74-
Default is 30 seconds.
76+
they will be consideyush_red as stale and removed if status
77+
has not changed. This can be expressed in human-readable
78+
format. Default is 30 seconds, e.g. 30s.
7579
--busybox Docker busybox image tag to be used for volume content
7680
collection.
7781
--namesgen URL to go implementation for Docker container names
@@ -114,6 +118,11 @@ while [ $# -gt 0 ]; do
114118
--age=*)
115119
AGE="${1#*=}"; shift 1;;
116120

121+
--ancient)
122+
ANCIENT="$2"; shift 2;;
123+
--ancient=*)
124+
ANCIENT="${1#*=}"; shift 1;;
125+
117126
-t | --timeout)
118127
TIMEOUT="$2"; shift 2;;
119128
--timeout=*)
@@ -234,10 +243,10 @@ rm_image() {
234243
# for removal.
235244
CONSIDER=0
236245
creation=$(docker image inspect --format '{{.Created}}' "$1")
237-
howold=$((now-$(yush_iso8601 "$creation")))
246+
howold=$(( now - $(yush_iso8601 "$creation") ))
238247
if [ -z "$tags" ] && [ -z "$digests" ]; then
239248
CONSIDER=1
240-
elif [ "$howold" -ge "$AGE" ]; then
249+
elif [ -n "$AGE" ] && [ "$howold" -ge "$AGE" ]; then
241250
CONSIDER=1
242251
fi
243252

@@ -254,12 +263,23 @@ rm_image() {
254263
fi
255264
}
256265

257-
# Convert period
258-
if printf %s\\n "$AGE"|grep -Eq '[0-9]+[[:space:]]*[A-Za-z]+'; then
259-
NEWAGE=$(yush_howlong "$AGE")
260-
yush_debug "Converted yush_human_period-readable age $AGE to $NEWAGE seconds"
261-
AGE=$NEWAGE
262-
fi
266+
to_seconds() {
267+
if [ -n "$1" ]; then
268+
if printf %s\\n "$1"|grep -Eq '[0-9]+[[:space:]]*[A-Za-z]+'; then
269+
NEWAGE=$(yush_howlong "$1")
270+
if [ -n "$NEWAGE" ]; then
271+
yush_debug "Converted human-readable age $1 to $NEWAGE seconds"
272+
printf %d\\n "$NEWAGE"
273+
else
274+
abort "Could not convert human-readable $1 to a period!"
275+
fi
276+
fi
277+
fi
278+
}
279+
280+
# Convert human-readable periods
281+
AGE=$(to_seconds "$AGE")
282+
ANCIENT=$(to_seconds "$ANCIENT")
263283

264284
NAMES_DICTIONARY=
265285
if [ -n "$NAMESGEN" ]; then
@@ -276,7 +296,7 @@ fi
276296
# Start by cleaning up containers so we can free as many (dependent) resources
277297
# as possible.
278298
if printf %s\\n "$RESOURCES" | grep -qo "container"; then
279-
yush_notice "Cleaning up exited and dead containers..."
299+
yush_notice "Cleaning up exited, dead and ancient containers..."
280300
for cnr in $(docker container ls -a --filter status=exited --filter status=dead --format '{{.Names}}'); do
281301
rm_container "$cnr"
282302
done
@@ -301,6 +321,21 @@ if printf %s\\n "$RESOURCES" | grep -qo "container"; then
301321
fi
302322
done
303323
fi
324+
325+
if [ -n "$ANCIENT" ]; then
326+
now=$(date -u +'%s')
327+
for cnr in $(docker container ls --filter status=running --format '{{.Names}}'); do
328+
started=$(docker container inspect --format '{{.State.StartedAt}}' "$cnr")
329+
started_secs=$(yush_iso8601 "$started")
330+
howold=$(( now - started_secs ))
331+
if [ "$howold" -gt "$ANCIENT" ]; then
332+
yush_info "Container $cnr is $(yush_human_period "$howold")ancient"
333+
rm_container "$cnr"
334+
else
335+
yush_debug "Container $cnr is still young"
336+
fi
337+
done
338+
fi
304339
fi
305340

306341
if printf %s\\n "$RESOURCES" | grep -qo "volume"; then

0 commit comments

Comments
 (0)