Google App Engine 자바 앱에서 Docker를 사용하여 Cloud Run으로 마이그레이션

1. 개요

이 Codelab 시리즈 (사용자 주도형, 실무 가이드)는 Google App Engine (표준) Java 개발자가 일련의 마이그레이션을 통해 자신의 앱을 현대화할 수 있도록 돕기 위한 것입니다. 이 단계를 따르면 앱을 더 쉽게 이동할 수 있도록 업데이트하고 Cloud Run, App Engine에 대한 Google Cloud의 컨테이너 호스팅 자매 서비스, 기타 컨테이너 호스팅 서비스에 앱을 컨테이너화할 수 있습니다.

이 튜토리얼에서는 Dockerfile을 사용하여 Cloud Run 완전 관리형 서비스에 배포할 App Engine 앱을 컨테이너화하는 방법을 알아봅니다. Dockerfile은 이 마이그레이션에 가장 실용적인 배포 방법이지만 빌드 프로세스를 맞춤설정할 수 있는 옵션도 가장 많이 제공합니다.

App Engine에서 Cloud Run으로 이동하는 데 필요한 단계를 알려주는 것 외에도 Java 8 App Engine 앱을 Java 17로 업그레이드하는 방법을 알아봅니다.

마이그레이션하려는 애플리케이션에서 App Engine 기존 번들 서비스 또는 기타 App Engine 관련 기능을 많이 사용하는 경우 이 Codelab보다는 Java 11/17용 App Engine 번들 서비스 액세스 가이드가 더 나은 시작점이 될 수 있습니다.

다음 실습에서는

  • Cloud Shell 사용
  • Cloud Run, Artifact Registry, Cloud Build API 사용 설정
  • Docker, Docker, Cloud Build를 사용하여 앱 컨테이너화
  • 컨테이너 이미지를 Cloud Run에 배포

필요한 항목

설문조사

이 튜토리얼을 어떻게 사용하실 계획인가요?

읽기만 할 계획입니다 읽은 다음 연습 활동을 완료할 계획입니다

귀하의 Java 사용 경험을 평가해 주세요.

초급 중급 고급

귀하의 Google Cloud 서비스 사용 경험을 평가해 주세요.

초급 중급 고급

2. 배경

App Engine 및 Cloud Functions와 같은 PaaS 시스템은 시스템 관리자와 DevOps가 솔루션 빌드에 집중할 수 있도록 지원하는 등 팀과 애플리케이션에 다양한 편의 기능을 제공합니다. 서버리스 플랫폼을 사용하면 필요에 따라 앱을 자동으로 확장하고, 사용량 기반 결제로 0까지 축소하여 비용을 관리하고, 다양한 일반 개발 언어를 사용할 수 있습니다.

하지만 컨테이너의 유연성도 매력적입니다. 컨테이너를 사용하면 언어, 라이브러리, 바이너리를 선택할 수 있으므로 서버리스의 편리함과 컨테이너의 유연성을 모두 누릴 수 있습니다. 이것이 바로 Google Cloud Run의 핵심입니다.

Cloud Run 사용 방법을 배우는 것은 Cloud Run 문서에서 다루는 이 Codelab의 범위에 포함되지 않습니다. 여기서 목표는 Cloud Run (또는 기타 컨테이너 호스팅 서비스)용 App Engine 앱을 컨테이너화하는 방법을 알아보는 것입니다. 계속하기 전에 알아두어야 할 몇 가지 사항이 있는데, 일단 사용자 환경이 약간 달라집니다.

이 Codelab에서는 컨테이너를 빌드하고 배포하는 방법을 알아봅니다. Dockerfile로 앱을 컨테이너화하고, App Engine 구성에서 마이그레이션하고, Cloud Build의 빌드 단계를 정의하는 방법을 알아봅니다 (선택사항). 이렇게 하면 특정 App Engine 관련 기능을 사용하지 않게 됩니다. 이 경로를 따르지 않으려면 App Engine에서 앱을 유지하면서 Java 11/17 런타임으로 업그레이드하면 됩니다.

3. 설정/사전 작업

1. 프로젝트 설정

이 튜토리얼에서는 새 프로젝트appengine-java-migration-samples 저장소에 있는 샘플 앱을 사용합니다. 프로젝트에 활성 결제 계정이 있는지 확인합니다.

기존 App Engine 앱을 Cloud Run으로 이동하려는 경우 해당 앱을 사용하여 따라할 수 있습니다.

다음 명령어를 실행하여 프로젝트에 필요한 API를 사용 설정합니다.

gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com

2. 기준 샘플 앱 가져오기

자체 머신 또는 Cloud Shell에서 샘플 앱을 클론한 후 baseline 폴더로 이동합니다.

샘플은 App Engine에 배포하기 위한 Java 8, 서블릿 기반 Datastore 앱입니다. README의 안내에 따라 App Engine 배포를 위해 이 앱을 준비하세요.

3. (선택사항) 기준 앱 배포

다음은 Cloud Run으로 마이그레이션하기 전에 App Engine에서 앱이 작동하는지 확인하려는 경우에만 필요합니다.

README.md의 단계를 참고하세요.

  1. gcloud CLI 설치/재숙지
  2. gcloud init를 사용하여 프로젝트의 gcloud CLI를 초기화합니다.
  3. gcloud app create로 App Engine 프로젝트 만들기
  4. App Engine에 샘플 앱 배포
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. 앱이 문제 없이 App Engine에서 실행되는지 확인합니다.

4. Artifact Registry 저장소 만들기

앱을 컨테이너화한 후에는 이미지를 푸시하고 저장할 위치가 필요합니다. Google Cloud에서 이 작업을 수행하는 데 권장되는 방법은 Artifact Registry를 사용하는 것입니다.

다음과 같이 gcloud를 사용하여 migration라는 저장소를 만듭니다.

gcloud artifacts repositories create migration --repository-format=docker \
--description="Docker repository for the migrated app" \
--location="northamerica-northeast1"

이 저장소는 docker 형식 유형을 사용하지만 사용할 수 있는 여러 저장소 유형이 있습니다.

이제 기준 App Engine 앱이 있고 Google Cloud 프로젝트에서 이를 Cloud Run으로 마이그레이션할 준비가 되었습니다.

4. 애플리케이션 파일 수정

앱에서 App Engine의 기존 번들 서비스, 구성 또는 기타 App Engine 전용 기능을 많이 사용하는 경우 새 런타임으로 업그레이드하는 동안 이러한 서비스에 계속 액세스하는 것이 좋습니다. 이 Codelab에서는 이미 독립형 서비스를 사용하거나 독립형 서비스를 사용하도록 리팩터링할 수 있는 애플리케이션의 이전 경로를 보여줍니다.

1. Java 17로 업그레이드

앱이 Java 8을 사용 중인 경우 보안 업데이트를 유지하고 새로운 언어 기능을 이용할 수 있도록 11 또는 17과 같은 최신 LTS 후보로 업그레이드하는 것이 좋습니다.

먼저 pom.xml의 속성을 업데이트하여 다음을 포함합니다.

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

이렇게 하면 프로젝트 버전이 17로 설정되고, 컴파일러 플러그인에 Java 17 언어 기능에 액세스하고 컴파일된 클래스가 Java 17 JVM과 호환되기를 원한다고 알립니다.

2. 웹 서버 포함

App Engine과 Cloud Run 간에 이동할 때 고려해야 할 여러 차이점이 있습니다. 한 가지 차이점은 App Engine의 Java 8 런타임이 호스팅된 앱에 Jetty 서버를 제공하고 관리하는 반면 Cloud Run은 그렇지 않다는 것입니다. 여기서는 Spring Boot를 사용하여 웹 서버와 서블릿 컨테이너를 제공합니다.

다음 종속 항목을 추가합니다.

<dependencies>
<!-- ... -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
       <version>2.6.6</version>
       <exclusions>
           <!-- Exclude the Tomcat dependency -->
           <exclusion>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-tomcat</artifactId>
           </exclusion>
       </exclusions>
   </dependency>
   <!-- Use Jetty instead -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-jetty</artifactId>
       <version>2.6.6</version>
   </dependency>
<!-- ... -->
</dependencies>

Spring Boot는 기본적으로 Tomcat 서버를 삽입하지만 이 샘플에서는 해당 아티팩트를 제외하고 Jetty를 사용하여 마이그레이션 후 기본 동작의 차이를 최소화합니다.

3. Spring Boot 설정

Spring Boot는 수정 없이 서블릿을 재사용할 수 있지만, 서블릿이 검색 가능하도록 하려면 몇 가지 구성이 필요합니다.

com.example.appengine 패키지에 다음 MigratedServletApplication.java 클래스를 만듭니다.

package com.example.appengine;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
@EnableAutoConfiguration
public class MigratedServletApplication {
    public static void main(String[] args) {
        SpringApplication.run(MigratedServletApplication.class, args);
    }
}

여기에는 @ServletComponentScan 주석이 포함되어 있습니다. 이 주석은 @WebServlets를 찾아 예상대로 사용할 수 있도록 합니다 (기본적으로 현재 패키지에서).

4. 앱을 JAR로 패키징

war에서 시작하여 앱을 컨테이너화할 수 있지만 앱을 실행 가능한 JAR로 패키징하면 더 쉬워집니다. 특히 Maven을 빌드 도구로 사용하는 프로젝트의 경우 jar 패키징이 기본 동작이므로 많은 구성이 필요하지 않습니다.

pom.xml 파일에서 packaging 태그를 삭제합니다.

<packaging>war</packaging>

다음으로 spring-boot-maven-plugin을 추가합니다.

<plugins>
<!-- ... -->
  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.6.6</version>
  </plugin>
<!-- ... -->
</plugins>

5. App Engine 구성, 서비스, 종속 항목에서 마이그레이션

Codelab 시작 부분에서 언급한 것처럼 Cloud Run과 App Engine은 서로 다른 사용자 환경을 제공하도록 설계되었습니다. App Engine에서 기본적으로 제공하는 특정 기능(예: CronTask Queue 서비스)은 수동으로 다시 만들어야 하며, 이후 모듈에서 자세히 다루겠습니다.

샘플 앱은 기존 번들 서비스를 사용하지 않지만 앱이 사용하는 사용자는 다음 가이드를 참고할 수 있습니다.

이제부터 Cloud Run에 배포하므로 appengine-maven-plugin를 삭제할 수 있습니다.

<plugin>
 <groupId>com.google.cloud.tools</groupId>
 <artifactId>appengine-maven-plugin</artifactId>
 <version>2.4.1</version>
 <configuration>
   <!-- can be set w/ -DprojectId=myProjectId on command line -->
   <projectId>${app.projectId}</projectId>
   <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
   <version>GCLOUD_CONFIG</version>
 </configuration>
</plugin>

5. 애플리케이션 컨테이너화

이제 애플리케이션의 컨테이너를 실제로 빌드하는 방법을 Cloud Build에 알릴 준비가 되었습니다. 이 컨테이너화 방법을 사용하면 별도의 빌드 구성 파일 (cloudbuild.yaml)이 필요하지 않습니다. 간단히 최소 Dockerfile을 시작점으로 정의할 수 있습니다.

FROM eclipse-temurin

ARG JAR_FILE=JAR_FILE_MUST_BE_SPECIFIED_AS_BUILD_ARG

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java", "-jar","/app.jar"]

이 Dockerfile은 Spring Boot 서비스의 uber-jar 버전을 단일 레이어로 번들링합니다. Dockerfile 컨테이너화에 가장 간단한 접근 방식이지만, 특히 종속 항목이 비교적 안정적인 반복적인 경우 여러 단점이 있습니다. 이러한 우려사항 때문에 이 컨테이너화 방법이 더 고급으로 간주됩니다. 하지만 자체 Dockerfile을 작성하면 기본 이미지를 완전히 제어할 수 있고 신중하게 레이어가 지정된 이미지를 작성하여 성능 이점을 누릴 수 있습니다.

2**. 빌드 프로세스 실행**

이제 원하는 빌드 단계를 Cloud Build에 알렸으므로 원클릭 배포를 할 준비가 되었습니다.

다음 명령어를 실행합니다.

gcloud builds submit --tag LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME

위의 명령어에서 자리표시자 값을 다음으로 바꿉니다.

  • 위치: 저장소의 리전 또는 멀티 리전 위치입니다.
  • PROJECT_ID: Cloud 프로젝트 ID입니다.
  • REPOSITORY: Artifact Registry 저장소의 이름입니다.
  • IMAGE_NAME: 컨테이너 이미지의 이름입니다.

프로세스가 완료되면 컨테이너 이미지가 빌드되고, Artifact Registry에 저장되고, Cloud Run에 배포됩니다.

이 Codelab을 마치면 앱이 mod4-migrate-to-cloud-run 폴더의 앱과 동일해야 합니다.

이제 Cloud 함수가 완성되었네요. Java 8 App Engine 앱을 Java 17 및 Cloud Run으로 성공적으로 이전했으며 이제 전환 시 필요한 작업과 호스팅 옵션 간 선택에 대해 더 명확하게 이해할 수 있습니다.

6. 요약/삭제

축하합니다. 앱을 업그레이드하고, 컨테이너화하고, 이전했습니다. 이로써 튜토리얼이 완료되었습니다.

이제 Cloud Build로 배포할 수 있으므로 다음 단계는 CI/CD 및 소프트웨어 공급망 보안 기능에 대해 자세히 알아보는 것입니다.

선택사항: 서비스 정리 또는 사용 중지

이 튜토리얼에서 App Engine에 샘플 앱을 배포한 경우 요금이 청구되지 않도록 을 사용 중지해야 합니다. 다음 Codelab으로 이동할 준비가 되면 다시 사용 설정하면 됩니다. App Engine 앱이 사용 중지되면 비용이 발생하는 트래픽이 수행되지 않지만, 무료 할당량을 초과하는 경우 Datastore 사용량에 대한 요금이 청구될 수 있습니다. 따라서 제한에 걸리지 않도록 충분히 삭제해야 합니다.

반면에 마이그레이션을 계속하지 않고 모든 것을 완전히 삭제하려면 서비스를 삭제하거나 프로젝트를 완전히 종료하면 됩니다.

7. 추가 리소스

App Engine 마이그레이션 모듈 Codelab 문제/의견

이 Codelab에 문제가 발견된 경우 문제를 기록하기 전에 먼저 비슷한 기록이 있는지 검색해보세요. 검색 및 새 문제 만들기 링크:

이전 리소스

온라인 리소스

다음은 이 튜토리얼과 관련이 있을 수 있는 온라인 리소스입니다.

App Engine

기타 클라우드 정보

동영상

라이선스

이 작업물은 Creative Commons Attribution 2.0 일반 라이선스에 따라 사용이 허가되었습니다.