DockerAlt: различия между версиями

Материал из wiki.nntc.nnov.ru
Перейти к навигации Перейти к поиску
(Подготовка рабочего места)
(Загрузка образов Docker из архивного файла)
 
(не показано 137 промежуточных версий этого же участника)
Строка 1: Строка 1:
 +
=DOCKER_IN_ESPD=
 +
 +
==Прокси сервер==
 +
 +
В ЕСПД каждой организации существует адрес прокси-сервера для доступа в централизованно-ограниченный провайдером интернет.
 +
 +
Например, это может быть адрес и порт:
 +
 +
10.0.52.52:3128
 +
 +
==Настройка сервиса для работы с прокси-сервером в ОС Альт==
 +
 +
Для настройки сервиса docker в ОС Альт на доступ к образам с
 +
 +
hub.docker.com
 +
 +
необходимо:
 +
 +
Импортировать сертификат (подробнее об этом здесь [https://www.altlinux.org/%D0%95%D0%A1%D0%9F%D0%94 здесь]):
 +
 +
Переходим в каталог
 +
 +
cd /etc/pki/ca-trust/source/anchors/
 +
 +
Скачиваем сертификат
 +
 +
wget --no-check-certificate https://espd.rt.ru/docs/ca-root.crt
 +
 +
Приминяем
 +
 +
update-ca-trust
 +
 +
Далее предполагается что Docker в ОС Альт уже установлен и необходимо добавить в окружение сервиса инициализацию переменных окружения
 +
 +
HTTP_PROXY
 +
 +
и
 +
 +
HTTPS_PROXY
 +
 +
Для этого необходимо отредактировать файл
 +
 +
/etc/sysconfig/docker
 +
 +
Было:
 +
<pre>
 +
cat /etc/sysconfig/docker
 +
OPTIONS=""
 +
</pre>
 +
 +
Стало:
 +
<pre>
 +
cat /etc/sysconfig/docker
 +
HTTP_PROXY=http://10.0.52.52:3128
 +
HTTPS_PROXY=http://10.0.52.52:3128
 +
OPTIONS=""
 +
</pre>
 +
 +
Важно! Адрес и порт прокси сервера могут быть другими!
 +
 +
Затем необходимо перезапустить сервис
 +
 +
systemctl restart docker
 +
 +
Теперь можно пробовать получить образ
 +
 +
docker pull alt:p10
 +
 +
В случае успешной настройки в ответ должно быть что-то вроде этого
 +
 +
<pre>
 +
p10: Pulling from library/alt
 +
8d0b964d5817: Pulling fs layer
 +
529c2ffbf4d6: Download complete
 +
8d0b964d5817: Pull complete
 +
529c2ffbf4d6: Pull complete
 +
Digest: sha256:1a4f3803dee404126c6947ea9f791eb781e25b541477dc242ef188e4e7734bef
 +
Status: Downloaded newer image for alt:p10
 +
docker.io/library/alt:p10
 +
</pre>
 +
 
=Лабораторные работы по Docker=
 
=Лабораторные работы по Docker=
  
Строка 17: Строка 98:
 
  update-kernel -f
 
  update-kernel -f
  
открыть терминал и установить Docker командой
+
открыть терминал и установить Docker командой
 +
 
 +
apt-get install docker-engine docker-compose-v2
  
sudo apt update && sudo apt install docker.io
+
Затем добавить текущего пользователя в группу docker командой
  
Затем добавить текущего пользователя в группу
+
usermod -a -Gdocker student
  
  docker
+
затем включить сервис и поставить его в автозагрузку
 +
 
 +
  systemctl start docker
  
это можно сделать командой
+
systemctl enable docker
  
sudo usermod -a -Gdocker $USER
+
перезагрузиться
  
затем перезагрузиться.
+
reboot
  
 
==[Практическая работа №1] Создание простого контейнера==
 
==[Практическая работа №1] Создание простого контейнера==
Строка 39: Строка 124:
 
На базе официального стандартного Docker-образа
 
На базе официального стандартного Docker-образа
  
  ubuntu
+
  alt:p10
 +
 
 +
Только получить образ на компьютер можно командой:
 +
 
 +
docker pull alt:p10
  
 
создайте и запустите Docker-контейнер:
 
создайте и запустите Docker-контейнер:
  
  docker run -it --name=my_first_container --hostname=my-first-container ubuntu /bin/bash
+
  docker run -it --name=my_first_container --hostname=my-first-container alt:p10 /bin/bash
  
  
Строка 62: Строка 151:
 
в ответе среди возможных прочих контейнеров должен быть такой:
 
в ответе среди возможных прочих контейнеров должен быть такой:
  
  f0a3cc6a8b63        ubuntu                 "/bin/bash"              15 seconds ago      Exited (0) 5 seconds ago                                my_first_container
+
  f0a3cc6a8b63        altlinux/base:p10                 "/bin/bash"              15 seconds ago      Exited (0) 5 seconds ago                                my_first_container
  
 
Имя его в данном случае:
 
Имя его в данном случае:
Строка 137: Строка 226:
  
 
  #!/bin/bash
 
  #!/bin/bash
  echo "Hello, $USERNAME"
+
  echo "Hello, $USER_NAME"
  
 
Сделайте файл исполняемым
 
Сделайте файл исполняемым
Строка 145: Строка 234:
 
Проверьте работоспособность командой:
 
Проверьте работоспособность командой:
  
  USERNAME=Ivan /bootstrap.sh
+
  USER_NAME=Ivan /bootstrap.sh
  
 
в результате в терминал должна быть выдана строка
 
в результате в терминал должна быть выдана строка
Строка 165: Строка 254:
 
Выполните запуск контейнера с автоматическим удалением его после завершения, передавая в команду запуска различные значения переменной окружения
 
Выполните запуск контейнера с автоматическим удалением его после завершения, передавая в команду запуска различные значения переменной окружения
  
  USERNAME
+
  USER_NAME
  
 
Примеры команды:
 
Примеры команды:
  
  docker run --rm -e USERNAME=Ivan -it my_first_image /bootstrap.sh
+
  docker run --rm -e USER_NAME=Ivan my_first_image /bootstrap.sh
  
  docker run --rm -e USERNAME=Maria -it my_first_image /bootstrap.sh
+
  docker run --rm -e USER_NAME=Maria my_first_image /bootstrap.sh
  
  docker run --rm -e USERNAME=Petr -it my_first_image /bootstrap.sh
+
  docker run --rm -e USER_NAME=Petr my_first_image /bootstrap.sh
  
  docker run --rm -e USERNAME=Ekaterina -it my_first_image /bootstrap.sh
+
  docker run --rm -e USER_NAME=Ekaterina my_first_image /bootstrap.sh
  
 
===Автоматически (посредством файла Dockerfile)===
 
===Автоматически (посредством файла Dockerfile)===
Строка 181: Строка 270:
 
Откройте терминал хостовой машины и создайте рабочий каталог
 
Откройте терминал хостовой машины и создайте рабочий каталог
  
  mkdir docker
+
  mkdir pr01
  
 
Перейдите в рабочий каталог
 
Перейдите в рабочий каталог
  
  cd docker
+
  cd pr01
  
===Создание файлов===
+
====Создание файлов====
  
 
В рабочем каталоге создайте файл  
 
В рабочем каталоге создайте файл  
Строка 196: Строка 285:
  
 
<pre>
 
<pre>
FROM ubuntu
+
FROM alt:p10
 
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
 
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
 
RUN echo '#!/bin/bash' > /bootstrap.sh
 
RUN echo '#!/bin/bash' > /bootstrap.sh
RUN echo 'echo "Hello, $USERNAME"' >> /bootstrap.sh
+
RUN echo 'echo "Hello, $USER_NAME"' >> /bootstrap.sh
 
RUN chmod +x /bootstrap.sh
 
RUN chmod +x /bootstrap.sh
 
CMD /bootstrap.sh
 
CMD /bootstrap.sh
Строка 209: Строка 298:
 
  Dockerfile
 
  Dockerfile
  
===Создание образа контейнера===
+
====Создание образа контейнера====
  
 
Для создания Docker-образа (image) выполните команду:
 
Для создания Docker-образа (image) выполните команду:
Строка 223: Строка 312:
 
  my_second_image        latest              add5d00c3dc0        7 seconds ago      72.9MB
 
  my_second_image        latest              add5d00c3dc0        7 seconds ago      72.9MB
  
===Запуск контейнера на базе образа===
+
====Запуск контейнера на базе образа====
  
 
Запуск контейнеров на базе созданного образа (за исключением имени образа и отсутствием необходимости указывать исполняемый скрипт (он указан непосредственно в Dockerfile)) ни чем не будет отличаться от запуска контейнеров в ходе создания образа вручную:
 
Запуск контейнеров на базе созданного образа (за исключением имени образа и отсутствием необходимости указывать исполняемый скрипт (он указан непосредственно в Dockerfile)) ни чем не будет отличаться от запуска контейнеров в ходе создания образа вручную:
  
  docker run --rm -e USERNAME=Ivan -it my_second_image
+
  docker run --rm -e USER_NAME=Ivan my_second_image
  
  docker run --rm -e USERNAME=Maria -it my_second_image
+
  docker run --rm -e USER_NAME=Maria my_second_image
  
  docker run --rm -e USERNAME=Petr -it my_second_image
+
  docker run --rm -e USER_NAME=Petr my_second_image
  
  docker run --rm -e USERNAME=Ekaterina -it my_second_image
+
  docker run --rm -e USER_NAME=Ekaterina my_second_image
  
==[Практическая работа №2] Создание контейнера для разработки приложения на Lazarus==
+
==[Практическая работа №2] Создание контейнера для разработки приложения на языке Java==
  
 
Откройте терминал хостовой машины и создайте рабочий каталог
 
Откройте терминал хостовой машины и создайте рабочий каталог
  
  mkdir docker
+
  mkdir pr02
  
 
Перейдите в рабочий каталог
 
Перейдите в рабочий каталог
  
  cd docker
+
  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
  
 
В рабочем каталоге создайте файл  
 
В рабочем каталоге создайте файл  
Строка 254: Строка 363:
  
 
<pre>
 
<pre>
FROM ubuntu:20.04
+
FROM alt:p10
 
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
 
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
 +
RUN apt-get update -q -y && apt-get install nano git libX11 libX11-devel libXxf86vm libXxf86vm-devel libGL xorg-dri-swrast fonts-ttf-dejavu mate-calc -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
 +
</pre>
 +
 +
В конце этого этапа в рабочем каталоге должны быть файл:
 +
 +
Dockerfile_dev
 +
 +
и каталог
 +
 +
jdk-19.0.1
  
ENV DEBIAN_FRONTEND noninteractive
+
===Создание образа контейнера===
ENV USER ubuntu
 
ENV HOME /home/$USER
 
  
# Create new user for vnc login.
+
Далее в этом разделе будем исходить из условия, что ваш логин на https://hub.docker.com/ будет
RUN adduser $USER --disabled-password
 
  
# Install MATE and dependency component.
+
vpupkin
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 \
+
Для создания Docker-образа (image) выполните команду:
    && apt-get autoremove \
+
 
    && rm -rf /var/lib/apt/lists/*
+
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
 +
 
 +
На базе полученного образа запустите контейнер, пробросив внутрь контейнера локальный каталог хостовой машины:
  
# Clone noVNC.
+
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
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.
+
root@java-dev:/#
COPY supervisor.conf /etc/supervisor/conf.d/
 
  
# Copy startup script.
+
Проверка версии Java RE и  компилятора должны возвращать примерно следующее:
COPY startup.sh $HOME
 
  
EXPOSE 6080 5901 4040
+
<pre>
 +
root@java-dev:/# 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
 
</pre>
 
</pre>
  
В рабочем каталоге создайте файл
+
Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать
 +
 
 +
exit
 +
 
 +
, то контейнер завершит свою работу и найти и запустить его можно таким образом:
  
supervisor.conf
+
Найти:
  
со следующим содержимым:
+
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 install
 +
bash mvnw dependency:copy-dependencies
 +
 
 +
В случае успешной сборки в терминале котейнера долждно быть написано что-то похожее на это:
  
 
<pre>
 
<pre>
[program:vncserver]
+
[INFO] ------------------------------------------------------------------------
command=vncserver -geometry 1600x900 :1
+
[INFO] BUILD SUCCESS
user=ubuntu
+
[INFO] ------------------------------------------------------------------------
 +
</pre>
 +
 
 +
На этом этам сборки приложения заврешён.
 +
 
 +
Теперь наша задача - запустить приложение прямо на хостовой машине (но выполняться оно будет в контейнере).
 +
 
 +
===Запуск собранного приложения в docker-контейнере на базе образа с JDK===
 +
 
 +
Запустим новый контейнер командой:
 +
 
 +
docker run --rm -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --mount source=/home/student/pr02/src,target=/root/src,type=bind --name=java_test --hostname=java-test vpupkin/java_dev /bin/bash
 +
 
 +
Для успешного запуска графического приложения, работающего в контейнере, с возможностью отображения графического интерфейса, в этой команде сделано две вещи:
 +
 
 +
Первая: установлена (внутрь контейнера) переменная окружения
 +
 
 +
DISPLAY
 +
 
 +
равная значению аналогичной переменной окружения хостовой системы.
 +
 
 +
Вторая: проброшено устройство
 +
 
 +
/tmp/.X11-unix
 +
 
 +
из хостовой системы в контейнер.
 +
 
 +
Также добавлено монтирование каталога src для обмена файлами межу контейнером и хостовой системой, а также добавлена опция
 +
 
 +
--rm
 +
 
 +
которая уничтожает контейнер после его завершения (за данные мы не переживаем, они же лежат локально в каталоге src, который каждый раз монтируется при старте в новый контейнер).
 +
 
 +
 
 +
Эта опция сюда добавлена, поскольку сама команда старта контейнера содержит в себе цель запускать именно оболочку /bin/bash для ручного тестирования запуска собранного приложения.
 +
 
 +
Предполагается, что после такого тестирования контейнер не нужен и при выходе из него его логичнее всего автоматически удалять.
 +
 
 +
 
 +
Когда работа собранного приложения протестирована и есть понимание, что всё работает корректно, можно приступать к сборке образа для production-контейнера, в котором необходимо оставить необходимое и достаточное количество библиотек, необходимых только для запуска уже собранного приложения, а пакеты и утилиты, необходимые для сборки, не включать в результирующий образ.
 +
 
 +
Важный момент: В некоторых операционных системах может потребоваться выполнить команду
 +
 
 +
xhost +
 +
 
 +
для разрешения подключения контейнера к графической оболочке X-сервера.
 +
 
 +
Тестовый запуск приложения можно выполнить командами:
 +
 
 +
cd /root/src/simple-counter/
 +
java --module-path=target/dependency/ --add-modules javafx.controls,javafx.fxml -cp target/demo_up04-1.0-SNAPSHOT.jar com.example.demo_up04.DemoApplication
 +
 
 +
===Отвечаем на главный вопрос?===
 +
 
 +
Вопрос звучит так:
  
[program:noVNC]
+
Если мы уже собрали приложение, то нужно ли конечному пользователю инструменты для сборки приложения, которые были нужны в сборочном контейнере, и исходный код приложения?
command=/home/ubuntu/noVNC/utils/launch.sh --vnc localhost:5901
+
 
user=ubuntu
+
 
stdout_logfile=/var/log/novnc.log
+
Не нужны по нескольким причинам:
redirect_stderr=true
+
 
</pre>
+
# Исходный код чаще всего остаётся интеллектуальной собственностью компании-разработчика и не должен оказаться у заказчика;
 +
# Наличие на Production-системе компилятора какого-либо языка и/или каких-либо средств разработки является потенциальной уязвимостью системы;
 +
# Инструменты сборки и тестирования никогда не понадобятся конечному пользователю на Production-системе, но всегда будут занимать место на файловой системе контейнера.
 +
 
 +
Поэтому для конечного пользователя целесообразно создать новый образ, исключив оттуда всё лишнее и оставив лишь непосредственно готовое приложение.
 +
 
 +
Как это сделать -- см. в следующей практической работе.
 +
 
 +
==[Практическая работа №3] Создание контейнера для запуска Java-приложения==
 +
Откройте терминал хостовой машины. Создайте рабочий каталог
 +
 
 +
mkdir pr03
 +
 
 +
Перейдите в рабочий каталог
 +
 
 +
cd pr03
  
 +
===Создание файлов===
  
В рабочем каталоге создайте файл
+
В рабочем каталоге создайте файл  
  
  startup.sh
+
  Dockerfile_prod
  
со следующим содержимым:
+
по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):
  
 
<pre>
 
<pre>
#!/bin/bash
+
FROM alt:p10
 +
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
 +
RUN apt-get update -q -y \
 +
    && apt-get install nano su libX11 libX11-devel libXxf86vm libXxf86vm-devel libGL xorg-dri-swrast fonts-ttf-dejavu mate-calc -q -y \
 +
    && apt-get autoclean \
 +
    && apt-get autoremove
  
if [ ! -f $HOME/.vnc/passwd ] ; then
+
RUN adduser app
  
    if  [ -z "$PASSWORD" ] ; then
+
RUN mkdir /opt/jdk-19.0.1
        PASSWORD=`pwgen -c -n -1 12`
+
COPY jdk-19.0.1 /opt/jdk-19.0.1
        echo -e "PASSWORD = $PASSWORD" > $HOME/password.txt
 
    fi
 
  
    echo "$USER:$PASSWORD" | chpasswd
+
RUN mkdir /opt/app
 +
COPY app /opt/app
 +
COPY startup.sh /
 +
RUN chmod +x /startup.sh
  
    # Set up vncserver
+
RUN echo "PATH=$PATH:/opt/jdk-19.0.1/bin" > /home/app/.bashrc
    su $USER -c "mkdir $HOME/.vnc && echo '$PASSWORD' | vncpasswd -f > $HOME/.vnc/passwd && chmod 600 $HOME/.vnc/passwd && touch $HOME/.Xresources"
+
RUN echo "export JAVA_HOME=/opt/jdk-19.0.1" >> /home/app/.bashrc
    chown -R $USER:$USER $HOME
 
  
    if [ ! -z "$SUDO" ]; then
+
USER app
        case "$SUDO" in
 
            [yY]|[yY][eE][sS])
 
                adduser $USER sudo
 
        esac
 
    fi
 
  
else
+
CMD /startup.sh
 +
</pre>
  
    VNC_PID=`find $HOME/.vnc -name '*.pid'`
+
Создайте каталог app в рабочем каталоге
    if [ ! -z "$VNC_PID" ] ; then
+
        vncserver -kill :1
+
mkdir app
        rm -rf /tmp/.X1*
 
    fi
 
  
fi
+
Скопируйте исполняемый файл, полученный в предыдущей работе в рабочий каталог
  
if [ ! -z "$NGROK" ] ; then
+
/bin/cp -r ../pr02/src/simple-counter/target app/
        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
+
Скачайте в рабочий каталог JDK версии 19.0.1. Это можно сделать командой (рекомендуется использовать в локальной сети колледжа)
</pre>
 
  
В конце этого этапа в рабочем каталоге должно быть три файла:
+
wget https://wiki.nntc.nnov.ru/download/openjdk-19.0.1_linux-x64_bin.tar.gz
  
Dockerfile_dev
+
или командой (при работе вне локальной сети колледжа)
supervisor.conf
 
startup.sh
 
  
===Создание каталогов===
+
wget https://download.java.net/java/GA/jdk19.0.1/afdd2e245b014143b62ccb916125e3ce/10/GPL/openjdk-19.0.1_linux-x64_bin.tar.gz
  
В рабочем каталоге создайте каталог
+
Распакуйте загруженный файл командой
  
  lazarus
+
  tar -xzpf openjdk-19.0.1_linux-x64_bin.tar.gz
  
командой
+
На этом этапе архив можно удалить командой
  
  mkdir lazarus
+
  rm openjdk-19.0.1_linux-x64_bin.tar.gz
  
В конце этого этапа в рабочем каталоге должно быть три файла:
+
Создайте в рабочем каталоге файл
  
Dockerfile_dev
 
supervisor.conf
 
 
  startup.sh
 
  startup.sh
  
и один каталог:
+
со следующим содержимым
  
lazarus
+
<pre>
 +
#!/bin/bash
 +
source /home/app/.bashrc
 +
cd /opt/app
 +
java --module-path=target/dependency/ --add-modules javafx.controls,javafx.fxml -cp target/demo_up04-1.0-SNAPSHOT.jar com.example.demo_up04.DemoApplication
 +
</pre>
 +
 
 +
В конце этого этапа в рабочем каталоге должно быть два файла:
  
 +
Dockerfile_prod
 +
startup.sh
 +
 +
И два каталога:
 +
 +
jdk-19.0.1
 +
app
  
 
===Создание образа контейнера===
 
===Создание образа контейнера===
Строка 413: Строка 703:
 
Для создания Docker-образа (image) выполните команду:
 
Для создания Docker-образа (image) выполните команду:
  
  docker build -t 'vpupkin/lazarus_dev:latest' -f Dockerfile_dev .
+
  docker build -t 'vpupkin/java_prod:latest' -f Dockerfile_prod .
  
  
Строка 422: Строка 712:
 
Среди текста ответа должна появиться строчка с новым контейнером:
 
Среди текста ответа должна появиться строчка с новым контейнером:
  
  vpupkin/lazarus_dev   latest              fa1a63896356       9 seconds ago       2.42GB
+
  vpupkin/java_prod   latest              20bb2900074d       16 seconds ago     217MB
 +
 
  
 +
! Обратите внимание на размер контейнера !
 +
Сравните размер контейнера с размером контейнера java_dev из предыдущей работы
  
 
===Запуск контейнера на базе образа===
 
===Запуск контейнера на базе образа===
  
На базе полученного образа запустите контейнер, пробросив внутрь контейнера локальный каталог хостовой машины и пробросив порт для взаимодействия с графической оболочкой контейнера посредством клиента 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
+
  mkdir $HOME/data
  
Также в этой команде запуска задаются: имя контейнера, имя хоста, команда, которую выполнит контейнер при запуске и указаны ключи, которые автоматически подключают терминал к контейнеру. Для доступа по протоколу VNC посредством переменной окружения PASSWORD задаётся пароль.
+
На базе полученного образа запустите контейнер, пробросив внутрь контейнера локальный каталог хостовой машины:
 +
 
 +
docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --mount source="$HOME/data",target=/home/app/data,type=bind --name=java_prod --hostname=java-prod vpupkin/java_prod
  
В случае успешного создания контейнера в эмуляторе терминала приглашение должно смениться на такое:
 
  
root@lazarus-dev:/#
+
При запуске контейнера таким образом не указывается команда, т.к. она задаётся в файле
  
Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать
+
Dockerfile_prod
 +
 
 +
строчкой
  
  exit
+
  CMD /bin/su -c "/startup.sh" app
  
, то контейнер завершит свою работу и найти и запустить его можно таким образом:
+
Результатом запуска контейнера должно стать запущенное внутри контейнера графическое приложение с отображением графического интерфейса на хостовой машине.
  
Найти:
+
При закрытии окна графического приложения контейнер будет завершён и будет доступен среди списка контейнеров
  
 
  docker ps -a
 
  docker ps -a
  
в ответе среди возможных прочих контейнеров должен быть такой:
+
Повторный запуск уже существующего контейнера можно осуществить по имени контейнера командой:
 +
 
 +
docker start java_prod
 +
 
 +
==[Практическая работа №4] Взаимодействие двух контейнеров по сети (ручной запуск)==
 +
 
 +
Задача: Запустить Java-приложение в контейнере с именем c2, который взаимодействует с базой данных Mariadb, запущенной в контейнере с именем c1
 +
 
 +
===Загрузка образа для контейнера с mariadb===
 +
 
 +
docker pull mariadb
 +
 
 +
===Создание сетевого моста===
 +
 
 +
docker network create net_c1_c2
 +
 
 +
Проверить список сетевых мостов можно командой
 +
 
 +
docker network list
 +
 
 +
===Запуск контейнера c1 и подготовка базы данных===
 +
 
 +
Создать контейнер с базой данных Mariadb и задать исходные параметры работы СУБД (название базы данных, логин и пароль для базы данных, пароль пользователя root) через переменные окружения
 +
 
 +
docker run --name=c1 --hostname=c1 -e MARIADB_ROOT_PASSWORD=123321 -e MARIADB_DATABASE=java_app_db -e MARIADB_USER=java_app_user -e MARIADB_PASSWORD=java_app_password --network net_c1_c2 -d mariadb
 +
 
 +
Проверить корректность подключения к Mariadb с созданным пользователем к созданной базе данных (подключиться к консоли контейнера c1 и воспользоваться клиентом mariadb)
 +
 
 +
docker exec -it c1 /bin/bash
 +
 
 +
Внутри контейнера запустить клиент mariadb (ранее это был клиент mysql) с параметрами подключения к бд:
 +
 
 +
mariadb -u java_app_user -pjava_app_password -h localhost java_app_db
 +
 +
Выход из mariadb и затем из контейнера
 +
 
 +
exit
 +
exit
 +
 
 +
===Запуск контейнера c2 с Java-приложением===
  
8e5f4fd0a99b        vpupkin/lazarus_dev  "/bin/bash"        3 minutes ago      Exited (0) 6 seconds ago                      lazarus_dev
+
Запуск контейнера с Java-приложением производится аналогично запуску, подробно описанному в практической работе №3 с учётом ряда нюансов:
  
Имя его в данном случае:
+
1. Необходимо учитывать, что имя запускаемого контейнера должно быть
  
  lazarus_dev
+
  с2
  
Идентификатор его в данном случае:
+
2. Необходимо учитывать, что имя хоста запускаемого контейнера должно быть
  
  8e5f4fd0a99b
+
  с2
  
Остальное пока не важно, однако можно догадаться за что отвечают остальные параметры...
+
3. Необходимо учитывать, что для корректного подключения Java-приложения к базе данных, доступной в контейнере с именем_контейнера=именем_хоста=с1 необходимо при запуске контейнера с2 передать набор переменных окружения для настройки Java-приложения на работу с базой данных в контейнере c1
  
 +
DB_HOST=c1
 +
DB_PORT=3306
 +
DB_NAME=java_app_db
 +
DB_USER=java_app_user
 +
DB_PASS=java_app_password
  
Запустить:
+
Пример команды для запуска контейнера c2 (запуск контейнера осуществляется на базе образа, созданного в практической работе №3)
  
docker start lazarus_dev
+
Не забудем про
  
или:
+
xhost +
  
  docker start 8e5f4fd0a99b
+
  docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name=c2 --hostname=c2 -e DB_HOST=c1 -e DB_PORT=3306 -e DB_NAME=java_app_db -e DB_USER=java_app_user -e DB_PASS=java_app_password --network net_c1_c2 vpupkin/java_prod
  
Естественно, в конкретном случае идентификатор будет другой.
+
При необходимости монтирования директорий хостовой машины в контейнер также могут быть использованы дополнительные параметры, как было показано в примере запуска контейнера в практической работе №3 с параметром
  
 +
--mount source="$HOME/data",target=/home/app/data,type=bind
  
Подключиться к терминалу:
+
В данном примере этот параметр опущен, т.к. тестовое приложение не имеет функций чтения и записи файлов.
  
docker attach lazarus_dev
+
===Самостоятельное задание===
  
или
+
====Подготовка====
  
docker attach 8e5f4fd0a99b
+
Придумать уникальный префикс для именования названий, завязанный на фамилию и инициалы обучающегося.
  
 +
Например, для обучающегося
  
Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать
+
Иванов Иван Иванович
  
exit
+
Префикс (<prefix>) будет состоять из фамилии и инициалов
  
, то контейнер завершит свою работу придётся опять читать выше по тексту как его запускать...
+
ivanov_ii
  
 +
Тогда в приведённых ниже примерах необходимо
  
Однако есть способ отключиться от терминала и не завершить контейнер:
+
<prefix>
  
Для этого нужно последовательно нажать сочетания клавиш:
+
заменять на
  
  Ctrl + P
+
  ivanov_ii
  
затем
+
Например
  
  Ctrl + Q
+
  ivanov_ii_container_db
  
  
После этого приглашение командной строки контейнера должно заменить приглашение хостовой системы.
+
====Выполнение задания====
  
 +
Используя справку по docker и набор выполненных практических работ запустить тестовое Java-приложение в двух контейнерах, аналогичных контейнерам с1 и с2, исходя из следующих параметров:
  
На этом этапе мы научились создавать образ контейнера и запускать контейнер на его базе.
+
0. Сетевой мост должен иметь имя
  
===Запуск графической подсистемы и вход в неё посредством браузера===
+
net_<prefix>
  
Для запуска окружения рабочего стола и доступа в него по протоколу VNC в контейнере предусмотрен специальный сценарий запуска.
+
1. Контейнер с базой данных должен иметь имя
Чтобы его запустить нужно зайти в терминал контейнера (см. предыдущие пункты)
 
  
И выполнить внутри контейнера команду:
+
<prefix>_container_db
  
/bin/bash /home/ubuntu/startup.sh
+
и хостовое имя
  
Далее можно либо оставить эмулятор терминала и открыть браузер (правда помни, что если случайно закрыть эмулятор терминала, то контейнер завершит выполнение), либо отключиться от терминала контейнера без его завершения (тоже см. выше - про горячие клавиши).
+
<prefix>-container-db
  
 +
2. Контейнер с Java-приложением должен иметь имя
  
В любом случае, убедиться, что контейнер запущен можно выполнив команду в хостовой машине:
+
<prefix>_container_app
  
docker ps
+
и хостовое имя
  
и найдя свой контейнер среди списка, который вернёт команда.
+
<prefix>-container-app
  
 +
3. База данных должна иметь название
  
Для работы с окружением рабочего стола зайдите браузером по адресу:
+
<prefix>_application_db
  
http://localhost:6080/vnc.html
+
имя пользователя
  
мы же там порт забрасывали, при старте контейнера...
+
<prefix>_application_user
  
В окне, которое загрузится в браузере, ввести пароль. Какой? -- см. выше. Мы его там в переменной окружения задавали, при старте контейнера...
+
пароль
  
 +
<prefix>_applicationPassw0rd123
  
На этом этапе загрузится стандартное окружение рабочего стола MATE, в котором можно использовать файловый менеджер и непосредственно IDE Lazarus.
+
Ход работы отразить в отчёте по практической работе №4
  
Внутри окружения в домашнем каталоге пользователя
+
==[Практическая работа №5] Взаимодействие двух контейнеров по сети (docker compose)==
  
ubuntu
+
===Предисловие===
  
есть каталог
+
Решаемая в данной практической работе задача аналогична задаче из практической работы №4. Отличия состоят лишь в том, что в практической работе №4 запуск двух контейнеров, взаимодействующих между собой внутри изолированной сети, осуществляется вручную, путём выполнения команд:
  
  lazarus
+
  docker run ...
  
Он связан с хостовой системой. Зря мы чтоли создавали этот каталог и потом биндили его при старте контейнера?
+
Для автоматизации запуска приложений, компоненты которых разделены по контейнерам (их (приложения в контейнерах) ещё называют микросервисами) может быть использован инструмент:
  
Конечно не зря. Через этот каталог хостовая машина может обмениваться с контейнером файлами. А самое главное, что при уничтожении контейнера все ваши ценные файлы останутся на хостовой машине в каталоге
+
docker compose
  
lazarus
+
Инструмент docker compose (смысл названия можно перевести как "композиция из докер контейнеров") предназначен для того, чтобы автоматически запустить несколько docker-контейнеров в одном контексте (как правило, под контекстом подразумевается общая сеть, изолированная от хостовой системы но доступная для всех контейнеров композиции (как говорят DevOps-инженеры -- "композы")).
  
, если вы, конечно, будете хранить ценные файлы именно в каталоге, который из окружения MATE контейнера имеет такой полный путь:
+
В практической работе №2 мы изучали два способа создания docker-образа: ручной и автоматический.
  
/home/ubuntu/lazarus
+
Ручной способ подразумевал создание контейнера на базе стандартного образа, выполнение ряда действий внутри этого контейнера вручную, с последующим созданием образа на базе изменённого вручную контейнера. В результате получался новый образ, на базе которого можно запускать новые контейнеры.
  
(а теперь внимательно смотрим на команду старта контейнера и смотрим где там встречается такая строчка...)
+
Автоматический способ подразумевал решение аналогичной задачи, но без участия пользователя. Т.е. пользователь один раз описывал файл (Dockerfile), который включал в себя все необходимые команды (которые в ручном режиме пользователь выполнял вручную) и директивы, которых минимально необходимо и достаточно для сборки образа в автоматическом режиме. После того, как был подготовлен Dockerfile, на его базе командой:
  
 +
docker build...
  
Внутри окружения MATE и в непосредственно IDE Lazarus работаем самостоятельно. Вы это умеете :-)
+
производилась сборка образа
  
===Порядок работы с IDE Lazarus===
 
  
После запуска IDE Lazarus необходимо сразу сохранить проект так, чтобы он в итоге лежал в каталоге:
+
Между ручным запуском двух контейнеров, описанным в практической работе №4, и автоматическим запуском композиции из докер контейнеров (композы), описываемой в этой практической работе, можно провести такую же аналогию, как между созданием образа контейнера вручную и созданием образа контейнера автоматически. Два этих способа (ручной и автоматический) объединяет наличие специального конфигурационного файла. В случае с автоматической сборкой docker-образа это файл:
  
  /home/ubuntu/lazarus/project_name
+
  Dockerfile
  
project_name - любое логичное имя вашего проекта.
+
, в случае же с автоматическим запуском нескольких контейнеров в композе -- это файл:
  
Также есть вариант наоборот: загружаем в каталог lazarus (тот, который прибиндили в контейнер, см. выше, если непонятно) уже существующий проект, затем открываем его в IDE Lazarus из окружения MATE контейнера.
+
docker-compose.yaml
  
 +
Для того, чтобы запустить любую композицию контейнеров, необходимо:
  
Работаем над проектом в IDE Lazarus, затем собираем его, сохраняем проект и закрываем IDE Lazarus
+
1. Сконфигурировать файл
  
 +
docker-compose.yaml
  
На этом этапе в
+
2. Выполнить запуск композы командой
  
  /home/ubuntu/lazarus/project_name
+
  docker compose up ...
  
должен находиться исполняемый файл проекта. Например, если проект вы назвали
+
===Практика===
  
mypr.lpr
+
Создайте рабочий каталог и перейдите в него
  
, то этот файл будет таким:
+
mkdir compose_с1_с2
 +
cd compose_с1_с2
  
/home/ubuntu/lazarus/project_name/mypr
+
Создайте файл
  
 +
docker-compose.yaml
  
Вот примерно такой командой его и можно запустить отдельно от IDE Lazarus. Проверим?
+
со следующим содержимым
  
 +
<pre>
 +
version: '3.9'
  
Откройте эмулятор терминала из окружения MATE контейнера и введите там полный путь до исполняемого файла получившейся программы:
+
services:
 +
  c1:
 +
    container_name: "c1"
 +
    hostname: "c1"
 +
    image: "mariadb"
 +
    restart: "always"
 +
    environment:
 +
      MARIADB_ROOT_PASSWORD: "123321"
 +
      MARIADB_DATABASE: "java_app_db"
 +
      MARIADB_USER: "java_app_user"
 +
      MARIADB_PASSWORD: "java_app_password"
 +
    networks:
 +
      - net_c1_c2
  
/home/ubuntu/lazarus/project_name/mypr
+
  c2:
 +
    container_name: "c2"
 +
    hostname: "c2"
 +
    image: "vpupkin/java_prod"
 +
    restart: "no"
 +
    environment:
 +
      DISPLAY: "$DISPLAY"
 +
      DB_HOST: "c1"
 +
      DB_PORT: "3306"
 +
      DB_NAME: "java_app_db"
 +
      DB_USER: "java_app_user"
 +
      DB_PASS: "java_app_password"
 +
    volumes:
 +
      - /tmp/.X11-unix:/tmp/.X11-unix
 +
    networks:
 +
      - net_c1_c2
  
В результате внутри окружения MATE контейнера должно запуститься ваше приложение, написанное на Lazarus.
+
networks:
 +
  net_c1_c2:
 +
    name: net_c1_c2
 +
</pre>
  
  
Получилось? Если да, то теперь нам не нужо все это тяжёлое окружение в виде MATE и сервера с noVNC. Выключите его. Для этого нужно зайти в терминал контейнера:
+
В результате в рабочем каталоге должен быть файл:
  
  docker attach lazarus_dev
+
  docker-compose.yaml
  
и завершить выполнение сценария, который до этого стартовали, сочетанием клавиш:
+
Для запуска композиции выполните в рабочем каталоге команду
  
  Ctrl + C
+
  docker compose up -d
  
вам должно будет вернуться приглашение командной строки контейнера - это признак того что окружение и сервер с noVNC завершены (можете проверить -- в браузере уже ничего не загрузится).
+
В результате по описанной в файле docker-compose.yaml схеме сервисов будут запущены два контейнера: с1 и с2. В том числе из контейнера с2 будет запущено графическое приложение, которое будет работать с базой данных, запущенной в контейнере с1.
  
 +
====Возможные проблемы и их решения====
  
Теперь наша задача - запустить приложение прямо на хостовой машине (но выполняться оно будет в контейнере).
+
Проблема №1: не запускается графический интерфейс Java-приложения.
 +
Решение: Открыть терминал хостовой системы и выполнить в нём команду для разрешения подключения к графической системы извне частности -- из контейнера):
  
===Делаем образ из контейнера с приложением на Lazarus===
+
xhost +
  
Для того, чтобы запустить получившееся приложение внутри контейнера, но графическую часть его иметь на хостовой машине, нужно запустить еще один контейнер. Однако, из какого образа?
+
Проблема №2: Java-приложение не может подключиться к базе данных.
 +
Решение: Повторно запустить контейнер c2. При первом запуске композы в контейнере c1 сервис базы данных не успевает запуститься к моменту, когда в контейнере c2 стартует Java-приложение. Поэтому приложение показывает ошибку. Когда окно приложение закрывается -- контейнер c2 прекращает свою работу, однако контейнер c1 по прежнему работает (и в нём с высокой долей вероятности уже запустилась СУБД). Поэтому повторный запуск контейнера c2 запустит Java-приложение, в котором уже не будет ошибки подключения к базе данных (конечно, при условии, что всё верно настроено).
  
Вероятно, из такого, где оно (приложение на Lazarus) присутствует. У нас есть такой образ?
+
====Работа с контейнерами в контексте docker compose====
  
 +
Если мы находимся в каталоге с файлом (Это важно! Все команды этого раздела актуальны, если соблюдается простое правило -- мы стоим в каталоге с этим файлом):
  
Верно, нет. У нас есть лишь контейнер, который мы получили на базе подготовленного чистого образа.
+
docker-compose.yaml
  
 +
то для упрощения работы с контейнерами (сервисами микросервисной архитектуры), входящими в состав композы, можно вместо команды
  
Но мы можем теперь легко получить образ на базе нашего контейнера с приложением на Lazarus. Для этого нужно завершить контейнер и выполнить команду в хостовой систиеме:
+
docker
  
docker commit -a Vasya lazarus_dev vpupkin/lazarus_test
+
использовать команду
  
Убедиться, что образ создался, можно по прежнему командой:
+
  docker compose
 
  docker images
 
 
  
А вот теперь уже можно запустить контейнер на базе образа:
+
В случае с нашей композой сервисы имеют названия c1 и с2, следовательно, для их остановки можно применять команды:
  
  vpupkin/lazarus_test
+
  docker compose stop c1
  
, который будет запускать приложение на 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
+
  docker compose stop c2
  
Для успешного запуска графического приложения, работающего в контейнере, с возможностью отображения графического интерфейса, в этой команде сделано две вещи:
+
а для остановки всей композы -- команду:
  
Первая: установлена (внутрь контейнера) переменная окружения
+
docker compose stop
  
DISPLAY
+
а для запуска, соответственно
  
равная значению аналогичной переменной окружения хостовой системы.
+
docker compose start c1
  
Вторая: проброшено устройство
+
или
  
  /tmp/.X11-unix
+
  docker compose start c2
  
из хостовой системы в контейнер.
+
а для запуска всей композы -- команду:
  
Также добавлено монтирование каталога lazarus для обмена файлами межу контейнером и хостовой системой, а также добавлена опция
+
docker compose start
  
--rm
 
  
которая уничтожает контейнер после его завершения (за данные мы не переживаем, они же лежат локально в каталоге lazarus, который каждый раз монтируется при старте в новый контейнер).
+
Для развёртывания (поднятия -- up) композы выше использовалась команда:
  
 +
docker compose up -d
  
Однако, возможно, не стоит каждый раз содавать контейнер из образа, если изменений в параметрах запуска не требуется?
 
  
Достаточно убрать параметр
+
Существует обратная операция, которую условно можно назвать свёртыванием (опускания -- down) композы. Для этого может быть использована команда:
  
  --rm
+
  docker compose down
  
из команды запуска контейнера, но следует помнить, что при завершении графического приложения контейнер будет завершён и запускать его уже нужно будет командой старта контейнера (в этом случае контейнер никуда не девается, а просто лежит на хостовой системе в выключенном состоянии).
+
Выполнение этой команды приводит к остановке и удалению всех контейнеров композы. При этом образы остаются в системе.
  
И включить его можно (т.е. запустить наше lazarus-приложение) так:
+
После операции свёртывания композы в системе остаются занятые виртуальные диски, которые резервируются для контейнеров в момент запуска композы. Для очистки этих дисков, а следовательно для увеличения свободного места на диске, можно выполнить команду:
  
  docker start lazarus_test
+
  docker volume prune
  
===Отвечаем на главный вопрос?===
+
Эта команда удалит все не занятые контейнерами виртуальные диски (volumes) подсистемы docker.
  
Вопрос звучит так:
 
  
Если мы уже разработали приложение, то надо ли конечному пользователю все эти окружения MATE, сервер для запуска окружения noVNC и прочие скрипты инициализации, которые использовались для создания контейнера с инструментами разработки?
+
Также посредством команды
  
 +
docker compose
  
Наверное нет. Они сильно загружают систему при том, что больше никогда не понадобятся пользователю.
+
помимо остановки и запуска контейнеров можно выполнять другие действия над контенерами композы. Например, просмотр журналов (логов) и другие.
  
Поэтому для конечного пользователя целесообразно создать новый контейнер, исключив оттуда всё лишнее и оставив лишь непосредственно готовое приложение.
 
  
 +
Изучите справочную систему команды
  
Как это сделать -- см. в лабораторной работе ниже.
+
docker compose
  
==[Практическая работа №3] Создание контейнера для запуска приложения на Lazarus==
+
для ознакомления с другим её функционалом.
Откройте терминал хостовой машины. Если в домашнем каталоге пользователя присутствует каталог
 
  
docker
+
===Самостоятельное задание===
  
то переместите его в резервную копию командой:
+
====Подготовка====
  
mv docker docker_backup1
+
Придумать уникальный префикс для именования названий, завязанный на фамилию и инициалы обучающегося.
  
затем заново создайте рабочий каталог командой:
+
Например, для обучающегося
  
  mkdir docker
+
  Иванов Иван Иванович
  
Перейдите в рабочий каталог
+
Префикс (<prefix>) будет состоять из фамилии и инициалов
  
  cd docker
+
  ivanov_ii
  
===Создание файлов===
+
Тогда в приведённых ниже примерах необходимо
  
В рабочем каталоге создайте файл
+
<prefix>
  
Dockerfile_prod
+
заменять на
  
по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):
+
ivanov_ii
  
<pre>
+
Например
FROM ubuntu:20.04
 
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
 
  
ENV USER ubuntu
+
ivanov_ii_container_db
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
+
Используя справку по docker, docker-compose и набор выполненных практических работ запустить тестовое Java-приложение в композиции из двух контейнеров, аналогичных контейнерам с1 и с2, описанных в практической работе №5, исходя из следующих параметров:
COPY mypr /home/$USER/
 
CMD /bin/su -c "/home/ubuntu/mypr" ubuntu
 
</pre>
 
  
Скопируйте исполняемый файл, полученный в предыдущей работе в рабочий каталог
+
0. Сеть должна иметь имя
  
  cp ../docker_backup1/lazarus/project_name/mypr ./
+
  net_<prefix>
  
Мы находимся в новом рабочем каталоге хостовой машины:
+
1. Контейнер с базой данных должен иметь имя
  
  /home/user/docker
+
  <prefix>_container_db
  
В начале этой работы каталог предыдущей работы мы переместили сюда:
+
и хостовое имя
  
  /home/user/docker_backup1
+
  <prefix>-container-db
  
Следовательно, относительно каталога
+
2. Контейнер с Java-приложением должен иметь имя
  
  /home/user/docker
+
  <prefix>_container_app
  
команда копирования исполняемого файла требует подняться на уровень выше
+
и хостовое имя
  
  ../
+
  <prefix>-container-app
  
и из каталога
+
3. База данных должна иметь название
  
  docker_backup1
+
  <prefix>_application_db
  
уровнем выше относительно
+
имя пользователя
  
  /home/user/docker
+
  <prefix>_application_user
  
скопировать необходимый файл в текущий каталог
+
пароль
  
  ./
+
  <prefix>_applicationPassw0rd123
  
В конце этого этапа в рабочем каталоге должно быть два файла:
+
На основе этих данных должен быть создан файл
  
  Dockerfile_prod
+
  docker-compose.yaml
mypr
 
  
===Создание образа контейнера===
+
а ход работы по его созданию и процедуре запуска работоспособной композы должен быть отражён в отчёте по практической работе №5
  
Далее в этом разделе будем исходить из условия, что ваш логин на https://hub.docker.com/ будет
+
==[Практическая работа №6] Загрузка образа на hub.docker.com==
  
vpupkin
+
===Исходные данные===
  
а пароль
+
У нас есть docker-образ с Java-приложением. Скорее всего он называется
  
  ну, вы сами знаете...
+
  vpupkin/java_prod
  
 +
В практических работах 1-5 изучение работы с docker и docker-compose осуществлялось исходя из идеи о том, что в будущем для выгрузки docker-образов на hub.docker.com имя образа должно обязательно содержать префикс в виде логина на портале hub.docker.com, отделённый от имени самого образа символом
  
 +
/
  
! Также стоит помнить, что в эмуляторе терминала находиться нужно в рабочем каталоге !
+
В общем виде имя docker-образа, пригодного для загрузки на портал hub.docker.com выглядит так:
  
 +
<username>/<imagename>:<tag>
  
Для создания Docker-образа (image) выполните команду:
+
Например, для пользователя с логином
  
  docker build -t 'vpupkin/lazarus_prod:latest' -f Dockerfile_prod .
+
  vpupkin
  
 +
и смысловым названием контейнера с Java-приложением:
  
Для проверки существования созданного контейнера выполните команду:
+
java_prod
  
docker images
+
полное имя docker-образа будет следующим:
  
Среди текста ответа должна появиться строчка с новым контейнером:
+
vpupkin/java_prod
  
vpupkin/lazarus_prod  latest              20bb2900074d        16 seconds ago      217MB
+
Ещё более полное имя docker-образа может быть таким:
  
 +
vpupkin/java_prod:some_tag_name
  
! Обратите внимание на размер контейнера !
+
, где
Сравните размер контейнера с размером контейнера lazarus_dev из предыдущей работы
 
  
===Запуск контейнера на базе образа===
+
some_tag_name
  
На базе полученного образа запустите контейнер, пробросив внутрь контейнера локальный каталог хостовой машины и пробросив порт для взаимодействия с графической оболочкой контейнера посредством клиента noVNC:
+
это любое имя тега, которое может быть придумано создателем образа.
  
docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name=lazarus_prod --hostname=lazarus-prod vpupkin/lazarus_prod
+
Обычно, для production-образов значением тега по умолчанию является:
  
 +
latest
  
При запуске контейнера таким образом не указывается команда, т.к. она задаётся в файле
+
Следовательно, если на портале hub.docker.com предполагается публиковать единственный вариант образа контейнера, то в полном имени образа будем использовать рекомендованный вариант тега. Тогда общий вид имени образа приобретёт следующий вид:
  
  Dockerfile_prod
+
  vpupkin/java_prod:latest
  
строчкой
+
===Изменение имени docker-образа===
  
CMD /bin/su -c "/home/ubuntu/mypr" ubuntu
+
Если в процессе выполнения практических работ 1-5 у docker-образа имя осталось шаблонным (т.е. в качестве пользователя остался собирательный образ пользователя -- vpupkin), то перед публикацией образа на hub.docker.com необходимо его изменить.
  
Результатом запуска контейнера должно стать запущенное внутри контейнера графическое приложение с отображением графического интерфейса на хостовой машине.
+
Если ваш образ называется
  
При закрытии окна графического приложения контейнер будет завершён и будет доступен среди списка контейнеров
+
vpupkin/java_prod
  
docker ps -a
+
, а ваш настоящий аккаунт на hub.docker.com имеет логин:
  
Повторный запуск уже существующего контейнера можно осуществить по имени контейнера командой:
+
ivanov_ii
  
docker start lazarus_prod
+
, то прежде чем выполнять публикацию образа его необходимо переименовать. Новое имя образа может быть, например, таким:
  
==[Практическая работа №4] Взаимодействие двух контейнеров по сети==
+
ivanov_ii/java_prod
  
Задача: Запустить ПО Moodle в контейнере с именем c2, который взаимодействует с базой данных Mariadb, запущенной в контейнере с именем c1
+
В целом, не имеет значения какое название образ будет иметь справа от символа
  
===Загрузить образы контейнеров===
+
/
  
docker pull mariadb
+
Главное, не давать контейнеру названий, совпадающих с уже загруженными в hub.docker.com контейнерами под вашим именем пользователя (в данном случае -- под логином ivanov_ii).
docker pull bitnami/moodle
+
Строго говоря, значение тега справа от двоеточия в имени образа предназначено для того, чтобы у пользователя была возможность не придумывать новые названия для разновидностей docker-образа (при необходимости их публикации на портале), а просто тегировать эти названия.
  
 +
Учитывая факт того, что в случае отсутствия имени тега (значения справа от двоеточия) у docker-образа при использовании имени образа в команде
  
===Создание и подготовка контейнера C1===
+
docker run ...
Создать контейнер с базой данных Mariadb и задать пароль пользователя root через переменную окружения
 
  
docker run --name=c1 --hostname=c1 -e MYSQL_ROOT_PASSWORD=123321 --network bridge -d mariadb
+
или при использовании имени образа в файле
  
Создать временный контейнер с ПО Moodle и запустить его с доступом в командную оболочку
+
docker-compose.yaml
  
docker run -it --rm --name c2_tmp --network bridge bitnami/moodle:latest /bin/bash
+
инфраструктура docker подразумевает использование тега по умолчанию (latest), необходимо задать тег по умолчанию при задании имени образу перед публикацией его на портале hub.docker.com
  
Установить во временный контейнер утилиты проверки состояния сети
+
Изменить имя docker-образа с
  
  apt update
+
  vpupkin/java_prod
apt install net-tools iputils-ping
 
  
Изнутри контейнера c2_tmp проверить доступ в базу данных (для этого нужно убедиться в корректности ip адреса контейнера c1):
+
на
  
1. Посмотреть ip адрес конейнера c2_tmp (если контейнеры были запущены последовательно, то адрес контейнера c1 будет на единицу меньше)
+
ivanov_ii/java_prod:latest
  
ifconfig
+
можно командой (дополнительно уточнив в новом имени значение тега -- справа от двоеточия):
  
2. Выполнить
+
docker tag vpupkin/java_prod ivanov_ii/java_prod:latest
  
ping <предполагаемый адрес контейнера c1>
+
Результат переименования образа можно проверить командой:
  
в соседней консоли остановить контейнер c1
+
docker images
  
docker stop c1
+
В ответе можно наблюдать несколько образов с одинаковым IMAGE ID
  
в предыдущей консоли убедиться что пинги прекратились. Вернуться в соседнюю консоль. Запустить контейнер c1
+
<pre>
 +
REPOSITORY            TAG      IMAGE ID      CREATED        SIZE
 +
ivanov_ii/java_prod  latest    82acd99eb61f  20 hours ago  1.09GB
 +
vpupkin/java_prod    latest    82acd99eb61f  20 hours ago  1.09GB
 +
</pre>
  
docker start c1
+
При необходимости, образ с предыдущим тегом (vpupkin/java_prod) можно удалить (при отсутствии контейнеров, запущенных на его базе!) командой:
  
в предыдущей консоли убедиться что пинги возобновились.
+
docker rmi vpupkin/java_prod
  
3. Выполнить проверку подключения к Mariadb посредством клиента mysql в контейнере c2_tmp
+
===Решаемая задача===
  
mysql -u root -p<пароль, установленный в переменной окружения при запуске контейнера c1> -h <корректный ip адрес контейнера c1>
+
Опубликовать подготовленный docker-образ, имеющий имя
  
4. Создать базу пользователя и базу данных Mariadb для работы Moodle (из консоли mysql, предварительно подключившись к ней под пользователем root)
+
ivanov_ii/java_prod:latest
  
CREATE DATABASE mdatabase;
+
на hub.docker.com
CREATE USER 'muser'@'%' IDENTIFIED BY '123456';
 
GRANT ALL PRIVILEGES ON mdatabase.* to 'muser'@'%' WITH GRANT OPTION;
 
  
5. Проверить корректность подключения к Mariadb с созданным пользователем к созданной базе данных
+
Для этого необходимо иметь логин и пароль от учётной записи на портале hub.docker.com
  
mysql -u muser -p123456 -h <корректный ip адрес контейнера c1> mdatabase
+
===Публикация docker-образа===
 
6. Выйти из временного контейнера c2_tmp
 
  
exit
+
Выполните аутентификацию на портале. Для этого в терминале (где обычно запускаете команды docker... и другие) выполните команду:
  
===Запуск контейнера C2 с ПО Moodle===
+
docker login
  
Поскольку в предыдущем пункте были подготовлены параметры доступа в базу данных 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
+
  Login Succeeded
  
Проверка: Открыть в браузере адрес:
+
Полный текст диалога должен быть похож на этот:
  
http://localhost:8080
+
<pre>
 +
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
 +
Username: ivanov_ii
 +
Password:
 +
WARNING! Your password will be stored unencrypted in /home/student/.docker/config.json.
 +
Configure a credential helper to remove this warning. See
 +
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  
Ввести логин и пароль от ПО Moodle, указанные ранее в переменных окружения при старте контейнера.
+
Login Succeeded
 +
</pre>
  
Подробное описание по контейнеру: https://hub.docker.com/r/bitnami/moodle
 
  
Важно! Первые несколько минут ПО Moodle не будет доступно по указанному адресу http://localhost:8080
+
После успешного логина для публикации образа выполните команду
т.к. будет выполняться его первое развёртывание.
 
  
Проследить процесс развёртывания можно внутри базы данных в контейнере c1, подключившись к ней с хостовой машины
+
docker push ivanov_ii/java_prod:latest
  
mysql -u muser -p123456 -h <корректный ip адрес контейнера c1> mdatabase
+
Процедура публикации будет похожа на эту:
  
и из консоли mysql проверить наличие таблиц в базе данных
+
<pre>
 +
The push refers to repository [docker.io/ivanov_ii/java_prod]
 +
e1640cc719ff: Pushed
 +
6fb986383f38: Pushed
 +
fbf95f9f9b64: Pushed
 +
9e9e19c988d7: Pushed
 +
fa67c5190d97: Pushed
 +
2b1db325894b: Pushed
 +
60bdc4ff8a54: Mounted from library/alt
 +
9a03b2bc42d8: Mounted from library/alt
 +
latest: digest: sha256:e75a567439afb64a9d3b5b119650e91775e7eb1d9345f5171fefba0cfe18aea3 size: 1990
 +
</pre>
  
show tables
+
После завершения процедуры публикации можно проверить наличие образа на портале https://hub.docker.com в личном кабинете, загрузив страницу в браузере выполнив вход в систему.
  
===Самостоятельное задание===
+
==Загрузка образов Docker из архивного файла==
  
Используя справку по утилите docker запустить два аналогичных контейнера, установив статические ip адреса для них.
+
Скачать архивный файл
  
==[Практическая работа №5] Взаимодействие двух контейнеров по сети==
+
wget https://wiki.nntc.nnov.ru/download/images.tar.xz
  
Создайте рабочий каталог и перейдите в него
+
Распаковать и загрузить образы в docker
  
  mkdir composemoodle
+
  unxz -c images.tar.xz | docker load
cd composemoodle
 
  
Создайте файл
+
==Оптимизации==
  
docker-compose.yml
+
===Оптимизация для контейнера в практической работе №2===
  
со следующим содержимым
+
Для сборки приложения можно использовать компилятор Java, доступный в репозитории операционной системы. Для этого нужно скорректировать Dockerfile следующим образом:
  
 
<pre>
 
<pre>
version: "2.2"
+
FROM alt:p10
services:
+
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
  mariadb:
+
RUN apt-get update -q -y \
    image: "mariadb:latest"
+
    && apt-get dist-upgrade -q -y \
    environment:
+
     && apt-get install java-11-openjdk-devel nano git java-11-openjdk libGL libgtk+3 libXxf86vm xorg-dri-swrast fonts-ttf-dejavu -q -y
      - 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>
 
</pre>
  
 +
Шаг по загрузке Java-19 с внешнего сервера и интеграция платформы в контейнер выполнять не нужно (Java-11 будет установлена штатным для дистрибутива средством)
 +
 +
затем на этапе клонирования проекта командой
 +
 +
git clone https://gitlab.nntc.nnov.ru/vlad.tancev/simple-counter
 +
 +
нужно сменить ветку для использования кода, адаптированного под платформу Java-11 (вместо Java-19 по умолчанию)
 +
 +
git checkout jdk11
 +
 +
 +
Преимущества: не нужно отдельно закачивать платформу Java-19 и заниматься её настройкой в контейнере
 +
Недостатки: более низкая версия платформы Java (11)
 +
 +
Также следует обратить внимание на то, что сборка контейнера производится на другом образе операционной системы (alt:p10) -- официальный образ производителя -- и набор устанавливаемых пакетов отличается от оригинального набора, описанного в практической работе №3.
 +
 +
В остальном порядок выполнения практической работы не отличается от практической работы №3.
 +
 +
Следует обратить внимание, что в операционной системе Alt для получения компилятора javac нужно установить пакет
 +
 +
java-11-openjdk-devel
 +
 +
, что и сделано в соответствюущей RUN-команде в Dockerfile. Также для целей сборки приложения установлены утилиты git и nano.
 +
 +
Пакеты
 +
 +
java-11-openjdk-devel nano git
 +
 +
не нужны в образе для контейнера практической работы №3, следовательно на этапе выполнения практической работы №3 их нужно убрать из команды в Dockerfile
 +
 +
===Оптимизация для контейнера в практической работе №3===
 +
 +
Для сборки образа с готовым приложением можно использовать Runtime-платформу Java (JRE), доступную в репозитории операционной системы. Для этого нужно скорректировать Dockerfile следующим образом:
  
В результате в рабочем каталоге должен быть файл:
+
<pre>
 +
FROM alt:p10
 +
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
 +
RUN apt-get update -q -y \
 +
    && apt-get dist-upgrade -q -y \
 +
    && apt-get install java-11-openjdk libGL libgtk+3 libXxf86vm xorg-dri-swrast fonts-ttf-dejavu -q -y \
 +
    && apt-get autoclean \
 +
    && apt-get autoremove \
 +
    && /bin/rm /var/cache/apt/archives/*.rpm
  
docker-compose.yml
+
RUN adduser app
  
В рабочем каталоге выполнить команду для запуска проекта
+
RUN mkdir /opt/app
 +
COPY app /opt/app
 +
COPY startup.sh /
 +
RUN chmod +x /startup.sh
  
docker-compose up
+
USER app
  
=Проблемы под Windows=
+
CMD /startup.sh
 +
</pre>
  
В этом разделе описаны возможные проблемы при использовании Docker и Docker-compose в Windows в случае если до этого была нормальная и понятная работа в системах GNU/Linux или MacOSx, а теперь по каким-то причинам потребовалось работать с Docker из Windows...
+
Шаг по загрузке Java-19 с внешнего сервера и интеграция платформы в контейнер выполнять не нужно (Java-11 будет установлена штатным для дистрибутива средством. При чём -- только JRE, т.е. без компилятора javac. Компилятор для работы приложения -- не нужен).
  
==Как запускать под виндой синтаксический сахар, если он у вас есть в формате bash скриптов==
+
Преимущества: не нужно отдельно закачивать платформу Java-19 и заниматься её настройкой в контейнере
 +
Недостатки: более низкая версия платформы Java (11)
  
Поставить GIT отсюда https://git-scm.com (он все равно будет нужен)
+
Также следует обратить внимание на то, что сборка контейнера производится на другом образе операционной системы (alt:p10) -- официальный образ производителя -- и набор устанавливаемых пакетов отличается от оригинального набора, описанного в практической работе №3.
  
Вместе с ним поставится Git Bash, которому будет передавать управление Power Shell, если из него (из Power Shell) запускать исполняемые *.sh файлы с шебангом:
+
В остальном порядок выполнения практической работы не отличается от практической работы №3.
  
#!/bin/bash
+
===Оптимизация композиции контейнеров в практической работе №5===
  
==/bin/bash^M: bad interpreter: No such file or directory==
+
Для добавления к композе контейнера с веб-приложением phpmyadmin необходимо расширить набор сервисов в файле
  
Решение описано здесь: https://forums.docker.com/t/error-while-running-docker-code-in-powershell/34059/5
+
docker-compose.yaml
  
Кратко:
+
следующим образом
  
Шаг 1
+
<pre>
 +
version: '3.9'
  
удалить репозиторий
+
services:
 +
  c1:
 +
    container_name: "c1"
 +
    hostname: "c1"
 +
    image: "mariadb"
 +
    restart: "always"
 +
    environment:
 +
      MARIADB_ROOT_PASSWORD: "123321"
 +
      MARIADB_DATABASE: "java_app_db"
 +
      MARIADB_USER: "java_app_user"
 +
      MARIADB_PASSWORD: "java_app_password"
 +
    networks:
 +
      - net_c1_c2
  
Шаг 2
+
  c2:
 +
    container_name: "c2"
 +
    hostname: "c2"
 +
    image: "vpupkin/java_prod"
 +
    restart: "no"
 +
    environment:
 +
      DISPLAY: "$DISPLAY"
 +
      DB_HOST: "c1"
 +
      DB_PORT: "3306"
 +
      DB_NAME: "java_app_db"
 +
      DB_USER: "java_app_user"
 +
      DB_PASS: "java_app_password"
 +
    volumes:
 +
      - /tmp/.X11-unix:/tmp/.X11-unix
 +
    networks:
 +
      - net_c1_c2
  
Настроить git командой
+
  c3:
 +
    container_name: "c3"
 +
    hostname: "c3"
 +
    image: phpmyadmin
 +
    restart: always
 +
    ports:
 +
      - 8080:80
 +
    environment:
 +
      - PMA_ARBITRARY=1
 +
    networks:
 +
      - net_c1_c2
  
git config --global core.autocrlf input
 
  
Шаг 3
+
networks:
 +
  net_c1_c2:
 +
    name: net_c1_c2
  
склонировать заново и попробовать ещё раз
+
</pre>
  
Но есть вероятность что винда не поймёт эту глобальную настройку, если командовать из PowerShell. Поэтому сразу железобетонный вариант -- клонировать с указанием ключа, например:
 
  
  git clone -o core.autocrlf=input https://ну_и_тут_путь_к_репозиторию
+
Относительно конфигурации, представленной в практической работе №5, был добавлен сервис c3:
  
==Кеширование образов контейнеров виндой==
 
  
Вроде бы полностью удален и контейнер и образ, однако, при повторном создании контейнера и докер-файла в консоли видно что он поднимается из кеша и не пересобирается как нужно.
+
<pre>
 +
  c3:
 +
    container_name: "c3"
 +
    hostname: "c3"
 +
    image: phpmyadmin
 +
    restart: always
 +
    ports:
 +
      - 8080:80
 +
    environment:
 +
      - PMA_ARBITRARY=1
 +
    networks:
 +
      - net_c1_c2
 +
</pre>
  
Решение - отключить кеширование. Для этого нужно создать пустой файл
+
который был подключен к той же сети, что и остальные контейнеры.
  
%APPDATA%\Docker\disable-filesystem-caching
+
У сервиса c3 экспортирован 80-й порт, на котором работает веб-приложение, на порт 8080 хостовой системы.
  
Источник: https://github.com/docker/for-win/issues/5530
+
Следовательно, веб-приложение phpmyadmin можен быть запущена в браузере хостовой машины по адресу
  
Возможно, способ с созданием файла поможет после перезагрузки ОС.
+
http://localhost:8080
  
Если способ не помогает, то можно попробовать остановить Docker (пкм на иконке Docker Desktop в трее), затем перейти в каталог
+
Для подключения необходимо использовать следующие данные:
  
  %APPDATA%\
+
  Сервер: c1
 +
Пользователь: root или java_app_user
 +
Пароль: 123321 или java_app_password
  
и удалить там оба каталога, имя которых начинается на
+
Почему так? Смотрите внимательно в файл
  
  Docker
+
  docker-compose.yaml
  
Затем запустить Docker Desktop тыком в ярлык
+
===Оптимизация №6 (запуск графического приложения в Docker под Windows)===
  
=NVIDIA IN DOCKER=
+
1. Установить VcXsrv Windows X Server: https://sourceforge.net/projects/vcxsrv/
  
https://nvidia.github.io/nvidia-container-runtime/
+
2. Запустить приложение в режиме "Multiple windows", Display Number = 0, Start no client, поставить галочку "Disable Access Control"
  
https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/user-guide.html
+
3. Приложение будет запущено в трее.
  
=Backup and Restore docker volumes=
+
Команда для запуска приложения (на примере Практической работы №2)
  
==Backup==
+
docker run --rm -it -e DISPLAY=<здесь ip адрес вашей windows-машины>:0 --mount source=C:\Users\student\pr02\src,target=/root/src,type=bind --name=java_test --hostname=java-test vpupkin/java_dev /bin/bash
  
Допустим, у нас был запущен контейнер с локальным volume такой командой:
+
==Примеры==
  
docker run -v /dbdata --name dbstore ubuntu /bin/bash
+
===Lazarus приложение===
  
/dbdata
+
https://hub.docker.com/r/vslugin/lazarus_prod
  
здесь это указание на то, что внутри контейнера в каталоге /dbdata будут находиться данные, которые docker будет физически хранить в одном из volumes. Эти данные мы и будем резервировать.
+
docker pull vslugin/lazarus_prod:latest
 +
docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name=lazarus_prod --hostname=lazarus-prod vslugin/lazarus_prod
  
 +
Пример запуска контейнера
  
Общая суть заключается в том, что мы забрасываем все volumes из определённого контейнера (в данном случае имя контейнера -- dbstore) в новый промежуточный контейнер (как можно заметить, он запускается с ключом самоуничтожения --rm), который, в свою очередь, монтирует текущий каталог пользователя (вне контейнера, на хосте, который управляет контейнерами) в каталог /backup (это уже внутри контейнера, который временно запускается). Затем происходит процедура создания архива tar из содержимого /dbdata внутри контейнера. Таким образом сам контейнер уничтожается, но в рабочем каталоге пользователя на хост-машине остаётся файл резервной копии backup.tar
+
docker start lazarus_prod
  
docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
+
===Java приложение с базой данных (два контейнера)===
  
 +
https://hub.docker.com/r/vslugin/java_prod
  
==Restore==
+
====Развёртывание и запуск вручную====
  
Допустим у нас есть бэкап, сделанный в предыдущем пункте и он у нас лежит в текущем каталоге и называется backup.tar
+
=====Команда для разрешения подключения к X-серверу=====
  
Теперь нам нужно этот бэкап распаковать в определённый каталог внутри контейнера. На текущем этапе нам без разницы: каталог назначения (куда мы будем распаковывать архив backup.tar) находится на volume или это маппинг каталога в каталог хостовой системы без использования volume -- смотрим на этот каталог назначения как на обычный каталог дерева внутри контейнера. При необходимости можно воспользоваться опцией
+
На докер-хосте под пользователем, под которым планируется запускать приложение из контейнера, выполнить команду:
  
  --volumes-from
+
  xhost +
  
при старте контейнера, чтобы "подкинуть" в этот контейнер volume из другого контейнера. Всё зависит от задачи.
+
=====Команда для ручного развёртывания=====
  
И так, мы собираемся распаковать backup.tar в каталог /dbdata нового контейнера. Для этого примерная команда будет выглядеть так:
+
docker network create net_c1_c2;docker run --name=c1 --hostname=c1 -e MARIADB_ROOT_PASSWORD=123321 -e MARIADB_DATABASE=java_app_db -e MARIADB_USER=java_app_user -e MARIADB_PASSWORD=java_app_password --network net_c1_c2 -d mariadb;sleep 5s;docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name=c2 --hostname=c2 -e DB_HOST=c1 -e DB_PORT=3306 -e DB_NAME=java_app_db -e DB_USER=java_app_user -e DB_PASS=java_app_password --network net_c1_c2 vslugin/java_prod:latest
  
docker run -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar /dbdata
+
=====Команда запуска приложения=====
  
Если предполагается, что контейнер, из которого даётся команда для распаковки, временный и его задача на время зацепить volume из другого контейнера (в примере этот контейнер называется dbstorecopy), то есть смысл использовать ключ самоуничтожения контейнера (--rm) и зацепить из другого контейнера volume опцией --volumes-from dbstorecopy. Тогда команда будет такой:
+
`docker start c2`
  
docker run --rm --volumes-from dbstorecopy -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar /dbdata
+
====Развёртывание и запуск в docker-compose====
  
==Перемещение данных между двумя контейнерами==
+
=====Развёртывание=====
Кейс для 12.12.2022
 
  
 +
Просто бросьте это в консоль:
 
<pre>
 
<pre>
# [1] stop two containers
+
cd
docker stop nntc_de_mobd_c1_1 nntc_de_mobd_c2_1
+
mkdir compose_c1_c2
 +
cd compose_c1_c2
 +
cat << EOF > docker-compose.yaml
 +
version: '3.9'
  
# [2] make dir for backups
+
services:
mkdir /root/containers/nntc-jupyter/backup
+
  c1:
 +
    container_name: "c1"
 +
    hostname: "c1"
 +
    image: "mariadb"
 +
    restart: "always"
 +
    environment:
 +
      MARIADB_ROOT_PASSWORD: "123321"
 +
      MARIADB_DATABASE: "java_app_db"
 +
      MARIADB_USER: "java_app_user"
 +
      MARIADB_PASSWORD: "java_app_password"
 +
    networks:
 +
      - net_c1_c2
  
# [3] backup dir `/opt/notebooks` from nntc_de_mobd_c1_1 to /root/containers/nntc-jupyter/backup/q.tar
+
  c2:
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 .
+
    container_name: "c2"
 +
    hostname: "c2"
 +
    image: "vslugin/java_prod:latest"
 +
    restart: "no"
 +
    environment:
 +
      DISPLAY: "$DISPLAY"
 +
      DB_HOST: "c1"
 +
      DB_PORT: "3306"
 +
      DB_NAME: "java_app_db"
 +
      DB_USER: "java_app_user"
 +
      DB_PASS: "java_app_password"
 +
    volumes:
 +
      - /tmp/.X11-unix:/tmp/.X11-unix
 +
    networks:
 +
      - net_c1_c2
  
# [4] restore dir `/opt/notebooks` in nntc_de_mobd_c2_1 from /root/containers/nntc-jupyter/backup/q.tar
+
networks:
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
+
  net_c1_c2:
 +
    name: net_c1_c2
 +
EOF
  
# [5] start two containers
+
docker-compose up -d
docker start nntc_de_mobd_c1_1 nntc_de_mobd_c2_1
 
 
</pre>
 
</pre>
 +
 +
==== Команда запуска ====
 +
 +
docker start c2

Текущая версия на 09:25, 28 января 2025

Содержание

DOCKER_IN_ESPD

Прокси сервер

В ЕСПД каждой организации существует адрес прокси-сервера для доступа в централизованно-ограниченный провайдером интернет.

Например, это может быть адрес и порт:

10.0.52.52:3128

Настройка сервиса для работы с прокси-сервером в ОС Альт

Для настройки сервиса docker в ОС Альт на доступ к образам с

hub.docker.com

необходимо:

Импортировать сертификат (подробнее об этом здесь здесь):

Переходим в каталог

cd /etc/pki/ca-trust/source/anchors/

Скачиваем сертификат

wget --no-check-certificate https://espd.rt.ru/docs/ca-root.crt

Приминяем

update-ca-trust

Далее предполагается что Docker в ОС Альт уже установлен и необходимо добавить в окружение сервиса инициализацию переменных окружения

HTTP_PROXY

и

HTTPS_PROXY

Для этого необходимо отредактировать файл

/etc/sysconfig/docker

Было:

cat /etc/sysconfig/docker
OPTIONS=""

Стало:

cat /etc/sysconfig/docker
HTTP_PROXY=http://10.0.52.52:3128
HTTPS_PROXY=http://10.0.52.52:3128
OPTIONS=""

Важно! Адрес и порт прокси сервера могут быть другими!

Затем необходимо перезапустить сервис

systemctl restart docker

Теперь можно пробовать получить образ

docker pull alt:p10

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

p10: Pulling from library/alt
8d0b964d5817: Pulling fs layer 
529c2ffbf4d6: Download complete 
8d0b964d5817: Pull complete 
529c2ffbf4d6: Pull complete 
Digest: sha256:1a4f3803dee404126c6947ea9f791eb781e25b541477dc242ef188e4e7734bef
Status: Downloaded newer image for alt:p10
docker.io/library/alt:p10

Лабораторные работы по 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-compose-v2

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

usermod -a -Gdocker student

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

systemctl start docker
systemctl enable docker

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

reboot

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

Вручную

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

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

alt:p10

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

docker pull alt:p10

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

docker run -it --name=my_first_container --hostname=my-first-container alt: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 my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Maria my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Petr my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Ekaterina my_first_image /bootstrap.sh

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

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

mkdir pr01

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

cd pr01

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

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

Dockerfile

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

FROM alt: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 my_second_image
docker run --rm -e USER_NAME=Maria my_second_image
docker run --rm -e USER_NAME=Petr my_second_image
docker run --rm -e USER_NAME=Ekaterina 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 alt:p10
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
RUN apt-get update -q -y && apt-get install nano git libX11 libX11-devel libXxf86vm libXxf86vm-devel libGL xorg-dri-swrast fonts-ttf-dejavu mate-calc -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 и компилятора должны возвращать примерно следующее:

root@java-dev:/# 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 install
bash mvnw dependency:copy-dependencies

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

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

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

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

Запуск собранного приложения в docker-контейнере на базе образа с JDK

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

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

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

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

DISPLAY

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

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

/tmp/.X11-unix

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

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

--rm

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


Эта опция сюда добавлена, поскольку сама команда старта контейнера содержит в себе цель запускать именно оболочку /bin/bash для ручного тестирования запуска собранного приложения.

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


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

Важный момент: В некоторых операционных системах может потребоваться выполнить команду

xhost +

для разрешения подключения контейнера к графической оболочке X-сервера.

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

cd /root/src/simple-counter/
java --module-path=target/dependency/ --add-modules javafx.controls,javafx.fxml -cp target/demo_up04-1.0-SNAPSHOT.jar com.example.demo_up04.DemoApplication

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

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

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


Не нужны по нескольким причинам:

  1. Исходный код чаще всего остаётся интеллектуальной собственностью компании-разработчика и не должен оказаться у заказчика;
  2. Наличие на Production-системе компилятора какого-либо языка и/или каких-либо средств разработки является потенциальной уязвимостью системы;
  3. Инструменты сборки и тестирования никогда не понадобятся конечному пользователю на Production-системе, но всегда будут занимать место на файловой системе контейнера.

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

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

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

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

mkdir pr03

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

cd pr03

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

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

Dockerfile_prod

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

FROM alt:p10
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
RUN apt-get update -q -y \
    && apt-get install nano su libX11 libX11-devel libXxf86vm libXxf86vm-devel libGL xorg-dri-swrast fonts-ttf-dejavu mate-calc -q -y \
    && apt-get autoclean \
    && apt-get autoremove

RUN adduser app

RUN mkdir /opt/jdk-19.0.1
COPY jdk-19.0.1 /opt/jdk-19.0.1

RUN mkdir /opt/app
COPY app /opt/app
COPY startup.sh /
RUN chmod +x /startup.sh

RUN echo "PATH=$PATH:/opt/jdk-19.0.1/bin" > /home/app/.bashrc
RUN echo "export JAVA_HOME=/opt/jdk-19.0.1" >> /home/app/.bashrc

USER app

CMD /startup.sh

Создайте каталог app в рабочем каталоге

mkdir app

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

/bin/cp -r ../pr02/src/simple-counter/target app/

Скачайте в рабочий каталог 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

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

rm openjdk-19.0.1_linux-x64_bin.tar.gz

Создайте в рабочем каталоге файл

startup.sh

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

#!/bin/bash
source /home/app/.bashrc
cd /opt/app
java --module-path=target/dependency/ --add-modules javafx.controls,javafx.fxml -cp target/demo_up04-1.0-SNAPSHOT.jar com.example.demo_up04.DemoApplication

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

Dockerfile_prod
startup.sh

И два каталога:

jdk-19.0.1
app

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

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

vpupkin

а пароль

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


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


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

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


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

docker images

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

vpupkin/java_prod   latest              20bb2900074d        16 seconds ago      217MB


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

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

Создадим каталог для обмена данными с контейнером

mkdir $HOME/data

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

docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --mount source="$HOME/data",target=/home/app/data,type=bind --name=java_prod --hostname=java-prod vpupkin/java_prod


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

Dockerfile_prod

строчкой

CMD /bin/su -c "/startup.sh" app

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

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

docker ps -a

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

docker start java_prod

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

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

Загрузка образа для контейнера с mariadb

docker pull mariadb

Создание сетевого моста

docker network create net_c1_c2

Проверить список сетевых мостов можно командой

docker network list

Запуск контейнера c1 и подготовка базы данных

Создать контейнер с базой данных Mariadb и задать исходные параметры работы СУБД (название базы данных, логин и пароль для базы данных, пароль пользователя root) через переменные окружения

docker run --name=c1 --hostname=c1 -e MARIADB_ROOT_PASSWORD=123321 -e MARIADB_DATABASE=java_app_db -e MARIADB_USER=java_app_user -e MARIADB_PASSWORD=java_app_password --network net_c1_c2 -d mariadb

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

docker exec -it c1 /bin/bash

Внутри контейнера запустить клиент mariadb (ранее это был клиент mysql) с параметрами подключения к бд:

mariadb -u java_app_user -pjava_app_password -h localhost java_app_db

Выход из mariadb и затем из контейнера

exit
exit

Запуск контейнера c2 с Java-приложением

Запуск контейнера с Java-приложением производится аналогично запуску, подробно описанному в практической работе №3 с учётом ряда нюансов:

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

с2

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

с2

3. Необходимо учитывать, что для корректного подключения Java-приложения к базе данных, доступной в контейнере с именем_контейнера=именем_хоста=с1 необходимо при запуске контейнера с2 передать набор переменных окружения для настройки Java-приложения на работу с базой данных в контейнере c1

DB_HOST=c1
DB_PORT=3306
DB_NAME=java_app_db
DB_USER=java_app_user
DB_PASS=java_app_password

Пример команды для запуска контейнера c2 (запуск контейнера осуществляется на базе образа, созданного в практической работе №3)

Не забудем про

xhost +
docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name=c2 --hostname=c2 -e DB_HOST=c1 -e DB_PORT=3306 -e DB_NAME=java_app_db -e DB_USER=java_app_user -e DB_PASS=java_app_password --network net_c1_c2 vpupkin/java_prod

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

--mount source="$HOME/data",target=/home/app/data,type=bind

В данном примере этот параметр опущен, т.к. тестовое приложение не имеет функций чтения и записи файлов.

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

Подготовка

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

Например, для обучающегося

Иванов Иван Иванович

Префикс (<prefix>) будет состоять из фамилии и инициалов

ivanov_ii

Тогда в приведённых ниже примерах необходимо

<prefix>

заменять на

ivanov_ii

Например

ivanov_ii_container_db


Выполнение задания

Используя справку по docker и набор выполненных практических работ запустить тестовое Java-приложение в двух контейнерах, аналогичных контейнерам с1 и с2, исходя из следующих параметров:

0. Сетевой мост должен иметь имя

net_<prefix>

1. Контейнер с базой данных должен иметь имя

<prefix>_container_db

и хостовое имя

<prefix>-container-db

2. Контейнер с Java-приложением должен иметь имя

<prefix>_container_app

и хостовое имя

<prefix>-container-app

3. База данных должна иметь название

<prefix>_application_db

имя пользователя

<prefix>_application_user

пароль

<prefix>_applicationPassw0rd123

Ход работы отразить в отчёте по практической работе №4

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

Предисловие

Решаемая в данной практической работе задача аналогична задаче из практической работы №4. Отличия состоят лишь в том, что в практической работе №4 запуск двух контейнеров, взаимодействующих между собой внутри изолированной сети, осуществляется вручную, путём выполнения команд:

docker run ...

Для автоматизации запуска приложений, компоненты которых разделены по контейнерам (их (приложения в контейнерах) ещё называют микросервисами) может быть использован инструмент:

docker compose

Инструмент docker compose (смысл названия можно перевести как "композиция из докер контейнеров") предназначен для того, чтобы автоматически запустить несколько docker-контейнеров в одном контексте (как правило, под контекстом подразумевается общая сеть, изолированная от хостовой системы но доступная для всех контейнеров композиции (как говорят DevOps-инженеры -- "композы")).

В практической работе №2 мы изучали два способа создания docker-образа: ручной и автоматический.

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

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

docker build...

производилась сборка образа


Между ручным запуском двух контейнеров, описанным в практической работе №4, и автоматическим запуском композиции из докер контейнеров (композы), описываемой в этой практической работе, можно провести такую же аналогию, как между созданием образа контейнера вручную и созданием образа контейнера автоматически. Два этих способа (ручной и автоматический) объединяет наличие специального конфигурационного файла. В случае с автоматической сборкой docker-образа это файл:

Dockerfile

, в случае же с автоматическим запуском нескольких контейнеров в композе -- это файл:

docker-compose.yaml

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

1. Сконфигурировать файл

docker-compose.yaml

2. Выполнить запуск композы командой

docker compose up ...

Практика

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

mkdir compose_с1_с2
cd compose_с1_с2

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

docker-compose.yaml

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

version: '3.9'

services:
  c1:
    container_name: "c1"
    hostname: "c1"
    image: "mariadb"
    restart: "always"
    environment:
      MARIADB_ROOT_PASSWORD: "123321"
      MARIADB_DATABASE: "java_app_db"
      MARIADB_USER: "java_app_user"
      MARIADB_PASSWORD: "java_app_password"
    networks:
      - net_c1_c2

  c2:
    container_name: "c2"
    hostname: "c2"
    image: "vpupkin/java_prod"
    restart: "no"
    environment:
      DISPLAY: "$DISPLAY"
      DB_HOST: "c1"
      DB_PORT: "3306"
      DB_NAME: "java_app_db"
      DB_USER: "java_app_user"
      DB_PASS: "java_app_password"
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
    networks:
      - net_c1_c2

networks:
  net_c1_c2:
    name: net_c1_c2


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

docker-compose.yaml

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

docker compose up -d

В результате по описанной в файле docker-compose.yaml схеме сервисов будут запущены два контейнера: с1 и с2. В том числе из контейнера с2 будет запущено графическое приложение, которое будет работать с базой данных, запущенной в контейнере с1.

Возможные проблемы и их решения

Проблема №1: не запускается графический интерфейс Java-приложения. Решение: Открыть терминал хостовой системы и выполнить в нём команду для разрешения подключения к графической системы извне (в частности -- из контейнера):

xhost +

Проблема №2: Java-приложение не может подключиться к базе данных. Решение: Повторно запустить контейнер c2. При первом запуске композы в контейнере c1 сервис базы данных не успевает запуститься к моменту, когда в контейнере c2 стартует Java-приложение. Поэтому приложение показывает ошибку. Когда окно приложение закрывается -- контейнер c2 прекращает свою работу, однако контейнер c1 по прежнему работает (и в нём с высокой долей вероятности уже запустилась СУБД). Поэтому повторный запуск контейнера c2 запустит Java-приложение, в котором уже не будет ошибки подключения к базе данных (конечно, при условии, что всё верно настроено).

Работа с контейнерами в контексте docker compose

Если мы находимся в каталоге с файлом (Это важно! Все команды этого раздела актуальны, если соблюдается простое правило -- мы стоим в каталоге с этим файлом):

docker-compose.yaml

то для упрощения работы с контейнерами (сервисами микросервисной архитектуры), входящими в состав композы, можно вместо команды

docker

использовать команду

docker compose

В случае с нашей композой сервисы имеют названия c1 и с2, следовательно, для их остановки можно применять команды:

docker compose stop c1

или

docker compose stop c2

а для остановки всей композы -- команду:

docker compose stop

а для запуска, соответственно

docker compose start c1

или

docker compose start c2

а для запуска всей композы -- команду:

docker compose start


Для развёртывания (поднятия -- up) композы выше использовалась команда:

docker compose up -d


Существует обратная операция, которую условно можно назвать свёртыванием (опускания -- down) композы. Для этого может быть использована команда:

docker compose down

Выполнение этой команды приводит к остановке и удалению всех контейнеров композы. При этом образы остаются в системе.

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

docker volume prune

Эта команда удалит все не занятые контейнерами виртуальные диски (volumes) подсистемы docker.


Также посредством команды

docker compose

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


Изучите справочную систему команды

docker compose

для ознакомления с другим её функционалом.

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

Подготовка

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

Например, для обучающегося

Иванов Иван Иванович

Префикс (<prefix>) будет состоять из фамилии и инициалов

ivanov_ii

Тогда в приведённых ниже примерах необходимо

<prefix>

заменять на

ivanov_ii

Например

ivanov_ii_container_db


Выполнение задания

Используя справку по docker, docker-compose и набор выполненных практических работ запустить тестовое Java-приложение в композиции из двух контейнеров, аналогичных контейнерам с1 и с2, описанных в практической работе №5, исходя из следующих параметров:

0. Сеть должна иметь имя

net_<prefix>

1. Контейнер с базой данных должен иметь имя

<prefix>_container_db

и хостовое имя

<prefix>-container-db

2. Контейнер с Java-приложением должен иметь имя

<prefix>_container_app

и хостовое имя

<prefix>-container-app

3. База данных должна иметь название

<prefix>_application_db

имя пользователя

<prefix>_application_user

пароль

<prefix>_applicationPassw0rd123

На основе этих данных должен быть создан файл

docker-compose.yaml

а ход работы по его созданию и процедуре запуска работоспособной композы должен быть отражён в отчёте по практической работе №5

[Практическая работа №6] Загрузка образа на hub.docker.com

Исходные данные

У нас есть docker-образ с Java-приложением. Скорее всего он называется

vpupkin/java_prod

В практических работах 1-5 изучение работы с docker и docker-compose осуществлялось исходя из идеи о том, что в будущем для выгрузки docker-образов на hub.docker.com имя образа должно обязательно содержать префикс в виде логина на портале hub.docker.com, отделённый от имени самого образа символом

/

В общем виде имя docker-образа, пригодного для загрузки на портал hub.docker.com выглядит так:

<username>/<imagename>:<tag>

Например, для пользователя с логином

vpupkin

и смысловым названием контейнера с Java-приложением:

java_prod

полное имя docker-образа будет следующим:

vpupkin/java_prod

Ещё более полное имя docker-образа может быть таким:

vpupkin/java_prod:some_tag_name

, где

some_tag_name

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

Обычно, для production-образов значением тега по умолчанию является:

latest

Следовательно, если на портале hub.docker.com предполагается публиковать единственный вариант образа контейнера, то в полном имени образа будем использовать рекомендованный вариант тега. Тогда общий вид имени образа приобретёт следующий вид:

vpupkin/java_prod:latest

Изменение имени docker-образа

Если в процессе выполнения практических работ 1-5 у docker-образа имя осталось шаблонным (т.е. в качестве пользователя остался собирательный образ пользователя -- vpupkin), то перед публикацией образа на hub.docker.com необходимо его изменить.

Если ваш образ называется

vpupkin/java_prod

, а ваш настоящий аккаунт на hub.docker.com имеет логин:

ivanov_ii

, то прежде чем выполнять публикацию образа его необходимо переименовать. Новое имя образа может быть, например, таким:

ivanov_ii/java_prod

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

/

Главное, не давать контейнеру названий, совпадающих с уже загруженными в hub.docker.com контейнерами под вашим именем пользователя (в данном случае -- под логином ivanov_ii). Строго говоря, значение тега справа от двоеточия в имени образа предназначено для того, чтобы у пользователя была возможность не придумывать новые названия для разновидностей docker-образа (при необходимости их публикации на портале), а просто тегировать эти названия.

Учитывая факт того, что в случае отсутствия имени тега (значения справа от двоеточия) у docker-образа при использовании имени образа в команде

docker run ...

или при использовании имени образа в файле

docker-compose.yaml

инфраструктура docker подразумевает использование тега по умолчанию (latest), необходимо задать тег по умолчанию при задании имени образу перед публикацией его на портале hub.docker.com

Изменить имя docker-образа с

vpupkin/java_prod

на

ivanov_ii/java_prod:latest

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

docker tag vpupkin/java_prod ivanov_ii/java_prod:latest

Результат переименования образа можно проверить командой:

docker images

В ответе можно наблюдать несколько образов с одинаковым IMAGE ID

REPOSITORY            TAG       IMAGE ID       CREATED        SIZE
ivanov_ii/java_prod   latest    82acd99eb61f   20 hours ago   1.09GB
vpupkin/java_prod     latest    82acd99eb61f   20 hours ago   1.09GB

При необходимости, образ с предыдущим тегом (vpupkin/java_prod) можно удалить (при отсутствии контейнеров, запущенных на его базе!) командой:

docker rmi vpupkin/java_prod

Решаемая задача

Опубликовать подготовленный docker-образ, имеющий имя

ivanov_ii/java_prod:latest

на hub.docker.com

Для этого необходимо иметь логин и пароль от учётной записи на портале hub.docker.com

Публикация docker-образа

Выполните аутентификацию на портале. Для этого в терминале (где обычно запускаете команды docker... и другие) выполните команду:

docker login

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

Login Succeeded

Полный текст диалога должен быть похож на этот:

Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: ivanov_ii
Password: 
WARNING! Your password will be stored unencrypted in /home/student/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded


После успешного логина для публикации образа выполните команду

docker push ivanov_ii/java_prod:latest

Процедура публикации будет похожа на эту:

The push refers to repository [docker.io/ivanov_ii/java_prod]
e1640cc719ff: Pushed 
6fb986383f38: Pushed 
fbf95f9f9b64: Pushed 
9e9e19c988d7: Pushed 
fa67c5190d97: Pushed 
2b1db325894b: Pushed 
60bdc4ff8a54: Mounted from library/alt 
9a03b2bc42d8: Mounted from library/alt 
latest: digest: sha256:e75a567439afb64a9d3b5b119650e91775e7eb1d9345f5171fefba0cfe18aea3 size: 1990

После завершения процедуры публикации можно проверить наличие образа на портале https://hub.docker.com в личном кабинете, загрузив страницу в браузере выполнив вход в систему.

Загрузка образов Docker из архивного файла

Скачать архивный файл

wget https://wiki.nntc.nnov.ru/download/images.tar.xz 

Распаковать и загрузить образы в docker

unxz -c images.tar.xz | docker load

Оптимизации

Оптимизация для контейнера в практической работе №2

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

FROM alt:p10
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
RUN apt-get update -q -y \
    && apt-get dist-upgrade -q -y \
    && apt-get install java-11-openjdk-devel nano git java-11-openjdk libGL libgtk+3 libXxf86vm xorg-dri-swrast fonts-ttf-dejavu -q -y

Шаг по загрузке Java-19 с внешнего сервера и интеграция платформы в контейнер выполнять не нужно (Java-11 будет установлена штатным для дистрибутива средством)

затем на этапе клонирования проекта командой

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

нужно сменить ветку для использования кода, адаптированного под платформу Java-11 (вместо Java-19 по умолчанию)

git checkout jdk11


Преимущества: не нужно отдельно закачивать платформу Java-19 и заниматься её настройкой в контейнере Недостатки: более низкая версия платформы Java (11)

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

В остальном порядок выполнения практической работы не отличается от практической работы №3.

Следует обратить внимание, что в операционной системе Alt для получения компилятора javac нужно установить пакет

java-11-openjdk-devel

, что и сделано в соответствюущей RUN-команде в Dockerfile. Также для целей сборки приложения установлены утилиты git и nano.

Пакеты

java-11-openjdk-devel nano git

не нужны в образе для контейнера практической работы №3, следовательно на этапе выполнения практической работы №3 их нужно убрать из команды в Dockerfile

Оптимизация для контейнера в практической работе №3

Для сборки образа с готовым приложением можно использовать Runtime-платформу Java (JRE), доступную в репозитории операционной системы. Для этого нужно скорректировать Dockerfile следующим образом:

FROM alt:p10
MAINTAINER Vasya I Pupkin <vasya@pupkin.com>
RUN apt-get update -q -y \
    && apt-get dist-upgrade -q -y \
    && apt-get install java-11-openjdk libGL libgtk+3 libXxf86vm xorg-dri-swrast fonts-ttf-dejavu -q -y \
    && apt-get autoclean \
    && apt-get autoremove \
    && /bin/rm /var/cache/apt/archives/*.rpm

RUN adduser app

RUN mkdir /opt/app
COPY app /opt/app
COPY startup.sh /
RUN chmod +x /startup.sh

USER app

CMD /startup.sh

Шаг по загрузке Java-19 с внешнего сервера и интеграция платформы в контейнер выполнять не нужно (Java-11 будет установлена штатным для дистрибутива средством. При чём -- только JRE, т.е. без компилятора javac. Компилятор для работы приложения -- не нужен).

Преимущества: не нужно отдельно закачивать платформу Java-19 и заниматься её настройкой в контейнере Недостатки: более низкая версия платформы Java (11)

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

В остальном порядок выполнения практической работы не отличается от практической работы №3.

Оптимизация композиции контейнеров в практической работе №5

Для добавления к композе контейнера с веб-приложением phpmyadmin необходимо расширить набор сервисов в файле

docker-compose.yaml

следующим образом

version: '3.9'

services:
  c1:
    container_name: "c1"
    hostname: "c1"
    image: "mariadb"
    restart: "always"
    environment:
      MARIADB_ROOT_PASSWORD: "123321"
      MARIADB_DATABASE: "java_app_db"
      MARIADB_USER: "java_app_user"
      MARIADB_PASSWORD: "java_app_password"
    networks:
      - net_c1_c2

  c2:
    container_name: "c2"
    hostname: "c2"
    image: "vpupkin/java_prod"
    restart: "no"
    environment:
      DISPLAY: "$DISPLAY"
      DB_HOST: "c1"
      DB_PORT: "3306"
      DB_NAME: "java_app_db"
      DB_USER: "java_app_user"
      DB_PASS: "java_app_password"
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
    networks:
      - net_c1_c2

  c3:
    container_name: "c3"
    hostname: "c3"
    image: phpmyadmin
    restart: always
    ports:
      - 8080:80
    environment:
      - PMA_ARBITRARY=1
    networks:
      - net_c1_c2


networks:
  net_c1_c2:
    name: net_c1_c2


Относительно конфигурации, представленной в практической работе №5, был добавлен сервис c3:


  c3:
    container_name: "c3"
    hostname: "c3"
    image: phpmyadmin
    restart: always
    ports:
      - 8080:80
    environment:
      - PMA_ARBITRARY=1
    networks:
      - net_c1_c2

который был подключен к той же сети, что и остальные контейнеры.

У сервиса c3 экспортирован 80-й порт, на котором работает веб-приложение, на порт 8080 хостовой системы.

Следовательно, веб-приложение phpmyadmin можен быть запущена в браузере хостовой машины по адресу

http://localhost:8080

Для подключения необходимо использовать следующие данные:

Сервер: c1
Пользователь: root или java_app_user
Пароль: 123321 или java_app_password

Почему так? Смотрите внимательно в файл

docker-compose.yaml

Оптимизация №6 (запуск графического приложения в Docker под Windows)

1. Установить VcXsrv Windows X Server: https://sourceforge.net/projects/vcxsrv/

2. Запустить приложение в режиме "Multiple windows", Display Number = 0, Start no client, поставить галочку "Disable Access Control"

3. Приложение будет запущено в трее.

Команда для запуска приложения (на примере Практической работы №2)

docker run --rm -it -e DISPLAY=<здесь ip адрес вашей windows-машины>:0 --mount source=C:\Users\student\pr02\src,target=/root/src,type=bind --name=java_test --hostname=java-test vpupkin/java_dev /bin/bash

Примеры

Lazarus приложение

https://hub.docker.com/r/vslugin/lazarus_prod

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

Пример запуска контейнера

docker start lazarus_prod

Java приложение с базой данных (два контейнера)

https://hub.docker.com/r/vslugin/java_prod

Развёртывание и запуск вручную

Команда для разрешения подключения к X-серверу

На докер-хосте под пользователем, под которым планируется запускать приложение из контейнера, выполнить команду:

xhost +
Команда для ручного развёртывания
docker network create net_c1_c2;docker run --name=c1 --hostname=c1 -e MARIADB_ROOT_PASSWORD=123321 -e MARIADB_DATABASE=java_app_db -e MARIADB_USER=java_app_user -e MARIADB_PASSWORD=java_app_password --network net_c1_c2 -d mariadb;sleep 5s;docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name=c2 --hostname=c2 -e DB_HOST=c1 -e DB_PORT=3306 -e DB_NAME=java_app_db -e DB_USER=java_app_user -e DB_PASS=java_app_password --network net_c1_c2 vslugin/java_prod:latest
Команда запуска приложения

`docker start c2`

Развёртывание и запуск в docker-compose

Развёртывание

Просто бросьте это в консоль:

cd
mkdir compose_c1_c2
cd compose_c1_c2
cat << EOF > docker-compose.yaml
version: '3.9'

services:
  c1:
    container_name: "c1"
    hostname: "c1"
    image: "mariadb"
    restart: "always"
    environment:
      MARIADB_ROOT_PASSWORD: "123321"
      MARIADB_DATABASE: "java_app_db"
      MARIADB_USER: "java_app_user"
      MARIADB_PASSWORD: "java_app_password"
    networks:
      - net_c1_c2

  c2:
    container_name: "c2"
    hostname: "c2"
    image: "vslugin/java_prod:latest"
    restart: "no"
    environment:
      DISPLAY: "$DISPLAY"
      DB_HOST: "c1"
      DB_PORT: "3306"
      DB_NAME: "java_app_db"
      DB_USER: "java_app_user"
      DB_PASS: "java_app_password"
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
    networks:
      - net_c1_c2

networks:
  net_c1_c2:
    name: net_c1_c2
EOF

docker-compose up -d

Команда запуска

docker start c2