GKEでHTTP Load Balancerを使う


この記事は[Google Cloud Platform Advent Calender 2015](http://qiita.com/advent-calendar/2015/gcp)の12月5日分の記事です

皆さんこんばんは。
Google Container Engine(GKE)使ってますか！？
と、いろいろなところで聞いていますが全く手が上がりません。
しかし、使いはじめると必ず「あれ？GKEとHTTP LB連携ってどうやって使うんだ？」という疑問が出てくることでしょう。今回はその先取りです。

というわけで、今回はGKEでHTTP Load Balancer(HTTP LB)を使う方法についてステップバイステップで解説していきたいと思います。
ただし、ここらへんはバージョンアップがとても早いので、常に最新の文章を見るようにしてください。

##そもそも[GKE|HTTP LB]って？

GKEは、簡単に言ってしまえば、マネージドなKubernetesを提供するGoogle Cloud Platform(GCP)のサービス群の1つのことです。今回はKubernetesについての解説はしません。（それだけで5記事ぐらい書けそう）

HTTP LBは、GCPで提供されているロードバランサーのサービスの1つです。GCPにはNetwork Load BalancerとHTTP Load Balancerがあります。Network LBは[L4](http://www.sophia-it.com/content/%E3%83%AC%E3%82%A4%E3%83%A44), HTTP LBは[L7](http://www.sophia-it.com/content/%E3%83%AC%E3%82%A4%E3%83%A47)で動いています。
HTTP LBはとても強力な機能をいくつか持っており、それらに関しては[ここらへん](http://qiita.com/kazunori279/items/8d2417c8510021c697e7)が詳しいです。

###GKEでHTTP LBを使いたいと思うモチベーション

私の場合、そのモチベーションは2つほどありました。

####HTTPS、HTTP/2対応

HTTP LBには、HTTPSをHTTPになおして下流に流したり、HTTP/2をHTTP/1.1になおして下流に流したりという機能があり、しかも特別に設定することといえば証明書ぐらいです。特にHTTP/2は、これだけでは本当の意味で対応したとは言いがたいですが、やる価値はあるでしょう。

####Content-based Load Balancingを使いたい

GCPではUrlMapと呼ばれるリソースを設定すると、どのパスでアクセスされたら、どのBackend Serviceを利用するか、ということが設定できます。
例えば、`http://example.com/api/*`アクセスしたら、APIを提供しているバックエンド、`http://example.com/admin/*`だったら内部用のバックエンド、それ以外(`http://example.com/*`)だったらフロントエンド用のバックエンド、といった具合です。
この要領で、このURLだったらこのpodにアクセスする、というようにLBを使いたくなります。特に、Microserviceな感じでサービスを作成する場合、かなり便利です。

##GKEとHTTP LBを連携させてみる

###前提条件

今回は、3つのGCEインスタンスでクラスタを組み、[pod](http://kubernetes.io/v1.1/docs/user-guide/pods.html)は[Replication Controller](http://kubernetes.io/v1.1/docs/user-guide/replication-controller.html)で作成・管理する想定です。
今回使用する[Replication Controller](http://kubernetes.io/v1.1/docs/user-guide/replication-controller.html)と[Service](http://kubernetes.io/v1.1/docs/user-guide/services.html)を設定するファイルはこのような感じです。

```frontend-replication-controller.yml
apiVersion: v1
kind: ReplicationController
metadata:
   name: frontend
   labels:
      name: frontend
spec:
   replicas: 3
   selector:
      name: frontend
   template:
      metadata:
         labels:
            name: frontend
      spec:
         containers:
         - name: frontend
           image: asia.gcr.io/project/frontend
           ports:
           - containerPort: 80
             protocol: TCP
```

```frontend-service.yml
apiVersion: v1
kind: Service
metadata:
   name: frontend
   labels:
      name: frontend
spec:
   ports:
      port: 8000
      targetPort 80
      protocol: TCP
      nodePort: 30062
   type: NodePort
   selector:
      name: frontend
```

そして、作成するクラスタ名やどこのゾーンに作るかなどは環境変数に入れておきます。

```
$ export CLUSTER_NAME="kuma-project"
$ export ZONE="asia-east1-a"
```

また、gcloudなどは予め使えるようにしておきましょう。
[ここ](https://cloud.google.com/sdk/)を読めば詳細がわかりますが、LinuxやMacだと、基本的には

```
$ curl https://sdk.cloud.google.com | bash
```

でセットアップが終わるかと思います。

###1: クラスタを作成する

```
$ gcloud container clusters create $CLUSTER_NAME --zone $ZONE
```

###2: Replication ControllerとServiceを作成する

```
$ kubectl create -f frontend-replication-controller.yml
$ kubectl create -f frontend-service.yml
```

ちゃんとそれぞれ作成されたか確認して見ましょう。

```
$ kubectl get pods
NAME                                                 READY     STATUS    RESTARTS   AGE
frontend-xxxxx                                       1/1       Running   0          1m
frontend-yyyyy                                       1/1       Running   0          1m
frontend-zzzzz                                       1/1       Running   0          1m
```

```
$ kubectl get services
NAME           CLUSTER_IP       EXTERNAL_IP   PORT(S)    SELECTOR            AGE
frontend       10.xx.xx.xx     nodes         8000/TCP   name=frontend       1m
kubernetes     10.xx.xx.xx     <none>        443/TCP    <none>              3m
```

###3: HTTP healthcheckを作成する

HTTP LB用に、今回作ったpodsのhealthcheckの設定を作成します

```
$ gcloud compute http-health-checks create http-basic-check-30062 --port 30062
```

ポートは`frontend-service.yml`でしているnodeportである`30062`を指定します。

###3.5:クラスターのtagとグループ名を確認する

クラスタが組まれたら、そのクラスタには特有のtagと、自動的にインスタンスグループが作成されています。それらの名前を調べて環境変数に入れておきましょう。GUIでも見れますが、コマンドでも簡単にできます。

```
$ export TAG=$(basename `gcloud container clusters describe ${CLUSTER_NAME} --zone ${ZONE} | grep gke | awk '{print $2}'` | sed -e s/group/node/)
$ export GROUP_NAME=$(basename `gcloud container clusters describe $CLUSTER_NAME --zone $ZONE | grep gke | awk '{print $2}'`)
```


###4: ファイアーウォールのルールを作成する

LBがアクセスできるようにファイアーウォールのルールを作成しましょう


```
$ gcloud compute firewall-rules create frontend-pods-30062 --source-ranges 130.211.0.0/22 --allow=tcp:30062 --target-tags $TAG
```

###5: インスタンスグループにNamed Port追加する

```
$ gcloud compute instance-groups managed set-named-ports $GROUP_NAME --named-ports http:30062 --zone $ZONE
```

###6: インスタンスグループをバックエンドサービスとしてLB
に登録する

```
gcloud compute backend-services create web-map-backend-service --protocol HTTP --port-name http --http-health-check http-basic-check-30062
```

今回、frontendはHTTPSの対応はしていないのでプロトコルはHTTPを選択します。また、ヘルスチェックを行う設定は、3で作ったものを指定します。

###7: 登録したバックエンドサービスを使用可能にする

```
gcloud compute backend-services add-backend web-map-backend-service --balancing-mode UTILIZATION --max-utilization 0.8 --capacity-scaler 1 --instance-group $GROUP_NAME --zone $ZONE
```

###8: UrlMapを作成する

```
$ gcloud compute url-maps create web-map --default-service web-map-backend-service
```

今回はバックエンドサービスはこれしか登録しないため、上記のようになりますが、バックエンドサービスが複数ある場合は適所登録してください。

###9: LBのプロキシを作成する

```
$ gcloud compute target-http-proxies create http-lb-proxy --url-map web-map
```

###10: 作成したプロキシに対してフォワードルールを作成する

```
$ gcloud compute forwarding-rules create http-content-rule --global --target-http-proxy http-lb-proxy --port-range 80
```

##まとめ

いかがだったでしょうか。おそらく、HTTP LB、GKEとの組み合わせになるため、それぞれを多少使ってみないとイメージがつかないかもしれませんが、これらを組み合わせることで、特にMicroserviceな構成のサービスは格段に作りやすく、管理・運用・拡張性が高いものになるかと思います。
もしかしたら、手順5からはGUI（マネジメントコンソール）で行ったほうがイメージが付くかもしれません。要望があれば、そちらの方も作成したいかと思います。


#参考文献

https://cloud.google.com/container-engine/docs/tutorials/http-balancer