DockerAlt

Материал из wiki.nntc.nnov.ru
Версия от 14:16, 13 января 2023; Vovan (обсуждение | вклад) (Сборка приложения на языке Java в docker-контейнере)
Перейти к навигации Перейти к поиску

Содержание

Лабораторные работы по Docker

Подготовка рабочего места

Для выполнения всех работ достаточно установить в виртуальную машину ОС Альт Рабочая Станция 10.

Ссылка на загрузку установочного образа: https://download.basealt.ru/pub/distributions/ALTLinux/p10/images/workstation/x86_64/alt-workstation-10.0-x86_64.iso

После установки нужно обновить систему

su -
apt-get update
apt-get dist-upgrade
update-kernel -f

открыть терминал и установить Docker командой

apt-get install docker-engine

Затем добавить текущего пользователя в группу docker командой

usermod -a -Gdocker student

затем включить сервис и поставить его в автозагрузку

systemctl start docker
systemctl enable docker

перезагрузиться

reboot

[Практическая работа №1] Создание простого контейнера

Вручную

Откройте терминал хостовой машины

На базе официального стандартного Docker-образа

altlinux/base:p10

Только получить образ на компьютер можно командой:

docker pull altlinux/base:p10

создайте и запустите Docker-контейнер:

docker run -it --name=my_first_container --hostname=my-first-container altlinux/base:p10 /bin/bash


В случае успешного создания Docker-контейнера в эмуляторе терминала приглашение должно смениться на такое:

root@my-first-container:/#

Внимание! Сейчас вы внутри Docker-контейнера и можете командовать им! Если скомандовать

exit

, то контейнер завершит свою работу и найти и запустить его можно таким образом:

Найти:

docker ps -a

в ответе среди возможных прочих контейнеров должен быть такой:

f0a3cc6a8b63        altlinux/base:p10                 "/bin/bash"              15 seconds ago      Exited (0) 5 seconds ago                                my_first_container

Имя его в данном случае:

my_first_container

Идентификатор его в данном случае:

f0a3cc6a8b63

Запустить:

docker start my_first_container

или:

docker start f0a3cc6a8b63

Естественно, в конкретном случае идентификатор будет другой.


Подключиться к терминалу Docker-контейнера:

docker attach my_first_container

или

docker attach f0a3cc6a8b63


Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать

exit

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


Однако есть способ отключиться от терминала и не завершить Docker-контейнер:

Для этого нужно последовательно нажать сочетания клавиш:

Ctrl + P

затем

Ctrl + Q


После этого приглашение командной строки контейнера должно заменить приглашение хостовой системы.


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

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

Задача

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

Ход работы

Запустите контейнер my_first_container и подключитесь к его терминалу (как это сделать - описано выше)

Установите внутри контейнера текстовый редактор

apt-get update
apt-get install nano

Создайте с помощью установленного редактора nano файл сценария

bootstrap.sh

со следующим содержимым:

#!/bin/bash
echo "Hello, $USER_NAME"

Сделайте файл исполняемым

chmod +x /bootstrap.sh

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

USER_NAME=Ivan /bootstrap.sh

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

Hello, Ivan

Завершите контейнер, выйдя из него:

exit

Создайте новый образ на базе изменённого контейнера командой:

docker commit -a Vasya -m "My first own image" my_first_container my_first_image

Образ будет доступен в списке образов

docker images

Выполните запуск контейнера с автоматическим удалением его после завершения, передавая в команду запуска различные значения переменной окружения

USER_NAME

Примеры команды:

docker run --rm -e USER_NAME=Ivan -it my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Maria -it my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Petr -it my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Ekaterina -it my_first_image /bootstrap.sh

Автоматически (посредством файла Dockerfile)

Откройте терминал хостовой машины и создайте рабочий каталог

mkdir pr01

Перейдите в рабочий каталог

cd pr01

Создание файлов

В рабочем каталоге создайте файл

Dockerfile

по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):

FROM altlinux/base:p10
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
RUN echo '#!/bin/bash' > /bootstrap.sh
RUN echo 'echo "Hello, $USER_NAME"' >> /bootstrap.sh
RUN chmod +x /bootstrap.sh
CMD /bootstrap.sh


В конце этого этапа в рабочем каталоге должен быть один файл:

Dockerfile

Создание образа контейнера

Для создания Docker-образа (image) выполните команду:

docker build -t 'my_second_image:latest' .

Для проверки существования созданного контейнера выполните команду:

docker images

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

my_second_image        latest              add5d00c3dc0        7 seconds ago       72.9MB

Запуск контейнера на базе образа

Запуск контейнеров на базе созданного образа (за исключением имени образа и отсутствием необходимости указывать исполняемый скрипт (он указан непосредственно в Dockerfile)) ни чем не будет отличаться от запуска контейнеров в ходе создания образа вручную:

docker run --rm -e USER_NAME=Ivan -it my_second_image
docker run --rm -e USER_NAME=Maria -it my_second_image
docker run --rm -e USER_NAME=Petr -it my_second_image
docker run --rm -e USER_NAME=Ekaterina -it my_second_image

[Практическая работа №2] Создание контейнера для разработки приложения на языке Java

Откройте терминал хостовой машины и создайте рабочий каталог

mkdir pr02

Перейдите в рабочий каталог

cd pr02

Создание файлов

Скачайте в рабочий каталог JDK версии 19.0.1. Это можно сделать командой (рекомендуется использовать в локальной сети колледжа)

wget https://wiki.nntc.nnov.ru/download/openjdk-19.0.1_linux-x64_bin.tar.gz

или командой (при работе вне локальной сети колледжа)

wget https://download.java.net/java/GA/jdk19.0.1/afdd2e245b014143b62ccb916125e3ce/10/GPL/openjdk-19.0.1_linux-x64_bin.tar.gz

Распакуйте загруженный файл командой

tar -xzpf openjdk-19.0.1_linux-x64_bin.tar.gz

В результате будет доступен каталог

jdk-19.0.1

На этом этапе архив можно удалить командой

rm openjdk-19.0.1_linux-x64_bin.tar.gz

В рабочем каталоге создайте файл

Dockerfile_dev

по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):

FROM altlinux/base:p10
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
RUN apt-get update -q -y && apt-get install nano git -q -y
RUN mkdir /opt/jdk-19.0.1
COPY jdk-19.0.1 /opt/jdk-19.0.1
RUN echo PATH="$PATH:/opt/jdk-19.0.1/bin" > /root/.bashrc
RUN source /root/.bashrc

В конце этого этапа в рабочем каталоге должны быть файл:

Dockerfile_dev

и каталог

jdk-19.0.1

Создание образа контейнера

Далее в этом разделе будем исходить из условия, что ваш логин на https://hub.docker.com/ будет

vpupkin

а пароль

ну, вы сами знаете...


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


Для создания Docker-образа (image) выполните команду:

docker build -t 'vpupkin/java_dev:latest' -f Dockerfile_dev .


Для проверки существования созданного образа выполните команду:

docker images

Среди текста ответа должна появиться строчка с новым образом:

vpupkin/java_dev   latest              fa1a63896356        9 seconds ago       2.42GB


Запуск контейнера на базе образа

mkdir /home/student/pr02/src

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

docker run -it --mount source=/home/student/pr02/src,target=/root/src,type=bind --name=java_dev --hostname=java-dev vpupkin/java_dev /bin/bash

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

В случае успешного создания контейнера в эмуляторе терминала приглашение должно смениться на такое:

root@java-dev:/#

Проверка версии Java RE и компилятора должны возвращать примерно следующее:

bash-4.4# java -version
openjdk version "19.0.1" 2022-10-18
OpenJDK Runtime Environment (build 19.0.1+10-21)
OpenJDK 64-Bit Server VM (build 19.0.1+10-21, mixed mode, sharing)
bash-4.4# 
bash-4.4# javac -version
javac 19.0.1

Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать

exit

, то контейнер завершит свою работу и найти и запустить его можно таким образом:

Найти:

docker ps -a

в ответе среди возможных прочих контейнеров должен быть такой:

8e5f4fd0a99b        vpupkin/java_dev   "/bin/bash"         3 minutes ago       Exited (0) 6 seconds ago                       java_dev

Имя его в данном случае:

java_dev

Идентификатор его в данном случае:

8e5f4fd0a99b

Остальное пока не важно, однако можно догадаться за что отвечают остальные параметры...


Запустить:

docker start java_dev

или:

docker start 8e5f4fd0a99b

Естественно, в конкретном случае идентификатор будет другой.


Подключиться к терминалу:

docker attach java_dev

или

docker attach 8e5f4fd0a99b


Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать

exit

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


Однако есть способ отключиться от терминала и не завершить контейнер:

Для этого нужно последовательно нажать сочетания клавиш:

Ctrl + P

затем

Ctrl + Q


После этого приглашение командной строки контейнера должно заменить приглашение хостовой системы.


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

Сборка приложения на языке Java в docker-контейнере

Перейдём в каталог

cd /root/src/

Склонируем проект приложения на Java

git clone https://gitlab.nntc.nnov.ru/vlad.tancev/simple-counter

Перейдём в проект

cd simple-counter

Исходя из рекомендаци в файле README.md выполним сборку проекта

bash mvnw compile

В случае успешной сборки в терминале котейнера долждно быть написано что-то похожее на это:

[INFO] Changes detected - recompiling the module!
[INFO] Compiling 5 source files to /root/src/simple-counter/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  34.809 s
[INFO] Finished at: 2023-01-13T11:12:55Z
[INFO] ------------------------------------------------------------------------

На этом этам сборки приложения заврешён.



Теперь наша задача - запустить приложение прямо на хостовой машине (но выполняться оно будет в контейнере).

Делаем образ из контейнера с приложением на языке Java

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

Вероятно, из такого, где оно (приложение на языке Java) присутствует. У нас есть такой образ?


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


Но мы можем теперь легко получить образ на базе нашего контейнера с приложением на языке Java. Для этого нужно завершить контейнер и выполнить команду в хостовой систиеме:

docker commit -a Vasya java_dev vpupkin/java_test

Убедиться, что образ создался, можно по прежнему командой:

docker images

А вот теперь уже можно запустить контейнер на базе образа:

vpupkin/java_test

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

docker run --rm -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --mount source=/home/user/pr02/src,target=/root/src,type=bind --name=java_test --hostname=java-test vpupkin/java_test /startup.sh

Для успешного запуска графического приложения, работающего в контейнере, с возможностью отображения графического интерфейса, в этой команде сделано две вещи:

Первая: установлена (внутрь контейнера) переменная окружения

DISPLAY

равная значению аналогичной переменной окружения хостовой системы.

Вторая: проброшено устройство

/tmp/.X11-unix

из хостовой системы в контейнер.

Также добавлено монтирование каталога src для обмена файлами межу контейнером и хостовой системой, а также добавлена опция

--rm

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


Однако, возможно, не стоит каждый раз содавать контейнер из образа, если изменений в параметрах запуска не требуется?

Достаточно убрать параметр

--rm

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

И включить его можно (т.е. запустить наше java-приложение) так:

docker start java_test

Отвечаем на главный вопрос?

Вопрос звучит так:

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


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

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


Как это сделать -- см. в следующей практической работе.

[Практическая работа №3] Создание контейнера для запуска приложения на Lazarus

Откройте терминал хостовой машины. Если в домашнем каталоге пользователя присутствует каталог

docker

то переместите его в резервную копию командой:

mv docker docker_backup1

затем заново создайте рабочий каталог командой:

mkdir docker

Перейдите в рабочий каталог

cd docker

Создание файлов

В рабочем каталоге создайте файл

Dockerfile_prod

по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):

FROM ubuntu:20.04
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>

ENV USER ubuntu
ENV HOME /home/$USER

# Install dependencyes
RUN apt-get update \
    && apt-get install -y libgtk2.0-0 \
    && apt-get autoclean \
    && apt-get autoremove \
    && rm -rf /var/lib/apt/lists/*

# Create new user for run app
RUN adduser $USER --disabled-password

# Copy app to user homedir
COPY mypr /home/$USER/
CMD /bin/su -c "/home/ubuntu/mypr" ubuntu

Скопируйте исполняемый файл, полученный в предыдущей работе в рабочий каталог

cp ../docker_backup1/lazarus/project_name/mypr ./

Мы находимся в новом рабочем каталоге хостовой машины:

/home/user/docker

В начале этой работы каталог предыдущей работы мы переместили сюда:

/home/user/docker_backup1

Следовательно, относительно каталога

/home/user/docker

команда копирования исполняемого файла требует подняться на уровень выше

../

и из каталога

docker_backup1

уровнем выше относительно

/home/user/docker

скопировать необходимый файл в текущий каталог

./

В конце этого этапа в рабочем каталоге должно быть два файла:

Dockerfile_prod
mypr

Создание образа контейнера

Далее в этом разделе будем исходить из условия, что ваш логин на https://hub.docker.com/ будет

vpupkin

а пароль

ну, вы сами знаете...


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


Для создания Docker-образа (image) выполните команду:

docker build -t 'vpupkin/lazarus_prod:latest' -f Dockerfile_prod .


Для проверки существования созданного контейнера выполните команду:

docker images

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

vpupkin/lazarus_prod   latest              20bb2900074d        16 seconds ago      217MB


! Обратите внимание на размер контейнера !
Сравните размер контейнера с размером контейнера lazarus_dev из предыдущей работы

Запуск контейнера на базе образа

На базе полученного образа запустите контейнер, пробросив внутрь контейнера локальный каталог хостовой машины и пробросив порт для взаимодействия с графической оболочкой контейнера посредством клиента noVNC:

docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name=lazarus_prod --hostname=lazarus-prod vpupkin/lazarus_prod


При запуске контейнера таким образом не указывается команда, т.к. она задаётся в файле

Dockerfile_prod

строчкой

CMD /bin/su -c "/home/ubuntu/mypr" ubuntu

Результатом запуска контейнера должно стать запущенное внутри контейнера графическое приложение с отображением графического интерфейса на хостовой машине.

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

docker ps -a

Повторный запуск уже существующего контейнера можно осуществить по имени контейнера командой:

docker start lazarus_prod

[Практическая работа №4] Взаимодействие двух контейнеров по сети

Задача: Запустить ПО Moodle в контейнере с именем c2, который взаимодействует с базой данных Mariadb, запущенной в контейнере с именем c1

Загрузить образы контейнеров

docker pull mariadb
docker pull bitnami/moodle


Создание и подготовка контейнера C1

Создать контейнер с базой данных Mariadb и задать пароль пользователя root через переменную окружения

docker run --name=c1 --hostname=c1 -e MYSQL_ROOT_PASSWORD=123321 --network bridge -d mariadb

Создать временный контейнер с ПО Moodle и запустить его с доступом в командную оболочку

docker run -it --rm --name c2_tmp --network bridge bitnami/moodle:latest /bin/bash

Установить во временный контейнер утилиты проверки состояния сети

apt update
apt install net-tools iputils-ping

Изнутри контейнера c2_tmp проверить доступ в базу данных (для этого нужно убедиться в корректности ip адреса контейнера c1):

1. Посмотреть ip адрес конейнера c2_tmp (если контейнеры были запущены последовательно, то адрес контейнера c1 будет на единицу меньше)

ifconfig

2. Выполнить

ping <предполагаемый адрес контейнера c1>

в соседней консоли остановить контейнер c1

docker stop c1

в предыдущей консоли убедиться что пинги прекратились. Вернуться в соседнюю консоль. Запустить контейнер c1

docker start c1

в предыдущей консоли убедиться что пинги возобновились.

3. Выполнить проверку подключения к Mariadb посредством клиента mysql в контейнере c2_tmp

mysql -u root -p<пароль, установленный в переменной окружения при запуске контейнера c1> -h <корректный ip адрес контейнера c1>

4. Создать базу пользователя и базу данных Mariadb для работы Moodle (из консоли mysql, предварительно подключившись к ней под пользователем root)

CREATE DATABASE mdatabase;
CREATE USER 'muser'@'%' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON mdatabase.* to 'muser'@'%' WITH GRANT OPTION;

5. Проверить корректность подключения к Mariadb с созданным пользователем к созданной базе данных

mysql -u muser -p123456 -h <корректный ip адрес контейнера c1> mdatabase

6. Выйти из временного контейнера c2_tmp

exit

Запуск контейнера C2 с ПО Moodle

Поскольку в предыдущем пункте были подготовлены параметры доступа в базу данных Mariadb, используем их для запуска контейнера с ПО Moodle

docker run -d --name c2 -p 8080:8080 -p 8443:8443 --env ALLOW_EMPTY_PASSWORD=no --env MOODLE_DATABASE_USER=muser --env MOODLE_DATABASE_PASSWORD=123456 --env MOODLE_DATABASE_NAME=mdatabase --env MOODLE_DATABASE_HOST=<корректный ip адрес контейнера c1> --env MOODLE_USERNAME=user --env MOODLE_PASSWORD=123321 --env MOODLE_EMAIL=user@host.com --env MOODLE_SITE_NAME=user_moodle --network bridge bitnami/moodle:latest

Проверка: Открыть в браузере адрес:

http://localhost:8080

Ввести логин и пароль от ПО Moodle, указанные ранее в переменных окружения при старте контейнера.

Подробное описание по контейнеру: https://hub.docker.com/r/bitnami/moodle

Важно! Первые несколько минут ПО Moodle не будет доступно по указанному адресу http://localhost:8080
т.к. будет выполняться его первое развёртывание.

Проследить процесс развёртывания можно внутри базы данных в контейнере c1, подключившись к ней с хостовой машины

mysql -u muser -p123456 -h <корректный ip адрес контейнера c1> mdatabase

и из консоли mysql проверить наличие таблиц в базе данных

show tables

Самостоятельное задание

Используя справку по утилите docker запустить два аналогичных контейнера, установив статические ip адреса для них.

[Практическая работа №5] Взаимодействие двух контейнеров по сети

Создайте рабочий каталог и перейдите в него

mkdir composemoodle
cd composemoodle

Создайте файл

docker-compose.yml

со следующим содержимым

version: "2.2"
services:
  mariadb:
     image: "mariadb:latest"
     environment:
      - MYSQL_ROOT_PASSWORD=123321
      - MYSQL_ALLOW_EMPTY_PASSWORD=no
      - MYSQL_DATABASE=mdatabase
      - MYSQL_USER=muser
      - MYSQL_PASSWORD=123456
  moodle:
    ports:
      - "8080:8080"
      - "8443:8443"
    image: "bitnami/moodle:latest"
    environment:
      - ALLOW_EMPTY_PASSWORD=no
      - MOODLE_DATABASE_USER=muser
      - MOODLE_DATABASE_PASSWORD=123456
      - MOODLE_DATABASE_NAME=mdatabase
      - MOODLE_DATABASE_HOST=mariadb
      - MOODLE_USERNAME=user
      - MOODLE_PASSWORD=123321
      - MOODLE_EMAIL=user@host.com
      - MOODLE_SITE_NAME=user_moodle


В результате в рабочем каталоге должен быть файл:

docker-compose.yml

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

docker-compose up

Проблемы под Windows

В этом разделе описаны возможные проблемы при использовании Docker и Docker-compose в Windows в случае если до этого была нормальная и понятная работа в системах GNU/Linux или MacOSx, а теперь по каким-то причинам потребовалось работать с Docker из Windows...

Как запускать под виндой синтаксический сахар, если он у вас есть в формате bash скриптов

Поставить GIT отсюда https://git-scm.com (он все равно будет нужен)

Вместе с ним поставится Git Bash, которому будет передавать управление Power Shell, если из него (из Power Shell) запускать исполняемые *.sh файлы с шебангом:

#!/bin/bash

/bin/bash^M: bad interpreter: No such file or directory

Решение описано здесь: https://forums.docker.com/t/error-while-running-docker-code-in-powershell/34059/5

Кратко:

Шаг 1

удалить репозиторий

Шаг 2

Настроить git командой

git config --global core.autocrlf input

Шаг 3

склонировать заново и попробовать ещё раз

Но есть вероятность что винда не поймёт эту глобальную настройку, если командовать из PowerShell. Поэтому сразу железобетонный вариант -- клонировать с указанием ключа, например:

 git clone -o core.autocrlf=input https://ну_и_тут_путь_к_репозиторию

Кеширование образов контейнеров виндой

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

Решение - отключить кеширование. Для этого нужно создать пустой файл

%APPDATA%\Docker\disable-filesystem-caching

Источник: https://github.com/docker/for-win/issues/5530

Возможно, способ с созданием файла поможет после перезагрузки ОС.

Если способ не помогает, то можно попробовать остановить Docker (пкм на иконке Docker Desktop в трее), затем перейти в каталог

%APPDATA%\

и удалить там оба каталога, имя которых начинается на

Docker

Затем запустить Docker Desktop тыком в ярлык

NVIDIA IN DOCKER

https://nvidia.github.io/nvidia-container-runtime/

https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/user-guide.html

Backup and Restore docker volumes

Backup

Допустим, у нас был запущен контейнер с локальным volume такой командой:

docker run -v /dbdata --name dbstore ubuntu /bin/bash
/dbdata

здесь это указание на то, что внутри контейнера в каталоге /dbdata будут находиться данные, которые docker будет физически хранить в одном из volumes. Эти данные мы и будем резервировать.


Общая суть заключается в том, что мы забрасываем все volumes из определённого контейнера (в данном случае имя контейнера -- dbstore) в новый промежуточный контейнер (как можно заметить, он запускается с ключом самоуничтожения --rm), который, в свою очередь, монтирует текущий каталог пользователя (вне контейнера, на хосте, который управляет контейнерами) в каталог /backup (это уже внутри контейнера, который временно запускается). Затем происходит процедура создания архива tar из содержимого /dbdata внутри контейнера. Таким образом сам контейнер уничтожается, но в рабочем каталоге пользователя на хост-машине остаётся файл резервной копии backup.tar

docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata


Restore

Допустим у нас есть бэкап, сделанный в предыдущем пункте и он у нас лежит в текущем каталоге и называется backup.tar

Теперь нам нужно этот бэкап распаковать в определённый каталог внутри контейнера. На текущем этапе нам без разницы: каталог назначения (куда мы будем распаковывать архив backup.tar) находится на volume или это маппинг каталога в каталог хостовой системы без использования volume -- смотрим на этот каталог назначения как на обычный каталог дерева внутри контейнера. При необходимости можно воспользоваться опцией

--volumes-from

при старте контейнера, чтобы "подкинуть" в этот контейнер volume из другого контейнера. Всё зависит от задачи.

И так, мы собираемся распаковать backup.tar в каталог /dbdata нового контейнера. Для этого примерная команда будет выглядеть так:

docker run -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar /dbdata

Если предполагается, что контейнер, из которого даётся команда для распаковки, временный и его задача на время зацепить volume из другого контейнера (в примере этот контейнер называется dbstorecopy), то есть смысл использовать ключ самоуничтожения контейнера (--rm) и зацепить из другого контейнера volume опцией --volumes-from dbstorecopy. Тогда команда будет такой:

docker run --rm --volumes-from dbstorecopy -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar /dbdata

Перемещение данных между двумя контейнерами

Кейс для 12.12.2022

# [1] stop two containers
docker stop nntc_de_mobd_c1_1 nntc_de_mobd_c2_1

# [2] make dir for backups
mkdir /root/containers/nntc-jupyter/backup

# [3] backup dir `/opt/notebooks` from nntc_de_mobd_c1_1 to /root/containers/nntc-jupyter/backup/q.tar
docker run --rm --volumes-from nntc_de_mobd_c1_1 -v /root/containers/nntc-jupyter/backup:/backup --workdir /opt/notebooks ubuntu tar -cpf /backup/q.tar .

# [4] restore dir `/opt/notebooks` in nntc_de_mobd_c2_1 from /root/containers/nntc-jupyter/backup/q.tar
docker run --rm --volumes-from nntc_de_mobd_c2_1 -v /root/containers/nntc-jupyter/backup:/backup --workdir /opt/notebooks ubuntu tar -xpf /backup/q.tar

# [5] start two containers
docker start nntc_de_mobd_c1_1 nntc_de_mobd_c2_1