Создание собственного образа Docker

Thank you for reading this post, don't forget to subscribe!

Docker поз­во­ля­ет не толь­ко загру­жать и исполь­зо­вать гото­вые кон­тей­не­ры, но созда­вать свои. В дан­ной инструк­ции мы поша­го­во раз­бе­рем уста­нов­ку Docker на Linux, созда­ние соб­ствен­но­го обра­за и загруз­ку его на Docker Hub.

Установка Docker

Рас­смот­рим при­ме­ры уста­нов­ки на базе опе­ра­ци­он­ных систем Red Hat/CentOS и Debian/Ubuntu.

Red Hat/CentOS

Уста­нав­ли­ва­ем репо­зи­то­рий — для это­го загру­жа­ем файл с настрой­ка­ми репозитория:

wget https://download.docker.com/linux/centos/docker-ce.repo

* если систе­ма вер­нет ошиб­ку, уста­нав­ли­ва­ем wget коман­дой yum install wget.

… и пере­но­сим его в ката­лог yum.repos.d:

mv docker-ce.repo /etc/yum.repos.d/

Уста­нав­ли­ва­ем docker:

yum install docker-ce docker-ce-cli containerd.io

Если систе­ма вер­нет ошиб­ку Необ­хо­ди­мо: container-selinux >= …, пере­хо­дим на стра­ни­цу паке­тов CentOS, нахо­дим нуж­ную вер­сию container-selinux и копи­ру­ем на него ссылку:

… с помо­щью дан­ной ссыл­ки выпол­ня­ем установку:

yum install http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.99-1.el7_6.noarch.rpm

После повто­ря­ем коман­ду на уста­нов­ку докера:

yum install docker-ce docker-ce-cli containerd.io

Debian/Ubuntu

В deb-систе­ме ста­вит­ся командой:

apt-get install docker docker.io

После установки

Раз­ре­ша­ем запуск сер­ви­са docker:

systemctl enable docker

… и запус­ка­ем его:

systemctl start docker

После про­ве­ря­ем:

docker run hello-world

… мы долж­ны увидеть:


Hello from Docker!
This message shows that your installation appears to be working correctly.

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

Сбор­ка начи­на­ет­ся с созда­ния фай­ла Dockerfile — он содер­жит инструк­ции того, что долж­но быть в кон­тей­не­ре. В каче­стве при­ме­ра, собе­рем свой веб-сер­вер nginx.

И так, что­бы создать свой образ с нуля, созда­ем ката­лог для раз­ме­ще­ния Dockerfile:

mkdir -p /opt/docker/mynginx

* где /opt/docker/mynginx — пол­ный путь до ката­ло­га, где будем созда­вать образ.

… пере­хо­дим в дан­ный каталог:

cd /opt/docker/mynginx

… и созда­ем Dockerfile:

vi Dockerfile

* в дан­ном фай­ле мы:

  1. исполь­зу­ем базо­вый образ centos 7;
  2. в каче­стве авто­ра обра­за ука­зы­ва­ем Andrey;
  3. уста­нав­ли­ва­ем epel-release и nginx;
  4. чистим систе­му от мета­дан­ных и кэша паке­тов после установки;
  5. ука­зы­ва­ем nginx запус­кать­ся на перед­нем плане (daemon off); 
  6. в индекс­ном фай­ле меня­ем пер­вое вхож­де­ние nginx на docker-nginx;
  7. запус­ка­ем nginx.

 

Запус­ка­ем сборку:

docker build -t test/nginx:v1 .

* где test— имя авто­ра; nginx — назва­ние для сбор­ки; v1 — тег с ука­за­ни­ем вер­сии. Точ­ка на кон­це ука­зы­ва­ет, что поиск Dockerfile выпол­ня­ем в теку­щей директории.

… нач­нет­ся про­цесс сбор­ки обра­за — после его завер­ше­ния мы долж­ны уви­деть что-то на подобие:

Successfully built eae801eaeff2
Successfully tagged test/nginx:v1

Посмот­реть спи­сок обра­зов мож­но командой:

docker images

Созда­ем и запус­ка­ем кон­тей­нер из образа:

docker run -d -p 8080:80 test/nginx:v1

* в дан­ном при­ме­ре мы запу­стим кон­тей­нер из обра­за test/nginx:v1 и ука­жем, что необ­хо­ди­мо опуб­ли­ко­вать внеш­ний порт 8080, кото­рый будет пере­на­прав­лять тра­фик на порт 80 внут­ри контейнера.

Откры­ва­ем бра­у­зер и пере­хо­дим по адре­су http://<IP-адрес наше­го докера>:8080 — мы долж­ны уви­деть стра­ни­цу при­вет­ствия с нашим docker-nginx:

Посмот­реть создан­ные кон­тей­не­ры мож­но командой:

docker ps -a

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

docker stop 5fe78aca2e1d

docker start 5fe78aca2e1d

* где 5fe78aca2e1d — иден­ти­фи­ка­тор контейнера.

Редактирование образа

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

Ска­ча­ем образ опе­ра­ци­он­ной систе­мы CentOS:

docker pull centos:latest

Вой­дем в ска­чан­ный образ для его изменения:

docker run -t -i centos:latest /bin/bash

Вне­сем неболь­шие изме­не­ния, напри­мер, созда­дим учет­ную запись:

[root@8f07ef93918f /]# useradd test -G wheel -m

[root@8f07ef93918f /]# passwd test

[root@8f07ef93918f /]# exit

* в дан­ном при­ме­ре мы созда­ли поль­зо­ва­те­ля test и зада­ли ему пароль.

Ком­ми­тим образ:

docker commit -m "Add user test" -a "Andrey" 8f07ef93918f centos:my

* где -m — пара­метр для ука­за­ния ком­мен­та­рия; -a — ука­зы­ва­ет авто­ра; 8f07ef93918f — иден­ти­фи­ка­тор кон­тей­не­ра, кото­рый был нами изме­нен (его мож­но было уви­деть в при­гла­ше­нии команд­ной стро­ки); centos:my — назва­ние наше­го ново­го образа.

Новый образ создан.

Загрузка образа на Docker Hub

Захо­дим на Docker Hub стра­ни­цу реги­стра­ции. Созда­ем пользователя:

На сле­ду­ю­щей стра­ни­це так­же запол­ня­ем дан­ные про­фи­ля. После пере­хо­дим в поч­то­вый ящик, кото­рый был ука­зан при реги­стра­ции и пере­хо­дим по ссыл­ке Confirm Your Email With Docker для под­твер­жде­ния реги­стра­ции. Реги­стра­ция закончена.

Пере­хо­дим на стра­ни­цу Repositories и созда­ем свой репо­зи­то­рий, напри­мер, test. Теперь мож­но загру­зить наши обра­зы в репозиторий.

Сна­ча­ла авто­ри­зу­ем­ся в Linux под нашим заре­ги­стри­ро­ван­ным пользователем:

docker login --username test

Зада­ем тег для одно­го из обра­зов и загру­жа­ем его в репозиторий:

docker tag centos:my test/test

docker push test/test:centos

Загру­зим вто­рой образ:

docker tag test/nginx:v1 test/test:nginx

docker push test/test:nginx

В Docker Hub долж­ны появить­ся наш образы:

Что­бы вос­поль­зо­вать­ся обра­зом на дру­гом ком­пью­те­ре, так­же авто­ри­зу­ем­ся под заре­ги­стри­ро­ван­ным поль­зо­ва­те­лем docker:

docker login --username test

Загру­жа­ем образ:

docker pull test/test:nginx

Запус­ка­ем его:

docker run -d -p 8080:80 test/test:nginx

Описание инструкций Dockerfile

 

Инструк­ция Опи­са­ние При­мер
FROM Ука­зы­ва­ет, какой базо­вый образ нуж­но исполь­зо­вать. Обя­за­тель­ная инструк­ция для Dockerfile FROM ubuntu:16.04
MAINTAINER Автор обра­за. MAINTAINER Andrey <master@test.ru>
RUN Выпол­ня­ет коман­ду в новом слое при постро­е­нии образа. RUN apt-get install python
CMD Запус­ка­ет коман­ду каж­дый раз при запус­ке кон­тей­не­ра. Может быть вызва­на толь­ко один раз. Если в Dockerfile ука­зать несколь­ко таких инструк­ций, то выпол­не­на будет последняя. CMD ["openvpn"]
LABEL Добав­ля­ет метаданные. LABEL version="2"
EXPOSE Ука­зы­ва­ет, какой порт долж­но исполь­зо­вать при­ло­же­ние внут­ри контейнера. EXPOSE 8080
ENV Зада­ет пере­мен­ные окру­же­ния в образе. ENV PGPASSWORD pass
ADD Добав­ля­ет файлы/папки из теку­ще­го окру­же­ния в образ. Если в каче­стве копи­ру­е­мо­го фай­ла ука­зать архив, то он будет добав­лен в образ в рас­па­ко­ван­ном виде. Так­же в каче­стве источ­ни­ка при­ни­ма­ет URL. ADD /root/.ssh/{id_rsa,id_rsa.pub} /root/.ssh/
COPY Так­же как и ADD добав­ля­ет фай­лы в образ, но обла­да­ет мень­ши­ми функ­ци­я­ми — не при­ни­ма­ет URL и не рас­па­ко­вы­ва­ет архи­вы. Реко­мен­до­ван для исполь­зо­ва­ния в слу­ча­ях, где не тре­бу­ют­ся воз­мож­но­сти ADD или когда нуж­но пере­не­сти архив, как архив. COPY ./mypasswd /root/
ENTRYPOINT Ука­зы­ва­ет коман­ду, кото­рой будет пере­да­вать­ся пара­метр при запус­ке контейнера. ENTRYPOINT ["/sbin/apache2"]
VOLUME Добав­ля­ет том в контейнер. VOLUME ["/opt/myapp"]
USER Зада­ет поль­зо­ва­те­ля, от кото­ро­го будет запу­щен образ. USER user:group
WORKDIR Мож­но задать ката­лог, отку­да будут запус­кать­ся коман­ды ENTRYPOINT и CMD. WORKDIR /opt/apps
ARG Созда­ет пере­мен­ную, кото­рую может исполь­зо­вать сборщик. ARG folder=/opt/apps
WORKDIR $folder
ONBUILD Дей­ствия, кото­рые выпол­ня­ют­ся, если наш образ исполь­зу­ет­ся как базо­вый для дру­гой сборки. ONBUILD ADD . /app/src
STOPSIGNAL Пере­опре­де­ля­ет сиг­нал SIGTERM для завер­ше­ния контейнера. STOPSIGNAL SIGINT
HEALTHCHECK Коман­да, кото­рая будет про­ве­рять рабо­то­спо­соб­ность контейнера. HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1
SHELL Поз­во­ля­ет заме­нить стан­дарт­ную обо­лоч­ку для выпол­не­ния команд на пользовательскую. SHELL ["/bin/sh", "-c"]

Резервное копирование и восстановление контейнера

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

Создание резерва

И так, для созда­ния резерв­ной копии кон­тей­не­ра, смот­рим их список:

docker ps -a

… и для нуж­но­го выпол­ня­ем команду:

docker save -o /backup/docker/container.tar <container image>

* в дан­ном при­ме­ре мы созда­ем архив кон­тей­не­ра <container image> в файл /backup/docker/container.tar.

Что­бы умень­шить раз­мер, зани­ма­е­мый создан­ным фай­лом, раар­хи­вир­кем его командой:

gzip /backup/docker/container.tar

* в ито­ге, мы полу­чим файл container.tar.gz.

Восстановление

Сна­ча­ла рас­па­ко­вы­ва­ем архив:

gunzip container.tar.gz

После вос­ста­нав­ли­ва­ем контейнер:

docker load -i container.tar

Смот­рим, что нуж­ный нам кон­тей­нер появился:

docker images

Дополнительные команды

В дан­ном под­раз­де­ле при­ве­дем при­ме­ры команд, кото­рые могут ока­зать­ся полез­ны­ми при рабо­те с образами.

1. Уда­лить один образ:

docker rmi <назва­ние образа>

Напри­мер:

docker rmi test/nginx:v1

2. Уда­лить все образы:

docker rmi $(docker images -q)

Мы можем полу­чить ошиб­ки на подобие:

Error response from daemon: conflict: unable to delete 857594f280c1 (must be forced) - image is being used by stopped container …

Это зна­чит, что для уда­ля­е­мо­го обра­за есть дей­ству­ю­щие кон­тей­не­ры — они могут быть как вклю­че­ны, так и нахо­дит­ся в отклю­чен­ном состо­я­нии. Уда­лить все нера­бо­чие кон­тей­не­ры мож­но командой:

docker rm $(docker ps --filter status=exited -q)

Если нуж­но, мож­но оста­но­вить все дей­ству­ю­щие кон­тей­не­ры командой:

docker stop $(docker ps -a -q)