tekton+argocd 部署golang项目
这里我只是想做一个v1.0版本,后期逐步的进化。我这里是最近单的docker in docker的方式打包镜像,正确的方式可以使用sidecar的方式或者kaniko的方式后面去实现,这里直接build完推送到镜像仓库。argocd的原理就是再k8s里面有一个控制器一直监听git的变化,然后对比集群中实际的状态,所以你也要先有一个git仓库,这里就是helm的仓库。ci无非就是从 gitlab拉取
背景
由于公司要做容器平台的升级旧平台需要迁移到新平台,所以觉得有那个时间不如迁移到部门的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)
}
}
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"]
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: 密码
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: 密码
sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: cicd
namespace: golang-demo-pipeline
secrets:
- name: gitlab-secret
- name: harbor-secret
由于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: 代码库地址
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
好了、前期工作准备好了开始写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']
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)
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
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
有了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
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
最后执行以下apply -f . 如果一些正常可以从tekton ui看到,当然如果不成功根据错误自己改一下,也会加深你的记忆。
对tekton的理解
我把task比喻成一个个function
func taskA(paramA string){}
func taskB(paramB string){}
func taskC(paramC string){}
pipeline就是一个调用A、B、C的函数
func pipeline(paramA,paramB,paramC string){
taskA(paramA)
taskC(paramB)
taskC(paramC)
}
pipelineRun 就是真正的调用者来调用pipeline
pipeline("a","b","c")
如下图 task需要参数git_manifest_dir
pipeline调用tasl也需要参数git_manifest_dir
pipelineRun作为真正的调用者来传递参数值
是不是有点感觉。。。
CD
argocd的原理就是再k8s里面有一个控制器一直监听git的变化,然后对比集群中实际的状态,所以你也要先有一个git仓库,这里就是helm的仓库。
有了仓库就开始建立应用了
如果再一切顺利,你应该看到如下画面
更多推荐
所有评论(0)