更新
2020/07/19 Kubernetes 1.18.6, Calico 3.15.1 も同じ手順でインストール可能です。
#環境
ESXi7.0上にVM3台作成
-
vm
- k8s-master cpu:2 mem:4GB HDD:30GB IP:192.168.123.150
- k8s-node1 cpu:2 mem:4GB HDD:30GB IP:192.168.123.151
- k8s-node2 cpu:2 mem:4GB HDD:30GB IP:192.168.123.152
-
OS
- CentOS8.2.2004 Minimalインストール
-
インストールするKubernetesのバージョン
- 1.18.4
Installing kubeadmによると、インストールするマシンは2GB以上のメモリ、cpu2コア以上が必要とのこと。
#はじめに
Kubernetesの勉強用に自前で環境を組んでみることにしました。
手っ取り早く環境を構築して動かしたい人向けです。
基本的に公式のBootstrapping clusters with kubeadmの通りに進めていますが、結構苦戦したので手順をまとめました。
#手順
-
各ノードで最新のアップデートを適用する
dnf update -y
-
各ノードのswapをオフにする(ここでは設定のみ。後でノード再起動で反映させる。)
swapをオフにし、/etc/fstabからswap領域のマウントの記載を削除する。# vi /etc/fstab → swapの行をコメントアウト
-
各ノードで名前解決ができるようにする
各ノードの /etc/hosts に以下の値を追加する192.168.123.150 k8s-master 192.168.123.151 k8s-node1 192.168.123.152 k8s-node2
-
各ノードのMACアドレスと product_uuidが一意であることの確認
-
MACアドレス確認
# ip link
-
product_uuid確認
# cat /sys/class/dmi/id/product_uuid
-
-
各ノードのFirewallの無効化(ここでは自動起動無効化のみ。後でノード再起動で反映させる。)
# systemctl disable firewalld
-
各ノードのselinuxの無効化(ここでは設定のみ。後でノード再起動で反映させる。)
# vi /etc/selinux/config →SELINUX=permissive に変更
-
各ノードのipv6無効化(ここでは設定のみ。後でノード再起動で反映させる。)
# echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf # echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf
-
各ノードのネットワーク・ブリッジを通過するパケットにiptablesを適用(ここでは設定のみ。後でノード再起動で反映させる。)
# cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF
-
各ノードのipv4のフォワード設定(ここでは設定のみ。後でノード再起動でまとめて反映させる。)
# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
-
これまでの設定を反映させるため、全ノードを再起動する
# shutdown -r now
-
各ノードでコンテナランタイムをインストール
Dockerをインストールします。
インストール手順は「Install Docker Engine on CentOS」を参考にしています。
手順通りにインストールしようとするとエラーが発生したので、「How to install Docker CE on RHEL 8 / CentOS 8」を参考にインストール手順を少し変更しています。(CentOS8からはDockerコンテナエンジンが削除されてpodmanを使うようになったのが原因のようです。)# dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo # dnf install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.13-3.2.el7.x86_64.rpm -y # dnf install docker-ce docker-ce-cli -y # mkdir /etc/docker # cat > /etc/docker/daemon.json <<EOF { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] } EOF # mkdir -p /etc/systemd/system/docker.service.d # systemctl daemon-reload # systemctl enable --now docker
-
各ノードでkubeadm, kubelet, kubectlをインストール
Kubernetesのリポジトリを追加してkubeadm, kubelet, kubectlをインストールし、kubeletを起動します。
この時点では、kubeletは起動&失敗を繰り返しますが、次の手順のkubeadm initを実行することで正常に起動するようになります。
公式の手順では、ここでSELinuxをpermissiveに変更していますが、事前に変更済みのため省略しています。# cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg exclude=kubelet kubeadm kubectl EOF # dnf install kubelet kubeadm kubectl --disableexcludes=kubernetes -y # systemctl enable --now kubelet
-
k8s-masterノードでkubeadmコマンドを使用してControl-plane nodeを初期化する
- kubeadmコマンドのオプション
- --apiserver-advertise-address:apiサーバのIPアドレス。マスターノードのIPアドレスを指定する。
- --pod-network-cidr:Podに割り当てるIPアドレスの範囲。(ホストネットワークと重複しないように設定する)
# kubeadm init --apiserver-advertise-address 192.168.123.150 --pod-network-cidr 10.240.0.0/16
実行例
[root@k8s-master ~]# kubeadm init --apiserver-advertise-address 192.168.123.150 --pod-network-cidr 10.240.0.0/16 W0621 23:58:11.156994 134717 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io] [init] Using Kubernetes version: v1.18.4 [preflight] Running pre-flight checks [WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly [WARNING FileExisting-tc]: tc not found in system path [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' [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 [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 [k8s-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.123.150] [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 [k8s-master localhost] and IPs [192.168.123.150 127.0.0.1 ::1] [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [k8s-master localhost] and IPs [192.168.123.150 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 [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" W0621 23:58:18.001687 134717 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC" [control-plane] Creating static Pod manifest for "kube-scheduler" W0621 23:58:18.002962 134717 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC" [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 [apiclient] All control plane components are healthy after 21.503071 seconds [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.18" in namespace kube-system with the configuration for the kubelets in the cluster [upload-certs] Skipping phase. Please see --upload-certs [mark-control-plane] Marking the node k8s-master as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node k8s-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: u4t96u.malq5uoi0of545r6 [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 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/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.123.150:6443 --token u4t96u.malq5uoi0of545r6 \ --discovery-token-ca-cert-hash sha256:1700be62aefeb52188c53ff77e0ce43b329fec3837dc83b45bd9d7d649f767e2 [root@k8s-master ~]#
上記実行例の出力にもある通り、一般ユーザでkubectl コマンドを実行する場合は、一般ユーザで以下のコマンドを実行する必要があります。
$ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config
rootユーザの場合は、以下のコマンドを実行すると、kubectlコマンドが実行できます。
export KUBECONFIG=/etc/kubernetes/admin.conf
私は以下のコマンドをrootで実行してrootコマンドでkubectlを実行できるようにしました。
# mkdir -p $HOME/.kube # cp -pi /etc/kubernetes/admin.conf $HOME/.kube/config
また、上記実行例の出力の最後に出力された以下の部分はノードを追加する際に使用するためメモしておいてください。
kubeadm join 192.168.123.150:6443 u4t96u.malq5uoi0of545r6 \ --discovery-token-ca-cert-hash sha256:1700be62aefeb52188c53ff77e0ce43b329fec3837dc83b45bd9d7d649f767e2
- kubeadmコマンドのオプション
-
Container Network Interface(CNI)のインストール
kubectl get all -Aでリソースを表示すると、CoreDNSが動作していません。CNIをインストールしないと動作しません(「Installing a Pod network add-on」)。[root@k8s-master ~]# kubectl get all -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system pod/coredns-66bff467f8-dp8bl 0/1 Pending 0 62s kube-system pod/coredns-66bff467f8-sqsgg 0/1 Pending 0 62s : NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE kube-system deployment.apps/coredns 0/2 2 0 78s :
いくつか選択肢があるようですが、今回は「Calico」をインストールします。
現時点での最新版となる3.15をインストールしました。NetworkManagerがインターフェースに干渉しないように、
/etc/NetworkManager/conf.d/calico.conf
を作成します。
(Configure NetworkManager)[https://docs.projectcalico.org/maintenance/troubleshoot/troubleshooting#configure-networkmanager]全ノードで作成します。
cat <<EOF > /etc/NetworkManager/conf.d/calico.conf [keyfile] unmanaged-devices=interface-name:cali*;interface-name:tunl*;interface-name:vxlan.calico EOF
k8s-masterノードでCalioをインストール(Calio 3.15.1も同じURLでインストールできます)
# kubectl apply -f https://docs.projectcalico.org/v3.15/manifests/calico.yaml
しばらく待つと、corednsおよびcalicoがRunningになります。
kubectl get pods -n kube-system
で確認できます。 -
Kubernetesクラスタにノードを追加する
k8s-node1, k8s-node2で以下のコマンドを実行し、Kubernetesクラスタに各ノードを追加します。# kubeadm join 192.168.123.150:6443 --token u4t96u.malq5uoi0of545r6 \ --discovery-token-ca-cert-hash sha256:1700be62aefeb52188c53ff77e0ce43b329fec3837dc83b45bd9d7d649f767e2
追加されたかどうかは
kubectl get nodes
で確認できます。[root@k8s-master ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready master 42m v1.18.4 k8s-node1 Ready <none> 68s v1.18.4 k8s-node2 Ready <none> 26s v1.18.4 [root@k8s-master ~]#
しばらくすると、coredns、追加されたノード用のcalico-nodeの起動が完了します。
[root@k8s-master ~]# kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE calico-kube-controllers-58b656d69f-4kd5f 1/1 Running 0 64m calico-node-2w98n 1/1 Running 0 62m calico-node-cqw29 1/1 Running 0 64m calico-node-fh2zw 1/1 Running 0 61m coredns-66bff467f8-st5k8 1/1 Running 0 65m coredns-66bff467f8-zk27f 1/1 Running 0 65m :
-
動作確認
Kubernetes pods by exampleを参考にして作ったPodとサービス(NodePort)を動かします。-
k8s-master で以下のコマンドを実行してnginxのサンプルを動かします。
# kubectl apply -f https://raw.githubusercontent.com/yasubehe/k8s-test001/master/sample-nginx-pod.yaml # kubectl get pods -l run=my-nginx -o wide # kubectl apply -f https://raw.githubusercontent.com/yasubehe/k8s-test001/master/sample-nginx-service-nodeport.yaml # kubectl describe svc my-nginx
起動したことを確認します。
[root@k8s-master ~]# kubectl get pods -l run=my-nginx -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-5dc4865748-64l7d 1/1 Running 0 43s 10.240.169.130 k8s-node2 <none> <none> my-nginx-5dc4865748-6lxhv 1/1 Running 0 43s 10.240.36.66 k8s-node1 <none> <none> [root@k8s-master ~]# kubectl get svc my-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-nginx NodePort 10.111.252.182 <none> 8080:30080/TCP 36s [root@k8s-master ~]#
-
別のターミナルを2つ用意し、k8s-master にログインしてmy-nginxのpodのログを監視します。
kubectl get pods -l run=my-nginx -o wide
に出力されたPodのNAMEの1つ目# kubectl logs -f my-nginx-xxxxxxxxxxxxxxxx
kubectl get pods -l run=my-nginx -o wide
に出力されたPodのNAMEの2つ目# kubectl logs -f my-nginx-yyyyyyyyyyyyyyyy
-
別のターミナルを2つ用意し、それぞれk8s-node1、k8s-node2 にログインしてmy-nginxにアクセスします。
コマンドを何度か実行すると、ランダムにmy-nginx-xxxxxxxxxxxxxxxx,my-nginx-yyyyyyyyyyyyyyyyにアクセスされることがわかります。[root@k8s-node1 ~]# curl 192.168.123.151:30080 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title>
[root@k8s-node2 ~]# curl 192.168.123.152:30080 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> :
-
-
動作確認のために作成したService, Podの削除
k8s-masterノードで以下のコマンドを実行します。# kubectl delete -f https://raw.githubusercontent.com/yasubehe/k8s-test001/master/sample-nginx-service-nodeport.yaml # kubectl delete -f https://raw.githubusercontent.com/yasubehe/k8s-test001/master/sample-nginx-pod.yaml
今後は、Kubernetesダッシュボードを動かしたりPrometheusでの監視を試してみようと思います。
#参考URL
Bootstrapping clusters with kubeadm
Kubernetes on CentOS on ESXi 環境を構築してみた
kubeadmでk8sクラスタを構築
VirtualBox+CentOS 7+kubeadmを利用してKubernetesクラスタのローカル構築を試してみる
Install Calico networking and network policy for on-premises deployments
calicoが起動しない(CrashLoopBackOff)
【Kubernetes】VirtualBox上のVM(CentOS 7)にkubeadmで1Master+2Node環境作ってみた