skills/a6-recipe-canary/SKILL.md
Recipe skill for implementing canary releases using the a6 CLI. Covers gradual traffic shifting with the traffic-split plugin, header-based canary routing, weight adjustment progression, monitoring checkpoints, and full promotion or rollback workflows.
npx skillsauth add moonming/a6 a6-recipe-canaryInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A canary release gradually shifts traffic from the stable version to a new version. Start with a small percentage (e.g., 5%), monitor for errors, then increase incrementally until the new version receives 100% of traffic. If errors spike at any stage, roll back instantly.
This recipe uses the traffic-split plugin to manage weighted traffic
distribution between stable and canary upstreams.
a6 upstream create -f - <<'EOF'
{
"id": "stable",
"type": "roundrobin",
"nodes": {
"stable-v1:8080": 1
}
}
EOF
a6 upstream create -f - <<'EOF'
{
"id": "canary",
"type": "roundrobin",
"nodes": {
"canary-v2:8080": 1
}
}
EOF
a6 route create -f - <<'EOF'
{
"id": "api",
"uri": "/api/*",
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": "canary",
"weight": 5
},
{
"weight": 95
}
]
}
]
}
},
"upstream_id": "stable"
}
EOF
Check error rates, latency, and logs. If healthy:
a6 route update api -f - <<'EOF'
{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": "canary",
"weight": 25
},
{
"weight": 75
}
]
}
]
}
}
}
EOF
a6 route update api -f - <<'EOF'
{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": "canary",
"weight": 50
},
{
"weight": 50
}
]
}
]
}
}
}
EOF
Remove traffic-split and switch to canary as the new stable:
a6 route update api -f - <<'EOF'
{
"plugins": {},
"upstream_id": "canary"
}
EOF
Then update the "stable" upstream nodes to the new version for next time:
a6 upstream update stable -f - <<'EOF'
{
"nodes": {
"canary-v2:8080": 1
}
}
EOF
Remove the traffic-split plugin to send all traffic back to stable:
a6 route update api -f - <<'EOF'
{
"plugins": {},
"upstream_id": "stable"
}
EOF
Route specific users (e.g., internal testers) to the canary version:
a6 route update api -f - <<'EOF'
{
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [["http_x-canary", "==", "true"]]
}
],
"weighted_upstreams": [
{
"upstream_id": "canary",
"weight": 1
}
]
}
]
}
},
"upstream_id": "stable"
}
EOF
Only requests with header x-canary: true go to the canary. All others stay on stable.
Route users who opted into beta:
{
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [["cookie_beta", "==", "1"]]
}
],
"weighted_upstreams": [
{
"upstream_id": "canary",
"weight": 1
}
]
}
]
}
}
}
#!/bin/bash
set -euo pipefail
ROUTE_ID="api"
CANARY_UPSTREAM="canary"
WEIGHTS=(5 25 50 75 100)
HEALTH_URL="http://gateway:9080/api/health"
WAIT_SECONDS=300 # 5 minutes between stages
for w in "${WEIGHTS[@]}"; do
if [ "$w" -eq 100 ]; then
echo "Promoting canary to 100%..."
a6 route update "$ROUTE_ID" -f - <<EOF
{"plugins": {}, "upstream_id": "$CANARY_UPSTREAM"}
EOF
else
stable_w=$((100 - w))
echo "Setting canary to ${w}% (stable ${stable_w}%)..."
a6 route update "$ROUTE_ID" -f - <<EOF
{
"plugins": {
"traffic-split": {
"rules": [{
"weighted_upstreams": [
{"upstream_id": "$CANARY_UPSTREAM", "weight": $w},
{"weight": $stable_w}
]
}]
}
}
}
EOF
fi
echo "Waiting ${WAIT_SECONDS}s and checking health..."
sleep "$WAIT_SECONDS"
if ! curl -sf "$HEALTH_URL" > /dev/null; then
echo "❌ Health check failed at ${w}%. Rolling back."
a6 route update "$ROUTE_ID" -f - <<EOF
{"plugins": {}, "upstream_id": "stable"}
EOF
exit 1
fi
echo "✅ Healthy at ${w}%"
done
echo "🎉 Canary release complete!"
version: "1"
upstreams:
- id: stable
type: roundrobin
nodes:
"stable-v1:8080": 1
- id: canary
type: roundrobin
nodes:
"canary-v2:8080": 1
routes:
- id: api
uri: /api/*
plugins:
traffic-split:
rules:
- weighted_upstreams:
- upstream_id: canary
weight: 10
- weight: 90
upstream_id: stable
| Symptom | Cause | Fix |
|---------|-------|-----|
| Traffic ratio not exact | Round-robin approximation | Expected; ratios converge over many requests |
| Canary not receiving traffic | Match condition never true | Check header/cookie name; use a6 route get to verify config |
| Rollback not instant | Plugin config cached | APISIX updates propagate via etcd in milliseconds — verify with a6 route get |
| 502 errors from canary | Canary upstream not healthy | Check canary service health before starting rollout |
| Weight changes have no effect | Editing wrong route | Verify route ID with a6 route list |
tools
Core skill for working with the a6 CLI — the Apache APISIX command-line tool. Provides project conventions, command patterns, architecture overview, and development workflow. Load this skill when working on a6 source code, adding new commands, writing tests, or modifying any a6 component.
tools
Recipe skill for implementing multi-tenant API gateway patterns using the a6 CLI. Covers tenant isolation via Consumer Groups, host/path/header-based routing, per-tenant rate limiting, context forwarding with proxy-rewrite, and declarative config sync workflows for multi-tenant management.
tools
Recipe skill for configuring mutual TLS (mTLS) using the a6 CLI. Covers SSL certificate management, upstream mTLS to backend services, client certificate verification, and end-to-end mTLS setup from client through APISIX to upstream.
tools
Recipe skill for configuring upstream health checks using the a6 CLI. Covers active health checks (HTTP probing), passive health checks (response analysis), combining both, configuring healthy/unhealthy thresholds, and monitoring upstream node status.