今日はだいぶ前に宿題となっていた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日追記
後編です。