# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: Deploy backend application to production
run-name: Deploy backend application to production
# git add .; git commit -m "test: test github actions"
# git tag v1.1.8; git push; git push main v1.1.8
REGISTER_NAMESPACE: e-commence
# https://docs.github.com/zh/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context
#VERSION: ${{ github.ref_name }}
# 目标架构列表,例如: linux/amd64,linux/arm64
TARGET_PLATFORMS: linux/amd64
GO_IMAGE: golang:1.23.3-alpine3.20
GO_PROXY: https://proxy.golang.org
BACKEND_NAMESPACE: tiktok
service: [ addresses, balances, cart, checkout, credit_cards, order, payment, product, user ] # 定义要并行执行的服务
working-directory: ${{ matrix.service }}
# Service containers to run with `container-job`
# Label used to access the service container
image: postgres:17-alpine
# Provide the password for postgres
POSTGRES_PASSWORD: postgres
# 此可选环境变量可用于为首次启动映像时创建的默认数据库定义不同的名称。如果未指定,则将使用 POSTGRES_USER 的值。
# Set health checks to wait until postgres has started
# Maps tcp port 5432 on service container to the host
- # 检出仓库中的代码,确保脚本可以访问仓库中的所有文件
name: Checkout repository
uses: actions/checkout@v4
# https://github.com/actions/setup-go#caching-dependency-files-and-build-outputs
uses: actions/setup-go@v5
# 检查项目中所有的go.sum, 对于单体和多服务的应用都生效
cache-dependency-path: '**/go.sum'
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.18.1/migrate.linux-amd64.tar.gz | tar xvz
sudo mv migrate /usr/bin/
- name: Run database migrate
export DB_SOURCE="postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable"
if [ -d ${{ matrix.service }} ]; then
echo "Migration directory exists. Running migrations..."
echo "Migration directory does not exist. Skipping migrations."
go test -short -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
- { service: addresses, http_port: 30015, grpc_port: 30016 }
- { service: balances, http_port: 30017, grpc_port: 30018 }
- { service: cart, http_port: 30003, grpc_port: 30004 }
- { service: checkout, http_port: 30005, grpc_port: 30006 }
- { service: credit_cards, http_port: 30007, grpc_port: 30008 }
- { service: order, http_port: 30009, grpc_port: 30010 }
- { service: payment, http_port: 30011, grpc_port: 30012 }
- { service: product, http_port: 30013, grpc_port: 30014 }
- { service: user, http_port: 30001, grpc_port: 30002 }
working-directory: ${{ matrix.service_config.service }} # 动态指定工作目录
- # 检出仓库中的代码,确保脚本可以访问仓库中的所有文件
name: Checkout repository
uses: actions/checkout@v4
- # 设置 QEMU 仿真器。允许你在 x86 架构的主机上构建和测试其他架构的 Docker 镜像
# https://github.com/docker/setup-qemu-action
uses: docker/setup-qemu-action@v3
# - # Buildx 是 Docker 的一个插件,支持多平台构建
# name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v3
key: ${{ runner.os }}-go-modules-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-modules-
name: Login Cloud Registry
run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login ${{ secrets.REGISTRY }} --username ${{ secrets.REGISTRY_USERNAME }} --password-stdin
name: Build tag and push image to Cloud Registry
-t actions/${{ matrix.service_config.service }} \
--build-arg GO_PROXY=$GO_PROXY \
--build-arg GOIMAGE=$GO_IMAGE \
--build-arg CGOENABLED=$CGO_ENABLED \
--build-arg VERSION=$VERSION \
--build-arg HTTP_PORT=${{ matrix.service_config.http_port }} \
--build-arg GRPC_PORT=${{ matrix.service_config.grpc_port }} \
--build-arg GOARCH=$GOARCH
docker tag actions/${{ matrix.service_config.service }} ${{ secrets.REGISTRY }}/${REGISTER_NAMESPACE}/${{ matrix.service_config.service }}:$VERSION
# docker tag actions/backend ${{ secrets.REGISTRY }}/${REGISTER_NAMESPACE}/${{ matrix.service_config.service }}:latest
# docker tag actions/backend ${{ secrets.REGISTRY }}/${REGISTER_NAMESPACE}/${{ matrix.service_config.service }}:$GITHUB_SHA
docker push ${{ secrets.REGISTRY }}/${REGISTER_NAMESPACE}/${{ matrix.service_config.service }}:$VERSION
# docker push ${{ secrets.REGISTRY }}/${REGISTER_NAMESPACE}/${{ matrix.service_config.service }}:latest
# docker push ${{ secrets.REGISTRY }}/${REGISTER_NAMESPACE}/${{ matrix.service_config.service }}:$GITHUB_SHA
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl{,.sha256}"
echo "$(cat kubectl.sha256) kubectl" | sha256sum --check
cp ./kubectl /usr/local/bin
- name: Write Kubernetes config file
echo "${{secrets.KUBE_CONF}}" > ~/.kube/config
uses: nick-fields/retry@v3
if kubectl get ns $BACKEND_NAMESPACE; then
echo "namespaces $BACKEND_NAMESPACE already exists, skip create"
kubectl create ns $BACKEND_NAMESPACE
kubectl config set-context --current --namespace $BACKEND_NAMESPACE
uses: nick-fields/retry@v3
kubectl delete secret db-source-secret --ignore-not-found
kubectl delete secret redis-address-secret --ignore-not-found
kubectl delete secret redis-username-secret --ignore-not-found
kubectl delete secret redis-password-secret --ignore-not-found
kubectl create secret generic db-source-secret --from-literal='DB_SOURCE=${{ secrets.DB_SOURCE }}'
kubectl create secret generic redis-address-secret --from-literal='REDIS_ADDRESS=${{ secrets.REDIS_ADDRESS }}'
kubectl create secret generic redis-username-secret --from-literal='REDIS_USERNAME=${{ secrets.REDIS_USERNAME }}'
kubectl create secret generic redis-password-secret --from-literal='REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}'
# kubectl delete secret db-source-secret --ignore-not-found
# kubectl delete secret redis-address-secret --ignore-not-found
# kubectl delete secret redis-username-secret --ignore-not-found
# kubectl delete secret redis-password-secret --ignore-not-found
# kubectl create secret generic db-source-secret --from-literal='DB_SOURCE=${{ secrets.DB_SOURCE }}'
# kubectl create secret generic redis-address-secret --from-literal='REDIS_ADDRESS=${{ secrets.REDIS_ADDRESS }}'
# kubectl create secret generic redis-username-secret --from-literal='REDIS_USERNAME=${{ secrets.REDIS_USERNAME }}'
# kubectl create secret generic redis-password-secret --from-literal='REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}'
service: [ addresses, balances, cart, checkout, credit_cards, order, payment, product, user ] # 定义要并行执行的服务
- # 检出仓库中的代码,确保脚本可以访问仓库中的所有文件
name: Checkout repository
uses: actions/checkout@v4
- name: Install Argocd CLI
curl -LO https://github.com/argoproj/argo-cd/releases/download/v2.13.3/argocd-linux-amd64
mv argocd-linux-amd64 argocd
cp ./argocd /usr/local/bin
# https://github.com/marketplace/actions/retry-step
- name: Connect ArgoCD Server
uses: nick-fields/retry@v3
${{ secrets.ARGOCD_SERVER_ADDR }} \
--username ${{ secrets.ARGOCD_SERVER_USER }} \
--password ${{ secrets.ARGOCD_SERVER_PASS }} \
# - name: Connect ArgoCD Server
# ${{ secrets.ARGOCD_SERVER_ADDR }} \
# --username ${{ secrets.ARGOCD_SERVER_USER }} \
# --password ${{ secrets.ARGOCD_SERVER_PASS }} \
- name: Connect Kubernetes Cluster
echo "${{secrets.KUBE_CONF}}" > ~/.kube/config
uses: nick-fields/retry@v3
if kubectl get ns $BACKEND_NAMESPACE; then
echo "namespaces $BACKEND_NAMESPACE already exists, skip create"
kubectl create ns $BACKEND_NAMESPACE
kubectl config set-context --current --namespace $BACKEND_NAMESPACE
# if kubectl get ns $BACKEND_NAMESPACE; then
# echo "namespaces $BACKEND_NAMESPACE already exists, skip create"
# kubectl create ns $BACKEND_NAMESPACE
# kubectl config set-context --current --namespace $BACKEND_NAMESPACE
- name: Deploy app to kubernetes
uses: nick-fields/retry@v3
echo "ls ${{ matrix.service_config.service }}/manifests/kustomize/overlays/production"
ls ${{ matrix.service_config.service }}/manifests/kustomize/overlays/production
kubectl apply -f ${{ matrix.service_config.service }}/application.yaml
argocd app set argocd/${REGISTER_NAMESPACE}-${{ matrix.service_config.service }} \
--kustomize-image example=${{ secrets.REGISTRY }}/${REGISTER_NAMESPACE}/${{ matrix.service_config.service }}:$VERSION
# - name: Deploy app to kubernetes
# kubectl apply -f ./application.yaml
# argocd app set argocd/${REGISTER_NAMESPACE}-${{ matrix.service_config.service }} --kustomize-image example=${{ secrets.REGISTRY }}/${REGISTER_NAMESPACE}/${{ matrix.service_config.service }}:$VERSION
uses: nick-fields/retry@v3
# kubectl rollout status deploy || kubectl rollout undo deploy
kubectl get deploy -owide
# # kubectl rollout status deploy || kubectl rollout undo deploy
# kubectl get deploy -owide