基于demo理解osm的二次开发流程 - flomesh-io/osm GitHub Wiki

通过本文档,尝试让开发人员快速掌握OpenServiceMesh二次开发的流程。

建议优选阅读 demo/readme.md

1.准备工作

OS: Ubuntu 20.04

ARCH: amd64/arm64

1.1获取工程源码

下载OpenServiceMesh源码,切换到v1.0.0,获取go依赖库

git clone https://github.com/openservicemesh/osm.git
cd osm
git checkout v1.0.0
git status
GO111MODULE=on GOPROXY=https://goproxy.cn go get -d ./...

1.2环境设置

通过环境变量,设置使用本地的Registry

echo export CTR_REGISTRY=localhost:5000/flomesh >> ~/.bashrc
source ~/.bashrc

初始化.env,调整环境变量

make .env
sed -i 's/^# export TIMEOUT=90s/export TIMEOUT=900s/g' .env
sed -i 's/localhost:5000$/localhost:5000\/flomesh/g' .env
sed -i 's/^# export CTR_TAG=.*/export CTR_TAG=latest/g' .env
sed -i 's/^#export USE_PRIVATE_REGISTRY=.*/export USE_PRIVATE_REGISTRY=true/g' .env

arm64下额外执行:

echo export TARGETS=linux/arm64 >> ~/.bashrc
echo export DOCKER_BUILDX_PLATFORM=linux/arm64 >> ~/.bashrc
source ~/.bashrc

1.3支持远程调试模式

1.3.1注入远程调试工具dlv

sed -i '/WORKDIR \/osm/i\WORKDIR /delve' dockerfiles/Dockerfile.osm-bootstrap
sed -i '/WORKDIR \/osm/i\RUN --mount=type=cache,target=/root/.cache/go-build \\' dockerfiles/Dockerfile.osm-bootstrap
sed -i '/WORKDIR \/osm/i\    --mount=type=cache,target=/go/pkg \\' dockerfiles/Dockerfile.osm-bootstrap
sed -i '/WORKDIR \/osm/i\    CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go install github.com/go-delve/delve/cmd/dlv@latest' dockerfiles/Dockerfile.osm-bootstrap
sed -i '/COPY --from=builder/a\COPY --from=builder /go/bin/dlv /' dockerfiles/Dockerfile.osm-bootstrap

sed -i '/WORKDIR \/osm/i\WORKDIR /delve' dockerfiles/Dockerfile.osm-injector
sed -i '/WORKDIR \/osm/i\RUN --mount=type=cache,target=/root/.cache/go-build \\' dockerfiles/Dockerfile.osm-injector
sed -i '/WORKDIR \/osm/i\    --mount=type=cache,target=/go/pkg \\' dockerfiles/Dockerfile.osm-injector
sed -i '/WORKDIR \/osm/i\    CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go install github.com/go-delve/delve/cmd/dlv@latest' dockerfiles/Dockerfile.osm-injector
sed -i '/COPY --from=builder/a\COPY --from=builder /go/bin/dlv /' dockerfiles/Dockerfile.osm-injector

sed -i '/WORKDIR \/osm/i\WORKDIR /delve' dockerfiles/Dockerfile.osm-controller
sed -i '/WORKDIR \/osm/i\RUN --mount=type=cache,target=/root/.cache/go-build \\' dockerfiles/Dockerfile.osm-controller
sed -i '/WORKDIR \/osm/i\    --mount=type=cache,target=/go/pkg \\' dockerfiles/Dockerfile.osm-controller
sed -i '/WORKDIR \/osm/i\    CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go install github.com/go-delve/delve/cmd/dlv@latest' dockerfiles/Dockerfile.osm-controller
sed -i '/COPY --from=builder/a\COPY --from=builder /go/bin/dlv /' dockerfiles/Dockerfile.osm-controller

1.3.2增加GCC编译参数,支持GDB变量打印

sed -i 's/-ldflags "$LDFLAGS"/-ldflags "$LDFLAGS" -gcflags=all="-N -l"/g' dockerfiles/Dockerfile.osm-bootstrap
sed -i 's/-ldflags "$LDFLAGS"/-ldflags "$LDFLAGS" -gcflags=all="-N -l"/g' dockerfiles/Dockerfile.osm-injector
sed -i 's/-ldflags "$LDFLAGS"/-ldflags "$LDFLAGS" -gcflags=all="-N -l"/g' dockerfiles/Dockerfile.osm-controller

1.3.3删除Makefile中GCC优化编译参数

sed -i 's/ -s -w"/"/g' Makefile

1.3.4设置远程调试端口号

sed -i '/containerPort: 9091/a\              containerPort: 30121' charts/osm/templates/osm-bootstrap-deployment.yaml
sed -i '/containerPort: 9091/a\            - name: "dlv"' charts/osm/templates/osm-bootstrap-deployment.yaml
sed -i "s#command: \['/osm-bootstrap'\]#command: \['/dlv', '--listen=:30121', '--headless=true', '--api-version=2', '--accept-multiclient', 'exec', '/osm-bootstrap', '--continue', '--'\]#g" charts/osm/templates/osm-bootstrap-deployment.yaml

sed -i '/containerPort: 9091/a\              containerPort: 30123' charts/osm/templates/osm-deployment.yaml
sed -i '/containerPort: 9091/a\            - name: "dlv"' charts/osm/templates/osm-deployment.yaml
sed -i "s#command: \['/osm-controller'\]#command: \['/dlv', '--listen=:30123', '--headless=true', '--api-version=2', '--accept-multiclient', 'exec', '/osm-controller', '--continue', '--'\]#g" charts/osm/templates/osm-deployment.yaml

sed -i '/containerPort: 9091/a\              containerPort: 30122' charts/osm/templates/osm-injector-deployment.yaml
sed -i '/containerPort: 9091/a\            - name: "dlv"' charts/osm/templates/osm-injector-deployment.yaml
sed -i "s#command: \['/osm-injector'\]#command: \['/dlv', '--listen=:30122', '--headless=true', '--api-version=2', '--accept-multiclient', 'exec', '/osm-injector', '--continue', '--'\]#g" charts/osm/templates/osm-injector-deployment.yaml

1.3.5远程调试会增加内存的使用,放大内存上限

sed -i 's/memory: "64M"/memory: "256M"/g' charts/osm/values.yaml
sed -i 's/memory: "128M"/memory: "256M"/g' charts/osm/values.yaml

1.4GOPROXY国内代理

sed -i 's/CH go/CH GO111MODULE=on GOPROXY=https:\/\/goproxy.cn go/g' dockerfiles/Dockerfile.demo
sed -i 's/CH go/CH GO111MODULE=on GOPROXY=https:\/\/goproxy.cn go/g' dockerfiles/Dockerfile.osm-bootstrap
sed -i 's/CH go/CH GO111MODULE=on GOPROXY=https:\/\/goproxy.cn go/g' dockerfiles/Dockerfile.osm-injector
sed -i 's/CH go/CH GO111MODULE=on GOPROXY=https:\/\/goproxy.cn go/g' dockerfiles/Dockerfile.osm-controller

1.5丰富镜像里常用的操作指令

sed -i 's#gcr.io/distroless/base#--platform=$BUILDPLATFORM busybox:1.33#g' dockerfiles/Dockerfile.demo
sed -i 's#gcr.io/distroless/static#--platform=$BUILDPLATFORM busybox:1.33#g' dockerfiles/Dockerfile.osm-bootstrap
sed -i 's#gcr.io/distroless/static#--platform=$BUILDPLATFORM busybox:1.33#g' dockerfiles/Dockerfile.osm-injector
sed -i 's#gcr.io/distroless/static#--platform=$BUILDPLATFORM busybox:1.33#g' dockerfiles/Dockerfile.osm-controller

1.6远程调试端口转发脚本

sudo tee ./scripts/dlv-port-forward-osm-bootstrap.sh <<-'EOF'
#!/bin/bash
# shellcheck disable=SC1091
source .env

POD="$(kubectl get pods --selector app=osm-bootstrap -n "$K8S_NAMESPACE" --no-headers | grep 'Running' | awk 'NR==1{print $1}')"

kubectl port-forward "$POD" -n "$K8S_NAMESPACE" 30121:30121
EOF

sudo tee ./scripts/dlv-port-forward-osm-injector.sh <<-'EOF'
#!/bin/bash
# shellcheck disable=SC1091
source .env

POD="$(kubectl get pods --selector app=osm-injector -n "$K8S_NAMESPACE" --no-headers | grep 'Running' | awk 'NR==1{print $1}')"

kubectl port-forward "$POD" -n "$K8S_NAMESPACE" 30122:30122
EOF

sudo tee ./scripts/dlv-port-forward-osm-controller.sh <<-'EOF'
#!/bin/bash
# shellcheck disable=SC1091
source .env

POD="$(kubectl get pods --selector app=osm-controller -n "$K8S_NAMESPACE" --no-headers | grep 'Running' | awk 'NR==1{print $1}')"

kubectl port-forward "$POD" -n "$K8S_NAMESPACE" 30123:30123
EOF

sudo tee ./scripts/dlv-port-forward-all.sh <<-'EOF'
#!/bin/bash

./scripts/dlv-port-forward-osm-bootstrap.sh &
./scripts/dlv-port-forward-osm-injector.sh &
./scripts/dlv-port-forward-osm-controller.sh &

wait
EOF

chmod u+x ./scripts/dlv-port-forward-osm-bootstrap.sh
chmod u+x ./scripts/dlv-port-forward-osm-injector.sh
chmod u+x ./scripts/dlv-port-forward-osm-controller.sh
chmod u+x ./scripts/dlv-port-forward-all.sh

1.7ARM64支持

1.7.1架构调整

find charts -type f | xargs sed -i 's/amd64/arm64/g'
find demo -type f | xargs sed -i 's/amd64/arm64/g'

1.7.2依赖镜像调整

sed -i 's/kind create cluster --name/kind create cluster --image kindest\/node-arm64:v1.20.15 --name/g' scripts/kind-with-registry.sh

sed -i 's/image: mysql:5.6/image: devilbox\/mysql:mysql-8.0/g' demo/deploy-mysql.sh

#envoyproxy/envoy:v1.19.3
sed -i 's/repository: envoyproxy\/envoy-alpine/repository: envoyproxy\/envoy/g' charts/osm/values.yaml
sed -i 's/envoy-alpine@sha256:6502a637c6c5fba4d03d0672d878d12da4bcc7a0d0fb3f1d506982dde0039abd/envoy@sha256:9bbd3140c7ba67e32ecdf1731c03f010e2de386ef84d215023327624fc2c37ae/g' charts/osm/values.yaml
sed -i 's/envoy-alpine@sha256:6502a637c6c5fba4d03d0672d878d12da4bcc7a0d0fb3f1d506982dde0039abd/envoy@sha256:9bbd3140c7ba67e32ecdf1731c03f010e2de386ef84d215023327624fc2c37ae/g' charts/osm/values.schema.json

1.8暂关WASMStats

sed -i 's/enableWASMStats: true$/enableWASMStats: false/g' charts/osm/values.yaml

sed -i 's/^FROM --platform=\$BUILDPLATFORM openservicemesh\/proxy-wasm-cpp-sdk/#FROM --platform=\$BUILDPLATFORM openservicemesh\/proxy-wasm-cpp-sdk/g' dockerfiles/Dockerfile.osm-controller
sed -i 's/^WORKDIR \/wasm/#WORKDIR \/wasm/g' dockerfiles/Dockerfile.osm-controller
sed -i 's/^COPY \.\/wasm \./#COPY \.\/wasm \./g' dockerfiles/Dockerfile.osm-controller
sed -i 's/^RUN \/build_wasm\.sh/#RUN \/build_wasm\.sh/g' dockerfiles/Dockerfile.osm-controller
sed -i 's/^COPY --from=wasm/#COPY --from=wasm/g' dockerfiles/Dockerfile.osm-controller

备注,现存的问题:

A. 暂关wasm stats

1.9.启动Kind集群

make kind-up

1.10设置secret

1.10.1创建secret

只需执行一次,后续再发布时,本步骤可忽略

kubectl create namespace osm-system

kubectl --namespace=osm-system \
create secret docker-registry acr-creds \
--docker-server=localhost:5000 \
--docker-username=flomesh \
--docker-password=flomesh

kubectl get secret acr-creds --namespace=osm-system

1.10.2设置.env文件secret

sed -i '/export CTR_REGISTRY_PASSWORD=/i\export CTR_REGISTRY_USERNAME=flomesh' .env
sed -i 's/^export CTR_REGISTRY_PASSWORD=.*/export CTR_REGISTRY_PASSWORD=flomesh/' .env

2.本地镜像加速

2.1清理本地镜像

非必要操作,根据自己的实际情况选择是否执行

清理本地Registry上的镜像

REGPOD="$(docker ps --filter 'name=kind-registry' |tail -n 1| awk 'NR==1{print $1}')"
docker exec $REGPOD  bin/registry garbage-collect /etc/docker/registry/config.yml
docker exec $REGPOD rm -rf /var/lib/registry/docker/registry/v2/repositories/flomesh
docker restart $REGPOD

查看本地Registry上的镜像

curl http://localhost:5000/v2/_catalog | jq

2.2清理本机镜像

非必要操作,根据自己的实际情况选择是否执行

docker ps -a | grep osm- | awk -F' ' '{print $1}' | xargs docker stop
docker ps -a | grep osm- | awk -F' ' '{print $1}' | xargs docker rm
docker images -a|grep localhost:5000/flomesh | awk -F ' ' '{print $3}' | xargs docker rmi
docker images

2.3本地镜像缓存

2.3.1 AMD64架构执行

docker pull docker.io/library/alpine:3
docker pull docker.io/library/busybox:1.33
docker pull docker.io/openservicemesh/proxy-wasm-cpp-sdk:956f0d500c380cc1656a2d861b7ee12c2515a664
docker pull docker.io/library/golang:1.17
docker pull docker.io/library/mysql:5.6
docker pull docker.io/envoyproxy/envoy-alpine:v1.19.3
docker pull docker.io/projectcontour/contour:v1.18.0
docker pull docker.io/curlimages/curl:latest
docker pull docker.io/flomesh/pipy-nightly:latest
docker pull gcr.io/distroless/static:latest

docker tag docker.io/library/alpine:3 localhost:5000/library/alpine:3
docker tag docker.io/library/busybox:1.33 localhost:5000/library/busybox:1.33
docker tag docker.io/openservicemesh/proxy-wasm-cpp-sdk:956f0d500c380cc1656a2d861b7ee12c2515a664 localhost:5000/openservicemesh/proxy-wasm-cpp-sdk:956f0d500c380cc1656a2d861b7ee12c2515a664
docker tag docker.io/library/golang:1.17 localhost:5000/library/golang:1.17
docker tag docker.io/library/mysql:5.6 localhost:5000/library/mysql:5.6
docker tag docker.io/envoyproxy/envoy-alpine:v1.19.3 localhost:5000/envoyproxy/envoy-alpine:v1.19.3
docker tag docker.io/projectcontour/contour:v1.18.0 localhost:5000/projectcontour/contour:v1.18.0
docker tag docker.io/curlimages/curl:latest localhost:5000/curlimages/curl:latest
docker tag docker.io/flomesh/pipy-nightly:latest localhost:5000/flomesh/pipy-nightly:latest
docker tag gcr.io/distroless/static:latest localhost:5000/distroless/static:latest

docker push localhost:5000/library/alpine:3
docker push localhost:5000/library/busybox:1.33
docker push localhost:5000/openservicemesh/proxy-wasm-cpp-sdk:956f0d500c380cc1656a2d861b7ee12c2515a664
docker push localhost:5000/library/golang:1.17
docker push localhost:5000/library/mysql:5.6
docker push localhost:5000/envoyproxy/envoy-alpine:v1.19.3
docker push localhost:5000/projectcontour/contour:v1.18.0
docker push localhost:5000/curlimages/curl:latest
docker push localhost:5000/flomesh/pipy-nightly:latest
docker push localhost:5000/distroless/static:latest

find dockerfiles -type f | xargs sed -i 's# alpine:3$# localhost:5000/library/alpine:3#g'
find dockerfiles -type f | xargs sed -i 's# busybox:1.33$# localhost:5000/library/busybox:1.33#g'
find dockerfiles -type f | xargs sed -i 's# busybox:1.33 # localhost:5000/library/busybox:1.33 #g'
find dockerfiles -type f | xargs sed -i 's# golang:\$GO_VERSION # localhost:5000/library/golang:$GO_VERSION #g'
find dockerfiles -type f | xargs sed -i 's#gcr.io/distroless/static#localhost:5000/distroless/static#g'
find dockerfiles -type f | xargs sed -i 's# openservicemesh/proxy-wasm-cpp-sdk# localhost:5000/openservicemesh/proxy-wasm-cpp-sdk#g'

sed -i 's#image: mysql:5.6#image: localhost:5000/library/mysql:5.6#g' demo/deploy-mysql.sh
sed -i 's#image: curlimages/curl#image: localhost:5000/curlimages/curl#g' demo/multicluster-fault-injection.sh
sed -i 's#docker.io#localhost:5000#g' charts/osm/values.yaml
sed -i 's#sidecarImage: envoyproxy/envoy-alpine:v1.19.3.*#sidecarImage: localhost:5000/envoyproxy/envoy-alpine:v1.19.3#g' charts/osm/values.yaml
sed -i 's#curlImage: curlimages/curl#curlImage: localhost:5000/curlimages/curl#g' charts/osm/values.yaml

2.3.2 ARM64架构执行

docker pull docker.io/arm64v8/alpine:3.12
docker pull docker.io/library/busybox:1.33
docker pull docker.io/library/golang:1.17
docker pull docker.io/devilbox/mysql:mysql-8.0
docker pull docker.io/envoyproxy/envoy:v1.19.3
docker pull docker.io/projectcontour/contour:v1.18.0
docker pull docker.io/curlimages/curl:latest
docker pull docker.io/flomesh/pipy-nightly:latest
docker pull gcr.io/distroless/static:latest
#docker pull docker.io/naqvis/proxy-wasm-cpp-sdk:v2

docker tag docker.io/arm64v8/alpine:3.12 localhost:5000/arm64v8/alpine:3.12
docker tag docker.io/library/busybox:1.33 localhost:5000/library/busybox:1.33
docker tag docker.io/library/golang:1.17 localhost:5000/library/golang:1.17
docker tag docker.io/devilbox/mysql:mysql-8.0 localhost:5000/devilbox/mysql:mysql-8.0
docker tag docker.io/envoyproxy/envoy:v1.19.3 localhost:5000/envoyproxy/envoy:v1.19.3
docker tag docker.io/projectcontour/contour:v1.18.0 localhost:5000/projectcontour/contour:v1.18.0
docker tag docker.io/curlimages/curl:latest localhost:5000/curlimages/curl:latest
docker tag docker.io/flomesh/pipy-nightly:latest localhost:5000/flomesh/pipy-nightly:latest
docker tag gcr.io/distroless/static:latest localhost:5000/distroless/static:latest
#docker tag docker.io/naqvis/proxy-wasm-cpp-sdk:v2 localhost:5000/naqvis/proxy-wasm-cpp-sdk:v2

docker push localhost:5000/arm64v8/alpine:3.12
docker push localhost:5000/library/busybox:1.33
docker push localhost:5000/library/golang:1.17
docker push localhost:5000/devilbox/mysql:mysql-8.0
docker push localhost:5000/envoyproxy/envoy:v1.19.3
docker push localhost:5000/projectcontour/contour:v1.18.0
docker push localhost:5000/curlimages/curl:latest
docker push localhost:5000/flomesh/pipy-nightly:latest
docker push localhost:5000/distroless/static:latest
#docker push localhost:5000/naqvis/proxy-wasm-cpp-sdk:v2

find dockerfiles -type f | xargs sed -i 's# alpine:3$# localhost:5000/arm64v8/alpine:3.12#g'
find dockerfiles -type f | xargs sed -i 's# busybox:1.33$# localhost:5000/library/busybox:1.33#g'
find dockerfiles -type f | xargs sed -i 's# busybox:1.33 # localhost:5000/library/busybox:1.33 #g'
find dockerfiles -type f | xargs sed -i 's# golang:\$GO_VERSION # localhost:5000/library/golang:$GO_VERSION #g'
find dockerfiles -type f | xargs sed -i 's#gcr.io/distroless/static#localhost:5000/distroless/static#g'
find dockerfiles -type f | xargs sed -i 's#openservicemesh/proxy-wasm-cpp-sdk:.* AS#localhost:5000/naqvis/proxy-wasm-cpp-sdk:v2 AS#g'

sed -i 's# devilbox/mysql:mysql-8.0# localhost:5000/devilbox/mysql:mysql-8.0#g' demo/deploy-mysql.sh
sed -i 's# curlimages/curl# localhost:5000/devilbox/curlimages/curl#g' demo/multicluster-fault-injection.sh
sed -i 's#docker.io#localhost:5000#g' charts/osm/values.yaml
sed -i 's#sidecarImage: envoyproxy/envoy.*#sidecarImage: localhost:5000/envoyproxy/envoy:v1.19.3#g' charts/osm/values.yaml
sed -i 's#curlImage: curlimages/curl#curlImage: localhost:5000/curlimages/curl#g' charts/osm/values.yaml

3.工程发布

完成相关的功能代码修改后,执行如下操作

3.1sidecar替换为pipy

sed -i 's#sidecarImage: .*#sidecarImage: localhost:5000/flomesh/pipy-nightly:latest#g' charts/osm/values.yaml
sed -i 's#repository: envoyproxy/envoy#repository: flomesh/pipy-nightly#g' charts/osm/values.yaml
sed -i 's#tag: v1.19.3#tag: latest#g' charts/osm/values.yaml
sed -i '/COPY --from=builder \/osm\/osm-controller \//aCOPY pipyrepo \/repo' dockerfiles/Dockerfile.osm-controller

3.2编译镜像文件

make docker-build DOCKER_BUILDX_OUTPUT=type=docker

docker images | grep localhost:5000/flomesh

3.3上传镜像文件

docker push localhost:5000/flomesh/osm-healthcheck
docker push localhost:5000/flomesh/osm-preinstall
docker push localhost:5000/flomesh/osm-bootstrap
docker push localhost:5000/flomesh/osm-controller
docker push localhost:5000/flomesh/osm-injector
docker push localhost:5000/flomesh/tcp-client
docker push localhost:5000/flomesh/tcp-echo-server
docker push localhost:5000/flomesh/bookwarehouse
docker push localhost:5000/flomesh/bookstore
docker push localhost:5000/flomesh/bookthief
docker push localhost:5000/flomesh/bookbuyer
docker push localhost:5000/flomesh/osm-crds
docker push localhost:5000/flomesh/init

curl http://localhost:5000/v2/_catalog | jq

3.4更新values.yaml文件中镜像摘要

sed -i "s/osmController: \".*\"/osmController: \"`make docker-digest-osm-controller | awk -F' ' '{print $2}'`\"/g" charts/osm/values.yaml
sed -i "s/osmInjector: \".*\"/osmInjector: \"`make docker-digest-osm-injector | awk -F' ' '{print $2}'`\"/g" charts/osm/values.yaml
sed -i "s/osmSidecarInit: \".*\"/osmSidecarInit: \"`make docker-digest-init | awk -F' ' '{print $2}'`\"/g" charts/osm/values.yaml
sed -i "s/osmCRDs: \".*\"/osmCRDs: \"`make docker-digest-osm-crds | awk -F' ' '{print $2}'`\"/g" charts/osm/values.yaml
sed -i "s/osmBootstrap: \".*\"/osmBootstrap: \"`make docker-digest-osm-bootstrap | awk -F' ' '{print $2}'`\"/g" charts/osm/values.yaml
sed -i "s/osmPreinstall: \".*\"/osmPreinstall: \"`make docker-digest-osm-preinstall | awk -F' ' '{print $2}'`\"/g" charts/osm/values.yaml
sed -i "s/osmHealthcheck: \".*\"/osmHealthcheck: \"`make docker-digest-osm-healthcheck | awk -F' ' '{print $2}'`\"/g" charts/osm/values.yaml

3.5编译osm

rm -rf bin/osm
rm -rf cmd/cli/chart.tgz
make build-osm

3.6重启kind集群

make kind-reset
make kind-up

3.7开启一个窗口监视pods的状态

watch -n 2 kubectl get pods -A -o wide

3.8运行demo

./demo/run-osm-demo.sh

3.9打开调试端口转发

./scripts/dlv-port-forward-all.sh

3.10IDE里配置远程调试并运行

3.11调整流量策略并运行

demo/deploy-traffic-specs.sh
demo/deploy-traffic-split.sh
demo/deploy-traffic-target.sh
demo/deploy-traffic-target-with-same-sa.sh

Enjoy it!