.gitlab-ci.yml

流水线入口:阶段

stages:
  - lint
  - test
  - build
  - deploy

流水线以job为单位运行,每个job就是自己想通过流水线做的事情,例如单元测试的job,核心是运行脚本:

go test -short go list ./...

每个阶段下可以定义多个job。

同一阶段的job会并行执行。

阶段是串行执行。

全局变量

variables:
  IMAGE_GROUP: xxx
  NAME_SPACE: xxx
  GOPATH: ${CI_PROJECT_DIR}/.go
  GOMODCACHE: ${CI_PROJECT_DIR}/.go/pkg/mod
  GOCACHE: ${CI_PROJECT_DIR}/.go/.cache/go-build
  GOLANGCI_LINT_CACHE: ${CI_PROJECT_DIR}/.go/.cache/golangci-lint
GOPATH.goGOMODCACHEGOCACHEGOLANGCI_LINT_CACHE

公共模板

job公共模板

.template:
  image: 172.30.3.150/xxx/go-tools:latest
  tags:
    - 172.30.3.219-runner
  interruptible: true
go-tools
  • Dockerfile
FROM golang:1.17.9
USER root

ENV GOPATH /go
ENV PATH ${GOPATH}/bin:$PATH

# 设置私服
RUN go env -w GOPRIVATE=xxx.com
# 设置忽略私服的https证书校验
RUN go env -w GOINSECURE=xxx.com
RUN git config --global http.sslverify false
RUN git config --global https.sslverify false

RUN go env -w GOPROXY="https://goproxy.cn,direct"
RUN go env -w GO111MODULE=on

# install docker
RUN curl -O https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz 
    && tar zxvf docker-latest.tgz 
    && cp docker/docker /usr/local/bin/ 
    && rm -rf docker docker-latest.tgz
tags
.template.
interruptible

缓存模板

.go_cache:
  cache:
    key: go-cache-${CI_PROJECT_PATH_SLUG}
    paths:
      - .go
.go

lint阶段

代码检测job

golangci_lint:
  stage: lint
  only:
    - merge_requests
    - /^release/.*$/
  extends:
    - .go_cache
    - .template
  script:
    - make golangci_lint
stageextendsscript

test阶段

单元测试、检查数据竞争job

unit_test:
  stage: test
  only:
    - merge_requests
    - /^release/.*$/
  extends:
    - .go_cache
    - .template
  cache:
    policy: pull
  script:
    - make unit_test
cache.policy

build阶段

打包镜像的job模板

.build_image:
  stage: build
  only:
    - tags
    - /^release/.*$/
  extends:
    - .go_cache
    - .template

打包镜像job

build_xxx_admin_image:
  extends:
    - .build_image
  script:
    - make build_admin_app
    - make build_admin_image
    - make push_admin_image

build_xxx_interface_image:
  extends:
    - .build_image
  script:
    - make build_interface_app
    - make build_interface_image
    - make push_interface_image

build_xxx_job_image:
  extends:
    - .build_image
  script:
    - make build_job_app
    - make build_job_image
    - make push_job_image

build_xxx_task_image:
  extends:
    - .build_image
  script:
    - make build_task_app
    - make build_task_image
    - make push_task_image
  • 一个阶段多个job。

deploy阶段

部署到测试环境的job模板

.deploy_to_test_k8s:
  stage: deploy
  only:
    - tags
    - /^release/.*$/
  extends:
    - .template
  image:
    name: 172.30.3.150/xxx/kubectl:latest
    entrypoint: [ "" ]
image
172.30.3.150/xxx/kubectlkubectl
  • Dockerfile
FROM bitnami/kubectl

USER root
RUN apt-get update && apt-get install -y --no-install-recommends 
    make git

部署到测试环境job

deploy_admin_to_test_k8s:
  extends:
    - .deploy_to_test_k8s
  needs: [ build_xxx_admin_image ]
  script:
    - make deploy_admin_to_test_k8s

deploy_interface_to_test_k8s:
  extends:
    - .deploy_to_test_k8s
  needs: [ build_xxx_interface_image ]
  script:
    - make deploy_interface_to_test_k8s

deploy_job_to_test_k8s:
  extends:
    - .deploy_to_test_k8s
  needs: [ build_xxx_job_image ]
  script:
    - make deploy_job_to_test_k8s

.deploy_task_to_test_k8s:
  extends:
    - .deploy_to_test_k8s
  needs: [ build_xxx_task_image ]
  script:
    - make deploy_task_to_test_k8s
needs

完整的.gitlab-ci.yml

stages:
  - lint
  - test
  - build
  - deploy

#定义全局变量
variables:
  IMAGE_GROUP: xxx
  NAME_SPACE: xxx
  GOPATH: ${CI_PROJECT_DIR}/.go
  GOMODCACHE: ${CI_PROJECT_DIR}/.go/pkg/mod
  GOCACHE: ${CI_PROJECT_DIR}/.go/.cache/go-build
  GOLANGCI_LINT_CACHE: ${CI_PROJECT_DIR}/.go/.cache/golangci-lint

########################### 公共模板 ###########################

#job公共模板
.template:
  image: 172.30.3.150/xxx/go-tools:latest
  tags:
    - 172.30.3.219-runner
  interruptible: true

#缓存模板
.go_cache:
  cache:
    key: go-cache-${CI_PROJECT_PATH_SLUG}
    paths:
      - .go

########################### lint阶段 ###########################

#代码检测job
golangci_lint:
  stage: lint
  only:
    - merge_requests
    - /^release/.*$/
  extends:
    - .go_cache
    - .template
  script:
    - make golangci_lint

########################### test阶段 ###########################

#单元测试、检查数据竞争job
unit_test:
  stage: test
  only:
    - merge_requests
    - /^release/.*$/
  extends:
    - .go_cache
    - .template
  cache:
    policy: pull
  script:
    - make unit_test

########################### build阶段 ###########################

#打包镜像的job模板
.build_image:
  stage: build
  only:
    - tags
    - /^release/.*$/
  extends:
    - .go_cache
    - .template

#打包镜像job
build_xxx_admin_image:
  extends:
    - .build_image
  script:
    - make build_admin_app
    - make build_admin_image
    - make push_admin_image

build_xxx_interface_image:
  extends:
    - .build_image
  script:
    - make build_interface_app
    - make build_interface_image
    - make push_interface_image

build_xxx_job_image:
  extends:
    - .build_image
  script:
    - make build_job_app
    - make build_job_image
    - make push_job_image

build_xxx_task_image:
  extends:
    - .build_image
  script:
    - make build_task_app
    - make build_task_image
    - make push_task_image

########################### deploy阶段 ###########################

#部署到测试环境的job模板
.deploy_to_test_k8s:
  stage: deploy
  only:
    - tags
    - /^release/.*$/
  extends:
    - .template
  image:
    name: 172.30.3.150/xxx/kubectl:latest
    entrypoint: [ "" ]

#部署到测试环境job
deploy_admin_to_test_k8s:
  extends:
    - .deploy_to_test_k8s
  needs: [ build_xxx_admin_image ]
  script:
    - make deploy_admin_to_test_k8s

deploy_interface_to_test_k8s:
  extends:
    - .deploy_to_test_k8s
  needs: [ build_xxx_interface_image ]
  script:
    - make deploy_interface_to_test_k8s

deploy_job_to_test_k8s:
  extends:
    - .deploy_to_test_k8s
  needs: [ build_xxx_job_image ]
  script:
    - make deploy_job_to_test_k8s

.deploy_task_to_test_k8s:
  extends:
    - .deploy_to_test_k8s
  needs: [ build_xxx_task_image ]
  script:
    - make deploy_task_to_test_k8s

Makefile

.gitlab-ci.yml
VERSION=$(shell git describe --tags --always)

#################################### 代码检查 ####################################

.PHONY: golangci_lint
golangci_lint:
    go mod tidy # 必须先下载依赖,否则golangci-lint会报:could not load export data: no export data for
    go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.0
    golangci-lint run -v --timeout=5m --color always --out-format colored-line-number

#################################### 单元测试 ####################################

.PHONY: unit_test
unit_test:
    go test -short `go list ./...`

#################################### 构建应用二进制执行文件 ####################################

.PHONY: build_all_app
build_all_app: build_admin_app build_interface_app build_job_app build_task_app

.PHONY: build_admin_app
build_admin_app:
    make build_app SUB_MODULE=admin

.PHONY: build_interface_app
build_interface_app:
    make build_app SUB_MODULE=interface

.PHONY: build_job_app
build_job_app:
    make build_app SUB_MODULE=job

.PHONY: build_task_app
build_task_app:
    make build_app SUB_MODULE=task

.PHONY: build_app
build_app:
    mkdir -p bin
    cd cmd/$(SUB_MODULE) && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o ../../bin/ && cd -

#################################### 打镜像 ####################################

.PHONY: build_all_image
build_all_image: build_admin_image build_interface_image build_job_image build_task_image

.PHONY: build_admin_image
build_admin_image:
    make build_image SUB_MODULE=admin

.PHONY: build_interface_image
build_interface_image:
    make build_image SUB_MODULE=interface

.PHONY: build_job_image
build_job_image:
    make build_image SUB_MODULE=job

.PHONY: build_task_image
build_task_image:
    make build_image SUB_MODULE=task

.PHONY: build_image
build_image:
    docker build --build-arg SUB_MODULE=$(SUB_MODULE) -t xxx-$(SUB_MODULE):$(VERSION) .

#################################### 推镜像到私仓 ####################################

.PHONY: push_all_image
build_all_image: push_admin_image push_interface_image push_job_image push_task_image

.PHONY: push_admin_image
push_admin_image:
    make push_image SUB_MODULE=admin

.PHONY: push_interface_image
push_interface_image:
    make push_image SUB_MODULE=interface

.PHONY: push_job_image
push_job_image:
    make push_image SUB_MODULE=job

.PHONY: push_task_image
push_task_image:
    make push_image SUB_MODULE=task

.PHONY: push_image
push_image:
    docker login "${DOCKER_REGISTRY_SERVER}" --username "${DOCKER_REGISTRY_USER}" --password "${DOCKER_REGISTRY_PASSWORD}"

    docker tag "xxx-$(SUB_MODULE):$(VERSION)" "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):$(VERSION)"
    docker push "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):$(VERSION)"
    docker rmi -f "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):$(VERSION)"

    docker tag "xxx-$(SUB_MODULE):$(VERSION)" "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):latest"
    docker push "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):latest"
    docker rmi -f "${DOCKER_REGISTRY_ADDR}/${IMAGE_GROUP}/xxx-$(SUB_MODULE):latest"

    docker rmi -f "xxx-$(SUB_MODULE):$(VERSION)"

#################################### 部署到k8s ####################################

.PHONY: deploy_all_to_test_k8s
deploy_all_to_test_k8s: deploy_admin_to_test_k8s deploy_interface_to_test_k8s deploy_job_to_test_k8s deploy_task_to_test_k8s

.PHONY: deploy_admin_to_test_k8s
deploy_admin_to_test_k8s:
    make deploy_to_test_k8s SUB_MODULE=admin

.PHONY: deploy_interface_to_test_k8s
deploy_interface_to_test_k8s:
    make deploy_to_test_k8s SUB_MODULE=interface

.PHONY: deploy_job_to_test_k8s
deploy_job_to_test_k8s:
    make deploy_to_test_k8s SUB_MODULE=job

.PHONY: deploy_task_to_test_k8s
deploy_task_to_test_k8s:
    make deploy_to_test_k8s SUB_MODULE=task

.PHONY: deploy_to_test_k8s
deploy_to_test_k8s:
    echo ${K8S_CONFIG_192} | base64 -id > /.kube/config
    sed -i "s/IMAGE_VERSION/$(VERSION)/g" deploy/$(SUB_MODULE)/test/*.yaml
    sed -i "s/NAME_SPACE/${NAME_SPACE}/g" deploy/$(SUB_MODULE)/test/*.yaml
    sed -i "s/DOCKER_REGISTRY_ADDR/${DOCKER_REGISTRY_ADDR}/g" deploy/$(SUB_MODULE)/test/*.yaml
    sed -i "s/IMAGE_GROUP/${IMAGE_GROUP}/g" deploy/$(SUB_MODULE)/test/*.yaml
    kubectl apply -f deploy/$(SUB_MODULE)/test
VERSION.PHONYDOCKER_REGISTRY_SERVER