legacyシステムからGoogle Cloudへの道のり

GYAOのtsです。
我々のチームは、オールパブリッククラウドで、[Microservice Architecture](http://microservices.io/patterns/microservices.html)を採用した次期バックエンドを設計中です。

# 経緯

今回も[前回](http://qiita.com/tstakano-yj/items/ae9307704d2356d40158)と同じ少し脱線です。

ある大企業の話だがコンテナ技術や、仮想化技術を完全にオンプレミスで使用しているが、
かなり独自拡張もされており、使いにくく保守もしにくい状況。且つ、申請ベースな部分が細かく残っており、何か「ものづくり」をする際に結構な時間を要する。正確には時間を要すると言うよりかは、手順が多くて面倒くさい。


下記は何かシステムを作るときのざっくりとした例だが


ポート開放依頼・・・事前に登録依頼（依頼自体は10分くらい）
DNS登録依頼・・・事前に登録依頼（依頼自体は10分くらい）
アプリケーションアカウント作ってシステムに登録しておく・・・5分くらい
社内ネットワークからのみアクセス可能な仮想サーバーの調達（例えば3インスタンスGUIでポチポチっと）・・・10分くらいかな
LBの設定・・・GUIで10分くらいかな
Gateway申請（外→内）・・・下手すると1週間。早くて3日
Gateway申請（内→外）・・・アクセスするDNSやipをホワイトリスト化して登録。3日くらいはかかる。どこにでもアクセスできるようにすれば早い、その際は1日くらいか
計 4営業日〜6営業日と45分


こうしてみるとGatewayだけ解決すればいいように見えるが、
申請が結構あるため、各種申請の状況を掌握しておかないといけない。それがコスト。
それに加えて、上記の申請自体やルール、申請ツールがコロコロ変わったりする。現状の最新の社内ツールやレギュレーションをキャッチアップしておかなければいけない。部署によっては、それらをまとめるチームを作ったりしている。。。


加えて、社内に便利であろうプラットフォーム（例えば画像入稿PFや検索PF）が数多くあるのだが、PFのバージョンアップの際、必ずこちら側（使用者側）に対応を強いる。
更にOpenSSLの脆弱性等の対応も全て行うので、
一般的なエンジニアは


脆弱性の対応 ＋ 社内PFのバージョンアップ対応 ＋ 社内申請


をずっと回しているエンジニアリングライフサイクルになる。


よって上記のみができるエンジニアが育ちやすい。
なので転職すると転職先で使い物にならなくて意気消沈するエンジニアが結構見受けられたりする。


まぁ。。。何が言いたいかというと、

「オープンな技術を使って普通に世の中のスタートアップのように開発してかないと、オープンな経験は積めないよ。」というだけなのだが。。。

その思想に基づきお話します。

# そこで

社内技術者向けに簡単にクラウド上にサービスを構築・運用してみようと思えるような、わかりやすいドキュメントを書いてみようかと。
今回はGoogle Cloud（GKE）を使用する。

## Stateless Service と Stateful Service

GKEはDockerコンテナの管理にkubernetes（以下、k8s）を使用しているわけだが、
k8s上でApacheやnginx等、データを共通で保持しないでStatelessなシステム運用をする場合はいいのだが、OSSのアプリケーションサーバーをAPIサーバーとしてクラスタリングをするとか、例えば永続化層等、共通でデータを保持するシステムの場合、podが内部処理の途中でRollingUpdateされたり消されたり作られたりすると不整合が生じる。

我々のチームもどうしようか迷って、2016年にGoogleの方と話したのだが、そういう用途には適さないので、その際はPet-sets（現在はStatefulSets）を使用してくださいと言っていました。なんか、イレギュラーだね的な感じでした。

* [GCP NEXT 2016のlog](https://prezi.com/khuku0k578q1/gcp-next-201696/)（prezi）

社内で、クラスタリング等を行っている事例をあまり聞かないので、今回はStatelessサービスに絞って進めます。

## 概要
以下のようなシステム構成のアプリケーションを作成することを目的とする。
ただのnginxの3台構成。
![export (1).png](https://qiita-image-store.s3.amazonaws.com/0/114329/a82b1ae9-8439-5d5c-2f3c-84669c4cb0c7.png)

これをk8s上で構築すると以下のような形になる。
![export (2).png](https://qiita-image-store.s3.amazonaws.com/0/114329/0ae09c6e-df1b-fc21-8a52-ca745d8bdede.png)


## 用語

| name | detail |
|:--|:--|
|nginx container|nginxのコンテナ。コンテナイメージは今回はDockerhubから持ってくる。（GoogleCloudRepositoryに登録し、そこから引っ張ってくるようにすることも可能。）|
|pod（nginx）|containerの集合体。k8sではこの単位でスケールアウトしたりして、アプリケーションを管理する。|
|kube-proxy|yamlに書かれた通り（設定されたとおり）TCPとUDPをPodに転送するプロキシ。serviceからつながるのはこれのおかげ。|
|serivice（nginx-service）|ポッドに通信するネットワーク外からのエンドポイント。今回は、ReplicationControllerでpodを冗長構成で作成するので、そこに向けての入り口となる。|
|node|コンテナ（pod）が立ち上がる環境。GKEの場合、GCPのvmインスタンスがこれに当たる。 |
|node-pool|クラスタを作成すると、設定したnode分のvmインスタンスが立ち上がり、default-poolというnode-poolが割り当てられる。このnode-pool上にpodを配備していくイメージ。よって、図のように1vmインスタンスに対して1podとなるわけではない。|
|kube-ui|状態を見れるui|
|k8s Master|k8sは1マスター、nレプリケーション構成だが、GKEはmasterが隠蔽される。|
|k8s API Server|masterのAPI。中央集権的に各node、podsを管理できる。クラウドシェルからkubectlコマンドを打つとこのAPI→kubelet経由でコンテナを立ち上げたりする。|
|kubelet|yamlに書かれたPodの情報と設定をもとにコンテナを立ち上げます。|

## 実際に作成してみる
それでは実際に作成してみよう。

### yamlの準備

```yaml:nginx_pod.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
```
```yaml:nginx_service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    name: nginxservice
  name: nginxservice
spec:
  ports:
    - port: 80
      targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
```

### クラスタの作成
クラウドシェルから実行
<img width="240" alt="スクリーンショット 2017-02-28 16.29.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/4b542c66-4826-f68f-e1f7-8d4eab0182a8.png">

```bash:クラスタ作成
gcloud container clusters create "nginx-asia"  --num-nodes 2 --zone "asia-east1-a" --machine-type "n1-standard-2"  --scopes "compute-rw","storage-ro","bigquery","logging-write","monitoring"
```

<img width="857" alt="スクリーンショット 2017-02-28 16.36.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/b984a87b-8227-e8c1-9e03-9deb74b6804e.png">

### pod、serviceの作成

```bash:pod&service
//pod
kubectl create -f nginx_pod.yaml

//確認
kubectl get pods

NAME          READY     STATUS    RESTARTS   AGE
nginx-6wtxj   1/1       Running   0          47s
nginx-rtj4f   1/1       Running   0          47s

//service
kubectl create -f nginx_service.yaml

//確認
kubectl get service

NAME           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes     10.3.240.1     <none>        443/TCP        29m
nginxservice   10.3.242.169   <pending>     80:30823/TCP   10s

```

そのうちserviceが以下のようにEXTERNAL-IPが発行された状態になる。

```
NAME           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
kubernetes     10.3.240.1     <none>           443/TCP        31m
nginxservice   10.3.242.169   104.155.212.***   80:30823/TCP   2m
```

### アクセス
EXTERNAL-IP:80でアクセス可能
<img width="607" alt="スクリーンショット 2017-02-28 17.11.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/c0775001-f34b-9781-bf82-a87be8a855c4.png">

2 pod構成のnginxのfrontendが構築できた。

### スケールアウト

```
//現状の確認
kubectl get rc

NAME      DESIRED   CURRENT   READY     AGE
nginx     2         2         2         43m

//4nodesにスケールアウト
kubectl scale rc nginx --replicas=4

kubectl get pod
NAME          READY     STATUS    RESTARTS   AGE
nginx-6wtxj   1/1       Running   0          44m
nginx-98h46   1/1       Running   0          12s
nginx-pcmm2   1/1       Running   0          12s
nginx-rtj4f   1/1       Running   0          44m
```

さらに　**閾値を決めて、それ以上の負荷が来た際にオートスケールする様に設定も可能。**
kube-uiやオートスケールに関してはまた今度かこうかな。
それでは。