フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

【手順あり】MetalLBとIngressを併用してL7負荷分散を実施する方法まとめ(オンプレミス)

Ingressについて

今回はオンプレミスの環境に対してIngressリソースを作成し、Ingressコントローラーを動作させます。GCP上のIngressとは概念や方法が異なりますのでご注意ください。

Ingressを使う上で2つのコンポーネントが存在します。

  • Ingressリソース
  • Ingressコントローラー

kuberneteの中身から紹介すると、マニュフェストに定義したリソースをkubernetesに登録することから始まります。登録しただけでは何もおきず、リソースを元に何か処理を行う「コントローラー」が存在しなければなりません。

例えばDeploymentをマニュフェストで定義したとしましょう。登録されたDeploymentをあるべき状態にするDeployment Controllerが存在しなければ何も設定されないのです。ということでIngressについてもリソースとコントローラーが必要になってきます。

少し他と違うのはIngressのコントローラーは自分で入れる必要があるということです。

オンプレミス環境におけるNginx Ingressについて

今回はNginx Ingress Controllerを使います。図示するとこのようなアーキテクチャーとなっています。(WebサーバはNginx Ingress Controllerには含まれていません)

f:id:lirlia:20200416045804p:plain

名前 役割
Ingressリソース Ingressの定義を行う
Ingressコントローラ Ingressリソースを監視し変更をL7 LBに伝える
Nginx Ingress(L7 LB) Ingressリソースで指定されたルールに従ってリクエストを処理する
Nginx(Web) コンテンツを保有している(最終的にアクセスされる)
※WebサーバはNginx Ingress Controllerには含まれていません

ここでややこしいのがNginx Ingress Controller podが「Contollerの機能」と「L7 LB機能」の両方を持っている点です。そのためControllerという名前ですがトラフィックを受け付けL7の負荷分散を実施します。

f:id:lirlia:20200416045743p:plain

実際にpod内のプロセスをみてみるとinitプロセス(dumb-initは軽量のinit)の配下に/nginx-ingress-controllernginxが起動していることがわかります。

bash-5.0$ ps -ef
PID   USER     TIME  COMMAND
    1 www-data  0:00 /usr/bin/dumb-init -- /nginx-ingress-controller --configmap=ingress-nginx
    6 www-data  0:41 /nginx-ingress-controller --configmap=ingress-nginx/nginx-configuration -
   25 www-data  0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.con
  730 www-data  0:01 nginx: worker process
  731 www-data  0:02 nginx: worker process
  732 www-data  0:00 nginx: cache manager process

【ハンズオン】MetalLB+Ingressの実装

最終的に目指す姿はこちら。

f:id:lirlia:20200416043242p:plain

今回つかったコードはGitHubに格納しています。

k8s-sample/ingress at master · lirlia/k8s-sample · GitHub

環境

名前 バージョン
OS CentOS Linux release 7.6.1810 (Core)
kubelet v1.18.1
kubeadm v1.18.1
docker v1.13.1
calico v3.8.8-1
metallb v0.9.3
Ingress-nginx-controller v0.30.0

kubernetesの導入はこちらを参考にしてください

blog.framinal.life

事前準備

  • kubernetes(kubeadm/kubelet/kubectl/docker)がインストールされている
  • calicoが導入されている

MetalLBの準備

MetalLBの準備はこちらをご覧ください。L2 modeでやっていきます。

blog.framinal.life

Ingress リソースの準備

ingress.yamlという名前で作成します。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  namespace: default
  name: test-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: test.com
    http:
      paths:
      - backend:
          serviceName: nginx-ingress-test
          servicePort: 80
        path: /ingress

Ingress Controllerの準備

必要なファイルをダウンロードします。

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

service-nodeport.yamlを以下のように書き換えます。

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
- type: NodePort
+ type: LoadBalancer
+ loadBalancerIP: 192.168.10.10
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

ついで名前を変えておきます

mv service-nodeport.yaml service-lb.yaml

動作させるNginxサービス&podを準備

ややこしいですが先ほどのNginx Ingress Controllerではなく、最終的にアクセスするWebサーバとしてのNginxを用意します。名前はnginx.yamlです。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-ingress-test
  name: nginx-ingress-test
spec:
  selector:
    matchLabels:
      app: nginx-ingress-test
  template:
    metadata:
      labels:
        app: nginx-ingress-test
    spec:
      containers:
      - image: nginx
        name: nginx-ingress-test
        ports:
        - containerPort: 80
---

apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress-test
spec:
  type: NodePort
  selector:
    app: nginx-ingress-test
  ports:
    - name: http
      port: 80
      targetPort: 80

リソースの作成

ここまでできたら適用します

kubectl apply -f ingress.yaml
kubectl apply -f mandatory.yaml
kubectl apply -f service-lb.yaml
kubectl apply -f nginx.yaml

正しく適用するとこのようになります。

[root@master ingress]# kubectl get svc nginx-ingress-test 
NAME                 TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
nginx-ingress-test   NodePort   10.103.112.35   <none>        80:30471/TCP   28m
  
[root@master ingress]# kubectl get ingress
NAME           CLASS    HOSTS   ADDRESS         PORTS   AGE
test-ingress   <none>   *       192.168.10.10   80      162m
  
[root@master ingress]# kubectl get svc -n ingress-nginx 
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                      AGE
ingress-nginx   LoadBalancer   10.101.97.141   192.168.10.10   80:32398/TCP,443:30249/TCP   80m

実際にアクセスしてみる

[root@master ingress]# curl 192.168.10.10/ingress
  
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
  
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
  
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

curl 192.168.10.10の場合はIngressにて指定されていないパスになるためアクセスできず404が返却されます。

[root@master ingress]# curl 192.168.10.10  
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>

お疲れ様でした、以上で終了です。

参考