5장 헬름

헬름이란 ?

  1. 커스터마이즈와 유사하지만 템플릿 기반 솔루션
  2. 커스터마이즈와 헬름의 차이점 중 하나는 chart 개념
  3. 패키지 관리자처럼 동작하여 버전관리, 공유, 배포 가능 Artifact를 생성
  4. chart는 공유 가능한 쿠버네티스 패지리
  5. 헬름은 애플리케이션의 ConfigMap이 변경되면 자동으로 롤링 업데이트가 시작되도록 하는 기능 몇가지를 제공

5.1 Creating a Helm Project

 

실습을 위한 kind ( k8s ) 배포

# kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
EOF

Creating cluster "myk8s" ...
 ✓ Ensuring node image (kindest/node:v1.32.8) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-myk8s"
You can now use your cluster with:

kubectl cluster-info --context kind-myk8s

Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂

 

 

헬름 챠트 디렉터리 레이아웃 생성

# 헬름 챠트 디렉터리 레이아웃 생성
mkdir pacman
mkdir pacman/templates
cd pacman

# 루트 디렉토리에 차트 정의 파일 작성 : 버전, 이름 등 정보
cat << EOF > Chart.yaml
apiVersion: v2
name: pacman
description: A Helm chart for Pacman
type: application
version: 0.1.0        # 차트 버전, 차트 정의가 바뀌면 업데이트한다
appVersion: "1.0.0"   # 애플리케이션 버전
EOF

# templates 디렉터리에 Go 템플릿 언어와 Sprig 라이브러리의 템플릿 함수를 사용해 정의한 배포 템플릿 파일 작성 : 애플리케이션 배포
## deployment.yaml 파일에서 템플릿화 : dp 이름, app 버전, replicas 수, 이미지/태그, 이미지 풀 정책, 보안 컨텍스트, 포트 
cat << EOF > templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name}}            # Chart.yaml 파일에 설정된 이름을 가져와 설정
  labels:
    app.kubernetes.io/name: {{ .Chart.Name}}
    {{- if .Chart.AppVersion }}     # Chart.yaml 파일에 appVersion 여부에 따라 버전을 설정
    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}     # appVersion 값을 가져와 지정하고 따움표 처리
    {{- end }}
spec:
  replicas: {{ .Values.replicaCount }}     # replicaCount 속성을 넣을 자리 placeholder
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .Chart.Name}}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ .Chart.Name}}
    spec:
      containers:
        - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion}}"   # 이미지 지정 placeholder, 이미지 태그가 있으 면 넣고, 없으면 Chart.yaml에 값을 설정
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 14 }} # securityContext의 값을 YAML 객체로 지정하며 14칸 들여쓰기
          name: {{ .Chart.Name}}
          ports:
            - containerPort: {{ .Values.image.containerPort }}
              name: http
              protocol: TCP
EOF

# service.yaml 파일에서 템플릿화 : service 이름, 컨테이너 포트
minji  ~/Desktop/work/Gasida_series/practice/pacman  cat << EOF > templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
  name: {{ .Chart.Name }}
spec:
  ports:
    - name: http
      port: {{ .Values.image.containerPort }}
      targetPort: {{ .Values.image.containerPort }}
  selector:
    app.kubernetes.io/name: {{ .Chart.Name }}
EOF

# 차트 기본값 default values이 담긴 파일 작성 : 애플리케이션 배포 시점에 다른 값으로 대체될 수 있는, 기본 설정을 담아두는 곳
minji  ~/Desktop/work/Gasida_series/practice/pacman  cat << EOF > values.yaml
image:     # image 절 정의
  repository: quay.io/gitops-cookbook/pacman-kikd
  tag: "1.0.0"
  pullPolicy: Always
  containerPort: 8080

replicaCount: 1
securityContext: {}     # securityContext 속성의 값을 비운다
EOF


# 디렉터리 레이아웃 확인
minji  ~/Desktop/work/Gasida_series/practice/pacman  tree
.
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   └── service.yaml
└── values.yaml

 

 

헬름 차트를 로컬에서 Yaml로 렌더링

minji  ~/Desktop/work/Gasida_series/practice/pacman  helm template .
---
# Source: pacman/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: pacman
  name: pacman
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  selector:
    app.kubernetes.io/name: pacman
---
# Source: pacman/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman            # Chart.yaml 파일에 설정된 이름을 가져와 설정
  labels:
    app.kubernetes.io/name: pacman     # Chart.yaml 파일에 appVersion 여부에 따라 버전을 설정
    app.kubernetes.io/version: "1.0.0"     # appVersion 값을 가져와 지정하고 따움표 처리
spec:
  replicas: 1     # replicaCount 속성을 넣을 자리 placeholder
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman
    spec:
      containers:
        - image: "quay.io/gitops-cookbook/pacman-kikd:1.0.0"   # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
          imagePullPolicy: Always
          securityContext:
              {} # securityContext의 값을 YAML 객체로 지정하며 14칸 들여쓰기
          name: pacman
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
              
# --set 파라미터를 사용하여 기본값을 재정의
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm template --set replicaCount=3 .
---
# Source: pacman/templates/service.yaml
.
spec:
  replicas: 3     # replicaCount 속성을 넣을 자리 placeholder
.

 

 

해당 챠트를 kind ( k8s )배포 및 helm 확인

# 해당 차트 배포
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm install pacman .
NAME: pacman
LAST DEPLOYED: Thu Oct 23 22:27:43 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

minji  ~/Desktop/work/Gasida_series/practice/pacman  helm list
NAME  	NAMESPACE	REVISION	UPDATED                             	STATUS  	CHART       	APP VERSION
pacman	default  	1       	2025-10-23 22:27:43.064742 +0900 KST	deployed	pacman-0.1.0	1.0.0

# 배포된 리소스 확인
minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get deploy,pod,svc,ep
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/pacman   1/1     1            1           108s

NAME                          READY   STATUS    RESTARTS   AGE
pod/pacman-576769bb86-pqkg7   1/1     Running   0          108s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    18m
service/pacman       ClusterIP   10.96.184.154   <none>        8080/TCP   108s

NAME                   ENDPOINTS           AGE
endpoints/kubernetes   192.168.97.2:6443   18m
endpoints/pacman       10.244.0.5:8080     108s

minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get pod -o yaml | kubectl neat | yq  # kubectl krew install neat
apiVersion: v1
items:
  - apiVersion: v1
    kind: Pod
    metadata:
      labels:
        app.kubernetes.io/name: pacman
        pod-template-hash: 576769bb86
      name: pacman-576769bb86-pqkg7
      namespace: default
    spec:
      containers:
        - image: quay.io/gitops-cookbook/pacman-kikd:1.0.0
          imagePullPolicy: Always
          name: pacman
          ports:
            - containerPort: 8080
              name: http
          volumeMounts:
            - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
              name: kube-api-access-dzgc2
              readOnly: true
      preemptionPolicy: PreemptLowerPriority
      priority: 0
      serviceAccountName: default
      tolerations:
        - effect: NoExecute
          key: node.kubernetes.io/not-ready
          operator: Exists
          tolerationSeconds: 300
        - effect: NoExecute
          key: node.kubernetes.io/unreachable
          operator: Exists
          tolerationSeconds: 300
      volumes:
        - name: kube-api-access-dzgc2
          projected:
            sources:
              - serviceAccountToken:
                  expirationSeconds: 3607
                  path: token
              - configMap:
                  items:
                    - key: ca.crt
                      path: ca.crt
                  name: kube-root-ca.crt
              - downwardAPI:
                  items:
                    - fieldRef:
                        fieldPath: metadata.namespace
                      path: namespace
kind: List
metadata: {}

minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get pod -o json | grep securityContext -A1
                        "securityContext": {},
                        "terminationMessagePath": "/dev/termination-log",
--
                "securityContext": {},
                "serviceAccount": "default",
                
##
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm history pacman
REVISION	UPDATED                 	STATUS  	CHART       	APP VERSION	DESCRIPTION
1       	Thu Oct 23 22:27:43 2025	deployed	pacman-0.1.0	1.0.0      	Install complete


# Helm 자체가 배포 릴리스 메타데이터를 저장하기 위해 자동으로 Sercet 리소스 생성 : Helm이 차트의 상태를 복구하거나 rollback 할 때 이 데이터를 이용
minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get secret
NAME                           TYPE                 DATA   AGE
sh.helm.release.v1.pacman.v1   helm.sh/release.v1   1      11m

 

 

업그레이드, 메타데이터 확인

##
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm upgrade pacman --reuse-values --set relicaCount=2 .
Release "pacman" has been upgraded. Happy Helming!
NAME: pacman
LAST DEPLOYED: Thu Oct 23 22:39:50 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

##
minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
pacman-576769bb86-pqkg7   1/1     Running   0          12m

# helm 배포 정보 확인
#-1. 모든 정보
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm get all pacman
NAME: pacman
LAST DEPLOYED: Thu Oct 23 22:39:50 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
CHART: pacman
VERSION: 0.1.0
APP_VERSION: 1.0.0
TEST SUITE: None
USER-SUPPLIED VALUES:
relicaCount: 2

COMPUTED VALUES:
image:
  containerPort: 8080
  pullPolicy: Always
  repository: quay.io/gitops-cookbook/pacman-kikd
  tag: 1.0.0
relicaCount: 2
replicaCount: 1
securityContext: {}

HOOKS:
MANIFEST:
---
# Source: pacman/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: pacman
  name: pacman
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  selector:
    app.kubernetes.io/name: pacman
---
# Source: pacman/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman            # Chart.yaml 파일에 설정된 이름을 가져와 설정
  labels:
    app.kubernetes.io/name: pacman     # Chart.yaml 파일에 appVersion 여부에 따라 버전을 설정
    app.kubernetes.io/version: "1.0.0"     # appVersion 값을 가져와 지정하고 따움표 처리
spec:
  replicas: 1     # replicaCount 속성을 넣을 자리 placeholder
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman
    spec:
      containers:
        - image: "quay.io/gitops-cookbook/pacman-kikd:1.0.0"   # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
          imagePullPolicy: Always
          securityContext:
              {} # securityContext의 값을 YAML 객체로 지정하며 14칸 들여쓰기
          name: pacman
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP

#-2. values 적용 정보          
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm get values pacman
USER-SUPPLIED VALUES:
relicaCount: 2

#-3. 실제 적용된 manifest
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm get manifest pacman
---
# Source: pacman/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: pacman
  name: pacman
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  selector:
    app.kubernetes.io/name: pacman
---
# Source: pacman/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman            # Chart.yaml 파일에 설정된 이름을 가져와 설정
  labels:
    app.kubernetes.io/name: pacman     # Chart.yaml 파일에 appVersion 여부에 따라 버전을 설정
    app.kubernetes.io/version: "1.0.0"     # appVersion 값을 가져와 지정하고 따움표 처리
spec:
  replicas: 1     # replicaCount 속성을 넣을 자리 placeholder
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman
    spec:
      containers:
        - image: "quay.io/gitops-cookbook/pacman-kikd:1.0.0"   # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
          imagePullPolicy: Always
          securityContext:
              {} # securityContext의 값을 YAML 객체로 지정하며 14칸 들여쓰기
          name: pacman
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
              
              
# chart nodes
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm get notes pacman

# 삭제 후 secret 확인
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm uninstall pacman
release "pacman" uninstalled

minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get secret
No resources found in default namespace.

 

 

5.2 Reusing Statements Between Templates

같은 코드 확인 및 재사용 가능 코드 블록 정의

# deployment.yaml, service.yaml 에 selector 필드가 동일
## deployment.yaml
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .Chart.Name}}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ .Chart.Name}}

## service.yaml
  selector:
    app.kubernetes.io/name: {{ .Chart.Name }}
    
## 이 필드를 업데이트하려면(selector 필드에 새 레이블 추가 등) 3곳을 똑같이 업데이트 해야함
# 템플릿 디렉터리에 _helpers.tpl 파일을 만들고 그 안에 재사용 가능한 템플릿 코드를 두어 재사용할 수 있게 기존 코드를 디렉터링하자
## _helpers.tpl 파일 작성
minji  ~/Desktop/work/Gasida_series/practice  cat << EOF > templates/_helpers.tpl
{{- define "pacman.selectorLabels" -}}   # stetement 이름을 정의
app.kubernetes.io/name: {{ .Chart.Name}} # 해당 stetement 가 하는 일을 정의
{{- end }}
EOF

## deployment.yaml 수정
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "pacman.selectorLabels" . | nindent 6 }}   # pacman.selectorLabels를 호출한 결과를 6만큼 들여쓰기하여 주입
  template:
    metadata:
      labels:
        {{- include "pacman.selectorLabels" . | nindent 8 }} # pacman.selectorLabels를 호출한 결과를 8만큼 들여쓰기하여 주입
        
## service.yaml 수정
  selector:
    {{- include "pacman.selectorLabels" . | nindent 6 }}


minji  ~/Desktop/work/Gasida_series/practice/pacman  helm template .
---
# Source: pacman/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: pacman
  name: pacman
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  selector:
      app.kubernetes.io/name: pacman
      app.kubernetes.io/version: 1.0.0
---
# Source: pacman/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman            # Chart.yaml 파일에 설정된 이름을 가져와 설정
  labels:
    app.kubernetes.io/name: pacman     # Chart.yaml 파일에 appVersion 여부에 따라 버전을 설정
    app.kubernetes.io/version: "1.0.0"     # appVersion 값을 가져와 지정하고 따움표 처리
spec:
  replicas: 1     # replicaCount 속성을 넣을 자리 placeholder
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman
      app.kubernetes.io/version: 1.0.0   # pacman.selectorLabels를 호출한 결과를 6만큼 들여쓰기하여 주입
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman
        app.kubernetes.io/version: 1.0.0 # pacman.selectorLabels를 호출한 결과를 8만큼 들여쓰기하여 주입
    spec:
      containers:
        - image: "quay.io/gitops-cookbook/pacman-kikd:1.0.0"   # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
          imagePullPolicy: Always
          securityContext:
              {} # securityContext의 값을 YAML 객체로 지정하며 14칸 들여쓰기
          name: pacman
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP

 

 

5.3 Updating a Container Image in Helm

 

차트 배포

# _helpers.tpl 파일 초기 설정으로 수정
minji  ~/Desktop/work/Gasida_series/practice/pacman  cat << EOF > templates/_helpers.tpl
{{- define "pacman.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name}}
{{- end }}
EOF

# helm 배포
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm install pacman .
NAME: pacman
LAST DEPLOYED: Thu Oct 23 23:32:37 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

# 확인 : 리비전 번호, 이미지 정보 확인
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm history pacman
REVISION	UPDATED                 	STATUS  	CHART       	APP VERSION	DESCRIPTION
1       	Thu Oct 23 23:32:37 2025	deployed	pacman-0.1.0	1.0.0      	Install complete

minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get deploy -owide
NAME     READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                                      SELECTOR
pacman   1/1     1            1           84s   pacman       quay.io/gitops-cookbook/pacman-kikd:1.0.0   app.kubernetes.io/name=pacman

 

 

1.1.0 으로 이미지 갱신

# values.yaml에 이미지 태그 업데이트
minji  ~/Desktop/work/Gasida_series/practice/pacman  cat << EOF > values.yaml
image:
  repository: quay.io/gitops-cookbook/pacman-kikd
  tag: "1.1.0"
  pullPolicy: Always
  containerPort: 8080

replicaCount: 1
securityContext: {}
EOF

# Chart.yaml 파일에 appVersion 필드 갱신
minji  ~/Desktop/work/Gasida_series/practice/pacman  cat << EOF > Chart.yaml
apiVersion: v2
name: pacman
description: A Helm chart for Pacman
type: application
version: 0.1.0
appVersion: "1.1.0"
EOF

# 배포 업그레이드
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm upgrade pacman .
Release "pacman" has been upgraded. Happy Helming!
NAME: pacman
LAST DEPLOYED: Thu Oct 23 23:36:24 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

# 확인
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm history pacman
REVISION	UPDATED                 	STATUS    	CHART       	APP VERSION	DESCRIPTION
1       	Thu Oct 23 23:32:37 2025	superseded	pacman-0.1.0	1.0.0      	Install complete
2       	Thu Oct 23 23:36:24 2025	deployed  	pacman-0.1.0	1.1.0      	Upgrade complete

minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get secret
NAME                           TYPE                 DATA   AGE
sh.helm.release.v1.pacman.v1   helm.sh/release.v1   1      4m16s
sh.helm.release.v1.pacman.v2   helm.sh/release.v1   1      29s

minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get deploy,replicaset -owide
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES                                      SELECTOR
deployment.apps/pacman   1/1     1            1           4m30s   pacman       quay.io/gitops-cookbook/pacman-kikd:1.1.0   app.kubernetes.io/name=pacman

NAME                                DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES                                      SELECTOR
replicaset.apps/pacman-576769bb86   0         0         0       4m30s   pacman       quay.io/gitops-cookbook/pacman-kikd:1.0.0   app.kubernetes.io/name=pacman,pod-template-hash=576769bb86
replicaset.apps/pacman-64c54b85f9   1         1         1       43s     pacman       quay.io/gitops-cookbook/pacman-kikd:1.1.0   app.kubernetes.io/name=pacman,pod-template-hash=64c54b85f9

 

 

여기서 잠깐

두 개의 개별 필드 ( tag, appVersion)대신 appVersion을 tag로도 쓰는 방법을 생각해 볼 수 있다.

버전 필드의 쓰임새, 버전 관리 전략, 소프트웨어 수명 주기에 따라 어느쪽으로 할지 정할 필요가 있다.

appVersion은 애플리케이션의 버전이므로 애플리케이션을 변경할 때 마다 업데이트가 필요

한편 version은 chart버전이기 때문에 chart정의 ( 템플릿 등 )가 변경되면 갱신한다.

따라서 두 필드는 서로 관계가 없다

 

이전 버전으로 롤백

# 이전 버전으로 롤백
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm rollback pacman 1 && kubectl get pod -w
Rollback was a success! Happy Helming!
NAME                      READY   STATUS              RESTARTS   AGE
pacman-576769bb86-t5scc   0/1     ContainerCreating   0          0s
pacman-64c54b85f9-xqx2n   1/1     Running             0          2m44s
pacman-576769bb86-t5scc   1/1     Running             0          3s
pacman-64c54b85f9-xqx2n   1/1     Terminating         0          2m47s
pacman-64c54b85f9-xqx2n   0/1     Error               0          2m47s
pacman-64c54b85f9-xqx2n   0/1     Error               0          2m48s
pacman-64c54b85f9-xqx2n   0/1     Error               0          2m48s

# 확인
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm history pacman
REVISION	UPDATED                 	STATUS    	CHART       	APP VERSION	DESCRIPTION
1       	Thu Oct 23 23:32:37 2025	superseded	pacman-0.1.0	1.0.0      	Install complete
2       	Thu Oct 23 23:36:24 2025	superseded	pacman-0.1.0	1.1.0      	Upgrade complete
3       	Thu Oct 23 23:39:08 2025	superseded	pacman-0.1.0	1.0.0      	Rollback to 1
4       	Thu Oct 23 23:40:12 2025	deployed  	pacman-0.1.0	1.0.0      	Rollback to 1

minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get secret
NAME                           TYPE                 DATA   AGE
sh.helm.release.v1.pacman.v1   helm.sh/release.v1   1      10m
sh.helm.release.v1.pacman.v2   helm.sh/release.v1   1      7m3s
sh.helm.release.v1.pacman.v3   helm.sh/release.v1   1      4m19s
sh.helm.release.v1.pacman.v4   helm.sh/release.v1   1      3m15s

minji  ~/Desktop/work/Gasida_series/practice/pacman  kubectl get deploy,replicaset -owide
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                                      SELECTOR
deployment.apps/pacman   1/1     1            1           11m   pacman       quay.io/gitops-cookbook/pacman-kikd:1.0.0   app.kubernetes.io/name=pacman

NAME                                DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES                                      SELECTOR
replicaset.apps/pacman-576769bb86   1         1         1       11m     pacman       quay.io/gitops-cookbook/pacman-kikd:1.0.0   app.kubernetes.io/name=pacman,pod-template-hash=576769bb86
replicaset.apps/pacman-64c54b85f9   0         0         0       7m37s   pacman       quay.io/gitops-cookbook/pacman-kikd:1.1.0   app.kubernetes.io/name=pacman,pod-template-hash=64c54b85f9

 

 

values yaml file override

# value 새 파일 작성
minji  ~/Desktop/work/Gasida_series/practice/pacman  cat << EOF > newvalues.yaml
image:
  tag: "1.2.0"
EOF

# template 명령 실행 시 새 values 파일 함께 전달 : 결과적으로 values.yaml 기본값을 사용하지만, image.tag 값은 override 함
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm template pacman -f newvalues.yaml .
---
# Source: pacman/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: pacman
  name: pacman
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  selector:
      app.kubernetes.io/name: pacman
---
# Source: pacman/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman            # Chart.yaml 파일에 설정된 이름을 가져와 설정
  labels:
    app.kubernetes.io/name: pacman     # Chart.yaml 파일에 appVersion 여부에 따라 버전을 설정
    app.kubernetes.io/version: "1.1.0"     # appVersion 값을 가져와 지정하고 따움표 처리
spec:
  replicas: 1     # replicaCount 속성을 넣을 자리 placeholder
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman   # pacman.selectorLabels를 호출한 결과를 6만큼 들여쓰기하여 주입
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman # pacman.selectorLabels를 호출한 결과를 8만큼 들여쓰기하여 주입
    spec:
      containers:
        - image: "quay.io/gitops-cookbook/pacman-kikd:1.2.0"   # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
          imagePullPolicy: Always
          securityContext:
              {} # securityContext의 값을 YAML 객체로 지정하며 14칸 들여쓰기
          name: pacman
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP

 

 

5.4 Packaging and Distributing a Helm Chart

helm chart를 패키징하고 공개하여 다른 차트의 의존성으로 이용될 수 있도록 하거나 다른 사용자가 시스템에 배포할 수 있도록 하는 방법을 알아보자

# pacman 차트를 .tgz 파일로 패키징
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm package .
Successfully packaged chart and saved it to: /Users/howoo/Desktop/work/Gasida_series/practice/pacman/pacman-0.1.0.tgz

minji  ~/Desktop/work/Gasida_series/practice/pacman  gzcat pacman-0.1.0.tgz
pacman/Chart.yaml0000644000000000000000000000016415076440060012433 0ustar0000000000000000apiVersion: v2
appVersion: 1.1.0
description: A Helm chart for Pacman
name: pacman
type: application
version: 0.1.0
pacman/values.yaml0000644000000000000000000000023015076440060012663 0ustar0000000000000000image:
  repository: quay.io/gitops-cookbook/pacman-kikd
  tag: "1.1.0"
  pullPolicy: Always
  containerPort: 8080

replicaCount: 1
securityContext: {}
pacman/templates/_helpers.tpl0000644000000000000000000000013315076440060015022 0ustar0000000000000000{{- define "pacman.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name}}
{{- end }}
pacman/templates/deployment.yaml0000644000000000000000000000276515076440060015561 0ustar0000000000000000apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name}}            # Chart.yaml 파일에 설정된 이름을 가져와 설정
  labels:
    app.kubernetes.io/name: {{ .Chart.Name}}
    {{- if .Chart.AppVersion }}     # Chart.yaml 파일에 appVersion 여부에 따라 버전을 설정
    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}     # appVersion 값을 가져와 지정하고 따움표 처리
    {{- end }}
spec:
  replicas: {{ .Values.replicaCount }}     # replicaCount 속성을 넣을 자리 placeholder
  selector:
    matchLabels:
      {{- include "pacman.selectorLabels" . | nindent 6 }}   # pacman.selectorLabels를 호출한 결과를 6만큼 들여쓰기하여 주입
  template:
    metadata:
      labels:
        {{- include "pacman.selectorLabels" . | nindent 8 }} # pacman.selectorLabels를 호출한 결과를 8만큼 들여쓰기하여 주입
    spec:
      containers:
        - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion}}"   # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 14 }} # securityContext의 값을 YAML 객체로 지정하며 14칸 들여쓰기
          name: {{ .Chart.Name}}
          ports:
            - containerPort: {{ .Values.image.containerPort }}
              name: http
              protocol: TCP
pacman/templates/service.yaml0000644000000000000000000000050015076440060015022 0ustar0000000000000000apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
  name: {{ .Chart.Name }}
spec:
  ports:
    - name: http
      port: {{ .Values.image.containerPort }}
      targetPort: {{ .Values.image.containerPort }}
  selector:
    {{- include "pacman.selectorLabels" . | nindent 6 }}
pacman/newvalues.yaml0000644000000000000000000000002615076440060013400 0ustar0000000000000000image:
  tag: "1.2.0"
  
# 해당 차트를 차트 저장소 repository 에 게시
# 차트 저장소는 차트 및 .tgz 차트에 대한 메타데이터 정보를 담은 index.html 파일이 있는 HTTP 서버
# 차트를 저장소에 게시하려면 index.html 파일을 새 메타데이터 정보로 업데이트하고 아티팩트를 업로드해야 한다.

# index.html file 생성
minji  ~/Desktop/work/Gasida_series/practice/pacman  helm repo index .
minji  ~/Desktop/work/Gasida_series/practice/pacman 
 
minji  ~/Desktop/work/Gasida_series/practice/pacman  cat index.yaml
apiVersion: v1
entries:
  pacman:
  - apiVersion: v2
    appVersion: 1.1.0
    created: "2025-10-23T23:50:45.092915+09:00"
    description: A Helm chart for Pacman
    digest: ecf7e2eb903a569ede9d11c989f76895d72850c653b630aa213835e5efe9a2b8
    name: pacman
    type: application
    urls:
    - pacman-0.1.0.tgz
    version: 0.1.0
generated: "2025-10-23T23:50:45.092641+09:00"

 

 

※ Bitnami 공개 카탈로그 삭제

Bitnamo Helm Charts : 컨테이너 이미지 Tag ( latest )

# Bitnami nginx 의 OCI 주소
oci://registry-1.docker.io/bitnamicharts/nginx

# 기존 식 helm repo 확인
# helm 저장소를 추가 하지 않았으므로 Error
minji  ~  helm repo list
Error: no repositories to show

# helm chart 가져오기
minji  ~  helm pull oci://registry-1.docker.io/bitnamicharts/nginx --version 22.0.11
Pulled: registry-1.docker.io/bitnamicharts/nginx:22.0.11
Digest: sha256:22c9a95eced446e53f75fa41764059812049cfcbabe273942ea46b69183b496d

# 파일 목록 확인
minji  ~  tar -tf nginx-22.0.11.tgz
nginx/
nginx/charts/
nginx/charts/common/
nginx/charts/common/templates/
nginx/charts/common/templates/validations/
nginx/templates/
                 .
                 .
                 .

# helm show 명령
## helm show readme oci://registry-1.docker.io/bitnamicharts/nginx
                 .
                 .
                 .                
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

<http://www.apache.org/licenses/LICENSE-2.0>

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

## helm show values oci://registry-1.docker.io/bitnamicharts/nginx
  						    .
							    .
							    .
  ## @param metrics.startupProbe.successThreshold Success threshold for startupProbe

  ##
  startupProbe:
    enabled: false
    initialDelaySeconds: 5
    timeoutSeconds: 3
    periodSeconds: 5
    failureThreshold: 10
    successThreshold: 1


## helm show chart oci://registry-1.docker.io/bitnamicharts/nginx
								.
								.
								.
icon: https://dyltqmyl993wv.cloudfront.net/assets/stacks/nginx/img/nginx-stack-220x234.png
keywords:
- nginx
- http
- web
- www
- reverse proxy
maintainers:
- name: Broadcom, Inc. All Rights Reserved.
  url: https://github.com/bitnami/charts
name: nginx
sources:
- https://github.com/bitnami/charts/tree/main/bitnami/nginx
version: 22.1.1

# helm chart 바로 설치
minji  ~  helm install my-nginx oci://registry-1.docker.io/bitnamicharts/nginx --version 22.0.11
Pulled: registry-1.docker.io/bitnamicharts/nginx:22.0.11
Digest: sha256:22c9a95eced446e53f75fa41764059812049cfcbabe273942ea46b69183b496d
NAME: my-nginx
LAST DEPLOYED: Fri Oct 24 20:30:07 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: nginx
CHART VERSION: 22.0.11
APP VERSION: 1.29.2
									.
									.
									.

minji  ~  helm repo list
Error: no repositories to show

# helm 확인
minji  ~  helm repo list
Error: no repositories to show

minji  ~  helm list
NAME    	NAMESPACE	REVISION	UPDATED                             	STATUS  	CHART        	APP VERSION
my-nginx	default  	1       	2025-10-24 20:30:07.731724 +0900 KST	deployed	nginx-22.0.11	1.29.2
pacman  	default  	4       	2025-10-23 23:40:12.59885 +0900 KST 	deployed	pacman-0.1.0 	1.0.0
 minji  ~  helm get metadata my-nginx
NAME: my-nginx
CHART: nginx
VERSION: 22.0.11
APP_VERSION: 1.29.2
ANNOTATIONS: fips=true,images=- name: git
  version: 2.51.0
  image: registry-1.docker.io/bitnami/git:latest
- name: nginx
  version: 1.29.2
  image: registry-1.docker.io/bitnami/nginx:latest
- name: nginx-exporter
  version: 1.5.0
  image: registry-1.docker.io/bitnami/nginx-exporter:latest
,licenses=Apache-2.0,tanzuCategory=clusterUtility
DEPENDENCIES: common
NAMESPACE: default
REVISION: 1
STATUS: deployed
DEPLOYED_AT: 2025-10-24T20:30:07+09:00

# deployment 확인 : IMAGES tags 확인
minji  ~  kubectl get deploy -owide
NAME       READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES                                      SELECTOR
my-nginx   1/1     1            1           2m30s   nginx        registry-1.docker.io/bitnami/nginx:latest   app.kubernetes.io/instance=my-nginx,app.kubernetes.io/name=nginx
pacman     1/1     1            1           21h     pacman       quay.io/gitops-cookbook/pacman-kikd:1.0.0   app.kubernetes.io/name=pacman

minji  ~  helm get manifest my-nginx | grep 'image:'
          image: registry-1.docker.io/bitnami/nginx:latest
          image: registry-1.docker.io/bitnami/nginx:latest
          
# 삭제
minji  ~  helm uninstall my-nginx
release "my-nginx" uninstalled

 

 

5.5 Deploying a Chart from a Repository

Bitnami / postgresql 배포 실습

# repo
minji  ~  helm repo add bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories

minji  ~  helm repo list
NAME   	URL
bitnami	https://charts.bitnami.com/bitnami

minji  ~  helm search repo postgresql
NAME                  	CHART VERSION	APP VERSION	DESCRIPTION
bitnami/postgresql    	18.1.1       	18.0.0     	PostgreSQL (Postgres) is an open source object-...
bitnami/postgresql-ha 	16.3.2       	17.6.0     	This PostgreSQL cluster solution includes the P...
bitnami/cloudnative-pg	1.0.11       	1.26.1     	CloudNativePG is an open-source tool for managi...
bitnami/supabase      	5.3.6        	1.24.7     	DEPRECATED Supabase is an open source Firebase ...
bitnami/minio-operator	0.2.9        	7.1.1      	MinIO(R) Operator is a Kubernetes-native tool f...

minji  ~  helm search repo postgresql -o json | jq
[
  {
    "name": "bitnami/postgresql",
    "version": "18.1.1",
    "app_version": "18.0.0",
    "description": "PostgreSQL (Postgres) is an open source object-relational database known for reliability and data integrity. ACID-compliant, it supports foreign keys, joins, views, triggers and stored procedures."
  },
  {
    "name": "bitnami/postgresql-ha",
    "version": "16.3.2",
    "app_version": "17.6.0",
    "description": "This PostgreSQL cluster solution includes the PostgreSQL replication manager, an open-source tool for managing replication and failover on PostgreSQL clusters."
  },
  {
    "name": "bitnami/cloudnative-pg",
    "version": "1.0.11",
    "app_version": "1.26.1",
    "description": "CloudNativePG is an open-source tool for managing PostgreSQL databases on Kubernetes, from setup to ongoing upkeep."
  },
  {
    "name": "bitnami/supabase",
    "version": "5.3.6",
    "app_version": "1.24.7",
    "description": "DEPRECATED Supabase is an open source Firebase alternative. Provides all the necessary backend features to build your application in a scalable way. Uses PostgreSQL as datastore."
  },
  {
    "name": "bitnami/minio-operator",
    "version": "0.2.9",
    "app_version": "7.1.1",
    "description": "MinIO(R) Operator is a Kubernetes-native tool for deploying and managing high-performance, S3-compatible MinIO(R) object storage across hybrid cloud infrastructures."
  }
]


# 배포
minji  ~  helm install my-db \
--set postgresql.postgresqlUsername=my-default,postgresql.postgresqlPassword=postgres,postgresql.postgresqlDatabase=mydb,postgresql.persistence.enabled=false \
bitnami/postgresql
NAME: my-db
LAST DEPLOYED: Fri Oct 24 20:36:45 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: postgresql
CHART VERSION: 18.1.1
APP VERSION: 18.0.0
														.
														.
														.
WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs:
  - primary.resources
  - readReplicas.resources
+info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

# 확인
minji  ~  helm list
NAME  	NAMESPACE	REVISION	UPDATED                             	STATUS  	CHART            	APP VERSION
my-db 	default  	1       	2025-10-24 20:36:45.218051 +0900 KST	deployed	postgresql-18.1.1	18.0.0
pacman	default  	4       	2025-10-23 23:40:12.59885 +0900 KST 	deployed	pacman-0.1.0     	1.0.0

minji  ~  kubectl get sts,pod,svc,ep,secret
NAME                                READY   AGE
statefulset.apps/my-db-postgresql   1/1     77s

NAME                          READY   STATUS    RESTARTS      AGE
pod/my-db-postgresql-0        1/1     Running   0             77s
pod/pacman-576769bb86-t5scc   1/1     Running   2 (18m ago)   20h

NAME                          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/kubernetes            ClusterIP   10.96.0.1      <none>        443/TCP    22h
service/my-db-postgresql      ClusterIP   10.96.23.246   <none>        5432/TCP   77s
service/my-db-postgresql-hl   ClusterIP   None           <none>        5432/TCP   77s
service/pacman                ClusterIP   10.96.105.28   <none>        8080/TCP   21h

NAME                            ENDPOINTS           AGE
endpoints/kubernetes            192.168.97.2:6443   22h
endpoints/my-db-postgresql      10.244.0.8:5432     77s
endpoints/my-db-postgresql-hl   10.244.0.8:5432     77s
endpoints/pacman                10.244.0.4:8080     21h

NAME                                  TYPE                 DATA   AGE
secret/my-db-postgresql               Opaque               1      77s
secret/sh.helm.release.v1.my-db.v1    helm.sh/release.v1   1      77s
secret/sh.helm.release.v1.pacman.v1   helm.sh/release.v1   1      21h
secret/sh.helm.release.v1.pacman.v2   helm.sh/release.v1   1      21h
secret/sh.helm.release.v1.pacman.v3   helm.sh/release.v1   1      20h
secret/sh.helm.release.v1.pacman.v4   helm.sh/release.v1   1      20h

# 서드 파티 챠트 사용시 기본값(default value)나 override 파라미터를 직접 확인 할 수 없고, helm show 로 확인 가능
helm show values bitnami/postgresql
																.
																.
																.
## rules:
##   - alert: HugeReplicationLag
##     expr: pg_replication_lag{service="{{ printf "%s-metrics" (include "postgresql.v1.chart.fullname" .) }}"} / 3600 > 1
##     for: 1m
##     labels:
##       severity: critical
##     annotations:
##       description: replication for {{ include "postgresql.v1.chart.fullname" . }} PostgreSQL is lagging by {{ "{{ $value }}" }} hour(s).
##       summary: PostgreSQL replication is lagging by {{ "{{ $value }}" }} hour(s).
##
rules: []

# 실습 후 삭제
minji  ~  helm uninstall my-db
release "my-db" uninstalled

 

 

5.6 Deploying a Chart with a dependency

다른 챠트를 의존성으로 사용하는 차트를 배포

실습에서는 PostgreSQL, 데이터베이스에 저장된 노래 목록을 반환하는 Java 서비스를 배포

## 
mkdir music
mkdir music/templates
cd music

##
minji  ~/Desktop/work/Gasida_series/practice/music  cat << EOF > templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name}}
  labels:
    app.kubernetes.io/name: {{ .Chart.Name}}
    {{- if .Chart.AppVersion }}
    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
    {{- end }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .Chart.Name}}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ .Chart.Name}}
    spec:
      containers:
        - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion}}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          name: {{ .Chart.Name}}
          ports:
            - containerPort: {{ .Values.image.containerPort }}
              name: http
              protocol: TCP
          env:
            - name: QUARKUS_DATASOURCE_JDBC_URL
              value: {{ .Values.postgresql.server | default (printf "%s-postgresql" ( .Release.Name )) | quote }}
            - name: QUARKUS_DATASOURCE_USERNAME
              value: {{ .Values.postgresql.postgresqlUsername | default (printf "postgres" ) | quote }}
            - name: QUARKUS_DATASOURCE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: {{ .Values.postgresql.secretName | default (printf "%s-postgresql" ( .Release.Name )) | quote }}
                  key: {{ .Values.postgresql.secretKey }}
EOF

##
minji  ~/Desktop/work/Gasida_series/practice/music  cat << EOF > templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
  name: {{ .Chart.Name }}
spec:
  ports:
    - name: http
      port: {{ .Values.image.containerPort }}
      targetPort: {{ .Values.image.containerPort }}
  selector:
    app.kubernetes.io/name: {{ .Chart.Name }}
EOF

## psql 10.16.2 차트 책 버전 사용 시
minji  ~/Desktop/work/Gasida_series/practice/music  cat << EOF > Chart.yaml
apiVersion: v2
name: music
description: A Helm chart for Music service
type: application
version: 0.1.0
appVersion: "1.0.0"
dependencies:
  - name: postgresql
    version: 10.16.2
    repository: "https://charts.bitnami.com/bitnami"
EOF

##
minji  ~/Desktop/work/Gasida_series/practice/music  helm search repo postgresql
NAME                  	CHART VERSION	APP VERSION	DESCRIPTION
bitnami/postgresql    	18.1.1       	18.0.0     	PostgreSQL (Postgres) is an open source object-...
bitnami/postgresql-ha 	16.3.2       	17.6.0     	This PostgreSQL cluster solution includes the P...
bitnami/cloudnative-pg	1.0.11       	1.26.1     	CloudNativePG is an open-source tool for managi...
bitnami/supabase      	5.3.6        	1.24.7     	DEPRECATED Supabase is an open source Firebase ...
bitnami/minio-operator	0.2.9        	7.1.1      	MinIO(R) Operator is a Kubernetes-native tool f...

##
minji  ~/Desktop/work/Gasida_series/practice/music  helm search repo bitnami/postgresql --versions
NAME                 	CHART VERSION	APP VERSION	DESCRIPTION
bitnami/postgresql   	18.1.1       	18.0.0     	PostgreSQL (Postgres) is an open source object-...
bitnami/postgresql   	18.0.17      	18.0.0     	PostgreSQL (Postgres) is an open source object-...
bitnami/postgresql   	18.0.16      	18.0.0     	PostgreSQL (Postgres) is an open source object-...
bitnami/postgresql   	18.0.15      	18.0.0     	PostgreSQL (Postgres) is an open source object-...
bitnami/postgresql   	18.0.14      	18.0.0     	PostgreSQL (Postgres) is an open source object-...
bitnami/postgresql   	18.0.12      	18.0.0     	PostgreSQL (Postgres) is an open source object-...
																			.
																			.
																			.

## 현재 최신 챠트 버전 사용
minji  ~/Desktop/work/Gasida_series/practice/music  cat << EOF > Chart.yaml
apiVersion: v2
name: music
description: A Helm chart for Music service
type: application
version: 0.1.0
appVersion: "1.0.0"
dependencies:
  - name: postgresql
    version: 18.0.17 # book 10.16.2
    repository: "https://charts.bitnami.com/bitnami"
EOF

##
minji  ~/Desktop/work/Gasida_series/practice/music  cat << EOF > values.yaml
image:
  repository: quay.io/gitops-cookbook/music
  tag: "1.0.0"
  pullPolicy: Always
  containerPort: 8080

replicaCount: 1

postgresql:
  server: jdbc:postgresql://music-db-postgresql:5432/mydb
  postgresqlUsername: my-default
  postgresqlPassword: postgres
  postgresqlDatabase: mydb
  secretName: music-db-postgresql
  secretKey: postgresql-password
EOF

##
minji  ~/Desktop/work/Gasida_series/practice/music  cat << EOF > values.yaml
image:
  repository: quay.io/gitops-cookbook/music
  tag: "1.0.0"
  pullPolicy: Always
  containerPort: 8080

replicaCount: 1

postgresql:
  server: jdbc:postgresql://music-db-postgresql:5432/mydb
  postgresqlUsername: my-default
  postgresqlPassword: postgres
  postgresqlDatabase: mydb
  secretName: music-db-postgresql
  secretKey: postgresql-password
EOF

# 의존성으로 선언된 챠트를 다운로드하여 챠트 디렉터리에 저장
minji  ~/Desktop/work/Gasida_series/practice/music  helm dependency update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "bitnami" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 1 charts
Downloading postgresql from repo https://charts.bitnami.com/bitnami
Pulled: registry-1.docker.io/bitnamicharts/postgresql:18.0.17
Digest: sha256:84b63af46f41ac35e3cbcf098e8cf124211c250807cfed43f7983c39c6e30b72
Deleting outdated charts

##
minji  ~/Desktop/work/Gasida_series/practice/music  tree
.
├── Chart.lock
├── Chart.yaml
├── charts
│   └── postgresql-18.0.17.tgz
├── templates
│   ├── deployment.yaml
│   └── service.yaml
└── values.yaml

3 directories, 6 files

# 챠트 배포
minji  ~/Desktop/work/Gasida_series/practice/music  helm install music-db .
NAME: music-db
LAST DEPLOYED: Fri Oct 24 20:51:28 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

# 확인
minji  ~/Desktop/work/Gasida_series/practice/music  kubectl get sts,pod,svc,ep,secret,pv,pvc
NAME                                   READY   AGE
statefulset.apps/music-db-postgresql   1/1     93s

NAME                          READY   STATUS                       RESTARTS      AGE
pod/music-6c45d566f4-v7btz    0/1     CreateContainerConfigError   0             93s
pod/music-db-postgresql-0     1/1     Running                      0             93s
pod/pacman-576769bb86-t5scc   1/1     Running                      2 (33m ago)   21h

NAME                             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/kubernetes               ClusterIP   10.96.0.1      <none>        443/TCP    22h
service/music                    ClusterIP   10.96.45.200   <none>        8080/TCP   93s
service/music-db-postgresql      ClusterIP   10.96.131.73   <none>        5432/TCP   93s
service/music-db-postgresql-hl   ClusterIP   None           <none>        5432/TCP   93s
service/pacman                   ClusterIP   10.96.105.28   <none>        8080/TCP   21h

NAME                               ENDPOINTS           AGE
endpoints/kubernetes               192.168.97.2:6443   22h
endpoints/music                                        93s
endpoints/music-db-postgresql      10.244.0.11:5432    93s
endpoints/music-db-postgresql-hl   10.244.0.11:5432    93s
endpoints/pacman                   10.244.0.4:8080     21h

NAME                                    TYPE                 DATA   AGE
secret/music-db-postgresql              Opaque               1      93s
secret/sh.helm.release.v1.music-db.v1   helm.sh/release.v1   1      93s
secret/sh.helm.release.v1.pacman.v1     helm.sh/release.v1   1      21h
secret/sh.helm.release.v1.pacman.v2     helm.sh/release.v1   1      21h
secret/sh.helm.release.v1.pacman.v3     helm.sh/release.v1   1      21h
secret/sh.helm.release.v1.pacman.v4     helm.sh/release.v1   1      21h

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-5c9948cf-c5fe-41b3-ba23-33453f80eaf2   8Gi        RWO            Delete           Bound    default/data-my-db-postgresql-0      standard       <unset>                          16m
persistentvolume/pvc-947648b2-8fb2-43c3-816a-11078b1594f3   8Gi        RWO            Delete           Bound    default/data-music-db-postgresql-0   standard       <unset>                          91s

NAME                                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/data-music-db-postgresql-0   Bound    pvc-947648b2-8fb2-43c3-816a-11078b1594f3   8Gi        RWO            standard       <unset>                 93s
persistentvolumeclaim/data-my-db-postgresql-0      Bound    pvc-5c9948cf-c5fe-41b3-ba23-33453f80eaf2   8Gi        RWO            standard       <unset>                 16m

# TS 1 : secret에 key/value 추가
kubectl edit secret music-db-postgresql
postgresql-password: cG9zdGdyZXMK

# TS2 : 직접 해결해보자!
kubectl logs -l app.kubernetes.io/name=music -f
__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2025-10-24 11:58:11,847 WARN  [io.agr.pool] (agroal-11) Datasource '<default>': Something unusual has occurred to cause the driver to fail. Please report this exception.
2025-10-24 11:58:11,876 WARN  [org.hib.eng.jdb.env.int.JdbcEnvironmentInitiator] (JPA Startup Thread: <default>) HHH000342: Could not obtain connection to query metadata: org.postgresql.util.PSQLException: Something unusual has occurred to cause the driver to fail. Please report this exception.
	at org.postgresql.Driver.connect(Driver.java:286)
																.
																.
																.

# music service 에 port-forward 설정 후 호출하여 노래 목록 확인
minji  ~/Desktop/work/Gasida_series/practice/music  kubectl port-forward service/music 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

minji  ~/Desktop/work/Gasida_series/practice/music  helm uninstall music-db
release "music-db" uninstalled
 minji  ~/Desktop/work/Gasida_series/practice/music  kubectl delete pvc --all
persistentvolumeclaim "data-music-db-postgresql-0" deleted

 

 

6장 Cloud Native CI/CD

  • 기본적으로 지속적 통합 ( CI )은 개발자가 만들 새 코드를 가져와서 빌드, 테스트, 실행하는 과정을 자동으로 처리하는 프로세스
  • 텍톤이란 ?
    • 쿠버네티스 기반 오픈 소스 클라우드 네이티브 CI/CD 시스템이다
  • 기본 개념
    • Task
      • 특정 기능 (예: 컨테이너 이미지 빌드)을 수행하는 재사용 가능하고 느슨하게 결합된 여러 개의 단계(steps).
      • 태스크는 쿠버네티스 파드로 실행되고, 태스트의 각 단계는 컨테이너에 대응된다.
    • Pipeline
      • 앱을 빌드 및 또는 배포하는 데 필요한 Task의 목록
    • TaskRun
      • Task 인스턴스의 실행 및 그 결과
    • PipelineRun
      • Pipeline 인스턴스의 실행 및 그 결과. 다수의 TaskRun 포함
    • Trigger
      • 이벤트를 감지하고 다른 CRD에 연결하여 해당 이벤트가 발생했을 때 어떤 일이 발생하는지 지정.
  • 구성요소
    • 텍톤은 모듈식 구조로 되어 있다. 모든 구성 요소를 개별적으로 또는 한 번에 설치할 수 있다.
    • Tekton Pilelines
      • Task 및 Pipeline포함
    • Tekton Triggers
      • Trigger 및 EventListener 포함
    • Tekton Dashbaord
      • 파이프라인과 로그를 시각화 할 수 있는 대시보드
    • Tekton CLI
      • 텍톤 객체를 관리하기 위한 CLI (파이프라인 및 작업 시작/중지, 로그 확인)
  • 텍톤 flow

 

6.1 install tekton

Pipeline

# Takton dependency pipeline 설치
minji  ~/Desktop/work/Gasida_series/practice/music  kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
namespace/tekton-pipelines created
clusterrole.rbac.authorization.k8s.io/tekton-pipelines-controller-cluster-access created
clusterrole.rbac.authorization.k8s.io/tekton-pipelines-controller-tenant-access created
clusterrole.rbac.authorization.k8s.io/tekton-pipelines-webhook-cluster-access created
clusterrole.rbac.authorization.k8s.io/tekton-events-controller-cluster-access created
role.rbac.authorization.k8s.io/tekton-pipelines-controller created
role.rbac.authorization.k8s.io/tekton-pipelines-webhook created
																.
																.
																.

# Takton dependency pipeline 설치 확인
minji  ~/Desktop/work/Gasida_series/practice/music  kubectl get crd
NAME                                       CREATED AT
customruns.tekton.dev                      2025-10-24T13:14:17Z
pipelineruns.tekton.dev                    2025-10-24T13:14:17Z
pipelines.tekton.dev                       2025-10-24T13:14:17Z
resolutionrequests.resolution.tekton.dev   2025-10-24T13:14:17Z
stepactions.tekton.dev                     2025-10-24T13:14:17Z
taskruns.tekton.dev                        2025-10-24T13:14:17Z
tasks.tekton.dev                           2025-10-24T13:14:17Z
verificationpolicies.tekton.dev            2025-10-24T13:14:17Z

#
minji  ~/Desktop/work/Gasida_series/practice/music  kubectl get ns | grep tekton
tekton-pipelines             Active   81s
tekton-pipelines-resolvers   Active   81s

#
minji  ~/Desktop/work/Gasida_series/practice/music  kubectl krew install get-all
WARNING: To be able to run kubectl plugins, you need to add
the following to your ~/.zshrc:

    export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"
														    .
														    .
														    .
														    
#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get-all -n tekton-pipelines
NAME                                                                                                                                     NAMESPACE         AGE
configmap/config-defaults                                                                                                                tekton-pipelines  7m
configmap/config-events                                                                                                                  tekton-pipelines  7m
configmap/config-leader-election-controller                                                                                              tekton-pipelines  7m
configmap/config-leader-election-events
														    .
														    .
														    .

# 
minji  ~/Desktop/work/Gasida_series/practice  kubectl get-all -n tekton-pipelines-resolvers
NAME                                                                                  NAMESPACE                   AGE
configmap/bundleresolver-config                                                       tekton-pipelines-resolvers  7m36s
configmap/cluster-resolver-config                                                     tekton-pipelines-resolvers  7m36s
configmap/config-leader-election-resolvers                                            tekton-pipelines-resolvers  7m36s
configmap/config-logging                                                              tekton-pipelines-resolvers  7m36s
configmap/config-observability                                                        tekton-pipelines-resolvers  7m36s
configmap/git-resolver-config                                                         tekton-pipelines-resolvers  7m36s
configmap/http-resolver-config                                                        tekton-pipelines-resolvers  7m36s
configmap/hubresolver-config                                                          tekton-pipelines-resolvers  7m36s
configmap/kube-root-ca.crt                                                            tekton-pipelines-resolvers  7m36s
configmap/resolvers-feature-flags                                                     tekton-pipelines-resolvers  7m36s
endpoints/tekton-pipelines-remote-resolvers                                           tekton-pipelines-resolvers  7m36s
pod/tekton-pipelines-remote-resolvers-86f56b6664-rjhxv                                tekton-pipelines-resolvers  7m36s
serviceaccount/default                                                                tekton-pipelines-resolvers  7m36s
serviceaccount/tekton-pipelines-resolvers                                             tekton-pipelines-resolvers  7m36s
service/tekton-pipelines-remote-resolvers                                             tekton-pipelines-resolvers  7m36s
deployment.apps/tekton-pipelines-remote-resolvers                                     tekton-pipelines-resolvers  7m36s
replicaset.apps/tekton-pipelines-remote-resolvers-86f56b6664                          tekton-pipelines-resolvers  7m36s
lease.coordination.k8s.io/controller.tektonresolverframework.bundleresolver.00-of-01  tekton-pipelines-resolvers  7m4s
lease.coordination.k8s.io/controller.tektonresolverframework.cluster.00-of-01         tekton-pipelines-resolvers  7m4s
lease.coordination.k8s.io/controller.tektonresolverframework.git.00-of-01             tekton-pipelines-resolvers  7m4s
lease.coordination.k8s.io/controller.tektonresolverframework.http.00-of-01            tekton-pipelines-resolvers  7m4s
lease.coordination.k8s.io/controller.tektonresolverframework.hub.00-of-01             tekton-pipelines-resolvers  7m4s
endpointslice.discovery.k8s.io/tekton-pipelines-remote-resolvers-gtrch                tekton-pipelines-resolvers  7m36s
rolebinding.rbac.authorization.k8s.io/tekton-pipelines-resolvers-namespace-rbac       tekton-pipelines-resolvers  7m36s
role.rbac.authorization.k8s.io/tekton-pipelines-resolvers-namespace-rbac              tekton-pipelines-resolvers  7m36s

#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get all -n tekton-pipelines-resolvers
NAME                                                     READY   STATUS    RESTARTS   AGE
pod/tekton-pipelines-remote-resolvers-86f56b6664-rjhxv   1/1     Running   0          7m47s

NAME                                        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                      AGE
service/tekton-pipelines-remote-resolvers   ClusterIP   10.96.65.6   <none>        9090/TCP,8008/TCP,8080/TCP   7m47s

NAME                                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/tekton-pipelines-remote-resolvers   1/1     1            1           7m47s

NAME                                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/tekton-pipelines-remote-resolvers-86f56b6664   1         1         1       7m47s

# pod 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl get pod -n tekton-pipelines
NAME                                           READY   STATUS    RESTARTS   AGE
tekton-events-controller-99665746c-v4bw8       1/1     Running   0          8m49s
tekton-pipelines-controller-7595d6585d-vjhq8   1/1     Running   0          8m49s
tekton-pipelines-webhook-5967d74cc4-t5th4      1/1     Running   0          8m49s

 

 

Trigger

# Tekton Trigger 설치
minji  ~/Desktop/work/Gasida_series/practice  kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
clusterrole.rbac.authorization.k8s.io/tekton-triggers-admin created
clusterrole.rbac.authorization.k8s.io/tekton-triggers-core-interceptors created
clusterrole.rbac.authorization.k8s.io/tekton-triggers-core-interceptors-secrets created
clusterrole.rbac.authorization.k8s.io/tekton-triggers-eventlistener-roles created
																		.
																		.
																		.
# 
minji  ~/Desktop/work/Gasida_series/practice  kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
secret/tekton-triggers-core-interceptors-certs created
deployment.apps/tekton-triggers-core-interceptors created
service/tekton-triggers-core-interceptors created
clusterinterceptor.triggers.tekton.dev/cel created
clusterinterceptor.triggers.tekton.dev/bitbucket created
clusterinterceptor.triggers.tekton.dev/slack created
clusterinterceptor.triggers.tekton.dev/github created
clusterinterceptor.triggers.tekton.dev/gitlab created

# Tekton Trigger 설치 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl get crd | grep triggers
clusterinterceptors.triggers.tekton.dev      2025-10-24T13:26:39Z
clustertriggerbindings.triggers.tekton.dev   2025-10-24T13:26:39Z
eventlisteners.triggers.tekton.dev           2025-10-24T13:26:39Z
interceptors.triggers.tekton.dev             2025-10-24T13:26:39Z
triggerbindings.triggers.tekton.dev          2025-10-24T13:26:39Z
triggers.triggers.tekton.dev                 2025-10-24T13:26:39Z
triggertemplates.triggers.tekton.dev         2025-10-24T13:26:39Z

#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get all -n tekton-pipelines
NAME                                                     READY   STATUS    RESTARTS   AGE
pod/tekton-events-controller-99665746c-v4bw8             1/1     Running   0          14m
pod/tekton-pipelines-controller-7595d6585d-vjhq8         1/1     Running   0          14m
pod/tekton-pipelines-webhook-5967d74cc4-t5th4            1/1     Running   0          14m
pod/tekton-triggers-controller-74fccfc888-kks9r          1/1     Running   0          118s
pod/tekton-triggers-core-interceptors-7b8dcb59fb-5h42s   1/1     Running   0          74s
pod/tekton-triggers-webhook-5465cc8d5b-9kq58             1/1     Running   0          118s

NAME                                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                              AGE
service/tekton-events-controller            ClusterIP   10.96.87.139    <none>        9090/TCP,8008/TCP,8080/TCP           14m
service/tekton-pipelines-controller         ClusterIP   10.96.138.51    <none>        9090/TCP,8008/TCP,8080/TCP           14m
service/tekton-pipelines-webhook            ClusterIP   10.96.164.74    <none>        9090/TCP,8008/TCP,443/TCP,8080/TCP   14m
service/tekton-triggers-controller          ClusterIP   10.96.129.69    <none>        9000/TCP                             118s
service/tekton-triggers-core-interceptors   ClusterIP   10.96.150.198   <none>        8443/TCP                             74s
service/tekton-triggers-webhook             ClusterIP   10.96.22.249    <none>        443/TCP                              118s

NAME                                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/tekton-events-controller            1/1     1            1           14m
deployment.apps/tekton-pipelines-controller         1/1     1            1           14m
deployment.apps/tekton-pipelines-webhook            1/1     1            1           14m
deployment.apps/tekton-triggers-controller          1/1     1            1           118s
deployment.apps/tekton-triggers-core-interceptors   1/1     1            1           74s
deployment.apps/tekton-triggers-webhook             1/1     1            1           118s

NAME                                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/tekton-events-controller-99665746c             1         1         1       14m
replicaset.apps/tekton-pipelines-controller-7595d6585d         1         1         1       14m
replicaset.apps/tekton-pipelines-webhook-5967d74cc4            1         1         1       14m
replicaset.apps/tekton-triggers-controller-74fccfc888          1         1         1       118s
replicaset.apps/tekton-triggers-core-interceptors-7b8dcb59fb   1         1         1       74s
replicaset.apps/tekton-triggers-webhook-5465cc8d5b             1         1         1       118s

NAME                                                           REFERENCE                             TARGETS               MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/tekton-pipelines-webhook   Deployment/tekton-pipelines-webhook   cpu: <unknown>/100%   1         5         1          14m

# Trigger 관련 deployment 설치 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl get deploy -n tekton-pipelines | grep triggers
tekton-triggers-controller          1/1     1            1           2m41s
tekton-triggers-core-interceptors   1/1     1            1           117s
tekton-triggers-webhook             1/1     1            1           2m41s

 

 

Dashboard

# Tekton dashboard 설치
minji  ~/Desktop/work/Gasida_series/practice  kubectl apply -f https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml
customresourcedefinition.apiextensions.k8s.io/extensions.dashboard.tekton.dev created
serviceaccount/tekton-dashboard created
role.rbac.authorization.k8s.io/tekton-dashboard-info created
clusterrole.rbac.authorization.k8s.io/tekton-dashboard-backend-edit created
clusterrole.rbac.authorization.k8s.io/tekton-dashboard-backend-view created
clusterrole.rbac.authorization.k8s.io/tekton-dashboard-tenant-view created
rolebinding.rbac.authorization.k8s.io/tekton-dashboard-info created
clusterrolebinding.rbac.authorization.k8s.io/tekton-dashboard-backend-view created
configmap/dashboard-info created
service/tekton-dashboard created
deployment.apps/tekton-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/tekton-dashboard-tenant-view created
clusterrolebinding.rbac.authorization.k8s.io/tekton-dashboard-pipelines-view created
clusterrolebinding.rbac.authorization.k8s.io/tekton-dashboard-triggers-view created

# Tekton Dashboard 설치 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl get crd | grep dashboard
extensions.dashboard.tekton.dev              2025-10-24T13:30:07Z

#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get all -n tekton-pipelines
NAME                                                     READY   STATUS    RESTARTS   AGE
pod/tekton-dashboard-7d4499b584-5fxb5                    1/1     Running   0          58s
pod/tekton-events-controller-99665746c-v4bw8             1/1     Running   0          16m
pod/tekton-pipelines-controller-7595d6585d-vjhq8         1/1     Running   0          16m
pod/tekton-pipelines-webhook-5967d74cc4-t5th4            1/1     Running   0          16m
pod/tekton-triggers-controller-74fccfc888-kks9r          1/1     Running   0          4m26s
pod/tekton-triggers-core-interceptors-7b8dcb59fb-5h42s   1/1     Running   0          3m42s
pod/tekton-triggers-webhook-5465cc8d5b-9kq58             1/1     Running   0          4m26s

NAME                                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                              AGE
service/tekton-dashboard                    ClusterIP   10.96.30.117    <none>        9097/TCP                             58s
service/tekton-events-controller            ClusterIP   10.96.87.139    <none>        9090/TCP,8008/TCP,8080/TCP           16m
service/tekton-pipelines-controller         ClusterIP   10.96.138.51    <none>        9090/TCP,8008/TCP,8080/TCP           16m
service/tekton-pipelines-webhook            ClusterIP   10.96.164.74    <none>        9090/TCP,8008/TCP,443/TCP,8080/TCP   16m
service/tekton-triggers-controller          ClusterIP   10.96.129.69    <none>        9000/TCP                             4m26s
service/tekton-triggers-core-interceptors   ClusterIP   10.96.150.198   <none>        8443/TCP                             3m42s
service/tekton-triggers-webhook             ClusterIP   10.96.22.249    <none>        443/TCP                              4m26s

NAME                                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/tekton-dashboard                    1/1     1            1           58s
deployment.apps/tekton-events-controller            1/1     1            1           16m
deployment.apps/tekton-pipelines-controller         1/1     1            1           16m
deployment.apps/tekton-pipelines-webhook            1/1     1            1           16m
deployment.apps/tekton-triggers-controller          1/1     1            1           4m26s
deployment.apps/tekton-triggers-core-interceptors   1/1     1            1           3m42s
deployment.apps/tekton-triggers-webhook             1/1     1            1           4m26s

NAME                                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/tekton-dashboard-7d4499b584                    1         1         1       58s
replicaset.apps/tekton-events-controller-99665746c             1         1         1       16m
replicaset.apps/tekton-pipelines-controller-7595d6585d         1         1         1       16m
replicaset.apps/tekton-pipelines-webhook-5967d74cc4            1         1         1       16m
replicaset.apps/tekton-triggers-controller-74fccfc888          1         1         1       4m26s
replicaset.apps/tekton-triggers-core-interceptors-7b8dcb59fb   1         1         1       3m42s
replicaset.apps/tekton-triggers-webhook-5465cc8d5b             1         1         1       4m26s

NAME                                                           REFERENCE                             TARGETS               MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/tekton-pipelines-webhook   Deployment/tekton-pipelines-webhook   cpu: <unknown>/100%   1         5         1          16m

# Dashboard 관련 deployment 설치 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl get deploy -n tekton-pipelines
NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
tekton-dashboard                    1/1     1            1           2m34s
tekton-events-controller            1/1     1            1           18m
tekton-pipelines-controller         1/1     1            1           18m
tekton-pipelines-webhook            1/1     1            1           18m
tekton-triggers-controller          1/1     1            1           6m2s
tekton-triggers-core-interceptors   1/1     1            1           5m18s
tekton-triggers-webhook             1/1     1            1           6m2s

# service 정보 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl get svc,ep -n tekton-pipelines tekton-dashboard
NAME                       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/tekton-dashboard   ClusterIP   10.96.30.117   <none>        9097/TCP   3m9s

NAME                         ENDPOINTS          AGE
endpoints/tekton-dashboard   10.244.0.25:9097   3m9s

#
minji  ~/Desktop/work/Gasida_series/practice  [200~kubectl get svc -n tekton-pipelines tekton-dashboard -o yaml~
 ✘ minji  ~/Desktop/work/Gasida_series/practice 
 ✘ minji  ~/Desktop/work/Gasida_series/practice  kubectl get svc -n tekton-pipelines tekton-dashboard -o yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"tekton-dashboard","app.kubernetes.io/component":"dashboard","app.kubernetes.io/instance":"default","app.kubernetes.io/name":"dashboard","app.kubernetes.io/part-of":"tekton-dashboard","app.kubernetes.io/version":"v0.62.0","dashboard.tekton.dev/release":"v0.62.0","version":"v0.62.0"},"name":"tekton-dashboard","namespace":"tekton-pipelines"},"spec":{"ports":[{"name":"http","port":9097,"protocol":"TCP","targetPort":9097}],"selector":{"app.kubernetes.io/component":"dashboard","app.kubernetes.io/instance":"default","app.kubernetes.io/name":"dashboard","app.kubernetes.io/part-of":"tekton-dashboard"}}}
  creationTimestamp: "2025-10-24T13:30:07Z"
																			  .
																			  .
																			  .

# Service 를 node port 설정 ( nodeport 30000 )
minji  ~/Desktop/work/Gasida_series/practice  kubectl patch svc -n tekton-pipelines tekton-dashboard -p '{"spec":{"type":"NodePort","ports":[{"port":9097,"targetPort":9097,"nodePort":30000}]}}'
service/tekton-dashboard patched
 
#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get svc,ep -n tekton-pipelines tekton-dashboard
NAME                       TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/tekton-dashboard   NodePort   10.96.30.117   <none>        9097:30000/TCP   5m44s

NAME                         ENDPOINTS          AGE
endpoints/tekton-dashboard   10.244.0.25:9097   5m44s

# tekton dashboard 접속
minji  ~/Desktop/work/Gasida_series/practice  open http://localhost:30000

 

 

Tekton CLI 설치

minji  ~/Desktop/work/Gasida_series/practice  brew install tektoncd-cli
==> Auto-updating Homebrew...
Adjust how often this is run with `$HOMEBREW_AUTO_UPDATE_SECS` or disable with
`$HOMEBREW_NO_AUTO_UPDATE=1`. Hide these hints with `$HOMEBREW_NO_ENV_HINTS=1` (see `man brew`).
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
==> New Formulae
btllib: Bioinformatics Technology Lab common code library
ghidra: Multi-platform software reverse engineering framework
																	.
																	.
																	.
  
#
minji  ~/Desktop/work/Gasida_series/practice 
 ✘ minji  ~/Desktop/work/Gasida_series/practice 
 ✘ minji  ~/Desktop/work/Gasida_series/practice  tkn version
Client version: 0.42.0
Pipeline version: v1.5.0
Triggers version: v0.33.0
Dashboard version: v0.62.0

 

 

6.2 Create a hello world task

Task 생성

#
minji  ~/Desktop/work/Gasida_series/practice  kubectl explain tasks.tekton.dev
GROUP:      tekton.dev
KIND:       Task
VERSION:    v1

# task 생성
minji  ~/Desktop/work/Gasida_series/practice  cat << EOF | kubectl apply -f -
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: hello
spec:
  steps:
    - name: echo    # step 이름
      image: alpine # step 수행 컨테이너 이미지
      script: |
        #!/bin/sh
        echo "Hello World"
EOF
task.tekton.dev/hello created

# 확인
minji  ~/Desktop/work/Gasida_series/practice  tkn task list
NAME    DESCRIPTION   AGE
hello                 9 seconds ago

#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get tasks
NAME    AGE
hello   29s

#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get tasks -o yaml
apiVersion: v1
items:
- apiVersion: tekton.dev/v1
  kind: Task
  metadata:
    annotations:
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"tekton.dev/v1","kind":"Task","metadata":{"annotations":{},"name":"hello","namespace":"default"},"spec":{"steps":[{"image":"alpine","name":"echo","script":"#!/bin/sh\necho \"Hello World\"\n"}]}}
    creationTimestamp: "2025-10-24T13:52:15Z"
    generation: 1
    name: hello
    namespace: default
    resourceVersion: "25364"
    uid: b29d6f56-b42c-4856-a412-186fc80cd25d
  spec:
    steps:
    - computeResources: {}
      image: alpine
      name: echo
      script: |
        #!/bin/sh
        echo "Hello World"
kind: List
metadata:
  resourceVersion: ""
  
#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get pod
NAME                      READY   STATUS    RESTARTS       AGE
pacman-576769bb86-t5scc   1/1     Running   2 (154m ago)   23h

 

 

 

tkn CLI로 task 시작

# 신규 터미널 : pod status monitoring
minji  ~  kubectl get pod -w
NAME                      READY   STATUS    RESTARTS       AGE
pacman-576769bb86-t5scc   1/1     Running   2 (156m ago)   23h
hello-run-7rb4h-pod       0/1     Pending   0              0s
hello-run-7rb4h-pod       0/1     Pending   0              0s
hello-run-7rb4h-pod       0/1     Init:0/2   0              0s
hello-run-7rb4h-pod       0/1     Init:1/2   0              7s
hello-run-7rb4h-pod       0/1     PodInitializing   0              11s
hello-run-7rb4h-pod       1/1     Running           0              18s
hello-run-7rb4h-pod       1/1     Running           0              18s
hello-run-7rb4h-pod       0/1     Completed         0              19s
hello-run-7rb4h-pod       0/1     Completed         0              20s

# tkn CLI로 task 시작
minji  ~/Desktop/work/Gasida_series/practice  kubectl get pod
NAME                      READY   STATUS    RESTARTS       AGE
pacman-576769bb86-t5scc   1/1     Running   2 (154m ago)   23h
 minji  ~/Desktop/work/Gasida_series/practice  tk
n task start --showlog hello
TaskRun started: hello-run-7rb4h
Waiting for logs to be available...
[echo] Hello World

# pod 내 "2개의 init 컨테이너, 1개의 컨테이너" 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl describe pod -l tekton.dev/task=hello

																		.
																		.
																		.

Init Containers:
  prepare:
    Container ID:  containerd://a43c17ce1d040c740775d3aa404a09ea90e048ba7a8a6e4c78008e4e6ec3331f
    Image:         ghcr.io/tektoncd/pipeline/entrypoint-bff0a22da108bc2f16c818c97641a296:v1.5.0@sha256:ff5ee925ff7b08853cc4caa93e5e3e0ee761a2db6ae0a1ae6a0f6f120f170b56
    Image ID:      ghcr.io/tektoncd/pipeline/entrypoint-bff0a22da108bc2f16c818c97641a296@sha256:ff5ee925ff7b08853cc4caa93e5e3e0ee761a2db6ae0a1ae6a0f6f120f170b56

																		.
																		.
																		.

# log 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl logs -l tekton.dev/task=hello -c prepare
2025/10/24 13:55:43 Entrypoint initialization

minji  ~/Desktop/work/Gasida_series/practice  kubectl logs -l tekton.dev/task=hello -c place-scripts
2025/10/24 13:55:46 Decoded script /tekton/scripts/script-0-tccks

minji  ~/Desktop/work/Gasida_series/practice  kubectl logs -l tekton.dev/task=hello -c step-echo
Hello World

#
minji  ~/Desktop/work/Gasida_series/practice  tkn task logs hello
Hello World

 minji  ~/Desktop/work/Gasida_series/practice  tkn task describe hello
Name:        hello
Namespace:   default

🦶 Steps

 ∙ echo

🗂  Taskruns

NAME              STARTED         DURATION   STATUS
hello-run-7rb4h   5 minutes ago   19s        Succeeded

#
minji  ~/Desktop/work/Gasida_series/practice  tkn taskrun logs
[echo] Hello World

 minji  ~/Desktop/work/Gasida_series/practice  tkn taskrun list
NAME              STARTED         DURATION   STATUS
hello-run-7rb4h   5 minutes ago   19s        Succeeded

# 다음 실습을 위해 taskrun 삭제
minji  ~/Desktop/work/Gasida_series/practice  kubectl delete taskruns --all
taskrun.tekton.dev "hello-run-7rb4h" deleted

 

 

6.3 Create a Task to compile and package an App from git

Tekton을 사용하여 git 저장소에 보관된 app code를 compile하고 패키징하는 작업을 자동화 해보자

지금 하는 내용의 핵심 아이디어는 추후 파이프라인을 만들 떄 쓸 수 있도록 input과 output이 잘 규정된 task를 만드는것

Tekton pipelines를 사용하여 git에서 소스 코드를 복제

# 파이프라인 파일 작성
owoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  cat << EOF | kubectl apply -f -
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: clone-read
spec:
  description: |
    This pipeline clones a git repo, then echoes the README file to the stout.
  params:     # 매개변수 repo-url
  - name: repo-url
    type: string
    description: The git repo URL to clone from.
  workspaces: # 다운로드할 코드를 저장할 공유 볼륨인 작업 공간을 추가
  - name: shared-data
    description: |
      This workspace contains the cloned repo files, so they can be read by the
      next task.
  tasks:      # task 정의
  - name: fetch-source
    taskRef:
      name: git-clone
    workspaces:
    - name: output
      workspace: shared-data
    params:
    - name: url
      value: \$(params.repo-url)
EOF
pipeline.tekton.dev/clone-read created

# 확인
minji  ~/Desktop/work/Gasida_series/practice  tkn pipeline list
NAME         AGE              LAST RUN   STARTED   DURATION   STATUS
clone-read   36 seconds ago   ---        ---       ---        ---

#
minji  ~/Desktop/work/Gasida_series/practice  tkn pipeline describe
Name:          clone-read
Namespace:     default
Description:   This pipeline clones a git repo, then echoes the README file to the stout.


⚓ Params

 NAME         TYPE     DESCRIPTION              DEFAULT VALUE
 ∙ repo-url   string   The git repo URL to...   ---

📂 Workspaces

 NAME            DESCRIPTION              OPTIONAL
 ∙ shared-data   This workspace cont...   false

🗒  Tasks

 NAME             TASKREF     RUNAFTER   TIMEOUT   PARAMS
 ∙ fetch-source   git-clone              ---       url: string
#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get pipeline
NAME         AGE
clone-read   57s

#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get pipeline -o yaml
apiVersion: v1
items:
- apiVersion: tekton.dev/v1
  kind: Pipeline
  metadata:
    annotations:
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"tekton.dev/v1","kind":"Pipeline","metadata":{"annotations":{},"name":"clone-read","namespace":"default"},"spec":{"description":"This pipeline clones a git repo, then echoes the README file to the stout.\n","params":[{"description":"The git repo URL to clone from.","name":"repo-url","type":"string"}],"tasks":[{"name":"fetch-source","params":[{"name":"url","value":"$(params.repo-url)"}],"taskRef":{"name":"git-clone"},"workspaces":[{"name":"output","workspace":"shared-data"}]}],"workspaces":[{"description":"This workspace contains the cloned repo files, so they can be read by the\nnext task.\n","name":"shared-data"}]}}
    creationTimestamp: "2025-10-24T14:11:08Z"
    generation: 1
    name: clone-read
    namespace: default
    resourceVersion: "29298"
    uid: 835cc5df-8ad7-4ae7-af32-073069f38770
  spec:
    description: |
      This pipeline clones a git repo, then echoes the README file to the stout.
    params:
    - description: The git repo URL to clone from.
      name: repo-url
      type: string
    tasks:
    - name: fetch-source
      params:
      - name: url
        value: $(params.repo-url)
      taskRef:
        kind: Task
        name: git-clone
      workspaces:
      - name: output
        workspace: shared-data
    workspaces:
    - description: |
        This workspace contains the cloned repo files, so they can be read by the
        next task.
      name: shared-data
kind: List
metadata:
  resourceVersion: ""
 minji  ~/Desktop/work/Gasida_series/practice  kubectl get pod
NAME                      READY   STATUS    RESTARTS       AGE
pacman-576769bb86-t5scc   1/1     Running   2 (173m ago)   23h

 

# 파이프라인 실행 : 파이프라인을 인스턴스화하고 실제 값 설정
cat << EOF | kubectl create -f -
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: clone-read-run-
spec:
  pipelineRef:
    name: clone-read
  taskRunTemplate:
    podTemplate:
      securityContext:
        fsGroup: 65532
  workspaces: # 작업 공간 인스턴스화, PVC 생성
  - name: shared-data
    volumeClaimTemplate:
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 1Gi
  params:    # 저장소 URL 매개변수 값 설정
  - name: repo-url
    value: https://github.com/tektoncd/website
EOF

#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get pipelineruns -o yaml
apiVersion: v1
items:
- apiVersion: tekton.dev/v1
  kind: PipelineRun
  metadata:
																		.
																		.
																		.
        runningInEnvWithInjectedSidecars: true
        verificationNoMatchPolicy: ignore
    startTime: "2025-10-24T14:14:16Z"
kind: List
metadata:
  resourceVersion: ""
  
#
minji  ~/Desktop/work/Gasida_series/practice  kubectl get pipelineruns
NAME                   SUCCEEDED   REASON           STARTTIME   COMPLETIONTIME
clone-read-run-zjfkj   False       CouldntGetTask   45s         45s

#
minji  ~/Desktop/work/Gasida_series/practice  tkn pipelinerun list
NAME                   STARTED        DURATION   STATUS
clone-read-run-zjfkj   1 minute ago   0s         Failed(CouldntGetTask)

#
minji  ~/Desktop/work/Gasida_series/practice  tkn pipelinerun logs
Pipeline default/clone-read can't be Run; it contains Tasks that don't exist: Couldn't retrieve Task "git-clone": tasks.tekton.dev "git-clone" not found

#
minji  ~/Desktop/work/Gasida_series/practice  tkn pipelinerun logs
Pipeline default/clone-read can't be Run; it contains Tasks that don't exist: Couldn't retrieve Task "git-clone": tasks.tekton.dev "git-clone" not found

 

# 파이프라인에서 git clone 작업을 사용하려면 먼저 클러스터에 설치 필요
minji  ~/Desktop/work/Gasida_series/practice  tkn hub install task git-clone
WARN: This version has been deprecated
Task git-clone(0.9) installed in default namespace

# 추가된 task 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl get tasks
NAME        AGE
git-clone   43s
hello       27m
 minji  ~/Desktop/work/Gasida_series/practice  kubectl get tasks git-clone -o yaml | kubectl neat | yq
apiVersion: tekton.dev/v1
kind: Task
metadata:
  annotations:
    tekton.dev/categories: Git
																	.
																	.
																	.
																	
# 파이프라인 재실행
minji  ~/Desktop/work/Gasida_series/practice  cat << EOF | kubectl create -f -
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: clone-read-run-
spec:
  pipelineRef:
    name: clone-read
  taskRunTemplate:
    podTemplate:
      securityContext:
        fsGroup: 65532
  workspaces:
  - name: shared-data
    volumeClaimTemplate:
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 1Gi
  params:
  - name: repo-url
    value: https://github.com/tektoncd/website
EOF
pipelinerun.tekton.dev/clone-read-run-fk5fb created

#
minji  ~/Desktop/work/Gasida_series/practice  tkn pipelinerun list
NAME                   STARTED          DURATION   STATUS
clone-read-run-fk5fb   24 seconds ago   19s        Succeeded
clone-read-run-zjfkj   6 minutes ago    0s         Failed(CouldntGetTask)

#
minji  ~/Desktop/work/Gasida_series/practice  tkn pipelinerun logs
? Select pipelinerun: )  [Use arrows to move, type to filter]

# pv, pvc 확인
minji  ~/Desktop/work/Gasida_series/practice  kubectl get pod,pv,pvc
NAME                                        READY   STATUS      RESTARTS       AGE
pod/clone-read-run-fk5fb-fetch-source-pod   0/1     Completed   0              100s
pod/pacman-576769bb86-t5scc                 1/1     Running     2 (3h2m ago)   23h

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-b5399cd4-c602-4fe4-9424-ee3ea6e76cac   1Gi        RWO            Delete           Bound    default/pvc-fcf9b36883   standard       <unset>                          98s

NAME                                   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/pvc-fcf9b36883   Bound    pvc-b5399cd4-c602-4fe4-9424-ee3ea6e76cac   1Gi        RWO            standard       <unset>

 

6.4 Create a task to compile and package an ap from private git

비공개 git 저장소의 앱을 컴파일하고 패키징하는 과정을 tekton으로 자동화

tekton은 git을 위해 2가지 인증 체계를 지원 : basic-auth, ssh

2가지 옵션 모두 k8s secret를 사용하여 자격 증명을 저장하고 이를 tekton 또는 pipeline을 실행하는 serviceaccount에 연결

 

실습 - 샘플 앱 생성 및 git 초기화

# git 초기화
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app  git init
Initialized empty Git repository in /Users/howoo/Desktop/work/Gasida_series/practice/my-sample-app/.git/

# git 사용자 설정
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  git config --global user.name "*********"
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  git config --global user.email "*********"
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  git add .
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main ✚  git commit -m "Initial commit - sample app"
[main (root-commit) 88c932e] Initial commit - sample app
 1 file changed, 1 insertion(+)
 create mode 100644 app.js

 

Github remote 연결 및 push

# origin remote 등록:
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  git remote add origin https://github.com/ktokang/my-sample-app.git

# 메인 브랜치 이름을 main으로 변경 (GitHub 기본 브랜치와 맞춤):
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  git branch -M main

# push
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  git push -u origin main
Username for 'https://github.com': *******
Password for 'https://ktokang@github.com':
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 247 bytes | 247.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://github.com/ktokang/my-sample-app.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.

 

 

SSH key로 인증 설정

# ssh key 생성 & 보기
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  ls -al ~/.ssh | grep ed25519
-rw-------@  1 howoo  staff   411 10월 24 23:47 id_ed25519
-rw-r--r--@  1 howoo  staff    98 10월 24 23:47 id_ed25519.pub

# 
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  eval "$(ssh-agent -s)"
Agent pid 8866

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  ssh-add ~/.ssh/id_ed25519
Identity added: /Users/howoo/.ssh/id_ed25519

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  cat ~/.ssh/id_ed25519.pub

 

ssh 연결 방식 사용 테스트

# 
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  ssh -i ~/.ssh/id_ed25519 -T git@github.com
The authenticity of host 'github.com (20.200.245.247)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
Hi ktokang! You've successfully authenticated, but GitHub does not provide shell access.

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  git remote set-url origin git@github.com:ktokang/my-sample-app.git

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  git add .

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main ✚  git commit -m "add readme.md file"
[main 604fcd4] add readme.md file
 3 files changed, 10 insertions(+)
 create mode 100644 readme.md

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app  ↱ main  git push -u origin main
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 10 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 809 bytes | 809.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To github.com:ktokang/my-sample-app.git
   88c932e..604fcd4  main -> main
branch 'main' set up to track 'origin/main'.

 

 

Tekton Pipelines를 사용하여 git 소스코드를 복제

# Git 인증용 ssh 사설키를 base64 인코딩
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  SSHPK=$(cat ~/.ssh/id_ed25519 | base64 -w0

# Git 인증서버 known_hosts 값을 base64 인코딩
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  SSHKH=$(ssh-keyscan github.com | grep ecdsa-sha2-nistp256 | base64 -w0)

# 
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: git-credentials
data:
  id_rsa: $SSHPK
  known_hosts: $SSHKH
EOF

secret/git-credentials created

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  kubectl get secret
NAME                           TYPE                 DATA   AGE
git-credentials                Opaque               2      47s
sh.helm.release.v1.pacman.v1   helm.sh/release.v1   1      24h
sh.helm.release.v1.pacman.v2   helm.sh/release.v1   1      24h
sh.helm.release.v1.pacman.v3   helm.sh/release.v1   1      24h
sh.helm.release.v1.pacman.v4   helm.sh/release.v1   1      24h

# serviceaccount 에 secret 속성 지정 및 확인
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-bot
secrets:
  - name: git-credentials
EOF
serviceaccount/build-bot created

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  kubectl get sa
NAME        SECRETS   AGE
build-bot   1         6s
default     0         25h

 

 

파이프라인, 파이프라인 실행

# 파이프라인 파일 작성
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  cat << EOF | kubectl apply -f -
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: my-clone-read
spec:
  description: |
    This pipeline clones a git repo, then echoes the README file to the stout.
  params:     # 매개변수 repo-url
  - name: repo-url
    type: string
    description: The git repo URL to clone from.
  workspaces: # 다운로드할 코드를 저장할 공유 볼륨인 작업 공간을 추가
  - name: shared-data
    description: |
      This workspace contains the cloned repo files, so they can be read by the
      next task.
  - name: git-credentials
    description: My ssh credentials
  tasks:      # task 정의
  - name: fetch-source
    taskRef:
      name: git-clone
    workspaces:
    - name: output
      workspace: shared-data
    - name: ssh-directory
      workspace: git-credentials
    params:
    - name: url
      value: \$(params.repo-url)
  - name: show-readme # add task
    runAfter: ["fetch-source"]
    taskRef:
      name: show-readme
    workspaces:
    - name: source
      workspace: shared-data
EOF

pipeline.tekton.dev/my-clone-read created

# 확인
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  tkn pipeline list
NAME            AGE              LAST RUN               STARTED          DURATION   STATUS
clone-read      1 hour ago       clone-read-run-fk5fb   51 minutes ago   19s        Succeeded

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  tkn pipeline describe
? Select pipeline:  [Use arrows to move, type to filter]
> clone-read
  my-clone-read
																			  .
																			  .
																			  .

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  kubectl get pipeline -o wide
NAME            AGE
clone-read      62m
my-clone-read   2m18s

#
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  kubectl get pod
NAME                                    READY   STATUS      RESTARTS        AGE
clone-read-run-fk5fb-fetch-source-pod   0/1     Completed   0               53m
pacman-576769bb86-t5scc                 1/1     Running     2 (3h54m ago)   24h
 
# show-readme task
cat << EOF | kubectl apply -f -
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: show-readme
spec:
  description: Read and display README file.
  workspaces:
  - name: source
  steps:
  - name: read
    image: alpine:latest
    script: | 
      #!/usr/bin/env sh
      cat \$(workspaces.source.path)/readme.md
EOF

# 파이프라인 실행
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  cat << EOF | kubectl create -f -
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: clone-read-run-
spec:
  pipelineRef:
    name: my-clone-read
  taskRunTemplate:
    serviceAccountName: build-bot
    podTemplate:
      securityContext:
        fsGroup: 65532
  workspaces:
  - name: shared-data
    volumeClaimTemplate:
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 1Gi
  - name: git-credentials
    secret:
      secretName: git-credentials
  params:
  - name: repo-url
    value: git@github.com:gasida/my-sample-app.git # 제가 사용하는 것 or 자신의 private repo 지정
EOF

pipelinerun.tekton.dev/clone-read-run-cm7fg created


# 결과 확인 : 둘중에 한개는 실패함 ????
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  kubectl get pod,pv,pvc
NAME                                        READY   STATUS      RESTARTS        AGE
pod/clone-read-run-cm7fg-fetch-source-pod   0/1     Error       0               19s
pod/clone-read-run-fk5fb-fetch-source-pod   0/1     Completed   0               55m
pod/pacman-576769bb86-t5scc                 1/1     Running     2 (3h56m ago)   24h

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-b5399cd4-c602-4fe4-9424-ee3ea6e76cac   1Gi        RWO            Delete           Bound    default/pvc-fcf9b36883   standard       <unset>                          55m
persistentvolume/pvc-bdd52583-7010-4db6-8f82-219133ee1988   1Gi        RWO            Delete           Bound    default/pvc-964ade2b5e   standard       <unset>                          16s

NAME                                   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/pvc-964ade2b5e   Bound    pvc-bdd52583-7010-4db6-8f82-219133ee1988   1Gi        RWO            standard       <unset>                 19s
persistentvolumeclaim/pvc-fcf9b36883   Bound    pvc-b5399cd4-c602-4fe4-9424-ee3ea6e76cac   1Gi        RWO            standard       <unset>

# task를 실행하는 파드에 Serivce accout 정보 확인
minji  ~/Desktop/work/Gasida_series/practice/my-sample-app   main  kubectl describe pod | grep 'Service Account'
Service Account:  build-bot
Service Account:  default
Service Account:  default

# 삭제
kubectl delete taskruns,pipelineruns.tekton.dev --all

 

 

 

+ Recent posts