kubernetesのnginx-ingress、いろいろ調べたり手を動かしてみても、どうしても理解ができなくてずっと悩んでましたが、少し理解が進んだ気がしたので、自分用まとめ。
前提
- type:loadbalancerは使わない。metal-lbも使わない。諸般の事情により公開はnodeportのみ。
- クラスタはVagrantでmaster x 1, worker x 2とします。以下のレポジトリで公開しています。
シンプルなnodeport serviceの場合
kubernetes bootcampのイメージをサンプルに、Deploymentを作ります。podは8080で待ち受けます。
apiVersion: apps/v1 kind: Deployment metadata: labels: app: bootcamp name: bootcamp spec: replicas: 2 selector: matchLabels: app: bootcamp template: metadata: labels: app: bootcamp spec: containers: - image: gcr.io/google-samples/kubernetes-bootcamp:v1 name: bootcamp ports: - containerPort: 8080 dnsPolicy: ClusterFirst restartPolicy: Always
Serviceはこんな感じです。nodeport:31001 -> port:80 -> targetport:8080 という感じでDeploymentのpodまで到達します。
apiVersion: v1 kind: Service metadata: name: bootcamp labels: app: bootcamp spec: type: NodePort ports: - port: 80 protocol: TCP targetPort: 8080 nodePort: 31001 selector: app: bootcamp
適用します。
$ kubectl apply -f bootcamp-deployment.yaml deployment.apps/bootcamp created $ kubectl apply -f bootcamp-service.yaml service/bootcamp created
確認します
$ kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE bootcamp 2/2 2 2 39s $ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES bootcamp-7465f56-4zt4d 1/1 Running 0 4m25s 192.168.226.81 worker-1 <none> <none> bootcamp-7465f56-gphwd 1/1 Running 0 4m26s 192.168.133.207 worker-2 <none> <none> $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE bootcamp NodePort 10.101.29.7 <none> 80:31001/TCP 2m13s
実際にアクセスしてみましょう。pod ip/cluster ip/nodeportでどれもアクセスができているのがわかりますね。
$ curl 192.168.226.81:8080 Hello Kubernetes bootcamp! | Running on: bootcamp-7465f56-4zt4d | v=1 $ curl 192.168.133.207:8080 Hello Kubernetes bootcamp! | Running on: bootcamp-7465f56-gphwd | v=1 $ curl 10.101.29.7:80 Hello Kubernetes bootcamp! | Running on: bootcamp-7465f56-gphwd | v=1 $ curl 10.101.29.7:80 Hello Kubernetes bootcamp! | Running on: bootcamp-7465f56-4zt4d | v=1 $ curl 10.240.0.22:31001 Hello Kubernetes bootcamp! | Running on: bootcamp-7465f56-gphwd | v=1 $ curl 10.240.0.21:31001 Hello Kubernetes bootcamp! | Running on: bootcamp-7465f56-4zt4d | v=1
図だとこんな感じかなと思います。
nginx-ingress の場合
ではnginx-ingressを使ってbootcampを公開してみましょう。まず、helmで nginx-ingress をインストールします。
$ helm install nginx-ingress stable/nginx-ingress
まずこの状態で見てみます。deploymentから。
$ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE nginx-ingress-controller 1/1 1 1 93s nginx-ingress-default-backend 1/1 1 1 93s bootcamp 2/2 2 2 60m
nginx-ingress-controllerのpodが80番と443番ポートで待ち受けています。
$ kubectl get deployment nginx-ingress-controller -o yaml apiVersion: apps/v1 kind: Deployment ・・・ metadata: ・・・ name: nginx-ingress-controller namespace: default ・・・ name: nginx-ingress-controller ports: - containerPort: 80 name: http protocol: TCP - containerPort: 443 name: https protocol: TCP ・・・
nginx-ingress-default-backend のpodが8080で待ち受けています。
$ kubectl get deployment nginx-ingress-default-backend -o yaml apiVersion: apps/v1 kind: Deployment ・・・ name: nginx-ingress-default-backend namespace: default ・・・ ports: - containerPort: 8080 name: http protocol: TCP ・・・
podに直接アクセスしてみます。
$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES bootcamp-7465f56-4zt4d 1/1 Running 0 73m 192.168.226.81 worker-1 <none> <none> bootcamp-7465f56-gphwd 1/1 Running 0 73m 192.168.133.207 worker-2 <none> <none> nginx-ingress-controller-857967b4f-2sz64 1/1 Running 0 14m 192.168.226.82 worker-1 <none> <none> nginx-ingress-default-backend-7c868597f4-fftss 1/1 Running 0 14m 192.168.133.208 worker-2 <none> <none>
全部404ではありますけど、何かしら応答はしてますね。ちょっと置いときましょう。
$ curl http://192.168.226.82/ default backend - 404 $ curl --insecure https://192.168.226.82/ default backend - 404 $ curl 1192.168.133.208:8080 default backend - 404
serviceを見てみます。
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-controller LoadBalancer 10.103.246.235 <pending> 80:32012/TCP,443:32050/TCP 19m nginx-ingress-default-backend ClusterIP 10.99.30.83 <none> 80/TCP 19m
もう少し詳しく。まずはnginx-ingress-controllerから。
$ kubectl get svc nginx-ingress-controller -o yaml apiVersion: v1 kind: Service ・・・ name: nginx-ingress-controller namespace: default ・・・ spec: clusterIP: 10.103.246.235 externalTrafficPolicy: Cluster ports: - name: http nodePort: 32012 port: 80 protocol: TCP targetPort: http - name: https nodePort: 32050 port: 443 protocol: TCP targetPort: https ・・・ type: LoadBalancer
冒頭でお伝えしたとおり、type: LoadBalancerは使えない(だからEXTERNAL-IPはpending)なのですが、そこはちょっと置いといて、ポートのところを見ると、
- nodeport:32012 -> port:80 -> targetport:80
- nodeport:32005 -> port:443 -> targetport:443
になっています。つまり、nginx-ingress-controllerのpodに向かって転送しているわけですね。
ということはすなわち、cluster ipでもnodeportでもアクセスができるはずです。
$ curl http://10.103.246.235:80 default backend - 404 $ curl --insecure https://10.103.246.235:443 default backend - 404 $ curl http://10.240.0.21:32012 default backend - 404 $ curl http://10.240.0.22:32012 default backend - 404 $ curl --insecure https://10.240.0.21:32050 default backend - 404 $ curl --insecure https://10.240.0.22:32050 default backend - 404
できましたね。nginx-ingress-default-backendも詳しく見てみましょう。
$ kubectl get svc nginx-ingress-default-backend -o yaml apiVersion: v1 kind: Service ・・・ name: nginx-ingress-default-backend namespace: default spec: clusterIP: 10.99.30.83 ports: - name: http port: 80 protocol: TCP targetPort: http ・・・ type: ClusterIP
こちらはcluster ipなので外部からのアクセスはできません。cluster ipに対してアクセスすると応答します。
$ curl 10.99.30.83:80 default backend - 404
これがnginx-ingressをインストールした直後です。nginx-ingressを使うと関係者が多くなるのでちょっとわかりにくくなるのですが、これだけ見てるとtype: nodeportで公開しているのとそんなに変わらないですよね。
で、今回type: loadbalancerは使えないので、nginx-ingress-controllerのserviceはtype: nodeportに変更します。また80/443それぞれのnodeportも固定します。
$ kubectl edit service nginx-ingress-controller
変更点だけ。
・・・ - name: http nodePort: 32001 ・・・ - name: https nodePort: 32002 ・・・ type: NodePort
確認します。
$ kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-controller NodePort 10.103.246.235 <none> 80:32001/TCP,443:32002/TCP 49m nginx-ingress-default-backend ClusterIP 10.99.30.83 <none> 80/TCP 49m
変わりました。
ではingressを追加します。こんな感じにしてみました。時間の都合上httpだけ、default-backendは後で調べます。
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx name: bootcamp-nginx-ingress spec: rules: - host: example.com http: paths: - backend: serviceName: bootcamp servicePort: 80 path: /
serviceNameのところはserviceのmetadata.nameと合わせる必要がありますので注意してください。
ではアクセスしてみましょう。架空のホスト名なのでhostヘッダをつけています。
$ curl -H 'host: example.com' http://10.240.0.21:32001 Hello Kubernetes bootcamp! | Running on: bootcamp-7465f56-gphwd | v=1 $ curl -H 'host: example.com' http://10.240.0.22:32001 Hello Kubernetes bootcamp! | Running on: bootcamp-7465f56-4zt4d | v=1
うまくいきました!アクセスログも見てみましょう。
$ kubectl logs nginx-ingress-controller-857967b4f-2sz64 10.0.2.15 - - [18/May/2020:17:40:08 +0000] "GET / HTTP/1.1" 200 81 "-" "curl/7.58.0" 75 0.008 [default-bootcamp-80] [] 192.168.226.81:8080 92 0.004 200 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 192.168.133.192 - - [18/May/2020:17:40:12 +0000] "GET / HTTP/1.1" 200 92 "-" "curl/7.58.0" 75 0.003 [default-bootcamp-80] [] 192.168.133.207:8080 92 0.004 200 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
アクセス元IPアドレスのところがおかしいのはvagrantだからですね。ちゃんとアクセスが来てるので良しとします。図にまとめるとこんな感じになるのかな。
serviceがmanfiestだけで動くのに対し、nginx-ingressはservice/pod/ingressといろいろなものが強調して動くことになるので、非常にわかりにくいですね。しかもtype: LoadBalancerならもちょっとシンプルなはずなんですが、そうじゃないので余計にわかりにくい・・・
とりあえずなんとなくは理解できたんじゃないかと。