Docker on Amazon Web Services
上QQ阅读APP看书,第一时间看更新

Cleaning up the Docker environment

Throughout this chapter, we have been cleaning up our environment by running the docker-compose down command, which stops and destroys any containers associated with the todobackend Docker Compose environment.  

One other aspect of housekeeping that you need to be aware of when building Docker images is the concept of orphaned or dangling images, which are images that have been superseded by a newer build. You can get a sense of this by running the docker images command, and I have indicated which images are dangling in bold:

> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
todobackend_app latest ca3e62e168f2 13 minutes ago 137MB
todobackend_migrate latest ca3e62e168f2 13 minutes ago 137MB
todobackend_release latest ca3e62e168f2 13 minutes ago 137MB
<none> <none> 03cc5d44bd7d 14 minutes ago 253MB
<none> <none> e88666a35577 22 minutes ago 137MB
<none> <none> 8909f9001297 23 minutes ago 253MB
<none> <none> 3d6f9a5c9322 2 hours ago 137MB
todobackend_test latest 60b3a71946cc 2 hours ago 253MB
<none> <none> 53d19a2de60d 9 hours ago 136MB
<none> <none> 54f0fb70b9d0 15 hours ago 135MB
alpine latest 11cd0b38bc3c 23 hours ago 4.41MB

Note that each highlighted image has no repository and no tag, hence why they are referred to as orphaned or dangling. These dangling images are of no use and take up resources and storage, so it is ideal that you clean up these images regularly, to ensure the performance of your Docker environment. Back in our Dockerfile, we added the LABEL directive to each stage, which allows for easy identification of images that relate to our todobackend application.

We can leverage these labels to target dangling images built for the todobackend application, so let's add a new target, called clean, to our Makefile, which brings down the Docker Compose environment and removes dangling images:

.PHONY: test release clean

test:
docker-compose build --pull release
docker-compose build
docker-compose run test

release:
docker-compose up --abort-on-container-exit migrate
docker-compose run app python3 manage.py collectstatic --no-input
docker-compose up --abort-on-container-exit acceptance

clean:
docker-compose down -v
docker images -q -f dangling=true -f label=application=todobackend | xargs -I ARGS docker rmi -f --no-prune ARGS

We use the -q flag to only print out image IDs, and then use the -f flag to add filters that specify to only show dangling images that have a label of application=todobackend. We then pipe the output of this command to the xargs command, which captures the list of filtered images in the ARGS parameter and passes ARGS to the docker rmi -f --no-prune command, removing the images forcibly as specified by the -f flag with the --no-prune flag ensuring any untagged images that include layers from current tagged images are not removed. We use xargs here because it deals with the list of images intelligently for example, if there are no images to delete, then xargs exits silently without an error.

The following demonstrates the output of running the make clean command:

> make test
...
...
> make release
...
...
> make clean
docker-compose down -v
Stopping todobackend_app_1 ... done
Stopping todobackend_db_1 ... done
Removing todobackend_app_run_2 ... done
Removing todobackend_app_1 ... done
Removing todobackend_app_run_1 ... done
Removing todobackend_migrate_1 ... done
Removing todobackend_db_1 ... done
Removing todobackend_test_run_1 ... done
Removing network todobackend_default
Removing volume todobackend_public
docker images -q -f dangling=true -f label=application=todobackend | xargs -I ARGS docker rmi -f --no-prune ARGS
Deleted: sha256:03cc5d44bd7dec8d535c083dd5a8e4c177f113bc49f6a97d09f7a1deb64b7728
Deleted: sha256:6448ea330f415f773fc4cd5fe35862678ac0e35a1bf24f3780393eb73637f765
Deleted: sha256:baefcaca3929d6fc419eab06237abfb6d9ba9a1ba8d5623040ea4f49b2cc22d4
Deleted: sha256:b1dca5a87173bfa6a2c0c339cdeea6287e4207f34869a2da080dcef28cabcf6f
...
...

One thing you may notice when running the make clean command is that stopping the todobackend app service takes some time, in fact, it takes around 10 seconds to stop. This is because Docker first sends a SIGTERM signal to the container when stopping a container, which signals to the container that it is about to be terminated.  By default, if the container does not exit within 10 seconds, Docker sends a SIGKILL signal, which forcibly terminates the container.

The problem here is that the uwsgi process running in our app container ignores SIGTERM signals by default, so we need to add the --die-on-term flag in the Docker Compose file that configures uwsgi to shut down if it receives a SIGTERM signal, ensuring it will be able to shut down gracefully and in a timely fashion:

version: '2.4'

volumes:
public:
driver: local

services:
test:
...
...
release:
...
...
app:
extends:
service: release
depends_on:
db:
condition: service_healthy
volumes:
- public:/public
healthcheck:
test: curl -fs localhost:8000
interval: 3s
retries: 10
ports:
- 8000:8000
command:
- uwsgi
- --http=0.0.0.0:8000
- --module=todobackend.wsgi
- --master
- --check-static=/public
- --die-on-term
- --processes=4
- --threads=2
acceptance:
...
...
migrate:
...
...
db:
...
...

In the preceding example, I have also added the --processes and --threads flags, which enable concurrent processing.  You can read about these and more configuration options at https://uwsgi-docs.readthedocs.io/en/latest/WSGIquickstart.html#adding-concurrency-and-monitoring.