おうちKubernetesで構築するCilium Gateway
今回のポストではCilium Gatewayをセットアップします。
おうちラボでのKubernetesクラスタ上にセットアップするのですが、LANからクラスタ内で動いているサービスにアクセスできるようGatewayのIPアドレスはCilium L2Announcementで広報し、クラスタ外のホストからもサービスへアクセスできるようにします。
今回はplain httpだけセットアップするのですが、別のポストでcert-managerもセットアップしてhttpsアクセスを構築するものも用意しています。よければご覧ください。
次のポスト:Cilium Gatewayと連動するcert-managerの導入でTLS証明書自動化
前提
- fluxcdとGitLabでGitOpsがセットアップ済み
- 次の5つのflux kustomizationsがセットアップ済み
-
./clusters/lab-hlv3
as flux-system created during bootstrap process -
./infrastructure/lab-hlv3/controllers
as infra-controllers -
./infrastructure/lab-hlv3/configs
as infra-configs -
./apps/lab-hlv3
as apps -
./sops/lab-hlv3
as sops # 前回の記事, "SOPSを用いたGitOpsレポジトリ上のsecretの暗号化"で構築
-
"lab-hlv3"と名付けている試験用のクラスタで構築と記事作成をしています。またドメイン名は"lab.blink-1x52.net"としています。
手順
- "testbed" namespaceの準備
- traefik/whoamiのdeploymentとserviceを作成
- Cilium Gatewayを使うための要件を確認
- Gateway API CRDsをインストール
- Gateway専用のnamespaceを用意
- Gateway作成
- IP pool作成
- L2Announcement作成
- 出来上がったものの確認
Namespaceの準備
先のポストで作成済みのnamespaceですが、こちらを用意します。
# ./clusters/lab-hlv3/namespaces/testbed.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: testbed
httpアクセス確認用のwhoamiサービスの用意
https://github.com/traefik/whoami
Tiny Go webserver that prints OS information and HTTP request to output.
こちらをdeploymentとして用意し、アクセスするためのserviceも作成します。
以下は最小限の内容のファイルですが、基本的にtraefik/whoamiコンテナを立ち上げ、ポート80で通信を受け、whoamiコンテナのポート80へ通信を流すserviceを用意するというものです。
# ./apps/base/testbed/whoami.yaml
---
apiVersion: v1
kind: Service
metadata:
name: whoami
namespace: testbed
spec:
ports:
- name: http
targetPort: 80
port: 80
selector:
app: whoami
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
namespace: testbed
labels:
app: whoami
spec:
replicas: 1
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
hostname: whoami
containers:
- name: whoami
image: traefik/whoami:v1.10.3
imagePullPolicy: IfNotPresent
Apps flux kustomizationでは上のファイルが入っているディレクトリを指しています。
# ./apps/lab-hlv3/kustomization.yaml
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
# testbed
- ../base/testbed
そしてそのtestbedディレクトリのkustomizationで、先のwhoami.yamlを含めています。
# ./apps/base/testbed/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- tools-deployment.yaml
- whoami.yaml
ここまでで出来上がったもの
出来上がったものは次の通りです。
$ flux tree ks apps
Kustomization/flux-system/apps
├── Service/testbed/whoami
├── Deployment/testbed/tools
├── Deployment/testbed/whoami
$ kubectl get svc whoami -n testbed
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
whoami ClusterIP 10.96.133.198 <none> 80/TCP 5d5h
Kubernetesクラスタ上でのサービスへのアクセス
クラスタのメンバーノードからは、サービスにアクセスすることが可能です。この時点では、クラスタ外からはアクセスできません。
# check the cluster IP of the service whoami
$ kubectl get svc -n testbed
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
whoami ClusterIP 10.96.133.198 <none> 80/TCP 5d4h
# access the service
$ curl 10.96.133.198
Hostname: whoami
IP: 127.0.0.1
IP: ::1
IP: 10.0.3.170
IP: fe80::e834:eff:fe1f:44f3
RemoteAddr: 10.0.3.163:55572
GET / HTTP/1.1
Host: 10.96.133.198
User-Agent: curl/7.76.1
Accept: */*
Cilium Gatewayの要件
https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/#prerequisites
- NodePort有効、あるいはkube-proxy replacement構成
- L7プロキシ有効
- Kubernetes Gateway API v1.2.0 CRDsのインストール
- (optional) experimental TLSRoute CRDのインストール
Gateway APIのCRDsのインストールだけ未対応ですので次に実施します。その他はKubernetesクラスタ構築時およびCiliumインストール時に対応しており、以前のポストより確認できます。今回の構成は、Kube-proxyはインストールせず、Cilium (envoy)に代わりに活躍してもらっている構成です。
Gateway API CRDs
これらはKubernetesクラスタ構築時、デフォルトではインストールされていないものです。ファイルをダウンロードし、GitOpsレポジトリ内、infra-controllers flux kustomization配下に置きます。
infra-controllers kustomizationのファイルはこのような内容です。
# ./infrastructure/lab-hlv3/controllers/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cm-placeholder.yaml
### crds
# gateway api
# version 1.2.0
- crds/gateway-api/standard/standard-install-v1.2.0.yaml
- crds/gateway-api/experimental/gateway.networking.k8s.io_tlsroutes-v1.2.0.yaml
Gateway API CRDsのファイルはダウンロードし、次のように配置しました。
./infrastructure/lab-hlv3/controllers/crds/gateway-api/standard/standard-install-v1.2.0.yaml
./infrastructure/lab-hlv3/controllers/crds/gateway-api/experimental/gateway.networking.k8s.io_tlsroutes-v1.2.0.yaml
CRDsインストール結果
kubectl get crds
やkubectl api-resources
などのコマンドでインストールが確認できます。
$ kubectl api-resources | grep gateway
gatewayclasses gc gateway.networking.k8s.io/v1 false GatewayClass
gateways gtw gateway.networking.k8s.io/v1 true Gateway
grpcroutes gateway.networking.k8s.io/v1 true GRPCRoute
httproutes gateway.networking.k8s.io/v1 true HTTPRoute
referencegrants refgrant gateway.networking.k8s.io/v1beta1 true ReferenceGrant
tlsroutes gateway.networking.k8s.io/v1alpha2 true TLSRoute
Cilium helmチャートのvaluesファイル
Cilium v1.17.1のインストール時のオプションですが、以下のリストがvaluesファイル上での変更点です。
以前のポストではexample.netドメインで記載していたのですが、今後cert-managerなどもやる関係でドメイン名を変更しています。
- k8sServiceHost: lab-kube-endpoint.lab.blink-1x52.net
- k8sServicePort: "8443"
- k8sClientRateLimit.qps: 33
- k8sClientRateLimit.burst: 50
- kubeProxyReplacement: "true"
- kubeProxyReplacementHealthzBindAddr: "0.0.0.0:10256"
- l2announcements.enabled: true
- l2announcements.leaseDuration: 3s
- l2announcements.leaseRenewDeadline: 1s
- l2announcements.leaseRetryPeriod: 200ms
- externalIPs.enabled: true
- gatewayAPI.enabled: true
- etcd.enabled: true
- etcd.ssl: true
- etcd.endpoints: ["https://192.0.2.5:2379", "https://192.0.2.6:2379", "https://192.0.2.7:2379"] # dummy ipaddr here
- hubble.ui.enabled: true
- hubble.relay.enabled: true
- hubble.peerService.clusterDomain: lab.blink-1x52.net
Cilium Gateway用のnamespace
Cilium gatewayを動かすに際し、専用のnamespaceを用意することにしました。
# ./clusters/lab-hlv3/namespaces/gateway.yaml
---
kind: Namespace
apiVersion: v1
metadata:
name: gateway
labels:
service: gateway
type: infrastructure
Gateway作成
ではCiliumのgatewayを作成します。
以下のgatewayは"cilium"というGatewayClassを使うよう記載してあります。これはCiliumインストール時に自動的に作られるGatewayClassで、kubectl describe gc
で内容を確認できます。他には、ダミーIPアドレスとして192.0.2.83を使うこと、またホスト名"whoami-kube.lab.blink-1x52.net"用のplain httpのリスナーを用意し、このリスナーを利用できるのは"gateway: cilium"というラベルがセットされているnamespaceからのみという条件を付けてあります。
# ./infrastructure/lab-hlv3/configs/cilium/gateway.yaml
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: cilium-gateway
namespace: gateway
spec:
gatewayClassName: cilium
addresses:
- type: IPAddress
value: 192.0.2.83
listeners:
- name: whoami-kube-http
hostname: whoami-kube.lab.blink-1x52.net
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway: cilium
では"testbed" namespaceの方も更新し、ラベルをセットします。
# ./clusters/lab-hlv3/namespaces/testbed.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: testbed
labels:
service: testbed
type: app
gateway: cilium
Cilium Gateway用のIP PoolおよびL2Announcement
Gatewayが作られると、gatewayおよびserviceが出来ていることが確認できると思います。kubectl get gtw -n gateway
やkubectl get svc -n gateway
といったコマンドで確認できます。
次に、クラスタ作成時のポストでHubble UIへのアクセスを用意したのと同じように、gatewayもLAN上、クラスタ外からアクセスできるようにします。
- GatewayのserviceにIPアドレスを振るためのIP poolの作成
- GatewayのserviceのIPアドレスをL2AnnouncementでLANへ広報
ダミーIPアドレスを使っていますがこちらがIP poolです。serviceSelector
としては、"gateway" namespace上のサービス何にでも、という条件にしてあります。
---
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
name: "ippool-gateway"
spec:
blocks:
- start: "192.0.2.83"
stop: "192.0.2.83"
serviceSelector:
matchLabels:
"io.kubernetes.service.namespace": "gateway"
次にL2Announcementです。また上とは異なるserviceSelector
をセットしてしまっていますが、これはkubectl get svc -n gateway -o yaml
などで確認できる、作成されたcilium gatewayのserviceにセットされているラベルを持ってきています。またinterfaces
に関しては、labではなくメインで動かしているクラスタがVM, baremetal, OSディストロあれこれ混在しているので、どのノードでもマッチするよう対象リストを増やしており、それをそのまま今回も使っている形です。
---
apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
name: l2-cilium-gateway
spec:
serviceSelector:
matchLabels:
io.cilium.gateway/owning-gateway: cilium-gateway
gateway.networking.k8s.io/gateway-name: cilium-gateway
interfaces:
- ^eth[0-9]+
- ^eno[0-9]+
- ^enp[0-9]s[0-9]+
loadBalancerIPs: true
infra-configs kustomization
更新後のinfra-configs flux kustomizationのファイルの中身は次の通りです。
# ./infrastructure/lab-hlv3/configs/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cm-placeholder.yaml
# cilium gateway
- cilium/gateway.yaml
- cilium/ippools-cilium-gateway.yaml
- cilium/l2announcement-cilium-gateway.yaml
GatewayにIPアドレスがセットされた状態
ダミーIPアドレスでの出力ですが、変更後のgateway (およびsvc)は以下の通りです。LAN上のホストでARP情報を確認すると(例えばWindowsでarp -a
など実行すると)、EXTERNAL-IPが認識されていることが確認できると思います。
$ kubectl get svc,gtw -n gateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/cilium-gateway-cilium-gateway LoadBalancer 10.96.87.48 192.0.2.83 80:31710/TCP,443:30231/TCP 5d5h
NAME CLASS ADDRESS PROGRAMMED AGE
gateway.gateway.networking.k8s.io/cilium-gateway cilium 192.0.2.83 True 5d18h
whomaiサービスアクセス用のHTTPRouteの作成
Gatewayもwhoamiサービスも出来ていますので、次はこの二つを繋ぐためのHTTPRouteを作成します。
既存のwhomai.yamlファイルに追加で着たらよかったのですが、一つのGitOpsレポジトリで複数のクラスタを管理しており、あるクラスタではGateway APIがインストールされていないということがあるので、HTTPRouteは個別のファイルで以下の通り用意しました。
- parentRefsは"gateway" namespace上の"cilium-gateway"の"whoami-kube-http"リスナーを指定している
- backendRefsは"whoami"サービスのポート80を指定している
# ./apps/lab-hlv3/httproutes/whoami-http.yaml
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: whoami-http
namespace: testbed
spec:
parentRefs:
- name: cilium-gateway
sectionName: whoami-kube-http
namespace: gateway
hostnames:
- "whoami-kube.lab.blink-1x52.net"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: whoami
port: 80
Flux apps kustomizationファイルはこのようになりました。
# ./apps/lab-hlv3/kustomization.yaml
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
# testbed
- ../base/testbed
# http routes
- httproutes/whoami-http.yaml
Cilium Gatewayを通じてwhoamiサービスへアクセス
出来上がりです!
$ curl http://whoami-kube.lab.blink-1x52.net
Hostname: whoami
IP: 127.0.0.1
IP: ::1
IP: 10.0.3.170
IP: fe80::e834:eff:fe1f:44f3
RemoteAddr: 10.0.3.174:39409
GET / HTTP/1.1
Host: whoami-kube.lab.blink-1x52.net
User-Agent: curl/8.5.0
Accept: */*
X-Envoy-Internal: true
X-Forwarded-For: IP_ADDR_OF_HOST_EXECUTING_CURL
X-Forwarded-Proto: http
X-Request-Id: 96f39cec-ce39-4c26-97d3-216dae13b9d0
このセットアップが完成すれば、あとはcilium-gatewayのリスナー追加とHTTPRouteの作成で新たなウェブアクセスが簡単に用意できます。なお今回のセットアップでは"gateway: cilium"というラベルの有無でgateway利用可否がnamespace単位でコントロールできます。別のnamespace上に作ったあのサービスを新たにアクセスできるようにしよう、といった時にはラベルの更新もお忘れなく!
Discussion