Nodeコンポーネント@Kubernetes¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. Nodeコンポーネントとは¶
ワーカーNode上で稼働するKubernetesコンポーネントのこと。
02. ワーカーNode¶
ワーカーNodeとは¶
ノードコンポーネントが稼働する。Kubernetesの実行時に自動的に作成される。
もし手動で作成する場合は、kubectl
コマンドで--register-node=false
とする必要がある。
ワーカーNodeで待ち受けるポート番号¶
ワーカーNodeがパケットを待ち受けるデフォルトのポート番号は、以下の通りである。
03. Nodeグループ¶
Nodeグループとは¶
KubernetesにはNodeグループというリソースがなく、グループを宣言的に定義することはできない。
ただ、クラウドプロバイダーのサーバーオートスケーリング機能 (例:AWS EC2AutoScaling) を使用して、Nodeグループ (例:AWS EKS Nodeグループ) を実現できる。
同じ設定値 (.metadata.labels
キー、CPU、メモリなど) や同じ役割を持ったNodeのグループのこと。
基本的には、Nodeグループは冗長化されたワーカーNodeで構成されており、IDは違えど、ワーカーNode名は全て同じである。
NodeグループをターゲットとするL7
ロードバランサーでは、Nodeグループ内で冗長化ワーカーNodeのいずれかに対してルーティングすることになる。
Nodeグループの粒度¶
node affinityやnode selectorを実施できるように、.metadata.labels
キーにNodeグループ名を設定しておく。
キー名は、node.kubernetes.io/nodetype
とする。
Nodeグループ名の例と.metadata.labels キー値 |
説明 |
---|---|
app 、service |
アプリコンテナを稼働させる。 |
batch 、job |
単発的なバッチ処理やジョブ (定期的なバッチ処理) のコンテナを配置する。 |
deploy |
他のKubernetesリソースをデプロイするためのKubernetesリソース (例:ArgoCDのPod) のコンテナを配置する。Nodeグループ内に含めずに、異なるClusterに切り分けて管理しても良い。 |
ingress 、gateway |
ワーカーNodeへのインバウンド通信の入口になるリソース (例:Ingress、IngressGateway) のコンテナや、API Gatewayのアプリコンテナを配置する。これは単一障害点になりうるため、ワーカーNodeのCPUやメモリを潤沢にしようできるように、他のリソースのコンテナとは別のNodeグループにした方が良い。また、アップグレード時間の短縮にも繋がる。 |
master |
セルフマネージドなKubernetesコントロールプレーンNodeのコンテナを稼働させる。マネージドなコントロールプレーンNode (例:AWS EKS、Google Cloud GKE、Azure AKSなど) の場合、このNodeグループは不要になる。 |
system |
ログやメトリクスのデータポイントを収集するリソース (例:Prometheus、Alertmanager、のPod) のコンテナを配置する。また、セルフマネージドなサービスメッシュコントロールプレーンNodeのコンテナを稼働させる。マネージドなコントロールプレーンNode (例:AWS VPC Latticeなど) の場合、このNodeグループは不要になる。 |
apiVersion: v1
kind: Pod
metadata:
name: foo-pod
labels:
node.kubernetes.io/nodetype: batch
spec: ...
ワーカーNodeのオートスケーリング¶
執筆時点 (2022/07/20) では、KubernetesのAPIにはワーカーNodeのオートスケーリング機能はない。
そのため、Node数は固定である。
ただし、cluster-autoscalerを使用すると、各クラウドプロバイダーのAPIからワーカーNodeのオートスケーリングを実行できるようになる。
04. kube-proxy¶
kube-proxyとは¶
kube-proxyは、サービスディスカバリーとL4
ロードバランシングを実行する。
この時、ワーカーNodeをクライアント、コントロールプレーンをサービスレジストリ、としたクライアントサイドサービスディスカバリーを実現する。
各ワーカーNode上でDaemonSetとして稼働する。
Serviceネットワークさえ作成できていれば、ServiceとPodが同じワーカーNode上にあるか否かに限らず、Serviceは、ワーカーNodeの宛先情報ルールを使用してPodを動的に検出できる。
ただし、宛先のIPアドレスは動的に変化するため、別途CoreDNSも使用して、サービスディスカバリーを実装する。
セットアップ¶
▼ 起動コマンド¶
$ kube-proxy \
--config=/var/lib/kube-proxy/config.conf \
--hostname-override=foo-node \
...
その他のプロキシ¶
ワーカーNode外部からのインバウンド通信をPodにルーティングするためのプロキシが、他にもいくつかある。
kubectl proxy
コマンドminikube tunnel
コマンド- LoadBalancer
04-02.プロキシモードの種類¶
iptablesプロキシモード¶
▼ iptablesプロキシモード¶
デフォルトのプロキシモードである。
項目 | 仕組み |
---|---|
サービスディスカバリー | ServiceとそのService配下のEndpointSliceの追加と削除を監視し、これらの増減に合わせて、ワーカーNode上で稼働するiptablesにIPアドレスを追加/削除する。 |
L4 ロードバランサー |
ランダム方式のみ。 |
- https://kubernetes.io/docs/concepts/services-networking/service/#proxy-mode-iptables
- https://www.mtioutput.com/entry/kube-proxy-iptable
- https://github.com/kubernetes/kubernetes/pull/81430
- https://www.imagazine.co.jp/%e5%ae%9f%e8%b7%b5-kubernetes%e3%80%80%e3%80%80%ef%bd%9e%e3%82%b3%e3%83%b3%e3%83%86%e3%83%8a%e7%ae%a1%e7%90%86%e3%81%ae%e3%82%b9%e3%82%bf%e3%83%b3%e3%83%80%e3%83%bc%e3%83%89%e3%83%84%e3%83%bc%e3%83%ab/
▼ サービスディスカバリー¶
iptable方式の場合、kube-proxyはiptablesにPodのIPアドレスを追加/削除する。
iptables
コマンドで、『KUBE-SERVICES
』というチェインのターゲットを確認する。
ターゲットには、Serviceのルーティング先となるPod (異なるワーカーNode上にある場合もある) の宛先情報が登録されている。
source
列に含まれるIPアドレスを持つパケットのみでルールが適用され、各ルールに対応するPodに送信する場合、宛先IPアドレスをdestination
列のIPアドレスに変換する。
$ iptables -L -n KUBE-SERVICES -t nat --line-number
Chain KUBE-SERVICES (2 references)
num target prot opt source destination
1 KUBE-SVC-ERIFXISQEP7F7OF4 tcp -- 0.0.0.0/0 10.96.0.10 /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:53
2 KUBE-SVC-V2OKYYMBY3REGZOG tcp -- 0.0.0.0/0 10.101.67.107 /* default/nginx-service cluster IP */ tcp dpt:8080
3 KUBE-SVC-NPX46M4PTMTKRN6Y tcp -- 0.0.0.0/0 10.96.0.1 /* default/kubernetes:https cluster IP */ tcp dpt:443
4 KUBE-SVC-JD5MR3NA4I4DYORP tcp -- 0.0.0.0/0 10.96.0.10 /* kube-system/kube-dns:metrics cluster IP */ tcp dpt:9153
5 KUBE-SVC-TCOU7JCQXEZGVUNU udp -- 0.0.0.0/0 10.96.0.10 /* kube-system/kube-dns:dns cluster IP */ udp dpt:53
6 KUBE-NODEPORTS all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL
▼ L4
ロードバランシング¶
iptable方式の場合、kube-proxyによって検出されたPodのIPアドレスに対して、L4
ロードバランシングを実行する。
userspaceプロキシモード¶
▼ userspaceプロキシモード¶
項目 | 仕組み |
---|---|
サービスディスカバリー | ServiceとそのService配下のEndpointSliceの追加と削除を監視し、これらの増減に合わせて、ワーカーNode上で稼働するiptablesにIPアドレスを追加/削除する。 |
L4 ロードバランサー |
ラウンドロビン方式のみ。 |
ipvsプロキシモード¶
▼ ipvsプロキシモード¶
kube-proxyの起動時に、--feature-gates
オプションにSupportIPVSProxyMode=true
、--proxy-mode
オプションにipvs
を設定する。
項目 | 仕組み |
---|---|
サービスディスカバリー | ServiceとそのService配下のEndpointSliceの追加と削除を監視し、これらの増減に合わせて、ワーカーNode上で稼働するipvsにハッシュ値を追加/削除する。 |
L4 ロードバランサー |
ラウンドロビン方式、コネクションの最低数、宛先ハッシュ値、送信元ハッシュ値など。 |
05. kubelet¶
kubeletとは¶
各ワーカーNode上で直接デーモンとして常駐し、コンテナランタイムを操作することにより、Podを作成する。
また、ワーカーNodeやPodを監視し、メトリクスのデータポイントをkube-apiserverに提供する。
セットアップ¶
▼ 起動コマンド¶
$ kubelet \
--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
`# kubeletの設定ファイル` \
--kubeconfig=/etc/kubernetes/kubelet.conf \
--config=/var/lib/kubelet/config.yaml \
--authentication-token-webhook=true
--authorization-mode=Webhook \
--container-runtime=remote \
`# コンテナランタイムの設定` \
--container-runtime-endpoint=unix:///run/containerd/containerd.sock \
--max-pods=250 \
--node-ip=*.*.*.* \
--rotate-server-certificates=true \
--seccomp-default=true \
--cgroup-driver=systemd \
--runtime-cgroups=/system.slice/containerd.service \
...
▼ kubelet-config.json
ファイル (KubeletConfiguration)¶
kubeletを設定する。
{
"kind": "KubeletConfiguration",
"apiVersion": "kubelet.config.k8s.io/v1beta1",
"address": "0.0.0.0",
"authentication":
{
"anonymous": {"enabled": "false"},
"webhook": {"cacheTTL": "2m0s", "enabled": "true"},
"x509": {"clientCAFile": "/etc/kubernetes/pki/ca.crt"},
},
"authorization":
{
"mode": "Webhook",
"webhook": {"cacheAuthorizedTTL": "5m0s", "cacheUnauthorizedTTL": "30s"},
},
"clusterDomain": "cluster.local",
"hairpinMode": "hairpin-veth",
"readOnlyPort": 0,
"cgroupDriver": "cgroupfs",
"cgroupRoot": "/",
"featureGates": {"RotateKubeletServerCertificate": "true"},
"protectKernelDefaults": "true",
"serializeImagePulls": "false",
"serverTLSBootstrap": "true",
"tlsCipherSuites":
[
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
],
# コンテナのログローテーションの閾値
"containerLogMaxSize": "100Mi",
# コンテナのログの最大世代数
"containerLogMaxFiles": 2,
}
コンテナランタイムの操作¶
▼ ガベージコレクション¶
コンテナランタイム (例:Docker、Containerdなど) は、ベースイメージを含む各イメージレイヤーをキャッシュとしてローカルストレージ (例:var/lib/docker
ディレクトリ、var/lib/containerd
ディレクトリなど) に保管する。
kubeletは、使用されていないイメージレイヤー (5
分ごと) やコンテナ (10
分ごと) のキャッシュのガベージコレクションを実行する。
コンテナイメージのガベージコレクションであれば、Nodeのストレージ使用量が85
%を超過していると、kubeletは80
%未満になるようにコンテナイメージの残骸を削除する。
- https://zenn.dev/tmoka/articles/d7e428da4026a5#%E4%BD%BF%E3%82%8F%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%82%84%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8
- https://github.com/kubernetes/kubernetes/blob/v1.24.0/pkg/kubelet/apis/config/v1beta1/defaults.go#L138-L144
- https://github.com/kubernetes/kubernetes/blob/v1.24.0/pkg/kubelet/images/image_gc_manager.go#L63-L76
- https://docker-docs.uclv.cu/storage/storagedriver/#sharing-promotes-smaller-images
▼ ログローテション¶
kubeletは、Pod内のコンテナが標準出力に出力したログを取得し、サイズが一定量を超過するとNode上に.zip
形式で圧縮して保管する。
また、ログローテーションの結果で作成されるファイルの世代数が一定数を超過すると、古い世代順に削除する。
これらは、containerLogMaxSize
とcontainerLogMaxFiles
で設定できる。
kubeletではログの保管期間を設定できないため、もし保管期間を設定したい場合はNode上にログローテーションツール (例:logrotate) をインストールする必要がある。
ログ¶
▼ kubeletのログの確認¶
kubeletは、ワーカーNodeでデーモンとして常駐しているため、journalctl
コマンドでログを取得できる。
$ journalctl -u kubelet.service
-- Logs begin at Mon 2022-04-18 21:04:26 JST, end at Mon 2022-12-05 17:42:29 JST. --
04/21 14:21:55 foo-node systemd[1]: Started kubelet: The Kubernetes Node Agent.
...
▼ kubeletのバージョン¶
ログ内にkubeletのバージョンが定義されている。
$ journalctl -u kubelet.service | grep "Kubelet version"
kubelet[405976]: I0421 14:22:01.838974 405976 server.go:440] "Kubelet version" kubeletVersion="v1.22"
ユニットファイル¶
▼ kubelet.service
ファイル¶
おおよそ、/etc/systemd/system
ディレクトリにある。
ファイルの設定例は以下の通りである。
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service sandbox-image.service
Requires=containerd.service sandbox-image.service
[Service]
Slice=runtime.slice
ExecStartPre=/sbin/iptables -P FORWARD ACCEPT -w 5
ExecStart=/usr/bin/kubelet \
--config /etc/kubernetes/kubelet/kubelet-config.json \
--kubeconfig /var/lib/kubelet/kubeconfig \
--container-runtime-endpoint unix:///run/containerd/containerd.sock \
--image-credential-provider-config /etc/eks/image-credential-provider/config.json \
--image-credential-provider-bin-dir /etc/eks/image-credential-provider \
$KUBELET_ARGS \
$KUBELET_EXTRA_ARGS
Restart=on-failure
RestartForceExitStatus=SIGPIPE
RestartSec=5
KillMode=process
CPUAccounting=true
MemoryAccounting=true
06. コンテナランタイム (Containerd)¶
セットアップ¶
▼ Containerdのインストールの事前作業¶
(1)
-
/etc/modules-load.d/containerd.conf
ファイルに、カーネルモジュールを設定する。
overlay
br_netfilter
(2)
-
カーネルモジュールを読み込む。
$ modprobe overlay
$ modprobe br_netfilter
(3)
-
/etc/sysctl.d/99-kubernetes-cri.conf
ファイルに、カーネルオプションを設定する。
net.bridge.bridge-nf-call-iptables=1
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables=1
(4)
-
カーネルに設定を反映する。
$ sysctl --system
▼ Containerdのインストール¶
(1)
-
要件のパッケージをインストールする。
$ apt-get update -y \
&& apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
(2)
-
Docker公式の提供するGPGキーを追加する。
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
(3)
-
リポジトリを追加する。
$ add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
(4)
-
Containerdをインストールする。
$ apt-get update && apt-get install containerd.io
▼ Containerdの設定ファイルの準備¶
(1)
-
設定ファイルとして、
/etc/containerd/config.toml
ファイルを作成する。
$ mkdir -p /etc/containerd
$ containerd config default | sudo tee /etc/containerd/config.toml
(2)
-
Containerdに設定を反映する。
$ systemctl restart containerd
▼ kubeletによるContainerdの指定¶
kubeletの起動時に、--container-runtime
オプションと--container-runtime-endpoint
オプションを使用する。
$ kubelet \
--container-runtime=remote \
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
...
ログ¶
ワーカーNodeでデーモンとして常駐しているため、journalctl
コマンドでログを取得できる。
$ journalctl -u containerd.service
-- Logs begin at Mon 2022-04-18 21:04:26 JST, end at Mon 2022-12-05 17:43:49 JST. --
04/19 18:10:17 fo-node systemd[1]: Starting containerd container runtime...
コンテナのライフサイクル¶
▼ フェーズ¶
コンテナのライフサイクルにはフェーズがある。
フェーズ名 | 説明 |
---|---|
Waiting | Running フェーズとTerminated フェーズ以外のフェーズにある。 |
Running | コンテナの起動が完了し、実行中である。 |
Terminated | コンテナが正常/異常に停止した。 |