LoginSignup
0
0

Kubernetes The Easy Way(Kubeadm編) 

Last updated at Posted at 2021-09-22

始めに

Kubernetesへの理解を深めるために役に立つ物としてKubernetes The Hard Wayというチュートリアルがあります1。自動化ツール無しでkubernetesクラスターを構築することでKubernetesの構造を学べます。この記事はkubeadmを使って と上記のチュートリアルと同じクラスターを立ち上げて見ることでThe Hard Wayの理解を深める事を目的とします。

基本的にはThe Hard Wayの流れに沿って記述します。なるべく元の設定に寄せますが不必要だと思う所は修正を加えた後に注意書きでお知らせします。もとのチュートリアルと同じくGoogle Cloud Platform上で3つのmasterと3つのworkerを持つクラスターを構築します。作業環境はGoogle CloudCloud Shellを使います。

自分もただKubernetesについて勉強している途中ですので間違ってる所や無駄な部分が多々あると思います。お気づきの点などございましたら、ご指摘いただけると幸いです。

Prerequisites

gcloudのcommand-line toolを使う基本的な設定を行います。違いはありません。

command-line
(
gcloud config set compute/region us-west1
gcloud config set compute/zone us-west1-c
)

Installing the Client Tools

要りません。

Provisioning Compute Resources

ネットワークのセッティングとVMインスタンスを立ち上げます。

Networking

ファイアウォール規則がちょっと違います。

command-line
(
gcloud compute networks create kubernetes-the-easy-way --subnet-mode custom

gcloud compute networks subnets create kubernetes \
  --network kubernetes-the-easy-way \
  --range 10.240.0.0/24

gcloud compute firewall-rules create kubernetes-the-easy-way-allow-internal \
  --allow tcp,udp,icmp,ipip \
  --network kubernetes-the-easy-way \
  --source-ranges 10.240.0.0/24,10.200.0.0/16

gcloud compute firewall-rules create kubernetes-the-easy-way-allow-external \
  --allow tcp:22,tcp:6443,icmp\
  --network kubernetes-the-easy-way \
  --source-ranges 0.0.0.0/0

gcloud compute addresses create kubernetes-the-easy-way \
  --region $(gcloud config get-value compute/region)
)

内部用のファイアウォール規則(kubernetes-the-easy-way-allow-internal)の許可項目にIPIPプロトコールを追加します。

この記事ではチュートリアルと違ってCNIとしてCalicoを使います。よって内部のファイアウォールでIPIPプロトコールを許可する必要があります2

gcloud compute firewall-rules list --filter="network:kubernetes-the-easy-way"を通して以下のような設定を確認できます。

check
$ gcloud compute firewall-rules list --filter="network:kubernetes-the-easy-way"
NAME                                    NETWORK                  DIRECTION  PRIORITY  ALLOW                 DENY  DISABLED
kubernetes-the-easy-way-allow-external  kubernetes-the-easy-way  INGRESS    1000      tcp:22,tcp:6443,icmp        False
kubernetes-the-easy-way-allow-internal  kubernetes-the-easy-way  INGRESS    1000      tcp,udp,icmp                False

また、gcloud compute addresses list --filter="name=('kubernetes-the-easy-way')"を通してパブリックIPアドレスを確認できます。

check
$ gcloud compute addresses list --filter="name=('kubernetes-the-easy-way')"
NAME                     ADDRESS/RANGE   TYPE      PURPOSE  NETWORK  REGION    SUBNET  STATUS
kubernetes-the-easy-way  XXX.XXX.XXX.XXX  EXTERNAL                    us-west1          RESERVED

Compute Instances

インスタンスを立ち上げます。違いはありません。

Kubernetes Controllers

command-line
for i in 0 1 2; do
  gcloud compute instances create controller-${i} \
    --async \
    --boot-disk-size 200GB \
    --can-ip-forward \
    --image-family ubuntu-2004-lts \
    --image-project ubuntu-os-cloud \
    --machine-type e2-standard-2 \
    --private-network-ip 10.240.0.1${i} \
    --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
    --subnet kubernetes \
    --tags kubernetes-the-easy-way,controller
done

Kubernetes Workers

command-line
for i in 0 1 2; do
  gcloud compute instances create worker-${i} \
    --async \
    --boot-disk-size 200GB \
    --can-ip-forward \
    --image-family ubuntu-2004-lts \
    --image-project ubuntu-os-cloud \
    --machine-type e2-standard-2 \
    --metadata pod-cidr=10.200.${i}.0/24 \
    --private-network-ip 10.240.0.2${i} \
    --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
    --subnet kubernetes \
    --tags kubernetes-the-easy-way,worker
done

gcloud compute instances list --filter="tags.items=kubernetes-the-easy-way"を打つと

check
$ gcloud compute instances list --filter="tags.items=kubernetes-the-easy-way"
NAME          ZONE        MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
controller-0  us-west1-c  e2-standard-2               10.240.0.10  XXX.XXX.XXX.XXX  RUNNING
controller-1  us-west1-c  e2-standard-2               10.240.0.11  XXX.XXX.XXX.XXX  RUNNING
controller-2  us-west1-c  e2-standard-2               10.240.0.12  XXX.XXX.XXX.XXX  RUNNING
worker-0      us-west1-c  e2-standard-2               10.240.0.20  XXX.XXX.XXX.XXX  RUNNING
worker-1      us-west1-c  e2-standard-2               10.240.0.21  XXX.XXX.XXX.XXX  RUNNING
worker-2      us-west1-c  e2-standard-2               10.240.0.22  XXX.XXX.XXX.XXX  RUNNING

六つのインスタンスが立ち上がっている事が確認できます。

Provisioning the CA and Generating TLS Certificates

要りません。

Generating Kubernetes Configuration Files for Authentication

要りません。

Generating the Data Encryption Config and Key

要りません。

#※kubernetesのインストール※
元のチュートリアルではないセクションですが、kubeadmを使う場合、マスターノードとワーカーノードで同じ環境を使います。よって各VMに接続して3以下の過程を六つのインスタンスで行います。

ルート権限を仮定しています。

command-line
(
# Swapをオフにする。
swapoff -a
# sed to comment the swap partition in /etc/fstab
sed -i.bak -r 's/(.+ swap .+)/#\1/' /etc/fstab

# iptablesがブリッジを通過するトラフィックを処理できるようにする
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

modprobe overlay
modprobe br_netfilter

# iptablesをレガシーバージョンに切り替える。
apt-get update && apt-get install -y iptables arptables ebtables
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy

# Dockerをインストールする
apt-get install -y \
  apt-transport-https ca-certificates curl software-properties-common gnupg2

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -

add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) \
  stable"

apt-get update && apt-get install -y \
  containerd.io=1.2.13-2 \
  docker-ce=5:19.03.11~3-0~ubuntu-$(lsb_release -cs) \
  docker-ce-cli=5:19.03.11~3-0~ubuntu-$(lsb_release -cs)

apt-mark hold containerd.io docker-ce docker-ce-cli

# Dockerデーモンをセットアップ
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

systemctl daemon-reload
systemctl restart docker
systemctl enable docker

# kubernetesをインストールする
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-get update && apt-get install -y kubelet kubeadm kubectl

apt-mark hold kubelet kubeadm kubectl

systemctl daemon-reload
systemctl restart kubelet
systemctl enable kubelet
)

kubeadm version -o shortkubelet --versionでインストールが正しく行われたか確認でみます。

check
$ kubeadm version -o short
v1.22.1
$ kubelet --version
Kubernetes v1.22.1

Bootstrapping the etcd Cluster & Bootstrapping the Kubernetes Control Plane

controller-0,controller-1,controller-2を用いて積層コントロールプレーンを構成します。

kubeadmの積層HAクラスターはデフォルトで積層etcdトポロジーのクラスターを生成します。別途にetcdクラスターを構築する必要はありません。

Provision a Network Load Balancer

ターゲットプールではなくバックエンドサービスを使用したネットワークロードバランサを使用します。

Enable HTTPS Health Checks

kubernetesは基本的にヘルスチェック用のHTTPSエンドポイントを持っています4。即ち、新しいロードバランサを使えばHTTPSヘルスチェックでNGINXなしに直接繋げます5

command-line
(
KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-easy-way \
        --region $(gcloud config get-value compute/region) \
        --format 'value(address)')

# リージョンヘルスチェックを作成
gcloud compute health-checks create https kubernetes \
        --region=$(gcloud config get-value compute/region) \
        --description="Kubernetes Health Check" \
        --host "kubernetes.default.svc.cluster.local" \
        --request-path "/readyz" \
        --port=6443

# ネットワーク負荷分散のソースIP
gcloud compute firewall-rules create kubernetes-the-easy-way-allow-health-check \
        --network kubernetes-the-easy-way \
        --source-ranges=35.191.0.0/16,209.85.152.0/22,209.85.204.0/22 \
        --allow tcp
)

Provision a Network Load Balancer

非マネージドインスタンスグループとバックエンドサービスを作りネットワークロードバランサに繋げます。まだインスタンスグループにcontrollerインスタンスは追加しないでください。

command-line
(
KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-easy-way \
        --region $(gcloud config get-value compute/region) \
        --format 'value(address)')

# 非マネージドインスタンスグループの作成
gcloud compute instance-groups unmanaged create instance-group-easy-way \
        --zone $(gcloud config get-value compute/zone)

# リージョンバックエンドサービスを作成
gcloud compute backend-services create kubernetes-network-lb-backend-service \
        --region $(gcloud config get-value compute/region) \
        --health-checks kubernetes \
        --health-checks-region $(gcloud config get-value compute/region) \
        --protocol TCP

# インスタンスグループをバックエンドとして追加
gcloud compute backend-services add-backend kubernetes-network-lb-backend-service \
   --instance-group instance-group-easy-way \
   --instance-group-zone $(gcloud config get-value compute/zone) \
   --region $(gcloud config get-value compute/region)

# 転送ルールを作成
gcloud compute forwarding-rules create kubernetes-forwarding-rule \
        --address ${KUBERNETES_PUBLIC_ADDRESS} \
        --ports 6443 \
        --region $(gcloud config get-value compute/region) \
        --backend-service kubernetes-network-lb-backend-service
)

Provision the Kubernetes Control Plane

kubeadmを使ってコントロールプレーンを構成していきます。最初のcontrollerと他のcontrollerではンスタンスグループにインスタンスを追加する順番が逆なことにご注意ください。もし、順番を間違えばcontroller同士の通信ができなくなりtimeoutが発生します。

command-line
# インスタンスグループにcontroller-0を追加
gcloud compute instance-groups unmanaged add-instances instance-group-easy-way \
        --instances controller-0 \
        --zone $(gcloud config get-value compute/zone)
controller-0
# controller-0で実行
(
REGION=$(curl -s -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/project/attributes/google-compute-default-region)

KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-easy-way \
  --region $REGION \
  --format 'value(address)')

kubeadm init --pod-network-cidr=10.200.0.0/16 --service-cidr=10.32.0.0/24 --control-plane-endpoint "${KUBERNETES_PUBLIC_ADDRESS}:6443" --upload-certs

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

# CNIとしてCalicoを指定
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
)

出力されるkubeadmのテキストを記録しておきます。上の方に書かれているjoinはcontrollerで下のjoinはworkerでクラスターに参加させる際に使います。

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

kubeadm join XXX.XXX.XXX.XXX:6443 --token XXXXXX.xxxxxxxxxxxxxxxx \
        --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
        --control-plane --certificate-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

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 XXX.XXX.XXX.XXX:6443 --token XXXXXX.xxxxxxxxxxxxxxxx \
        --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

このトークンはデフォルトで2時間で消滅します。joinコマンドは"kubeadm token create --print-join-command"で、コントロールプレーンの為のcertificate-keyは"kubeadm init phase upload-certs --upload-certs"で再発行できます。

上記のコマンドを使ってcontroller-1とcontroller-2をjoinさせていきます。

必ず各インスタンスでkubernetesを立ち上げた後にVMインスタンスをインスタンスグループに加えてください。

もし先にインスタンスグループに加えてしまえば、ロードバランサが常にトラフィックをリクエストを送る側のVMに返してしまうため、クラスターに参加できなくなります6

controller-1
# controller-1で実行
(
kubeadm join XXX.XXX.XXX.XXX:6443 --token XXXXXX.xxxxxxxxxxxxxxxx \
        --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
        --control-plane --certificate-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
)
command-line
# インスタンスグループにcontroller-1を追加
gcloud compute instance-groups unmanaged add-instances instance-group-easy-way \
        --instances controller-1 \
        --zone $(gcloud config get-value compute/zone)
controller-2
# controller-2で実行
(
kubeadm join XXX.XXX.XXX.XXX:6443 --token XXXXXX.xxxxxxxxxxxxxxxx \
        --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
        --control-plane --certificate-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
)
command-line
# インスタンスグループにcontroller-2を追加
gcloud compute instance-groups unmanaged add-instances instance-group-easy-way \
        --instances controller-2 \
        --zone $(gcloud config get-value compute/zone)

各インスタンスでkubectl get nodesを通して積層コントロールプレーンが構築されている事が確認できます。

check
# controllerで実行
$ kubectl get nodes
NAME           STATUS   ROLES                  AGE     VERSION
controller-0   Ready    control-plane,master   10m     v1.22.2
controller-1   Ready    control-plane,master   3m30s   v1.22.2
controller-2   Ready    control-plane,master   101s    v1.22.2

各インスタンスで以下のコマンドを通して積層etcdクラスターが正常に動作している事が確認できます。

check
# controllerで実行
$ kubeadm config images list --kubernetes-version v1.22.2

k8s.gcr.io/kube-apiserver:v1.22.2
k8s.gcr.io/kube-controller-manager:v1.22.2
k8s.gcr.io/kube-scheduler:v1.22.2
k8s.gcr.io/kube-proxy:v1.22.2
k8s.gcr.io/pause:3.5
k8s.gcr.io/etcd:3.5.0-0
k8s.gcr.io/coredns/coredns:v1.8.4

$ docker run --rm -it \
--net host \
-v /etc/kubernetes:/etc/kubernetes k8s.gcr.io/etcd:3.5.0-0 etcdctl \
--cert /etc/kubernetes/pki/etcd/peer.crt \
--key /etc/kubernetes/pki/etcd/peer.key \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--endpoints https://10.240.0.10:2379 endpoint health --cluster

https://10.240.0.10:2379 is healthy: successfully committed proposal: took = 18.440766ms
https://10.240.0.11:2379 is healthy: successfully committed proposal: took = 21.317217ms
https://10.240.0.12:2379 is healthy: successfully committed proposal: took = 22.050581ms

Bootstrapping the Kubernetes Worker Nodes

前のパートでもう環境設定は終わっています。各workerインスタンスでkubeadm joinコマンドを実行するだけでクラスターに加わります。

worker-0,worker-1,worker-2
# 各々のworkerで実行
kubeadm join XXX.XXX.XXX.XXX:6443 --token XXXXXX.xxxxxxxxxxxxxxxx \
        --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
check
# controllerで実行
$ kubectl get nodes
NAME           STATUS   ROLES                  AGE    VERSION
controller-0   Ready    control-plane,master   25m    v1.22.2
controller-1   Ready    control-plane,master   18m    v1.22.2
controller-2   Ready    control-plane,master   16m    v1.22.2
worker-0       Ready    <none>                 2m     v1.22.2
worker-1       Ready    <none>                 2m7s   v1.22.2
worker-2       Ready    <none>                 117s   v1.22.2

Configuring kubectl for Remote Access

Master Nodeでkubectl config view --rawを実行した後、出力されるテキストを~/.kube/configに上書きすることでkubectlでのリモートアクセスが可能になります。もともとグローバルIPでの証明書なので問題なく作動します。

Provisioning Pod Network Routes

Calicoを導入しているので必要ありません。

Deploying the DNS Cluster Add-on

もう作動しています。

check
# controllerで実行
$ kubectl get pods -l k8s-app=kube-dns -n kube-system
NAME                       READY   STATUS    RESTARTS   AGE
coredns-78fcd69978-kvcjq   1/1     Running   0          49m
coredns-78fcd69978-nvhkf   1/1     Running   0          49m

$ kubectl run busybox --image=busybox:1.28 --command -- sleep 360
$ kubectl get pods -l run=busybox
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          3s

$ POD_NAME=$(kubectl get pods -l run=busybox -o jsonpath="{.items[0].metadata.name}")
$ kubectl exec -ti $POD_NAME -- nslookup kubernetes
Server:    10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local
Name:      kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local

Smoke Test

テストなので割愛します。参考までにData Encryptionセッションでは証明書を使用していますが、kubeadmが自動生成する証明書は/etc/kubernetes/pkiに位置します7

Cleaning Up

command-line
# インスタンスの削除
gcloud -q compute instances delete \
        controller-0 controller-1 controller-2 \
        worker-0 worker-1 worker-2 \
        --zone $(gcloud config get-value compute/zone)

# ロードバランサの削除
gcloud -q compute forwarding-rules delete kubernetes-forwarding-rule \
        --region $(gcloud config get-value compute/region)

gcloud -q compute backend-services remove-backend kubernetes-network-lb-backend-service \
        --instance-group instance-group-easy-way \
        --instance-group-zone $(gcloud config get-value compute/zone) \
        --region $(gcloud config get-value compute/region)

gcloud -q compute backend-services delete kubernetes-network-lb-backend-service \
        --region $(gcloud config get-value compute/region)

# インスタンスグループの削除
gcloud -q compute instance-groups unmanaged delete instance-group-easy-way \
        --zone $(gcloud config get-value compute/zone)

# ヘルスチェックの削除
gcloud -q compute health-checks delete kubernetes \
    --region=$(gcloud config get-value compute/region)

# ファイアウォール規則の削除
gcloud -q compute firewall-rules delete \
        kubernetes-the-easy-way-allow-internal \
        kubernetes-the-easy-way-allow-external \
        kubernetes-the-easy-way-allow-health-check

# ネットワークの削除
gcloud -q compute networks subnets delete kubernetes
gcloud -q compute networks delete kubernetes-the-easy-way

# ip addressesの解放
gcloud -q compute addresses delete kubernetes-the-easy-way \
        --region $(gcloud config get-value compute/region)
  1. Kubernetes The Hard Way, https://github.com/kelseyhightower/kubernetes-the-hard-way

  2. Self-managed Kubernetes in Google Compute Engine (GCE), https://docs.projectcalico.org/getting-started/kubernetes/self-managed-public-cloud/gce

  3. Linux VM への SSH 接続, https://cloud.google.com/compute/docs/instances/ssh?hl=ja

  4. Kubernetes API health endpoints, https://kubernetes.io/docs/reference/using-api/health-checks/

  5. Google Cloud Load Balancing ガイド - ヘルスチェックの概要, https://cloud.google.com/load-balancing/docs/health-check-concepts?hl=ja

  6. Google Cloud Load Balancing ガイド - 負荷分散された VM からのリクエストの送信, https://cloud.google.com/load-balancing/docs/internal/setting-up-internal#test-from-backend-vms

  7. Kubernetesドキュメント ベストプラクティス - PKI証明書とその要件, https://kubernetes.io/ja/docs/setup/best-practices/certificates/

0
0
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
0
0