notes/docker.md

1487 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

###### 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: <name|uid>[:<group|gid>])
-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>[:<group>]`
`USER <UID>[:<GID>]` - устанавливает имя пользователя и группу пользователей при запуске образа
`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: <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 #
```
*контейнер можно создавать сразу с подключением к необходимоу сети*
```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: <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*
```bash
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`*
```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: <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
```
[вверх](#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`.
* Можно выбрать специальный драйвер для тома и хранить данные не на хосте, а на удалённом сервере или в облаке.
*<u>Для чего стоит использовать тома в Docker:</u>*
+ шаринг данных между несколькими запущенными контейнерами;
+ решение проблемы привязки к ОС хоста;
+ удалённое хранение данных;
+ бэкап или миграция данных на другой хост с 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
```