Контейнеризация приложения Java
В этом уроке вы контейнеризируете приложение Java.
Как упоминалось ранее, контейнеры выполняются непосредственно поверх хост-системы, ядра и оборудования как обычные системные процессы. Контейнеры требуют меньше системных ресурсов, что приводит к меньшему объему ресурсов, меньшему объему затрат и более быстрому времени запуска приложения. Эти преимущества являются отличными вариантами использования для масштабирования по требованию.
Существуют контейнеры Windows и контейнеры Linux. В этом модуле используется широко используемая среда выполнения Docker для создания образа контейнера Linux. Затем вы развернете образ контейнера Linux в операционной системе узла локального компьютера. Наконец, вы развернете образ контейнера Linux в службе Azure Kubernetes.
Обзор Docker
Среда выполнения Docker используется для создания, извлечения, запуска и отправки образов контейнеров, как показано на следующей схеме:
В следующей таблице описана каждая команда Docker:
| Команда Docker | Описание |
|---|---|
docker build |
Создает образ контейнера, состоящий из инструкций или слоев, необходимых для Docker, чтобы создать запущенный контейнер из образа. Результатом этой команды является изображение. |
docker pull |
Загружает образ из реестра в хранилище образов демона Docker, выбранного клиентом. Существующие слои изображений можно повторно использовать. В этом модуле локальная среда Docker использует образы из реестров во время разработки; позже узлы AKS извлекут образ приложения из Реестр контейнеров Azure для развертывания. |
docker run |
Создает и запускает новый контейнер из образа. Контейнер запускает настроенный процесс запуска с учетом переопределений через командную строку. Слои образа предоставляют файловую систему контейнера; инструкции по сборке Dockerfile не выполняются повторно при запуске контейнера. |
docker push |
Реестр контейнеров Azure хранит образы так, чтобы они были легко доступны и находились близко к сети для развертывания и масштабирования Azure. |
Клонирование приложения Java
Сначала клонируйте репозиторий Flight Booking System for Airline Reservations и перейдите в папку проекта веб-приложения авиакомпаний.
Заметка
Если создание службы Azure Kubernetes завершено на вкладке CLI, используйте её. Если она всё ещё выполняется, откройте новую вкладку и перейдите к расположению, где вы хотите клонировать систему бронирования авиабилетов.
Выполните следующие команды:
git clone https://github.com/Azure-Samples/containerize-and-deploy-Java-app-to-Azure.git
cd containerize-and-deploy-Java-app-to-Azure/Project/Airlines
При необходимости при установке Java и Maven можно выполнить следующую команду в консоли терминала, чтобы получить представление о создании приложения без Docker. Если у вас нет java и Maven, вы можете безопасно перейти к следующему разделу, создайте файл Docker. В этом разделе вы используете Docker для загрузки Java и Maven, чтобы автоматически выполнять сборки.
mvn clean package
Заметка
Мы использовали mvn clean package команду, чтобы проиллюстрировать операционные проблемы, связанные с неиспользованием многоэтапных сборок Docker, которые мы рассмотрим далее. Опять же, этот шаг является необязательным. В любом случае можно безопасно продолжить без выполнения команды Maven.
Если процесс был успешным, Maven успешно собрал артефакт веб-приложения для бронирования авиабилетов Flight Booking System for Airline Reservations AirlinesReservationSample-0.0.1-SNAPSHOT.war, как показано в приведенном ниже выводе. Метка времени сборки и длительность могут отличаться:
[INFO] Building war: $PROJECT_PATH/containerize-and-deploy-Java-app-to-Azure/Project/Airlines/target/AirlinesReservationSample-0.0.1-SNAPSHOT.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.776 s
[INFO] Finished at: 2024-11-15T09:33:26+09:00
[INFO] ------------------------------------------------------------------------
Представьте, что вы разработчик Java, и вы только что создали AirlinesReservationSample-0.0.1-SNAPSHOT.war. Следующий шаг, вероятно, заключается в работе с инженерами эксплуатации, чтобы развернуть этот артефакт на локальном сервере или виртуальной машине. Для успешного запуска и запуска приложения серверы и виртуальные машины должны быть доступны и настроены с необходимыми зависимостями. Этот процесс является сложным и трудоемким, особенно в моменты повышенной нагрузки на приложение. С помощью контейнеров эти проблемы устраняются.
Создайте Dockerfile
Теперь вы готовы создать Dockerfile. Dockerfile — это текстовый документ, содержащий все команды, которые пользователь выполнит в командной строке для сборки образа контейнера. Образ контейнера может содержать несколько уровней файловой системы только для чтения. Docker может повторно использовать кэшированные результаты сборки для неизменённых шагов. Слои создаются поверх друг друга.
Например, система бронирования полетов для резервирования авиакомпаний должна развертываться и запускаться внутри сервера приложений. Сервер приложений не упакован внутри AirlinesReservationSample-0.0.1-SNAPSHOT.war. Это внешняя зависимость, необходимая для AirlinesReservationSample-0.0.1-SNAPSHOT.war для запуска, прослушивания и обработки HTTP-запросов, управления сеансами пользователей и обеспечения бронирования рейсов. Если вы использовали традиционное развертывание без использования контейнеров, то инженеры по эксплуатации устанавливают и настраивают сервер приложений на физическом сервере или виртуальной машине перед развертыванием AirlinesReservationSample-0.0.1-SNAPSHOT.war. Инженеры по операциям также должны убедиться, что JDK, используемый на вашем компьютере, с помощью которого mvn clean package производится компиляция WAR-файла, соответствует тому же JRE, который используется сервером приложений. Управление этими зависимостями является сложным и трудоемким.
С помощью Dockerfile вы можете автоматически составить инструкции или уровни, необходимые для достижения этой цели, поэтапно добавляя шаги, чтобы убедиться, что система бронирования авиабилетов имеет все необходимые зависимости для развертывания в среде выполнения контейнеров Docker. Это решение представляет собой убедительное решение при работе с масштабированием по запросу в незапланированные моменты времени. Каждый слой использует кэш Docker, содержащий состояние образа контейнера на каждой вехе инструкции, оптимизируя время вычислений и повторное использование. Если слой не изменяется, используются кэшированные слои. Распространенные варианты использования кэшированных уровней — это среда выполнения Java, сервер приложений и другие зависимости для веб-приложения "Резервирование рейсов для резервирования авиакомпаний". Если и когда версия изменяется на ранее кэшированном слое, создается новая кэшированная запись.
Образ контейнера содержит слои файловой системы только для чтения. В этом примере Dockerfile копирует Tomcat и WAR-файл Flight Booking System в образ во время сборки. Docker добавляет отдельный доступный для записи слой при создании контейнера из образа. Доступный для записи слой контейнера записывает собственные изменения файловой системы, не изменяя слои образа.
Заметка
Для файлов, хранящихся в доступном для записи слое контейнера, добавления, изменения и удаления влияют на этот контейнер, а не на исходный образ. При изменении файлов, поступающих из слоя образа, используется механизм копирования при записи.
Docker имеет концепцию многоэтапных сборок, функцию, которая позволяет создавать меньший образ контейнера с улучшенным кэшированием и меньшим объемом безопасности, что позволяет повысить оптимизацию и обслуживание Dockerfile с течением времени. Например, можно разделить этап сборки контейнера для компиляции и создания приложения с этапа запуска приложения. Эта функция позволяет копировать только артефакты, созданные во время сборки, в производственный контейнерный образ, что уменьшает занимаемое пространство. Так как образы контейнеров кэшируются, если изменения отсутствуют, кэшированные образы можно повторно использовать, уменьшая затраты и время загрузки из сети.
Службы, предоставляемые в рабочей среде, должны тщательно контролироваться для обеспечения безопасности. Поэтому в рабочей среде используется и работает защищенный образ контейнера. В этом примере используется образ Linux Azure, предоставляемый Microsoft.
Последний этап использует Microsoft Build of OpenJDK 17 в Azure Linux 3.0. Тег 17-azurelinux именует эту базу явным образом. Старый 17-mariner тег остается псевдонимом совместимости, который зеркально отражает образ Linux Azure; его не следует путать с устаревшими 17-mariner-cm1 и 17-mariner-cm2 изображениями. Дополнительные сведения см. в разделе образы контейнеров Microsoft Build of OpenJDK.
Заметка
Microsoft предоставляет образы контейнеров, поставляемые с OpenJDK, включая образы Ubuntu, Azure Linux и distroless. Изображение distroless имеет наименьший размер, но запуск Tomcat на нем представляет сложность. Чтобы достичь упрощенного дизайна, distroless изображение удаляет множество команд и инструментов, включая оболочку, что означает, что вы не можете вызвать catalina.sh для запуска Tomcat. Образ distroless подходит для запуска исполняемых файлов JAR, таких как те, которые используются с Spring Boot или Quarkus.
В следующем примере одна и та же версия Microsoft Build OpenJDK используется как на этапе сборки, так и на последнем этапе. Этот подход гарантирует, что исходный код создается с той же версией JDK, что используется в развертывании службы Tomcat, что помогает избежать непредвиденного поведения из-за несоответствия версий.
На следующем рисунке показана многоэтапная сборка и то, что происходит на каждом этапе на основе команд, указанных в Dockerfile:
На этапе 0 Tomcat загружается из архива Apache для конкретной версии, проверяется с помощью контрольной суммы SHA-512 и извлекается в каталог, указанный переменной среды на образе Ubuntu. Переменная TOMCAT_VERSION задает выпуск, а аргумент сборки TOMCAT_SHA512 указывает ожидаемую контрольную сумму. Обновите оба значения вместе при выборе более нового поддерживаемого выпуска. Docker может повторно использовать кэшированный уровень установки, если его инструкции и входные данные остаются неизменными. Установка Tomcat копируется в окружение финального этапа для использования.
На этапе 1 Maven устанавливается на образ Ubuntu, а созданные исходные коды и файлы конфигурации копируются перед созданием проекта Maven. Каждый из слоев кэшируется, поэтому слои образов ОС и Maven используют повторно этот кэш. Если файлы конфигурации, файлы исходного кода или веб-каталог обновляются, слои будут перестроены с этого момента. Если сборка успешно завершается без ошибок во время компиляции, создается артефакт с именем AirlinesReservationSample-0.0.1-SNAPSHOT.war в целевом каталоге. Этот артефакт копируется в последнюю среду этапа для использования.
На последнем этапе артефакты сборки Tomcat и Java с этапа 0 и этапа 1, соответственно, копируются в образ Microsoft Build of OpenJDK 17 на Azure Linux 3.0. Пользователь с именем app владеет всеми файлами, используемыми в проекте, и приложение также запускается под пользователем app вместо использования привилегий root. Эта настройка гарантирует, что образ контейнера можно безопасно использовать без предоставления ненужных разрешений. Наконец, предоставляется номер порта 8080, и скрипт catalina.sh выполняется для запуска Tomcat. При запуске на локальном компьютере Docker Desktop вы можете получить доступ к нему по URL-адресу http://localhost:8080/AirlinesReservationSample.
В containerize-and-deploy-Java-app-to-Azure/Project/Airlines используйте установленный текстовый редактор для создания файла с именем Dockerfile. Добавьте следующее содержимое и сохраните файл:
Important
Перед созданием образа, который вы сделаете общедоступным, проверьте текущий поддерживаемый выпуск Tomcat 10.1.x на странице скачивания Apache Tomcat и просмотрите уведомления о безопасности. Обновляйте TOMCAT_VERSION и TOMCAT_SHA512 вместе, используя опубликованную Apache информацию о выпусках. Артефакт, оставшийся доступным в архиве Apache , не означает, что его версия является текущей или рекомендуемой.
############################################
# Tomcat Intall stage
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat
ENV CATALINA_HOME=/usr/local/tomcat
# Configure the reviewed Tomcat version and checksum
ENV TOMCAT_VERSION=10.1.61
ARG TOMCAT_SHA512=35120a2b1182bac3d55438fbec0dc581d03b0f1c16ce692a930f3bb6a1097cf896b94b389152257071a87cb2928ac8c15f1bad08387c14acc7c17dbc1bb598fb
# Install Tomcat and required packages
RUN apt-get update && \
apt-get install -y --no-install-recommends curl ca-certificates && \
curl -fSL \
"https://archive.apache.org/dist/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz" \
-o /tmp/tomcat.tar.gz && \
echo "${TOMCAT_SHA512} /tmp/tomcat.tar.gz" | sha512sum -c - && \
mkdir -p "${CATALINA_HOME}" && \
tar -xzf /tmp/tomcat.tar.gz --strip-components=1 -C "${CATALINA_HOME}" && \
rm /tmp/tomcat.tar.gz && \
apt-get remove --purge -y curl && \
apt-get autoremove -y && \
apt-get clean
############################################
# Build stage (Compiles with Java 17)
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build
WORKDIR /build
# Install Maven
RUN apt-get update && apt-get install -y maven && mvn --version
# Copy source code
COPY pom.xml .
COPY src ./src
COPY web ./web
# Build the project
RUN mvn clean package
############################################
# Package final stage
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-azurelinux
# Configure the location of the Tomcat installation
ENV CATALINA_HOME=/usr/local/tomcat
# Configure the path to the Tomcat binaries
ENV PATH=$CATALINA_HOME/bin:$PATH
# This is the user that runs the Tomcat process
USER app
# Copy the Tomcat installation from the Tomcat stage
COPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME}
# Copy the Tomcat configuration files
COPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/conf
# Copy the compiled WAR file from the build stage
COPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.war
# Expose the default Tomcat port
EXPOSE 8080
# Start Tomcat
CMD ["catalina.sh", "run"]
Заметка
Используйте Dockerfile, показанный в этом уроке для этого упражнения. Приложение должно быть скопировано в webapps/AirlinesReservationSample.war, чтобы URL-адреса в следующих блоках использовали контекст /AirlinesReservationSample/. Другое имя WAR-файла изменяет контекст приложения Tomcat по умолчанию.
Dockerfile разделен на три этапа, которые описаны в следующих таблицах:
Этап установки Tomcat:
Команда Docker Описание FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcatзадает базовый образ Microsoft Build of OpenJDK 17 на Ubuntu и называет этот этапtomcat. Здесь устанавливается Tomcat.ENVENV CATALINA_HOME=/usr/local/tomcatзадает переменную среды для каталога установки Tomcat.ENVENV TOMCAT_VERSION=10.1.61задает фиксированную версию Tomcat для этого примера. Просмотрите поддерживаемые выпуски и обновите его вместе сTOMCAT_SHA512, при необходимости.ARGARG TOMCAT_SHA512предоставляет опубликованную контрольную сумму SHA-512 Apache для выбранного архива в качестве аргумента сборки.RUNУстанавливает curlи сертификаты ЦС, а затем используетcurl -fSLдля скачивания архива Apache для конкретной версии.-fприводит к сбою при HTTP-ошибках;-Lследует перенаправлениям. Архив проверяется с помощьюsha512sum -c -перед извлечением вCATALINA_HOMEс помощью--strip-components=1. Цепочка&&останавливается на сбое вместо маскирования ошибок во время очистки. Наконец, он удаляет архив и ненужные пакеты и очищает кэш пакетов.Этап сборки, который компилируется с помощью Java 17:
Команда Docker Описание FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS buildзадает базовый образ Microsoft Build of OpenJDK 17 на Ubuntu и называет этот этапbuild. Этот этап используется для компиляции приложения Java.WORKDIRWORKDIR /buildзадает рабочий каталог внутри контейнера/build, где исходный код копируется и компилируется.RUNRUN apt-get update && apt-get install -y maven && mvn --versionустанавливает Maven, средство автоматизации сборки, используемое для проектов Java, и проверяет его установку.COPYCOPY pom.xml .копирует файл конфигурации Maven в рабочий каталог. Этот файл необходим для создания проекта.COPYCOPY src ./srcкопирует каталог исходного кода в контейнер. Здесь находится код приложения Java.COPYCOPY web ./webкопирует каталог веб-ресурсов в контейнер. Сюда входят ресурсы веб-приложения, необходимые для сборки.RUNRUN mvn clean packageвыполняет процесс сборки Maven, который компилирует приложение Java и упаковает его в WAR-файл.Заключительный этап пакета:
Команда Docker Описание FROMFROM mcr.microsoft.com/openjdk/jdk:17-azurelinuxУстанавливает Microsoft Build of OpenJDK 17 на Azure Linux 3.0 в качестве базового образа, который используется для окончательного развертывания приложения.ENVENV CATALINA_HOME=/usr/local/tomcatзадает переменную среды для каталога установки Tomcat, аналогичную этапу установки.ENVENV PATH=$CATALINA_HOME/bin:$PATHдобавляет каталог bin Tomcat в системуPATH, позволяя командам Tomcat легко выполняться.USERUSER appуказывает пользователя, под которым выполняется процесс Tomcat, что повышает безопасность, так как процесс не выполняется от имени корневого пользователя.COPYCOPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME}копирует установку Tomcat с этапаtomcat, устанавливая право владения для пользователяapp.COPYCOPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/confкопирует файл конфигурации пользователя Tomcat в контейнер, задав пользователю право владенияapp.COPYCOPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.warкопирует скомпилированный WAR-файл изbuildэтапа в каталог веб-приложений Tomcat, задав пользователю право владенияapp.EXPOSEEXPOSE 8080документирует, что приложение должно прослушивать TCP-порт 8080. Порт хоста не публикуется. Следующая единица публикует порт с параметром-p 8080:8080наdocker run.CMDCMD ["catalina.sh", "run"]указывает команду для запуска Tomcat при запуске контейнера.
Дополнительные сведения о построении Dockerfile см. в справочнике по Dockerfile.