Kubernetes の CNI として Calico を利用する場合、Ansible や Helm のテンプレートを経由して設定を生成する方法があります。しかし、Calico の設定の多くは Kubernetes API 上の Custom Resource として表現できます。設定内容がそれほど多くない環境では、さらにテンプレートエンジンを重ねるよりも、Calico の Custom Resource を通常の Kubernetes Manifest として管理した方が構成を読みやすくなります。
この記事では、Dual Stack、BGP 有効、IP-in-IP なし、VXLAN なし、Pod 通信の NAT なし、LoadBalancer 用 IPPool の NAT なし、Node-to-Node Mesh なし、外部 BGP Peer への経路広告、Calico LoadBalancer IPAM の利用を前提に、Calico の基本的な Manifest を整理します。狙いは、Kubernetes のネットワークを Overlay や NAT に隠さず、外部ネットワーク側で Prefix を扱う routed network として設計することです。
ここで重要なのは、Manifest を単なる設定ファイルとして扱わないことです。`encapsulation: None`、`natOutgoing: Disabled`、`nodeToNodeMeshEnabled: false` のような値は、個別のパラメーターではなく、トンネルを使わず、NAT せず、BGP topology を明示的に設計するという判断の表現です。
Manifest は役割ごとに分ける
Calico の構成を Kubernetes Manifest として管理する場合でも、一つの巨大な YAML にまとめる必要はありません。役割ごとにファイルを分けると、どの Resource がどの設計判断を表しているのかをレビューしやすくなります。
calico/
├── config/
│ ├── 10-installation.yaml
│ ├── 20-apiserver.yaml
│ ├── 30-kube-controllers.yaml
│ ├── 40-loadbalancer-pools.yaml
│ ├── 50-bgp-peers.yaml
│ └── 60-bgp-configuration.yaml
├── patches/
│ └── control-plane-label.patch.yaml
└── examples/
└── 70-service-loadbalancer.yaml| ファイル | 主な役割 |
|---|---|
| 10-installation.yaml | Calico Network の基本方針、Pod CIDR、dataplane、encapsulation、NAT の定義 |
| 20-apiserver.yaml | Calico API Server の有効化 |
| 30-kube-controllers.yaml | LoadBalancer IPAM の割り当て条件 |
| 40-loadbalancer-pools.yaml | LoadBalancer Service 用 IPPool |
| 50-bgp-peers.yaml | 外部ルーターまたは Route Reflector との BGP Peer |
| 60-bgp-configuration.yaml | クラスタ全体の BGP 設定、Service CIDR、LoadBalancer CIDR の広告 |
ファイルを分ける目的は、管理を細かくすることではありません。Installation、IPPool、BGPPeer、BGPConfiguration の責務を分け、レビュー時に設計意図を追いやすくするためです。
Installation で routed network の前提を明示する
まず Calico Operator が管理する `Installation` を定義します。ここでは BGP を有効にし、Linux dataplane には nftables を指定し、Pod 用の IPv4 / IPv6 IPPool では encapsulation と NAT を無効化します。
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
registry: quay.io/
calicoNetwork:
bgp: Enabled
linuxDataplane: Nftables
ipPools:
- cidr: <POD_CIDR_IPV4>
blockSize: <POD_BLOCK_SIZE_IPV4>
encapsulation: None
natOutgoing: Disabled
nodeSelector: all()
- cidr: <POD_CIDR_IPV6>
blockSize: <POD_BLOCK_SIZE_IPV6>
encapsulation: None
natOutgoing: Disabled
nodeSelector: all()この構成では、Pod Network に対して IP-in-IP も VXLAN も使わず、Pod 通信の NAT も行いません。Pod CIDR の到達性は、Calico BGP と外部ネットワークのルーティングによって確保します。既存環境を eBPF dataplane から nftables dataplane へ変更する場合には、単純な Manifest 適用とは別に移行手順が必要です。この記事は既存 eBPF 環境からの切替手順ではなく、Manifest として表現する構成要素の整理です。
Calico API Server を使う
Calico Resource を Kubernetes API と統合した形で扱う場合は、Calico API Server を有効化します。これにより、Calico の Custom Resource を Kubernetes 側の管理対象として扱いやすくなります。
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
name: default
spec: {}LoadBalancer IPAM は明示要求に限定する
Calico LoadBalancer IPAM を使用する場合、`KubeControllersConfiguration` で LoadBalancer Controller の割り当て方針を指定します。ここでは `assignIPs: RequestedServicesOnly` とし、すべての `type: LoadBalancer` Service へ自動で Calico の IP を割り当てない構成にします。
apiVersion: projectcalico.org/v3
kind: KubeControllersConfiguration
metadata:
name: default
spec:
controllers:
loadBalancer:
assignIPs: RequestedServicesOnlyこの設定は、複数の LoadBalancer 実装を併用する環境で特に重要です。Calico が扱う Service と、別の LoadBalancer Controller が扱う Service を分けたい場合、明示的に Calico を要求した Service だけを対象にした方が運用上の衝突を避けやすくなります。
LoadBalancer 用 IPPool でも NAT とトンネルを使わない
LoadBalancer Service に割り当てるアドレス範囲は、Pod 用 IPPool とは別に定義します。ここでも `ipipMode: Never`、`vxlanMode: Never`、`natOutgoing: false` を明示し、LoadBalancer 用アドレスについても NAT や Overlay に依存しない設計にします。
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: loadbalancer-ipv4
spec:
cidr: <LOADBALANCER_CIDR_IPV4>
blockSize: <LOADBALANCER_BLOCK_SIZE_IPV4>
ipipMode: Never
vxlanMode: Never
natOutgoing: false
nodeSelector: all()
assignmentMode: Automatic
allowedUses:
- LoadBalancer
---
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: loadbalancer-ipv6
spec:
cidr: <LOADBALANCER_CIDR_IPV6>
blockSize: <LOADBALANCER_BLOCK_SIZE_IPV6>
ipipMode: Never
vxlanMode: Never
natOutgoing: false
nodeSelector: all()
assignmentMode: Automatic
allowedUses:
- LoadBalancer`allowedUses` を `LoadBalancer` に限定することで、この Pool を Pod IP 用ではなく LoadBalancer IP 用として扱います。Pod 用 Prefix と Service 公開用 Prefix を分けると、外部ルーター側の経路制御、Prefix filter、障害時の切り分けも設計しやすくなります。
外部ルーターとの BGP Peer を Resource として定義する
Calico Node が経路を交換する外部ルーターや Route Reflector は、`BGPPeer` として定義します。IPv4 と IPv6 の Peer を分けて Resource 化しておくと、経路交換の対象や障害調査時の確認点を明確にできます。
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
name: upstream-router-ipv4
spec:
peerIP: <BGP_PEER_IPV4>
asNumber: <BGP_PEER_AS>
---
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
name: upstream-router-ipv6
spec:
peerIP: <BGP_PEER_IPV6>
asNumber: <BGP_PEER_AS>複数のルーターと Peer を張る場合は、Resource を追加します。ここで重要なのは、Peer の数を増やすこと自体ではなく、Calico Node、外部ルーター、Route Reflector、AS 設計の関係を明確にすることです。
BGPConfiguration で Mesh と広告 Prefix を定義する
クラスタ全体の BGP 設定は `BGPConfiguration` に定義します。ここでは Node-to-Node Mesh を無効化し、クラスタの AS 番号、Service CIDR、LoadBalancer CIDR の広告をまとめて表現します。
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
name: default
spec:
nodeToNodeMeshEnabled: false
asNumber: <CALICO_LOCAL_AS>
serviceClusterIPs:
- cidr: <SERVICE_CIDR_IPV4>
- cidr: <SERVICE_CIDR_IPV6>
serviceLoadBalancerAggregation: Enabled
serviceLoadBalancerIPs:
- cidr: <LOADBALANCER_CIDR_IPV4>
- cidr: <LOADBALANCER_CIDR_IPV6>`nodeToNodeMeshEnabled: false` は、Calico Node 同士で自動的な full-mesh BGP Session を構成しないという意味です。外部ルーターや Route Reflector を中心に BGP topology を設計する場合に使えます。ただし、Mesh を無効化しただけで Node 間到達性が保証されるわけではありません。
特に iBGP を使う場合、通常の iBGP Speaker は、ある iBGP Peer から学習した経路を別の iBGP Peer へそのまま再広告しません。全 Peer が同一 AS で Node-to-Node Mesh を無効化するなら、Route Reflector、eBGP、または適切な BGP topology のいずれかが成立しているかを確認する必要があります。
Service CIDR と LoadBalancer CIDR を広告する
`serviceClusterIPs` を設定すると、Kubernetes Service CIDR を Calico BGP から広告できます。これにより、クラスタ外部のルーターが Service CIDR への経路を学習できる構成を作れます。ただし、Service CIDR を広告することと、どの Service を外部から到達可能にするかは別の設計です。Service 種別、NetworkPolicy、Firewall、外部ルーターの経路制御を合わせて考える必要があります。
LoadBalancer Service のアドレスについては、`serviceLoadBalancerAggregation: Enabled` と `serviceLoadBalancerIPs` を設定します。Calico LoadBalancer IPAM で割り当てたアドレス範囲を、BGP によって外部へ広告するためです。構成としては、クライアントから外部ルーターまたは Fabric を経由し、Calico Node、LoadBalancer Service、Pod へ到達する流れになります。
| Prefix | 広告の目的 | 注意点 |
|---|---|---|
| Pod CIDR | Pod 間通信や外部から Pod Network への到達性を確保する | Underlay 側で Pod CIDR を正しくルーティングできる必要がある |
| Service CIDR | ClusterIP を外部ネットワークから到達可能にする構成を作る | 全 Service を公開する設計ではないため、制御面を別途設計する |
| LoadBalancer CIDR | LoadBalancer Service 用 IP を外部へ広告する | Calico IPAM、Service 定義、外部経路制御の整合が必要になる |
Service 側で Calico の利用を明示する
Calico LoadBalancer IPAM を利用する Service では、Calico による割り当てを明示します。固定 IP を指定するか、Pool から自動割り当てするかは、Calico のバージョン、運用方式、アドレス管理方針に合わせて決めます。
apiVersion: v1
kind: Service
metadata:
name: example
namespace: default
annotations:
projectcalico.org/loadBalancerIPs: '["<LOADBALANCER_IP>"]'
spec:
type: LoadBalancer
loadBalancerClass: calico
selector:
app: example
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP`assignIPs: RequestedServicesOnly` と組み合わせる場合、Service 側で Calico の利用を明示することが重要です。LoadBalancer 実装を複数持つ環境では、この明示がないと、どの Controller がどの Service を扱うべきかが曖昧になります。
Control Plane Node は label と taint を分けて見る
Control Plane Node に Workload を配置しない構成では、Node label や taint と Calico の設定を合わせて管理する必要があります。たとえば Node label は通常の Kubernetes patch として管理できます。
apiVersion: v1
kind: Node
metadata:
name: <CONTROL_PLANE_NODE>
labels:
node-role.kubernetes.io/control-plane: ただし、Node の scheduler 制御には label だけでなく taint も関係します。label は役割や選択条件を表し、taint は Pod を配置させない制約として働きます。実際のクラスタポリシーに合わせて、どの Node が経路広告だけを担うのか、どの Node に Workload を載せるのかを分けて考える必要があります。
さらに、外部 LoadBalancer の対象 Node から外すかどうかは、scheduler の label や taint とは別に確認する必要があります。Kubernetes には node.kubernetes.io/exclude-from-external-load-balancers という well-known label があり、この label を付けた Node は、外部 LoadBalancer が利用する backend servers の一覧から除外できます。
kubectl label nodes <node-name> node.kubernetes.io/exclude-from-external-load-balancers=trueControl Plane Node を Workload 配置対象から外すだけなら taint が主な制御点になります。しかし、LoadBalancer Service の経路や backend としてその Node を扱うかどうかは別問題です。Calico LoadBalancer IPAM や BGP 広告を設計する場合、Control Plane Node が経路広告、Service 到達性、外部 LoadBalancer の backend のどこに関与するのかを分けて整理する必要があります。
適用前に server dry-run で検証する
Manifest を直接管理する場合でも、いきなり変更する必要はありません。Kubernetes API Server による検証を先に実施し、Resource とフィールドが受け付けられるかを確認します。
kubectl --context "$CTX" apply \
--server-side \
--dry-run=server \
-f calico/config/問題がなければ実際に適用します。ここでも、Manifest の適用に成功したことと、BGP Session が確立し、外部ルーターの RIB / FIB に経路が入っていることは別の確認項目です。
kubectl --context "$CTX" apply -f calico/config/Resource と経路交換を分けて確認する
適用後は、Kubernetes Resource と実際の BGP 状態を分けて確認します。Kubernetes API 上の Resource が作成されていることは必要条件ですが、それだけで外部ネットワークとの経路交換が成立したとは言えません。
kubectl --context "$CTX" get installation,apiserver -A
kubectl --context "$CTX" get ippool
kubectl --context "$CTX" get bgpconfiguration
kubectl --context "$CTX" get bgppeer
kubectl --context "$CTX" get kubecontrollersconfiguration| 確認対象 | 確認内容 |
|---|---|
| Calico Resource | Installation、IPPool、BGPPeer、BGPConfiguration が意図した値で存在するか |
| BGP Session | Calico Node と Peer Router の Session が Established か |
| 広告 Prefix | Pod CIDR、Service CIDR、LoadBalancer CIDR が意図どおり広告されているか |
| Router RIB / FIB | 外部ルーターが経路を学習し、転送経路として使えるか |
| 疎通 | Pod、Service、LoadBalancer IP への通信が IPv4 / IPv6 で成立するか |
Calico 側の Resource が正常でも、外部ルーターの Prefix filter、AS 設計、Route Reflector、ECMP、Firewall、MTU、Failure detection、Route convergence が合っていなければ、実際の到達性は成立しません。Manifest の検証とネットワークの検証は、必ず別の確認項目として扱うべきです。
この構成で設計意図を Manifest に残す
今回の構成では、Kubernetes Network をできるだけ通常の routed network として扱います。IP-in-IP は使わず、VXLAN も使わず、Pod NAT と LoadBalancer NAT も使いません。Dual Stack の Pod / Service / LoadBalancer Prefix を Calico BGP で外部ルーターや Fabric へ広告し、Underlay 側で通常の L3 Route として扱います。
| 項目 | 方針 |
|---|---|
| IP-in-IP | 使用しない |
| VXLAN | 使用しない |
| Pod NAT | 使用しない |
| LoadBalancer NAT | 使用しない |
| BGP | 使用する |
| Dual Stack | IPv4 / IPv6 の両方を設計対象にする |
この設計では、Calico の Manifest だけで完結するわけではありません。BGP AS、Route Reflector、ECMP、Prefix filter、IPv4 / IPv6 reachability、MTU、Firewall、Failure detection、Route convergence も合わせて設計する必要があります。だからこそ、Manifest には実装値だけでなく、どのネットワーク設計を採用しているのかが読み取れる形で残す意味があります。
まとめ
Calico の設定は Kubernetes Custom Resource として表現できるため、必ずしも Ansible やテンプレートエンジンを利用する必要はありません。比較的小規模で設定内容が明確な構成であれば、Git で Calico Manifest を管理し、server dry-run で検証し、`kubectl apply` で反映する単純な管理方法でも十分に成立します。
特に `encapsulation: None`、`natOutgoing: Disabled`、`ipipMode: Never`、`vxlanMode: Never`、`nodeToNodeMeshEnabled: false` のような値を Manifest に明示しておけば、トンネルを使用しない、NAT を使用しない、BGP routing を利用するという設計意図を Manifest から読み取れます。
ただし、Manifest が正しいことと、ネットワーク全体が正しいことは同じではありません。Calico の Resource、BGP Session、外部ルーターの経路、Firewall、MTU、障害時の収束まで確認して初めて、routed network としての Kubernetes が成立します。Manifest を単なる設定ファイルではなく、ネットワーク設計結果の明示的な表現として管理することが、この方法の大きな利点です。
参考書籍
書籍
Kubernetes 完全ガイド 第 2 版
Kubernetes のリソース、ネットワーク、Service、運用設計を体系的に確認する際の参考書籍です。価格や在庫はリンク先で確認してください。
Amazon で見るこのリンクは Amazon アソシエイトリンクです。
参考資料
- Calico: Configure BGP peering
- Calico: IPPool resource
- Calico: BGPPeer resource
- Calico: BGPConfiguration resource
- Calico: Use Calico LoadBalancer IPAM
- Calico: Installation API
- Kubernetes: Declarative Management of Kubernetes Objects Using Configuration Files
- Kubernetes: node.kubernetes.io/exclude-from-external-load-balancers


