publish blog on kubernetes with ingress | iii threetreeslight

May 19, 2018

publish blog on kubernetes with ingress

gcs上での展開が完了したのと、gcpでのloadbalancingも含めて大体わかってきたので、このblogをgkeを利用してcotnainer運用してみようと思う

構成

多分こんな感じになるだろうと考えて作業

forwarding rule <-> target proxy <-> url-map <-> backend-service <-> node ip <-> pod

Create blog image

展開するためのcontaienrを作成する。

まずはnginxまわりを設定

nginx.conf

volumeを圧迫しないように、error_log, access_logを /dev つなぎこむ

user  nginx;
worker_processes  1;

error_log  stderr info;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log    /dev/stdout;
    sendfile        on;
    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;
}

blog.conf

8080 portでアクセスを受けるようにする

server {
    listen       8080;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   404              /404.html;
    error_page   500 502 503 504  /50x.html;

    location = /(404|50x).html {
        root   /usr/share/nginx/html;
    }
}

dockerfile

confをcopyしつつ、buildしたblog contatentsを固める

FROM nginx:mainline-alpine

COPY ./public /usr/share/nginx/html
COPY ./nginx/blog.conf.tmpl /etc/nginx/conf.d/default.conf
COPY ./nginx/nginx.conf.tmpl /etc/nginx/nginx.conf

build and publish

docker build -t threetreeslight/blog
docker push threetreelsight/blog

Prepare to use gke

まずkubernetesを操作するためにはkubectlを利用するのでそれを入れる

これはgcp cliを利用していれることができる

# https://kubernetes.io/docs/tasks/tools/install-kubectl/
$ brew install kubectl

また、実際にkubernetesを触ってみるquick start があるので、これを触っておくと良い。

create cluster, pods

blogを公開するためのclusterを作成する

% gcloud container clusters create blog-cluster --no-enable-autorepair
WARNING: Starting in Kubernetes v1.10, new clusters will no longer get compute-rw and storage-ro scopes added to what is specified in --scopes (though the latter will remain included in the default --scopes). To use these scopes, add them explicitly to --scopes. To use the new behavior, set container/new_scopes_behavior property (gcloud config set container/new_scopes_behavior true).
Creating cluster blog-cluster...done.
Created [https://container.googleapis.com/v1/projects/threetreeslight/zones/us-west1-a/clusters/blog-cluster].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-west1-a/blog-cluster?project=threetreeslight
kubeconfig entry generated for blog-cluster.
NAME          LOCATION    MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
blog-cluster  us-west1-a  1.8.10-gke.0    35.199.155.107  n1-standard-1  1.8.10-gke.0  3          RUNNING

clusterの認証情報を渡す

% gcloud container clusters get-credentials blog-cluster
Fetching cluster endpoint and auth data.
kubeconfig entry generated for blog-cluster

これでkubectlの操作を上記で作成したclusterに対して実行できるようになります。

create deployment

続いてdeploymentを作成する。docker-composeやECSでいうtaskが近い。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: blog
  name: blog
  namespace: default
  selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/blog
spec:
  replicas: 1
  selector:
    matchLabels:
      app: blog
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: blog
    spec:
      containers:
      - image: threetreeslight/blog:latest
        imagePullPolicy: Always
        name: blog
        ports:
        - containerPort: 8080
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

上記で作成したdeploymentをkubectlに適用します

% kubectl apply -f blog-pod.yaml
% kubectl get po,deploy
NAME                        READY     STATUS    RESTARTS   AGE
pod/blog-8547868bd8-brpsr   1/1       Running   0          9h

NAME                         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/blog   1         1         1            1           2d

うん、podが1つ稼働していることがわかります。

このdeploymentに対し、外部に公開しアクセスできるようにしてみます。

$ kubectl expose deployment blog --type "LoadBalancer"
$ kubectl get service blog

NAME      TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
blog      LoadBalancer   10.59.242.212   35.233.232.33   80:32439/TCP   52s

上記のようにexternal-ipが割り当てられます。 これはexpose commandを通して公開用loadbalancerが作成されたことがわかります。

なんて便利。

一旦個々まで

アクセスしてみる。loadbalancerで経由でアクセスできることがわかったので一旦削除する

kubectl expose deployment blog --target-port=8080 --type=NodePort

GKEはclusterに直接loadbalancerを接続して公開できるのね

support https

expose type "loadbalancer" では、http forwarding ruleしか作られないことがみるとわかります。

こうするとhttpsでアクセスが出来ません。

loadbalancerにおけるbackend serivceから後ろは以下のような処理になっているイメージです。

backend service <-> cluster_ip:port <-> pods
  1. bakcend serviceによって特定cluster ipの特定port宛に通信がproxyされる
  2. cluster_ip, portの情報を元にkubernetesはどのservice(port)にproxyすればよいか決定される
  3. proxyされた通信はserviceとdyanmic port mappingされたpodsにproxyされる
    1. replicaが2以上のときはどんなルールでproxyされるかはdeploymentに記述できる(と思う)

そのため、あくまでexposeの処理は、cluster_ip:port の割り当てまでに留め、loadbalancerの設定は別で行う必要が考えられます。

ここで必要となってくるのがingressです。

Ingressを利用したloadbalancerの作成

ingressとは?

Ingress は、外部 HTTP(S) トラフィックを内部サービスにルーティングするためのルールと設定の集合をカプセル化する Kubernetes リソースです。

です。

Ingress での HTTP 負荷分散の設定をやっておくと良いです。

まずは、DNS record、およびloadbalancerのエンドポイントとして利用するipを払い出します。

% gcloud compute addresses create blog-gke --global
% gcloud compute addresses list
NAME                          REGION  ADDRESS        STATUS
blog-gke                              35.201.67.24   RESERVED

続いて、blog serviceをnodeport modeでexposeします。

% kubectl expose deployment blog --target-port=8080 --type=NodePort
% kubectl get po,deploy,service
NAME                        READY     STATUS    RESTARTS   AGE
pod/blog-8547868bd8-brpsr   1/1       Running   0          9h

NAME                         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/blog   1         1         1            1           2d

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/blog         NodePort    10.59.253.98   <none>        8080:31453/TCP   10h

clusteripとportの割り当てができている。良い。

続いてingress resourceの作成をします。httpsアクセスをしたいので、登録されているtls証明書を設定します。

blog-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: blog
  annotations:
    kubernetes.io/ingress.global-static-ip-name: blog-gke
spec:
  tls:
  - secretName: threetreeslight-com
  backend:
    serviceName: blog
    servicePort: 8080

適用します

% kubectl apply -f blog-ingress.yaml
% kubectl get ingress blog
NAME      HOSTS     ADDRESS        PORTS     AGE
blog      *         35.201.67.24   80, 443   10h

80, 443 portが公開され、addressも作成たexternal ipが設定されていることがわかります。