0부터 시작하는 TEKTON 공부 - CI/CD Pipeline 구축 - GitLab Private Repo Clone With TLS

Jaehong Lee·2023년 5월 11일
2
post-thumbnail

GitLab Private Repo를 Clone해서 Image를 Build 하고, Kubernetes Cluster에 배포해보자. Trigger를 사용하지 않고, 수동으로 PipelineRun을 생성하여 Pipeline을 실행시킬 것이다

Deploy 에서 이어서 진행된다


1. GitLab & Auth

GitLab Project

GitLab 설치가 필요하다. 추가적으로 Openssl을 이용하여 TLS 인증서를 발급하고, 해당 인증서로 Secret을 만들어서 GitLab Ingress에 설정해줘야 한다

  • 외부에서 GitLab에 접속할 때, 가장 먼저 Ingress Controller LB에 접근하므로, GitLab에 대한 Ingress에 TLS 인증서를 설정해줘야 한다

  • GitLab에 접속하여 Project를 생성하고, 파일을 준비하자
  • 파일은 Docker Image Build를 위한 Dockerfile, Image Build에 사용할 index.html, 배포에 필요한 Kubernetes 매니페스트 파일로 구성된다

  • Settings -> General에 들어가서 Project 공개 범위를 Private으로 설정하자
    • Public : 로그인 없이 모든 USER가 접근 가능
    • Internal : 로그인 가능한 모든 USER가 접근 가능
    • Private : Project 생성자 및 Project에 초대된 USER만 접근 가능

GitLab Repository File

test.yaml

apiVersion: apps/v1
kind: Deployment
metadata: 
  name: tektontest
  namespace: hongspace
spec:
  replicas: 5
  selector: 
    matchLabels: 
      app: hong
  template: 
    metadata: 
      name: hongpod
      labels: 
        app: hong
    spec:
      containers: 
      - name: hongcontainer
        image: changetagname
        ports:
        - containerPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: svc-lb-hong
  namespace: hongspace
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: hong
  • Kubernetes Deployment와 Service에 대한 매니페스트 파일 내용은 위와 같다

Dockerfile

FROM nginx:1.21.1

COPY ./index.html /usr/share/nginx/html/index.html

EXPOSE 80
  • Docker Image를 만들기 위한 Dockerfile 내용은 위와 같다

index.html

<html>
  <head>
    <title>test for tekton</title>
  </head>
  <body>
    <div>
      <h1>this is test for gitlabw3-te2kton</h1>
    </div>
  </body>
</html>
  • Docker Image를 만드는데 사용할 Index.html 내용은 위와 같다

GitLab AccessToken

외부에서 Private Project에 접근하려면 인증 & 인가 정보가 필요하다. 우리는 AccessToken을 이용하여 인증할 것이다

  • 해당 Project의 Access Token을 생성하자. 역할은 Owner를 선택하자

  • Clone을 통해 Repository의 파일들을 가져올 것이므로, read 권한만 허용하자

  • 생성한 AccessToken 값은 잘 기억해두자

Secret - Root CA

우리는 GitLab에 TLS 인증서를 등록했으므로, GitLab에 접근하기 위해선 TLS 인증을 거쳐야 한다. TLS 인증 방식에 대한 자세한 정보는 해당 글을 참조하자

우리는 GitLab에 CA에서 발급 받은 공인 TLS 인증서가 아닌, OpenSSL을 이용하여 생성한 사설 TLS 인증서를 등록하였다. 공인 TLS 인증서라면 OS나 WEB 브라우저에 Root CA 인증서가 기본적으로 내장되어 있으므로 문제 없지만, 사설 TLS 인증서는 Root CA 인증서를 따로 등록해줘야 한다

  • Root CA 인증서란 최상위 인증 기관인 Root 인증 기관 ( Root CA )에서 자체 서명한 인증서로 공개키 기반 암호화를 사용한다
  • Root CA 인증서는 서버 인증서가 신뢰 가능한 인증서인지 확인하는데 사용된다

GitClone Task 실행 시 생성되는 Container에 Root CA 인증서를 등록해줘야 한다. Root CA 인증서를 Secret에 담아 해당 Container에 Volumn으로 붙여줘야 하므로, Secret을 생성하자

cat localCA.pem | base64
  • Root CA 인증서를 base64로 인코딩하자
apiVersion: v1
kind: Secret
metadata:
  name: gitlab-ssl
  namespace: hongspace
type: Opaque
data:
  localCA.pem: 'base64로 Root CA 인증서 인코딩한 값'
  • 인코딩한 값을 이용하여 Secret을 생성하자

Secret - AccessToken

TLS 인증을 통해 GitLab에 접근하게 되면, Private Project에 접근하기 위해 인증 & 인가를 거쳐야 한다. 이때 사용할 username과 AccessToken을 Secret에 담아 GitClone Task 실행 시 생성되는 Container에 Volume으로 붙여줘야 하므로, Secret을 생성하자

echo -n 'username값' | base64
echo -n 'AccessToken값' | base64
  • username 값과 위에서 생성한 AccessToken 값을 base64로 인코딩하자
apiVersion: v1
kind: Secret
metadata:
  name: gitlab-secret
  namespace: hongspace
type: Opaque
data:
  username: 'base64로 username 인코딩한 값'
  accesstoken: 'base64로 AccessToken 인코딩한 값'
  • 인코딩한 값들을 이용하여 Secret을 생성하자

2. SA & RBAC & Docker Secret

Docker Secret & SA

Docker Secret & SA에 대한 상세 내용은 아래 링크를 참조하자

apiVersion: v1
kind: Secret
metadata:
  name: docker-config-secret
  namespace: hongspace
data:
  .dockerconfigjson:********************************************
type: kubernetes.io/dockerconfigjson
  • dockerconfig.json 파일을 이용하여 Secret을 생성하자
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-bot
  namespace: hongspace
secrets:
  - name: docker-config-secret
  • ServiceAccount를 생성하고, 위에서 생성한 Secret을 할당해주자

ImagePullSecret

namespace hongspace의 default ServiceAccount에 ImagePullSecret 할당하기. 해당 과정에 대한 상세 내용은 아래 링크를 참조하자

[ec2-user@ip-100-0-1-19 auth]$ k get sa -n hongspace
NAME        SECRETS   AGE
build-bot   2         25m
default     0         7d4h
  • default ServiceAccount를 확인하자
kubectl patch serviceaccount -n hongspace default -p '{"imagePullSecrets": [{"name": "docker-config-secret"}]}'
  • 위에서 생성한 Docker 인증 정보가 담긴 Secret을 default SA에게 할당하자
[ec2-user@ip-100-0-1-19 auth]$ k describe sa -n hongspace default
Name:                default
Namespace:           hongspace
Labels:              <none>
Annotations:         <none>
Image pull secrets:  docker-credential
Mountable secrets:   <none>
Tokens:              <none>
Events:              <none>
  • 잘 할당됬는지 확인하자

RBAC

RBAC에 대한 상세 내용은 아래 링크를 참조하자

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: '*'
  name: role-for-tektondeploy
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
  • ClusterRole을 생성하자
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rolebind-for-deploy
subjects:
  - kind: ServiceAccount
    name: build-bot
    namespace: hongspace
roleRef:
  kind: ClusterRole
  name: role-for-tektondeploy
  apiGroup: rbac.authorization.k8s.io
  • ClusterRoleBinding을 통해 ServiceAccount와 Role을 연결하자

3. PipelineRun & Pipeline

PipelineRun

전체 코드

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  namespace: hongspace
  generateName: hong-cicd-run- # make name automate with random index ( for re use pipelinerun yaml )
spec:
  serviceAccountName: build-bot # sa for git credientials -> pipeline will use for clone private repo
  pipelineRef: # select pipeline
    name: hong-cicd
  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
  - name: ssl-directory
    secret:
      secretName: gitlab-ssl
  - name: gitlab-auth
    secret:
      secretName: gitlab-secret
  params: # gitlab address
    value: "https://gitlab.mandu.com/userhong/jh_tekton_test.git"
  - name: image-reference
    value: lijahong/tektontest:2.0
  - name: kubectl-args
    value:
      - "apply"
      - "-f"
      - "test.yaml"
  • PipelineRun을 작성하자

Workspaces 부분

workspaces: # volume for clone code
  - name: shared-data
    volumeClaimTemplate: # automatically create pvc -> create pv
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 1Gi
  - name: ssl-directory
    secret:
      secretName: gitlab-ssl
  - name: gitlab-auth
    secret:
      secretName: gitlab-secret
  • 2 개의 Workspace를 추가해주자. GitLab TLS 인증을 위한 Root CA 인증서를 담은 Secret과 GitLab 인증 & 인가를 위한 Username / AccessToken을 담은 Secret 이다

Params - url 부분

params: # git address
  - name: repo-url
    value: "https://username:acccesstoken@gitlab.mandu.com/userhong/jh_tekton_test.git"
  • GitLab에 인증 & 인가하기 위해선, 위와 같이 URL에 Username과 AccessToken 값을 넣어야 한다
  • 하지만 우리는 Secret을 통해 Username과 AccessToken을 TaskRun Pod에게 넘겨주어, Container 내부에서 Script를 통해 Url을 설정하게 할 것이다
  • 이는 Secret을 통해 AccessToken 데이터를 감추려는 의도도 있지만, Task에서 URL을 설정하여 추후에 Trigger를 통해 URL을 파라미터로 받아와 사용하기 위한 의도이기도 하다

params: # gitlab address
    value: "https://gitlab.mandu.com/userhong/jh_tekton_test.git"
  • 현재는 Trigger를 사용하지 않으므로, URL은 위와 같이 설정하자
  • 위와 같이 설정하는 이유는 GitLab Web-Hook Json Payload를 살펴보면, body.repository.git_http_url을 통해 위와 같은 URL 데이터를 가져올 수 있기 때문이다

PipelineRun에 대한 상세 내용은 아래 링크를 참조하자


Pipeline

전체 코드

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: hong-cicd
  namespace: hongspace
spec:
  params:
  - name: repo-url
    type: string
  - name: image-reference
    type: string
  - name: kubectl-args
    type: array

  workspaces:
  - name: shared-data
  - name: ssl-directory
  - name: gitlab-auth

  tasks:
  - name: fetch-source
    taskRef:
      name: git-clone
    workspaces:
    - name: output
      workspace: shared-data
    - name: ssl-ca-directory
      workspace: ssl-directory
    - name: gitlab-se
      workspace: gitlab-auth
    params:
    - name: url
      value: $(params.repo-url)

  - name: build-push
    runAfter: ["fetch-source"]
    taskRef:
      name: kaniko
    workspaces:
      - name: source
        workspace: shared-data
    params:
      - name: IMAGE
        value: $(params.image-reference)

  - name: deploy
    runAfter: ["build-push"]
    taskRef:
      name: kubernetes-actions
    workspaces:
      - name: manifest-dir
        workspace: shared-data
    params:
      - name: args
        value: $(params.kubectl-args[*])
      - name: deployimage
        value: $(params.image-reference)
  • Pipeline을 작성하자

Workspaces 부분

workspaces:
  - name: shared-data
  - name: ssl-directory # 추가!
  - name: gitlab-auth # 추가!

  tasks:
  - name: fetch-source
    taskRef:
      name: git-clone
    workspaces:
    - name: output
      workspace: shared-data
    - name: ssl-ca-directory # 추가!
      workspace: ssl-directory
    - name: gitlab-se # 추가!
      workspace: gitlab-auth
  • PipelineRun으로부터 전달 받은 GitLab 인증에 대한 Workspace들을 선언하고, 이를 git-clone Task에게 넘겨주자

Pipeline에 대한 상세 내용은 아래 링크를 참조하자


4. Task

Git-Clone

전체 코드

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-clone
  namespace: hongspace
  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
    - name: gitlab-se # workspace which carry Gitlab auth information for Gitlab Clone
      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)

      # custom env for gitlab authentication by username & accesstoken
      - name: WORKSPACE_GITLAB_SE_PATH
        value: $(workspaces.gitlab-se.path)
      - name: WORKSPACE_GITLAB_SE_BOUND
        value: $(workspaces.gitlab-se.bound)

      script: |
        #!/usr/bin/env sh
        set -eu

        # Print Command by Standard Error Print before activate Command
        if [ "${PARAM_VERBOSE}" = "true" ] ; then
          set -x
        fi

        #### CUSTOMIZE SETTING START ####

        # Setting GitLab Ip address for Domain Address
        echo "11.111.111.11 gitlab.mandu.com" | tee -a /etc/hosts

        # Setting Root CA - This OS is Alpine Linux -> for TLS AUTH
        if [ "${WORKSPACE_SSL_CA_DIRECTORY_BOUND}" = "true" ] ; then
           cp ${WORKSPACE_SSL_CA_DIRECTORY_PATH}/localCA.pem  /usr/local/share/ca-certificates/
           update-ca-certificates
        fi

        # Setting Url Using Username and AccessToken -> for GITLAB AUTH
        if [ "${WORKSPACE_GITLAB_SE_BOUND}" = "true" ] ; then
           usernamevalue=$(cat ${WORKSPACE_GITLAB_SE_PATH}/username)
           tokenvalue=$(cat ${WORKSPACE_GITLAB_SE_PATH}/accesstoken)
           gitlabadrr=$(echo ${PARAM_URL:8})
           # username + accesstoken + url
           gitlab_url="https://${usernamevalue}:${tokenvalue}@${gitlabadrr}"
        fi

        #### CUSTOMIZE SETTING END ####

        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

        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="${gitlab_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)"
  • git-clone Task 코드를 작성하자

Workspaces 부분

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
    - name: gitlab-se # workspace which carry Gitlab auth information for Gitlab Clone
      optional: True
  • Pipeline으로부터 전달 받은 GitLab 인증에 대한 Workspace들을 선언하자

spec.steps.env 부분

	  - name: WORKSPACE_SSL_CA_DIRECTORY_BOUND
        value: $(workspaces.ssl-ca-directory.bound)
      - name: WORKSPACE_SSL_CA_DIRECTORY_PATH
        value: $(workspaces.ssl-ca-directory.path)

      # custom env for gitlab authentication by username & accesstoken
      - name: WORKSPACE_GITLAB_SE_PATH
        value: $(workspaces.gitlab-se.path)
      - name: WORKSPACE_GITLAB_SE_BOUND
        value: $(workspaces.gitlab-se.bound)
  • 전달 받은 Workspace들에 대한 경로를 Container의 환경 변수로 설정하자. 이를 통해 TaskRun Pod 안에 Container들이 Bound된 Workspace에 접근할 수 있다
  • Bound는 해당 Workspace가 Bound 됬는지에 대한 여부를 나타낸다

Git-Clone Task에 대한 상세 설명은 아래 링크를 참조하자


Git-Clone - 추가 Script

Git-Clone Task의 spec.steps.script에 추가한 GitLab 인증에 대한 설정 명령을 살펴보자

       #### CUSTOMIZE SETTING START ####

        # Setting GitLab Ip address for Domain Address
        echo "11.111.111.11 gitlab.mandu.com" | tee -a /etc/hosts

        # Setting Root CA - This OS is Alpine Linux -> for TLS AUTH
        if [ "${WORKSPACE_SSL_CA_DIRECTORY_BOUND}" = "true" ] ; then
           cp ${WORKSPACE_SSL_CA_DIRECTORY_PATH}/localCA.pem  /usr/local/share/ca-certificates/
           update-ca-certificates
        fi

        # Setting Url Using Username and AccessToken -> for GITLAB AUTH
        if [ "${WORKSPACE_GITLAB_SE_BOUND}" = "true" ] ; then
           usernamevalue=$(cat ${WORKSPACE_GITLAB_SE_PATH}/username)
           tokenvalue=$(cat ${WORKSPACE_GITLAB_SE_PATH}/accesstoken)
           gitlabadrr=$(echo ${PARAM_URL:8})
           # username + accesstoken + url
           gitlab_url="https://${usernamevalue}:${tokenvalue}@${gitlabadrr}"
        fi

        #### CUSTOMIZE SETTING END ####
  • 살펴볼 전체 코드는 위와 같다

GitLab Domain 주소 설정

echo "11.111.111.11 gitlab.mandu.com" | tee -a /etc/hosts
  • 우리는 GitLab 설치 시, Ingress에 설정한 Domain 주소를 DNS 서버에 등록하지 않았다. 따라서 해당 Domain 주소에 대한 Ip 주소를 Hosts에 등록해야 한다
  • /etc/hosts 파일은 Domain 주소와 Ip 주소를 매핑해주어, DNS로부터 Ip 주소 정보를 제공받지 않아도 서버의 Ip 주소를 알 수 있게 해준다
    • DNS에 질의하기 전에, /etc/hosts 파일에서 먼저 찾아본다

Root CA 인증서 등록

if [ "${WORKSPACE_SSL_CA_DIRECTORY_BOUND}" = "true" ] ; then
           cp ${WORKSPACE_SSL_CA_DIRECTORY_PATH}/localCA.pem  /usr/local/share/ca-certificates/
           update-ca-certificates
fi
  • 우리는 사설 TLS 인증서를 GitLab에 대한 Ingress LB에 등록했기에, 이 인증서가 신뢰 가능한지 확인하려면 Root CA 인증서를 등록해야 한다
  • 해당 Container Image의 Base Image는 Alpine Linux이므로, 위와 같이 Bound된 Workspace에서 Root CA 인증서 파일을 복사하여 등록해주면 된다

Url 설정

"https://username:acccesstoken@gitlab.mandu.com/userhong/jh_tekton_test.git"
  • GitLab 인증 & 인가를 위해선, 위와 같이 URL에 Username과 Password를 넣어줘야 한다
https://gitlab.mandu.com/userhong/jh_tekton_test.git
  • 우리는 파라미터를 통해 URL을 위와 같은 형식의 문자열로 넘겨 받는다. 이를 Script를 통해 변경시키면 된다
if [ "${WORKSPACE_GITLAB_SE_BOUND}" = "true" ] ; then
           usernamevalue=$(cat ${WORKSPACE_GITLAB_SE_PATH}/username)
           tokenvalue=$(cat ${WORKSPACE_GITLAB_SE_PATH}/accesstoken)
           gitlabadrr=$(echo ${PARAM_URL:8})
           # username + accesstoken + url
           gitlab_url="https://${usernamevalue}:${tokenvalue}@${gitlabadrr}"
fi
  • 문자열 슬라이싱을 통해 Url 앞부분을 없애고, Bound된 Workspace에 들어있는 Username 파일과 AccessToken 파일을 이용하여 설정한 URL을 새로운 환경 변수에 등록하였다
/ko-app/git-init \
          -url="${gitlab_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}"
  • 위에서 생성한 환경 변수를 git-init 명령의 url옵션 값으로 설정하였다

Kaniko

전체 코드

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: kaniko
  namespace: hongspace
  labels:
    app.kubernetes.io/version: "0.6"
  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"
    tekton.dev/platforms: "linux/amd64,linux/arm64,linux/ppc64le"
spec:
  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 # kaniko image who build and push image
      description: The image on which builds will run (default is v1.5.1)
      default: gcr.io/kaniko-project/executor:v1.5.1@sha256:c6166717f7fe0b7da44908c986137ecfeab21f31ec3992f6e128fff8a94be8a5
  workspaces:
    - name: source
      description: Holds the context and Dockerfile
    - name: dockerconfig # we will not use this time, we use access token by service account
      description: Includes a docker `config.json`
      optional: true
      mountPath: /kaniko/.docker
  results:
    - name: IMAGE_DIGEST
      description: Digest of the image just built.
    - name: IMAGE_URL
      description: URL 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)
        - --destination=$(params.IMAGE)
        - --digest-file=$(results.IMAGE_DIGEST.path)
      securityContext:
        runAsUser: 0
    - name: write-url
      image: docker.io/library/bash:5.1.4@sha256:c523c636b722339f41b6a431b44588ab2f762c5de5ec3bd7964420ff982fb1d9
      script: |
        set -e
        image="$(params.IMAGE)"
        echo -n "${image}" | tee "$(results.IMAGE_URL.path)"
  • Docker Container Image를 Build 하고, Repository에 Push 해주는 Kaniko Task를 작성하자

Kaniko Task에 대한 상세 설명은 아래 링크를 참조하자


Deploy

전체 코드

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: kubernetes-actions
  namespace: hongspace
  labels:
    app.kubernetes.io/version: "0.2"
  annotations:
    tekton.dev/pipelines.minVersion: "0.17.0"
    tekton.dev/categories: Kubernetes
    tekton.dev/tags: CLI, kubectl
    tekton.dev/displayName: "kubernetes actions"
    tekton.dev/platforms: "linux/amd64"
spec:
  description: >-
    This task is the generic kubectl CLI task which can be used
    to run all kinds of k8s commands
  workspaces:
    - name: manifest-dir # if you have yaml
      optional: true
    - name: kubeconfig-dir # it is need when yo deploy at other cluster
      optional: true
  results:
    - name: output-result # result text
      description: some result can be emitted if someone wants to.
  params:
    - name: script  # cli command, you setting
      description: The Kubernetes CLI script to run
      type: string
      default: "kubectl $@" # $@ means use all parameter and all parameter is individual. parameter is args
    - name: args
      description: The Kubernetes CLI arguments to run # args for kubectl command. if you not describe script. then default script " kubectl $@ " activate and use this args like "get" "pod"
      type: array # multiple args can come
      default:
        - "help"
    - name: image # image for use kubectl to our cluster or other cluster ( if you set kubeconfig )
      default: gcr.io/cloud-builders/kubectl@sha256:8ab94be8b2b4f3d117f02d868b39540fddd225447abf4014f7ba4765cb39f753 #image is huge
      description: Kubectl wrapper image
    - name: deployimage # deploy image, which kaniko build
      description: Name (reference) of the image to build.
  steps:
    - name: kubectl
      image: $(params.image)
      script: |
        #!/usr/bin/env bash

        # if workspace which yaml file saved has bound, go to that directory
        [[ "$(workspaces.manifest-dir.bound)" == "true" ]] && \
        cd $(workspaces.manifest-dir.path)

        # update yaml file image name
        sed -i "s@changetagname@$(params.deployimage)@" test.yaml

        # if kubeconfig workspace has bound and kubeconfig file exist, set env for kubeconfig path
        [[ "$(workspaces.kubeconfig-dir.bound)" == "true" ]] && \
        [[ -f $(workspaces.kubeconfig-dir.path)/kubeconfig ]] && \
        export KUBECONFIG=$(workspaces.kubeconfig-dir.path)/kubeconfig

        # do kubectl command
        $(params.script)

      args: # args for kubectl command
        - "$(params.args)"
  • Kubectl 명령을 실행해주는 Deploy Task를 작성하자

Deploy Task에 대한 상세 설명은 아래 링크를 참조하자


5. 결과 확인

kubectl create -f pipelineRun.yaml
  • Trigger를 사용하지 않으므로, 수동으로 PipelineRun을 생성하여 Pipeline을 실행시키자

  • Pipeline이 잘 실행되었다

  • Image가 DockerHub Private Repo에 잘 Push 되었다
[ec2-user@ip-100-0-1-19 pipeline]$ k get pod,svc -n hongspace
NAME                                        READY   STATUS      RESTARTS   AGE
pod/tektontest-77c8c887f5-2gc25             1/1     Running     0          2m15s
pod/tektontest-77c8c887f5-66w72             1/1     Running     0          2m15s
pod/tektontest-77c8c887f5-9hhrg             1/1     Running     0          2m14s
pod/tektontest-77c8c887f5-chfr6             1/1     Running     0          2m14s
pod/tektontest-77c8c887f5-jnwnd             1/1     Running     0          2m15s

NAME                           TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)             AGE
service/svc-lb-hong            LoadBalancer   10.100.170.244   ***************************.ap-northeast-2.elb.amazonaws.com   80:31180/TCP        2m15s
  • Pod와 Service가 잘 배포되었다

  • Pod에 잘 접속된다
profile
멋진 엔지니어가 될 때까지

0개의 댓글