HELM K8S 패키지 관리
charts를 사용한다.
charts는 k8s yaml 파일을 템플릿으로 만들고 메타정보 파일을 압축한 파일

Helm charts의 경우 기본적으로 artifacthub 에서 찾아서 설치 (https://artifacthub.io/)
출처: https://www.youtube.com/watch?v=ajcyC_6velc

출처 : https://www.youtube.com/watch?v=m7iZtjeIHJw
관리해야하는 매니페스트가 많아지고 → 많아질수록 유지보수가 힘듦
하나의 template을 통해 동적으로 생성하게 해주는 tool 이 필요하다.

출처 : https://www.youtube.com/watch?v=m7iZtjeIHJw
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

(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# cat Chart.yaml
apiVersion: v2
name: pacman
description: A Helm chart for Pacman
type: application
version: 0.1.0 # 차트 버전, 차트 정의가 바뀌면 업데이트한다
appVersion: "1.0.0" # 애플리케이션 버전
| 항목 | 의미 |
|---|---|
| apiVersion: v2 | Helm 차트 스펙 버전. Helm 3 이상에서 사용 |
| name: pacman | 차트 이름 |
| description | 차트 설명 |
| type: application | 앱 배포용 차트임을 의미 |
| version: 0.1.0 | Helm 차트 자체의 버전 |
| appVersion: "1.0.0" | 실제 Pacman 애플리케이션 버전 |
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# cat values.yaml
image: # image 절 정의
repository: quay.io/gitops-cookbook/pacman-kikd
tag: "1.0.0"
pullPolicy: Always
containerPort: 8080
replicaCount: 1
securityContext: {} # securityContext 속성의 값을 비운다
| 키 | 설명 |
|---|---|
| image.repository | 사용할 컨테이너 이미지 경로 |
| image.tag | 이미지 버전 |
| image.pullPolicy | 이미지를 언제 새로 받아올지 |
| image.containerPort | 컨테이너 내부에서 열리는 포트 |
| replicaCount | 배포 시 파드 복제 개수 |
| securityContext | Pod의 보안 컨텍스트 |
# 헬름 차트 디렉터리 레이아웃 생성
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 이름, 컨테이너 포트
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 vales 이 담긴 파일 작성 : 애플리케이션 배포 시점에 다른 값으로 대체될 수 있는, 기본 설정을 담아두는 곳
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
# 디렉터리 레이아웃 확인
**tree**
├── Chart.yaml # 차트를 설명하며, 차트 관련 메타데이터를 포함
├── templates # 차트 설치에 사용되는 모든 템플릿 파일
│ ├── deployment.yaml # 애플리케이션 배포에 사용되는 헬름 템플릿 파일들
│ └── service.yaml
└── values.yaml # 차트 기본값
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/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
**helm template --set replicaCount=3 .**
spec:
replicas: 3 # 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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm install pacman .
NAME: pacman
LAST DEPLOYED: Mon Oct 20 00:15:50 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
pacman default 1 2025-10-20 00:15:50.938977487 +0900 KST deployed pacman-0.1.0 1.0.0
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get pod
NAME READY STATUS RESTARTS AGE
pacman-576769bb86-vbm9x 1/1 Running 0 2m4s
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm upgrade pacman --reuse-values --set replicaCount=2 .
Release "pacman" has been upgraded. Happy Helming!
NAME: pacman
LAST DEPLOYED: Mon Oct 20 00:18:17 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get pod
NAME READY STATUS RESTARTS AGE
pacman-576769bb86-ks4wn 0/1 ContainerCreating 0 4s
pacman-576769bb86-vbm9x 1/1 Running 0 2m30s
| 부분 | 의미 |
|---|---|
helm upgrade | 기존에 설치된 Helm 릴리스를 업그레이드 (재배포) |
pacman | 업그레이드할 릴리스(배포 인스턴스)의 이름 |
. | 현재 디렉터리(Chart.yaml과 values.yaml이 있는 곳)를 차트 소스로 사용 |
--reuse-values | 이전에 사용했던 values 설정을 그대로 유지 |
--set replicaCount=2 | 단일 값만 덮어쓰기(override) — replicas를 1 → 2로 변경 |
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm get all pacman
NAME: pacman
LAST DEPLOYED: Mon Oct 20 00:18:17 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
CHART: pacman
VERSION: 0.1.0
APP_VERSION: 1.0.0
TEST SUITE: None
USER-SUPPLIED VALUES:
replicaCount: 2
COMPUTED VALUES:
image:
containerPort: 8080
pullPolicy: Always
repository: quay.io/gitops-cookbook/pacman-kikd
tag: 1.0.0
replicaCount: 2
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: 2 # 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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm get values pacman
USER-SUPPLIED VALUES:
replicaCount: 2
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/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: 2 # 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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm get notes pacman
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm uninstall pacman
release "pacman" uninstalled
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get secret
No resources found in default namespace.
재사용 가능한 코드 블록을 정의하려면 _helpers.tpl 사용하면 된다.
템플릿 함수를 정의하는 파일명으로는 _helpers.tpl 을 사용하는 것이 일반적이지만, 사실 _로 시작하기만 하면 된다.
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# tree
.
├── Chart.yaml
├── templates
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
{{- define "pacman.selectorLabels" -}} # stetement 이름을 정의
app.kubernetes.io/name: {{ .Chart.Name}} # 해당 stetement 가 하는 일을 정의
{{- end }}
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:
{{- include "pacman.selectorLabels" . | nindent 6 }}
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 }}
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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/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:
# stetement 이름을 정의
app.kubernetes.io/name: pacman # 해당 stetement 가 하는 일을 정의
---
# 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
selector:
matchLabels:
# stetement 이름을 정의
app.kubernetes.io/name: pacman # 해당 stetement 가 하는 일을 정의 # pacman.selectorLabels를 호출한 결과를 6만큼 들여쓰기하여 주입
template:
metadata:
labels:
# stetement 이름을 정의
app.kubernetes.io/name: pacman # 해당 stetement 가 하는 일을 정의 # 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: TC
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm install pacman .
NAME: pacman
LAST DEPLOYED: Mon Oct 20 00:46:16 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm history pacman
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Mon Oct 20 00:46:16 2025 deployed pacman-0.1.0 1.0.0 Install complete
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
pacman 1/1 1 1 20s pacman quay.io/gitops-cookbook/pacman-kikd:1.0.0 app.kubernetes.io/name=pacman
# values.yaml 에 이미지 태그 업데이트
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 필드 갱신
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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm upgrade pacman .
Release "pacman" has been upgraded. Happy Helming!
NAME: pacman
LAST DEPLOYED: Mon Oct 20 00:48:00 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm history pacman
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Mon Oct 20 00:46:16 2025 superseded pacman-0.1.0 1.0.0 Install complete
2 Mon Oct 20 00:48:00 2025 deployed pacman-0.1.0 1.1.0 Upgrade complete
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get secret
NAME TYPE DATA AGE
sh.helm.release.v1.pacman.v1 helm.sh/release.v1 1 2m22s
sh.helm.release.v1.pacman.v2 helm.sh/release.v1 1 38s
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get deploy,replicaset -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/pacman 1/1 1 1 2m35s 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 2m35s 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 51s pacman quay.io/gitops-cookbook/pacman-kikd:1.1.0 app.kubernetes.io/name=pacman,pod-template-hash=64c54b85f9
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm history pacman
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Mon Oct 20 00:46:16 2025 superseded pacman-0.1.0 1.0.0 Install complete
2 Mon Oct 20 00:48:00 2025 deployed pacman-0.1.0 1.1.0 Upgrade complete
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm rollback pacman 1 && kubectl get pod -w
Rollback was a success! Happy Helming!
NAME READY STATUS RESTARTS AGE
pacman-576769bb86-lq669 0/1 ContainerCreating 0 0s
pacman-64c54b85f9-9mb5k 1/1 Running 0 97s
pacman-576769bb86-lq669 1/1 Running 0 2s
pacman-64c54b85f9-9mb5k 1/1 Terminating 0 99s
pacman-64c54b85f9-9mb5k 0/1 Error 0 100s
pacman-64c54b85f9-9mb5k 0/1 Error 0 100s
pacman-64c54b85f9-9mb5k 0/1 Error 0 100s
^C(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm history pacman
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Mon Oct 20 00:46:16 2025 superseded pacman-0.1.0 1.0.0 Install complete
2 Mon Oct 20 00:48:00 2025 superseded pacman-0.1.0 1.1.0 Upgrade complete
3 Mon Oct 20 00:49:37 2025 deployed pacman-0.1.0 1.0.0 Rollback to 1
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get secret
NAME TYPE DATA AGE
sh.helm.release.v1.pacman.v1 helm.sh/release.v1 1 3m57s
sh.helm.release.v1.pacman.v2 helm.sh/release.v1 1 2m13s
sh.helm.release.v1.pacman.v3 helm.sh/release.v1 1 36s
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get deploy,replicaset -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/pacman 1/1 1 1 4m10s 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 4m10s 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 2m26s pacman quay.io/gitops-cookbook/pacman-kikd:1.1.0 app.kubernetes.io/name=pacman,pod-template-hash=64c54b85f9
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman#
# values 새 파일 작성
cat << EOF > newvalues.yaml
image:
tag: "1.2.0"
EOF
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm template pacman -f newvalues.yaml . | grep image
- image: "quay.io/gitops-cookbook/pacman-kikd:1.2.0" # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
imagePullPolicy: Always
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm package .
Successfully packaged chart and saved it to: /home/suha/pacman/pacman-0.1.0.tgz
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# ls
Chart.yaml newvalues.yaml pacman-0.1.0.tgz templates values.yaml
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# zcat pacman-0.1.0.tgz
pacman/Chart.yaml0000644000000000000000000000016415075407062012437 0ustar0000000000000000apiVersion: v2
appVersion: 1.1.0
description: A Helm chart for Pacman
name: pacman
type: application
version: 0.1.0
pacman/values.yaml0000644000000000000000000000034015075407062012671 0ustar0000000000000000image: # image 절 정의
repository: quay.io/gitops-cookbook/pacman-kikd
tag: "1.1.0"
pullPolicy: Always
containerPort: 8080
replicaCount: 1
securityContext: {} # securityContext 속성의 값을 비운다
pacman/templates/_helpers.tpl0000644000000000000000000000024615075407062015033 0ustar0000000000000000{{- define "pacman.selectorLabels" -}} # stetement 이름을 정의
app.kubernetes.io/name: {{ .Chart.Name}} # 해당 stetement 가 하는 일을 정의
{{- end }}
pacman/templates/deployment.yaml0000644000000000000000000000267615075407062015566 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 }}
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.yaml0000644000000000000000000000050415075407062015032 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.yaml0000644000000000000000000000002615075407062013404 0ustar0000000000000000image:
tag: "1.2.0"
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm repo index .
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# cat index.yaml
apiVersion: v1
entries:
pacman:
- apiVersion: v2
appVersion: 1.1.0
created: "2025-10-20T19:27:52.033099902+09:00"
description: A Helm chart for Pacman
digest: 5b96f3e9aecccabc08d4d04d25fe5bdda9ed8e662ab6a5cccfda9c1035288cbd
name: pacman
type: application
urls:
- pacman-0.1.0.tgz
version: 0.1.0
generated: "2025-10-20T19:27:52.032770711+09:00"
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# tree
.
├── Chart.yaml
├── index.yaml
├── newvalues.yaml
├── pacman-0.1.0.tgz
├── templates
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
2 directories, 8 files
chart 저장소는 chart 및 .tgz 차트에 대한 메타데이터 정보를 담은 index.yaml 파일이 있는 HTTP 서버다.
helm repo는 Helm에서 사용되는 Helm Chart 저장소(Repository)를 관리하는 명령어.
서명 파일을 사용하여 차트가 임의로 수정되지 않은 올바른 차트인지 확인 할 수 있다.
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# sudo apt install gnupg
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
gnupg is already the newest version (2.4.4-2ubuntu17.3).
gnupg set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 108 not upgraded.
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# gpg --full-generate-key
gpg (GnuPG) 2.4.4; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: directory '/root/.gnupg' created
gpg: keybox '/root/.gnupg/pubring.kbx' created
Please select what kind of key you want:
(1) RSA and RSA
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(9) ECC (sign and encrypt) *default*
(10) ECC (sign only)
(14) Existing key from card
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072)
gpg: signal Interrupt caught ... exiting
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# gpg --full-generate-key
gpg (GnuPG) 2.4.4; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
(1) RSA and RSA
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(9) ECC (sign and encrypt) *default*
(10) ECC (sign only)
(14) Existing key from card
Your selection? 9
Please select which elliptic curve you want:
(1) Curve 25519 *default*
(4) NIST P-384
(6) Brainpool P-256
Your selection? 1
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: suha
Email address: hp980724@gmail.com
Comment: cicd-study
You selected this USER-ID:
"suha (cicd-study) <hp980724@gmail.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/EAD35F7026C2C95E96F8BE4F4044423E61017A62.rev'
public and secret key created and signed.
pub ed25519 2025-10-20 [SC]
EAD35F7026C2C95E96F8BE4F4044423E61017A62
uid suha (cicd-study) <hp980724@gmail.com>
sub cv25519 2025-10-20 [E]
설치 및 RSA 생성
gpg list keys
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# gpg --list-keys
/root/.gnupg/pubring.kbx
------------------------
pub ed25519 2025-10-20 [SC]
EAD35F7026C2C95E96F8BE4F4044423E61017A62
uid [ultimate] suha (cicd-study) <hp980724@gmail.com>
sub cv25519 2025-10-20 [E]
helm package --sign --key F035A1D797A8F00DB779BBA3B3B8B968F1CBB8B9 --keyring /root/.gnupg/pubring.kbx ./pacman
error
Error: openpgp: invalid data: tag byte does not have MSB set
자체 서명은 잘됨
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# gpg --armor --detach-sign ./pacman-0.1.0.tgz
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# ls
Chart.yaml index.yaml newvalues.yaml pacman-0.1.0.tgz pacman-0.1.0.tgz.asc templates values.yaml
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm repo add bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm repo list
NAME URL
bitnami https://charts.bitnami.com/bitnami
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm search repo postgresql
NAME CHART VERSION APP VERSION DESCRIPTION
bitnami/postgresql 18.0.17 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...
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm search repo postgresql -o json | jq
[
{
"name": "bitnami/postgresql",
"version": "18.0.17",
"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."
}
]
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
pacman default 3 2025-10-20 00:49:37.795103667 +0900 KST deployed pacman-0.1.0 1.0.0
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# 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: Mon Oct 20 21:03:50 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: postgresql
CHART VERSION: 18.0.17
APP VERSION: 18.0.0
⚠ WARNING: Since August 28th, 2025, only a limited subset of images/charts are available for free.
Subscribe to Bitnami Secure Images to receive continued support and security updates.
More info at https://bitnami.com and https://github.com/bitnami/containers/issues/83267
** Please be patient while the chart is being deployed **
PostgreSQL can be accessed via port 5432 on the following DNS names from within your cluster:
my-db-postgresql.default.svc.cluster.local - Read/Write connection
To get the password for "postgres" run:
export POSTGRES_PASSWORD=$(kubectl get secret --namespace default my-db-postgresql -o jsonpath="{.data.postgres-password}" | base64 -d)
To connect to your database run the following command:
kubectl run my-db-postgresql-client --rm --tty -i --restart='Never' --namespace default --image registry-1.docker.io/bitnami/postgresql:latest --env="PGPASSWORD=$POSTGRES_PASSWORD" \
--command -- psql --host my-db-postgresql -U postgres -d postgres -p 5432
> NOTE: If you access the container using bash, make sure that you execute "/opt/bitnami/scripts/postgresql/entrypoint.sh /bin/bash" in order to avoid the error "psql: local user with ID 1001} does not exist"
To connect to your database from outside the cluster execute the following commands:
kubectl port-forward --namespace default svc/my-db-postgresql 5432:5432 &
PGPASSWORD="$POSTGRES_PASSWORD" psql --host 127.0.0.1 -U postgres -d postgres -p 5432
WARNING: The configured password will be ignored on new installation in case when previous PostgreSQL release was deleted through the helm command. In that case, old PVC will have an old password, and setting it through helm won't take effect. Deleting persistent volumes (PVs) will solve the issue.
WARNING: Rolling tag detected (bitnami/postgresql:latest), please note that it is strongly recommended to avoid using rolling tags in a production environment.
+info https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html
WARNING: Rolling tag detected (bitnami/os-shell:latest), please note that it is strongly recommended to avoid using rolling tags in a production environment.
+info https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html
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/
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
my-db default 1 2025-10-20 21:03:50.50731746 +0900 KST deployed postgresql-18.0.17 18.0.0
pacman default 3 2025-10-20 00:49:37.795103667 +0900 KST deployed pacman-0.1.0 1.0.0
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get sts,pod,svc,ep,secret
NAME READY AGE
statefulset.apps/my-db-postgresql 1/1 52s
NAME READY STATUS RESTARTS AGE
pod/my-db-postgresql-0 1/1 Running 0 52s
pod/pacman-576769bb86-lq669 1/1 Running 1 (109m ago) 20h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d23h
service/my-db-postgresql ClusterIP 10.96.75.52 <none> 5432/TCP 52s
service/my-db-postgresql-hl ClusterIP None <none> 5432/TCP 52s
service/pacman ClusterIP 10.96.55.229 <none> 8080/TCP 20h
NAME ENDPOINTS AGE
endpoints/kubernetes 172.18.0.2:6443 4d23h
endpoints/my-db-postgresql 10.244.1.4:5432 52s
endpoints/my-db-postgresql-hl 10.244.1.4:5432 52s
endpoints/pacman 10.244.1.2:8080 20h
NAME TYPE DATA AGE
secret/my-db-postgresql Opaque 1 52s
secret/sh.helm.release.v1.my-db.v1 helm.sh/release.v1 1 52s
secret/sh.helm.release.v1.pacman.v1 helm.sh/release.v1 1 20h
secret/sh.helm.release.v1.pacman.v2 helm.sh/release.v1 1 20h
secret/sh.helm.release.v1.pacman.v3 helm.sh/release.v1 1 20h
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# helm uninstall my-db
release "my-db" uninstalled
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman# kubectl get sts,pod,svc,ep,secret
NAME READY STATUS RESTARTS AGE
pod/pacman-576769bb86-lq669 1/1 Running 1 (110m ago) 20h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d
service/pacman ClusterIP 10.96.55.229 <none> 8080/TCP 20h
NAME ENDPOINTS AGE
endpoints/kubernetes 172.18.0.2:6443 5d
endpoints/pacman 10.244.1.2:8080 20h
NAME TYPE DATA AGE
secret/sh.helm.release.v1.pacman.v1 helm.sh/release.v1 1 20h
secret/sh.helm.release.v1.pacman.v2 helm.sh/release.v1 1 20h
secret/sh.helm.release.v1.pacman.v3 helm.sh/release.v1 1 20h
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/pacman#
어떤 chart가 다른 chart를 의존하는 것을 선언하는 경우 chart.yaml 파일의 dependencies 섹션을 사용한다.
mkdir music
mkdir music/templates
cd 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
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
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
repository: "https://charts.bitnami.com/bitnami"***
EOF
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music/templates# helm search repo bitnami/postgresql --versions
NAME CHART VERSION APP VERSION DESCRIPTION
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-...
최신 버전 사용
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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# tree
.
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# tree
.
├── Chart.lock
├── Chart.yaml
├── charts
│ └── postgresql-18.0.17.tgz
├── templates
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
helm dependency update 명령어는 Helm 차트의 의존성(dependencies)을 자동으로 다운로드 및 갱신하는 기능
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# helm install music-db .
NAME: music-db
LAST DEPLOYED: Tue Oct 21 00:26:23 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# kubectl get sts,pod,svc,ep,secret,pv,pvc
NAME READY AGE
statefulset.apps/music-db-postgresql 1/1 3m21s
NAME READY STATUS RESTARTS AGE
pod/music-6c45d566f4-v58fk 0/1 CrashLoopBackOff 4 (20s ago) 3m21s
pod/music-db-postgresql-0 1/1 Running 0 3m21s
pod/pacman-576769bb86-lq669 1/1 Running 1 (169m ago) 21h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d
service/music ClusterIP 10.96.184.92 <none> 8080/TCP 3m21s
service/music-db-postgresql ClusterIP 10.96.168.136 <none> 5432/TCP 3m21s
service/music-db-postgresql-hl ClusterIP None <none> 5432/TCP 3m21s
service/pacman ClusterIP 10.96.55.229 <none> 8080/TCP 21h
NAME ENDPOINTS AGE
endpoints/kubernetes 172.18.0.2:6443 5d
endpoints/music 3m21s
endpoints/music-db-postgresql 10.244.1.7:5432 3m21s
endpoints/music-db-postgresql-hl 10.244.1.7:5432 3m21s
endpoints/pacman 10.244.1.2:8080 21h
NAME TYPE DATA AGE
secret/music-db-postgresql Opaque 1 3m21s
secret/sh.helm.release.v1.music-db.v1 helm.sh/release.v1 1 3m21s
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
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
persistentvolume/pvc-4fe9328a-23ea-4a2f-a069-c7c762a32308 8Gi RWO Delete Bound default/data-my-db-postgresql-0 standard <unset> 60m
persistentvolume/pvc-cdc45d2b-45f7-49bb-a519-de539198f069 8Gi RWO Delete Bound default/data-music-db-postgresql-0 standard <unset> 3m18s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
persistentvolumeclaim/data-music-db-postgresql-0 Bound pvc-cdc45d2b-45f7-49bb-a519-de539198f069 8Gi RWO standard <unset> 3m21s
persistentvolumeclaim/data-my-db-postgresql-0 Bound pvc-4fe9328a-23ea-4a2f-a069-c7c762a32308 8Gi RWO standard <unset> 60m
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# kubectl get pods
NAME READY STATUS RESTARTS AGE
music-6c45d566f4-v44bl 0/1 CreateContainerConfigError 0 113s
music-db-postgresql-0 1/1 Running 0 113s
pacman-576769bb86-lq669 1/1 Running 1 (5h13m ago) 23h
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# kubectl describe pod music-6c45d566f4-v44bl
Name: music-6c45d566f4-v44bl
Namespace: default
Priority: 0
Service Account: default
Node: myk8s-worker/172.18.0.3
Start Time: Tue, 21 Oct 2025 00:26:24 +0900
Labels: app.kubernetes.io/name=music
pod-template-hash=6c45d566f4
Annotations: <none>
Status: Pending
IP: 10.244.1.22
IPs:
IP: 10.244.1.22
Controlled By: ReplicaSet/music-6c45d566f4
Containers:
music:
Container ID:
Image: quay.io/gitops-cookbook/music:1.0.0
Image ID:
Port: 8080/TCP (http)
Host Port: 0/TCP (http)
State: Waiting
Reason: CreateContainerConfigError
Ready: False
Restart Count: 0
Environment:
QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://music-db-postgresql:5432/mydb
QUARKUS_DATASOURCE_USERNAME: my-default
QUARKUS_DATASOURCE_PASSWORD: <set to the key 'postgresql-password' in secret 'music-db-postgresql'> Optional: false
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7rtj6 (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
kube-api-access-7rtj6:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
Optional: false
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 118s default-scheduler Successfully assigned default/music-6c45d566f4-v44bl to myk8s-worker
Normal Pulled 117s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 828ms (828ms including waiting). Image size: 94836428 bytes.
Normal Pulled 115s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 954ms (954ms including waiting). Image size: 94836428 bytes.
Normal Pulled 101s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 4.518s (4.518s including waiting). Image size: 94836428 bytes.
Normal Pulled 87s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 787ms (787ms including waiting). Image size: 94836428 bytes.
Normal Pulled 75s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 2.06s (2.06s including waiting). Image size: 94836428 bytes.
Normal Pulled 58s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 3.694s (3.694s including waiting). Image size: 94836428 bytes.
Normal Pulled 43s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 1.014s (1.014s including waiting). Image size: 94836428 bytes.
Normal Pulled 30s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 1.993s (1.993s including waiting). Image size: 94836428 bytes.
Normal Pulled 16s kubelet Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 878ms (878ms including waiting). Image size: 94836428 bytes.
Warning Failed 4s (x10 over 117s) kubelet Error: couldn't find key postgresql-password in Secret default/music-db-postgresql
Normal Pulling 4s (x10 over 118s) kubelet Pulling image "quay.io/gitops-cookbook/music:1.0.0"
Normal Pulled 4s kubelet (combined from similar events): Successfully pulled image "quay.io/gitops-cookbook/music:1.0.0" in 736ms (736ms including waiting). Image size: 94836428 bytes.
Warning Failed 4s (x10 over 117s) kubelet Error: couldn't find key postgresql-password in Secret default/music-db-postgresql
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# kubectl get secrets
NAME TYPE DATA AGE
music-db-postgresql Opaque 1 4m20s
sh.helm.release.v1.music-db.v1 helm.sh/release.v1 1 4m20s
sh.helm.release.v1.pacman.v1 helm.sh/release.v1 1 23h
sh.helm.release.v1.pacman.v2 helm.sh/release.v1 1 23h
sh.helm.release.v1.pacman.v3 helm.sh/release.v1 1 23h
**kubectl edit secret music-db-postgresql**
postgresql-password: cG9zdGdyZXMK
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# kubectl describe secrets music-db-postgresql
Name: music-db-postgresql
Namespace: default
Labels: app.kubernetes.io/instance=music-db
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=postgresql
app.kubernetes.io/version=18.0.0
helm.sh/chart=postgresql-18.0.17
Annotations: meta.helm.sh/release-name: music-db
meta.helm.sh/release-namespace: default
Type: Opaque
Data
====
postgresql-password: 9 bytes
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/music# kubectl get secret music-db-postgresql -o jsonpath="{.data.postgresql-password}" | base64 -d
postgres
kubectl rollout restart deployment music
2025-10-21 15:19:51,229 WARN [io.agr.pool] (agroal-11) Datasource '<default>': FATAL: password authentication failed for user "my-default"
2025-10-21 15:19:51,263 WARN [org.hib.eng.jdb.env.int.JdbcEnvironmentInitiator] (JPA Startup Thread: <default>) HHH000342: Could not obtain connection to query metadata: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "my-default"
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:623)
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:163)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:215)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:51)
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:225)
at org.postgresql.Driver.makeConnection(Driver.java:466)
at org.postgresql.Driver.connect(Driver.java:265)
at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:210)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:513)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:494)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
2025-10-21 15:19:51,681 WARN [io.agr.pool] (agroal-11) Datasource '<default>': FATAL: password authentication failed for user "my-default"
2025-10-21 15:19:51,682 WARN [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: <default>) SQL Error: 0, SQLState: 28P01
2025-10-21 15:19:51,683 ERROR [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: <default>) FATAL: password authentication failed for user "my-default"
2025-10-21 15:19:51,871 ERROR [io.qua.run.Application] (main) Failed to start application (with profile prod): org.postgresql.util.PSQLException: FATAL: password authentication failed for user "my-default"
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:623)
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:163)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:215)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:51)
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:225)
at org.postgresql.Driver.makeConnection(Driver.java:466)
at org.postgresql.Driver.connect(Driver.java:265)
at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:210)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:513)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:494)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings# tree
.
├── Chart.yaml
├── templates
│ ├── configMap.yaml
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
2 directories, 5 files
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings/templates# cat 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}}
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings/templates# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/versions: {{ .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: GREETING
valueFrom:
configMapKeyRef:
name: {{ .Values.configmap.name }}
key: greeting # "greetin" -> "greeting"
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings/templates# cat configMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: greeting-config
data:
greeting: Aloha
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings# cat Chart.yaml
apiVersion: v1
name: greetings
description: A Helm chart for Greetings
type: application
version: 0.1.0 # 차트 버전, 차트 정의가 바뀌면 업데이트한다
appVersion: "1.0.0" # 애플리케이션 버전
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings# helm install greetings .
NAME: greetings
LAST DEPLOYED: Tue Oct 21 22:25:26 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings# kubectl port-forward service/greetings 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Handling connection for 8080
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings/templates# cat configMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: greeting-config
data:
greeting: Hola
helm upgrade greetings .
Aloha Alexandra(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings/templates# curl localhost:8080
sha256sum을 이용해서 configMap.yaml 파일콘텐츠의 SHA-256 값 계산하고 pod annotation으로 설정하면 configMap의 내용이 바뀔때마다 pod 정의도 바뀌면서 rolling update 자동으로 됨
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/versions: {{ .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 }}
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} # .Files.Get을 사용하여 템플릿 파일을 가져오기
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: GREETING
valueFrom:
configMapKeyRef:
name: {{ .Values.configmap.name }}
key: greeting # "greetin" -> "greeting"
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings/templates# cat configMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: greeting-config
data:
greeting: Namaste
helm upgrade greetings .
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings# curl localhost:8080
Namastee Ada(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings# curl localhost:8080
Namastee Alexandra(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings# curl localhost:8080
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/greetings# kubectl describe pod greetings-c85547b5-bnx8r
Name: greetings-c85547b5-bnx8r
Namespace: default
Priority: 0
Service Account: default
Node: myk8s-worker/172.18.0.2
Start Time: Tue, 21 Oct 2025 23:13:49 +0900
Labels: app.kubernetes.io/name=greetings
pod-template-hash=c85547b5
Annotations: checksum/config: 840f32730bba68080f033d5c1cff7fc0854e0c7da35f3675292029ca76bf87ee
Status: Running
IP: 10.244.1.13
IPs:
IP: 10.244.1.13
Controlled By: ReplicaSet/greetings-c85547b5
Containers:
greetings:
Container ID: containerd://58acc16679414b82fc3a4bc45c1024d44a70a3a0af47501c1103f45fb43ee269
Image: quay.io/gitops-cookbook/greetings:1.0.0
Image ID: quay.io/gitops-cookbook/greetings@sha256:e76247a12671afd2540af4dd59368a5188983a92d77c52b22762d76c34eb52ab
Port: 8080/TCP (http)
Host Port: 0/TCP (http)
State: Running
Started: Tue, 21 Oct 2025 23:13:50 +0900
Ready: True
Restart Count: 0
Environment:
GREETING: <set to the key 'greeting' of config map 'greeting-config'> Optional: false
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8mxft (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-8mxft:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
Optional: false
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 61s default-scheduler Successfully assigned default/greetings-c85547b5-bnx8r to myk8s-worker
Normal Pulling 61s kubelet Pulling image "quay.io/gitops-cookbook/greetings:1.0.0"
Normal Pulled 60s kubelet Successfully pulled image "quay.io/gitops-cookbook/greetings:1.0.0" in 807ms (807ms including waiting). Image size: 349721197 bytes.
Normal Created 60s kubelet Created container: greetings
Normal Started 60s kubelet Started container greetings

쿠버네티스 기반 오픈 소스 클라우드 네이티비 CI/CD 시스템

출처 : https://nangman14.tistory.com/85
| 구성요소 | 설명 |
|---|---|
| Task | 하나의 작업 단위 (예: 빌드, 테스트, 배포). 여러 Step으로 구성됨. |
| 쿠버네티스 관점에서 pod로 실행된다. | |
| Step | 컨테이너 하나에서 실행되는 실제 명령 또는 스크립트 단위. |
| 쿠버네티스 관점에서 컨테이너 이미지로 동작한다. | |
| Pipeline | 여러 Task를 순서대로 또는 병렬로 실행하는 흐름 정의. Task들의 데이터 공유 설정 가능 |
| 쿠버네티스 관점에서 실행에 필요한 pod를 생성하고 순서대로 실행되도록 보장한 | |
| PipelineRun | 정의된 Pipeline을 실제로 실행하는 객체. |
| TaskRun | 특정 Task의 실행 인스턴스. |
| Workspace | Task 간에 공유되는 볼륨 (예: 소스코드, 빌드 산출물). |
Pipeline, Task, Step, PipelineRun, TaskRun 등의 리소스로 구성되어 있습니다.kubectl apply -f https://storage.googleapis.com/tekton-releases/**pipeline/latest**/release.yaml
# **Tekton Trigger 설치 :** 현재 v0.33.0
kubectl apply -f https://storage.googleapis.com/tekton-releases/**triggers**/latest/release.yaml
kubectl apply -f https://storage.googleapis.com/tekton-releases/**triggers**/latest/interceptors.yaml
**# Tekton Dashboard 설치 :** 현재 v0.62.0
kubectl apply -f https://storage.googleapis.com/tekton-releases/**dashboard**/latest/release.yaml
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:~# kubectl patch svc -n tekton-pipelines tekton-dashboard -p '{"spec":{"type":"NodePort","ports":[{"port":9097,"targetPort":9097,"nodePort":30000}]}}'
service/tekton-dashboard patched
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:~# kubectl get svc,ep -n tekton-pipelines tekton-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/tekton-dashboard NodePort 10.96.81.64 <none> 9097:30000/TCP 31s
NAME ENDPOINTS AGE
endpoints/tekton-dashboard 10.244.1.12:9097 31s
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:~#

# Windows WSL - Ubuntu Linux 경우
sudo apt update;sudo apt install -y gnupg
sudo mkdir -p /etc/apt/keyrings/
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/tektoncd.gpg --keyserver keyserver.ubuntu.com --recv-keys 3EFE0E0A2F2F60AA
echo "deb [signed-by=/etc/apt/keyrings/tektoncd.gpg] http://ppa.launchpad.net/tektoncd/cli/ubuntu eoan main"|sudo tee /etc/apt/sources.list.d/tektoncd-ubuntu-cli.list
sudo apt update && sudo apt install -y tektoncd-cli
**tkn version
...**
해당 페이지 참조해서 설치 진행

출처 : https://tekton.dev/docs/concepts/concept-model/
# task 생성
**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
# 확인
kubectl get tasks

확인
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# kubectl logs -l tekton.dev/task=hello -c step-echo
Hello World
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# tkn task logs hello
Hello World
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# tkn task describe hello
Name: hello
Namespace: default
🦶 Steps
∙ echo
🗂 Taskruns
NAME STARTED DURATION STATUS
hello-run-cs4bj 2 minutes ago 21s Succeeded
# task 생성
**cat << EOF | kubectl apply -f -**
apiVersion: tekton.dev/**v1**
kind: **Task**
metadata:
name: **two-step**
spec:
**steps:**
- name: **echo1**
image: alpine
script: |
#!/bin/sh
echo "Hello World 11111"
- name: **echo2**
image: alpine
script: |
#!/bin/sh
echo "Hello World 22222"
EOF
# taskrun
**tkn task start --showlog two-step**
two-step-run-jvnvd-pod 0/2 Pending 0 0s
two-step-run-jvnvd-pod 0/2 Pending 0 0s
two-step-run-jvnvd-pod 0/2 Init:0/2 0 0s
two-step-run-jvnvd-pod 0/2 Init:0/2 0 1s
two-step-run-jvnvd-pod 0/2 Init:1/2 0 2s
two-step-run-jvnvd-pod 0/2 PodInitializing 0 3s
two-step-run-jvnvd-pod 2/2 Running 0 7s
two-step-run-jvnvd-pod 2/2 Running 0 7s
two-step-run-jvnvd-pod 0/2 Completed 0 10s
two-step-run-jvnvd-pod 0/2 Completed 0 11s
1개의 pod에 2개의 실행 컨테이너 확인
Tekton Pipelines를 사용하여 git에서 소스 코드를 복제 : Git 저장소에서 소스 코드를 복제하는 작업
⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# 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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# tkn pipeline list
NAME AGE LAST RUN STARTED DURATION STATUS
clone-read 30 seconds ago --- --- --- ---
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# 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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# kubectl get pipeline
NAME AGE
clone-read 40s
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# 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
pipelinerun.tekton.dev/clone-read-run-9rrtg created
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# kubectl get pipelineruns
NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
clone-read-run-9rrtg False CouldntGetTask 7s 7s
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# tkn pipelinerun list
NAME STARTED DURATION STATUS
clone-read-run-9rrtg 13 seconds ago 0s Failed(CouldntGetTask)
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# tkn hub install task git-clone
WARN: This version has been deprecated
Task git-clone(0.9) installed in default namespace
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# kubectl get tasks
NAME AGE
git-clone 7s
hello 91m
two-step 15m
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# 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-pkb66 created
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# tkn pipelinerun list
NAME STARTED DURATION STATUS
clone-read-run-pkb66 7 seconds ago --- Running
clone-read-run-9rrtg 57 seconds ago 0s Failed(CouldntGetTask)
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# tkn pipelinerun logs
? Select pipelinerun: clone-read-run-pkb66 started 13 seconds ago
Pipeline still running ...
[fetch-source : clone] + '[' false '=' true ]
[fetch-source : clone] + '[' false '=' true ]
[fetch-source : clone] + '[' false '=' true ]
[fetch-source : clone] + CHECKOUT_DIR=/workspace/output/
[fetch-source : clone] + '[' true '=' true ]
[fetch-source : clone] + cleandir
[fetch-source : clone] + '[' -d /workspace/output/ ]
[fetch-source : clone] + rm -rf '/workspace/output//*'
[fetch-source : clone] + rm -rf '/workspace/output//.[!.]*'
[fetch-source : clone] + rm -rf '/workspace/output//..?*'
[fetch-source : clone] + test -z
[fetch-source : clone] + test -z
[fetch-source : clone] + test -z
[fetch-source : clone] + git config --global --add safe.directory /workspace/output
[fetch-source : clone] + /ko-app/git-init '-url=https://github.com/tektoncd/website' '-revision=' '-refspec=' '-path=/workspace/output/' '-sslVerify=true' '-submodules=true' '-depth=1' '-sparseCheckoutDirectories='
[fetch-source : clone] {"level":"info","ts":1761232233.046652,"caller":"git/git.go:176","msg":"Successfully cloned https://github.com/tektoncd/website @ e6d8959b05b8bbd4aa798b28153b25c0f8766dc7 (grafted, HEAD) in path /workspace/output/"}
[fetch-source : clone] {"level":"info","ts":1761232233.0987167,"caller":"git/git.go:215","msg":"Successfully initialized and updated submodules in path /workspace/output/"}
[fetch-source : clone] + cd /workspace/output/
[fetch-source : clone] + git rev-parse HEAD
[fetch-source : clone] + RESULT_SHA=e6d8959b05b8bbd4aa798b28153b25c0f8766dc7
[fetch-source : clone] + EXIT_CODE=0
[fetch-source : clone] + '[' 0 '!=' 0 ]
[fetch-source : clone] + git log -1 '--pretty=%ct'
[fetch-source : clone] + RESULT_COMMITTER_DATE=1760686100
[fetch-source : clone] + printf '%s' 1760686100
[fetch-source : clone] + printf '%s' e6d8959b05b8bbd4aa798b28153b25c0f8766dc7
[fetch-source : clone] + printf '%s' https://github.com/tektoncd/website
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/usr/bin# kubectl get pod,pv,pvc
NAME READY STATUS RESTARTS AGE
pod/clone-read-run-pkb66-fetch-source-pod 0/1 Completed 0 37s
pod/music-7c495495bf-qfdpn 0/1 CrashLoopBackOff 45 (38s ago) 2d
pod/music-db-postgresql-0 0/1 CrashLoopBackOff 37 (83s ago) 2d
pod/pacman-576769bb86-lq669 1/1 Running 6 (115m ago) 3d23h
pod/two-step-run-jvnvd-pod 0/2 Completed 0 16m
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
persistentvolume/pvc-4fe9328a-23ea-4a2f-a069-c7c762a32308 8Gi RWO Delete Bound default/data-my-db-postgresql-0 standard <unset> 3d3h
persistentvolume/pvc-74d9ecdf-a900-4748-ae2b-39032c0714e7 8Gi RWO Delete Bound default/data-music-postgresql-0 standard <unset> 2d23h
persistentvolume/pvc-cdc45d2b-45f7-49bb-a519-de539198f069 8Gi RWO Delete Bound default/data-music-db-postgresql-0 standard <unset> 3d2h
persistentvolume/pvc-d831c42c-392a-4bf6-beef-9442947f2c1e 1Gi RWO Delete Bound default/pvc-a4c5537716 standard <unset> 32s
NAME


echo "# my-sample-app" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/hp0724/my-sample-app.git
git push -u origin main


(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# SSHKH=$(ssh-keyscan github.com | grep ecdsa-sha2-nistp256 | base64 -w0)
# github.com:22 SSH-2.0-85ba476
# github.com:22 SSH-2.0-85ba476
# github.com:22 SSH-2.0-85ba476
# github.com:22 SSH-2.0-85ba476
# github.com:22 SSH-2.0-85ba476
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# kubectl get secrets
NAME TYPE DATA AGE
git-credentials Opaque 0 15h
music-db-postgresql Opaque 1 3d10h
sh.helm.release.v1.music-db.v1 helm.sh/release.v1 1 3d10h
sh.helm.release.v1.pacman.v1 helm.sh/release.v1 1 5d10h
sh.helm.release.v1.pacman.v2 helm.sh/release.v1 1 5d10h
sh.helm.release.v1.pacman.v3 helm.sh/release.v1 1 5d10h
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: git-credentials
data:
id_rsa: $SSHPK
known_hosts: $SSHKH
EOF
secret/git-credentials configured
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-bot
secrets:
- name: git-credentials
EOF
serviceaccount/build-bot unchanged
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# 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
EOF workspace: shared-data"]sk
pipeline.tekton.dev/my-clone-read configured
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# tkn pipeline list
NAME AGE LAST RUN STARTED DURATION STATUS
clone-read 1 day ago --- --- --- ---
my-clone-read 15 hours ago clone-read-run-cq5jq 15 hours ago 10s Failed
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha#
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha#
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha#
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# tkn pipeline describe
? Select pipeline: clone-read
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
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# kubectl get pipeline
NAME AGE
clone-read 34h
my-clone-read 15h
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# ssh -i ~/.ssh/id_ed25519 -T git@github.com
Hi hp0724! You've successfully authenticated, but GitHub does not provide shell access.
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# ls
chapters get-docker.sh hello.sh music node-js-sample-app pacman-0.1.0.tgz
docker-compose.yaml greetings kube-ps1 my-sample-app pacman tkn
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha# cd my-sample-app/
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# ls
app.js readme.md
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# git branch
* main
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# SSHPK=$(cat ~/.ssh/id_ed25519 | base64 -w0)
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# ssh-keygen -t ed25519 -C "^C
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# ls -l ~/.ssh | grep ed25519
-rw------- 1 root root 411 Oct 24 19:37 id_ed25519
-rw-r--r-- 1 root root 100 Oct 24 19:37 id_ed25519.pub
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# eval "$(ssh-agent -s)"
Agent pid 8721
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# ssh-add ~/.ssh/id_ed25519
Identity added: /root/.ssh/id_ed25519 (hp980724@gmail.com)
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# ssh -i ~/.ssh/id_ed25519 -T git@github.com
Hi hp0724! You've successfully authenticated, but GitHub does not provide shell access.
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# SSHPK=$(cat ~/.ssh/id_ed25519 | base64 -w0)
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app#
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# SSHPK=$(cat ~/.ssh/id_ed25519 | base64 -w0)
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# cat ~/.ssh/known_hosts | grep github
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# SSHKH=$(ssh-keyscan github.com | grep ecdsa-sha2-nistp256 | base64 -w0)
# github.com:22 SSH-2.0-85ba476
# github.com:22 SSH-2.0-85ba476
# github.com:22 SSH-2.0-85ba476
# github.com:22 SSH-2.0-85ba476
# github.com:22 SSH-2.0-85ba476
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# echo $SSHKH
Z2l0aHViLmNvbSBlY2RzYS1zaGEyLW5pc3RwMjU2IEFBQUFFMlZqWkhOaExYTm9ZVEl0Ym1semRIQXlOVFlBQUFBSWJtbHpkSEF5TlRZQUFBQkJCRW1LU0VOalFFZXpPbXhrWk15N29wS2d3RkI5bmt0NVlScllNak51RzVOODd1UmdnNkNMcmJvNXdBZFQveTZ2MG1LVjBVMncwV1oyWUIvKytUcG9ja2c9Cg==
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# kubectl get sa
NAME SECRETS AGE
build-bot 1 15h
default 0 9d
music-db-postgresql 0 3d11h
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-bot
secrets:
- name: git-credentials
EOF
serviceaccount/build-bot unchanged
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# kubectl get sa
NAME SECRETS AGE
build-bot 1 15h
default 0 9d
music-db-postgresql 0 3d11h
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# 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
EOF workspace: shared-data"]sk
pipeline.tekton.dev/my-clone-read configured
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# 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
task.tekton.dev/show-readme configured
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# 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:hp0724/my-sample-app.git # 제가 사용하는 것 or 자신의 private repo 지정
EOF
pipelinerun.tekton.dev/clone-read-run-fljlt created
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# kubectl get pod,pv,pvc
NAME READY STATUS RESTARTS AGE
pod/affinity-assistant-e3ce80ce97-0 0/1 ContainerCreating 0 5s
pod/clone-read-run-cq5jq-fetch-source-pod 0/1 Error 0 15h
pod/clone-read-run-fljlt-fetch-source-pod 0/1 Init:0/2 0 5s
pod/clone-read-run-kpcd6-fetch-source-pod 0/1 Error 0 15h
pod/music-7c495495bf-qfdpn 0/1 CrashLoopBackOff 68 (2m11s ago) 3d11h
pod/music-db-postgresql-0 0/1 CrashLoopBackOff 60 (2m2s ago) 3d11h
pod/pacman-576769bb86-lq669 1/1 Running 8 (19m ago) 5d10h
pod/two-step-run-jvnvd-pod 0/2 Completed 0 35h
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
persistentvolume/pvc-2129fdec-ebfe-48fc-a167-f32e59db49f2 1Gi RWO Delete Bound default/pvc-77e7882074 standard <unset> 15h
persistentvolume/pvc-4fe9328a-23ea-4a2f-a069-c7c762a32308 8Gi RWO Delete Bound default/data-my-db-postgresql-0 standard <unset> 4d14h
persistentvolume/pvc-74d9ecdf-a900-4748-ae2b-39032c0714e7 8Gi RWO Delete Bound default/data-music-postgresql-0 standard <unset> 4d10h
persistentvolume/pvc-7934fd60-0a97-4fd9-964a-9dd2226bf102 1Gi RWO Delete Bound default/pvc-3d83f4ae8a standard <unset> 2s
persistentvolume/pvc-cdc45d2b-45f7-49bb-a519-de539198f069 8Gi RWO Delete Bound default/data-music-db-postgresql-0 standard <unset> 4d13h
persistentvolume/pvc-e3763428-6c8b-4534-ad6e-7dd5b6133f74 1Gi RWO Delete Bound default/pvc-c89fc044ac standard <unset> 15h
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
persistentvolumeclaim/data-music-db-postgresql-0 Bound pvc-cdc45d2b-45f7-49bb-a519-de539198f069 8Gi RWO standard <unset> 4d13h
persistentvolumeclaim/data-music-postgresql-0 Bound pvc-74d9ecdf-a900-4748-ae2b-39032c0714e7 8Gi RWO standard <unset> 4d10h
persistentvolumeclaim/data-my-db-postgresql-0 Bound pvc-4fe9328a-23ea-4a2f-a069-c7c762a32308 8Gi RWO standard <unset> 4d14h
persistentvolumeclaim/pvc-3d83f4ae8a Bound pvc-7934fd60-0a97-4fd9-964a-9dd2226bf102 1Gi RWO standard <unset> 5s
persistentvolumeclaim/pvc-77e7882074 Bound pvc-2129fdec-ebfe-48fc-a167-f32e59db49f2 1Gi RWO standard <unset> 15h
persistentvolumeclaim/pvc-c89fc044ac Bound pvc-e3763428-6c8b-4534-ad6e-7dd5b6133f74 1Gi RWO standard <unset> 15h
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/my-sample-app# kubectl describe pod | grep 'Service Account'
Service Account: default
Service Account: build-bot
Service Account: build-bot
Service Account: build-bot
Service Account: build-bot
Service Account: default
Service Account: music-db-postgresql
Service Account: default
Service Account: default

kaniko 하고 레지스트리에 푸시하는 두 번째 작업# task 설치 : https://hub.tekton.dev/tekton/task/kaniko
tkn hub install task **kaniko**
kubectl get tasks
kubectl get tasks kaniko -o yaml | k neat | yq
# Docker 자격 증명으로 Secret을 적용
-------------------------------------------------
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:~/.docker# cat ~/.docker/config.json
{
"auths": {
"https://index.docker.io/v1/": {
"username":"hp980724",
"password":"password",
"email":"email",
"auth": "auth"
},
#
cat ~/.docker/config.json | base64 -w0
DSH=$(cat ~/.docker/config.json | base64 -w0)
echo $DSH
-------------------------------------------------
**cat << EOF | kubectl apply -f -**
apiVersion: v1
kind: Secret
metadata:
name: docker-credentials
data:
config.json: $DSH
EOF
# ServiceAccount 생성 및 Secert 연결
kubectl create sa **build-sa**
kubectl patch sa build-sa -p '{"secrets": [{"name": "docker-credentials"}]}'
kubectl get sa build-sa -o yaml | kubectl neat | yq
# 파이프라인 파일 작성
**cat << EOF | kubectl apply -f -**
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: **clone-build-push**
spec:
description: |
This pipeline clones a git repo, builds a Docker image with Kaniko and pushes it to a registry
**params**:
- name: repo-url
type: string
- name: image-reference
type: string
**workspaces**:
- name: shared-data
- name: docker-credentials
**tasks**:
**- name: fetch-source**
taskRef:
name: **git-clone**
**workspaces**:
- name: output
workspace: shared-data
**params**:
- name: url
value: \$(params.repo-url)
**- name: build-push**
runAfter: ["fetch-source"]
taskRef:
name: **kaniko**
workspaces:
- name: source
workspace: shared-data
- name: dockerconfig
workspace: docker-credentials
params:
- name: IMAGE
value: \$(params.image-reference)
EOF
# 파이프라인 실행
**cat << EOF | kubectl create -f -**
apiVersion: tekton.dev/v1
kind: **PipelineRun**
metadata:
generateName: clone-build-push-run-
spec:
**pipelineRef:
name: clone-build-push**
taskRunTemplate:
serviceAccountName: **build-sa**
podTemplate:
securityContext:
fsGroup: 65532
**workspaces:**
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
- name: docker-credentials
secret:
secretName: docker-credentials
params:
- name: repo-url
value: https://github.com/gasida/docsy-example.git *# 유형욱님이 제보해주신 대로 Dockerfile 에 USER root 추가해두었습니다*
- name: image-reference
value: *docker.io/hp980724/docsy:1.0.0 # 각자 자신의 저장소*
EOF


빌드가 항상 동일한 서버에서 실행되고 레이어를 로컬에 저장할 수 있는 환경에서는 캐시된 레이어를 사용하는 것이 비교적 쉽다
빌드가 Kubernetes의 비영구 컨테이너에서 실행되는 환경에서는 캐시된 레이어를 사용하는 것이 어렵다.
Kaniko 캐싱 기능을 사용하여 Tekton Pipeline에서 빌드 속도를 높여보자
https://github.com/tektoncd/website
git-clone.yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: git-clone
labels:
app.kubernetes.io/version: "0.5"
annotations:
tekton.dev/pipelines.minVersion: "0.21.0"
tekton.dev/categories: Git
tekton.dev/tags: git
tekton.dev/displayName: "git clone"
tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64"
spec:
description: >-
These Tasks are Git tasks to work with repositories used by other tasks
in your Pipeline.
The git-clone Task will clone a repo from the provided url into the
output Workspace. By default the repo will be cloned into the root of
your Workspace. You can clone into a subdirectory by setting this Task's
subdirectory param. This Task also supports sparse checkouts. To perform
a sparse checkout, pass a list of comma separated directory patterns to
this Task's sparseCheckoutDirectories param.
workspaces:
- name: source
description: The git repo will be cloned onto the volume backing this Workspace.
params:
- name: url
description: Repository URL to clone from.
type: string
results:
- name: commit
description: The short commit SHA that was fetched by this Task.
- name: url
description: The precise URL that was fetched by this Task.
steps:
- name: clone
image: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.21.0"
env:
- name: PARAM_URL
value: $(params.url)
- name: WORKSPACE_OUTPUT_PATH
value: $(workspaces.source.path)
script: |
#!/usr/bin/env sh
set -eu
set -x
CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}"
cleandir() {
# Delete any existing contents of the repo directory if it exists.
#
# We don't just "rm -rf ${CHECKOUT_DIR}" because ${CHECKOUT_DIR} might be "/"
# or the root of a mounted volume.
if [ -d "${CHECKOUT_DIR}" ] ; then
# Delete non-hidden files and directories
rm -rf "${CHECKOUT_DIR:?}"/*
# Delete files and directories starting with . but excluding ..
rm -rf "${CHECKOUT_DIR}"/.[!.]*
# Delete files and directories starting with .. plus any other character
rm -rf "${CHECKOUT_DIR}"/..?*
fi
}
cleandir
/ko-app/git-init \
-url="${PARAM_URL}" \
-path="${CHECKOUT_DIR}" \
-submodules="true" \
-depth="1"
cd "${CHECKOUT_DIR}"
RESULT_SHA="$(git rev-parse --short HEAD)"
EXIT_CODE="$?"
if [ "${EXIT_CODE}" != 0 ] ; then
exit "${EXIT_CODE}"
fi
printf "%s" "${RESULT_SHA}" > "$(results.commit.path)"
printf "%s" "${PARAM_URL}" > "$(results.url.path)"
image-build.yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: image-build
labels:
app.kubernetes.io/version: "0.6"
annotations:
tekton.dev/pipelines.minVersion: "0.17.0"
tekton.dev/categories: Image Build
tekton.dev/tags: image-build
tekton.dev/displayName: "Build and upload container image using Kaniko"
tekton.dev/platforms: "linux/amd64"
spec:
description: >-
This Task builds a simple Dockerfile with kaniko and pushes to a registry.
params:
- name: IMAGE
description: Name (reference) of the image to build.
- name: DOCKERFILE
description: Path to the Dockerfile to build.
default: $(workspaces.source.path)/sample-app/Dockerfile
- name: CONTEXT
description: The build context used by Kaniko.
default: $(workspaces.source.path)/sample-app/
- name: commit
description: Short Commit SHA.
workspaces:
- name: source
description: Holds the context and Dockerfile
results:
- name: IMAGE_DIGEST
description: Digest of the image just built.
- name: IMAGE_URL
description: URL of the image just built.
steps:
- name: build-and-push
workingDir: $(workspaces.source.path)/sample-app/
image: gcr.io/kaniko-project/executor:latest
args:
- --dockerfile=$(params.DOCKERFILE)
- --context=$(params.CONTEXT) # The user does not need to care the workspace and the source.
- --destination=$(params.IMAGE):$(params.commit)
- --digest-file=$(results.IMAGE_DIGEST.path)
# kaniko assumes it is running as root, which means this example fails on platforms
# that default to run containers as random uid (like OpenShift). Adding this securityContext
# makes it explicit that it needs to run as root.
securityContext:
runAsUser: 0
- name: write-url
image: docker.io/library/bash:5.1.4@sha256:b208215a4655538be652b2769d82e576bc4d0a2bb132144c060efc5be8c3f5d6
script: |
set -e
image="$(params.IMAGE):$(params.commit)"
echo -n "${image}" | tee "$(results.IMAGE_URL.path)"
pipeline.yaml
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: pipeline-clone-and-build
spec:
params:
- name: git-url
- name: image-name
workspaces:
- name: source
tasks:
- name: git-clone
taskRef:
name: git-clone
params:
- name: url
value: $(params.git-url)
workspaces:
- name: source
workspace: source
- name: image-build
taskRef:
name: image-build
runAfter:
- git-clone
params:
- name: IMAGE
value: $(params.image-name)
- name: commit
value: "$(tasks.git-clone.results.commit)"
workspaces:
- name: source
workspace: source
source-pvc
(⎈|kind-myk8s:default) root@DESKTOP-8S932ET:/home/suha/website/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/tekton-assets# cat source-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: source-pvc
spec:
resources:
requests:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce(
권한 지정
https://tekton.dev/docs/how-to-guides/kaniko-build-push/#container-registry-authentication


TEE는 운영체제(OS), 하이퍼바이저, 관리자(root)조차도 접근할 수 없는 하드웨어 수준의 보안 구역(enclave)을 제공합니다.
| 특징 | 설명 |
|---|---|
| 격리(Isolation) | 일반 프로세스나 커널로부터 메모리와 실행 영역이 완전히 분리되어 있습니다. |
| 무결성(Integrity) | 내부 코드나 데이터가 외부에서 변조되지 않았음을 보장합니다. |
| 기밀성(Confidentiality) | 외부(운영체제, 관리자, 클라우드 제공자)에서 내부 데이터를 읽을 수 없습니다. |
| 원격 증명(Remote Attestation) | 외부 시스템이 “이 코드가 신뢰할 수 있는 환경(TEE)에서 실행 중”임을 암호학적으로 검증할 수 있습니다. |

기밀 클러스터 : 쿠버네티스 클러스터 전체가 기밀 환경에서 실행됩니다. 클러스터 노드는 기밀 VM이며, 이러한 클러스터 노드에 배포된 모든 워크로드는 기밀성의 이점을 누립니다.
기밀 컨테이너 : 쿠버네티스 포드는 기밀 환경 내에서 실행됩니다. 이 접근 방식은 더욱 세분화되어 선택한 워크로드에 대해 기밀성을 유지할 수 있습니다.