DockerAlt: различия между версиями
Vovan (обсуждение | вклад) (→Создание файлов) |
Vovan (обсуждение | вклад) (→Сборка приложения на языке Java в docker-контейнере) |
||
Строка 438: | Строка 438: | ||
Исходя из рекомендаци в файле README.md выполним сборку проекта | Исходя из рекомендаци в файле README.md выполним сборку проекта | ||
− | bash mvnw | + | bash mvnw install |
+ | bash mvnw dependency:copy-dependencies | ||
В случае успешной сборки в терминале котейнера долждно быть написано что-то похожее на это: | В случае успешной сборки в терминале котейнера долждно быть написано что-то похожее на это: |
Версия 10:11, 16 января 2023
Содержание
- 1 Лабораторные работы по Docker
- 1.1 Подготовка рабочего места
- 1.2 [Практическая работа №1] Создание простого контейнера
- 1.3 [Практическая работа №2] Создание контейнера для разработки приложения на языке Java
- 1.4 [Практическая работа №3] Создание контейнера для запуска Java-приложения
- 1.5 [Практическая работа №4] Взаимодействие двух контейнеров по сети
- 1.6 [Практическая работа №5] Взаимодействие двух контейнеров по сети
Лабораторные работы по Docker
Подготовка рабочего места
Для выполнения всех работ достаточно установить в виртуальную машину ОС Альт Рабочая Станция 10.
Ссылка на загрузку установочного образа: https://download.basealt.ru/pub/distributions/ALTLinux/p10/images/workstation/x86_64/alt-workstation-10.0-x86_64.iso
После установки нужно обновить систему
su -
apt-get update
apt-get dist-upgrade
update-kernel -f
открыть терминал и установить Docker командой
apt-get install docker-engine
Затем добавить текущего пользователя в группу docker командой
usermod -a -Gdocker student
затем включить сервис и поставить его в автозагрузку
systemctl start docker
systemctl enable docker
перезагрузиться
reboot
[Практическая работа №1] Создание простого контейнера
Вручную
Откройте терминал хостовой машины
На базе официального стандартного Docker-образа
altlinux/base:p10
Только получить образ на компьютер можно командой:
docker pull altlinux/base:p10
создайте и запустите Docker-контейнер:
docker run -it --name=my_first_container --hostname=my-first-container altlinux/base:p10 /bin/bash
В случае успешного создания Docker-контейнера в эмуляторе терминала приглашение должно смениться на такое:
root@my-first-container:/#
Внимание! Сейчас вы внутри Docker-контейнера и можете командовать им! Если скомандовать
exit
, то контейнер завершит свою работу и найти и запустить его можно таким образом:
Найти:
docker ps -a
в ответе среди возможных прочих контейнеров должен быть такой:
f0a3cc6a8b63 altlinux/base:p10 "/bin/bash" 15 seconds ago Exited (0) 5 seconds ago my_first_container
Имя его в данном случае:
my_first_container
Идентификатор его в данном случае:
f0a3cc6a8b63
Запустить:
docker start my_first_container
или:
docker start f0a3cc6a8b63
Естественно, в конкретном случае идентификатор будет другой.
Подключиться к терминалу Docker-контейнера:
docker attach my_first_container
или
docker attach f0a3cc6a8b63
Внимание! Сейчас вы внутри контейнера и можете командовать им! Если скомандовать
exit
, то контейнер завершит свою работу придётся опять читать выше по тексту как его запускать...
Однако есть способ отключиться от терминала и не завершить Docker-контейнер:
Для этого нужно последовательно нажать сочетания клавиш:
Ctrl + P
затем
Ctrl + Q
После этого приглашение командной строки контейнера должно заменить приглашение хостовой системы.
На этом этапе мы научились запускать контейнер на базе образа. Однако наша цель -- создать собственный образ, поведение контейнеров, запущенных на базе которого который будет отличаться от поведения только что созданного нами контейнера.
Для создания собственного образа вручную необходимо внести изменения внутри нашего контейнера, а затем выполнить операцию по "превращению" нашего контейнера в образ.
Задача
Создать образ, содержащий стартовый сценарий, который будет считывать переменную окружения с именем пользователя и приветствовать пользователя по имени.
Ход работы
Запустите контейнер my_first_container и подключитесь к его терминалу (как это сделать - описано выше)
Установите внутри контейнера текстовый редактор
apt-get update apt-get install nano
Создайте с помощью установленного редактора nano файл сценария
bootstrap.sh
со следующим содержимым:
#!/bin/bash echo "Hello, $USER_NAME"
Сделайте файл исполняемым
chmod +x /bootstrap.sh
Проверьте работоспособность командой:
USER_NAME=Ivan /bootstrap.sh
в результате в терминал должна быть выдана строка
Hello, Ivan
Завершите контейнер, выйдя из него:
exit
Создайте новый образ на базе изменённого контейнера командой:
docker commit -a Vasya -m "My first own image" my_first_container my_first_image
Образ будет доступен в списке образов
docker images
Выполните запуск контейнера с автоматическим удалением его после завершения, передавая в команду запуска различные значения переменной окружения
USER_NAME
Примеры команды:
docker run --rm -e USER_NAME=Ivan -it my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Maria -it my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Petr -it my_first_image /bootstrap.sh
docker run --rm -e USER_NAME=Ekaterina -it my_first_image /bootstrap.sh
Автоматически (посредством файла Dockerfile)
Откройте терминал хостовой машины и создайте рабочий каталог
mkdir pr01
Перейдите в рабочий каталог
cd pr01
Создание файлов
В рабочем каталоге создайте файл
Dockerfile
по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):
FROM altlinux/base:p10 MAINTAINER Vasya I Pupkin <vasya@pupkin.com> RUN echo '#!/bin/bash' > /bootstrap.sh RUN echo 'echo "Hello, $USER_NAME"' >> /bootstrap.sh RUN chmod +x /bootstrap.sh CMD /bootstrap.sh
В конце этого этапа в рабочем каталоге должен быть один файл:
Dockerfile
Создание образа контейнера
Для создания Docker-образа (image) выполните команду:
docker build -t 'my_second_image:latest' .
Для проверки существования созданного контейнера выполните команду:
docker images
Среди текста ответа должна появиться строчка с новым контейнером:
my_second_image latest add5d00c3dc0 7 seconds ago 72.9MB
Запуск контейнера на базе образа
Запуск контейнеров на базе созданного образа (за исключением имени образа и отсутствием необходимости указывать исполняемый скрипт (он указан непосредственно в Dockerfile)) ни чем не будет отличаться от запуска контейнеров в ходе создания образа вручную:
docker run --rm -e USER_NAME=Ivan -it my_second_image
docker run --rm -e USER_NAME=Maria -it my_second_image
docker run --rm -e USER_NAME=Petr -it my_second_image
docker run --rm -e USER_NAME=Ekaterina -it my_second_image
[Практическая работа №2] Создание контейнера для разработки приложения на языке Java
Откройте терминал хостовой машины и создайте рабочий каталог
mkdir pr02
Перейдите в рабочий каталог
cd pr02
Создание файлов
Скачайте в рабочий каталог JDK версии 19.0.1. Это можно сделать командой (рекомендуется использовать в локальной сети колледжа)
wget https://wiki.nntc.nnov.ru/download/openjdk-19.0.1_linux-x64_bin.tar.gz
или командой (при работе вне локальной сети колледжа)
wget https://download.java.net/java/GA/jdk19.0.1/afdd2e245b014143b62ccb916125e3ce/10/GPL/openjdk-19.0.1_linux-x64_bin.tar.gz
Распакуйте загруженный файл командой
tar -xzpf openjdk-19.0.1_linux-x64_bin.tar.gz
В результате будет доступен каталог
jdk-19.0.1
На этом этапе архив можно удалить командой
rm openjdk-19.0.1_linux-x64_bin.tar.gz
В рабочем каталоге создайте файл
Dockerfile_dev
по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):
FROM altlinux/base:p10 MAINTAINER Vasya I Pupkin <vasya@pupkin.com> RUN apt-get update -q -y && apt-get install nano git 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] Changes detected - recompiling the module! [INFO] Compiling 5 source files to /root/src/simple-counter/target/classes [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 34.809 s [INFO] Finished at: 2023-01-13T11:12:55Z [INFO] ------------------------------------------------------------------------
На этом этам сборки приложения заврешён.
Теперь наша задача - запустить приложение прямо на хостовой машине (но выполняться оно будет в контейнере).
Запуск собранного приложения в 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-сервера.
Отвечаем на главный вопрос?
Вопрос звучит так:
Если мы уже собрали приложение, то нужно ли конечному пользователю инструменты для сборки приложения, которые были нужны в сборочном контейнере, и исходный код приложения?
Не нужны по нескольким причинам:
- Исходный чаще всего остаётся интеллектуальной собственностью компании-разработчика и не должен оказаться у заказчика
- Наличие на Production-системе компилятора какого-либо языка и/или каких-либо средств разработки является потенциальной уязвимостью системы
- Инструменты сборки и тестирования никогда не понадобятся конечному пользователю на Production-системе, но всегда будут занимать место на файловой системе контейнера
Поэтому для конечного пользователя целесообразно создать новый образ, исключив оттуда всё лишнее и оставив лишь непосредственно готовое приложение.
Как это сделать -- см. в следующей практической работе.
[Практическая работа №3] Создание контейнера для запуска Java-приложения
Откройте терминал хостовой машины. Создайте рабочий каталог
mkdir pr03
Перейдите в рабочий каталог
cd pr03
Создание файлов
В рабочем каталоге создайте файл
Dockerfile_prod
по следующему шаблону (в файле нужно изменить имя и емэйл разработчика на собственное):
FROM altlinux/base: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 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 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 CMD /bin/su - -c "/startup.sh" app
Создайте каталог app в рабочем каталоге
mkdir app
Скопируйте исполняемый файл, полученный в предыдущей работе в рабочий каталог
/bin/cp -rf ../pr02/src/simple-counter/target ../pr02/src/simple-counter/.mvn ../pr02/src/simple-counter/mvnw ../pr02/src/simple-counter/pom.xml 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 cd /opt/app bash mvnw exec:java -Dexec.mainClass="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] Взаимодействие двух контейнеров по сети
Задача: Запустить ПО Moodle в контейнере с именем c2, который взаимодействует с базой данных Mariadb, запущенной в контейнере с именем c1
Загрузить образы контейнеров
docker pull mariadb docker pull bitnami/moodle
Создание и подготовка контейнера C1
Создать контейнер с базой данных Mariadb и задать пароль пользователя root через переменную окружения
docker run --name=c1 --hostname=c1 -e MYSQL_ROOT_PASSWORD=123321 --network bridge -d mariadb
Создать временный контейнер с ПО Moodle и запустить его с доступом в командную оболочку
docker run -it --rm --name c2_tmp --network bridge bitnami/moodle:latest /bin/bash
Установить во временный контейнер утилиты проверки состояния сети
apt update apt install net-tools iputils-ping
Изнутри контейнера c2_tmp проверить доступ в базу данных (для этого нужно убедиться в корректности ip адреса контейнера c1):
1. Посмотреть ip адрес конейнера c2_tmp (если контейнеры были запущены последовательно, то адрес контейнера c1 будет на единицу меньше)
ifconfig
2. Выполнить
ping <предполагаемый адрес контейнера c1>
в соседней консоли остановить контейнер c1
docker stop c1
в предыдущей консоли убедиться что пинги прекратились. Вернуться в соседнюю консоль. Запустить контейнер c1
docker start c1
в предыдущей консоли убедиться что пинги возобновились.
3. Выполнить проверку подключения к Mariadb посредством клиента mysql в контейнере c2_tmp
mysql -u root -p<пароль, установленный в переменной окружения при запуске контейнера c1> -h <корректный ip адрес контейнера c1>
4. Создать базу пользователя и базу данных Mariadb для работы Moodle (из консоли mysql, предварительно подключившись к ней под пользователем root)
CREATE DATABASE mdatabase; CREATE USER 'muser'@'%' IDENTIFIED BY '123456'; GRANT ALL PRIVILEGES ON mdatabase.* to 'muser'@'%' WITH GRANT OPTION;
5. Проверить корректность подключения к Mariadb с созданным пользователем к созданной базе данных
mysql -u muser -p123456 -h <корректный ip адрес контейнера c1> mdatabase
6. Выйти из временного контейнера c2_tmp
exit
Запуск контейнера C2 с ПО Moodle
Поскольку в предыдущем пункте были подготовлены параметры доступа в базу данных Mariadb, используем их для запуска контейнера с ПО Moodle
docker run -d --name c2 -p 8080:8080 -p 8443:8443 --env ALLOW_EMPTY_PASSWORD=no --env MOODLE_DATABASE_USER=muser --env MOODLE_DATABASE_PASSWORD=123456 --env MOODLE_DATABASE_NAME=mdatabase --env MOODLE_DATABASE_HOST=<корректный ip адрес контейнера c1> --env MOODLE_USERNAME=user --env MOODLE_PASSWORD=123321 --env MOODLE_EMAIL=user@host.com --env MOODLE_SITE_NAME=user_moodle --network bridge bitnami/moodle:latest
Проверка: Открыть в браузере адрес:
http://localhost:8080
Ввести логин и пароль от ПО Moodle, указанные ранее в переменных окружения при старте контейнера.
Подробное описание по контейнеру: https://hub.docker.com/r/bitnami/moodle
Важно! Первые несколько минут ПО Moodle не будет доступно по указанному адресу http://localhost:8080 т.к. будет выполняться его первое развёртывание.
Проследить процесс развёртывания можно внутри базы данных в контейнере c1, подключившись к ней с хостовой машины
mysql -u muser -p123456 -h <корректный ip адрес контейнера c1> mdatabase
и из консоли mysql проверить наличие таблиц в базе данных
show tables
Самостоятельное задание
Используя справку по утилите docker запустить два аналогичных контейнера, установив статические ip адреса для них.
[Практическая работа №5] Взаимодействие двух контейнеров по сети
Создайте рабочий каталог и перейдите в него
mkdir composemoodle cd composemoodle
Создайте файл
docker-compose.yml
со следующим содержимым
version: "2.2" services: mariadb: image: "mariadb:latest" environment: - MYSQL_ROOT_PASSWORD=123321 - MYSQL_ALLOW_EMPTY_PASSWORD=no - MYSQL_DATABASE=mdatabase - MYSQL_USER=muser - MYSQL_PASSWORD=123456 moodle: ports: - "8080:8080" - "8443:8443" image: "bitnami/moodle:latest" environment: - ALLOW_EMPTY_PASSWORD=no - MOODLE_DATABASE_USER=muser - MOODLE_DATABASE_PASSWORD=123456 - MOODLE_DATABASE_NAME=mdatabase - MOODLE_DATABASE_HOST=mariadb - MOODLE_USERNAME=user - MOODLE_PASSWORD=123321 - MOODLE_EMAIL=user@host.com - MOODLE_SITE_NAME=user_moodle
В результате в рабочем каталоге должен быть файл:
docker-compose.yml
В рабочем каталоге выполнить команду для запуска проекта
docker-compose up