Docker
- Запуск контейнера
 - Еще полезные аргументы:
 - Запуск команды в контейнере:
 - Остановка контейнера
 - Удаление контейнера
 - Просмотр всех созданных контейнеров
 - Запуск консоли в контейнере винды:
 - Сохранение образа в файл:
 - Загрузка образа из файла:
 - Удаление образа с диска:
 - Список образов:
 - Удаление всех образов с тэгом none:
 - Удаление всех образов с rancher в названии:
 - Вывод инфы об контейнере:
 - Open container
 - Links
 - Вывод всех образов в приватном репозитории:
 - Ограничение контейнеров**
 - Пользователи
 - Создание образа из контейнера:**
 - Union file system
 - Docker file system
 - Network problems
 
Запуск контейнера
 docker run --name mytarantool -d -p 3301:3301 -v c:/tarantool/data:/var/lib/tarantool tarantool/tarantool:1.7--name - задает имя для контейнера
-d - detach, означает что контейнер будет запущен в фоне. Следует использовать для всяких бэкграундных сервисов/демонов
-p - проброс портов от контейнера на хост. Первое значение - порт хоста, второе - порт контейнера.
-v - маунт папки хоста в папку контейнера. Формат - key:value, где key - папка хоста, value - папка контейнера (можно не указывать key, тогда будет создана docker-managed volume, см. ниже). При этом если у образа уже есть такая папка с каким-то содержимым, то это содержимое будет стерто полностью. Чтобы этого избежать, можно маунтить не директории, а отдельные файлы.
Если на windows ошибок при маунте директорий нет, а директории в образе все равно пустые, то надо в настройках докера поставить галочки у дисков в разделе Shared Drives. Если уже стоят - снять и поставить обратно
-v key:value:ro - указание :ro в конце позволяет замаунтить папку как read-only.
--volumes-from - позволяет указать ранее созданный контейнер, с которым будут шариться волюмы
Еще полезные аргументы:
-i --interactive - оставлять стандартный поток ввода открытым даже если не приаттачено никакого терминала
-t --tty - выделить виртуальный терминал для контейнера, что позволит передавать сигналы внутрь контейнера
Обычно для интерактивных программ используется сразу -it
-e --env - позволяет задать переменную окружения, например, -e MY_ENVIRONMENT_VAR="test"
--restart always - указывает, что после завершения работы контейнер нужно рестартануть. Первый раз рестартует через 1 секунду, потом через 2, 4 и так далее.
docker run -it <image_name> /bin/sh \- запускает контейнер и сразу в интерактивном режиме баш в нем
docker logs <container_name> \- выводит все, что вывелось в контейнере в stdout и stderr
docker create <image_name% \- то же, что и run, только запускается остановленным
docker ps \- показывает список ==запущенных== контейнеров. Если нужны все, то указать флаг **-a**Запуск команды в контейнере:
docker exec -it mytarantool bashздесь mytarantool - имя контейнера, bash - команда
Остановка контейнера
docker stop mytarantool
Удаление контейнера
docker rm mytarantool
Чтобы docker for windows имел доступ к дискам, нужно сделать диск доступным в меню Settings -> Shared Drives
Просмотр всех созданных контейнеров
docker ps
Создание своего образа: https://docs.docker.com/engine/getstarted/step_four/#step-2-build-an-image-from-your-dockerfile
Запуск консоли в контейнере винды:
docker run -it microsoft/windowsservercore cmd
## Поиск образов:
Искать образы удобнее в консоли:
docker search rabbitmq
Найдя нужный образ, качаем его:
docker pull rabbitmq
Сохранение образа в файл:
docker save -o myfile.tar busybox:latest
Загрузка образа из файла:
docker load -i myfile.tar
Удаление образа с диска:
docker rmi busybox
Список образов:
docker images
Удаление всех образов с тэгом none:
docker rmi $(docker images -f 'dangling=true' -q)
Удаление всех образов с rancher в названии:
docker rmi $(docker images | gren 'rancher' | tr -s ' ' | cut -d ' ' -f 3)
Вывод инфы об контейнере:
docker inspect <container id>
Выдастся большой json, если нужен его определенный узел, то можно через -f указать узел, пример:
docker inspect -f "{{json .HostConfig.Binds}}" bmweb выдаст все мапы волюмов
docker inspect -f "{{json .Mounts}}" bmweb аналогично, но более подробно
Построение образа из Dockerfile:
docker build -t dia_ch3/dockerfile:latest ch3_dockerfile
-t - имя полученного образа. По умолчанию будет установлен в локальный регистр с указанным именем.
последний аргумент - папка, в которой лежит Dockerfile и все сопутствующие файлы
Волюмы бывают двух типов:
bind mount - обычный, где папка контейнера мапится на пользовательскую папку хоста
docker-managed volume - папка контейнера маппится на папку хоста, созданную демоном докера (/var/lib/docker/vfs/dir/<some volume ID>)
Быстрое поднятие веб-сервера, раздающего папку с файлами с локального диска:
docker run -d --name bmweb -v c:\userfiles:/usr/local/apache2/htdocs -p 80:80 httpd:latest**Volume container - контейнер, предоставляющий волюм, чтобы остальные контейнерымогли использовать его в флаге --volumes-from. Так же позволяет избежать orphane volume, когда на волюм не осталось ссылок и его никто не удалил и он занимает место на диске.
Data-packed volume container - это такой контейнер, который не содержит в себе никакого приложения, но содержит контент, который при старте копируется в шаренный волюм.
Полиформный контейнер - такой контейнер, поведение которого определяется содержимым его волюма. Например, контейнер содержит NodeJS и запускает приложение по адресу /app/app.js, а это волюм и определяется хостом.
А вот так можно задавать разные конфиги одному и тому же приложению в образе:
docker run --name devConfig -v /config dockerinaction/ch4_packed_config:latest /bin/sh -c 'cp /development/* /config/'
docker run --name prodConfig -v /config dockerinaction/ch4_packed_config:latest /bin/sh -c 'cp /production/* /config/'
docker run --name devApp --volumes-from devConfig dockerinaction/ch4_polyapp
docker run --name prodApp --volumes-from prodConfig dockerinaction/ch4_polyapp4 архетипа контейнеров по отношению к закрытости сети:
- closed container
- bridged container
- joined container
- open container
Closed container**
Может общаться только с собой через loopback-интерфейс. Создается, используя --net none при создании контейнера
Bridged container
Дефолтный вариант. Имеет loopback-интерфейс и приватный интерфейс, соединенный с хостом через мост. Создается, используя --net bridge.
docker port <container id>- показывает список всех замапленных портов.
--hostname - задает имя хоста, видимое только изнутри этого же самого контейнера.
--dns - задает главный DNS-сервер. Можно задать несколько таких серверов, а еще можно этот флаг задать демону dockerd и эти сервера будут по умолчанию заданы всем создаваемым контейнерам.
--dns-search - позволяет задать задать домен, по которому будут искаться все адреса, для которых не указан домен. Таким образом можно, например, различать тестовое и продакшн-окружение.
--add-host - позволяет задать ip для определенного хоста (как запись в hosts в Windows)
-p/--publish - позволяет задать порт-форвардинг
-P//--publish-all - паблишит все порты, которые заданы через EXPOSE
--expose - заэкспоузить дополнительный порт
--icc=false - отключает inter-container communication
--bip - позволяет задать IP-адрес контейнера и его subnet range, пример: --bip "192.168.0.128/25"
--mtu - задает MTU, максимальный размер пакета в байтах
-b/--bridge - позволяет задать собственный интерфейс моста
Joined container
Это несколько контейнеров, которые шарят общий сетевой стэк.
Docker в этом случае предоставляет интерфейсы, созданные специально для одного контейнера, другим контейнерам.
Для этого типа соединения первый контейнер создается как угодно, а затем к нему присоединяются остальные.
Присоединяются так: docker run --net container:<first container id> ...
Полезно, когда нужно чтобы 2 контейнера могли общаться меж собой, но не могли общаться с внешним миром. Тогда создаем первый закрытым и присоединяем к нему второй.
Open container
--net host Никакой изоляции, видит все те же сетевые интерфейсы, что и хост.
Links
Можно связать контейнеры однонаправленной связью через --link.
Пример:
docker run -d --name a mysql
docker run -d --name b --link a:db
При этом в контейнер b будут добавлены:
- переменные окружения для связи с a
- запись в dns, сопоставляющая ip контейнера a с хостом db
- если icc=false, то будут также добавлены правила в фаерволлы контейнеров для сетевого взаимодействия между ними
Сценарий использования: в контейнере b сервис ожидает, что по адресу tcp://db:3306 будет база данных. Или же он может брать порт базы из переменной окружения DB_PORT. Когда делаем --link оба этих значения будут автоматически заполнены.
Хорошей практикой считается на старте контейнера проверять, что заданы все необходимые переменные окружения/записи днс. Пример такого скрипта:
if [ -z ${DATABASE_PORT+x} ]
then
echo "Link alias 'database' was not set!"
exit
else
exec "$@"
fi Список переменных окружения, задаваемых при линке:
docker run -d --name mydb --expose 2222 --expose 3333 --expose 4444/udp alpine:latest nc -l 0.0.0.0:2222
docker run -it --rm --link mydb:database dockerinaction/ch5_ff env
DATABASE_PORT=tcp://172.17.0.23:3333 - любой из полных адресов для exposed-портов
DATABASE_PORT_3333_TCP=tcp://172.17.0.23:3333
DATABASE_PORT_2222_TCP=tcp://172.17.0.23:2222
DATABASE_PORT_4444_UDP=udp://172.17.0.23:4444
DATABASE_PORT_2222_TCP_PORT=2222
DATABASE_PORT_3333_TCP_PORT=3333
DATABASE_PORT_4444_UDP_PORT=4444
DATABASE_PORT_3333_TCP_ADDR=172.17.0.23
DATABASE_PORT_2222_TCP_ADDR=172.17.0.23
DATABASE_PORT_4444_UDP_ADDR=172.17.0.23
DATABASE_PORT_2222_TCP_PROTO=tcp
DATABASE_PORT_3333_TCP_PROTO=tcp
DATABASE_PORT_4444_UDP_PROTO=udp
DATABASE_NAME=/furious_lalande/database - имя текущего контейнера + / + имя алиасаПроблема с линками в том, что если контейнер-зависимость перезапустится, то у него будет новый Ip и все эти переменные станут неактуальными. Решением может быть использование DNS, либо же включение nter-process communication.
Вывод всех образов в приватном репозитории:
curl -X GET gitlab.factory.vocord.ru:5000/v2/_catalog
Ограничение контейнеров**
-m/--memory - ограничение по памяти, пример --memory 256m
\--cpu-shares - относительное ограничение CPU. Если одному связанному контейнеру указать 512, а другому 256, то второй будет получать 1 цикл на каждые 2цикла первого.
\--cpuset-cpus - указывает контейнерам, что они должны выполняться только на определенных ядрах
\--device /dev/video0:/dev/video0 - маппит девайсы внутрь контейнера
\--ipc container:<container id> \- шарит shared memory с указанным контейнером
\--ipc host - шарить всю память с хостомПользователи
docker run --rm --entrypoint "" busybox:latest whoami - вывод дефолтного пользователя внутри контейнера
-u/--user - указывает пользователя, под которым запустить контейнер
Пример: docker run -u nobody:default - устанавливает юзера nobody и группу default
Создание образа из контейнера:**
- Скачиваем образ
 - Делаем изменения в его файловой системе 
docker run --name hw_container ubuntu:latest touch /HelloWorld - Коммитим эти изменения как новый контейнер 
docker commit hw_container hw_image 
Флаги commit:
-a - подписывает образ авторской строкой
-m - commit message
-c --change - позволяет дописывать строки в Dockerfile, пример: docker commit -c "CMD /notebook.sh" notebook notebook-my
Пример:
docker commit -a "@dockerinaction" -m "Added git" image-dev ubuntu-gitentrypoint - Это программа, которая будет запущена при старте. Она тоже коммитится в образ.
docker run --name cmd-git --entrypoint git ubuntu-gitКроме этого коммитятся:
- все переменные окружения
 - рабочая директория
 - открытые порты
 - объявления волюмов
 - точка входа в контейнер
 - сама команда и все ее аргументы
 
docker diff <container id>- выводит список изменений в файловой системе контейнера относительно образа, из которого он создан. A - added, C - changed, D - deleted.
Union file system
В докере используется UFS, в которой файловая система представляется в виде объединения слоев. Редактируемый слой - только верхний, остальные все read-only. Новый слой сохраняется при коммите образа.
Благодаря такой системе, слои могут переиспользоваться в нескольких контейнерах, вместо того чтобы каждый раз копироваться. Однако есть и недостаток - старые слои никогда не удаляются, а значит образ может только увеличиваться в размерах и никогда не уменьшаться.
Максимальное количество слоев - 42.
docker history - выводит все коммиты/слои файловой системы
docker export --output export.tar ubuntu - сохраняет всю файловую систему контейнера в архив на хосте
docker import -c "ENTRYPOINT [\"/hello\"]" hello.tar dockerinaction/ch7_static - берет .tar с файлами и создает из них образ
Dockerfile
Пример докерфайла:
FROM ubuntu:latest
MAINTAINER "dockerinaction@allingeek.com"
RUN apt-get update
RUN apt-get install -y git
ENTRYPOINT ["git"] Построение:
docker build --tag ubuntu-git:auto . - точка на конце означает текущую директорию
Все команды, описанные в докерфайле (включая RUN) будут выполнены на этапе построения образа.
Первая команда всегда должна быть FROM. Если нужен пустой родитель, то можно указать FROM scratch.
Каждая инструкция в докерфайле создает новый слой в образе. Поэтому лучше эти инструкции по максимуму объединять, чтобы уменьшить размер образа. Если возникла ошибка на шаге N, то при повторной попытке шаги 1..N-1 будут взяты из кэша. Но если хочется не юзать кэш, то можно указать флаг --no-cache. 
Всего есть 14 инструкций Dockerfile.
В файле .dockerignore можно перечислить, какие файлы не включать в образ.
Инструкции
ENV - задает переменные окружения, пример: ENV APPROOT="/app" APP="mailer.sh" VERSION="0.6" (здесь задается 3 переменных). Заданные переменные окружения можно использовать в последующих инструкциях, используя синтаксис ${NAME}
** LABEL** - дополнительные пары ключ-значение, записываемые в метаданные образа. Пример: LABEL base.name="Mailer Archetype" base.version="${VERSION}"
WORKDIR- задает working directory, то есть ту директорию, в которой начнется исполнение образа. Пример: WORKDIR $APPROOT 
EXPOSE- Открывает порт. Пример: EXPOSE 33333
ENTRYPOINT- команда, которую запускать при старте образа. Можно либо задать команду консоли (shell form), либо массив строк, в котором первая строка - путь к исполняемому файлу, а остальные - аргументы запуска (exec form). shell form при этом менее гибок, так как не позволяет задавать последний аргумент в docker run или предоставлять дополнительные аргументы в инструкции CMD. Дефолтный entrypoint - /bin/sh
COPY - копирует файлы в образ. Принимает массив строк, где последний аргумент - папка назначения, а все остальные - копируемые файлы. Пример: COPY ["./log-impl", "${APPROOT}"] 
VOLUME- создает волюм, то же самое что и --volume. Только нельзя задать bind-mount или read-only волюм. В массиве аргументов для каждого значения будет создан волюм. Пример: VOLUME ["/var/log"].
CMD- задает аргументы для entrypoint. Если entrypoint не задан, либо задан в shell-форме, то это может быть команда для шелла, так как будет использован дефолтный entrypoint.
ONBUILD- инструкция, которая будет выполняться, если текущий образ будет использован как базовый для другого образа. Эти инструкции записываются в метаданные текущего образа. С их помощью можно, например, сбилдить программу, предоставляемую образом-потомком. ONBUILD-инструкции выполняются сразу после FROM в потомке.
Docker file system
Используется файловая система overlay2.
https://docs.docker.com/storage/storagedriver/overlayfs-driver/#how-the-overlay2-driver-works
Слои для каждого контейнера перечислены здесь:
/var/lib/docker/image/overlay2/layerdb/mounts/%CONTAINER_ID%
Там есть 3 файла:
- init-id - это идентификатор слоя, используемый при создании контейнера
 - mount-id - идентификатор слоя, который был образован в процессе работы контейнера
 - parent - какой-то идентификатор, видимо, родительского слоя
 
По идентификатору слоя можно получить его содержимое так:
/var/lib/docker/overlay2/%LAYER_ID%
Network problems
Если во всех образах перестала работать сеть, то можно пересоздать мост:
pkill docker
iptables -t nat -F
ifconfig docker0 down
ip link del docker0
systemctl start dockerЕсли ifconfig не найден, то apt install net-tools
Автоматическая очистка места на диске
По адресу /etc/cron.daily/docker-gc создаем скрипт следующего содержания:
#!/bin/sh -e
# Delete all stopped containers (including data-only containers).
docker ps -a -q --no-trunc --filter "status=exited" | xargs --no-run-if-empty docker rm -v
# Delete all tagged images more than a month old
docker images --no-trunc --format '{{.ID}} {{.CreatedSince}}' | grep ' months' | awk '{ print $1 }' | xargs --no-run-if-empty docker rmi -f || true
# Delete all 'untagged/dangling' (<none>) images
# Those are used for Docker caching mechanism.
docker images -q --no-trunc --filter dangling=true | xargs --no-run-if-empty docker rmi
# Delete all dangling volumes.
docker volume ls -qf dangling=true | xargs --no-run-if-empty docker volume rmДаем ему права:
sudo chmod +x /etc/cron.daily/docker-gcДобавляем новый джоб в crontab:
crontab -eОткрывается текстовый редактор, нужно в него добавить строчку:
0 0 * * * /etc/cron.daily/docker-gcне забыть последнюю строчку сделать пустой (иначе кронтаб ругаться будет) и выйти с сохранением
Файловая система докера
По умолчанию находится в папке /var/lib/docker
Структура файловой системы зависит от используемого драйвера хранилища. У меня на Debian это по уомлчанию overlay2, поэтому дальнейшая информация справедлива для него. Узнать свой драйвер можно командой docker info в графе Storage Driver 
В /var/lib/docker можем найти следующие подпапки:
- builder
 - buildkit
 - containerd
 - containers
 - image
 - network
 - overlay2
 - plugins
 - runtimes
 - swarm
 - tmp
 - trust
 - volumes
 
Описания образов лежат по адресу: /var/lib/docker/image/overlay2/imagedb/content/sha256.
Например, если мы ходим посмотреть описание образа с идентификатором ebaee1a37cda..., то нам нужно в текстовом редакторе открыть файл /var/lib/docker/image/overlay2/imagedb/content/sha256/ebaee1a37cda.... В этом текстовом файле лежит в основном та же инфа, которую мы получаем через docker inspect ebaee1a37cda, только иначе структурирована.
Но в этом файле мы не найден идентификаторы слоев образа для overlay2, те идентификаторы которые там указаны - они для RootFS (так и не понял, зачем нужны). Полезные идентификаторы будем брать из вывода docker inspect ebaee1a37cda:
"GraphDriver": {
    "Data": {
        "LowerDir": "/var/lib/docker/overlay2/1ef930458b9b7c4b107589bfa8708a5a905c0bff78fe82c04db1b65908ca356f/diff:/var/lib/docker/overlay2/990d47bc6c20549415caca3a6f6cfffc43b34491f128eeafffc2a8214c86ff1a/diff:/var/lib/docker/overlay2/6465e9cbb477e85f312139fd430c82649d5559190f2eed4fe32d1b2c2ca9bd9b/diff:/var/lib/docker/overlay2/7a924b04842adb199e077c02c4661955fb318d5d276c5c66b2e07628a69fc49d/diff:/var/lib/docker/overlay2/b4cf7f55f924b2167262f246ecdd8d2400adfbac69d0258049c619293228b6f0/diff",
        "MergedDir": "/var/lib/docker/overlay2/cf7ef417035f8dcbaabecdb4897a94ef1ad00b0919ddf4f7af0b1150b9c7bd8f/merged",
        "UpperDir": "/var/lib/docker/overlay2/cf7ef417035f8dcbaabecdb4897a94ef1ad00b0919ddf4f7af0b1150b9c7bd8f/diff",
        "WorkDir": "/var/lib/docker/overlay2/cf7ef417035f8dcbaabecdb4897a94ef1ad00b0919ddf4f7af0b1150b9c7bd8f/work"
    },
    "Name": "overlay2"
},Верхний слой описан в поле MergedDir. Пройдем по этому адресу:
$ cd /var/lib/docker/overlay2/cf7ef417035f8dcbaabecdb4897a94ef1ad00b0919ddf4f7af0b1150b9c7bd8f/
$ ls
diff link lower work	В файле link содержится сокращенный идентификатор слоя:
$ cat link
HRKAB26PG22YEF25QW3DFUSPVOВ lower - сокращенные идентификаторы нижних слоев, разделенные двоеточием:
$ cat lower
l/ZJPNNPNGB2QUT7UHS6FGJAJEXS:l/ITT6VDHHVLTL4XSV4MKXFARWZX:l/D73DFE6U73XW47KLW2IWYFN3X4:l/GPI73DKAIBG4M4HEPH22KTQBLS:l/AIQ55Z4PNLZZZTY5PWAD7EY74KВ папке /var/lib/docker/overlay2/l содержатся симлинки от сокращенных идентификаторов слоев к нормальным:
y# ls /var/lib/docker/overlay2/l/ZJPNNPNGB2QUT7UHS6FGJAJEXS -l
lrwxrwxrwx 1 root root 72 Jan 22 11:17 /var/lib/docker/overlay2/l/ZJPNNPNGB2QUT7UHS6FGJAJEXS -> ../1ef930458b9b7c4b107589bfa8708a5a905c0bff78fe82c04db1b65908ca356f/diffКак видим, второй сверху слой нашего образа ZJPNNPNGB2QUT7UHS6FGJAJEXS соответствует слою 1ef930458b9b7c4b107589bfa8708a5a905c0bff78fe82c04db1b65908ca356f. А его содержимое можем посмотреть в папке diff (посмотрим самый нижний слой нашего образа, содержащий файловую систему базового образа):
y# ls /var/lib/docker/overlay2/l/AIQ55Z4PNLZZZTY5PWAD7EY74K 
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var