仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

Kubernetes Ingressを触ってみた

今日はだいぶ前に宿題となっていたKubernetes Ingress機能を使ってみました。

はじめに

まず、実際に導入する前に、ここら辺の情報を確認しました。

JujuでデプロイしたKubernetesを想定しています。Juju Bundleは以下のものを使いました。はい、そうです。いつも使うやつです。

今回使うJuju BundleでKubernetesをデプロイすると、LoadBalancerとIngressをデフォルトでインストールしてくれます。そのため、Podを作ってPodにServiceを割り当てた後にIngressを適用することで、Kubernetesクラスターの外へアプリケーションを公開できます。

また、永続ストレージを使いたかったので前回取り上げたように「Kubernetes Calico #273」にNFSサーバーを追加してデプロイするようにちょっとだけ手直ししたものを使いました。

tech.virtualtech.jp

先ずはすぐにできるNodePortを使った方法

こんなYAMLを用意しました。

% cat app1.yml
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: app1-claim
spec:
  storageClassName: default
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app1
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
      - name: app1
        image: nginx:alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: "/usr/share/nginx/html/"
          name: app1
      volumes:
      - name: app1
        persistentVolumeClaim:
          claimName: app1-claim
---
apiVersion: v1
kind: Service
metadata:
  name: svc1
  labels:
    app: app1
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: app1
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: svc1
spec:
  rules:
  - host: svc1.cluster.local
    http:
      paths:
      - path: /
        backend:
          serviceName: svc1
          servicePort: 80

Podを作成します。

% kubectl create -f app1.yml
persistentvolumeclaim/app1-claim created
deployment.extensions/app1 created
service/svc1 created
ingress.extensions/svc1 created

PVC,Pod(deployment),Service,Ingressが作成できたことを確認します。

% kubectl get -f app1.yml
NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/app1-claim   Bound    pvc-9e7355d3-1584-11e9-89c0-525400dd100b   1Gi        RWX            default        4m58s

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/app1   2/2     2            2           4m58s

NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/svc1   NodePort   10.152.183.56   <none>        80:31925/TCP   4m57s

NAME                      HOSTS                ADDRESS   PORTS   AGE
ingress.extensions/svc1   svc1.cluster.local             80      4m57s

うまくいったようです。http://kubeapi-load-balancer:NodePortにアクセスできるようにするため、名前解決できるようにします。今回は手っ取り早くクライアントのhostsファイルに追記します。

% sudo sh -c 'echo 172.17.28.40 svc1.cluster.local >> /etc/hosts'

デプロイしたNGINX Webサーバーにコンテンツを追加します。

% kubectl get po |grep app1
app1-848b6ff9d-98s8j                      1/1     Running   0          5m17s
app1-848b6ff9d-fqbd2                      1/1     Running   0          5m17s
(app1のPod一覧を出力)

% kubectl exec -it app1-848b6ff9d-98s8j  -- sh -c 'echo I am app1 server >> /usr/share/nginx/html/index.html'
(どちらかにコンテンツを配置)

% kubectl get -f app1.yml
...
service/svc1   NodePort   10.152.183.56   <none>        80:31925/TCP   4m57s
...
(NodePortを確認)

アクセスしてみます。

% curl http://svc1.cluster.local:31925
I am app1 server

うまくいった模様です。

Ingressはなんとなく使えましたが

ただこれ、NodePortを指定するのが面倒ですよね。そこで次の方法が type: LoadBalancerモードを使う方法です。 オンプレなKubernetesでは type: LoadBalancerモードはデフォルトでは使えませんが、MetalLBを使うと割と簡単に試すことができます。

セットアップ方法については以下の情報が参考になります。

blog.web-apps.tech

Load BalancerモードでIngressを使ってみる

KubernetesにMetalLBを展開できたら、こんなYAMLを書いてみましょう。

% cat app3.yml
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: app3-claim
spec:
  storageClassName: default
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app3
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: app3
    spec:
      containers:
      - name: app3
        image: nginx:alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: "/usr/share/nginx/html/"
          name: app3
      volumes:
      - name: app3
        persistentVolumeClaim:
          claimName: app3-claim
---
apiVersion: v1
kind: Service
metadata:
  name: svc3
  labels:
    app: app3
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: app3
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: svc3
spec:
  rules:
  - host: svc3.cluster.local
    http:
      paths:
      - path: /
        backend:
          serviceName: svc3
          servicePort: 80

app3を展開しましょう。

% kubectl create -f app3.yml

NodePortで試した時とは異なり、app3はサービス「svc3」を割り当てられ、このサービスには「172.17.28.31」というEXTERNAL-IPアドレスがMetalLBから割り当てられました。アプリケーションごとに固有のEXTERNAL-IPアドレスが割り当てられるのがtype: LoadBalancerの良いところですね。

このサービスは「svc3.cluster.local」というホスト名でアクセスします。

% kubectl get svc,ing svc3
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
service/svc3   LoadBalancer   10.152.183.91   172.17.28.31   80:30557/TCP   5m26s

NAME                      HOSTS                ADDRESS   PORTS   AGE
ingress.extensions/svc3   svc3.cluster.local             80      5m25s

EXTERNAL-IPは「172.17.28.31」らしいのでとりあえずhostsに書きます。

% sudo sh -c 'echo 172.17.28.31 svc3.cluster.local >> /etc/hosts'

コンテンツを置いてみます。

% kubectl exec -it app3-86cd876664-gnqfz -- sh -c 'echo I am app3 server >> /usr/share/nginx/html/index.html'

アクセスしてみます。

% curl http://svc3.cluster.local
I am app3 server

うまくいったようです。

注意する点

ちなみにJujuで構築したKubernetesの仕様上、MetalLBを導入した時点でtype: NodePortを使う方法はうまくいかなくなります。Juju BundleのYAMLの書き方で回避できるのかなあ。今度もう少し調査してみよう。

MetalLBも内部でLBとしてNGINXを使うので、アクセスが曲げられるとかでアクセスができなくなるのかなと思っています。

ということで併用はできないため、いずれかを選択する必要があります。

以上、KubernetesでIngressを触ってみた話でした。