Table of Contents
Oracle Linux 7.4.0のVMでKubernetes 1.10.0のクラスタをスクラッチから全手動で作った。
参考にしたのは主に以下。
- https://nixaid.com/deploying-kubernetes-cluster-from-scratch/
- https://github.com/kubernetes/kubeadm/blob/master/docs/design/design_v1.10.md
- https://kubernetes.io/docs/getting-started-guides/scratch/
- https://kubernetes.io/docs/reference/setup-tools/kubeadm/implementation-details/
- https://ulam.io/blog/kubernetes-scratch/
- https://docs.microsoft.com/en-us/virtualization/windowscontainers/kubernetes/creating-a-linux-master
(2019/1/17追記: クラスタ全手動構築手順はKubernetes 1.13になってもほとんど変わっていない。ユニットファイルに指定するオプションが多少減ったりしたくらい。
また、ホストがRHELでもほとんど変わらない。インストールするDockerがDocker-CE(もしくはRedhatのやつ)に変わるくらいで、あとはkubeletの--cgroup-driver
をsystemd
にしないといけなかったかも。)
(2020/3/2更新。)
構成
- マシン: Windows 10 Homeのラップトップの上のVMware PlayerのVM
- CPU: 2コア
- メモリ: 4GB
- NIF: NATのを一つ
- OS: Oracle Linux 7.4.0
- Minimalインストール
- IPアドレス: 192.168.171.200、静的割り当て
- ホスト名: k8s-master (hostsで解決)
- Docker: Oracle Container Runtime for Docker (docker-engine) 17.06.2
- Kubernetes: バージョン1.10.0
- 単一ノード
- 全コンポーネント(kubelet、kube-proxy、kube-apiserver、kube-controller-manager、kube-scheduler、etcd)をsystemdで起動 (i.e. 非コンテナ)
- kubeletとkube-proxy以外は非rootユーザ
- kubeletは現時点でrootで動かす必要がある
- kube-proxyはiptableいじったりする都合上rootで動かす必要があるっぽい。
- コンポーネント間通信とkubectlの通信をTLSで暗号化
- TLS 1.2
- セキュアなCipher Suites
- コンポーネント間通信とkubectlの通信の認証はx509クライアント証明書
- TLS Bootstrapping
- Bootstrap token使用
- CSR自動承認
- Certificate Rotation有効
- etcd 3.1.12
- flannel 0.10.0
- CoreDNS 1.1.1
- SERVICE_CLUSTER_IP_RANGE (Serviceに割り当てるIPの範囲) は10.0.0.0/16
- kube-apiserverのIPはこの範囲の最初のIP(i.e. 10.0.0.1)になる。
- ホストネットワークや、CLUSTER_CIDRと範囲が被らないようにする必要がある。
- CLUSTER_CIDR (Podに割り当てるIPの範囲) は10.244.0.0/16
- flannelの要件に合わせている。
- ホストネットワークや、SERVICE_CLUSTER_IP_RANGEと範囲が被らないようにする必要がある。
- Proxyモードはiptables。
- ipvsのほうが速いけど、flannelとかがサポートしているかよくわからないので。
kubeletの動作条件にあるので、swapをoffにする。
Oracle Linuxにログインして、/etc/fstab
のswapの行を削除して、以下のコマンドを実行。
# swapoff -a
# cd /tmp
SELinuxはちゃんと設定すればKubernetes動かせるはずだけど、面倒なのでとりあえず無効にする。
/etc/selinux/config
を編集して、SELINUX
をpermissive
にして、以下のコマンドを実行。
# setenforce 0
ファイアウォールもちゃんと設定すればいいんだけど面倒なのでとりあえず無効にする。
# systemctl stop firewalld
# systemctl disable firewalld
これで準備完了。
クラスタ構築手順
おおむね、k8sコンポーネント間の通信の暗号化に使う鍵と証明書の生成、各コンポーネント用kubeconfigの生成、etcdのデプロイ、k8sコンポーネントのデプロイ、fannelデプロイ、CoreDNSデプロイ、という流れ。 ついでに最後にWeave Scopeをデプロイしてみる。
1. Bridge netfilterとIP forwardingを設定
まず、Bridge netfilterモジュールとoverlayモジュールをロードする。 (kube-proxyをipvsモードで動かすなら、さらにip_vs、ip_vs_rr、ip_vs_wrr、ip_vs_sh、nf_conntrack_ipv4が要る。)
# modprobe br_netfilter
# echo "br_netfilter" > /etc/modules-load.d/99-k8s.conf
# modprobe overlay
# echo "overlay" >> /etc/modules-load.d/99-k8s.conf
Bridge netfilterとIP forwardingを有効化する。
# cat > /etc/sysctl.d/kubernetes.conf << EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# sysctl -p /etc/sysctl.d/kubernetes.conf
設定確認。
# lsmod |grep br_netfilter
# sysctl -a | grep -E "net.bridge.bridge-nf-call-|net.ipv4.ip_forward"
2. x509証明書生成
opensslの設定作成
# mkdir -p /etc/kubernetes/pki # HOSTNAME=k8s-master # K8S_SERVICE_IP=10.0.0.1 # MASTER_IP=192.168.171.200 # cat > /etc/kubernetes/pki/openssl.cnf << EOF [ req ] distinguished_name = req_distinguished_name [req_distinguished_name] [ v3_ca ] basicConstraints = critical, CA:TRUE keyUsage = critical, digitalSignature, keyEncipherment, keyCertSign [ v3_req_client ] basicConstraints = CA:FALSE keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth [ v3_req_apiserver ] basicConstraints = CA:FALSE keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names_cluster [ v3_req_etcd ] basicConstraints = CA:FALSE keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names_etcd [ alt_names_cluster ] DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc DNS.4 = kubernetes.default.svc.cluster.local DNS.5 = ${HOSTNAME} IP.1 = ${MASTER_IP} IP.2 = ${K8S_SERVICE_IP} [ alt_names_etcd ] DNS.1 = ${HOSTNAME} IP.1 = ${MASTER_IP} EOF
Kubernetes CA証明書生成
以降で生成する証明書に署名するための証明書。 後述のTLS Bootstrappingでの証明書生成にも使う。
# groupadd -r kubernetes # adduser -r -g kubernetes -M -s /sbin/nologin kubernetes # CA_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/ca.key # chown kubernetes:kubernetes /etc/kubernetes/pki/ca.key # chmod 0600 /etc/kubernetes/pki/ca.key # openssl req -x509 -new -sha256 -nodes -key /etc/kubernetes/pki/ca.key -days $CA_DAYS -out /etc/kubernetes/pki/ca.crt -subj "/CN=kubernetes-ca" -extensions v3_ca -config /etc/kubernetes/pki/openssl.cnf
kube-apiserver証明書生成
kube-apiserverのサーバ証明書。
# APISERVER_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/kube-apiserver.key # chown kubernetes:kubernetes /etc/kubernetes/pki/kube-apiserver.key # chmod 0600 /etc/kubernetes/pki/kube-apiserver.key # openssl req -new -sha256 -key /etc/kubernetes/pki/kube-apiserver.key -subj "/CN=kube-apiserver" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/kube-apiserver.crt -days $APISERVER_DAYS -extensions v3_req_apiserver -extfile /etc/kubernetes/pki/openssl.cnf
kube-apiserver-kubelet証明書生成
kube-apiserverがkubeletのAPIにアクセスするときのクライアント証明書。
# APISERVER_KUBELET_CLIENT_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/apiserver-kubelet-client.key # chown kubernetes:kubernetes /etc/kubernetes/pki/apiserver-kubelet-client.key # chmod 0600 /etc/kubernetes/pki/apiserver-kubelet-client.key # openssl req -new -key /etc/kubernetes/pki/apiserver-kubelet-client.key -subj "/CN=kube-apiserver-kubelet-client/O=system:masters" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/apiserver-kubelet-client.crt -days $APISERVER_KUBELET_CLIENT_DAYS -extensions v3_req_client -extfile /etc/kubernetes/pki/openssl.cnf
adminクライアント証明書生成
kubectlがkube-apiserverのAPIにアクセスするときのクライアント証明書。
# groupadd -r kube-admin # adduser -r -g kube-admin -M -s /sbin/nologin kube-admin # ADMIN_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/admin.key # chown kube-admin:kube-admin /etc/kubernetes/pki/admin.key # chmod 0600 /etc/kubernetes/pki/admin.key # openssl req -new -key /etc/kubernetes/pki/admin.key -subj "/CN=kubernetes-admin/O=system:masters" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/admin.crt -days $ADMIN_DAYS -extensions v3_req_client -extfile /etc/kubernetes/pki/openssl.cnf
kube-controller-managerのクライアント証明書生成
kube-controller-managerがkube-apiserverに接続するときのクライアント証明書。 この証明書に対応する秘密鍵と公開鍵はそれぞれ、kube-controller-managerがService Accountトークンに署名するとき、kube-apiserverがトークンの署名を確認するときにも使う。
# CONTROLLER_MANAGER_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/kube-controller-manager.key # openssl ec -in /etc/kubernetes/pki/kube-controller-manager.key -outform PEM -pubout -out /etc/kubernetes/pki/kube-controller-manager.pub # chown kubernetes:kubernetes /etc/kubernetes/pki/kube-controller-manager.key # chmod 0600 /etc/kubernetes/pki/kube-controller-manager.key # openssl req -new -sha256 -key /etc/kubernetes/pki/kube-controller-manager.key -subj "/CN=system:kube-controller-manager" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/kube-controller-manager.crt -days $CONTROLLER_MANAGER_DAYS -extensions v3_req_client -extfile /etc/kubernetes/pki/openssl.cnf
kube-schedulerクライアント証明書生成
kube-schedulerがkube-apiserverにリクエストするときに使うクライアント証明書。
# SCHEDULER_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/kube-scheduler.key # chown kubernetes:kubernetes /etc/kubernetes/pki/kube-scheduler.key # chmod 0600 /etc/kubernetes/pki/kube-scheduler.key # openssl req -new -sha256 -key /etc/kubernetes/pki/kube-scheduler.key -subj "/CN=system:kube-scheduler" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/kube-scheduler.crt -days $SCHEDULER_DAYS -extensions v3_req_client -extfile /etc/kubernetes/pki/openssl.cnf
kube-proxyクライアント証明書生成
kube-proxyがkube-apiserverにリクエストするときに使うクライアント証明書。
# PROXY_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/kube-proxy.key # chown kubernetes:kubernetes /etc/kubernetes/pki/kube-proxy.key # chmod 0600 /etc/kubernetes/pki/kube-proxy.key # openssl req -new -sha256 -key /etc/kubernetes/pki/kube-proxy.key -subj "/CN=system:kube-proxy/O=system:node-proxier" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/kube-proxy.crt -days $PROXY_DAYS -extensions v3_req_client -extfile /etc/kubernetes/pki/openssl.cnf
front proxy CA証明書生成
front proxyの証明書に署名するのにつかう証明書。 front proxyはAPI Aggregationのためのもの。 API Aggregationは、kube-apiserverを変更することなく、別途作られたExtension API ServerでKubernetesのAPIを拡張できるようにする機能。 API Aggregationは現時点ではkube-apiserverの一機能として実装されていて、将来的にはkubernetes-aggregatorという別のコンポーネントで実現される。
API AggregationしないならこのCA証明書と次のクライアント証明書はいらないはず。 今回はしないけど、とりあえず作って設定したおく。
# FRONT_PROXY_CA_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/front-proxy-ca.key # chown kubernetes:kubernetes /etc/kubernetes/pki/front-proxy-ca.key # chmod 0600 /etc/kubernetes/pki/front-proxy-ca.key # openssl req -x509 -new -sha256 -nodes -key /etc/kubernetes/pki/front-proxy-ca.key -days $FRONT_PROXY_CA_DAYS -out /etc/kubernetes/pki/front-proxy-ca.crt -subj "/CN=front-proxy-ca" -extensions v3_ca -config /etc/kubernetes/pki/openssl.cnf
front proxyクライアント証明書
Extension API ServerのAPIへのリクエストは、いったんkube-apiserverが受け取ってExtension API Serverに転送される。(多分。) この転送の暗号化と認証にTLSが使われていて、ここではそのクライアント証明書を生成する。
# FRONT_PROXY_CLIENT_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/front-proxy-client.key # chown kubernetes:kubernetes /etc/kubernetes/pki/front-proxy-client.key # chmod 0600 /etc/kubernetes/pki/front-proxy-client.key # openssl req -new -sha256 -key /etc/kubernetes/pki/front-proxy-client.key -subj "/CN=front-proxy-client" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/front-proxy-ca.crt -CAkey /etc/kubernetes/pki/front-proxy-ca.key -CAcreateserial -out /etc/kubernetes/pki/front-proxy-client.crt -days $FRONT_PROXY_CLIENT_DAYS -extensions v3_req_client -extfile /etc/kubernetes/pki/openssl.cnf
etcd CA証明書
以降で生成するetcdの証明書に署名するための証明書。
# groupadd -r etcd # adduser -r -g etcd -M -s /sbin/nologin etcd # ETCD_CA_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/etcd-ca.key # chown etcd:etcd /etc/kubernetes/pki/etcd-ca.key # chmod 0600 /etc/kubernetes/pki/etcd-ca.key # openssl req -x509 -new -sha256 -nodes -key /etc/kubernetes/pki/etcd-ca.key -days $ETCD_CA_DAYS -out /etc/kubernetes/pki/etcd-ca.crt -subj "/CN=etcd-ca" -extensions v3_ca -config /etc/kubernetes/pki/openssl.cnf
etcd証明書
etcdのサーバ証明書。
# ETCD_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/etcd.key # chown etcd:etcd /etc/kubernetes/pki/etcd.key # chmod 0600 /etc/kubernetes/pki/etcd.key # openssl req -new -sha256 -key /etc/kubernetes/pki/etcd.key -subj "/CN=etcd" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/etcd-ca.crt -CAkey /etc/kubernetes/pki/etcd-ca.key -CAcreateserial -out /etc/kubernetes/pki/etcd.crt -days $ETCD_DAYS -extensions v3_req_etcd -extfile /etc/kubernetes/pki/openssl.cnf
etcdクライアント証明書
etcdのクライアント証明書。 kube-apiserverだけがetcdと話すので、kube-apiserverだけが使う。
# ETCD_CLIENT_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/etcd-client.key # chown kubernetes:kubernetes /etc/kubernetes/pki/etcd-client.key # chmod 0600 /etc/kubernetes/pki/etcd-client.key # openssl req -new -sha256 -key /etc/kubernetes/pki/etcd-client.key -subj "/CN=kube-apiserver" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/etcd-ca.crt -CAkey /etc/kubernetes/pki/etcd-ca.key -CAcreateserial -out /etc/kubernetes/pki/etcd-client.crt -days $ETCD_CLIENT_DAYS -extensions v3_req_client -extfile /etc/kubernetes/pki/openssl.cnf
etcd peer証明書
etcdサーバが冗長構成のとき、サーバ間の通信の暗号化に使う証明書。 マスタが一つなら要らないはずだけど、今回とりあえず作って設定しておく。
# ETCD_PEER_DAYS=5475 # openssl ecparam -name secp521r1 -genkey -noout -out /etc/kubernetes/pki/etcd-peer.key # chown etcd:etcd /etc/kubernetes/pki/etcd-peer.key # chmod 0600 /etc/kubernetes/pki/etcd-peer.key # openssl req -new -sha256 -key /etc/kubernetes/pki/etcd-peer.key -subj "/CN=etcd-peer" | openssl x509 -req -sha256 -CA /etc/kubernetes/pki/etcd-ca.crt -CAkey /etc/kubernetes/pki/etcd-ca.key -CAcreateserial -out /etc/kubernetes/pki/etcd-peer.crt -days $ETCD_PEER_DAYS -extensions v3_req_etcd -extfile /etc/kubernetes/pki/openssl.cnf
確認
以上で生成した証明書の内容を確認する。
# for i in /etc/kubernetes/pki/*crt; do echo $i:; openssl x509 -subject -issuer -noout -in $i; echo; done
3. Kubernetesバイナリインストール
公式ドキュメントによると、Docker、kubelet、kube-proxyはコンテナ外で動かして、etcd、kube-apiserver、kube-controller-manager、kube-schedulerはコンテナで動かすのが推奨されている。 けど、とりあえずは簡単に全部コンテナ外でやる。
(Oracle Linux用には、各コンポのコンテナイメージ詰め合わせがOracle Container Services for use with Kubernetesという名前で配布されているけど、現時点で1.9までしかないので使わない。)
バイナリは以下URLからダウンロードできる。
- 全部入り: https://storage.googleapis.com/kubernetes-release/release/v1.10.0/kubernetes-server-linux-amd64.tar.gz
- kube-apiserver
- kube-controller-manager
- kube-scheduler
- kube-proxy
- kubelet: https://storage.googleapis.com/kubernetes-release/release/v1.10.0/bin/linux/amd64/kubelet
- kubectl: https://storage.googleapis.com/kubernetes-release/release/v1.10.0/bin/linux/amd64/kubectl
- kubeadm: https://storage.googleapis.com/kubernetes-release/release/v1.10.0/bin/linux/amd64/kubeadm
- hyperkube: https://storage.googleapis.com/kubernetes-release/release/v1.10.0/bin/linux/amd64/hyperkube
最後のhyperkubeは、各種Kubernetesバイナリのごった煮。 ファイル名によって動作が変わる。 簡単のためこれを使うけど、個別のバイナリ使ったほうがメモリ使用量などで有利そう。
hyperkubeとkubeadmのバイナリを/usr/bin/
において、以下のコマンドを実行。
# ln -s /usr/bin/hyperkube /usr/bin/kube-apiserver
# ln -s /usr/bin/hyperkube /usr/bin/kube-controller-manager
# ln -s /usr/bin/hyperkube /usr/bin/kube-scheduler
# ln -s /usr/bin/hyperkube /usr/bin/kube-proxy
# ln -s /usr/bin/hyperkube /usr/bin/kubelet
# ln -s /usr/bin/hyperkube /usr/bin/kubectl
# chmod +x /usr/bin/kube*
# mkdir -p /var/lib/{kubelet,kube-proxy}
4. kubeconfigファイル生成
kubectlとマスタコンポーネントがkube-apiserverと話すときに使うkubeconfigファイルを生成する。
kube-controller-managerのkubeconfig
# MASTER_IP=192.168.171.200 # KUBERNETES_PUBLIC_ADDRESS=$MASTER_IP # CLUSTER_NAME="k8s" # KCONFIG=/etc/kubernetes/kube-controller-manager.kubeconfig # KUSER="system:kube-controller-manager" # kubectl config set-cluster ${CLUSTER_NAME} --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 --kubeconfig=${KCONFIG} # kubectl config set-credentials ${KUSER} --client-certificate=/etc/kubernetes/pki/kube-controller-manager.crt --client-key=/etc/kubernetes/pki/kube-controller-manager.key --embed-certs=true --kubeconfig=${KCONFIG} # kubectl config set-context ${KUSER}@${CLUSTER_NAME} --cluster=${CLUSTER_NAME} --user=${KUSER} --kubeconfig=${KCONFIG} # kubectl config use-context ${KUSER}@${CLUSTER_NAME} --kubeconfig=${KCONFIG} # chown kubernetes:kubernetes ${KCONFIG} # chmod 0600 ${KCONFIG}
設定確認。
# kubectl config view --kubeconfig=${KCONFIG}
kube-schedulerのkubeconfig
# MASTER_IP=192.168.171.200 # KUBERNETES_PUBLIC_ADDRESS=$MASTER_IP # CLUSTER_NAME="k8s" # KCONFIG=/etc/kubernetes/kube-scheduler.kubeconfig # KUSER="system:kube-scheduler" # kubectl config set-cluster ${CLUSTER_NAME} --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 --kubeconfig=${KCONFIG} # kubectl config set-credentials ${KUSER} --client-certificate=/etc/kubernetes/pki/kube-scheduler.crt --client-key=/etc/kubernetes/pki/kube-scheduler.key --embed-certs=true --kubeconfig=${KCONFIG} # kubectl config set-context ${KUSER}@${CLUSTER_NAME} --cluster=${CLUSTER_NAME} --user=${KUSER} --kubeconfig=${KCONFIG} # kubectl config use-context ${KUSER}@${CLUSTER_NAME} --kubeconfig=${KCONFIG} # chown kubernetes:kubernetes ${KCONFIG} # chmod 0600 ${KCONFIG}
設定確認。
# kubectl config view --kubeconfig=${KCONFIG}
adminのkubeconfig
kubectl用。
# MASTER_IP=192.168.171.200 # KUBERNETES_PUBLIC_ADDRESS=$MASTER_IP # CLUSTER_NAME="k8s" # KCONFIG=/etc/kubernetes/admin.kubeconfig # KUSER="kubernetes-admin" # kubectl config set-cluster ${CLUSTER_NAME} --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 --kubeconfig=${KCONFIG} # kubectl config set-credentials ${KUSER} --client-certificate=/etc/kubernetes/pki/admin.crt --client-key=/etc/kubernetes/pki/admin.key --embed-certs=true --kubeconfig=${KCONFIG} # kubectl config set-context ${KUSER}@${CLUSTER_NAME} --cluster=${CLUSTER_NAME} --user=${KUSER} --kubeconfig=${KCONFIG} # kubectl config use-context ${KUSER}@${CLUSTER_NAME} --kubeconfig=${KCONFIG} # chown kube-admin:kube-admin ${KCONFIG} # chmod 0600 ${KCONFIG} # ln -s ${KCONFIG} ~/.kube/config
設定確認。
# kubectl config view --kubeconfig=${KCONFIG}
5. etcdデプロイ
https://github.com/coreos/etcd/releases/download/v3.1.12/etcd-v3.1.12-linux-amd64.tar.gz
からアーカイブをダウンロードして、中のetcdとetcdctlを/usr/bin/
にいれて、以下のコマンドを実行。
# chown root:root /usr/bin/etcd*
# chmod 0755 /usr/bin/etcd*
# mkdir -p /var/lib/etcd
# chown etcd:etcd /var/lib/etcd
で、systemdのユニットファイルを書いてサービス化。
(参考: Kubernetesドキュメント、etcdドキュメント)
# MASTER_IP=192.168.171.200
# ETCD_MEMBER_NAME=etcd1
# CLUSTER_NAME="k8s"
# ETCD_TOKEN=$(openssl rand -hex 5)
# ETCD_CLUSTER_TOKEN=$CLUSTER_NAME-$ETCD_TOKEN
# cat > /etc/systemd/system/etcd.service << EOF
[Unit]
Description=etcd
Documentation=https://coreos.com/etcd/docs/latest/
After=network.target
[Service]
Type=notify
NotifyAccess=all
User=etcd
Group=etcd
ExecStart=/usr/bin/etcd \\
--name ${ETCD_MEMBER_NAME} \\
--listen-client-urls https://${MASTER_IP}:2379 \\
--advertise-client-urls https://${MASTER_IP}:2379 \\
--data-dir=/var/lib/etcd \\
--cert-file=/etc/kubernetes/pki/etcd.crt \\
--key-file=/etc/kubernetes/pki/etcd.key \\
--peer-cert-file=/etc/kubernetes/pki/etcd-peer.crt \\
--peer-key-file=/etc/kubernetes/pki/etcd-peer.key \\
--trusted-ca-file=/etc/kubernetes/pki/etcd-ca.crt \\
--peer-trusted-ca-file=/etc/kubernetes/pki/etcd-ca.crt \\
--peer-client-cert-auth \\
--client-cert-auth \\
--initial-advertise-peer-urls https://${MASTER_IP}:2380 \\
--listen-peer-urls https://${MASTER_IP}:2380 \\
--initial-cluster-token ${ETCD_CLUSTER_TOKEN} \\
--initial-cluster ${ETCD_MEMBER_NAME}=https://${MASTER_IP}:2380 \\
--initial-cluster-state new
Restart=always
RestartSec=10s
[Install]
WantedBy=multi-user.target
EOF
# systemctl daemon-reload
# systemctl enable etcd
# systemctl start etcd
確認。
# systemctl status etcd -l
# MASTER_IP=192.168.171.200
# etcdctl --endpoints https://${MASTER_IP}:2379 --ca-file=/etc/kubernetes/pki/etcd-ca.crt --cert-file=/etc/kubernetes/pki/etcd-client.crt --key-file=/etc/kubernetes/pki/etcd-client.key cluster-health
# etcdctl --endpoints https://${MASTER_IP}:2379 --ca-file=/etc/kubernetes/pki/etcd-ca.crt --cert-file=/etc/kubernetes/pki/etcd-client.crt --key-file=/etc/kubernetes/pki/etcd-client.key member list
6. マスタコンポーネントデプロイ。
kube-apiserver
systemdのユニットファイルを書いてサービス化。
- d
# mkdir -p /var/log/kubernetes # chown kubernetes:kubernetes /var/log/kubernetes # chmod 0700 /var/log/kubernetes # MASTER_IP=192.168.171.200 # SERVICE_CLUSTER_IP_RANGE="10.0.0.0/16" # SECRET_ENC_KEY=$(echo -n 'your_32_bytes_secure_private_key' | base64) # cat > /etc/kubernetes/encryption.conf << EOF kind: EncryptionConfig apiVersion: v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: ${SECRET_ENC_KEY} - identity: {} EOF # cat > /etc/kubernetes/audit-policy.conf << EOF apiVersion: audit.k8s.io/v1beta1 kind: Policy # Don't generate audit events for all requests in RequestReceived stage. omitStages: - "RequestReceived" rules: # Log pod changes at RequestResponse level - level: RequestResponse resources: - group: "" # Resource "pods" doesn't match requests to any subresource of pods, # which is consistent with the RBAC policy. resources: ["pods"] # Log "pods/log", "pods/status" at Metadata level - level: Metadata resources: - group: "" resources: ["pods/log", "pods/status"] # Don't log requests to a configmap called "controller-leader" - level: None resources: - group: "" resources: ["configmaps"] resourceNames: ["controller-leader"] # Don't log watch requests by the "system:kube-proxy" on endpoints or services - level: None users: ["system:kube-proxy"] verbs: ["watch"] resources: - group: "" # core API group resources: ["endpoints", "services"] # Don't log authenticated requests to certain non-resource URL paths. - level: None userGroups: ["system:authenticated"] nonResourceURLs: - "/api*" # Wildcard matching. - "/version" # Log the request body of configmap changes in kube-system. - level: Request resources: - group: "" # core API group resources: ["configmaps"] # This rule only applies to resources in the "kube-system" namespace. # The empty string "" can be used to select non-namespaced resources. namespaces: ["kube-system"] # Log configmap and secret changes in all other namespaces at the Metadata level. - level: Metadata resources: - group: "" # core API group resources: ["secrets", "configmaps"] # Log all other resources in core and extensions at the Request level. - level: Request resources: - group: "" # core API group - group: "extensions" # Version of group should NOT be included. # A catch-all rule to log all other requests at the Metadata level. - level: Metadata # Long-running requests like watches that fall under this rule will not # generate an audit event in RequestReceived. omitStages: - "RequestReceived" EOF # cat > /etc/systemd/system/kube-apiserver.service << EOF [Unit] Description=Kubernetes API Server Documentation=https://github.com/kubernetes/kubernetes After=network.target [Service] User=kubernetes Group=kubernetes ExecStart=/usr/bin/kube-apiserver \\ --feature-gates=RotateKubeletServerCertificate=true \\ --apiserver-count=1 \\ --allow-privileged=true \\ --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,NodeRestriction,DenyEscalatingExec,StorageObjectInUseProtection \\ --authorization-mode=Node,RBAC \\ --bind-address=0.0.0.0 \\ --advertise-address=${MASTER_IP} \\ --client-ca-file=/etc/kubernetes/pki/ca.crt \\ --etcd-cafile=/etc/kubernetes/pki/etcd-ca.crt \\ --etcd-certfile=/etc/kubernetes/pki/etcd-client.crt \\ --etcd-keyfile=/etc/kubernetes/pki/etcd-client.key \\ --etcd-servers=https://${MASTER_IP}:2379 \\ --service-account-key-file=/etc/kubernetes/pki/kube-controller-manager.pub \\ --service-cluster-ip-range=${SERVICE_CLUSTER_IP_RANGE} \\ --tls-cert-file=/etc/kubernetes/pki/kube-apiserver.crt \\ --tls-private-key-file=/etc/kubernetes/pki/kube-apiserver.key \\ --kubelet-certificate-authority=/etc/kubernetes/pki/ca.crt \\ --enable-bootstrap-token-auth=true \\ --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt \\ --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key \\ --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \\ --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt \\ --requestheader-username-headers=X-Remote-User \\ --requestheader-group-headers=X-Remote-Group \\ --requestheader-allowed-names=front-proxy-client \\ --requestheader-extra-headers-prefix=X-Remote-Extra- \\ --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt \\ --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key \\ --experimental-encryption-provider-config=/etc/kubernetes/encryption.conf \\ --v=2 \\ --tls-min-version=VersionTLS12 \\ --tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 \\ --anonymous-auth=false \\ --audit-log-format=json \\ --audit-log-maxage=30 \\ --audit-log-maxbackup=3 \\ --audit-log-maxsize=100 \\ --audit-log-path=/var/log/kubernetes/kube-audit.log \\ --audit-policy-file=/etc/kubernetes/audit-policy.conf Restart=always RestartSec=10s [Install] WantedBy=multi-user.target EOF # systemctl daemon-reload # systemctl enable kube-apiserver # systemctl start kube-apiserver
(k8s 1.13から
EncryptionConfig
がEncryptionConfiguration
に変わり、そのapiVersionもv1
からapiserver.config.k8s.io/v1
に変わった。)(audit-policy.confに書くapiVersionもk8s 1.13から
audit.k8s.io/v1
になった。)--allow-privileged
はflannelなどに必要。--enable-admission-plugins
には公式推奨のプラグインに加えて、後述のTLS BootstrappingのためのNodeRestrictionを指定。 また、--allow-privileged
の効果を軽減するため、DenyEscalatingExecも追加で指定。 また、使われているPersistent VolumeやPersistent Volume Claimが誤って消されることを防ぐStorageObjectInUseProtectionも追加で指定。 因みに、プラグインを指定する順番はKubernetes 1.10からは気にしなくてよくなった。--authorization-mode
にはRBACを指定するのが標準。 後述のTLS Bootstrappingをするなら、Nodeも要る。--experimental-encryption-provider-config
はSecretを暗号化するための設定。(k8s 1.13でexperimentalじゃなくなった。) 暗号化のキーをローテーションすることもできるけど、それはやってない。--tls-min-version
と--tls-cipher-suites
はOpenSSLクックブックとGoのtlsパッケージドキュメントを参考に設定。 RSA鍵交換はNG、RC4と3DESもNG、AESの鍵長は128ビット以上、SHA1はNG。また、(–tls-min-versionをVersionTLS12にする場合?)TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256が必須で、CBCモードがNG。(参照: https://github.com/golang/go/blob/release-branch.go1.9/src/net/http/h2_bundle.go)
--anonymous-auth=false
はセキュリティのため設定。--requestheader-*
と--proxy-client-*
は上記API Aggregationのための設定。--audit-*
は監査ログ設定。 100MB3面のログを30日間保持する。 ログポリシーは公式のサンプルそのまま。 (ログポリシーのAPIバージョンはk8s 1.12でaudit.k8s.io/v1
になった。)--feature-gates
でRotateKubeletServerCertificateを有効にして、kubeletのサーバ証明書を自動更新するようにしている。 因みに、クライアント証明書を自動更新するRotateKubeletClientCertificateはデフォルトで有効。 これらがCertificate Rotationと呼ばれる機能。 (セキュリティの問題から、RotateKubeletServerCertificate
のサーバ証明書自動更新はk8s 1.11以降使えなくなった。)--feature-gates
は全Kubernetesコンポーネントで同じ値を指定するのがよさそう。確認。
# systemctl status kube-apiserver -l # journalctl -u kube-apiserver
kube-controller-manager
systemdのユニットファイルを書いてサービス化。
# CLUSTER_CIDR="10.244.0.0/16" # SERVICE_CLUSTER_IP_RANGE="10.0.0.0/16" # CLUSTER_NAME="k8s" # cat > /etc/systemd/system/kube-controller-manager.service << EOF [Unit] Description=Kubernetes Controller Manager Documentation=https://github.com/kubernetes/kubernetes After=network.target [Service] User=kubernetes Group=kubernetes ExecStart=/usr/bin/kube-controller-manager \\ --feature-gates=RotateKubeletServerCertificate=true \\ --kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\ --bind-address=0.0.0.0 \\ --controllers=*,bootstrapsigner,tokencleaner \\ --service-account-private-key-file=/etc/kubernetes/pki/kube-controller-manager.key \\ --allocate-node-cidrs=true \\ --cluster-cidr=${CLUSTER_CIDR} \\ --node-cidr-mask-size=24 \\ --cluster-name=${CLUSTER_NAME} \\ --service-cluster-ip-range=${SERVICE_CLUSTER_IP_RANGE} \\ --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt \\ --cluster-signing-key-file=/etc/kubernetes/pki/ca.key \\ --root-ca-file=/etc/kubernetes/pki/ca.crt \\ --use-service-account-credentials=true \\ --v=2 \\ --experimental-cluster-signing-duration=8760h0m0s Restart=always RestartSec=10s [Install] WantedBy=multi-user.target EOF # systemctl daemon-reload # systemctl enable kube-controller-manager # systemctl start kube-controller-manager
期限の切れたBootstrap token(後述)を消すためにtokencleanerを有効にしている。
bootstrapsignerは後述のcluster-infoにBootstrap tokenで署名するためのコントローラ。
csrapprovingというコントローラがデフォルトで有効になっていて、後述のTLS BootstrapppingやCertificate Rotationの時に作られるCSRを自動で承認する。
--cluster-cidr
で指定するネットワークは、後述のネットワークプロバイダの設定と合っている必要がある。--allocate-node-cidrs
は--cluster-cidr
の前提。--node-cidr-mask-size
は、ノードに使うネットワークのサイズを指定するオプションで、--cluster-cidr
で指定したネットワークの一部になるようにする。--cluster-cidr
で/16
を指定した場合、半分の/24
にするのが普通。 つまり256ノードまで作れて、それぞれ254個のPodをホストできるような構成。--experimental-cluster-signing-duration
は、Certificate Rotationのための設定で、自動発行する証明書の期限を1年に指定している。--use-service-account-credentials
をつけると、各コントローラが別々のService Accountで動く。--secure-port
や--tls-*
は、ヘルスチェックAPIをHTTPSにするだけで意味が無いし、設定するとkubectl get componentstatuses
でエラーが出るようになるので、設定しないほうがいい。 (k8s 1.12からは設定できるようになった。)確認。
# systemctl status kube-controller-manager -l
kube-scheduler
systemdのユニットファイルを書いてサービス化。
# cat > /etc/systemd/system/kube-scheduler.service << EOF [Unit] Description=Kubernetes Scheduler Documentation=https://github.com/kubernetes/kubernetes After=network.target [Service] User=kubernetes Group=kubernetes ExecStart=/usr/bin/kube-scheduler \\ --feature-gates=RotateKubeletServerCertificate=true \\ --kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \\ --address=0.0.0.0 \\ --v=2 Restart=always RestartSec=10s [Install] WantedBy=multi-user.target EOF # systemctl daemon-reload # systemctl enable kube-scheduler # systemctl start kube-scheduler
確認。
# systemctl status kube-scheduler -l
マスタコンポーネント状態確認
# kubectl version # kubectl get componentstatuses
7. TLS Bootstrappingの設定
TLS Bootstrappingは、Kubernetesクラスタのコンポーネント間の通信がTLSで暗号化されている環境で、ノードが新たにクラスタに参加するとき、自動的にセキュアにCSRを処理する仕組み。
TLS Bootstrappingでは、kubeletは起動時にBootstrap kubeconfigを読んで、kubeletとノード用のCSRを生成し、それらがkube-controller-managerに承認されると、kubelet用のクライアント証明書と秘密鍵を生成する。 その証明書と鍵を使ってkubeconfigを生成し、以降のクラスタへの接続に使う。
Bootstrap時の認証にはBootstrap TokensかToken authentication fileを使うことが推奨されていて、今回は前者を使う。
(後者についてはこの記事に詳しい。)
Bootstrap TokenのSecret生成
以下のように生成できる。
# TOKEN_PUB=$(openssl rand -hex 3) # TOKEN_SECRET=$(openssl rand -hex 8) # BOOTSTRAP_TOKEN="${TOKEN_PUB}.${TOKEN_SECRET}" # kubectl -n kube-system create secret generic bootstrap-token-${TOKEN_PUB} --type 'bootstrap.kubernetes.io/token' --from-literal description="cluster bootstrap token" --from-literal token-id=${TOKEN_PUB} --from-literal token-secret=${TOKEN_SECRET} --from-literal usage-bootstrap-authentication=true --from-literal usage-bootstrap-signing=true --from-literal auth-extra-groups=system:bootstrappers:worker,system:bootstrappers:ingress
けど、kubeadmでも生成出来てこっちのほうが楽なので、それで。
# BOOTSTRAP_TOKEN=$(kubeadm token create --kubeconfig /etc/kubernetes/admin.kubeconfig)
BOOTSTRAP_TOKENの値はあとで使う。
expirationは指定できなくて、1日で期限切れになっちゃうけど、クラスタにノードを追加するときに有効であればいいのでまあいい。
確認。
# TOKEN_PUB=$(echo $BOOTSTRAP_TOKEN | sed -e s/\\..*//) # kubectl -n kube-system get secret/bootstrap-token-${TOKEN_PUB} -o yaml
Bootstrap kubeconfig作成
Bootstrap時は
kubelet-bootstrap
というユーザでkube-apiserverに接続する。kubelet-bootstrap
はsystem:node-bootstrapper
ロールを持ってsystem:bootstrappers
に属しているユーザとして認証される必要がある。# mkdir -p /etc/kubernetes/manifests # MASTER_IP=192.168.171.200 # KUBERNETES_PUBLIC_ADDRESS=$MASTER_IP # CLUSTER_NAME="k8s" # KCONFIG="/etc/kubernetes/bootstrap.kubeconfig" # KUSER="kubelet-bootstrap" # kubectl config set-cluster ${CLUSTER_NAME} --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 --kubeconfig=${KCONFIG} # kubectl config set-context ${KUSER}@${CLUSTER_NAME} --cluster=${CLUSTER_NAME} --user=${KUSER} --kubeconfig=${KCONFIG} # kubectl config use-context ${KUSER}@${CLUSTER_NAME} --kubeconfig=${KCONFIG} # chown kubernetes:kubernetes ${KCONFIG} # chmod 0600 ${KCONFIG}
確認。
# kubectl config view --kubeconfig=${KCONFIG}
bootstrap.kubeconfigにトークンを追記
# kubectl config set-credentials kubelet-bootstrap --token=${BOOTSTRAP_TOKEN} --kubeconfig=/etc/kubernetes/bootstrap.kubeconfig
8. Docker、CNI、kubeletインストール
Docker
https://docs.docker.com/install/linux/docker-ce/centos/#set-up-the-repository に従ってDocker CEをインストール。 ストレージドライバにはoverlay2をつかうので、device-mapper-persistent-dataとlvm2は入れない。
# yum install -y yum-utils # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # yum install -y docker-ce
18.03.0-ceが入った。
が、よくみたらDocker CEはOracle Linuxをサポートしていないので、Docker CEはアンインストールして、代わりにOracle Container Runtime for Docker (aka docker-engine)を入れる。
/etc/yum.repos.d/public-yum-ol7.repo
のol7_addons
のenabled
を1にして、以下のコマンドでdocker-engineをインストール。# yum install -y docker-engine
docker-engine 17.06.2が入った。
/etc/sysconfig/docker
に以下を追記して、 Dockerがオープンできる最大ファイル数を増やす。DOCKER_NOFILE=1000000
Kubernetes環境ではiptablesはkube-proxyが操作するので、Dockerには操作させないようにするため、
/etc/sysconfig/docker
のOPTIONS
に--iptables=false
を追加。 (これをすると、--icc=false
は設定できなくなる(不要になる)。)また、PodのallowPrivilegeEscalationをfalseにできない問題に対処するため、
/etc/sysconfig/docker
のOPTIONS
から--selinux-enabled
を消す。で、起動。
# systemctl daemon-reload # systemctl enable docker # systemctl start docker
確認。
# cat /proc/$(pidof dockerd)/environ # systemctl status docker -l # docker version
CNI
# mkdir -p /etc/cni/net.d /opt/cni/bin/ # cd /tmp # curl -OL https://github.com/containernetworking/plugins/releases/download/v0.7.1/cni-plugins-amd64-v0.7.1.tgz # cd /opt/cni/bin # tar zxf /tmp/cni-plugins-amd64-v0.7.1.tgz # chmod +x /opt/cni/bin/* # cat >/etc/cni/net.d/99-loopback.conf <<EOF { "cniVersion": "0.3.1", "name": "lo", "type": "loopback" } EOF
kubelet
systemdのユニットファイルを書いてサービス化。
# DNS_SERVER_IP=10.0.0.10 # PAUSE_IMAGE=k8s.gcr.io/pause-amd64:3.1 # DNS_DOMAIN="cluster.local" # cat > /etc/systemd/system/kubelet.service << EOF [Unit] Description=Kubernetes Kubelet Documentation=https://github.com/kubernetes/kubernetes After=docker.service Requires=docker.service [Service] CPUAccounting=true MemoryAccounting=true User=root Group=root ExecStart=/usr/bin/kubelet \\ --feature-gates=RotateKubeletServerCertificate=true \\ --address=0.0.0.0 \\ --bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \\ --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\ --pod-manifest-path=/etc/kubernetes/manifests \\ --network-plugin=cni \\ --cni-conf-dir=/etc/cni/net.d \\ --cni-bin-dir=/opt/cni/bin \\ --cluster-dns=${DNS_SERVER_IP} \\ --cluster-domain=${DNS_DOMAIN} \\ --authorization-mode=Webhook \\ --client-ca-file=/etc/kubernetes/pki/ca.crt \\ --cert-dir=/etc/kubernetes/pki \\ --rotate-certificates=true \\ --v=2 \\ --cgroup-driver=cgroupfs \\ --pod-infra-container-image=${PAUSE_IMAGE} \\ --tls-min-version=VersionTLS12 \\ --tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 \\ --allow-privileged=true \\ --anonymous-auth=false Restart=always RestartSec=10s [Install] WantedBy=multi-user.target EOF # systemctl daemon-reload # systemctl enable kubelet # systemctl start kubelet
(実際は、systemctl start kubeletするまえに、後述のNode CSR自動承認設定をすべし。)
CPUAccounting=true
とMemoryAccounting=true
は、Redhat系LinuxでkubeletとdockerプロセスのメモリとCPUのcgroupが妙になる問題の対応。--allow-privileged
はflannelなどに必要。(k8s 1.11以降は指定不要になった。)--pod-infra-container-image
ではpauseコンテナイメージを指定する。 このコンテナはPod毎に起動され、Podネットワークの名前空間を保持するために使われるらしい。 今回使ったk8s.gcr.io/pause-amd64:3.1
はKubernetesチームが配布しているものだけど、Oracleが配布しているものもあり、そちらを使うには、Oracle Linux 7.4のダウンロード媒体リストに含まれるOracle Container Services for use with Kubernetes 1.1.9.1に入っているpause-amd64.tarをdocker load
しておいて、そのイメージ名を--pod-infra-container-image
に渡せばいい。--bootstrap-kubeconfig
で指定したkubeconfigでTLS Bootstrapして、--cert-dir
で指定したディレクトリに証明書と鍵を生成して、--kubeconfig
で指定したパスに以降使うkubeconfigを生成する。 この証明書を自動更新(i.e. Certificate Rotation)するオプションが--rotate-certificates
。--pod-manifest-path
で指定したディレクトリはkubeletに定期的にスキャンされ、そこに置いたKubernetesマニフェスト(ドットで始まるもの以外)が読まれる。 (参照: Static Pods)--pod-cidr
は指定しない。 これはkube-controller-managerに渡した--cluster-cidr
と--node-cidr-mask-size
から計算されるので。--anonymous-auth=false
はセキュリティのために推奨されたオプション。--authorization-mode=Webhook
もセキュリティのために推奨されたオプションで、認可処理をkube-apiserverに移譲する設定。本当はKubelet Configファイルを使ったほうがいいみたいなので、いずれそれに対応する。 (対応した: 「Kubernetes 1.10のkubeletの起動オプションをKubelet ConfigファイルとPodSecurityPolicyで置き換える」)
起動確認。
# systemctl status kubelet -l
Node CSR手動承認
TLS Bootstrappingで生成されたCSRを手動で承認する。
CSRは以下のコマンドで見れる。
# kubectl get csr NAME AGE REQUESTOR CONDITION csr-cf9hm 24m system:node:k8s-master Pending node-csr-Vcw_4HioW1CI96eDH29RMKPrOchEN133053wm6DCXUk 24m system:bootstrap:itacbw Pending
node-csr-…
がクライアント証明書のためのCSRで、csr-…
がサーバ証明書の。 これらを承認する。# kubectl certificate approve node-csr-Vcw_4HioW1CI96eDH29RMKPrOchEN133053wm6DCXUk # kubectl certificate approve csr-cf9hm
(因みに否認するときは
kubectl certificate deny
)これでクラスタにノードが追加されたはず。 確認。
# kubectl get node NAME STATUS ROLES AGE VERSION k8s-master Ready <none> 36s v1.10.0
Node CSR自動承認設定
前節でやった手動承認はcsrapprovingが自動でやってくれる。
新規ノード参加時のCSRを承認するClusterRoleとして
system:certificates.k8s.io:certificatesigningrequests:nodeclient
が自動生成されているので、これをsystem:bootstrappers
グループにバインドしてやると、自動承認が有効になる。- s
# cat <<EOF | kubectl create -f - kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: auto-approve-csrs-for-group subjects: - kind: Group name: system:bootstrappers apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: system:certificates.k8s.io:certificatesigningrequests:nodeclient apiGroup: rbac.authorization.k8s.io EOF
また、kubeletのクライアント証明書を自動更新(i.e. RotateKubeletClientCertificate)するときのCSRを承認するClusterRoleとして
system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
が自動生成されていて、これをsystem:nodesグループにバインドしてやると、自動承認が有効になる。# HOSTNAME=k8s-master # cat <<EOF | kubectl create -f - kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: auto-approve-renewals-for-nodes subjects: - kind: Group name: system:nodes apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient apiGroup: rbac.authorization.k8s.io EOF
9. kube-proxy、オーバレイネットワーク、DNSのデプロイ
kube-proxy
前提コマンド(conntrack)インストール。 (kube-proxyをipvsモードで動かす場合にはさらにipsetも入れる必要がある。)
# yum -y install conntrack-tools
kube-proxyのkubeconfigを作成。
# MASTER_IP=192.168.171.200 # KUBERNETES_PUBLIC_ADDRESS=$MASTER_IP # CLUSTER_NAME="k8s" # KCONFIG="/etc/kubernetes/kube-proxy.kubeconfig" # KUSER="system:kube-proxy" # kubectl config set-cluster ${CLUSTER_NAME} --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 --kubeconfig=${KCONFIG} # kubectl config set-credentials ${KUSER} --client-certificate=/etc/kubernetes/pki/kube-proxy.crt --client-key=/etc/kubernetes/pki/kube-proxy.key --embed-certs=true --kubeconfig=${KCONFIG} # kubectl config set-context ${KUSER}@${CLUSTER_NAME} --cluster=${CLUSTER_NAME} --user=${KUSER} --kubeconfig=${KCONFIG} # kubectl config use-context ${KUSER}@${CLUSTER_NAME} --kubeconfig=${KCONFIG} # chown kubernetes:kubernetes ${KCONFIG} # chmod 0600 ${KCONFIG}
確認。
# kubectl config view --kubeconfig=${KCONFIG}
systemdのユニットファイルを書いてサービス化。
# CLUSTER_CIDR="10.244.0.0/16" # cat > /etc/systemd/system/kube-proxy.service << EOF [Unit] Description=Kubernetes Kube Proxy Documentation=https://github.com/kubernetes/kubernetes After=network.target [Service] User=root Group=root ExecStart=/usr/bin/kube-proxy \\ --feature-gates=RotateKubeletServerCertificate=true \\ --bind-address 0.0.0.0 \\ --cluster-cidr=${CLUSTER_CIDR} \\ --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \\ --v=2 Restart=always RestartSec=10s [Install] WantedBy=multi-user.target EOF # systemctl daemon-reload # systemctl enable kube-proxy # systemctl start kube-proxy
確認。
# systemctl status kube-proxy -l
ネットワークプロバイダ (flannel)
flannelのドキュメントを参考に。
flannelをデプロイするには、kube-apiserverとkube-controller-managerの起動オプションに
--allow-privileged
を付ける必要がある。また、公式が配布しているKubernetesマニフェストを使う場合、kube-controller-managerの起動オプションの
--cluster-cidr
で10.244.0.0/16
を指定する必要がある。デプロイ自体は以下のコマンドを実行するだけ。
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
このKubernetesマニフェストでは、quay.ioから
quay.io/coreos/flannel:v0.10.0-amd64
というコンテナイメージがpullされる。Oracleもflannelのコンテナイメージを配布していて、そちらを使うには、Oracle Linux 7.4のダウンロード媒体リストに含まれるOracle Container Services for use with Kubernetes 1.1.9.1に入っているflannel.tarを
docker load
しておいて、そのイメージを使うようにマニフェストを書きかえればいい。起動確認。
# kubectl -n kube-system get po NAME READY STATUS RESTARTS AGE kube-flannel-ds-gkcqd 1/1 Running 0 1m
flannelはNetwork Policyをサポートしていないので、CalicoかWeave Netあたりにすればよかったかも。 (やった: 「Kubernetes 1.10のクラスタにWeave Netをデプロイする」)
CoreDNS
Kubernetes 1.10からは、サービスディスカバリに(kube-dnsの代わりに)CoreDNSを使うのが標準になった。
以下を参考にCoreDNSをデプロイする:
- https://kubernetes.io/docs/tasks/administer-cluster/coredns/
- https://coredns.io/2018/01/29/deploying-kubernetes-with-coredns-using-kubeadm/
- https://github.com/coredns/deployment/tree/master/kubernetes
# cd /tmp # curl -LO https://raw.githubusercontent.com/coredns/deployment/master/kubernetes/coredns.yaml.sed # curl -LO https://raw.githubusercontent.com/coredns/deployment/master/kubernetes/deploy.sh # chmod +x deploy.sh # DNS_SERVER_IP="10.0.0.10" # SERVICE_CLUSTER_IP_RANGE="10.0.0.0/16" # DNS_DOMAIN="cluster.local" # ./deploy.sh -r $SERVICE_CLUSTER_IP_RANGE -i $DNS_SERVER_IP -d $DNS_DOMAIN > coredns.yaml # kubectl apply -f coredns.yaml
このKubernetesマニフェストではDocker Hubから
coredns/coredns:1.1.1
というイメージがpullされる。起動確認。
# kubectl -n kube-system get pods -o wide | grep coredns coredns-8459d9f654-b585f 1/1 Running 0 48s 10.244.0.3 k8s-master coredns-8459d9f654-x7drc 1/1 Running 0 48s 10.244.0.2 k8s-master
起動確認時にCoreDNSのIPアドレスを確認して、動作確認。
# dig @10.244.0.3 kubernetes.default.svc.cluster.local +noall +answer ; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> @10.244.0.3 kubernetes.default.svc.cluster.local +noall +answer ; (1 server found) ;; global options: +cmd kubernetes.default.svc.cluster.local. 5 IN A 10.0.0.1
10. Kubernetesアプリデプロイ
前節まででKubernetesクラスタの構築は完了。 試しにKubernetesアプリをひとつデプロイしてみる。
-
ドキュメントを参考に。
# cd /tmp # curl -sSL -o scope.yaml https://cloud.weave.works/k8s/scope.yaml?k8s-service-type=NodePort # kubectl apply -f scope.yaml
このKubernetesマニフェストではDocker Hubから
weaveworks/scope:1.8.0
というイメージがpullされる。kubectl -n weave get svc/weave-scope-app
でポート調べて、http://k8s-master:<ポート>/
をブラウザ開くとWeave ScopeのGUIが見れる。