💬

kubeadmでのkubernetes構築

2022/11/09に公開約16,300字

はじめに

HAproxyを利用した高可用性のk8s環境を作ります。
構成は以下です。LBはHaproxy+keepalivedで動作させます。
OSはRasberryPi OS/Ubuntu22.04で試しています。
k8s-lb01 / k8s-lb02
k8s-master01 / k8s-master02 / k8s-master03
k8s-worker01 / k8s-worker02 / k8s-worker03

/etc/hostsは以下の通りになっています。

192.168.1.151 k8s-lb01
192.168.1.152 k8s-lb02
192.168.1.153 k8s-lbvip
192.168.1.154 k8s-master01
192.168.1.155 k8s-master02
192.168.1.156 k8s-master03
192.168.1.157 k8s-worker01
192.168.1.158 k8s-worker02
192.168.1.159 k8s-worker03

SSDの起動

SDカードに書き込みしたRasberryPi OSをSSDに書き込みします。
SDカードで起動を実施した上で、rpi-cloneでSSDにコピーを取ります。

# git clone https://github.com/billw2/rpi-clone.git
# cd rpi-clone/
# cp rpi-clone rpi-clone-setup /usr/local/sbin/
# rpi-clone sda -f
Initialize and clone to the destination disk sda? (yes/no):yes
Optional destination ext type file system label (16 chars max): yes
Hit Enter when ready to unmount the /dev/sda partitions ...
最後にEnterを押してUnmountします。

SSDから起動するために、raspi-configを使ってSSDを優先して起動するようにします。
SSDからの起動方法ならびに、以前Ubuntu版の場合でのSSD起動方法は以下で記載しているので、そちらを参考にしてください。
https://zenn.dev/nnagashima/articles/a89b3496344cd7

事前準備

対象:k8s-master01 / k8s-master02 / k8s-master03 / k8s-worker01 / k8s-worker02 / k8s-worker03

cgroupsの設定をするために、カーネルパラメータを編集します。
Controle Groupの略で、プロセスをグループ化して、利用を制限をかけることができるLinuxのカーネル機能になります。
cgroupがk8sでいくつか利用されているので、設定有効化後にOS再起動します。
またSWAPも無効化します。

# swapoff -a
# systemctl stop dphys-swapfile
# systemctl disable dphys-swapfile
# systemctl status dphys-swapfile
# sed -i 's/$/ cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory/g' /boot/cmdline.txt 
# reboot

Dockerランタイムの非推奨化のためCRIランタイムのインストールするための準備します。
CRIランタイムにはcontainerdとCRI-Oがありますが、ラズパイで動かしているということもあり軽量と言われているCRI-Oを採用しました。
また記事作成時点ではCRI-Oが1.25.1しかでていないので、 k8sも同じく1.25.1で構築しています。

# cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# modprobe overlay
# modprobe br_netfilter
# cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

# sysctl --system
# echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
# echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.25:/1.25.1/Debian_11/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:1.25.1.list
# curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:1.25.1/Debian_11/Release.key | apt-key add -
# curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/Release.key | apt-key add -
# apt update
# apt install cri-o cri-o-runc
# systemctl daemon-reload
# systemctl start crio'
# systemctl enable crio

参考までにcontainerdの方法も記載します。

# apt update && apt install -y apt-transport-https ca-certificates curl software-properties-common
# curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# mkdir -p /etc/apt/keyrings
# curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# apt update
# apt install containerd.io
# mkdir -p /etc/containerd
# containerd config default | sudo tee /etc/containerd/config.toml
# systemctl restart containerd
# systemctl enable containerd

HTTPS経由でリポジトリを使用aptできるようaptに、パッケージインデックスを更新してパッケージをインストールします。
k8sのGPGキーを追加し、その後kubeadm/kubelet/kubectlをインストールしバージョンを固定します。

# cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

# sysctl --system
# apt install -y apt-transport-https curl
# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
# cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF

# apt update
# apt install -y kubelet=1.25.1-00 kubeadm=1.25.1-00 kubectl=1.25.1-00
# apt-mark hold kubelet kubeadm kubectl

LBの構築

対象:k8s-lb01 / k8s-lb02

HAproxyとKeepAlibedをインストールします。

# apt install haproxy keepalived openssl

HAproxyの設定をしていきます。

# mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.org
# cat /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  http-in
    bind *:80
    mode  http
    stats enable
    stats auth admin:adminpassword
    stats hide-version
    stats show-node
    stats refresh 60s
    stats uri /haproxy?stats

frontend k8s
    bind *:8443
    mode               tcp
    default_backend    k8s_backend

backend k8s_backend
    balance            roundrobin
    server             k8s-master01 192.168.1.154:6443 check
    server             k8s-master02 192.168.1.155:6443 check
    server             k8s-master03 192.168.1.156:6443 check

HAproxyの冗長化のためにkeepalivedの設定をします。
なお、もう片方のLB側ではpriority 100にしてください。
数字が高い方が優先になります。

# cat /etc/keepalived/keepalived.conf 
vrrp_script chk_haproxy {
    script "systemctl is-active haproxy"
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 1
    priority 101
    virtual_ipaddress {
        192.168.1.153
    }
    track_script {
        chk_haproxy
    }
}

HAporxyとkeepalivedを起動と自動起動設定します。

# systemctl restart haproxy keepalived
# systemctl enable haproxy keepalived

k8sクラスタの構築

対象:k8s-master01

# kubeadm init --control-plane-endpoint "k8s-lbvip:8443" --pod-network-cidr=10.224.0.0/16 --upload-certs 

備考:
kubeadm-certsのSecretと復号キーは2時間で期限切れとなります。
--control-plane-endpointは、用意したLBのVIPを指定します。
--pod-network-cidrは、各自で使いたいNetworkアドレスを指定してください。

終了すると以下のように出力されます。

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of the control-plane node running the following command on each as root:

  kubeadm join k8s-lbvip:8443 --token *********************** \
        --discovery-token-ca-cert-hash *********************** \
        --control-plane --certificate-key ***********************

Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join k8s-lbvip:8443 --token *********************** \
        --discovery-token-ca-cert-hash ***********************

出力された内容に従って以下を実施します。

# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config
# export KUBECONFIG=/etc/kubernetes/admin.conf

続いて他のMasterサーバをJOINさせていきます。

対象:k8s-master02 / 対象:k8s-master03

# kubeadm join k8s-lbvip:8443 --token *********************** \
        --discovery-token-ca-cert-hash *********************** \
        --control-plane --certificate-key ***********************

# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config

続いてWokrerサーバをJOINさせていきます。

対象:k8s-worker01 / 対象:k8s-worker02 / k8s-worekr03

# kubeadm join k8s-lbvip:8443 --token *********************** \
        --discovery-token-ca-cert-hash ***********************

最後にPodやNodeの状態を確認します。

対象:k8s-master01

# kubectl get node
NAME                  STATUS   ROLES           AGE   VERSION
k8s-master01   Ready    control-plane   16h   v1.25.1
k8s-master02   Ready    control-plane   15h   v1.25.1
k8s-master03   Ready    control-plane   15h   v1.25.1
k8s-worker01   Ready    <none>          15h   v1.25.1
k8s-worker02   Ready    <none>          15h   v1.25.1
k8s-worker03   Ready    <none>          15h   v1.25.1

# kubectl get pods -A
kube-system        coredns-565d847f94-br6jq                      1/1     Running   0                16h
kube-system        coredns-565d847f94-t8qjf                      1/1     Running   0                16h
kube-system        etcd-k8s-master01                             1/1     Running   0                16h
kube-system        etcd-k8s-master02                             1/1     Running   0                15h
kube-system        etcd-k8s-master03                             1/1     Running   0                15h
kube-system        kube-apiserver-k8s-master01                   1/1     Running   0                16h
kube-system        kube-apiserver-k8s-master02                   1/1     Running   0                15h
kube-system        kube-apiserver-k8s-master03                   1/1     Running   0                15h
kube-system        kube-controller-manager-k8s-master01          1/1     Running   0                16h
kube-system        kube-controller-manager-k8s-master02          1/1     Running   0                15h
kube-system        kube-controller-manager-k8s-master03          1/1     Running   0                15h
kube-system        kube-proxy-4lbdk                              1/1     Running   0                16h
kube-system        kube-proxy-98zqb                              1/1     Running   0                15h
kube-system        kube-proxy-n2q6f                              1/1     Running   0                15h
kube-system        kube-proxy-nfzqw                              1/1     Running   0                15h
kube-system        kube-proxy-rqlr5                              1/1     Running   0                15h
kube-system        kube-proxy-zk4ch                              1/1     Running   0                15h
kube-system        kube-scheduler-k8s-master01                   1/1     Running   0                16h
kube-system        kube-scheduler-k8s-master02                   1/1     Running   0                15h
kube-system        kube-scheduler-k8s-master03                   1/1     Running   0                15h

最後にPod間の通信をするために今回ではCalicoを使用します。

# curl https://docs.projectcalico.org/manifests/calico.yaml -O
# export POD_CIDR="10.224.0.0/16"
# cp -ap calico.yaml calico.yaml.org
# sed -i -e "s?192.168.0.0/16?$POD_CIDR?g" calico.yaml
# kubectl apply -f calico.yaml
# kubectl get pods -A | grep calico
kube-system      calico-kube-controllers-798cc86c47-bqr95      1/1     Running   0          12m
kube-system      calico-node-dblnq                             1/1     Running   0          12m
kube-system      calico-node-dczc5                             1/1     Running   0          12m
kube-system      calico-node-l5b7t                             1/1     Running   0          12m
kube-system      calico-node-pr4pq                             1/1     Running   0          12m
kube-system      calico-node-qqjcv                             1/1     Running   0          12m
kube-system      calico-node-tr9vl                             1/1     Running   0          12m

これでクラスタの構築は終わりとなります。

LBのインストール

以下の通りにインストールを進めていきます。
https://metallb.universe.tf/installation/

# curl -O https://raw.githubusercontent.com/metallb/metallb/v0.13.5/config/manifests/metallb-native.yaml
# kubectl apply -f metallb-native.yaml
# kubectl get all -n metallb-system
NAME                              READY   STATUS    RESTARTS   AGE
pod/controller-8689779bc5-lpvvr   1/1     Running   0          6m13s
pod/speaker-49zrd                 1/1     Running   0          6m13s
pod/speaker-88d6b                 1/1     Running   0          6m13s
pod/speaker-j5vpz                 1/1     Running   0          6m13s
pod/speaker-jlnhc                 1/1     Running   0          6m13s
pod/speaker-qmnxb                 1/1     Running   0          6m13s
pod/speaker-vxfhn                 1/1     Running   0          6m13s

NAME                      TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/webhook-service   ClusterIP   10.104.67.25   <none>        443/TCP   6m13s

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

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   1/1     1            1           6m13s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-8689779bc5   1         1         1       6m13s

コンテナの動作テスト

hostnameが返答されるコンテナを起動するためのYAMLファイルを作成します。
こちらのものを動作テストに流用させて頂きました。

# cat sample.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-prod
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: pool-ips
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.210-192.168.1.215 # 外部IPレンジ(この中から適当に外部IPが選ばれる)
  autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: pool-ips
  namespace: metallb-system
spec:
  ipAddressPools:
  - pool-ips
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-lb # Service(LoadBalancer) の名前
  namespace: nginx-prod
  annotations:
    metallb.universe.tf/address-pool: pool-ips # MetallbのIPプール名
spec:
  type: LoadBalancer
  ports:
    - name: nginx-service-lb
      protocol: TCP
      port: 8080 # ServiceのIPでlistenするポート
      nodePort: 30080 # nodeのIPでlistenするポート(30000-32767)
      targetPort: 80 # 転送先(コンテナ)でlistenしているPort番号のポート
  selector: # service のselctorは、matchLabels 扱いになる
    app: nginx-pod # 転送先の Pod のラベル
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment # Deployment の名前(ReplicaSetの名前もこれになる)
  namespace: nginx-prod
spec:
  selector:
    matchLabels: # ラベルがマッチしたPodを対象とするReplicaSetの作成
      app: nginx-pod
  replicas: 2
  template: # Pod のテンプレート
    metadata:
      name: nginx-pod # Pod の名前
      namespace: nginx-prod
      labels: # Pod のラベル
        app: nginx-pod
    spec:
      containers: # コンテナの設定
        - name: nginx-container # コンテナの名前
          image: yasthon/nginx-display-hostname # イメージの名前
          env:
            - name: nginx-container
          ports:
            - containerPort: 80 # コンテナのポート
          volumeMounts:
            - name: file-hostname
              mountPath: /usr/share/nginx/html/hostname
      volumes:
        - name: file-hostname
          hostPath:
            path: /etc/hostname

EXTERNAL-IPに割り当ててられたことを確認します。

# kubectl get svc -n nginx-prod
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
nginx-service-lb   LoadBalancer   10.103.208.31   192.168.1.210   8080:30080/TCP   8m1s

URLをチェックして、ノード名が2つ返ってくることを確認します。

# curl 192.168.1.210:8080/index.sh
<html><head>
<title>rayras-k8s-worker01</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head><body>
HOSTNAME : rayras-k8s-worker01
</body></html>

# curl 192.168.1.210:8080/index.sh
<html><head>
<title>rayras-k8s-worker02</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head><body>
HOSTNAME : rayras-k8s-worker02
</body></html>

これでk8sクラスタ構成が作成できました。
この基盤を利用して色々勉強していきたいと思います。

終わり。

GitHubで編集を提案

Discussion

ログインするとコメントできます