Java 앱 컨테이너화
이 단원에서는 Java 애플리케이션을 컨테이너화합니다.
앞에서 설명한 것처럼 컨테이너는 호스트 운영 체제, 커널 및 하드웨어를 기반으로 일반 시스템 프로세스로 직접 실행됩니다. 컨테이너에는 더 적은 시스템 리소스가 필요하므로 사용 공간이 줄어들고 오버헤드가 줄어들며 애플리케이션 시작 시간이 빨라집니다. 이러한 이점은 주문형 크기 조정을 위한 유용한 사용 사례입니다.
Windows 컨테이너 및 Linux 컨테이너가 있습니다. 이 모듈에서는 널리 사용되는 Docker 런타임을 사용하여 Linux 컨테이너 이미지를 빌드합니다. 그런 다음 로컬 컴퓨터의 호스트 운영 체제에 Linux 컨테이너 이미지를 배포합니다. 마지막으로 Linux 컨테이너 이미지를 Azure Kubernetes Service에 배포합니다.
Docker 개요
Docker 런타임은 다음 다이어그램과 같이 컨테이너 이미지를 빌드, 끌어오기, 실행 및 푸시하는 데 사용됩니다.
다음 표에서는 각 Docker 명령에 대해 설명합니다.
| Docker 명령 | 설명 |
|---|---|
docker build |
Docker가 이미지에서 실행 중인 컨테이너를 만드는 데 필요한 지침 또는 계층으로 구성된 컨테이너 이미지를 빌드합니다. 이 명령의 결과는 이미지입니다. |
docker pull |
컨테이너는 Azure Container Registry와 같은 레지스트리에서 가져온 이미지에서 초기화됩니다. 이 레지스트리는 Azure Kubernetes Service에서 가져오는 위치입니다. 이 명령의 결과는 Azure에서 발생하는 이미지의 네트워크 끌어오기입니다. 필요에 따라 이미지를 로컬로 끌어올 수 있습니다. 이 옵션은 애플리케이션 서버와 같이 애플리케이션에 필요할 수 있는 종속성 또는 계층이 필요한 이미지를 빌드할 때 일반적입니다. |
docker run |
이미지의 실행 중인 인스턴스는 컨테이너이며, 이 명령은 실행 중인 컨테이너 애플리케이션을 실행하고 상호 작용하는 데 필요한 모든 계층을 실행합니다. 이 명령의 결과는 호스트 운영 체제에서 실행 중인 애플리케이션 프로세스입니다. |
docker push |
Azure Container Registry는 이미지를 쉽게 사용할 수 있도록 저장하고 Azure 배포 및 규모에 대한 네트워크를 닫습니다. |
Java 애플리케이션 복제
먼저 항공사 예약용 항공편 예약 시스템 리포지토리를 복제하고 Airlines 웹 애플리케이션 프로젝트 폴더로 이동합니다.
비고
CLI 탭에서 Azure Kubernetes Service 만들기가 완료되면 해당 탭을 사용합니다. 계속 실행 중인 경우 새 탭을 열고 항공사 예약에 대한 항공편 예약 시스템을 복제하려는 위치로 이동합니다.
다음 명령어를 실행하세요:
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은 다음 출력과 같이 항공사 예약 웹 응용 프로그램 보관 아티팩트 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은 사용자가 명령줄에서 실행하여 컨테이너 이미지를 어셈블하는 모든 명령을 포함하는 텍스트 문서입니다. 각 이미지는 효율성을 위해 캐시할 수 있는 계층입니다. 계층은 서로 위에 쌓입니다.
예를 들어 항공 예약에 대한 플라이트 예약 시스템은 애플리케이션 서버 내에 배포하고 실행해야 합니다. 애플리케이션 서버는 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을 사용하면 항공 예약 예약 시스템에 Docker 컨테이너 런타임에 배포하는 데 필요한 모든 종속성이 있는지 확인하는 데 필요한 단계를 계층화하여 이 목표를 자동으로 수행하는 데 필요한 지침 또는 계층을 작성할 수 있습니다. 이 솔루션은 계획되지 않은 간격으로 주문형 규모로 작업할 때 유용합니다. 각 계층은 각 지침 마일스톤에서 컨테이너 이미지의 상태를 포함하는 Docker 캐시를 사용하여 컴퓨팅 시간 및 재사용을 최적화합니다. 레이어가 변경되지 않으면 캐시된 계층이 사용됩니다. 캐시된 계층의 일반적인 사용 사례는 Java 런타임, 애플리케이션 서버 및 항공사 예약 웹 애플리케이션에 대한 플라이트 예약 시스템에 대한 기타 종속성입니다. 이전에 캐시된 계층에서 버전이 변경되면 캐시된 새 항목이 만들어집니다.
다음 다이어그램은 컨테이너 이미지의 레이어를 보여 줍니다. Dockerfile의 명령이 실행되면 계층이 만들어집니다. 최상위 계층은 항공사 예약 웹 애플리케이션 계층에 대한 읽기/쓰기 플라이트 예약 시스템입니다. 해당 계층은 이전 읽기 전용 계층 위에 빌드됩니다.
Docker에는 더 나은 캐싱 및 더 작은 보안 공간을 사용하여 더 작은 컨테이너 이미지를 만들 수 있는 기능인 다단계 빌드 개념이 있어 시간이 지남에 따라 Dockerfile의 최적화 및 유지 관리가 향상됩니다. 예를 들어 애플리케이션을 컴파일하고 빌드하기 위한 컨테이너 빌드 단계를 애플리케이션 실행 단계에서 분리할 수 있습니다. 이 기능을 사용하면 빌드 중에 생성된 아티팩트만 프로덕션 컨테이너 이미지에 복사하여 공간을 줄일 수 있습니다. 컨테이너 이미지는 캐시되므로 변경 내용이 없는 경우 캐시된 이미지를 재사용하여 네트워크에서 다운로드하는 비용과 시간을 줄일 수 있습니다.
프로덕션 환경에 노출되는 서비스는 보안을 위해 신중하게 관리해야 합니다. 따라서 프로덕션 환경에서는 보안 컨테이너 이미지를 사용하고 작동합니다. 이 예제에서는 Microsoft에서 CBL-Mariner 제공하는 이미지를 사용합니다.
CBL-Mariner Linux는 클라우드 환경에 필요한 패키지만 포함하는 경량 운영 체제입니다. 애플리케이션의 요구 사항에 맞게 사용자 지정 패키지 및 도구를 통해 사용자 지정할 수 있습니다. CBL-Mariner Azure 유효성 검사 테스트를 거치며 Azure 에이전트와 호환됩니다. Microsoft는 Azure 서비스부터 전원 공급 IoT 인프라에 이르기까지 다양한 사용 사례에 전원을 공급하기 위해 CBL-Mariner 빌드 및 테스트합니다. Microsoft 클라우드 서비스 및 관련 제품에 사용하기 위해 내부적으로 권장되는 Linux 배포입니다.
비고
Microsoft는 OpenJDK와 함께 번들로 제공되는 컨테이너 이미지(예Ubuntu: 및 이미지) CBL-Marinerdistroless 를 제공합니다. 이미지 크기가 distroless 가장 작지만 Tomcat을 실행하는 것은 어려운 일입니다. 경량 디자인을 distroless 구현하기 위해 이미지는 셸을 포함하여 많은 명령과 도구를 제거하므로 catalina.sh 호출하여 Tomcat을 시작할 수 없습니다. 이 distroless 이미지는 Spring Boot 또는 Quarkus와 함께 사용되는 것과 같은 실행 파일 JAR을 실행하는 데 적합합니다.
다음 예제에서는 빌드 단계와 최종 단계 모두에서 동일한 버전의 OpenJDK Microsoft Build가 사용됩니다. 이 방법을 사용하면 서비스 배포 Tomcat에서 사용하는 것과 동일한 버전의 JDK로 소스 코드를 빌드할 수 있으므로 버전 불일치로 인한 예기치 않은 동작을 방지할 수 있습니다.
다음 이미지는 Dockerfile에 지정된 명령에 따라 다단계 빌드 및 각 단계에서 발생하는 작업을 보여 줍니다.
0단계에서 Tomcat은 Ubuntu 이미지의 환경 변수에 의해 지정된 디렉터리로 다운로드되고 추출됩니다. 변수는 TOMCAT_VERSION 다운로드할 Tomcat의 버전을 지정합니다. 새 버전의 Tomcat이 릴리스된 경우 버전 번호가 변경될 때만 새 이미지를 가져오므로 버전 번호를 업데이트해야 합니다. 그렇지 않으면 캐시된 이미지가 사용됩니다. 다운로드한 Tomcat은 사용할 최종 단계 환경으로 복사됩니다.
1단계에서는 Maven이 Ubuntu 이미지에 설치되고, Maven 프로젝트를 빌드하기 전에 생성된 소스 코드 및 구성 파일이 복사됩니다. 각 계층은 캐시되므로 OS 이미지와 Maven 이미지 계층은 캐시를 다시 사용합니다. 구성 파일, 소스 코드 파일 또는 웹 디렉터리가 업데이트되면 변경 내용 이후의 계층이 다시 작성됩니다. 컴파일 중에 오류 없이 빌드가 성공적으로 완료되면 AirlinesReservationSample-0.0.1-SNAPSHOT.war 이라는 아티팩트가 대상 디렉터리 아래에 생성됩니다. 이 아티팩트가 사용할 최종 단계 환경에 복사됩니다.
최종 단계에서 Microsoft에서 제공하는 보안 CBL-Mariner 이미지는 각각 0단계와 1단계에서 Tomcat 및 Java 빌드 아티팩트 복사에 사용됩니다. 명명된 app 사용자는 프로젝트 내에서 사용되는 모든 파일을 소유하며, 애플리케이션도 권한이 없는 root 대신 사용자로 app 실행됩니다. 이 설정을 사용하면 불필요한 권한을 부여하지 않고도 컨테이너 이미지를 안전하게 작동할 수 있습니다. 마지막으로 포트 번호 8080이 노출되고 catalina.sh 스크립트가 실행되어 Tomcat을 시작합니다. 로컬 Docker Desktop에서 실행되면 URL http://localhost:8080/AirlinesReservationSample을 통해 액세스할 수 있습니다.
프로젝트의 루트 폴더인 containerize-and-deploy-Java-app-to-Azure/Project/Airlines 내에서 다음 명령을 사용하여 Dockerfile이라는 파일을 만듭니다.
vi Dockerfile
Dockerfile에 다음 내용을 추가한 다음 저장하고 종료합니다. 저장하고 종료하려면 ESC 키를 누르고 :wq!를 입력한 다음 Enter 키를 누릅니 다.
############################################
# Tomcat Intall stage
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat
ENV CATALINA_HOME=/usr/local/tomcat
# Configure Tomcat Version (Be sure to use the latest version)
ENV TOMCAT_VERSION=10.1.33
# Install Tomcat and required packages
RUN apt-get update ; \
apt-get install -y curl ; \
curl -O https://downloads.apache.org/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz ; \
tar xzf apache-tomcat-${TOMCAT_VERSION}.tar.gz ; \
mv apache-tomcat-${TOMCAT_VERSION} ${CATALINA_HOME} ; \
rm apache-tomcat-${TOMCAT_VERSION}.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-mariner
# 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_Solution 파일을 사용할 수 있습니다.
Dockerfile은 다음 표에 설명된 세 단계로 나뉩니다.
Tomcat 설치 단계:
Docker 명령 설명 FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat는 기본 이미지를 Ubuntu의 Microsoft Build of OpenJDK 17로 설정하고 이 단계tomcat의 이름을 지정합니다. Tomcat이 설치된 위치입니다.ENVENV CATALINA_HOME=/usr/local/tomcat는 Tomcat 설치 디렉터리에 대한 환경 변수를 설정합니다.ENVENV TOMCAT_VERSION=10.1.33는 설치할 Tomcat의 버전을 설정합니다. 필요에 따라 최신 버전으로 업데이트해야 합니다.RUN이 RUN명령은 패키지 목록을 업데이트하고, 설치curl하고, 지정된 버전의 Tomcat을 다운로드하고, 압축을 풀고, 지정된 디렉터리로 이동하고, 불필요한 파일 및 패키지를 정리합니다. 이렇게 하면 이미지가 경량으로 유지됩니다.Java 17로 컴파일되는 빌드 단계:
Docker 명령 설명 FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build는 기본 이미지를 Ubuntu의 Microsoft Build of OpenJDK 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-mariner는 애플리케이션의 최종 배포에CBL-Mariner사용되는 Microsoft Build of OpenJDK 17에 기본 이미지를 설정합니다.ENVENV CATALINA_HOME=/usr/local/tomcat는 설치 단계와 유사하게 Tomcat 설치 디렉터리에 대한 환경 변수를 설정합니다.ENVENV PATH=$CATALINA_HOME/bin:$PATH는 Tomcat bin 디렉터리를 시스템에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는 스테이지에서buildTomcat 웹앱 디렉터리로 컴파일된 WAR 파일을 복사하여 소유권app을 사용자에게 설정합니다.EXPOSEEXPOSE 8080는 Tomcat의 기본 포트인 포트 8080을 노출하여 애플리케이션에 대한 외부 액세스를 허용합니다.CMDCMD ["catalina.sh", "run"]는 컨테이너가 실행될 때 Tomcat을 시작하는 명령을 지정합니다.
Dockerfile 생성에 대한 자세한 내용은 Dockerfile 참조를 참조하세요.