Tekton으로 CI/CD 구축하기 - 2
Tekton으로 CI/CD 구축하기
- 깃허브에 특정 태그를 푸시하면 jib로 이미지를 빌드, 도커 허브로 푸시, 로컬 클러스터로 배포를 진행하는 파이프라인을 Tekton을 통해 만들어보겠습니다.
- Tekton으로 CI/CD 구축하기 - 1 에서 이어집니다.
Task 생성
- Tekton Hub에서 사람들이 만든 Task를 볼 수 있으며 자기가 Task를 정의할 수 도 있습니다. 깃허브에서 소스코드를 다운받는 Taks, Image Build Task, Kubectl Deploy Task를 바탕으로 파이프라인을 만들어보겠습니다.
Git-clone
- 깃허브 소스를 다운받는 Task
- https://hub.tekton.dev/tekton/task/git-clone
Jib-Build
- Jib를 통해 Spring 프로젝트를 이미지로 빌드 후 push 하는 Task
- https://hub.tekton.dev/tekton/task/jib-gradle
- 프로젝트가 사용하는 gradle은 7.3.2 버전이지만 해당 Task는 5 버전을 사용하고 있기 때문에 그대로 사용할 수 없고 openjdk11 이미지에서 gradlew를 사용해 gradlew jib 명령을 실행하는 새로운 Task를 정의했습니다.
kind: Task
metadata:
name: jib-gradle
labels:
app.kubernetes.io/version: "0.3"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/categories: Image Build
tekton.dev/tags: image-build
tekton.dev/displayName: "jib gradle"
tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le"
spec:
description: >-
This Task builds Java/Kotlin/Groovy/Scala source into a container image using Google’s Jib tool.
Jib works with Gradle and Maven projects, and this template is for Gradle projects.
params:
- name: BUILDER_IMAGE
description: The location of the gradle builder image
default: openjdk:11-jdk
- name: IMAGE
description: Reference of the image gradle will produce
- name: DIRECTORY
description: The directory containing the app, relative to the source repository root
default: .
- name: EXTRA_ARGS
description: Extra arguments to add to the gradle jib build
default: ""
workspaces:
- name: source
results:
- name: IMAGE_DIGEST
description: Digest of the image just built.
steps:
- name: build-and-push
image: $(params.BUILDER_IMAGE)
workingDir: $(workspaces.source.path)/$(params.DIRECTORY)
script: |
chmod +x gradlew
./gradlew jib \
-Djib.to.image="$(params.IMAGE)" \
$(params.EXTRA_ARGS)
env:
- name: HOME
value: /workspace
- name: "DOCKER_CONFIG"
value: $(credentials.path)/.docker/
volumeMounts:
securityContext:
runAsUser: 0
- name: digest-to-results
image: $(params.BUILDER_IMAGE)
script: cat $(workspaces.source.path)/$(params.DIRECTORY)/image-digest | tee /tekton/results/IMAGE_DIGEST
volumes:
- name: empty-dir-volume
emptyDir: {}
Kubectl-Deploy
- Tekton Hub에 존재하는 Kubectl Task는 kubectl apply 명령을 적용하기 위해 사용
- https://hub.tekton.dev/tekton/task/kubernetes-actions
- kubectl apply를 적용하기전에 sed 명령어를 통해 yaml 파일을 수정해주는 새로운 Task를 정의했습니다.
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
tekton.dev/categories: Kubernetes
tekton.dev/displayName: kubernetes actions
tekton.dev/pipelines.minVersion: 0.17.0
tekton.dev/platforms: linux/amd64
tekton.dev/tags: 'CLI, kubectl'
creationTimestamp: '2022-01-25T01:00:34Z'
generation: 1
labels:
app.kubernetes.io/version: '0.2'
managedFields:
- apiVersion: tekton.dev/v1beta1
fieldsType: FieldsV1
fieldsV1:
'f:metadata':
'f:annotations':
.: {}
'f:kubectl.kubernetes.io/last-applied-configuration': {}
'f:tekton.dev/categories': {}
'f:tekton.dev/displayName': {}
'f:tekton.dev/pipelines.minVersion': {}
'f:tekton.dev/platforms': {}
'f:tekton.dev/tags': {}
'f:labels':
.: {}
'f:app.kubernetes.io/version': {}
'f:spec':
.: {}
'f:description': {}
'f:params': {}
'f:results': {}
'f:steps': {}
'f:workspaces': {}
manager: kubectl-client-side-apply
operation: Update
time: '2022-01-25T01:00:34Z'
name: kubectl-deploy
resourceVersion: '3052774'
uid: 44000dca-ba62-4494-bb29-2dc4aa3af86b
spec:
description: This task is the generic kubectl CLI task which can be used to run all kinds of k8s commands
params:
- default: 'gcr.io/cloud-builders/kubectl@sha256:8ab94be8b2b4f3d117f02d868b39540fddd225447abf4014f7ba4765cb39f753'
name: IMAGE
type: string
- name: TAG
type: string
- name: YAMLFILE
type: string
- name: NAMESPACE
type: string
results:
- description: some result can be emitted if someone wants to.
name: output-result
steps:
- args:
- '-i'
- s;latest;$(params.TAG);g
- $(workspaces.manifest-dir.path)/$(params.YAMLFILE)
command:
- sed
image: alpine
name: update-yaml
resources: {}
- image: $(params.IMAGE)
name: kubectl
resources: {}
script: |
#!/usr/bin/env bash
[ "$(workspaces.manifest-dir.bound)" == "true" ] && \
cd $(workspaces.manifest-dir.path)
[ "$(workspaces.kubeconfig-dir.bound)" == "true" ] && \
[ -f $(workspaces.kubeconfig-dir.path)/kubeconfig ] && \
export KUBECONFIG=$(workspaces.kubeconfig-dir.path)/kubeconfig
kubectl apply -f $(workspaces.manifest-dir.path)/$(params.YAMLFILE) --namespace $(params.NAMESPACE)
workspaces:
- name: manifest-dir
optional: true
- name: kubeconfig-dir
optional: true
- Tekton DashBoard에서 만든 Task들 확인 가능
Pipeline, PipelineRun 생성
- Task들을 묶어서 하나의 파이프라인을 만들 수 있습니다.
- Pipeline을 만들 때 Task에서 정의한 Parameter 값을 새롭게 넣어줄 수 있습니다.
Pipeline
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: tekton-pipeline
spec:
workspaces:
- name: pipeline-shared-data
- name: kubeconfig-dir
tasks:
- name: clone-repository
taskRef:
kind: Task
name: git-clone
params:
- name: url
value: "https://github.com/sgwon96/devopsTest"
- name: revision
value: "main"
- name: deleteExisting
value: "true"
workspaces:
- name: output
workspace: pipeline-shared-data
- name: build-image
taskRef:
kind: Task
name: jib-gradle
runAfter:
- clone-repository
params:
- name: IMAGE
value: "zxcvb5434/devopstest:$(tasks.clone-repository.results.commit)"
workspaces:
- name: source
workspace: pipeline-shared-data
- name: kubectl-deploy
taskRef:
kind: Task
name: kubectl-deploy
runAfter:
- build-image
params:
- name: TAG
value: "$(tasks.clone-repository.results.commit)"
- name: YAMLFILE
value: "./k8s/deployment.yaml"
- name: NAMESPACE
value: "default"
workspaces:
- name: kubeconfig-dir
workspace: kubeconfig-dir
- name: manifest-dir
workspace: pipeline-shared-data
- params : Task에서 정의한 Parameter에 새로운 값을 넣을 수 있습니다. Pipeline을 생성할 때 마다 값을 변경할 수 있습니다.
- params를 정의하지 않으면 task에서 정의한 defaultvalue 값이 들어갑니다.
- runAfters : Task간의 순서를 정의해 줍니다. 해당 값에 들어간 Task가 완료되면 다음 Task가 실행됩니다.
- Pipleine에서 정의한 Workspace는 PipelineRun에서 입력 받습니다.
- workspace를 통해 Task들이 공유하는 Persistent Volume Claim을 설정하거나 Kubeconfig 값을 설정 할 수 있습니다.
- Task들은 Task가 종료될 때 Result를 만들어 다른 Task와 공유할 수 있는데 Git-Clone Task는 커밋의 sha 값을 Result로 생성합니다.
- 컨테이너 이미지 태그를 commit의 sha값으로 설정했습니다.
PipelineRun
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: tekton-pipelinerun
spec:
pipelineRef:
name: tekton-pipeline
serviceAccountName: tekton-sa
workspaces:
- name: pipeline-shared-data
persistentvolumeclaim:
claimName: task-pv-claim
- name: kubeconfig-dir
configMap:
name: kubeconfig
-
깃허브, Docker에 접근하기위한 Sercert 정보를 가지고 있는 Service Account를 PipelineRun에 할당
-
pipeline에서 정의해준 workspace에 persistent volume claim, configmap 할당
결과 확인
- Tekton DashBoard에서 파이프라인 실행 결과 확인 가능
Trigger를 통해 PipelineRun 자동 생성하기
- 이전까지는 수동으로 PipelineRun을 생성시켜 Pipeline을 실행 시켰습니다.
- Tekton은 Trigger를 통해 HTTP 요청으로 event가 발생할 때마다 자동으로 PipelineRun을 생성 할 수 있습니다.
- GitHub Webhook과 Tekton을 통해 깃허브에 코드가 푸시되면 자동으로 파이프라인을 실행하도록 만들어보겠습니다.
구성요소
- Trigger : 전달된 이벤트에 대한 검증, 파싱 로직을 실행시킨 뒤 Trigger Template 와 Trigger Binding을 연결
- EvnetListener : JSON payload를 사용하여 HTTP 기반 이벤트를 처리하는 Kubernetes custom Resource
- Trigger Bindings : Event와 Trigger를 연결 합니다. EventListener로 들어온 정보를 parsing 해 TriggerTemplate로 전달합니다.
- Trigger Template : Resource를 Template화 시킴. 파라미터를 통해 기존에 Pipeline에 정의된 Parameter에 새로운 값을 넣을 수 있습니다.
설치
kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/previous/v0.14.2/release.yaml
kubectl get pods -n tekton-pipelines
NAME READY STATUS RESTARTS AGE
tekton-dashboard-68b95c8fd5-mdl7q 1/1 Running 0 7h2m
tekton-pipelines-controller-8695d55cc6-mrg4f 1/1 Running 0 7h3m
tekton-pipelines-webhook-77bd94976b-4ghqj 1/1 Running 0 7h3m
tekton-triggers-controller-5878b4dcdb-q4xjv 1/1 Running 0 2m53s
tekton-triggers-webhook-5d5c4d948d-w4dzv 1/1 Running 0 2m53s
- tekton에서 제공해주는 yaml 파일을 바탕으로 apply 명령을 사용하면 tekton-trigger-controller, tekton-triggers-webhook이 생성 됩니다.
Trigger Binding
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: triggerbinding
spec:
params:
- name: tag
value: $(body.ref)
- https://docs.github.com/en/developers/webhooks-and-events/webhooks/about-webhooks
- 깃허브 웹훅으로 깃허브에 특정이벤트가 발생할 때마다 POST 요청을 보낼 수 있습니다.
- POST 요청의 body안에는 github event에 대한 정보가 들어 있는데 ref에는 태그 정보가 들어가 있습니다.
- Trigger Binding을 사용해 해당 정보를 파이프라인에 params 값으로 넣어주겠습니다.
Trigger Template
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: triggertemplate
spec:
params:
- name: tag
description: git tag
default: latest
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: tekton-pipeline-run-
spec:
serviceAccountName: tekton-sa
pipelineRef:
name: tekton-pipeline
params:
- name: tag
value: $(tt.params.tag)
workspaces:
- name: pipeline-shared-data
persistentvolumeclaim:
claimName: task-pv-claim
- name: kubeconfig-dir
configMap:
name: k8s-kubeconfig
- TriggerBinding에서 Parameter를 받아서 PipelineRun 실행합니다.
Pipeline 수정하기
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: tekton-pipeline
spec:
workspaces:
- name: pipeline-shared-data
- name: kubeconfig-dir
params:
- name: tag
type: string
description: Docker image tag
tasks:
- name: clone-repository
taskRef:
kind: Task
name: git-clone
params:
- name: url
value: "https://github.com/sgwon96/devopsTest"
- name: revision
value: "main"
- name: deleteExisting
value: "true"
workspaces:
- name: output
workspace: pipeline-shared-data
- name: build-image
taskRef:
kind: Task
name: jib-gradle
runAfter:
- clone-repository
params:
- name: IMAGE
value: "zxcvb5434/devopstest:$(params.tag)"
workspaces:
- name: source
workspace: pipeline-shared-data
- name: kubectl-deploy
taskRef:
kind: Task
name: kubectl-deploy
runAfter:
- build-image
params:
- name: TAG
value: "$(params.tag)"
- name: YAMLFILE
value: "./k8s/deployment.yaml"
- name: NAMESPACE
value: "default"
workspaces:
- name: kubeconfig-dir
workspace: kubeconfig-dir
- name: manifest-dir
workspace: pipeline-shared-data
- 기존에는 Pipeline에 github commit sha 값을 이미지 태그 값으로 설정했지만 Parmeter를 정의해서 Trigger Template에서 깃허브에 푸시된 태그 값을 받아오도록 설정합니다.
Event Listener
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: trigger-eventlistner
spec:
serviceAccountName: tekton-triggers-sa
triggers:
- bindings:
- ref: triggerbinding
template:
ref: triggertemplate
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-triggers-sa
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: tekton-triggers-role
rules:
# EventListeners need to be able to fetch all namespaced resources
- apiGroups: ["triggers.tekton.dev"]
resources: ["eventlisteners", "triggerbindings", "triggertemplates", "triggers"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
# secrets are only needed for GitHub/GitLab interceptors
# configmaps is needed for updating logging config
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch"]
# Permissions to create resources in associated TriggerTemplates
- apiGroups: ["tekton.dev"]
resources: ["pipelineruns", "pipelineresources", "taskruns"]
verbs: ["create"]
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["impersonate"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tekton-triggers-rolebinding
subjects:
- kind: ServiceAccount
name: tekton-triggers-sa
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: tekton-triggers-role
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: tekton-triggers-clusterrole
rules:
# EventListeners need to be able to fetch any clustertriggerbindings
- apiGroups: ["triggers.tekton.dev"]
resources: ["clustertriggerbindings","clusterinterceptors"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tekton-triggers-clusterbinding
subjects:
- kind: ServiceAccount
name: tekton-triggers-sa
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: tekton-triggers-clusterrole
- Github Webhok Event를 받을 Event Listener와 해당 Event Listener이 PipelineRun을 생성할 수 있게 만들어주는 Service Account와 권한 설정을 해줍니다.
k get pods
NAME READY STATUS RESTARTS AGE
devops-spring-deployment-7b4c96f45c-fhzzt 1/1 Running 0 20m
el-trigger-eventlistner-7fdcbfcb9-l9mqc 1/1 Running 0 52s
- 해당 pod을 원래는 Ingress를 통해 외부로 노출시켜줘야 하지만 파이프라인 실행 시연을 위해 port-forward를 사용해 외부로 노출시키겠습니다.
- kubectl port-forward pod/el-trigger-eventlistner-7fdcbfcb9-l9mqc 9098
- 공유기에도 port forward 설정을 진행하는 과정은 Kubernetes에 Spring 어플리케이션 배포하기 글을 참고 부탁드립니다.
GitHub Webhook 등록
- 저장소의 설정 → Webhooks에서 등록
- 포트포워딩이 설정 된 공인 아이피 주소로 웹훅 설정
- 브랜치 생성 또는 태그가 생성됬을 때 웹훅 실행
- final3 Tag를 달아 깃허브로 push하면 웹훅 실행
- Event Listener로 POST 요청을 보냄
- Event Listener가 GitHub Webhook으로 POST 요청을 받고 PipelineRun 생성
- 최종 버전으로 이미지 교체 성공
정리
- Kubernets 내부에 CI/CD를 구축하기 위해 Tekton을 사용할 수 있습니다.
- Git-clone,jib-build,kubectl-deploy 3가지 Task를 실행하는 파이프라인을 만들었습니다.
- GitHub Webhook 과 Event Listener Pod을 통해 깃허브 이벤트를 받아와 파이프라인을 실행시켰습니다.
- GitHub에 태그나 브랜치를 생성하면 github에서 소스코드를 다운받아 jib로 이미지를 빌드, Docker Hub에 업로드, kubectl apply를 통한 이미지 교체 작업이 실행 됩니다.
Reference
- https://gruuuuu.github.io/cloud/tekton-trigger/
- https://tekton.dev/docs/triggers/eventlisteners/
- https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads
Author And Source
이 문제에 관하여(Tekton으로 CI/CD 구축하기 - 2), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sgwon1996/Tekton으로-CICD-구축하기-2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)