• tekton+argocd 部署golang项目


    背景

    由于公司要做容器平台的升级旧平台需要迁移到新平台,所以觉得有那个时间不如迁移到部门的k8s集群中,因此就需要有一套相对完善的cicd。这里我只是想做一个v1.0版本,后期逐步的进化。

    golang项目

    这里只是演示发布一个最简单的服务器。

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    )
    
    // 处理主页请求
    func index(w http.ResponseWriter, r *http.Request) {
    	// 向客户端写入内容
    	fmt.Fprintf(w, "mother  fucker!")
    }
    
    func main() {
    	http.HandleFunc("/", index)              //设置访问的路由
    	err := http.ListenAndServe(":9090", nil) //设置监听的端口
    	if err != nil {
    		log.Fatal("ListenAndServe: ", err)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    Dockerfile
    FROM golang:1.14-alpine AS development
    WORKDIR $GOPATH/src
    COPY . .
    RUN go build -o golang-demo ./main.go
    
    FROM alpine:latest AS production
    WORKDIR /root/
    COPY --from=development /go/src/golang-demo .
    EXPOSE 9090
    ENTRYPOINT ["./golang-demo"]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    CI

    ci无非就是从 gitlab拉取代码,然后进行测试,编译,打包,然后将镜像推送到镜像仓库,最后修改helm的values.yaml。

    所以这里就需要gitlab的账号密码,harbor的账号密码。

    gitlab-secret.yaml

    apiVersion: v1
    kind: Secret
    metadata:
      name: gitlab-secret
      namespace: golang-demo-pipeline
      annotations:
        tekton.dev/git-0: 你的代码仓库
    type: kubernetes.io/basic-auth
    stringData:
      username: 账号
      password: 密码
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    harbor-secret.yaml

    apiVersion: v1
    kind: Secret
    metadata:
      name: harbor-secret
      namespace: golang-demo-pipeline
      annotations:
        tekton.dev/docker-0: https://镜像仓库地址
    type: kubernetes.io/basic-auth
    stringData:
      username: 用户名
      password: 密码
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    sa.yaml

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: cicd
      namespace: golang-demo-pipeline
    secrets:
      - name: gitlab-secret
      - name: harbor-secret
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    由于tekton里面git 和 image都是resource,因此需要创建git-resource 和 image-resource
    git-resource.yaml

    apiVersion: tekton.dev/v1alpha1
    kind: PipelineResource
    metadata:
      name: gitlab-pipeline-resource
      namespace: golang-demo-pipeline
    spec:
      type: git
      params:
        - name: revision
          value: main
        - name: url
          value: 代码库地址
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    image-resource.yaml

    apiVersion: tekton.dev/v1alpha1
    kind: PipelineResource
    metadata:
      name: harbor-image
      namespace: golang-demo-pipeline
    spec:
      type: image
      params:
        - name: url
          value: 镜像仓库地址/项目名/golang-demo-pipeline 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    好了、前期工作准备好了开始写task
    task-test.yaml
    这里我只是echo了一句,后面的版本再完善

    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
      name: test
      namespace: golang-demo-pipeline
    spec:
      resources:
        inputs:
          - name: repo
            type: git
      steps:
        - name: run-test
          image: golang:1.14-alpine
          workingDir: /workspace/repo
          command: ['echo']
          args: ['this is a test task']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    task-generate-build-id.yaml
    每次进行docker build -tag都需要有一个版本号,这里是根据基础版本+时间生成版本号

    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
      name: generate-build-id
      namespace: golang-demo-pipeline
    spec:
      description: >-
        Given a base version, this task generates a unique build id by appending
        the base-version to the current timestamp.
      params:
        - name: base-version
          description: Base product version
          type: string
          default: "1.0"
      results:
        - name: timestamp
          description: Current timestamp
        - name: build-id
          description: ID of the current build
      steps:
        - name: get-timestamp
          image: bash:5.0.18
          script: |
            #!/usr/bin/env bash
            ts=`date "+%Y%m%d-%H%M%S"`
            echo "Current Timestamp: ${ts}"
            echo ${ts} | tr -d "\n" | tee $(results.timestamp.path)
        - name: get-buildid
          image: bash:5.0.18
          script: |
            #!/usr/bin/env bash
            ts=`cat $(results.timestamp.path)`
            buildId=$(inputs.params.base-version)-${ts}
            echo ${buildId} | tr -d "\n" | tee $(results.build-id.path)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    task-build-and-push.yaml

    我这里是最近单的docker in docker的方式打包镜像,正确的方式可以使用sidecar的方式或者kaniko的方式后面去实现,这里直接build完推送到镜像仓库。

    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
      name: build-and-push
      namespace: golang-demo-pipeline
    spec:
      resources:
        inputs: # 定义输入资源
          - name: repo #输入资源,就是github的那个仓库
            type: git
        outputs: # 定义输出资源
          - name: builtImage # 输出镜像名字
            type: image
      params:
        - name: pathToDockerfile #指明 dockerfile 在仓库中的哪个位置
          type: string
          default: /workspace/repo/Dockerfile # repo资源的路径
          description: dockerfile path
        - name: pathToContext #指明 dockerfile 在仓库中的哪个位置
          type: string
          default: /workspace/repo  # repo资源的路径
          description: the build context used by docker daemon
        - name: imageTag
          type: string
          default: "v0.0.0"
          description: the docker image tag
      steps:
        - name: build-and-push
          image: docker:stable
          script: |
            #!/usr/bin/env sh
            docker login 镜像仓库地址
            docker build -t $(resources.outputs.builtImage.url):$(params.imageTag) -f $(params.pathToDockerfile) $(params.pathToContext)
            docker push $(resources.outputs.builtImage.url):$(params.imageTag)  # 这边的参数都是在 input 和 output 中定义的
          volumeMounts:
            - name: dockersock #将docker.sock文件挂载进来,使用宿主机docker daemon 构建镜像
              mountPath: /var/run/docker.sock
      volumes:
        - name: dockersock
          hostPath:
            path: /var/run/docker.sock
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    task-helm-values.yaml
    我这里选择使用helm来部署应用,因此需要修改helm的values.yaml,主要就是修改镜像的版本号。先把helm chart clone下来,然后修改image.tag最后push回去,就这么简单

    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
      name: helm-values
      namespace: golang-demo-pipeline
    spec:
      params:
        - name: git_url
          description: Git repository containing manifest files to update
        - name: git_email
          default: 你的git email
        - name: git_name
          default: 你的 git username
        - name: git_manifest_dir
          description: Manifests files dir
        - name: tool_image
          default: cnych/helm-kubectl-curl-git-jq-yq
        - name: image-tag
          description: Deploy docker image tag
      steps:
        - name: git-push
          image: $(params.tool_image)
          env:
            - name: GIT_USERNAME
              valueFrom:
                secretKeyRef:
                  name: gitlab-secret
                  key: username
                  optional: true
            - name: GIT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: gitlab-secret
                  key: password
                  optional: true
          command: ["/bin/bash"]
          args:
            - -c
            - |
              set -eu
              echo Load environment variables from previous steps
              #source /workspace/env-config
              git config --global user.email "$(params.git_email)"
              git config --global user.name "$(params.git_name)"
              git clone --branch master --depth 1 http://${GIT_USERNAME}:${GIT_PASSWORD}@$(params.git_url) repo
              cd "repo/$(params.git_manifest_dir)"
              ls -l
              echo old value:
              cat values.yaml | yq r - 'image.tag'
              echo replacing with new value:
              echo $(params.image-tag)
              yq w --inplace values.yaml 'image.tag' "$(params.image-tag)"
              echo verifying new value
              yq r values.yaml 'image.tag'
              if ! git diff-index --quiet HEAD --; then
                git status
                git add .
                git commit -m "helm values updated by tekton pipeline in change-manifests task"
                git push
              else
                  echo "no changes, git repository is up to date"
              fi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    有了task后,要开始写pipeline和pipeline run了,把task组合起来并运行起来
    pipeline.yaml

    apiVersion: tekton.dev/v1beta1
    kind: Pipeline
    metadata:
      name: golang-demo
      namespace: golang-demo-pipeline
    spec:
      resources:
      - name: repo
        type: git
      - name: builtImage
        type: builtImage
      params:
      - name: image-tag
        type: string
      - name: git_url
        type: string
      - name: git_manifest_dir
        type: string
      tasks:
      - name: test
        taskRef:
          name: test
        resources:
          inputs:
          - name: repo      # Task 输入名称
            resource: repo  # Pipeline 资源名称
      - name: get-build-id
        taskRef:
          name: generate-build-id
        params:
        - name: base-version
          value: $(params.image-tag)
      - name: build-and-push
        taskRef:
          name: build-and-push
        runAfter:
        - test              # 测试任务执行之后
        resources:
          inputs:
          - name: repo      # Task 输入名称
            resource: repo  # Pipeline 资源名称
          outputs:
          - name: builtImage
            resource: builtImage
        params:
        - name: imageTag
          value: "$(tasks.get-build-id.results.build-id)" # 使用generate-build-id生成tag
      - name: helm-values
        taskRef:
          name: helm-values
        runAfter:
        - build-and-push
        params:
        - name: git_url
          value: $(params.git_url)
        - name: git_manifest_dir
          value: $(params.git_manifest_dir)
        - name: image-tag
          value:  "$(tasks.get-build-id.results.build-id)"  # 使用generate-build-id生成tag
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    pipeline-run.yaml

    apiVersion: tekton.dev/v1beta1
    kind: PipelineRun
    metadata:
      name: golang-demo
      namespace: golang-demo-pipeline
    spec:
      serviceAccountName: cicd
      pipelineRef:
        name: golang-demo
      resources:
      - name: repo
        resourceRef:
          name: gitlab-pipeline-resource
      - name: builtImage
        resourceRef:
          name: harbor-image
      params:
      - name: image-tag
        value: "v0.1.0"
      - name: git_url
        value: 你的helm git仓库地址
      - name: git_manifest_dir
        value: helm-golang-demo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    最后执行以下apply -f . 如果一些正常可以从tekton ui看到,当然如果不成功根据错误自己改一下,也会加深你的记忆。
    在这里插入图片描述

    对tekton的理解

    我把task比喻成一个个function

    func taskA(paramA string){}
    func taskB(paramB string){}
    func taskC(paramC string){}
    
    • 1
    • 2
    • 3

    pipeline就是一个调用A、B、C的函数

    func pipeline(paramA,paramB,paramC string){
    	taskA(paramA)
    	taskC(paramB)
    	taskC(paramC)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    pipelineRun 就是真正的调用者来调用pipeline

    pipeline("a","b","c")
    
    • 1

    如下图 task需要参数git_manifest_dir
    在这里插入图片描述
    pipeline调用tasl也需要参数git_manifest_dir
    在这里插入图片描述
    pipelineRun作为真正的调用者来传递参数值
    在这里插入图片描述
    是不是有点感觉。。。

    CD

    argocd的原理就是再k8s里面有一个控制器一直监听git的变化,然后对比集群中实际的状态,所以你也要先有一个git仓库,这里就是helm的仓库。
    在这里插入图片描述

    有了仓库就开始建立应用了
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    如果再一切顺利,你应该看到如下画面
    在这里插入图片描述

  • 相关阅读:
    Android基础第八天 | 字节跳动第四届青训营笔记
    SpringBoot Actuator未授权访问漏洞修复
    bootstrap-datepicker实现只能选择每一年的某一个月份
    项目分析(三个小众的嵌入式产品)
    遗传算法在TSP中的两步求解(Matlab代码实现)
    【面试题-Vue】常见问题二、组件类
    RxJava(三)-合并操作符
    1033 To Fill or Not to Fill
    遨博机械臂——ROS通讯机制
    Java 简单实现一个 TCP 回显服务器
  • 原文地址:https://blog.csdn.net/yanchendage/article/details/126871588