Java 앱을 컨테이너화하세요
이 단원에서는 Java 애플리케이션을 컨테이너화합니다.
앞에서 설명한 것처럼 컨테이너는 호스트 운영 체제, 커널 및 하드웨어 위에서 일반 시스템 프로세스로 직접 실행됩니다. 컨테이너에는 더 적은 시스템 리소스가 필요하므로 사용 공간이 줄어들고 오버헤드가 줄어들며 애플리케이션 시작 시간이 빨라집니다. 이러한 장점은 온디맨드 스케일링의 유용한 사용 사례입니다.
Windows 컨테이너 및 Linux 컨테이너가 있습니다. 이 모듈에서는 널리 사용되는 Docker 런타임을 사용하여 Linux 컨테이너 이미지를 빌드합니다. 그런 다음 로컬 컴퓨터의 호스트 운영 체제에 Linux 컨테이너 이미지를 배포합니다. 마지막으로 Linux 컨테이너 이미지를 Azure Kubernetes Service에 배포합니다.
Docker 개요
Docker 런타임은 다음 다이어그램과 같이 컨테이너 이미지를 빌드, 끌어오기, 실행 및 푸시하는 데 사용됩니다.
다음 표에서는 각 Docker 명령에 대해 설명합니다.
| Docker 명령 | 설명 |
|---|---|
docker build |
Docker가 이미지로부터 실행 중인 컨테이너를 만드는 데 필요한 지침 또는 계층으로 구성된 컨테이너 이미지를 빌드합니다. 이 명령의 결과는 이미지입니다. |
docker pull |
레지스트리에서 클라이언트가 선택한 Docker 디먼의 이미지 저장소로 이미지를 다운로드합니다. 기존 이미지 계층을 다시 사용할 수 있습니다. 이 모듈에서는 로컬 Docker 환경이 개발 중에 레지스트리의 이미지를 사용하며 나중에 AKS 노드는 배포를 위해 Azure Container Registry에서 애플리케이션 이미지를 가져와 다운로드합니다. |
docker run |
이미지에서 새 컨테이너를 만들고 시작합니다. 컨테이너는 명령줄 옵션으로 재정의될 수 있으며, 구성된 시작 프로세스를 실행합니다. 이미지 계층은 컨테이너의 파일 시스템을 제공합니다. Dockerfile 빌드 지침은 컨테이너가 시작될 때 다시 실행되지 않습니다. |
docker push |
Azure Container Registry는 이미지를 바로 사용할 수 있고 Azure 배포 및 크기 조정을 위해 네트워크 근접하도록 저장합니다. |
Java 애플리케이션 복제하기
먼저 Flight Booking System for Airline Reservations 리포지토리를 복제하고 Airlines 웹 애플리케이션 프로젝트 폴더로 이동합니다.
비고
CLI 탭에서 Azure Kubernetes Service 만들기가 완료된 경우 해당 탭을 사용하세요. 아직 실행 중인 경우 새 탭을 열고 Flight Booking System for Airline Reservations를 복제하려는 위치로 이동하세요.
다음 명령어를 실행하세요:
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 파일을 컴파일하는 데 사용한 JDK)가 실제로 애플리케이션 서버에서 사용되는 것과 동일한 JRE에 해당하는지 확인해야 합니다. 이러한 종속성을 관리하는 것은 어려운 일이며 시간이 많이 걸립니다.
Dockerfile을 사용하면 Flight Booking System for Airline Reservations에 Docker 컨테이너 런타임으로 배포하는 데 필요한 모든 종속성이 있는지 확인하는 데 필요한 단계를 계층화하여 이 작업을 자동으로 수행하는 데 필요한 지침이나 레이어를 작성할 수 있습니다. 이 솔루션은 예상치 못한 시점에 온-디맨드 확장으로 작업할 때 매력적입니다. 각 레이어는 각 빌드 단계에서 컨테이너 이미지의 상태를 포함하는 Docker 캐시를 사용하여 컴퓨팅 시간 및 재사용을 최적화합니다. 레이어가 변경되지 않으면 캐시된 계층이 사용됩니다. 캐시된 레이어의 일반적인 사용 사례는 Java 런타임, 애플리케이션 서버 및 기타 Flight Booking System for Airline Reservations 웹 애플리케이션 종속성입니다. 이전에 캐시된 계층에서 버전이 변경될 경우 캐시된 새 항목이 만들어집니다.
컨테이너 이미지에는 읽기 전용 파일 시스템 계층이 포함되어 있습니다. 이 예제에서 Dockerfile은 빌드 시 Tomcat 및 Flight Booking System WAR 파일을 이미지에 복사합니다. Docker는 이미지에서 컨테이너를 만들 때 별도의 쓰기 가능 계층을 추가합니다. 각 컨테이너의 쓰기 가능한 계층은 이미지 계층을 수정하지 않고 자체 파일 시스템 변경 내용을 기록합니다.
비고
컨테이너의 쓰기 가능한 계층에 저장된 파일의 경우 추가, 수정 및 삭제는 원래 이미지가 아닌 해당 컨테이너에 영향을 줍니다. 이미지 계층에서 온 파일을 변경하면 copy-on-write 동작이 적용됩니다.
Docker에는 더 나은 캐싱 및 더 작은 보안 노출 범위를 사용하여 더 작은 컨테이너 이미지를 만들 수 있는 기능인 다단계 빌드 개념이 있어 시간이 지남에 따라 Dockerfile의 최적화 및 유지 관리가 용이해집니다. 예를 들어 애플리케이션을 컴파일하고 빌드하기 위한 컨테이너 빌드 단계를 애플리케이션 실행 단계에서 분리할 수 있습니다. 이 기능을 사용하면 빌드 중에 생성된 아티팩트만 프로덕션 컨테이너 이미지에 복사하여 공간을 줄일 수 있습니다. 컨테이너 이미지는 캐시되므로 변경 내용이 없는 경우 캐시된 이미지를 재사용하여 네트워크에서 다운로드하는 비용과 시간을 줄일 수 있습니다.
프로덕션 환경에 노출되는 서비스는 보안을 위해 신중하게 관리해야 합니다. 따라서 프로덕션 환경에서는 보안 컨테이너 이미지를 사용하고 실행합니다. 이 예제에서는 Microsoft 제공하는 Azure Linux 이미지를 사용합니다.
최종 단계에서는 Azure Linux 3.0에서 OpenJDK의 Microsoft Build 17을 사용합니다.
17-azurelinux 태그 이름은 이 기본 항목을 명시적으로 지정합니다. 이전 17-mariner 태그는 Azure Linux 이미지를 미러링하는 호환성 별칭으로 남아 있으며 사용 중지된 17-mariner-cm1 및 17-mariner-cm2 이미지와 혼동해서는 안 됩니다. 자세한 내용은 OpenJDK의 Microsoft Build 컨테이너 이미지를 참조하세요.
비고
Microsoft는 Ubuntu, Azure Linux 및 distroless 이미지가 포함된 OpenJDK 번들 컨테이너 이미지를 제공합니다.
distroless 이미지의 크기가 가장 작지만 Tomcat을 실행하는 것은 어려운 일입니다. 경량 설계를 구현하기 위해 이 distroless 이미지는 셸을 비롯한 많은 명령과 도구가 제거되어 있으므로 catalina.sh를 호출하여 Tomcat을 시작할 수 없습니다. 이 distroless 이미지는 Spring Boot 또는 Quarkus와 함께 사용되는 것과 같은 실행 파일 JAR을 실행하는 데 적합합니다.
다음 예제에서는 빌드 단계와 최종 단계 모두에서 동일한 버전의 OpenJDK의 Microsoft Build가 사용됩니다. 이 방법을 사용하면 서비스 배포 Tomcat에서 사용하는 것과 동일한 버전의 JDK로 소스 코드를 빌드할 수 있으므로 버전 불일치로 인한 예기치 않은 동작을 방지할 수 있습니다.
다음 이미지는 Dockerfile에 지정된 명령에 따라 다단계 빌드 및 각 단계에서 발생하는 작업을 보여 줍니다.
0단계에서 Tomcat은 버전별 Apache 보관 파일에서 다운로드되고 SHA-512 체크섬으로 확인되며 Ubuntu 이미지에서 환경 변수로 지정된 디렉터리에 압축 해제됩니다.
TOMCAT_VERSION 변수는 릴리스를 지정하고, TOMCAT_SHA512 빌드 인수는 예상 체크섬을 지정합니다. 지원되는 최신 릴리스를 선택할 때 두 값을 함께 업데이트합니다. Docker는 명령 및 입력이 변경되지 않은 상태에서 캐시된 설치 계층을 다시 사용할 수 있습니다. Tomcat 설치는 사용할 최종 단계 환경에 복사됩니다.
1단계에서는 Maven이 Ubuntu 이미지에 설치되고, Maven 프로젝트를 빌드하기 전에 생성된 소스 코드 및 구성 파일이 복사됩니다. 각 계층은 캐시되므로 OS 이미지와 Maven 이미지 계층은 캐시를 다시 사용합니다. 구성 파일, 소스 코드 파일 또는 웹 디렉터리가 업데이트되면 변경된 지점부터의 계층이 다시 빌드됩니다. 컴파일 중에 오류 없이 빌드가 성공적으로 완료되면 AirlinesReservationSample-0.0.1-SNAPSHOT.war이라는 아티팩트가 target 디렉터리 아래에 생성됩니다. 이 아티팩트가 사용하기 위해 최종 단계 환경에 복사됩니다.
마지막 단계에서는 각각 0단계와 1단계의 Tomcat 및 Java 빌드 아티팩트가 Azure Linux 3.0의 OpenJDK의 Microsoft Build 17 이미지로 복사됩니다. 명명된 app 사용자는 프로젝트 내에서 사용되는 모든 파일을 소유하며, 애플리케이션도 root 권한이 아니라 app 사용자로 실행됩니다. 이 설정을 사용하면 불필요한 권한을 부여하지 않고도 컨테이너 이미지를 안전하게 실행할 수 있습니다. 마지막으로 포트 번호 8080이 노출되고 catalina.sh 스크립트가 실행되어 Tomcat을 시작합니다. 로컬 Docker Desktop에서 실행되면 URL http://localhost:8080/AirlinesReservationSample을 통해 액세스할 수 있습니다.
containerize-and-deploy-Java-app-to-Azure/Project/Airlines에서 설치된 텍스트 편집기를 사용하여 Dockerfile라는 이름의 파일을 만듭니다. 다음 콘텐츠를 추가하고 파일을 저장합니다.
Important
공개적으로 노출할 이미지를 빌드하기 전에 Apache Tomcat 다운로드 페이지에서 현재 지원되는 Tomcat 10.1.x 릴리스를 확인하고 보안 알림을 검토하세요. Apache의 게시된 릴리스 정보를 사용하여 TOMCAT_SHA512 및 TOMCAT_VERSION를 함께 업데이트합니다.
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을 사용합니다. 다음 단위의 URL이 /AirlinesReservationSample/ 컨텍스트를 사용하도록 애플리케이션을 webapps/AirlinesReservationSample.war에 복사해야 합니다. 다른 WAR 파일 이름은 기본 Tomcat 애플리케이션 컨텍스트를 변경합니다.
Dockerfile은 세 단계로 나뉘며, 각 단계는 다음 표에 설명되어 있습니다.
Tomcat 설치 단계:
Docker 명령 설명 FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat는 기본 이미지를 Ubuntu의 OpenJDK의 Microsoft Build 17로 설정하고 이 단계의 이름을tomcat로 지정합니다. Tomcat이 설치된 위치입니다.ENVENV CATALINA_HOME=/usr/local/tomcat는 Tomcat 설치 디렉터리의 환경 변수를 설정합니다.ENVENV TOMCAT_VERSION=10.1.61는 이 예제에 고정된 Tomcat 릴리스를 설정합니다. 지원되는 릴리스를 검토하고 필요에 따라TOMCAT_SHA512와 함께 업데이트합니다.ARGARG TOMCAT_SHA512는 선택한 아카이브에 대해 Apache의 게시된 SHA-512 체크섬을 빌드 인수로 제공합니다.RUNcurl및 CA 인증서를 설치한 다음curl -fSL를 사용하여 버전별 Apache 보관 파일을 다운로드합니다.-fHTTP 오류를 실패로 처리합니다.-L는 리디렉션을 따릅니다. 아카이브는sha512sum -c -로 확인된 후CATALINA_HOME에--strip-components=1로 추출됩니다. 체인은&&정리 중에 오류를 마스킹하는 대신 실패 시 중지됩니다. 마지막으로 아카이브 및 불필요한 패키지를 제거하고 패키지 캐시를 정리합니다.Java 17로 컴파일되는 빌드 단계:
Docker 명령 설명 FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build는 기본 이미지를 Ubuntu의 OpenJDK의 Microsoft Build 17로 설정하고 이 단계의 이름을build로 지정합니다. 이 단계는 Java 애플리케이션을 컴파일하는 데 사용됩니다.WORKDIRWORKDIR /build는 컨테이너 내부의 작업 디렉터리를/build로 설정하며, 이 위치에 소스 코드가 복사되고 컴파일됩니다.RUNRUN apt-get update && apt-get install -y maven && mvn --version는 Java 프로젝트에 사용되는 빌드 자동화 도구인 Maven을 설치하고 설치를 확인합니다.COPYCOPY pom.xml .는 Maven 구성 파일을 작업 디렉터리에 복사합니다. 이 파일은 프로젝트를 빌드하는 데 필수적입니다.COPYCOPY src ./src는 소스 코드 디렉터리를 컨테이너에 복사합니다. Java 애플리케이션 코드가 있는 위치입니다.COPYCOPY web ./web는 웹 리소스 디렉터리를 컨테이너에 복사합니다. 여기에는 빌드에 필요한 웹 애플리케이션 리소스가 포함됩니다.RUNRUN mvn clean package는 Java 애플리케이션을 컴파일하고 WAR 파일로 패키지하는 Maven 빌드 프로세스를 실행합니다.패키지 최종 단계:
Docker 명령 설명 FROMFROM mcr.microsoft.com/openjdk/jdk:17-azurelinux는 애플리케이션의 최종 배포에 사용되는 Azure Linux 3.0에서 기본 이미지를 OpenJDK의 Microsoft Build 17로 설정합니다.ENVENV CATALINA_HOME=/usr/local/tomcat는 설치 단계와 유사하게 Tomcat 설치 디렉터리에 대한 환경 변수를 설정합니다.ENVENV PATH=$CATALINA_HOME/bin:$PATH는 Tomcat bin 디렉터리를 시스템PATH(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는build단계에서 컴파일된 WAR 파일을 Tomcat 웹앱 디렉터리로 복사하여app사용자로 소유권을 설정합니다.EXPOSEEXPOSE 8080는 애플리케이션이 TCP 포트 8080에서 수신 대기해야 한다고 명시합니다. 호스트 포트를 노출하지 않습니다. 다음 단원에서는docker run에서-p 8080:8080옵션을 사용하여 포트를 게시합니다.CMDCMD ["catalina.sh", "run"]는 컨테이너가 실행될 때 Tomcat을 시작하는 명령을 지정합니다.
Dockerfile 생성에 대한 자세한 내용은 Dockerfile 참조를 참조하세요.