Docker: различия между версиями
Vovan (обсуждение | вклад) (→Создание и подготовка контейнера C1) |
Vovan (обсуждение | вклад) (→Save Load) |
||
(не показаны 33 промежуточные версии 2 участников) | |||
Строка 19: | Строка 19: | ||
это можно сделать командой | это можно сделать командой | ||
− | sudo usermod -Gdocker $USER | + | sudo usermod -a -Gdocker $USER |
затем перезагрузиться. | затем перезагрузиться. | ||
Строка 246: | Строка 246: | ||
<pre> | <pre> | ||
− | FROM ubuntu: | + | FROM ubuntu:20.04 |
MAINTAINER Vasya I Pupkin <vasya@pupkin.com> | MAINTAINER Vasya I Pupkin <vasya@pupkin.com> | ||
Строка 700: | Строка 700: | ||
<pre> | <pre> | ||
− | FROM ubuntu: | + | FROM ubuntu:20.04 |
MAINTAINER Vasya I Pupkin <vasya@pupkin.com> | MAINTAINER Vasya I Pupkin <vasya@pupkin.com> | ||
Строка 888: | Строка 888: | ||
Ввести логин и пароль от ПО Moodle, указанные ранее в переменных окружения при старте контейнера. | Ввести логин и пароль от ПО 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 адреса для них. | Используя справку по утилите docker запустить два аналогичных контейнера, установив статические ip адреса для них. | ||
+ | |||
+ | ==[Практическая работа №5] Взаимодействие двух контейнеров по сети== | ||
+ | |||
+ | Создайте рабочий каталог и перейдите в него | ||
+ | |||
+ | mkdir composemoodle | ||
+ | cd composemoodle | ||
+ | |||
+ | Создайте файл | ||
+ | |||
+ | docker-compose.yml | ||
+ | |||
+ | со следующим содержимым | ||
+ | |||
+ | <pre> | ||
+ | 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 | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | В результате в рабочем каталоге должен быть файл: | ||
+ | |||
+ | 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 | ||
+ | |||
+ | <pre> | ||
+ | # [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 | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | =Save Load= | ||
+ | |||
+ | docker save my-image:latest my-other-image:latest | xz > images.tar.xz | ||
+ | |||
+ | unxz -c images.tar.xz | docker load | ||
+ | |||
+ | =Save Load Over SSH= | ||
+ | |||
+ | docker save my-image:latest | bzip2 | pv | ssh root@another-host docker load |
Текущая версия на 09:45, 1 октября 2024
Содержание
- 1 Лабораторные работы по Docker
- 1.1 Подготовка рабочего места
- 1.2 [Практическая работа №1] Создание простого контейнера
- 1.3 [Практическая работа №2] Создание контейнера для разработки приложения на Lazarus
- 1.3.1 Создание файлов
- 1.3.2 Создание каталогов
- 1.3.3 Создание образа контейнера
- 1.3.4 Запуск контейнера на базе образа
- 1.3.5 Запуск графической подсистемы и вход в неё посредством браузера
- 1.3.6 Порядок работы с IDE Lazarus
- 1.3.7 Делаем образ из контейнера с приложением на Lazarus
- 1.3.8 Отвечаем на главный вопрос?
- 1.4 [Практическая работа №3] Создание контейнера для запуска приложения на Lazarus
- 1.5 [Практическая работа №4] Взаимодействие двух контейнеров по сети
- 1.6 [Практическая работа №5] Взаимодействие двух контейнеров по сети
- 2 Проблемы под Windows
- 3 NVIDIA IN DOCKER
- 4 Backup and Restore docker volumes
- 5 Save Load
- 6 Save Load Over SSH
Лабораторные работы по Docker
Подготовка рабочего места
Для выполнения всех работ достаточно установить в виртуальную машину
Ubuntu 20.04 LTS Desktop
Ссылка на загрузку установочного образа: https://releases.ubuntu.com/20.04.1/ubuntu-20.04.1-desktop-amd64.iso
После установки нужно открыть терминал и установить Docker командой
sudo apt update && sudo apt install docker.io
Затем добавить текущего пользователя в группу
docker
это можно сделать командой
sudo usermod -a -Gdocker $USER
затем перезагрузиться.
[Практическая работа №1] Создание простого контейнера
Вручную
Откройте терминал хостовой машины
На базе официального стандартного Docker-образа
ubuntu
создайте и запустите Docker-контейнер:
docker run -it --name=my_first_container --hostname=my-first-container ubuntu /bin/bash
В случае успешного создания Docker-контейнера в эмуляторе терминала приглашение должно смениться на такое:
root@my-first-container:/#
Внимание! Сейчас вы внутри Docker-контейнера и можете командовать им! Если скомандовать
exit
, то контейнер завершит свою работу и найти и запустить его можно таким образом:
Найти:
docker ps -a
в ответе среди возможных прочих контейнеров должен быть такой:
f0a3cc6a8b63 ubuntu "/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, $USERNAME"
Сделайте файл исполняемым
chmod +x /bootstrap.sh
Проверьте работоспособность командой:
USERNAME=Ivan /bootstrap.sh
в результате в терминал должна быть выдана строка
Hello, Ivan
Завершите контейнер, выйдя из него:
exit
Создайте новый образ на базе изменённого контейнера командой:
docker commit -a Vasya -m "My first own image" my_first_container my_first_image
Образ будет доступен в списке образов
docker images
Выполните запуск контейнера с автоматическим удалением его после завершения, передавая в команду запуска различные значения переменной окружения
USERNAME
Примеры команды:
docker run --rm -e USERNAME=Ivan -it my_first_image /bootstrap.sh
docker run --rm -e USERNAME=Maria -it my_first_image /bootstrap.sh
docker run --rm -e USERNAME=Petr -it my_first_image /bootstrap.sh
docker run --rm -e USERNAME=Ekaterina -it my_first_image /bootstrap.sh
Автоматически (посредством файла Dockerfile)
Откройте терминал хостовой машины и создайте рабочий каталог
mkdir docker
Перейдите в рабочий каталог
cd docker
Создание файлов
В рабочем каталоге создайте файл
Dockerfile
по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):
FROM ubuntu MAINTAINER Vasya I Pupkin <vasya@pupkin.com> RUN echo '#!/bin/bash' > /bootstrap.sh RUN echo 'echo "Hello, $USERNAME"' >> /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 USERNAME=Ivan -it my_second_image
docker run --rm -e USERNAME=Maria -it my_second_image
docker run --rm -e USERNAME=Petr -it my_second_image
docker run --rm -e USERNAME=Ekaterina -it my_second_image
[Практическая работа №2] Создание контейнера для разработки приложения на Lazarus
Откройте терминал хостовой машины и создайте рабочий каталог
mkdir docker
Перейдите в рабочий каталог
cd docker
Создание файлов
В рабочем каталоге создайте файл
Dockerfile_dev
по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):
FROM ubuntu:20.04 MAINTAINER Vasya I Pupkin <vasya@pupkin.com> ENV DEBIAN_FRONTEND noninteractive ENV USER ubuntu ENV HOME /home/$USER # Create new user for vnc login. RUN adduser $USER --disabled-password # Install MATE and dependency component. RUN apt-get update \ && apt-get install -y \ tightvncserver \ mate-core mate-desktop-environment mate-notification-daemon \ supervisor \ net-tools \ curl \ git \ pwgen \ lazarus \ && apt-get autoclean \ && apt-get autoremove \ && rm -rf /var/lib/apt/lists/* # Clone noVNC. RUN git clone https://github.com/novnc/noVNC.git $HOME/noVNC # Clone websockify for noVNC Run git clone https://github.com/kanaka/websockify $HOME/noVNC/utils/websockify # Download ngrok. ADD https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip $HOME/ngrok/ngrok.zip RUN unzip -o $HOME/ngrok/ngrok.zip -d $HOME/ngrok && rm $HOME/ngrok/ngrok.zip # Copy supervisor config. COPY supervisor.conf /etc/supervisor/conf.d/ # Copy startup script. COPY startup.sh $HOME EXPOSE 6080 5901 4040
В рабочем каталоге создайте файл
supervisor.conf
со следующим содержимым:
[program:vncserver] command=vncserver -geometry 1600x900 :1 user=ubuntu [program:noVNC] command=/home/ubuntu/noVNC/utils/launch.sh --vnc localhost:5901 user=ubuntu stdout_logfile=/var/log/novnc.log redirect_stderr=true
В рабочем каталоге создайте файл
startup.sh
со следующим содержимым:
#!/bin/bash if [ ! -f $HOME/.vnc/passwd ] ; then if [ -z "$PASSWORD" ] ; then PASSWORD=`pwgen -c -n -1 12` echo -e "PASSWORD = $PASSWORD" > $HOME/password.txt fi echo "$USER:$PASSWORD" | chpasswd # Set up vncserver su $USER -c "mkdir $HOME/.vnc && echo '$PASSWORD' | vncpasswd -f > $HOME/.vnc/passwd && chmod 600 $HOME/.vnc/passwd && touch $HOME/.Xresources" chown -R $USER:$USER $HOME if [ ! -z "$SUDO" ]; then case "$SUDO" in [yY]|[yY][eE][sS]) adduser $USER sudo esac fi else VNC_PID=`find $HOME/.vnc -name '*.pid'` if [ ! -z "$VNC_PID" ] ; then vncserver -kill :1 rm -rf /tmp/.X1* fi fi if [ ! -z "$NGROK" ] ; then case "$NGROK" in [yY]|[yY][eE][sS]) su ubuntu -c "$HOME/ngrok/ngrok http 6080 --log $HOME/ngrok/ngrok.log --log-format json" & sleep 5 NGROK_URL=`curl -s http://127.0.0.1:4040/status | grep -P "http://.*?ngrok.io" -oh` su ubuntu -c "echo -e 'Ngrok URL = $NGROK_URL/vnc.html' > $HOME/ngrok/Ngrok_URL.txt" esac fi /usr/bin/supervisord -n
В конце этого этапа в рабочем каталоге должно быть три файла:
Dockerfile_dev supervisor.conf startup.sh
Создание каталогов
В рабочем каталоге создайте каталог
lazarus
командой
mkdir lazarus
В конце этого этапа в рабочем каталоге должно быть три файла:
Dockerfile_dev supervisor.conf startup.sh
и один каталог:
lazarus
Создание образа контейнера
Далее в этом разделе будем исходить из условия, что ваш логин на https://hub.docker.com/ будет
vpupkin
а пароль
ну, вы сами знаете...
! Также стоит помнить, что в эмуляторе терминала находиться нужно в рабочем каталоге !
Для создания Docker-образа (image) выполните команду:
docker build -t 'vpupkin/lazarus_dev:latest' -f Dockerfile_dev .
Для проверки существования созданного контейнера выполните команду:
docker images
Среди текста ответа должна появиться строчка с новым контейнером:
vpupkin/lazarus_dev latest fa1a63896356 9 seconds ago 2.42GB
Запуск контейнера на базе образа
На базе полученного образа запустите контейнер, пробросив внутрь контейнера локальный каталог хостовой машины и пробросив порт для взаимодействия с графической оболочкой контейнера посредством клиента noVNC:
docker run -it --mount source="$(pwd)"/lazarus,target=/home/ubuntu/lazarus,type=bind -p 6080:6080 -e PASSWORD=123456 --name=lazarus_dev --hostname=lazarus-dev vpupkin/lazarus_dev /bin/bash
Также в этой команде запуска задаются: имя контейнера, имя хоста, команда, которую выполнит контейнер при запуске и указаны ключи, которые автоматически подключают терминал к контейнеру. Для доступа по протоколу VNC посредством переменной окружения PASSWORD задаётся пароль.
В случае успешного создания контейнера в эмуляторе терминала приглашение должно смениться на такое:
root@lazarus-dev:/#
Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать
exit
, то контейнер завершит свою работу и найти и запустить его можно таким образом:
Найти:
docker ps -a
в ответе среди возможных прочих контейнеров должен быть такой:
8e5f4fd0a99b vpupkin/lazarus_dev "/bin/bash" 3 minutes ago Exited (0) 6 seconds ago lazarus_dev
Имя его в данном случае:
lazarus_dev
Идентификатор его в данном случае:
8e5f4fd0a99b
Остальное пока не важно, однако можно догадаться за что отвечают остальные параметры...
Запустить:
docker start lazarus_dev
или:
docker start 8e5f4fd0a99b
Естественно, в конкретном случае идентификатор будет другой.
Подключиться к терминалу:
docker attach lazarus_dev
или
docker attach 8e5f4fd0a99b
Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать
exit
, то контейнер завершит свою работу придётся опять читать выше по тексту как его запускать...
Однако есть способ отключиться от терминала и не завершить контейнер:
Для этого нужно последовательно нажать сочетания клавиш:
Ctrl + P
затем
Ctrl + Q
После этого приглашение командной строки контейнера должно заменить приглашение хостовой системы.
На этом этапе мы научились создавать образ контейнера и запускать контейнер на его базе.
Запуск графической подсистемы и вход в неё посредством браузера
Для запуска окружения рабочего стола и доступа в него по протоколу VNC в контейнере предусмотрен специальный сценарий запуска. Чтобы его запустить нужно зайти в терминал контейнера (см. предыдущие пункты)
И выполнить внутри контейнера команду:
/bin/bash /home/ubuntu/startup.sh
Далее можно либо оставить эмулятор терминала и открыть браузер (правда помни, что если случайно закрыть эмулятор терминала, то контейнер завершит выполнение), либо отключиться от терминала контейнера без его завершения (тоже см. выше - про горячие клавиши).
В любом случае, убедиться, что контейнер запущен можно выполнив команду в хостовой машине:
docker ps
и найдя свой контейнер среди списка, который вернёт команда.
Для работы с окружением рабочего стола зайдите браузером по адресу:
http://localhost:6080/vnc.html
мы же там порт забрасывали, при старте контейнера...
В окне, которое загрузится в браузере, ввести пароль. Какой? -- см. выше. Мы его там в переменной окружения задавали, при старте контейнера...
На этом этапе загрузится стандартное окружение рабочего стола MATE, в котором можно использовать файловый менеджер и непосредственно IDE Lazarus.
Внутри окружения в домашнем каталоге пользователя
ubuntu
есть каталог
lazarus
Он связан с хостовой системой. Зря мы чтоли создавали этот каталог и потом биндили его при старте контейнера?
Конечно не зря. Через этот каталог хостовая машина может обмениваться с контейнером файлами. А самое главное, что при уничтожении контейнера все ваши ценные файлы останутся на хостовой машине в каталоге
lazarus
, если вы, конечно, будете хранить ценные файлы именно в каталоге, который из окружения MATE контейнера имеет такой полный путь:
/home/ubuntu/lazarus
(а теперь внимательно смотрим на команду старта контейнера и смотрим где там встречается такая строчка...)
Внутри окружения MATE и в непосредственно IDE Lazarus работаем самостоятельно. Вы это умеете :-)
Порядок работы с IDE Lazarus
После запуска IDE Lazarus необходимо сразу сохранить проект так, чтобы он в итоге лежал в каталоге:
/home/ubuntu/lazarus/project_name
project_name - любое логичное имя вашего проекта.
Также есть вариант наоборот: загружаем в каталог lazarus (тот, который прибиндили в контейнер, см. выше, если непонятно) уже существующий проект, затем открываем его в IDE Lazarus из окружения MATE контейнера.
Работаем над проектом в IDE Lazarus, затем собираем его, сохраняем проект и закрываем IDE Lazarus
На этом этапе в
/home/ubuntu/lazarus/project_name
должен находиться исполняемый файл проекта. Например, если проект вы назвали
mypr.lpr
, то этот файл будет таким:
/home/ubuntu/lazarus/project_name/mypr
Вот примерно такой командой его и можно запустить отдельно от IDE Lazarus. Проверим?
Откройте эмулятор терминала из окружения MATE контейнера и введите там полный путь до исполняемого файла получившейся программы:
/home/ubuntu/lazarus/project_name/mypr
В результате внутри окружения MATE контейнера должно запуститься ваше приложение, написанное на Lazarus.
Получилось? Если да, то теперь нам не нужо все это тяжёлое окружение в виде MATE и сервера с noVNC. Выключите его. Для этого нужно зайти в терминал контейнера:
docker attach lazarus_dev
и завершить выполнение сценария, который до этого стартовали, сочетанием клавиш:
Ctrl + C
вам должно будет вернуться приглашение командной строки контейнера - это признак того что окружение и сервер с noVNC завершены (можете проверить -- в браузере уже ничего не загрузится).
Теперь наша задача - запустить приложение прямо на хостовой машине (но выполняться оно будет в контейнере).
Делаем образ из контейнера с приложением на Lazarus
Для того, чтобы запустить получившееся приложение внутри контейнера, но графическую часть его иметь на хостовой машине, нужно запустить еще один контейнер. Однако, из какого образа?
Вероятно, из такого, где оно (приложение на Lazarus) присутствует. У нас есть такой образ?
Верно, нет. У нас есть лишь контейнер, который мы получили на базе подготовленного чистого образа.
Но мы можем теперь легко получить образ на базе нашего контейнера с приложением на Lazarus. Для этого нужно завершить контейнер и выполнить команду в хостовой систиеме:
docker commit -a Vasya lazarus_dev vpupkin/lazarus_test
Убедиться, что образ создался, можно по прежнему командой:
docker images
А вот теперь уже можно запустить контейнер на базе образа:
vpupkin/lazarus_test
, который будет запускать приложение на Lazarus прямо на хостовой системе. Для этого нужно запустить контейнер такой командой:
docker run --rm -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --mount source="$(pwd)"/lazarus,target=/home/ubuntu/lazarus,type=bind --name=lazarus_test --hostname=lazarus-test vpupkin/lazarus_test /bin/su -c "/home/ubuntu/lazarus/project_name/mypr" ubuntu
Для успешного запуска графического приложения, работающего в контейнере, с возможностью отображения графического интерфейса, в этой команде сделано две вещи:
Первая: установлена (внутрь контейнера) переменная окружения
DISPLAY
равная значению аналогичной переменной окружения хостовой системы.
Вторая: проброшено устройство
/tmp/.X11-unix
из хостовой системы в контейнер.
Также добавлено монтирование каталога lazarus для обмена файлами межу контейнером и хостовой системой, а также добавлена опция
--rm
которая уничтожает контейнер после его завершения (за данные мы не переживаем, они же лежат локально в каталоге lazarus, который каждый раз монтируется при старте в новый контейнер).
Однако, возможно, не стоит каждый раз содавать контейнер из образа, если изменений в параметрах запуска не требуется?
Достаточно убрать параметр
--rm
из команды запуска контейнера, но следует помнить, что при завершении графического приложения контейнер будет завершён и запускать его уже нужно будет командой старта контейнера (в этом случае контейнер никуда не девается, а просто лежит на хостовой системе в выключенном состоянии).
И включить его можно (т.е. запустить наше lazarus-приложение) так:
docker start lazarus_test
Отвечаем на главный вопрос?
Вопрос звучит так:
Если мы уже разработали приложение, то надо ли конечному пользователю все эти окружения MATE, сервер для запуска окружения noVNC и прочие скрипты инициализации, которые использовались для создания контейнера с инструментами разработки?
Наверное нет. Они сильно загружают систему при том, что больше никогда не понадобятся пользователю.
Поэтому для конечного пользователя целесообразно создать новый контейнер, исключив оттуда всё лишнее и оставив лишь непосредственно готовое приложение.
Как это сделать -- см. в лабораторной работе ниже.
[Практическая работа №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
Save Load
docker save my-image:latest my-other-image:latest | xz > images.tar.xz
unxz -c images.tar.xz | docker load
Save Load Over SSH
docker save my-image:latest | bzip2 | pv | ssh root@another-host docker load