notes/docker.md

60 KiB
Raw Blame History

top

Docker - справка


Базовые понятия Docker

Docker image

Сеть в Docker

Docker volumes

Docker compose


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 страницу и примонтируем том к контейнеру.

  1. Создадим Dockerfile
FROM nginx
WORKDIR /usr/share/nginx/html
VOLUME ["/usr/share/nginx/html"]
EXPOSE 80
  1. Создадим том
da2001@us:~$ docker volume create web
web
  1. Добавим в созданные том тестовую html страницу
da2001@us:~$ sudo bash -c 'echo "Welcome to static site from volume" > /var/lib/docker/volumes/web/_data/index.html'
  1. Создадим образ на основе 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
  1. Создадим контейнер на основе нового образа
da2001@us:~$ docker run -d --name web-demo -v web:/usr/share/nginx/html -p 8080:80 my-nginx
97c4b627bd7a7248ffdb33e90a2ec65678a432bb68db9fa16ad27061ae625f59
  1. Теперь убедимся, что том подключился к контейнеру и тестовая 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

>> документация по compose <<

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

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