0부터 시작하는 TEKTON 공부 - CI/CD Pipeline 구축 - GitHub Public Repo Clone

Jaehong Lee·2023년 4월 21일
2
post-thumbnail

GitHub Public Repo를 Clone 해보자

참조 : https://tekton.dev/docs/how-to-guides/clone-repository/


1. PipelineRun & Pipeline

리소스 준비

GitHub에 Public Repo를 생성하고, 아무 파일이나 저장하자. README.md 내용을 조회하는 작업을 실행할 것이므로, README.md는 반드시 있어야 한다


PipelineRun

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  generateName: clone-read-run- # make name automate with random index ( for re use pipelinerun yaml )
spec:
  #serviceAccountName: git-sa # sa for git credientials -> pipeline will use for clone private repo
  pipelineRef: # select pipeline
    name: clone-read
  podTemplate: # setting taskpod
    securityContext:  # pod security
      fsGroup: 65532 # set volume owner gid = 65532
  workspaces: # volume for clone code
  - name: shared-data
    volumeClaimTemplate: # automatically create pvc -> create pv
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 1Gi
  params: # git address
  - name: repo-url
    value: "https://github.com/lijahong/tektontest"
  • PipelineRun은 위와 같다. Clone할 repo url을 파라미터로 Pipeline에게 넘겨준다
  • generateName을 이용하여 PipelineRun을 생성할 때마다 새로운 이름으로 생성하여, 새로운 PipelineRun이 생성되게 한다. 이를 통해 동일한 PipelineRun 매니페스트 파일을 이용하여 Pipeline을 여러번 실행 가능하다
  • workspaces 정의시 volumeclaimtemplate을 정의하면, 자동으로 pvc가 만들진다
  • podtemplate은 실행될 TaskRun Pod에 대한 설정이다
    • security context는 쿠버네티스의 파드나 컨테이너에 대한 접근제어 설정이나 특수 권한과 같은 보안을 설정한다
    • 쿠버네티스는 볼륨이 마운트 될 때, pod의 fsgroup에 지정된 것과 일치하도록 볼륨의 소유권 ( 볼륨 소유자 gid ) 을 지속적으로 변경한다

Pipeline

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: clone-read
spec:
  params:
  - name: repo-url
    type: string

  workspaces:
  - name: shared-data

  tasks:
  - name: fetch-source
    taskRef:
      name: git-clone
    workspaces:
    - name: output
      workspace: shared-data
    params:
    - name: url
      value: $(params.repo-url)

  - name: show-readme
    runAfter: ["fetch-source"]
    taskRef:
      name: show-readme
    workspaces:
    - name: source
      workspace: shared-data
  • Pipeline은 2 개의 Task로 구성된다
  • repo를 clone할 git-clone과 clone한 README.md를 출력할 show-readme로 구성된다
  • runAfter를 통해 순서를 지정할 수 있다. runAfter는 특정 작업이 완료되면 실행하도록 하는 옵션이다. show-readme는 git-clone이 완료되면 실행된다

2. Task

Git Clone

tkn hub install task git-clone
  • tkn 명령어를 이용하여 TEKTON HUB에서 git-clone용 Task를 생성하자
kubectl apply -f \
https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.6/git-clone.yaml
  • Kubectl을 사용하여 생성할 수도 있다
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-clone
  labels:
    app.kubernetes.io/version: "0.6"
  annotations:
    tekton.dev/pipelines.minVersion: "0.29.0"
    tekton.dev/categories: Git
    tekton.dev/tags: git
    tekton.dev/displayName: "git clone"
    tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64"
spec:
  workspaces: # we only use output workspace for save clone file
    - name: output # volume for save clone file

    # following workspace is for authentication, which for clone private repo. each workspace contains authentication file
    - name: ssh-directory # workspace for using ssh
      optional: True
    - name: basic-auth # workspace for using git credentials
      optional: True
    - name: ssl-ca-directory # workspace for using  ca certificate ( https )
      optional: True

  params:
    - name: url # repo url
      description: Repository URL to clone from.
      type: string
    - name: revision
      description: Revision to checkout. (branch, tag, sha, ref, etc...)
      type: string
      default: ""
    - name: refspec
      description: Refspec to fetch before checking out revision.
      default: ""
    - name: submodules
      description: Initialize and fetch git submodules.
      type: string
      default: "true"
    - name: depth
      description: Perform a shallow clone, fetching only the most recent N commits.
      type: string
      default: "1"
    - name: sslVerify
      description: Set the `http.sslVerify` global git config. Setting this to `false` is not advised unless you are sure that you trust your git remote.
      type: string
      default: "true"
    - name: subdirectory
      description: Subdirectory inside the `output` Workspace to clone the repo into.
      type: string
      default: ""
    - name: sparseCheckoutDirectories
      description: Define the directory patterns to match or exclude when performing a sparse checkout.
      type: string
      default: ""
    - name: deleteExisting
      description: Clean out the contents of the destination directory if it already exists before cloning.
      type: string
      default: "true"
    - name: httpProxy
      description: HTTP proxy server for non-SSL requests.
      type: string
      default: ""
    - name: httpsProxy
      description: HTTPS proxy server for SSL requests.
      type: string
      default: ""
    - name: noProxy
      description: Opt out of proxying HTTP/HTTPS requests.
      type: string
      default: ""
    - name: verbose
      description: Log the commands that are executed during `git-clone`'s operation.
      type: string
      default: "true"
    - name: gitInitImage # image for git init
      description: The image providing the git-init binary that this Task runs.
      type: string
      default: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.29.0"
    - name: userHome
      description: |
        Absolute path to the user's home directory. Set this explicitly if you are running the image as a non-root user or have overridden
        the gitInitImage param with an image containing custom user configuration.
      type: string
      default: "/tekton/home"

  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)"
      env:
      - name: HOME
        value: "$(params.userHome)"
      - name: PARAM_URL
        value: $(params.url)
      - name: PARAM_REVISION
        value: $(params.revision)
      - name: PARAM_REFSPEC
        value: $(params.refspec)
      - name: PARAM_SUBMODULES
        value: $(params.submodules)
      - name: PARAM_DEPTH
        value: $(params.depth)
      - name: PARAM_SSL_VERIFY
        value: $(params.sslVerify)
      - name: PARAM_SUBDIRECTORY
        value: $(params.subdirectory)
      - name: PARAM_DELETE_EXISTING
        value: $(params.deleteExisting)
      - name: PARAM_HTTP_PROXY
        value: $(params.httpProxy)
      - name: PARAM_HTTPS_PROXY
        value: $(params.httpsProxy)
      - name: PARAM_NO_PROXY
        value: $(params.noProxy)
      - name: PARAM_VERBOSE
        value: $(params.verbose)
      - name: PARAM_SPARSE_CHECKOUT_DIRECTORIES
        value: $(params.sparseCheckoutDirectories)
      - name: PARAM_USER_HOME
        value: $(params.userHome)
      - name: WORKSPACE_OUTPUT_PATH
        value: $(workspaces.output.path)
      - name: WORKSPACE_SSH_DIRECTORY_BOUND
        value: $(workspaces.ssh-directory.bound)
      - name: WORKSPACE_SSH_DIRECTORY_PATH
        value: $(workspaces.ssh-directory.path)
      - name: WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND
        value: $(workspaces.basic-auth.bound)
      - name: WORKSPACE_BASIC_AUTH_DIRECTORY_PATH
        value: $(workspaces.basic-auth.path)
      - name: WORKSPACE_SSL_CA_DIRECTORY_BOUND
        value: $(workspaces.ssl-ca-directory.bound)
      - name: WORKSPACE_SSL_CA_DIRECTORY_PATH
        value: $(workspaces.ssl-ca-directory.path)
      script: |
        #!/usr/bin/env sh
        set -eu

        if [ "${PARAM_VERBOSE}" = "true" ] ; then
          set -x
        fi


        if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ] ; then
          cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" "${PARAM_USER_HOME}/.git-credentials"
          cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" "${PARAM_USER_HOME}/.gitconfig"
          chmod 400 "${PARAM_USER_HOME}/.git-credentials"
          chmod 400 "${PARAM_USER_HOME}/.gitconfig"
        fi

        if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ] ; then
          cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}" "${PARAM_USER_HOME}"/.ssh
          chmod 700 "${PARAM_USER_HOME}"/.ssh
          chmod -R 400 "${PARAM_USER_HOME}"/.ssh/*
        fi

        if [ "${WORKSPACE_SSL_CA_DIRECTORY_BOUND}" = "true" ] ; then
           export GIT_SSL_CAPATH="${WORKSPACE_SSL_CA_DIRECTORY_PATH}"
        fi
        CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_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 [ "${PARAM_DELETE_EXISTING}" = "true" ] ; then
          cleandir
        fi

        test -z "${PARAM_HTTP_PROXY}" || export HTTP_PROXY="${PARAM_HTTP_PROXY}"
        test -z "${PARAM_HTTPS_PROXY}" || export HTTPS_PROXY="${PARAM_HTTPS_PROXY}"
        test -z "${PARAM_NO_PROXY}" || export NO_PROXY="${PARAM_NO_PROXY}"

        /ko-app/git-init \
          -url="${PARAM_URL}" \
          -revision="${PARAM_REVISION}" \
          -refspec="${PARAM_REFSPEC}" \
          -path="${CHECKOUT_DIR}" \
          -sslVerify="${PARAM_SSL_VERIFY}" \
          -submodules="${PARAM_SUBMODULES}" \
          -depth="${PARAM_DEPTH}" \
          -sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}"
        cd "${CHECKOUT_DIR}"
        RESULT_SHA="$(git rev-parse HEAD)"
        EXIT_CODE="$?"
        if [ "${EXIT_CODE}" != 0 ] ; then
          exit "${EXIT_CODE}"
        fi
        printf "%s" "${RESULT_SHA}" > "$(results.commit.path)"
        printf "%s" "${PARAM_URL}" > "$(results.url.path)"
  • Task 파일은 위와 같다. 전체 작업 순서는 다음과 같다
    1. git init이 가능한 환경이 구성된 이미지를 사용하여 컨테이너를 배포
    2. 배포된 컨테이너에서 shell script를 실행하여 workspace에 git init 및 clone 실행
    3. 작업 완료 후 컨테이너 종료
  • 사용할 파라미터와 workspace를 정의하고, 이를 컨테이너의 환경 변수로 등록하여, 컨테이너 내부에서 환경 변수를 통해 파라미터와 workspace를 사용할 수 있다

Shell Script 내용은 크게 다음과 같다

  1. 인증 정보가 Volume으로 붙어있다면, 인증 정보 파일을 컨테이너 내로 가져온다
  2. clone한 데이터를 저장할 Volume에 데이터가 있다면, 내부의 데이터를 삭제한다
  3. Proxy 사용 시, Proxy 환경 변수로 등록한다
    • test는 파일이나 문자열을 점검하고, 비교하는 명령어다. z 옵션은 문자열의 길이가 0이라면 True를 반환한다
    test -z "${PARAM_HTTP_PROXY}" || export HTTP_PROXY="${PARAM_HTTP_PROXY}"
    • 위 명령어는 PARAM_HTTP_PROXY의 값이 비어있지 않다면 ( test 결과가 fail 이라면 ), export HTTP_PROXY="${PARAM_HTTP_PROXY}를 실행해준다. 즉 Proxy를 사용한다면, Proxy 환경 변수를 설정해주는 것이다
  4. git init를 하고, 해당 repo를 clone 한다
  5. 작업 결과를 result에 담는다

workspace optional

  • optional은 정의한 workspace를 반드시 넘겨 받아야 하는지 아닌지를 설정한다
    • false로 설정했을 때, 해당 workspace를 넘겨 받지 못하면, 오류가 발생한다
    • true로 설정하면, 해당 workspace를 넘겨 받지 못해도, 오류가 발생하지 않는다
  • 위에서 workspace는 clone 데이터를 저장할 output과 GIT에 대한 인증 정보를 가지고 있는 workspace 들로 구성된다. 우리는 Public Repo를 clone하므로 인증 정보를 담는 workspace를 사용하지 않는다. optional을 True로 설정했으므로 workspace를 넘겨주지 않아도 오류가 발생하지 않는다

result 란

 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.
  • result는 사용자나 파이프라인 내의 다른 Task에게 문자열 형식의 결과를 보내기 위해 사용한다
  • 이는 Commit SHA, Branch 이름, 컨테이너 이미지 다이제스트와 같은 소량의 데이터를 담는데 적합하다

Show README.md

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: show-readme # task for show readme
spec:
  workspaces: # using volume, where readme is saced
  - name: source
  steps:
  - name: read
    image: alpine:latest # we use alphin image, it will use cat for show readme file in workspace volume
    script: |
      #!/usr/bin/env sh
      cat $(workspaces.source.path)/README.md
  • clone한 repo 데이터 중 README.md 내용을 출력하는 작업이다
  • alpine 이미지와 clone한 repo 데이터가 저장된 volume을 사용한다
  • 컨테이너가 배포되면, cat 명령을 통해 volume에 저장된 README.md 파일 내용을 출력한다

3. 결과 확인

[ec2-user@ip-100-0-1-19 tektontest]$ k get pod
NAME                                    READY   STATUS      RESTARTS   AGE
clone-read-run-ngwht-fetch-source-pod   0/1     Completed   0          70m
clone-read-run-ngwht-show-readme-pod    0/1     Completed   0          70m
  • 각 Task 별로 TaskRun Pod가 배포되어 작업을 잘 실행하였다
[ec2-user@ip-100-0-1-19 tektontest]$ k get pr
NAME                   SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
clone-read-run-ngwht   True        Succeeded   72m         71m
[ec2-user@ip-100-0-1-19 tektontest]$ tkn pr list
NAME                   STARTED      DURATION   STATUS
clone-read-run-ngwht   1 hour ago   39s        Succeeded
  • PipelineRun이 잘 실행되었다
[ec2-user@ip-100-0-1-19 tektontest]$ tkn pr logs clone-read-run-ngwht
[fetch-source : clone] + '[' '$(workspaces.basic-auth.bound)' '=' true ]
[fetch-source : clone] + '[' '$(workspaces.ssh-directory.bound)' '=' true ]
[fetch-source : clone] + '[' '$(workspaces.ssl-ca-directory.bound)' '=' true ]
[fetch-source : clone] + CHECKOUT_DIR=/workspace/output/
[fetch-source : clone] + '[' true '=' true ]
[fetch-source : clone] + cleandir
[fetch-source : clone] + '[' -d /workspace/output/ ]
[fetch-source : clone] + rm -rf /workspace/output//lost+found
[fetch-source : clone] + rm -rf '/workspace/output//.[!.]*'
[fetch-source : clone] + rm -rf '/workspace/output//..?*'
[fetch-source : clone] + test -z
[fetch-source : clone] + test -z
.
.
.
[fetch-source : clone] + cd /workspace/output/
[fetch-source : clone] + git rev-parse HEAD
[fetch-source : clone] + RESULT_SHA=********************************
[fetch-source : clone] + EXIT_CODE=0
[fetch-source : clone] + '[' 0 '!=' 0 ]
[fetch-source : clone] + printf '%s' ********************
[fetch-source : clone] + printf '%s' https://github.com/lijahong/tektontest

[show-readme : read] # tektontest
[show-readme : read] file for clone by tekton
  • log를 통해 작업 결과를 확인하자
  • show-readme TASK의 경우, README.md 내용을 출력한다
  • git-clone TASK의 경우, 실행한 명령어 이력을 출력한다
    • fetch-source는 pipeline에서 git-clone TASK에 대해 설정한 이름이다

  • result를 확인하자

  • README.md 내용이 잘 출력되었다
profile
멋진 엔지니어가 될 때까지

0개의 댓글