컨테이너 소개


컨테이너화된 워크로드에 익숙하지 않다면 이 튜토리얼을 참고하세요. 이 튜토리얼에서는 소스 코드에서 GKE에서 실행되는 컨테이너로 간단한 애플리케이션을 설정하는 방법을 안내하여 컨테이너 및 컨테이너 조정에 대해 설명합니다.

이 튜토리얼에서는 컨테이너 또는 Kubernetes에 대한 이전 경험이 필요하지 않습니다. 하지만 이 튜토리얼을 시작하기 전에 핵심 Kubernetes 용어에 관한 개요를 읽으려면 Kubernetes 학습 시작을 참고하세요. 만화 형식으로 Kubernetes에 관해 알아보려면 Kubernetes 만화를 참고하세요. 자세한 리소스는 튜토리얼 끝에 있는 다음 단계 섹션을 참고하세요.

컨테이너와 Kubernetes에 이미 익숙하다면 이 튜토리얼을 건너뛰고 GKE 자체에 대해 알아보세요.

목표

  1. 간단한 다중 서비스 'hello world' 애플리케이션 살펴보기
  2. 소스에서 애플리케이션을 실행합니다.
  3. 애플리케이션 컨테이너화
  4. Kubernetes 클러스터 만들기
  5. 클러스터에 컨테이너 배포

시작하기 전에

다음 단계에 따라 Kubernetes Engine API를 사용 설정합니다.
  1. Google Cloud 콘솔에서 Kubernetes Engine 페이지로 이동합니다.
  2. 프로젝트를 만들거나 선택합니다.
  3. API 및 관련 서비스가 사용 설정될 때까지 기다립니다. 몇 분 정도 걸릴 수 있습니다.
  4. Make sure that billing is enabled for your Google Cloud project.

Cloud Shell 준비

이 튜토리얼에서는 Debian 기반 Linux 운영체제를 실행하는 g1-small Compute Engine 가상 머신 (VM)을 프로비저닝하는 Cloud Shell을 사용합니다.

Cloud Shell을 사용하면 다음과 같은 이점이 있습니다.

  • Python 3 개발 환경 (virtualenv 포함)이 완전히 설정됩니다.
  • 이 튜토리얼에 사용된 gcloud, docker, git, kubectl 명령줄 도구는 이미 설치되어 있습니다.
  • 다음과 같은 내장 텍스트 편집기를 선택할 수 있습니다.

    • Cloud Shell 편집기: Cloud Shell 창 상단의 편집기 열기를 클릭하여 액세스할 수 있습니다.

    • Cloud Shell의 명령줄에서 액세스할 수 있는 Emacs, Vim 또는 Nano

In the Google Cloud console, activate Cloud Shell.

Activate Cloud Shell

At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

샘플 코드 다운로드

  1. helloserver 소스 코드를 다운로드합니다.

    git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples
    
  2. 샘플 코드 디렉터리로 변경합니다.

    cd anthos-service-mesh-samples/docs/helloserver
    

멀티 서비스 애플리케이션 살펴보기

샘플 애플리케이션은 Python으로 작성됩니다. REST를 사용하여 통신하는 다음 구성요소가 있습니다.

  • server: GET 엔드포인트 하나, /가 있는 기본 서버로 , 터미널 창에 'hello world'를 인쇄합니다.
  • loadgen: 구성 가능한 초당 요청 수(RPS)와 함께 server로 트래픽을 전송하는 스크립트입니다.

샘플 애플리케이션

소스에서 애플리케이션 실행

샘플 애플리케이션에 익숙해지려면 Cloud Shell에서 실행하세요.

  1. sample-apps/helloserver 디렉터리에서 server를 실행합니다.

    python3 server/server.py
    

    시작 시 server에 다음이 표시됩니다.

    INFO:root:Starting server...
    
  2. server에 요청을 보낼 수 있도록 다른 터미널 창을 엽니다. Cloud Shell에서 이렇게 하려면 새 탭 열기를 클릭하여 다른 세션을 엽니다.

  3. 새 터미널 창에서 server에 요청을 보냅니다.

    curl http://localhost:8080
    

    server의 출력은 다음과 같습니다.

    Hello World!
    
  4. 동일한 탭에서 loadgen 스크립트가 포함된 디렉터리로 변경합니다.

    cd anthos-service-mesh-samples/docs/helloserver/loadgen
  5. 다음의 환경 변수를 만듭니다.

    export SERVER_ADDR=http://localhost:8080
    export REQUESTS_PER_SECOND=5
    
  6. virtualenv를 시작합니다.

    virtualenv --python python3 env
    
  7. 가상 환경을 활성화합니다.

    source env/bin/activate
    
  8. loadgen의 요구사항을 설치합니다.

    pip3 install -r requirements.txt
    
  9. loadgen 애플리케이션을 실행하여 server의 트래픽을 생성합니다.

    python3 loadgen.py
    

    시작 시 loadgen의 출력은 다음과 유사합니다.

    Starting loadgen: 2024-10-11 09:49:51.798028
    5 request(s) complete to http://localhost:8080
    
  10. 이제 server를 실행 중인 터미널 창을 엽니다. 다음과 유사한 메시지가 표시됩니다.

    127.0.0.1 - - [11/Oct/2024 09:51:28] "GET / HTTP/1.1" 200 -
    INFO:root:GET request,
    Path: /
    Headers:
    Host: localhost:8080
    User-Agent: python-requests/2.32.3
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    

    네트워킹 관점에서, 이제 전체 애플리케이션이 동일한 호스트에서 실행되므로 localhost를 사용하여 server에 요청을 보낼 수 있습니다.

  11. loadgenserver를 중지하려면 각 터미널 창에서 Ctrl-c를 누릅니다.

  12. loadgen 터미널 창에서 가상 환경을 비활성화합니다.

    deactivate
    

애플리케이션 컨테이너화

GKE에서 애플리케이션을 실행하려면 샘플 애플리케이션의 구성요소를 모두 컨테이너에 패키징해야 합니다. 컨테이너는 애플리케이션이 어떤 환경에서나 실행되기 위해 필요한 모든 요소가 포함된 패키지입니다. 이 튜토리얼에서는 Docker를 사용하여 애플리케이션을 컨테이너화합니다.

Docker로 애플리케이션을 컨테이너화하려면 Dockerfile이 필요합니다. Dockerfile은 애플리케이션 소스 코드와 종속 항목을 컨테이너 이미지로 조합하는 데 필요한 명령어를 정의하는 텍스트 파일입니다. 이미지를 빌드한 후에는 Artifact Registry와 같은 컨테이너 레지스트리에 업로드합니다.

이 튜토리얼의 소스 코드에는 이미지를 빌드하는 데 필요한 모든 명령어가 포함된 serverloadgenDockerfile가 포함되어 있습니다. 다음은 serverDockerfile입니다.

FROM python:3.13-slim as base
FROM base as builder
RUN apt-get -qq update \
    && apt-get install -y --no-install-recommends \
        g++ \
    && rm -rf /var/lib/apt/lists/*

# Enable unbuffered logging
FROM base as final
ENV PYTHONUNBUFFERED=1

RUN apt-get -qq update \
    && apt-get install -y --no-install-recommends \
        wget

WORKDIR /helloserver

# Grab packages from builder
COPY --from=builder /usr/local/lib/python3.* /usr/local/lib/

# Add the application
COPY . .

EXPOSE 8080
ENTRYPOINT [ "python", "server.py" ]

이 파일에서 다음을 확인할 수 있습니다.

  • FROM python:3-slim as base 안내는 최신 Python 3 이미지를 기본 이미지로 사용하도록 Docker에 지시합니다.
  • COPY . . 명령어는 현재 작업 디렉터리 (이 경우에는 server.py)의 소스 파일을 컨테이너의 파일 시스템에 복사합니다.
  • ENTRYPOINT는 컨테이너를 실행하는 데 사용되는 명령어를 정의합니다. 이 예에서 명령어는 소스 코드에서 server.py를 실행하는 데 사용된 명령어와 유사합니다.
  • EXPOSE 명령어는 server가 포트 8080에서 리슨하도록 지정합니다. 이 안내는 포트를 노출하지 않지만 컨테이너를 실행할 때 포트 8080를 여는 데 필요한 문서의 역할을 합니다.

애플리케이션 컨테이너화 준비

애플리케이션을 컨테이너화하기 전에 사용할 도구와 서비스를 설정해야 합니다.

  1. Google Cloud CLI의 기본 Google Cloud 프로젝트를 설정합니다.

    gcloud config set project PROJECT_ID
  2. Google Cloud CLI의 기본 리전을 설정합니다.

    gcloud config set compute/region us-central1
    

저장소 만들기

Artifact Registry에서 Docker 컨테이너 이미지의 새 저장소를 만들려면 다음 단계를 따르세요.

  1. Google Cloud 프로젝트에서 Artifact Registry 서비스가 사용 설정되어 있는지 확인합니다.

    gcloud services enable artifactregistry.googleapis.com
    
    
  2. Artifact Registry 저장소를 만듭니다.

    gcloud artifacts repositories create container-intro --repository-format=docker \
        --location=us-central1 \
        --description="My new Docker repository" 
    
  3. Google Cloud CLI를 사용하여 Docker에서 Artifact Registry로의 인증을 설정합니다.

    gcloud auth configure-docker us-central1-docker.pkg.dev
    

server 컨테이너화

이제 애플리케이션을 컨테이너화할 차례입니다. 먼저 'hello world' server를 컨테이너화하고 이미지를 Artifact Registry에 푸시합니다.

  1. 샘플 server가 있는 디렉터리로 변경합니다.

    cd ~/anthos-service-mesh-samples/docs/helloserver/server/
  2. Dockerfile를 사용하여 이미지를 빌드합니다.

    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1 .
    
    • PROJECT_ID를 Google Cloud 프로젝트의 ID로 바꿉니다.

    -t 플래그는 Docker 태그를 나타냅니다. 컨테이너를 배포할 때 사용하는 이미지의 이름입니다.

  3. 이미지를 Artifact Registry로 내보냅니다.

    docker push us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1
    

loadgen 컨테이너화

다음으로 동일한 방식으로 부하 생성기 서비스를 컨테이너화합니다.

  1. 샘플 loadgen가 있는 디렉터리로 변경합니다.

    cd ../loadgen
    
  2. 이미지를 빌드합니다.

    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1 .
    
  3. 이미지를 Artifact Registry로 내보냅니다.

    docker push us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1
    

이미지 나열

저장소의 이미지 목록을 가져와서 이미지가 푸시되었는지 확인합니다.

gcloud container images list --repository us-central1-docker.pkg.dev/PROJECT_ID/container-intro

출력에는 다음과 같이 푸시한 이미지 이름이 표시됩니다.

NAME
us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver
us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen

GKE 클러스터 만들기

이제 docker run 명령어를 사용하여 Cloud Shell VM에서 컨테이너를 실행하면 됩니다. 그러나 안정적인 프로덕션 워크로드를 실행하려면 컨테이너를 더 통합된 방식으로 관리해야 합니다. 예를 들어 컨테이너가 실패하면 다시 시작해야 하며 트래픽 증가를 처리하기 위해 컨테이너의 추가 인스턴스를 확장하고 시작하는 방법이 필요합니다.

GKE를 사용하면 이러한 요구사항을 충족할 수 있습니다. GKE는 VM을 클러스터에 연결하여 작동하는 컨테이너 조정 플랫폼입니다. 각 VM을 노드라고 합니다. GKE 클러스터는 Kubernetes 오픈소스 클러스터 관리 시스템을 기반으로 합니다. Kubernetes는 클러스터와 상호작용할 수 있는 메커니즘을 제공합니다.

GKE에서 컨테이너를 실행하려면 먼저 클러스터를 만든 다음 클러스터에 연결해야 합니다.

  1. 클러스터를 만듭니다.

    gcloud container clusters create-auto container-intro
    

    gcloud 명령어는 이전에 설정한 기본 Google Cloud 프로젝트 및 리전에 클러스터를 만듭니다.

    클러스터를 만드는 명령어는 완료하는 데 몇 분 정도 걸립니다. 클러스터가 준비되면 출력은 다음과 비슷합니다.

     NAME: container-intro
     LOCATION: us-central1
     MASTER_VERSION: 1.30.4-gke.1348000
     MASTER_IP: 34.44.14.166
     MACHINE_TYPE: e2-small
     NODE_VERSION: 1.30.4-gke.1348000
     NUM_NODES: 3
     STATUS: RUNNING
    
  2. 클러스터를 관리할 때 사용할 수 있도록 kubectl 명령줄 도구에 사용자 인증 정보를 제공합니다.

    gcloud container clusters get-credentials container-intro
    

Kubernetes 매니페스트 검사

소스 코드에서 애플리케이션을 실행한 경우 명령형 명령어(python3 server.py)를 사용한 것입니다.

명령형은 '수행하세요'와 같이 동사 기반입니다.

이와 달리 Kubernetes는 선언적 모델에서 작동합니다. 즉, Kubernetes에게 해야 할 일을 정확하게 알려주는 대신 Kubernetes에 원하는 상태를 제공합니다. 예를 들어 Kubernetes는 필요에 따라 포드를 시작하고 종료하여 실제 시스템 상태가 원하는 상태와 일치하도록 합니다.

매니페스트라는 파일에서 원하는 상태를 지정합니다. 매니페스트는 YAML 또는 JSON과 같은 언어로 작성되며 하나 이상의 Kubernetes 객체에 대한 사양을 포함합니다.

샘플에는 serverloadgen의 매니페스트가 각각 포함되어 있습니다. 각 매니페스트는 Kubernetes 배포 객체 (실행 중인 컨테이너를 관리하고 Kubernetes 포드로 패키징하여 관리하기 위한 것) 및 서비스 (포드의 IP 주소를 제공함)에 원하는 상태를 지정합니다. 포드는 Kubernetes에서 만들고 관리할 수 있는 배포 가능한 최소 컴퓨팅 단위이며 하나 이상의 컨테이너를 보유합니다.

다음 다이어그램은 GKE에서 실행되는 애플리케이션을 보여줍니다.

GKE에서 실행되는 컨테이너화된 애플리케이션

포드, 배포, 서비스에 대한 자세한 내용은 Kubernetes 학습 시작 또는 이 페이지 끝에 있는 리소스를 참고하세요.

서버

먼저 'Hello World' server의 매니페스트를 살펴봅니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helloserver
  template:
    metadata:
      labels:
        app: helloserver
    spec:
      containers:
      - image: gcr.io/google-samples/istio/helloserver:v0.0.1
        imagePullPolicy: Always
        name: main
      restartPolicy: Always
      terminationGracePeriodSeconds: 5

이 매니페스트에는 다음 필드가 포함됩니다.

  • kind는 객체 유형을 나타냅니다.
  • metadata.name은 배포 이름을 지정합니다.
  • 첫 번째 spec 필드에는 원하는 상태에 대한 설명이 포함됩니다.
  • spec.replicas는 원하는 포드 수를 지정합니다.
  • spec.template 섹션은 포드 템플릿을 정의합니다. 포드 사양에 포함된 image 필드는 Artifact Registry에서 가져올 이미지의 이름입니다. 다음 단계에서는 이를 방금 만든 새 이미지로 업데이트합니다.

hellosvc 서비스는 다음과 같이 정의됩니다.

apiVersion: v1
kind: Service
metadata:
  name: hellosvc
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  selector:
    app: helloserver
  type: LoadBalancer
  • LoadBalancer: 클라이언트가 안정적인 IP 주소를 가지고 있고 클러스터 외부에 연결할 수 있는 네트워크 부하 분산기의 IP 주소로 요청을 보냅니다.
  • targetPort: DockerfileEXPOSE 8080 명령어는 실제로 포트를 노출하지 않습니다. 클러스터 외부의 server 컨테이너에 도달할 수 있도록 포트 8080를 노출합니다. 이 경우 hellosvc.default.cluster.local:80(짧은 이름: hellosvc)는 helloserver 포드 IP의 포트 8080에 매핑합니다.
  • port: 클러스터의 다른 서비스가 요청을 보낼 때 사용하는 포트 번호입니다.

부하 생성기

loadgen.yaml의 배포 객체는 server.yaml과 비슷합니다. 한 가지 중요한 차이점은 loadgen 배포의 포드 사양에 env라는 필드가 있다는 것입니다. 이 섹션에서는 이전에 소스에서 애플리케이션을 실행할 때 설정한 loadgen에 필요한 환경 변수를 정의합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: loadgenerator
spec:
  replicas: 1
  selector:
    matchLabels:
      app: loadgenerator
  template:
    metadata:
      labels:
        app: loadgenerator
    spec:
      containers:
      - env:
        - name: SERVER_ADDR
          value: http://hellosvc:80/
        - name: REQUESTS_PER_SECOND
          value: '10'
        image: gcr.io/google-samples/istio/loadgen:v0.0.1
        imagePullPolicy: Always
        name: main
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 300m
            memory: 256Mi
      restartPolicy: Always
      terminationGracePeriodSeconds: 5

loadgen은 들어오는 요청을 수락하지 않으므로 type 필드는 ClusterIP로 설정됩니다. 이 유형의 서비스는 클러스터의 항목이 사용할 수 있는 안정적인 IP 주소를 제공하지만 IP 주소가 외부 클라이언트에 노출되지 않습니다.

apiVersion: v1
kind: Service
metadata:
  name: loadgensvc
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  selector:
    app: loadgenerator
  type: ClusterIP

GKE에 컨테이너 배포

컨테이너를 배포하려면 kubectl를 사용하여 원하는 상태를 지정하는 매니페스트를 적용합니다.

server 배포

  1. 샘플 server가 있는 디렉터리로 변경합니다.

    cd ~/anthos-service-mesh-samples/docs/helloserver/server/
  2. Cloud Shell 편집기 (또는 선호하는 텍스트 편집기)에서 server.yaml를 엽니다.

  3. image 필드의 이름을 Docker 이미지의 이름으로 바꿉니다.

    image: us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1
    

    PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.

    • Cloud Shell 편집기를 사용하는 경우 파일이 자동으로 저장됩니다. 터미널 열기를 클릭하여 터미널 창으로 돌아갑니다.
    • Cloud Shell에서 텍스트 편집기를 사용하는 경우 server.yaml을 저장하고 닫습니다.
  4. Kubernetes에 매니페스트를 배포합니다.

    kubectl apply -f server.yaml
    

    출력은 다음과 비슷합니다.

    deployment.apps/helloserver created
    service/hellosvc created
    

loadgen 배포

  1. loadgen이 있는 디렉터리로 변경합니다.

    cd ../loadgen
    
  2. 이전과 같이 텍스트 편집기에서 loadgen.yaml를 엽니다.

  3. image 필드의 이름을 Docker 이미지의 이름으로 다시 바꿉니다.

    image: us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1
    

    PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.

    • Cloud Shell 편집기를 사용하는 경우 파일이 자동으로 저장됩니다. 터미널 열기를 클릭하여 터미널 창으로 돌아갑니다.
    • Cloud Shell에서 텍스트 편집기를 사용하는 경우 loadgen.yaml을 저장하고 닫습니다.
  4. 클러스터에 매니페스트를 배포합니다.

    kubectl apply -f loadgen.yaml
    

    성공하면 명령어가 다음과 같이 응답합니다.

    deployment.apps/loadgenerator created
    service/loadgensvc created
    

배포 확인

클러스터에 매니페스트를 배포한 후 컨테이너가 성공적으로 배포되었는지 확인합니다.

  1. 클러스터의 포드 상태를 확인합니다.

    kubectl get pods
    

    이 명령어는 다음과 유사한 상태로 응답합니다.

    NAME                             READY   STATUS    RESTARTS   AGE
    helloserver-69b9576d96-mwtcj     1/1     Running   0          58s
    loadgenerator-774dbc46fb-gpbrz   1/1     Running   0          57s
    
  2. loadgen 포드에서 애플리케이션 로그를 가져옵니다. POD_ID를 이전 출력의 로드 생성기 포드 식별자로 바꿉니다.

    kubectl logs POD_ID
    
  3. hellosvc의 외부 IP 주소를 가져옵니다.

    kubectl get service hellosvc
    

    출력은 다음과 비슷합니다.

    NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
    hellosvc     LoadBalancer   10.81.15.158   192.0.2.1       80:31127/TCP   33m
    
  4. hellosvc로 요청을 보냅니다. EXTERNAL_IPhellosvc의 외부 IP 주소로 바꿉니다.

    curl http://EXTERNAL_IP
    

    서버에서 'Hello World!' 메시지가 표시됩니다.

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

전체 프로젝트를 삭제하지 않으려면 다음 단계를 따르세요.

  • GKE 클러스터를 삭제합니다. 클러스터를 삭제하면 Compute Engine 인스턴스, 디스크, 네트워크 리소스와 같이 클러스터를 구성하는 모든 리소스가 삭제됩니다.

     gcloud container clusters delete container-intro
    
  • Artifact Registry 저장소를 삭제합니다.

     gcloud artifacts repositories delete container-intro --location=us-central1
    

다음 단계