古いPCが余っていて,こいつでKubernetesクラスタを作ろうと思って公式ガイドを久しぶりに見に行ったのだが,デプロイツールを使ってインストールする方法しか案内されていない. 昔俺がKubernetesをインストールしようとしたときは,まだkubeadmをここまで推していなくて,公式でも「etcdを用意しましょう」とか書いてあって,心を折りに来ていた気がするんだけど,そのガイドは既になくなっていた.
kubeadmでもいいんだけど,ガイドを見る限りそこまで手数も多くないしあんまり面白くなさそうだったので,
をやってみることにした.これだよこれ,この長ったらしい手順がやりたかったんだよ.なのでこの記事も長いよ.
構成を決める
本家のthe hard wayではGCP上にマシンを用意してKubernetesクラスタを作っているが,今回はあくまで余ったマシンにKubernetesを入れたかった.そのためアレンジする必要がある.
- 物理マシンは1台の上にvagrantで複数のVMを立ち上げる
- VMのOSはArch Linuxにする
- masterは1台,壊れたときやアップグレードのときは全部作り直せばええやん
- nodeは2台,これはマシンのスペック的にこのくらいは渡せるかと
- kubectlはLAN内の別マシンから叩くよ
- CRIはdockerを利用
- CNIはCalicoを利用
大雑把にはこのくらい. 物理マシンを複数台用意するほど余っていないので,vagrantの仮想マシンで我慢する.Arch Linuxを選択したのは,完全に俺の趣味だ.だいたいのガイドでUbuntuを使っていたのだが,Ubuntuみたいに全部入りのOSが必要だとは全然感じなかったし,Archでも事足りる上に軽いと思ったのでArchにしている. ちなみに物理マシンのホストOSもArch Linuxだ.
nodeはスペックが許す限り用意したいけど,masterは1台で良い.これはプロダクション運用するわけではなくて,遊ぶために作っておくクラスタなので,壊れたらまた作れば良い.
vagrantで必要なマシンを用意する
本家01に該当: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/01-prerequisites.md
vagrantを触ること自体がかなり久しぶりで,いろんなことを忘れていた.そもそもVagrantfileはrubyっぽい文法で書けることすら忘れていた. とりあえずArchLinuxのVMを作り,適当なスペックとprivate IPを付与する.このIPは今後随所で使うので,ここできっちり決めておく.
public networkはいらないけど,LAN内の別マシンからアクセスするためport forwardをしておく.Kubernetes API Serverは6443 で立ち上げる,このポートを開けておく.
ホストで編集したシェルスクリプトを各VM内で実行できるようにvolume mountもやっておく.
Vagrant.configure("2") do |config| config.vm.box = "archlinux/archlinux" config.vm.boot_timeout = 600 config.vm.define "master" do |c| c.vm.hostname = "master" c.vm.network "private_network", ip: "10.240.0.10" c.vm.network "forwarded_port", guest: 6443, host: 6443 end config.vm.define "node-0" do |c| c.vm.hostname = "node-0" c.vm.network "private_network", ip: "10.240.0.20" end config.vm.define "node-1" do |c| c.vm.hostname = "node-1" c.vm.network "private_network", ip: "10.240.0.21" end config.vm.synced_folder "./scripts", "/provisoning_scripts" config.vm.provider "virtualbox" do |vb| vb.gui = false vb.memory = "1024" vb.cpus = 1 end config.vm.provision "shell", inline: <<-SHELL pacman-key --populate archlinux pacman -Sy --noconfirm pacman -S docker --noconfirm pacman -S git base-devel wget --noconfirm pacman -S ebtables ethtool socat conntrack-tools ipset net-tools --noconfirm systemctl enable docker systemctl start docker usermod -aG docker vagrant swapoff -a cat /etc/fstab sudo sed -ri '/\\sswap\\s/s/^#?/#/' /etc/fstab cat /etc/fstab cat >/etc/hosts <<EOF 127.0.0.1 localhost # KTHW Vagrant machines 10.240.0.10 master 10.240.0.20 node-0 10.240.0.21 node-1 EOF SHELL end
provisionでは,VMのOSとして必要なものをセットアップしている.
CRIにはdockerを使うのでdockerを入れて,起動しておく.
また,kubeletはswapがonの状態だと起動できないので sed でfstabをいじってswapを無効にしている.最初からswapが無効なVMならやらなくていいんだけど,公式のArch Linuxはswapがonになっていた.なお,sedをこのprovisionに書く場合は,\をエスケープしてやる必要があるので,手動でコマンド実行するときに比べて\が一つ増えることに注意.
/etc/hosts には各VMのprivate IPを書いておく.これは後半で必要になる.
ここまで書いたらvagrant upしてvagrant ssh masterでmasterに入っておく.
なお,今回は証明書の生成等の作業をすべてmaster上で行い,必要なものをnodeに配置する.この作業はぶっちゃけどこでやっても良くて,生成されたものを正しく各VMに配れれば良い.
クライアントツールのインストール
本家02に該当: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/02-client-tools.md
ひたすら必要なツールをwgetでとってきて配置する.
# 以下はmasterで行う wget -q --show-progress --https-only --timestamping \ https://storage.googleapis.com/kubernetes-the-hard-way/cfssl/1.4.1/linux/cfssl \ https://storage.googleapis.com/kubernetes-the-hard-way/cfssl/1.4.1/linux/cfssljson chmod +x cfssl cfssljson sudo mv cfssl cfssljson /usr/bin/ cfssl version cfssljson --version wget https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kubectl chmod +x kubectl sudo mv kubectl /usr/bin/ kubectl version --client
証明書の作成
03は既にvagrant upしてあるので必要ない,というわけで飛ばす.
CAを作る
# 以下はmasterで行う
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"kubernetes": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "8760h"
}
}
}
}
EOF
cat > ca-csr.json <<EOF
{
"CN": "Kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "CA",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
これで
ca-key.pemca.pem
ができるはず.
管理ユーザのClient Certificateを作る
管理ユーザとしてAdminを作る.
# 以下はmasterで行う
cat > admin-csr.json <<EOF
{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
admin-csr.json | cfssljson -bare admin
admin-key.pemadmin.pem
ができるはず.
kubeletのClient Certificateを作る
# 以下はmasterで行う
for instance in node-0 node-1; do
cat > ${instance}-csr.json <<EOF
{
"CN": "system:node:${instance}",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:nodes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
EXTERNAL_IP=10.240.0.10
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname=${instance},${EXTERNAL_IP} \
-profile=kubernetes \
${instance}-csr.json | cfssljson -bare ${instance}
done
今回はmasterが1台なので,EXTERNAL_IPをmasterのIPにしているが,もしmasterを複数台用意して,LBでバランシングするような場合は,ここにはLBのIPを指定する.
node-0-key.pemnode-0.pemnode-1-key.pemnode-1.pem
ができるはず.
Controller ManagerのClient Certificateを作る
# 以下はmasterで行う
cat > kube-controller-manager-csr.json <<EOF
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:kube-controller-manager",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
kube-controller-manager-key.pemkube-controller-manager.pem
ができるはず.
Kube ProxyのClient Certificateを作る
# 以下はmasterで行う
cat > kube-proxy-csr.json <<EOF
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:node-proxier",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-proxy-csr.json | cfssljson -bare kube-proxy
kube-proxy-key.pemkube-proxy.pem
ができるはず.
SchedulerのClient Certificateを作る
# 以下はmasterで行う
cat > kube-scheduler-csr.json <<EOF
{
"CN": "system:kube-scheduler",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:kube-scheduler",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-scheduler-csr.json | cfssljson -bare kube-scheduler
kube-scheduler-key.pemkube-scheduler.pem
ができるはず.
Kubernetes API ServerのCertificateを作る
# 以下はmasterで行う
KUBERNETES_EXTERNAL_ADDRESS=192.168.0.7
KUBERNETES_HOSTNAMES=kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.svc.cluster.local
cat > kubernetes-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname=10.32.0.1,10.240.0.10,10.240.0.11,10.240.0.12,${KUBERNETES_EXTERNAL_ADDRESS},127.0.0.1,${KUBERNETES_HOSTNAMES} \
-profile=kubernetes \
kubernetes-csr.json | cfssljson -bare kubernetes
ここでのIP指定は結構重要.
10.32.0.1 は,ここではまだ登場しないが後半ででてくる,ClusterIPのIP rangeで指定するIPだ.
10.240.0.10はmaster自身のVMのIPであり, 10.240.0.11と10.240.0.12 はnodeのVMのIPだ.
そして, KUBERNETES_EXTERNAL_ADDRESS で指定しているのが,物理マシンのLAN内でのIPになっている.
これはServer Certificateなので,ここで指定するIPでしかリクエストを受け付けない.このクラスタはvagrantで立ち上げたVMをport forwardして使うので,LAN内から見たKubernetes API ServerのIPは物理マシンのLAN内のIPということになる.それが192.168.0.7 なのだが,ここでこのIPをhostnameから外すとLAN内の別マシンからはアクセスできなくなってしまう.その状態であっても,もちろんmasterのVM内からはアクセスできる.なぜならmasterのVM内から見れば自身のIPは127.0.0.1になるから.
これで
kubernetes-key.pemkubernetes.pem
ができるはず.
Service AccountのKey Pairを作る
# これはmasterで行う
cat > service-account-csr.json <<EOF
{
"CN": "service-accounts",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
service-account-csr.json | cfssljson -bare service-account
service-account-key.pemservice-account.pem
ができるはず.
作成した証明書をVMに配る
masterに配る
といっても,今回はこれらはmasterで作成しているので,別に配る必要はないんだけど,一応手順としては残しておく.
# これはホストOSでやる
for instance in master; do
vagrant scp ca.pem ${instance}:~/
vagrant scp ca-key.pem ${instance}:~/
vagrant scp kubernetes.pem ${instance}:~/
vagrant scp kubernetes-key.pem ${instance}:~/
vagrant scp service-account.pem ${instance}:~/
vagrant scp service-account-key.pem ${instance}:~/
done
nodeに配る
# これはホストOSでやる
for instance in node-0 node-1; do
vagrant scp ca.pem ${instance}:~/
vagrant scp ${instance}-key.pem ${instance}:~/
vagrant scp ${instance}.pem ${instance}:~/
done
Configの作成
kubeletのconfigを作成
# これはmasterで行う
KUBERNETES_PUBLIC_ADDRESS=10.240.0.10
for instance in node-0 node-1; do
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
--kubeconfig=${instance}.kubeconfig
kubectl config set-credentials system:node:${instance} \
--client-certificate=${instance}.pem \
--client-key=${instance}-key.pem \
--embed-certs=true \
--kubeconfig=${instance}.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:node:${instance} \
--kubeconfig=${instance}.kubeconfig
kubectl config use-context default --kubeconfig=${instance}.kubeconfig
done
前述の通り,KUBERNETES_PUBLIC_ADDRESSはnodekから見たAPIサーバのIPなので,LBを使う場合はLBのIPを書く.今回はmasterが1台なので,masterのIPを指定している.
node-0.kubeconfignode-1.kubeconfig
ができるはず.
kube-proxyのconfigを作成
# masterで行う
KUBERNETES_PUBLIC_ADDRESS=10.240.0.10
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
--kubeconfig=kube-proxy.kubeconfig
kubectl config set-credentials system:kube-proxy \
--client-certificate=kube-proxy.pem \
--client-key=kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=kube-proxy.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:kube-proxy \
--kubeconfig=kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
kube-proxy.kubeconfig
ができるはず.
kube-controller-managerのconfigを作成
# masterで行う
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:6443 \
--kubeconfig=kube-controller-manager.kubeconfig
kubectl config set-credentials system:kube-controller-manager \
--client-certificate=kube-controller-manager.pem \
--client-key=kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=kube-controller-manager.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:kube-controller-manager \
--kubeconfig=kube-controller-manager.kubeconfig
kubectl config use-context default --kubeconfig=kube-controller-manager.kubeconfig
kube-controller-manager.kubeconfig
ができるはず.
kube-schedulerのconfigを作成
# masterで行う
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:6443 \
--kubeconfig=kube-scheduler.kubeconfig
kubectl config set-credentials system:kube-scheduler \
--client-certificate=kube-scheduler.pem \
--client-key=kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=kube-scheduler.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:kube-scheduler \
--kubeconfig=kube-scheduler.kubeconfig
kubectl config use-context default --kubeconfig=kube-scheduler.kubeconfig
kube-scheduler.kubeconfig
ができるはず.
adminのconfigを作成
# masterで行う
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:6443 \
--kubeconfig=admin.kubeconfig
kubectl config set-credentials admin \
--client-certificate=admin.pem \
--client-key=admin-key.pem \
--embed-certs=true \
--kubeconfig=admin.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=admin \
--kubeconfig=admin.kubeconfig
kubectl config use-context default --kubeconfig=admin.kubeconfig
admin.kubeconfig
ができるはず.
configを配布
masterに配布
masterで生成しているので特に配布する必要はないんだけど.
# ホストOSで行う
for instance in master; do
vagrant scp admin.kubeconfig ${instance}:~/
vagrant scp kube-controller-manager.kubeconfig ${instance}:~/
vagrant scp kube-scheduler.kubeconfig ${instance}:~/
done
nodeに配布
# ホストOSで行う
for instance in node-0 node-1; do
vagrant scp ${instance}.kubeconfig ${instance}:~/
vagrant scp kube-proxy.kubeconfig ${instance}:~/
done
データ暗号化用の鍵を作成
Secret等を保存するときに暗号化するんだけど,そのときに使う鍵を生成する.
鍵の作成
# masterで行う
ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
cat >encryption-config.yaml <<EOF
kind: EncryptionConfig
apiVersion: v1
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: ${ENCRYPTION_KEY}
- identity: {}
EOF
encryption-config.yaml
ができるはず.
鍵の配布
これはmasterにのみ配れば良い.つまり今回は特に配布する必要はないんだけど…….
# ホストOSで行う
for instance in master; do
vagrant scp encryption-config.yaml ${instance}:~/
done
etcdのセットアップ
本家07に該当: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/07-bootstrapping-etcd.md
etcdは本来3台以上のクラスタを構成する.そのため,masterが3台ある場合は,以降の操作を3台それぞれのmasterで行う必要がある.が,今回はmasterが1台だけなので,etcdも1台しか起動しない.
etcdのインストール
# masterで行う
wget -q --show-progress --https-only --timestamping \
"https://github.com/etcd-io/etcd/releases/download/v3.4.10/etcd-v3.4.10-linux-amd64.tar.gz"
tar -xvf etcd-v3.4.10-linux-amd64.tar.gz
sudo mv etcd-v3.4.10-linux-amd64/etcd* /usr/bin/
etcdの設定
# masterで行う
sudo mkdir -p /etc/etcd /var/lib/etcd
sudo chmod 700 /var/lib/etcd
sudo cp ca.pem kubernetes-key.pem kubernetes.pem /etc/etcd/
INTERNAL_IP=$(ip addr show eth1 | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1')
ETCD_NAME=master
cat <<EOF | sudo tee /etc/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.com/coreos
[Service]
Type=notify
ExecStart=/usr/bin/etcd \\
--name ${ETCD_NAME} \\
--cert-file=/etc/etcd/kubernetes.pem \\
--key-file=/etc/etcd/kubernetes-key.pem \\
--peer-cert-file=/etc/etcd/kubernetes.pem \\
--peer-key-file=/etc/etcd/kubernetes-key.pem \\
--trusted-ca-file=/etc/etcd/ca.pem \\
--peer-trusted-ca-file=/etc/etcd/ca.pem \\
--peer-client-cert-auth \\
--client-cert-auth \\
--initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
--listen-peer-urls https://${INTERNAL_IP}:2380 \\
--listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
--advertise-client-urls https://${INTERNAL_IP}:2379 \\
--initial-cluster-token etcd-cluster-0 \\
--initial-cluster master=https://10.240.0.10:2380 \\
--initial-cluster-state new \\
--data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
INTERNAL_IPはip addrでとっているけど,別にifconfig等でとっても構わない.
ETCD_NAMEは,複数台のmasterがある場合は,
master-0master-1master-2
のように名前が分散するようにしてやる必要がある.
また,--initial-cluster には,クラスタに所属するetcdのすべてのnameとアドレスを書く必要があるので,クラスタ化する際にはそれらをすべて列挙しておこう.
etcdを起動
# masterで行う sudo systemctl daemon-reload sudo systemctl enable etcd sudo systemctl start etcd
etcdの確認
# masterで行う
sudo ETCDCTL_API=3 etcdctl member list \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/ca.pem \
--cert=/etc/etcd/kubernetes.pem \
--key=/etc/etcd/kubernetes-key.pem
startedになっていれば問題ない.複数台でクラスタ化した場合は,クラスタ内のノードがすべて表示されていること.
f98dc20bce6225a0, started, master, https://10.240.0.10:2380, https://10.240.0.10:2379, false
Controle Planeをセットアップ
この章の操作は,masterとなるVMすべてで同じことを行う必要がある.
必要なものをインストール
# masterで行う
sudo mkdir -p /etc/kubernetes/config
wget -q --show-progress --https-only --timestamping \
"https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kube-apiserver" \
"https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kube-controller-manager" \
"https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kube-scheduler" \
"https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kubectl"
chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/bin/
API Serverの設定
sudo mkdir -p /var/lib/kubernetes/
sudo cp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
service-account-key.pem service-account.pem \
encryption-config.yaml /var/lib/kubernetes/
INTERNAL_IP=$(ip addr show eth1 | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1')
cat <<EOF | sudo tee /etc/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
[Service]
ExecStart=/usr/bin/kube-apiserver \\
--advertise-address=${INTERNAL_IP} \\
--allow-privileged=true \\
--apiserver-count=1 \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/var/log/audit.log \\
--authorization-mode=Node,RBAC \\
--bind-address=0.0.0.0 \\
--client-ca-file=/var/lib/kubernetes/ca.pem \\
--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
--etcd-cafile=/var/lib/kubernetes/ca.pem \\
--etcd-certfile=/var/lib/kubernetes/kubernetes.pem \\
--etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \\
--etcd-servers=https://10.240.0.10:2379 \\
--event-ttl=1h \\
--encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
--kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \\
--kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \\
--kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \\
--kubelet-https=true \\
--runtime-config='api/all=true' \\
--service-account-key-file=/var/lib/kubernetes/service-account.pem \\
--service-cluster-ip-range=10.32.0.0/24 \\
--service-node-port-range=30000-32767 \\
--tls-cert-file=/var/lib/kubernetes/kubernetes.pem \\
--tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
--etcd-servers は,クラスタ化しているのであればetcdすべてのノードのアドレスを列挙すること.
--service-cluster-ip-rangeが,API Server Certificateのときに出てきたClusterIPのIP rangeだ.ここは揃えておく必要がある.
Controller Managerの設定
# masterで行う sudo cp kube-controller-manager.kubeconfig /var/lib/kubernetes/ cat <<EOF | sudo tee /etc/systemd/system/kube-controller-manager.service [Unit] Description=Kubernetes Controller Manager Documentation=https://github.com/kubernetes/kubernetes [Service] ExecStart=/usr/bin/kube-controller-manager \\ --bind-address=0.0.0.0 \\ --cluster-cidr=10.200.0.0/16 \\ --cluster-name=kubernetes \\ --cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \\ --cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \\ --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\ --leader-elect=true \\ --root-ca-file=/var/lib/kubernetes/ca.pem \\ --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \\ --service-cluster-ip-range=10.32.0.0/24 \\ --use-service-account-credentials=true \\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
--cluster-cidrは,クラスタ内のPodに割り振られるIPのrange.この段階では割と好きに決めて良い.
--service-cluster-ip-rangeはAPI Serverと同じ.
Schedulerの設定
# masterで行う sudo cp kube-scheduler.kubeconfig /var/lib/kubernetes/ cat <<EOF | sudo tee /etc/kubernetes/config/kube-scheduler.yaml apiVersion: kubescheduler.config.k8s.io/v1alpha1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig" leaderElection: leaderElect: true # EOF cat <<EOA | sudo tee /etc/systemd/system/kube-scheduler.service [Unit] Description=Kubernetes Scheduler Documentation=https://github.com/kubernetes/kubernetes [Service] ExecStart=/usr/bin/kube-scheduler \\ --config=/etc/kubernetes/config/kube-scheduler.yaml \\ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOA
ControlerのServiceを起動
# masterで行う sudo systemctl daemon-reload sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler
HTTP HealthCheckの有効化のためにnginxを設定
これはLBを用意している場合には,LBでやれば良いだけの話となる.
# masterで行う
sudo pacman -Sy --noconfirm
sudo pacman -S nginx --noconfirm
sudo mkdir -p /etc/nginx/conf.d /etc/nginx/sites-available /etc/nginx/sites-enabled
cat > nginx.conf <<EOF
user http;
worker_processes auto;
worker_cpu_affinity auto;
events {
multi_accept on;
worker_connections 1024;
}
http {
charset utf-8;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
log_not_found off;
types_hash_max_size 4096;
client_max_body_size 16M;
# MIME
include mime.types;
default_type application/octet-stream;
# logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# load configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
EOF
sudo mv nginx.conf /etc/nginx/nginx.conf
cat > kubernetes.default.svc.cluster.local <<EOF
server {
listen 80;
server_name kubernetes.default.svc.cluster.local;
location /healthz {
proxy_pass https://127.0.0.1:6443/healthz;
proxy_ssl_trusted_certificate /var/lib/kubernetes/ca.pem;
}
}
EOF
sudo mv kubernetes.default.svc.cluster.local /etc/nginx/sites-available/kubernetes.default.svc.cluster.local
sudo ln -s /etc/nginx/sites-available/kubernetes.default.svc.cluster.local /etc/nginx/sites-enabled/
sudo systemctl restart nginx
sudo systemctl enable nginx
確認
これもLBでやればよい.
# masterで行う
$ kubectl get componentstatuses --kubeconfig admin.kubeconfig
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health":"true"}
$ curl -H "Host: kubernetes.default.svc.cluster.local" -i http://127.0.0.1/healthz
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 18 Aug 2020 13:20:55 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 2
Connection: keep-alive
Cache-Control: no-cache, private
X-Content-Type-Options: nosniff
ok
$ curl --cacert ca.pem https://10.240.0.10:6443/version
{
"major": "1",
"minor": "18",
"gitVersion": "v1.18.6",
"gitCommit": "dff82dc0de47299ab66c83c626e08b245ab19037",
"gitTreeState": "clean",
"buildDate": "2020-07-15T16:51:04Z",
"goVersion": "go1.13.9",
"compiler": "gc",
"platform": "linux/amd64"
}
こんな感じの出力になれば良い.
KubeletにアクセスするためのRBACを設定
ここでは,Kubernetes API ServerがKubelet APIにアクセスするためのRBACを設定しておく.
# masterで行う
cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
verbs:
- "*"
EOF
cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubernetes
EOF
Workerをセットアップ
本家はこの章でCNIのセットアップを行っているが,今回はCalicoを入れたいのでCNIのセットアップを次々章に飛ばす.その関係で手順が本家と少し異なる.
必要なツールのインストール
本家ではcontainerdを使っているが,ここはdockerを使いたかったので書き換えている.
# workerで実行
wget -q --show-progress --https-only --timestamping \
https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.18.0/crictl-v1.18.0-linux-amd64.tar.gz \
https://github.com/opencontainers/runc/releases/download/v1.0.0-rc91/runc.amd64 \
https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-amd64-v0.8.6.tgz \
https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kubectl \
https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kube-proxy \
https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kubelet
sudo mkdir -p \
/etc/cni/net.d \
/opt/cni/bin \
/var/lib/kubelet \
/var/lib/kube-proxy \
/var/lib/kubernetes \
/var/run/kubernetes
tar -xvf crictl-v1.18.0-linux-amd64.tar.gz
sudo tar -xvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin/
sudo mv runc.amd64 runc
chmod +x crictl kubectl kube-proxy kubelet runc
sudo mv crictl kubectl kube-proxy kubelet runc /usr/bin/
なおdocker自体はVagrantのprovisioningでインストールしてしまっているので,ここでは特に何もしない.
kubeletをセットアップ
# workerで実行
sudo cp ${HOSTNAME}-key.pem ${HOSTNAME}.pem /var/lib/kubelet/
sudo cp ${HOSTNAME}.kubeconfig /var/lib/kubelet/kubeconfig
sudo cp ca.pem /var/lib/kubernetes/
INTERNAL_IP=$(ip addr show eth1 | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1')
case "$INTERNAL_IP" in
10.240.0.20)
POD_CIDR="10.200.0.0/24"
;;
10.240.0.21)
POD_CIDR="10.200.1.0/24"
;;
*)
echo "invalid ip"
;;
esac
cat <<EOF | sudo tee /var/lib/kubelet/kubelet-config.yaml
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
enabled: true
x509:
clientCAFile: "/var/lib/kubernetes/ca.pem"
authorization:
mode: Webhook
clusterDomain: "cluster.local"
clusterDNS:
- "10.32.0.10"
podCIDR: "${POD_CIDR}"
resolvConf: "/run/systemd/resolve/resolv.conf"
runtimeRequestTimeout: "15m"
tlsCertFile: "/var/lib/kubelet/${HOSTNAME}.pem"
tlsPrivateKeyFile: "/var/lib/kubelet/${HOSTNAME}-key.pem"
EOF
cat <<EOF | sudo tee /etc/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service
[Service]
ExecStart=/usr/bin/kubelet \\
--config=/var/lib/kubelet/kubelet-config.yaml \\
--image-pull-progress-deadline=2m \\
--kubeconfig=/var/lib/kubelet/kubeconfig \\
--network-plugin=cni \\
--register-node=true \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
PodCIDRは好きに割り振っていいのだが,masterのkube-controller-managerの起動時に
--cluster-cidr=10.200.0.0/16
という指定をしているので,この範囲に収まるようにしておく.
clusterDNSとして 10.32.0.10 を指定しているが,これは後々corednsを入れる段階で,corednsのServiceのClusterIPに該当する.
kube-dnsとして入れるServiceのIPを記述するので,別のものや別のIPでServiceを作る場合は,ちゃんとここも書き換えておくこと.
kube-proxyのセットアップ
# workerで実行 sudo cp kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig cat <<EOF | sudo tee /var/lib/kube-proxy/kube-proxy-config.yaml kind: KubeProxyConfiguration apiVersion: kubeproxy.config.k8s.io/v1alpha1 clientConnection: kubeconfig: "/var/lib/kube-proxy/kubeconfig" mode: "iptables" clusterCIDR: "10.200.0.0/16" EOF cat <<EOF | sudo tee /etc/systemd/system/kube-proxy.service [Unit] Description=Kubernetes Kube Proxy Documentation=https://github.com/kubernetes/kubernetes [Service] ExecStart=/usr/bin/kube-proxy \\ --config=/var/lib/kube-proxy/kube-proxy-config.yaml Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF
ここで指定するclusterCIDRも,kube-controller-managerの
--cluster-cidr=10.200.0.0/16
と揃える必要がある.
WorkerのServiceを起動
# workerで実行 sudo systemctl daemon-reload sudo systemctl enable kubelet kube-proxy sudo systemctl start kubelet kube-proxy
本来であればこの後に確認ができるはずなのだが,CNIを飛ばしているので確認はCNIのセットアップ後になる.
リモートアクセス用のkubeconfigを準備
Adminのkubeconfigを用意
# masterで実行
KUBERNETES_PUBLIC_ADDRESS=10.240.0.10
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443
kubectl config set-credentials admin \
--client-certificate=admin.pem \
--client-key=admin-key.pem
kubectl config set-context kubernetes-the-hard-way \
--cluster=kubernetes-the-hard-way \
--user=admin
kubectl config use-context kubernetes-the-hard-way
確認
# masterで実行 kubectl get componentstatuses echo '' kubectl get nodes
ただ,CNIを入れてないのでこの段階ではkubectl get nodes は失敗するはずである.
Calicoをセットアップ
本家の該当項目なし.なお,11に関しては,GCPではないのでやる必要がないため飛ばす.
CalicoをKubernetesのnodeに入れるにしても,いくつか選択肢がある.楽なのはKubernetes API datastoreを使ってしまう方法だが,せっかくmaster用にetcdを入れてあるので,etcdを使うことにする.
Calicoのインストール
$ curl https://docs.projectcalico.org/manifests/calico-etcd.yaml -o calico.yaml
としてcalico.yaml をダウンロードする.
そしてこのマニフェストを手動で編集する必要がある.
まず,etcdへ接続できるようにするために,Secretの
- etcd-key
- etcd-cert
- etcd-ca
にそれぞれ,
cat kubernetes-key.pem | base64 -w 0cat kubernetes.pem | base64 -w 0cat ca.pem | base64 -w 0
の値を貼り付ける.
次に,ConfigMapの
etcd_endpoints: "https://10.240.0.10:2379"
を設定する.ここはmasterで稼働しているetcdのエンドポイントを指定する.
同じくConfigMapの
etcd_ca: "/calico-secrets/etcd-ca" # "ca.pem" etcd_cert: "/calico-secrets/etcd-cert" # "kubernetes.pem" etcd_key: "/calico-secrets/etcd-key" # "kubernetes-key.pem"
をコメントアウトしておく.
最後にDaemonSetの環境変数にPod network CIDRのIPレンジを書いておく.
- name: CALICO_IPV4POOL_CIDR value: "10.200.0.0/16" # Pod network cidr
これでできあがったcalico.yaml を kubectl apply -f してやる.
確認
# ホストOSで実行する
vagrant ssh master \
--command "kubectl get nodes --kubeconfig admin.kubeconfig"
で,
NAME STATUS ROLES AGE VERSION node-0 Ready <none> 17d v1.18.6 node-1 Ready <none> 17d v1.18.6 Connection to 127.0.0.1 closed.
こんな出力になれば問題ない.
ようやくこれでkubectl get nodesが通るようになった.
DNS add-onを入れる
本家12に該当: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/12-dns-addon.md
つまりkube-dnsやcorednsと呼ばれるものを入れる.
corednsのインストール
# masterで行う kubectl apply -f https://storage.googleapis.com/kubernetes-the-hard-way/coredns-1.7.0.yaml kubectl get pods -l k8s-app=kube-dns -n kube-system
これでcorednsのPodが起動してくるはず.
busyboxをデプロイ
確認のためにbusyboxを動かす.
# masterで行う kubectl run busybox --image=busybox:1.28 --command -- sleep 3600 kubectl get pods -l run=busybox
確認
# masterで行う
$ POD_NAME=$(kubectl get pods -l run=busybox -o jsonpath="{.items[0].metadata.name}")
$ kubectl exec -ti $POD_NAME -- nslookup kubernete
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
となれば問題ない.
残り
13のSmoke Testと14のCleaning Upはやっていない.
一応ちょいちょいPodをデプロイしたりSecretを作ってみたりして問題ないし,消すつもりはなかったのでCleanupは不要.
というわけでここまででできあがりということになる.
[番外編]一般ユーザを追加
Adminのユーザは作成して,system:mastersを与えたが,それ以外のユーザも作ってみたいと思う.
だいたいAdminと同じ手順になる.
ユーザのクライアント証明書を作る
cat > akira-csr.json <<EOF
{
"CN": "akira",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:authenticated",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
akira-csr.json | cfssljson -bare akira
なお,このユーザは管理者ではないので,system:mastersは付与せずsystem:authenticatedのみを付与する.こうすることで,このユーザは認証だけができる状態になり,あと必要な権限はRBACで付与していく形になる.
ユーザのkubeconfigを作る
KUBERNETES_PUBLIC_ADDRESS=192.168.0.7
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443
--kubeconfig=akira.kubeconfig
kubectl config set-credentials akira \
--client-certificate=akira.pem \
--client-key=akira-key.pem
--kubeconfig=akira.kubeconfig
kubectl config set-context user \
--cluster=kubernetes-the-hard-way \
--user=akira \
--kubeconfig=akira.kubeconfig
kubectl config use-context user --kubeconfig=akira.kubeconfig
あとは,これで~/.kube/config にakira用の設定ができるので,これを任意のホストに持ち出して入れておく.
ユーザに権限を付与する
このままの状態だと,system:authenticatedしか権限がないので,なにかやろうと思うとエラーになる.
$ kubectl get nodes Error from server (Forbidden): nodes is forbidden: User "akira" cannot list resource "nodes" in API group "" at the cluster scope
というわけで,適切な権限を付与してやる.
kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: akira-masters-all subjects: - kind: User name: akira apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io
で,これをkubectl apply -f してやれば,akiraは閲覧だけができるようになる.
なお,ここの操作自体はadminでやってやらないといけない.
トラブルシューティング
swapが生きてた
これは冒頭にも書いたが,kubeletはswapがonの状態だと起動できない.そのため,Wrokerのセットアップ時で失敗して,Vagrantfileにてswapを無効化してprovisionし直した.
なお,試すだけなら起動後にswapoff -aとしてもいいんだけど,これは再起動後に再びswapが復活してしまうため,起動後に毎回やる必要がある.
/etc/hosts への書き込みを忘れた
これを忘れるとcorednsインストール後の確認で,
$ kubectl exec -ti $POD_NAME -- nslookup kubernetes
とやったところでnode-0を解決できずにエラーが出た.まぁそうなるわな…….
CNIがbridgeだとFirewallをoffにする必要がある
本家では,CNIにbridgeを使っている.
しかし,このとおりにセットアップしたところ,corednsを入れたときにcorednsのpodがエラーになって落ちてしまう.その時のログ.
[INFO] plugin/ready: Still waiting on: "kubernetes" [INFO] plugin/ready: Still waiting on: "kubernetes" [INFO] plugin/ready: Still waiting on: "kubernetes" I0802 16:11:15.741083 1 trace.go:116] Trace[637979947]: "Reflector ListAndWatch" name:pkg/mod/k8s.io/client-go@v0.18.3/tools/cache/reflector.go:125 (started: 2020-08-02 16:10:45.740199663 +0000 UTC m=+134.639398318) (total time: 30.000839979s): Trace[637979947]: [30.000839979s] [30.000839979s] END E0802 16:11:15.741126 1 reflector.go:178] pkg/mod/k8s.io/client-go@v0.18.3/tools/cache/reflector.go:125: Failed to list *v1.Endpoints: Get "https://10.32.0.1:443/api/v1/endpoints?limit=500&resourceVersion=0": dial tcp 10.32.0.1:443: i/o timeout I0802 16:11:18.430763 1 trace.go:116] Trace[443632888]: "Reflector ListAndWatch" name:pkg/mod/k8s.io/client-go@v0.18.3/tools/cache/reflector.go:125 (started: 2020-08-02 16:10:48.429966802 +0000 UTC m=+137.329165455) (total time: 30.000752415s): Trace[443632888]: [30.000752415s] [30.000752415s] END E0802 16:11:18.430809 1 reflector.go:178] pkg/mod/k8s.io/client-go@v0.18.3/tools/cache/reflector.go:125: Failed to list *v1.Service: Get "https://10.32.0.1:443/api/v1/services?limit=500&resourceVersion=0": dial tcp 10.32.0.1:443: i/o timeout [INFO] plugin/ready: Still waiting on: "kubernetes" I0802 16:11:18.644349 1 trace.go:116] Trace[1496193015]: "Reflector ListAndWatch" name:pkg/mod/k8s.io/client-go@v0.18.3/tools/cache/reflector.go:125 (started: 2020-08-02 16:10:48.64359993 +0000 UTC m=+137.542798583) (total time: 30.000705162s): Trace[1496193015]: [30.000705162s] [30.000705162s] END E0802 16:11:18.644484 1 reflector.go:178] pkg/mod/k8s.io/client-go@v0.18.3/tools/cache/reflector.go:125: Failed to list *v1.Namespace: Get "https://10.32.0.1:443/api/v1/namespaces?limit=500&resourceVersion=0": dial tcp 10.32.0.1:443: i/o timeout [INFO] plugin/ready: Still waiting on: "kubernetes" [INFO] plugin/ready: Still waiting on: "kubernetes"
これに関してはufwでfirewallをoffにしろという情報がある.
確かにnode側のjournalctlで見ると
Aug 03 16:33:02 node-1 kernel: audit: type=1104 audit(1596472382.759:1538): pid=8075 uid=0 auid=1000 ses=3 msg='op=PAM:setcred grantors=pam_unix,pam_permit,pam_env acct="root" exe="/usr/bin/sudo" hostname=? add> Aug 03 16:33:03 node-1 kubelet[346]: I0803 16:33:03.080747 346 prober.go:124] Readiness probe for "coredns-5677dc4cdb-4ljsh_kube-system(9c653514-284a-4328-8eef-0a0d1292dbb6):coredns" failed (failure): HTTP > Aug 03 16:33:04 node-1 kernel: [UFW BLOCK] IN=cnio0 OUT=eth1 PHYSIN=veth9dbf349c MAC=fa:1b:40:ae:a5:e1:8e:25:1e:0a:a8:66:08:00 SRC=10.200.1.5 DST=10.240.0.10 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=16729 DF PROTO=T> Aug 03 16:33:05 node-1 kernel: [UFW BLOCK] IN=cnio0 OUT=eth1 PHYSIN=veth9dbf349c MAC=fa:1b:40:ae:a5:e1:8e:25:1e:0a:a8:66:08:00 SRC=10.200.1.5 DST=10.240.0.10 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=16730 DF PROTO=T> Aug 03 16:33:13 node-1 kubelet[346]: I0803 16:33:13.080574 346 prober.go:124] Readiness probe for "coredns-5677dc4cdb-4ljsh_kube-system(9c653514-284a-4328-8eef-0a0d1292dbb6):coredns" failed (failure): HTTP > Aug 03 16:33:23 node-1 kubelet[346]: I0803 16:33:23.080864 346 prober.go:124] Readiness probe for "coredns-5677dc4cdb-4ljsh_kube-system(9c653514-284a-4328-8eef-0a0d1292dbb6):coredns" failed (failure): HTTP > Aug 03 16:33:26 node-1 kernel: [UFW BLOCK] IN=cnio0 OUT=eth1 PHYSIN=veth9dbf349c MAC=fa:1b:40:ae:a5:e1:8e:25:1e:0a:a8:66:08:00 SRC=10.200.1.5 DST=10.240.0.10 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=8532 DF PROTO=TC> Aug 03 16:33:33 node-1 kubelet[346]: I0803 16:33:33.080790 346 prober.go:124] Readiness probe for "coredns-5677dc4cdb-4ljsh_kube-system(9c653514-284a-4328-8eef-0a0d1292dbb6):coredns" failed (failure): HTTP >
ブロックされていることがわかる.手っ取り早くsudo ufw disableすると無事疎通した.
が,このあと結局CNIはCalicoを入れてしまったし,Calicoを入れたらこの手順は不要になった.
CNIをflannelにするかCalicoにするか
ネット上ではflannelに関する情報が多いが,リリースがあまり頻繁ではないのと,CalicoのNetwork Policyを使ってみたかったこともあり,Calicoを入れた.
所感
出来上がったスクリプトたちがこれ.
トラブルシューティングにあるように,結構トラブルに遭遇しているので,どれも一発で全部が上手く行ったわけではない.結構作り直している.
そして最初からこの形だったわけではなく,最初はCNIはbridgeのままだったし(本家のthe hard wayはこれを使ってた),Container Runtimeもcontainerdだった.
そのため,上記のスクリプトには古いCNIの手順だったりContainer Runtimeの手順が少し残っている. _09-02-configure-cni.sh とかね.
ただトラブって何度も作り直しただけあって,だいぶ手慣れてきてしまった.VMごと作り直しを何回もやったので
- 証明書は作るだけ,作り直したら利用している箇所は再生成する必要があるが
- 例えばworkerの手順でミスってVMごと潰してしまっても,masterは何も変更する必要はない
- CNIとかCRIはすべてworkerだけの問題なので,ここを変更するのにmasterをいじる必要がない
- masterのetcdは大事,ここが吹き飛ぶと構成情報がみんな吹き飛ぶ
とかがわかるようになってくる.
PCは起動しっぱなしにするの?
これはNo. 最初からPCをつけっぱなしにするつもりはなかったのだが,Kubernetesはnodeもmasterも一度すべて停止しても,再起動時にはちゃんと復元してくれる.
これはetcdが構成情報をディスクに保存しておいてくれるおかげだが.
なので,PCを起動している間だけKubernetesクラスタも稼働している.
Ingress等への外部からのアクセスはどうする?
そもそもLAN外へ公開するつもりはなかったので,完全に外部へは公開していない.ただし,LAN内からのアクセスは行っている.
これにはingress-nginx等でIngressを作り,NodePortに公開した後,NodePortの範囲をVagrant側でforwarded_portしている.
MetalLBとかでIPを振ってもいいのだが,そのIPにLAN -> Host OS -> Vagrant VMというようにアクセスしたくて,これは今の構成ではちょっと面倒くさかったのでやっていない.
どうせなら,Vagrantの段階でPrivateIPではなくPublicIPを振ってしまったほうがよかったのかもしれない…….そうしたらport forwardから開放され,LAN内から自由にアクセスできたかも…….
参考
本家.
Vagrantでやっている人の例.
Calicoを入れている人の例.