2021/04/19

Ubuntu20.04のサーバーにkubeadmを使って開発用のk8sクラスターを作る

k8subuntu

Ubuntu20.04のマシーンがオフィスにやってきました。せっかくなので、k8sクラスターをインストールして便利な開発用サービスを立てていこうと思います。

こちらの記事に従って構築しました。

事前準備

Swapをオフに設定

Swapがオフであること。kubeletが正常に動作するためにはswapは必ずオフでなければなりません。

$ sudo swapoff -a

iptablesがブリッジを通過するトラフィックを処理できるようにするか確認

# br_netfilterモジュールロード済を確認
$ lsmod | grep br_netfilter
br_netfilter           28672  0
bridge                192512  1 br_netfilter

$ cat /proc/sys/net/bridge/bridge-nf-call-iptables
1
# 1だったのでOK

iptablesがnftablesバックエンドを使用しないようになっているか確認

これは、少なくともDebian 10(Buster)、Ubuntu 19.04、Fedora 29、およびこれらのディストリビューションの新しいリリースでのデフォルトです。

Ubuntu 20.04は言及されていなかったので、大丈夫そうですが、以下で念の為確認

$ lsmod | grep nf_tables
# 見つからない
$ iptables --version
iptables v1.8.4 (legacy)
# 大丈夫みたい

kubeadm、kubelet、kubectlのインストール

kubeadmはkubeletやkubectlをインストールまたは管理しないため、kubeadmにインストールするKubernetesコントロールプレーンのバージョンと一致させる必要があります。

kubeadm / kubelet / kubectlはうまくバージョンを同期させておく必要がありそうです。

$ sudo apt-get update && sudo apt-get install -y apt-transport-https curl
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
$ cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
$ sudo apt-get update
$ sudo apt-get install -y kubelet kubeadm kubectl
# パッケージが更新されないようにする。
$ sudo apt-mark hold kubelet kubeadm kubectl
kubelet は保留に設定されました。
kubeadm は保留に設定されました。
kubectl は保留に設定されました

コントロールプレーンノードのkubeletによって使用されるcgroupドライバーの設定の確認

Dockerを使用した場合、kubeadmは自動的にkubelet向けのcgroupドライバーを検出し、それを実行時に/var/lib/kubelet/kubeadm-flags.envファイルに設定します。

CRI(Container Runtime Interface)とは、2016年12月にKubernetes 1.5からαリリースされた、kubeletとコンテナランタイムが通信するためのI/Fを規定したもの

コンテナはdockerを利用しているので問題なさそうです。

kubeadm init 実行後に確認できました。

$ sudo cat /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.4.1"

コントロールプレーンノードの初期化

$ sudo kubeadm init --pod-network-cidr=192.168.0.0/16

kubectlをroot以外のユーザーでも実行できるようにする

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

# 以下で確認
$ kubectl  get node
NAME         STATUS     ROLES                  AGE   VERSION
<hostname>   NotReady   control-plane,master   89s   v1.21.0

シングルマシンのクラスターでの設定

コントロールプレーンノードの隔離
デフォルトでは、セキュリティ上の理由により、クラスターはコントロールプレーンノードにPodをスケジューリングしません。たとえば、開発用のKubernetesシングルマシンのクラスターなどで、Podをコントロールプレーンノードにスケジューリングしたい場合は、次のコマンドを実行します。

$ kubectl taint nodes --all node-role.kubernetes.io/master-
node/<hostname> untainted

Podネットワークアドオンのインストール

備考: 現在、Calicoはkubeadmプロジェクトがe2eテストを実施している唯一のCNIプラグインです。 もしCNIプラグインに関する問題を見つけた場合、kubeadmやkubernetesではなく、そのCNIプラグインの課題管理システムへ問題を報告してください。

とりあえず、Calicoを使えば良いのかな?ということで

$ curl https://docs.projectcalico.org/manifests/calico.yaml -O
$ vim calico.yaml

calico.yaml をそのままapplyしたら Couldn't autodetect an IPv4 address というエラーが出てしまいました。

こちらは(通常は無線LANを使わないと思うのですが、現状LANポートが空いてなくて、無線で無理やりやっていたのでエラーになっていました。)

このコメントにある通りで、自分が今使っているNICを特定できるように IP_AUTODETECTION_METHOD を変更(この時はwirelessのものを使っていたので、interface=wlo.* を指定)することで解決できました。(地味に1時間程度ハマりました。)

      containers:
        # Runs calico-node container on each Kubernetes node. This
        # container programs network policy and routes on each
        # host.
        - name: calico-node
          image: docker.io/calico/node:v3.18.1
          envFrom:
          - configMapRef:
              # Allow KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT to be overridden for eBPF mode.
              name: kubernetes-services-endpoint
              optional: true
          env:
            # ...中略...
            - name: IP
              value: "autodetect"
            - name: IP_AUTODETECTION_METHOD
              value: "interface=wlo.*"
$ kubectl apply -f 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

NodeとPodの確認

$ kubectl get nodes
NAME         STATUS   ROLES                  AGE    VERSION
<hostname>   Ready    control-plane,master   9m2s   v1.21.0

$ kubectl get pods -n kube-system
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-6d8ccdbf46-jwxgz   1/1     Running   0          23m
calico-node-bg896                          1/1     Running   0          4m25s
coredns-558bd4d5db-jxpdc                   1/1     Running   0          23m
coredns-558bd4d5db-m7dpb                   1/1     Running   0          23m
etcd-<hostname>                            1/1     Running   0          24m
kube-apiserver-<hostname>                  1/1     Running   0          24m
kube-controller-manager-<hostname>         1/1     Running   0          24m
kube-proxy-v9wzk                           1/1     Running   0          23m
kube-scheduler-<hostname>                  1/1     Running   0          24m

無事必要なpodが起動しているのが確認できました。

nginxのpodのテスト

最後に、テストを兼ねて、nginxのプロセスを常駐させ、ちゃんとアクセスできるか確認してみました。

$ cat <<EOF > test_deployment.yaml
> apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
> kind: Deployment
> metadata:
>   name: nginx-deployment
> spec:
>   selector:
>     matchLabels:
>       app: nginx
>   replicas: 2 # tells deployment to run 2 pods matching the template
>   template:
>     metadata:
>       labels:
>         app: nginx
>     spec:
>       containers:
>       - name: nginx
>         image: nginx:1.14.2
>         ports:
>         - containerPort: 80
> EOF

$ kubectl apply -f test_deployment.yaml
deployment.apps/nginx-deployment created

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-66b6c48dd5-8lflf   1/1     Running   0          22s
nginx-deployment-66b6c48dd5-xs4xr   1/1     Running   0          22s

$ kubectl port-forward nginx-deployment-66b6c48dd5-8lflf 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080

# 別のターミナルを立ち上げて、nginxに疎通できるか確認
$ curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
	body {
    	width: 35em;
    	margin: 0 auto;
    	font-family: Tahoma, Verdana, Arial, sans-serif;
	}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

以上で、ローカルのUbuntu20.04のサーバー(1台)にk8sを構築することができました。
現状ではシングル構成ですが、ヘビーユースするようになったら複数台構成でできるように拡張していきたいと思います。