Master Traffic Splitting and Version Control in Knative Serving
This guide walks through building a Go REST‑API, containerizing it, deploying multiple Knative Service revisions, configuring traffic percentages for gray releases, validating revisions before traffic shift, and rolling back, while comparing Knative’s traffic‑driven model to traditional pod‑based deployments.
This article explains how to use Knative Serving to perform traffic‑splitting (gray release) and version management with a simple Go rest‑api example that distinguishes revisions via the RESOURCE environment variable.
Go application source
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"flag"
)
var resource string
func main() {
flag.Parse()
resource = os.Getenv("RESOURCE")
if resource == "" {
resource = "NOT SPECIFIED"
}
root := "/" + resource
path := root + "/{stockId}"
http.HandleFunc("/", Index)
http.HandleFunc(root, StockIndex)
http.HandleFunc(path, StockPrice)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatalf("ListenAndServe error:%s ", err.Error())
}
}
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to the %s app!
", resource)
}
func StockIndex(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s ticker not found!, require /%s/{ticker}
", resource, resource)
}
func StockPrice(w http.ResponseWriter, r *http.Request) {
stockId := r.URL.Query().Get("stockId")
u := url.URL{Scheme: "https", Host: "api.iextrading.com", Path: "/1.0/stock/" + stockId + "/price"}
log.Print(u)
resp, err := http.Get(u.String())
if err != nil {
fmt.Fprintf(w, "%s not found for ticker : %s
", resource, stockId)
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Fprintf(w, "%s price for ticker %s is %s
", resource, stockId, string(body))
}Docker image
Create a Dockerfile that builds the binary in a Golang 1.12 builder stage and copies it into an Alpine‑sh runtime image, then push the image to your registry.
FROM registry.cn-hangzhou.aliyuncs.com/knative-sample/golang:1.12 as builder
WORKDIR /go/src/github.com/knative-sample/rest-api-go
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -v -o rest-api-go
FROM registry.cn-hangzhou.aliyuncs.com/knative-sample/alpine-sh:3.9
COPY --from=builder /go/src/github.com/knative-sample/rest-api-go/rest-api-go /rest-api-go
CMD ["/rest-api-go"]Deploy revision v1
Save the following Service definition as revision-v1.yaml and apply it:
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: stock-service-example
namespace: default
spec:
template:
metadata:
name: stock-service-example-v1
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1
env:
- name: RESOURCE
value: v1
readinessProbe:
httpGet:
path: /
initialDelaySeconds: 0
periodSeconds: 3Running kubectl apply -f revision-v1.yaml creates the Revision stock-service-example-v1 and routes 100 % of traffic to it.
Verify Knative resources
kubectl get ksvc stock-service-example -o yaml kubectl get configuration -l "serving.knative.dev/service=stock-service-example" -o yaml kubectl get revision -l "serving.knative.dev/service=stock-service-example" -o yaml kubectl get route -l "serving.knative.dev/service=stock-service-example" -o yamlTest the service
Create run-test.sh to discover the Istio Ingress IP and the Service domain, then curl with the proper Host header:
#!/bin/bash
SVC_NAME="stock-service-example"
export INGRESSGATEWAY=istio-ingressgateway
export GATEWAY_IP=$(kubectl get svc $INGRESSGATEWAY --namespace istio-system -o jsonpath="{.status.loadBalancer.ingress[*]['ip']}")
export DOMAIN_NAME=$(kubectl get route $SVC_NAME -o jsonpath="{.status.url}" | awk -F/ '{print $3}')
curl -H "Host: ${DOMAIN_NAME}" http://${GATEWAY_IP}Output shows Welcome to the v1 app!, confirming the deployment.
Deploy revision v2 with 50 % traffic
Save the following as revision-v2.yaml and apply:
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: stock-service-example
namespace: default
spec:
template:
metadata:
name: stock-service-example-v2
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1
env:
- name: RESOURCE
value: v2
readinessProbe:
httpGet:
path: /
initialDelaySeconds: 0
periodSeconds: 3
traffic:
- tag: v1
revisionName: stock-service-example-v1
percent: 50
- tag: v2
revisionName: stock-service-example-v2
percent: 50
- tag: latest
latestRevision: true
percent: 0After kubectl apply -f revision-v2.yaml, running the test script repeatedly yields alternating v1 and v2 responses, confirming the 50 % split.
Pre‑validation with a third revision
Create revision-v3.yaml (no traffic assigned) to verify the new version before exposing it:
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: stock-service-example
namespace: default
spec:
template:
metadata:
name: stock-service-example-v3
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1
env:
- name: RESOURCE
value: v3
readinessProbe:
httpGet:
path: /
initialDelaySeconds: 0
periodSeconds: 3Apply it with kubectl apply -f revision-v3.yaml. The Revision appears in kubectl get revision but receives no traffic.
Shift traffic to v3
Update the Service to allocate traffic among v1, v2 and v3 (40 % / 30 % / 30 %) in revision-v3-2.yaml:
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: stock-service-example
namespace: default
spec:
template:
metadata:
name: stock-service-example-v3
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1
env:
- name: RESOURCE
value: v3
readinessProbe:
httpGet:
path: /
initialDelaySeconds: 0
periodSeconds: 3
traffic:
- tag: v1
revisionName: stock-service-example-v1
percent: 40
- tag: v2
revisionName: stock-service-example-v2
percent: 30
- tag: v3
revisionName: stock-service-example-v3
percent: 30
- tag: latest
latestRevision: true
percent: 0After applying, the test script shows a distribution roughly 4:3:3 among the three versions.
Rollback
Revisions are immutable; to roll back, simply adjust the traffic block to point 100 % (or any desired percentage) to a previous revision.
Comparison with traditional pod‑based gray releases
In classic Kubernetes deployments, gray releases are achieved by manually scaling Pods of each version, which does not guarantee that traffic proportion matches pod proportion. Knative Serving automatically creates Pods based on incoming traffic, allowing precise traffic‑percentage control without pre‑defining replica counts.
Conclusion
Knative Serving’s traffic‑centric model enables fine‑grained gray releases, safe pre‑validation of new revisions, and effortless rollbacks, distinguishing it from traditional pod‑count‑driven approaches.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Native
We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
