Docker (Докер) для чайников

Вступление от автора руководства — Dmytro Yakovenko 2022/04/23: Дорогие мои читатели, я сам чайник в докерах, но куда деваться нужно изучить предметную область. Начнем помолясь:) Как всегда я стараюсь осветить терминологию, второй шаг установку, а дальше какой-нибудь интересную задачу решим с использованием доккера и какую-нибудь распространённую.

Docker (Докер) — программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации, контейнеризатор приложений. Docker — это инструмент, позволяющий запустить почти любое приложение со всеми его зависимостями в изолированной среде.

  • Docker Image (образы) - собственно, шаблон готового к запуску приложения со всем нужным для работы окружением. Является основой для контейнеров. Команда docker pull используется, чтобы скачать образ.
  • Контейнер (Containers) - это уже выполняющийся, запущенный образ (командой docker run), готовый к дальнейшему использованию. Список запущенных контейнеров можно увидеть с помощью команды docker ps.
  • Docker Hub (докер хаб) - сервис с реестром образов, где можно брать и загружать свои образы. Грубо говоря, архив всех доступных образов.
  • Docker Daemon (демон Докера) - Фоновый сервис, запущенный на хост-машине, который отвечает за создание, запуск и уничтожение Докер-контейнеров. Демон — это процесс, который запущен на операционной системе, с которой взаимодействует клиент.
  • Docker Client (клиент Докера) - Утилита командной строки, которая позволяет пользователю взаимодействовать с демоном. Существуют другие формы клиента, например, Kitematic, с графическим интерфейсом.

Основные компоненты Docker.

Есть два способа упаковки и переноса приложений со всеми его библиотеками между различными системами: использовать виртуальную машину или Docker-контейнер. Если выбрать виртуальную машину:

  • это ещё одна полноценная операционная система, в которой живут десятки процессов;
  • долгий старт приложения;
  • минимальный образ ОС весит более 100 МБ;
  • виртуальная машина потребляет много ресурсов, таких как процессор и оперативная память.

Из плюсов — у виртуальной машины удобные способы управления.

Если выбрать Docker-контейнер:

  • это будет облегченная операционная система с единственным процессом — вашим приложением;
  • быстрый старт приложения;
  • маленький размер контейнера.

Из минусов — у Docker сложная система управления контейнерами, которой можно управлять как локально на сервере, так и по протоколу HTTP.

Главное отличие технологий в том, что виртуальная машина виртуализирует аппаратные ресурсы, такие как процессор, память, системы input и output, а docker контейнеры виртуализируют только ОС.

С помощью команды docker можно пользоваться различными опциями, а также командами с аргументами. Ниже показан ее синтаксис. Запуск команды docker без ключей выведет весь список возможных ключей запуска.

docker [option] [command] [arguments]
  • Можно получить информацию о ключах, просто запустить команду docker. Для получения справки по использованию выбранной команды введите:
docker subcommand --help
  • Для получения полной информации по Docker потребуется ввести следующее или для краткой используйте ключ v, как показано ниже:
docker info
docker -v
Docker version 20.10.14, build a224086

Для просмотра запущенных контейнеров применяется команда docker ps, ключ а также показывает все контейнеры в системе. Разберем поля вывода команды

docker ps -a
или
docker container ls -a
  • CONTAINER ID - идентификатор контейнера, он уникален.
  • IMAGE - название образа, на основе которого запущен контейнер;
  • COMMAND - выполняемая при запуске контейнера команда;
  • CREATED - Когда был создан контейнер.
  • STATUS - статус контейнера, активен он или выключен.
  • PORTS - порты, через которые сервисы извне взаимодействует с контейнером и тем, что внутри него;
  • NAMES - имя контейнера.
  • Для просмотра последних созданных контейнеров используется опция -l:
docker ps -l
  • docker stats информация о потреблении ресурсов
  • docker kill ID принудительная остановка указанного контейнера, кроме того: stop, pause, unpause, restart.
  • -i опция, говорит о том, что мы хотим интерактивно взаимодействовать с контейнером (оказаться «внутри» него). Добавление опций -i (видеть, что происходит в контейнере, при помощи подключения telnet).
  • -t опция, говорит о том, что мы хотим взаимодействовать, то есть пересылать в контейнер наши команды) предоставляет доступ в интерактивном режиме к командному процессору.
  • -d, –detach указывает запуск в фоновом режиме
  • -p 8080:80 Проброс порта. Порт 80 «изнутри» контейнера становится портом 0.0.0.0:8080
  • Чтобы узнать IP адрес контейнера, используйте вывод ключа inspect:
docker container inspect ee7c5bd0f90e | grep IPAddress
  • –name задает имя контейнеру, что повышает удобочитаемость и написание скриптов, где вы указываете имя вместо ID.
  • остановить все запущенные контейнеры
    docker stop $(docker ps -q)

Команда docker exec используется для выполнения команд внутри запущенного контейнера. Общая синтаксис команды:

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

Аргументы:

  • CONTAINER - имя контейнера, в котором будет запущена команда.
  • COMMAND - команда, которая будет запущена в контейнере.
  • ARG… - аргументы команды.

Опции:

  • -it - запускает интерактивную сессию в контейнере.
  • -d - запускает команду в фоновом режиме.
  • -e - задает переменные окружения для команды.
  • -w - задает рабочую директорию для команды.

Можно говорить о том, что exec 3 режима работы.

1. Базовый режим exec

Базовый режим exec выполняет команду в контейнере синхронно с командной строкой.

docker exec my-container ls -al

Эта команда выведет список файлов в текущем каталоге контейнера my-container.

docker exec my-container ls cat /var/log/dpkg.log | head -3

Выведет 3 строки из файл dpkg.log.

2. Демон (фоновый режим)

В этом режиме команда в контейнере выполняется в фоновом режиме. Режим демона используется чтобы запустить команду и забыть о ней, например для очистки системных журналов

docker exec mycontainer sh -c 'truncate -s 0 /var/log/*'

В этой команде:

  • mycontainer - это имя или идентификатор вашего Docker-контейнера.
  • sh -c позволяет выполнить команду в оболочке контейнера.
  • truncate -s 0 /var/log/* - это команда, которая устанавливает размер всех файлов в директории /var/log в 0, что приводит к их очистке.

Аналогичная команда с использование for, find также обнуляет рекурсивно все log и выводит список обработанных файлов:

docker exec -it mycontainer sh -c 'for k in `find /var/log/ -type f -name *.log`; do echo $k && echo > $k ;done'
 
/var/log/apt/term.log
/var/log/apt/history.log
/var/log/dpkg.log
/var/log/alternatives.log
/var/log/fontconfig.log
...

3. Интерактивный режим

Выполняет команду и позволяет пользователю взаимодействовать с ней.

docker exec -it my-container bash

Эта команда запустит интерактивную сессию в контейнере my-container. В этой сессии можно выполнять любые команды, как в обычном терминале. Можно выполнять внутри контейнера все правки, которые нам необходимы. Не забывайте, что после перезапуска контейнера - все правки пропадут, для сохранения правок изучите Шаг 4: Как сохранить локально изменения в новый образ Docker.

Источник: Удаление образов, контейнеров и томов 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 system prune -a
docker system prune --all
docker system prune -a -f

Чтобы удалить все остановленные контейнеры и неиспользуемые образы (а не только образы, не связанные с контейнерами), добавьте в эту команду флаг -a.

  • Удаление одного или нескольких конкретных контейнеров.

Используйте команду docker ps с флагом -a для поиска имен или идентификаторов контейнеров, которые вы хотите удалить:

docker ps -a
docker rm ID_or_Name ID_or_Name
  • Удаление контейнера при выходе.

Если вы создаете контейнер, который вам не будет нужен после завершения его использования, вы можете использовать команду docker run –rm для его автоматического удаления при выходе.

docker run --rm image_name
  • Удаление всех контейнеров, из которых выполнен выход.

Вы можете найти контейнеры с помощью команды docker ps -a и отфильтровать их по статусу: created (создан), restarting (перезапускается), running (работает), paused (пауза) или exited (выполнен выход). Чтобы просмотреть список контейнеров, из которых выполнен выход, используйте флаг -f для фильтрации по статусу. Убедитесь, что вы хотите удалить эти контейнеры, и используйте флаг -q для передачи идентификаторов в команду docker rm.

docker ps -a -f status=exited
docker rm $(docker ps -a -f status=exited -q)

Более простой вариант

docker container prune
  • Удаление одного или нескольких конкретных образов.

Используйте команду docker images с флагом -a, чтобы найти идентификатор удаляемых образов. Эта команда покажет вам все образы, включая промежуточные слои образов. Когда вы определитесь с составом удаляемых образов, вы можете передать их идентификаторы или теги в docker rmi:

docker images -a
docker rmi Image Image
  • Удаление образов, не привязанных к контейнеру.

Образы Docker состоят из нескольких слоев. Несвязанные образы — это слои, не имеющие связей с каким-либо образами с тегами. У них нет никакого назначения, и они просто занимают место на диске. Их можно найти, добавив флаг фильтра -f со значением dangling=true в команду docker images. Если вы уверены, что хотите удалить их, вы можете использовать команду docker images purge:

docker images -f dangling=true
docker images purge
  • Удаление образов по шаблону.

Вы можете найти все образы, соответствующие определенному шаблону, используя комбинацию команд docker images и grep. Когда вы будете довольны, вы можете удалить их, используя awk для передачи идентификаторов в docker rmi. Эти утилиты не предоставляются Docker и могут быть доступны не во всех системах:

docker images -a |  grep "pattern"
docker images -a | grep "pattern" | awk '{print $3}' | xargs docker rmi

docker logs ID вывод логов из указанного контейнера -f вывод логов в стиле tail –f (соответственно если логи пишутся в консоль контейнера STDOUT/STDERR)

docker logs -f eef97a115270

Ключевое логи можно смотреть и у остановленных контейнеров.

Лог из контейнера также пишутся на хостовую машина, найти файл лога можно при помощи ключа inspect:

docker inspect --format "{{.LogPath}}" <id_контенера>
или так
docker container inspect <id_контенера> | grep LogPath

Вывести лог можно например так

sudo cat $(docker inspect --format "{{.LogPath}}" <id_контенера>)

В зависимости от реализации ПО внутри контейнера может понадобиться перенаправить поток ошибок (2 — STDERR) в стандартный поток (1 — STDOUT), например чтобы grep заработал:

docker logs -f eef97a115270 2>&1 | grep ERROR

Долго работающие контейнеры Docker могут быстро накапливать большое количество логов. Они потребляют емкость хранилища и снижают производительность при доступе к данным и их фильтрации. Хотя Docker содержит встроенные инструменты для просмотра логов, в нем нет встроенного механизма для их очистки. Вы можете очистить содержимое журнала, не удаляя его, передав echo пустую строку в его содержимое.

sudo sh -c 'echo "" > $(docker inspect --format="{{.LogPath}}" <id_контенера>)'

Настройка ротации логов Docker: Многие драйверы логирования Docker, включая json-file, имеют опциональную поддержку ротации логов, которую можно включить глобально для демона Docker или на основе каждого контейнера. Параметры демона настраиваются в файле /etc/docker/daemon.json (умолчанию файл daemon.json не существует, вам нужно его создать). Ниже пример, который ротирует логи контейнеров, когда они достигают 8 МБ. В каждый момент времени сохраняется до пяти файлов, при этом старые файлы автоматически удаляются при новой ротации.

{
    "log-opts": {
        "max-size": "8m",
        "max-file": "5"
    }
}

Не забудьте перезапустить демон Docker, чтобы применились изменения (все ваши контейнеры выключаться!!!):

systemctl restart docker

Еще раз подытожим:

  • > — запись stdout в файл
  • » — дозапись stdout в файл
  • 2> — запись stderr в файл
  • 2» — дозапись stderr в файл

Давайте для примера сохраним логи в 2 файла — stdout.log и stderr.log. Команда будет выглядеть так:

docker logs logs_task > stdout.log 2> stderr.log

Читайте также: Стек ELK служит для аналитики журналов в облаке

У вас есть какая-то программа, которая пишет логи в файл. Например возьмем Nginx и выведем его логи в консоль. Пример взят из официальной документации. Это настройка позволит просматривать логи Nginx, при помощи стандартной команды docker logs. Также такой подход позволяет из инфраструктуры докера логи отсылать в Kubernetes или еще куда-то.

RUN ln -sf /dev/stdout /var/log/nginx/access.log \
	&& ln -sf /dev/stderr /var/log/nginx/error.log

Полный листинг

FROM debian:jessie
 
MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com"
 
ENV NGINX_VERSION 1.11.5-1~jessie
 
RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \
	&& echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list \
	&& apt-get update \
	&& apt-get install --no-install-recommends --no-install-suggests -y \
						ca-certificates \
						nginx=${NGINX_VERSION} \
						nginx-module-xslt \
						nginx-module-geoip \
						nginx-module-image-filter \
						nginx-module-perl \
						nginx-module-njs \
						gettext-base \
	&& rm -rf /var/lib/apt/lists/*
 
# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
	&& ln -sf /dev/stderr /var/log/nginx/error.log
 
EXPOSE 80 443
 
CMD ["nginx", "-g", "daemon off;"]

Лайфхак

В случае Nginx, можно сделать еще проще, просто для виртуального хоста указать настройки логов в таком формате:

access_log  /var/log/nginx/access.log  main; 
access_log  /dev/stdout  main;

EXPOSE директива Dockerfile имеет свою специфику применения.

Если требуется пробросить и сопоставить разные порты внутри и снаружи контейнера используется docker run -p порт на хосте: порт в контейнере

docker run -d -p 81:80 --name httpd-container httpd

Эта команда запускает Docker-контейнер httpd (HTTP-сервер Apache) и маппинг 81 порта хоста с 80 портом внутри Docker-контейнера.

При поднятии контейнера можно прокинуть несколько портов. Для этого нужно просто задать опцию -p несколько раз:

docker run -p <порт_на_хосте_1>:<порт_в_контейнере_1> -p <порт_на_хосте_2>:<порт_в_контейнере_2> ...

Например, можно сделать вот так и связать порты 80, 81 и 82 с портом 80 в контейнере:

docker run -p 80:80 -p 81:80 -p 82:80 nginx

Команда Docker create создает новый новый контейнер из образа Docker, но он не запускается сразу.

Команда start запустит любой остановленный контейнер. Если вы использовали команду docker create для создания контейнера, вы можете запустить его с помощью этой команды.

Команда run представляет собой комбинацию create и start, поскольку она создает новый контейнер и запускает его немедленно. Фактически, команда docker run может извлечь образ из Docker Hub, если она не находит упомянутый образ в вашей системе.

Изначально Docker берет образы в хабах Docker Hub (докер хаб). Docker Hub является реестром образов, поддерживаемых разработчиком. Любой имеет возможность создавать и загружать собственные образы. Для большей части дистрибутивов и программ уже имеются необходимые образы в Docker Hub. Для подключения к Docker Hub используйте команду:

docker login

Докер хранит файлы (контейнеры) в виде папок и файлов в директории /var/lib/docker/containers.

  • Представленные в хабе образы можно найти при помощи команд docker и search. К примеру, найти образ MariaDB можно следующим образом:
docker search mariadb

Строчка OK в столбце OFFICIAL говорит о том, что образ создан и его поддержка осуществляется компанией, ответственной за этот проект.

  • Выбрав требуемый образ, например PhpMyAdmin, его можно скачать на компьютер (свое локальное хранилище), используя подкоманду pull.
docker pull phpmyadmin
  • Чтобы посмотреть, какие образы были загружены на компьютер, используется команда:
docker images
  • Запуск контейнера docker run
docker run hello-world

Добавление опций -i (видеть, что происходит в контейнере) и -t (взаимодействовать, то есть пересылать в контейнер наши команды) предоставляет доступ в интерактивном режиме к командному процессору.

docker run -it ubuntu
  • Чтобы запустить остановленный контейнер, необходимо ввести docker start и далее указать идентификатор или имя контейнера. Так выглядит запуск контейнера 98ed79500b2d:
docker start 98ed79500b2d
  • Чтобы выключить активный контейнер, используется команда docker stop с указанием его идентификатора или имени.
  • Для перезапуска контейнер, не отключая его используйте ключ restart.
    docker restart имя/id контейнера
  • Удалить можно только остановленный контейнер. Для удаления используйте rm, указав имя или идентификатор контейнера:
docker container rm имя_контейнера
или
docker rm [OPTIONS] CONTAINER [CONTAINER...]

Во время запуска контейнера из существующего образа у пользователя есть возможность создавать или удалять файлы, аналогично работе на виртуальной машине. При этом изменения будут распространяться только в определенном контейнере. Доступна и возможность запуска с последующей остановкой контейнера, но после его удаления с помощью docker rm будут утеряны внесенные изменения.

Соответственно, следует ознакомиться со способом сохранения текущего контейнера как нового образа.

Сохраните результаты в текущем образе командой:

docker commit -m "Что вы сделали с образом" -a "Имя автора" container_id repository/new_image_name

Добавление опции -m дает возможность указать сообщение подтверждения. Это позволит будущим пользователям образа понять, что именно было изменено. Что касается параметра -a — с его помощью можно указать, кто его создатель. container_id является тем же идентификатором, который был использован ранее, во время запуска интерактивной сессии в Docker.

Если вы не занимались до этого созданием новых репозиториев в Docker Hub, имя создаваемого репозитория по умолчанию будет названо именем вашего пользователя в Docker Hub.

Рассмотрим как правильно установить и настроить СУБД MySQL MariaDB в виде приложения Docker, при этом все постоянные данные будут храниться в файловой системе хоста.

Зачем использовать Docker для установки MariaDB? Использование Docker-контейнера позволяет не только обеспечивает чистое развертывание, не зависящее от программного обеспечения сервера, но и позволяет поддерживать несколько СУБД MySQL разных версий и различного назначения в рамках одной операционной системы.

При установке MariaDB будет использован внешний конфигурационный файл и внешний каталог хранения данных для того, чтобы при перезапуске контейнера вся информация оставалась в сохранности. Сначала создадим необходимые каталоги, в которых будут храниться настройки, журналы и базы данных MySQL:

mkdir -p /opt/mariadb/{data,etc,logs}

Создадим конфигурационный файл /opt/mariadb/etc/config.cnf, который будет уточнять настройки, применяемые контейнером по умолчанию. В этом файле вы можете переопределять переменные MySQL для задания нужного поведения. Мы определим 3 переменных для демонстрации возможностей:

[mysqld]
log_error=/var/lib/mysql/logs/errorlog
slow_query_log=on
slow_query_log_file=/var/lib/mysql/logs/slowlog

Теперь можно запустить сам сервер MySQL:

sudo docker run -d --restart=always --name mariadb_1 \
         -v /opt/mariadb/data:/var/lib/mysql \
         -v /opt/mariadb/etc:/etc/mysql/conf.d \
         -v /opt/mariadb/logs:/var/lib/mysql/logs \
         -e MYSQL_ROOT_PASSWORD=secret \
         -p 127.0.0.1:3306:3306 mariadb:10.3

Где ключи

  • name задает собственное (удобное нам) имя для контейнера
  • -d, –detach указывает запуск в фоновом режиме
  • -v, –volume list несколько ключей v указывают монтирование директории из хостовой машины
  • -e, –env list Обратите внимание на пароль пользователя root, который задается с помощью переменной окружения MYSQL_ROOT_PASSWORD. Этот пароль будет записан в системную БД mysql, если вы после остановите контейнер и поменяете его, это не окажет влияние на пароль в БД.
  • -p, –publish list публикация портов контейнера на хосте

Для проверки работоспособности сервера используйте консольный клиент MySQL:

sudo docker run -it --rm --link mariadb_1:mysql mariadb:10.3 \
       mysql -hmysql -uroot -psecret

Выгрузка данных БД для резервных копий в самом простом случае может выполняться стандартным

sudo docker run -it --rm --link mariadb_1:mysql mariadb:10.3 \
   mysqldump --all-databases -hmysql -uroot -psecret > all-databases.sql

Всё, сервер MariaDB развернут, при этом файлы располагаются в каталогах хоста, что позволяет изменять настройки сервера, получать доступ к записям журналов и сами данным баз данных.

Установка хранилища Redis в Докер одной командой:

docker run --rm -d -p 6379:6379 --name redis -v redis_vol:/var/lib/redis/ redis redis-server --appendonly yes

Проверим что контейнер с Rdis работает и данные сохраняются в Docker Volumes:

docker exec -it redis redis-cli
127.0.0.1:6379> SET test "Hi"
OK
127.0.0.1:6379> GET test
"Hi"
127.0.0.1:6379> exit
PQ VPS сервера в 28+ странах.