at kaneshin

Free space for me.

GKE を使って golang アプリケーションコンテナを稼働させる

f:id:laplus-knsn:20161215015401p:plain

この記事は Google Cloud Platform(1) Advent Calendar 2016 の15日目の記事です。

普段は golang をやってるアプリケーションの人っぽい感じになっていますが、他にも色々とやっています。(と、いうアピールをたまにしておかないと) さて、今回は GKE + golang のデプロイ話でもしましょう。結局、golang が絡んでいますね。

準備

Docker をインストールしておき、使用できるようにしましょう。

コンテナイメージの作成・プッシュ

f:id:laplus-knsn:20161215020441p:plain

プロジェクト構成は下記のようにし、docker ビルドしたイメージを Container Registry にプッシュするようにします。

helloworld/
├── deployment.yaml
├── Dockerfile
├── main.go
└── service.yaml

main.go

アプリケーションコードはとてもシンプルに、8080番ポートで構えるサーバーを用意し、アクセスがあったときに "Hello world!" と表示するアプリケーションを用意します。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello world!")
    })

    log.Fatal(http.ListenAndServe(":8080", nil))
}

動作確認するには go run してビルド・起動し、 curl などで叩いてみてください。

# 実行
$ go run main.go

# 確認
$ curl -XGET localhost:8080
Hello world!

Dockerfile

golang をビルドするイメージが公開されているので、そのイメージを使用します。

FROM golang:1.7.4-onbuild

Docker ビルド・実行

main.go と Dockerfile が用意できたら実際にイメージをビルド・実行してみます。

# ビルド
$ docker build -t hello-container .

# 実行
$ docker run -p 8080:8080 hello-container

# 確認
$ curl -XGET localhost:8080
Hello world!

ビルドや実行で使用している hello-container はコンテナイメージへのタグです。

Container Registry にプッシュ

先ほど作成したコンテナイメージを Google Container Registry にプッシュします。先ほど作成したタグにエイリアスを張っておきます。

$ docker tag hello-container asia.gcr.io/[YOUR_PROJECT_ID]/helloworld

asia.gcr.io の部分はホスト先を指定することが可能です。

Registry Host Region
us.gcr.io US
es.gcr.io EU
asia.gcr.io ASIA
gcr.io US (unfixed)

あと、わざわざエイリアスを張らずに、直接レジストリの命名でタグを作成しても大丈夫です。 Google Container Registry 用にエイリアス・タグを作成したらプッシュします。

$ gcloud docker push asia.gcr.io/[YOUR_PROJECT_ID]/helloworld

[YOUR_PROJECT_ID] は GCP の Project ID を指定するようにしてください。


ここまで作成できたらコンテナイメージ作成については完了です。

Container Engine クラスタの作成

デプロイ先となるクラスタの作成を行います。コンソールから作成もできますし、コマンドからも作成が可能です。 お試しで試してみるなら Cloud Shell をオススメします。

f:id:laplus-knsn:20161215012952p:plain

クラスタ作成

今回は gcloud コマンドから作成します。

$ gcloud container clusters create helloworld --zone asia-northeast1-c \
  --scopes cloud-platform \
  --num-nodes 2

scopes オプションはアプリケーションの必要に応じて datastore や bigquery のスコープも --scopes cloud-platform,datastore,bigquery のように増やしてください。

f:id:laplus-knsn:20161215013439p:plain

クラスタの認証

gcloud コマンドで認証を行うために、作成したクラスタの認証から行います。

$ gcloud container clusters get-credentials helloworld --zone asia-northeast1-c

Fetching cluster endpoint and auth data. kubeconfig entry generated for helloworld.

が出力されればOK。

クラスタの確認

問題なく作成されたか確認してみます。

$ kubectl cluster-info
Kubernetes master is running at https://xxx.xxx.xxx.xxx
GLBCDefaultBackend is running at https://xxx.xxx.xxx.xxx/api/v1/proxy/namespaces/kube-system/services/default-http-backend
Heapster is running at https://xxx.xxx.xxx.xxx/api/v1/proxy/namespaces/kube-system/services/heapster
KubeDNS is running at https://xxx.xxx.xxx.xxx/api/v1/proxy/namespaces/kube-system/services/kube-dns
kubernetes-dashboard is running at https://xxx.xxx.xxx.xxx/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard

デプロイ

コンテナイメージ化されたアプリケーションをデプロイするためクラスタのレプリカセットとサービスの作成を行います。

Deployment

deployment.yaml という命名で下記のような Yaml ファイルを用意し、 kubectl コマンドを使用してレプリカセットを作成します。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: helloworld
  labels:
    app: helloworld
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: helloworld
    spec:
      containers:
      - name: helloworld-app
        image: us.gcr.io/[YOUR_PROJECT_ID]/hello-golang:latest
        imagePullPolicy: Always
        ports:
        - name: http-server
          containerPort: 8080

continers.image には先ほどプッシュしたコンテナイメージの Registry Host を指定します。ここまでできたら kubectl コマンドを使用します。

$ kubectl create -f deployment.yaml 

レプリカセットの進捗状況は下記で確認がとれます。

$ kubectl get deployments
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
helloworld   3         3         3            3           42m

Service

今度は service.yaml という命名で下記のような Yaml ファイルを用意します。サービスはレプリカセットと一緒に作成されたポッドにアクセスするための定義になります。

apiVersion: v1
kind: Service
metadata:
  name: helloworld
  labels:
    app: helloworld
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: http-server
  selector:
    app: helloworld
$ kubectl create -f service.yaml 

サービスの作成進捗は下記を叩くことでわかりますし、 LoadBalancer Ingress の IP が公開された IP アドレスとなるので、LoadBalancer 作成後、この IP にアクセスすることによって "Hello world!" が表示されるはずです。

$ kubectl describe service helloworld
Name:                   helloworld
Namespace:              default
Labels:                 app=helloworld
Selector:               app=helloworld
Type:                   LoadBalancer
IP:                     xxx.xxx.xxx.xxx
LoadBalancer Ingress:   xxx.xxx.xxx.xxx.
Port:                   <unset> 80/TCP
NodePort:               <unset> 31510/TCP
Endpoints:              xxx.xxx.xxx.xxx:8080,xxx.xxx.xxx.xxx:8080,xxx.xxx.xxx.xxx:8080
Session Affinity:       None
Events:
  FirstSeen     LastSeen        Count   From                    SubobjectPath   Type            Reason                 Message
  ---------     --------        -----   ----                    -------------   --------        ------                 -------
  43m           43m             1       {service-controller }                   Normal          CreatingLoadBalancer   Creating load balancer
  42m           42m             1       {service-controller }                   Normal          CreatedLoadBalancer    Created load balancer

動作検証

ここまでできたら、先ほどの LoadBalancer Ingress にある IP にアクセスして "Hello world!" が表示されることを確認してみましょう。

停止方法

クラスタを削除することによって、ポッドやロードバランサーもあわせて削除されます。超楽。

$ gcloud container clusters delete helloworld --zone asia-northeast1-c
The following clusters will be deleted.
 - [helloworld] in [asia-northeast1-c]

リソース