- Post-installation steps for Linux
- Manage Docker as a non-root user
- Configure Docker to start on boot
- Use a different storage engine
- Configure default logging driver
- Configure where the Docker daemon listens for connections
- Configuring remote access with systemd unit file
- Пользователь в Docker
- Создание пользователя
- Запуск процессов от пользователя
- Монтирование томов
- Присвоение пользователю UID и GID
- Передача идентификатора пользователя внутрь контейнера при построении образа
- Погружаемся в Docker: Dockerfile и коммуникация между контейнерами
- Dockerfile
- Коммуникация между контейнерами
- Заключение
Post-installation steps for Linux
Estimated reading time: 15 minutes
This section contains optional procedures for configuring Linux hosts to work better with Docker.
Manage Docker as a non-root user
The Docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo . The Docker daemon always runs as the root user.
If you don’t want to preface the docker command with sudo , create a Unix group called docker and add users to it. When the Docker daemon starts, it creates a Unix socket accessible by members of the docker group.
The docker group grants privileges equivalent to the root user. For details on how this impacts security in your system, see Docker Daemon Attack Surface.
To create the docker group and add your user:
Create the docker group.
Add your user to the docker group.
Log out and log back in so that your group membership is re-evaluated.
If testing on a virtual machine, it may be necessary to restart the virtual machine for changes to take effect.
On a desktop Linux environment such as X Windows, log out of your session completely and then log back in.
On Linux, you can also run the following command to activate the changes to groups:
Verify that you can run docker commands without sudo .
This command downloads a test image and runs it in a container. When the container runs, it prints a message and exits.
If you initially ran Docker CLI commands using sudo before adding your user to the docker group, you may see the following error, which indicates that your
/.docker/ directory was created with incorrect permissions due to the sudo commands.
To fix this problem, either remove the
/.docker/ directory (it is recreated automatically, but any custom settings are lost), or change its ownership and permissions using the following commands:
Configure Docker to start on boot
Most current Linux distributions (RHEL, CentOS, Fedora, Debian, Ubuntu 16.04 and higher) use systemd to manage which services start when the system boots. On Debian and Ubuntu, the Docker service is configured to start on boot by default. To automatically start Docker and Containerd on boot for other distros, use the commands below:
To disable this behavior, use disable instead.
If you need to add an HTTP Proxy, set a different directory or partition for the Docker runtime files, or make other customizations, see customize your systemd Docker daemon options.
Use a different storage engine
For information about the different storage engines, see Storage drivers. The default storage engine and the list of supported storage engines depend on your host’s Linux distribution and available kernel drivers.
Configure default logging driver
Docker provides the capability to collect and view log data from all containers running on a host via a series of logging drivers. The default logging driver, json-file , writes log data to JSON-formatted files on the host filesystem. Over time, these log files expand in size, leading to potential exhaustion of disk resources.
To alleviate such issues, either configure the json-file logging driver to enable log rotation, use an alternative logging driver such as the “local” logging driver that performs log rotation by default, or use a logging driver that sends logs to a remote logging aggregator.
Configure where the Docker daemon listens for connections
By default, the Docker daemon listens for connections on a UNIX socket to accept requests from local clients. It is possible to allow Docker to accept requests from remote hosts by configuring it to listen on an IP address and port as well as the UNIX socket. For more detailed information on this configuration option take a look at “Bind Docker to another host/port or a unix socket” section of the Docker CLI Reference article.
Before configuring Docker to accept connections from remote hosts it is critically important that you understand the security implications of opening docker to the network. If steps are not taken to secure the connection, it is possible for remote non-root users to gain root access on the host. For more information on how to use TLS certificates to secure this connection, check this article on how to protect the Docker daemon socket.
Configuring Docker to accept remote connections can be done with the docker.service systemd unit file for Linux distributions using systemd, such as recent versions of RedHat, CentOS, Ubuntu and SLES, or with the daemon.json file which is recommended for Linux distributions that do not use systemd.
Configuring Docker to listen for connections using both the systemd unit file and the daemon.json file causes a conflict that prevents Docker from starting.
Configuring remote access with systemd unit file
Use the command sudo systemctl edit docker.service to open an override file for docker.service in a text editor.
Add or modify the following lines, substituting your own values.
Источник
Пользователь в Docker
Андрей Копылов, наш технический директор, любит, активно использует и пропагандирует Docker. В новой статье он рассказывает, как создать пользователей в Docker. Правильная работа с ними, почему пользователей нельзя оставлять с root правами и, как решить задачу несовпадения идентификаторов в Dockerfile.
Все процессы в контейнере будут работать из-под пользователя root, если специальным образом его не указать. Это кажется очень удобно, ведь у этого пользователя нет никаких ограничений. Именно поэтому работать под рутом неправильно с точки зрения безопасности. Если на локальном компьютере никто в здравом уме не работает с рутовыми правами, то многие запускают процессы под рутом в контейнерах.
Всегда есть баги, которые позволят зловреду выбраться из контейнера и попасть на хостовый компьютер. Предполагая худшее, мы должны обеспечить запуск процессов внутри контейнера от пользователя, который не имеет никаких прав на хостовой машине.
Создание пользователя
Создание пользователя в контейнере не отличается от его создания в линуксовых дистрибутивах. Однако для разных базовых образов команды могут различаться.
Для дистрибутивов основанных на debian в Dockerfile необходимо добавить:
Запуск процессов от пользователя
Для запуска всех последующих процессов от пользователя с UID 2000 выполните:
Для запуска всех последующих процессов от пользователя node выполните:
Монтирование томов
При монтировании томов внутрь контейнера обеспечьте пользователю возможность читать и (или) писать файлы. Для этого UID (GID) пользователя в контейнере и пользователя за пределами контейнера, у которого есть соответствующие права на доступ к файлу, должны соответствовать. При этом имена пользователей значения не имеют.
Часто на линуксовом компьютере у пользователя UID и GID равны 1000. Эти идентификаторы присваиваются первому пользователю компьютера.
Узнать свои идентификаторы просто:
Вы получите исчерпывающую информацию о своем пользователе.
Замените 2000 из примеров на свой идентификатор и все будет в порядке.
Присвоение пользователю UID и GID
Если пользователь создан ранее, но необходимо изменить идентификаторы, то можно сделать это так:
Если вы используете базовый образ alpine, то нужно установить пакет shadow:
Передача идентификатора пользователя внутрь контейнера при построении образа
Если ваш идентификатор и идентификаторы всех людей, которые работают над проектом, совпадают, то достаточно указать этот идентификатор в Dockerfile. Однако часто идентификаторы пользователей не совпадают.
Как осуществить желаемое не сразу понятно. Для меня это было самым сложным в процессе освоения docker. Многие пользователи docker не задумываются о том, что есть разные этапы жизни образа. Сначала образ собирается для этого используют Dockerfile. При запуске контейнера из образа Dockerfile уже не используется.
Создание пользователей должно происходить при построении образа. Это же касается и определения пользователя, из-под которого запускаются процессы. Значит, что мы каким-то образом должны передать внутрь контейнера UID (GID).
Для использования внешних переменных в Dockerfile служат директивы ENV и ARG. Подробное сравнение директив тут.
Передать аргументы через docker-compose можно так:
Источник
Погружаемся в Docker: Dockerfile и коммуникация между контейнерами
В прошлой статье мы рассказали, что такое Docker и как с его помощью можно обойти Vendor–lock. В этой статье мы поговорим о Dockerfile как о правильном способе подготовки образов для Docker. Также мы рассмотрим ситуацию, когда контейнерам нужно взаимодействовать друг с другом.
В InfoboxCloud мы сделали готовый образ Ubuntu 14.04 с Docker. Не забудьте поставить галочку «Разрешить управление ядром ОС» при создании сервера, это требуется для работы Docker.
Dockerfile
Подход docker commit, описанный в предыдущей статье, не является рекомендованным для Docker. Его плюс состоит в том, что мы настраиваем контейнер практически так, как привыкли настраивать стандартный сервер.
Вместо этого подхода мы рекомендуем использовать подход Dockerfile и команду docker build. Dockerfile использует обычный DSL с инструкциями для построения образов Docker. После этого выполняется команда docker build для построения нового образа с инструкциями в Dockerfile.
Написание Dockerfile
Давайте создадим простой образ с веб-сервером с помощью Dockerfile. Для начала создадим директорию и сам Dockerfile.
Созданная директория — билд-окружение, в которой Docker вызывает контекст или строит контекст. Docker загрузит контекст в папке в процессе работы Docker–демона, когда будет запущена сборка образа. Таким образом будет возможно для Docker–демона получить доступ к любому коду, файлам или другим данным, которые вы захотите включить в образ.
Добавим в Dockerfile информацию по построению образа:
Dockerfile содержит набор инструкций с аргументами. Каждая инструкция пишется заглавными буквами (например FROM). Инструкции обрабатываются сверху вниз. Каждая инструкция добавляет новый слой в образ и коммитит изменения. Docker исполняет инструкции, следуя процессу:
- Запуск контейнера из образа
- Исполнение инструкции и внесение изменений в контейнер
- Запуск эквивалента docker commit для записи изменений в новый слой образа
- Запуск нового контейнера из нового образа
- Исполнение следующей инструкции в файле и повторение шагов процесса.
Это означает, что если исполнение Dockerfile остановится по какой-то причине (например инструкция не сможет завершиться), вы сможете использовать образ до этой стадии. Это очень полезно при отладке: вы можете запустить контейнер из образа интерактивно и узнать, почему инструкция не выполнилась, используя последний созданный образ.
Также Dockerfile поддерживает комментарии. Любая строчка, начинающаяся с # означает комментарий.
Первая инструкция в Dockerfile всегда должна быть FROM, указывающая, из какого образа нужно построить образ. В нашем примере мы строим образ из базового образа ubuntu версии 14:04.
Далее мы указываем инструкцию MAINTAINER, сообщающую Docker автора образа и его email. Это полезно, чтобы пользователи образа могли связаться с автором при необходимости.
Инструкция RUN исполняет команду в конкретном образе. В нашем примере с помощью ее мы обновляем APT репозитории и устанавливаем пакет с NGINX, затем создаем файл /usr/share/nginx/html/index.html.
По-умолчанию инструкция RUN исполняется внутри оболочки с использованием обертки команд /bin/sh -c. Если вы запускаете инструкцию на платформе без оболочки или просто хотите выполнить инструкцию без оболочки, вы можете указать формат исполнения:
Мы используем этот формат для указания массива, содержащего команду для исполнения и параметры команды.
Далее мы указываем инструкцию EXPOSE, которая говорит Docker, что приложение в контейнере должно использовать определенный порт в контейнере. Это не означает, что вы можете автоматически получать доступ к сервису, запущенному на порту контейнера (в нашем примере порт 80). По соображениям безопасности Docker не открывает порт автоматически, но ожидает, когда это сделает пользователь в команде docker run. Вы можете указать множество инструкций EXPOSE для указания, какие порты должны быть открыты. Также инструкция EXPOSE полезна для проброса портов между контейнерами.
Строим образ из нашего файла
, где trukhinyuri – название репозитория, где будет храниться образ, nginx – имя образа. Последний параметр — путь к папке с Dockerfile. Если вы не укажете название образа, он автоматически получит название latest. Также вы можете указать git репозиторий, где находится Dockerfile.
В данном примере мы строим образ из Dockerfile, расположенном в корневой директории Docker.
Если в корне билд контекста есть файл .dockerignore – он интерпретируется как список паттернов исключений.
Что произойдет, если инструкция не исполнится?
Давайте переименуем в Dockerfile nginx в ngin и посмотрим.
Мы можем создать контейнер из предпоследнего шага с ID образа 066b799ea548
docker run -i -t 066b799ea548 /bin/bash
и отладить исполнение.
По-умолчанию Docker кеширует каждый шаг и формируя кеш сборок. Чтобы отключить кеш, например для использования последнего apt-get update, используйте флаг —no-cache.
Использования кеша сборок для шаблонизации
Используя кеш сборок можно строить образы из Dockerfile в форме простых шаблонов. Например шаблон для обновления APT-кеша в Ubuntu:
Инструкция ENV устанавливает переменные окружения в образе. В данном случае мы указываем, когда шаблон был обновлен. Когда необходимо обновить построенный образ, просто нужно изменить дату в ENV. Docker сбросит кеш и версии пакетов в образе будут последними.
Инструкции Dockerfile
Давайте рассмотрим и другие инструкции Dockerfile. Полный список можно посмотреть тут.
Инструкция CMD указывает, какую команду необходимо запустить, когда контейнер запущен. В отличие от команды RUN указанная команда исполняется не во время построения образа, а во время запуска контейнера.
В данном случае мы запускаем bash и передаем ему параметр в виде массива. Если мы задаем команду не в виде массива — она будет исполняться в /bin/sh -c. Важно помнить, что вы можете перегрузить команду CMD, используя docker run.
ENTRYPOINT
Часто команду CMD путают с ENTRYPOINT. Разница в том, что вы не можете перегружать ENTRYPOINT при запуске контейнера.
При запуске контейнера параметры передаются команде, указанной в ENTRYPOINT.
Можно комбинировать ENTRYPOINT и CMD.
В этом случае команда в ENTRYPOINT выполнится в любом случае, а команда в CMD выполнится, если не передано другой команды при запуске контейнера. Если требуется, вы все-таки можете перегрузить команду ENTRYPOINT с помощью флага —entrypoint.
WORKDIR
С помощью WORKDIR можно установить рабочую директорию, откуда будут запускаться команды ENTRYPOINT и CMD.
Вы можете перегрузить рабочую директорию контейнера в рантайме с помощью флага -w.
Специфицирует пользователя, под которым должен быть запущен образ. Мы можем указать имя пользователя или UID и группу или GID.
Вы можете перегрузить эту команду, используя глаг -u при запуске контейнера. Если пользователь не указан, используется root по-умолчанию.
VOLUME
Инструкция VOLUME добавляет тома в образ. Том — папка в одном или более контейнерах или папка хоста, проброшенная через Union File System (UFS).
Тома могут быть расшарены или повторно использованы между контейнерами. Это позволяет добавлять и изменять данные без коммита в образ.
В примере выше создается точка монтирования /opt/project для любого контейнера, созданного из образа. Таким образом вы можете указывать и несколько томов в массиве.
Инструкция ADD добавляет файлы или папки из нашего билд-окружения в образ, что полезно например при установке приложения.
Источником может быть URL, имя файла или директория.
В последнем примере архив tar.gz будет распакован в /var/www/wordpress. Если путь назначения не указан — будет использован полный путь включая директории.
Инструкция COPY отличается от ADD тем, что предназначена для копирования локальных файлов из билд-контекста и не поддерживает распаковки файлов:
ONBUILD
Инструкция ONBUILD добавляет триггеры в образы. Триггер исполняется, когда образ используется как базовый для другого образа, например, когда исходный код, нужный для образа еще не доступен, но требует для работы конкретного окружения.
Коммуникация между контейнерами
В предыдущей статье было показано, как запускать изолированные контейнеры Docker и как пробрасывать файловую систему в них. Но что, если приложениям нужно связываться друг с другом. Есть 2 способа: связь через проброс портов и линковку контейнеров.
Проброс портов
Такой способ связи уже был показан ранее. Посмотрим на варианты проброса портов чуть шире.
Когда мы используем EXPOSE в Dockerfile или параметр -p номер_порта – порт контейнера привязывается к произвольному порту хоста. Посмотреть этот порт можно командой docker ps или docker port имя_контейнера номер_порта_в_контейнере. В момент создания образа мы можем не знать, какой порт будет свободен на машине в момент запуска контейнера.
Указать, на какой конкретный порт хоста мы привяжем порт контейнера можно параметром docker run -p порт_хоста: порт_контейнера
По-умолчанию порт используется на всех интерфейсах машины. Можно, например, привязать к localhost явно:
Можно привязать UDP порты, указав /udp:
Линковка контейнеров
Связь через сетевые порты — лишь один способ коммуникации. Docker предоставляет систему линковки, позволяющую связать множество контейнеров вместе и отправлять информацию о соединении от одного контейнера другому.
Для установки связи нужно использовать имена контейнеров. Как было показано ранее, вы можете дать имя контейнеру при создании с помощью флага —name.
Допустим у вас есть 2 контейнера: web и db. Чтобы создать связь, удалите контейнер web и пересоздайте с использованием команды —link name:alias.
Используя docker -ps можно увидеть связанные контейнеры.
Что на самом деле происходит при линковке? Создается контейнер, который предоставляет информацию о себе контейнеру-получателю. Это происходит двумя способами:
- Через переменные окружения
- Через /etc/hosts
Переменные окружения можно посмотреть, выполнив команду env:
Префикс DB_ был взят из alias контейнера.
Можно просто использовать информацию из hosts, например команда ping db (где db – alias) будет работать.
Заключение
В этой статье мы научились использовать Dockerfile и организовывать связь между контейнерами. Это только вершина айсберга, очень многое осталось за кадром и будет рассмотрено в будущем. Для дополнительного чтения рекомендуем книгу The Docker Book.
Готовый образ с Docker доступен в облаке InfoboxCloud.
В случае, если вы не можете задавать вопросы на Хабре, можно задать в Сообществе InfoboxCloud.
Если вы обнаружили ошибку в статье, автор ее с удовольствием исправит. Пожалуйста напишите в ЛС или на почту о ней.
Источник