LoginSignup
2
5

More than 5 years have passed since last update.

MetalLBでKubernetesのtype:LoadBalancerを有効化させるときに嵌まったこと

Last updated at Posted at 2018-12-30

タイトルについては最下部あたりに見出し付きで記述(本記事自体は構築手順メモ)。
MetalLBをfirewalld有効下で使おうとしたところ少し詰まったので今後のために。

構成

ハードウェア

type spec remarks
Masterノード 2コア、8GB RAM、64GB HDD × 3台 m1 10.0.3.1 / m2 10.0.3.2 / m3 10.0.3.3
Workerノード 2コア、8GB RAM、64GB HDD × 3台 w1 10.0.3.4 / w2 10.0.3.5 / w3 10.0.3.6
LBノード 1コア、2GB RAM、16GB HDD × 2台 lb1 10.0.3.11 / lb2 10.0.3.12

ソフトウェア

  • CentOS 7.6
  • Kubernetes v1.13.1
  • Weave v1.10

ネットワーク

range remarks
10.0.0.0/16 existing private network
10.0.3.0/24 Kubernetes infrastructure
10.0.4.0/24 MetalLB External IP
  • DHCP, DNSサーバ側でホスト名、IPは固定済

参考にした記事、URL等

以降、公式手順書/HAに具体的手順が記載されていなかった部分や、やや相違ある部分はマークつける。

Kubernetes構築

LB構築

まずはkubeapi endpointの冗長化から。このサイトが分かりやすい。
※今回はkeepalivedを用いたものの、ifcfgを弄る方法でも良いんじゃないかと思った

HAProxyについてはこちらこの辺を参考に設定した。

下記はLBノード(lb1 10.0.3.11, lb2 10.0.3.12)に対しての設定例。

yum -y update
yum -y install ntpdate haproxy keepalived
# 時間がサーバによってずれているとTLSハンドシェイクが失敗したりするので
ntpdate ntp.nict.jp
systemctl enable ntpdate
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
# keepalived
mv /etc/keepalived/keepalived.conf{,.org}
cat <<EOF > /etc/keepalived/keepalived.conf
global_defs {
   notification_email {
   }
}

vrrp_instance keepalive {
    state BACKUP
    interface ens192
    virtual_router_id 10
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass arbitraryPassword
    }
    virtual_ipaddress {
        10.0.3.10
    }
}
EOF
# haproxy
mv /etc/haproxy/haproxy.cfg{,.org}
cat <<EOF > /etc/haproxy/haproxy.cfg
 global
    log         127.0.0.1 local2 info
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     256
    user        haproxy
    group       haproxy
    daemon

defaults
    mode               tcp
    log                global
    option             tcplog
    timeout connect    10s
    timeout client     30s
    timeout server     30s

frontend kubeapi6443
    bind *:6443
    default_backend    backend6443

frontend kubeapi10250
    bind *:10250
    default_backend backend10250

backend backend6443
    option redispatch
    retries 1
    balance            roundrobin
    server             m1 10.0.3.1:6443 check
    server             m2 10.0.3.2:6443 check
    server             m3 10.0.3.3:6443 check

backend backend10250
    option redispatch
    retries 1
    balance            roundrobin
    server             m1 10.0.3.1:10250 check
    server             m2 10.0.3.2:10250 check
    server             m3 10.0.3.3:10250 check
EOF
systemctl start keepalived haproxy
systemctl enable keepalived haproxy
firewall-cmd --zone=public --add-port=6443/tcp --add-port=10250/tcp --permanent
firewall-cmd --reload

構築後、nc -v 10.0.3.10 6443で、lb 10.0.3.10まで疎通確認(Masterノード構築まではちゃんとは繋がらない)。

Master/Workerノード共通

ほぼ公式手順書のまま。
Dockerの導入とipv4.ip_forwardの追加くらい。

yum -y update
yum -y install ntpdate yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum -y install docker-ce
ntpdate ntp.nict.jp
systemctl start ntpdate docker
systemctl enable ntpdate docker
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable kubelet

Masterノード(m1 10.0.3.1)

公式手順書/HAでは開放対象ポートが足りなかったり、CNI(Weave)のURLがやや古かったり。

for x in {m,w}{1,2,3}; do echo for $x; ssh $x yes y ¥| ssh-keygen -q -t rsa -N '' ¥> /dev/null; ssh $x "cat >> .ssh/authorized_keys" < .ssh/id_rsa.pub; ssh $x firewall-cmd --zone=public --add-port={6443/tcp,2379/tcp,2380/tcp,10250/tcp,10251/tcp,10252/tcp,30000-32767/tcp,6783/tcp,6783/udp,6784/udp,53/udp} --add-masquerade --permanent; firewall-cmd --reload; systemctl start kubelet; done
cat <<EOF > kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: stable
apiServer:
  certSANs:
  - "lb"
controlPlaneEndpoint: "lb:6443"
EOF
kubeadm init --config=kubeadm-config.yaml
kubectl apply -f https://cloud.weave.works/k8s/v1.10/net.yaml
kubectl get pod -n kube-system -w
cat <<EOF > copy.sh
USER=root # customizable
CONTROL_PLANE_IPS="m2 m3"
for host in ${CONTROL_PLANE_IPS}; do
    ssh $host mkdir -p /etc/kubernetes/pki/etcd
    scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:/etc/kubernetes/pki/
    scp /etc/kubernetes/pki/ca.key "${USER}"@$host:/etc/kubernetes/pki/
    scp /etc/kubernetes/pki/sa.key "${USER}"@$host:/etc/kubernetes/pki/
    scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:/etc/kubernetes/pki/
    scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:/etc/kubernetes/pki/
    scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:/etc/kubernetes/pki/
    scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:/etc/kubernetes/pki/etcd/
    scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:/etc/kubernetes/pki/etcd/
    scp /etc/kubernetes/admin.conf "${USER}"@$host:/etc/kubernetes/
    ssh $host mkdir -p .kube
    ssh $host cp /etc/kubernetes/admin.conf .kube/config
done
EOF
chmod a+x copy.sh
./copy.sh

途中、kubeadm init ...実行時に得られたkubeadm join lb:6443 ...はメモしておく。

Masterノード(その他)

kubeadm join lb:6443 ... --experimental-control-plane

Workerノード

kubeadm join lb:6443 ...

構築後確認

kubectl get pods -n kube-systemでRunning以外のステータスが上がる場合は正常に起動できていない。
describeで原因詳細を確認し対応するか、面倒なら当該Masterノード上で

systemctl stop kubelet
docker stop `docker ps | awk '{print $1}' | grep -v C`
docker rm `docker ps -a | awk '{print $1}' | grep -v C`
systemctl start kubelet

を叩くなどして一旦kubeletの初期化を試みてみる。

MetalLB導入

kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml
cat <<EOF > configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 10.0.4.1-10.0.4.254
EOF
kubectl apply -f configmap.yaml
kubectl get pods -n metallb-system -w

controllerがContainerCreatingで止まる

手順に沿えば難しくないはずなのだが、controllerが下記ContainerCreatingで止まる現象に悩まされた。

[root@m1 ~]# kubectl get pods -n metallb-system
NAME                          READY   STATUS              RESTARTS   AGE
controller-7cc9c87cfb-9q8rj   0/1     ContainerCreating   0          2m13s
speaker-b7k5m                 1/1     Running             0          2m13s
speaker-c9kb7                 1/1     Running             0          2m13s
speaker-qv8xb                 1/1     Running             0          2m13s

しばらく放置するとEventsにrpc error: code = DeadlineExceeded desc = context deadline exceededの文字が。
yum install dockerでCentOS公式リポジトリからdockerをインストールしていたのが原因だった。恥ずかしい。

[root@m1 ~]# kubectl describe pod controller-7d94c7b8c5-plrxh -n metallb-system
Name:               controller-7d94c7b8c5-plrxh
Namespace:          metallb-system
Priority:           0
PriorityClassName:  <none>
Node:               w2/10.0.3.5
Start Time:         Sun, 30 Dec 2018 17:21:37 +0900
Labels:             app=metallb
                    component=controller
                    pod-template-hash=7d94c7b8c5
Annotations:        prometheus.io/port: 7472
                    prometheus.io/scrape: true
Status:             Pending
IP:                 
Controlled By:      ReplicaSet/controller-7d94c7b8c5
Containers:
  controller:
    Container ID:  
    Image:         metallb/controller:v0.7.2
    Image ID:      
    Port:          7472/TCP
    Host Port:     0/TCP
    Args:
      --port=7472
      --config=config
    State:          Waiting
      Reason:       ContainerCreating
    Ready:          False
    Restart Count:  0
    Limits:
      cpu:     100m
      memory:  100Mi
    Requests:
      cpu:        100m
      memory:     100Mi
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from controller-token-m7x87 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  controller-token-m7x87:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  controller-token-m7x87
    Optional:    false
QoS Class:       Guaranteed
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason                  Age   From                      Message
  ----     ------                  ----  ----                      -------
  Normal   Scheduled               4m3s  default-scheduler         Successfully assigned metallb-system/controller-7d94c7b8c5-plrxh to w2
  Warning  FailedCreatePodSandBox  2s    kubelet, w2  Failed create pod sandbox: rpc error: code = DeadlineExceeded desc = context deadline exceeded
  Normal   SandboxChanged          2s    kubelet, w2  Pod sandbox changed, it will be killed and re-created.

その他にも健全に起動していたと思っていたkube-system + weaveも、下記コマンドを実行するとやたらにdial tcp4 :0->10.0.3.1:6783: connect: no route to host, retry...を吐く。

for i in $(kubectl get pods -n kube-system | grep weave | awk '{ print $1}'); do kubectl get pods $i -o wide -n kube-system; kubectl exec -n kube-system $i -c weave -- /home/weave/weave --local status connections; done

こちらもWeave側のサイトに下記注記があったので自身の確認不足。

Note: If there is a firewall between $HOST1 and $HOST2, you must permit traffic to flow through TCP 6783 and UDP 6783/6784, which are Weave’s control and data ports.

いつまで経ってもExternalIPがアサインされない

全てRunningになったのを確認した後、チュートリアルのnginxをデプロイしてみるも、いつまでたってもserviceにExternalIPが割り当てられず、pendingのままとなった。

下記コマンドを実行したところ53/udp宛通信破棄やno route to host...を確認したため、53/udpへのアクセスとmasquerade許可設定を追加したところ、解消した。

# firewall-cmd --set-log-denied all
# tail -100 /var/log/messages | grep REJECT | tail -1
Dec 30 20:17:55 m1 kernel: FINAL_REJECT: IN=weave OUT=weave PHYSIN=vethwe-bridge PHYSOUT=vethwepl51affd6 MAC=ee:f0:1f:bd:27:85:06:ae:ab:d3:75:25:08:00 SRC=10.0.3.4 DST=10.32.0.13 LEN=82 TOS=0x00 PREC=0x00 TTL=64 ID=44486 PROTO=UDP SPT=39203 DPT=53 LEN=62 
# kubectl logs -l component=controller -n metallb-system
{"caller":"reflector.go:205","level":"error","msg":"go.universe.tf/metallb/internal/k8s/k8s.go:237: Failed to list *v1.ConfigMap: Get https://10.96.0.1:443/api/v1/namespaces/metallb-system/configmaps?fieldSelector=metadata.name%3Dconfig\u0026limit=500\u0026resourceVersion=0: dial tcp 10.96.0.1:443: getsockopt: no route to host","ts":"2018-12-30T11:05:13.674244Z"}
{"caller":"reflector.go:205","level":"error","msg":"go.universe.tf/metallb/internal/k8s/k8s.go:231: Failed to list *v1.Service: Get https://10.96.0.1:443/api/v1/services?limit=500\u0026resourceVersion=0: dial tcp 10.96.0.1:443: getsockopt: no route to host","ts":"2018-12-30T11:05:13.674466Z"}
2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5