Cloud Run으로 간단한 3단계로 개발부터 프로덕션까지

1. 소개

애플리케이션 관리가 어려운 이유는 무엇인가요?

가장 큰 이유는 개발자가 종종 파트타임 시스템 관리자가 되어야 하기 때문입니다. 최신 프로덕션 등급 웹 애플리케이션을 개발, 배포, 관리하려면 다음 우려사항 목록 (일부)을 고려하세요.

4d018476b4a73b47.png

어떠신지 모르겠지만 저는 이런 것들을 걱정하고 싶지 않아요. 제가 정말로 생각하고 싶은 것은 애플리케이션 로직입니다.

6dfd143d20e5548b.png

간단히 말해 Cloud Run은 앱에 집중할 수 있도록 지원하고 관리 및 유지보수는 이 분야에서 수백만 시간을 투자하여 기술을 개선하고 완성한 Google에 맡기는 서비스입니다.

위에서 언급한 관리상의 문제 외에도 다음과 같은 문제가 있습니다.

  • 종속 항목 - 앱이 실행되는 환경은 가능한 한 테스트된 환경과 정확히 일치해야 합니다. 여기에는 운영체제, 지원 라이브러리, 언어 인터프리터 또는 컴파일러, 하드웨어 구성, 기타 여러 요인이 포함될 수 있습니다.
  • 배포 - 앱의 로컬 버전에서 인터넷에서 광범위하게 공유되는 버전으로 이동하려면 런타임 환경을 변경하고 복잡성을 대폭 높여야 하며 학습 곡선이 가파릅니다.

Cloud Run은 이러한 문제와 그 밖의 여러 문제를 대신 처리합니다. 하지만 제 말을 믿기보다는 함께 앱을 빌드하여 몇 단계만으로 로컬 개발 환경에서 프로덕션 등급 클라우드 앱으로 전환하는 것이 얼마나 쉬운지 확인해 보겠습니다.

실습할 내용…

  • 간단한 웹 앱을 빌드하고 개발 환경에서 예상대로 실행되는지 확인합니다.
  • 그런 다음 동일한 앱의 컨테이너화된 버전으로 이동합니다. 이 과정에서 컨테이너화의 의미와 컨테이너화가 유용한 이유를 알아봅니다.
  • 마지막으로 앱을 클라우드에 배포하고 명령줄과 Google Cloud 콘솔을 사용하여 Cloud Run 서비스를 얼마나 쉽게 관리할 수 있는지 확인합니다.

학습할 내용…

  • Python에서 간단한 웹 서버 앱을 만드는 방법
  • 어디서나 실행되는 Docker 컨테이너로 앱을 패키징하는 방법
  • 누구나 새 창작물을 사용해 볼 수 있도록 앱을 클라우드에 배포하는 방법
  • 빌드팩을 사용하여 위의 단계를 더욱 간소화하는 방법
  • Google Cloud 명령줄 도구 및 Cloud Console 웹 UI를 사용하는 방법

필요한 항목…

  • 웹브라우저
  • Google 계정

이 실습은 초보자를 포함한 모든 수준의 개발자를 대상으로 합니다. Python을 사용하지만 Python 프로그래밍에 익숙하지 않아도 됩니다. 사용하는 모든 코드를 설명해 드리기 때문입니다.

2. 설정하기

5110b5081a1e1c49.png

이 섹션에서는 실습을 시작하는 데 필요한 모든 사항을 다룹니다.

자습형 환경 설정

  1. Cloud 콘솔에 로그인하고 새 프로젝트를 만들거나 기존 프로젝트를 다시 사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

모든 Google Cloud 프로젝트에서 고유한 이름인 프로젝트 ID를 기억하세요(위의 이름은 이미 사용되었으므로 사용할 수 없습니다). 이 ID는 나중에 이 Codelab에서 PROJECT_ID라고 부릅니다.

  1. 그런 후 Google Cloud 리소스를 사용할 수 있도록 Cloud Console에서 결제를 사용 설정해야 합니다.

이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 가이드를 마친 후 비용이 결제되지 않도록 리소스 종료 방법을 알려주는 '삭제' 섹션의 안내를 따르세요. Google Cloud 신규 사용자에게는 미화$300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

Cloud Shell 시작

이 실습에서는 Google의 클라우드에서 실행되는 가상 머신이 호스팅하는 명령어 인터프리터인 Cloud Shell 세션에서 작업합니다. 이 섹션은 사용자의 컴퓨터에서 로컬로 쉽게 실행할 수도 있지만, Cloud Shell을 사용하면 모든 사람이 일관되고 재현 가능한 환경에 액세스할 수 있습니다. 실습을 마치고 로컬 컴퓨터에서 이 섹션을 다시 시도하셔도 됩니다.

704a7b7491bd157.png

Cloud Shell 활성화

  1. Cloud Console에서 Cloud Shell 활성화4292cbf4971c9786.png를 클릭합니다.

bce75f34b2c53987.png

이전에 Cloud Shell을 시작하지 않았으면 설명이 포함된 중간 화면 (스크롤해야 볼 수 있는 부분)이 제공됩니다. 이 경우 계속을 클릭합니다 (이후 다시 표시되지 않음). 이 일회성 화면은 다음과 같습니다.

70f315d7b402b476.png

Cloud Shell을 프로비저닝하고 연결하는 작업은 몇 분이면 끝납니다.

fbe3a0674c982259.png

이 가상 머신에는 필요한 개발 도구가 모두 포함되어 로드됩니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab에서 대부분의 작업은 브라우저나 Chromebook만 사용하여 수행할 수 있습니다.

Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 이미 설정된 것을 볼 수 있습니다.

  1. Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.
gcloud auth list

명령어 결과

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project

명령어 결과

[core]
project = <PROJECT_ID>

또는 다음 명령어로 설정할 수 있습니다.

gcloud config set project <PROJECT_ID>

명령어 결과

Updated property [core/project].

터미널에서 후속 단계에서 작업을 더 쉽게 할 수 있는 몇 가지 환경 변수를 설정합니다.

export PROJ=$GOOGLE_CLOUD_PROJECT 
export APP=hello 
export PORT=8080
export REGION="us-central1"
export TAG="gcr.io/$PROJ/$APP"

API 사용 설정

이러한 서비스가 필요한 경우와 그 이유는 이후 단계에서 설명하겠습니다. 우선 이 명령어를 실행하여 프로젝트에 Cloud Build, Container Registry, Cloud Run 서비스에 대한 액세스 권한을 부여해 보겠습니다.

gcloud services enable cloudbuild.googleapis.com         \
                       containerregistry.googleapis.com  \
                       run.googleapis.com          

그러면 다음과 비슷한 성공 메시지가 표시될 것입니다.

Operation "operations/acf.cc11852d-40af-47ad-9d59-477a12847c9e" finished successfully.

3. 간단한 웹 앱 빌드

eef530b56b8e93a3.png

Cloud Shell 패널 상단의 Open Editor 버튼을 클릭하여 시작합니다. 상태 메시지가 표시됩니다.

9b81c8a37a6bcdd8.png

그러면 Visual Studio Code와 유사한 IDE 환경이 표시되며, 여기에서 프로젝트를 만들고, 소스 코드를 수정하고, 프로그램을 실행하는 등의 작업을 할 수 있습니다. 화면이 너무 좁은 경우 여기에서 강조 표시된 콘솔과 수정/터미널 창 사이의 가로 막대를 드래그하여 두 영역 사이의 구분선을 확장하거나 축소할 수 있습니다.

8dea35450851af53.png

Open EditorOpen Terminal 버튼을 클릭하여 편집기와 터미널 간에 전환할 수 있습니다. 이제 이 두 환경을 번갈아 전환해 보세요.

다음으로 파일->새 폴더를 선택하여 이 실습의 작업을 저장할 폴더를 만들고 hello를 입력한 후 OK를 클릭합니다. 이 실습에서 만드는 모든 파일과 Cloud Shell에서 수행하는 모든 작업은 이 폴더에서 이루어집니다.

이제 requirements.txt 파일을 만듭니다. 이렇게 하면 앱이 종속된 라이브러리가 Python에 알려집니다. 이 간단한 웹 앱에서는 웹 서버를 빌드하기 위한 인기 Python 모듈인 Flask와 웹 서버 프레임워크인 gunicorn를 사용합니다. Cloud Editor 창에서 File->New File 메뉴를 클릭하여 새 파일을 만듭니다. 새 파일 이름을 묻는 메시지가 표시되면 requirements.txt를 입력하고 OK 버튼을 누릅니다. 새 파일이 hello 프로젝트 폴더에 있는지 확인합니다.

새 파일에 다음 줄을 입력하여 앱이 Python Flask 패키지 및 gunicorn 웹 서버에 종속된다고 지정합니다.

Flask
gunicorn

Cloud Editor에서 변경사항을 자동으로 저장하므로 이 파일을 명시적으로 저장할 필요는 없습니다.

버전 1: Hello world!

동일한 기법을 사용하여 main.py라는 새 파일을 만듭니다. 이 파일이 앱의 기본 (이자 유일한) Python 소스 파일이 됩니다. 새 파일이 hello 프로젝트 폴더에 있는지 다시 한번 확인합니다.

다음 코드를 이 파일에 삽입합니다.

from flask import Flask
import os
import random

app = Flask(__name__)  # Create a Flask object.
PORT = os.environ.get("PORT")  # Get PORT setting from the environment.

# The app.route decorator routes any GET requests sent to the root path
# to this function, which responds with a "Hello world!" HTML document.
@app.route("/", methods=["GET"])
def say_hello():
    html = "<h1>Hello world!</h1>"
    return html


# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=PORT)

터미널로 다시 전환하고 다음 명령어를 사용하여 프로젝트 폴더로 변경합니다.

cd hello

다음 명령어를 실행하여 프로젝트 종속 항목을 설치합니다.

pip3 install -r requirements.txt

이제 터미널에서 다음 명령어를 실행하여 앱을 실행합니다.

python3 main.py

이제 앱이 Cloud Shell 세션 전용 가상 머신에서 실행됩니다. Cloud Shell에는 전 세계 인터넷의 어느 곳에서나 가상 머신에서 실행되는 웹 서버 (방금 시작한 서버와 같은)에 액세스할 수 있도록 하는 프록시 메커니즘이 포함되어 있습니다.

web preview 버튼을 클릭한 다음 Preview on Port 8080 메뉴 항목을 클릭합니다.

fe45e0192080efd6.png

그러면 실행 중인 앱이 웹브라우저 탭에 열리며 다음과 같이 표시됩니다.

b1f06501509aefb9.png

버전 2: URL 경로 에코

Open Editor 버튼을 통해 Cloud Editor로 돌아가서 다음과 같이 main.py 파일을 업데이트하여 선택적 URL 접미사를 에코하는 지원을 추가합니다.

from flask import Flask
import os
import random

app = Flask(__name__)  # Create a Flask object.
PORT = os.environ.get("PORT")  # Get PORT setting from environment.

# The app.route decorator routes any GET requests sent to the root path
# to this function, which responds with a "Hello world!" HTML document.
# If something is specified as the URL path (after the '/'), say_hello()
# responds with "Hello X", where X is the string at the end of the URL.
@app.route("/", methods=["GET"])
@app.route("/<name>", methods=["GET"])     # ← NEW
def say_hello(name="world"):               # ← MODIFIED
    html = f"<h1>Hello {name}!</h1>"       # ← MODIFIED
    return html


# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=PORT)

터미널로 다시 전환하고 (Open Terminal 버튼을 통해) control-C를 입력하여('C'를 누르는 동안 컨트롤 키를 길게 누름) 실행 중인 앱을 중지한 다음 다음을 입력하여 다시 시작합니다.

python3 main.py

다시 web preview 버튼을 클릭한 다음 Preview on Port 8080 메뉴 항목을 클릭하여 실행 중인 앱의 웹브라우저 탭을 엽니다. 다시 'Hello world!' 메시지가 표시되지만 이제 슬래시 문자 뒤의 URL 텍스트를 원하는 문자열 (예: /your-name)로 바꾸고 다음과 같은 내용이 표시되는지 확인합니다.

93b87996f88fa370.png

버전 3: 무작위 색상

이제 Cloud Editor (Open Editor 버튼을 통해)로 돌아가서 main.py 파일을 다음과 같이 업데이트하여 임의 배경색을 지원하도록 합니다.

from flask import Flask
import os
import random

app = Flask(__name__)  # Create a Flask object.
PORT = os.environ.get("PORT")  # Get PORT setting from the environment.

# This function decides whether foreground text should be
# displayed in black or white, to maximize fg/bg contrast.
def set_text_color(rgb):                      # ← NEW
    sum = round(                              # ← NEW
        (int(rgb[0]) * 0.299)                 # ← NEW
        + (int(rgb[1]) * 0.587)               # ← NEW
        + (int(rgb[2]) * 0.114)               # ← NEW
    )                                         # ← NEW
    return "black" if sum > 186 else "white"  # ← NEW


# The app.route decorator routes any GET requests sent to the root path
# to this function, which responds with a "Hello world!" HTML document.
# If something is specified as the URL path (after the '/'), say_hello()
# responds with "Hello X", where X is the string at the end of the URL.
# To verify each new invocation of these requests, the HTML document
# includes CSS styling to produce a randomly colored background.
@app.route("/", methods=["GET"])
@app.route("/<name>", methods=["GET"])
def say_hello(name="world"):
    bg = random.sample(range(1, 255), 3)                       # ← NEW
    hex = (int(bg[0]) * 256) + (int(bg[1]) * 16) + int(bg[2])  # ← NEW
    fg_color = set_text_color(bg)                              # ← NEW
    bg_color = f"#{hex:06x}"                                   # ← NEW
    style = f"color:{fg_color}; background-color:{bg_color}"   # ← NEW
    html = f'<h1 style="{style}">Hello {name}!</h1>'           # ← MODIFIED
    return html


# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=PORT)

터미널로 다시 전환하고 (Open Terminal 버튼을 통해) control-C를 입력하여('C'를 누르는 동안 컨트롤 키를 길게 누름) 실행 중인 앱을 중지한 다음 다음을 입력하여 다시 시작합니다.

python3 main.py

다시 web preview 버튼을 클릭한 다음 Preview on Port 8080 메뉴 항목을 클릭하여 실행 중인 앱의 웹브라우저 탭을 엽니다. 지정된 접미사 또는 기본 'Hello world!' 문자열이 무작위로 색상이 지정된 배경 앞에 표시됩니다.

baf8d028f15ea7f4.png

페이지를 여러 번 새로고침하여 앱을 방문할 때마다 임의의 배경색이 변경되는지 확인합니다.

이제 앱이 완성되었습니다. 축하합니다. 다음 단계에서는 앱을 컨테이너로 패키징하는 방법과 컨테이너로 패키징하는 것이 유용한 이유를 알아봅니다.

4. 앱 컨테이너화

17cc234ec3325a8a.png

컨테이너란 무엇인가요?

일반적으로 컨테이너와 특히 Docker를 사용하면 모든 종속 항목이 번들로 묶인 애플리케이션을 실행할 모듈식 상자를 만들 수 있습니다. 이 결과를 컨테이너 이미지라고 합니다. 이 섹션에서는 애플리케이션과 모든 종속 항목을 캡슐화하는 데 사용할 컨테이너 이미지를 만듭니다.

종속 항목에 관해 말하자면, 이전 단계에서 개발자 환경에서 앱을 실행할 때 pip3 install -r requirements.txt를 실행하고 requirements.txt 파일에 모든 종속 라이브러리와 해당 버전이 포함되어 있는지 확인해야 했습니다. 컨테이너를 사용하면 컨테이너 이미지를 생성할 때 이러한 요구사항을 설치하므로 컨테이너 소비자가 설치에 대해 걱정할 필요가 없습니다.

이 컨테이너 이미지는 Cloud Run에 애플리케이션을 배포하기 위한 기본 빌딩 블록을 구성합니다. 컨테이너는 거의 모든 가상 또는 실제 서버에서 사용할 수 있으므로 원하는 곳에 애플리케이션을 배포하고, 한 서비스 제공업체에서 다른 서비스 제공업체로 또는 온프레미스에서 클라우드로 애플리케이션을 이동할 수 있습니다.

컨테이너는 애플리케이션을 다음과 같이 만드는 데 도움이 됩니다.

  • 재현 가능 - 컨테이너가 독립적이고 완전함
  • 이식 가능 - 컨테이너는 업계 전반의 빌딩 블록으로, 클라우드 제공업체와 환경 간에 애플리케이션을 이식할 수 있습니다.

간단히 말해 컨테이너를 사용하면 드디어 '한 번 작성하면 어디서나 실행'할 수 있습니다. 이 규칙의 한 가지 예외는 생성된 컨테이너가 생성된 프로세서 유형에서 실행되도록 제한된다는 것입니다. 하지만 다른 하드웨어 구성을 위한 컨테이너 버전을 생성하는 방법도 있습니다.

이제 컨테이너를 만들어 보겠습니다. Docker라는 컨테이너를 만들기 위한 특정 기술을 사용합니다.

Cloud Editor에서 Dockerfile이라는 새 파일을 만듭니다. 이 파일은 이미지를 구성하기 위한 청사진입니다. 운영 환경과 소스 코드, 종속 항목 설치 방법, 앱 빌드 방법, 코드 실행 방법을 Docker에 알려줍니다.

# Use an official lightweight Python image.
FROM python:3.9-slim

# Copy local code to the container image.
WORKDIR /app
COPY main.py .
COPY requirements.txt .

# Install dependencies into this container so there's no need to 
# install anything at container run time.
RUN pip install -r requirements.txt

# Service must listen to $PORT environment variable.
# This default value facilitates local development.
ENV PORT 8080

# Run the web service on container startup. Here you use the gunicorn
# server, with one worker process and 8 threads. For environments 
# with multiple CPU cores, increase the number of workers to match 
# the number of cores available.
CMD exec gunicorn --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 0 main:app

Cloud 터미널에서 다음 명령어를 실행하여 Cloud Build로 컨테이너 이미지를 빌드합니다.

gcloud builds submit --tag $TAG

레지스트리로 푸시된 후에는 이미지 이름이 포함된 SUCCESS 메시지가 표시됩니다. 메시지는 gcr.io/<project-id>/hello와 같은 형식입니다. 이제 이미지가 Google Container Registry에 저장되며 언제 어디서나 다시 사용할 수 있습니다.

다음 명령어를 사용하여 현재 프로젝트에 연결된 모든 컨테이너 이미지를 나열할 수 있습니다.

gcloud container images list

이제 다음 docker 명령어를 사용하여 Cloud Shell에서 로컬로 애플리케이션을 실행하고 테스트합니다.

docker run -p $PORT:$PORT -e PORT=$PORT $TAG

-p $PORT:$PORT 옵션은 Docker가 호스트 환경의 외부 포트 $PORT (위에서 8080으로 설정됨)을 실행 중인 컨테이너 내부의 동일한 포트 번호로 매핑하도록 지시합니다. 이렇게 하면 작성하는 서버 코드와 앱을 테스트할 때 연결하는 외부 포트 번호가 동일 (8080)하므로 작업이 더 쉬워지지만, -p 옵션을 사용하여 호스트의 임의 외부 포트를 컨테이너 내부의 원하는 내부 포트에 매핑할 수도 있습니다.

-e PORT=$PORT 옵션은 컨테이너 내에서 실행되는 앱에서 $PORT 환경 변수 (위에서 8080으로 설정됨)를 사용할 수 있도록 Docker에 지시합니다.

이제 컨테이너 내에서 실행되는 Python 코드를 웹브라우저로 가리켜 앱을 테스트할 수 있습니다. Cloud Shell 창에서 이전 단계에서와 같이 '웹 미리보기' 아이콘을 클릭하고 '포트 8080에서 미리보기'를 선택합니다.

결과는 익숙할 것입니다. Cloud Shell 터미널에서 직접 앱을 실행했을 때와 마찬가지로 무작위로 색상이 지정된 배경 앞에 생성된 텍스트가 표시됩니다. 페이지를 여러 번 새로고침하여 앱을 방문할 때마다 임의의 배경색이 변경되는지 확인합니다.

축하합니다. 이제 컨테이너화된 앱 버전을 실행했습니다. 다음 섹션에서는 코드 한 줄도 수정하지 않고 컨테이너 이미지를 프로덕션 품질 웹 앱으로 변환합니다.

5. 클라우드로...

1b0665d94750ded6.gif

이제 앱을 컨테이너화했으므로 이 멋진 앱을 전 세계와 공유할 차례입니다. 클라우드에 배포하세요. 하지만 단순히 공유하는 것 이상을 하고 싶을 것입니다. 다음 사항을 확인해야 합니다.

  • 안정적으로 실행됨 - 앱을 실행하는 컴퓨터가 비정상 종료되는 경우 자동 내결함성 제공
  • 자동 확장: 앱이 대규모 트래픽을 처리하고 사용하지 않을 때는 공간을 자동으로 줄입니다.
  • 사용하지 않는 리소스에 대한 비용을 청구하지 않아 비용을 최소화합니다. 트래픽에 응답하는 동안 소비된 리소스에 대해서만 비용이 청구됩니다.
  • 커스텀 도메인 이름을 통해 액세스할 수 있습니다. 서비스를 커스텀 도메인 이름에 할당하는 원클릭 솔루션에 액세스할 수 있습니다.
  • 훌륭한 응답 시간을 제공합니다. 콜드 스타트는 적절하게 응답하지만 최소 인스턴스 구성을 지정하여 미세 조정할 수 있습니다.
  • 표준 SSL/TLS 웹 보안을 사용한 엔드 투 엔드 암호화 지원: 서비스를 배포하면 표준 웹 암호화와 해당 필수 인증서가 무료로 자동으로 제공됩니다.

Google Cloud Run에 앱을 배포하면 위의 모든 기능과 그 이상의 기능을 사용할 수 있습니다.

Cloud Run에 앱 배포

먼저 새 버전과 이전 버전을 구분할 수 있도록 앱을 수정해 보겠습니다. 기본 메시지가 'Hello world!'에서 'Hello from Cloud Run!'으로 변경되도록 main.py 파일을 수정하여 이를 수행합니다. 즉, main.py에서 다음 줄을

def say_hello(name="world"):

다음과 같이 바꿉니다.

def say_hello(name="from Cloud Run"):

Cloud Run은 리전을 기반으로 합니다. 즉, Cloud Run 서비스를 실행하는 인프라가 특정 리전에 위치해 있으며, 해당 리전 내의 모든 영역에서 중복으로 사용할 수 있도록 Google이 관리합니다. 위의 '설정' 섹션에서는 REGION 환경 변수를 통해 기본 리전을 정의했습니다.

다음 명령어를 사용하여 컨테이너 이미지를 다시 빌드하고 컨테이너화된 애플리케이션을 Cloud Run에 배포합니다.

gcloud builds submit --tag $TAG
gcloud run deploy "$APP"   \
  --image "$TAG"           \
  --platform "managed"     \
  --region "$REGION"       \
  --allow-unauthenticated
  • gcloud config set run/region $REGION를 사용하여 기본 리전을 정의할 수도 있습니다.
  • --allow-unauthenticated 옵션을 사용하면 서비스를 공개적으로 사용할 수 있습니다. 인증되지 않은 요청을 방지하려면 대신 --no-allow-unauthenticated을 사용하세요.

여기에 지정된 이미지는 마지막 단계에서 빌드한 Docker 이미지입니다. 결과 이미지를 Google Container Registry에 저장한 Cloud Build 서비스 덕분에 Cloud Run 서비스가 이미지를 찾아 배포할 수 있습니다.

그런 다음 배포가 완료될 때까지 잠시 기다립니다. 성공하면 명령줄에 다음과 같은 서비스 URL이 표시됩니다.

Deploying container to Cloud Run service [hello] in project [PROJECT_ID...
✓ Deploying new service... Done.                                   
  ✓ Creating Revision... Revision deployment finished. Waiting for health check...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [hello] revision [hello-...] has been deployed and is serving 100 percent of traffic.
Service URL: https://hello-....a.run.app

다음 명령어를 사용하여 서비스 URL을 가져올 수도 있습니다.

gcloud run services describe hello  \
  --platform managed                \
  --region $REGION                  \
  --format "value(status.url)"

다음과 같이 표시됩니다.

https://hello-....a.run.app

이 링크는 Cloud Run 서비스의 전용 URL이며 TLS 보안이 적용됩니다. 이 링크는 서비스가 사용 중지되지 않는 한 영구적이며 인터넷 어디에서나 사용할 수 있습니다. 일시적인 가상 머신에 의존하는 앞서 언급한 Cloud Shell의 프록시 메커니즘을 사용하지 않습니다.

강조 표시된 Service URL를 클릭하여 실행 중인 앱의 웹브라우저 탭을 엽니다. 결과로 무작위로 색상이 지정된 배경 앞에 'Hello from Cloud Run!' 메시지가 표시됩니다.

축하합니다. 이제 앱이 Google Cloud에서 실행됩니다. 앱은 TLS (HTTPS) 암호화와 함께 공개적으로 제공되며, 엄청난 수준의 트래픽에 맞게 자동으로 확장됩니다.

하지만 이 프로세스를 더 쉽게 만들 수 있다고 생각합니다.

6. 컨테이너 자동 생성

이 모든 것이 꽤 멋지지만 Dockerfile과 컨테이너에 대해 생각하고 싶지 않다면 어떻게 해야 할까요? 대부분의 개발자처럼 애플리케이션 코드 작성에만 집중하고 다른 사람이 컨테이너화를 담당하도록 하고 싶다면 어떻게 해야 하나요? 다행히 Cloud Run은 소스 파일 모음에서 컨테이너를 제조하는 프로세스를 자동화하기 위해 존재하는 오픈소스 표준인 빌드팩을 지원합니다.

컨테이너 빌드 방식을 세부적으로 맞춤설정하려는 경우와 같이 개발자가 명시적 Dockerfile을 사용하는 것을 선호할 수 있는 사례도 있습니다. 하지만 이 연습과 같은 일반적인 경우에는 빌드팩이 잘 작동하며 Dockerfile를 직접 만들 필요가 없습니다. 빌드팩을 사용하도록 코드를 수정해 보겠습니다.

먼저 새 버전과 이전 버전을 구분할 수 있도록 앱을 수정해 보겠습니다. 기본 메시지가 'Hello from Cloud Run!'에서 'Hello from Cloud Run with Buildpacks!'로 변경되도록 main.py 파일을 수정합니다. 즉, main.py에서 다음 줄을

def say_hello(name="from Cloud Run"):

다음과 같이 바꿉니다.

def say_hello(name="from Cloud Run with Buildpacks"):

이제 Procfile라는 새 파일을 만들어 빌드팩을 활용해 보겠습니다. Cloud Editor에서 파일을 만들고 다음 텍스트 한 줄을 삽입합니다.

web: python3 main.py

이렇게 하면 빌드백 시스템에 자동 생성된 컨테이너에서 앱을 실행하는 방법을 알려줍니다. 이 안내를 사용하면 Dockerfile이 더 이상 필요하지 않습니다. 이를 확인하려면 Dockerfile을 삭제하고 Cloud Shell 터미널에서 다음 명령어를 실행합니다.

gcloud beta run deploy "$APP"  \
    --source .                 \
    --platform "managed"       \
    --region "$REGION"         \
    --allow-unauthenticated

이는 마지막 단계에서 앱을 배포하기 위해 실행한 명령어와 유사하지만 이번에는 --image 옵션을 --source . 옵션으로 바꿨습니다. 이렇게 하면 gcloud 명령어에 현재 디렉터리에서 찾은 소스 파일을 기반으로 빌드팩을 사용하여 컨테이너 이미지를 만들도록 지시합니다 (--source .dot은 현재 디렉터리의 약어임). 서비스에서 컨테이너 이미지를 암시적으로 처리하므로 이 gcloud 명령어에서 이미지를 지정할 필요가 없습니다.

강조 표시된 Service URL를 클릭하여 실행 중인 앱의 웹브라우저 탭을 열고 서비스가 임의로 색상이 지정된 배경 앞에 'Hello from Cloud Run with Buildpacks!'를 표시하는지 확인하여 이 배포가 작동하는지 다시 한번 확인합니다.

빌드팩을 사용하여 Dockerfile를 제조하면 세 가지 간단한 단계가 두 단계로 줄어듭니다.

  1. 개발 환경에서 앱을 만듭니다.
  2. 하나의 명령어로 동일한 코드를 클라우드에 배포합니다.

7. 명령줄을 사용해야 하나요?

아니요 거의 모든 Google Cloud 서비스와 마찬가지로 Cloud Run과 상호작용하는 방법은 세 가지가 있습니다.

  • gcloud 명령줄 도구(방금 확인한 도구)
  • 직관적인 포인트 앤 클릭 상호작용 스타일을 지원하는 Cloud Console을 통한 풍부한 웹 사용자 인터페이스
  • 프로그래매틱 방식으로, Java, C#, Python, Go, JavaScript, Ruby, C/C++ 등 다양한 언어로 제공되는 Google 클라이언트 라이브러리를 사용합니다.

콘솔 UI를 사용하여 Cloud Run 앱의 인스턴스를 추가로 배포해 보겠습니다. 왼쪽 상단 메뉴를 통해 Cloud Run 서비스 방문 페이지로 이동합니다.

e2b4983b38c81796.png

그러면 다음과 같이 Cloud Run 서비스의 요약이 표시됩니다.

b335e7bf0a3af845.png

'서비스 만들기' 링크를 클릭하여 배포 프로세스를 시작합니다.

51f61a8ddc7a4c0b.png

서비스 이름으로 'hello-again'을 입력하고 기본 배포 플랫폼과 리전을 선택한 후 '다음'을 클릭합니다.

8a17baa45336c4c9.png

테스트 목적으로 Google에서 만든 컨테이너인 gcr.io/cloudrun/hello 컨테이너 이미지의 URL을 입력하고 '고급 설정' 드롭다운을 클릭하여 사용할 수 있는 다양한 구성 설정을 확인합니다. 맞춤설정할 수 있는 몇 가지를 예로 들면 다음과 같습니다.

  • 포트 번호 및 컨테이너 진입점 (컨테이너 빌드 시 지정된 진입점을 재정의함)
  • 하드웨어: 메모리 및 CPU 수
  • 확장: 최소 및 최대 인스턴스
  • 환경 변수
  • 기타: 요청 제한 시간 설정, 컨테이너당 최대 요청 수, HTTP/2

'다음' 버튼을 클릭하여 대화상자를 진행합니다. 다음 대화상자에서는 서비스가 트리거되는 방식을 지정할 수 있습니다. '인그레스'에서 '모든 트래픽 허용'을 선택하고 '인증'에서 '인증되지 않은 트래픽 허용'을 선택합니다.

e78281d1cff3418.png

인증 사용자 인증 정보를 지정하지 않고도 공개 인터넷의 어디에서나 Cloud Run 앱에 액세스할 수 있으므로 가장 자유로운 설정입니다. 앱에 더 제한적인 설정을 적용할 수도 있지만 이 학습에서는 간단하게 유지하겠습니다.

이제 Create 버튼을 클릭하여 Cloud Run 서비스를 만듭니다. 몇 초 후 Cloud Run 서비스의 요약 목록에 새 서비스가 표시됩니다. 요약 행에는 일부 주요 구성 설정과 함께 가장 최근 배포 (날짜/시간 및 배포자)가 표시됩니다. 서비스 이름 링크를 클릭하여 새 서비스에 관한 세부정보를 자세히 확인합니다.

서비스를 확인하려면 요약 페이지 상단에 표시된 URL을 클릭합니다(아래 예시 참고).

6c35cf0636dddc51.png

다음과 같은 결과를 확인할 수 있습니다.

3ba6ab4fe0da1f84.png

이제 새 Cloud Run 서비스를 배포했으므로 REVISIONS 탭을 선택하여 여러 배포를 관리하는 방법을 확인하세요.

2351ee7ec4a356f0.png

콘솔에서 직접 새 버전을 배포하려면 아래 예시 스크린샷에 강조 표시된 EDIT & DEPLOY NEW REVISION 버튼을 클릭하면 됩니다.

a599fa88d00d6776.png

지금 버튼을 클릭하여 새 수정 버전을 만드세요. 컨테이너 URL 옆에 있는 SELECT 버튼을 클릭합니다(아래 참고).

5fd1b1f8e1f11d40.png

팝업되는 대화상자에서 이전에 Buildpacks를 사용하여 Cloud Build에서 배포한 간단한 웹 앱을 찾아 선택을 클릭합니다. '컨테이너 이미지'에서

gcr.io/<project>/cloud-run-source-deploy

폴더를 다음과 같이 만듭니다.

8a756c6157face3a.png

선택한 후 하단으로 스크롤하여 DEPLOY 버튼을 클릭합니다. 이제 앱의 새 버전을 배포했습니다. 이를 확인하려면 서비스 URL을 다시 방문하여 다채로운 'Hello from Cloud Run with Buildpacks!' 웹 앱이 표시되는지 확인합니다.

보시다시피 버전 탭에는 배포한 모든 버전의 요약이 표시되며, 이제 이 서비스에 대해 두 개의 버전이 표시됩니다. 버전 이름 왼쪽에 있는 라디오 버튼을 클릭하여 특정 버전을 선택할 수 있으며, 화면 오른쪽에 버전 세부정보의 요약이 표시됩니다. 이 버튼을 선택하면 두 버전이 서로 다른 두 컨테이너 이미지에서 파생되었음을 확인할 수 있습니다.

MANAGE TRAFFIC 버튼을 사용하면 특정 버전에 전송된 수신 요청의 배포를 수정할 수 있습니다. 특정 버전에 전송되는 트래픽 양을 세부적으로 조정할 수 있으므로 다음과 같은 유용한 사용 사례가 가능합니다.

  • 수신 트래픽의 일부를 사용하여 앱의 새 버전을 카나리아 테스트
  • 문제가 있는 출시 버전의 트래픽을 이전 버전으로 되돌리기
  • A/B 테스트

MANAGE TRAFFIC 버튼은 다음 위치에 있습니다.

519d3c22ae028287.png

다음과 같이 50/50 트래픽 분할을 지정하여 두 버전 간에 50/50 트래픽 분할을 구성합니다.

8c37d4f115d9ded4.png

이제 저장 버튼을 클릭하고 서비스의 URL을 반복적으로 방문하여 50/50 분할을 확인합니다. 평균적으로 요청의 절반은 현재 버전 ('Hello from Cloud Run with Buildpacks!')에서 처리되고 절반은 이전 버전 ('It's running!')에서 처리되는지 확인합니다.

서비스 세부정보 페이지의 다른 탭에서는 성능, 트래픽, 로그를 모니터링할 수 있으며, 이를 통해 서비스가 얼마나 열심히, 얼마나 잘 작동하는지에 대한 유용한 정보를 얻을 수 있습니다. '권한' 탭을 통해 서비스에 대한 액세스를 세부적으로 조정할 수도 있습니다. 잠시 시간을 내어 이 페이지의 탭을 살펴보고 여기에서 사용할 수 있는 기능을 확인하세요.

프로그래매틱 인터페이스

앞서 언급한 것처럼 프로그래매틱 방식으로 Cloud Run 서비스를 만들고, 배포하고, 관리할 수도 있습니다. 수동 작업의 경우 이 옵션이 명령줄이나 웹 콘솔보다 고급이지만 Cloud Run 서비스를 자동화하는 데는 확실히 이 방법이 좋습니다. 널리 사용되는 여러 프로그래밍 언어로 Google 클라이언트 라이브러리를 사용할 수 있습니다.

8. 앱 테스트

198ada162d1f0bf1.png

이 마지막 단계에서는 인공 부하 테스트를 실행하여 앱에 스트레스 테스트를 실행하고 수신되는 수요에 따라 앱이 어떻게 확장되는지 확인합니다. Cloud Shell에 사전 설치되어 있으며 부하 테스트를 실행하고 결과를 표시할 수 있는 hey라는 도구를 사용합니다.

테스트 실행

Cloud Shell 터미널에서 다음 명령어를 실행하여 부하 테스트를 실행합니다.

hey -q 1000 -c 200 -z 30s https://hello-...run.app

명령어 인수는 다음과 같이 해석됩니다.

  • -q 1000 - 초당 약 1,000개의 요청으로 부하를 유도합니다.
  • -c 200 - 병렬 작업자 200개 할당
  • -z 30s - 30초 동안 부하 테스트 실행
  • 이 명령줄에서 서비스 URL을 마지막 인수로 사용해야 합니다

테스트 결과는 다음과 같이 표시됩니다.

 Summary:
 Total:        30.2767 secs
 Slowest:      3.3633 secs
 Fastest:      0.1071 secs
 Average:      0.1828 secs
 Requests/sec: 1087.2387
 Total data:   3028456 bytes
 Size/request: 92 bytes

Response time histogram:
 0.107 [1]     |
 0.433 [31346] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
 0.758 [1472]  |■■
 1.084 [82]    |
 1.410 [4]     |
...

Latency distribution:
...
 50% in 0.1528 secs
 75% in 0.1949 secs
 90% in 0.2442 secs
 95% in 0.4052 secs
 99% in 0.7062 secs

Details (average, fastest, slowest):
...
 req write:    0.0000 secs, 0.0000 secs, 0.0232 secs
 resp wait:    0.1824 secs, 0.1070 secs, 3.2953 secs
 resp read:    0.0000 secs, 0.0000 secs, 0.0010 secs
Status code distribution:
 [200] 32918 responses

이 요약에서는 다음과 같은 몇 가지 흥미로운 사항을 알 수 있습니다.

  • 30초 동안 초당 약 1,000개의 요청이 전송되었습니다.
  • 오류가 없습니다 (200 HTTP 응답만 있음).
  • 평균 지연 시간은 180ms였습니다.
  • 최소 지연 시간은 107ms, 최악의 경우는 3.3초였습니다.
  • 90번째 백분위수 지연 시간은 244ms였습니다.

Cloud Run 콘솔의 METRICS 탭을 확인하면 서버 측 성능 스토리를 확인할 수 있습니다.

e635c6831c468dd3.png

9. 삭제

Cloud Run에서는 서비스를 사용하지 않을 때 비용이 청구되지 않지만 빌드된 컨테이너 이미지를 저장하는 데 요금이 부과될 수 있습니다.

GCP 프로젝트를 삭제하여 비용 발생을 피하거나(해당 프로젝트 내에서 사용된 모든 리소스에 대한 청구가 중단됨) 간단하게 다음 명령어를 사용하여 컨테이너 이미지를 삭제할 수 있습니다.

gcloud container images delete $TAG

Cloud Run 서비스를 삭제하려면 다음 명령어를 사용하세요.

gcloud run services delete hello --platform managed --region $REGION --quiet
gcloud run services delete hello-again --platform managed --region $REGION --quiet

10. 잘하셨습니다!

9a31f4fdbbf1ddcb.png

축하합니다. 프로덕션 Cloud Run 앱을 성공적으로 빌드하고 배포했습니다. 이 과정에서 컨테이너와 자체 컨테이너를 빌드하는 방법을 배웠습니다. gcloud 명령줄 도구와 Cloud Console을 모두 사용하여 Cloud Run으로 앱을 쉽게 배포하는 방법도 살펴보았습니다. 이제 멋진 작품을 전 세계와 공유하는 방법을 알게 되었습니다.

한 가지 중요한 질문을 드리고 싶습니다.

개발자 환경에서 앱을 작동시킨 후 Cloud Run에서 제공하는 모든 프로덕션 등급 속성을 사용하여 클라우드에 배포하려면 몇 줄의 코드를 수정해야 하나요?

물론 답은 0입니다. :)

확인할 Codelab...

기타 유용한 기능 살펴보기

참조 문서…

11. 클릭 유도 문구

Google Cloud 로고

이 Codelab이 마음에 들었고 Google Cloud를 직접 사용해 보는 데 더 많은 시간을 할애할 계획이라면 지금 바로 Google Cloud Innovators에 가입하세요.

Innovators 일반 회원 배지 로고

Google Cloud Innovators는 무료이며 다음과 같은 혜택이 제공됩니다.

  • Google 직원이 직접 전하는 최신 소식을 알아볼 수 있는 실시간 토론, AMA, 로드맵 세션
  • 받은편지함에서 바로 최신 Google Cloud 뉴스 확인
  • 디지털 배지 및 화상 회의 배경
  • Skills Boost의 실습 및 학습 500 크레딧

등록하려면 여기를 클릭하세요.