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