Docker — флагман рынка ПО для контейнеризации и микросервисов, появившийся в 2013 году и до сих пор остающийся основным игроком. Для его использования в Ubuntu не требуется установки отдельной ВМ, т.к. он использует возможности ядра.
Читать
Архив метки: docker
Docker Tips: Очистите свою машину от хлама /Как удалить старые и не используемые образы Docker
Сегодня мы поговорим о том, как Docker использует дисковое пространство хостовой машины, а также разберемся в том, как это пространство освободить от ошметков неиспользуемых образов и контейнеров.

Общее потребление
Docker – крутая штука, наверное сегодня мало кто в этом сомневается. Всего несколько лет назад этот продукт предоставил нам совершенно новый способ построения, доставки и запуска любого окружения, позволяя значительно сэкономить ресурсы процессора и оперативной памяти. В дополнение к этому (а для кого-то это будет даже самым важным) Docker позволил нам невероятно упростить и унифицировать управление жизненным циклом используемых рабочих сред.
Однако, за все эти прелести современной жизни приходится платить. Когда мы запускаем контейнеры, скачиваем или создаем собственные образы, разворачиваем сложные экосистемы, нам приходится платить. И платим мы, в том числе, дисковым пространством.
Если вы никогда не задумывались о том, сколько же места реально занято на вашей машине Docker’ом, то можете быть неприятно удивлены выводом этой команды:
$ docker system df

Здесь отображено использование диска Docker’ом в различных разрезах:
- образы (images) – общий размер образов, которые были скачаны из хранилищ образов и построены в вашей системе;
- контейнеры (containers) – общий объем дискового пространства, используемый запущенными контейнерами (имеется ввиду общий объем слоев чтения-записи всех контейнеров);
- локальные тома (local volumes) – объем локальных хранилищ, примонтированных к контейнерам;
- кэш сборки (build cache) – временные файлы, сгенерированные процессом построения образов (при использовании инструмента BuildKit, доступного начиная с Docker версии 18.09).
Готов поспорить, что уже после этого простого перечисления вы горите желанием почистить диск от мусора и вернуть к жизни драгоценные гигабайты (прим. перев.: особенно, если за эти гигабайты вы ежемесячно перечисляете арендную плату).
Использование диска контейнерами
Каждый раз при создании контейнера на хостовой машине в каталоге /var/lib/docker создается несколько файлов и каталогов, среди которых стоит отметить следующие:
- Каталог /var/lib/docker/containers/ID_контейнера – при использовании стандартного драйвера логгирования именно сюда сохраняются журналы событий в JSON-формате. Слишком подробные логи, а также логи, которые никто не читает и не обрабатывает иными способами, часто становятся причиной переполнения дисков.
- Каталог /var/lib/docker/overlay2 – содержит слои чтения-записи контейнеров (overlay2 – предпочитаемые драйвер в большинстве дистрибутивов Linux). Если контейнер сохраняет данные в своей файловой системе, то именно в этом каталоге они и будут размещены.
Давайте представим себе систему, на которой установлен девственно чистый Docker, ни разу не участвовавший в запуске контейнеров и сборке образов. Его отчет об использовании дискового пространства будет выглядеть так:
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 0 0 0B 0B
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
Запустим какой-нибудь контейнер, например, NGINX:
$ docker container run --name www -d -p 8000:80 nginx:1.16
Что происходит с диском:
- образы (images) занимают 126 Мб, это тот самый NGINX, который мы запустили в контейнере;
- контейнеры (containers) занимают смешные 2 байта.
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 1 1 126M 0B (0%)
Containers 1 1 2B 0B (0%)
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
Судя по выводу, у нас еще нет пространства, которое мы могли бы высвободить. Так как 2 байта это совершенно несерьезно, давайте представим, что наш NGINX неожиданно для всех написал куда-то 100 Мегабайт данных и создал внутри себя файл test.img именно такого размера.
$ docker exec -ti www
dd if=/dev/zero of=test.img bs=1024 count=0 seek=$[1024*100]
Снова исследуем использование дискового пространства на хосте. Мы увидим, что контейнер (containers) занимает там 100 Мегабайт.
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 1 1 126M 0B (0%)
Containers 1 1 104.9MB 0B (0%)
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
Думаю, ваш пытливый мозг уже задается вопросом, где же находится наш файл test.img. Давайте его поищем:
$ find /var/lib/docker -type f -name test.img
/var/lib/docker/overlay2/83f177...630078/merged/test.img
/var/lib/docker/overlay2/83f177...630078/diff/test.img
Не вдаваясь в подробности можно отметить, что файл test.img удобно расположился на уровне чтения-записи, управляемом драйвером overlay2. Если же мы остановим наш контейнер, то хост подскажет нам, что это место, в принципе, можно высвободить:
# Stopping the www container
$ docker stop www
# Visualizing the impact on the disk usage
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 1 1 126M 0B (0%)
Containers 1 0 104.9MB 104.9MB (100%)
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
Как мы можем это сделать? Удалением контейнера, которое повлечет за собой очистку соответствующего пространства на уровне чтения-записи.
С помощью следующей команды вы можете удалить все установленные контейнеры одним махом и очистить ваш диск от всех созданных ими на уровне чтения-записи файлов:
$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2
Total reclaimed space: 104.9MB
Итак, мы высвободили 104,9 Мегабайта удалением контейнера. Но так как мы уже не используем скачанный ранее образ, то он тоже становится кандидатом на удаление и высвобождение наших ресурсов:
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 1 0 126M 126M (100%)
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
Внимание: до тех пор, пока образ используется хотя бы одним контейнером, вы не сможете использовать этот трюк.
Субкоманда prune, которую мы использовали выше, дает эффект только на остановленных контейнерах. Если мы хотим удалить не только остановленные, но и запущенные контейнеры, следует использовать одну из этих команд:
# Historical command
$ docker rm -f $(docker ps –aq)
# More recent command
$ docker container rm -f $(docker container ls -aq)
Заметки на полях: если при запуске контейнера использовать параметр —rm, то при его остановке будут высвобождено все дисковое пространство, которое он занимал.
Использование диска образами
Несколько лет назад размер образа в несколько сотен мегабайт был совершенно нормальным: образ Ubuntu весил 600 Мегабайт, а образ Microsoft .Net – несколько Гигабайт. В те лохматые времена скачивание одного только образа могло нанести большой урон вашему свободному месту на диске, даже если вы расшаривали уровни между образами. Сегодня – хвала великим – образы весят намного меньше, но даже в этом случае можно быстро забить имеющиеся ресурсы, если не принимать некоторых мер предосторожности.
Есть несколько типов образов, которые напрямую не видны конечному пользователю:
- intermediate образы, на основе которых собраны другие образы в – они не могут быть удалены, если вы используете контейнеры на базе этих самых «других» образов;
- dangling образы – это такие intermediate образы, на которые не ссылается ни один из запущенных контейнеров – они могут быть удалены.
- С помощью следующей команды вы можете проверить наличие в вашей системе dangling образов:
$ docker image ls -f dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
none none 21e658fe5351 12 minutes ago 71.3MB
Удалить их можно следующим способом:
$ docker image rm $(docker image ls -f dangling=true -q)
Мы можем использовать также субкоманду prune:
$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
deleted: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
deleted: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
deleted: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
deleted: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f
Total reclaimed space: 12.9kB
Если мы вдруг захотим удалить вообще все образы (а не только dangling) одной командой, то можно сделать так:
$ docker image rm $(docker image ls -q)
Использование диска томами
Тома (volumes) применяются для хранения данных за пределами файловой системы контейнера. Например, если мы хотим сохранить результаты работы какого-либо приложения, чтобы использовать их как-то еще. Частым примером являются базы данных.
Давайте запустим контейнер MongoDB, примонтируем к нему внешний по отношению к контейнеру том, и восстановим из него бэкап базы данных (у нас он доступен в файле bck.json):
# Running a mongo container
$ docker run --name db -v $PWD:/tmp -p 27017:27017 -d mongo:4.0
# Importing an existing backup (from a huge bck.json file)
$ docker exec -ti db mongoimport
--db 'test'
--collection 'demo'
--file /tmp/bck.json
--jsonArray
Данные будут находиться на хостовой машине в каталоге /var/lib/docker/volumes. Но почему не на уровне чтения-записи контейнера? Потому что в Dockerfile образа MongoDB каталог /data/db (в котором MongoDB по умолчанию хранит свои данные) определен как том (volume).

Заметки на полях: многие образы, в результате работы которых должны создаваться данные, используют тома (volumes) для сохранения этих самых данных.
Когда мы наиграемся с MongoDB и остановим (а может даже и удалим) контейнер, том не будет удален. Он продолжит занимать наше драгоценное дисковое пространство до тех пор, пока мы явно не удалим его такой командой:
$ docker volume rm $(docker volume ls -q)
Ну или мы можем использовать уже знакомую нам субкоманду prune:
$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da
Total reclaimed space: 25.82GB
luc@saturn:~$
Использование диска для кэша сборки образов
В Docker 18.09 процесс создания образов претерпел некоторые изменения благодаря инструменту BuildKit. С помощью этой штуки увеличивается скорость процесса, оптимизируется управление хранением данных и безопасностью. Здесь мы не будем рассматривать все детали этого замечательного инструмента, остановимся лишь нам том, как он затрагивает вопросы использования дискового пространства.
Предположим, что у нас есть совершенно простое приложение Node.Js:
- файл index.js запускает простой HTTP сервер, который отвечает строкой на каждый полученный запрос:
- файл package.json определяет зависимости, из которых используется только expressjs для запуска HTTP сервера:
$ cat index.js
var express = require('express');
var util = require('util');
var app = express();
app.get('/', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end(util.format("%s - %s", new Date(), 'Got Request'));
});
app.listen(process.env.PORT || 80);
$ cat package.json
{
"name": "testnode",
"version": "0.0.1",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.14.0"
}
}
Dockerfile для сборки образа выглядит так:
FROM node:13-alpine
COPY package.json /app/package.json
RUN cd /app && npm install
COPY . /app/
WORKDIR /app
EXPOSE 80
CMD ["npm", "start"]
Давайте соберем образ обычным способом, без использования BuildKit:
$ docker build -t app:1.0 .
Если мы проверим использование дискового пространства, то увидим, что место занимают только базовый образ (node:13-alpine) и конечный образ (app:1.0):
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 0 109.3MB 109.3MB (100%)
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
Давайте соберем вторую версию нашего приложения, уже с использованием BuildKit. Для этого нам лишь необходимо установить переменную DOCKER_BUILDKIT в значение 1:
$ DOCKER_BUILDKIT=1 docker build -t app:2.0 .
Если мы сейчас проверим использование диска, то увидим, что теперь там участвует кэш сборки (buid-cache):
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 0 109.3MB 109.3MB (100%)
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 11 0 8.949kB 8.949kB
Для его очистки воспользуемся следующей командой:
$ docker builder prune
WARNING! This will remove all dangling build cache.
Are you sure you want to continue? [y/N] y
Deleted build cache objects:
rffq7b06h9t09xe584rn4f91e
ztexgsz949ci8mx8p5tzgdzhe
3z9jeoqbbmj3eftltawvkiayi
Total reclaimed space: 8.949kB
Очистить все!
Итак, мы рассмотрели очистку дискового пространства, занятого контейнерами, образами и томами. В этом нам помогает субкоманда prune. Но ее можно использовать и на системном уровне docker, и она очистит все, что только сможет:
$ docker system prune
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all dangling build cache
Are you sure you want to continue? [y/N]
Если вы по каким-либо причинам экономите дисковое пространство на машине с Docker, то периодический запуск этой команды стоит ввести в привычку.
====================================================================
Так как в Docker более менее адекватный механизм удаления старых образов и контейнеров появился в версии 1.13: PR 26108 (за счет параметра prune который удаляет все старые контейнеры volume без контейнеров и образа без контейнеров), но зная что с каждой новой версией кол-во багов и проблем ростет, я лично не рискую обновляться, потому использую такие механизмы:
Удаление всех не используемых images
docker rmi $(docker images --filter "dangling=true" -q --no-trunc)
Удаление контейнеров в статусе “exited”
docker rm $(docker ps -qa --no-trunc --filter "status=exited")
Удаление не используемых volume
docker volume ls -qf "dangling=true" | xargs docker volume rm
Все это можно совместить в один алиас для bash окружения:
alias docker-clean='
docker ps --no-trunc -aqf "status=exited" | xargs docker rm ;
docker images --no-trunc -aqf "dangling=true" | xargs docker rmi ;
docker volume ls -qf "dangling=true" | xargs docker volume rm'
Источник:
- https://demi4.com/kak-udalit-staryie-i-ne-ispolzuemyie-obrazyi-docker/
- https://habr.com/ru/post/486200/
Настройка имени хоста в Docker Compose
Из этого быстрого совета по Docker вы узнаете, как установить имя хоста для вашего контейнера с помощью Docker Compose.
Не знаете, как установить имя хоста в Docker Compose? Мы вам это покажем.Вы можете определить его в рамках службы следующим образом:
Читать
Установка RabbitMQ в Ubuntu 20.04
RabbitMQ — это сервер очередей, который позволяет работать с сообщениями по протоколу AMQP (Advanced Message Queuing Protocol). Кроме того, может использоваться несколько других протоколов с помощью плагинов. Чаще всего RabbitMQ используется в качестве брокера текстовых сообщений.
Он получает сообщения, от программ, которые их генерируют и доставляет в программы, которые готовы их получать. Сам сервер написан на Erlang. В этой статье мы рассмотрим как установить RabbitMQ в Ubutntu 20.04.
Docker для python приложения
Частенько бывает ситуация, что сервер для различных задач задействует возможности Python v2. При этом есть существенная необходимость запускать приложения, написанные на Python v3. Использование Docker позволяет элегантно решить эту задачу. Читать
Настройка репликации PostgreSQL в контейнерах Docker
Мы рассмотрим процесс поднятия двух контейнеров с PostgreSQL и настройки репликации данных между ними. Использовать будем систему на базе Linux, однако, сам процесс настройки Docker и репликации не зависит от операционной системы.
Подготовка компьютера
На компьютере, где мы будем запускать наш кластер баз данных должен быть установлен Docker. Также мы сразу рассмотрим развертывание нужной нам инфраструктуры в docker-compose. Для установки необходимой одноименной платформы смотрим инструкцию Установка Docker на Linux.
После мы можем переходить к поднятию контейнеров.
Запуск контейнеров с СУБД
Как говорилось выше, мы будем поднимать наши контейнеры с помощью docker-compose.
Создадим каталог, в котором будем работать:
mkdir -p /opt/docker/postgresql
Переходим в него:
cd /opt/docker/postgresql
Создаем файл для docker-compose:
vi docker-compose.yml
---
services:
postgresql_01:
image: postgres
container_name: postgresql_01
restart: always
volumes:
- /data/postgresql_01:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgres024
postgresql_02:
image: postgres
container_name: postgresql_02
restart: always
volumes:
- /data/postgresql_02/:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgres024
* рассмотрим некоторый опции подробнее:
- postgresql_01/postgresql_02 — названия для сервисов, контейнеры для которых мы будем поднимать.
- image — образ, из которого будут создаваться контейнеры. В данном примере мы берем официальный образ postgres.
- container_name — имя, которое будет присвоено контейнеру после его запуска. В нашем примере это postgresql_01 и postgresql_02.
- restart — режим перезапуска. Говорит, в каких случаях наш контейнер должен стартовать.
- volumes — хорошим тоном для работы базы данных в контейнере является проброс каталога хостового компьютера внутрь контейнера. Таким образом, после удаления контейнера данные останутся на компьютере. В нашем примере в каталоге /data будут созданы каталоги postgresql_01 и postgresql_02, которые будут прокинуты в каталог /var/lib/postgresql/data контейнера.
- environment — для первого запуска необходима инициализация базы данных. Без пароля системы выдает ошибку. Поэтому мы задаем переменную среды POSTGRES_PASSWORD.
Запускаем наши контейнеры:
docker-compose up -d
Мы должны увидеть:
Creating postgresql_02 ... done
Creating postgresql_01 ... done
А если вывести список контейнеров:
docker ps
… мы должны увидеть наши два.
Теперь можно переходить к настройке репликации.
Настройка репликации
Условимся, что первичный сервер или master будет в контейнере с названием postgresql_01. Вторичный — postgresql_02. Мы будем настраивать потоковую (streaming) асинхронную репликацию.
Настройка на мастере
Подключаемся к контейнеру docker:
docker exec -it postgresql_01 bash
Заходим под пользователем postgres:
su - postgres
Создаем пользователя, под которым будем подключаться со стороны вторичного сервера:
createuser --replication -P repluser
* в данном примере будет создаваться учетная запись repluser с правами репликации.
Система потребует ввода пароля. Придумываем его и набираем дважды.
Выходим из-под пользователя postgres:
exit
Выходим из контейнера:
exit
Открываем конфигурационный файл postgresql.conf:
vi /data/postgresql_01/postgresql.conf
Приводим к следующием виду некоторые параметры:
wal_level = replica
max_wal_senders = 2
max_replication_slots = 2
hot_standby = on
hot_standby_feedback = on
* где
- wal_level указывает, сколько информации записывается в WAL (журнал операций, который используется для репликации). Значение replica указывает на необходимость записывать только данные для поддержки архивирования WAL и репликации.
- max_wal_senders — количество планируемых слейвов;
- max_replication_slots — максимальное число слотов репликации (данный параметр не нужен для postgresql 9.2 — с ним сервер не запустится);
- hot_standby — определяет, можно или нет подключаться к postgresql для выполнения запросов в процессе восстановления;
- hot_standby_feedback — определяет, будет или нет сервер slave сообщать мастеру о запросах, которые он выполняет.
Посмотрим подсеть, которая используется для контейнеров с postgresql:
docker network inspect postgresql_default | grep Subnet
В моем случае, ответ был:
"Subnet": "172.19.0.0/16",
Теперь открываем файл:
vi /data/postgresql_01/pg_hba.conf
И добавляем строку после остальных «host replication»:
host replication all 172.19.0.0/16 md5
* в данном примере мы разрешили подключение пользователю replication из подсети 172.19.0.0/16 с проверкой подлинности по паролю.
Перезапустим докер контейнер:
docker restart postgresql_01
Настройка на слейве
Выполним настройку вторичного сервера. Для начала, удалим содержимое рабочего каталога вторичной базы:
rm -r /data/postgresql_02/*
* в данном примере мы удалим все содержимое каталога /data/postgresql_02.
Мы должны быть уверены, что в базе нет ничего важного. Только после этого стоить удалять данные.
Заходим внутрь контейнера postgresql_02:
docker exec -it postgresql_02 bash
Выполняем команду:
su - postgres -c "pg_basebackup --host=postgresql_01 --username=repluser --pgdata=/var/lib/postgresql/data --wal-method=stream --write-recovery-conf"
* где postgresql_01 — наш мастер; /var/lib/postgresql/data — путь до каталога с данными слейва.
Система должна запросить пароль для пользователя repluser — вводим его. Начнется процесс репликации, продолжительность которого зависит от объема данных.
Проверка
Смотрим статус работы мастера:
docker exec -it postgresql_01 su - postgres -c "psql -c 'select * from pg_stat_replication;'"
Смотрим статус работы слейва:
docker exec -it postgresql_02 su - postgres -c "psql -c 'select * from pg_stat_wal_receiver;'"
Источник: https://www.dmosk.ru/miniinstruktions.php?mini=postgresql-replication-docker