コンテナの概要

このチュートリアルでは、コンテナ化されたワークロードに馴染みがない方を対象に、ソースコードから GKE でのコンテナ実行までのシンプルなアプリケーションの設定手順を通して、コンテナとコンテナ オーケストレーションについて説明します。

このチュートリアルには、コンテナや Kubernetes の使用経験は必要ありません。このチュートリアルを開始する前に Kubernetes の主な用語をおおまかに確認しておくには、Kubernetes の学習を開始するをご覧ください。ご希望なら、Kubernetes を漫画で学習できる Kubernetes コミックもあります。詳細なリソースについては、チュートリアルの最後にある次のステップをご覧ください。

コンテナと Kubernetes をすでによくご存じの場合は、このチュートリアルをスキップして、GKE 自体の学習を開始できます。

サンプルコードをダウンロードする

  1. helloserver ソースコードをダウンロードします。

    git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples
    
  2. サンプルコードのディレクトリに移動します。

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

マルチサービス アプリケーションを確認する

サンプル アプリケーションは Python で記述されており、REST を使用して通信する次のコンポーネントがあります。

  • server: 1 つの GET エンドポイント(/)を持つ基本的なサーバー。ターミナル ウィンドウに「hello world」を出力します。
  • loadgen: server にトラフィックを送信するスクリプト。1 秒あたりのリクエスト数(RPS)を構成できます。

サンプル アプリケーション

ソースからアプリケーションを実行する

サンプル アプリケーションに慣れるため、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 などのコンテナ レジストリにアップロードします。

このチュートリアルのソースコードには、serverloadgen の両方の Dockerfile があり、イメージのビルドに必要なすべてのコマンドが用意されています。以下は、server 用の Dockerfile です。

FROM python:3.14-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 に push します。

  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 に push します。

    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 に push します。

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

イメージのリストを表示する

リポジトリ内のイメージのリストを取得して、イメージが push されたことを確認します。

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

出力には、push したイメージ名が次のように一覧表示されます。

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 は必要に応じて Pod を起動または停止します。

望ましい状態は、マニフェストというファイルで指定します。マニフェストは YAML や JSON などの言語で記述され、1 つ以上の Kubernetes オブジェクトの仕様が含まれています。

このサンプルには、serverloadgen のマニフェストがそれぞれ含まれています。各マニフェストは、Kubernetes Deployment オブジェクト(Kubernetes Pod として管理用にパッケージ化されたコンテナの実行を管理する)と Service(Pod の IP アドレスを提供する)の望ましい状態を指定します。Pod は、Kubernetes で作成して管理できる、デプロイ可能なコンピューティングの最小単位であり、1 つ以上のコンテナを保持しています。

次の図は、GKE で実行されるアプリケーションを示しています。

GKE で実行されているコンテナ化されたアプリケーション

Pod、Deployment、Service の詳細については、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 で Deployment の名前を指定します。
  • 最初の spec フィールドには、望ましい状態の説明が含まれています。
  • spec.replicas で目的の Pod の数を指定します。
  • spec.template セクションで Pod テンプレートを定義します。Pod の仕様には、Artifact Registry から pull するイメージの名前である image フィールドが含まれています。次のステップでは、このイメージを先ほど作成した新しいイメージに更新します。

hellosvc Service は、次のように定義されます。

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 コマンドでは実際にはポートが公開されないことに注意してください。ポート 8080 を公開して、クラスタの外部にある server コンテナにアクセスできるようにします。この場合、hellosvc.default.cluster.local:80(略称: hellosvc)は helloserver Pod IP のポート 8080 にマッピングされます。
  • port: クラスタ内の他のサービスでリクエストを送信するときに使用するポート番号です。

負荷生成ツール

loadgen.yaml の Deployment オブジェクトは server.yaml に類似します。大きな違いとして、loadgen Deployment の Pod 仕様に 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 に設定されます。このタイプの Service は、クラスタ内のエンティティが使用できる安定した 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. クラスタ内の Pod のステータスを確認します。

    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 からアプリケーション ログを取得します。POD_ID は、出力済みの負荷生成ツールの 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!」というメッセージが表示されます。