60 KiB
top
Docker - справка
- Устройство и типы volumes
- Использование volumes
- Volume в Dockerfile
- bind mounts
- tmpfs
- Копирование данных
docker --help
part1
Базовые понятия Docker
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
- удалить все остановленные контейнеры
Chapter2
Логи и статистика работы
docker stats
- статистика по используемым ресурсам запущенных контейнеров
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
da2001@us:~$ docker inspect my-web -f '{{.State.Status}}'
running
форматирование и фильтрация вывода доступна во многих командах, например
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
или
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
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
da2001@us:~$ docker ps --filter
ancestor= exited= health= is-task= name= publish= status=
before= expose= id= label= network= since= volume=
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
- отображать логи в реальном времени
Chapter3
Команды в контейнере
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: <name|uid>[:<group|gid>])
-w, --workdir string Working directory inside the container
В контейнере mongo
перейти в директорию /root
и выполнить команду pwd
da2001@us:~$ docker exec -w /root mongo pwd
/root
Задать переменную в контейнере и вывести список всех переменных окружения, доступных в контейнере
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
Покдлючиться к оболочке контейнера в интерактивном режиме
da2001@us:~$ docker exec -it mongo bash
root@08d3dc4c1595:/#
Выполнить в контейнере команду mongo --version
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'
- перенаправить вывод в файл в контейнере
part2
Docker image
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
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
вывести определённую колонку, название колонки с большой буквы
da2001@us:~$ docker image ls --format {{.Tag}}
latest
latest
da2001@us:~$ docker image ls --format {{.Repository}}
mongo
nginx
если образов много, вывод можно отфильтровать
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
- удалить все образы без тега
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>[:<group>]
USER <UID>[:<GID>]
- устанавливает имя пользователя и группу пользователей при запуске образа
WORKDIR /var/lib/
- установит рабочий каталог. Он создаст каталог, если его нет
Chapter6
Создание образа
docker build --help
Пример сборки образа
docker build -f ./apps/api/Dockerfile -t test:latest .
-f
- указать путь к Dockerfile, если он не в текущей директории
-t
- указать имя образа с тегом, если тег не будет указан, по-умолчанию присвоится :latest
.
- брать контекст для образа из текущей директории
part3
Сеть в Docker
-
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
Устройство сети
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
Отобразить имеющиеся сети
da2001@us:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
222826f8b512 bridge bridge local
5f64c40ea352 host host local
79350884305f none null local
Создать сеть типа bridge
с именем br2
da2001@us:~$ docker network create br2
40ff1259ca7e103736c74da0309d6fde5d8439d6844d6f5997b216912d05a705
или
da2001@us:~$ docker network create --driver=bridge br2
По-умолчанию, всегда создаётся мост
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
пример создания оверлей-сети
da2001@us:~$ docker network create --driver overlay overlay-net
для создания оверлей-сети необходимо активировать docker-swarm
Chapter8
Драйвер bridge
Сеть с драйвером bridge создаётся по-умолчанию.
Контейнеры, использующие одну сеть могут видеть друг друга по выделенному им IP адресу.
Посмотреть детальную информацию о сети можно с помощью команды inspect
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": {}
}
]
в длинном выводе указана вся информация о сети, её адресации и контейнерах, которые используют эту сеть.
Чтобы контейнеры могли обращаться друг к другу по имени, необходимо создать новую сеть и добавить в неё эти контейнеры
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
da2001@us:~$ docker exec -it node-1 sh
/opt/app # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> 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: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> 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 #
контейнер можно создавать сразу с подключением к необходимоу сети
da2001@us:~$ docker run -d --name node-3 --network br2 demo3
daa1712392be54aa26b8f14365d3a9cdfa13cf19ad0524afe1db352d9c3e4e77
Chapter9
Проброс портов
Для взаимодействия с приложениями внутри контейнеров из хост системы необходимо выполнить проброс портов в контейнер
da2001@us:~$ docker run -d --name node-4 --network br2 -p 2000:3000 demo3
25dfcaa0e29e7e99f2e93b45dbdbd3268b9781998215343323afceaeefff8c72
порт 2000 хоста пробросили на порт 3000 контейнера
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
da2001@us:~$ curl localhost:2000
{"eth0":["172.18.0.5"]}
при этом, порт 3000 дотсупен не будет
da2001@us:~$ curl localhost:3000
curl: (7) Failed to connect to localhost port 3000: Connection refused
Chapter10
Драйвера host и null
Если дополнительный слой абстракции в виде сети внутри контейнера не нужен, можно создать контейнер с сетью host
, тогда у контейнера будет IP адрес сети docker0 хоста
da2001@us:~$ docker run -d --name node-5 --network host demo3
e7ea1e790aca5e122883e994e836fae835e8b9f4bd0c02acbc0a691ed7a5a2bc
посмотрим IP адрес хоста
da2001@us:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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
da2001@us:~$ docker exec -it node-5 sh
/opt/app # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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
da2001@us:~$ docker run -d --name node-6 --network none demo3
9fc34160933654ac7b2ec8ec57c8de9a488de080262d836d3fd97c7ff43d26ac
подключимся к контейнеру и проверим его сетевые интерфейсы
da2001@us:~$ docker exec -it node-6 sh
/opt/app # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> 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
Chapter11
DNS
Если необходимо в контейнере указать определённый DNS сервер, его можно передать в качестве параметра при создании контейнера
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
part4
Docker volumes
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
- монтирование каталога хоста. Более простая концепция: файл или каталог с хоста просто монтируется в контейнер.
Chapter13
Использование volumes
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
da2001@us:~$ docker volume create demo
demo
da2001@us:~$ docker volume ls
DRIVER VOLUME NAME
local demo
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
сейчас эта папка пуста
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 контейнера и в качестве аргумента укажем использовать созданный том
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
da2001@us:~$ docker exec -it web-1 sh
/ # echo TEST > /data/file
/ # cat /data/file
TEST
проверим наличие файла на хосте
da2001@us:~$ sudo cat /var/lib/docker/volumes/demo/_data/file
TEST
проверим доступность этого файла в контейнере web-2
и добавим в этот файл еще одну строку
da2001@us:~$ docker exec -it web-2 sh
/ # cat /data/file
TEST
/ # echo TEST from web-2 >> /data/file
убедимся, что в контейнере web-1
в файле также появилась новая строка
da2001@us:~$ docker exec -it web-1 sh
/ # cat /data/file
TEST
TEST from web-2
При попытке удалить том, который используется контейнерами, получим ошибку
da2001@us:~$ docker volume rm demo
Error response from daemon: remove demo: volume is in use - [1d0eeceefa56d2a60d4deb3c7dadfcf90b75df42e497c6dbd91546510b33ce6b, eb5d5a92157e4bce9c61c8e9735b53217268fa4777354a493dca3765950a93b4]
после остановки и удаления контейнеров, том удаляется без ошибок
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
Chapter14
Volume в Dockerfile
Создадим свой образ на основе официального образа nginx, но добавим в Dockerfile данные о необходимом томе. Создадим том, положим в него тестовую html страницу и примонтируем том к контейнеру.
- Создадим Dockerfile
FROM nginx
WORKDIR /usr/share/nginx/html
VOLUME ["/usr/share/nginx/html"]
EXPOSE 80
- Создадим том
da2001@us:~$ docker volume create web
web
- Добавим в созданные том тестовую html страницу
da2001@us:~$ sudo bash -c 'echo "Welcome to static site from volume" > /var/lib/docker/volumes/web/_data/index.html'
- Создадим образ на основе Dockerfile
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
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
- Создадим контейнер на основе нового образа
da2001@us:~$ docker run -d --name web-demo -v web:/usr/share/nginx/html -p 8080:80 my-nginx
97c4b627bd7a7248ffdb33e90a2ec65678a432bb68db9fa16ad27061ae625f59
- Теперь убедимся, что том подключился к контейнеру и тестовая html страница доступна из контейнера
da2001@us:~$ curl localhost:8080
Welcome to static site from volume
Chapter15
bind mounts
bind mounts
- позволяет примонтировать папку/файл из хостовой системы в контейнер
Пример: создадим в текущей директории хоста папку html
и положим в неё файл index.html
da2001@us:~$ mkdir html
da2001@us:~$ echo 'Start page from bind mounts' > html/index.html
Теперь запустим контейнер и примонтируем в него созданную папку
da2001@us:~$ docker run -d --name web-2 -v /home/da2001/html:/usr/share/nginx/html -p 8080:80 nginx
ddeefdec9653793acb01b2c25ee412fb60a7b5cdb42330d211113c3e299d6c1d
Проверим работу nginx запущенного контейнера - должна открыться созданная ранее html страница
da2001@us:~$ curl localhost:8080
Start page from bind mounts
Chapter16
tmpfs
tmpfs
- указанные данные этого типа существуют только пока контейнер работает, после остановки контейнера данные удаляются
Для монтирования можно использовать 2 вида записи
da2001@us:~$ docker run -d --name demo --tmpfs /vardir -p 8080:80 nginx
или
da2001@us:~$ docker run -d --name demo --mount type=tmpfs,dectination=/vardir -p 8080:80 nginx
второй тип записи применим и для других типов монтирования
Chapter17
Копирование данных
Если возникает необходимость скопировать какие-то данные в контейнер или из него, можно воспользоваться командой docker cp
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 в контейнере
da2001@us:~/html$ docker cp /home/da2001/html web-2:/usr/share/nginx/html
скопировать содержимое папки html хоста в папку html в контейнере
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
part5
Docker compose
Chapter18
YAML
yaml
- считается наиболее удобным для восприятия человеком среди подобных форматов: yaml, xml, json.
В основе лежит принцип ключ: значение и отступы для создания структуры подчинённости.
Стандартный размер отступа - 2 пробела.
# comment
# text
name: test
name2: "test \n"
name3: 'test 234'
# digit
age: 35
version: 2.3
Логические значения могут быть заданы тремя равнозначными способами
# boolean
isDev: True
isDev2: False
isDev3: on
isDev4: off
isDev5: yes
isDev6: no
Описание объектов
user:
name: Василий
age: 25
position: engineer
Списки
users:
- name: Дмитрий
age: 34
position: administrator
- name: Анна
age: 24
position: accountant
альтернативная запись списков без отступов
users:
- name: Дмитрий
age: 34
position: administrator
- name: Анна
age: 24
position: accountant
списки без ключей
users:
- Николай
- Андрей
описание списков в виде json
versions: [1.7, 2.3, 'latest']
Описание строк многострочная строка
multiline: |
Эта строка сохранит своё
форматирование и будет
отображаться в несколько строк
длинная строка без переноса
singleline: >
Это очень длинная строка,
но она будет отображена без
использования переносов
Если в рамках одного yaml файла необходимо описать несколько независимых сущностей, их можно отделить друг от друга с помощью ---
Chapter19
Пример файла docker-compose.yml
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
Каждая директива может быть описана в краткой и полной форме. Формы записи равнозначны, полная запись может быть проще для восприятия, но длиннее в записи. В данном примере будет рассмотрена краткая форма описания.
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 описывает сеть, к которой должен подключиться контейнер, если секция указана, её необходимо обязательно создать.
Кроме ситуации, в которой контейнеру запрещается использовать сеть:
app:
build: ./app
networks:
- none
или когда используется сеть хоста
app:
build: ./app
networks:
- host
networks:
- в отдельной секции описывает сети, которые необходимо создать для использования в контейнерах. Для режимов сети без дополнительных плагинов, используются три драйвера: bridge
- контейнерам выделяются IP адреса из одной подсети, host
- контейнеры используют сеть хоста, none
- контейнеры не используют сеть.
Chapter20
Профили
Иногда возникают ситуации, когда при запуске compose нет необходимости стартовать все сервисы, например, в целях тестирования или отладки. В таких ситуациях можно создать профили и добавить необходимые сервисы в эти профили. В этом случае, compose можно запускать явно указав какие профили необходимо запустить.
wordpress:
image: wordpress
restart: always
ports:
- 8080:80
profile:
- wordpress_1
Теперь, чтобы запустить контейнер с указанным профилем, его необходимо явно указать при запуске
da2001@us:~/wp$ docker-compose --profile wordpress_1 up -d
этой командой будут запущены контейнеры у которых указан профиль wordpress_1
и не указан профиль вообще.
Если необходимо запустить контейнеры с несколькими профилями, каждый необходимо отдельно указать
da2001@us:~/wp$ docker-compose --profile wordpress_1 --profile database up -d
Кроме этого, может встречаться и другая запись, когда перед стартом через запятую передаются все необходимые профили в виде переменных окружения
da2001@us:~/wp$ COMPOSE_PROFILES=wordpress_1 docker-compose up -d
Стоит иметь ввиду, если один сервис зависит от другого - указана директива depends_on
, нужно внимательно использовать профили. Например, если взять предыдущий пример compose и добавить в секцию сервиса db
профиль, а в секции сервиса wordpress
профиль указан не будет:
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
завершится ошибкой, т.к. при таком запуске будут стартовать только контейнеры без указанного профиля, а в этом примере - контейнер без профиля зависит от успешного запуска контейнера с указанным профилем.
Chapter21
Запуск отдельных сервисов
При использовании compose можно запустить отдельные сервисы явно указав это в команде запуска
da2001@us:~/wp$ docker-compose run wordpress -d
НО, в нашем примере будут запущены оба контейнера, т.к. запуск wordpress зависит от успешного запуска db
Кроме этого стоит брать во внимание особенности запуска при использовании профилей.
Chapter22
Переменные окружения
Переменные окружения удобно использовать для передачи значений в запускаемые контейнеры, например для указания имён контейнеров или передачи значений имени, пароля, названия базы данных и пр.
По-умолчанию, compose считывает значения из файла .env
, находящегося в той же директории что и docker-compose.yml
.
Например:
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
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 нужно это явно указать
da2001@us:~/wp$ docker-compose --env-file .env-web up -d
Также можно указать для каждого сервиса свой файл с переменными окружения и указать в нём необходимые имена и значения переменных
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 будет полезным посмотреть верно ли подставились переменные, для этого используется следующая команда:
docker-compose config
или если указано своё имя для файла с переменными
docker-compose --env-file .env-web config
в результате на экране будет показан compose с уже подставленными значениями переданных переменных
Chapter23
Объединение конфигураций
Описание конфигурации можно разделить на несколько файлов, например для возможности запуска с разными параметрами
docker-compose.yml
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
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
.
Так и объединив оба конфигурационных файла для полного запуска
docker-compose -f docker-compose.yml -f docker-compose.wp.yml up -d
Также можно добавить ссылку на другой конфиг в самом описании
docker-compose.yml
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
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"]
В этом случае перечислять конфигурационные файлы при запуске не нужно.
git add . && git commit -m 'mod docker' && git push