Перейти к содержимому

Docker как пробросить порты

  • автор:

Как настроить маппинг портов между хостом и Docker-контейнером

Как настроить маппинг портов между хостом и Docker-контейнером главное изображение

Для взаимодействия с Docker-контейнером с хоста нужно настроить маппинг портов. Разберемся, почему это важно, и рассмотрим несколько способов добавления нового маппинга после запуска Docker-контейнера.

Это адаптированный перевод статьи Assigning a Port Mapping to a Running Docker Container из блога образовательного проекта Baeldung.

Эта статья предназначена для разработчиков, которые знают Docker хотя бы на базовом уровне. Если вы еще не знакомы с этой технологией и вам интересно с ней разобраться, пройдите курс по Docker на Хекслете.

Зачем нужен маппинг

По умолчанию Docker запускает сервис изолированно — то есть все порты между хостом и Docker-контейнером закрыты. Для того, чтобы получить доступ к сервису с хоста или из внешней сети, нужно использовать сопоставление портов или маппинг.

Маппинг нужен для того, чтобы все запросы, проходящие через порт хоста, перенаправлялись в Docker-контейнер. Другими словами, сопоставление портов делает процессы внутри контейнера доступными извне.

При запуске нового Docker-контейнера с помощью команды docker run можно сопоставить порты опцией —publish или -p :

-d -p 81:80 --name httpd-container httpd 

Эта команда запускает Docker-контейнер httpd (HTTP-сервер Apache) и маппинг 81 порта хоста с 80 портом внутри Docker-контейнера. Стоит отметить, что по умолчанию сервер httpd прослушивает порт 80.

Теперь доступ к приложению можно получить, используя порт 81 на хосте:

It works!

Важно отметить, что выполнять маппинг для всех Docker-контейнеров необязательно. Например, в случаях, когда нужно сохранить службы Docker-контейнера закрытыми или видимыми только родственным контейнерам в той же сети Docker.

Бесплатные курсы по программированию в Хекслете

  • Освойте азы современных языков программирования
  • Изучите работу с Git и командной строкой
  • Выберите себе профессию или улучшите навыки

Как назначить маппинг работающему Docker-контейнеру

Рассмотрим ситуацию, в которой маппинг не был задан при запуске Docker-контейнера или был задан с ошибкой. Получить доступ к сервису через TCP/IP-соединение на хосте не получится, но есть три способа решить эту проблему:

  • Остановить работающий Dockerконтейнер, а затем создать и запустить новый c оригинальным docker images
  • Сделать docker commit работающего Docker-контейнера, создать новый и запустите его через docker images , сохранив состояние
  • Добавить новый маппинг, используя файлы конфигурации Docker

Разберем каждый способ подробнее.

Освойте DevOps на интенсиве Хекслета Научитесь автоматизировать окружение, деплоить приложения одной кнопкой одновременно на любое количество машин и разворачивать облачный кластер на Digital Ocean или Yandex Cloud.

Перезапуск Docker-контейнера

Это самое технически простое решение: работающий Docker-контейнер удаляется, а вместо него создается новый, запущенный из образа. При создании Docker-контейнера сопоставляются порты.

Хотя это самый простой способ, он подходит не во всех ситуациях. Например, решение не подойдет в ситуации, когда внутри Docker-контейнера уже выполнены некоторые операции: установились зависимости, запустились процессы или обновились файлы. Если восстановить такой Docker-контейнер из образа, все эти изменения будут потеряны.

Стоит отметить, что важные данные лучше хранить в Docker volumes, чтобы упростить замену Docker-контейнеров.

Повторный запуск из docker commit

Этот подход предполагает создание нового образа на базе существующего Docker-контейнера. Затем образ можно использовать для запуска нового Docker-контейнера с открытыми нужными портами.

Поскольку мы фиксируем состояние существующего Docker-контейнера оно становится доступно в новом образе.

Попробуем реализовать этот способ. Сначала остановим Docker-контейнер и создадим его образ с помощью команды docker commit :

# Останавливаем контейнер docker stop httpd-container # Команда напечатает на экране название остановленного контейнера httpd-container # Создаем образ на основе существующего контейнера docker commit httpd-container httpd-image # Хэш образа sha256:33da33fcad051c90ac9b7dea9b2dbda442767e05ddebd8d6db8ac6893ef4ef40 

Затем удалим Docker-контейнер и заново запустим его из образа. На этом этапе важно убедиться, что маппинг настроен верно:

# Удаляем контейнер docker rm httpd-container # Команда напечатает на экране название удалённого контейнера httpd-container # Запускаем контейнер docker run -d -p 83:80 --name httpd-container httpd-image # На экране выведится хеш запущенного контейнера dd2535c477ad74e80b3642abca9055efacb89eaf14572b91f91bf20cd3f0cbf3 

Перенастройка Docker-контейнера без его удаления

В подходах, которые обсуждались выше, речь шла об удалении существующего Docker-контейнера и создании нового. Хотя новый Docker-контейнер работает также, его метаданные полностью отличаются.

Рассмотрим способ, как настроить маппинг в уже существующем Docker-контейнере. Сначала запустим новый без сопоставления портов:

-d --name httpd-container httpd a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7 # Команда выведет запущенные контейнеры docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a0ed1c9fc60c httpd "httpd-foreground" 1 second ago Up 1 second 80/tcp httpd-container 

Команда docker run возвращает полный идентификатор Docker длиной 64 символа. Другой способ получить его — команда docker inspect:

$ docker inspect --format=">" httpd-container a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7 

Идентификатор пригодится для поиска файла конфигурации Docker.

Остановка Docker-контейнера и службы Docker

Первый шаг по перенастройке работающего Docker-контейнера — его остановка. Выполнить ее можно командой docker stop :

Для обновления конфигурационных файлов Docker-контейнера нужно остановить и службу Docker. Стоит отметить, что это действие приведет к отключению всех Docker-контейнеров до тех пор, пока процесс настройки не закончится.

# Останавливаем службу Docker systemctl stop docker 

Читайте также: Как сохранять фокус на протяжении всего обучения: советы от Хекслета

Как найти конфигурационные файлы

Все конфигурационные файлы, которые относятся к Docker-контейнерам, образам, томам и сетям Docker, можно найти в каталоге /var/lib/docker . Стоит отметить, что на Windows и MacOS путь к каталогу отличается.

В данном случае интерес представляют два файла: hostconfig.json и config.v2.json . Найти их можно в следующем каталоге:

В данном случае ID — полный идентификатор Docker-контейнера, который мы получили ранее:
Конфигурационные файлы можно найти в следующем каталоге:
$ ls /var/lib/docker/containers/a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7/ a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7-json.log checkpoints config.v2.json hostconfig.json hostname hosts mounts resolv.conf resolv.conf.hash 

Обновление конфигурационных файлов

В первую очередь стоит обновить файл hostconfig.json . Для этого найдем ключ привязки портов в этом файле. Поскольку при запуске Docker-контейнера маппинг не был настроен, поле ключа PortBindings Docker-контейнера будет пустым:

 . . "PortBindings": <>, . . > 

Следующий шаг — назначение 82 порта хоста 80 порту Docker-контейнера httpd-container . Для этого обновим привязки портов в файле JSON:

 . . "PortBindings": "80/tcp":["HostIp":"","HostPort":"82">]>, . . > 

Как только маппинг выполнен, нужно открыть порт 80 Docker-контейнера в файле config.v2.json . Для этого добавим поле открытых портов (если его еще нет) в ключ конфигурации:

 . "Config":  . "ExposedPorts":  "80/tcp":<> >, . > > 

Таким образом мы сообщаем демону Docker, что Docker-контейнер прослушивает 80 порт в этом сетевом интерфейсе.

Можно открыть несколько портов, передав значения в виде пар ключ-значение, разделенных запятыми:

 . "Config":  . "ExposedPorts":  "80/tcp":<>, "82/tcp":<>, "8080/tcp":<> >, . > > 

Проверка изменений

Проверка изменений состоит из нескольких шагов. Сначала запустим службу Docker:

Теперь запустим httpd-контейнер и проверим маппинг портов с помощью команды docker ps :

"httpd-foreground" 1 hours ago Up 1 seconds 0.0.0.0:82->80/tcp, . 82->80/tcp httpd-container 

Из результата выполнения команды видно, что порты Docker-контейнера теперь сопоставлены с портами хоста. После этого доступ к службе httpd Docker-контейнера можно получить извне — через 82 порт:

It works!

При таком подходе идентификатор Docker-контейнера и все выполненные в нем настройки сохраняются, поскольку исходный контейнер не заменяется новым.

Изменить существующие маппинги любого Docker-контейнера можно используя процедуру, описанную выше. Единственное отличие будет заключаться в том, что ключ привязки портов в файле hostconfig.json не будет пустым. В этом случае достаточно просто обновить номер используемого порта.

При обновлении TCP-порта Docker-контейнера в маппинге необходимо указать тот же порт в файле config.v2.json .

Теперь все проверки прошли — можно запустить службу Docker и Docker-контейнер, чтобы изменения вступили в силу.

Бесплатные курсы по программированию в Хекслете

  • Освойте азы современных языков программирования
  • Изучите работу с Git и командной строкой
  • Выберите себе профессию или улучшите навыки

Как открыть порт для docker-контейнера?

Есть боевая машина с базой данных, и есть контейнер с веб-сервером и cgi.

Пробросить порт из контейнера на localhost понятно, -p=80:80
И docker port покажет 80/tcp -> 0.0.0.0:80

Но вот как пробросить порт наоборот, т.е. дать порт базы данных боевого сервера докер-контейнеру, не совсем понятно.
Как вы это делаете? Какие существуют способы?

PS Тега «docker» не существует?

  • Вопрос задан более трёх лет назад
  • 25166 просмотров

Комментировать
Решения вопроса 1

dimonchik2013

Dimonchik @dimonchik2013
non progredi est regredi

но лучше бы mysql тоже в контейнере запускать

Ответ написан более трёх лет назад
Нравится 2 3 комментария

comm1x

Павел Шорохов @comm1x Автор вопроса

Что делать если база уже живет на боевой системе? Или нужно обеспечить взаимодействие контейнеров с боевой машиной (например при постепенном переезде на контейнеры)?

comm1x

Павел Шорохов @comm1x Автор вопроса
По ссылке нашел решение, спасибо.

dimonchik2013

Dimonchik @dimonchik2013

сама идеология Докера такова + можно же зарезать память контейнеру, к примеру, правда, случай не для базы ))

Ответы на вопрос 0
Ваш ответ на вопрос

Войдите, чтобы написать ответ

debian

  • Debian
  • +1 ещё

Как правильно перенести контейнеры на другой сервер (LXC 5.0)?

  • 1 подписчик
  • 03 окт. 2023
  • 80 просмотров

docker — не работает проброс портов

Имеется ноутбук с установленной Xubuntu 20.04. Docker 20.10.2 установлен из убунтовской репы.

Возникла проблема с пробросом портов, фактически он не работает. Тот же хром пишет ERR_CONNECTION_REFUSED. Пробовал на нескольких контейнерах, которыми пользовался ранее и с которыми проблем на других машинах не было. Дополнительно даже попробовал запустить tomcat c 10М+ инсталляций из dockerhub — та же самая проблема.

docker run -it --rm -p 8888:8080 tomcat:9.0
$nmap localhost . 8888/tcp open sun-answerbook
$docker port e6c924d444ce 8080/tcp -> 0.0.0.0:8888
$docker network inspect bridge [ < "Name": "bridge", "Id": "203dfd988b025f76a03f3e3fd6e57a991993a6ca4d0c2e815231dbcd7b77ebac", "Created": "2021-07-09T09:53:59.264082024+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": < "e6c924d444ce12d1595f94c4f44b7a7defbc71ed9b535143d232c2991cb45228": < "Name": "quizzical_sammet", "EndpointID": "2e6694fead03379c9209aea5ef6955e692d27c714f7dc413554724f48d1cfd9d", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/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": <> > ]

milton14
09.07.21 12:08:54 MSK

How’s that again?

-p — проброс портов от контейнера на хост. Первое значение — порт хоста, второе — порт контейнера.

-v — маунт папки хоста в папку контейнера. Формат — key:value, где key — папка хоста, value — папка контейнера (можно не указывать key, тогда будет создана docker-managed volume, см. ниже). При этом если у образа уже есть такая папка с каким-то содержимым, то это содержимое будет стерто полностью. Чтобы этого избежать, можно маунтить не директории, а отдельные файлы.

Если на windows ошибок при маунте директорий нет, а директории в образе все равно пустые, то надо в настройках докера поставить галочки у дисков в разделе Shared Drives. Если уже стоят — снять и поставить обратно

-v key:value:ro — указание :ro в конце позволяет замаунтить папку как read-only.

—volumes-from — позволяет указать ранее созданный контейнер, с которым будут шариться волюмы

Еще полезные аргументы:

-i —interactive — оставлять стандартный поток ввода открытым даже если не приаттачено никакого терминала

-t —tty — выделить виртуальный терминал для контейнера, что позволит передавать сигналы внутрь контейнера

Обычно для интерактивных программ используется сразу -it

-e —env — позволяет задать переменную окружения, например, -e MY_ENVIRONMENT_VAR=»test»

—restart always — указывает, что после завершения работы контейнер нужно рестартануть. Первый раз рестартует через 1 секунду, потом через 2, 4 и так далее.

docker run -it /bin/sh \- запускает контейнер и сразу в интерактивном режиме баш в нем docker logs \- выводит все, что вывелось в контейнере в stdout и stderr docker create 

Запуск команды в контейнере:

docker exec -it mytarantool bash

здесь mytarantool - имя контейнера, bash - команда

docker stop mytarantool

docker rm mytarantool

Чтобы docker for windows имел доступ к дискам, нужно сделать диск доступным в меню Settings -> Shared Drives

Просмотр всех созданных контейнеров

Запуск консоли в контейнере винды:

docker run -it microsoft/windowsservercore cmd

Искать образы удобнее в консоли:

docker search rabbitmq

Найдя нужный образ, качаем его:

docker pull rabbitmq

Сохранение образа в файл:

docker save -o myfile.tar busybox:latest

Загрузка образа из файла:

docker load -i myfile.tar

Удаление образа с диска:

docker rmi busybox

Удаление всех образов с тэгом none:

docker rmi $(docker images -f 'dangling=true' -q)

Удаление всех образов с rancher в названии:

docker rmi $(docker images | gren 'rancher' | tr -s ' ' | cut -d ' ' -f 3)

Вывод инфы об контейнере:

Выдастся большой json, если нужен его определенный узел, то можно через -f указать узел, пример:

docker inspect -f ">" bmweb выдаст все мапы волюмов

docker inspect -f ">" bmweb аналогично, но более подробно

Построение образа из Dockerfile:

docker build -t dia_ch3/dockerfile:latest ch3_dockerfile

-t - имя полученного образа. По умолчанию будет установлен в локальный регистр с указанным именем.

последний аргумент - папка, в которой лежит Dockerfile и все сопутствующие файлы

Волюмы бывают двух типов:

bind mount - обычный, где папка контейнера мапится на пользовательскую папку хоста

docker-managed volume - папка контейнера маппится на папку хоста, созданную демоном докера ( /var/lib/docker/vfs/dir/ )

Быстрое поднятие веб-сервера, раздающего папку с файлами с локального диска:

docker run -d --name bmweb -v c:\userfiles:/usr/local/apache2/htdocs -p 80:80 httpd:latest**

Volume container - контейнер, предоставляющий волюм, чтобы остальные контейнерымогли использовать его в флаге --volumes-from. Так же позволяет избежать orphane volume, когда на волюм не осталось ссылок и его никто не удалил и он занимает место на диске.

Data-packed volume container - это такой контейнер, который не содержит в себе никакого приложения, но содержит контент, который при старте копируется в шаренный волюм.

Полиформный контейнер - такой контейнер, поведение которого определяется содержимым его волюма. Например, контейнер содержит NodeJS и запускает приложение по адресу /app/app.js, а это волюм и определяется хостом.

А вот так можно задавать разные конфиги одному и тому же приложению в образе:

docker run --name devConfig -v /config dockerinaction/ch4_packed_config:latest /bin/sh -c 'cp /development/* /config/' docker run --name prodConfig -v /config dockerinaction/ch4_packed_config:latest /bin/sh -c 'cp /production/* /config/' docker run --name devApp --volumes-from devConfig dockerinaction/ch4_polyapp docker run --name prodApp --volumes-from prodConfig dockerinaction/ch4_polyapp

4 архетипа контейнеров по отношению к закрытости сети:

Может общаться только с собой через loopback-интерфейс. Создается, используя --net none при создании контейнера

Дефолтный вариант. Имеет loopback-интерфейс и приватный интерфейс, соединенный с хостом через мост. Создается, используя --net bridge .

docker port - показывает список всех замапленных портов.

--hostname - задает имя хоста, видимое только изнутри этого же самого контейнера.

--dns - задает главный DNS-сервер. Можно задать несколько таких серверов, а еще можно этот флаг задать демону dockerd и эти сервера будут по умолчанию заданы всем создаваемым контейнерам.

--dns-search - позволяет задать задать домен, по которому будут искаться все адреса, для которых не указан домен. Таким образом можно, например, различать тестовое и продакшн-окружение.

--add-host - позволяет задать ip для определенного хоста (как запись в hosts в Windows)

-p/--publish - позволяет задать порт-форвардинг

-P//--publish-all - паблишит все порты, которые заданы через EXPOSE

--expose - заэкспоузить дополнительный порт

--icc=false - отключает inter-container communication

--bip - позволяет задать IP-адрес контейнера и его subnet range, пример: --bip "192.168.0.128/25"

--mtu - задает MTU, максимальный размер пакета в байтах

-b/--bridge - позволяет задать собственный интерфейс моста

Это несколько контейнеров, которые шарят общий сетевой стэк.

Docker в этом случае предоставляет интерфейсы, созданные специально для одного контейнера, другим контейнерам.

Для этого типа соединения первый контейнер создается как угодно, а затем к нему присоединяются остальные.

Присоединяются так: docker run --net container: .

Полезно, когда нужно чтобы 2 контейнера могли общаться меж собой, но не могли общаться с внешним миром. Тогда создаем первый закрытым и присоединяем к нему второй.

--net host Никакой изоляции, видит все те же сетевые интерфейсы, что и хост.

Можно связать контейнеры однонаправленной связью через --link.

docker run -d --name a mysql

docker run -d --name b --link a:db

При этом в контейнер b будут добавлены:

- переменные окружения для связи с a

- запись в dns, сопоставляющая ip контейнера a с хостом db

- если icc=false, то будут также добавлены правила в фаерволлы контейнеров для сетевого взаимодействия между ними

Сценарий использования: в контейнере b сервис ожидает, что по адресу tcp://db:3306 будет база данных. Или же он может брать порт базы из переменной окружения DB_PORT. Когда делаем --link оба этих значения будут автоматически заполнены.

Хорошей практикой считается на старте контейнера проверять, что заданы все необходимые переменные окружения/записи днс. Пример такого скрипта:

if [ -z $ ] then echo "Link alias 'database' was not set!" exit else exec "$@" fi 

Список переменных окружения, задаваемых при линке:

docker run -d --name mydb --expose 2222 --expose 3333 --expose 4444/udp alpine:latest nc -l 0.0.0.0:2222 docker run -it --rm --link mydb:database dockerinaction/ch5_ff env DATABASE_PORT=tcp://172.17.0.23:3333 - любой из полных адресов для exposed-портов DATABASE_PORT_3333_TCP=tcp://172.17.0.23:3333 DATABASE_PORT_2222_TCP=tcp://172.17.0.23:2222 DATABASE_PORT_4444_UDP=udp://172.17.0.23:4444 DATABASE_PORT_2222_TCP_PORT=2222 DATABASE_PORT_3333_TCP_PORT=3333 DATABASE_PORT_4444_UDP_PORT=4444 DATABASE_PORT_3333_TCP_ADDR=172.17.0.23 DATABASE_PORT_2222_TCP_ADDR=172.17.0.23 DATABASE_PORT_4444_UDP_ADDR=172.17.0.23 DATABASE_PORT_2222_TCP_PROTO=tcp DATABASE_PORT_3333_TCP_PROTO=tcp DATABASE_PORT_4444_UDP_PROTO=udp DATABASE_NAME=/furious_lalande/database - имя текущего контейнера + / + имя алиаса

Проблема с линками в том, что если контейнер-зависимость перезапустится, то у него будет новый Ip и все эти переменные станут неактуальными. Решением может быть использование DNS, либо же включение nter-process communication.

Вывод всех образов в приватном репозитории:

curl -X GET gitlab.factory.vocord.ru:5000/v2/_catalog

-m/--memory - ограничение по памяти, пример --memory 256m \--cpu-shares - относительное ограничение CPU. Если одному связанному контейнеру указать 512, а другому 256, то второй будет получать 1 цикл на каждые 2цикла первого. \--cpuset-cpus - указывает контейнерам, что они должны выполняться только на определенных ядрах \--device /dev/video0:/dev/video0 - маппит девайсы внутрь контейнера \--ipc container: \- шарит shared memory с указанным контейнером \--ipc host - шарить всю память с хостом

docker run --rm --entrypoint "" busybox:latest whoami - вывод дефолтного пользователя внутри контейнера

-u/--user - указывает пользователя, под которым запустить контейнер

Пример: docker run -u nobody:default - устанавливает юзера nobody и группу default

Создание образа из контейнера:**

  1. Скачиваем образ
  2. Делаем изменения в его файловой системе docker run --name hw_container ubuntu:latest touch /HelloWorld
  3. Коммитим эти изменения как новый контейнер docker commit hw_container hw_image

-a - подписывает образ авторской строкой

-m - commit message

-c --change - позволяет дописывать строки в Dockerfile, пример: docker commit -c "CMD /notebook.sh" notebook notebook-my

docker commit -a "@dockerinaction" -m "Added git" image-dev ubuntu-git

entrypoint - Это программа, которая будет запущена при старте. Она тоже коммитится в образ.

docker run --name cmd-git --entrypoint git ubuntu-git

Кроме этого коммитятся:

  • все переменные окружения
  • рабочая директория
  • открытые порты
  • объявления волюмов
  • точка входа в контейнер
  • сама команда и все ее аргументы

docker diff - выводит список изменений в файловой системе контейнера относительно образа, из которого он создан. A - added, C - changed, D - deleted.

Union file system

В докере используется UFS, в которой файловая система представляется в виде объединения слоев. Редактируемый слой - только верхний, остальные все read-only. Новый слой сохраняется при коммите образа.

Благодаря такой системе, слои могут переиспользоваться в нескольких контейнерах, вместо того чтобы каждый раз копироваться. Однако есть и недостаток - старые слои никогда не удаляются, а значит образ может только увеличиваться в размерах и никогда не уменьшаться.

Максимальное количество слоев - 42.

docker history - выводит все коммиты/слои файловой системы

docker export --output export.tar ubuntu - сохраняет всю файловую систему контейнера в архив на хосте

docker import -c "ENTRYPOINT [\"/hello\"]" hello.tar dockerinaction/ch7_static - берет .tar с файлами и создает из них образ

FROM ubuntu:latest MAINTAINER "dockerinaction@allingeek.com" RUN apt-get update RUN apt-get install -y git ENTRYPOINT ["git"] 

docker build --tag ubuntu-git:auto . - точка на конце означает текущую директорию

Все команды, описанные в докерфайле (включая RUN ) будут выполнены на этапе построения образа.

Первая команда всегда должна быть FROM . Если нужен пустой родитель, то можно указать FROM scratch .

Каждая инструкция в докерфайле создает новый слой в образе. Поэтому лучше эти инструкции по максимуму объединять, чтобы уменьшить размер образа. Если возникла ошибка на шаге N, то при повторной попытке шаги 1..N-1 будут взяты из кэша. Но если хочется не юзать кэш, то можно указать флаг --no-cache .

Всего есть 14 инструкций Dockerfile.

В файле .dockerignore можно перечислить, какие файлы не включать в образ.

ENV - задает переменные окружения, пример: ENV APPROOT="/app" APP="mailer.sh" VERSION="0.6" (здесь задается 3 переменных). Заданные переменные окружения можно использовать в последующих инструкциях, используя синтаксис $

** LABEL** - дополнительные пары ключ-значение, записываемые в метаданные образа. Пример: LABEL base.name="Mailer Archetype" base.version="$"

WORKDIR- задает working directory, то есть ту директорию, в которой начнется исполнение образа. Пример: WORKDIR $APPROOT

EXPOSE- Открывает порт. Пример: EXPOSE 33333

ENTRYPOINT- команда, которую запускать при старте образа. Можно либо задать команду консоли (shell form), либо массив строк, в котором первая строка - путь к исполняемому файлу, а остальные - аргументы запуска (exec form). shell form при этом менее гибок, так как не позволяет задавать последний аргумент в docker run или предоставлять дополнительные аргументы в инструкции CMD. Дефолтный entrypoint - /bin/sh

COPY - копирует файлы в образ. Принимает массив строк, где последний аргумент - папка назначения, а все остальные - копируемые файлы. Пример: COPY ["./log-impl", "$"]

VOLUME- создает волюм, то же самое что и --volume. Только нельзя задать bind-mount или read-only волюм. В массиве аргументов для каждого значения будет создан волюм. Пример: VOLUME ["/var/log"] .

CMD- задает аргументы для entrypoint. Если entrypoint не задан, либо задан в shell-форме, то это может быть команда для шелла, так как будет использован дефолтный entrypoint.

ONBUILD- инструкция, которая будет выполняться, если текущий образ будет использован как базовый для другого образа. Эти инструкции записываются в метаданные текущего образа. С их помощью можно, например, сбилдить программу, предоставляемую образом-потомком. ONBUILD-инструкции выполняются сразу после FROM в потомке.

Docker file system

Используется файловая система overlay2.

Слои для каждого контейнера перечислены здесь:

Там есть 3 файла:

  • init-id - это идентификатор слоя, используемый при создании контейнера
  • mount-id - идентификатор слоя, который был образован в процессе работы контейнера
  • parent - какой-то идентификатор, видимо, родительского слоя

По идентификатору слоя можно получить его содержимое так:

Если во всех образах перестала работать сеть, то можно пересоздать мост:

pkill docker iptables -t nat -F ifconfig docker0 down ip link del docker0 systemctl start docker

Если ifconfig не найден, то apt install net-tools

Автоматическая очистка места на диске

По адресу /etc/cron.daily/docker-gc создаем скрипт следующего содержания:

#!/bin/sh -e # Delete all stopped containers (including data-only containers). docker ps -a -q --no-trunc --filter "status=exited" | xargs --no-run-if-empty docker rm -v # Delete all tagged images more than a month old docker images --no-trunc --format '> >' | grep ' months' | awk '< print $1 >' | xargs --no-run-if-empty docker rmi -f || true # Delete all 'untagged/dangling' () images # Those are used for Docker caching mechanism. docker images -q --no-trunc --filter dangling=true | xargs --no-run-if-empty docker rmi # Delete all dangling volumes. docker volume ls -qf dangling=true | xargs --no-run-if-empty docker volume rm
sudo chmod +x /etc/cron.daily/docker-gc

Добавляем новый джоб в crontab :

crontab -e

Открывается текстовый редактор, нужно в него добавить строчку:

0 0 * * * /etc/cron.daily/docker-gc

не забыть последнюю строчку сделать пустой (иначе кронтаб ругаться будет) и выйти с сохранением

Файловая система докера

По умолчанию находится в папке /var/lib/docker

Структура файловой системы зависит от используемого драйвера хранилища. У меня на Debian это по уомлчанию overlay2, поэтому дальнейшая информация справедлива для него. Узнать свой драйвер можно командой docker info в графе Storage Driver

В /var/lib/docker можем найти следующие подпапки:

  • builder
  • buildkit
  • containerd
  • containers
  • image
  • network
  • overlay2
  • plugins
  • runtimes
  • swarm
  • tmp
  • trust
  • volumes

Описания образов лежат по адресу: /var/lib/docker/image/overlay2/imagedb/content/sha256 .

Например, если мы ходим посмотреть описание образа с идентификатором ebaee1a37cda. , то нам нужно в текстовом редакторе открыть файл /var/lib/docker/image/overlay2/imagedb/content/sha256/ebaee1a37cda. . В этом текстовом файле лежит в основном та же инфа, которую мы получаем через docker inspect ebaee1a37cda , только иначе структурирована.

Но в этом файле мы не найден идентификаторы слоев образа для overlay2, те идентификаторы которые там указаны - они для RootFS (так и не понял, зачем нужны). Полезные идентификаторы будем брать из вывода docker inspect ebaee1a37cda :

"GraphDriver": < "Data": < "LowerDir": "/var/lib/docker/overlay2/1ef930458b9b7c4b107589bfa8708a5a905c0bff78fe82c04db1b65908ca356f/diff:/var/lib/docker/overlay2/990d47bc6c20549415caca3a6f6cfffc43b34491f128eeafffc2a8214c86ff1a/diff:/var/lib/docker/overlay2/6465e9cbb477e85f312139fd430c82649d5559190f2eed4fe32d1b2c2ca9bd9b/diff:/var/lib/docker/overlay2/7a924b04842adb199e077c02c4661955fb318d5d276c5c66b2e07628a69fc49d/diff:/var/lib/docker/overlay2/b4cf7f55f924b2167262f246ecdd8d2400adfbac69d0258049c619293228b6f0/diff", "MergedDir": "/var/lib/docker/overlay2/cf7ef417035f8dcbaabecdb4897a94ef1ad00b0919ddf4f7af0b1150b9c7bd8f/merged", "UpperDir": "/var/lib/docker/overlay2/cf7ef417035f8dcbaabecdb4897a94ef1ad00b0919ddf4f7af0b1150b9c7bd8f/diff", "WorkDir": "/var/lib/docker/overlay2/cf7ef417035f8dcbaabecdb4897a94ef1ad00b0919ddf4f7af0b1150b9c7bd8f/work" >, "Name": "overlay2" >,

Верхний слой описан в поле MergedDir . Пройдем по этому адресу:

$ cd /var/lib/docker/overlay2/cf7ef417035f8dcbaabecdb4897a94ef1ad00b0919ddf4f7af0b1150b9c7bd8f/ $ ls diff link lower work 

В файле link содержится сокращенный идентификатор слоя:

$ cat link HRKAB26PG22YEF25QW3DFUSPVO

В lower - сокращенные идентификаторы нижних слоев, разделенные двоеточием:

$ cat lower l/ZJPNNPNGB2QUT7UHS6FGJAJEXS:l/ITT6VDHHVLTL4XSV4MKXFARWZX:l/D73DFE6U73XW47KLW2IWYFN3X4:l/GPI73DKAIBG4M4HEPH22KTQBLS:l/AIQ55Z4PNLZZZTY5PWAD7EY74K

В папке /var/lib/docker/overlay2/l содержатся симлинки от сокращенных идентификаторов слоев к нормальным:

y# ls /var/lib/docker/overlay2/l/ZJPNNPNGB2QUT7UHS6FGJAJEXS -l lrwxrwxrwx 1 root root 72 Jan 22 11:17 /var/lib/docker/overlay2/l/ZJPNNPNGB2QUT7UHS6FGJAJEXS -> ../1ef930458b9b7c4b107589bfa8708a5a905c0bff78fe82c04db1b65908ca356f/diff

Как видим, второй сверху слой нашего образа ZJPNNPNGB2QUT7UHS6FGJAJEXS соответствует слою 1ef930458b9b7c4b107589bfa8708a5a905c0bff78fe82c04db1b65908ca356f . А его содержимое можем посмотреть в папке diff (посмотрим самый нижний слой нашего образа, содержащий файловую систему базового образа):

y# ls /var/lib/docker/overlay2/l/AIQ55Z4PNLZZZTY5PWAD7EY74K bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *