0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kong GatewayをKubernetes上でHybridモードで構築する(cert-manager使用)

Last updated at Posted at 2024-11-13

Kong Gatewayにはデプロイ方法が2種類用意されており、ControlPlane(CP)とDataPlane(DP)を分離せず一緒くたにデプロイするTraditionalモードと、ControlPlaneとDataPlaneを別々に展開するHybridモードがある。
冗長構成などを取りたい場合はHybridモードが推奨されており、Kubernetesで利用する場合は同一のHelmリポジトリを利用してvalues.yamlでモードを指定して別々のリリースとしてデプロイしてあげる必要がある。

このHybridモードをHelmで試そうとした時、かなりハマったので手順を残しておく。

なお、デプロイに使うHelmのvalues.yamlは以下にサンプルが大量にあるので、以下を参考にするのもオススメとなる。
https://github.com/Kong/charts/tree/main/charts/kong/example-values

今回はhybrid-cert-managerをベースにvalues.yamlを作成した。

前提

以下の環境で検証を行った。

  • EKS
  • cert-managerは導入済み

また、Kong GatewayのデプロイはDBありのHybridモードで行い、証明書は自己署名証明書を使い、管理はcert-managerに任せる。
Kong GatewayへのアクセスはKong Ingress Controller(KIC)経由で行いたいため、Gatewayデプロイ時にあわせてKICもデプロイする。
証明書についてはsharedモードで配布し、クラスタ用に作成した証明書を別のコンポーネントでも使い回すようにする。
なお、HybridモードだとDBが必須となる。
DBがないとCP起動時にin-memory storage can not be used when roleというエラーになるので注意。

構築手順

事前準備

最初にkongという名前のNamespaceを作成する。

kubectl create namespace kong

次に各コンポーネントで利用する証明書を発行するためのcert-managerのリソースを作成する。

cat <<EOF > ./cert.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-selfsigned-ca
  namespace: kong
spec:
  isCA: true
  commonName: my-selfsigned-ca
  secretName: root-secret
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
    group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: my-ca-issuer
  namespace: kong
spec:
  ca:
    secretName: root-secret
EOF
kubectl apply -f ./cert.yaml

自分がハマった点として、kind: ClusterIssuerだけで済まそうとやったらDataPlaneのデプロイ時に以下のようなエラーが出てデプロイに失敗した点がある。

2024/11/12 23:57:00 [error] 1336#0: *153 [lua] data_plane.lua:158: communicate(): [clustering] connection to control plane wss://kong-cp-kong-cluster.kong.svc.cluster.local:8005/v1/outlet?node_id=f40db4df-7de3-4e6c-9465-f9c202ad5ef8&node_hostname=kong-dp-kong-db6b76cfc-hpsjx&node_version=3.7.1 broken: ssl handshake failed: 18: self-signed certificate (retrying after 10 seconds) [kong-cp-kong-cluster.kong.svc.cluster.local:8005], context: ngx.timer

どうもCA証明書が必須のようで、kind: CertificateisCA: trueがないとこれが出る模様。
cert-managerの設定を変更する場合は上記の点には気をつけた方がいい。

次にControlPlaneとDataPlaneを作成していくが、その前準備として環境変数を設定する。

# ControlPlaneのHelmのリリース名
CP_RELEASE_NAME=kong-aws-cp
# DataPlaneのHelmのリリース名
DP_RELEASE_NAME=kong-aws-dp
# Ingressでアクセスする際のドメイン
DOMAIN=eks.hogehoge.info

ControlPlaneのデプロイ

ControlPlaneのvalues.yamlを作成する。

cat <<EOF > ./cp.yaml
image:
  repository: kong/kong-gateway
env:
  role: control_plane
  cluster_telemetry_listen: 0.0.0.0:8006
  database: "postgres"
  pg_database: kong
  pg_host: ${CP_RELEASE_NAME}-postgresql.kong.svc
  pg_user: kong
certificates:
  enabled: true
  issuer: "my-ca-issuer"
  cluster:
    enabled: true
    commonName: "$DOMAIN"
    dnsNames:
    - "*.$DOMAIN"
ingressController:
  enabled: true
  env:
    kong_admin_filter_tag: ingress_controller_default
    kong_admin_tls_skip_verify: true
    kong_admin_url: https://localhost:8444
    kong_workspace: default
    publish_service: kong/${DP_RELEASE_NAME}-kong-proxy
  ingressClass: kong
  installCRDs: false
postgresql:
  enabled: true
  auth:
    database: kong
    username: kong
migrations:
  enabled: true
  postUpgrade: true
  preUpgrade: true
manager:
  enabled: true
  type: ClusterIP
  annotations:
    konghq.com/protocol: https
  ingress:
    enabled: true
    ingressClassName: kong
    tls: ${CP_RELEASE_NAME}-kong-cluster-cert
    hostname: kong.$DOMAIN
admin:
  annotations:
    konghq.com/protocol: https
  enabled: true
  type: ClusterIP
  ingress:
    annotations:
      konghq.com/https-redirect-status-code: "301"
      konghq.com/protocols: https
      konghq.com/strip-path: "true"
    enabled: true
    ingressClassName: kong
    tls: ${CP_RELEASE_NAME}-kong-cluster-cert
    hostname: kong.$DOMAIN
    path: /api
enterprise:
  enabled: true
cluster:
  enabled: true
  tls:
    enabled: true
    servicePort: 8005
    containerPort: 8005
clustertelemetry:
  enabled: true
  tls:
    enabled: true
    servicePort: 8006
    containerPort: 8006
proxy:
  enabled: false
portal:
  enabled: false
portalapi:
  enabled: false
status:
  enabled: true
  http:
    enabled: true
    containerPort: 8100
EOF

設定内容について、各ブロックを解説する。

image:
  repository: kong/kong-gateway

上記はkong/kong-gatewayイメージを使うことでOSS版ではなくEnterprise版のイメージを使うことを明示している。

env:
  role: control_plane
  cluster_telemetry_listen: 0.0.0.0:8006
  database: "postgres"
  pg_database: kong
  pg_host: ${CP_RELEASE_NAME}-postgresql.kong.svc
  pg_user: kong

上記はKongのパラメータを指定する。
rolecontrol_planeを指定することでHybridモード、かつデプロイするKongはControlPlaneとして動作することを指示している。
またdatabase: "postgres"でDBありモードでデプロイすることを指示している。

certificates:
  enabled: true
  issuer: "my-ca-issuer"
  cluster:
    enabled: true
    commonName: "$DOMAIN"
    dnsNames:
    - "*.$DOMAIN"

上記は証明書をcert-managerに管理させる場合に指定する項目となる。
issuerにcert-managerのIssuerを指定し、cluster.enabledでクラスタに対する証明書を発行している。
ここはcluster以外にもadminmanagerなどの各コンポーネントごとに証明書の設定を書くことが出来るが、sharedモードで動かす場合は証明書は1つで良いのでclusterのみ指定している。

ingressController:
  enabled: true
  env:
    kong_admin_filter_tag: ingress_controller_default
    kong_admin_tls_skip_verify: true
    kong_admin_url: https://localhost:8444
    kong_workspace: default
    publish_service: kong/${DP_RELEASE_NAME}
  ingressClass: kong
  installCRDs: false

上記はKICをあわせてデプロイするかどうかの設定であり、今回はありでデプロイしている。
ポイントとしてはpublish_service: kong/${DP_RELEASE_NAME}で、どのDPのプロキシを介してKICを利用するかを設定する箇所であり、ここにDPのProxyのServiceを指定する。
今回のデプロイ順序はCP→DPであり、CPのデプロイ直後はDPがデプロイされておらず、Ingressはこのpublish_serviceのServiceが見つからず機能しない。
DPをデプロイした後に初めてIngressは使えるようになる。

installCRDs: falseについては人によってはtrueにした方がいいかもしれない。
(自分の環境は既に入っていたようで、trueにするとエラーが出る)

postgresql:
  enabled: true
  auth:
    database: kong
    username: kong
migrations:
  enabled: true
  postUpgrade: true
  preUpgrade: true

上記はPostgresをあわせてデプロイして初期化する設定となる。
Postgresを別で用意する場合はfalseで問題ない。

manager:
  enabled: true
  type: ClusterIP
  annotations:
    konghq.com/protocol: https
  ingress:
    enabled: true
    ingressClassName: kong
    tls: ${CP_RELEASE_NAME}-kong-cluster-cert
    hostname: kong.$DOMAIN

上記はKong Managerのデプロイ設定となる。
ポイントとしてはIngressで使う証明書をtls: ${CP_RELEASE_NAME}-kong-cluster-certと指定しており、これはクラスタ向けにcert-managaerが払い出す証明書を流用している。

admin:
  annotations:
    konghq.com/protocol: https
  enabled: true
  type: ClusterIP
  ingress:
    annotations:
      konghq.com/https-redirect-status-code: "301"
      konghq.com/protocols: https
      konghq.com/strip-path: "true"
    enabled: true
    ingressClassName: kong
    tls: ${CP_RELEASE_NAME}-kong-cluster-cert
    hostname: kong.$DOMAIN
    path: /api

上記はAdminAPIのデプロイ設定となる。
こちらもKong Managerと同様に証明書を流用している。
AdminAPIについては注意点がいくつかある。
まず、KongManagerアクセス時、AdminAPIを呼び出す関係でドメインが異なるとクロスオリジン的なものになり、自己証明書だとAdminAPIへのアクセスに失敗してWorkspacesの表示が"Data cannot be displayed due to an error."となって表示できない。
そのため、ここではドメインをManagerと統一している。
(設定次第で回避できるっぽいけど、ここでは割愛)
また、ドメインを統一した都合上、パスでアクセス先を変える必要があり、path: /apiを指定し、更に使い勝手を同じようにするためにKICのAnnotationにkonghq.com/strip-path: "true"を追加してAdminAPIアクセス時にAdminAPI側に/apiが渡らないようにしている。

enterprise:
  enabled: true

上記はEnterprise版の機能を利用する際に有効化する。
使わない場合はfalseでも問題ない。

cluster:
  enabled: true
  tls:
    enabled: true
    servicePort: 8005
    containerPort: 8005
clustertelemetry:
  enabled: true
  tls:
    enabled: true
    servicePort: 8006
    containerPort: 8006

上記はHybridモード固有で、このCPに繋ぐためのエンドポイント公開のために必要な設定となる。
clustertelemetryは無効化しても問題ない。

proxy:
  enabled: false

ProxyはDP側で有効化するため明示的にfalseにする。

portal:
  enabled: false
portalapi:
  enabled: false
status:
  enabled: true
  http:
    enabled: true
    containerPort: 8100

その他、不要そうなものは明示的にfalseにした。
statusについてはReadiness/Liveness Proveで利用しており、これを無効化するとPodが1/2のままで止まってしまうので有効化している。
(サンプルを見ているとなくても1/2にならないようなので、設定次第では不要かもしれない)

ControlPlaneをデプロイする。

helm upgrade -i $CP_RELEASE_NAME kong/kong -f ./cp.yaml -n kong --wait

DataPlaneのデプロイ

DataPlaneのvalues.yamlを作成する。

cat <<EOF > ./dp.yaml
image:
  repository: kong/kong-gateway
env:
  role: data_plane
  database: "off"
  cluster_control_plane: ${CP_RELEASE_NAME}-kong-cluster.kong.svc:8005
  cluster_telemetry_endpoint: ${CP_RELEASE_NAME}-kong-clustertelemetry.kong.svc.cluster.local:8006
cluster:
  enabled: true
  tls:
    enabled: true

certificates:
  enabled: true
  issuer: "my-ca-issuer"
  cluster:
    enabled: true
    commonName: "$DOMAIN"
    dnsNames:
    - "*.$DOMAIN"
proxy:
  enabled: true
  http:
    enabled: true
  ingress:
    enabled: false
  tls:
    enabled: true
  type: LoadBalancer
ingressController:
  enabled: false
postgresql:
  enabled: false
migrations:
  enabled: false
manager:
  enabled: false
admin:
  enabled: false
EOF

こちらでも各ブロックを解説する。

env:
  role: data_plane
  database: "off"
  cluster_control_plane: ${CP_RELEASE_NAME}-kong-cluster.kong.svc:8005
  cluster_telemetry_endpoint: ${CP_RELEASE_NAME}-kong-clustertelemetry.kong.svc.cluster.local:8006

HybridモードでDataPlaneをデプロイする場合はroledata_planeを指定する。
またcluster_control_planeは必須で、cluster_telemetry_endpointはなくても動きそうだがエラーが出るので先程のControlPlaneのServiceを宛先として指定する。

cluster:
  enabled: true
  tls:
    enabled: true

certificates:
  enabled: true
  issuer: "my-ca-issuer"
  cluster:
    enabled: true
    commonName: "eks.$DOMAIN"
    dnsNames:
    - "*.$DOMAIN"

ControlPlaneと同じように証明書を作成する。

proxy:
  enabled: true
  http:
    enabled: true
  ingress:
    enabled: false
  tls:
    enabled: true
  type: LoadBalancer

Proxyの設定になるが、ここではhttp,https両方でアクセスできるようにし、かつtype: LoadBalancerでProxyを外部に公開する。
KICはこの公開されたアドレスを使ってIngress処理を行う。

こちらもhelmコマンドで以下のようにデプロイする。

helm upgrade -i kong-aws-dp kong/kong -f ./dp.yaml -n kong

動作確認

DPのデプロイ後、必要に応じてtype: LoadBalancerで公開されたアドレスをDNS登録する。
変更が浸透したらアクセスしてみる。

curl kong.$DOMAIN/api -L -k

問題なければAdminAPIが出力したJSONが表示されるはずだ。

Kong Managerにもアクセスしてみる。
image.png

問題なく表示された。
なお、最初からServiceなどが複数あるのはKICが入っていて、勝手にGatewayに追加してくれてるからである。

ということで、ドキュメントだけでvalues.yamlを書くのは大変なので、Hybridモードで構築しようとする人の助けになれば幸いである。

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?