Введение

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.

Рис. 1
Рис. 1

FROM debian - указывает из какого образа из репозитория необходимо создать образ контейнера, произвести поиск доступных образов для загрузки можно командой sudo docker search debian.

Рис. 2
Рис. 2

Официальные образы помечены ОК

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
Рис. 3
Рис. 3

В данном примере имя созданного контейнера 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)


  1. 3vi1_0n3
    12.02.2022 09:22
    +3

    MAINTAINER считается deprecated с некоторого времени. Пруф


  1. edo1h
    12.02.2022 10:37
    +1

    Добавим ключи, а также репозитории:

    зачем вам прописывать отдельный репозиторий, чем не устраивают пакеты, идущие в составе дистрибутива?
    https://packages.debian.org/docker.io


    1. SergeyMax
      12.02.2022 13:10
      -1

      Возможно потому, что так написано в документации?


      1. edo1h
        12.02.2022 16:01

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


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


        1. ferocactus
          12.02.2022 16:14
          +2

          Есть один аргумент в пользу установки самой свежей версии, даже если она не в официальном репозитории.

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

          Да, считается, что в официальном репозитории версии более стабильные, проверенные теми, кто поддерживает репозиторий и/или даже сам дистрибутив ОС. Но что дальше, в случае если баг там всё-таки обнаружится? Поддержка репозитория ничем не поможет, лишь перенаправит к авторам пакета. А те, скажут "попробуйте последнюю версию". Так зачем удлиннять этот путь?

          Идея официальных репозиториев была красивая, но на практике, мне кажется, она изживает себя. Пакетов много, авторы разные, дистрибутивов тоже много -- мало кто хочет тратить время на поддержку своего пакета под десяток разных дистрибутивов. Так что не только со сторонних репозиториев ставить приходится, но и зачастую собирать из исходников.


          1. Revertis
            13.02.2022 00:31

            Идея официальных репозиториев была красивая, но на практике, мне кажется, она изживает себя. Пакетов много, авторы разные, дистрибутивов тоже много

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


    1. numb
      12.02.2022 14:17

      Возможно пакеты из реп дистра старее, чем те что в офф. репозитории докера


      1. edo1h
        12.02.2022 15:54

        да, старее. вам действительно нужна самая последняя версия докера?


        1. ferocactus
          12.02.2022 16:28
          +1

          А вам действительно нужна установка из официального репозитория?


          1. edo1h
            12.02.2022 16:50
            +4

            А вам действительно нужна установка из официального репозитория?

            да.


            1. это банально быстрее и проще;
            2. это несёт гораздо меньше потенциальных рисков по несовместимости между разными версиями пакетов.

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

            Так зачем удлиннять этот путь?

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


            и да, как минимум security fix'ы debian активно бэкпортирует.


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

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


            Идея официальных репозиториев была красивая, но на практике, мне кажется, она изживает себя.

            lfs никто не отмненял )


            1. ferocactus
              12.02.2022 17:11
              +1

              если столкнёшься с багом

              В моей практике это не если, а когда.

              Про lfs не понял.

              На самом деле я тоже предпочитал официальные репозитории альтернативным способам установки, так как чувствую, что это linux way. Но многократно сталкивался с багами или длительным отставанием даже мажорной версии dotnet, suricata, smbclient, grpc, terraform, terragrunt, terraspace, nodejs, а то и вовсе отсутствием для выбранного дистрибутива.

              Кстати, возможно, на идеоматичность подхода со временем повлияет тот факт, что в мире docker базовый образ по умолчанию это Alpine, если ни busybox. И всё более выраженной становится потребность иметь пакет именно для него. Хотя пока что как раз из-за отсутствия многих пакетов и приходится собирать образы на centos или debian (ну это, на самом деле, вообще экзотика).


      1. AVX
        12.02.2022 16:13

        Да вроде ж одинаковая версия 20.10. Или 20.10.12 vs 20.10.5 какое-то значение имеют на практике?


        1. SergeyMax
          13.02.2022 20:02

          Если бы не имело значения, их бы наверное не выпускали?)


    1. horror_x
      12.02.2022 19:46
      +4

      Сколько ни пользуюсь докером, всегда были проблемы со «стабильными» версиями в составе дистрибутива, особенно в LTS. То баг, который исправлен только в более поздних версиях, то фича, которая давно всеми используется, но доступна только с какой-то версии.

      Т.е. версия дистрибутива может и LTS, а вот docker нет.


      1. edo1h
        12.02.2022 23:44

        примеры можно? именно с докером из состава debain ни разу на грабли не наступал


        1. horror_x
          13.02.2022 00:15

          Да ещё б вспомнить. Поскольку обновление помогает, оно в памяти не оседает. Случайный пример: в Ubuntu 18.04 была такая проблема при использовании qmake. Его помню, потому что недавно пришлось один старый сборочный сервер из-за этого обновлять.

          А ради актуальных фич вообще частая история. Если не изменяет память, даже ради поддержки ARG в своё время приходилось обновляться.


  1. AVX
    12.02.2022 15:18

    Почему так сложно докер ставится?

    Разе не достаточно будет что-то вроде apt-get install -y docker ?

    Я на своём компе (не дебиан правда) поставил одной командой: urpmi docker

    Всё. И оно работает.


    1. edo1h
      12.02.2022 16:02
      +3

      да, всё так, только пакет в debian называется docker.io (имя пакета docker было уже занято)


    1. horror_x
      12.02.2022 19:48
      +2

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


  1. Tibor128
    12.02.2022 16:56
    +1

    Коль Вы тему изучали, то должны знать, что контейнеры к виртуализации не имеют ни какого отношение. Зачем писать чушь?


  1. mc2
    12.02.2022 20:52
    +1

    Зачем столько sudo?


    1. horror_x
      12.02.2022 21:02
      +3

      Наверное автор не знал про sudo usermod -aG docker $USER.


  1. maksasila
    12.02.2022 22:01

    Однако, это не создание собственного образа с нуля. Используется официальный образ Дебиана. Заявленная цель не достигнута. :)

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


  1. karabanov
    12.02.2022 23:09
    +1

    команду на создание образа необходимо выполнить из под sudo

    Если добавить пользователя в группу docker то можно и без sudo

    sudo usermod -aG docker $USER

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


  1. CrocodileRed
    13.02.2022 19:33

    Чем это лучше официальной документации?


  1. 13werwolf13
    14.02.2022 12:45
    +1

    ко всему вышесказанному негодованию добавлю ещё то что

    > докерфайл
    >> в mcedit
    >>> скриншотом
    >>>> с мака

    я так понимаю цель была "смотрите у меня есть мак"?