クイックスタート:言語に固有のアプリのデプロイ

このページでは、次の方法について説明します。

  1. Hello World アプリを作成する。
  2. Cloud Build を使用して、アプリをコンテナ イメージにパッケージ化する。
  3. Google Kubernetes Engine(GKE)でクラスタを作成する。
  4. コンテナ イメージをクラスタにデプロイする。

ここでは、複数の言語でサンプルを示しますが、それ以外の言語を使用することもできます。

始める前に

  1. Google アカウントにログインします。

    Google アカウントをまだお持ちでない場合は、新しいアカウントを登録します。

  2. GCP プロジェクトを選択または作成します。

    プロジェクト セレクタのページに移動

  3. Google Cloud Platform プロジェクトに対して課金が有効になっていることを確認します。 詳しくは、課金を有効にする方法をご覧ください。

  4. Cloud Build と Google Kubernetes Engine API を有効にします。

    APIを有効にする

  5. Cloud SDK をインストールして初期化します。
  6. kubectl は、GKE で使用されるクラスタ オーケストレーション システムである Kubernetes の管理に使用されます。kubectlgcloud でインストールできます。
    gcloud components install kubectl

サンプルアプリの作成

GKE で実行される Hello World アプリの作成手順については、ご使用の言語をクリックしてください。

Go

  1. helloworld-gke という名前の新しいディレクトリを作成し、そのディレクトリに移動します。

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. example.com/helloworld という名前の新しいモジュールを作成します。

    go mod init example.com/helloworld
    
  3. helloworld.go という名前で新しいファイルを作成し、次のコードを貼り付けます。

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	http.HandleFunc("/", handler)
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    	log.Printf("Listening on localhost:%s", port)
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	log.Print("Hello world received a request.")
    	target := os.Getenv("TARGET")
    	if target == "" {
    		target = "World"
    	}
    	fmt.Fprintf(w, "Hello %s!\n", target)
    }
    

    このコードは、PORT 環境変数で定義されたポートをリッスンするウェブサーバーを作成します。

これでアプリが完成しました。このアプリを Docker コンテナにパッケージ化し、Container Registry にアップロードできます。

Node.js

  1. helloworld-gke という名前の新しいディレクトリを作成し、そのディレクトリに移動します。

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. package.json ファイルを作成し、次の内容を追加します。

    {
      "name": "gke-helloworld",
      "version": "1.0.0",
      "description": "GKE hello world sample in Node",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "author": "",
      "license": "Apache-2.0",
      "dependencies": {
        "express": "^4.16.4"
      }
    }
    
  3. 同じディレクトリに index.js ファイルを作成し、次の行をコピーします。

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      console.log('Hello world received a request.');
    
      const target = process.env.TARGET || 'World';
      res.send(`Hello ${target}!`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log('Hello world listening on port', port);
    });
    

    このコードは、PORT 環境変数で定義されたポートをリッスンするウェブサーバーを作成します。

これでアプリが完成しました。このアプリを Docker コンテナにパッケージ化し、Container Registry にアップロードできます。

Python

  1. helloworld-gke という名前の新しいディレクトリを作成し、そのディレクトリに移動します。

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. app.py という名前のファイルを作成し、次のコードを貼り付けます。

    import os
    
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        target = os.environ.get('TARGET', 'World')
        return 'Hello {}!\n'.format(target)
    
    if __name__ == "__main__":
        app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT', 8080)))
    

Java

Spring Boot アプリを作成します。

  1. Java SE 8 以降の JDKcURL をインストールします。 Java SE と cURL は、次のステップで新しいウェブ プロジェクトを作成する場合にのみ必要になります。Dockerfile がすべての依存関係をコンテナに読み込みます(詳細はあとで説明します)。

  2. ターミナルで、新しい空のウェブ プロジェクトを作成します。

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d javaVersion=1.8 \
        -d bootVersion=2.1.3.RELEASE \
        -d name=helloworld \
        -d artifactId=helloworld \
        -d baseDir=helloworld-gke \
        -o helloworld-gke.zip
    unzip helloworld-gke.zip
    cd helloworld-gke
    

    新しい Spring Boot プロジェクトが helloworld-gke に作成されました。

  3. src/main/java/com/example/helloworld/HelloworldApplication.java ファイルで、/ マッピングを処理する @RestController を追加して HelloworldApplication クラスを更新します。

    package com.example.helloworld;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    public class HelloworldApplication {
    
    	@Value("${TARGET:World}")
    	String target;
    
    	@RestController
    	class HelloworldController {
    		@GetMapping("/")
    		String hello() {
    			return "Hello " + target + "!";
    		}
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(HelloworldApplication.class, args);
    	}
    }
    

    このコードは、PORT 環境変数で定義されたポートをリッスンするウェブサーバーを作成します。

これでアプリが完成しました。このアプリを Docker コンテナにパッケージ化し、Container Registry にアップロードできます。

C#

  1. .NET Core SDK 2.2 をインストールします。 .NET Core SDK は、次のステップで新しいウェブ プロジェクトを作成する場合にのみ必要です。Dockerfile がすべての依存関係をコンテナに読み込みます(詳細はあとで説明します)。

  2. ターミナルで、新しい空のウェブ プロジェクトを作成します。

    dotnet new web -o helloworld-gke
    
  3. helloworld-gke ディレクトリに移動します。

  4. Program.cs で、.UseUrls() のポート URL を指定してサービスポートを定義し、CreateWebHostBuilder の定義を更新します。このサンプルでは 8080 を使用していますが、他のポートを使用することもできます。サーバーがリッスンするポートを指定する必要があります。

    // Copyright (c) 2019 Google LLC.
    //
    // Licensed under the Apache License, Version 2.0 (the "License"); you may not
    // use this file except in compliance with the License. You may obtain a copy of
    // the License at
    //
    // http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    // License for the specific language governing permissions and limitations under
    // the License.
    
    using System;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    
    namespace HelloGKE
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>()
                    .UsePortEnvironmentVariable();
        }
    
        static class ProgramExtensions
        {
            // Google Cloud Run sets the PORT environment variable to tell this
            // process which port to listen to.
            public static IWebHostBuilder UsePortEnvironmentVariable(
                this IWebHostBuilder builder)
            {
                string port = Environment.GetEnvironmentVariable("PORT");
                if (!string.IsNullOrEmpty(port))
                {
                    builder.UseUrls($"http://0.0.0.0:{port}");
                }
                return builder;
            }
        }
    }
    

これでアプリが完成しました。このアプリを Docker コンテナにパッケージ化し、Container Registry にアップロードできます。

PHP

  1. helloworld-gke という名前の新しいディレクトリを作成し、そのディレクトリに移動します。

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. index.php という名前のファイルを作成し、次のコードを貼り付けます。

    <?php
    $target = getenv('TARGET', true) ?: 'World';
    echo sprintf("Hello %s!", $target);
    

これでアプリが完成しました。このアプリを Docker コンテナにパッケージ化し、Container Registry にアップロードできます。

Ruby

  1. helloworld-gke という名前の新しいディレクトリを作成し、そのディレクトリに移動します。

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. app.rb という名前のファイルを作成し、次のコードを貼り付けます。

    require 'sinatra'
    
    set :bind, '0.0.0.0'
    set :port, ENV['PORT'] || '8080'
    
    get '/' do
      target = ENV['TARGET'] || 'World'
      "Hello #{target}!\n"
    end
    

    このコードは、PORT 環境変数で定義されたポートをリッスンするウェブサーバーを作成します。

  3. Gemfile という名前のファイルを作成し、次の内容をコピーします。

    source 'https://rubygems.org'
    
    gem 'sinatra'
    gem 'rack', '>= 2.0.6'
    

Cloud Build によるアプリのコンテナ化

  1. サンプルアプリをコンテナ化するには、ソースファイルと同じディレクトリに Dockerfile という名前の新しいファイルを作成し、次の内容をコピーします。

    Go

    # Use the offical Golang image to create a build artifact.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.12 as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY . .
    
    # Build the command inside the container.
    RUN CGO_ENABLED=0 GOOS=linux go build -v -o helloworld
    
    # Use a Docker multi-stage build to create a lean production image.
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM alpine
    RUN apk add --no-cache ca-certificates
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /app/helloworld /helloworld
    
    # Run the web service on container startup.
    CMD ["/helloworld"]
    

    Node.js

    # Use the official lightweight Node.js 10 image.
    # https://hub.docker.com/_/node
    FROM node:10-slim
    
    # Create and change to the app directory.
    WORKDIR /usr/src/app
    
    # Copy application dependency manifests to the container image.
    # A wildcard is used to ensure both package.json AND package-lock.json are copied.
    # Copying this separately prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install production dependencies.
    RUN npm install --only=production
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]
    

    さらに、ローカル ファイルがコンテナのビルドプロセスに影響しないように、.dockerignore ファイルを追加します。

    Dockerfile
    README.md
    node_modules
    npm-debug.log
    

    Python

    # Use the official lightweight Python image.
    # https://hub.docker.com/_/python
    FROM python:3.7-slim
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Install production dependencies.
    RUN pip install Flask gunicorn
    
    # Run the web service on container startup. Here we use the gunicorn
    # webserver, with one worker process and 8 threads.
    # For environments with multiple CPU cores, increase the number of workers
    # to be equal to the cores available.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app
    

    ローカル ファイルがコンテナのビルドプロセスに影響しないように、.dockerignore ファイルを追加します。

    Dockerfile
    README.md
    *.pyc
    *.pyo
    *.pyd
    __pycache__
    

    Java

    # Use the official maven/Java 8 image to create a build artifact.
    # https://hub.docker.com/_/maven
    FROM maven:3.5-jdk-8-alpine as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY pom.xml ./
    COPY src ./src/
    
    # Build a release artifact.
    RUN mvn package -DskipTests
    
    # Use AdoptOpenJDK for base image.
    # It's important to use OpenJDK 8u191 or above that has container support enabled.
    # https://hub.docker.com/r/adoptopenjdk/openjdk8
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
    
    # Copy the jar to the production image from the builder stage.
    COPY --from=builder /app/target/helloworld-*.jar /helloworld.jar
    
    # Run the web service on container startup.
    CMD ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/helloworld.jar"]
    

    C#

    # Use Microsoft's official lightweight .NET images.
    # https://hub.docker.com/r/microsoft/dotnet
    
    FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build
    WORKDIR /app
    
    # Install production dependencies.
    # Copy csproj and restore as distinct layers.
    COPY *.csproj ./
    RUN dotnet restore
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build a release artifact.
    RUN dotnet publish -c Release -o out
    
    # Run the web service on container startup in a lean production image.
    FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine
    WORKDIR /app
    
    COPY --from=build /app/out ./
    CMD ["dotnet", "HelloGKE.dll"]
    

    ローカル ファイルがコンテナのビルドプロセスに影響しないように、.dockerignore ファイルを追加します。

    Dockerfile
    README.md
    **/obj/
    **/bin/
    

    PHP

    # Use the official PHP 7.2 image.
    # https://hub.docker.com/_/php
    FROM php:7.2-apache
    
    # Copy local code to the container image.
    COPY index.php /var/www/html/
    
    # Use port 8080 in Apache configuration files.
    RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
    
    # Configure PHP for development.
    # Switch to the production php.ini for production operations.
    # RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
    # https://hub.docker.com/_/php#configuration
    RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
    

    ローカル ファイルがコンテナのビルドプロセスに影響しないように、.dockerignore ファイルを追加します。

    Dockerfile
    README.md
    vendor
    

    Ruby

    # Use the official lightweight Ruby image.
    # https://hub.docker.com/_/ruby
    FROM ruby:2.5-slim
    
    # Install production dependencies.
    WORKDIR /usr/src/app
    COPY Gemfile ./
    RUN bundle install
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD ["ruby", "./app.rb"]
    

  2. GCP プロジェクト ID を取得します。

    gcloud config get-value project
    

    Cloud Build を使用してコンテナ イメージを作成します。これは、docker builddocker push を実行する場合と似ていますが、処理は Google Cloud Platform(GCP)で実行されます。PROJECT_ID は GCP ID で置き換えます。

    gcloud builds submit --tag gcr.io/PROJECT_ID/helloworld-gke .
    

    イメージが Container Registry に保存されます。

Kubernetes Engine クラスタの作成

GKE クラスタは、単一の GKE クラスタとして動作する Compute Engine 仮想マシンのマネージド セットです。このチュートリアルでは、単一ノードを使用します。

  1. クラスタを作成します。YOUR_GCP_ZONE は、クラスタをホストする GCP ゾーンで置き換えます。完全なリストについては、地域とリージョンをご覧ください。

    gcloud container clusters create helloworld-gke \
       --num-nodes 1 \
       --enable-basic-auth \
       --issue-client-certificate \
       --zone YOUR_GCP_ZONE
    
  2. クラスタに対するアクセス権があることを確認します。次のコマンドは、コンテナ クラスタ内の稼働中のノードを一覧表示し、ユーザーにアクセス権があることを示します。

    kubectl get nodes
    

    エラーが発生した場合は、Kubernetes トラブルシューティング ガイドをご覧ください。

GKE へのデプロイ

作成した GKE クラスタにアプリをデプロイするには、2 つの Kubernetes オブジェクトが必要です。

  1. アプリを定義する Deployment
  2. アプリへのアクセス方法を定義する Service

アプリをデプロイする

アプリには、ウェブ リクエストを処理するフロントエンド サーバーがあります。deployment.yaml という新しいファイルに、フロントエンドの実行に必要なクラスタ リソースを定義します。これらのリソースは Deployment として記述されます。Deployment を使用して、ReplicaSet とそれに関連するポッドの作成と更新を行います。

  1. 他のファイルと同じディレクトリに deployment.yaml ファイルを作成し、次の内容をコピーします。$GCLOUD_PROJECT は、GCP プロジェクト ID で置き換えます。

    # This file configures the hello-world app which serves public web traffic.
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: helloworld-gke
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: hello
      template:
        metadata:
          labels:
            app: hello
        spec:
          containers:
          - name: hello-app
            # Replace $GCLOUD_PROJECT with your project ID
            image: gcr.io/$GCLOUD_PROJECT/helloworld-gke:latest
            # This app listens on port 8080 for web traffic by default.
            ports:
            - containerPort: 8080
            env:
              - name: PORT
                value: "8080"
    
  2. リソースをクラスタにデプロイします。

    kubectl apply -f deployment.yaml
    
  3. Deployment のステータスを確認します。

    kubectl get deployments
    

    Deployment に、DESIRED ポッドと同じ数の AVAILABLE ポッドが定義されていれば、Deployment は完成です。

    NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    hello-deployment   1         1         1            1           20s
    

    Deployment に間違いがある場合は、kubectl apply -f deployment.yaml を再度実行し、必要な変更を行って Deployment を更新します。

  4. Deployment が完成すると、Deployment によって作成されたポッドが表示されます。

    kubectl get pods
    

Service をデプロイする

Serviceは、一連のポッドに単一のアクセス ポイントを提供します。それぞれのポッドには個別にアクセスできますが、ポッドは一時的なものであるため、確実にアクセスするには Service のアドレスを使う必要があります。Hello World アプリでは、hello Service にロードバランサが定義されています。これにより、単一の IP アドレスから hello-app ポッドにアクセスできるようになります。この Service は、service.yaml ファイルに定義されています。

  1. 他のソースファイルと同じディレクトリに service.yaml ファイルを作成し、次の内容をコピーします。

    # The hello service provides a load-balancing proxy over the hello-app
    # pods. By specifying the type as a 'LoadBalancer', Kubernetes Engine will
    # create an external HTTP load balancer.
    apiVersion: v1
    kind: Service
    metadata:
      name: hello
    spec:
      type: LoadBalancer
      selector:
        app: hello
      ports:
      - port: 80
        targetPort: 8080
    

    ポッドは、ポッドを使用する Service とは別に定義されます。 Kubernetes は、ラベルを使用して Service のポッドを選択します。ラベルを使用すると、1 つの Service で異なるレプリカセットにある複数のポッドに対応することも、複数の Service で 1 つずつのポッドに対応することもできます。

  2. Hello World Service を作成します。

    kubectl apply -f service.yaml
    
  3. Service の外部 IP アドレスを取得します。

    kubectl get services
    

    IP アドレスの割り当てに 60 秒ほどかかることがあります。外部 IP アドレスが、hello Service の EXTERNAL-IP 列に表示されます。

    NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
    hello        LoadBalancer   10.22.222.222   35.111.111.11   80:32341/TCP   1m
    kubernetes   ClusterIP      10.22.222.1     <none>          443/TCP        20m
    

デプロイされたアプリを表示する

GKE で Hello World アプリを実行するために必要なすべてのリソースがデプロイされました。前の手順の外部 IP アドレスを使用して、ウェブブラウザでアプリを読み込み、実行中のアプリを表示します。

# Example cURL call to your running appication on GKE
$ kubectl get service hello \
    -o=custom-columns=NAME:.status.loadBalancer.ingress[*].ip --no-headers
35.111.111.11
$ curl 35.111.111.11
Hello World!

クリーンアップ

このチュートリアルで使用したリソースについて GCP アカウントに課金されないようにするには:

クラスタで実行される Compute Engine インスタンスContainer Registry のコンテナ イメージは課金対象です。

プロジェクトの削除

GCP プロジェクトを削除すると、そのプロジェクト内で使用されているすべてのリソースに対する課金が停止します。

  1. GCP Console で [プロジェクト] ページに移動します。

    プロジェクト ページに移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

クラスタとコンテナの削除

プロジェクトを削除せず、このチュートリアルで使用したリソースのみを削除する場合は、クラスタとイメージを削除します。

gcloud コマンドライン ツールを使用してクラスタを削除するには、次のコマンドを実行します。

gcloud container clusters delete helloworld-gke

Container Registry リポジトリからイメージを削除するには、次のコマンドを実行します。

gcloud container images delete gcr.io/[PROJECT-ID]/helloworld-gke

次のステップ

Kubernetes の詳細については、次をご覧ください。

GKE へのデプロイの詳細については、次をご覧ください。

Cloud Code を使用して IDE から直接 GKE にデプロイする方法については、次をご覧ください。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Kubernetes Engine のドキュメント