今日はだいぶ前に宿題となっていたKubernetes Ingress機能を使ってみました。
はじめに
まず、実際に導入する前に、ここら辺の情報を確認しました。
JujuでデプロイしたKubernetesを想定しています。Juju Bundleは以下のものを使いました。はい、そうです。いつも使うやつです。
今回使うJuju BundleでKubernetesをデプロイすると、LoadBalancerとIngressをデフォルトでインストールしてくれます。そのため、Podを作ってPodにServiceを割り当てた後にIngressを適用することで、Kubernetesクラスターの外へアプリケーションを公開できます。
また、永続ストレージを使いたかったので前回取り上げたように「Kubernetes Calico #273」にNFSサーバーを追加してデプロイするようにちょっとだけ手直ししたものを使いました。
先ずはすぐにできる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を使うと割と簡単に試すことができます。
セットアップ方法については以下の情報が参考になります。
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を触ってみた話でした。
2019年12月4日追記
後編です。