1. 개요
이 Codelab 시리즈 (사용자 주도형, 실무 가이드)는 Google App Engine (표준) Java 개발자가 일련의 마이그레이션을 통해 자신의 앱을 현대화할 수 있도록 돕기 위한 것입니다. 이 단계에 따라 앱을 더 쉽게 이동할 수 있도록 업데이트하고 Cloud Run, App Engine의 Google Cloud 컨테이너 호스팅 자매 서비스, 기타 컨테이너 호스팅 서비스에 앱을 컨테이너화할 수 있습니다.
이 튜토리얼에서는 Jib를 사용하여 Cloud Run 완전 관리형 서비스에 배포하기 위해 App Engine 앱을 컨테이너화하는 방법을 설명합니다. Jib를 사용하면 컨테이너에서 애플리케이션을 개발, 제공, 실행하기 위해 업계에서 잘 알려진 플랫폼인 Docker 이미지를 만들 수 있습니다.
App Engine에서 Cloud Run으로 이전하는 데 필요한 단계를 안내하는 것 외에도 Java 8 App Engine 앱을 Java 17로 업그레이드하는 방법도 알아봅니다.
애플리케이션에서 App Engine 기존 번들 서비스나 기타 App Engine 기능을 많이 사용하는 경우 Cloud Run으로 이동하기 전에 이러한 번들 서비스에서 마이그레이션하거나 해당 기능을 교체하는 것이 좋습니다. 마이그레이션 옵션을 조사하는 데 시간이 더 필요하거나 당분간 기존 번들 서비스를 계속 사용하려는 경우 최신 런타임으로 업그레이드할 때 Java 11/17용 App Engine 번들 서비스에 계속 액세스할 수 있습니다. 앱의 이식성이 향상되면 이 Codelab으로 돌아와 안내를 앱에 적용하는 방법을 알아보세요.
다음 실습에서는
- Cloud Shell 사용
- Cloud Run, Artifact Registry, Cloud Build API 사용 설정
- Jib 및 Cloud Build를 사용하여 앱 컨테이너화
- Cloud Run에 컨테이너 이미지 배포
필요한 항목
- 활성 GCP 결제 계정 및 App Engine이 사용 설정된 Google Cloud Platform 프로젝트
- 일반적인 Linux 명령어에 대한 실무 지식
- App Engine 앱 개발 및 배포에 관한 기본 지식
- Java 17로 이전하고 Cloud Run에 배포하려는 Java 8 Servlet 앱 (App Engine의 앱이거나 소스일 수 있음)
설문조사
이 튜토리얼을 어떻게 사용하실 계획인가요?
Java 사용 경험을 평가해 주세요.
귀하의 Google Cloud 서비스 사용 경험을 평가해 주세요.
2. 배경
App Engine 및 Cloud Functions와 같은 PaaS (Platform as a Service) 시스템은 SysAdmin 및 DevOps가 솔루션 빌드에 집중할 수 있도록 하는 등 팀과 애플리케이션에 많은 편의성을 제공합니다. 서버리스 플랫폼을 사용하면 앱이 필요에 따라 자동 확장하고, 사용량 기반 결제를 통해 0으로 축소하여 비용을 관리하고, 다양한 일반적인 개발 언어를 사용할 수 있습니다.
하지만 컨테이너의 유연성도 매력적입니다. 원하는 언어, 모든 라이브러리, 바이너리를 선택할 수 있는 컨테이너는 서버리스의 편의성과 컨테이너의 유연성이라는 두 가지 이점을 모두 제공합니다. 이것이 Cloud Run의 핵심입니다.
Cloud Run 사용 방법을 배우는 것은 Cloud Run 문서에서 다루는 이 Codelab의 범위에 포함되지 않습니다. 여기서 목표는 Cloud Run (또는 기타 컨테이너 호스팅 서비스)용 App Engine 앱을 컨테이너화하는 방법을 익히는 것입니다. 계속하기 전에 알아두어야 할 몇 가지 사항이 있는데, 일단 사용자 환경이 약간 달라집니다.
이 Codelab에서는 컨테이너를 빌드하고 배포하는 방법을 알아봅니다. 다음 작업을 수행하는 방법을 배우게 됩니다.
- Jib로 앱 컨테이너화
- 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, Servlet 기반의 Datastore 앱입니다. App Engine 배포를 위해 이 앱을 준비하는 방법에 관한 README의 안내를 따릅니다.
3. (선택사항) 기준 앱 배포
다음은 Cloud Run으로 이전하기 전에 앱이 App Engine에서 작동하는지 확인하려는 경우에만 필요합니다.
README.md의 단계를 참조하세요.
gcloud
CLI 설치/재숙지gcloud init
로 프로젝트의 gcloud CLI 초기화gcloud app create
로 App Engine 프로젝트 만들기- App Engine에 샘플 앱 배포
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
- 앱이 문제 없이 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를 사용하여 이전 후 기본 동작의 차이를 최소화합니다. App Engine에서 제공하는 버전과 일치하도록 Jetty 버전을 구성할 수도 있습니다.
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<jetty.version>9.4.46.v20220331</jetty.version>
</properties>
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로 패키징
Jib를 사용하여 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 및 태스크 큐 서비스)은 수동으로 다시 만들어야 하며, 이는 이후 모듈에서 자세히 다룹니다.
샘플 앱은 기존 번들 서비스를 사용하지 않지만 앱에서 기존 번들 서비스를 사용하는 사용자는 다음 가이드를 참고할 수 있습니다.
- 번들 서비스에서 마이그레이션하여 적절한 독립형 서비스를 찾습니다.
- App Engine을 계속 사용하면서 Java 11/17 런타임으로 이전하는 사용자를 위한 XML 구성 파일을 YAML로 마이그레이션
지금부터 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 Run에 앱을 수동으로 배포할 수 있습니다. 이 방법은 백그라운드에서 Cloud Build를 사용하여 배포를 자동화하는 훌륭한 옵션입니다. 소스 배포는 이후 모듈에서 자세히 다룹니다.
또는 앱이 배포되는 방식을 더 세부적으로 제어해야 하는 경우 의도한 빌드 단계를 명시적으로 배치하는 cloudbuild.yaml
파일을 정의하여 이를 실행할 수 있습니다.
1. cloudbuild.yaml 파일 정의
pom.xml
와 동일한 수준에서 다음 cloudbuild.yaml
파일을 만듭니다.
steps:
# Test your build
- name: maven:eclipse-temurin
entrypoint: mvn
args: ["test"]
# Build with Jib
- name: maven:eclipse-temurin
entrypoint: mvn
args: [ "compile", "com.google.cloud.tools:jib-maven-plugin:3.2.1:build", "-Dimage=northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib"]
# Deploy to Cloud Run
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args: [ 'run', 'deploy', 'visitors', '--image', 'northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib', '--region', 'northamerica-northeast1', '--allow-unauthenticated']
Cloud Build에 이러한 단계를 따르도록 지시하면 다음 작업이 실행됩니다.
./mvnw test
로 테스트 실행- Jib를 사용하여 Artifact Registry에 이미지를 빌드, 푸시, 태그하기
gcloud run deploy
를 사용하여 Cloud Run에 이미지 배포
‘visitors'
은 Cloud Run에 원하는 서비스 이름으로 제공됩니다. –allow-unauthenticated
플래그를 사용하면 사용자가 인증 없이 웹 앱을 방문할 수 있습니다. cloudbuild.yaml
파일에서 PROJECT_ID를 프로젝트의 ID로 바꿔야 합니다.
다음으로 다음 IAM 정책 바인딩을 추가하여 Cloud Build 서비스 계정이 Artifact Registry에 액세스하도록 허용합니다.
export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)" )
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role=roles/run.admin \
--project=$PROJECT_ID
gcloud iam service-accounts add-iam-policy-binding $PROJECT_NUMBER-compute@developer.gserviceaccount.com \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role roles/iam.serviceAccountUser --project=$PROJECT_ID
2. 빌드 프로세스 실행
이제 Cloud Build에 원하는 빌드 단계를 알렸으므로 원클릭 배포를 시작할 수 있습니다.
다음 명령어를 실행합니다.
gcloud builds submit
프로세스가 완료되면 컨테이너 이미지가 빌드되고 Artifact Registry에 저장된 후 Cloud Run에 배포됩니다.
이 Codelab을 마치면 앱은 java17-and-cloud-run/finish의 앱과 동일하게 표시됩니다.
이제 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
- App Engine 문서
- App Engine 가격 책정 및 할당량 정보
- 1세대 및 2세대 플랫폼 비교
- 기존 런타임 장기 지원
기타 클라우드 정보
- Google Cloud '항상 무료' 등급
- Google Cloud CLI (
gcloud
CLI) - 모든 Google Cloud 문서
동영상
라이선스
이 작업물은 Creative Commons Attribution 2.0 일반 라이선스에 따라 사용이 허가되었습니다.