GKEで複数コンテナのアプリケーションを動かす

(2016-08-26)

前回は単一コンテナのアプリケーションを動かしたが、今回はコンテナ間でやり取りが発生するものを動かす。 流れとしては、クライアントからのリクエストをGATEWAYサーバーで受け取り、SERVICEサーバーにリクエストし、その結果を返すまで。

プログラムは以下の通り、環境変数TYPEの値によって挙動を変えていて、同じイメージを使い回す。コードはここ

var http = require('http');
var handleRequest = function(request, response) {
  if(process.env.TYPE == "GATEWAY"){
    console.log('Passed.');
    var options = {
      host: 'service',
      port: 8080,
      method: 'GET'
    };
    var req = http.request(options, function(res) {
      data = ""
      res.on('data', function (chunk) {
        data+=chunk;
      });

      res.on('end', () => {
        response.writeHead(200);
        response.end(data);
      });
    });
    req.on('error', function(e) {
      response.writeHead(500)
      response.end(e.message);
    });
    req.end();
  }else{
    console.log('Received.');
    response.writeHead(200);
    response.end('ok');
  }
};
var www = http.createServer(handleRequest);
www.listen(8080);

これをContainer RegistryにPushする。

$ export PROJECT_ID="gcp-test-141011"
$ docker build -t gcr.io/$PROJECT_ID/multitest:v1 .
$ gcloud docker push gcr.io/$PROJECT_ID/multitest:v1

ローカルで試すためにminikubeを起動。コンテキストがminikubeに設定される。

$ minikube start
$ kubectl config current-context
minikube

minikubeでContainer Registryから取得できるようにsecretを作成する。

$ kubectl create secret docker-registry myregistrykey --docker-server=https://gcr.io --docker-username=oauth2accesstoken --docker-password="$(gcloud auth print-access-token)" --docker-email=***

まず、以下のservice_deployment.yamlでDeploymentを作成する。 envのところで環境変数TYPESERVICEに設定した。 また、先ほど作成したsecretをimagePullSecretsで指定し、 ローカルのminikube環境でContainer Registryから取得できるようにしている。 同様にgateway_deployment.yamlでも作成する。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: service
  labels:
    app: service
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: service
    spec:
      containers:
      - name: service
        image: gcr.io/gcp-test-141011/multitest:v1
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        env:
        - name: TYPE
          value: SERVICE
        ports:
        - containerPort: 8080
      imagePullSecrets:
      - name: myregistrykey    
$ kubectl create -f service_deployment.yaml
$ kubectl create -f gateway_deployment.yaml
$ kubectl get deployment
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
gateway   1         1         1            1           8m
service   1         1         1            1           28m

次に、これを内部から呼べるようにするためのServiceを作成する。

apiVersion: v1
kind: Service
metadata:
  name: service
  labels:
    app: service
spec:
  ports:
  - port: 8080
  selector:
    app: service

GATEWAYの方は外に開くので、EXTERNAL IPが割り当てられるようにする。 ただ、minikubeではtype: LoadBalancerに対応していないので代わりにtype: NodePortを指定する。

apiVersion: v1
kind: Service
metadata:
  name: gateway
  labels:
    app: gateway
spec:
  # type: LoadBalancer
  type: NodePort
  ports:
  - port: 8080
    nodePort: 30002
  selector:
    app: gateway
$ kubectl create -f service_service.yaml
$ kubectl create -f gateway_service.yaml
$ kubectl get services
NAME            CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
gateway         10.0.0.176   <nodes>       8080/TCP   1h
service         10.0.0.111   <none>        8080/TCP   2d

GATEWAYサーバーを越えてSERVICEサーバーまで到達したことが確認できた。

$ curl 192.168.99.100:30002
ok

$ kubectl get pods
NAME                       READY     STATUS    RESTARTS   AGE
gateway-3043515563-a0tb5   1/1       Running   0          38m
service-2727435432-9glvb   1/1       Running   0          38m

$ kubectl logs service-2727435432-9glvb
Received.

一通り動いたのでこんなシェルスクリプトを書いた。

#!/bin/bash

context=`kubectl config current-context`
echo "${context}で実行します。よろしいですか[Y/N]"
read ANSWER
case $ANSWER in
    "Y" ) :;;
    * ) exit;;
esac
if [ $context = "minikube" ] ; then
  kubectl create -f yaml/gateway_service_minikube.yaml
  kubectl create -f yaml/service_deployment_minikube.yaml
  kubectl create -f yaml/gateway_deployment_minikube.yaml
else
  kubectl create -f yaml/gateway_service.yaml
  kubectl create -f yaml/service_deployment.yaml
  kubectl create -f yaml/gateway_deployment.yaml
fi
kubectl create -f yaml/service_service.yaml

これを実行するとこうなる。

$ gcloud container clusters create multi-container-app
$ kubectl config current-context
gke_gcp-test-141011_asia-east1-b_multi-container-app

$ sh create.sh
gke_gcp-test-141011_asia-east1-b_multi-container-appで実行します。よろしいですか[Y/N]
Y
service "gateway" created
deployment "service" created
deployment "gateway" created
service "service" created

$ kubectl get service
NAME         CLUSTER-IP      EXTERNAL-IP       PORT(S)    AGE
gateway      10.83.254.5     104.199.206.147   8080/TCP   4m
service      10.83.255.118   <none>            8080/TCP   4m

$ curl 104.199.206.147:8080
ok