본 포스팅은 "Tekton 사용해보기" 시리즈의 두 번째 글입니다.
해당 시리즈의 첫 번째 글은 Tekton 사용해보기 (1) Tekton으로 쿠버네티스 CI/CD 파이프라인을 구성해보자 에서 볼 수 있습니다.
이번 포스팅에서는 Tekton을 이용해서 Terraform으로 인프라를 자동 배포하는 파이프라인을 구성해보겠습니다.
저번 포스팅에서 소개했듯이 Tekton은 사용자가 자유롭게 취사선택할 수 있는 빌딩 블록을 제공하기 때문에 원하는 작업을 수행하는 파이프라인을 유연하게 구성할 수 있다는 장점이 있는데요.
Terraform 파이프라인도 이러한 Tekton의 유연한 빌딩 블록의 장점을 활용해서 구성한 것이라 할 수 있겠습니다.
이번 Tekton 사용해보기의 두 번째 글을 통해서는 Tekton으로 Terraform 배포 파이프라인을 어떻게 구성할 수 있는지에 대해서 알아보겠습니다.
1. Tekton 파이프라인 개요
이번 포스팅에서 소개할 Tekton 파이프라인의 아키텍쳐 다이어그램은 위와 같습니다.
파이프라인이 실행할 작업들을 순서대로 나열하면 아래와 같습니다.
1. Terraform 코드가 존재하는 Git repository에 Push 작업을 제출합니다.
2. 동시에 Git repository는 Kubernetes Ingress로 노출되어 있는 Tekton Eventlistener에게 Webhook을 호출합니다.
3. Tekton Eventlistener는 이벤트를 감지해 지정된 Tekton Pipline을 Trigger합니다.
4. Tekton Pipeline은 git-clone Task를 실행해 Webhook을 호출한 Git repository를 Clone해 저장장치에 저장합니다.
5. 이후 terraform-cli Task를 실행해 Terraform init 및 지정한 Terraform 명령어를 실행합니다.
위 Terraform 파이프라인의 실제 사용 결과는 아래와 같습니다.
1. Terraform 코드가 존재하는 Git repository를 준비합니다.
2. 해당 Repository에 Webhook을 Trigger하기 위해 Push 작업을 제출합니다.
3. Webhook을 감지한 Tekton EventListener가 Tekton Pipeline을 실행합니다. Pipeline은 실행되며 git-clone 및 terraform 커맨드를 실행합니다.
4. Tekton Pipeline이 실행되며 실제 인프라가 배포된 것을 확인합니다.
본 포스팅에서는 Git repository로 Bitbucket을, Cloud Provider는 Google Cloud Platform를, Tekton 환경은 GKE를 사용했습니다.
하지만 파이프라인 구성은 유연하게 가져갈 수 있기 때문에 위 컴포넌트들은 Github, AWS, Azure, EKS 등의 다른 구성요소로 대체 가능합니다.
2. Tekton Pipeline 구성요소
이번 파이프라인에서 사용되는 Tekton 구성 요소들은 위와 같은 관계도를 가지게 됩니다.
EventListener, TriggerBinding, Pipeine, Task 등의 Tekton 구성요소들에 대한 설명이 필요하다면 이전 글인
Tekton 사용해보기 (1) Tekton으로 쿠버네티스 CI/CD 파이프라인을 구성해보자 를 참고하시기 바랍니다.
이제 파이프라인을 구성하는 Tekton 빌딩 블록들을 분석해보며 어떤 코드로 이루어져 있는지 살펴보겠습니다.
2-1. Task "git-clone"
첫번째로 살펴볼 구성요소는 파이프라인에서 가장 먼저 실행되는 Task인 "git-clone" Task입니다.
"git-clone" Task는 Tekton의 레포지토리와도 같은 Tekton Hub에서 제공해주는 커뮤니티 제공 Task이기 때문에 tkn 명령어 등으로 간단하게 내려받을 수 있습니다.
1
|
tkn hub install task git-clone
|
cs |
"git-clone" Task는 "url" 변수로 지정한 Repository를 Clone해 내부 저장장치에 저장하도록 구성되어 있습니다.
그 외에 자세한 동작 및 Parameter에 대한 설명은 아래 Tekton hub 페이지에서 확인할 수 있습니다.
https://hub.tekton.dev/tekton/task/git-clone
2-2. Task "terraform-cli"
다음으로 살펴볼 구성요소는 테라폼 명령어를 실행하는 "terraform-cli" Task입니다.
이 Task는 이전 "git-clone"에서 실행되어 저장된 Terraform 코드를 기반으로 테라폼 명령어를 실행해 인프라를 배포하는 역할을 합니다.
"terraform-cli" Task 또한 "git-clone"과 마찬가지로 tekton hub에서 제공되는 커뮤니티 제공 Task지만, 이번 파이프라인에서 사용하기 위해서는 약간의 수정이 필요하기 때문에 아래 yaml 매니페스트를 사용합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
annotations:
tekton.dev/categories: CLI
tekton.dev/displayName: terraform cli
tekton.dev/pipelines.minVersion: 0.12.1
tekton.dev/platforms: linux/amd64
tekton.dev/tags: cli
labels:
app.kubernetes.io/version: "0.2"
hub.tekton.dev/catalog: tekton
name: terraform-cli
spec:
description: |-
Terraform is an open-source infrastructure as code software tool created by HashiCorp.
It enables users to define and provision a datacenter infrastructure using a high-level configuration language known as Hashicorp Configuration Language (HCL), or optionally JSON
This Task will do a terraform init before it executes the actual configured ARGS from parameter.
params:
- default:
- --help
description: The terraform cli commands to tun
name: ARGS
type: array
- default: terraform-creds
description: The terraform secret with credentials
name: terraform-secret
type: string
- default: docker.io/hashicorp/terraform:light
description: the terraform image to use
name: image
type: string
- default: ""
description: HTTP proxy server for non-SSL requests
name: httpProxy
type: string
- default: ""
description: HTTPS proxy server for SSL requests
name: httpsProxy
type: string
- default: ""
description: no proxy - opt out of proxying HTTP/HTTPS requests
name: noProxy
type: string
steps:
- args:
- init
command:
- terraform
env:
- name: HTTP_PROXY
value: $(params.httpProxy)
- name: HTTPS_PROXY
value: $(params.httpsProxy)
- name: HTTP_PROXY
value: $(params.httpProxy)
image: $(params.image)
name: init
resources: {}
volumeMounts:
- mountPath: $(workspaces.source.path)/key
name: gcp-sa
workingDir: $(workspaces.source.path)
- args:
- $(params.ARGS)
command:
- terraform
env:
- name: HTTP_PROXY
value: $(params.httpProxy)
- name: HTTPS_PROXY
value: $(params.httpsProxy)
- name: HTTP_PROXY
value: $(params.httpProxy)
envFrom:
- secretRef:
name: $(params.terraform-secret)
image: $(params.image)
name: terraform-cli
resources: {}
volumeMounts:
- mountPath: $(workspaces.source.path)/key
name: gcp-sa
workingDir: /workspace/source
volumes:
- name: gcp-sa
secret:
secretName: gcp-sa-key
workspaces:
- name: source
|
cs |
코드를 살펴보면 이 Task는 terraform init 명령어 실행, terraform $ARGS 명령어 실행의 2개 Step으로 이루어져 있는 것을 알 수 있습니다.
즉 우선 terraform init을 실행한 뒤, ARGS 파라미터에 받은 변수를 기반으로 한 terraform 명령어를 실행하는 구조로 되어있는 것입니다.
ARGS 파라미터에는 테라폼 코드 검증을 위한 validate, 배포 확인을 위한 plan, 실제 배포를 위한 apply 등 다양한 명령어를 사용할 수 있으므로 상황에 맞는 변수를 할당하면 되겠습니다. 이번 포스팅에서는 실제 배포를 위한 apply 명령어를 넣겠습니다.
중요한 점은 이 Task에 2개의 Kubernetes Secret이 사용된다는 점인데요. 2개의 Secret 모두 GCP의 Service account key를 필요로 합니다.
위 Secret에 사용되는 Service account Key를 생성하는 방법은 아래 Document를 참고하시기 바랍니다.
https://cloud.google.com/iam/docs/creating-managing-service-account-keys
하나는 Terraform backend 인증에 사용할 Secret으로 GCS 접근에 필요한 Service account key JSON 파일을 담고 있습니다.
이 Secret은 "gcp-sa"라는 volume으로 추가되어 각 Step에 VolumeMount된 것을 볼 수 있습니다.
나머지 하나는 Terraform Provider 인증에 사용할 Secret으로 GCP 인프라 배포에 필요한 Service account key JSON 파일을 담고 있습니다.
이 Secret은 Task의 "terraform-secret" parameter에 할당되어 환경 변수로 사용되는 것을 볼 수 있습니다.
2-3. Pipeline "clone-terraform-cli"
다음은 위에서 알아본 Task들을 일련의 실행 가능한 구성으로 묶어주는 매개체인 Pipeline에 대해서 알아보겠습니다.
Pipeline 리소스에서는 실행할 Task의 순서를 지정할 수 있는데, Git repo에서 가져온 코드를 기반으로 Terraform 커맨드를 실행해야 하기 때문에 "git-clone" -> "terraform-cli" 순으로 실행하도록 지정합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-terraform-cli
spec:
description: |
This pipeline clones a git repo, run "terraform plan" command based on .tf config file
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: terraform-command
runAfter: ["fetch-source"]
taskRef:
name: terraform-cli
workspaces:
- name: source
workspace: shared-data
params:
- name: terraform-secret
value: "terraform-secret"
- name: ARGS
value:
- apply
- "-auto-approve"
|
cs |
코드를 보면 spec.tasks.runAfter 애트리뷰트를 통해 "terraform-cli" Task를 "git-clone" 이후에 실행하도록 지정한 것을 볼 수 있습니다.
"terraform-cli" Task를 실행하는 부분에서는 "ARGS" params를 통해 실행하고자 하는 Terraform 명령어를 지정할 수 있습니다.
실제 환경에 인프라를 배포하고자 한다면 여기에 apply -auto-approve를 넣습니다.
2-4. TriggerTemplate "terraform-triggertemplate"
TriggerTemplate 리소스는 앞서 생성한 Pipeline에 EventListner에서 받은 Parameter를 부여함으로써 Pipelinerun 리소스를 생성해주는 역할을 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: terraform-triggertemplate
spec:
params:
- name: gitrepositoryurl
description: The git repository url
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-terraform-plan-run-
spec:
pipelineRef:
name: clone-terraform-plan
podTemplate:
securityContext:
fsGroup: 65532
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
params:
- name: repo-url
value: $(tt.params.gitrepositoryurl)
|
cs |
spec.resourcetemplates 어트리뷰트를 통해 이전에 생성한 Pipeline을 참조해서 PipelineRun 리소스를 생성하는 것을 확인할 수 있습니다.
spec.params 값은 TriggerBinding에서 미리 정의한 파라미터를 넣어야 합니다. 이 어트리뷰트를 통해 EventListener에서 받아온 정보를 기반으로 Pipeline 작업을 수행할 수 있습니다.
이 값은 sepc.resourcetemplates.params 어트리뷰트의 $(tt.params.gitrepositoryurl)와 같이 참조할 수 있습니다.
2-5. TriggerBinding "terraform-triggerbinding"
다음은 EventListner에서 어떤 정보를 받아올지 정의할 수 있는 TriggerBinding 리소스입니다.
1
2
3
4
5
6
7
8
|
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: terraform-triggerbinding
spec:
params:
- name: gitrepositoryurl
value: $(body.repository.url)
|
cs |
여기서는 EventListener가 받는 정보가 Github Webhook이 보내는 payload이므로, 여기서 git clone을 위해 필요한 git repository url 정보만 가져오도록 정의하겠습니다.
필요한 정보를 어떤 경로로 가져올 수 있는지는 Github webhook Payload 구성을 참조하세요.
https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push
2-6. EventListener "terraform-eventlistener"
마지막으로 Tekton Trigger의 맨 앞단에서 Event의 감지를 담당하는 EventListner입니다.
본 파이프라인에서는 Github webhook을 감지해 Tekton Pipeline을 Trigger하는 역할을 하게 됩니다.
1
2
3
4
5
6
7
8
9
10
11
|
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: terraform-eventlistener
spec:
serviceAccountName: tekton-trigger-sa # clusterrolebindinag과 rolebinding 둘 다 존재해야 권한문제가 발생하지 않음
triggers:
- bindings:
- ref: terraform-triggerbinding
template:
ref: terraform-triggertemplate
|
cs |
EventListener는 실제 Pod가 실행되는 리소스이기 때문에 Pod를 실행할 Service account를 지정해야 합니다.
이 Service account는 Tekton 리소스에 대한 적절한 권한이 부여되어 있어야 권한 이슈 없이 Pipeline을 실행할 수 있습니다.
마지막으로 Binding할 TriggerTemplate과 TriggerBinding을 지정해 위에서 생성한 리소스들을 EventListener 아래로 묶어줍니다.
3. TF State 관리
Terraform을 사용하고자 할때 고려해야 할 점 중 한가지는 TF State 파일의 관리입니다.
특히 이번처럼 Pipeline을 태우며 Terraform 배포를 자동화하고자 할때 State 파일만 따로 관리할 수는 없을 텐데요.
이를 해결하기 위해 Remote Backend에 State 파일을 두어서 저장하는 것을 권장합니다.
특히 Public Cloud Provider 환경에 인프라를 배포하고자 하는 경우에는 그 Provider가 제공하는 오브젝트 스토리지 서비스를 Backend로 사용하는 것을 권장합니다.
이에 대한 이유는 다음과 같습니다.
1. 여러 사용자가 동시에 Pipeline을 실행할 경우에도 일관성이 보장된다.
대부분의 Public Cloud 제공 오브젝트 스토리지는 어느정도의 일관성 수준을 제공하고 있습니다. 때문에 여러 사용자가 동시에 Pipeline을 실행하는 경우에도 배포되는 TF State에 대한 일관성을 유지할 수 있습니다.
2. State파일과 Configration파일의 관리 포인트가 일원화되어 Burden이 줄어든다.
Local Backend를 사용하거나 각기 다른 Provider의 서비스를 이용한다면 관리 포인트가 많아져 관리에 대한 부담이 가중될 수 밖에 없습니다. 하지만 같은 Provider의 서비스를 이용한다면 이와 같은 Burden을 덜 수 있습니다.
3. 인증에 필요한 키, 암호 등의 Secret의 관리가 용이해진다.
Backend 인증에 필요한 Secret을 관리하는 것도 부담이 되는 관리 포인트가 될 것입니다. 이때 Provider의 Secret Management 서비스를 이용하거나 Provider를 통일한다면 관리를 용이하게 만들 수 있습니다.
본 포스팅의 DEMO에 사용한 환경은 아래와 같이 Backend 설정이 구성되어 있습니다.
Terraform을 통해 배포하고자 하는 환경이 "Google Cloud Platform" Provider이므로 같은 Provider에서 제공하는 오브젝트 스토리지인 GCS를 Backend로 사용했습니다.
GCS를 Backend로 사용했을 시 인증 방법에는 Service account Key를 참조하게끔 하는 방법이 있습니다.
"terraform-cli" Task 구성시 해당 Key를 Mount해 참조할 수 있도록 구성했습니다.
GCS는 Eventual Consistency를 보장하기 때문에 여러 사용자의 Pipeline 이용시에도 어느 정도의 일관성을 보장할 수 있습니다.
게다가 Object Versioning 기능을 활성화하면 삭제된 오브젝트에 대해서 복구할 수 있기 때문에 이전 Terraform State로 복구할 수 있는 선택지가 생긴다는 장점도 존재합니다.
추가적으로 Lifecycle 규칙을 사용하면 Object Versioning으로 인해 쌓인 버전들을 무제한 쌓이지 않도록 관리할 수도 있습니다.
4. 마치며
본 포스팅은 "Tekton 사용해보기" 시리즈의 두 번째 글로 Tekton을 사용해 Terraform 파이프라인을 구성해봤습니다.
이를 통해 Tekton Pipeline, Tekton Trigger와 Tekton Dashboard 컴포넌트를 사용하면 Terraform 코드를 배포할 수 있는 자동화된 파이프라인을 생성할 수 있다는 것을 함께 알아볼 수 있었습니다.
게다가 Terraform 파이프라인의 Backend로 배포할 환경에서 제공하는 오브젝트 스토리지 서비스를 사용하는 것의 이점도 알아봤습니다.
이 글을 읽으시는 분들이 Tekton으로 파이프라인을 구성하는데 많은 도움이 되었으면 합니다.
다음 시리즈에서는 Tekton Dashboard에 Oauth2.0을 활용한 RBAC 적용해보기를 포스팅할 예정입니다.
'Devops' 카테고리의 다른 글
Tekton 사용해보기 (4) GCP Terraform 인프라를 Validation하는 파이프라인 구축하기 (0) | 2022.12.31 |
---|---|
Tekton 사용해보기 (3) Tekton Dashboard에 OIDC를 기반으로 RBAC 적용하기 (0) | 2022.11.13 |
Tekton 사용해보기 (1) Tekton으로 쿠버네티스에서 CI/CD 파이프라인을 구성해보자 (1) | 2022.10.03 |
GCP에서 Terraform을 사용하기 위한 Best Practice (1) | 2022.09.16 |
CKA(Certified Kubernetes Administrator) 자격증 시험 및 합격 후기 (2) | 2022.08.13 |