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 관련 기능을 많이 사용하는 경우 자바 11/17용 App Engine 번들 서비스에 액세스 가이드가 이 Codelab보다 더 나은 시작점이 될 수 있습니다.

다음 실습에서는

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

필요한 항목

설문조사

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

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

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

초급 중급 고급

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

초급 중급 고급

2. 배경

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

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

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

이 Codelab에서는 컨테이너를 빌드하고 배포하는 방법을 알아봅니다. Dockerfile로 앱을 컨테이너화하고, App Engine 구성에서 이전하고, 원하는 경우 Cloud Build의 빌드 단계를 정의하는 방법을 알아봅니다. 이 과정에서 특정 App Engine 관련 기능이 지원 중단됩니다. 이 경로를 따르지 않으려는 경우에도 App Engine에서 앱을 유지하면서 자바 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 앱입니다. App Engine 배포를 위해 이 앱을 준비하는 방법에 관한 README의 안내를 따릅니다.

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를 사용하여 웹 서버와 Servlet 컨테이너를 제공합니다.

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

<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는 수정 없이 Servlet을 재사용할 수 있지만 검색 가능하도록 하려면 몇 가지 구성이 필요합니다.

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);
    }
}

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

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에서 기본적으로 제공하는 특정 기능(예: Cron태스크 큐 서비스)은 수동으로 다시 만들어야 하며, 이는 이후 모듈에서 자세히 다룹니다.

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

지금부터 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

${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

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

  • LOCATION: 저장소의 리전 또는 멀티 리전 위치입니다.
  • 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 일반 라이선스에 따라 사용이 허가되었습니다.