Docker (Русский)

From ArchWiki
Состояние перевода: На этой странице представлен перевод статьи Docker. Дата последней синхронизации: 13 декабря 2023. Вы можете помочь синхронизировать перевод, если в английской версии произошли изменения.

Docker — утилита для упаковки, загрузки и запуска любых приложений в легковесных контейнерах.

Установка

Чтобы скачивать образы Docker и запускать контейнеры Docker, вам понадобится Docker Engine. Docker Engine включает в себя демон для управления контейнерами, а также интерфейс CLI docker. Установите пакет docker или разрабатываемую версию docker-gitAUR. Затем запустите/включите docker.service или docker.socket. Обратите внимание, что docker.service запускает службу при загрузке, тогда как docker.socket запускает docker при первом использовании, что может сократить время загрузки системы. Проверьте работу демона:

# docker info

Обратите внимание, что запуск службы Docker может завершиться сбоем, если имеется активное VPN-соединение. Это происходит из-за IP-конфликтов между сетевыми мостами и оверлейными сетями VPN и Docker. Если это так, попробуйте отключить VPN перед запуском службы Docker. Вы можете переподключить VPN сразу после этого. Вы также можете попытаться устранить конфликты сетей (смотрите решения [1] или [2]).

Затем проверьте, что запуск контейнеров работает. Следующая команда скачивает свежий образ Arch Linux и использует его для запуска программы Hello World в контейнере:

# docker run -it --rm archlinux bash -c "echo hello world"

Если требуется использовать команду docker от имени обычного пользователя, добавьте его в группу docker, перелогиньтесь и перезапустите службу docker.service.

Важно: Каждый пользователь в группе docker имеет права, равноценные правам суперпользователя, поскольку они могут использовать docker run --privileged для запуска контейнеров с привилегиями суперпользователя. Подробнее [3] и [4].

Docker Compose

Docker Compose — это альтернативный интерфейс CLI для Docker Engine, который определяет свойства контейнеров с помощью YAML-файла docker-compose.yml вместо, например, скрипта с параметрами docker run. Это полезно для настройки служб, которые часто используются и/или имеют сложные конфигурации. Для использования установите пакет docker-compose.

Docker Desktop

Docker Desktop — это проприетарное настольное приложение, которое запускает Docker Engine внутри виртуальной машины Linux. Включены дополнительные функции, такие как кластер Kubernetes и сканер уязвимостей. Это приложение полезно для групп разработчиков программного обеспечения, которые разрабатывают контейнеры Docker с использованием macOS и Windows. Порт приложения для Linux является относительно новым и дополняет интерфейс командной строки Docker [5].

Экспериментальный пакет для Arch предоставляется непосредственно Docker. Подробнее в руководстве. К сожалению, он содержит файлы, которые конфликтуют с пакетом docker-compose, поэтому сначала вам необходимо удалить docker-compose, если он установлен. Но вы можете установить пакет docker-desktopAUR, который не конфликтует с существующими пакетами.

Кроме того, для запуска Docker Desktop ваша система должна соответствовать определённым требованиям, в частности, должна быть включена поддержка виртуализации KVM. Чтобы увидеть значок на панели задач в Gnome, потребуется gnome-shell-extension-appindicator.

Наконец, поддержка совместного использования файлов требует сопоставления идентификаторов пользователей и групп через /etc/subuid и /etc/subgid. Дополнительные сведения см. в Инструкции по совместному использованию файлов Docker Desktop для Linux.

Использование

Docker состоит из нескольких компонентов:

  • Демон Docker (иногда его также называют Docker Engine) — это процесс, который запускается через docker.service. Он реализует Docker API и управляет контейнерами Docker.
  • Команда docker, которая позволяет пользователям взаимодействовать с Docker API через командную строку и управлять демоном Docker.
  • Контейнеры Docker — это изолированные (namespaced) процессы, которые запускаются и управляются демоном Docker по запросу через Docker API.

Обычно пользователи используют Docker, выполняя команды docker, которые, в свою очередь, обращаются к демону Docker для выполнения действий, которые, в свою очередь, манипулируют контейнерами Docker. Понимание взаимосвязи между клиентом (docker), сервером (docker.service) и контейнерами важно для успешного администрирования Docker.

Обратите внимание, что если демон Docker останавливается или перезапускается, все запущенные в данный момент контейнеры Docker тоже останавливаются или перезапускаются.

Также можно отправлять запросы к Docker API и управлять демоном Docker без использования команды docker. Смотрите документацию Docker API.

Подробнее об использовании Docker можно почитать в Docker Getting Started guide.

Настройка

Демон Docker настраивается через файл настроек /etc/docker/daemon.json или через флаги командной строки в юните docker.service. Официальная документация рекомендует использовать файл настроек. Если вы хотите использовать флаги командной строки, используйте drop-in файлы, чтобы переопределить директиву ExecStart в docker.service.

Информация об опциях в daemon.json есть в документации.

Драйвер хранения

Драйвер хранения (storage driver) управляет хранением образов и контейнеров на вашем Docker-хосте. По умолчанию используется драйвер overlay2, который имеет хорошую производительность и является хорошим выбором для современных ядер Linux и файловых систем. Более старые драйверы devicemapper и aufs могут использоваться для совместимости со старыми ядрами Linux, но использовать их в Arch Linux вместо overlay2 смысла мало.

Пользователи Btrfs или ZFS могут использовать драйвер btrfs или zfs соответственно, преимущество которых в использовании возможностей, специфичных для файловой системы. Смотрите документацию драйвера btrfs и документацию драйвера zfs для более подробной информации.

Сокет демона

По умолчанию демон Docker принимает запросы Docker API через Unix-сокет /var/run/docker.sock. Это подходящий вариант в большинстве случаев.

Можно настроить демон так, чтобы он дополнительно слушал TCP-сокет, что позволит получить удалённый доступ к Docker API с других компьютеров. [6] Это можно использовать, например, для того, чтобы команды docker, выполняемые на хосте, могли получить доступ к демону Docker, запущенному в виртуальной машине с Linux, например в виртуальной машине с Arch на хосте Windows или macOS.

Важно: По умолчанию Docker API не использует шифрование или аутентификацию. Удалённый доступ к демону Docker через TCP эквивалентен незащищенному удалённому root-доступу, если не включены шифрование TLS и авторизация либо с помощью HTTP-прокси, либо с помощью дополнительной настройки Docker. В целом, включение TCP-сокетов для Docker API следует рассматривать как высокий риск для безопасности.

В стандартном файле docker.service установлен флаг -H, и Docker не запустится, если опция присутствует одновременно во флагах и в файле /etc/docker/daemon.json. Поэтому самый простой способ изменить настройки сокета — использовать drop-in файл. Пример ниже добавляет TCP-сокет на порту 2376:

/etc/systemd/system/docker.service.d/docker.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376

Для применения изменений выполните daemon-reload и перезапустите службу docker.service.

HTTP-прокси

Настройка Docker для использования HTTP-прокси состоит из двух частей: настройка демона и настройка контейнеров.

Настройка демона для использования прокси

Смотрите документацию Docker.

Настройка контейнеров для использования прокси

Смотрите документацию Docker.

Настройка DNS

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

Большинство DNS-серверов, запущенных на 127.0.0.0/8, не поддерживается из-за конфликтов между сетевыми пространствам имён хоста и контейнеров. Такие серверы убираются из файлов /etc/resolv.conf внутри контейнеров. Если в результате этого /etc/resolv.conf окажется пустым, то будет использоваться Google DNS.

Особым случаем является использование 127.0.0.53 в качестве единственного указанного DNS-сервера. В таком случае Docker предполагает наличие systemd-resolved и использует /run/systemd/resolve/resolv.conf.

Если вы используете службу вроде dnsmasq, можно добавить виртуальный сетевой интерфейс с link-local адресом из блока 169.254.0.0/16 вместо 127.0.0.1.

Расположение образов

По умолчанию Docker образы расположены в /var/lib/docker. Они могут быть перемещены в другие разделы. Ниже в качестве примера рассматривается перемещение в /mnt/docker.

Для начала остановите docker.service. Это также остановит все запущенные контейнеры и размонтирует все образы. После этого можно поместить файлы образов в нужное место, например, командой cp -r /var/lib/docker /mnt/docker.

После этого в файле /etc/docker/daemon.json измените опцию data-root:

/etc/docker/daemon.json
{
  "data-root": "/mnt/docker"
}

Перезапустите docker.service для применения изменений.

Небезопасные реестры

Если вы решите использовать самозаверенный сертификат для своего личного реестра, Docker откажется использовать его, пока вы не заявите, что доверяете ему. Например, чтобы разрешить использование образов из реестра myregistry.example.com:8443, измените опцию /etc/docker/daemon.json в файле /etc/docker/daemon.json:

/etc/docker/daemon.json
{
  "insecure-registries": [
    "my.registry.example.com:8443"
  ]
}

Перезапустите docker.service для применения изменений.

IPv6

Чтобы включить поддержку IPv6 в Docker, необходимо выполнить несколько действий. Подробнее смотрите [7] и [8].

Сперва включите параметр ipv6 в файле /etc/docker/daemon.json и задайте определённую подсеть IPv6. В примерах ниже используется частная подсеть fd00::/80. Убедитесь, что используете подсеть не менее 80 бит, так как это позволит IPv6-адресу контейнера оканчиваться его MAC-адресом, что уменьшит проблемы с недействительностью кэша соседей NDP.

/etc/docker/daemon.json
{
  "ipv6": true,
  "fixed-cidr-v6": "fd00::/80"
}

Перезапустите docker.service для применения изменений.

После этого, чтобы предоставить контейнерам доступ к сети хоста, необходимо решить проблемы с маршрутизацией, возникающие из-за использования частной подсети IPv6. Добавьте IPv6 NAT:

# ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE

После этого IPv6 должен полноценно заработать. Проверить можно такой командой:

# docker run curlimages/curl curl -v -6 archlinux.org

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

# firewall-cmd --zone=public --add-rich-rule='rule family="ipv6" destination not address="fd00::1/80" source address="fd00::/80" masquerade'

Для ufw нужно сперва разрешить ipv6 forwarding, как описано в разделе Uncomplicated Firewall#Forward policy. Затем отредактируйте файл /etc/default/ufw, раскомментировав следующие строки:

/etc/ufw/sysctl.conf
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1

После этого можно добавить правило iptables:

# ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE

Для контейнеров docker, созданных с помощью docker-compose, может потребоваться установить значение enable_ipv6: true в разделе networks для соответствующей сети. Кроме того, может потребоваться настройка подсети IPv6. Смотрите [9] для более подробной информации.

Изоляция пользовательского пространства имён

По умолчанию процессы в контейнерах Docker запускаются в том же пользовательском пространстве имён, что и основной демон dockerd, то есть контейнеры не изолированы от него с помощью user_namespaces(7). Это позволяет процессу внутри контейнера получать доступ к настроенным ресурсам на хосте в соответствии с обычными правами доступа. Это обеспечивает максимальную совместимость, но создаёт риск безопасности в случае появления уязвимостей, связанных с повышением привилегий или побегом из контейнера (одна такая уязвимость была обнародована и исправлена в феврале 2019 года).

Влияние такой уязвимости можно уменьшить с помощью изоляции пользовательского пространства имён — UID и GID внутри контейнеров будут сопоставляться с другим (как правило, непривилегированным) диапазоном UID/GID на хосте.

Примечание:
  • Демон dockerd всё равно будет запускаться от имени суперпользователя. Запуск Docker без прав суперпользователя — отдельная, не связанная с этим функция.
  • Процессы в контейнере запускаются от имени пользователя, указанного в директиве USER в Dockerfile, используемом для создания образа контейнера.
  • Все контейнеры используют и тот же диапазон UID/GID. Это сохраняет возможность совместного использования томов контейнерами.
  • Включение изоляции пользовательского пространства имён имеет ряд ограничений.
  • Включение изоляции пользовательского пространства имён фактически замаскирует существующие слои образов и контейнеров, а также другие объекты Docker в /var/lib/docker/, поскольку Docker необходимо настроить права на них. В официальной документации рекомендуется включать эту функцию на новой установке Docker, а не на существующей.

В файле /etc/docker/daemon.json измените опцию userns-remap. Значение default автоматически создаст пользователя и группу dockremap для использования с изоляцией пользовательского пространства имён.

/etc/docker/daemon.json
{
  "userns-remap": "default"
}

Настройте /etc/subuid и /etc/subgid, указав имя пользователя/группы, начальные UID/GID и размеры диапазонов UID/GID. В примере ниже пользователю и группе dockremap назначается диапазон из 65536 UID и GID, начиная с 165536.

/etc/subuid
dockremap:165536:65536
/etc/subgid
dockremap:165536:65536

Перезапустите docker.service для применения изменений.

После этого все контейнеры будут по умолчанию работать в изолированном пользовательском пространстве имён. Это можно отключить для отдельных контейнеров с помощью флага --userns=host команды docker. Смотрите [10] для более подробной информации.

Запуск демона Docker без прав суперпользователя

Примечание: Без прав суперпользователя Docker полагается на непривилегированные пользовательские пространства имён (unprivileged user namespaces, CONFIG_USER_NS_UNPRIVILEGED). Это включено по умолчанию в ядрах linux, linux-lts и linux-zen. Пользователям других ядер может потребоваться явно включить эту функцию. Это имеет некоторые последствия для безопасности; смотрите Безопасность#Запуск приложений в песочнице.

Чтобы сам демон Docker запускался от имени обычного пользователя, установите пакет docker-rootless-extrasAUR.

Настройте /etc/subuid и /etc/subgid, указав имя пользователя/группы, начальные UID/GID и размеры диапазонов UID/GID.

/etc/subuid
имя_пользователя:165536:65536
/etc/subgid
имя_пользователя:165536:65536

Включите пользовательский юнит docker.socket; благодаря ему демон Docker будет автоматически запускаться при обращении к его сокету.

Наконец, задайте переменную окружения, задающую путь к сокету демона Docker:

$ export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock

Включение native overlay diff engine

Некоторые пользователи сообщают, что на их системах Docker не может использовать native overlay diff engine, что замедляет сборку образов. Если вы часто собираете образы, вы можете включить это, добавив параметры модуля ядра, как описано в [11]:

/etc/modprobe.d/disable-overlay-redirect-dir.conf
options overlay metacopy=off redirect_dir=off

После этого остановите docker.service и перезагрузите модуль overlay:

# modprobe -r overlay
# modprobe overlay

Затем можно снова запустить docker.service.

Для проверки выполните docker info — в строке Native Overlay Diff должно быть true.

Образы

Arch Linux

Следующая команда скачивает x86_64 образ archlinux. Это урезанная версия ядра Arch без сети и т.д.

# docker pull archlinux

Смотрите также README.md.

Для полноценного образа Arch, клонируйте репозиторий и создайте свой собственный образ.

$ git clone https://gitlab.archlinux.org/archlinux/archlinux-docker.git

Убедитесь, что пакеты devtools, fakechroot и fakeroot установлены.

Сборка базового образа:

$ make image-base

Alpine Linux

Alpine Linux — популярный выбор для создания небольших образов, особенно для статически слинкованных программ. Следующая команда скачивает свежий образ Alpine Linux:

# docker pull alpine

Alpine Linux использует реализацию musl libc вместо glibc, используемой в большинстве дистрибутивов Linux. Поскольку Arch Linux использует glibc, существует ряд функциональных различий между хостом Arch Linux и контейнером Alpine Linux, которые могут повлиять на производительность и корректность работы программ. Список этих различий описан здесь.

Обратите внимание, что динамически слинкованные программы, собранные на Arch Linux (или любой другой системе, использующей glibc), могут иметь ошибки и проблемы с производительностью при запуске на Alpine Linux (или любой другой системе, использующей другую libc). Примеры: [12], [13], [14].

Debian

Следующая команда скачивает свежий образ debian:

# docker pull debian

Полный список доступных тегов, включая стандартные и тонкие (slim) версии для каждого выпуска Debian, есть на странице Docker Hub.

Distroless

Google поддерживает образы distroless — минимальные образы без компонентов ОС, таких как менеджеры пакетов или оболочки, что позволяет создавать очень маленькие образы для упаковки программ.

Список образов и инструкции по их использованию с различными языками программирования есть в README на GitHub.

Советы и рекомендации

Получение IP-адреса запущенного контейнера

Чтобы получить IP адрес контейнера, выполните:

$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container-name OR id> 
172.17.0.37

Для каждого работающего контейнера имя и соответствующий IP-адрес могут быть перечислены для использования в /etc/hosts:

#!/usr/bin/env sh
for ID in $(docker ps -q | awk '{print $1}'); do
    IP=$(docker inspect --format="{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" "$ID")
    NAME=$(docker ps | grep "$ID" | awk '{print $NF}')
    printf "%s %s\n" "$IP" "$NAME"
done

Запуск графических программ внутри контейнера

В этом разделе описаны действия, необходимые для того, чтобы графические программы (в том числе те, которые используют OpenGL или Vulkan) могли работать на X-сервере хоста.

Во-первых, в контейнере должны быть установлены правильные драйверы, совместимые с графическим оборудованием хоста. Процедура установки зависит от типа контейнера, но для контейнеров, основанных на образах Arch Linux, обратитесь к разделам OpenGL#Installation и Vulkan (Русский)#Установка для получения пакетов, специфичных для вашего оборудования.

Далее нужно предоставить контейнеру доступ к X-серверу хоста. В однопользовательской среде это можно легко сделать, запустив Xhost на хосте, который добавляет несетевые локальные соединения в список контроля доступа:

$ xhost +local:

После этого нужно добавить следующие параметры к команде docker run:

  • -e "DISPLAY=$DISPLAY" для установки внутри контейнера переменной окружения DISPLAY, соответствующей дисплею хоста;
  • --mount type=bind,src=/tmp/.X11-unix,dst=/tmp/.X11-unix для доступа к сокету X-сервера изнутри контейнера;
  • --device=/dev/dri:/dev/dri для доступа к устройствам Direct Rendering Infrastructure хоста.

Для проверки можно внутри контейнера запустить glxgears из пакета mesa-utils или vkcube из пакета vulkan-tools.

Запуск проектов Docker Compose при загрузке системы

Создайте юнит-шаблон для Docker Compose, параметром которого является название вашего проекта (смотрите systemd (Русский)#Написание файлов юнитов и systemd.service(5) § SERVICE TEMPLATES):

/etc/systemd/system/docker-compose@.service
[Unit]
Description=%i service with docker compose
Requires=docker.service
After=docker.service

[Service]
WorkingDirectory=/opt/%i
ExecStartPre=-/usr/bin/docker compose pull
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down
ExecReload=/usr/bin/docker compose pull
ExecReload=/usr/bin/docker compose up --remove-orphans

[Install]
WantedBy=multi-user.target

Затем для каждого проекта, который вы хотите запускать таким образом, создайте каталог /opt/название_проекта, содержащий файл Compose и другие необходимые для запуска файлы (например, .env). [15]

После этого запустите/включите docker-compose@название_проекта.service.

Использование buildx для кросс-компиляции

Плагин buildx использует новый набор инструментов для сборки BuildKit. Установите пакет docker-buildx. Интерфейс buildx поддерживает сборку мультиплатформенных образов, в том числе для архитектур, отличных от архитектуры хоста.

Для кросс-компиляции образов требуется QEMU. Чтобы настроить статическую сборку QEMU в Docker, смотрите информацию об использовании образа multiarch/qemu-user-static. В противном случае, чтобы настроить QEMU на хост-системе для использования с Docker, смотрите QEMU#Chrooting into arm/arm64 environment from x86_64. В любом случае система будет настроена на эмуляцию гостевой архитектуры в пользовательском режиме.

$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS  PLATFORMS
default * docker
  default default         running linux/amd64, linux/386, linux/arm64, linux/riscv64, linux/s390x, linux/arm/v7, linux/arm/v6

Запуск Docker-контейнеров с ускорением на графических процессорах NVIDIA

С помощью NVIDIA Container Toolkit (рекомендуется)

Начиная с версии 19.03, графические процессоры NVIDIA поддерживаются в качестве устройств Docker. NVIDIA Container Toolkit ― рекомендуемый способ запуска контейнеров, использующих графические процессоры NVIDIA.

Установите пакет nvidia-container-toolkit и перезапустите Docker. Теперь вы можете запускать контейнеры Docker, использующие графические процессоры NVIDIA, с помощью параметра --gpus:

# docker run --gpus all nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

Укажите, сколько графических процессоров разрешено в контейнере:

# docker run --gpus 2 nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

Укажите, какие GPU следует использовать:

# docker run --gpus '"device=1,2"' nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

или

# docker run --gpus '"device=UUID-ABCDEF,1"' nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

Если при использовании вышеуказанных команд вы получаете ошибку типа Failed to initialize NVML: Unknown Error, вы можете попробовать более точно указать GPU:

# docker run --gpus all --device /dev/nvidiactl:/dev/nvidiactl --device /dev/nvidia-uvm:/dev/nvidia-uvm --device /dev/nvidia0:/dev/nvidia0 nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

Укажите возможности ("graphics", "compute", ...) контейнера (хотя это редко, если вообще когда либо используется таким образом):

# docker run --gpus all,capabilities=utility nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

Для получения дополнительной информации смотрите документацию и руководство по установке.

Если у вас установлен VirtualGL и вы получаете ошибку NVML, замените

/etc/nvidia-container-runtime/config.toml
#user = "root:video"

на

user = "root:root"

Подробнее об этой проблеме в NVIDIA/nvidia-docker на GitHub.

С помощью NVIDIA Container Runtime

Установите пакет nvidia-container-runtimeAUR[ссылка недействительна: package not found]. Затем, зарегистрируйте среду выполнения NVIDIA, отредактировав конфигурационный файл /etc/docker/daemon.json:

/etc/docker/daemon.json
{
  "runtimes": {
    "nvidia": {
      "path": "/usr/bin/nvidia-container-runtime",
      "runtimeArgs": []
    }
  }
}

и перезапустите docker.

Среда выполнения также может быть зарегистрирована с помощью параметра командной строки dockerd:

# /usr/bin/dockerd --add-runtime=nvidia=/usr/bin/nvidia-container-runtime

После этого контейнеры с ускорением на графических процессорах могут быть запущены с помощью следующей команды:

# docker run --runtime=nvidia nvidia/cuda:9.0-base nvidia-smi

или (требуется Docker версии 19.03 или выше):

# docker run --gpus all nvidia/cuda:9.0-base nvidia-smi

Смотрите также README.md.

С помощью nvidia-docker (устарело)

nvidia-docker — обёртка над библиотекой среды исполнения NVIDIA Container Runtime, которая регистрирует среду выполнения NVIDIA по умолчанию и предоставляет команду nvidia-docker.

Чтобы использовать nvidia-docker, установите пакет nvidia-dockerAUR[ссылка недействительна: package not found] и перезапустите Docker. Контейнеры с поддержкой NVIDIA GPU могут быть запущены, используя один из следующих методов:

# docker run --runtime=nvidia nvidia/cuda:9.0-base nvidia-smi
# nvidia-docker run nvidia/cuda:9.0-base nvidia-smi

или (требуется Docker версии 19.03 или выше)

# docker run --gpus all nvidia/cuda:9.0-base nvidia-smi
Примечание: nvidia-docker — устаревший метод запуска Docker-контейнеров с ускорением на графических процессорах NVIDIA, использующийся в версиях Docker, предшествующих версии 19.03. Если вы используете Docker версии 19.03 или выше, рекомендуется использовать NVIDIA Container Toolkit.

Образ Arch Linux с CUDA

Можно использовать следующий Dockerfile для создания собственного образа Arch Linux с CUDA. Он использует Dockerfile frontend syntax 1.2 для кэширования пакетов pacman на хосте. Перед запуском сборки нужно установить переменную окружения DOCKER_BUILDKIT=1.

Dockerfile
# syntax = docker/dockerfile:1.2

FROM archlinux

# установка пакетов
RUN --mount=type=cache,sharing=locked,target=/var/cache/pacman \
    pacman -Syu --noconfirm --needed base base-devel cuda

# настройка nvidia container runtime
# https://github.com/NVIDIA/nvidia-container-runtime#environment-variables-oci-spec
ENV NVIDIA_VISIBLE_DEVICES all
ENV NVIDIA_DRIVER_CAPABILITIES compute,utility

Удаление Docker и образов

Если вы хотите полностью удалить Docker, вам следует выполнить следующие шаги:

Примечание: Не копируйте бездумно эти команды, не убедившись, что вы знаете, что делаете.

Выдать список работающих контейнеров:

# docker ps

Выдать список всех контейнеров, запущенных на хосте для удаления:

# docker ps -a

Остановить работающий контейнер:

# docker stop <CONTAINER ID>

Выполнить команду kill для всё ещё работающих контейнеров:

# docker kill <CONTAINER ID>

Удалить все контейнеры, перечисленные по ID:

# docker rm <CONTAINER ID>

Выдать список всех образов Docker:

# docker images

Удалить все образы Docker по ID:

# docker rmi <IMAGE ID>

Удалить все образы, контейнеры, тома и сети, которые не связаны с контейнерами (висячие):

# docker system prune

Чтобы дополнительно удалить все остановленные контейнеры и все неиспользуемые образы (не только висячие), добавьте к команде флаг -a:

# docker system prune -a

Удалить все данные Docker (очистить каталог):

# rm -R /var/lib/docker

Решение проблем

docker0 Bridge не получает IP / нет доступа к Интернету в контейнерах при использовании systemd-networkd

Docker пытается включить пересылку (forwarding) IP-пакетов глобально, но по умолчанию systemd-networkd переопределяет глобальную настройку sysctl настройками конкретных сетевых профилей. Укажите IPForward=yes в сетевом профиле. Подробнее в разделе Раздача интернета#Разрешите пересылку пакетов.

Когда systemd-networkd пытается управлять сетевыми интерфейсами, которые создал Docker, например, когда вы прописали Name=* в секции Match, это может привести к проблемам с подключением. Решить их можно сужением выбора интерфейсов, то есть избегайте использования Name=* или других масок, которые соответствуют сетевым интерфейсам Docker. Убедитесь, что networkctl list в столбце SETUP сообщает unmanaged для таких интерфейсов.

Примечание:
  • Вам может понадобится перезапускать docker.service каждый раз, когда вы выполняете перезапуск systemd-networkd.service или iptables.service.
  • Также имейте в виду, что nftables может блокировать соединения docker по умолчанию. Используйте nft list ruleset, чтобы проверить наличие блокирующих правил. nft flush chain inet filter forward временно удаляет все правила пересылки. Отредактируйте /etc/nftables.conf, чтобы сделать изменения постоянными. Не забудьте перезапустить nftables.service для применения изменений из файла. Подробнее о поддержке nftables в Docker: [16].

Слишком маленькое разрешённое количество процессов/потоков по умолчанию

Если вы столкнетесь с сообщениями об ошибках, похожими на следующие:

# e.g. Java
java.lang.OutOfMemoryError: unable to create new native thread
# e.g. C, bash, ...
fork failed: Resource temporarily unavailable

то вам, возможно, необходимо изменить количество процессов, разрешённых systemd. Отредактируйте юнит docker.service следующим образом:

[Service]
TasksMax=infinity

Подробнее смотрите DefaultLimitNPROC в systemd-system.conf(5) § OPTIONS и TasksMax в systemd.resource-control(5) § OPTIONS.

Error initializing graphdriver: devmapper

Если systemctl не запускает Docker и выдаёт ошибку:

Error starting daemon: error initializing graphdriver: devmapper: Device docker-8:2-915035-pool is not a thin pool

Попробуйте выполнить следующие действия, чтобы устранить ошибку. Остановите службу, сделайте резервную копию /var/lib/docker/ (если это необходимо), удалите содержимое /var/lib/docker/ и попробуйте запустить службу. Смотрите описание проблемы на GitHub для более подробной информации.

Failed to create some/path/to/file: No space left on device

Если вы получаете сообщение об ошибке, подобное этому:

ERROR: Failed to create some/path/to/file: No space left on device

при создании или исполнении Docker образа, даже если у вас достаточно свободного места на диске, убедитесь, что:

  • Tmpfs отключен или имеет достаточно памяти. Docker может пытаться записать файлы в /tmp, но терпит неудачу из-за ограничений в использовании памяти, а не дискового пространства.
  • Если вы используете XFS, вы можете удалить опцию монтирования noquota из соответствующих записей в /etc/fstab (обычно тех, на которых находятся /tmp и/или /var/lib/docker). Для получения дополнительной информации обратитесь к Disk quota, особенно, если вы планируете использовать и изменить размер overlay2 Docker хранилища.
  • Варианты установки монтирования квоты XFS (uquota, gquota, prjquota, и т.д.) выдают ошибку при перемонтировании файловой системы. Чтобы включить квоту для корневой файловой системы, параметр монтирования должен быть передан как параметр ядра rootflags=. Впоследствии его не следует указывать среди параметров монтирования в /etc/fstab для корневой файловой системы (/).
Примечание: Есть некоторые отличия XFS Quota по сравнению со стандартом Linux Disk quota, [17] рекомендуется к прочтению.

Docker-machine не может создать виртуальные машины с драйвером virtualbox

Если docker-machine не может создать виртуальные машины с драйвером virtualbox и отображает следующую ошибку:

VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory

Перезагрузите virtualbox из командной строки с помощью команды vboxreload.

Запуск Docker ломает сетевой мост KVM

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

В примерах ниже замените br0 на имя своего моста.

Самое быстрое решение (но отключает все правила iptables, которые добавляет Docker, что может оказаться не тем, что вы хотите):

/etc/docker/daemon.json
{
  "iptables": false
}

Если для KVM уже настроен сетевой мост, проблему можно решить, попросив docker использовать этот самый мост: [18]

/etc/docker/daemon.json
{
  "bridge": "br0"
}

Если это не работает или вы предпочитаете решать проблему через iptables напрямую или через менеджер вроде UFW, добавьте следующее:

iptables -I FORWARD -i br0 -o br0 -j ACCEPT

Более подробные решения можно почитать здесь.

Ограничения на скачивание образов с Docker Hub

С 1 ноября 2020 года для загрузок из Docker Hub с анонимных и бесплатных аккаунтов включены лимиты (rate limiting). Подробнее в документации.

Лимиты для неаутентифицированных пользователей отслеживаются по IP-адресу, а для аутентифицированных — по учётной записи.

Если вам нужно превысить лимиты, вы можете либо использовать платный тарифный план, либо сделать зеркало нужных вам образов в другом реестре. Вы можете создать свой собственный реестр или использовать облачный хостинг, например Amazon ECR, Google Container Registry, Azure Container Registry или Quay Container Registry.

Чтобы создать зеркало образа, используйте pull, tag и push в Docker CLI. Пример создания зеркала образа Nginx 1.19.3 в реестре cr.example.com:

$ docker pull nginx:1.19.3
$ docker tag nginx:1.19.3 cr.example.com/nginx:1.19.3
$ docker push cr.example.com/nginx:1.19.3

После этого можно скачивать или запускать образы с зеркала:

$ docker pull cr.example.com/nginx:1.19.3
$ docker run cr.example.com/nginx:1.19.3

iptables (legacy): unknown option "--dport"

Если возникает такая ошибка при запуске контейнера, установите iptables-nft вместо iptables (legacy) и перезагрузитесь [19].

"Your password will be stored unencrypted" при выполнении docker login

По умолчанию Docker попытается использовать pass или secretservice для хранения паролей в реестре. Если он не найдёт эти программы, то сохранит пароли в виде обычного текста (закодированного в base64) в файле $HOME/.docker/config.json и выведет следующее сообщение после успешного входа в систему:

$ WARNING! Your password will be stored unencrypted in /home/пользователь/.docker/config.json.

Если вы используете менеджер паролей, реализующий Secret Service Freedesktop DBUS API, например, kwallet из KDE или gnome-keyring из GNOME, вы можете установить пакет docker-credential-secretserviceAUR, чтобы хранить пароли в своём менеджере.

"Could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network"

Иногда при использовании большого числа проектов на Docker (например, при использовании docker-compose), может случиться так, что у вас закончатся IP-адреса для контейнеров, что приведёт к возникновению ошибки:

Could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network

Как описано здесь, значения по умолчанию такие:

Тип Размер по умолчанию Пул по умолчанию
local /16 172.17.0.0/12
local* /20 192.168.0.0/16

Это можно легко исправить увеличением IP-пространства Docker через настройку default-address-pools в файле /etc/docker/daemon.json. Увеличьте первый диапазон с 16 до 24, а второй диапазон не трогайте, чтобы избежать коллизий в локальной сети:

/etc/docker/daemon.json
{
  ...
  "default-address-pools" : [
    {
      "base" : "172.17.0.0/12",
      "size" : 24
    },
    {
      "base" : "192.168.0.0/16",
      "size" : 24
    }
  ]
}

Перезапустите docker.service для применения изменений.

Более подробную информацию можно почитать в статье The definitive guide to docker's default-address-pools option.

Смотрите также