DockerAlt: различия между версиями
Vovan (обсуждение | вклад) (→Подготовка рабочего места) |
Vovan (обсуждение | вклад) (→Docker_IN_ESPD) |
||
(не показано 114 промежуточных версий этого же участника) | |||
Строка 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 командой | |
− | + | apt-get install docker-engine | |
− | Затем добавить текущего пользователя в группу | + | Затем добавить текущего пользователя в группу docker командой |
− | docker | + | usermod -a -Gdocker student |
+ | |||
+ | затем включить сервис и поставить его в автозагрузку | ||
+ | |||
+ | systemctl start docker | ||
− | + | systemctl enable docker | |
− | + | перезагрузиться | |
− | + | reboot | |
==[Практическая работа №1] Создание простого контейнера== | ==[Практическая работа №1] Создание простого контейнера== | ||
Строка 39: | Строка 124: | ||
На базе официального стандартного Docker-образа | На базе официального стандартного Docker-образа | ||
− | + | alt:p10 | |
+ | |||
+ | Только получить образ на компьютер можно командой: | ||
+ | |||
+ | docker pull alt:p10 | ||
создайте и запустите Docker-контейнер: | создайте и запустите Docker-контейнер: | ||
− | docker run -it --name=my_first_container --hostname=my-first-container | + | docker run -it --name=my_first_container --hostname=my-first-container alt:p10 /bin/bash |
Строка 62: | Строка 151: | ||
в ответе среди возможных прочих контейнеров должен быть такой: | в ответе среди возможных прочих контейнеров должен быть такой: | ||
− | f0a3cc6a8b63 | + | 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, $ | + | echo "Hello, $USER_NAME" |
Сделайте файл исполняемым | Сделайте файл исполняемым | ||
Строка 145: | Строка 234: | ||
Проверьте работоспособность командой: | Проверьте работоспособность командой: | ||
− | + | USER_NAME=Ivan /bootstrap.sh | |
в результате в терминал должна быть выдана строка | в результате в терминал должна быть выдана строка | ||
Строка 165: | Строка 254: | ||
Выполните запуск контейнера с автоматическим удалением его после завершения, передавая в команду запуска различные значения переменной окружения | Выполните запуск контейнера с автоматическим удалением его после завершения, передавая в команду запуска различные значения переменной окружения | ||
− | + | USER_NAME | |
Примеры команды: | Примеры команды: | ||
− | docker run --rm -e | + | docker run --rm -e USER_NAME=Ivan my_first_image /bootstrap.sh |
− | docker run --rm -e | + | docker run --rm -e USER_NAME=Maria my_first_image /bootstrap.sh |
− | docker run --rm -e | + | docker run --rm -e USER_NAME=Petr my_first_image /bootstrap.sh |
− | docker run --rm -e | + | docker run --rm -e USER_NAME=Ekaterina my_first_image /bootstrap.sh |
===Автоматически (посредством файла Dockerfile)=== | ===Автоматически (посредством файла Dockerfile)=== | ||
Строка 181: | Строка 270: | ||
Откройте терминал хостовой машины и создайте рабочий каталог | Откройте терминал хостовой машины и создайте рабочий каталог | ||
− | mkdir | + | mkdir pr01 |
Перейдите в рабочий каталог | Перейдите в рабочий каталог | ||
− | cd | + | cd pr01 |
− | ===Создание файлов=== | + | ====Создание файлов==== |
В рабочем каталоге создайте файл | В рабочем каталоге создайте файл | ||
Строка 196: | Строка 285: | ||
<pre> | <pre> | ||
− | FROM | + | 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, $ | + | 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 | + | docker run --rm -e USER_NAME=Ivan my_second_image |
− | docker run --rm -e | + | docker run --rm -e USER_NAME=Maria my_second_image |
− | docker run --rm -e | + | docker run --rm -e USER_NAME=Petr my_second_image |
− | docker run --rm -e | + | docker run --rm -e USER_NAME=Ekaterina my_second_image |
− | ==[Практическая работа №2] Создание контейнера для разработки приложения на | + | ==[Практическая работа №2] Создание контейнера для разработки приложения на языке Java== |
Откройте терминал хостовой машины и создайте рабочий каталог | Откройте терминал хостовой машины и создайте рабочий каталог | ||
− | mkdir | + | mkdir pr02 |
Перейдите в рабочий каталог | Перейдите в рабочий каталог | ||
− | cd | + | 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 | + | 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 | ||
+ | |||
+ | ===Создание образа контейнера=== | ||
− | + | Далее в этом разделе будем исходить из условия, что ваш логин на 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 и компилятора должны возвращать примерно следующее: | |
− | |||
− | + | <pre> | |
+ | bash-4.4# java -version | ||
+ | openjdk version "19.0.1" 2022-10-18 | ||
+ | OpenJDK Runtime Environment (build 19.0.1+10-21) | ||
+ | OpenJDK 64-Bit Server VM (build 19.0.1+10-21, mixed mode, sharing) | ||
+ | bash-4.4# | ||
+ | bash-4.4# javac -version | ||
+ | javac 19.0.1 | ||
</pre> | </pre> | ||
− | + | Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать | |
+ | |||
+ | 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 | ||
+ | |||
+ | В случае успешной сборки в терминале котейнера долждно быть написано что-то похожее на это: | ||
<pre> | <pre> | ||
− | [ | + | [INFO] ------------------------------------------------------------------------ |
− | + | [INFO] BUILD SUCCESS | |
− | + | [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 | ||
+ | |||
+ | ===Отвечаем на главный вопрос?=== | ||
+ | |||
+ | Вопрос звучит так: | ||
+ | |||
+ | Если мы уже собрали приложение, то нужно ли конечному пользователю инструменты для сборки приложения, которые были нужны в сборочном контейнере, и исходный код приложения? | ||
+ | |||
+ | |||
+ | Не нужны по нескольким причинам: | ||
+ | |||
+ | # Исходный чаще всего остаётся интеллектуальной собственностью компании-разработчика и не должен оказаться у заказчика | ||
+ | # Наличие на Production-системе компилятора какого-либо языка и/или каких-либо средств разработки является потенциальной уязвимостью системы | ||
+ | # Инструменты сборки и тестирования никогда не понадобятся конечному пользователю на Production-системе, но всегда будут занимать место на файловой системе контейнера | ||
+ | |||
+ | Поэтому для конечного пользователя целесообразно создать новый образ, исключив оттуда всё лишнее и оставив лишь непосредственно готовое приложение. | ||
+ | |||
+ | Как это сделать -- см. в следующей практической работе. | ||
+ | |||
+ | ==[Практическая работа №3] Создание контейнера для запуска Java-приложения== | ||
+ | Откройте терминал хостовой машины. Создайте рабочий каталог | ||
+ | |||
+ | mkdir pr03 | ||
+ | |||
+ | Перейдите в рабочий каталог | ||
+ | |||
+ | cd pr03 | ||
+ | ===Создание файлов=== | ||
− | В рабочем каталоге создайте файл | + | В рабочем каталоге создайте файл |
− | + | Dockerfile_prod | |
− | + | по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное): | |
<pre> | <pre> | ||
− | + | 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 | |
+ | </pre> | ||
− | + | Создайте каталог 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 | startup.sh | ||
− | + | со следующим содержимым | |
+ | |||
+ | <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/ | + | docker build -t 'vpupkin/java_prod:latest' -f Dockerfile_prod . |
Строка 422: | Строка 712: | ||
Среди текста ответа должна появиться строчка с новым контейнером: | Среди текста ответа должна появиться строчка с новым контейнером: | ||
− | vpupkin/ | + | vpupkin/java_prod latest 20bb2900074d 16 seconds ago 217MB |
+ | |||
+ | ! Обратите внимание на размер контейнера ! | ||
+ | Сравните размер контейнера с размером контейнера java_dev из предыдущей работы | ||
===Запуск контейнера на базе образа=== | ===Запуск контейнера на базе образа=== | ||
− | На базе полученного образа запустите контейнер, пробросив внутрь контейнера локальный каталог хостовой машины | + | Создадим каталог для обмена данными с контейнером |
+ | |||
+ | mkdir $HOME/data | ||
+ | |||
+ | На базе полученного образа запустите контейнер, пробросив внутрь контейнера локальный каталог хостовой машины: | ||
− | docker run -it --mount source="$ | + | 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 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 | + | 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 и воспользоваться клиентом mysql) | |
+ | docker exec -it c1 /bin/bash | ||
− | + | Внутри контейнера запустить клиент mysql с параметрами подключения к бд: | |
− | + | mysql -u java_app_user -pjava_app_password -h localhost java_app_db | |
+ | |||
+ | Выход из mysql и из контейнера | ||
− | + | 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) | |
− | + | 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 | + | docker-compose.yaml |
− | + | 2. Выполнить запуск композы командой | |
− | + | docker-compose up ... | |
− | + | ===Установка docker-compose=== | |
+ | В хостовой системе откройте терминал и выполните команду для получения доступа под суперпользователем root | ||
− | + | su - | |
− | + | Введите пароль от суперпользователя. Приглашение должно смениться на суперпользовательское и заканчиваться символом решётки. В этом режиме выполните команду установки пакета из репозитория: | |
− | + | apt-get install docker-compose -y | |
− | + | При необходимости, перед выполнением этой команды можно выполнить команду обновления базы данных пакетов в репозитории: | |
+ | apt-get update | ||
− | + | ===Практика=== | |
+ | Создайте рабочий каталог и перейдите в него | ||
− | + | mkdir compose_с1_с2 | |
+ | cd compose_с1_с2 | ||
− | + | Создайте файл | |
− | + | docker-compose.yaml | |
− | |||
− | docker | ||
− | |||
− | + | со следующим содержимым | |
− | + | <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 | ||
− | + | 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 | ||
+ | </pre> | ||
− | |||
− | + | В результате в рабочем каталоге должен быть файл: | |
− | + | 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 | |
− | + | <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> | ||
− | + | При необходимости, образ с предыдущим тегом (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 | |
− | + | Полный текст диалога должен быть похож на этот: | |
− | + | <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 | ||
− | + | Login Succeeded | |
+ | </pre> | ||
− | |||
− | + | После успешного логина для публикации образа выполните команду | |
− | + | docker push ivanov_ii/java_prod:latest | |
− | + | Процедура публикации будет похожа на эту: | |
− | + | <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> | ||
− | + | После завершения процедуры публикации можно проверить наличие образа на портале https://hub.docker.com в личном кабинете, загрузив страницу в браузере выполнив вход в систему. | |
− | + | ==Оптимизации== | |
− | + | ===Оптимизация для контейнера в практической работе №2=== | |
− | + | Для сборки приложения можно использовать компилятор Java, доступный в репозитории операционной системы. Для этого нужно скорректировать 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-devel nano git java-11-openjdk libGL libgtk+3 libXxf86vm xorg-dri-swrast fonts-ttf-dejavu -q -y | ||
+ | </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 | ||
− | + | RUN adduser app | |
− | + | RUN mkdir /opt/app | |
+ | COPY app /opt/app | ||
+ | COPY startup.sh / | ||
+ | RUN chmod +x /startup.sh | ||
− | + | USER app | |
− | + | CMD /startup.sh | |
+ | </pre> | ||
− | + | Шаг по загрузке Java-19 с внешнего сервера и интеграция платформы в контейнер выполнять не нужно (Java-11 будет установлена штатным для дистрибутива средством. При чём -- только JRE, т.е. без компилятора javac. Компилятор для работы приложения -- не нужен). | |
− | + | Преимущества: не нужно отдельно закачивать платформу Java-19 и заниматься её настройкой в контейнере | |
+ | Недостатки: более низкая версия платформы Java (11) | ||
− | + | Также следует обратить внимание на то, что сборка контейнера производится на другом образе операционной системы (alt:p10) -- официальный образ производителя -- и набор устанавливаемых пакетов отличается от оригинального набора, описанного в практической работе №3. | |
− | + | В остальном порядок выполнения практической работы не отличается от практической работы №3. | |
+ | ===Оптимизация композиции контейнеров в практической работе №5=== | ||
− | + | Для добавления к композе контейнера с веб-приложением phpmyadmin необходимо расширить набор сервисов в файле | |
− | docker | + | docker-compose.yaml |
+ | следующим образом | ||
− | + | <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 | ||
− | + | 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 | ||
− | + | </pre> | |
− | |||
− | + | Относительно конфигурации, представленной в практической работе №5, был добавлен сервис c3: | |
− | |||
− | |||
<pre> | <pre> | ||
− | + | c3: | |
− | + | container_name: "c3" | |
+ | hostname: "c3" | ||
+ | image: phpmyadmin | ||
+ | restart: always | ||
+ | ports: | ||
+ | - 8080:80 | ||
+ | environment: | ||
+ | - PMA_ARBITRARY=1 | ||
+ | networks: | ||
+ | - net_c1_c2 | ||
+ | </pre> | ||
+ | |||
+ | который был подключен к той же сети, что и остальные контейнеры. | ||
+ | |||
+ | У сервиса c3 экспортирован 80-й порт, на котором работает веб-приложение, на порт 8080 хостовой системы. | ||
+ | |||
+ | Следовательно, веб-приложение phpmyadmin можен быть запущена в браузере хостовой машины по адресу | ||
+ | |||
+ | http://localhost:8080 | ||
− | + | Для подключения необходимо использовать следующие данные: | |
− | |||
− | + | Сервер: c1 | |
− | + | Пользователь: root или java_app_user | |
+ | Пароль: 123321 или java_app_password | ||
− | + | Почему так? Смотрите внимательно в файл | |
− | |||
− | + | docker-compose.yaml | |
− | docker | ||
− |
Текущая версия на 12:06, 12 октября 2024
Содержание
- 1 DOCKER_IN_ESPD
- 2 Лабораторные работы по Docker
- 2.1 Подготовка рабочего места
- 2.2 [Практическая работа №1] Создание простого контейнера
- 2.3 [Практическая работа №2] Создание контейнера для разработки приложения на языке Java
- 2.4 [Практическая работа №3] Создание контейнера для запуска Java-приложения
- 2.5 [Практическая работа №4] Взаимодействие двух контейнеров по сети (ручной запуск)
- 2.6 [Практическая работа №5] Взаимодействие двух контейнеров по сети (docker-compose)
- 2.7 [Практическая работа №6] Загрузка образа на hub.docker.com
- 2.8 Оптимизации
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 командой
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 и компилятора должны возвращать примерно следующее:
bash-4.4# java -version openjdk version "19.0.1" 2022-10-18 OpenJDK Runtime Environment (build 19.0.1+10-21) OpenJDK 64-Bit Server VM (build 19.0.1+10-21, mixed mode, sharing) bash-4.4# bash-4.4# javac -version javac 19.0.1
Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать
exit
, то контейнер завершит свою работу и найти и запустить его можно таким образом:
Найти:
docker ps -a
в ответе среди возможных прочих контейнеров должен быть такой:
8e5f4fd0a99b vpupkin/java_dev "/bin/bash" 3 minutes ago Exited (0) 6 seconds ago java_dev
Имя его в данном случае:
java_dev
Идентификатор его в данном случае:
8e5f4fd0a99b
Остальное пока не важно, однако можно догадаться за что отвечают остальные параметры...
Запустить:
docker start java_dev
или:
docker start 8e5f4fd0a99b
Естественно, в конкретном случае идентификатор будет другой.
Подключиться к терминалу:
docker attach java_dev
или
docker attach 8e5f4fd0a99b
Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать
exit
, то контейнер завершит свою работу придётся опять читать выше по тексту как его запускать...
Однако есть способ отключиться от терминала и не завершить контейнер:
Для этого нужно последовательно нажать сочетания клавиш:
Ctrl + P
затем
Ctrl + Q
После этого приглашение командной строки контейнера должно заменить приглашение хостовой системы.
На этом этапе мы научились создавать образ контейнера и запускать контейнер на его базе.
Сборка приложения на языке Java в docker-контейнере
Перейдём в каталог
cd /root/src/
Склонируем проект приложения на Java
git clone https://gitlab.nntc.nnov.ru/vlad.tancev/simple-counter
Перейдём в проект
cd simple-counter
Исходя из рекомендаци в файле README.md выполним сборку проекта
bash mvnw 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
Отвечаем на главный вопрос?
Вопрос звучит так:
Если мы уже собрали приложение, то нужно ли конечному пользователю инструменты для сборки приложения, которые были нужны в сборочном контейнере, и исходный код приложения?
Не нужны по нескольким причинам:
- Исходный чаще всего остаётся интеллектуальной собственностью компании-разработчика и не должен оказаться у заказчика
- Наличие на Production-системе компилятора какого-либо языка и/или каких-либо средств разработки является потенциальной уязвимостью системы
- Инструменты сборки и тестирования никогда не понадобятся конечному пользователю на 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 и воспользоваться клиентом mysql)
docker exec -it c1 /bin/bash
Внутри контейнера запустить клиент mysql с параметрами подключения к бд:
mysql -u java_app_user -pjava_app_password -h localhost java_app_db
Выход из mysql и из контейнера
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)
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 ...
Установка docker-compose
В хостовой системе откройте терминал и выполните команду для получения доступа под суперпользователем root
su -
Введите пароль от суперпользователя. Приглашение должно смениться на суперпользовательское и заканчиваться символом решётки. В этом режиме выполните команду установки пакета из репозитория:
apt-get install docker-compose -y
При необходимости, перед выполнением этой команды можно выполнить команду обновления базы данных пакетов в репозитории:
apt-get update
Практика
Создайте рабочий каталог и перейдите в него
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 в личном кабинете, загрузив страницу в браузере выполнив вход в систему.
Оптимизации
Оптимизация для контейнера в практической работе №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