Kubernetesの基本アーキテクチャ
Kubernetesクラスターは主にマスターノードとワーカーノードの2種類のノードで構成されます。
マスターノードのコンポーネント
- APIサーバー: 全てのサービスリクエストの統一アクセスポイント
- コントローラーマネージャー: K8Sリソースオブジェクトのコントローラーを管理し、リソース状態を監視
- スケジューラー: Podリソースのスケジューリングを担当し、最適なノードを選択
- etcd: K8Sクラスターのデータベース。キー値ペア構造の分散データベース
ワーカーノードのコンポーネント
- kubelet: APIサーバーからのリクエストを受信し、Podとコンテナを管理
- kube-proxy: Serviceリソースの実体として、Podのネットワークプロキシを実現
- コンテナランタイム: コンテナを実行(Docker、containerdなど)
Podリソース作成のワークフロー
- クライアントがPod作成リクエストをAPIサーバーに送信
- APIサーバーがリクエスト情報をetcdに保存し、コントローラーマネージャーにPod作成を依頼
- コントローラーマネージャーがスケジューラーを呼び出し、新規Podのスケジューリングを実行
- スケジューラーがスケジューリングアルゴリズムを使用して最適なノードを選択
- APIサーバーが対象ノードのkubeletにPod作成を指示
- kubeletがコンテナランタイムと連携してPodおよびコンテナのライフサイクルを管理
- ユーザーがAPIサーバー経由でkube-proxyにネットワークルールを書き込み、Serviceを作成
K8Sリソースオブジェクトと設定情報
主要なリソースオブジェクト
- Pod: K8Sが作成・管理できる最小単位。1つのPodに複数のコンテナを含めることが可能
- Podコントローラー:
- Deployment: ステートレスアプリケーションのデプロイ
- StatefulSet: ステートフルアプリケーションのデプロイ
- DaemonSet: 全ノードに同一タイプのPodをデプロイ
- Job/CronJob: 一時的または周期的なタスクの実行
- Service: クラスター内でPodグループに統一アクセスポイントを提供
- Ingress: クラスター外部アクセス層として、7層プロキシ転送をサポート
リソース設定情報
- apiVersion: リソースオブジェクトが使用するAPIインターフェースのバージョン
- kind: リソースオブジェクトのタイプ
- metadata: リソースオブジェクトのメタデータ(名前、アノテーション、名前空間、ラベル)
- spec: リソースオブジェクトの設定プロパティ(レプリカ数、イメージ、ボリュームなど)
- status: リソースオブジェクトの現在の実行状態情報
K8Sの3種類のネットワークとインターフェース
3種類のネットワーク
- ノードネットワーク: nodeIP
- Podネットワーク: podIP
- Serviceネットワーク: clusterIP
3種類のインターフェース
| CRI | コンテナランタイムインターフェース | docker, containerd, podman, cri-o |
| CNI | コンテナネットワークインターフェース | flannel, calico, cilium |
| CSI | コンテナストレージインターフェース | ceph, nfs, gfs, oss, s3 |
etcdクラスター
etcdはCoreOSチームによって開発されたオープンソースの分散キー値データベースです。Go言語で記述され、Raftアルゴリズムを使用して一貫性を確保します。
etcdの特徴
- シンプルさ: インストールと設定が簡単で、HTTP APIを提供
- セキュリティ: SSL証明書認証をサポート
- 高速性: シングルインスタンスで毎秒2k以上の読み取り操作をサポート
- 信頼性: Raftアルゴリズムにより、分散システムデータの可用性と一貫性を実現
etcdはデフォルトでポート2379を使用してHTTP APIサービスを提供し、ポート2380でピア通信を行います。本番環境では通常、クラスター方式でのデプロイが推奨されます。リーダー選挙メカニズムのため、少なくとも3台以上の奇数台が必要です。
Flannelネットワーク
Flannelの基本概念
Flannelは各ノード上でコンテナ宛のデータパケットをカプセル化し、トンネル経由で対象Podが実行されているノードに送信します。対象ノードはカプセル化を解除し、元のデータパケットを対象Podに転送します。この方法ではデータ通信のパフォーマンスに影響が出ます。
K8S内のPodネットワーク通信
- 同一Pod内のコンテナ間通信: 同じネットワーク名前空間を共有するため、localhostアドレスで直接通信可能
- 同一ノード内のPod間通信: 各Podはグローバルに一意なIPアドレスを持ち、同じdocker0ブリッジに接続されているため直接通信可能
- 異なるノード上のPod間通信: 物理NICを介した通信が必要で、PodのIPが衝突しないこと、PodのIPとノードIPを関連付ける必要がある
Flannelの動作モードと原理
UDPモードの動作原理
- 元のデータパケットがソースホストのPodコンテナからcni0ブリッジインターフェースへ送信され、flannel0仮想インターフェースへ転送
- flanneldプロセスがflannel0インターフェースで受信したデータを監視し、元のデータパケットをUDPパケットにカプセル化
- flanneldプロセスがetcdで維持されているルーティングテーブルに基づき対象PodのあるノードIPを検索し、UDPパケットを物理NIC経由で対象ノードに送信
- UDPパケットがポート8285で対象ノードのflanneldプロセスに到達し、復号化された後、flannel0インターフェースからcni0ブリッジへ転送され、最終的に対象Podコンテナへ
VXLANモードの動作原理
- 元のデータフレームがソースホストのPodコンテナからcni0ブリッジインターフェースへ送信され、flannel.1仮想インターフェースへ転送
- flannel.1インターフェースがデータフレームを受信後、VXLANヘッダーを追加し、カーネル内で元のデータフレームをUDPパケットにカプセル化
- flanneldプロセスがetcdで維持されているルーティングテーブルに基づきUDPパケットを物理NIC経由で対象ノードに送信
- UDPパケットがポート8472で対象ノードのflannel.1インターフェースに到達し、カーネル内で復号化された後、flannel.1インターフェースからcni0ブリッジへ転送され、最終的に対象Podコンテナへ
Calicoネットワーク
Calicoの基本概念
CalicoはトンネルやNATを使用せずに転送を実現し、ホストをインターネット上のルーターとして扱い、BGPでルートを同期し、iptablesを使用してセキュリティアクセスポリシーを実装します。
Calicoの主要コンポーネント
- Calico CNIプラグイン: Kubernetesとの連携を担当
- Felix: ホスト上のルーティングルールやFIB転送情報ベースの維持を担当
- BIRD: ルーティングルールの配信を担当(ルーターに類似)
- Confd: 設定管理コンポーネント
Calicoの動作原理
Calicoはルーティングテーブルを使用して各Podの通信を維持します。CalicoのCNIプラグインは各コンテナにveth pairデバイスを設定し、もう一方の端をホストのネットワーク名前空間に接続します。ブリッジがないため、CNIプラグインはホスト上で各コンテナのveth pairデバイスに受信用のルーティングルールを設定する必要があります。
IPIPモードとBGPモードの動作原理
IPIPモードの動作原理
- 元のデータパケットがソースホストのPodコンテナからtunl0インターフェースへ送信され、カーネルのIPIPドライバによってノードネットワークのIPパケットにカプセル化
- tunl0インターフェースのルートに従い、物理NIC経由で対象ノードに送信
- IPデータパケットが対象ノードに到達後、カーネルのIPIPドライバによって復号化され元のIPデータパケットを取得
- ローカルのルーティングルールに従い、veth pairデバイス経由で対象Podコンテナに送達
BGPモードの動作原理
- ソースホストのPodコンテナから送信された元のIPデータパケットがveth pairデバイス経由でノードネットワーク空間に送達
- 元のIPデータパケットの宛先IPとノードのルーティングルールに基づき対象ノードのIPを検索し、物理NIC経由で対象ノードに送信
- IPデータパケットが対象ノードに到達後、ローカルのルーティングルールに従いveth pairデバイス経由で対象Podコンテナに送達
FlannelとCalicoの比較
Flannel
- 動作モード: UDP、VXLAN、HOST-GW
- デフォルトネットワーク: 10.244.0.0/16
- 特徴: 通常VXLANモードを使用し、オーバーレイネットワーク、IPトンネル方式でデータを転送。設定が簡単で管理が容易ですが、複雑なネットワークポリシー設定能力はありません
Calico
- 動作モード: IPIP、BGP、混合モード(CrossSubnet)
- デフォルトネットワーク: 192.168.0.0/16
- 特徴:
- IPIPモード: サブネットを超えた転送が可能ですが、追加のカプセル化・復号化プロセスが必要
- BGPモード: 各ノードをルーターとして扱い、FelixとBIRDコンポーネントでルーティングルールを維持・配信。BGPプロトコルによる直接ルーティング転送を実現し、パフォーマンスが良いが同一サブネット内のみ使用可能
- 利点: cni0ブリッジを使用せず、ルーティングルールでデータパケットを直接宛先NICに送信するため高性能。豊富なネットワークポリシー設定管理能力を持つ
小規模でネットワーク要件がシンプルなK8SクラスターにはFlannelを、大規模でより多くのネットワークポリシー設定が必要な場合はCalicoを採用することをお勧めします。
バイナリによるデプロイ手順
1. etcdのデプロイ
cfsslツールを使用して証明書と秘密鍵を発行し、etcdソフトウェアパッケージを解凍してバイナリファイルを取得します。etcdクラスター設定ファイルを準備し、etcdサービスプロセスを起動してetcdクラスターに参加させます。
# etcdクラスターの健全性状態を確認
ETCDCTL_API=3 /opt/etcd/bin/etcdctl --endpoints="https://etcd01IP:2379,https://etcd02IP:2379,https://etcd03IP:2379" --cacert=CA証明書 --cert=クライアント証明書 --key=クライアント秘密鍵 endpoint health -wtable
# etcdクラスター状態情報を確認
ETCDCTL_API=3 /opt/etcd/bin/etcdctl --endpoints="https://etcd01IP:2379,https://etcd02IP:2379,https://etcd03IP:2379" --cacert=CA証明書 --cert=クライアント証明書 --key=クライアント秘密鍵 endpoint status -wtable
# etcdクラスターメンバーリストを確認
ETCDCTL_API=3 /opt/etcd/bin/etcdctl --endpoints="https://etcd01IP:2379" --cacert=CA証明書 --cert=クライアント証明書 --key=クライアント秘密鍵 member list -wtable
2. マスターコンポーネントのデプロイ
cfsslツールを使用して証明書と秘密鍵を発行し、K8Sサーバーソフトウェアパッケージを解凍してバイナリファイルを取得します。kube-apiserver起動時に呼び出されるbootstrap-token認証ファイルを準備し、各コンポーネントのサービスプロセス起動パラメータ設定ファイルを準備します。
# マスターコンポーネントの健全性状態を確認
kubectl get cs
3. ノードコンポーネントのデプロイ
kubeletとkube-proxyのkubeconfigクラスター誘導設定ファイルを準備し、サービスプロセス起動パラメータ設定ファイルを準備します。kubeletサービスプロセスを起動し、APIサーバーにCSRリクエストを送信して証明書を発行してもらいます。ipvsモジュールをロードし、kube-proxyサービスプロセスを起動します。
# ノードの状態を確認
kubectl get nodes
K8Sバイナリデプロイの実践
# クラスターノード構成例
k8sクラスターmaster01: 192.168.30.100(kube-apiserver、kube-controller-manager、kube-scheduler、etcd)
k8sクラスターmaster02: 192.168.30.105
k8sクラスターmaster03: 192.168.30.203
etcdクラスターnode1: 192.168.30.100
etcdクラスターnode2: 192.168.30.200
etcdクラスターnode3: 192.168.30.104
k8sクラスターnode01: 192.168.30.200(kubelet、kube-proxy、docker)
k8sクラスターnode02: 192.168.30.104
ロードバランサーnginx+keepalive01(master): 192.168.30.14
ロードバランサーnginx+keepalive02(backup): 192.168.30.15
シングルマスター構成
オペレーティングシステムの初期設定
全ノードでファイアウォール、SELinux、スワップを無効化し、ホストファイルを設定し、カーネルパラメータを調整します。
# ファイアウォールの無効化(全ノード)
systemctl stop firewalld
systemctl disable firewalld
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
# SELinuxの無効化(全ノード)
setenforce 0
sed -i 's/enforcing/disabled/' /etc/selinux/config
# スワップの無効化(全ノード)
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 全ノードにhostsを追加
cat >> /etc/hosts << EOF
192.168.80.10 master01
192.168.80.11 node01
192.168.80.12 node02
EOF
# カーネルパラメータの調整(全ノード)
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv6.conf.all.disable_ipv6=1
net.ipv4.ip_forward=1
EOF
sysctl --system
# 時刻同期(全ノード)
yum install ntpdate -y
ntpdate ntp.aliyun.com
etcdクラスターのデプロイ
master01ノードでCFSSL証明書生成ツールを準備し、Etcd証明書を生成します。etcdバイナリファイルを配置し、サービスを起動します。設定ファイルと証明書を他のetcdノードにコピーし、各ノードでサービスを起動します。
Dockerエンジンのデプロイ
全ノードでDockerエンジンをインストールし、設定ファイルをカスタマイズしてサービスを起動します。
# Dockerエンジンのインストール(全ノード)
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
# Docker設定ファイルのカスタマイズ
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://6na95ym4.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "500m",
"max-file": "3"
}
}
EOF
systemctl start docker.service
systemctl enable docker.service
マスターコンポーネントのデプロイ
master01ノードでK8Sコンポーネントの証明書を生成し、バイナリファイルを配置してサービスを起動します。kubectlのkubeconfigファイルを生成し、クラスターの状態を確認します。
ワーカーノードコンポーネントのデプロイ
全ノードでkubeletとkube-proxyを設定し、サービスを起動します。マスターノードでCSRリクエストを承認し、ノードの状態を確認します。
CNIネットワークコンポーネントのデプロイ
全ノードでCNIプラグインをインストールし、FlannelまたはCalicoをデプロイします。CoreDNSをデプロイしてDNS解決をテストします。
マルチマスター高可用性構成
追加マスターノードの設定
master02とmaster03ノードでオペレーティングシステムの初期設定を行い、master01ノードから証明書ファイルと設定ファイルをコピーします。各ノードのIPアドレスを設定ファイルに反映し、サービスを起動します。
ロードバランサーのデプロイ
lb01とlb02ノードでNginxとKeepalivedをインストールし、設定を行います。Nginxで4層リバースプロキシ負荷分散を設定し、Keepalivedで双機ホットスタンバイを実現します。
# Nginx設定例
stream {
upstream k8s-apiserver {
server 192.168.30.100:6443;
server 192.168.30.203:6443;
server 192.168.30.105:6443;
}
server {
listen 6443;
proxy_pass k8s-apiserver;
}
}
# Keepalived設定例
vrrp_script check_nginx {
script "/etc/nginx/check_nginx.sh"
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.80.100/24
}
track_script {
check_nginx
}
}
ノード設定の更新
全ノードでbootstrap.kubeconfig、kubelet.kubeconfig、kube-proxy.kubeconfigファイルを更新し、VIPを指すように設定します。kubeletとkube-proxyサービスを再起動します。
まとめ
etcdデータベース
- 分散キー値型データベース、サービスディスカバリシステム
- Go言語で開発、Raft一貫性アルゴリズムを使用
- クラスター展開時は3台以上の奇数台が必要
- 2379ポート:外部(クライアント)通信用
- 2380ポート:内部(クラスター内ノード間)通信用
マスターコンポーネントのインストール手順
- APIサーバーのインストール:
- コンポーネント関連の証明書と秘密鍵ファイルを準備
- bootstrap token認証ファイルを準備(kubelet起動時の証明書発行用)
- コンポーネントの起動設定ファイルを準備
- APIサーバーサービスを起動(ポート6443、HTTPS)
- コントローラーマネージャーとスケジューラーの起動:
- 起動設定ファイルを準備
- 証明書と秘密鍵ファイルを使用してkubeconfigファイルを生成
- サービスを起動
- クラスターコンポーネント状態の確認:
- kubeconfigファイルを準備し、kubectlをクラスターに追加
- kubectl get csで状態を確認
マルチマスター展開手順
- 他のマスターノード(master02など)を展開
- Nginx/Haproxy + Keepalived高可用性負荷分散を構築
- マスターノードクラスターを設定
- ノード上のkubeletとkube-proxyのkubeconfig設定ファイルをVIPに接続するよう更新
- kubectlの設定ファイルもVIPまたは現在のノードIPに接続するよう更新