はじめに
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 共通バックエンドを作成する
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を作成する
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 検証用バックエンドを作成する
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を作成する
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
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に対応する静的ファイルをマウントします。
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へ直接アクセスします。
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を作成します。
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を適用します。
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
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設定を含めます。
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
-
Traefik is now generally available on IBM Cloud Kubernetes Service
- TraefikのGA、Ingress-NGINXからTraefikへの移行概要、ClassicとVPC Gen 2におけるLoad Balancer構成の違いが説明されています。
-
Introducing Traefik Ingress Controller Preview
- IKSでのTraefik導入背景とPreview時点の情報です。
IBM Cloud Kubernetes Service 公式ドキュメント
-
- IKSで提供されるTraefik Ingress、Ingress class、Classic/VPCのALB構成、TLSなどの基本仕様です。
-
Migrating from Ingress-NGINX to Traefik Ingress controller
- Classic/VPCそれぞれの移行戦略、並行テスト、Direct migration、VPCでのLoad Balancer backend切り替えなどの公式移行手順です。
-
Moving from Ingress-NGINX to Traefik on IBM Cloud
- Ingress-NGINXとTraefikの機能差、およびAnnotationやConfigMapなどの設定をTraefikでどう置き換えるかを比較できます。
Traefik公式ドキュメント
-
Traefik Kubernetes Ingress Routing Configuration
- Kubernetes Ingressで利用できるTraefik AnnotationやMiddleware参照方法を確認できます。
-
- Kubernetes CRDとしてMiddlewareを定義する方法を確認できます。
-
Traefik StripPrefix Middleware
- 本記事のRewrite移行で利用した
StripPrefixMiddlewareの仕様です。
- 本記事のRewrite移行で利用した