接上一篇 【Tekton】组件介绍及安装部署,本文介绍如何使用 Tekton 完成 CI/CD 的全流程,包括 WebHook、代码拉取、go test、go build、docker build and push、helm/kubectl k8s 部署,其中涉及 Git/镜像仓库的 Basic 认证、kubeconfig、以及 go mod 缓存和多项目目录结构等实践内容。
首先看下本文实践的 CI/CD 全部流程:
graph LR
G(GitHub) --webhook--> EL(EventListener<br>Multi Repo)
subgraph Tekton
EL --trigger--> P(Pipelines)
end
P --deploy--> k8s(Kubernetes)
style EL fill:#fbf
- Pipelines
graph LR
git(Git Clone<br>GitHub) --> test(Go Test)
test --> build(Go Build)
build --> docker(Docker Build<br>镜像仓库)
docker --> deploy(Deploy<br>Helm/Kubectl)
内容如下:
- GitHub 仓库通过 Webhook 触发流水线
- 支持多项目构建
- 多个项目共用 PVC,通过子目录区分
- EventListener 接收 Webhook 后根据 Repo 信息区分项目,并触发不同的 Pipeline
- 流水线完成仓库的 克隆、test、build、镜像构建、发布到 K8S 平台
- 指定 go mod 目录,避免每次重新拉取依赖,做构建缓存
- 秘钥配置
- Webhook 秘钥配置
- Git 仓库 Basic 认证
- Docker Hub
config.json
认证 - K8S kubeConfig
Webhook 触发器
首先从 Trigger 开始,触发器对应的 CRD
为 EventListener
,由 TriggerController
负责 EL
实例的生命周期管理,EL
为接收 Webhook 的服务。相关的 CRD
还有 TriggerBinding
和TriggerTemplate
,TriggerBinding
用于将 Webhook 请求的数据映射到 TriggerTemplate
的输入参数;TriggerTemplate
则用于定义触发器所要运行的流水线,有关 Triiger 的文档参考 Triggers and EventListeners。具体 CRD
如下:
kind: Secret
:github-secret
定义 Webhook 接口所需要的秘钥kind: EventListener
:github-listener-interceptor
主要在triggers
中分别定义两个 GitHub 项目的 triggerinterceptors
中用github
关联了 Webhook 需要的secret
,用cel.filter
过滤指定项目的 Repo,用于测试的两个用例分别为 hb-chen/gateway 和 hb-chen/gmqtttemplate
和bindings
分别用于关联TriggerTemplate
和TriggerBinding
Trigger 也可以通过单独 CRD 来定义,用
triggerRef
来关联
kind: TriggerBinding
: 仅从 body 中获取了 Repo 地址,更多信息可以根据 Template 的需求情况进行绑定kind: TriggerTemplate
: 分别定义了两个项目的流水线模板,在触发器出发后使用resourcetemplates
创建资源,并可以通过params
定义模板参数,结合TriggerBinding
便可以获取 Webhook 接口 Request 中的信息
---
apiVersion: v1
kind: Secret
metadata:
name: github-secret
type: Opaque
stringData:
secretToken: "123456"
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: github-listener-interceptor
spec:
triggers:
- name: github-gateway-listener
interceptors:
- github:
secretRef:
secretName: github-secret
secretKey: secretToken
eventTypes:
# CEL 过滤或扩展 Event
- cel:
filter: "body.repository.full_name in ['hb-chen/gateway']"
bindings:
- ref: pipeline-binding
template:
ref: grpc-gateway-pipeline-template
- name: github-gmqtt-listener
interceptors:
- github:
secretRef:
secretName: github-secret
secretKey: secretToken
eventTypes:
# CEL 过滤或扩展 Event
- cel:
filter: "body.repository.full_name in ['hb-chen/gmqtt']"
bindings:
- ref: pipeline-binding
template:
ref: gmqtt-pipeline-template
resources:
kubernetesResource:
spec:
template:
spec:
serviceAccountName: tekton-triggers-example-sa
containers:
- resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: pipeline-binding
spec:
params:
- name: gitrepositoryurl
value: $(body.repository.clone_url)
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: grpc-gateway-pipeline-template
spec:
params:
- name: gitrevision
description: The git revision
default: master
- name: gitrepositoryurl
description: The git repository url
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: grpc-gateway-pipeline-run-
spec:
serviceAccountName: build-bot
pipelineRef:
name: grpc-gateway-pipeline
workspaces:
- name: shared-workspace
persistentvolumeclaim:
claimName: golang-source-pvc
- name: dockerconfig
secret:
secretName: dockerconfig
- name: kubeconfig
secret:
secretName: k8s-kubeconfig
params:
- name: url
value: $(tt.params.gitrepositoryurl)
- name: revision
value: $(tt.params.gitrevision)
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: gmqtt-pipeline-template
spec:
params:
- name: gitrevision
description: The git revision
default: master
- name: gitrepositoryurl
description: The git repository url
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: gmqtt-pipeline-run-
spec:
serviceAccountName: build-bot
pipelineRef:
name: gmqtt-pipeline
workspaces:
- name: shared-workspace
persistentvolumeclaim:
claimName: golang-source-pvc
- name: dockerconfig
secret:
secretName: dockerconfig
- name: kubeconfig
secret:
secretName: k8s-kubeconfig
params:
- name: url
value: $(tt.params.gitrepositoryurl)
- name: revision
value: $(tt.params.gitrevision)
RBAC
前面有了 Trigger 相关的资源,最后还缺一个 ServiceAccount
,并且需要做相应的 RBAC
授权,主要包括:
triggers.tekton.dev
相关CRD
资源获取允许创建的
CRD
资源- > Trigger 是 Tekton 的一个独立组件,
TriggerTemplate
可以用来创建各类CRD
资源,自然要有相应资源的create
权限才行
- > Trigger 是 Tekton 的一个独立组件,
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-triggers-example-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tekton-triggers-example-binding
subjects:
- kind: ServiceAccount
name: tekton-triggers-example-sa
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: tekton-triggers-eventlistener-roles
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tekton-triggers-example-clusterbinding
subjects:
- kind: ServiceAccount
name: tekton-triggers-example-sa
namespace: tekton-pipelines
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: tekton-triggers-eventlistener-clusterroles
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tekton-triggers-eventlistener-roles
labels:
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-triggers
rules:
- apiGroups: ["triggers.tekton.dev"]
resources: ["eventlisteners", "triggerbindings", "triggertemplates", "triggers"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["tekton.dev"]
resources: ["pipelineruns", "pipelineresources", "taskruns"]
verbs: ["create"]
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["impersonate"]
- apiGroups: ["policy"]
resources: ["podsecuritypolicies"]
resourceNames: ["tekton-triggers"]
verbs: ["use"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: tekton-triggers-eventlistener-clusterroles
labels:
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-triggers
rules:
- apiGroups: ["triggers.tekton.dev"]
resources: ["clustertriggerbindings", "clusterinterceptors"]
verbs: ["get", "list", "watch"]
流水线任务
Task 主要参考官方的 catalog,结合自身需求做了适当的改造,详细内容如下:
增加了
GOPROXY
和GOMODCACHE
的支持,加速依赖下载速度,使用国内 Proxy,并将 mod cache 指定到workspace
的独立目录,多个项目共享且避免被清理,路径为$(workspaces.source.path)/$(params.GOMODCACHE)
,GOMODCACHE
参数默认为pkg/mod
增加对子目录的支持,在同一
workspace
下同时存储多个项目的源码- > 未必是个好的实践方式,不过适合我的需求😂
镜像构建选用的
kaniko
而没有用docker-build
,都尝试后发现用kaniko
可以比较方便的获取image digested
发布到
k8s
没有使用catalog
中的 Task,而是使用dtzar/helm-kubectl
镜像自己定义的一个 Task,可以自定义helm
或kubectl
命令
每个 Task 的具体工作在此不做详细的介绍,基本通过源码的参数和步骤可以很快了解每个 Task 的具体任务内容
git-clone.yml
最新配置以 github.com/hb-chen/tekton-practice 为准
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: git-clone
labels:
app.kubernetes.io/version: "0.2"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: git
tekton.dev/displayName: "git clone"
spec:
description: >-
These Tasks are Git tasks to work with repositories used by other tasks
in your Pipeline.
The git-clone Task will clone a repo from the provided url into the
output Workspace. By default the repo will be cloned into the root of
your Workspace. You can clone into a subdirectory by setting this Task's
subdirectory param.
workspaces:
- name: output
description: The git repo will be cloned onto the volume backing this workspace
params:
- name: url
description: git url to clone
type: string
- name: revision
description: git revision to checkout (branch, tag, sha, ref…)
type: string
default: ""
- name: refspec
description: (optional) git refspec to fetch before checking out revision
default: ""
- name: submodules
description: defines if the resource should initialize and fetch the submodules
type: string
default: "true"
- name: depth
description: performs a shallow clone where only the most recent commit(s) will be fetched
type: string
default: "1"
- name: sslVerify
description: defines if http.sslVerify should be set to true or false in the global git config
type: string
default: "true"
- name: subdirectory
description: subdirectory inside the "output" workspace to clone the git repo into
type: string
default: ""
- name: deleteExisting
description: clean out the contents of the repo's destination directory (if it already exists) before trying to clone the repo there
type: string
default: "true"
- name: httpProxy
description: git HTTP proxy server for non-SSL requests
type: string
default: ""
- name: httpsProxy
description: git HTTPS proxy server for SSL requests
type: string
default: ""
- name: noProxy
description: git no proxy - opt out of proxying HTTP/HTTPS requests
type: string
default: ""
- name: verbose
description: log the commands used during execution
type: string
default: "true"
- name: gitInitImage
description: the image used where the git-init binary is
type: string
default: "registry.cn-hangzhou.aliyuncs.com/hb-chen/tektoncd-git-init:v0.20.0@sha256:e8e38d1ad630cc2e435deed289b6283cb0a06d3c00947131f371f151781db2b3"
results:
- name: commit
description: The precise commit SHA that was fetched by this Task
- name: url
description: The precise URL that was fetched by this Task
steps:
- name: clone
image: $(params.gitInitImage)
script: |
#!/bin/sh
set -eu -o pipefail
if [[ "$(params.verbose)" == "true" ]] ; then
set -x
fi
CHECKOUT_DIR="$(workspaces.output.path)/$(params.subdirectory)"
cleandir() {
# Delete any existing contents of the repo directory if it exists.
#
# We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/"
# or the root of a mounted volume.
if [[ -d "$CHECKOUT_DIR" ]] ; then
# Delete non-hidden files and directories
rm -rf "$CHECKOUT_DIR"/*
# Delete files and directories starting with . but excluding ..
rm -rf "$CHECKOUT_DIR"/.[!.]*
# Delete files and directories starting with .. plus any other character
rm -rf "$CHECKOUT_DIR"/..?*
fi
}
if [[ "$(params.deleteExisting)" == "true" ]] ; then
cleandir
fi
test -z "$(params.httpProxy)" || export HTTP_PROXY=$(params.httpProxy)
test -z "$(params.httpsProxy)" || export HTTPS_PROXY=$(params.httpsProxy)
test -z "$(params.noProxy)" || export NO_PROXY=$(params.noProxy)
/ko-app/git-init \
-url "$(params.url)" \
-revision "$(params.revision)" \
-refspec "$(params.refspec)" \
-path "$CHECKOUT_DIR" \
-sslVerify="$(params.sslVerify)" \
-submodules="$(params.submodules)" \
-depth "$(params.depth)"
cd "$CHECKOUT_DIR"
RESULT_SHA="$(git rev-parse HEAD)"
EXIT_CODE="$?"
if [ "$EXIT_CODE" != 0 ] ; then
exit $EXIT_CODE
fi
# ensure we don't add a trailing newline to the result
echo -n "$RESULT_SHA" > $(results.commit.path)
echo -n "$(params.url)" > $(results.url.path)
golang-test.yml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: golang-test
labels:
app.kubernetes.io/version: "0.1"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: test
tekton.dev/displayName: "golang test"
spec:
description: >-
This Task is Golang task to test Go projects.
params:
- name: package
description: package (and its children) under test
- name: packages
description: "packages to test (default: ./...)"
default: "./..."
- name: subdirectory
description: subdirectory inside the "source"
type: string
default: ""
- name: version
description: golang version to use for tests
default: "latest"
- name: flags
description: flags to use for the test command
default: -race -cover -v
- name: GOOS
description: "running program's operating system target"
default: linux
- name: GOARCH
description: "running program's architecture target"
default: amd64
- name: GO111MODULE
description: "value of module support"
default: auto
- name: GOPROXY
description: "go proxy"
default: "https://mirrors.aliyun.com/goproxy/,direct"
- name: GOMODCACHE
description: "go mod cache sub directory, base on source path"
default: "pkg/mod"
workspaces:
- name: source
steps:
- name: unit-test
image: docker.io/library/golang:$(params.version)
script: |
SRC_PATH="$GOPATH/src/$(params.package)"
mkdir -p $SRC_PATH
cp -R "$(workspaces.source.path)"/$(params.subdirectory)/* $SRC_PATH
cd $SRC_PATH
go test $(params.flags) $(params.packages)
env:
- name: GOOS
value: "$(params.GOOS)"
- name: GOARCH
value: "$(params.GOARCH)"
- name: GO111MODULE
value: "$(params.GO111MODULE)"
- name: GOPROXY
value: "$(params.GOPROXY)"
- name: GOMODCACHE
value: "$(workspaces.source.path)/$(params.GOMODCACHE)"
golang-build.yml
# fork from tektoncd/catalog, add GOPROXY
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: golang-build
labels:
app.kubernetes.io/version: "0.1"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: build-tool
tekton.dev/displayName: "golang build"
spec:
description: >-
This Task is Golang task to build Go projects.
params:
- name: package
description: base package to build in
- name: packages
description: "packages to build (default: ./cmd/...)"
default: "./cmd/..."
- name: subdirectory
description: subdirectory inside the "source"
type: string
default: ""
- name: version
description: golang version to use for builds
default: "latest"
- name: flags
description: flags to use for the test command
default: -v
- name: GOOS
description: "running program's operating system target"
default: linux
- name: GOARCH
description: "running program's architecture target"
default: amd64
- name: CGO_ENABLED
description: "value of cgo enabled"
default: "0"
- name: GO111MODULE
description: "value of module support"
default: auto
- name: GOPROXY
description: "go proxy"
default: "https://mirrors.aliyun.com/goproxy/,direct"
- name: GOMODCACHE
description: "go mod cache sub directory, base on source path"
default: "pkg/mod"
workspaces:
- name: source
steps:
- name: build
image: docker.io/library/golang:$(params.version)
script: |
SRC_PATH="$GOPATH/src/$(params.package)"
mkdir -p $SRC_PATH
cp -R "$(workspaces.source.path)"/$(params.subdirectory)/* $SRC_PATH
cd $SRC_PATH
go env
go build $(params.flags) $(params.packages)
env:
- name: GOOS
value: "$(params.GOOS)"
- name: GOARCH
value: "$(params.GOARCH)"
- name: CGO_ENABLED
value: "$(params.CGO_ENABLED)"
- name: GO111MODULE
value: "$(params.GO111MODULE)"
- name: GOPROXY
value: "$(params.GOPROXY)"
- name: GOMODCACHE
value: "$(workspaces.source.path)/$(params.GOMODCACHE)"
kaniko.yml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: kaniko
labels:
app.kubernetes.io/version: "0.4"
annotations:
tekton.dev/pipelines.minVersion: "0.17.0"
tekton.dev/categories: Image Build
tekton.dev/tags: image-build
tekton.dev/displayName: "Build and upload container image using Kaniko"
spec:
description: >-
This Task builds source into a container image using Google's kaniko tool.
Kaniko doesn't depend on a Docker daemon and executes each
command within a Dockerfile completely in userspace. This enables
building container images in environments that can't easily or
securely run a Docker daemon, such as a standard Kubernetes cluster.
params:
- name: IMAGE
description: Name (reference) of the image to build.
- name: DOCKERFILE
description: Path to the Dockerfile to build.
default: ./Dockerfile
- name: CONTEXT
description: The build context used by Kaniko.
default: ./
- name: EXTRA_ARGS
type: array
default: []
- name: BUILDER_IMAGE
description: The image on which builds will run
default: registry.cn-hangzhou.aliyuncs.com/hb-chen/kaniko-executor:v1.5.1@sha256:c812530c2ea981d3316c7544b180289abfbd9adf1dde6f1345692b8fb0a65cb0
workspaces:
- name: source
description: Holds the context and docker file
- name: dockerconfig
description: Includes a docker `config.json`
optional: true
mountPath: /kaniko/.docker
results:
- name: IMAGE-DIGEST
description: Digest of the image just built.
steps:
- name: build-and-push
workingDir: $(workspaces.source.path)
image: $(params.BUILDER_IMAGE)
args:
- $(params.EXTRA_ARGS[*])
- --dockerfile=$(params.DOCKERFILE)
- --context=$(workspaces.source.path)/$(params.CONTEXT) # The user does not need to care the workspace and the source.
- --destination=$(params.IMAGE)
- --oci-layout-path=$(workspaces.source.path)/$(params.CONTEXT)/image-digest
# kaniko assumes it is running as root, which means this example fails on platforms
# that default to run containers as random uid (like OpenShift). Adding this securityContext
# makes it explicit that it needs to run as root.
securityContext:
runAsUser: 0
- name: write-digest
workingDir: $(workspaces.source.path)
image: registry.cn-hangzhou.aliyuncs.com/hb-chen/tektoncd-imagedigestexporter:v0.16.2@sha256:542d437868a0168f0771d840233110fbf860b210b0e9becce5d75628c694b958
# output of imagedigestexport [{"key":"digest","value":"sha256:eed29..660","resourceRef":{"name":"myrepo/myimage"}}]
command: ["/ko-app/imagedigestexporter"]
args:
- -images=[{"name":"$(params.IMAGE)","type":"image","url":"$(params.IMAGE)","digest":"","OutputImageDir":"$(workspaces.source.path)/$(params.CONTEXT)/image-digest"}]
- -terminationMessagePath=$(params.CONTEXT)/image-digested
securityContext:
runAsUser: 0
- name: digest-to-results
workingDir: $(workspaces.source.path)
image: docker.io/stedolan/jq@sha256:a61ed0bca213081b64be94c5e1b402ea58bc549f457c2682a86704dd55231e09
script: |
cat $(params.CONTEXT)/image-digested | jq '.[0].value' -rj | tee /tekton/results/IMAGE-DIGEST
helm-kubectl.yml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: helm-kubectl-deploy
labels:
app.kubernetes.io/version: "0.1"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: helm, kubectl
tekton.dev/displayName: helm-kubectl-deploy
spec:
description: >-
Use kubectl and helm deploy application
params:
- name: image
default: dtzar/helm-kubectl:3.4.2
description: kubectl and helm image
- name: commands
default: kubectl version
workspaces:
- name: source
- name: kubeconfig
description: Includes a `.kube/config`
optional: true
mountPath: /root/.kube
results:
steps:
- name: helm-kubectl-deploy
image: $(params.image)
workingDir: $(workspaces.source.path)
script: |
ls -l
kubectl version
helm version
$(params.commands)
流水线定义
Pipeline 基本就是对 Task 的配置,其中最主要的就是根据项目区分 workspace
下的子目录:
- 统一
subdirectory
- Golang build 编译的输出位置
-o $(workspaces.source.path)/${subdirectory}
- 镜像构建的
DOCKERFILE
和CONTEXT
也是在./${subdirectory}/
目录下 helm
部署时chart
也是在./${subdirectory}/
以下是 hb-chen/gateway 的示例:
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: grpc-gateway-pipeline
spec:
workspaces:
- name: shared-workspace
- name: dockerconfig
- name: kubeconfig
params:
- name: url
- name: revision
default: master
tasks:
- name: fetch-repository
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-workspace
params:
- name: url
value: $(params.url)
- name: revision
value: $(params.revision)
- name: subdirectory
value: "gateway"
- name: deleteExisting
value: "true"
- name: run-test
taskRef:
name: golang-test
runAfter:
- fetch-repository
workspaces:
- name: source
workspace: shared-workspace
params:
- name: package
value: github.com/hb-chen/gateway
- name: subdirectory
value: "gateway"
- name: version
value: 1.14.15
- name: run-build
taskRef:
name: golang-build
runAfter:
- run-test
workspaces:
- name: source
workspace: shared-workspace
params:
- name: package
value: github.com/hb-chen/gateway
- name: subdirectory
value: "gateway"
- name: version
value: 1.15.11
- name: flags
value: -v -o $(workspaces.source.path)/gateway/bin/linux/gateway
- name: docker-build
taskRef:
name: kaniko
runAfter:
- run-build
workspaces:
- name: source
workspace: shared-workspace
- name: dockerconfig
workspace: dockerconfig
params:
- name: IMAGE
value: registry.cn-hangzhou.aliyuncs.com/hb-chen/grpc-gateway:latest
- name: DOCKERFILE
value: ./gateway/Dockerfile
- name: CONTEXT
value: ./gateway/
- name: EXTRA_ARGS
value:
- "--skip-tls-verify"
- "--insecure-registry=registry.cn-hangzhou.aliyuncs.com"
- name: helm-kubectl-deploy
taskRef:
name: helm-kubectl-deploy
runAfter:
- docker-build
workspaces:
- name: source
workspace: shared-workspace
- name: kubeconfig
workspace: kubeconfig
params:
- name: commands
value: |
helm template \
--release-name grpc-gateway \
--no-hooks \
--set image.repository=registry.cn-hangzhou.aliyuncs.com/hb-chen/grpc-gateway \
--set image.tag=latest \
--set image.digest=@$(tasks.docker-build.results.IMAGE-DIGEST) \
./gateway/helm | kubectl apply -n grpc-gateway -f -
PVC
PVC 选择是多个项目共用一个,所以在前面的 Task 和 Pipeline 中需要通过 subdirectory
来规划不同项目的源码位置
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: golang-source-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
安全认证
整个过程涉及到多出认证,Trigger 中 Webhook secret 已经介绍,剩余的还有是和流水线 Task 有关的,其中 Git 和 Docker Hub 使用 Basic 认证,与 ServiceAcount
绑定,Kubernetes 则通过挂在 KubeConfig Secret 实现。
Git
apiVersion: v1
kind: Secret
metadata:
name: basic-git-user-pass
annotations:
tekton.dev/git-0: https://github.com
type: kubernetes.io/basic-auth
stringData:
username: hobo@hbchen.com
password: 123456
镜像仓库
镜像仓库的认证信息通过挂载 config.json
的方式,而不使用 Basic Auth,这个改动在 Kaniko task 中有说明:
- Replace ServiceAccount based authentication with a workspace based one. Tekton’s built-in auth can be disabled, it can be hard to debug and it might not work for all type of credentials. Workspaces are available to all deployments, and can be bound to both secrets and PVCs.
另外注意如果
config.json
中没有auth
信息,删掉credsStore
,重新docker login
,参考 Pull an Image from a Private Registry
kubectl create secret generic dockerconfig \
-n tekton-pipelines \
--from-file=config.json=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfig
KubeConfig
如果使用本地 KubeConfig 配置可以使用以下命令快速创建
kubectl create secret generic k8s-kubeconfig --from-file=$HOME/.kube/config
---
apiVersion: v1
kind: Secret
metadata:
name: k8s-kubeconfig
type: Opaque
data:
config: {$HOME/.kube/config base64 encode}
Service Account
将 Docker 和 Git 的 Basic 认证都绑定到 build-bot
,这是运行流水线是使用的 ServiceAccount
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-bot
secrets:
- name: basic-git-user-pass