Difference between revisions of "R-Car/k8s-draft"

From eLinux.org
Jump to: navigation, search
(Pod展開手順)
(Kubernetes関連ツールインストール)
 
(21 intermediate revisions by the same user not shown)
Line 9: Line 9:
 
= 環境構築手順 =
 
= 環境構築手順 =
  
1台のR-Car Kubernetes が動作する環境を構築する手順を説明する。
+
1台のR-Car Kubernetes が動作する環境を構築する手順を説明する。
  
 
以下のような流れで環境構築を行う。
 
以下のような流れで環境構築を行う。
Line 224: Line 224:
  
 
<syntaxhighlight lang="text">
 
<syntaxhighlight lang="text">
sudo mkdir /etc/docker
+
# mkdir /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon2.json
+
# cat <<EOF | sudo tee /etc/docker/daemon2.json
 
{
 
{
 
   "exec-opts": ["native.cgroupdriver=systemd"],
 
   "exec-opts": ["native.cgroupdriver=systemd"],
Line 283: Line 283:
 
[[File:K8s-rcar-overview.png|center|caption]]
 
[[File:K8s-rcar-overview.png|center|caption]]
  
<center>'''Figure3.1. k8s Cluster Configuration'''</center>
+
<center>'''Figure3.1.1. k8s Cluster Configuration'''</center>
  
  
 
[[File:Pod-configuration.png|center|caption]]
 
[[File:Pod-configuration.png|center|caption]]
  
<center>'''Figure3.2. Pod Configuration'''</center>
+
<center>'''Figure3.1.2 Pod Configuration'''</center>
  
 
== k8sクラスタ構成手順 ==
 
== k8sクラスタ構成手順 ==
  
HAProxy用1台、master node 用 2台、worker node 用 2台 をそれぞれ設定し、k8sクラスタを構成する手順を説明する。
+
HAProxy用1台、master node 用 2台、worker node 用 2台 をそれぞれ設定し、k8sクラスタを構成する手順を説明する。<br>
事前にすべてのR-Carを起動し、同一ネットワークに接続しておく。
+
事前にすべてのR-Carを起動し、同一ネットワークに接続しておく。<br>
 
(本手順は環境にもよるが30分以上かかる。)
 
(本手順は環境にもよるが30分以上かかる。)
  
Line 544: Line 544:
 
<syntaxhighlight lang="text">
 
<syntaxhighlight lang="text">
 
# kubeadm join 192.168.179.52:6443 --token 21sx8f.t536gdy7uzhk5o2o \
 
# kubeadm join 192.168.179.52:6443 --token 21sx8f.t536gdy7uzhk5o2o \
         --discovery-token-ca-cert-hash sha256:232e02ecc69e4ba4bf5806d6ae7cba591be6b67e4de3973597c069c0a9fc1be1 --node-name work1
+
         --discovery-token-ca-cert-hash sha256:232e02ecc69e4ba4bf5806d6ae7cba591be6b67e4de3973597c069c0a9fc1be1 --node-name work2
 
・・・
 
・・・
 
[preflight] Running pre-flight checks
 
[preflight] Running pre-flight checks
Line 614: Line 614:
 
本手順はコントロールプレーンノード上(master1 または master2)で実施する。
 
本手順はコントロールプレーンノード上(master1 または master2)で実施する。
  
 +
[[File:Pod-configuration.png|center|caption]]
 +
 +
<center>'''Figure3.2 Pod Configuration'''</center>
 +
 +
manifestファイルを作成する。 app.yml という名前で任意の場所に作成し、以下の内容を記載する。以下の定義では 10個のPodを展開する。
 +
 +
<syntaxhighlight lang="text">
 +
cat <<EOF > app.yml
 +
apiVersion: apps/v1
 +
kind: Deployment
 +
metadata:
 +
  name: app
 +
spec:
 +
  replicas: 10
 +
  strategy:
 +
    rollingUpdate:
 +
      maxSurge: 50%
 +
      maxUnavailable: 0%
 +
  minReadySeconds: 5
 +
  selector:
 +
    matchLabels:
 +
      pod: web
 +
  template:
 +
    metadata:
 +
      name: web-pod
 +
      labels:
 +
        pod: web
 +
    spec:
 +
      containers:
 +
      - name: nginx
 +
        image: nginx:1.17.6-alpine
 +
        ports:
 +
        - name: http
 +
          containerPort: 80
 +
 +
---
 +
apiVersion: v1
 +
kind: Service
 +
metadata:
 +
  name: web-service
 +
spec:
 +
  selector:
 +
    pod: web
 +
  ports:
 +
  - port: 8080
 +
    targetPort: http
 +
    nodePort: 30000
 +
  type: NodePort
 +
 +
EOF
 +
</syntaxhighlight>
 +
 +
以下のコマンドを実行し、Podを展開する。
 +
 +
<syntaxhighlight lang="text">
 +
# kubectl apply -f app.yml
 +
deployment.apps/app created
 +
service/web-service created
 +
</syntaxhighlight>
 +
 +
以下のコマンドを実行して展開したPodとServiceの状態を確認する。
 +
 +
<syntaxhighlight lang="text">
 +
# kubectl get pods -o wide
 +
NAME                  READY  STATUS    RESTARTS  AGE  IP            NODE    NOMINATED NODE  READINESS GATES
 +
app-849858b7fd-2cd6d  1/1    Running  0          23m  172.16.215.2  work1  <none>          <none>
 +
app-849858b7fd-hc82t  1/1    Running  0          23m  172.16.123.5  work2  <none>          <none>
 +
app-849858b7fd-k9twv  1/1    Running  0          23m  172.16.215.5  work1  <none>          <none>
 +
app-849858b7fd-kpwq8  1/1    Running  0          23m  172.16.215.4  work1  <none>          <none>
 +
app-849858b7fd-mt77h  1/1    Running  0          23m  172.16.123.1  work2  <none>          <none>
 +
app-849858b7fd-q4pz7  1/1    Running  0          23m  172.16.123.2  work2  <none>          <none>
 +
app-849858b7fd-q7w6m  1/1    Running  0          23m  172.16.123.3  work2  <none>          <none>
 +
app-849858b7fd-qv4t6  1/1    Running  0          23m  172.16.123.4  work2  <none>          <none>
 +
app-849858b7fd-sncpg  1/1    Running  0          23m  172.16.215.1  work1  <none>          <none>
 +
app-849858b7fd-xvhkz  1/1    Running  0          23m  172.16.215.3  work1  <none>          <none>
 +
</syntaxhighlight>
 +
 +
== 動作確認 ==
 +
 +
worker node で 起動しているアプリ(nginx) にアクセスできることを確認する。
 +
 +
=== htmlファイルの書き換え ===
 +
 +
どのアプリにアクセスしたか分かりやすくするために、htmlファイルを編集する。
 +
 +
 +
worker node 上で docker コンテナ名を確認する。
 +
 +
<syntaxhighlight lang="text">
 +
# docker ps
 +
CONTAINER ID        IMAGE                  COMMAND                  CREATED            STATUS              PORTS    NAMES
 +
6e8035242c20        0bc7924c6ae1            "nginx -g 'daemon of…"  27 seconds ago      Up 7 seconds                  k8s_nginx_app-849858b7fd-rvwjb_default_b512a661-1f3d-4535-af5d-1685c560634c_1
 +
a52d96fec203        0bc7924c6ae1            "nginx -g 'daemon of…"  15 minutes ago      Up 14 minutes                  k8s_nginx_app-849858b7fd-jhczv_default_302c64ef-899a-4904-90f8-46f45007d200_0
 +
・・・
 +
</syntaxhighlight>
 +
 +
アプリのindex.html をホスト側にコピーする。
 +
 +
<syntaxhighlight lang="text">
 +
NAME=k8s_nginx_app-849858b7fd-rvwjb_default_b512a661-1f3d-4535-af5d-1685c560634c_1
 +
docker container cp ${NAME}:/usr/share/nginx/html/index.html .
 +
</syntaxhighlight>
 +
 +
index.html を以下のように編集する。
  
# kubectl apply -f app.yml
+
<syntaxhighlight lang="text">
deployment.apps/app created
+
<!DOCTYPE html>
service/web-service created
+
<html>
 +
<head>
 +
<title>Welcome to nginx! Node1-App1</title>
 +
・・・
 +
</syntaxhighlight>
  
# kubectl get pods -o wide
+
index.html を書き戻す
NAME                  READY  STATUS    RESTARTS  AGE  IP            NODE    NOMINATED NODE  READINESS GATES
+
 
app-849858b7fd-2cd6d  1/1    Running  0          23m  172.16.215.2  work1  <none>          <none>
+
<syntaxhighlight lang="text">
app-849858b7fd-hc82t  1/1    Running  0          23m  172.16.123.5  work2  <none>           <none>
+
docker container cp index.html ${NAME}:/usr/share/nginx/html/index.html
  app-849858b7fd-k9twv  1/1    Running  0          23m  172.16.215.5  work1  <none>           <none>
+
</syntaxhighlight>
  app-849858b7fd-kpwq8  1/1    Running  0          23m  172.16.215.4  work1  <none>           <none>
+
 
  app-849858b7fd-mt77h  1/1    Running  0          23m  172.16.123.1  work2  <none>           <none>
+
同様に、すべてのアプリのindex.htmlを編集する。
  app-849858b7fd-q4pz7  1/1    Running  0          23m  172.16.123.2  work2  <none>           <none>
+
 
app-849858b7fd-q7w6m  1/1    Running  0          23m  172.16.123.3  work2  <none>           <none>
+
=== アクセス確認 ===
app-849858b7fd-qv4t6  1/1    Running  0          23m  172.16.123.4  work2  <none>          <none>
+
 
app-849858b7fd-sncpg  1/1    Running  0          23m  172.16.215.1  work1   <none>          <none>
+
同一ネットワーク上のPCから master1 node を介して NodePort にアクセスする。
app-849858b7fd-xvhkz  1/1    Running  0          23m  172.16.215.3  work1  <none>           <none>
+
Node1, Node2 それぞれのアプリケーションに分散してアクセスできることを確認する。
 +
 
 +
<syntaxhighlight lang="text">
 +
$ curl -s 192.168.179.48:30000 | grep title
 +
<title>Welcome to nginx! Node1-App5</title>
 +
$ curl -s 192.168.179.48:30000 | grep title
 +
<title>Welcome to nginx! Node2-App4</title>
 +
$ curl -s 192.168.179.48:30000 | grep title
 +
<title>Welcome to nginx! Node1-App5</title>
 +
$ curl -s 192.168.179.48:30000 | grep title
 +
<title>Welcome to nginx! Node2-App3</title>
 +
</syntaxhighlight>
 +
 
 +
== k8sクラスタの削除手順 ==
 +
 
 +
k8sクラスタを削除する手順を説明する。本手順ではmaster1で実施する手順を記載する。
 +
 
 +
master1で以下のコマンドを実施する。
 +
 
 +
<syntaxhighlight lang="text">
 +
kubectl drain master1 --delete-local-data --force --ignore-daemonsets
 +
kubectl drain master2 --delete-local-data --force --ignore-daemonsets
 +
kubectl drain work1 --delete-local-data --force --ignore-daemonsets
 +
kubectl drain work2 --delete-local-data --force --ignore-daemonsets
 +
 
 +
 
 +
kubectl delete node master1
 +
kubectl delete node master2
 +
kubectl delete node work1
 +
kubectl delete node work2
 +
</syntaxhighlight>
 +
 
 +
次に、各ノード上で以下のコマンドを実施する。
 +
<syntaxhighlight lang="text">
 +
kubeadm reset
 +
</syntaxhighlight>
 +
 
 +
上記の手順を実施せずに電源を落とした場合、次回起動したときに各ノードで kubeadm reset を実施すると、 k8s クラスタを再構築できるようになる。
  
 
= 参考資料 =
 
= 参考資料 =
 +
 +
* Yocto-Gen3/v4.7.0
 +
** https://elinux.org/R-Car/Boards/Yocto-Gen3/v4.7.0
 +
* R-Car on Ubuntu
 +
** https://www.elinux.org/R-Car/Ubuntu
 +
** https://www.elinux.org/R-Car/Ubuntu(J)
 +
* Docker
 +
** https://docs.docker.com/engine/install/ubuntu
 +
* Kubeadm
 +
** https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm
 +
** https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm
 +
** https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/high-availability

Latest revision as of 19:23, 26 April 2021

はじめに

複数のR-Carを用いて、以下の図のようなKubernetesの高可用性クラスタを構築する手順を紹介する

caption
Figure1. k8s on R-Car

環境構築手順

1台のR-Car に Kubernetes が動作する環境を構築する手順を説明する。

以下のような流れで環境構築を行う。

  1. Yocto-Gen3 をビルドする。
  2. 1.のビルドイメージを使用してUbuntu on R-Car をセットアップする。
  3. 2.に Kubernetes をインストールする。
  4. 1.~3.の環境を書き込んだ SD Card を R-Car の台数分コピーする。

概要

本手順の開発環境は以下を使用している。


本手順で1台のR-Car上に構築する環境の概要を以下に示す。

  • OS: Ubuntu 18.04.5 LTS (GNU/Linux 5.4.72-yocto-standard aarch64)
    • Docker: version 19.03.12
    • Kubeadm: version 1.19.0
    • Kubelet: version 1.19.0
    • Kubectl: version 1.19.0
    • HAProxy: version 1.8.8

Yoctoビルド手順

Yoctoビルド手順を説明する。

まず、Yocto-Gen3/v4.7.0/Building the BSP for Renesas H3 Starter Kit, M3 Starter Kit を参考に bitbake core-image-weston の直前まで行う。


Docker が実行するために必要なカーネルオプションを追加する。 docker-config.cfg を新規作成する。

cat <<EOF > meta-renesas/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/docker-config.cfg
CONFIG_CGROUP_FREEZER=y
CONFIG_NETFILTER_XT_MATCH_IPVS=m
CONFIG_IP_VS=m
CONFIG_IP_VS_TAB_BITS=12
CONFIG_IP_VS_SH_TAB_BITS=8
 
CONFIG_BLK_DEV_THROTTLING=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_NET_SCHED=y
CONFIG_NET_CLS=y
CONFIG_NET_CLS_CGROUP=m
CONFIG_NET_SCH_FIFO=y
CONFIG_CGROUP_NET_CLASSID=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_IP_VS_NFCT=y
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_RR=m
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT4_FS_SECURITY=y

CONFIG_XFRM_USER=m
CONFIG_XFRM_ALGO=m
CONFIG_INET_ESP=m
CONFIG_NET_L3_MASTER_DEV=y
CONFIG_IPVLAN=m
CONFIG_DUMMY=m
CONFIG_NF_NAT_FTP=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_NAT_TFTP=m
CONFIG_NF_CONNTRACK_TFTP=m
 
CONFIG_DAX=m
CONFIG_DM_THIN_PROVISIONING=m
CONFIG_SQUASHFS_XZ=y
EOF


Kubernetes が実行するために必要なカーネルオプションを追加する。 kubernetes-config.cfg を新規作成する。

cat <<EOF > meta-renesas/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/kubernetes-config.cfg
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_VS=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_SH=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
CONFIG_NETFILTER_XT_MATCH_RECENT=m
CONFIG_NETFILTER_XT_TARGET_REDIRECT=m
CONFIG_IP_SET=m
CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_NET=m
CONFIG_NETFILTER_XT_MARK=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
EOF


上記 cfg ファイルを適用させるために、linux-renesas_5.4.bb を以下のように修正する。

diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas_5.4.bb b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas_5.4.bb
index 91a3a3e..06abfb9 100644
--- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas_5.4.bb
+++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas_5.4.bb
@@ -27,6 +27,8 @@ KBUILD_DEFCONFIG = "defconfig"
 SRC_URI_append = " \
     file://touch.cfg \
     ${@oe.utils.conditional("USE_AVB", "1", " file://usb-video-class.cfg", "", d)} \
+    file://docker-config.cfg \
+    file://kubernetes-config.cfg \
 "
 
 # Enable RPMSG_VIRTIO depend on ICCOM

ビルドする。

bitbake core-image-minimal

Flashing firmware/In case of DDR 8GiB board の手順に従い、ビルドした firmware を書き込む。(※使用する R-Car の台数分書き込む。)

Ubuntu on R-Car 構築手順

前章で作成したイメージを使用し、R-Car/Ubuntu (R-Car/Ubuntu(日本語))の手順に従ってUbuntu on R-Car 環境を構築する。

NOTE:

  • 本手順では SD Card は 8GB を使用し、パーティション構成は以下に設定しています。
    $ sudo fdisk /dev/mmcblk0
     
    Welcome to fdisk (util-linux 2.31.1).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.
     
     
    Command (m for help): p
    Disk /dev/mmcblk0: 7.2 GiB, 7751073792 bytes, 15138816 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0xde138033
     
    Device         Boot   Start      End  Sectors  Size Id Type
    /dev/mmcblk0p1         2048  2099199  2097152    1G 83 Linux
    /dev/mmcblk0p2      2099200 15138815 13039616  6.2G 83 Linux
    

Kubernetes インストール手順

Dockerインストール

Kubernetes の コンテナとして使用する Docker をインストールする。


まず、カーネルモジュールを読み込み再起動する。

apt install kmod
depmod -a
reboot

Docker をインストールする。

# apt-get update
# apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
OK
# apt-key fingerprint 0EBFCD88
pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]
# add-apt-repository \
   "deb [arch=arm64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
# apt-get update
# VERSION_STRING=5:19.03.12~3-0~ubuntu-bionic
# apt-get install –y docker-ce=${VERSION_STRING} docker-ce-cli=${VERSION_STRING} containerd.io

Kubernetes関連ツールインストール

Kubeadm, Kubelet, Kubectl をインストールする。

# apt-get update && apt-get install -y apt-transport-https curl
# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
# cat <<EOF | tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
# apt-get update
# apt install -y kubelet=1.19.0-00 kubeadm=1.19.0-00 kubectl=1.19.0-00
# apt-mark hold kubelet kubeadm kubectl

https://kubernetes.io/docs/setup/cri/ にしたがって Docker daemon の設定を行う。

# mkdir /etc/docker
# cat <<EOF | sudo tee /etc/docker/daemon2.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

Docker を再起動する。

mkdir -p /etc/systemd/system/docker.service.d
systemctl daemon-reload
systemctl restart docker

HAProxyインストール

コントロールプレーンノード用のロードバランサーとしてHAProxyをインストールする。自動起動は無効にしておく。

apt install -y haproxy
systemctl disable haproxy

SD Card イメージの複製

ここまでに作成した SD Card イメージ を、使用する R-Car の台数分コピーし、それぞれのR-Car で Ubuntu が起動するようにU-bootの設定を行う。

例) dd コマンドを使う場合。

# read
sudo dd if=/dev/mmcblk0 of=kubernetes-rcar-h3ulcb-sdcard-8g.img

# write
sudo dd bs=4M if=kubernetes-rcar-h3ulcb-sdcard-8g.img of=/dev/mmcblk0 conv=fsync

例) U-boot設定内容

setenv bootargs 'root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'run load_ker; run load_dtb; booti 0x48080000 - 0x48000000'
setenv load_dtb 'ext4load mmc 0:1 0x48000000 /boot/r8a7795-h3ulcb-4x2g.dtb'
setenv load_ker 'ext4load mmc 0:1 0x48080000 /boot/Image'
saveenv

使用方法

前章で作成した環境を使用して、以下の図のようなk8sクラスタを構築する手順、Podを展開する手順を説明する。

本手順ではR-CarのIPアドレスは図に記載のIPアドレスで説明する。また、以降の説明ではそれぞれのR-Carを HAProxy, master1, master2, worker1, worker2 と呼ぶ。

caption
Figure3.1.1. k8s Cluster Configuration


caption
Figure3.1.2 Pod Configuration

k8sクラスタ構成手順

HAProxy用1台、master node 用 2台、worker node 用 2台 をそれぞれ設定し、k8sクラスタを構成する手順を説明する。
事前にすべてのR-Carを起動し、同一ネットワークに接続しておく。
(本手順は環境にもよるが30分以上かかる。)

HAProxy設定

R-Car (HAProxy) の設定手順を説明する。本手順はR-Car (HAProxy)上で実施する。

/etc/haproxy/haproxy.cfg を開いて、最後尾に以下の設定を追記する。 master1, master2 のIPアドレスは環境に合わせて変更する。

・・・
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend kubernetes
    bind *:6443
    option tcplog
    mode tcp
    default_backend kubernetes-master-nodes
 
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend kubernetes-master-nodes
    mode tcp
    balance     roundrobin
    option tcp-check
    server  master1 192.168.179.48:6443 check
    server  master2 192.168.179.49:6443 check

HAProxy を起動する

systemctl start haproxy

master1設定

R-Car (master1) の設定手順を説明する。本手順はR-Car (master1)上で実施する。


Kubernetes のデータストア(etcd)をRAM上にマウントする。

mkdir /var/lib/etcd
mount -t tmpfs tmpfs /var/lib/etcd

WARNING! デフォルトではブロックデバイス上(/var/lib/etcd) にデータストアが作成されるが、データストアへアクセス時のタイムアウトエラーが多く発生して動作が安定しない。本手順では、アクセス速度を速くするために、データストアの場所をRAM上に変更する(tmpfsでマウントする)。kubeadm の --config オプションを使ってデータストアのパス変更もできるが、--config オプションは他のオプションと併用できない為、今回は上記の方法を取る。


HAProxy サーバのIPアドレスを設定する。(IPアドレスは環境に合わせて変更する。)

LOAD_BALANCER_DNS=192.168.179.52
LOAD_BALANCER_PORT=6443

1つめのコントロールプレーンノードを初期化する。

# kubeadm init --control-plane-endpoint "${LOAD_BALANCER_DNS}:${LOAD_BALANCER_PORT}" --upload-certs --node-name master1
[init] Using Kubernetes version: v1.21.0
[preflight] Running pre-flight checks
        [WARNING Hostname]: hostname "master1" could not be reached
        [WARNING Hostname]: hostname "master1": lookup master1 on 192.168.179.1:53: no such host
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local master1] and IPs [10.96.0.1 192.168.179.48 192.168.179.52]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost master1] and IPs [192.168.179.48 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost master1] and IPs [192.168.179.48 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[kubelet-check] Initial timeout of 40s passed.
[apiclient] All control plane components are healthy after 92.558093 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.21" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
a7dbea8c50522416fc30be35a8cfd2b72c60d2540c74e6bad5832e3dcf3ff9c9
[mark-control-plane] Marking the node master1 as control-plane by adding the labels: [node-role.kubernetes.io/master(deprecated) node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node master1 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: 21sx8f.t536gdy7uzhk5o2o
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

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 192.168.179.52:6443 --token 21sx8f.t536gdy7uzhk5o2o \
        --discovery-token-ca-cert-hash sha256:232e02ecc69e4ba4bf5806d6ae7cba591be6b67e4de3973597c069c0a9fc1be1 \
        --control-plane --certificate-key a7dbea8c50522416fc30be35a8cfd2b72c60d2540c74e6bad5832e3dcf3ff9c9

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 192.168.179.52:6443 --token 21sx8f.t536gdy7uzhk5o2o \
        --discovery-token-ca-cert-hash sha256:232e02ecc69e4ba4bf5806d6ae7cba591be6b67e4de3973597c069c0a9fc1be1

上記表示にも説明があるように、以下の設定を行う。これでmaster1 で kubectrl が使えるようになる。

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

Podネットワークプラグインをインストールする。本手順では Calico を使用する。

# kubectl apply -f https://docs.projectcalico.org/v3.15/manifests/calico.yaml
configmap/calico-config created
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created
clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrole.rbac.authorization.k8s.io/calico-node created
clusterrolebinding.rbac.authorization.k8s.io/calico-node created
daemonset.apps/calico-node created
serviceaccount/calico-node created
deployment.apps/calico-kube-controllers created
serviceaccount/calico-kube-controllers created
Warning: policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget
poddisruptionbudget.policy/calico-kube-controllers created

master2設定

R-Car (master2) の設定手順を説明する。本手順はR-Car (master2)上で実施する。


Kubernetes のデータストア(etcd)をRAM上にマウントする。

mkdir /var/lib/etcd
mount -t tmpfs tmpfs /var/lib/etcd

2つめのコントロールプレーンノードを初期化する。 master1 のノードを初期化したときに表示されるコントロールプレーンノード用のコマンドを実行する。
(ハッシュ値は環境によって異なるので、環境に合わせて変更する)
( --node-name オプションを追加して node名を指定する)

$ kubeadm join 192.168.179.52:6443 --token 21sx8f.t536gdy7uzhk5o2o \
       --discovery-token-ca-cert-hash sha256:232e02ecc69e4ba4bf5806d6ae7cba591be6b67e4de3973597c069c0a9fc1be1 \
       --control-plane --certificate-key a7dbea8c50522416fc30be35a8cfd2b72c60d2540c74e6bad5832e3dcf3ff9c9 --node-name master2
・・・


以下の設定を行う。これでmaster2 で kubectrl が使えるようになる。

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

worker1設定

R-Car (worker1) の設定手順を説明する。本手順はR-Car (worker1)上で実施する。

1つめのワーカーノードを初期化する。 master1 のノードを初期化したときに表示されるワーカーノード用のコマンドを実行する。
(ハッシュ値は環境によって異なるので、環境に合わせて変更する)
( --node-name オプションを追加して node名を指定する)

# kubeadm join 192.168.179.52:6443 --token 21sx8f.t536gdy7uzhk5o2o \
        --discovery-token-ca-cert-hash sha256:232e02ecc69e4ba4bf5806d6ae7cba591be6b67e4de3973597c069c0a9fc1be1 --node-name work1
・・・
[preflight] Running pre-flight checks
        [WARNING Hostname]: hostname "work1" could not be reached
        [WARNING Hostname]: hostname "work1": lookup work1 on 192.168.179.1:53: no such host
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
 
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
 
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

上記のように表示されればOK。

worker2設定

R-Car (worker2) の設定手順を説明する。本手順はR-Car (worker2)上で実施する。

1つめのワーカーノードを初期化する。 master1 のノードを初期化したときに表示されるワーカーノード用のコマンドを実行する。
(ハッシュ値は環境によって異なるので、環境に合わせて変更する)
( --node-name オプションを追加して node名を指定する)

# kubeadm join 192.168.179.52:6443 --token 21sx8f.t536gdy7uzhk5o2o \
        --discovery-token-ca-cert-hash sha256:232e02ecc69e4ba4bf5806d6ae7cba591be6b67e4de3973597c069c0a9fc1be1 --node-name work2
・・・
[preflight] Running pre-flight checks
        [WARNING Hostname]: hostname "work1" could not be reached
        [WARNING Hostname]: hostname "work1": lookup work1 on 192.168.179.1:53: no such host
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
 
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
 
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

上記のように表示されればOK。

k8sクラスタの状態確認

k8sクラスタの状態を確認し、k8sクラスタの構築が完了するまで待つ。 本手順はコントロールプレーンノード上(master1 または master2)で実施する。

以下のコマンドを実施し、k8sクラスタを構成するコンテナの状態を確認する。 以下のように STATUS がすべてRunning になるまで待つ。

# kubectl get pods -A -o wide
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATES
kube-system   calico-kube-controllers-7d66c56c96-hh5tx   1/1     Running   0          40m   172.16.137.66    master1   <none>           <none>
kube-system   calico-node-55ndb                          0/1     Running   0          25m   192.168.179.49   master2   <none>           <none>
kube-system   calico-node-8lrcm                          1/1     Running   0          14m   192.168.179.50   work1     <none>           <none>
kube-system   calico-node-9nsv5                          0/1     Running   0          40m   192.168.179.48   master1   <none>           <none>
kube-system   calico-node-s2tnv                          0/1     Running   0          13m   192.168.179.51   work2     <none>           <none>
kube-system   coredns-f9fd979d6-5f4pj                    1/1     Running   0          40m   172.16.137.65    master1   <none>           <none>
kube-system   coredns-f9fd979d6-pd7lm                    1/1     Running   0          40m   172.16.137.67    master1   <none>           <none>
kube-system   etcd-master1                               1/1     Running   1          40m   192.168.179.48   master1   <none>           <none>
kube-system   etcd-master2                               1/1     Running   0          22m   192.168.179.49   master2   <none>           <none>
kube-system   kube-apiserver-master1                     1/1     Running   4          40m   192.168.179.48   master1   <none>           <none>
kube-system   kube-apiserver-master2                     1/1     Running   0          22m   192.168.179.49   master2   <none>           <none>
kube-system   kube-controller-manager-master1            1/1     Running   1          40m   192.168.179.48   master1   <none>           <none>
kube-system   kube-controller-manager-master2            1/1     Running   0          22m   192.168.179.49   master2   <none>           <none>
kube-system   kube-proxy-d8gm5                           1/1     Running   0          14m   192.168.179.50   work1     <none>           <none>
kube-system   kube-proxy-gq6l4                           1/1     Running   0          40m   192.168.179.48   master1   <none>           <none>
kube-system   kube-proxy-klhmd                           1/1     Running   1          13m   192.168.179.51   work2     <none>           <none>
kube-system   kube-proxy-l8w5k                           1/1     Running   0          25m   192.168.179.49   master2   <none>           <none>
kube-system   kube-scheduler-master1                     1/1     Running   1          40m   192.168.179.48   master1   <none>           <none>
kube-system   kube-scheduler-master2                     1/1     Running   0          22m   192.168.179.49   master2   <none>           <none>

また、以下のコマンドを実行して各ノードのSTATUSが Ready になっていることを確認する。

# kubectl get nodes -o wide
NAME       STATUS   ROLES    AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION                CONTAINER-RUNTIME
master1    Ready    master   19m   v1.19.0   192.168.179.48   <none>        Ubuntu 18.04.5 LTS   4.14.75-ltsi-yocto-standard   docker://19.3.12
master2    Ready    master   16m   v1.19.0   192.168.179.49   <none>        Ubuntu 18.04.5 LTS   4.14.75-ltsi-yocto-standard   docker://19.3.12
work1      Ready    <none>   11m   v1.19.0   192.168.179.50   <none>        Ubuntu 18.04.5 LTS   4.14.75-ltsi-yocto-standard   docker://19.3.12
work2      Ready    <none>   10m   v1.19.0   192.168.179.51   <none>        Ubuntu 18.04.5 LTS   4.14.75-ltsi-yocto-standard   docker://19.3.12

Pod展開手順

以下のような構成で nginx Podを複数展開する手順を説明する。 本手順はコントロールプレーンノード上(master1 または master2)で実施する。

caption
Figure3.2 Pod Configuration

manifestファイルを作成する。 app.yml という名前で任意の場所に作成し、以下の内容を記載する。以下の定義では 10個のPodを展開する。

cat <<EOF > app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  replicas: 10
  strategy:
    rollingUpdate:
      maxSurge: 50%
      maxUnavailable: 0%
  minReadySeconds: 5
  selector:
    matchLabels:
      pod: web
  template:
    metadata:
      name: web-pod
      labels:
        pod: web
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.6-alpine
        ports:
        - name: http
          containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    pod: web
  ports:
  - port: 8080
    targetPort: http
    nodePort: 30000
  type: NodePort

EOF

以下のコマンドを実行し、Podを展開する。

# kubectl apply -f app.yml
deployment.apps/app created
service/web-service created

以下のコマンドを実行して展開したPodとServiceの状態を確認する。

# kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
app-849858b7fd-2cd6d   1/1     Running   0          23m   172.16.215.2   work1   <none>           <none>
app-849858b7fd-hc82t   1/1     Running   0          23m   172.16.123.5   work2   <none>           <none>
app-849858b7fd-k9twv   1/1     Running   0          23m   172.16.215.5   work1   <none>           <none>
app-849858b7fd-kpwq8   1/1     Running   0          23m   172.16.215.4   work1   <none>           <none>
app-849858b7fd-mt77h   1/1     Running   0          23m   172.16.123.1   work2   <none>           <none>
app-849858b7fd-q4pz7   1/1     Running   0          23m   172.16.123.2   work2   <none>           <none>
app-849858b7fd-q7w6m   1/1     Running   0          23m   172.16.123.3   work2   <none>           <none>
app-849858b7fd-qv4t6   1/1     Running   0          23m   172.16.123.4   work2   <none>           <none>
app-849858b7fd-sncpg   1/1     Running   0          23m   172.16.215.1   work1   <none>           <none>
app-849858b7fd-xvhkz   1/1     Running   0          23m   172.16.215.3   work1   <none>           <none>

動作確認

worker node で 起動しているアプリ(nginx) にアクセスできることを確認する。

htmlファイルの書き換え

どのアプリにアクセスしたか分かりやすくするために、htmlファイルを編集する。


worker node 上で docker コンテナ名を確認する。

# docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS    NAMES
6e8035242c20        0bc7924c6ae1            "nginx -g 'daemon of…"   27 seconds ago      Up 7 seconds                   k8s_nginx_app-849858b7fd-rvwjb_default_b512a661-1f3d-4535-af5d-1685c560634c_1
a52d96fec203        0bc7924c6ae1            "nginx -g 'daemon of…"   15 minutes ago      Up 14 minutes                  k8s_nginx_app-849858b7fd-jhczv_default_302c64ef-899a-4904-90f8-46f45007d200_0
・・・

アプリのindex.html をホスト側にコピーする。

NAME=k8s_nginx_app-849858b7fd-rvwjb_default_b512a661-1f3d-4535-af5d-1685c560634c_1
docker container cp ${NAME}:/usr/share/nginx/html/index.html .

index.html を以下のように編集する。

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx! Node1-App1</title>
・・・

index.html を書き戻す

docker container cp index.html ${NAME}:/usr/share/nginx/html/index.html

同様に、すべてのアプリのindex.htmlを編集する。

アクセス確認

同一ネットワーク上のPCから master1 node を介して NodePort にアクセスする。 Node1, Node2 それぞれのアプリケーションに分散してアクセスできることを確認する。

$  curl -s 192.168.179.48:30000 | grep title
<title>Welcome to nginx! Node1-App5</title>
$  curl -s 192.168.179.48:30000 | grep title
<title>Welcome to nginx! Node2-App4</title>
$  curl -s 192.168.179.48:30000 | grep title
<title>Welcome to nginx! Node1-App5</title>
$  curl -s 192.168.179.48:30000 | grep title
<title>Welcome to nginx! Node2-App3</title>

k8sクラスタの削除手順

k8sクラスタを削除する手順を説明する。本手順ではmaster1で実施する手順を記載する。

master1で以下のコマンドを実施する。

kubectl drain master1 --delete-local-data --force --ignore-daemonsets
kubectl drain master2 --delete-local-data --force --ignore-daemonsets
kubectl drain work1 --delete-local-data --force --ignore-daemonsets
kubectl drain work2 --delete-local-data --force --ignore-daemonsets


kubectl delete node master1
kubectl delete node master2
kubectl delete node work1
kubectl delete node work2

次に、各ノード上で以下のコマンドを実施する。

kubeadm reset

上記の手順を実施せずに電源を落とした場合、次回起動したときに各ノードで kubeadm reset を実施すると、 k8s クラスタを再構築できるようになる。

参考資料