[Lauro Fialho Müller] GitOps in Practice with Argo CD and Argo Rollouts [ENG, 2026]: Argo Rollouts: Advanced Traffic Management
Делаю:
2026.01.29
Дока по инсталляции:
https://github.com/lm-academy/argo-rollouts-course/blob/main/setup-gateway-api/setup-instructions.md
Миникуб версии v1.32.2 стартован с metallb и без ingress
// minikube addons --profile ${PROFILE} enable ingress
minikube addons --profile ${PROFILE} enable metallb
$ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
$ helm repo add traefik https://traefik.github.io/charts
$ helm repo update
$ cd ~/tmp
ии добавил
enabled: true
name: traefik-gateway
namespace: traefik
$ cat > traefik-values.yaml << 'EOF'
# values.yaml
ports:
web:
port: 80
nodePort: 30000
# No redirection to HTTPS
api:
dashboard: true
insecure: true
ingressRoute:
dashboard:
enabled: true
matchRule: Host(`dashboard.local`)
entryPoints:
- web
ingressClass:
enabled: false
providers:
kubernetesIngress:
enabled: false
kubernetesGateway:
enabled: true
gateway:
enabled: true
name: traefik-gateway
namespace: traefik
listeners:
web:
port: 80
protocol: HTTP
namespacePolicy:
from: All
logs:
access:
enabled: true
metrics:
prometheus:
enabled: true
EOF
$ helm upgrade traefik traefik/traefik \
--version 37.4.0 \
--namespace traefik \
--create-namespace \
--install \
--values traefik-values.yaml
$ kubectl get svc -n traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.107.104.12 192.168.49.20 80:30000/TCP,443:30675/TCP 10s
marley@workstation:~/tmp$ kubectl get Gateway -n traefik
NAME CLASS ADDRESS PROGRAMMED AGE
traefik-gateway traefik 192.168.49.20 True 40s
Deploy Demo Application
$ cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
namespace: traefik
spec:
replicas: 2
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: whoami
namespace: traefik
spec:
selector:
app: whoami
ports:
- port: 80
EOF
5.2 Create HTTPRoute
$ cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami
namespace: traefik
spec:
parentRefs:
- name: traefik-gateway
hostnames:
- 'whoami.local'
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: whoami
port: 80
EOF
$ kubectl get httproute whoami -n traefik
NAME HOSTNAMES AGE
whoami ["whoami.local"] 22m
Step 6: Access the Application
// Добавить в hosts
$ echo "192.168.49.20 whoami.local" | sudo tee -a /etc/hosts
$ echo "192.168.49.20 dashboard.local" | sudo tee -a /etc/hosts
$ kubectl get httproute whoami -n traefik -o jsonpath='{.status.parents[0].conditions[?(@.type=="Accepted")].status}'
$ curl -v -H "Host: whoami.local" http://192.168.49.20 curl -v -H "Host: whoami.local" http://192.168.49.20
* Trying 192.168.49.20:80...
* Connected to 192.168.49.20 (192.168.49.20) port 80 (#0)
> GET / HTTP/1.1
> Host: whoami.local
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Length: 404
< Content-Type: text/plain; charset=utf-8
< Date: Thu, 29 Jan 2026 02:57:37 GMT
<
Hostname: whoami-64f6cf779d-gmvhb
IP: 127.0.0.1
IP: ::1
IP: 10.244.0.8
IP: fe80::6a:4cff:fee2:fb80
RemoteAddr: 10.244.0.7:40178
GET / HTTP/1.1
Host: whoami.local
User-Agent: curl/7.81.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.244.0.1
X-Forwarded-Host: whoami.local
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-5997b59959-nqsct
X-Real-Ip: 10.244.0.1
* Connection #0 to host 192.168.49.20 left intact
// OK!
http://dashboard.local
http://whoami.local
Install Argo Rollouts Gateway API Plugin
https://rollouts-plugin-trafficrouter-gatewayapi.readthedocs.io/en/latest/installation/
$ cd ~/tmp
$ cat > values-argo-rollouts.yaml << 'EOF'
# values-rollouts.yaml
dashboard:
enabled: true
# New: For configuring the Gateway API Plugin
# Source: https://rollouts-plugin-trafficrouter-gatewayapi.readthedocs.io/en/latest/installation/#installing-the-plugin-via-init-containers
controller:
initContainers:
- name: copy-gwapi-plugin
image: ghcr.io/argoproj-labs/rollouts-plugin-trafficrouter-gatewayapi:v0.8.0
command: ['/bin/sh', '-c']
args:
- cp /bin/rollouts-plugin-trafficrouter-gatewayapi /plugins
volumeMounts:
- name: gwapi-plugin
mountPath: /plugins
trafficRouterPlugins:
- name: argoproj-labs/gatewayAPI
location: 'file:///plugins/rollouts-plugin-trafficrouter-gatewayapi'
volumes:
- name: gwapi-plugin
emptyDir: {}
volumeMounts:
- name: gwapi-plugin
mountPath: /plugins
EOF
// Upgrade the helm chart with
$ helm upgrade argo-rollouts argo/argo-rollouts \
--install \
--namespace argo-rollouts \
--create-namespace \
--version 2.40.5 \
--values values-argo-rollouts.yaml
// Restart Argo Rollouts
$ kubectl rollout restart deployment -n argo-rollouts argo-rollouts
$ kubectl get pod -n argo-rollouts
NAME READY STATUS RESTARTS AGE
argo-rollouts-6876f47dd4-fx5br 1/1 Running 0 13m
argo-rollouts-6876f47dd4-tnnwv 1/1 Running 0 14m
argo-rollouts-dashboard-6bc9fff6fc-29kbh 1/1 Running 0 14m
marley@workstation:~/projects/docs.gitops.ru$
// Плагин должен быть скопирован
$ kubectl logs argo-rollouts-6876f47dd4-fx5br -n argo-rollouts | grep plugin
Defaulted container "argo-rollouts" out of: argo-rollouts, copy-gwapi-plugin (init)
time="2026-01-29T03:01:22Z" level=info msg="Copied plugin from /plugins/rollouts-plugin-trafficrouter-gatewayapi to /home/argo-rollouts/plugin-bin/argoproj-labs/gatewayAPI"
Traffic-Weighted Canary
https://github.com/lm-academy/argo-rollouts-course/tree/main/traffic-weighting/manifests
$ cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: gateway-lab
EOF
$ cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: rollout-gateway-stable
namespace: gateway-lab
spec:
ports:
- port: 3000
name: http
selector:
app: rollout-gateway
---
apiVersion: v1
kind: Service
metadata:
name: rollout-gateway-canary
namespace: gateway-lab
spec:
ports:
- port: 3000
name: http
selector:
app: rollout-gateway
EOF
$ cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: rollout-gateway
namespace: gateway-lab
spec:
gatewayClassName: traefik
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
EOF
$ cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rollout-gateway-route
namespace: gateway-lab
spec:
parentRefs:
- name: rollout-gateway
hostnames:
- 'color-app.local'
rules:
- backendRefs:
- name: rollout-gateway-stable
port: 3000
- name: rollout-gateway-canary
port: 3000
EOF
$ kubectl describe httproute -n gateway-lab rollout-gateway-route
$ cat << EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollout-gateway
namespace: gateway-lab
spec:
replicas: 5
selector:
matchLabels:
app: rollout-gateway
template:
metadata:
labels:
app: rollout-gateway
spec:
containers:
- name: rollout-gateway
image: lmacademy/simple-color-app:1.0.0
env:
- name: APP_COLOR
value: blue
strategy:
canary:
canaryService: rollout-gateway-canary
stableService: rollout-gateway-stable
dynamicStableScale: true
trafficRouting:
plugins:
argoproj-labs/gatewayAPI:
httpRoute: rollout-gateway-route # our created httproute
namespace: gateway-lab # namespace where this rollout resides
steps:
- setWeight: 30
- pause: {}
- setWeight: 40
- pause:
duration: 10s
- setWeight: 60
- pause:
duration: 10s
- setWeight: 80
- pause:
duration: 10s
EOF
$ kubectl argo rollouts get rollout rollout-gateway -n gateway-lab
// Добавить в hosts
$ echo "192.168.49.20 color-app.local" | sudo tee -a /etc/hosts
// OK!
http://color-app.local/
// Запуск dashboard
$ kubectl argo rollouts dashboard
// OK!
http://localhost:3100/rollouts/gateway-lab
$ kubectl describe httproute rollout-gateway-route -n gateway-lab
$ cat << EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollout-gateway
namespace: gateway-lab
spec:
replicas: 5
selector:
matchLabels:
app: rollout-gateway
template:
metadata:
labels:
app: rollout-gateway
spec:
containers:
- name: rollout-gateway
image: lmacademy/simple-color-app:1.0.0
env:
- name: APP_COLOR
value: green
strategy:
canary:
canaryService: rollout-gateway-canary
stableService: rollout-gateway-stable
dynamicStableScale: true
trafficRouting:
plugins:
argoproj-labs/gatewayAPI:
httpRoute: rollout-gateway-route # our created httproute
namespace: gateway-lab # namespace where this rollout resides
steps:
- setWeight: 30
- pause: {}
- setWeight: 40
- pause:
duration: 10s
- setWeight: 60
- pause:
duration: 10s
- setWeight: 80
- pause:
duration: 10s
EOF
$ kubectl argo rollouts promote rollout-gateway -n gateway-lab
Traffic Management - Header-Based Routing
https://github.com/lm-academy/argo-rollouts-course/tree/main/header-based-routing
$ cat << EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollout-gateway
namespace: gateway-lab
spec:
replicas: 5
selector:
matchLabels:
app: rollout-gateway
template:
metadata:
labels:
app: rollout-gateway
spec:
containers:
- name: rollout-gateway
image: lmacademy/simple-color-app:1.0.0
env:
- name: APP_COLOR
value: red
strategy:
canary:
canaryService: rollout-gateway-canary
stableService: rollout-gateway-stable
dynamicStableScale: true
trafficRouting:
plugins:
argoproj-labs/gatewayAPI:
httpRoute: rollout-gateway-route # our created httproute
namespace: gateway-lab # namespace where this rollout resides
managedRoutes:
- name: qa-override
steps:
- setWeight: 1
- pause:
duration: 20s
- setCanaryScale:
weight: 40
- setHeaderRoute:
name: qa-override
match:
- headerName: x-canary
headerValue:
exact: 'true'
- pause: {}
- setWeight: 30
- pause: {}
- setWeight: 40
- pause:
duration: 10s
- setWeight: 60
- pause:
duration: 10s
- setWeight: 80
- pause:
duration: 10s
EOF
$ ./test-requests.sh color-app.local -1 0.2
$ ./test-requests.sh --tester color-app.local -1 0.2
$ kubectl argo rollouts promote rollout-gateway -n gateway-lab