Kubernetes(K3s) + Flexisip + Flexisip Account Manager

ドキュメント


  • ホストPC(virt-manager:KVM/QEMU)(192.168.1.100
  • ブリッジネットワーク(ホストを有線ネットワーク接続:192.168.1.0/24
  • Master-Node: k3s server (192.168.1.10
  • Worker-Node: k3s worker (複数可) (192.168.1.20
  • VM3: NFS(共有ファイルサーバ)(192.168.1.30
  • ホストPCと同一LAN内の別PC: (192.168.1.200)
  • デュアルスタック(IPv4,IPv6)
  • K3sデフォルトのIngress:traefikは使わない —> Ingress-Nginx
  • K3sデフォルトのCNIプラグイン:flannelは使わない —> Calico
  • K3sデフォルトのロードバランサー:ServiceLBは使う—> 代替:MetalLB

注) 各VMはホストとブリッジ接続するため、IPアドレスはホストと同じDHCPサーバから付与されます。ホストと各VMでNetplanの設定が必須。

注) サーバノード、エージェントノードにK3sをインストールするスクリプトについては次の投稿記事参照。


ホストPC: 192.168.1.100 での作業

ブリッジ接続するための設定(Netplan)は下記リンク先参照


minikubeで作成したマニフェストのコピー
(virt-managerで作成したNFS-VMの共有ディレクトリにコピー)

$ scp -r ./ [email protected]:/home/xxx/~

Master-Node: 192.168.1.10 での作業

NetplanでIPv6対応、SHCPを有効にして再起動

network:
  version: 2
  ethernets:
    enp1s0:
      dhcp4: yes
      dhcp6: yes

再起動後K3sのインストール

$ curl -sfL https://get.k3s.io | sh -

Ingress-Nginxのインストール

$ sudo kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.3/deploy/static/provider/baremetal/deploy.yaml

NodePortでポートがランダムに割当てられるため固定ポートを指定します。
新しいマニフェストを作成するか既存の設定を編集します。
マニフェスト:

$ sudo nano ingress-nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/component: controller
  ports:
  - name: http
    port: 80
    targetPort: http
    nodePort: 30080
  - name: https
    port: 443
    targetPort: https
    nodePort: 30443

適用

$ sudo kubectl apply -f ingress-nginx-service.yaml

既存マニフェストを編集する場合

$ sudo kubectl edit service ingress-nginx-controller -n ingress-nginx

以下のnodePortの箇所を変更

  ports:                        
  - name: http                  
    nodePort: 30080                        
    port: 80       
    protocol: TCP               
    targetPort: http            
  - name: https     
    nodePort: 30443             
    port: 443                   
    protocol: TCP
    targetPort: https

Worker-Node用トークン取得

$ sudo cat /var/lib/rancher/k3s/server/node-token

注)取得したトークンは、後ほどワーカノード内で使用します。


Cert-Managerのインストール

$ sudo kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml

CloudflareへアクセスするためのAPIトークンをSecretへ登録

$ sudo kubectl create secret generic cloudflare-api-token-secret --from-literal=api-token='YOUR_CLOUDFLARE_API_TOKEN' --namespace=cert-manager

ClusterIssuer適用

$ sudo kubectl apply -f cluster-issuer.yaml

Ingress適用

$ sudo kubectl apply -f ingress.yaml

認証ステータス確認

$ sudo kubectl get certificate

Worker-Node: 192.168.1.20 での作業

Master-Nodeから取得したトークンを指定してk3sをインストール

$ curl -sfL https://get.k3s.io | K3S_URL=https://192.168.1.10:6443 K3S_TOKEN=K10f8d5...abcdef sh -

設定(IPアドレス)を変更する場合

K3sサービス停止

$ sudo systemctl stop k3s-agent

環境変数で設定されている場合、サービスファイルを確認

$ sudo systemctl cat k3s-agent
[Service]
Type=notify
EnvironmentFile=-/etc/default/%N
EnvironmentFile=-/etc/sysconfig/%N
EnvironmentFile=-/etc/systemd/system/k3s-agent.service.env

環境変数を変更(IPアドレス変更)

$ sudo nano /etc/systemd/system/k3s-agent.service.env
K3S_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
K3S_URL='https://192.168.1.10:6443'

サービスを起動

$ sudo systemctl start k3s-agent

Master-Node: 192.168.1.10 での作業

ノード確認

$ sudo kubectl get nodes
NAME             STATUS   ROLES                  AGE   VERSION
master-node      Ready    control-plane,master   23h   v1.32.5+k3s1
worker-node001   Ready    <none>                 23h   v1.32.5+k3s1

containerd (k3s内部) 直接確認

$ sudo crictl ps
$ sudo crictl logs <container-id>

K3sアンインストール(サーバ、エージェント)

$ sudo /usr/local/bin/k3s-uninstall.sh
$ sudo /usr/local/bin/k3s-agent-uninstall.sh

Dual-stack (IPv4 + IPv6) Networking

IPv6ネットワークを追加したデュアルスタックでシステムを運用

K3sのデフォルトCNIであるflannelはデュアルスタックにも対応。別のCNIであるCalicoCiliumなどを別途インストールする場合は、K3s起動時に以下オプションを付与すること

–flannel-backend=none
–disable-network-policy

Master-Node:サーバ

TraeficによるIngressではなくIngress-Nginxを使用(--disable=traefik)。

$ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="\
  --cluster-cidr=10.42.0.0/16,fd00:10:42::/48 \
  --service-cidr=10.43.0.0/16,fd00:10:43::/112 \
  --disable=traefik \
  --flannel-backend=none \
  --disable-network-policy" \
  sh -

トークン確認

$ sudo cat /var/lib/rancher/k3s/server/node-token

Calicoのインストール

  • If your Linux distribution comes with installed Firewalld or another iptables manager it should be disabled. These may interfere with rules added by Calico and result in unexpected behavior.
$ sudo kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.30.2/manifests/calico.yaml

注) 上記のURLからダウンロードしたcalico.yamlファイルに、下記の箇所を追加して $ sudo kubectl apply -f calico.yaml した方が楽

$ sudo kubectl edit configmap calico-config -n kube-system

以下追加

"ipam": {
        "type": "calico-ipam",
        "assign_ipv4": "true",
        "assign_ipv6": "true"
    },

calico-nodeにIPv6環境変数を追加

$ sudo kubectl edit daemonset calico-node -n kube-system

spec.containers.envに以下追加

        - name: IP6                        
          value: autodetect           
        - name: CALICO_IPV6POOL_NAT_OUTGOING     
          value: "true"              
        - name: CALICO_IPV6POOL_CIDR       
          value: fd00:10:42::/48  

IPPoolの設定

$ sudo kubectl get ippool -A
NAME                  AGE
default-ipv4-ippool   3h38m
default-ipv6-ippool   142m

k3s起動時に指定したIP範囲と一致させる必要があります。

$ sudo kubectl edit ippool default-ipv4-ippool

cidr: 10.42.0.0/16

$ sudo kubectl edit ippool default-ipv6-ippool

cidr: fd00:10:42::/48
ipipMode: Never

別途IP Pool用マニフェストを作成・適用する場合

API Resourceの確認

$ sudo kubectl api-resources | grep ippool
ippools                                          crd.projectcalico.org/v1            false        IPPool

calico_pool.yaml

apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  name: default-ipv4-ippool
spec:
  cidr: 10.42.0.0/16
  ipipMode: Never
  natOutgoing: true
  nodeSelector: all()
---
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  name: default-ipv6-ippool
spec:
  cidr: fd00:10:42::/48
  ipipMode: Never
  natOutgoing: true
  nodeSelector: all()

リソースの適用

$ sudo kubectl apply -f calico_pool.yaml

calico-nodeの再起動

calio-nodeのpodを削除することで、設定変更後の新たなpodが立ち上がります。

$ sudo kubectl delete pod -n kube-system -l k8s-app=calico-node

PodのIPv6割当て確認

$ kubectl get pod -A -o jsonpath="{range .items[*]}{.metadata.name}{': '}{.status.podIPs[*].ip}{'\n'}{end}"

Worker-Node:エージェント

$ curl -sfL https://get.k3s.io | K3S_URL=https://<MASTER-IP>:6443 \
  K3S_TOKEN=<取得したK3S_TOKEN> \
  sh -

トラブルシュート

$ sudo kubectl describe clusterissuer letsencrypt-dns

Warning ErrInitIssuer 3m42s cert-manager-clusterissuers Error initializing issuer: Get “https://acme-v02.api.letsencrypt.org/directory”: dial tcp: lookup acme-v02.api.letsencrypt.org on [fd00:10:43::a]:53: read udp [fd00:10:42:f15b:c88e:aa72:b0f8:6f08]:38331->[fd00:10:43::a]:53: i/o timeout

Cert-ManagerがLet’s EncryptのACMEサーバー(acme-v02.api.letsencrypt.org )に接続できない(IPv6 DNS解決が失敗)

[対策] CoreDNSの設定を変更

以下のようにforwardを変更

$ sudo kubectl edit configmap -n kube-system coredns

forward . 8.8.8.8 1.1.1.1 {
    prefer_udp
    force_tcp
}

coreDNSを再起動

$ sudo kubectl rollout restart -n kube-system deployment/coredns

ロードバランサー

ServiceLBMetalLB

機能 serviceLB(k3s組み込み) MetalLB
IP割り当て ノードのIPを直接使用 専用のVIP(仮想IP)を割り当て
プロトコル シンプルなポート転送 L2(ARP/NDP) or BGP
高可用性 :cross_mark: ノード障害時は手動対応 :white_check_mark: フェイルオーバー可能
外部依存 不要 不要(オンプレで動作)
適した環境 小規模/テスト環境 本番環境(オンプレ/ベアメタル)

To disable ServiceLB, configure all servers in the cluster with the --disable=servicelb

ServiceLB は、Kubernetes の標準 Service メカニズム(type: LoadBalancer)を活用しており、実際のパケット処理は kube-proxy によって行われます。

その kube-proxy が、iptables もしくは IPVS を用いて内部的に転送ルールを構築します。

よってufwとの併用には注意が必要。MetalLBを採用すればufwとの競合は回避できます。

ufwについて

It is recommended to turn off ufw (uncomplicated firewall):

$ sudo ufw disable

If you wish to keep ufw enabled, by default, the following rules are required:

$ sudo ufw allow 6443/tcp #apiserver
$ sudo ufw allow from 10.42.0.0/16 to any #pods
$ sudo ufw allow from 10.43.0.0/16 to any #services

Additional ports may need to be opened depending on your setup. See Inbound Rules for more information. If you change the default CIDR for pods or services, you will need to update the firewall rules accordingly.


ServiceLBからMetalLBへ

Disabling ServiceLB

既にK3sデフォルトのServiceLBを使用している場合は、K3sのSystemctl起動ファイルに以下のオプション--disable=servicelbを追加。ネットワークポリシーはCalicoで実装するため、デフォルトのネットワークポリシーは’–disable-network-policy’で無効。

/etc/systemd/system/k3s.service

ExecStart=/usr/local/bin/k3s \
    server \
        '--cluster-cidr=10.42.0.0/16,fd00:10:42::/48' \
        '--service-cidr=10.43.0.0/16,fd00:10:43::/112' \
        '--flannel-backend=none' \
        '--disable-network-policy' \
        '--disable=traefik' \
        '--disable=servicelb' 

再起動・デーモンのリロード

$ sudo systemctl restart k3s
$ sudo systemctl daemon-reload

MetalLBのインストール

$ sudo kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml

IPv4/IPv6両方のIPAddressPoolL2Advertisementを定義。

metallb-config.yaml

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: dualstack-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.xx.xx/32
    - xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/128
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2adv
  namespace: metallb-system
spec:
  ipAddressPools:
    - dualstack-pool

L2Advertisement : Layer2モード

  • ARP (IPv4) / NDP (IPv6) によって、同一L2ネットワーク(L2Advertisement)上の他ノードへ IP アナウンスを行う方式。
  • ルータやBGP設定が不要で、LANスコープで完結するシンプルな方式。

/32(IPv4)・/128(IPv6)により、1個だけの単一IPをサービスに割当て

適用

$ sudo kubectl apply -f metallb-config.yaml

Ingress-nginxのマニフェスト

ingress-nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/component: controller
  ipFamilyPolicy: PreferDualStack
  ipFamilies:
    - IPv4
    - IPv6
  ports:
    - name: http
      port: 80
      targetPort: http
    - name: https
      port: 443
      targetPort: https

適用

$ sudo kubectl apply -f ingress-nginx-service.yaml

ステータス確認

$ sudo kubectl get pods -n metallb-system
[sudo] password for takanobu: 
NAME                          READY   STATUS    RESTARTS   AGE
controller-58fdf44d87-5n9nv   1/1     Running   0          3h19m
speaker-rbgcw                 1/1     Running   0          3h19m
speaker-zjcj5                 1/1     Running   0          3h19m
$ sudo kubectl get l2advertisements.metallb.io -n metallb-system
NAME          IPADDRESSPOOLS       IPADDRESSPOOL SELECTORS   INTERFACES
adv4          ["ipv4-pool"]                                  
adv6          ["ipv6-pool"]                                  
l2-adv-ipv4   ["ingress-ipv4"]                               
l2-adv-ipv6   ["ingress-ipv6"]                               
l2adv         ["dualstack-pool"] 
$ sudo kubectl get ipaddresspool -n metallb-system
NAME             AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES
dualstack-pool   true          false             ["192.168.xx.xx/32","xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/128"]
$ sudo kubectl get svc ingress-nginx-controller -n ingress-nginx
NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP                                          PORT(S)                      AGE
ingress-nginx-controller   LoadBalancer   10.43.115.23   192.168.xx.xx,xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx   80:32078/TCP,443:32592/TCP   3h1m

開放ポート

Inbound Rules for K3s Nodes​

Protocol Port Source Destination Description
TCP 2379-2380 Servers Servers Required only for HA with embedded etcd
TCP 6443 Agents Servers K3s supervisor and Kubernetes API Server
UDP 8472 All nodes All nodes Required only for Flannel VXLAN
TCP 10250 All nodes All nodes Kubelet metrics
UDP 51820 All nodes All nodes Required only for Flannel Wireguard with IPv4
UDP 51821 All nodes All nodes Required only for Flannel Wireguard with IPv6
TCP 5001 All nodes All nodes Required only for embedded distributed registry (Spegel)
TCP 6443 All nodes All nodes Required only for embedded distributed registry (Spegel)

Calico Network requirements

Ensure that your hosts and firewalls allow the necessary traffic based on your configuration.

Configuration Host(s) Connection type Port/protocol
Calico networking (BGP) All Bidirectional TCP 179
Calico networking with IP-in-IP enabled (default) All Bidirectional IP-in-IP, often represented by its protocol number 4
Calico networking with VXLAN enabled All Bidirectional UDP 4789
Calico networking with Typha enabled Typha agent hosts Incoming TCP 5473 (default)
Calico networking with IPv4 Wireguard enabled All Bidirectional UDP 51820 (default)
Calico networking with IPv6 Wireguard enabled All Bidirectional UDP 51821 (default)
flannel networking (VXLAN) All Bidirectional UDP 4789
All kube-apiserver host Incoming Often TCP 443 or 6443*
etcd datastore etcd hosts Incoming Officially TCP 2379 but can vary
  • The value passed to kube-apiserver using the --secure-port flag. If you cannot locate this, check the targetPort value returned by kubectl get svc kubernetes -o yaml.

Flexisip+Flexisip Account Manager+K3s(Kubernetes)システム構成

KVM/QEMU(Virtual Machine Manager)により3つの仮想マシンで構築

  • K3Sサーバノード
  • K3Sエージェントノード
  • NFSネットワークファイルサーバ

システム条件

  • サーバノード1,エージェントノード1のマルチノード構成(サーバノード、エージェントノードの拡張可能)
  • K3SデフォルトのロードバランサーServiceLBの代替LBとしてMetalLBを採用
  • K3SデフォルトのCNIプラグインの代替CNIとしてCalicoを採用
  • IPv4/IPv6のデュアルスタック
  • PV+PVCにはネットワークファイルサーバNFS-Serverを使用
  • Dockerイメージをプライベートで保存・配布するための「Docker Registry(レジストリ)」をNFS-VMへコンテナとして常駐

Podリスト

$ sudo kubectl get pod -A -o wide
NAMESPACE        NAME                                        READY   STATUS    RESTARTS         AGE     IP              NODE             NOMINATED NODE   READINESS GATES
cert-manager     cert-manager-69f7f6c764-dtmmt               1/1     Running   14 (4m1s ago)    9d      10.42.111.41    worker-node001   <none>           <none>
cert-manager     cert-manager-cainjector-8fbb9ccfc-9xcwr     1/1     Running   20 (17h ago)     9d      10.42.111.38    worker-node001   <none>           <none>
cert-manager     cert-manager-webhook-667968f47b-2rpv7       1/1     Running   10 (4m15s ago)   9d      10.42.77.188    master-node      <none>           <none>
default          apache-deployment-6b466f667c-pl9rc          1/1     Running   5 (4m1s ago)     5d      10.42.111.35    worker-node001   <none>           <none>
default          flexisip-648df6d797-thln2                   1/1     Running   8 (4m1s ago)     3d23h   192.168.1.182   worker-node001   <none>           <none>
default          mariadb-statefullset-0                      1/1     Running   10 (4m15s ago)   9d      10.42.77.168    master-node      <none>           <none>
default          nginx-deployment-5584f6f877-qxwrf           1/1     Running   10 (4m1s ago)    5d18h   10.42.111.34    worker-node001   <none>           <none>
default          php-fpm-5dd64c9ccb-gnfmw                    1/1     Running   4 (4m15s ago)    3d23h   10.42.77.172    master-node      <none>           <none>
default          phpmyadmin-6746977694-6lkhw                 1/1     Running   5 (4m15s ago)    5d7h    10.42.77.174    master-node      <none>           <none>
default          redis-58d6bd9ccb-cdg9d                      1/1     Running   10 (4m1s ago)    9d      10.42.111.25    worker-node001   <none>           <none>
ingress-nginx    ingress-nginx-controller-6fd9986775-pzlgp   1/1     Running   4 (4m15s ago)    4d8h    10.42.77.190    master-node      <none>           <none>
kube-system      calico-kube-controllers-576865d959-cwzjb    1/1     Running   10 (4m15s ago)   9d      10.42.77.189    master-node      <none>           <none>
kube-system      calico-node-5dq7l                           1/1     Running   10 (4m1s ago)    9d      192.168.1.182   worker-node001   <none>           <none>
kube-system      calico-node-xqkkk                           1/1     Running   10 (4m15s ago)   9d      192.168.1.188   master-node      <none>           <none>
kube-system      coredns-76746786f-rfmk9                     1/1     Running   10 (4m1s ago)    9d      10.42.111.36    worker-node001   <none>           <none>
kube-system      local-path-provisioner-774c6665dc-drks6     1/1     Running   10 (4m15s ago)   9d      10.42.77.171    master-node      <none>           <none>
kube-system      metrics-server-6f4c6675d5-kv8xf             1/1     Running   10 (4m15s ago)   9d      10.42.77.191    master-node      <none>           <none>
metallb-system   controller-58fdf44d87-5n9nv                 1/1     Running   8 (4m1s ago)     8d      10.42.111.39    worker-node001   <none>           <none>
metallb-system   speaker-rbgcw                               1/1     Running   9 (4m15s ago)    8d      192.168.1.188   master-node      <none>           <none>
metallb-system   speaker-zjcj5                               1/1     Running   8 (4m1s ago)     8d      192.168.1.182   worker-node001   <none>           <none>

Serviceリスト

$ sudo kubectl get svc -A -o wide
NAMESPACE        NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP                                          PORT(S)                      AGE    SELECTOR
cert-manager     cert-manager                         ClusterIP      10.43.134.99    <none>                                               9402/TCP                     9d     app.kubernetes.io/component=controller,app.kubernetes.io/instance=cert-manager,app.kubernetes.io/name=cert-manager
cert-manager     cert-manager-cainjector              ClusterIP      10.43.39.28     <none>                                               9402/TCP                     9d     app.kubernetes.io/component=cainjector,app.kubernetes.io/instance=cert-manager,app.kubernetes.io/name=cainjector
cert-manager     cert-manager-webhook                 ClusterIP      10.43.21.173    <none>                                               443/TCP,9402/TCP             9d     app.kubernetes.io/component=webhook,app.kubernetes.io/instance=cert-manager,app.kubernetes.io/name=webhook
default          apache-service                       ClusterIP      10.43.159.102   <none>                                               80/TCP                       5d5h   app=apache
default          kubernetes                           ClusterIP      10.43.0.1       <none>                                               443/TCP                      9d     <none>
default          mariadb-headless                     ClusterIP      None            <none>                                               3306/TCP                     9d     app=mariadb
default          mariadb-service                      ClusterIP      10.43.75.30     <none>                                               3306/TCP                     9d     app=mariadb
default          nginx-service                        ClusterIP      10.43.15.175    <none>                                               80/TCP                       9d     app=nginx
default          php-fpm                              ClusterIP      10.43.220.66    <none>                                               9000/TCP                     9d     app=php-fpm
default          phpmyadmin                           ClusterIP      10.43.26.153    <none>                                               9000/TCP                     9d     app=phpmyadmin
default          redis                                ClusterIP      10.43.22.12     <none>                                               6379/TCP                     9d     app=redis
ingress-nginx    ingress-nginx-controller             LoadBalancer   10.43.115.23    192.168.1.188,240b:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx   80:32078/TCP,443:32592/TCP   8d     app.kubernetes.io/component=controller,app.kubernetes.io/name=ingress-nginx
ingress-nginx    ingress-nginx-controller-admission   ClusterIP      10.43.212.169   <none>                                               443/TCP                      8d     app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
kube-system      kube-dns                             ClusterIP      10.43.0.10      <none>                                               53/UDP,53/TCP,9153/TCP       9d     k8s-app=kube-dns
kube-system      metrics-server                       ClusterIP      10.43.108.148   <none>                                               443/TCP                      9d     k8s-app=metrics-server
metallb-system   metallb-webhook-service              ClusterIP      10.43.49.145    <none>                                               443/TCP                      8d     component=controller