###### top ## Docker - справка *** [Базовые понятия Docker](#part1) - [Управление контейнерами](#chapter1) - [Логи и статистика работы](#chapter2) - [Команды в контейнере](#chapter3) [Docker image](#part2) - [Общие данные](#chapter4) - [Dockerfile](#chapter5) - [Создание образа](#chapter6) [Сеть в Docker](#part3) - [Устройство сети](#chapter7) - [Драйвер bridge](#chapter8) - [Проброс портов](#chapter9) - [Драйвера host и null](#chapter10) - [DNS](#chapter11) [Docker volumes](#part4) - [Устройство и типы volumes](#chapter12) - [Использование volumes](#chapter13) - [Volume в Dockerfile](#chapter14) - [bind mounts](#chapter15) - [tmpfs](#chapter16) - [Копирование данных](#chapter17) [Docker compose](#part5) - [YAML](#chapter18) - [Простой конфиг](#chapter19) - [Профили](#chapter20) - [Запуск отдельных сервисов](#chapter21) - [Переменные окружения](#chapter22) - [Объединение конфигураций](#chapter23) - [](#chapter24) - [](#chapter25) - [](#chapter26) - [](#chapter27) - [](#chapter28) - [](#chapter29) - [](#chapter30) *** `docker --help` *** ###### part1 ## Базовые понятия Docker [вверх](#top) ###### Chapter1 ### Управление контейнерами `docker run nginx` - создать и запустить контейнер из образа nginx, если образа нет локально, образ будет скачан из репозитория. `docker run --name my-nginx -d nginx` - создать и запустить контейнер с указанным именем `--name my-nginx`; в фоновом процессе `-d` - detach; из образа nginx *кроме этого есть команды:* `create` - создать контейнер, не запуская `start`, `stop`, `pause` `docker ps` - показать все запущенные контейнеры `docker ps -a` - показать все контейнеры, в том числе остановленные `docker rm nginx` - удалить остановленный контейнер с именем nginx `docker rm -f nginx` - удалить контейнер с именем nginx принудительно, даже если он запущен `docker container prune` - удалить все остановленные контейнеры [вверх](#top) *** ###### Chapter2 ### Логи и статистика работы `docker stats` - статистика по используемым ресурсам запущенных контейнеров ```bash CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 6ed9807997de my-web 0.00% 3.348MiB / 1.941GiB 0.17% 1.22kB / 0B 0B / 16.4kB 3 08d3dc4c1595 mongo 0.22% 147.2MiB / 1.941GiB 7.41% 1.51kB / 0B 3.1MB / 43.9MB 33 ^C ``` `docker inspect` - информация о контейнере или локальном образе *можно получить выдержку из состояния, использовав ключ `-f` - format* ```bash da2001@us:~$ docker inspect my-web -f '{{.State.Status}}' running ``` ***форматирование и фильтрация вывода доступна во многих командах, например*** ```bash da2001@us:~$ docker inspect --help Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...] Return low-level information on Docker objects Options: -f, --format string Format the output using the given Go template -s, --size Display total file sizes if the type is container --type string Return JSON for specified type ``` *или* ```bash da2001@us:~$ docker ps --help Usage: docker ps [OPTIONS] List containers Options: -a, --all Show all containers (default shows just running) -f, --filter filter Filter output based on conditions provided --format string Pretty-print containers using a Go template -n, --last int Show n last created containers (includes all states) (default -1) -l, --latest Show the latest created container (includes all states) --no-trunc Don't truncate output -q, --quiet Only display container IDs -s, --size Display total file sizes ``` ```bash da2001@us:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6ed9807997de nginx "/docker-entrypoint.…" 5 seconds ago Up 3 seconds 80/tcp my-web 08d3dc4c1595 mongo "docker-entrypoint.s…" About an hour ago Up About an hour 27017/tcp mongo ``` ```bash da2001@us:~$ docker ps --filter ancestor= exited= health= is-task= name= publish= status= before= expose= id= label= network= since= volume= ``` ```bash da2001@us:~$ docker ps --filter name=my-web CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6ed9807997de nginx "/docker-entrypoint.…" About an hour ago Up About an hour 80/tcp my-web ``` **Логи** `docker logs my-web` - показать логи контейнера `docker logs my-web | grep 'default.conf'` - вывести логи и отфильтровать по сочетанию `default.conf` `docker logs my-web | grep 'default.conf' -A 2` - строка соответствующая сочетанию `default.conf` + 2 строки после `docker logs my-web | grep 'default.conf' -B 2` - строка соответствующая сочетанию `default.conf` + 2 строки перед `docker logs my-web -f` - отображать логи в реальном времени [вверх](#top) *** ###### Chapter3 ### Команды в контейнере ```bash da2001@us:~$ docker exec --help Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] Run a command in a running container Options: -d, --detach Detached mode: run command in the background --detach-keys string Override the key sequence for detaching a container -e, --env list Set environment variables --env-file list Read in a file of environment variables -i, --interactive Keep STDIN open even if not attached --privileged Give extended privileges to the command -t, --tty Allocate a pseudo-TTY -u, --user string Username or UID (format: [:]) -w, --workdir string Working directory inside the container ``` *В контейнере `mongo` перейти в директорию `/root` и выполнить команду `pwd`* ```bash da2001@us:~$ docker exec -w /root mongo pwd /root ``` *Задать переменную в контейнере и вывести список всех переменных окружения, доступных в контейнере* ```bash da2001@us:~$ docker exec -e MYVAR=1 mongo printenv PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=08d3dc4c1595 GOSU_VERSION=1.12 JSYAML_VERSION=3.13.1 MONGO_PACKAGE=mongodb-org MONGO_REPO=repo.mongodb.org MONGO_MAJOR=5.0 MONGO_VERSION=5.0.3 MYVAR=1 HOME=/root ``` *Покдлючиться к оболочке контейнера в интерактивном режиме* ```bash da2001@us:~$ docker exec -it mongo bash root@08d3dc4c1595:/# ``` *Выполнить в контейнере команду `mongo --version`* ```bash da2001@us:~$ docker exec mongo mongo --version MongoDB shell version v5.0.3 Build Info: { "version": "5.0.3", "gitVersion": "657fea5a61a74d7a79df7aff8e4bcf0bc742b748", "openSSLVersion": "OpenSSL 1.1.1f 31 Mar 2020", "modules": [], "allocator": "tcmalloc", "environment": { "distmod": "ubuntu2004", "distarch": "x86_64", "target_arch": "x86_64" } } ``` `docker exec mongo mongo --version > ver.txt` - перенаправить вывод в файл на хосте `docker exec mongo bash -c 'mongo --version > ver.txt'` - перенаправить вывод в файл в контейнере [вверх](#top) *** ###### part2 ## Docker image [вверх](#top) ###### Chapter4 ### Общие данные `docker image --help` `docker images` - показать скачанные образы `docker save --output nginx.tar nginx` - сохранить образ в текущую директорию `docker image import --help` - импорт ранее сохранённого образа `docker history nginx` - информация о создании образа `docker inspect nginx` - информация об образе `docker pull nginx` - скачать образ nginx не запуская контейнер `docker push --help` - опубликовать созданный образ во внешнем реестре образов *`ls` - аналог `docker images`* ```bash da2001@us:~$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE mongo latest fefd78e9381a 12 days ago 699MB nginx latest 87a94228f133 2 weeks ago 133MB ``` *вывести определённую колонку, название колонки с **большой** буквы* ```bash da2001@us:~$ docker image ls --format {{.Tag}} latest latest ``` ```bash da2001@us:~$ docker image ls --format {{.Repository}} mongo nginx ``` *если образов много, вывод можно отфильтровать* ```bash da2001@us:~$ docker image ls --filter before= dangling= label= reference= since= ``` `docker image rm hello-world` - удалить образ `docker rmi hello-world` - удалить образ `docker image rm hello-world -f` - удалить образ даже если его использует какой-то контейнер, контейнер удалён НЕ будет `docker image prune` - удалить все образы без тега [вверх](#top) *** ###### Chapter5 ### Dockerfile `FROM ubuntu:20.04` - установит базовый образ, на основе которого будет создаваться текущий образ. Если тег `20.04` не указан, будет использован образ `latest` `LABEL ENV=”DEVELOPMENT”` - пара ключ-значение, используемая для указания метаданных информации образа `RUN apt-get update` `RUN apt-get install tomcat` - используется для выполнения команды на базовом образе и создает новый слой `CMD [“java”, “-jar”, “app.jar”]` - используется для задания команды, которая будет выполняться первой при запуске контейнера `EXPOSE 8080` - откроет порт для доступа к контейнеру. Контейнер будет прослушивать этот сетевой порт `MAINTAINER devops@admin.in` - предоставит подробную информацию об авторе, который создал этот образ `ENV DB_NAME=”MySQL”` `ENV DB_VERSION=”8.0”` - используется для установки переменных среды в паре ключ-значение. Эти переменные устанавливаются во время сборки образа и доступны после создания контейнера `COPY /target/devops.jar devops.jar` - используется для копирования локальных файлов в контейнер `ADD devops.tar.xz / .` `ADD http://example.com/abc.git /usr/local/devops/` - работает так же, как COPY, но имеет некоторые дополнительные функции, такие например, что мы можем извлечь локальный tar и добавить удаленный URL `ENTRYPOINT [“java”, “-jar”, “app.jar”]` - используется для установки основной команды для образа. Он работает так же, как инструкция CMD. Разница между CMD и ENTRYPOINT в том, что инструкции не перезаписываются в ENTRYPOINT `VOLUME /app/devops` - создает точку монтирования с указанным именем `USER [:]` `USER [:]` - устанавливает имя пользователя и группу пользователей при запуске образа `WORKDIR /var/lib/` - установит рабочий каталог. Он создаст каталог, если его нет [вверх](#top) *** ###### Chapter6 ### Создание образа `docker build --help` *Пример сборки образа* ```bash docker build -f ./apps/api/Dockerfile -t test:latest . ``` `-f` - указать путь к Dockerfile, если он не в текущей директории `-t` - указать имя образа с тегом, если тег не будет указан, по-умолчанию присвоится `:latest` `.` - брать контекст для образа из текущей директории [вверх](#top) *** ###### part3 ## Сеть в Docker [вверх](#top) - `bridge` мост — это сетевой драйвер по умолчанию. Бридж сеть используется, когда приложения запускаются в автономных контейнерах, которые должны взаимодействовать между собой (Наглядный пример Nginx + MySQL); - `host` хост — это сетевой драйвер для автономных контейнеров (удаленная сетевая изоляция между контейнером и Docker хостом). Данный драйвер доступен только для docker-swarm; - `overlay/overlay2` оверлей (наложенная сеть), — это сетевой драйвер для соединения нескольких демонов Docker между собой и которые позволяют docker-swarm службам взаимодействовать друг с другом. Также можно использовать оверлейные сети для облегчения связи между docker-swarm и автономным контейнером или между двумя отдельными контейнерами на разных Docker демонах. Эта стратегия устраняет необходимость выполнения маршрутизации на уровне ОС между этими контейнерами; - `macvlan` маквлан — это сетевой драйвер, который позволяют назначать MAC-адрес контейнеру, делая его отображаемым как физическое устройство в сети. Docker демон направляет трафик на контейнеры по их MAC-адресам. Использование macvlan драйвера иногда является лучшим выбором при работе с устаревшими приложениями, которые ожидают, что они будут напрямую подключены к физической сети; - `none` — это сетевой драйвер, который умеет отключать всю сеть для контейнеров. Обычно используется в сочетании с пользовательским сетевым драйвером; - `Network plugins` — кроме этого, можно установить и использовать сторонние сетевые плагины с Docker контейнерами. Эти плагины доступны в Docker Store или у сторонних поставщиков услуг. ###### Chapter7 ### Устройство сети ```bash Usage: docker network COMMAND Manage networks Commands: connect Connect a container to a network create Create a network disconnect Disconnect a container from a network inspect Display detailed information on one or more networks ls List networks prune Remove all unused networks rm Remove one or more networks ``` *Отобразить имеющиеся сети* ```bash da2001@us:~$ docker network ls NETWORK ID NAME DRIVER SCOPE 222826f8b512 bridge bridge local 5f64c40ea352 host host local 79350884305f none null local ``` *Создать сеть типа `bridge` с именем `br2`* ```bash da2001@us:~$ docker network create br2 40ff1259ca7e103736c74da0309d6fde5d8439d6844d6f5997b216912d05a705 ``` или ```bash da2001@us:~$ docker network create --driver=bridge br2 ``` По-умолчанию, всегда создаётся мост ```bash da2001@us:~$ docker network ls NETWORK ID NAME DRIVER SCOPE 40ff1259ca7e br2 bridge local 222826f8b512 bridge bridge local 5f64c40ea352 host host local 79350884305f none null local ``` *пример создания оверлей-сети* ```bash da2001@us:~$ docker network create --driver overlay overlay-net ``` для создания оверлей-сети необходимо активировать docker-swarm [вверх](#top) *** ###### Chapter8 ### Драйвер bridge Сеть с драйвером bridge создаётся по-умолчанию. Контейнеры, использующие одну сеть могут видеть друг друга по выделенному им IP адресу. Посмотреть детальную информацию о сети можно с помощью команды `inspect` ```bash da2001@us:~$ docker network inspect bridge [ { "Name": "bridge", "Id": "222826f8b512e0803fc5d6fa26c443af23908be03f46b15f41d1a932557a9df5", "Created": "2021-10-29T15:30:59.140332733+03:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "08d3dc4c15953ed7a25e629b983ecba977ed64f73bf3d138943bb12e644c463b": { "Name": "mongo", "EndpointID": "f24d0dfbe08458bc7c7c5ca31cec04832c00e3ba062f18757277033754d4e4bb", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" }, "56e21d5c7bbdf562e75a5ee614e43648273e9960bc72678285a02863c46b2061": { "Name": "node-1", "EndpointID": "788fcfc6ce612363128d7b3d8c16fd259ea0bd84c0114702fefb64ec739161d6", "MacAddress": "02:42:ac:11:00:04", "IPv4Address": "172.17.0.4/16", "IPv6Address": "" }, "6ed9807997de2bed3d6f2aeafc2fca5f2d843a55e10b1611e7f5e474f2be473d": { "Name": "my-web", "EndpointID": "a7d5032f4ea38edb0cf7f6f3ecbed7eada2e0cf9184dfb5c393b67cfb6f72c57", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" }, "f4331c7520ba749fbdf33d98c1fcb5284a2df63e510f841e7dcd655878c43941": { "Name": "node-2", "EndpointID": "82baf3a4d8fcddd3538b86cf3237e710b53d9975a78ec98a07e3055fb7ee80a8", "MacAddress": "02:42:ac:11:00:05", "IPv4Address": "172.17.0.5/16", "IPv6Address": "" } }, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" }, "Labels": {} } ] ``` *в длинном выводе указана вся информация о сети, её адресации и контейнерах, которые используют эту сеть.* ***Чтобы контейнеры могли обращаться друг к другу по имени, необходимо создать новую сеть и добавить в неё эти контейнеры*** ```bash da2001@us:~$ docker network create br2 40ff1259ca7e103736c74da0309d6fde5d8439d6844d6f5997b216912d05a705 da2001@us:~/docker-demo-3$ docker run -d --name node-1 demo3 56e21d5c7bbdf562e75a5ee614e43648273e9960bc72678285a02863c46b2061 da2001@us:~/docker-demo-3$ docker run -d --name node-2 demo3 f4331c7520ba749fbdf33d98c1fcb5284a2df63e510f841e7dcd655878c43941 da2001@us:~/docker-demo-3$ docker network connect br2 node-1 da2001@us:~/docker-demo-3$ docker network connect br2 node-2 da2001@us:~/docker-demo-3$ docker network inspect br2 [ { "Name": "br2", "Id": "40ff1259ca7e103736c74da0309d6fde5d8439d6844d6f5997b216912d05a705", "Created": "2021-10-31T11:20:50.595291142+03:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "56e21d5c7bbdf562e75a5ee614e43648273e9960bc72678285a02863c46b2061": { "Name": "node-1", "EndpointID": "9ac4317d24147360565c69e021e4c6bc7a407103c2e6a907475f707f4deed32a", "MacAddress": "02:42:ac:12:00:02", "IPv4Address": "172.18.0.2/16", "IPv6Address": "" }, "f4331c7520ba749fbdf33d98c1fcb5284a2df63e510f841e7dcd655878c43941": { "Name": "node-2", "EndpointID": "3e41fd9618f71446878a7c585d9289bc4a099c7c15f8cf835084c0015c87ed54", "MacAddress": "02:42:ac:12:00:03", "IPv4Address": "172.18.0.3/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] ``` *из вывода видно, что к сети br2 подключено 2 контейнера: node-1(172.18.0.2) и node-2(172.18.0.3)* *подключимся к node-1 и попробуем пинговать node-2* ```bash da2001@us:~$ docker exec -it node-1 sh /opt/app # ip a 1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 11: eth0@if12: mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever 15: eth1@if16: mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1 valid_lft forever preferred_lft forever /opt/app # ping 172.17.0.5 PING 172.17.0.5 (172.17.0.5): 56 data bytes 64 bytes from 172.17.0.5: seq=0 ttl=64 time=0.099 ms 64 bytes from 172.17.0.5: seq=1 ttl=64 time=0.065 ms 64 bytes from 172.17.0.5: seq=2 ttl=64 time=0.058 ms 64 bytes from 172.17.0.5: seq=3 ttl=64 time=0.058 ms ^C64 bytes from 172.17.0.5: seq=4 ttl=64 time=0.060 ms 64 bytes from 172.17.0.5: seq=5 ttl=64 time=0.057 ms ^C --- 172.17.0.5 ping statistics --- 6 packets transmitted, 6 packets received, 0% packet loss round-trip min/avg/max = 0.057/0.066/0.099 ms /opt/app # ping node-2 PING node-2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.060 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.061 ms 64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.061 ms 64 bytes from 172.18.0.3: seq=3 ttl=64 time=0.067 ms 64 bytes from 172.18.0.3: seq=4 ttl=64 time=0.062 ms ^C --- node-2 ping statistics --- 5 packets transmitted, 5 packets received, 0% packet loss round-trip min/avg/max = 0.060/0.062/0.067 ms /opt/app # ``` *контейнер можно создавать сразу с подключением к необходимоу сети* ```bash da2001@us:~$ docker run -d --name node-3 --network br2 demo3 daa1712392be54aa26b8f14365d3a9cdfa13cf19ad0524afe1db352d9c3e4e77 ``` [вверх](#top) *** ###### Chapter9 ### Проброс портов Для взаимодействия с приложениями внутри контейнеров из хост системы необходимо выполнить проброс портов в контейнер ```bash da2001@us:~$ docker run -d --name node-4 --network br2 -p 2000:3000 demo3 25dfcaa0e29e7e99f2e93b45dbdbd3268b9781998215343323afceaeefff8c72 ``` порт 2000 хоста пробросили на порт 3000 контейнера ```bash da2001@us:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 25dfcaa0e29e demo3 "docker-entrypoint.s…" 2 minutes ago Up About a minute 0.0.0.0:2000->3000/tcp, :::2000->3000/tcp node-4 ``` *теперь с хоста к контейнеру можно обратиться на порт 2000* ```bash da2001@us:~$ curl localhost:2000 {"eth0":["172.18.0.5"]} ``` *при этом, порт 3000 дотсупен не будет* ```bash da2001@us:~$ curl localhost:3000 curl: (7) Failed to connect to localhost port 3000: Connection refused ``` [вверх](#top) *** ###### Chapter10 ### Драйвера host и null Если дополнительный слой абстракции в виде сети внутри контейнера не нужен, можно создать контейнер с сетью `host`, тогда у контейнера будет IP адрес сети docker0 хоста ```bash da2001@us:~$ docker run -d --name node-5 --network host demo3 e7ea1e790aca5e122883e994e836fae835e8b9f4bd0c02acbc0a691ed7a5a2bc ``` *посмотрим IP адрес хоста* ```bash da2001@us:~$ ip a 1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens18: mtu 1500 qdisc fq_codel state UP qlen 1000 link/ether 8e:eb:ab:c6:9b:ff brd ff:ff:ff:ff:ff:ff inet 192.168.13.254/24 brd 192.168.13.255 scope global dynamic ens18 valid_lft 328sec preferred_lft 328sec inet6 fe80::8ceb:abff:fec6:9bff/64 scope link valid_lft forever preferred_lft forever 3: docker0: mtu 1500 qdisc noqueue state UP link/ether 02:42:50:59:0e:e1 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:50ff:fe59:ee1/64 scope link valid_lft forever preferred_lft forever ``` *подключимся к контейнеру и проверим его IP* ```bash da2001@us:~$ docker exec -it node-5 sh /opt/app # ip a 1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens18: mtu 1500 qdisc fq_codel state UP qlen 1000 link/ether 8e:eb:ab:c6:9b:ff brd ff:ff:ff:ff:ff:ff inet 192.168.13.254/24 brd 192.168.13.255 scope global dynamic ens18 valid_lft 328sec preferred_lft 328sec inet6 fe80::8ceb:abff:fec6:9bff/64 scope link valid_lft forever preferred_lft forever 3: docker0: mtu 1500 qdisc noqueue state UP link/ether 02:42:50:59:0e:e1 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:50ff:fe59:ee1/64 scope link valid_lft forever preferred_lft forever ``` ***IP адреса на хосте и в контейнере идентичны*** Обратная ситуация, когда для работы контейнера сеть не нужна совсем. *в этом случае необходимо создать контейнер с сетью `none`* ```bash da2001@us:~$ docker run -d --name node-6 --network none demo3 9fc34160933654ac7b2ec8ec57c8de9a488de080262d836d3fd97c7ff43d26ac ``` *подключимся к контейнеру и проверим его сетевые интерфейсы* ```bash da2001@us:~$ docker exec -it node-6 sh /opt/app # ip a 1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever ``` [вверх](#top) *** ###### Chapter11 ### DNS Если необходимо в контейнере указать определённый DNS сервер, его можно передать в качестве параметра при создании контейнера ```bash da2001@us:~$ docker run -d --name node-7 --dns 8.8.8.8 demo3 8c0e984de40f504f1a747a5c85fed2c8b7b6e8f5e8379a9bbc0da352ad77612d da2001@us:~$ docker exec -it node-7 sh /opt/app # cat /etc/resolv.conf search da2001.ru nameserver 8.8.8.8 ``` [вверх](#top) *** ###### part4 ## Docker volumes [вверх](#top) ###### Chapter12 ### Устройство и типы volumes - `tmpfs` - данные хранятся внутри контейнера, доступны только в нём и цикл жизни этих данных совпадается с циклом жизни контейнера. Т.е. при остановке/удалении контейнера, данные недоступны; - `volumes` - ***тома хранения данных, рекомендуемый разработчиками Docker способ хранения данных***. В Linux тома находятся по умолчанию в `/var/lib/docker/volumes/`. Другие программы не должны получать к ним доступ напрямую, только через контейнер. * Тома создаются и управляются средствами Docker: командой docker volume create, через указание тома при создании контейнера в Dockerfile или docker-compose.yml. * В контейнере том видно как обычный каталог, который мы определяем в Dockerfile. Тома могут быть с именами или без — безымянным томам Docker сам присвоит имя. * Один том может быть примонтирован одновременно в несколько контейнеров. Когда никто не использует том, он не удаляется, а продолжает существовать. Команда для удаления томов: `docker volume prune`. * Можно выбрать специальный драйвер для тома и хранить данные не на хосте, а на удалённом сервере или в облаке. *Для чего стоит использовать тома в Docker:* + шаринг данных между несколькими запущенными контейнерами; + решение проблемы привязки к ОС хоста; + удалённое хранение данных; + бэкап или миграция данных на другой хост с Docker (для этого надо остановить все контейнеры и скопировать содержимое из каталога тома в нужное место). - `bind mounts` - монтирование каталога хоста. Более простая концепция: файл или каталог с хоста просто монтируется в контейнер. [вверх](#top) *** ###### Chapter13 ### Использование volumes ```bash da2001@us:~$ docker volume --help Usage: docker volume COMMAND Manage volumes Commands: create Create a volume inspect Display detailed information on one or more volumes ls List volumes prune Remove all unused local volumes rm Remove one or more volumes Run 'docker volume COMMAND --help' for more information on a command. ``` *Создадим volume с именем demo* ```bash da2001@us:~$ docker volume create demo demo da2001@us:~$ docker volume ls DRIVER VOLUME NAME local demo ``` ```bash da2001@us:~$ docker volume inspect demo [ { "CreatedAt": "2021-10-31T13:41:28+03:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/demo/_data", "Name": "demo", "Options": {}, "Scope": "local" } ] ``` `/var/lib/docker/volumes/demo` - путь к папке с созданным томом на хосте. Данные контейнера будут храниться в папке `_data` *сейчас эта папка пуста* ```bash da2001@us:~$ sudo ls /var/lib/docker/volumes/demo/_data [sudo] password for da2001: da2001@us:~$ sudo du -hs /var/lib/docker/volumes/demo/_data 4,0K /var/lib/docker/volumes/demo/_data ``` *Создадим 2 контейнера и в качестве аргумента укажем использовать созданный том* ```bash da2001@us:~$ docker run -d --name web-1 -v demo:/data nginx:alpine 1d0eeceefa56d2a60d4deb3c7dadfcf90b75df42e497c6dbd91546510b33ce6b da2001@us:~$ docker run -d --name web-2 -v demo:/data nginx:alpine eb5d5a92157e4bce9c61c8e9735b53217268fa4777354a493dca3765950a93b4 da2001@us:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES eb5d5a92157e nginx:alpine "/docker-entrypoint.…" 56 seconds ago Up 54 seconds 80/tcp web-2 1d0eeceefa56 nginx:alpine "/docker-entrypoint.…" About a minute ago Up About a minute 80/tcp web-1 ``` *подключимся к контейнеру `web-1` и создадим файл в папке `/data`* ```bash da2001@us:~$ docker exec -it web-1 sh / # echo TEST > /data/file / # cat /data/file TEST ``` *проверим наличие файла на хосте* ```bash da2001@us:~$ sudo cat /var/lib/docker/volumes/demo/_data/file TEST ``` *проверим доступность этого файла в контейнере `web-2` и добавим в этот файл еще одну строку* ```bash da2001@us:~$ docker exec -it web-2 sh / # cat /data/file TEST / # echo TEST from web-2 >> /data/file ``` *убедимся, что в контейнере `web-1` в файле также появилась новая строка* ```bash da2001@us:~$ docker exec -it web-1 sh / # cat /data/file TEST TEST from web-2 ``` *При попытке удалить том, который используется контейнерами, получим ошибку* ```bash da2001@us:~$ docker volume rm demo Error response from daemon: remove demo: volume is in use - [1d0eeceefa56d2a60d4deb3c7dadfcf90b75df42e497c6dbd91546510b33ce6b, eb5d5a92157e4bce9c61c8e9735b53217268fa4777354a493dca3765950a93b4] ``` *после остановки и удаления контейнеров, том удаляется без ошибок* ```bash da2001@us:~$ docker stop web-1 web-2 web-1 web-2 da2001@us:~$ docker container prune WARNING! This will remove all stopped containers. Are you sure you want to continue? [y/N] y Deleted Containers: eb5d5a92157e4bce9c61c8e9735b53217268fa4777354a493dca3765950a93b4 1d0eeceefa56d2a60d4deb3c7dadfcf90b75df42e497c6dbd91546510b33ce6b Total reclaimed space: 2.308kB da2001@us:~$ docker volume rm demo demo ``` [вверх](#top) *** ###### Chapter14 ### Volume в Dockerfile Создадим свой образ на основе официального образа nginx, но добавим в Dockerfile данные о необходимом томе. Создадим том, положим в него тестовую html страницу и примонтируем том к контейнеру. 1. Создадим Dockerfile ```dockerfile FROM nginx WORKDIR /usr/share/nginx/html VOLUME ["/usr/share/nginx/html"] EXPOSE 80 ``` 2. Создадим том ```bash da2001@us:~$ docker volume create web web ``` 3. Добавим в созданные том тестовую html страницу ```bash da2001@us:~$ sudo bash -c 'echo "Welcome to static site from volume" > /var/lib/docker/volumes/web/_data/index.html' ``` 4. Создадим образ на основе Dockerfile ```bash da2001@us:~$ docker build -t my-nginx . Sending build context to Docker daemon 145.3MB Step 1/4 : FROM nginx latest: Pulling from library/nginx b380bbd43752: Pull complete fca7e12d1754: Pull complete 745ab57616cb: Pull complete a4723e260b6f: Pull complete 1c84ebdff681: Pull complete 858292fd2e56: Pull complete Digest: sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36 Status: Downloaded newer image for nginx:latest ---> 87a94228f133 Step 2/4 : WORKDIR /usr/share/nginx/html ---> Running in 3a87fe17392b Removing intermediate container 3a87fe17392b ---> 9637854f3611 Step 3/4 : VOLUME ["/usr/share/nginx/html"] ---> Running in f332cde38eef Removing intermediate container f332cde38eef ---> 75291905e821 Step 4/4 : EXPOSE 80 ---> Running in d5faf760b570 Removing intermediate container d5faf760b570 ---> f194075a481b Successfully built f194075a481b Successfully tagged my-nginx:latest ``` ```bash da2001@us:~$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-nginx latest f194075a481b 7 seconds ago 133MB nginx latest 87a94228f133 3 weeks ago 133MB ``` 5. Создадим контейнер на основе нового образа ```bash da2001@us:~$ docker run -d --name web-demo -v web:/usr/share/nginx/html -p 8080:80 my-nginx 97c4b627bd7a7248ffdb33e90a2ec65678a432bb68db9fa16ad27061ae625f59 ``` 6. Теперь убедимся, что том подключился к контейнеру и тестовая html страница доступна из контейнера ```bash da2001@us:~$ curl localhost:8080 Welcome to static site from volume ``` [вверх](#top) *** ###### Chapter15 ### bind mounts `bind mounts` - позволяет примонтировать папку/файл из хостовой системы в контейнер Пример: создадим в текущей директории хоста папку `html` и положим в неё файл `index.html` ```bash da2001@us:~$ mkdir html da2001@us:~$ echo 'Start page from bind mounts' > html/index.html ``` Теперь запустим контейнер и примонтируем в него созданную папку ```bash da2001@us:~$ docker run -d --name web-2 -v /home/da2001/html:/usr/share/nginx/html -p 8080:80 nginx ddeefdec9653793acb01b2c25ee412fb60a7b5cdb42330d211113c3e299d6c1d ``` Проверим работу nginx запущенного контейнера - должна открыться созданная ранее html страница ```bash da2001@us:~$ curl localhost:8080 Start page from bind mounts ``` [вверх](#top) *** ###### Chapter16 ### tmpfs `tmpfs` - указанные данные этого типа существуют только пока контейнер работает, после остановки контейнера данные удаляются Для монтирования можно использовать 2 вида записи ```bash da2001@us:~$ docker run -d --name demo --tmpfs /vardir -p 8080:80 nginx ```` или ```bash da2001@us:~$ docker run -d --name demo --mount type=tmpfs,dectination=/vardir -p 8080:80 nginx ``` *второй тип записи применим и для других типов монтирования* [вверх](#top) *** ###### Chapter17 ### Копирование данных Если возникает необходимость скопировать какие-то данные в контейнер или из него, можно воспользоваться командой `docker cp` ```bash da2001@us:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ddeefdec9653 nginx "/docker-entrypoint.…" 20 minutes ago Up 20 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp web-2 ``` *скопировать папку html хоста в папку html в контейнере* ```bash da2001@us:~/html$ docker cp /home/da2001/html web-2:/usr/share/nginx/html ``` *скопировать содержимое папки html хоста в папку html в контейнере* ```bash da2001@us:~/html$ docker cp /home/da2001/html/. web-2:/usr/share/nginx/html ``` *обратная задача - скопировать данные из контейнера на хост* ``` da2001@us:~/html$ docker cp web-2:/usr/share/nginx/html /home/da2001/html ``` [вверх](#top) *** ###### part5 ## Docker compose [вверх](#top) ###### Chapter18 ### YAML `yaml` - считается наиболее удобным для восприятия человеком среди подобных форматов: yaml, xml, json. В основе лежит принцип ключ: значение и отступы для создания структуры подчинённости. Стандартный размер отступа - 2 пробела. ```yaml # comment # text name: test name2: "test \n" name3: 'test 234' # digit age: 35 version: 2.3 ``` Логические значения могут быть заданы тремя равнозначными способами ```yaml # boolean isDev: True isDev2: False isDev3: on isDev4: off isDev5: yes isDev6: no ``` Описание объектов ```yaml user: name: Василий age: 25 position: engineer ``` Списки ```yaml users: - name: Дмитрий age: 34 position: administrator - name: Анна age: 24 position: accountant ``` *альтернативная запись списков без отступов* ```yaml users: - name: Дмитрий age: 34 position: administrator - name: Анна age: 24 position: accountant ``` *списки без ключей* ```yaml users: - Николай - Андрей ``` *описание списков в виде json* ```yaml versions: [1.7, 2.3, 'latest'] ``` Описание строк *многострочная строка* ```yaml multiline: | Эта строка сохранит своё форматирование и будет отображаться в несколько строк ``` *длинная строка без переноса* ```yaml singleline: > Это очень длинная строка, но она будет отображена без использования переносов ``` Если в рамках одного yaml файла необходимо описать несколько независимых сущностей, их можно отделить друг от друга с помощью `---` [вверх](#top) *** ###### Chapter19 ### Пример файла docker-compose.yml ```yaml version: '3.1' services: wordpress: image: wordpress restart: always ports: - 8080:80 depends_on: - db environment: WORDPRESS_DB_NAME: wp_db WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: db_user WORDPRESS_DB_PASSWORD: wp_db_pass volumes: ["./:/var/www/html"] db: image: mysql:5.7 restart: always environment: MYSQL_DATABASE: wp_db MYSQL_USER: db_user MYSQL_PASSWORD: wp_db_pass MYSQL_ROOT_PASSWORD: db_root_pass volumes: - db:/var/lib/mysql volumes: db: ``` Эта конфигурация запустит 2 контенера: mysql и wordpress **Разбор параметров** `version: '3.1'` - в зависимости от используемой версии, compose может принимать или нет некоторые директивы, также зависит от установленной версии docker *Зависимость версии compose от версии docker указана в таблице на сайте с документацией. Также объясняются возможные директивы, которые могут быть описаны в файле docker-compose.yml* [*>> документация по compose <<*](https://docs.docker.com/compose/compose-file/compose-file-v3/) *Каждая директива может быть описана в краткой и полной форме. Формы записи равнозначны, полная запись может быть проще для восприятия, но длиннее в записи. В данном примере будет рассмотрена краткая форма описания.* `services:` - из названия понятно, что в этой секции описаны используемые сервисы. Указаны образы, на основе которых будут запущены контейнеры и параметры запуска: хранилища, сеть, переменные и пр. `wordpress:` - произвольное название сервиса, который собираемся запустить `image:` - указан образ, на основе которого будет запущен контейнер. Может быть указан с конкретной версией `mysql:5.7`, `wordpress:latest`, так и без указания версии `wordpress`, в этом случае будет подставлен тег `latest` `restart:` - опция перезапуска контейнера. Может принимать значения: `"no"`, `always`, `on-failure`, `unless-stopped`. Игнорируется при запуске в swarm. `ports:` - проброс портов. В данном примере - на порт 8080 хоста будет проброшен порт 80 контейнера. `depends_on:` - зависимость при запуске. Если параметр указан, контейнер этой секции будет запущен после того, который указан в параметре. В данном примере - `wordpress` будет запущен только после успешного запуска `db`. `environment:` - переменные, которые необходимо передать в контейнер в формате `ключ: значение`. Необходимые переменные для успешного запуска, обычно указаны на странице описания образа в docker hub. `volumes:` - в секции services описывает тома, которые будут использованы в контейнере. В контейнер можно подключить созданный в docker том или выполнить монтирование директории или отдельного файла из хоста. Используется, когда необходимо сохранить данные после остановки/удаления контейнера, например базу данных, конфигурационные файлы, контент сайта и т.д. `volumes:` - в отдельной секции описывает название томов, которые необходимо создать посредством docker для использования в контейнерах. В данном примере не описано, но часто применяется на практике: `networks:` - в секции services описывает сеть, к которой должен подключиться контейнер, если секция указана, её необходимо обязательно создать. Кроме ситуации, в которой контейнеру запрещается использовать сеть: ```yaml app: build: ./app networks: - none ``` или когда используется сеть хоста ```yaml app: build: ./app networks: - host ``` `networks:` - в отдельной секции описывает сети, которые необходимо создать для использования в контейнерах. Для режимов сети без дополнительных плагинов, используются три драйвера: `bridge` - контейнерам выделяются IP адреса из одной подсети, `host` - контейнеры используют сеть хоста, `none` - контейнеры не используют сеть. [вверх](#top) *** ###### Chapter20 ### Профили Иногда возникают ситуации, когда при запуске compose нет необходимости стартовать все сервисы, например, в целях тестирования или отладки. В таких ситуациях можно создать профили и добавить необходимые сервисы в эти профили. В этом случае, compose можно запускать явно указав какие профили необходимо запустить. ```yaml wordpress: image: wordpress restart: always ports: - 8080:80 profile: - wordpress_1 ``` Теперь, чтобы запустить контейнер с указанным профилем, его необходимо явно указать при запуске ```bash da2001@us:~/wp$ docker-compose --profile wordpress_1 up -d ``` *этой командой будут запущены контейнеры у которых указан профиль `wordpress_1` и не указан профиль вообще.* Если необходимо запустить контейнеры с несколькими профилями, каждый необходимо отдельно указать ```bash da2001@us:~/wp$ docker-compose --profile wordpress_1 --profile database up -d ``` Кроме этого, может встречаться и другая запись, когда перед стартом через запятую передаются все необходимые профили в виде переменных окружения ```bash da2001@us:~/wp$ COMPOSE_PROFILES=wordpress_1 docker-compose up -d ``` Стоит иметь ввиду, если один сервис зависит от другого - указана директива `depends_on`, нужно внимательно использовать профили. Например, если взять предыдущий пример compose и добавить в секцию сервиса `db` профиль, а в секции сервиса `wordpress` профиль указан не будет: ```yaml services: wordpress: image: wordpress restart: always ports: - 8080:80 depends_on: - db db: image: mysql:5.7 restart: always profile: - database ``` команда `docker-compose up -d` завершится ошибкой, т.к. при таком запуске будут стартовать только контейнеры без указанного профиля, а в этом примере - контейнер без профиля зависит от успешного запуска контейнера с указанным профилем. [вверх](#top) *** ###### Chapter21 ### Запуск отдельных сервисов При использовании compose можно запустить отдельные сервисы явно указав это в команде запуска ```bash da2001@us:~/wp$ docker-compose run wordpress -d ``` *НО, в нашем примере будут запущены оба контейнера, т.к. запуск wordpress зависит от успешного запуска db* Кроме этого стоит брать во внимание особенности запуска при использовании профилей. [вверх](#top) *** ###### Chapter22 ### Переменные окружения Переменные окружения удобно использовать для передачи значений в запускаемые контейнеры, например для указания имён контейнеров или передачи значений имени, пароля, названия базы данных и пр. По-умолчанию, compose считывает значения из файла `.env`, находящегося в той же директории что и `docker-compose.yml`. Например: ```bash da2001@us:~/wp$ cat .env wp_container_name=wp db_container_name=db db_name=wp_db db_root_pass=db_root_pass db_user=db_user db_pass=wp_db_pass ``` ```bash da2001@us:~/wp$ cat docker-compose.yml version: '3.1' services: wordpress: image: wordpress container_name: "${wp_container_name}" restart: always ports: - 8080:80 depends_on: - db environment: WORDPRESS_DB_NAME: "${db_name}" WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: "${db_user}" WORDPRESS_DB_PASSWORD: "${db_pass}" volumes: - wp:/var/www/html db: image: mysql:5.7 container_name: "${db_container_name}" restart: always environment: MYSQL_DATABASE: "${db_name}" MYSQL_USER: "${db_user}" MYSQL_PASSWORD: "${db_pass}" MYSQL_ROOT_PASSWORD: "${db_root_pass}" volumes: - db:/var/lib/mysql volumes: db: wp: ``` Если файл с описанием переменных называется не `.env`, тогда при запуске compose нужно это явно указать ```bash da2001@us:~/wp$ docker-compose --env-file .env-web up -d ``` Также можно указать для каждого сервиса свой файл с переменными окружения и указать в нём необходимые имена и значения переменных ```bash da2001@us:~/wp$ cat docker-compose.yml version: '3.1' services: wordpress: image: wordpress container_name: "${wp_container_name}" restart: always ports: - 8080:80 depends_on: - db env_file: - .env-wp volumes: - wp:/var/www/html db: image: mysql:5.7 container_name: "${db_container_name}" restart: always env_file: - .env-db volumes: - db:/var/lib/mysql volumes: db: wp: ``` Перед запуском compose будет полезным посмотреть верно ли подставились переменные, для этого используется следующая команда: ```bash docker-compose config ``` или если указано своё имя для файла с переменными ```bash docker-compose --env-file .env-web config ``` в результате на экране будет показан compose с уже подставленными значениями переданных переменных [вверх](#top) *** ###### Chapter23 ### Объединение конфигураций Описание конфигурации можно разделить на несколько файлов, например для возможности запуска с разными параметрами `docker-compose.yml` ```yaml version: '3.1' services: wordpress: image: wordpress restart: always depends_on: - db volumes: ["./:/var/www/html"] db: image: mysql:5.7 restart: always environment: MYSQL_DATABASE: wp_db MYSQL_USER: db_user MYSQL_PASSWORD: wp_db_pass MYSQL_ROOT_PASSWORD: db_root_pass volumes: - db:/var/lib/mysql volumes: db: ``` `docker-compose.wp.yml` ```yaml version: '3.1' services: wordpress: ports: - 8080:80 environment: WORDPRESS_DB_NAME: wp_db WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: db_user WORDPRESS_DB_PASSWORD: wp_db_pass ``` Описание проброса портов и переменные перенесли в отдельный файл. Теперь запускать эти контейнеры можем используя как и раньше, но без проброса портов и передачи переменных в контейнер `docker-compose up -d`. Так и объединив оба конфигурационных файла для полного запуска ```bash docker-compose -f docker-compose.yml -f docker-compose.wp.yml up -d ``` Также можно добавить ссылку на другой конфиг в самом описании `docker-compose.yml` ```yaml version: '3.1' services: wordpress: extends: file: docker-compose.wp.yml service: wordpress depends_on: - db db: image: mysql:5.7 restart: always environment: MYSQL_DATABASE: wp_db MYSQL_USER: db_user MYSQL_PASSWORD: wp_db_pass MYSQL_ROOT_PASSWORD: db_root_pass volumes: - db:/var/lib/mysql volumes: db: ``` `docker-compose.wp.yml` ```yaml version: '3.1' services: wordpress: image: wordpress restart: always ports: - 8080:80 environment: WORDPRESS_DB_NAME: wp_db WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: db_user WORDPRESS_DB_PASSWORD: wp_db_pass volumes: ["./:/var/www/html"] ``` В этом случае перечислять конфигурационные файлы при запуске не нужно. [вверх](#top) *** ```bash git add . && git commit -m 'mod docker' && git push ```