Opensourcetechブログ

OpensourcetechによるNGINX/Kubernetes/Zabbix/Neo4j/Linuxなどオープンソース技術に関するブログです。

MetalLBとService(type:LoadBalancer)による外部クライアントへのサービス公開(kubernetes v1.26.00 on ubuntu22.04)


LinuCエヴァンジェリストの鯨井貴博@opensourcetechです。


はじめに
今回は、こちらの記事で作成したkubernetesクラスター v1.26.00で、
MetalLBとService(type:LoadBalancer)を使って外部クライアントへのサービス公開をやってみます。
なお、サービス公開はDual Stack(IPv4&IPv6)で行います。


Serviceとは
kubernetesにおけるServiceは、起動済みのPod(コンテナ)へと外部からアクセスする手段の一つであり、以下の4種類があります。

ClusterIP:kubernetesクラスター内部のPodなどからアクセスする
NodePort:kubernetesクラスターを構成するノード(Master/Worker)が持つIPアドレスの特定ポート(デフォルト設定だと、30000-32767)を公開する
LoadBalancer:連携するLBから払い出された外部からのアクセスが可能なIPアドレスの指定ポートを公開する
ExternalName:DNSのCNAME(別名)レコードを使って指定したFQDNとServiceを関連付() ※Service以外にも、Ingressを使って外部アクセスを実現する方法があります。


MetalLBとは
AWS・GCP・Azureなどのクラウド環境では、外部からアクセスできるように静的にグローバルIPアドレスなどを利用できるサービスが提供されています。
AWSの静的IPアドレスサービス/Elastic IP アドレス
GCPの静的IPアドレスサービス
Azureの静的IPアドレスサービス

各クラウドサービスでは、ユーザからの静的IPアドレス要求に対して払い出しをするための機能を実装しています。

しかし、ローカルで構築したkubernetes環境ではこれと同等の機能を有していないため、MetalLBなどを使って、これを実現させます。


MetalLBのインストール
こちらに記載されている方法でインストールします。
ログを見ると、namespace(名前空間)"metallb-system"・controller(リソースの管理)・speaker(Serviceに付与するIPへの通信の処理など)・ipaddresspools(Serviceへ付与するIPのリスト)やl2advertisements(Serviceへ付与するIPアドレスの広報)などのCRD(CustomeResourceDifinition)などがデプロイされているのが分かります。

kubeuser@master01:~$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml
namespace/metallb-system created
customresourcedefinition.apiextensions.k8s.io/addresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created
customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created
customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created
serviceaccount/controller created
serviceaccount/speaker created
role.rbac.authorization.k8s.io/controller created
role.rbac.authorization.k8s.io/pod-lister created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/controller created
rolebinding.rbac.authorization.k8s.io/pod-lister created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
secret/webhook-server-cert created
service/webhook-service created
deployment.apps/controller created
daemonset.apps/speaker created
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created


少し待つと、Deployments/ReplicaSet/Podが起動完了となります。

kubeuser@master01:~$ kubectl get ns
NAME              STATUS   AGE
default           Active   21h
kube-node-lease   Active   21h
kube-public       Active   21h
kube-system       Active   21h
metallb-system    Active   21s


kubeuser@master01:~$ kubectl get all -n metallb-system
NAME                              READY   STATUS    RESTARTS   AGE
pod/controller-68bf958bf9-qpwrj   1/1     Running   0          4m55s
pod/speaker-8cmkk                 1/1     Running   0          4m55s
pod/speaker-fjjfg                 1/1     Running   0          4m55s
pod/speaker-wgxdr                 1/1     Running   0          4m55s

NAME                      TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/webhook-service   ClusterIP   10.1.53.189   <none>        443/TCP   4m56s

NAME                     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/speaker   3         3         3       3            3           kubernetes.io/os=linux   4m56s

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   1/1     1            1           4m56s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-68bf958bf9   1         1         1       4m56s



Serviceへ付与するIPアドレスリストの適用
IPAddressPoolとL2Advertisementをデプロイします。
※IPv4とIPv6の両方を設定しています。 ※設定するIPアドレスは、それぞれの環境で合わせてください。

kubeuser@master01:~$ vi metallb-address-pool.yaml 

kubeuser@master01:~$ cat metallb-address-pool.yaml 
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: metallb-address-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.50-192.168.1.59
  - 240f:32:57b8:1::1:0/112
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: metallb-l2advertisement
  namespace: metallb-system
spec:
  ipAddressPools:
  - metallb-address-pool

kubeuser@master01:~$ kubectl apply -f metallb-address-pool.yaml 
ipaddresspool.metallb.io/metallb-address-pool created
l2advertisement.metallb.io/metallb-l2advertisement created


デプロイ出来ました。
これでMetalLBに関する作業は完了です。

kubeuser@master01:~$ kubectl get ipaddresspools.metallb.io -n metallb-system
NAME                   AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES
metallb-address-pool   true          false             ["192.168.1.50-192.168.1.59","240f:32:57b8:1::1:0/112"]

kubeuser@master01:~$ kubectl get l2advertisements.metallb.io -n metallb-system 
NAME                      IPADDRESSPOOLS             IPADDRESSPOOL SELECTORS   INTERFACES
metallb-l2advertisement   ["metallb-address-pool"]     



Service(type:LoadBalancer)のデプロイ
予め用意したDeployments"nginx"をServiceで公開します。

kubeuser@master01:~$ kubectl get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           22h


Serviceのyamlファイルを作成して、デプロイします。
なお、Dual Stack環境のService yamlファイルの記載方法は、
こちらを参照ください。

kubeuser@master01:~$ vi svc_nginx_loadbalancer.yaml 

kubeuser@master01:~$ cat svc_nginx_loadbalancer.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ipFamilies:
  - IPv4
  - IPv6
  ipFamilyPolicy: RequireDualStack
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
status:
  loadBalancer: {}

kubeuser@master01:~$ kubectl apply -f svc_nginx_loadbalancer.yaml 
service/nginx created

kubeuser@master01:~$ kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP                        PORT(S)        AGE
kubernetes   ClusterIP      10.1.0.1       <none>                             443/TCP        22h
nginx        LoadBalancer   10.1.243.106   192.168.1.50,240f:32:57b8:1::1:0   80:30586/TCP   5s

kubeuser@master01:~$ kubectl get svc nginx -o yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx","namespace":"default"},"spec":{"ipFamilies":["IPv4","IPv6"],"ipFamilyPolicy":"RequireDualStack","ports":[{"port":80,"protocol":"TCP","targetPort":80}],"selector":{"app":"nginx"},"type":"LoadBalancer"},"status":{"loadBalancer":{}}}
    metallb.universe.tf/ip-allocated-from-pool: metallb-address-pool
  creationTimestamp: "2023-03-15T12:17:21Z"
  labels:
    app: nginx
  name: nginx
  namespace: default
  resourceVersion: "121450"
  uid: f63b731c-29e8-4d79-a8d2-c261d5e0da12
spec:
  allocateLoadBalancerNodePorts: true
  clusterIP: 10.1.243.106
  clusterIPs:
  - 10.1.243.106
  - fd12:b5e0:383f::2971
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  - IPv6
  ipFamilyPolicy: RequireDualStack
  ports:
  - nodePort: 30586
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.168.1.50
    - ip: 240f:32:57b8:1::1:0



外部クライアントからのアクセス
Serivce(type:LoadBalancer)で公開されたIPv4/IPv6のアドレスにアクセスしてみます。
アクセス成功!




参考
MetalLBの設定で使った"metallb-address-pool.yaml"ですが、
version0.12まではconfigmapを使って定義していました。
それが、version0.13からはCRDs(CustomeResourceDefinitions)を使うように変更されました。
詳細は、こちら




おわりに
今回kubernetes v1.26(Dual Stack) + MetalLB(CRDs)という環境を使いましたが、
以前 kubernetes v1.22(IPv4のみ) + MetalLB(当時はconfigmapで設定していた)で動作させた時とは設定方法など変化していることを発見しました。
改めて、使用しているソフトウェアの更新情報はちゃんとチェックしないといけないなぁと感じた次第。



今回気づいたこと
・MetalLBがversion0.13からconfigmapではなく、CRDsでipaddresspoolを設定するようになっていた
・kubernetesでIPv6(Single Stack/Dual Stackのいずれも)を使う場合は、明示的に使用することを設定する必要がある
・MetalLBの"l2advertisements"を有効にしないと、外部クライアントでarp解決が出来ずService(type:LoadBalancer)で公開したIPアドレスにはアクセスできない

Opensourcetech by Takahiro Kujirai