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?

IBM Cloud Kubernetes ServiceのIngress ControllerをNGINXからTraefikへ移行するための基本的な検証

0
Last updated at Posted at 2026-11-04

はじめに

IBM Cloud Kubernetes Service(IKS)では、managed Ingress ControllerとしてIngress-NGINX(コミュニティ版のNGINXをベースとしたもの)が利用されてきましたが、コミュニティによるIngress-NGINXの終了を受け、後継のmanaged Ingress ControllerとしてTraefikが2026年7月にGAとなりました。

既存のIKSクラスターではIngress-NGINXを利用している環境もあります。IBM-managed Ingress-NGINXは2027年1月末にEnd of Lifeを迎える予定であるため、それまでにTraefikへの移行を計画・実施する必要があります。

そこで本記事では、

既存のIngress-NGINXをTraefikへ移行する場合、Ingressの設定をどこまでそのまま利用でき、どこから変更が必要になるのか

という点を意識して実際のIKS環境で移行の検証を行いました。実際のアプリはPublic, Private両方に公開できますが、この記事ではPublicのみに絞って説明しています。Privateについても同様の考え方で移行の計画・実施を行うことができます。

今回は以下を確認しました。

  • 基本的なHost / Path routing
  • 複数Path
  • TLS / HTTPS
  • HTTP → HTTPS redirect
  • NGINX固有のRewrite
  • ClassicとVPCでの移行方法の違い

実際に試して確認できたこととして、

NGINX固有Annotationを使用していなくても、Ingress Controllerのデフォルト動作が異なる場合がある
ClassicクラスターとVPCクラスターではアプリケーション公開の方式が異なり、その点はこの移行でも継承される

という点です。

長い記事ですが、急いで移行を検討する必要がある方は最初に11章〜13章の内容を確認いただき、その後に最初から読んでいただくと何をすべきか理解いただけるかと思います。


1. 検証の前提

本記事ではIKSクラスター自体の作成手順は扱いません。

すでにIKSクラスターが存在し、

ibmcloud ks cluster config --cluster <cluster-name>

で接続できる状態を前提とします。

また、開始時点で有効になっているIngress ControllerはIngress-NGINXでもTraefikでも構いません。

まずIngressClassを確認します。

kubectl get ingressclass

Ingress-NGINXのみの場合、例えば次のようになります。既存のクラスターの多くはこの構成となっているはずです。

NAME                   CONTROLLER
public-iks-k8s-nginx   cloud.ibm.com/public-iks-k8s-nginx

Traefikのみの場合、例えば次のようになります。

NAME                 CONTROLLER
public-iks-traefik   traefik.io/ingress-controller

Ingress-NGINXとTraefikの両方が存在する場合は次のようになります。
このケースは誰かが意図的に両方が存在する構成を作っている可能性が高いので同じクラスターを使っているメンバーで同じような作業をされている方がいらっしゃるかもしれないのでご注意ください。

NAME                   CONTROLLER
public-iks-k8s-nginx   cloud.ibm.com/public-iks-k8s-nginx
public-iks-traefik     traefik.io/ingress-controller

2. 利用可能なIngress Controllerを確認する

利用可能なALBバージョンを確認します。

ibmcloud ks ingress alb versions

今回の検証時点では以下を確認しました。

Kubernetes Ingress バージョン
1.15.10_381939429_iks

Traefik Ingress versions
3.7.13_382110373_iks
3.7.14_382121212_iks
3.7.15_382127968_iks
3.7.16_382127996_iks

本検証では、それぞれのdefaultとなっていた以下のバージョンを使用しました。

Ingress-NGINX : 1.15.10_381939429_iks
Traefik       : 3.7.14_382121212_iks

3. もう一方のIngress Controllerを追加する

移行元と移行先のControllerを同じクラスターに用意しておくと、比較検証が容易になります。

Classicの場合

ClassicではZoneごとにALBを作成できます。

Ingress-NGINXを追加する例です。

ibmcloud ks ingress alb create classic \
  --cluster <cluster-name> \
  --type public \
  --vlan <public-vlan-id> \
  --zone <zone> \
  --version 1.15.10_381939429_iks

Multi-Zoneクラスターでは各Zoneについて作成します。

作成後に確認します。

ibmcloud ks ingress alb ls \
  --cluster <cluster-name>

今回の検証ではtok02, tok05の2zone構成で作成しました。


VPCの場合

VPCでもZoneごとにALBを追加できます。

ibmcloud ks ingress alb create vpc-gen2 \
  --cluster <cluster-name> \
  --type public \
  --zone <zone> \
  --version 1.15.10_381939429_iks

今回の環境では、jp-tok-1、jp-tok-3の2zone構成としました。

確認します。

kubectl get ingressclass
NAME                   CONTROLLER
public-iks-k8s-nginx   cloud.ibm.com/public-iks-k8s-nginx
public-iks-traefik     traefik.io/ingress-controller

4. ClassicとVPCでは外部公開方式が違う

Classic

Classicでは各Public ALBが個別のIPアドレスを持ちます。

そのため、NGINX / TraefikそれぞれのALBへ直接アクセスして比較できます。

VPC

VPCではNGINXとTraefikが同じIKS-managed VPC Load Balancerを使用します。

現在のbackendは次のコマンドで確認できます。

$ ibmcloud ks ingress load-balancer get --cluster <cluster-name>
OK

Load Balancer backend

Public backend    ingress-nginx
Private backend   -

NGINXへ切り替える

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend ingress-nginx
OK

Traefikへ切り替える

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend traefik
OK

VPCでは、IngressClassとVPC Public Load Balancer backendの両方を移行対象として考える必要があります。


5. Level 1: シンプルなIngressを移行する

最初はController固有Annotationを持たないIngressです。

5.1 共通バックエンドを作成する

app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ingress-test
  template:
    metadata:
      labels:
        app: ingress-test
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: ingress-test
spec:
  selector:
    app: ingress-test
  ports:
    - name: http
      port: 80
      targetPort: 80

app.yamlとして保存し、適用します。

$ kubectl apply -f app.yaml
deployment.apps/ingress-test created
service/ingress-test created

$ kubectl get pod -l app=ingress-test
NAME                           READY   STATUS    RESTARTS
ingress-test-xxxxxxxxxx-xxxxx   1/1     Running   0

$ kubectl get svc ingress-test
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
ingress-test   ClusterIP   172.21.x.x     <none>        80/TCP

5.2 NGINX用Ingressを作成する

ingress-test.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-test
spec:
  ingressClassName: public-iks-k8s-nginx
  rules:
    - host: test.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: ingress-test
                port:
                  number: 80
$ kubectl apply -f ingress-test.yaml
ingress.networking.k8s.io/ingress-test created

$ kubectl get ingress ingress-test
NAME           CLASS                  HOSTS              PORTS
ingress-test   public-iks-k8s-nginx   test.example.com   80

ClassicではNGINX ALBのIPへHostヘッダーを指定します。

$ curl -i \
    -H 'Host: test.example.com' \
    http://<NGINX-ALB-IP>/
HTTP/1.1 200 OK
content-type: text/html

VPCで外部公開する場合は、先にPublic Load Balancer backendをIngress-NGINXへ切り替えます。

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend ingress-nginx
OK

$ ibmcloud ks ingress load-balancer get \
    --cluster <cluster-name>
OK

Load Balancer backend

Public backend    ingress-nginx
Private backend   -

5.3 移行前の状態を保存する

$ kubectl get ingress ingress-test -o yaml > ingress-before.yaml

5.4 IngressClassをTraefikへ変更する

Controller固有設定がないため、IngressClassのみ変更します。

$ kubectl patch ingress ingress-test \
    --type=merge \
    -p '{"spec":{"ingressClassName":"public-iks-traefik"}}'
ingress.networking.k8s.io/ingress-test patched

$ kubectl get ingress ingress-test
NAME           CLASS                HOSTS              PORTS
ingress-test   public-iks-traefik   test.example.com   80

VPCではPublic Load Balancer backendもTraefikへ変更します。

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend traefik
OK

5.5 切替完了を確認する

VPCでは設定値だけでなく、LoadBalancer ServiceのselectorとEndpointSliceを確認します。

$ ibmcloud ks ingress load-balancer get \
    --cluster <cluster-name>
OK

Load Balancer backend

Public backend    traefik
Private backend   -

Public Ingress Service名を確認します。

$ kubectl get svc -n kube-system -l app.kubernetes.io/part-of=managed-ingress

確認したService名を指定します。

$ kubectl get svc <public-ingress-service> \
    -n kube-system \
    -o jsonpath='{.spec.selector}'; echo
{"app.kubernetes.io/vpcComponent":"<cluster-component>-traefik"}

$ kubectl get endpointslice \
    -n kube-system \
    -l kubernetes.io/service-name=<public-ingress-service> \
    -o wide

EndpointSliceがTraefik Podを指してから、同じHostとPathで疎通確認します。

Classicの場合:

$ curl -i \
    -H 'Host: test.example.com' \
    http://<TRAEFIK-ALB-IP>/

VPCで443のみ公開されている場合は、後述のTLS構成で確認します。

5.6 移行後の差分を確認する

$ kubectl get ingress ingress-test -o yaml > ingress-after.yaml

$ diff -u ingress-before.yaml ingress-after.yaml

本質的な差分はIngressClassのみです。

 spec:
-  ingressClassName: public-iks-k8s-nginx
+  ingressClassName: public-iks-traefik

6. Level 2: 複数Pathを移行する

複数Pathでも、Controller固有設定を使わないPrefix routingを検証します。

6.1 検証用バックエンドを作成する

multipath-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app1
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
        - name: app1
          image: hashicorp/http-echo:1.0
          args:
            - "-text=Hello from APP1"
          ports:
            - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: app1-service
spec:
  selector:
    app: app1
  ports:
    - port: 80
      targetPort: 5678
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app2
  template:
    metadata:
      labels:
        app: app2
    spec:
      containers:
        - name: app2
          image: hashicorp/http-echo:1.0
          args:
            - "-text=Hello from APP2"
          ports:
            - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: app2-service
spec:
  selector:
    app: app2
  ports:
    - port: 80
      targetPort: 5678

利用可能なコンテナイメージに社内制約がある場合は、承認済みの標準イメージへ置き換えてください。今回のRewrite検証では公式nginx:alpineのみを使用しています。

$ kubectl apply -f multipath-app.yaml

$ kubectl get pod -l app=app1
$ kubectl get pod -l app=app2
$ kubectl get svc app1-service app2-service

6.2 NGINX用Ingressを作成する

multipath-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multipath-test
spec:
  ingressClassName: public-iks-k8s-nginx
  rules:
    - host: multipath-test.example.com
      http:
        paths:
          - path: /app1
            pathType: Prefix
            backend:
              service:
                name: app1-service
                port:
                  number: 80
          - path: /app2
            pathType: Prefix
            backend:
              service:
                name: app2-service
                port:
                  number: 80
$ kubectl apply -f multipath-ingress.yaml

$ kubectl get ingress multipath-test

6.3 NGINXでBaselineを取得する

$ curl -H 'Host: multipath-test.example.com' \
    http://<NGINX-ALB-IP>/app1
Hello from APP1

$ curl -H 'Host: multipath-test.example.com' \
    http://<NGINX-ALB-IP>/app2
Hello from APP2
$ kubectl get ingress multipath-test -o yaml > multipath-before.yaml

6.4 Traefikへ移行する

$ kubectl patch ingress multipath-test \
    --type=merge \
    -p '{"spec":{"ingressClassName":"public-iks-traefik"}}'
ingress.networking.k8s.io/multipath-test patched

VPCの場合はPublic Load Balancer backendも切り替えます。

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend traefik
OK

実際のdiffにはgenerationやresourceVersionなど、Kubernetesリソースの更新に伴う管理情報の変更も含まれます。

それらを除いた本質的な設定差分は、次のIngressClassのみです。

 spec:
-  ingressClassName: public-iks-k8s-nginx
+  ingressClassName: public-iks-traefik

以下の設定には変更を加えていません。

rules:
  - host: multipath-test.example.com
    http:
      paths:
        - path: /app1
          pathType: Prefix
          backend:
            service:
              name: app1-service
              port:
                number: 80

        - path: /app2
          pathType: Prefix
          backend:
            service:
              name: app2-service
              port:
                number: 80

したがって今回検証した、Kubernetes標準のPrefixを利用した複数Path構成では、

- ingressClassName: public-iks-k8s-nginx
+ ingressClassName: public-iks-traefik

のみの変更で、NGINXとTraefikのどちらでも同じPath routingが動作することを確認できました。


7. Level 2: TLS / HTTPSを移行する

7.1 検証用証明書を作成する

$ openssl req -x509 -nodes \
    -days 365 \
    -newkey rsa:2048 \
    -keyout tls.key \
    -out tls.crt \
    -subj "/CN=tls-test.example.com" \
    -addext "subjectAltName=DNS:tls-test.example.com"
$ openssl x509 -in tls.crt \
    -noout \
    -subject \
    -issuer \
    -ext subjectAltName
subject=CN=tls-test.example.com
issuer=CN=tls-test.example.com
X509v3 Subject Alternative Name:
    DNS:tls-test.example.com

7.2 TLS SecretとNGINX用Ingressを作成する

$ kubectl create secret tls tls-test-secret \
    --cert=tls.crt \
    --key=tls.key
secret/tls-test-secret created
tls-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-test
spec:
  ingressClassName: public-iks-k8s-nginx
  tls:
    - hosts:
        - tls-test.example.com
      secretName: tls-test-secret
  rules:
    - host: tls-test.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: ingress-test
                port:
                  number: 80
$ kubectl apply -f tls-ingress.yaml

$ kubectl get ingress tls-test

7.3 NGINXでBaselineを取得する

ClassicではNGINX ALB IPを指定します。

$ curl -ik \
    --resolve tls-test.example.com:443:<NGINX-ALB-IP> \
    https://tls-test.example.com/

VPCではPublic backendをIngress-NGINXへ変更し、VPC Load BalancerのPublic IPを指定します。

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend ingress-nginx
OK

$ curl -ik \
    --resolve tls-test.example.com:443:<VPC-LB-PUBLIC-IP> \
    https://tls-test.example.com/

期待結果:

HTTP/2 200
content-type: text/html

証明書も確認します。

$ openssl s_client \
    -connect <ALB-IP>:443 \
    -servername tls-test.example.com \
    </dev/null 2>/dev/null \
  | openssl x509 \
      -noout \
      -subject \
      -issuer \
      -ext subjectAltName
subject=CN=tls-test.example.com
issuer=CN=tls-test.example.com
X509v3 Subject Alternative Name:
    DNS:tls-test.example.com
$ kubectl get ingress tls-test -o yaml > tls-before.yaml

7.4 Traefikへ移行する

$ kubectl patch ingress tls-test \
    --type=merge \
    -p '{"spec":{"ingressClassName":"public-iks-traefik"}}'
ingress.networking.k8s.io/tls-test patched

VPCの場合:

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend traefik
OK

VPCではEndpointSliceがTraefik Podへ切り替わるまで確認します。

$ kubectl get endpointslice \
    -n kube-system \
    -l kubernetes.io/service-name=<public-ingress-service> \
    -o wide

7.5 Traefikで同じTLS Secretを確認する

$ curl -ik \
    --resolve tls-test.example.com:443:<TRAEFIK-ALB-OR-VPC-LB-IP> \
    https://tls-test.example.com/
HTTP/2 200
content-type: text/html
$ kubectl get ingress tls-test -o yaml > tls-after.yaml

$ diff -u tls-before.yaml tls-after.yaml

本質的なIngress差分は次の1行です。

- ingressClassName: public-iks-k8s-nginx
+ ingressClassName: public-iks-traefik

TLS Secret、Host、Path、Backend Serviceは変更していません。


8. Annotationを使っていなくても注意が必要

Classic環境で同じTLS IngressへHTTPアクセスしたところ、デフォルト動作に差がありました。

NGINX

$ curl -i \
    -H 'Host: tls-test.example.com' \
    http://<NGINX-ALB-IP>/
HTTP/1.1 308 Permanent Redirect
Location: https://tls-test.example.com

Traefik

$ curl -i \
    -H 'Host: tls-test.example.com' \
    http://<TRAEFIK-ALB-IP>/
HTTP/1.1 200 OK

この検証ではcurl -Lを付けません。redirectを自動追跡すると、Controllerが最初に返したstatusとLocationヘッダーが分かりにくくなるためです。

今回のVPC環境ではIKS-managed Public Load Balancerが443のみを公開していたため、HTTP→HTTPS比較は対象外としました。


9. Level 3: NGINX固有Rewrite

RewriteはIngressClassだけを変更するのではなく、Ingress-NGINX用とTraefik用の定義を別ファイルで管理します。

今回の検証では、ClassicとVPCで外部公開方式が異なるため、次のYAMLをそれぞれ用意しました。

Infrastructure Controller YAMLファイル
Classic Ingress-NGINX rewrite-ingress.yaml
Classic Traefik rewrite-ingress-traefik.yaml
VPC Ingress-NGINX rewrite-ingress-nginx-vpc.yaml
VPC Traefik rewrite-ingress-traefik-vpc.yaml
共通 Traefik Middleware rewrite-middleware.yaml

9.1 共通のRewrite検証用Backendを作成する

ClassicとVPCの両方で同じBackendを使用します。

Backendには公式nginx:alpineイメージを使用し、ConfigMapから/helloと/users/123に対応する静的ファイルをマウントします。

rewrite-app.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: rewrite-test-content
data:
  hello: |
    Rewrite test: Hello endpoint OK
  123: |
    Rewrite test: Users 123 endpoint OK

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rewrite-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: rewrite-test
  template:
    metadata:
      labels:
        app: rewrite-test
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          ports:
            - containerPort: 80
          volumeMounts:
            - name: hello-content
              mountPath: /usr/share/nginx/html/hello
              subPath: hello
            - name: user-content
              mountPath: /usr/share/nginx/html/users/123
              subPath: "123"
      volumes:
        - name: hello-content
          configMap:
            name: rewrite-test-content
            items:
              - key: hello
                path: hello
        - name: user-content
          configMap:
            name: rewrite-test-content
            items:
              - key: "123"
                path: "123"

---
apiVersion: v1
kind: Service
metadata:
  name: rewrite-test
spec:
  selector:
    app: rewrite-test
  ports:
    - name: http
      port: 80
      targetPort: 80

適用します。

$ kubectl apply -f rewrite-app.yaml
configmap/rewrite-test-content created
deployment.apps/rewrite-test created
service/rewrite-test created

$ kubectl rollout status deployment rewrite-test
deployment "rewrite-test" successfully rolled out

PodとServiceを確認します。

$ kubectl get pod -l app=rewrite-test
NAME                            READY   STATUS    RESTARTS
rewrite-test-xxxxxxxxxx-xxxxx   1/1     Running   0

$ kubectl get svc rewrite-test
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
rewrite-test   ClusterIP   172.21.x.x     <none>        80/TCP

配置したファイルも確認します。

$ POD=$(kubectl get pod -l app=rewrite-test \
    -o jsonpath='{.items[0].metadata.name}')

$ kubectl exec "$POD" -- cat /usr/share/nginx/html/hello
Rewrite test: Hello endpoint OK

$ kubectl exec "$POD" -- cat /usr/share/nginx/html/users/123
Rewrite test: Users 123 endpoint OK

9.2 Classic: Ingress-NGINXでBaselineを取得する

ClassicではHTTPで各ALBへ直接アクセスします。

rewrite-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-test
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: public-iks-k8s-nginx
  rules:
    - host: rewrite-test.example.com
      http:
        paths:
          - path: /app(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: rewrite-test
                port:
                  number: 80

適用します。

$ kubectl apply -f rewrite-ingress.yaml
ingress.networking.k8s.io/rewrite-test created

$ kubectl get ingress rewrite-test
NAME           CLASS                  HOSTS                      PORTS
rewrite-test   public-iks-k8s-nginx   rewrite-test.example.com   80

/app/helloを確認します。

$ curl -i \
    -H 'Host: rewrite-test.example.com' \
    http://<NGINX-ALB-IP>/app/hello
HTTP/1.1 200 OK
content-type: application/octet-stream

Rewrite test: Hello endpoint OK

/app/users/123も確認します。

$ curl -i \
    -H 'Host: rewrite-test.example.com' \
    http://<NGINX-ALB-IP>/app/users/123
HTTP/1.1 200 OK
content-type: application/octet-stream

Rewrite test: Users 123 endpoint OK

Backendログで、Rewrite後のURIを確認します。

$ kubectl logs -l app=rewrite-test --tail=20
"GET /hello HTTP/1.1" 200
"GET /users/123 HTTP/1.1" 200

移行前のIngressを保存します。

$ kubectl get ingress rewrite-test -o yaml > rewrite-before.yaml

9.3 Classic: Traefikへ移行する

まずTraefik Middlewareを作成します。

rewrite-middleware.yaml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: rewrite-strip-app
  namespace: default
spec:
  stripPrefix:
    prefixes:
      - /app
$ kubectl apply -f rewrite-middleware.yaml
middleware.traefik.io/rewrite-strip-app created

次にClassic用Traefik Ingressを適用します。

rewrite-ingress-traefik.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-test
  namespace: default
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: default-rewrite-strip-app@kubernetescrd
spec:
  ingressClassName: public-iks-traefik
  rules:
    - host: rewrite-test.example.com
      http:
        paths:
          - path: /app
            pathType: Prefix
            backend:
              service:
                name: rewrite-test
                port:
                  number: 80
$ kubectl apply -f rewrite-ingress-traefik.yaml
ingress.networking.k8s.io/rewrite-test configured

$ kubectl get ingress rewrite-test
NAME           CLASS                HOSTS                      PORTS
rewrite-test   public-iks-traefik   rewrite-test.example.com   80

/app/helloを確認します。

$ curl -i \
    -H 'Host: rewrite-test.example.com' \
    http://<TRAEFIK-ALB-IP>/app/hello
HTTP/1.1 200 OK
content-type: application/octet-stream

Rewrite test: Hello endpoint OK

/app/users/123も確認します。

$ curl -i \
    -H 'Host: rewrite-test.example.com' \
    http://<TRAEFIK-ALB-IP>/app/users/123
HTTP/1.1 200 OK
content-type: application/octet-stream

Rewrite test: Users 123 endpoint OK

Backendログでも、NGINXと同じURIが渡されたことを確認します。

$ kubectl logs -l app=rewrite-test --tail=20
"GET /hello HTTP/1.1" 200
"GET /users/123 HTTP/1.1" 200

移行後のIngressを保存して差分を確認します。

$ kubectl get ingress rewrite-test -o yaml > rewrite-after.yaml

$ diff -u rewrite-before.yaml rewrite-after.yaml

実際のdiffにはgenerationやresourceVersionなど、Kubernetesリソースの更新に伴う管理情報の変更も含まれます。

それらを除いた本質的な設定差分は次のとおりです。

 metadata:
   annotations:
-    nginx.ingress.kubernetes.io/rewrite-target: /$2
+    traefik.ingress.kubernetes.io/router.middlewares: default-rewrite-strip-app@kubernetescrd

 spec:
-  ingressClassName: public-iks-k8s-nginx
+  ingressClassName: public-iks-traefik

   rules:
   - host: rewrite-test.example.com
     http:
       paths:
       - backend:
           service:
             name: rewrite-test
             port:
               number: 80
-        path: /app(/|$)(.*)
-        pathType: ImplementationSpecific
+        path: /app
+        pathType: Prefix

Classic環境のRewrite移行では、単純にIngressClassを変更しただけではありません。

Ingress-NGINXでは、rewrite-target Annotationと正規表現を含むPathを組み合わせていました。

metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
    - http:
        paths:
          - path: /app(/|$)(.*)
            pathType: ImplementationSpecific

Traefikでは、Middleware参照と標準的なPrefix Pathへ変更しました。

metadata:
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: default-rewrite-strip-app@kubernetescrd
spec:
  rules:
    - http:
        paths:
          - path: /app
            pathType: Prefix

別途作成したStripPrefix Middlewareが、Backendへ転送する前に/appを削除します。

その結果、移行前後とも以下の動作を確認できました。

/app/hello
      ↓
/hello
      ↓
HTTP 200

/app/users/123
      ↓
/users/123
      ↓
HTTP 200

9.4 VPC: Ingress-NGINXでBaselineを取得する

今回のVPC環境では、IKS-managed Public Load Balancerが443のみを公開していました。

そのため、VPC用IngressにはTLS設定を含めます。

事前にtls-test-secretを作成しておきます。

$ kubectl create secret tls tls-test-secret \
    --cert=tls.crt \
    --key=tls.key
secret/tls-test-secret created
rewrite-ingress-nginx-vpc.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-test
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: public-iks-k8s-nginx
  tls:
    - hosts:
        - rewrite-test.example.com
      secretName: tls-test-secret
  rules:
    - host: rewrite-test.example.com
      http:
        paths:
          - path: /app(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: rewrite-test
                port:
                  number: 80

まずVPC Public Load BalancerのbackendをIngress-NGINXへ切り替えます。

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend ingress-nginx
OK

$ ibmcloud ks ingress load-balancer get \
    --cluster <cluster-name>
OK

Load Balancer backend

Public backend    ingress-nginx
Private backend   -

Ingressを適用します。

$ kubectl apply -f rewrite-ingress-nginx-vpc.yaml
ingress.networking.k8s.io/rewrite-test created

$ kubectl get ingress rewrite-test
NAME           CLASS                  HOSTS                      PORTS
rewrite-test   public-iks-k8s-nginx   rewrite-test.example.com   80,443

Public Ingress Service名を確認します。

$ kubectl get svc -n kube-system \
    -l app.kubernetes.io/part-of=managed-ingress

EndpointSliceがIngress-NGINX Podを指していることを確認します。

$ kubectl get endpointslice \
    -n kube-system \
    -l kubernetes.io/service-name=<public-ingress-service> \
    -o wide

その後、HTTPSでBaselineを取得します。

$ curl -ik \
    --resolve rewrite-test.example.com:443:<VPC-LB-PUBLIC-IP> \
    https://rewrite-test.example.com/app/hello
HTTP/2 200
content-type: application/octet-stream

Rewrite test: Hello endpoint OK
$ curl -ik \
    --resolve rewrite-test.example.com:443:<VPC-LB-PUBLIC-IP> \
    https://rewrite-test.example.com/app/users/123
HTTP/2 200
content-type: application/octet-stream

Rewrite test: Users 123 endpoint OK

Backendログも確認します。

$ kubectl logs -l app=rewrite-test --tail=20
"GET /hello HTTP/1.1" 200
"GET /users/123 HTTP/1.1" 200

移行前のIngressを保存します。

$ kubectl get ingress rewrite-test -o yaml > vpc-rewrite-before.yaml

9.5 VPC: Traefikへ移行する

MiddlewareはClassicと共通です。

$ kubectl apply -f rewrite-middleware.yaml
middleware.traefik.io/rewrite-strip-app created

VPC用Traefik Ingressには、Classic用と異なりTLS設定を含めます。

rewrite-ingress-traefik-vpc.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-test
  namespace: default
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: default-rewrite-strip-app@kubernetescrd
spec:
  ingressClassName: public-iks-traefik
  tls:
    - hosts:
        - rewrite-test.example.com
      secretName: tls-test-secret
  rules:
    - host: rewrite-test.example.com
      http:
        paths:
          - path: /app
            pathType: Prefix
            backend:
              service:
                name: rewrite-test
                port:
                  number: 80

Ingressを適用します。

$ kubectl apply -f rewrite-ingress-traefik-vpc.yaml
ingress.networking.k8s.io/rewrite-test configured

$ kubectl get ingress rewrite-test
NAME           CLASS                HOSTS                      PORTS
rewrite-test   public-iks-traefik   rewrite-test.example.com   80,443

次にVPC Public Load Balancer backendをTraefikへ切り替えます。

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend traefik
OK

$ ibmcloud ks ingress load-balancer get \
    --cluster <cluster-name>
OK

Load Balancer backend

Public backend    traefik
Private backend   -

すぐにcurlせず、EndpointSliceまで確認します。

$ kubectl get endpointslice \
    -n kube-system \
    -l kubernetes.io/service-name=<public-ingress-service> \
    -o wide

実機検証では次のように切り替わりました。

Ingress-NGINX
172.23.15.24
172.23.18.197

        ↓

Traefik
172.23.15.6
172.23.18.193

EndpointSliceがTraefik Podを指してから疎通確認します。

$ curl -ik \
    --resolve rewrite-test.example.com:443:<VPC-LB-PUBLIC-IP> \
    https://rewrite-test.example.com/app/hello
HTTP/2 200
content-type: application/octet-stream

Rewrite test: Hello endpoint OK
$ curl -ik \
    --resolve rewrite-test.example.com:443:<VPC-LB-PUBLIC-IP> \
    https://rewrite-test.example.com/app/users/123
HTTP/2 200
content-type: application/octet-stream

Rewrite test: Users 123 endpoint OK

Backendログでも、NGINXと同じRewrite後URIを確認します。

$ kubectl logs -l app=rewrite-test --tail=20
"GET /hello HTTP/1.1" 200
"GET /users/123 HTTP/1.1" 200

9.6 Classic/VPCのYAML差分

今回使用したYAMLは次のとおりです。

Infrastructure Controller YAMLファイル
Classic Ingress-NGINX rewrite-ingress.yaml
Classic Traefik rewrite-ingress-traefik.yaml
VPC Ingress-NGINX rewrite-ingress-nginx-vpc.yaml
VPC Traefik rewrite-ingress-traefik-vpc.yaml
共通 Traefik Middleware rewrite-middleware.yaml

ClassicとVPCの主な差はTLS設定です。

Classic用IngressにはTLS設定を含めていません。

spec:
  ingressClassName: public-iks-k8s-nginx

VPC用Ingressには、443で検証するためTLS設定を追加しました。

spec:
  ingressClassName: public-iks-k8s-nginx
  tls:
    - hosts:
        - rewrite-test.example.com
      secretName: tls-test-secret

Traefik用Ingressについても同様に、VPC版にTLS設定を追加しています。


9.7 NGINXからTraefikへの移行差分

VPCの移行後Ingressを保存します。

$ kubectl get ingress rewrite-test -o yaml > vpc-rewrite-after.yaml

$ diff -u \
    vpc-rewrite-before.yaml \
    vpc-rewrite-after.yaml

generationやresourceVersionなどのKubernetes管理情報を除くと、本質的な差分は次のとおりです。

 metadata:
   annotations:
-    nginx.ingress.kubernetes.io/rewrite-target: /$2
+    traefik.ingress.kubernetes.io/router.middlewares: default-rewrite-strip-app@kubernetescrd

 spec:
-  ingressClassName: public-iks-k8s-nginx
+  ingressClassName: public-iks-traefik

-  path: /app(/|$)(.*)
-  pathType: ImplementationSpecific
+  path: /app
+  pathType: Prefix

TLS設定は変更していません。

tls:
  - hosts:
      - rewrite-test.example.com
    secretName: tls-test-secret

今回のRewrite移行では、単純なIngressClass変更ではなく、NGINXのrewrite-target + regex pathをTraefikのPrefix + StripPrefix Middlewareへ機能変換しています。


10. ClassicとVPCの比較

ここまでに実施したことをベースにClassicとVPCでの稼働に関する比較を行いました。

項目 Classic VPC
Ingress-NGINX / Traefik共存 可能 可能
外部Endpoint ALBごとのPublic IP 共通VPC LB
IngressClass変更 必要 必要
Public LB backend変更 不要 必要
TLS Secret変更 今回は不要 今回は不要
アプリ変更 今回は不要 今回は不要
Rewrite Middleware変換で対応 Middleware変換で対応
データパス確認 ALBへ直接curl Service / EndpointSlice確認

11. 移行対象を3段階に分類する

Level 1: 基本Ingress

Host
Path
Service

Controller固有設定なし。まずIngressClass変更を中心に検証します。

Level 2: Kubernetes標準機能

複数Path
TLS Secret
HTTPS termination

標準設定をそのまま利用できる場合でも、Controllerのデフォルト動作を確認したほうがより確実な移行を行えます。

Level 3: Controller固有機能

Rewrite
Timeout
Request body size
Session affinity
NGINX固有Annotation
Controller固有ConfigMap

単純なIngressClass変更ではなく、次の手順で進めます。

NGINX設定
    ↓
何を実現しているか確認
    ↓
Traefikの同等機能を確認
    ↓
設定を再構成
    ↓
移行前後を比較

12. 今回の検証結果まとめ

検証 結果 Ingress定義 ClassName以外の変更
基本Host/Path 成功 不要
複数Prefix Path 成功 不要
TLS Secret 成功 不要
HTTPS termination 成功 不要
HTTP→HTTPS Controller間で差あり 要確認・対応
Rewrite Traefik Middlewareへ変換して成功 必要
VPC Public LB backend切替が必要 (Ingress外で対応)

13. まとめ:どのような環境なら移行しやすいか

今回の検証結果から、Ingress-NGINXからTraefikへの移行難易度は、Ingress-NGINX固有機能への依存度によって大きく変わると考えられます。

簡単に整理すると次のようになります。

移行難易度 利用状況 主な対応
低 Host、Path、Prefix、ServiceなどKubernetes標準Ingressを中心に利用 ingressClassNameの変更を中心に検証
低~中 TLS Secret、複数PathなどKubernetes標準機能を利用 基本設定は維持しつつ、Controllerのデフォルト動作を確認
中~高 nginx.ingress.kubernetes.io/* Annotationを利用 TraefikのAnnotationやMiddleware、CRDなどへの機能変換が必要
高 NGINX固有ConfigMap、Rewrite、Timeout、Request body size、Session affinityなどを多数利用 設定ごとにTraefikの同等機能を確認し、個別に移行・テスト

移行しやすいケース

例えば、次のようなシンプルなIngressです。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sample
spec:
  ingressClassName: public-iks-k8s-nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app
                port:
                  number: 80

このように、

  • Host routing
  • PrefixによるPath routing
  • 標準的なService指定
  • Kubernetes TLS Secret
  • 複数Path

など、Kubernetes標準のIngress機能を中心に利用している場合は、比較的移行しやすいと考えられます。

今回検証した範囲でも、基本的なHost/Path routing、複数Prefix Path、標準的なTLS Secretについては、Ingress定義では基本的にingressClassNameの変更を中心にTraefikへ移行できました。

- ingressClassName: public-iks-k8s-nginx
+ ingressClassName: public-iks-traefik

ただしVPCの場合は、Ingressの変更とは別にIKS-managed Public Load Balancerのbackend切り替えも必要です。

$ ibmcloud ks ingress load-balancer backend set \
    --cluster <cluster-name> \
    --public-backend traefik

移行時の確認が多くなるケース

一方、次のようなNGINX固有Annotationを利用している場合は、単純なIngressClass変更だけでは移行できない可能性があります。

metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2

今回のRewrite検証では、Ingress-NGINX側の、

rewrite-target + regex path

という構成を、そのままTraefikへ持っていくのではなく、

Ingress-NGINX
rewrite-target + regex path

        ↓ 機能をTraefikへ変換

Traefik
Prefix path + StripPrefix Middleware

へ変更する必要がありました。

つまり重要なのは、

NGINX AnnotationをTraefik用Annotationへ機械的に置き換えるのではなく、その設定が何を実現しているのかを確認して、Traefikの同等機能へ置き換えること

です。

Annotationがなくても確認は必要

また今回のClassic環境では、NGINX固有Annotationを使用していないTLS Ingressでも、HTTPアクセス時のデフォルト動作に違いがありました。

Ingress-NGINX
HTTP → 308 Permanent Redirect → HTTPS

Traefik
HTTP → 200 OK

したがって、

NGINX Annotationを使っていない = Traefikへ完全にそのまま移行できる

とは限りません。

Ingress YAMLに現れないControllerのデフォルト動作にも依存している可能性があります。

まず既存Ingressを棚卸しする

移行を始める前に、既存Ingressを確認しておくと移行規模を把握しやすくなります。

$ kubectl get ingress -A

すべてのIngress定義を確認する場合は、

$ kubectl get ingress -A -o yaml

NGINX固有Annotationを使用しているIngressを探すのであれば、例えば次のように確認できます。

$ kubectl get ingress -A -o yaml \
    | grep 'nginx.ingress.kubernetes.io'

NGINX固有設定が見つかった場合は、Annotation名だけを見るのではなく、

  • Rewrite
  • Redirect
  • Timeout
  • Request body size
  • Session affinity
  • TLS関連設定
  • Header操作

など、その設定で何を実現しているのかを整理してからTraefik側の対応方法を確認します。

移行難易度を判断するポイント

まとめると、次のように考えると分かりやすいです。

Kubernetes標準Ingress中心
        ↓
比較的移行しやすい

        ↓

NGINX固有Annotationを利用
        ↓
機能ごとの変換が必要

        ↓

NGINX固有Annotation
+
Controller ConfigMap
+
複数の高度なController固有機能
        ↓
移行難易度が高くなる

したがって、移行難易度を判断するときは、

NGINX Annotationが何個あるかだけではなく、Ingress-NGINX固有のAnnotation、ConfigMap、Controllerのデフォルト動作にどの程度依存しているか

を見ることがポイントです。

既存IngressがKubernetes標準機能を中心に構成されている環境ほど移行はシンプルになりやすく、Ingress-NGINX固有機能への依存が大きい環境ほど、Traefik側の同等機能への変換と個別テストが重要になります。


参考情報

IBM Cloud / IBM Community

IBM Cloud Kubernetes Service 公式ドキュメント

Traefik公式ドキュメント

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?