Введение
Docker единственная система контейнерной виртуализации с которой мне еще не доводилось сталкиваться, по этому после изучения данной темы решил написать данную публикацию. В данной публикации пойдет речь о сборке собственного образа (с помощью dockerfile) на основе официальных образов системы от debian, монтировании различных файловых систем (nfs, btrfs, ext4), а также о различных параметрах dockerfile и командах управления контейнерами docker.
Создание образа
Перед созданием образа необходимо установить некоторые зависимости для корректного добавления официальных GPG-ключ Docker:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
Добавим ключи, а также репозитории:
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Установим Docker Engine:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
После данных манипуляций можно приступать к сборке собственного образа, путем создания файла Dockerfile (данный файл можно создать, например, в каталоге пользователя), команду на создание образа необходимо выполнить из под sudo. На рисунке 1 представлен пример файла Dockerfile.
FROM debian
- указывает из какого образа из репозитория необходимо создать образ контейнера, произвести поиск доступных образов для загрузки можно командой sudo docker search debian.
Официальные образы помечены ОК
MAINTAINER nemets
- указать автора образа.
RUN apt-get update
- обновить список доступных пакетов.
RUN apt-get install -y apache2 mc htop net-tools nfs-common && apt-get clean
- установить apache2, а также дополнительные пакеты, при необходимости.
VOLUME /etc/apach2
- создать точку монтирования.
#WORKDIR /home
- указывает текущий каталог для работы (например, если использовать директиву COPY test.txt user/test.txt, то файл будет скопирован в каталог /home/user).
COPY --chown=www-data:www-data test.txt /home/
- скопировать файл test.txt из каталога из которого была выполнена сборка образа в каталог /home, с правами www-data, если указанного пользователя не существует, то в этом случаи появится ошибка (можно указать uid и gid пользователя).
ADD --chown=www-data:www-data test.txt /home
- команда аналогична команде copy.
ENV MY_NAME="nemets"
- создать постоянную переменную окружения для образа.
ARG NAME="nemets"
- создать временную переменную, данная переменная будет доступна только во время создания образа.
EXPOSE 80/tcp
- указать, что в образе используется 80 порт tcp (исключительно информационная опция, при запуске контейнера в любом случаи необходимо явно указать порты).
EXPOSE 443/tcp
- указать, что в образе используется 443 порт tcp.
#EXPOSE 80/udp
- указать, что в образе используется 80 порт udp.
#EXPOSE 443/udp
- указать, что в образе используется 443 порт udp.
#USER root
- указать от какого пользователя необходимо выполнять команды, в данном примере apache по умолчанию запускается от пользователя root, по этой причине данная директива не обязательна, если например контейнер используется для запуска postgresql, то в директиве user необходимо использовать postgres, так как postgresql запускается от пользователя postgres.
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
- данная строка укажет образу, что необходимо выполнять apache с данными параметрами при запуске контейнера. В официальной документации данный способ запуска (exec) является предпочтительным, так как docker предполагается, что процесс будет один и с pid 1, а также в этом случаи процесс будет корректно принимать unix сигналы, но нужно учитывать, что при данном способе запуска не будут доступны переменные окружения, и по этой причине необходимо указать полный путь до apachectl.
#ENTRYPOINT apachectl -D FOREGROUND
- данный способ запуска apache происходит через shell, по этой причине в контейнере будет запущенно как минимум два процесса (/bin/bash и httpd), а также будут доступны переменные окружения.
#CMD echo "Hello world"
- данная команда дополнит команду ENTRYPOINT, но только если ENTRYPOINT выполняется в режиме exec, если ENTRYPOINT выполняется в режиме shell, то директива CMD будет проигнорирована (также можно в директиве указать запуск apache, как и в директиве ENTRYPOINT).
После того как Dockerfile был создан, можно приступать к сборке образа, для этого необходимо выполнить команду:
sudo docker build -t local/debian .
ключ -t
добавит имя и "тэг" (формата name/tag) для созданного контейнера.
При необходимости можно выгрузить созданный образ в репозитории (необходима регистрация):
docker push yourname/newimage
Команды для работы с образами и контейнерами
Для просмотра созданного образа используется команда:
sudo docker images
Для удаления созданного образа используется команда:
sudo docker rmi local/debian
Можно приступать к запуску контейнера, после его запуска, контейнеру будет присвоено имя, а также CONTAINER ID, по которым можно обращаться к контейнеру:
sudo docker run -d --restart=always --cpuset-cpus="0" --cpus=".5" --memory="1g" --memory-swap="1g" -p 80:80 -p 443:443 -v /home/user:/user --add-host=docker:10.180.0.1 local/debian
-d
- запустит контейнер в фоновом режиме.
--restart-always
- поместить контейнер в автозапуск.
--cpuset-cpus="0"
- разрешить использовать только первое ядро процессора (можно указать ядра через запятую 0,3,5, или через тире 0-2).
--cpus=".5"
- использовать процессор максимум на 50%.
--memory="1g"
- ограничить использование оперативной памяти в 1 ГБ.
--memory-swap="1g"
- ограничить использование swap в 1 ГБ.
-p 80:80 -p 443:443
- пробросить 80 и 443 порты в контейнер.
-v /home/user:/user
- смонтировать каталог /home/user в папку /user контейнера.
--add-host=docker:10.180.0.1
- добавить запись в файл /etc/hosts.
local/debian
- имя образа на основе которого будет создан и запущен контейнер.
Список запущенных контейнером можно посмотреть командой:
sudo docker ps
Список всех контейнеров, в том числе не запущенных, можно посмотреть командой:
sudo docker ps -a
В данном примере имя созданного контейнера vibrant_pascal, а CONTAINER ID - 174fdcafd234, именно по этим параметрам можно обращаться к контейнеру:
sudo docker stop vibrant_pascal #остановить выполнение контейнера
sudo docker start 174fdcafd234 #запустить контейнер
sudo docker pause 174fdcafd234 #поставить контейнер на паузу
sudo docker unpause 174fdcafd234 #запустить контейнер поставленный на паузу
sudo docker stats 174fdcafd234 #посмотреть использование ресурсов контейнером
sudo docker rm 174fdcafd234 #удалить контейнер
Для того что бы войти в контейнер необходимо выполнить команду:
sudo docker exec -it vibrant_pascal bash
Иногда после каких либо изменений в контейнере, необходимо сохранить данные изменения в изначальный образ, для этого следует использовать команду:
docker commit -m "added updates" -a "nemets" 174fdcafd234 local/debian
-m
- комментарий с информацией об изменениях в образе.
-a
- имя автора изменений.
Также можно указать другое имя образа (например local/debian1), если, например, необходимо сохранить изначальный образ.
Для того что бы создать еще один контейнер из образа, достаточно еще раз выполнить команду:
sudo docker run -d --restart=always --cpuset-cpus="0" --cpus=".5" --memory="1g" --memory-swap="1g" -p 8080:80 -p 4443:443 -v /home/user:/user --add-host=docker:10.180.0.1 local/debian
но при этом необходимо указать другой порт.
Монтирование nfs "шары"
Первым делом необходимо поднять nfs сервер, для этого необходимо установить следующие пакеты:
sudo apt install nfs-kernel-server nfs-common portmap
Внесем изменения в файл /etc/exports, а именно добавим строку:
/mnt 192.168.1.0/24(rw,no_root_squash)
Данная строка разрешит доступ к каталогу /mnt всем хостам из сети 192.168.1.0/24.
Активируем и запустим nfs сервер:
sudo systemctl enable nfs-server
sudo systemctl start nfs-server
После того как nfs сервер запущен, можно приступать к созданию сервиса volume для docker (в данном примере nfs сервер запущен на 192.168.1.103):
sudo docker volume create --driver local --opt type=nfs --opt o=addr=192.168.1.103,rw --opt device=:/mnt shara
После выполнения данной команды, в docker будет создан volume с именем shara, который можно монтировать во вновь созданные контейнеры. Для того что бы смонтировать созданную "шару" в контейнер в команду run необходимо добавить --mount source=shara,target=/mnt
sudo docker run -d --restart=always --cpuset-cpus="0" --cpus=".5" --memory="1g" --memory-swap="1g" -p 8080:80 -p 8443:443 --mount source=shara,target=/mnt -v /home/user:/user --add-host=docker:10.180.0.1 local/debian
При создании volume для параметра --opt type
возможно использовать следующие параметры:
--opt type=cifs
- монтировать smb "шару"
--opt type=btrfs
- монтировать раздел btrfs
--opt type=ext4
- монтировать раздел ext4
Также необходимо указать устройство с указанной файловой системой:
--opt device=/dev/sda2
Команда для создания ext4 volume будет выглядеть так:
sudo docker volume create --driver local --opt type=ext4 --opt device=/dev/sda2 shara
Вывод
Как видно из данной публикации создание собственного образа не сложный процесс, на мой взгляд лучше использовать собственный образ, чем использовать уже созданные не официальные, в которых может находиться вредоносный софт.
Список источников, которые мне помогли в написании данной публикации
Комментарии (26)
edo1h
12.02.2022 10:37+1Добавим ключи, а также репозитории:
зачем вам прописывать отдельный репозиторий, чем не устраивают пакеты, идущие в составе дистрибутива?
https://packages.debian.org/docker.ioSergeyMax
12.02.2022 13:10-1Возможно потому, что так написано в документации?
edo1h
12.02.2022 16:01да, вполне разумный аргумент.
но инструкция не является догмой.на мой взгляд нужно отдавать предпочтение предоставляемым дистрибутивом версиям пакетов, если только нет веских причин поступать иначе (например, требуется функционал новых версий, которого нет в версии из дистрибутива).
ferocactus
12.02.2022 16:14+2Есть один аргумент в пользу установки самой свежей версии, даже если она не в официальном репозитории.
Когда столкнёшься с багом, и начнёшь разбираться, то либо обнаружишь, что он уже исправлен в свежей версии, либо, что старая версия не поддерживается и нужно проверить в последней, для составления багрепорта. После которого фикс выпустят так же только в ещё более новой версии.
Да, считается, что в официальном репозитории версии более стабильные, проверенные теми, кто поддерживает репозиторий и/или даже сам дистрибутив ОС. Но что дальше, в случае если баг там всё-таки обнаружится? Поддержка репозитория ничем не поможет, лишь перенаправит к авторам пакета. А те, скажут "попробуйте последнюю версию". Так зачем удлиннять этот путь?
Идея официальных репозиториев была красивая, но на практике, мне кажется, она изживает себя. Пакетов много, авторы разные, дистрибутивов тоже много -- мало кто хочет тратить время на поддержку своего пакета под десяток разных дистрибутивов. Так что не только со сторонних репозиториев ставить приходится, но и зачастую собирать из исходников.
Revertis
13.02.2022 00:31Идея официальных репозиториев была красивая, но на практике, мне кажется, она изживает себя. Пакетов много, авторы разные, дистрибутивов тоже много
Важнее проблема того, что все программы разрабатываются с разной скоростью. А современные и новые программы релизятся каждые несколько дней-недль, и зависеть от меинтейнера плохой выбор.
numb
12.02.2022 14:17Возможно пакеты из реп дистра старее, чем те что в офф. репозитории докера
edo1h
12.02.2022 15:54да, старее. вам действительно нужна самая последняя версия докера?
ferocactus
12.02.2022 16:28+1А вам действительно нужна установка из официального репозитория?
edo1h
12.02.2022 16:50+4А вам действительно нужна установка из официального репозитория?
да.
- это банально быстрее и проще;
- это несёт гораздо меньше потенциальных рисков по несовместимости между разными версиями пакетов.
Когда столкнёшься с багом, и начнёшь разбираться, то либо обнаружишь, что он уже исправлен в свежей версии, либо, что старая версия не поддерживается и нужно проверить в последней, для составления багрепорта. После которого фикс выпустят так же только в ещё более новой версии.
…
Так зачем удлиннять этот путь?если столкнёшься с багом, то да, всё так, в первую очередь проверяешь вопроизводимость на версии из апстрима.
только практика говорит, что на свежих версиях вероятность наткнуться на баг никак не меньше.и да, как минимум security fix'ы debian активно бэкпортирует.
Пакетов много, авторы разные, дистрибутивов тоже много — мало кто хочет тратить время на поддержку своего пакета под десяток разных дистрибутивов
разумеется. поэтому лучше пусть пакет собирают мейнтейнеры, которые хорошо знают дистрибутив, а не разработчик, который видел его один раз в виртуалке.
Идея официальных репозиториев была красивая, но на практике, мне кажется, она изживает себя.
lfs никто не отмненял )
ferocactus
12.02.2022 17:11+1если столкнёшься с багом
В моей практике это не если, а когда.
Про lfs не понял.
На самом деле я тоже предпочитал официальные репозитории альтернативным способам установки, так как чувствую, что это linux way. Но многократно сталкивался с багами или длительным отставанием даже мажорной версии dotnet, suricata, smbclient, grpc, terraform, terragrunt, terraspace, nodejs, а то и вовсе отсутствием для выбранного дистрибутива.
Кстати, возможно, на идеоматичность подхода со временем повлияет тот факт, что в мире docker базовый образ по умолчанию это Alpine, если ни busybox. И всё более выраженной становится потребность иметь пакет именно для него. Хотя пока что как раз из-за отсутствия многих пакетов и приходится собирать образы на centos или debian (ну это, на самом деле, вообще экзотика).
horror_x
12.02.2022 19:46+4Сколько ни пользуюсь докером, всегда были проблемы со «стабильными» версиями в составе дистрибутива, особенно в LTS. То баг, который исправлен только в более поздних версиях, то фича, которая давно всеми используется, но доступна только с какой-то версии.
Т.е. версия дистрибутива может и LTS, а вот docker нет.edo1h
12.02.2022 23:44примеры можно? именно с докером из состава debain ни разу на грабли не наступал
horror_x
13.02.2022 00:15Да ещё б вспомнить. Поскольку обновление помогает, оно в памяти не оседает. Случайный пример: в Ubuntu 18.04 была такая проблема при использовании qmake. Его помню, потому что недавно пришлось один старый сборочный сервер из-за этого обновлять.
А ради актуальных фич вообще частая история. Если не изменяет память, даже ради поддержки ARG в своё время приходилось обновляться.
AVX
12.02.2022 15:18Почему так сложно докер ставится?
Разе не достаточно будет что-то вроде apt-get install -y docker ?
Я на своём компе (не дебиан правда) поставил одной командой: urpmi docker
Всё. И оно работает.
edo1h
12.02.2022 16:02+3да, всё так, только пакет в debian называется docker.io (имя пакета docker было уже занято)
horror_x
12.02.2022 19:48+2Так сама установка так и происходит, просто сначала добавляется репозиторий самого докера, чтобы была актуальная версия. Если актуальность не критична, можно обойтись и без этого.
Tibor128
12.02.2022 16:56+1Коль Вы тему изучали, то должны знать, что контейнеры к виртуализации не имеют ни какого отношение. Зачем писать чушь?
maksasila
12.02.2022 22:01Однако, это не создание собственного образа с нуля. Используется официальный образ Дебиана. Заявленная цель не достигнута. :)
Как видно из данной публикации создание собственного образа не сложный процесс, на мой взгляд лучше использовать собственный образ, чем использовать уже созданные не официальные, в которых может находится вредоносный софт.
karabanov
12.02.2022 23:09+1команду на создание образа необходимо выполнить из под sudo
Если добавить пользователя в группу docker то можно и без sudo
sudo usermod -aG docker $USER
После выполнения этой команды надо перелогиниться, что бы настройки вступили в силу.
13werwolf13
14.02.2022 12:45+1ко всему вышесказанному негодованию добавлю ещё то что
> докерфайл
>> в mcedit
>>> скриншотом
>>>> с макая так понимаю цель была "смотрите у меня есть мак"?
3vi1_0n3
MAINTAINER считается deprecated с некоторого времени. Пруф