Sep 23, 2019
Jan 1, 1970
N/A Views
MD
warning
この記事は2年以上前に更新されたものです。情報が古くなっている可能性があります。

これまでにServiceによるロードバランシングは見てきましたが、Serviceは現時点ではL4 LoadBalancer相当であり、
HTTPヘッダーなどは考慮されません。TLS TerminationもServiceレベルでは行えないため、Podまたは外部LoadBalancer単位で行う必要があります。

また外部に公開するアプリケーションに対して、type=LoadBalancerなServiceを一つ一つ用意すると、Serviceの分だけLoadBalancerのコストがかかります。

image

このような課題に対して、IngressはService前のL7レベル LoadBalancer相当の機能を提供します。

IngressはServiceに対するHost名ベースまたはパスベースのルーティングを提供します。外部LoadBalancerはIngress (Controller)に対してルーティングすれば複数のLoadBalancerを用意する必要はありません。
またTLS Terminationを行うこともできます。

image

IngressはKubernetesのリソースであり、このリソースを以ってServiceへのルーティングを定義できます。
Ingreeリソースを使用するにはIngress Controllerを用意することが必要です。Ingress ControllerはPodとしてデプロイ可能です。

Ingress Controller自体はAPI仕様であり、Ingress Controllerの実装としては

などが有名です。

本ドキュメントではIaaSに依らずに使用できるContourを使用します。

目次

Contourのインストール

次のコマンドを実行してください。

kubectl apply -f https://raw.githubusercontent.com/projectcontour/contour/release-0.15/examples/render/deployment-rbac.yaml

デフォルトでtype: LoadBalancerなServiceが作成されます。type: NodePortを使用したい場合は次のコマンドを実行してください。

curl https://raw.githubusercontent.com/projectcontour/contour/release-0.15/examples/render/deployment-rbac.yaml | sed 's/LoadBalancer/NodePort/' | kubectl apply -f -
kubectl get -n heptio-contour all

出力結果

NAME                           READY   STATUS    RESTARTS   AGE
pod/contour-596f4bf6c4-48fs7   2/2     Running   0          13m
pod/contour-596f4bf6c4-ztmrc   2/2     Running   0          13m

NAME              TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
service/contour   NodePort   10.100.200.168   <none>        80:31005/TCP,443:31353/TCP   13m

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/contour   2/2     2            2           13m

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/contour-596f4bf6c4   2         2         2       13m

Ingressリソースの作成

hello-pksアプリのデプロイとそのアプリにhello-pks.example.comでアクセスするためのIngressリソースを作成します。

kind: Service
apiVersion: v1
metadata:
  name: hello-pks
spec:
  type: ClusterIP
  selector:
    app: hello-pks
  ports:
  - protocol: TCP
    port: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-pks
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-pks
  template:
    metadata:
      labels:
        app: hello-pks
    spec:
      containers:
      - image: making/hello-pks:0.0.2
        name: hello-pks
        ports:
        - containerPort: 8080
        env:
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: NODE_IP
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-pks
  annotations:
    kubernetes.io/ingress.class: contour
spec:
  rules:
  - host: hello-pks.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-pks
          servicePort: 8080

ここではtype: ClusterIPServiceリソースを作成するので、このままではクラスタ外から直接アクセスできません。
Ingressリソースを作成し、Hostヘッダがhello-pks.example.comの場合にhello-pksサービスにルーティングされるようにします。

kubernetes.io/ingress.classアノテーションはIngress Controllerが複数インストールされている場合は必須です。一つしかインストールされていない場合は不要です。

次のコマンドで作成されたリソースを確認してください。

kubectl get pod,service,ingress

出力結果

NAME                             READY   STATUS    RESTARTS   AGE
pod/hello-pks-7f897d97b9-g8tlp   1/1     Running   0          24m
pod/hello-pks-7f897d97b9-tbr7t   1/1     Running   0          24m

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/hello-pks    ClusterIP   10.100.200.179   <none>        8080/TCP   24m
service/kubernetes   ClusterIP   10.100.200.1     <none>        443/TCP    45d

NAME                           HOSTS                   ADDRESS   PORTS   AGE
ingress.extensions/hello-pks   hello-pks.example.com             80      24m

次のコマンドでアプリケーションにアクセスしてください。

curl http://<contour ServiceのExternal-IP>:80  -v -H "Host: hello-pks.example.com"

type: NodePortを使用している場合は、次のコマンドを実行してください。

curl http://<Worker NodeのIP>:<contour Serviceの80ポートに対するnodePort>  -v -H "Host: hello-pks.example.com"

出力結果

> GET / HTTP/1.1
> Host: hello-pks.example.com
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< content-type: application/json;charset=UTF-8
< x-envoy-upstream-service-time: 7
< date: Sun, 29 Sep 2019 16:50:48 GMT
< server: envoy
< transfer-encoding: chunked
< 
{
  "node" : {
    "NODE_IP" : "192.168.3.21",
    "NODE_NAME" : "093a9c8b-0827-41b2-bc12-e129f2c33833"
  },
  "pod" : {
    "POD_IP" : "10.200.33.56",
    "POD_NAME" : "hello-pks-7f897d97b9-g8tlp",
    "POD_NAMESPACE" : "default"
  },
  "container" : { }
}

Contourの場合はIngressリソースの代わりにIngressRouteカスタムリソースを使用することもできます。

IngressRouteリソースはContour独自ですが、Ingressよりも高度な設定ができます。

TLS終端の有効化

次にTLSを有効にします。

5. ConfigMap/Secretで設定情報の管理で作成したようにgen_ssl_certs.shでTLS証明書を作成します。

gen_ssl_certs.shをダウンロードしていない場合は次のコマンドで取得してください。

wget https://raw.githubusercontent.com/aws-quickstart/quickstart-pivotal-cloudfoundry/master/scripts/gen_ssl_certs.sh
chmod +x gen_ssl_certs.sh 

*.example.comに対する証明書を作成します。

./gen_ssl_certs.sh example.com

次のコマンドでこの証明書に対するSecretリソースを作成するYAMLを生成します。

kubectl create secret tls hello-pks-tls \
  --cert=example.com.crt \
  --key=example.com.key \
  --dry-run -o yaml > hello-pks-tls.yml

hello-pks.ymlを次のように変更してください。

kind: Service
apiVersion: v1
metadata:
  name: hello-pks
spec:
  type: ClusterIP
  selector:
    app: hello-pks
  ports:
  - protocol: TCP
    port: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-pks
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-pks
  template:
    metadata:
      labels:
        app: hello-pks
    spec:
      containers:
      - image: making/hello-pks:0.0.2
        name: hello-pks
        ports:
        - containerPort: 8080
        env:
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: NODE_IP
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-pks
  annotations:
    kubernetes.io/ingress.class: contour
spec:
  rules:
  - host: hello-pks.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-pks
          servicePort: 8080
  tls: # ここを追加
  - hosts:
    - hello-pks.example.com
    secretName: hello-pks-tls

次のコマンドで変更を反映します。

kubectl apply -f hello-pks.yml -f hello-pks-tls.yml

次のコマンドでIngressリソースを確認します。

kubectl get ingress

PORTS列に443が追加されたことを確認してください。

NAME        HOSTS                   ADDRESS   PORTS     AGE
hello-pks   hello-pks.example.com             80, 443   33m

/etc/hostsに次の行を追加してください。

<Worker NodeのIPまたはExternal IP>	hello-pks.example.com

次のコマンドでアプリケーションにアクセスしてください。

curl https://hello-pks.example.com:443 -k  -v 

type: NodePortを使用している場合は、次のコマンドを実行してください。

curl https://hello-pks.example.com:<contour Serviceの443ポートに対するnodePort> -k  -v 

実行結果

> GET / HTTP/2
> Host: hello-pks.example.com:31353
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/2 200 
< content-type: application/json;charset=UTF-8
< x-envoy-upstream-service-time: 10
< date: Sun, 29 Sep 2019 17:12:06 GMT
< server: envoy
< 
{
  "node" : {
    "NODE_IP" : "192.168.3.21",
    "NODE_NAME" : "093a9c8b-0827-41b2-bc12-e129f2c33833"
  },
  "pod" : {
    "POD_IP" : "10.200.33.56",
    "POD_NAME" : "hello-pks-7f897d97b9-g8tlp",
    "POD_NAMESPACE" : "default"
  },
  "container" : { }
}

TLS終端をIngress Controllerで行うことで、アプリケーション側では特にTLSの設定をすることなく、HTTPSでアクセスできるようになりました。

Found a mistake? Update the entry.
Share this article: