What is Ciliumで説明されるように、CiliumはKubernetesクラスターやその他のクラウドネイティブ環境にネットワーキング、セキュリティ、可観測性を提供するオープンソースプロジェクトです。 Ciliumの基盤となっているのは、eBPFと呼ばれるLinuxカーネルの技術であり、セキュリティや可視性、ネットワーク制御ロジックをLinuxカーネルに動的に挿入することが可能です。 eBPFについてはeBPF.ioをご確認ください。
Ciliumは広義的にはCNIの1つとして挙げられます。
- CNIとは、Cloud Native Computing Foundationプロジェクトの1つになります
- CNIは、LinuxやWindowsコンテナーのネットワーク機能を抽象化し、APIインターフェイス仕様として切り出したものです
- コンテナのネットワーク接続性にのみ関与し、コンテナが削除されると割り当てられたリソースを削除します
- CNIの仕様など詳細については、こちらをご参照ください
Cilium以外にもCNIとして提供されているプラグインは数多くあります。 その中のいくつかをご紹介します。
- Flannel
- シンプルなセットアップで利用可能で、Kubernetesクラスター内でのネットワーク通信を容易にするために適しています
- VXLANやHost-GWモードを使用したオーバーレイネットワークにもサポートしてます
- 単一Kubernetesクラスターのシンプルなネットワーキングが必要なときや、シンプルな設定と高い拡張性が求められる場合に適しています
- Calico
- BGPを使用したルーティングでスケーラビリティが高いと言われています
- セキュリティポリシーやセグメンテーションの管理が可能です
- また、ポリシードリブンで柔軟な通信制御も可能です
- 大規模かつ複雑なネットワーク環境がある場合や、セキュリティポリシーを重視し、通信の制御が必要な場合に適しています
- Weave
- メッシュネットワークを提供し、コンテナの動的な発見が可能です
- オーバーレイネットワークをサポートしており、シンプルで軽量な設計です
- 動的なワークロードディスカバリが必要な場合や、シンプルで効率的なネットワーキングが求められる場合に適しています
Ciliumは下記の主要コンポーネントで構成されています。 詳細についてはComponent Overviewをご参照ください。
- Agent
- Kubernetesクラスターの各ノードで実行され、Kubernetes APIサーバーとの接続を確立し、ネットワークおよびセキュリティポリシーを維持する役割を果たします
- Linuxカーネルがコンテナのネットワークアクセスを制御するために使用するeBPFプログラムの管理を行います
- Operator
- Kubernetesクラスター全体に対して実行されるタスクの管理を行います
- 構成にもよりますが、一時的に利用できなくてもKubernetesクラスターは機能し続けます
- Client(CLI)
- Cilium Agentとともにインストールされるコマンドラインツールです
- 同じノード上で動作するCilium AgentのREST APIと対話を行うことができ、Agentの状態やステータスの検査ができます
- Ciliumのインストールや管理、トラブルシュートなどに使用されるCLIとは別物になります
- CNI Plugin
- PodがNode上でスケジュールまたは終了される時にKubernetesによって呼び出されます
- Cilium APIと対話し、ネットワーキング/ロードバランシング/ネットワークポリシーを提供するために必要な設定を起動します
chapter Cluster Createで導入したCiliumに対して、上記のコンポーネントを簡単に確認してみます。
最初にAgentはDaemonSetリソース、OperatorはDeploymentリソースとしてデプロイされていることを確認します。
kubectl get -n kube-system -l app.kubernetes.io/part-of=cilium ds,deploy
下記のような出力になるはずです。hubble-relayやhubble-uiに関してはchapter_hubbleにて説明します。
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/cilium 3 3 3 3 3 kubernetes.io/os=linux 113m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/cilium-operator 2/2 2 2 113m
deployment.apps/hubble-relay 1/1 1 1 113m
deployment.apps/hubble-ui 1/1 1 1 113m
次に、Cilium AgentにインストールされるClient CLIのバージョンを確認します。
kubectl exec -n kube-system ds/cilium -c cilium-agent -- cilium version
下記のようにバージョンが確認できます。
Client: 1.16.1 68579055 2024-08-13T13:29:59+00:00 go version go1.22.5 linux/amd64
Daemon: 1.16.1 68579055 2024-08-13T13:29:59+00:00 go version go1.22.5 linux/amd64
この章ではCiliumの機能として下記について説明します。
- Networking
- Network Policy
- ServiceMesh
- Ingress
- Gateway API
- Traffic Management
Networkingに関しては、Netowrk Policyを利用した特定のPodに対するL7のトラフィック制御を行います。 ServiceMeshに関しては、まず初めに、CiliumのIngressClassを設定したIngressリソースを利用するデモを行います。 次に、トラフィックを9:1に分割するデモをGateway APIとCiliumのEnvoy Configを利用した2パターン説明します。 今回はトラフィック分割のデモのみですが、他にもヘッダー変更、URLの書き換えなど行うことができます。 その他の例については下記のページをご参照ください。
- Kubernetes Gateway API: Getting started with Gateway API
- Cilium: L7-Aware Traffic Management/Examples
Note
Observabilityについてはchapter_hubbleにて説明します。
Ciliumでは3種類のリソースでNetwork Policyを定義できます。 詳細はNetwork Policyを参照してください。
- NetworkPolicy
- PodのIngress/Egressに対しL3/L4のポリシーを定義することが可能です
- 詳細はNetwork Policiesを参照してください
- CiliumNetworkPolicy
- NetworkPolicyリソースとよく似ていますが、NetworkPolicyと異なりL7のポリシーを定義することが可能です
- CiliumClusterwideNetworkPolicy
- クラスター全体のポリシーを設定するためのリソースです
- CiliumNetworkPolicyと同じ設定が可能ですが、CiliumNetworkPolicyと異なり名前空間の指定はありません
この節ではCiliumNetworkPolicy
の動作確認を行います。
動作確認はchapter_cluster-createでデプロイしたアプリケーションを利用します。 また、このアプリケーションに接続するためのクライアントを2種類デプロイします。
kubectl run curl-allow -n handson --image=curlimages/curl --labels="app=curl-allow" --command -- sleep infinity
kubectl run curl-deny -n handson --image=curlimages/curl --labels="app=curl-deny" --command -- sleep infinity
下記図のような構成になります。
現状は何も設定を行っていないので、curl-allow
/curl-deny
の両方から/
と/color
にアクセスできます。
また、HTTPステータスコードはすべて200が返ってきます。
kubectl exec -n handson curl-allow -- /bin/sh -c "echo -n 'curl-allow -> / : ';curl -s -o /dev/null handson:8080 -w '%{http_code}\n'"
kubectl exec -n handson curl-allow -- /bin/sh -c "echo -n 'curl-allow -> /color: ';curl -s -o /dev/null handson:8080/color -w '%{http_code}\n'"
kubectl exec -n handson curl-deny -- /bin/sh -c "echo -n 'curl-deny -> / : ';curl -s -o /dev/null handson:8080 -w '%{http_code}\n'"
kubectl exec -n handson curl-deny -- /bin/sh -c "echo -n 'curl-deny -> /color: ';curl -s -o /dev/null handson:8080/color -w '%{http_code}\n'"
下記のような実行結果になります。
curl-allow -> / : 200
curl-allow -> /color: 200
curl-deny -> / : 200
curl-deny -> /color: 200
動作確認として下記設定のCiliumNetworkPolicy
をデプロイしてみます。
/
へはcurl-allow
からのみアクセス可能/color
へはcurl-allow
とcurl-deny
の両方からアクセスが可能
kubectl apply -f manifest/cnp.yaml
CiliumNetworkPolicy
リソースをデプロイした後に先ほどと同じコマンドを打ってみてください。
kubectl exec -n handson curl-allow -- /bin/sh -c "echo -n 'curl-allow -> / : ';curl -s -o /dev/null handson:8080 -w '%{http_code}\n'"
kubectl exec -n handson curl-allow -- /bin/sh -c "echo -n 'curl-allow -> /color: ';curl -s -o /dev/null handson:8080/color -w '%{http_code}\n'"
kubectl exec -n handson curl-deny -- /bin/sh -c "echo -n 'curl-deny -> / : ';curl -s -o /dev/null handson:8080 -w '%{http_code}\n'"
kubectl exec -n handson curl-deny -- /bin/sh -c "echo -n 'curl-deny -> /color: ';curl -s -o /dev/null handson:8080/color -w '%{http_code}\n'"
すると、curl-denyから/
へのアクセスがHTTPステータスコード403でできなくなっています。
このように、Ciliumでは、CiliumNetworkPolicy
を利用することで、L7のトラフィック制御が可能です。
curl-allow -> / : 200
curl-allow -> /color: 200
curl-deny -> / : 403
curl-deny -> /color: 200
Note
L3/L4のポリシーとL7のポリシーでルール違反の際の挙動が変わります。 L3/L4のポリシーに違反した場合は、パケットがDropされますが、L7のポリシー違反の場合は、HTTP 403 Access Deniedが返されます。 上記の例ではパスベースの制御が行われており、L7ポリシーのルール違反になるため、HTTP 403 Access Deniedとなります。
次節へ行く前に、作成したCiliumNetworkPolicyリソースを削除しておきます。
kubectl delete -f manifest/cnp.yaml
CiliumはIngressリソースをサポートしており、第1章でIngress NGINX Controllerをデプロイしましたが、Ingress NGINX Controllerを使わずとも、Cilium単体でIngressリソースを利用できます。
Ingressリソースを利用するためには、CiliumのHelm ChartでingressController.enabled: true
を指定する必要があります。
この設定はすでにchapter_cluster-createで行っており、現時点でIngressリソースは利用できる状態になっています。
詳細についてはKubernetes Ingress Supportを参照ください。
この節では、IngressClassとしてCiliumを利用したトラフィックルーティングのデモを行います。
Ingressリソースを利用するためには、ingressClassName
フィールドにcilium
を設定したIngressをアプライすればIngressリソースを利用できます。
kubectl apply -f manifest/ingress.yaml
app.cilium.example.com
の名前解決が可能な端末から、curlコマンドでHTTPステータスコード200が返ってくることを確認します。
curl -I app.cilium.example.com:8080
下記のような応答が返ってきます。
HTTP/1.1 200 OK
accept-ranges: bytes
content-length: 1395
content-type: text/html; charset=utf-8
last-modified: Tue, 22 Jun 2021 05:40:33 GMT
date: Wed, 01 Nov 2023 18:08:01 GMT
x-envoy-upstream-service-time: 0
server: envoy
CiliumはGateway APIをサポートしており、Gateway APIを利用することで、トラフィックの分割、ヘッダー変更、URLの書き換えなどのより高度なルーティング機能を利用することが可能です。 この節ではGateway APIを利用したトラフックの分割を行います。 Gateway APIの詳細はKubernetes Gateway APIを参照してください。
まず、デモのために第1章でデプロイしたblue
イメージに加えて、yellow
イメージをデプロイします。
また、yellowイメージとblueイメージのそれぞれにアクセスするためのServiceリソースを作成します。
kubectl apply -Rf ../chapter_cluster-create/manifest/app -n handson -l color=yellow
kubectl apply -f manifest/service.yaml
次に、トラフィック分割機能を利用して下記のように9:1にトラフィックを分割してみます。
トラフィックを分割するためにGatewayリソースとHTTPRouteリソースをデプロイします。
kubectl apply -n handson -f manifest/gateway_api.yaml
上記をデプロイすると、GatewayリソースとHTTPRouteリソース、そしてGatewayリソースに紐付くServiceリソースのType:Loadbalancer
が作成されます。
kubectl get gateway,httproute,svc -n handson
NAME CLASS ADDRESS PROGRAMMED AGE
gateway.gateway.networking.k8s.io/color-gw cilium True 52s
NAME HOSTNAMES AGE
httproute.gateway.networking.k8s.io/color-route-1 52s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/cilium-gateway-color-gw LoadBalancer 10.96.50.28 <pending> 80:32720/TCP 52s
service/handson ClusterIP 10.96.131.226 <none> 8080/TCP 24m
service/handson-blue ClusterIP 10.96.164.242 <none> 8080/TCP 113s
service/handson-yellow ClusterIP 10.96.189.95 <none> 8080/TCP 113s
ここで、Type:Loadbalancer
のEXTERNAL-IPが<pending>
表示になっていることが分かります。
ServiceリソースのType:Loadbalancer
とは、awsやGoogle Cloudなどのクラウドプロバイダーで利用できる外部のロードバランサーを利用するためのリソースになります。
そのため、別途ロードバランサーが必要になるのですが、今回のハンズオン環境では用意していないので、<pending>
表示のまま固まっています。
クラウドプロバイダーで利用できる外部のロードバランサーと説明しましたが、オンプレミスやローカルの開発環境でもType:Loadbalancer
を利用することは可能です。
やり方はいろいろありますが、有名なものとしてはMetalLBを利用する方法があげられます。
今回はせっかくCiliumについて学んでいるので、Cilium v1.14からサポートが始まったL2 Announcementを利用してみましょう。
Note
L2 Announcementの詳細についてはここで解説しませんが、より深く知りたい方は 公式ドキュメント: L2 AnnouncementやCilium L2 Announcement を使ってみるを参照してください。
Warning
ハンズオン作成時点で、L2 Announcementはβ機能なので本番利用には注意が必要です。
L2 Announcementを利用するためには、現行の設定に加えて、追加でCiliumL2AnnouncementPolicy
とCiliumLoadBalancerIPPool
を設定する必要があります。
下記コマンドでリソースを適用しましょう。
kubectl apply -f manifest/l2announcement.yaml
再度ServiceリソースのType:Loadbalancer
を確認すると、EXTERNAL-IPが振られていることが分かります。
docker network kindのIP帯を設定しているため、dockerを起動しているホストからのみアクセスすることが可能です。
kubectl get svc -n handson
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cilium-gateway-color-gw LoadBalancer 10.96.36.91 172.18.0.200 80:30183/TCP 12m
handson ClusterIP 10.96.238.128 <none> 8080/TCP 24m
handson-blue ClusterIP 10.96.244.167 <none> 8080/TCP 23m
handson-yellow ClusterIP 10.96.80.215 <none> 8080/TCP 23m
Warning
manifest/l2announcement.yamlでデプロイしたCiliumLoadBalancerIPPool
リソースのspec.blocks
に設定する値は、docker kindネットワークのアドレス帯から選択する必要があります。
今回は既に設定済みのため意識する必要はありせんが、別環境でL2 Announcementを利用するときには注意してください。
ServiceリソースのType:Loadbalancer
のIPアドレスを取得します。
LB_IP=$(kubectl get -n handson svc -l io.cilium.gateway/owning-gateway=color-gw -o=jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')
取得したIPアドレス宛に10回ほどアクセスし、おおよそ9:1に分散していることを確認します。
for in in {1..10}; do \
echo -n "Color is "
curl ${LB_IP}/color;echo
sleep 0.1
done
次節へ行く前に、作成したGatewayリソースとHTTPRouteリソースを削除しておきます。
kubectl delete -f manifest/gateway_api.yaml
Note
今回のようなルーティング機能はCilium Service Meshの機能を利用しても提供することができます。 次節でCilium Service Meshを利用したトラフィック分割のデモを説明します。
Ciliumでは、Network Policyで定義されたL7トラフィックなどの処理にEnvoyを利用します。
デフォルトでEnvoyはCiliumのAgentに埋め込まれていますが、Deploymentリソースとして外だしすることも可能です。
cilium status
コマンドを実行することで、現在どちらのモードで動作しているか確認することが可能です。
cilium status
Envoy DaemonSetがdisabledであれば、Cilium AgentにEnvoyが埋め込まれて動作しています。
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Envoy DaemonSet: OK
\__/¯¯\__/ Hubble Relay: OK
\__/ ClusterMesh: disabled
Deployment cilium-operator Desired: 2, Ready: 2/2, Available: 2/2
DaemonSet cilium-envoy Desired: 3, Ready: 3/3, Available: 3/3
Deployment hubble-relay Desired: 1, Ready: 1/1, Available: 1/1
Deployment hubble-ui Desired: 1, Ready: 1/1, Available: 1/1
DaemonSet cilium Desired: 3, Ready: 3/3, Available: 3/3
Containers: cilium-operator Running: 2
cilium-envoy Running: 3
hubble-ui Running: 1
hubble-relay Running: 1
cilium Running: 3
Cluster Pods: 21/21 managed by Cilium
Helm chart version:
Image versions hubble-relay quay.io/cilium/hubble-relay:v1.16.1@sha256:2e1b4c739a676ae187d4c2bfc45c3e865bda2567cc0320a90cb666657fcfcc35: 1
cilium quay.io/cilium/cilium:v1.16.1@sha256:0b4a3ab41a4760d86b7fc945b8783747ba27f29dac30dd434d94f2c9e3679f39: 3
cilium-operator quay.io/cilium/operator-generic:v1.16.1@sha256:3bc7e7a43bc4a4d8989cb7936c5d96675dd2d02c306adf925ce0a7c35aa27dc4: 2
cilium-envoy quay.io/cilium/cilium-envoy:v1.29.7-39a2a56bbd5b3a591f69dbca51d3e30ef97e0e51@sha256:bd5ff8c66716080028f414ec1cb4f7dc66f40d2fb5a009fff187f4a9b90b566b: 3
hubble-ui quay.io/cilium/hubble-ui:v0.13.1@sha256:e2e9313eb7caf64b0061d9da0efbdad59c6c461f6ca1752768942bfeda0796c6: 1
hubble-ui quay.io/cilium/hubble-ui-backend:v0.13.1@sha256:0e0eed917653441fded4e7cdb096b7be6a3bddded5a2dd10812a27b1fc6ed95b: 1
Envoyの設定は、CRDとして定義されたCiliumEnvoyConfig
とCiliumCllusterwideEnvoyConfig
を利用することで、L7トラフィック制御が可能です。
詳細はL7-Aware Traffic Managementを参照してください。
EnvoyのSupported API versionsにも記載がありますが、Envoy APIにはv1/v2/v3の3種類が存在します。 このうちCiliumでは、Envoy API v3のみをサポートしています。 なお、Envoy Extension Resource Typeへの対応状況に関してはEnvoy extensions configuration fileを確認してください。
この節では、envoy.filters.http.router
を利用したトラフィックシフトを行います。
handson-blue"
に10%、handson-yellow
に90%のトラフィックを流すように設定します。
kubectl apply -f manifest/cec.yaml
下記コマンドを実行すると、handson-blue"
に10%、handson-yellow
に90%のトラフィックが流れることが確認できます。
for in in {1..10}; do \
kubectl exec -n handson curl-allow -- /bin/sh -c "echo -n 'curl-allow: Color is ';curl -s handson:8080/color -w '\n'"
sleep 0.1
done
確認が終わったら本章でデプロイしたリソースを削除しておきます。
kubectl delete -f manifest/cec.yaml
kubectl delete -Rf ../chapter_cluster-create/manifest/app -n handson -l color=yellow
kubectl delete -f manifest/service.yaml
kubectl delete -n handson pod curl-allow --force
kubectl delete -n handson pod curl-deny --force