これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.
kubeadmを使ってクラスターを構築する
- 1: kubeadmのインストール
- 2: kubeadmのトラブルシューティング
- 3: kubeadmを使用したクラスターの作成
- 4: kubeadmを使ったコントロールプレーンの設定のカスタマイズ
- 5: 高可用性トポロジーのためのオプション
- 6: kubeadmを使用した高可用性クラスターの作成
- 7: kubeadmを使用した高可用性etcdクラスターの作成
- 8: kubeadmを使用したクラスター内の各kubeletの設定
- 9: コントロールプレーンをセルフホストするようにkubernetesクラスターを構成する
1 - kubeadmのインストール
このページではkubeadm
コマンドをインストールする方法を示します。このインストール処理実行後にkubeadmを使用してクラスターを作成する方法については、kubeadmを使用したシングルマスタークラスターの作成を参照してください。
始める前に
- 次のいずれかが動作しているマシンが必要です
- Ubuntu 16.04+
- Debian 9+
- CentOS 7
- Red Hat Enterprise Linux (RHEL) 7
- Fedora 25+
- HypriotOS v1.0.1+
- Container Linux (tested with 1800.6.0)
- 1台あたり2GB以上のメモリ(2GBの場合、アプリ用のスペースはほとんどありません)
- 2コア以上のCPU
- クラスター内のすべてのマシン間で通信可能なネットワーク(パブリックネットワークでもプライベートネットワークでも構いません)
- ユニークなhostname、MACアドレス、とproduct_uuidが各ノードに必要です。詳細はここを参照してください。
- マシン内の特定のポートが開いていること。詳細はここを参照してください。
- Swapがオフであること。kubeletが正常に動作するためにはswapは必ずオフでなければなりません。
MACアドレスとproduct_uuidが全てのノードでユニークであることの検証
- ネットワークインターフェースのMACアドレスは
ip link
もしくはifconfig -a
コマンドで取得できます。 - product_uuidは
sudo cat /sys/class/dmi/id/product_uuid
コマンドで確認できます。
ハードウェアデバイスではユニークなアドレスが割り当てられる可能性が非常に高いですが、VMでは同じになることがあります。Kubernetesはこれらの値を使用して、クラスター内のノードを一意に識別します。これらの値が各ノードに固有ではない場合、インストール処理が失敗することもあります。
ネットワークアダプタの確認
複数のネットワークアダプターがあり、Kubernetesコンポーネントにデフォルトで到達できない場合、IPルートを追加して、Kubernetesクラスターのアドレスが適切なアダプターを経由するように設定することをお勧めします。
iptablesがブリッジを通過するトラフィックを処理できるようにする
Linuxノードのiptablesがブリッジを通過するトラフィックを正確に処理する要件として、net.bridge.bridge-nf-call-iptables
をsysctl
の設定ファイルで1に設定してください。例えば以下のようにします。
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system
この手順の前にbr_netfilter
モジュールがロードされていることを確認してください。lsmod | grep br_netfilter
を実行することで確認できます。明示的にロードするにはmodprobe br_netfilter
を実行してください。
詳細はネットワークプラグインの要件を参照してください。
iptablesがnftablesバックエンドを使用しないようにする
Linuxでは、カーネルのiptablesサブシステムの最新の代替品としてnftablesが利用できます。iptables
ツールは互換性レイヤーとして機能し、iptablesのように動作しますが、実際にはnftablesを設定します。このnftablesバックエンドは現在のkubeadmパッケージと互換性がありません。(ファイアウォールルールが重複し、kube-proxy
を破壊するためです。)
もしあなたのシステムのiptables
ツールがnftablesバックエンドを使用している場合、これらの問題を避けるためにiptables
ツールをレガシーモードに切り替える必要があります。これは、少なくともDebian 10(Buster)、Ubuntu 19.04、Fedora 29、およびこれらのディストリビューションの新しいリリースでのデフォルトです。RHEL 8はレガシーモードへの切り替えをサポートしていないため、現在のkubeadmパッケージと互換性がありません。
# レガシーバイナリがインストールされていることを確認してください
sudo apt-get install -y iptables arptables ebtables
# レガシーバージョンに切り替えてください。
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo update-alternatives --set arptables /usr/sbin/arptables-legacy
sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy
update-alternatives --set iptables /usr/sbin/iptables-legacy
必須ポートの確認
コントロールプレーンノード
プロトコル | 通信の向き | ポート範囲 | 目的 | 使用者 |
---|---|---|---|---|
TCP | Inbound | 6443* | Kubernetes API server | 全て |
TCP | Inbound | 2379-2380 | etcd server client API | kube-apiserver、etcd |
TCP | Inbound | 10250 | Kubelet API | 自身、コントロールプレーン |
TCP | Inbound | 10251 | kube-scheduler | 自身 |
TCP | Inbound | 10252 | kube-controller-manager | 自身 |
ワーカーノード
プロトコル | 通信の向き | ポート範囲 | 目的 | 使用者 |
---|---|---|---|---|
TCP | Inbound | 10250 | Kubelet API | 自身、コントロールプレーン |
TCP | Inbound | 30000-32767 | NodePort Service† | 全て |
† NodePort Serviceのデフォルトのポートの範囲
*の項目は書き換え可能です。そのため、あなたが指定したカスタムポートも開いていることを確認する必要があります。
etcdポートはコントロールプレーンノードに含まれていますが、独自のetcdクラスターを外部またはカスタムポートでホストすることもできます。
使用するPodネットワークプラグイン(以下を参照)のポートも開く必要があります。これは各Podネットワークプラグインによって異なるため、必要なポートについてはプラグインのドキュメントを参照してください。
ランタイムのインストール
Podのコンテナを実行するために、Kubernetesはコンテナランタイムを使用します。
デフォルトでは、Kubernetesは選択されたコンテナランタイムと通信するためにContainer Runtime Interface (CRI)を使用します。
ランタイムを指定しない場合、kubeadmはよく知られたUnixドメインソケットのリストをスキャンすることで、インストールされたコンテナランタイムの検出を試みます。 次の表がコンテナランタイムと関連するソケットのパスリストです。
ランタイム | Unixドメインソケットのパス |
---|---|
Docker | /var/run/docker.sock |
containerd | /run/containerd/containerd.sock |
CRI-O | /var/run/crio/crio.sock |
Dockerとcontainerdの両方が同時に検出された場合、Dockerが優先されます。Docker 18.09にはcontainerdが同梱されており、両方が検出可能であるため、この仕様が必要です。他の2つ以上のランタイムが検出された場合、kubeadmは適切なエラーメッセージで終了します。
kubeletは、組み込まれたdockershim
CRIを通してDockerと連携します。
詳細は、コンテナランタイムを参照してください。
kubeadm、kubelet、kubectlのインストール
以下のパッケージをマシン上にインストールしてください
-
kubeadm
: クラスターを起動するコマンドです。 -
kubelet
: クラスター内のすべてのマシンで実行されるコンポーネントです。 Podやコンテナの起動などを行います。 -
kubectl
: クラスターにアクセスするためのコマンドラインツールです。
kubeadmはkubelet
やkubectl
をインストールまたは管理しないため、kubeadmにインストールするKubernetesコントロールプレーンのバージョンと一致させる必要があります。そうしないと、予期しないバグのある動作につながる可能性のあるバージョン差異(version skew)が発生するリスクがあります。ただし、kubeletとコントロールプレーン間のマイナーバージョン差異(minor version skew)は_1つ_サポートされていますが、kubeletバージョンがAPIサーバーのバージョンを超えることはできません。たとえば、1.7.0を実行するkubeletは1.8.0 APIサーバーと完全に互換性がありますが、その逆はできません。
kubectl
のインストールに関する詳細情報は、kubectlのインストールおよびセットアップを参照してください。
バージョン差異(version skew)に関しては下記を参照してください。
- Kubernetes Kubernetesバージョンとバージョンスキューサポートポリシー
- Kubeadm-specific バージョン互換ポリシー
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
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
# SELinuxをpermissiveモードに設定する(効果的に無効化する)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet
Note:
setenforce 0
およびsed ...
を実行することによりSELinuxをpermissiveモードに設定し、効果的に無効化できます。 これはコンテナがホストのファイルシステムにアクセスするために必要です。例えば、Podのネットワークに必要とされます。 kubeletにおけるSELinuxのサポートが改善されるまでは、これを実行しなければなりません。
CNIプラグインをインストールする(ほとんどのPodのネットワークに必要です):
CNI_VERSION="v0.8.2"
ARCH="amd64"
mkdir -p /opt/cni/bin
curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-${ARCH}-${CNI_VERSION}.tgz" | tar -C /opt/cni/bin -xz
crictlをインストールする (kubeadm / Kubelet Container Runtime Interface (CRI)に必要です)
CRICTL_VERSION="v1.17.0"
ARCH="amd64"
curl -L "https://github.com/kubernetes-sigs/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-${ARCH}.tar.gz" | sudo tar -C $DOWNLOAD_DIR -xz
kubeadm
、kubelet
、kubectl
をインストールしkubelet
をsystemd serviceに登録します:
RELEASE="$(curl -sSL https://dl.k8s.io/release/stable.txt)"
ARCH="amd64"
mkdir -p /opt/bin
cd /opt/bin
curl -L --remote-name-all https://storage.googleapis.com/kubernetes-release/release/${RELEASE}/bin/linux/${ARCH}/{kubeadm,kubelet,kubectl}
chmod +x {kubeadm,kubelet,kubectl}
curl -sSL "https://raw.githubusercontent.com/kubernetes/kubernetes/${RELEASE}/build/debs/kubelet.service" | sed "s:/usr/bin:/opt/bin:g" > /etc/systemd/system/kubelet.service
mkdir -p /etc/systemd/system/kubelet.service.d
curl -sSL "https://raw.githubusercontent.com/kubernetes/kubernetes/${RELEASE}/build/debs/10-kubeadm.conf" | sed "s:/usr/bin:/opt/bin:g" > /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
kubelet
を有効化し起動します:
systemctl enable --now kubelet
kubeadmが何をすべきか指示するまで、kubeletはクラッシュループで数秒ごとに再起動します。
コントロールプレーンノードのkubeletによって使用されるcgroupドライバーの設定
Dockerを使用した場合、kubeadmは自動的にkubelet向けのcgroupドライバーを検出し、それを実行時に/var/lib/kubelet/kubeadm-flags.env
ファイルに設定します。
もしあなたが異なるCRIを使用している場合、/etc/default/kubelet
(CentOS、RHEL、Fedoraでは/etc/sysconfig/kubelet
)ファイル内のcgroup-driver
の値を以下のように変更する必要があります。
KUBELET_EXTRA_ARGS=--cgroup-driver=<value>
このファイルは、kubeletの追加のユーザー定義引数を取得するために、kubeadm init
およびkubeadm join
によって使用されます。
CRIのcgroupドライバーがcgroupfs
でない場合にのみそれを行う必要があることに注意してください。なぜなら、これはすでにkubeletのデフォルト値であるためです。
kubeletをリスタートする方法:
systemctl daemon-reload
systemctl restart kubelet
CRI-Oやcontainerdといった他のコンテナランタイムのcgroup driverは実行中に自動的に検出されます。
トラブルシュート
kubeadmで問題が発生した場合は、トラブルシューティングを参照してください。
次の項目
2 - kubeadmのトラブルシューティング
どのプログラムでもそうですが、kubeadmのインストールや実行でエラーが発生することがあります。このページでは、一般的な失敗例をいくつか挙げ、問題を理解して解決するための手順を示しています。
本ページに問題が記載されていない場合は、以下の手順を行ってください:
-
問題がkubeadmのバグによるものと思った場合:
- github.com/kubernetes/kubeadmにアクセスして、既存のIssueを探してください。
- Issueがない場合は、テンプレートにしたがって新しくIssueを立ててください。
-
kubeadmがどのように動作するかわからない場合は、Slackの#kubeadmチャンネルで質問するか、StackOverflowで質問をあげてください。その際は、他の方が助けを出しやすいように
#kubernetes
や#kubeadm
といったタグをつけてください。
RBACがないため、v1.18ノードをv1.17クラスタに結合できない
v1.18では、同名のノードが既に存在する場合にクラスタ内のノードに参加しないようにする機能を追加しました。これには、ブートストラップトークンユーザがNodeオブジェクトをGETできるようにRBACを追加する必要がありました。
しかし、これによりv1.18のkubeadm join
がkubeadm v1.17で作成したクラスタに参加できないという問題が発生します。
この問題を回避するには、次の2つの方法があります。
-
kubeadm v1.18を用いて、コントロールプレーンノード上で
kubeadm init phase bootstrap-token
を実行します。 これには、ブートストラップトークンの残りのパーミッションも同様に有効にすることに注意してください。 -
kubectl apply -f ...
を使って以下のRBACを手動で適用します。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubeadm:get-nodes
rules:
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubeadm:get-nodes
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubeadm:get-nodes
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:kubeadm:default-node-token
インストール中にebtables
もしくは他の似たような実行プログラムが見つからない
kubeadm init
の実行中に以下のような警告が表示された場合は、以降に記載するやり方を行ってください。
[preflight] WARNING: ebtables not found in system path
[preflight] WARNING: ethtool not found in system path
このような場合、ノード上にebtables
, ethtool
などの実行ファイルがない可能性があります。これらをインストールするには、以下のコマンドを実行します。
- Ubuntu/Debianユーザーは、
apt install ebtables ethtool
を実行してください。 - CentOS/Fedoraユーザーは、
yum install ebtables ethtool
を実行してください。
インストール中にkubeadmがコントロールプレーンを待ち続けて止まる
以下のを出力した後にkubeadm init
が止まる場合は、kubeadm init
を実行してください:
[apiclient] Created API client, waiting for the control plane to become ready
これはいくつかの問題が原因となっている可能性があります。最も一般的なのは:
-
ネットワーク接続の問題が挙げられます。続行する前に、お使いのマシンがネットワークに完全に接続されていることを確認してください。
-
kubeletのデフォルトのcgroupドライバの設定がDockerで使用されているものとは異なっている場合も考えられます。 システムログファイル(例:
/var/log/message
)をチェックするか、journalctl -u kubelet
の出力を調べてください:error: failed to run Kubelet: failed to create kubelet: misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"
以上のようなエラーが現れていた場合、cgroupドライバの問題を解決するには、以下の2つの方法があります:
-
ここの指示に従ってDockerを再度インストールします。
-
Dockerのcgroupドライバに合わせてkubeletの設定を手動で変更します。その際は、マスターノード上でkubeletが使用するcgroupドライバを設定するを参照してください。
- control plane Dockerコンテナがクラッシュループしたり、ハングしたりしています。これは
docker ps
を実行し、docker logs
を実行して各コンテナを調査することで確認できます。
管理コンテナを削除する時にkubeadmが止まる
Dockerが停止して、Kubernetesで管理されているコンテナを削除しないと、以下のようなことが起こる可能性があります:
sudo kubeadm reset
[preflight] Running pre-flight checks
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[reset] Removing kubernetes-managed containers
(block)
考えられる解決策は、Dockerサービスを再起動してからkubeadm reset
を再実行することです:
sudo systemctl restart docker.service
sudo kubeadm reset
dockerのログを調べるのも有効な場合があります:
journalctl -u docker
Podの状態がRunContainerError
、CrashLoopBackOff
、またはError
となる
kubeadm init
の直後には、これらの状態ではPodは存在しないはずです。
kubeadm init
の 直後 にこれらの状態のいずれかにPodがある場合は、kubeadmのリポジトリにIssueを立ててください。ネットワークソリューションをデプロイするまではcoredns
(またはkube-dns
)はPending
状態でなければなりません。- ネットワークソリューションをデプロイしても
coredns
(またはkube-dns
)に何も起こらない場合にRunContainerError、
CrashLoopBackOff、
Error`の状態でPodが表示された場合は、インストールしたPodネットワークソリューションが壊れている可能性が高いです。より多くのRBACの特権を付与するか、新しいバージョンを使用する必要があるかもしれません。PodネットワークプロバイダのイシュートラッカーにIssueを出して、そこで問題をトリアージしてください。 - 1.12.1よりも古いバージョンのDockerをインストールした場合は、
systemd
でdockerd
を起動する際にMountFlags=slave
オプションを削除してdocker
を再起動してください。マウントフラグは/usr/lib/systemd/system/docker.service
で確認できます。MountFlagsはKubernetesがマウントしたボリュームに干渉し、PodsをCrashLoopBackOff
状態にすることがあります。このエラーは、Kubernetesがvar/run/secrets/kubernetes.io/serviceaccount
ファイルを見つけられない場合に発生します。
coredns
(もしくはkube-dns
)がPending
状態でスタックする
kubeadmはネットワークプロバイダに依存しないため、管理者は選択したPodネットワークソリューションをインストールをする必要があります。CoreDNSを完全にデプロイする前にPodネットワークをインストールする必要があります。したがって、ネットワークがセットアップされる前の Pending
状態になります。
HostPort
サービスが動かない
HostPort
とHostIP
の機能は、ご使用のPodネットワークプロバイダによって利用可能です。Podネットワークソリューションの作者に連絡して、HostPort
とHostIP
機能が利用可能かどうかを確認してください。
Calico、Canal、FlannelのCNIプロバイダは、HostPortをサポートしていることが確認されています。
詳細については、[CNI portmap documentation] (https://github.com/containernetworking/plugins/blob/master/plugins/meta/portmap/README.md) を参照してください。
ネットワークプロバイダが portmap CNI プラグインをサポートしていない場合は、NodePortサービスを使用するか、HostNetwork=true
を使用してください。
サービスIP経由でPodにアクセスすることができない
-
多くのネットワークアドオンは、PodがサービスIPを介して自分自身にアクセスできるようにするヘアピンモードを有効にしていません。これはCNIに関連する問題です。ヘアピンモードのサポート状況については、ネットワークアドオンプロバイダにお問い合わせください。
-
VirtualBoxを使用している場合(直接またはVagrant経由)は、
hostname -i
がルーティング可能なIPアドレスを返すことを確認する必要があります。デフォルトでは、最初のインターフェースはルーティング可能でないホスト専用のネットワークに接続されています。これを回避するには/etc/hosts
を修正する必要があります。例としてはこのVagrantfileを参照してください。
TLS証明書のエラー
以下のエラーは、証明書の不一致の可能性を示しています。
# kubectl get pods
Unable to connect to the server: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes")
-
HOME/.kube/config
ファイルに有効な証明書が含まれていることを確認し、必要に応じて証明書を再生成します。kubeconfigファイル内の証明書はbase64でエンコードされています。証明書をデコードするにはbase64 --decode
コマンドを、証明書情報を表示するにはopenssl x509 -text -noout
コマンドを用いてください。 -
環境変数
KUBECONFIG
の設定を解除するには以下のコマンドを実行するか:unset KUBECONFIG
設定をデフォルトの
KUBECONFIG
の場所に設定します:export KUBECONFIG=/etc/kubernetes/admin.conf
-
もう一つの回避策は、既存の
kubeconfig
を"admin"ユーザに上書きすることです:mv $HOME/.kube $HOME/.kube.bak mkdir $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
Vagrant内でPodネットワークとしてflannelを使用する時のデフォルトNIC
以下のエラーは、Podネットワークに何か問題があったことを示している可能性を示しています:
Error from server (NotFound): the server could not find the requested resource
-
Vagrant内のPodネットワークとしてflannelを使用している場合は、flannelのデフォルトのインターフェース名を指定する必要があります。
Vagrantは通常、2つのインターフェースを全てのVMに割り当てます。1つ目は全てのホストにIPアドレス
10.0.2.15
が割り当てられており、NATされる外部トラフィックのためのものです。これは、ホストの最初のインターフェイスをデフォルトにしているflannelの問題につながるかもしれません。これは、すべてのホストが同じパブリックIPアドレスを持っていると考えます。これを防ぐには、2番目のインターフェイスが選択されるように
--iface eth1
フラグをflannelに渡してください。
公開されていないIPがコンテナに使われている
状況によっては、kubectl logs
やkubectl run
コマンドが以下のようなエラーを返すことがあります:
Error from server: Get https://10.19.0.41:10250/containerLogs/default/mysql-ddc65b868-glc5m/mysql: dial tcp 10.19.0.41:10250: getsockopt: no route to host
-
これには、おそらくマシンプロバイダのポリシーによって、一見同じサブネット上の他のIPと通信できないIPをKubernetesが使用している可能性があります。
-
DigitalOceanはパブリックIPとプライベートIPを
eth0
に割り当てていますが、kubelet
はパブリックIPではなく、ノードのInternalIP
として後者を選択します。ifconfig
ではエイリアスIPアドレスが表示されないため、ifconfig
の代わりにip addr show
を使用してこのシナリオをチェックしてください。あるいは、DigitalOcean専用のAPIエンドポイントを使用して、ドロップレットからアンカーIPを取得することもできます:curl http://169.254.169.254/metadata/v1/interfaces/public/0/anchor_ipv4/address
回避策としては、
--node-ip
を使ってどのIPを使うかをkubelet
に伝えることです。DigitalOceanを使用する場合、オプションのプライベートネットワークを使用したい場合は、パブリックIP(eth0
に割り当てられている)かプライベートIP(eth1
に割り当てられている)のどちらかを指定します。これにはkubeadmNodeRegistrationOptions
構造体のKubeletExtraArgs
セクション が利用できます。kubelet
を再起動してください:systemctl daemon-reload systemctl restart kubelet
coredns
のPodがCrashLoopBackOff
もしくはError
状態になる
SELinuxを実行しているノードで古いバージョンのDockerを使用している場合、coredns
Podが起動しないということが起きるかもしれません。この問題を解決するには、以下のオプションのいずれかを試してみてください:
-
新しいDockerのバージョンにアップグレードする。
-
coredns
を変更して、allowPrivilegeEscalation
をtrue
に設定:
kubectl -n kube-system get deployment coredns -o yaml | \
sed 's/allowPrivilegeEscalation: false/allowPrivilegeEscalation: true/g' | \
kubectl apply -f -
CoreDNSにCrashLoopBackOff
が発生する別の原因は、KubernetesにデプロイされたCoreDNS Podがループを検出したときに発生します。CoreDNSがループを検出して終了するたびに、KubernetesがCoreDNS Podを再起動しようとするのを避けるために、いくつかの回避策が用意されています。
allowPrivilegeEscalation
をtrue
に設定すると、クラスタのセキュリティが損なわれる可能性があります。
etcdのpodが継続的に再起動する
以下のエラーが発生した場合は:
rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:247: starting container process caused "process_linux.go:110: decoding init error from pipe caused \"read parent: connection reset by peer\""
この問題は、CentOS 7をDocker 1.13.1.84で実行した場合に表示されます。このバージョンのDockerでは、kubeletがetcdコンテナに実行されないようにすることができます。
この問題を回避するには、以下のいずれかのオプションを選択します:
- 1.13.1-75のような以前のバージョンのDockerにロールバックする
yum downgrade docker-1.13.1-75.git8633870.el7.centos.x86_64 docker-client-1.13.1-75.git8633870.el7.centos.x86_64 docker-common-1.13.1-75.git8633870.el7.centos.x86_64
- 18.06のような最新の推奨バージョンをインストールする:
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce-18.06.1.ce-3.el7.x86_64
コンマで区切られた値のリストを--component-extra-args
フラグ内の引数に渡すことができない
-component-extra-args
のようなkubeadm init
フラグを使うと、kube-apiserverのようなコントロールプレーンコンポーネントにカスタム引数を渡すことができます。しかし、このメカニズムは値の解析に使われる基本的な型 (mapStringString
) のために制限されています。
もし、--apiserver-extra-args "enable-admission plugins=LimitRanger,NamespaceExists"
のようにカンマで区切られた複数の値をサポートする引数を渡した場合、このフラグはflag: malformed pair, expect string=string
で失敗します。これは--apiserver-extra-args
の引数リストがkey=value
のペアを期待しており、この場合NamespacesExists
は値を欠いたキーとみなされるためです。
別の方法として、key=value
のペアを以下のように分離してみることもできます:
--apiserver-extra-args "enable-admission-plugins=LimitRanger,enable-admission-plugins=NamespaceExists"
しかし、この場合は、キーenable-admission-plugins
はNamespaceExists
の値しか持ちません。既知の回避策としては、kubeadm設定ファイルを使用することが挙げられます。
cloud-controller-managerによってノードが初期化される前にkube-proxyがスケジューリングされる
クラウドプロバイダのシナリオでは、クラウドコントローラマネージャがノードアドレスを初期化する前に、kube-proxyが新しいワーカーノードでスケジューリングされてしまうことがあります。これにより、kube-proxyがノードのIPアドレスを正しく拾えず、ロードバランサを管理するプロキシ機能に悪影響を及ぼします。
kube-proxy Podsでは以下のようなエラーが発生します:
server.go:610] Failed to retrieve node IP: host IP unknown; known addresses: []
proxier.go:340] invalid nodeIP, initializing kube-proxy with 127.0.0.1 as nodeIP
既知の解決策は、初期のガード条件が緩和されるまで他のノードから離しておき、条件に関係なくコントロールプレーンノード上でスケジューリングできるように、キューブプロキシDaemonSetにパッチを当てることです:
kubectl -n kube-system patch ds kube-proxy -p='{ "spec": { "template": { "spec": { "tolerations": [ { "key": "CriticalAddonsOnly", "operator": "Exists" }, { "effect": "NoSchedule", "key": "node-role.kubernetes.io/master" } ] } } } }'
Tこの問題のトラッキング問題はこちら。
kubeadmの設定をマーシャリングする際、NodeRegistration.Taintsフィールドが省略される
注意: このIssueは、kubeadmタイプをマーシャルするツール(YAML設定ファイルなど)にのみ適用されます。これはkubeadm API v1beta2で修正される予定です。
デフォルトでは、kubeadmはコントロールプレーンノードにnode-role.kubernetes.io/master:NoSchedule
のテイントを適用します。kubeadmがコントロールプレーンノードに影響を与えないようにし、InitConfiguration.NodeRegistration.Taints
を空のスライスに設定すると、マーシャリング時にこのフィールドは省略されます。フィールドが省略された場合、kubeadmはデフォルトのテイントを適用します。
少なくとも2つの回避策があります:
-
空のスライスの代わりに
node-role.kubernetes.io/master:PreferNoSchedule
テイントを使用します。他のノードに容量がない限り、Podsはマスター上でスケジュールされます。 -
kubeadm init終了後のテイントの除去:
kubectl taint nodes NODE_NAME node-role.kubernetes.io/master:NoSchedule-
ノード{#usr-mounted-read-only}に/usr
が読み取り専用でマウントされる
Fedora CoreOSなどのLinuxディストリビューションでは、ディレクトリ/usr
が読み取り専用のファイルシステムとしてマウントされます。 flex-volumeサポートでは、kubeletやkube-controller-managerのようなKubernetesコンポーネントはデフォルトで/usr/libexec/kubernetes/kubelet-plugins/volume/exec/
のパスを使用していますが、この機能を動作させるためにはflex-volumeディレクトリは 書き込み可能 な状態でなければなりません。
この問題を回避するには、kubeadm設定ファイルを使用してflex-volumeディレクトリを設定します。
プライマリコントロールプレーンノード(kubeadm init
で作成されたもの)上で、--config
で以下のファイルを渡します:
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
controllerManager:
extraArgs:
flex-volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
ノードをジョインするには:
apiVersion: kubeadm.k8s.io/v1beta2
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
あるいは、/usr
マウントを書き込み可能にするために /etc/fstab
を変更することもできますが、これはLinuxディストリビューションの設計原理を変更していることに注意してください。
kubeadm upgrade plan
がcontext deadline exceeded
エラーメッセージを表示する
このエラーメッセージは、外部etcdを実行している場合にkubeadm
でKubernetesクラスタをアップグレードする際に表示されます。これは致命的なバグではなく、古いバージョンのkubeadmが外部etcdクラスタのバージョンチェックを行うために発生します。kubeadm upgrade apply ...
で進めることができます。
この問題はバージョン1.19で修正されます。
3 - kubeadmを使用したクラスターの作成
ベストプラクティスに準拠した実用最小限のKubernetesクラスターを作成します。実際、kubeadm
を使用すれば、Kubernetes Conformance testsに通るクラスターをセットアップすることができます。kubeadm
は、ブートストラップトークンやクラスターのアップグレードなどのその他のクラスターのライフサイクルの機能もサポートします。
kubeadm
ツールは、次のようなときに適しています。
- 新しいユーザーが初めてKubernetesを試すためのシンプルな方法が必要なとき。
- 既存のユーザーがクラスターのセットアップを自動化し、アプリケーションをテストする方法が必要なとき。
- より大きなスコープで、他のエコシステムやインストーラーツールのビルディングブロックが必要なとき。
kubeadm
は、ラップトップ、クラウドのサーバー群、Raspberry Piなどの様々なマシンにインストールして使えます。クラウドとオンプレミスのどちらにデプロイする場合でも、kubeadm
はAnsibleやTerraformなどのプロビジョニングシステムに統合できます。
始める前に
このガイドを進めるには、以下の環境が必要です。
- UbuntuやCentOSなど、deb/rpmパッケージと互換性のあるLinux OSが動作している1台以上のマシンがあること。
- マシンごとに2GiB以上のRAMが搭載されていること。それ以下の場合、アプリ実行用のメモリーがほとんど残りません。
- コントロールプレーンノードとして使用するマシンには、最低でも2CPU以上あること。
- クラスター内の全マシン間に完全なネットワーク接続があること。パブリックネットワークとプライベートネットワークのいずれでも使えます。
また、新しいクラスターで使いたいKubernetesのバージョンをデプロイできるバージョンのkubeadm
を使用する必要もあります。
Kubernetesのバージョンとバージョンスキューポリシーは、kubeadm
にもKubernetes全体と同じように当てはまります。Kubernetesとkubeadm
がサポートするバージョンを理解するには、上記のポリシーを確認してください。このページは、Kubernetes v1.23向けに書かれています。
kubeadmツールの全体の機能の状態は、一般利用可能(GA)です。一部のサブ機能はまだ活発に開発が行われています。クラスター作成の実装は、ツールの進化に伴ってわずかに変わるかもしれませんが、全体の実装は非常に安定しているはずです。
kubeadm alpha
以下のすべてのコマンドは、定義通り、アルファレベルでサポートされています。
目的
- シングルコントロールプレーンのKubernetesクラスターをインストールする
- クラスター上にPodネットワークをインストールして、Podがお互いに通信できるようにする
手順
ホストへのkubeadmのインストール
「kubeadmのインストール」を読んでください。
すでにkubeadmがインストール済みである場合は、最新バージョンのkubeadmを取得するためにapt-get update && apt-get upgrade
やyum update
を実行してください。
アップグレード中、kubeletが数秒ごとに再起動します。これは、kubeadmがkubeletにするべきことを伝えるまで、crashloopの状態で待機するためです。このcrashloopは期待通りの通常の動作です。コントロールプレーンの初期化が完了すれば、kubeletは正常に動作します。
コントロールプレーンノードの初期化
コントロールプレーンノードとは、etcd(クラスターのデータベース)やAPIサーバー(kubectlコマンドラインツールが通信する相手)などのコントロールプレーンのコンポーネントが実行されるマシンです。
- (推奨)シングルコントロールプレーンの
kubeadm
クラスターを高可用性クラスターにアップグレードする予定がある場合、--control-plane-endpoint
を指定して、すべてのコントロールプレーンノードとエンドポイントを共有する必要があります。エンドポイントにはDNSネームやロードバランサーのIPアドレスが使用できます。 - Podネットワークアドオンを選んで、
kubeadm init
に引数を渡す必要があるかどうか確認してください。選んだサードパーティーのプロバイダーによっては、--pod-network-cidr
をプロバイダー固有の値に設定する必要がある場合があります。詳しくは、Podネットワークアドオンのインストールを参照してください。 - (オプション)バージョン1.14から、
kubeadm
はよく知られたドメインソケットのパスリストを用いて、Linux上のコンテナランタイムの検出を試みます。異なるコンテナランタイムを使用する場合やプロビジョニングするノードに2つ以上のランタイムがインストールされている場合、kubeadm init
に--cri-socket
引数を指定してください。詳しくは、ランタイムのインストールを読んでください。 - (オプション)明示的に指定しない限り、
kubeadm
はデフォルトゲートウェイに関連付けられたネットワークインターフェイスを使用して、この特定のコントロールプレーンノードのAPIサーバーのadvertise addressを設定します。異なるネットワークインターフェイスを使用するには、kubeadm init
に--apiserver-advertise-address=<ip-address>
引数を指定してください。IPv6アドレスを使用するIPv6 Kubernetesクラスターをデプロイするには、たとえば--apiserver-advertise-address=fd00::101
のように、IPv6アドレスを指定する必要があります。 - (オプション)
kubeadm init
を実行する前にkubeadm config images pull
を実行して、gcr.ioコンテナイメージレジストリに接続できるかどうかを確認します。
コントロールプレーンノードを初期化するには、次のコマンドを実行します。
kubeadm init <args>
apiserver-advertise-addressとControlPlaneEndpointに関する検討
--apiserver-advertise-address
は、この特定のコントロールプレーンノードのAPIサーバーへのadvertise addressを設定するために使えますが、--control-plane-endpoint
は、すべてのコントロールプレーンノード共有のエンドポイントを設定するために使えます。
--control-plane-endpoint
はIPアドレスと、IPアドレスへマッピングできるDNS名を使用できます。利用可能なソリューションをそうしたマッピングの観点から評価するには、ネットワーク管理者に相談してください。
以下にマッピングの例を示します。
192.168.0.102 cluster-endpoint
ここでは、192.168.0.102
がこのノードのIPアドレスであり、cluster-endpoint
がこのIPアドレスへとマッピングされるカスタムDNSネームです。このように設定することで、--control-plane-endpoint=cluster-endpoint
をkubeadm init
に渡せるようになり、kubeadm join
にも同じDNSネームを渡せます。後でcluster-endpoint
を修正して、高可用性が必要なシナリオでロードバランサーのアドレスを指すようにすることができます。
kubeadmでは、--control-plane-endpoint
を渡さずに構築したシングルコントロールプレーンのクラスターを高可用性クラスターに切り替えることはサポートされていません。
詳細な情報
kubeadm init
の引数のより詳細な情報は、kubeadmリファレンスガイドを参照してください。
設定オプションの全リストは、設定ファイルのドキュメントで確認できます。
コントロールプレーンコンポーネントやetcdサーバーのliveness probeへのオプションのIPv6の割り当てなど、コントロールプレーンのコンポーネントをカスタマイズしたい場合は、カスタムの引数に示されている方法で各コンポーネントに追加の引数を与えてください。
kubeadm init
を再び実行する場合は、初めにクラスターの破壊を行う必要があります。
もし異なるアーキテクチャのノードをクラスターにjoinさせたい場合は、デプロイしたDaemonSetがそのアーキテクチャ向けのコンテナイメージをサポートしているか確認してください。
初めにkubeadm init
は、マシンがKubernetesを実行する準備ができているかを確認する、一連の事前チェックを行います。これらの事前チェックはエラー発生時には警告を表示して終了します。次に、kubeadm init
はクラスターのコントロールプレーンのコンポーネントをダウンロードしてインストールします。これには数分掛かるかもしれません。出力は次のようになります。
[init] Using Kubernetes version: vX.Y.Z
[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 "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [kubeadm-cp localhost] and IPs [10.138.0.4 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [kubeadm-cp localhost] and IPs [10.138.0.4 127.0.0.1 ::1]
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubeadm-cp kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.138.0.4]
[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 "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 31.501735 seconds
[uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-X.Y" 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 "kubeadm-cp" as an annotation
[mark-control-plane] Marking the node kubeadm-cp as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node kubeadm-cp as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: <token>
[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 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:
/docs/concepts/cluster-administration/addons/
You can now join any number of machines by running the following on each node
as root:
kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
kubectlをroot以外のユーザーでも実行できるようにするには、次のコマンドを実行します。これらのコマンドは、kubectl init
の出力の中にも書かれています。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
あなたがroot
ユーザーである場合は、代わりに次のコマンドを実行します。
export KUBECONFIG=/etc/kubernetes/admin.conf
kubeadm init
が出力したkubeadm join
コマンドをメモしておいてください。クラスターにノードを追加するために、このコマンドが必要になります。
トークンは、コントロールプレーンノードと追加ノードの間の相互認証に使用します。ここに含まれるトークンには秘密の情報が含まれます。このトークンを知っていれば、誰でもクラスターに認証済みノードを追加できてしまうため、取り扱いには注意してください。kubeadm token
コマンドを使用すると、これらのトークンの一覧、作成、削除ができます。詳しくはkubeadmリファレンスガイドを読んでください。
Podネットワークアドオンのインストール
このセクションには、ネットワークのセットアップとデプロイの順序に関する重要な情報が書かれています。先に進む前に以下のすべてのアドバイスを熟読してください。
Pod同士が通信できるようにするには、Container Network Interface(CNI)をベースとするPodネットワークアドオンをデプロイしなければなりません。ネットワークアドオンをインストールする前には、Cluster DNS(CoreDNS)は起動しません。
-
Podネットワークがホストネットワークと決して重ならないように気をつけてください。もし重なると、様々な問題が起こってしまう可能性があります。(ネットワークプラグインが優先するPodネットワークとホストのネットワークの一部が衝突することが分かった場合、適切な代わりのCIDRを考える必要があります。そして、
kubeadm init
の実行時に--pod-network-cidr
にそのCIDRを指定し、ネットワークプラグインのYAMLでは代わりにそのCIDRを使用してください) -
デフォルトでは、
kubeadm
はRBAC(role based access control)の使用を強制します。PodネットワークプラグインがRBACをサポートしていて、またそのデプロイに使用するマニフェストもRBACをサポートしていることを確認してください。 -
クラスターでIPv6を使用したい場合、デュアルスタック、IPv6のみのシングルスタックのネットワークのいずれであっても、PodネットワークプラグインがIPv6をサポートしていることを確認してください。IPv6のサポートは、CNIのv0.6.0で追加されました。
CNIを使用するKubernetes Podネットワークを提供する外部のプロジェクトがいくつかあります。一部のプロジェクトでは、ネットワークポリシーもサポートしています。
Kubernetesのネットワークモデルを実装したアドオンの一覧も確認してください。
Podネットワークアドオンをインストールするには、コントロールプレーンノード上またはkubeconfigクレデンシャルを持っているノード上で、次のコマンドを実行します。
kubectl apply -f <add-on.yaml>
インストールできるPodネットワークは、クラスターごとに1つだけです。
Podネットワークがインストールされたら、kubectl get pods --all-namespaces
の出力結果でCoreDNS PodがRunning
状態であることをチェックすることで、ネットワークが動作していることを確認できます。そして、一度CoreDNS Podが動作すれば、続けてノードを追加できます。
もしネットワークやCoreDNSがRunning
状態にならない場合は、kubeadm
のトラブルシューティングガイドをチェックしてください。
コントロールプレーンノードの隔離
デフォルトでは、セキュリティ上の理由により、クラスターはコントロールプレーンノードにPodをスケジューリングしません。たとえば、開発用のKubernetesシングルマシンのクラスターなどで、Podをコントロールプレーンノードにスケジューリングしたい場合は、次のコマンドを実行します。
kubectl taint nodes --all node-role.kubernetes.io/master-
出力は次のようになります。
node "test-01" untainted
taint "node-role.kubernetes.io/master:" not found
taint "node-role.kubernetes.io/master:" not found
このコマンドは、コントロールプレーンノードを含むすべてのノードからnode-role.kubernetes.io/master
taintを削除します。その結果、スケジューラーはどこにでもPodをスケジューリングできるようになります。
ノードの追加
ノードは、ワークロード(コンテナやPodなど)が実行される場所です。新しいノードをクラスターに追加するためには、各マシンに対して、以下の手順を実行してください。
- マシンへSSHする
- rootになる(例:
sudo su -
) kubeadm init
実行時に出力されたコマンドを実行する。たとえば、次のようなコマンドです。
kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
トークンがわからない場合は、コントロールプレーンノードで次のコマンドを実行すると取得できます。
kubeadm token list
出力は次のようになります。
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
8ewj1p.9r9hcjoqgajrj4gi 23h 2018-06-12T02:51:28Z authentication, The default bootstrap system:
signing token generated by bootstrappers:
'kubeadm init'. kubeadm:
default-node-token
デフォルトでは、トークンは24時間後に有効期限が切れます。もし現在のトークンの有効期限が切れた後にクラスターにノードを参加させたい場合は、コントロールプレーンノードで次のコマンドを実行することで、新しいトークンを生成できます。
kubeadm token create
このコマンドの出力は次のようになります。
5didvk.d09sbcov8ph2amjw
もし--discovery-token-ca-cert-hash
の値がわからない場合は、コントロールプレーンノード上で次のコマンドチェーンを実行することで取得できます。
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
出力は次のようになります。
8cb2de97839780a412b93877f8507ad6c94f73add17d5d7058e91741c9d5ec78
<control-plane-host>:<control-plane-port>
と指定するためには、IPv6アドレスを角括弧で囲みます。たとえば、[fd00::101]:2073
のように書きます。
出力は次のようになります。
[preflight] Running pre-flight checks
... (joinワークフローのログ出力) ...
Node join complete:
* Certificate signing request sent to control-plane and response
received.
* Kubelet informed of new secure connection details.
Run 'kubectl get nodes' on control-plane to see this machine join.
数秒後、コントロールプレーンノード上でkubectl get nodes
を実行すると、出力内にこのノードが表示されるはずです。
(オプション)コントロールプレーンノード以外のマシンからのクラスター操作
他のコンピューター(例: ラップトップ)上のkubectlがクラスターと通信できるようにするためには、次のようにして、administratorのkubeconfigファイルをコントロールプレーンノードからそのコンピューター上にコピーする必要があります。
scp root@<control-plane-host>:/etc/kubernetes/admin.conf .
kubectl --kubeconfig ./admin.conf get nodes
上の例では、rootユーザーに対するSSH接続が有効であることを仮定しています。もしそうでない場合は、admin.conf
ファイルを誰か他のユーザーからアクセスできるようにコピーした上で、代わりにそのユーザーを使ってscp
してください。
admin.conf
ファイルはユーザーにクラスターに対する 特権ユーザー の権限を与えます。そのため、このファイルを使うのは控えめにしなければなりません。通常のユーザーには、明示的に許可した権限を持つユニークなクレデンシャルを生成することを推奨します。これには、kubeadm alpha kubeconfig user --client-name <CN>
コマンドが使えます。このコマンドを実行すると、KubeConfigファイルがSTDOUTに出力されるので、ファイルに保存してユーザーに配布します。その後、kubectl create (cluster)rolebinding
コマンドを使って権限を付与します。
(オプション)APIサーバーをlocalhostへプロキシする
クラスターの外部からAPIサーバーに接続したいときは、次のようにkubectl proxy
コマンドが使えます。
scp root@<control-plane-host>:/etc/kubernetes/admin.conf .
kubectl --kubeconfig ./admin.conf proxy
これで、ローカルのhttp://localhost:8001/api/v1
からAPIサーバーにアクセスできるようになります。
クリーンアップ
テストのためにクラスターに破棄可能なサーバーを使用した場合、サーバーのスイッチをオフにすれば、以降のクリーンアップの作業は必要ありません。クラスターのローカルの設定を削除するには、kubectl config delete-cluster
を実行します。
しかし、もしよりきれいにクラスターのプロビジョンをもとに戻したい場合は、初めにノードのdrainを行い、ノードが空になっていることを確認した後、ノードの設定を削除する必要があります。
ノードの削除
適切なクレデンシャルを使用してコントロールプレーンノードに削除することを伝えます。次のコマンドを実行してください。
kubectl drain <node name> --delete-local-data --force --ignore-daemonsets
ノードが削除される前に、kubeadm
によってインストールされた状態をリセットします。
kubeadm reset
リセットプロセスでは、iptablesのルールやIPVS tablesのリセットやクリーンアップは行われません。iptablesをリセットしたい場合は、次のように手動でコマンドを実行する必要があります。
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
IPVS tablesをリセットしたい場合は、次のコマンドを実行する必要があります。
ipvsadm -C
ノードを削除します。
kubectl delete node <node name>
クラスターのセットアップを最初から始めたいときは、kubeadm init
やkubeadm join
を適切な引数を付けて実行すればいいだけです。
コントロールプレーンのクリーンアップ
コントロールホスト上でkubeadm reset
を実行すると、ベストエフォートでのクリーンアップが実行できます。
このサブコマンドとオプションに関するより詳しい情報は、kubeadm reset
リファレンスドキュメントを読んでください。
次の手順
- Sonobuoyを使用してクラスターが適切に動作しているか検証する。
kubeadm
を使用したクラスターをアップグレードする方法について、kubeadmクラスターをアップグレードするを読む。kubeadm
の高度な利用方法についてkubeadmリファレンスドキュメントで学ぶ。- Kubernetesのコンセプトや
kubectl
についてもっと学ぶ。 - Podネットワークアドオンのより完全なリストをクラスターのネットワークで確認する。
- ロギング、モニタリング、ネットワークポリシー、仮想化、Kubernetesクラスターの制御のためのツールなど、その他のアドオンについて、アドオンのリストで確認する。
- クラスターイベントやPod内で実行中のアプリケーションから送られるログをクラスターがハンドリングする方法を設定する。関係する要素の概要を理解するために、ロギングのアーキテクチャを読んでください。
フィードバック
- バグを見つけた場合は、kubeadm GitHub issue trackerで報告してください。
- サポートを受けたい場合は、#kubeadmSlackチャンネルを訪ねてください。
- General SIG Cluster Lifecycle development Slackチャンネル: #sig-cluster-lifecycle
- SIG Cluster Lifecycle SIG information
- SIG Cluster Lifecycleメーリングリスト: kubernetes-sig-cluster-lifecycle
バージョン互換ポリシー
バージョンv1.23のkubeadm
ツールは、バージョンv1.23またはv1.22のコントロールプレーンを持つクラスターをデプロイできます。また、バージョンv1.23のkubeadm
は、バージョンv1.22のkubeadmで構築されたクラスターをアップグレートできます。
未来を見ることはできないため、kubeadm CLI v1.23はv1.24をデプロイできないかもしれません。
例: kubeadm
v1.8は、v1.7とv1.8のクラスターをデプロイでき、v1.7のkubeadmで構築されたクラスターをv1.8にアップグレートできます。
kubeletとコントロールプレーンの間や、他のKubernetesコンポーネント間のバージョンの差異に関する詳しい情報は、以下の資料を確認してください。
- Kubernetesバージョンスキューサポートポリシー
- Kubeadm特有のインストールガイド
制限事項
クラスターのレジリエンス
ここで作られたクラスターは、1つのコントロールプレーンノードと、その上で動作する1つのetcdデータベースしか持ちません。つまり、コントロールプレーンノードが故障した場合、クラスターのデータは失われ、クラスターを最初から作り直す必要があるかもしれないということです。
対処方法:
-
定期的にetcdをバックアップする。kubeadmが設定するetcdのデータディレクトリは、コントロールプレーンノードの
/var/lib/etcd
にあります。 -
複数のコントロールプレーンノードを使用する。高可用性トポロジーのオプションでは、より高い可用性を提供するクラスターのトポロジーの選択について説明してます。
プラットフォームの互換性
kubeadmのdeb/rpmパッケージおよびバイナリは、multi-platform proposalに従い、amd64、arm(32ビット)、arm64、ppc64le、およびs390x向けにビルドされています。
マルチプラットフォームのコントロールプレーンおよびアドオン用のコンテナイメージも、v1.12からサポートされています。
すべてのプラットフォーム向けのソリューションを提供しているネットワークプロバイダーは一部のみです。それぞれのプロバイダーが選択したプラットフォームをサポートしているかどうかを確認するには、前述のネットワークプロバイダーのリストを参照してください。
トラブルシューティング
kubeadmに関する問題が起きたときは、トラブルシューティングドキュメントを確認してください。
4 - kubeadmを使ったコントロールプレーンの設定のカスタマイズ
Kubernetes 1.12 [stable]
kubeadmのClusterConfiguration
オブジェクトはAPIServer、ControllerManager、およびSchedulerのようなコントロールプレーンの構成要素に渡されたデフォルトのフラグを上書きすることができる extraArgs
の項目があります。
その構成要素は次の項目で定義されています。
apiServer
controllerManager
scheduler
extraArgs
の項目は キー: 値
のペアです。コントロールプレーンの構成要素のフラグを上書きするには:
- 設定内容に適切な項目を追加
- フラグを追加して項目を上書き
--config <任意の設定YAMLファイル>
でkubeadm init
を実行
各設定項目のより詳細な情報はAPIリファレンスのページを参照してください。
kubeadm config print init-defaults
を実行し、選択したファイルに出力を保存することで、デフォルト値でClusterConfiguration
オブジェクトを生成できます。
APIServerフラグ
詳細はkube-apiserverのリファレンスドキュメントを参照してください。
使用例:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
apiServer:
extraArgs:
advertise-address: 192.168.0.103
anonymous-auth: "false"
enable-admission-plugins: AlwaysPullImages,DefaultStorageClass
audit-log-path: /home/johndoe/audit.log
ControllerManagerフラグ
詳細はkube-controller-managerのリファレンスドキュメントを参照してください。
使用例:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
controllerManager:
extraArgs:
cluster-signing-key-file: /home/johndoe/keys/ca.key
bind-address: 0.0.0.0
deployment-controller-sync-period: "50"
Schedulerフラグ
詳細はkube-schedulerのリファレンスドキュメントを参照してください。
使用例:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
scheduler:
extraArgs:
bind-address: 0.0.0.0
config: /home/johndoe/schedconfig.yaml
kubeconfig: /home/johndoe/kubeconfig.yaml
5 - 高可用性トポロジーのためのオプション
このページでは、高可用性(HA)Kubernetesクラスターのトポロジーを設定するための2つのオプションについて説明します。
HAクラスターは次の方法で設定できます。
- 積層コントロールプレーンノードを使用する方法。こちらの場合、etcdノードはコントロールプレーンノードと同じ場所で動作します。
- 外部のetcdノードを使用する方法。こちらの場合、etcdがコントロールプレーンとは分離されたノードで動作します。
HAクラスターをセットアップする前に、各トポロジーの利点と欠点について注意深く考慮する必要があります。
積層etcdトポロジー
積層HAクラスターは、コントロールプレーンのコンポーネントを実行する、kubeadmで管理されたノードで構成されるクラスターの上に、etcdにより提供される分散データストレージクラスターがあるようなトポロジーです。
各コントロールプレーンノードは、kube-apiserver
、kube-scheduler
、およびkube-controller-manager
を実行します。kube-apiserver
はロードバランサーを用いてワーカーノードに公開されます。
各コントロールプレーンノードはローカルのetcdメンバーを作り、このetcdメンバーはそのノードのkube-apiserver
とだけ通信します。ローカルのkube-controller-manager
とkube-scheduler
のインスタンスも同様です。
このトポロジーは、同じノード上のコントロールプレーンとetcdのメンバーを結合します。外部のetcdノードを使用するクラスターよりはセットアップがシンプルで、レプリケーションの管理もシンプルです。
しかし、積層クラスターには、結合による故障のリスクがあります。1つのノードがダウンすると、etcdメンバーとコントロールプレーンのインスタンスの両方が失われ、冗長性が損なわれます。より多くのコントロールプレーンノードを追加することで、このリスクは緩和できます。
そのため、HAクラスターのためには、最低でも3台の積層コントロールプレーンノードを実行しなければなりません。
これがkubeadmのデフォルトのトポロジーです。kubeadm init
やkubeadm join --control-place
を実行すると、ローカルのetcdメンバーがコントロールプレーンノード上に自動的に作成されます。
外部のetcdトポロジー
外部のetcdを持つHAクラスターは、コントロールプレーンコンポーネントを実行するノードで構成されるクラスターの外部に、etcdにより提供される分散データストレージクラスターがあるようなトポロジーです。
積層etcdトポロジーと同様に、外部のetcdトポロジーにおける各コントロールプレーンノードは、kube-apiserver
、kube-scheduler
、およびkube-controller-manager
のインスタンスを実行します。そして、kube-apiserver
は、ロードバランサーを使用してワーカーノードに公開されます。しかし、etcdメンバーは異なるホスト上で動作しており、各etcdホストは各コントロールプレーンノードのkube-api-server
と通信します。
このトポロジーは、コントロールプレーンとetcdメンバーを疎結合にします。そのため、コントロールプレーンインスタンスまたはetcdメンバーを失うことによる影響は少なく、積層HAトポロジーほどクラスターの冗長性に影響しないHAセットアップが実現します。
しかし、このトポロジーでは積層HAトポロジーの2倍の数のホストを必要とします。このトポロジーのHAクラスターのためには、最低でもコントロールプレーンのために3台のホストが、etcdノードのために3台のホストがそれぞれ必要です。
次の項目
6 - kubeadmを使用した高可用性クラスターの作成
このページでは、kubeadmを使用して、高可用性クラスターを作成する、2つの異なるアプローチを説明します:
- 積層コントロールプレーンノードを使う方法。こちらのアプローチは、必要なインフラストラクチャーが少ないです。etcdのメンバーと、コントロールプレーンノードは同じ場所に置かれます。
- 外部のetcdクラスターを使う方法。こちらのアプローチには、より多くのインフラストラクチャーが必要です。コントロールプレーンノードと、etcdのメンバーは分離されます。
先へ進む前に、どちらのアプローチがアプリケーションの要件と、環境に適合するか、慎重に検討してください。こちらの比較が、それぞれの利点/欠点について概説しています。
高可用性クラスターの作成で問題が発生した場合は、kueadmのissue trackerでフィードバックを提供してください。
高可用性クラスターのアップグレードも参照してください。
始める前に
どちらの方法でも、以下のインフラストラクチャーが必要です:
- master用に、kubeadmの最小要件を満たす3台のマシン
- worker用に、kubeadmの最小要件を満たす3台のマシン
- クラスター内のすべてのマシン間がフルにネットワーク接続可能であること(パブリック、もしくはプライベートネットワーク)
- すべてのマシンにおいて、sudo権限
- あるデバイスから、システム内のすべてのノードに対しSSH接続できること
kubeadm
とkubelet
がすべてのマシンにインストールされていること。kubectl
は任意です。
外部etcdクラスターには、以下も必要です:
- etcdメンバー用に、追加で3台のマシン
両手順における最初のステップ
kube-apiserver用にロードバランサーを作成
-
DNSで解決される名前で、kube-apiserver用ロードバランサーを作成する。
-
クラウド環境では、コントロールプレーンノードをTCPフォワーディングロードバランサーの後ろに置かなければなりません。このロードバランサーはターゲットリストに含まれる、すべての健全なコントロールプレーンノードにトラフィックを分配します。apiserverへのヘルスチェックはkube-apiserverがリッスンするポート(デフォルト値:
:6443
)に対する、TCPチェックです。 -
クラウド環境では、IPアドレスを直接使うことは推奨されません。
-
ロードバランサーは、apiserverポートで、全てのコントロールプレーンノードと通信できなければなりません。また、リスニングポートに対する流入トラフィックも許可されていなければなりません。
-
ロードバランサーのアドレスは、常にkubeadmの
ControlPlaneEndpoint
のアドレスと一致することを確認してください。 -
詳細はOptions for Software Load Balancingをご覧ください。
-
-
ロードバランサーに、最初のコントロールプレーンノードを追加し、接続をテストする:
nc -v LOAD_BALANCER_IP PORT
- apiserverはまだ動いていないので、接続の拒否は想定通りです。しかし、タイムアウトしたのであれば、ロードバランサーはコントロールプレーンノードと通信できなかったことを意味します。もし、タイムアウトが起きたら、コントロールプレーンノードと通信できるように、ロードバランサーを再設定してください。
-
残りのコントロールプレーンノードを、ロードバランサーのターゲットグループに追加します。
積層コントロールプレーンとetcdノード
最初のコントロールプレーンノードの手順
-
最初のコントロールプレーンノードを初期化します:
sudo kubeadm init --control-plane-endpoint "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" --upload-certs
--kubernetes-version
フラグで使用するKubernetesのバージョンを設定できます。kubeadm、kubelet、kubectl、Kubernetesのバージョンを一致させることが推奨されます。--control-plane-endpoint
フラグは、ロードバランサーのIPアドレスまたはDNS名と、ポートが設定される必要があります。--upload-certs
フラグは全てのコントロールプレーンノードで共有する必要がある証明書をクラスターにアップロードするために使用されます。代わりに、コントロールプレーンノード間で手動あるいは自動化ツールを使用して証明書をコピーしたい場合は、このフラグを削除し、以下の証明書の手動配布のセクションを参照してください。
備考:kubeadm init
の--config
フラグと--certificate-key
フラグは混在させることはできないため、kubeadm configurationを使用する場合はcertificateKey
フィールドを適切な場所に追加する必要があります(InitConfiguration
とJoinConfiguration: controlPlane
の配下)。備考: いくつかのCNIネットワークプラグインはPodのIPのCIDRの指定など追加の設定を必要としますが、必要としないプラグインもあります。CNIネットワークドキュメントを参照してください。PodにCIDRを設定するには、ClusterConfiguration
のnetworking
オブジェクトにpodSubnet: 192.168.0.0/16
フィールドを設定してください。- このような出力がされます:
... You can now join any number of control-plane node by running the following command on each as a root: kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07 Please note that the certificate-key gives access to cluster sensitive data, keep it secret! As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use kubeadm init phase upload-certs to reload certs afterward. Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
-
この出力をテキストファイルにコピーします。あとで、他のコントロールプレーンノードとワーカーノードをクラスターに参加させる際に必要です。
-
--upload-certs
フラグをkubeadm init
で使用すると、プライマリコントロールプレーンの証明書が暗号化されて、kubeadm-certs
Secretにアップロードされます。 -
証明書を再アップロードして新しい復号キーを生成するには、すでにクラスターに参加しているコントロールプレーンノードで次のコマンドを使用します:
sudo kubeadm init phase upload-certs --upload-certs
- また、後で
join
で使用できるように、init
中にカスタムした--certificate-key
を指定することもできます。このようなキーを生成するには、次のコマンドを使用します:
kubeadm alpha certs certificate-key
備考:kubeadm-certs
のSecretと復号キーは2時間で期限切れとなります。注意: コマンド出力に記載されているように、証明書キーはクラスターの機密データへのアクセスを提供します。秘密にしてください! -
使用するCNIプラグインを適用します:
こちらの手順に従いCNIプロバイダーをインストールします。該当する場合は、kubeadmの設定で指定されたPodのCIDRに対応していることを確認してください。Weave Netを使用する場合の例:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
-
以下のコマンドを入力し、コンポーネントのPodが起動するのを確認します:
kubectl get pod -n kube-system -w
残りのコントロールプレーンノードの手順
追加のコントロールプレーンノード毎に、以下の手順を行います。
-
kubeadm init
を最初のノードで実行した際に取得したjoinコマンドを使って、新しく追加するコントロールプレーンノードでkubeadm join
を開始します。このようなコマンドになるはずです:sudo kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
--control-plane
フラグによって、kubeadm join
の実行は新しいコントロールプレーンを作成します。-certificate-key ...
を指定したキーを使って、クラスターのkubeadm-certs
Secretからダウンロードされたコントロールプレーンの証明書が復号されます。
外部のetcdノード
外部のetcdノードを使ったクラスターの設定は、積層etcdの場合と似ていますが、最初にetcdを設定し、kubeadmの設定ファイルにetcdの情報を渡す必要があります。
etcdクラスターの構築
-
こちらの手順にしたがって、etcdクラスターを構築してください。
-
こちらの手順にしたがって、SSHを構築してください。
-
以下のファイルをクラスター内の任意のetcdノードから最初のコントロールプレーンノードにコピーしてください:
export CONTROL_PLANE="[email protected]" scp /etc/kubernetes/pki/etcd/ca.crt "${CONTROL_PLANE}": scp /etc/kubernetes/pki/apiserver-etcd-client.crt "${CONTROL_PLANE}": scp /etc/kubernetes/pki/apiserver-etcd-client.key "${CONTROL_PLANE}":
CONTROL_PLANE
の値を、最初のコントロールプレーンノードのuser@host
で置き換えます。
最初のコントロールプレーンノードの構築
-
以下の内容で、
kubeadm-config.yaml
という名前の設定ファイルを作成します:apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration kubernetesVersion: stable controlPlaneEndpoint: "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" etcd: external: endpoints: - https://ETCD_0_IP:2379 - https://ETCD_1_IP:2379 - https://ETCD_2_IP:2379 caFile: /etc/kubernetes/pki/etcd/ca.crt certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
備考: ここで、積層etcdと外部etcdの違いは、外部etcdの構成ではetcd
のexternal
オブジェクトにetcdのエンドポイントが記述された設定ファイルが必要です。積層etcdトポロジーの場合、これは自動で管理されます。-
テンプレート内の以下の変数を、クラスターに合わせて適切な値に置き換えます:
LOAD_BALANCER_DNS
LOAD_BALANCER_PORT
ETCD_0_IP
ETCD_1_IP
ETCD_2_IP
-
以下の手順は、積層etcdの構築と同様です。
-
sudo kubeadm init --config kubeadm-config.yaml --upload-certs
をこのノードで実行します。 -
表示されたjoinコマンドを、あとで使うためにテキストファイルに書き込みます。
-
使用するCNIプラグインを適用します。以下はWeave CNIの場合です:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
残りのコントロールプレーンノードの手順
手順は、積層etcd構築の場合と同じです:
- 最初のコントロールプレーンノードが完全に初期化されているのを確認します。
- テキストファイルに保存したjoinコマンドを使って、それぞれのコントロールプレーンノードをクラスターへ参加させます。コントロールプレーンノードは1台ずつクラスターへ参加させるのを推奨します。
--certificate-key
で指定する復号キーは、デフォルトで2時間で期限切れになることを忘れないでください。
コントロールプレーン起動後の共通タスク
workerのインストール
kubeadm init
コマンドから返されたコマンドを利用して、workerノードをクラスターに参加させることが可能です。
sudo kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
証明書の手動配布
--upload-certs
フラグを指定してkubeadm init
を実行しない場合、プライマリコントロールプレーンノードから他のコントロールプレーンノードへ証明書を手動でコピーする必要があります。
コピーを行うには多くの方法があります。次の例ではssh
とscp
を使用しています。
1台のマシンから全てのノードをコントロールしたいのであれば、SSHが必要です。
-
システム内の全ての他のノードにアクセスできるメインデバイスで、ssh-agentを有効にします
eval $(ssh-agent)
-
SSHの秘密鍵を、セッションに追加します:
ssh-add ~/.ssh/path_to_private_key
-
正常に接続できることを確認するために、ノード間でSSHします。
-
ノードにSSHする際は、必ず
-A
フラグをつけます:ssh -A 10.0.0.7
-
ノードでsudoするときは、SSHフォワーディングが動くように、環境変数を引き継ぎます:
sudo -E -s
-
-
全てのノードでSSHを設定したら、
kubeadm init
を実行した後、最初のコントロールノードプレーンノードで次のスクリプトを実行します。このスクリプトは、最初のコントロールプレーンノードから残りのコントロールプレーンノードへ証明書ファイルをコピーします:次の例の、
CONTROL_PLANE_IPS
を他のコントロールプレーンノードのIPアドレスに置き換えます。USER=ubuntu # 環境に合わせる CONTROL_PLANE_IPS="10.0.0.7 10.0.0.8" for host in ${CONTROL_PLANE_IPS}; do scp /etc/kubernetes/pki/ca.crt "${USER}"@$host: scp /etc/kubernetes/pki/ca.key "${USER}"@$host: scp /etc/kubernetes/pki/sa.key "${USER}"@$host: scp /etc/kubernetes/pki/sa.pub "${USER}"@$host: scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host: scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host: scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt # 外部のetcdノード使用時はこちらのコマンドを実行 scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key done
注意: 上のリストにある証明書だけをコピーしてください。kubeadmが、参加するコントロールプレーンノード用に、残りの証明書と必要なSANの生成を行います。間違って全ての証明書をコピーしてしまったら、必要なSANがないため、追加ノードの作成は失敗するかもしれません。 -
次に、クラスターに参加させる残りの各コントロールプレーンノードで
kubeadm join
を実行する前に次のスクリプトを実行する必要があります。このスクリプトは、前の手順でコピーした証明書をホームディレクトリから/etc/kubernetes/pki
へ移動します:USER=ubuntu # 環境に合わせる mkdir -p /etc/kubernetes/pki/etcd mv /home/${USER}/ca.crt /etc/kubernetes/pki/ mv /home/${USER}/ca.key /etc/kubernetes/pki/ mv /home/${USER}/sa.pub /etc/kubernetes/pki/ mv /home/${USER}/sa.key /etc/kubernetes/pki/ mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/ mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/ mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt # 外部のetcdノード使用時はこちらのコマンドを実行 mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
7 - kubeadmを使用した高可用性etcdクラスターの作成
Kubeadm defaults to running a single member etcd cluster in a static pod managed by the kubelet on the control plane node. This is not a high availability setup as the etcd cluster contains only one member and cannot sustain any members becoming unavailable. This task walks through the process of creating a high availability etcd cluster of three members that can be used as an external etcd when using kubeadm to set up a kubernetes cluster.
始める前に
- Three hosts that can talk to each other over ports 2379 and 2380. This document assumes these default ports. However, they are configurable through the kubeadm config file.
- Each host must have docker, kubelet, and kubeadm installed.
- Each host should have access to the Kubernetes container image registry (
k8s.gcr.io
) or list/pull the required etcd image usingkubeadm config images list/pull
. This guide will setup etcd instances as static pods managed by a kubelet. - Some infrastructure to copy files between hosts. For example
ssh
andscp
can satisfy this requirement.
クラスターの構築
The general approach is to generate all certs on one node and only distribute the necessary files to the other nodes.
-
Configure the kubelet to be a service manager for etcd.
Since etcd was created first, you must override the service priority by creating a new unit file that has higher precedence than the kubeadm-provided kubelet unit file.
cat << EOF > /etc/systemd/system/kubelet.service.d/20-etcd-service-manager.conf [Service] ExecStart= # Replace "systemd" with the cgroup driver of your container runtime. The default value in the kubelet is "cgroupfs". ExecStart=/usr/bin/kubelet --address=127.0.0.1 --pod-manifest-path=/etc/kubernetes/manifests --cgroup-driver=systemd Restart=always EOF systemctl daemon-reload systemctl restart kubelet
-
Create configuration files for kubeadm.
Generate one kubeadm configuration file for each host that will have an etcd member running on it using the following script.
# Update HOST0, HOST1, and HOST2 with the IPs or resolvable names of your hosts export HOST0=10.0.0.6 export HOST1=10.0.0.7 export HOST2=10.0.0.8 # Create temp directories to store files that will end up on other hosts. mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/ ETCDHOSTS=(${HOST0} ${HOST1} ${HOST2}) NAMES=("infra0" "infra1" "infra2") for i in "${!ETCDHOSTS[@]}"; do HOST=${ETCDHOSTS[$i]} NAME=${NAMES[$i]} cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml apiVersion: "kubeadm.k8s.io/v1beta2" kind: ClusterConfiguration etcd: local: serverCertSANs: - "${HOST}" peerCertSANs: - "${HOST}" extraArgs: initial-cluster: ${NAMES[0]}=https://${ETCDHOSTS[0]}:2380,${NAMES[1]}=https://${ETCDHOSTS[1]}:2380,${NAMES[2]}=https://${ETCDHOSTS[2]}:2380 initial-cluster-state: new name: ${NAME} listen-peer-urls: https://${HOST}:2380 listen-client-urls: https://${HOST}:2379 advertise-client-urls: https://${HOST}:2379 initial-advertise-peer-urls: https://${HOST}:2380 EOF done
-
Generate the certificate authority
If you already have a CA then the only action that is copying the CA's
crt
andkey
file to/etc/kubernetes/pki/etcd/ca.crt
and/etc/kubernetes/pki/etcd/ca.key
. After those files have been copied, proceed to the next step, "Create certificates for each member".If you do not already have a CA then run this command on
$HOST0
(where you generated the configuration files for kubeadm).kubeadm init phase certs etcd-ca
This creates two files
/etc/kubernetes/pki/etcd/ca.crt
/etc/kubernetes/pki/etcd/ca.key
-
Create certificates for each member
kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml cp -R /etc/kubernetes/pki /tmp/${HOST2}/ # cleanup non-reusable certificates find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml cp -R /etc/kubernetes/pki /tmp/${HOST1}/ find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml # No need to move the certs because they are for HOST0 # clean up certs that should not be copied off this host find /tmp/${HOST2} -name ca.key -type f -delete find /tmp/${HOST1} -name ca.key -type f -delete
-
Copy certificates and kubeadm configs
The certificates have been generated and now they must be moved to their respective hosts.
USER=ubuntu HOST=${HOST1} scp -r /tmp/${HOST}/* ${USER}@${HOST}: ssh ${USER}@${HOST} USER@HOST $ sudo -Es root@HOST $ chown -R root:root pki root@HOST $ mv pki /etc/kubernetes/
-
Ensure all expected files exist
The complete list of required files on
$HOST0
is:/tmp/${HOST0} └── kubeadmcfg.yaml --- /etc/kubernetes/pki ├── apiserver-etcd-client.crt ├── apiserver-etcd-client.key └── etcd ├── ca.crt ├── ca.key ├── healthcheck-client.crt ├── healthcheck-client.key ├── peer.crt ├── peer.key ├── server.crt └── server.key
On
$HOST1
:$HOME └── kubeadmcfg.yaml --- /etc/kubernetes/pki ├── apiserver-etcd-client.crt ├── apiserver-etcd-client.key └── etcd ├── ca.crt ├── healthcheck-client.crt ├── healthcheck-client.key ├── peer.crt ├── peer.key ├── server.crt └── server.key
On
$HOST2
$HOME └── kubeadmcfg.yaml --- /etc/kubernetes/pki ├── apiserver-etcd-client.crt ├── apiserver-etcd-client.key └── etcd ├── ca.crt ├── healthcheck-client.crt ├── healthcheck-client.key ├── peer.crt ├── peer.key ├── server.crt └── server.key
-
Create the static pod manifests
Now that the certificates and configs are in place it's time to create the manifests. On each host run the
kubeadm
command to generate a static manifest for etcd.root@HOST0 $ kubeadm init phase etcd local --config=/tmp/${HOST0}/kubeadmcfg.yaml root@HOST1 $ kubeadm init phase etcd local --config=/tmp/${HOST1}/kubeadmcfg.yaml root@HOST2 $ kubeadm init phase etcd local --config=/tmp/${HOST2}/kubeadmcfg.yaml
-
Optional: Check the cluster health
docker run --rm -it \ --net host \ -v /etc/kubernetes:/etc/kubernetes k8s.gcr.io/etcd:${ETCD_TAG} etcdctl \ --cert /etc/kubernetes/pki/etcd/peer.crt \ --key /etc/kubernetes/pki/etcd/peer.key \ --cacert /etc/kubernetes/pki/etcd/ca.crt \ --endpoints https://${HOST0}:2379 endpoint health --cluster ... https://[HOST0 IP]:2379 is healthy: successfully committed proposal: took = 16.283339ms https://[HOST1 IP]:2379 is healthy: successfully committed proposal: took = 19.44402ms https://[HOST2 IP]:2379 is healthy: successfully committed proposal: took = 35.926451ms
- Set
${ETCD_TAG}
to the version tag of your etcd image. For example3.4.3-0
. To see the etcd image and tag that kubeadm uses executekubeadm config images list --kubernetes-version ${K8S_VERSION}
, where${K8S_VERSION}
is for examplev1.17.0
- Set
${HOST0}
to the IP address of the host you are testing.
- Set
次の項目
Once you have a working 3 member etcd cluster, you can continue setting up a highly available control plane using the external etcd method with kubeadm.
8 - kubeadmを使用したクラスター内の各kubeletの設定
Kubernetes 1.11 [stable]
kubeadm CLIツールのライフサイクルは、Kubernetesクラスター内の各ノード上で稼働するデーモンであるkubeletから分離しています。kubeadm CLIツールはKubernetesを初期化またはアップグレードする際にユーザーによって実行されます。一方で、kubeletは常にバックグラウンドで稼働しています。
kubeletはデーモンのため、何らかのinitシステムやサービスマネージャーで管理する必要があります。DEBパッケージやRPMパッケージからkubeletをインストールすると、systemdはkubeletを管理するように設定されます。代わりに別のサービスマネージャーを使用することもできますが、手動で設定する必要があります。
いくつかのkubeletの設定は、クラスターに含まれる全てのkubeletで同一である必要があります。一方で、特定のマシンの異なる特性(OS、ストレージ、ネットワークなど)に対応するために、kubeletごとに設定が必要なものもあります。手動で設定を管理することも可能ですが、kubeadmは一元的な設定管理のためのKubeletConfiguration
APIを提供しています。
Kubeletの設定パターン
以下のセクションでは、kubeadmを使用したkubeletの設定パターンについて説明します。これは手動で各Nodeの設定を管理するよりも簡易に行うことができます。
各kubeletにクラスターレベルの設定を配布
kubeadm init
およびkubeadm join
コマンドを使用すると、kubeletにデフォルト値を設定することができます。興味深い例として、異なるCRIランタイムを使用したり、Serviceが使用するデフォルトのサブネットを設定したりすることができます。
Serviceが使用するデフォルトのサブネットとして10.96.0.0/12
を設定する必要がある場合は、--service-cidr
パラメーターを渡します。
kubeadm init --service-cidr 10.96.0.0/12
これによってServiceの仮想IPはこのサブネットから割り当てられるようになりました。また、--cluster-dns
フラグを使用し、kubeletが用いるDNSアドレスを設定する必要もあります。この設定はクラスター内の全てのマネージャーとNode上で同一である必要があります。kubeletは、kubeletのComponentConfigと呼ばれる、バージョン管理と構造化されたAPIオブジェクトを提供します。これはkubelet内のほとんどのパラメーターを設定し、その設定をクラスター内で稼働中の各kubeletへ適用することを可能にします。以下の例のように、キャメルケースのキーに値のリストとしてクラスターDNS IPアドレスなどのフラグを指定することができます。
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
clusterDNS:
- 10.96.0.10
ComponentConfigの詳細については、このセクションをご覧ください
インスタンス固有の設定内容を適用
いくつかのホストでは、ハードウェア、オペレーティングシステム、ネットワーク、その他ホスト固有のパラメータの違いのため、特定のkubeletの設定を必要とします。以下にいくつかの例を示します。
- DNS解決ファイルへのパスは
--resolv-conf
フラグで指定することができますが、オペレーティングシステムやsystemd-resolved
を使用するかどうかによって異なる場合があります。このパスに誤りがある場合、そのNode上でのDNS解決は失敗します。 - クラウドプロバイダーを使用していない場合、Node APIオブジェクト
.metadata.name
はデフォルトでマシンのホスト名に設定されます。異なるNode名を指定する必要がある場合には、--hostname-override
フラグによってこの挙動を書き換えることができます。 - 現在のところ、kubletはCRIランタイムが使用するcgroupドライバを自動で検知することができませんが、kubeletの稼働を保証するためには、
--cgroup-driver
の値はCRIランタイムが使用するcgroupドライバに一致していなければなりません。 - クラスターが使用するCRIランタイムによっては、異なるフラグを指定する必要があるかもしれません。例えば、Dockerを使用している場合には、
--network-plugin=cni
のようなフラグを指定する必要があります。外部のランタイムを使用している場合には、--container-runtime=remote
と指定し、--container-runtime-endpoint=<path>
のようにCRIエンドポイントを指定する必要があります。
これらのフラグは、systemdなどのサービスマネージャー内のkubeletの設定によって指定することができます。
kubeadmを使用したkubeletの設定
kubeadm ... --config some-config-file.yaml
のように、カスタムのKubeletConfiguration
APIオブジェクトを設定ファイルを介して渡すことで、kubeadmによって起動されるkubeletに設定を反映することができます。
kubeadm config print init-defaults --component-configs KubeletConfiguration
を実行することによって、この構造体の全てのデフォルト値を確認することができます。
また、各フィールドの詳細については、kubelet ComponentConfigに関するAPIリファレンスを参照してください。
kubeadm init
実行時の流れ
kubeadm init
を実行した場合、kubeletの設定は/var/lib/kubelet/config.yaml
に格納され、クラスターのConfigMapにもアップロードされます。ConfigMapはkubelet-config-1.X
という名前で、X
は初期化するKubernetesのマイナーバージョンを表します。またこの設定ファイルは、クラスタ内の全てのkubeletのために、クラスター全体設定の基準と共に/etc/kubernetes/kubelet.conf
にも書き込まれます。この設定ファイルは、kubeletがAPIサーバと通信するためのクライアント証明書を指し示します。これは、各kubeletにクラスターレベルの設定を配布することの必要性を示しています。
二つ目のパターンである、インスタンス固有の設定内容を適用するために、kubeadmは環境ファイルを/var/lib/kubelet/kubeadm-flags.env
へ書き出します。このファイルは以下のように、kubelet起動時に渡されるフラグのリストを含んでいます。
KUBELET_KUBEADM_ARGS="--flag1=value1 --flag2=value2 ..."
kubelet起動時に渡されるフラグに加えて、このファイルはcgroupドライバーや異なるCRIランタイムソケットを使用するかどうか(--cri-socket
)といった動的なパラメータも含みます。
これら二つのファイルがディスク上に格納されると、systemdを使用している場合、kubeadmは以下の二つのコマンドを実行します。
systemctl daemon-reload && systemctl restart kubelet
リロードと再起動に成功すると、通常のkubeadm init
のワークフローが続きます。
kubeadm join
実行時の流れ
kubeadm join
を実行した場合、kubeadmはBootstrap Token証明書を使用してTLS bootstrapを行い、ConfigMapkubelet-config-1.X
をダウンロードするために必要なクレデンシャルを取得し、/var/lib/kubelet/config.yaml
へ書き込みます。動的な環境ファイルは、kubeadm init
の場合と全く同様の方法で生成されます。
次に、kubeadm
は、kubeletに新たな設定を読み込むために、以下の二つのコマンドを実行します。
systemctl daemon-reload && systemctl restart kubelet
kubeletが新たな設定を読み込むと、kubeadmは、KubeConfigファイル/etc/kubernetes/bootstrap-kubelet.conf
を書き込みます。これは、CA証明書とBootstrap Tokenを含みます。これらはkubeletがTLS Bootstrapを行い/etc/kubernetes/kubelet.conf
に格納されるユニークなクレデンシャルを取得するために使用されます。ファイルが書き込まれると、kubeletはTLS Bootstrapを終了します。
kubelet用のsystemdファイル
kubeadm
には、systemdがどのようにkubeletを実行するかを指定した設定ファイルが同梱されています。
kubeadm CLIコマンドは決してこのsystemdファイルには触れないことに注意してください。
kubeadmのDEBパッケージまたはRPMパッケージによってインストールされたこの設定ファイルは、/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
に書き込まれ、systemdで使用されます。基本的なkubelet.service
(RPM用または、 DEB用)を拡張します。
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
--kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generate at runtime, populating
the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably,
# the user should use the .NodeRegistration.KubeletExtraArgs object in the configuration files instead.
# KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/default/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
このファイルは、kubeadmがkubelet用に管理する全ファイルが置かれるデフォルトの場所を指定します。
- TLS Bootstrapに使用するKubeConfigファイルは
/etc/kubernetes/bootstrap-kubelet.conf
ですが、/etc/kubernetes/kubelet.conf
が存在しない場合にのみ使用します。 - ユニークなkublet識別子を含むKubeConfigファイルは
/etc/kubernetes/kubelet.conf
です。 - kubeletのComponentConfigを含むファイルは
/var/lib/kubelet/config.yaml
です。 KUBELET_KUBEADM_ARGS
を含む動的な環境ファイルは/var/lib/kubelet/kubeadm-flags.env
から取得します。KUBELET_EXTRA_ARGS
によるユーザー定義のフラグの上書きを格納できるファイルは/etc/default/kubelet
(DEBの場合)、または/etc/sysconfig/kubelet
(RPMの場合)から取得します。KUBELET_EXTRA_ARGS
はフラグの連なりの最後に位置し、優先度が最も高いです。
Kubernetesバイナリとパッケージの内容
Kubernetesに同梱されるDEB、RPMのパッケージは以下の通りです。
パッケージ名 | 説明 |
---|---|
kubeadm |
/usr/bin/kubeadm CLIツールと、kubelet用のsystemdファイルをインストールします。 |
kubelet |
kubeletバイナリを/usr/bin に、CNIバイナリを/opt/cni/bin にインストールします。 |
kubectl |
/usr/bin/kubectl バイナリをインストールします。 |
cri-tools |
/usr/bin/crictl バイナリをcri-tools gitリポジトリからインストールします。 |
9 - コントロールプレーンをセルフホストするようにkubernetesクラスターを構成する
コントロールプレーンのセルフホスティング
kubeadmを使用すると、セルフホスト型のKubernetesコントロールプレーンを実験的に作成できます。これはAPIサーバー、コントローラーマネージャー、スケジューラーなどの主要コンポーネントは、静的ファイルを介してkubeletで構成されたstatic podsではなく、Kubernetes APIを介して構成されたDaemonSet podsとして実行されることを意味します。
セルフホスト型クラスターを作成する場合はkubeadm alpha selfhosting pivotを参照してください。
警告
kubeadm upgrade
が含まれます。
-
1.8以降のセルフホスティングには、いくつかの重要な制限があります。特に、セルフホスト型クラスターは、手動の介入なしにコントロールプレーンのNode再起動から回復することはできません。
-
デフォルトでは、セルフホスト型のコントロールプレーンのPodは、
hostPath
ボリュームからロードされた資格情報に依存しています。最初の作成を除いて、これらの資格情報はkubeadmによって管理されません。 -
コントロールプレーンのセルフホストされた部分にはetcdが含まれていませんが、etcdは静的Podとして実行されます。
プロセス
セルフホスティングのブートストラッププロセスは、kubeadm design documentに記載されています。
要約すると、kubeadm alpha selfhosting
は次のように機能します。
-
静的コントロールプレーンのブートストラップが起動し、正常になるのを待ちます。これは
kubeadm init
のセルフホスティングを使用しないプロセスと同じです。 -
静的コントロールプレーンのPodのマニフェストを使用して、セルフホスト型コントロールプレーンを実行する一連のDaemonSetのマニフェストを構築します。また、必要に応じてこれらのマニフェストを変更します。たとえば、シークレット用の新しいボリュームを追加します。
-
kube-system
のネームスペースにDaemonSetを作成し、Podの結果が起動されるのを待ちます。 -
セルフホスト型のPodが操作可能になると、関連する静的Podが削除され、kubeadmは次のコンポーネントのインストールに進みます。これによりkubeletがトリガーされて静的Podが停止します。
-
元の静的なコントロールプレーンが停止すると、新しいセルフホスト型コントロールプレーンはリスニングポートにバインドしてアクティブになります。