Kubernetes | Tekton 배포 및 pipeline, trigger 사용방법

Tekton

Tekton CI/CD 스터디를 위해서 환경 구축을 해보았다.
결론은 사용측면에서는 jenkins나 gitAction이 쉽다.

https://tekton.dev/docs/installation

Tekton 배포

kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml

Tekton-Dashboard

kubectl apply --filename https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml

Dashbaord는 초기에 read-only로 배포되어있다. 설치전에 변경하던가 설치하고 수정한다.

spec:
      containers:
      - args:
        - --default-namespace=
        - --external-logs=
        - --log-format=json
        - --log-level=info
        - --logout-url=
        - --namespaces=
        - --pipelines-namespace=tekton-pipelines
        - --port=9097
        # - --read-only=true
        - --read-only=false
        - --stream-logs=true
        - --triggers-namespace=tekton-pipelines

Dashboard ingress

kubectl create secret tls ssl-common --cert ./chain.pem --key ./tk8s.test.key -n tekton-pipelines
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
  name: tekton-pipelines-ing
  namespace: tekton-pipelines
spec:
  ingressClassName: nginx
  rules:
  - host: tek.tk8s.test
    http:
      paths:
      - backend:
          service:
            name: tekton-dashboard
            port:
              number: 9097
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - tek.tk8s.test
    secretName: ssl-common

Tekton-triggers 배포

kubectl apply --filename \
https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml

kubectl apply --filename \
https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
kubectl create clusterrolebinding tekton-dashboard-clustertask \
  --clusterrole=cluster-admin \
  --serviceaccount=tekton-pipelines:tekton-dashboard
kubectl rollout restart deployment tekton-dashboard -n tekton-pipelines

chrome 사설인증서 신뢰할수있는 인증서 등록

Ubuntu Desktop chrome에 추가.

chrome://certificate-manager/localcerts/usercerts

Tekton Simple Test

demo 테스트를 해보자

kubectl create ns tekton-demo

Task 배포

# hello-task.yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: hello-task
  namespace: tekton-demo
spec:
  steps:
    - name: echo-hello
      image: ubuntu
      script: |
        #!/bin/bash
        echo "✅ Hello from Tekton Task!"

Sample Pipeline

# hello-pipeline.yaml
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: hello-pipeline
  namespace: tekton-demo
spec:
  tasks:
    - name: run-hello
      taskRef:
        name: hello-task

Pipeline Run

# hello-pipelinerun.yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: hello-pipelinerun
  namespace: tekton-demo
spec:
  pipelineRef:
    name: hello-pipeline

에러처리

ClusterTasks 에러

https://tekton.dev/docs/pipelines/deprecations

ClusterTask는 deprecated된 항목으로 무시할까하다 좀더 찾아보기로함.

crd를 추가함으로서 해결되었다.

# crd-clustertasks.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  labels:
    app.kubernetes.io/part-of: tekton-pipelines
    pipeline.tekton.dev/release: v0.68.0
    version: v0.68.0
  name: clustertasks.tekton.dev
spec:
  conversion:
    strategy: None
  group: tekton.dev
  names:
    categories:
    - tekton
    - tekton-pipelines
    kind: ClusterTask
    listKind: ClusterTaskList
    plural: clustertasks
    singular: clustertask
  scope: Cluster
  versions:
  - name: v1beta1
    schema:
      openAPIV3Schema:
        type: object
        x-kubernetes-preserve-unknown-fields: true
    served: true
    storage: true
    subresources:
      status: {}

Tekton build Test

- Git으로 Push하면 
- git은 web-hook으로 보낸다.
- hook은 event-lisner로 쏜다.
- event

Gitea Webhook연동

도메인 허용 설정

~/gitea-icurfer/gitea-data/gitea/conf/app.ini

[webhook]
ALLOWED_HOST_LIST = *
SKIP_TLS_VERIFY = true # 테스트 편의를 위해서 설정. 실사용에는 권장하지않음

gitea에 ALLOWE_HOST_LIST 설정이 안되서 발생하는 에러

사설인증서가 신뢰할수없어서 발생하는 에러

event lisner 설정이 안되서 발생하는 에러

Webhook을 받을 수있는 ingress 설정

dashboard의 url을 이용할 것이므로 ExternalName service를 추가하고 ingress를 수정한다.
tekton-demo에있는 service 오브젝트를 불러오는 역할을 하도록 구성한다.

# 09.ing-proxy.yaml
apiVersion: v1
kind: Service
metadata:
  name: el-tekton-demo-proxy
  namespace: tekton-pipelines
spec:
  type: ExternalName
  externalName: el-gitea-event-listener.tekton-demo.svc.cluster.local
  ports:
  - port: 8080
    targetPort: 8080
    protocol: TCP

Dashboard의 ingress 수정

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tekton-pipelines-ing
  namespace: tekton-pipelines
spec:
  ingressClassName: nginx
  rules:
  - host: tek.tk8s.test
    http:
      paths:
      - backend:
          service:
            name: tekton-dashboard
            port:
              number: 9097
        path: /
        pathType: Prefix
      - backend:
          service:
            name: el-tekton-demo-proxy
            port:
              number: 8080
        path: /webhook-demo
        pathType: Prefix
  tls:
  - hosts:
    - tek.tk8s.test
    secretName: ssl-common

URL을 변경하고 갱신테스트를 해본다.
잘 적용되었다.

ServiceAccount

# serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tekton-triggers-sa
  namespace: tekton-demo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: tekton-build-role
  namespace: tekton-demo
rules:
  - apiGroups: ["", "apps", "tekton.dev", "triggers.tekton.dev"]
    resources: ["pods", "pipelineruns", "tasks", "events"]
    verbs: ["get", "list", "watch", "create", "update", "delete"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: tekton-build-sa-binding
  namespace: tekton-demo
subjects:
  - kind: ServiceAccount
    name: tekton-build-sa
roleRef:
  kind: Role
  name: tekton-build-role
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tekton-build-sa
  namespace: tekton-demo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: tekton-triggers-role
rules:
- apiGroups: [""] # core API
  resources: ["pods", "services", "endpoints", "configmaps", "secrets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["triggers.tekton.dev"]
  resources: ["eventlisteners", "triggerbindings", "triggertemplates", "triggers"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tekton-build-sa-binding
subjects:
  - kind: ServiceAccount
    name: tekton-build-sa
    namespace: tekton-demo
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin

Secret for image pull

# secret-dockerconfig.yaml
apiVersion: v1
kind: Secret
metadata:
  name: harbor-dockerconfig
  namespace: tekton-demo
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: ewoJImF1dGhzI......

task와 pipeline은 실제 동작을 위해 구성하는 오브젝트 입니다.

task.yaml

# task-build.yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: build-image
  namespace: tekton-demo
spec:
  params:
    - name: IMAGE
      type: string
      description: Image name to build
  steps:
    - name: build-and-push
      image: gcr.io/kaniko-project/executor:latest
      args:
        - "--dockerfile=/workspace/source/Dockerfile"
        - "--context=/workspace/source/"
        - "--destination=$(params.IMAGE)"
      volumeMounts:
        - name: docker-config
          mountPath: /kaniko/.docker
  workspaces:
    - name: source
  volumes:
    - name: docker-config
      secret:
        secretName: harbor-dockerconfig

Pipeline

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: pipeline-build
  namespace: tekton-demo
spec:
  params:
    - name: IMAGE
      type: string
    - name: GIT_URL
      type: string
    - name: GIT_REVISION
      type: string
      default: main
  workspaces:
    - name: shared-data
  tasks:
    - name: build
      taskRef:
        name: build-image
      params:
        - name: IMAGE
          value: $(params.IMAGE)
        - name: GIT_URL
          value: $(params.GIT_URL)
        - name: GIT_REVISION
          value: $(params.GIT_REVISION)
      workspaces:
        - name: source
          workspace: shared-data

EventListener

텍톤이 webhook으로 받은 것을 수신할 리스너가 필요합니다.

apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: gitea-event-listener
  namespace: tekton-demo
spec:
  serviceAccountName: tekton-build-sa
  triggers:
    - name: gitea-trigger
      bindings:
        - ref: gitea-trigger-binding
      template:
        ref: gitea-trigger-template

Trigger Template

PipelineRun은 pipelineRef.name을 통해 어떤 Pipeline을 실행할지 지정하고, 실행에 필요한 파라미터를 전달합니다.

apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
  name: gitea-trigger-template
  namespace: tekton-demo
spec:
  params:
    - name: git-url
    - name: git-revision
  resourcetemplates:
    - apiVersion: tekton.dev/v1beta1
      kind: PipelineRun
      metadata:
        generateName: build-run-
      spec:
        serviceAccountName: tekton-build-sa
        pipelineRef:
          name: pipeline-build # 이부분이 사전에 정의한 pipeline을 가져다 쓰는 부분
        params:
          - name: IMAGE
            value: harbor.icurfer.com/open/tekton-demo:latest
          - name: GIT_URL
            value: $(params.git-url)
          - name: GIT_REVISION
            value: $(params.git-revision)
        workspaces:
          - name: shared-data
            volumeClaimTemplate:
              metadata:
                name: source-pvc
              spec:
                accessModes: ["ReadWriteOnce"]
                resources:
                  requests:
                    storage: 1Gi

Trigger Binding

이건 trigger template에 변수 전달할때 사용됨.

apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
  name: gitea-trigger-binding
  namespace: tekton-demo
spec:
  params:
    - name: git-url
      value: $(body.repository.clone_url)
    - name: git-revision
      value: $(body.ref)

git Push 결과

결론 gitAction이 쉽다. gitea-runner사용해야지…

gitAction(or gitea-runner)와 비교하면,
tekton은 event lisener를 만들어야하지만 gitAction은 아니다.
tekton은 대규모 환경에서 코드 재사용성을 높일수 있다. 반면에 틀에 갇힌다.