はじめに
オンプレ/VM/IaaS上でKubernetesを構築する方法は複数ありますが、公式のKubernetesではkubeadmを推奨しています。2018年12月の初めにKubernetes1.13がリリースされましたが、変更点の1つにkubeadmがGAになったことが挙げられます。今回は個人的な検証用のKubernetesの環境を構築した際にkubeadmを利用して構築したので、その手順を紹介したいと思います。
kubeadmとは
Kubernetesを簡便に構築するツールで、必要最小限の設定を行います。例えばKubernetes Dashboardなどはインストールされません。公式ページはこちら。
構築環境
今回は以下の環境で構築を行いました。
- EC2: t2.medium × 2 (master, node1つずつ)
- OS: centos7
手順
以下手順はすべてrootで実施しています。
下準備 (master, node共通)
- yum update -y
- vi /etc/hosts
- master, node両方の記載をします。
<masterのプライベートIPアドレス> k8s-master
<nodeのプライベートIPアドレス> k8s-node-1
- ホスト名の変更
- hostnamectl set-hostname --static k8s-master
- --static: /etc/hostnameに記載されるホスト名を変更
- vi /etc/cloud/cloud.cfg
preserve_hostname: true
- swapの無効化
- swapoff -a
- /etc/fstabにswapの項目がある場合はそちらも削除します。今回は特に変更しません。
- SELinuxの無効化
- setenforce 0
- /etc/selinux/configの編集
SELINUX=disabled
- firewall
- firewallが有効の場合は変更が必要ですが、今回は初めから有効でないので特に変更はしません。
docker-ce インストール
公式ページを参考にしながら実行します。
- 必要なパッケージのインストール
yum install -y yum-utils device-mapper-persistent-data lvm2
- リポジトリの追加
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
- dockerインストール
-
公式ページからdockerバージョンの依存性を確認し、別記事も参考にしつつ以下のバージョンをインストールしました。
コマンド中のオプションをつけると、インストール中のconflictが発生せずうまくインストールできるようです。
-
公式ページからdockerバージョンの依存性を確認し、別記事も参考にしつつ以下のバージョンをインストールしました。
yum install -y --setopt=obsoletes=0 docker-ce-17.03.2.ce
- docker起動・自動起動設定
systemctl enable docker && systemctl start docker
- docker起動の確認
[root@k8s-master ~]# docker version
Client:
Version: 17.03.2-ce
API version: 1.27
Go version: go1.7.5
Git commit: f5ec1e2
Built: Tue Jun 27 02:21:36 2017
OS/Arch: linux/amd64
Server:
Version: 17.03.2-ce
API version: 1.27 (minimum version 1.12)
Go version: go1.7.5
Git commit: f5ec1e2
Built: Tue Jun 27 02:21:36 2017
OS/Arch: linux/amd64
Experimental: false
kubeadmインストール (master, node共通)
- yumリポジトリの追加
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
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
EOF
- kubeadm・kubelet・kubectlインストール
yum install -y kubelet kubeadm kubectl
インストール中のログを見るとバージョンが1.13になっているのがわかります。
Dependencies Resolved
=======================================================================================================================================
Package Arch Version Repository Size
=======================================================================================================================================
Installing:
kubeadm x86_64 1.13.1-0 kubernetes 7.9 M
kubectl x86_64 1.13.1-0 kubernetes 8.5 M
kubelet x86_64 1.13.1-0 kubernetes 21 M
Installing for dependencies:
cri-tools x86_64 1.12.0-0 kubernetes 4.2 M
ebtables x86_64 2.0.10-16.el7 base 123 k
kubernetes-cni x86_64 0.6.0-0 kubernetes 8.6 M
socat x86_64 1.7.3.2-2.el7 base 290 k
Transaction Summary
=======================================================================================================================================
Install 3 Packages (+4 Dependent packages)
- kubelet起動・自動起動設定
systemctl enable kubelet && systemctl start kubelet
- kubelet起動確認
- ここではうまく起動していませんが、kubeadmコマンド実行時にkubelet起動に必要な設定を行ってくれるため、ここでは無視して次に進みます。
[root@k8s-master ~]# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: activating (auto-restart) (Result: exit-code) since Mon 2018-12-24 03:07:01 UTC; 5s ago
Docs: https://kubernetes.io/docs/
Process: 13362 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS (code=exited, status=255)
Main PID: 13362 (code=exited, status=255)
Dec 24 03:07:01 k8s-master systemd[1]: Unit kubelet.service entered failed state.
Dec 24 03:07:01 k8s-master systemd[1]: kubelet.service failed.
kubeadm init (master)
- dockerとkubernetesとのcgroup driverの確認
-
kubeletのデフォルト設定であるcgroupfsの場合は変更する必要はない
ため、今回は特に変更しません。
-
kubeletのデフォルト設定であるcgroupfsの場合は変更する必要はない
[root@k8s-master ~]# docker info | grep -i cgroup
Cgroup Driver: cgroupfs
- kubeadm起動
- 今回はCalicoを使用しますので、Calicoの使用条件に合わせてCIDRを指定します。
kubeadm init --pod-network-cidr=192.168.0.0/16
- kubeadm init時に何をしているか
- 上記コマンド実行時に出てくるログを見てみます。
[root@k8s-master ~]# kubeadm init --pod-network-cidr=192.168.0.0/16
[init] Using Kubernetes version: v1.13.1
[preflight] Running pre-flight checks
[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] Activating the kubelet service
[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 <k8s-masterのプライベートIPアドレス>]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k8s-master localhost] and IPs [<k8s-masterのプライベートIPアドレス> 127.0.0.1 ::1]
[certs] Generating "apiserver-etcd-client" 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 [<k8s-masterのプライベートIPアドレス> 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-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"
[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
[apiclient] All control plane components are healthy after 20.501682 seconds
[uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.13" in namespace kube-system with the configuration for the kubelets in the cluster
[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "k8s-master" as an annotation
[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: figfuf.3uvfrsxnowkrf5ed
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstraptoken] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstraptoken] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes master has initialized successfully!
- preflight: 必要なdockerイメージのインストールを行います。
- kubelet-start: kubelet起動に必要なコンフィグファイルの更新を行います。
- certs: Kubernetesの動作に必要な各コンポーネントの証明書を発行します。
- kubeconfig: 各コンポーネントのコンフィグファイルの更新を行います。
- control-plane: apiserverなどのcontrol planeに必要なmanifestファイルの作成を行います。
- etcd: etcd用のmanifestファイルを作成します。
- wait-control-plane: control planeが立ち上がるのを待ちます。
- apiclient: すべてのcontrol planeの動作を確認します。
- uploadconfig: kubeadm-configと言うConfigMapファイルで使用したコンフィグ情報を保存します。
- kubelet: 先ほど保存した情報を用いて、kubernetes 1.13用のConfigMapを作成します。
- patchnode: CRI(Container Runtime Interface)のsocket情報をk8s-master用に更新します。
- mark-control-plane: k8s-masterにcontrol plane用のlabelを添付し、control planeとして認識するようにします。
- bootstrap-token: RBAC用のtokenを発行します。
- bootstraptoken: 作成したtokenを用いてRBACルールを適用します。
- addons: Kubernetesに必要なaddonであるCoreDNSとkube-proxyをアプライします。
以上、これだけのことをkubeadmはやってくれているんですね。もっと具体的に、何をやっているかについては、公式ページに説明があります。
[追記]
kubeadm init時にオプションを追加することでセットアップ時の設定を変更できるようです。公式ページはこちらになります。本番環境への適用などを考える際には参考になりそうです。
- kubeadm init後の設定
- kubeadm init実行後に出てくる出力をもとに設定します。
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
Calicoデプロイ
- 条件確認
- 公式ページにある通りの条件を満たすか確認します。
[root@k8s-master ~]# sysctl -n net.bridge.bridge-nf-call-iptables
1
[root@k8s-master ~]#
- Calicoデプロイ
- 今回はやや古いバージョンのCalicoをデプロイしましたが、2018年12月28日時点での最新版であるv3.4ではやや手順が変わっています。
kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
- kubectl動作確認
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 4m v1.13.1
[root@k8s-master ~]#
kubeadm join (node)
- kubeadm join実行
- kubeadm init時に出力されるコマンドをnode側で実行します。
kubeadm join <k8s-masterプライベートIPアドレス:ポート番号> --token <token値> sha256:<sha256値>
- kubeadm join時に何をしているか
- 先ほどと同様に出力ログを確認します。
[preflight] Running pre-flight checks
[WARNING Service-Kubelet]: kubelet service is not enabled, please run 'systemctl enable kubelet.service'
[discovery] Trying to connect to API Server "<k8s-masterプライベートIPアドレス:ポート番号>"
[discovery] Created cluster-info discovery client, requesting info from "https://<k8s-masterプライベートIPアドレス:ポート番号>"
[discovery] Requesting info from "https://<k8s-masterプライベートIPアドレス:ポート番号>" again to validate TLS against the pinned public key
[discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "<k8s-masterプライベートIPアドレス:ポート番号>"
[discovery] Successfully established connection with API Server "<k8s-masterプライベートIPアドレス:ポート番号>"
[join] Reading configuration from the cluster...
[join] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.13" ConfigMap in the kube-system namespace
[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] Activating the kubelet service
[tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap...
[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "k8s-node-1" as an annotation
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 master to see this node join the cluster.
- preflight: 事前確認をします。ここでkubeletが起動していないと出ますが、しばらく後で実行してくれます。
- discovery: k8s-masterを探して接続を確立します。
- join: コンフィグ情報を取得してjoinします。
- kubelet: kubelet用のConfigMapを作成します。
- kubelet-start: kubeletを起動します。
- tlsbootstrap: TLS Bootstrapの起動を待ちます。
- patchnode: CRI socketを更新します。
動作確認
- kubectl実行(master)
- kubectlで追加したk8s-node-1が認識されたか確認します。
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 5m59s v1.13.1
k8s-node-1 Ready <none> 57s v1.13.1
[root@k8s-master ~]#
参考リンク