Self-hosted action runner란?

GitHub Actions는 코드 변경을 자동으로 감지하여 빌드, 테스트, 배포 등의 작업을 수행할 수 있는 강력한 CI/CD 플랫폼입니다. 기본적으로 GitHub에서는 자체적으로 관리되는 호스티드 러너(Hosted Runner)를 제공하며, 사용자는 별도의 설정 없이 워크플로를 실행할 수 있습니다.
하지만 때로는 GitHub에서 제공하는 러너로는 한계가 있을 수 있습니다. 이럴 때 사용하는 것이 바로 self-hosted Action Runner입니다. Self-hosted runner는 GitHub Actions 워크플로를 실행할 수 있는 러너를 사용자가 직접 운영하는 방식으로, GitHub에서 제공하는 러너와 동일한 기능을 제공하면서도 다음과 같은 이점이 있습니다

  • 비용 절감: GitHub의 호스티드 러너는 사용량에 따라 비용이 발생하지만, self-hosted runner는 자체 인프라를 활용하므로 요금을 줄일 수 있습니다.
  • 높은 유연성: 필요에 따라 원하는 도구, 라이브러리, 하드웨어(GPU 등)를 설치해 커스텀 환경을 구성할 수 있습니다.
  • 직접 제어 가능: runner의 리소스, 보안 정책, 확장 전략 등을 사용자가 직접 관리할 수 있습니다.

이번 실습에서는 Kubernetes 환경에 self-hosted runner를 구축하고, GitHub의 Private Repository에 코드가 수정될 때마다 자동으로 Docker 이미지를 빌드한 뒤, DockerHub의 Repository에 Push 하는 파이프라인을 구성해 보겠습니다. 이 실습을 통해 self-hosted runner의 구성 방법은 물론, 이를 활용한 실질적인 CI 자동화 사례를 직접 체험할 수 있도록 이번 문서를 작성하였습니다.

 


실습 환경 구성

minikube cluster 생성

필자는 개인 개발 환경에서 Minikube를 사용하고 있어, 아래와 같이 Kubernetes 클러스터를 생성하였습니다.
만약 이미 사용 중인 Kubernetes 클러스터가 있다면, 이 단계는 생략하셔도 괜찮습니다.

# node 2대, CPU 2core, Memory 2GB
# CRI는 containerd, CNI는 cilium으로 구성하였습니다.
minikube start -p=runner-profile --nodes 2 \
	--container-runtime=containerd --cni=cilium \
	--cpus=2 --memory=2048MB \
	--addons=metrics-server

 

cert-manager 설치

actions-runner-controller는 인증서 발급을 위해 cert-manager를 사용하므로, 먼저 cert-manager를 설치해야 합니다.
간단히 소개하자면, cert-manager는 Kubernetes 환경에서 TLS 인증서를 자동으로 발급하고 갱신해주는 오픈소스 도구입니다.
Let’s Encrypt와 같은 외부 CA(Certificate Authority)와 연동하여 인증서를 관리하며, Kubernetes 리소스와 통합되어 동작합니다.
이를 통해 사용자는 복잡한 인증서 관리를 수동으로 하지 않아도 되고, 보다 쉽게 안전한 HTTPS 연결을 구성할 수 있습니다.

# cert-manager Helm repository 추가
helm repo add cert-manager https://charts.jetstack.io
helm repo update

# cert-manager 설치
# installCRDs=true 옵션을 주지 않으면 CRD가 설치되지 않음
# CRD가 설치되지 않으면 actions-runner-controller가 정상적으로 동작하지 않음
helm install my-cert-manager cert-manager/cert-manager \
  --namespace cert-manager --create-namespace \
  --set installCRDs=true

 

Kubernetes에 action runner 설치

이제는 이번 문서 실습의 주제인 kubernetes에 action runner를 설치해보겠습니다.

actions-runner-controller는 GitHub Actions Runner를 Kubernetes 클러스터에서 관리할 수 있도록 도와주는 Helm 차트입니다. 이 차트를 사용하면 GitHub Actions Runner를 Kubernetes 클러스터에 쉽게 배포하고 관리할 수 있습니다. actions-runner-controller는 GitHub API와 상호작용하여 Runner의 상태를 모니터링하고, 필요한 경우 자동으로 스케일링 및 업데이트를 수행합니다.

# actions-runner-controller Helm repository 추가
helm repo add actions-runner-controller https://actions-runner-controller.github.io/actions-runner-controller
helm repo update

# action-runner-controller 설치
helm upgrade --install actions-runner-controller actions-runner-controller/actions-runner-controller \
  --namespace actions-runner-system --create-namespace \
  --set githubWebhookServer.enabled=false \
  --set syncPeriod=1m \
  --set authSecret.create=true \
  --set authSecret.github_token=ghp_나의깃헙토큰

"나의깃헙토큰" 위치에 GitHub Repo에 접근하기 위해 Read, Write 권한을 가진 토큰 값을 넣습니다.

https://docs.github.com/ko/actions/security-for-github-actions/security-guides/automatic-token-authentication?utm_source=chatgpt.com

 

RunnerDeployment 생성

kubectl apply -f - <<EOF
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
  name: self-hosted-runner
  namespace: actions-runner-system
spec:
  replicas: 1
  template:
    spec:
      repository: 깃헙유저명/깃헙레포명
EOF

"깃헙유저명/깃헙레포명" 본인 환경의 GitHub Repo명을 입력합니다.

 

Workflow 실습 진행

필자는 개인 GitHub Private Repository를 구성하여 실습을 진행하였습니다. "myapp"라는 이름의 Repository를 생성하고, 간단한 코드와 Dockerfile을 작성하였지만 이번 문서의 주제는 GitHub Action Self-hosted Runner 구축이므로, 코드 내용과 Dockerfile 내용은 생략하였습니다.

 

GitHub Repo Secret 생성

Action Runner가 코드를 가져와 Docker 이미지를 빌드하고, 이를 DockerHub에 Push 하려면 GitHub Token과 DockerHub Token이 필요합니다. 하지만 이러한 민감한 값은 workflow 파일 내에 직접 작성하면 보안상 문제가 발생할 수 있습니다. 따라서 GitHub에서는 Repository의 Secrets 기능을 제공하며, 토큰과 같은 민감한 정보를 안전하게 저장하고 워크플로에서 참조할 수 있도록 하고 있습니다.

 

아래 경로를 따라 이동하여 DOCKER_USERNAME, DOCKER_TOKEN, GH_TOKEN과 같은 필요한 이름으로 Secret을 생성하면 됩니다. 이렇게 등록한 값은 GitHub Actions 워크플로에서 ${{ secrets.DOCKER_TOKEN }} 형태로 안전하게 사용할 수 있습니다.

 

GitHub Repo >> Settings >> Secrets and variables >> Actions >> New repository secret

 

Workflow 작성

GitHub Repo(myapp)에 workflow를 작성합니다.

 

.github/workflows/myrunner.yml

name: Seft-Hosted CI
on:
  push:
    branches: [ "**" ]
  pull_request:
    branches: [ main, develop ]

jobs:
  build:
    # self-hosted 러너에서 실행하도록 설정
    runs-on: self-hosted

    env:
      IMAGE_REPO: standard2hsw/myapp

    steps:
      # 코드 체크아웃
      - name: Checkout code
        uses: actions/checkout@v2

      # DockerHub 로그인
      - name: DockerHub Login
        run: |
          echo "${{ secrets.DOCKER_TOKEN }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin

      # 브랜치명을 이용한 이미지 태그 생성
      # main branch는 latest로 설정하고 나머지 branch는 branch명으로 태그를 생성합니다.
      - name: Determine image tag
        id: vars
        run: |
          BRANCH_NAME=${GITHUB_REF#refs/heads/}
          SAFE_BRANCH_NAME=$(echo $BRANCH_NAME | sed 's#[^a-zA-Z0-9_.-]#-#g')
          if [ "$BRANCH_NAME" = "main" ]; then
            echo "tag=latest" >> $GITHUB_OUTPUT
          else
            echo "tag=$SAFE_BRANCH_NAME" >> $GITHUB_OUTPUT
          fi

      # 이미지 빌드
      - name: Build Docker image
        run: |
          docker build --platform linux/amd64 -t ${{ env.IMAGE_REPO }}:${{ steps.vars.outputs.tag }} .

      # 이미지 푸시
      - name: Push Docker image
        run: |
          docker push ${{ env.IMAGE_REPO }}:${{ steps.vars.outputs.tag }}

runs-on에 반드시 self-hosted를 입력해야 self hosted runner로 동작합니다.

 

RunnerDeployment 생성하기

kubectl apply -f - <<EOF
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
  name: self-hosted-runner
  namespace: actions-runner-system
spec:
  replicas: 1
  template:
    spec:
      repository: stdhsw/myapp
EOF

지금까지 실습을 잘 진행하셨다면 Self hosted runner가 정상적으로 동작하였는지 다음 위치에서 확인할 수 있습니다.

 

GitHub Repo >> Actions >> 해당 워크플로우 선택 >> Jobs 선택을 진행하시면 각각의 Job에서 Step별로 확인할 수 있습니다.

Set up job을 선택하여 보시면 어떤 Runner가 선택되어 동작되었는지 확인할 수 있습니다.

 

마지막으로 Hosted runner VS Self hosted runner

저는 개인적으로 절대적인 정답은 없다고 생각합니다. 따라서 Hosted Runner와 Self-hosted Runner의 장단점을 잘 비교하고, 각자의 환경과 목적에 맞는 최적의 선택을 하는 것이 중요합니다.
아래 표는 두 러너의 특성을 비교한 내용입니다. 표를 참고하셔서 여러분의 개발 환경에 가장 잘 맞는 러너를 선택하시기 바랍니다.

항목 GitHub Hosted Runner Self-hosted Runner
인프라 제공 GitHub에서 자동으로 VM 제공 사용자가 직접 서버/VM/Kubernetes 구성
비용 일정 사용량 이후 과금됨 GitHub에는 무료, 인프라 비용은 사용자 부담
환경 커스터마이징 제한적 (사전 설치된 도구만 사용 가능) 원하는 도구, 라이브러리, 하드웨어 설정 가능
실행 속도 동시 job 수 제한 시 대기 가능성 있음 러너 수 확장으로 빠르게 실행 가능
보안 GitHub 클라우드에서만 실행 사내망, VPC 등 폐쇄 환경에서도 사용 가능

 

 

Kubernetes Pod Resource CPU 설정

우리는 Kubernetes에서 Pod를 배포할 때 Node의 리소스 관리를 위하여 Resources에 CPU와 Memory의 사용량을 정의할 수 있습니다. 이때 Memory에 대한 설정은 명확하여 사용자가 알기 쉽지만 CPU에서는 "0.5"와 같은 설정이 가능하여 많은 사람들이 단순하게 "0.5"를 1/2 Core로 이해합니다. 하지만 Kubernetes에서 CPU는 Core가 아닌 CPU Share로 관리되며 CFS(Completely Fair Scheduler)와 밀접한 관계가 있습니다.
이번 문서에서는 Kubernetes Pod Resource CPU 설정과 CFS의 관계에 대해 알아보겠습니다.

resources:
  requests:
    cpu: "0.5"
  limits:
    cpu: "0.5"

 

CFS란 무엇인가?

CFS(Completely Fair Scheduler)는 리눅스 커널에서 CPU 자원을 여러 프로세스나 스레드에 공평하게 분배하기 위해 사용되는 CPU 스케줄링 알고리즘입니다. 리눅스 시스템에서 멀티태스킹 환경을 효율적으로 운영하려면, 여러 프로세스가 CPU를 공평하게 나누어 사용할 수 있도록 관리해야 합니다. CFS는 이를 위해 프로세스마다 가상 시간을 계산하고, 각 프로세스가 CPU를 사용하는 비율을 공정하게 유지하려고 합니다.

CFS의 작동 원리

  • 프로세스가 실행하면 CFS는 프로세스마다 가상 시간을 계산하여 CPU를 공정하게 할당합니다.
  • CPU가 할당되면, CFS는 프로세스의 가상 시간과 다른 프로세스들의 가상 시간을 비교하여, 가장 적은 가상 시간을 가진 프로세스를 먼저 실행합니다.
  • CPU 자원 분배는 각 프로세스의 가상 시간에 따라 조정되며, 시스템 자원이 고르게 분배될 수 있도록 관리됩니다.
  • CFS는 이를 위해 프로세스마다 가상 시간을 계산하고, 각 프로세스가 CPU를 사용하는 비율을 공정하게 유지하려고 합니다.

kubernetes pod 생성 흐름

kubernetes에서 CPU 리소스는 CFS를 기반으로 관리되며, CPU의 사용량을 조절하기 위해 CFS의 가상 시간과 실제 시간을 비교하여 스케줄링을 수행합니다. CFS는 각 프로세스에 대해 가상 시간을 계산하고, 이를 기반으로 CPU를 할당합니다. 이때, CPU의 사용량은 "CPU Share"라는 개념으로 표현됩니다.

Kubernetes Pod
   ↓
Kubelet
   ↓
CRI
   ↓
Linux Kernel
  - namespace (Isolation)
  - cgroup (Resource Control)
    - CPU: CFS Quota/Period
    - Memory: cgroup memory limit

cgroup v1에서는 cpu.cfs_quota_us와 cpu.cfs_period_us를 사용하여 CPU의 사용량을 조절합니다.
- cpu.cfs_quota_us : 프로세스가 사용할 수 있는 CPU 시간의 총량을 설정
- cpu.cfs_period_us : 동작하는 주기를 설정합니다. (기본값은 100,000us이며 100ms입니다.)
 
cgroup v2에서는 cpu.max를 사용하여 CPU의 사용량을 조절합니다.
- cpu.max : 프로세스가 사용할 수 있는 CPU 시간의 총량과 동작하는 주기를 설정합니다. (기본값은 100,000us이며 100ms입니다.)
 
여기서 우리가 알 수 있는 것은 Kubernetes에서 CPU를 0.5로 설정하였다는 것은 100,000us의 주기 동안 50,000us를 사용할 수 있다는 것입니다. 즉, 정확한 이해를 위해서는 CFS의 개념을 이해해야 합니다. CFS는 CPU를 공평하게 나누어 사용하기 위해 각 프로세스에 대해 가상 시간을 계산하고, 이를 기반으로 CPU를 할당합니다.
 

실습 예제를 통해 CFS값 확인하기

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: test-nginx
  name: test-nginx
spec:
  containers:
  - image: nginx:1.25
    name: test-nginx
    resources:
      requests:
        cpu: "0.5"
        memory: "100Mi"
      limits:
        cpu: "0.5"
        memory: "200Mi"

위와 같이 Pod를 생성합니다.
 
CFS확인하는 방법

# 파드의 노드, UID, QoS클래스 확인
kubectl get po test-nginx -o yaml | grep -E "nodeName:|uid:|qosClass:"

# 워커노드 접속 후 CFS 값을 확인합니다.
# 필자의 경우 cgroup v2를 사용하고 있어 cpu.max를 사용합니다.
cat /sys/fs/cgroup/kubepods/burstable/<pod_uid>/cpu.max

# 출력 결과
# quota = period * 0.5
# quota period 순서로 출력됩니다.
# 해당 파드는 매 100ms마다 50ms를 사용할 수 있습니다.
50000 100000

여기서 burstable는 QoS Class를 의미합니다. QoS Class는 Kubernetes에서 Pod의 리소스 requests와 limits를 기반으로 Pod의 우선순위를 결정하는 방법입니다.

QoS Class(Quality of Service Classes)는 Kubernetes에서 Pod의 리소스 requests와 limits를 기반으로 Pod의 우선 순위를 결정하는 방법입니다. 이 QoS에 따라 시스템은 리소스 부족 상황에서 어떤 Pod을 먼저 죽일지(OOMKilled), 어떤 Pod을 보호할지 결정합니다.
QoS Class는 다음과 같이 세 가지로 나뉩니다.

  • Guaranteed: 모든 컨테이너에 대해 requests와 limits가 동일하게 설정된 경우 (우선순위 가장 높음)
  • Burstable: requests와 limits가 다르게 설정된 경우 (중간 우선순위)
  • BestEffort: requests와 limits가 설정되지 않은 경우 (우선순위 가장 낮음)

QoS Class에 대한 자세한 설명은 Kubernetes 공식 문서를 참고하시기 바랍니다.

https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/

 

마지막으로 결론

  • Kubernetes의 cpu: 0.5 설정은 리눅스 CFS 스케줄러를 통해 실제 CPU 사용을 제한한다.
  • 리눅스 cgroup(v2)에서는 cpu.max 파일을 통해 quota/period를 설정한다.
  • cpu: 0.5 설정은 0.5Core라고 이해하지 말고 매 100ms 주기마다 50ms 동안만 CPU를 사용하게 한다고 이해하자.
  • Kubernetes는 period를 기본 100,000us(100ms)로 고정하고 quota만 조정한다.

Helm Hook이란

Helm Hook은 Kubernetes에서 Helm을 이용해 리소스를 배포하거나 삭제하는 과정 중에 특정 타이밍에 맞추어 추가 작업을 자동으로 실행할 수 있는 기능입니다. 즉, 단순히 애플리케이션만 배포하는 것이 아닌 설치 전/후, 업그레이드 전/후, 삭제 전/후 등 필요한 다양한 작업을 미리 정의해 놓을 수 있습니다. Helm Hook을 이용하면 복잡한 배포 시나리오를 쉽게 관리할 수 있고 특히 데이터베이스 초기화, 마이그레이션, 시스템 점검, 백업 그리고 CI/CD파이프라인이나 대규모 운영환경에 적용하여 다양한 자동화 작업에 활용할 수 있습니다.
이번 문서에서는 Helm Hook의 개념과 사용법에 대해 알아보겠습니다.

 

Helm Hook 작성법

Helm Hook은 Helm 차트의 메타데이터에 annotations을 추가하여 정의합니다. annotations은 `helm.sh/hook` 키를 사용하여 후크의 종류를 지정합니다. 예를 들어 설치 전에 실행되는 후크는 다음과 같이 정의할 수 있습니다.

metadata:
  annotations:
    "helm.sh/hook": pre-install
    "helm.sh/hook-delete-policy": before-hook-creation

Helm Hook 이벤트 종류

Helm Hook은 다음과 같은 이벤트 종류를 지원합니다.

  • pre-install: 차트 설치 전에 실행
  • post-install: 차트 설치 후에 실행
  • pre-upgrade: 차트 업그레이드 전에 실행
  • post-upgrade: 차트 업그레이드 후에 실행
  • pre-delete: 차트 삭제 전에 실행
  • post-delete: 차트 삭제 후에 실행
  • pre-rollback: 차트 롤백 전에 실행
  • post-rollback: 차트 롤백 후에 실행

Helm delete policy 종류

  • before-hook-creation: 후크가 실행되기 전에 기존 후크를 삭제합니다. (기본값)
  • hook-succeeded: 후크가 성공적으로 실행된 후에 삭제합니다.
  • hook-failed: 후크가 실패한 후에 삭제합니다.

 

Helm Hook 예제

이번 실습에서는 간단하게 nginx deployment와 service를 배포하고, 배포 후에 실행되는 후크를 정의하여 배포가 완료된 후에 nginx의 상태를 확인하는 예제를 만들어 보겠습니다.

 

1. Helm 차트 생성

helm create nginx-hook-test

 

2. values.yaml 수정

replicaCount: 1

image:
  repository: nginx
  tag: "1.25.0"
  pullPolicy: IfNotPresent

service:
  type: NodePort
  port: 80

nodePort: 30080

 

3. templates/deployment.yaml 수정

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        ports:
        - containerPort: 80

 

4. templates/service.yaml 수정

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: {{ .Values.service.type }}
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: {{ .Values.service.port }}
    targetPort: 80
    nodePort: {{ .Values.nodePort }}

 

5. templates/hook.yaml 생성

Helm Hook을 정의하는 Job 리소스를 생성합니다. 이 Job은 Helm 차트가 설치되기 전에 실행됩니다. 이번 테스트에서는 아주 간단하게 실습을 하기 위해 메시지를 출력하고 5초 후에 종료되록 설정하였습니다. 현업에서는 데이터베이스 초기화, 마이그레이션, 시스템 점검, 백업 등 다양한 작업을 수행할 수 있으니 본인의 환경에 맞게 수정하여 사용하시면 됩니다.

apiVersion: batch/v1
kind: Job
metadata:
  name: preinstall-hook
  annotations:
    "helm.sh/hook": pre-install
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      containers:
      - name: preinstall
        image: busybox
        command: ['sh', '-c', 'echo "Helm Pre-install Hook 실행 완료!" && sleep 5']
      restartPolicy: Never

 

6. 불필요한 파일 삭제

나머지 불필요한 파일은 모두 삭제하고 아래와 같이 Helm 차트를 구성하여 실행합니다.

├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── hook.yaml
│   └── service.yaml
└── values.yaml

 

7. Helm 실행

helm install nginx-hook-test .

# # Helm Hook 실행 결과
kubectl get pods -w
NAME                    READY   STATUS      RESTARTS   AGE
preinstall-hook-rb6bw   1/1     Running     0          3s
preinstall-hook-rb6bw   0/1     Completed   0          9s
nginx-55b5b869bd-b424z  0/1     Pending     0          0s
nginx-55b5b869bd-b424z  1/1     Running     0          1s

preinstall-hook이 실행 후에 5초 후에 종료되고 nginx가 실행되는 것을 확인할 수 있습니다.

 

8. Helm Hook 삭제

위와 같이 테스트를 진행하였다면 이제는 Helm Hook 삭제에 대해 알아보겠습니다. Helm Hook은 기본적으로 Helm 차트가 삭제될 때 자동으로 삭제되지 않습니다. 따라서 수동으로 삭제해주어야 합니다. 아래와 같이 Helm 차트를 삭제하고 Job 리소스를 수동으로 삭제합니다.
만약 Helm Hook이 성공하였을 시 자동적으로 삭제되도록 설정을 하기 위해서는 before-hook-creation 대신에 hook-succeeded를 사용하면 job 리소스가 성공적으로 실행된 후에 자동적으로 삭제됩니다.

helm delete nginx-hook-test
kubectl delete job preinstall-hook

 

참조

https://helm.sh/ko/docs/topics/charts_hooks/

Terraform이란?

Terraform은 HashiCorp에서 개발한 오픈소스 인프라스트럭처 자동화 도구로, 사용자가 작성한 코드를 이용하여 인프라를 정의하고 관리하는 도구입니다. Terraform을 이용하면 서버, 네트워크, 데이터베이스, 로드 밸런서 등 다양한 인프라 자원을 선언적인 설정 파일(HCL, HashiCorp Configuration Language) 형태로 작성할 수 있으며 이 파일을 기반으로 원하는 클라우드 환경이나 온프레미스 환경에 인프라를 일관되게 구축, 변경, 버전 관리할 수 있습니다.
기존에는 인프라 구축을 위해 수동으로 수십 번의 클릭과 설정이 필요했지만 Terraform을 사용하면 한 번의 명령어 실행으로 필요한 모든 인프라를 자동으로 프로비저닝 할 수 있으며, 인프라 변경사항 역시 코드로 관리하여 사람의 실수를 줄이고 인프라 환경을 보다 안전하고 예측 가능하게 만들 수 있습니다. 또한 Terraform은 멀티 클라우드와 하이브리드 클라우드를 지원하여 AWS, Azure, GCP와 같은 퍼블릭 클라우드는 물론 VMware, Kubernetes와 같은 온프레미스 환경까지 통합적으로 관리할 수 있습니다. 또한 Module 기능을 통해 인프라 구성을 재사용 가능한 코드 블록으로 관리함으로써 대규모 인프라 관리에도 매우 효율적인 기능을 제공합니다. 
무엇보다 Terraform의 강력한 장점 중 하나는 ‘플랜(plan)과 적용(apply)’ 과정이 명확히 분리되어 있어, 실제 인프라 변경 전에 예상 변경 사항을 검토할 수 있기 때문에 운영 환경에 미치는 영향을 최소화할 수 있다는 점입니다. 이러한 이유로 Terraform은 현재 많은 기업들이 인프라 운영 자동화(IaC, Infrastructure as Code) 전략의 핵심 도구로 채택하고 있으며 DevOps와 클라우드 네이티브 시대에 필수적인 기술로 자리 잡고 있습니다.
이번 문서에서는 Terraform의 기본 개념과 사용법, 그리고 실제로 Terraform을 사용하여 간단하게 Kubernetes에 deployment와 service를 생성하는 방법에 대해 알아보겠습니다.

 

Terraform HCL 기본 문법 (변수선언)

Terraform은 블록 구조를 사용하여 리소스, 데이터 소스, 모듈 등을 정의합니다. 블록은 특정 리소스나 설정을 나타내며 각 블록은 고유한 속성과 값을 가집니다. 블록 구조는 다음과 같은 형식을 가집니다.

# 블록 구조는 Terraform의 기본 구성 요소입니다.
블록타입 "종류" "이름" {
  속성1 = 값
  속성2 = 값
}

/* 예시
resource : 블록 타입
aws_instance : 리소스 종류
example : 리소스 이름
*/
resource "aws_instance" "example" {
  ami           = "ami-12345678"
  instance_type = "t2.micro"
}

 

Terraform에서는 변수를 사용하여 코드의 재사용성을 높이고, 환경에 따라 다른 값을 쉽게 설정할 수 있습니다. 변수를 선언하는 방법은 다음과 같습니다.

locals {
    숫자 = 123
    불리언 = true
    문자열 = "value"
    여러줄문자열 = <<EOF
    hello
    world
    EOF

    리스트 = [1, 2, 3]
    맵 = {
        key1 = "value1"
        key2 = "value2"
    }
}

# 변수 선언
variable "instance_count" {
  type        = number
  default     = 3
}

# 변수 사용
output "instance_count" {
  value = var.instance_count
}

 

Terraform HCL 기본 문법 (if, for)

Terraform에서는 조건문과 반복문을 사용하여 코드의 가독성을 높이고, 재사용성을 높일 수 있습니다.

# if문
variable "is_production" {
  type    = bool
  default = false
}

output "env_name" {
  value = var.is_production ? "production" : "development"
}

# if AND 연산
variable "is_enabled" {
  type    = bool
  default = true
}

variable "is_ready" {
  type    = bool
  default = true
}

output "service_status" {
  value = var.is_enabled && var.is_ready ? "RUNNING" : "STOPPED"
}

# if OR 연산
variable "is_weekend" {
  type    = bool
  default = false
}

variable "is_holiday" {
  type    = bool
  default = true
}

output "is_day_off" {
  value = var.is_weekend || var.is_holiday ? "YES" : "NO"
}

# for문
output "uppercase_fruits" {
  value = [for fruit in ["apple", "banana", "cherry"] : upper(fruit)]
}

# for + if 문
output "even_numbers" {
  value = [for n in [1,2,3,4,5] : n if n % 2 == 0]
}

 

Terraform 코드 구조

Terraform 코드는 선언적 언어로 작성되며, 각 블록은 특정 리소스나 설정을 정의합니다. Terraform 코드는 일반적으로 다음과 같은 구조로 작성됩니다.

블록 타입 설명 비고
provider 클라우드 provider 설정 AWS, GCP, Azure, Kubernetes 등 클라우드 제공자에 대한 설정을 정의합니다.
resource 리소스 생성 provider에 따라 실제 인프라 리소스를 생성하는 데 사용됩니다.
variable 변수 선언 코드에서 사용할 변수를 선언하여 재사용성을 높입니다.
output 결과 출력 Terraform 실행 후 출력할 값을 정의합니다.
module 코드 재사용 다른 Terraform 코드에서 재사용할 수 있는 모듈을 정의합니다.
data 외부 데이터 읽기 외부 데이터 소스에서 데이터를 읽어오는 데 사용됩니다.
locals 임시 변수 코드 내에서 사용할 임시 변수를 정의합니다.
terraform Terraform 기본 설정 backend, provider와 같은 필수적인 값을 설정합니다.
backend 상태 저장소 설정 Terraform 상태 파일을 저장할 위치를 설정합니다.
provisioner 서버 초기 작업 서버 생성 후 초기 작업을 수행하는 데 사용됩니다.
서버에 소프트웨어를 설치하거나 설정 파일을 복사하는 등의 작업을 수행합니다.

 

Terraform 파일명 규칙

Terraform 파일은 일반적으로 `.tf` 확장자를 사용합니다. 여러 개의 파일로 구성된 Terraform 프로젝트에서는 다음과 같은 규칙을 따릅니다. 꼭 파일명을 지키지 않아도 되지만, 가독성을 높이기 위해 다음과 같은 규칙을 따르는 것이 좋습니다.

- main.tf : 주요 리소스 및 설정을 정의하는 파일
- variables.tf : 변수 선언을 포함하는 파일
- outputs.tf : 출력 값을 정의하는 파일
- locals.tf : 로컬 변수를 정의하는 파일
- provider.tf : 클라우드 제공자 설정을 포함하는 파일
- terraform.tfvars : 변수 값을 정의하는 파일

Terraform 파일들
- terraform.tfvars : 변수 값을 정의하는 파일
- terraform.tfstate : Terraform 상태 파일
- terraform.tfstate.backup : Terraform 상태 파일 백업

Terraform은 상태 파일을 사용하여 현재 인프라의 상태를 관리합니다. 상태 파일은 Terraform이 관리하는 리소스의 현재 상태를 저장하며, 이를 통해 Terraform은 리소스의 변경 사항을 추적하고 관리합니다. 상태 파일은 기본적으로 `terraform.tfstate`라는 이름으로 생성됩니다. 상태 파일은 JSON 형식으로 저장되며, Terraform이 관리하는 모든 리소스의 정보를 포함합니다. 상태 파일은 Terraform이 리소스를 생성, 수정, 삭제할 때마다 업데이트됩니다. 

Terraform CLI 명령어

Terraform CLI는 Terraform을 사용하여 인프라를 관리하는 데 필요한 다양한 명령어를 제공합니다. 주요 명령어는 다음과 같습니다.

# Terraform 초기화
# 디렉토리에 tf 파일을 읽어서 필요한 provider를 다운로드합니다.
# backend 설정을 읽어서 상태 파일을 저장할 위치를 설정합니다.
terraform init

# Terraform 코드 문법 검사
# 실제로 리소스를 생성하지 않고, 코드 문법을 검사합니다.
terraform validate

# Terraform 계획
# Terraform 코드에 따라 어떤 리소스가 생성될지 계획을 세웁니다.
# 실제로 리소스를 생성하지 않고, 어떤 리소스가 생성될지 계획을 세웁니다.
terraform plan

# Terraform 적용
# Terraform 계획에 따라 실제로 리소스를 생성합니다.
# -auto-approve : 자동으로 승인합니다.
terraform apply

# Terraform 상태 확인
# 현재 Terraform 상태를 확인합니다.
terraform show

# Terraform 리소스 삭제
# Terraform 코드에 따라 생성된 리소스를 삭제합니다.
terraform destroy

# Terraform 스타일 가이드에 맞게 자동 정렬합니다.
# 코드의 가독성을 높이고, 일관성을 유지하는 데 도움이 됩니다.
# -recursive : 하위 디렉토리까지 재귀적으로 적용합니다.
terraform fmt

# Terraform 출력 값 확인
terraform output

# Terraform 상태 목록 확인
terraform state list
terraform state show

 


실습 예제 (on Minikube)

간단한 실습을 위해 Minikube를 사용하여 Kubernetes 클러스터를 로컬에서 실행하고, Terraform을 사용하여 Kubernetes에 Deployment와 Service를 생성하는 방법을 알아보겠습니다.

실습은 Minikube로 Kubernetes 클러스터가 동작하고 있다는 가정하에 진행하였으며 아래 파일들은 모두 같은 디렉토리에 존재하여야 합니다.

 

provider.tf

terraform init을 수행하면 설정한 provider를 설정한 버전으로 설치합니다.

# 테라폼 설정 파일
# 이 파일은 Kubernetes 클러스터에 대한 테라폼 설정을 포함합니다.
terraform {
  required_providers {
    kubernetes = {
      source = "hashicorp/kubernetes"
      version = "~> 2.20"
    }
  }
}

# Kubernetes provider 설정
# ~/.kube/config 파일을 사용하여 kubernetes provider 설정
provider "kubernetes" {
  config_path = "~/.kube/config"
}

 

variables.tf

variable로 변수를 선언하면 모든 파일에서 사용할 수 있습니다.

variable "nginx_image" {
  description = "nginx 컨테이너 이미지 (태그 포함)"
  type        = string
  default     = "nginx:latest"
}

variable "nginx_nodeport" {
  description = "NodePort 서비스에 사용할 포트 번호"
  type        = number
  default     = 30080
}

 

terraform.tfvars

variable로 선언된 값이 값을 할당할 수 있습니다.

nginx_image    = "nginx:1.25.2"
nginx_nodeport = 30081

 

namespace.tf

kubernetes의 namespace를 생성합니다.

resource "kubernetes_namespace" "example" {
  metadata {
    name = "test-namespace"
  }
}

 

deployment.tf

kubernetes의 deployment를 생성합니다.

resource "kubernetes_deployment" "nginx" {
  metadata {
    name      = "nginx-deployment"
    namespace = kubernetes_namespace.example.metadata[0].name
    labels = {
      app = "nginx"
    }
  }

  spec {
    replicas = 2

    selector {
      match_labels = {
        app = "nginx"
      }
    }

    template {
      metadata {
        labels = {
          app = "nginx"
        }
      }

      spec {
        container {
          name  = "nginx"
          image = var.nginx_image

          port {
            container_port = 80
          }
        }
      }
    }
  }
}

 

service.tf

kubernetes의 service를 생성합니다.

resource "kubernetes_service" "nginx" {
  metadata {
    name      = "nginx-service"
    namespace = kubernetes_namespace.example.metadata[0].name
  }

  spec {
    selector = {
      app = "nginx"
    }

    port {
      port        = 80
      target_port = 80
      node_port   = var.nginx_nodeport
    }

    type = "NodePort"
  }
}

 

실습 실행

# 테라폼을 초기화합니다.
terraform init

# 테라폼이 잘 작성되었는지 검증합니다.
terraform validate

# 테라폼이 앞으로 어떻게 리소스를 생성할 것인지 확인합니다.
terraform plan

# 실제로 리소스를 생성합니다.
# -auto-approve 옵션이 없으면 리소스 배포를 동의하도록 yes를 입력해야 합니다. 현업에서는 잘 사용하지 않습니다.
terraform apply -auto-approve

# 파드가 잘 떳는지 확인
kubectl get all -n test-namespace
# 출력 결과
NAME                                    READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-7f9c745664-whvzk   1/1     Running   0          6m55s
pod/nginx-deployment-7f9c745664-wnm87   1/1     Running   0          6m55s

NAME                    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/nginx-service   NodePort   10.107.11.247   <none>        80:30081/TCP   6m56s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   2/2     2            2           6m55s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-7f9c745664   2         2         2       6m55s

# 테스트가 끝났다면 아래와 같이 생성된 리소스를 삭제합니다.
terraform destroy -auto-approve

GitHub Action이란?

GitHub 저장소(repository) 안에서 코드 변경(push, pull request 등)이나 수동 실행(workflow_dispatch), 예약 실행(schedule) 같은 다양한 이벤트를 트리거로 하여 정해진 작업(workflow)을 자동으로 수행할 수 있도록 지원하는 GitHub 내장형 자동화 기능입니다. 사용자는 YAML 파일을 이용해 빌드, 테스트, 배포, 린트 검사, 문서 생성 등 필요한 작업을 정의할 수 있으며, 이러한 작업들은 하나 이상의 Job으로 구성되고, 각 Job은 여러 Step(명령 실행 또는 외부 Action 호출)으로 이루어져 독립적으로 혹은 서로 의존 관계를 갖고 실행될 수 있습니다. GitHub Actions는 GitHub와 완벽하게 통합되어 있어, 코드와 CI/CD 파이프라인을 한 곳에서 관리할 수 있습니다.
또한, Actions 마켓플레이스(GitHub Marketplace)에서 수천 개의 오픈소스 Action들을 가져와 조합하여 쉽게 복잡한 자동화를 구성할 수 있다는 장점도 가지고 있습니다.

 

시작하기 전에 테스트용 GitHub Repo 생성

필자는 CI 환경을 구축하기 위해 GitHub Action을 사용하였고 CD 환경은 ArgoCD를 사용하여 구축하였습니다. 그래서 myapp repo에 GitHub Action을 설정하여  이미지를 빌드하고 DockerHub에 이미지를 push하여 빌드된 이미지 정보를 myapp-deploy repo에 commit 하는 방법을 이용하여 CI/CD 환경을 구축하였습니다.
이번 실습에서는 GitHub Action을 사용하여 DockerHub에 이미지를 push하고, myapp-deploy repo에 commit 하는 방법을 익히는 방법에 대하여 알아보겠습니다.

GitHub Repo에 각자 자신의 코드를 작성하였고, GitHub Repo에 Dockerfile이 존재한다는 가정하에 실습을 진행하겠습니다.
필자는 go언어 개발자이기 때문에 아래와 같이 myapp repo를 작성하였습니다.

.
├── Dockerfile
├── go.mod
├── main.go
└── README.md

 

이번 실습 목표

  • GitHub Action을 사용하여 DockerHub에 이미지를 build하고 push 하는 방법을 익힌다.
  • GitHub Action을 사용하여 DockerHub에 이미지를 push한 후, myapp-deploy repository에 commit 하는 방법을 익힌다.

 

이번 실습 구성도

 

DockerHub Token 생성

Account Settings -> Personal access tokens -> New Access Token
생성된 token은 복사하여 저장합니다. 나중에 다시 확인할 수 없기 때문에 꼭 복사하여 저장합니다.

 

GitHub Token 생성

Settings -> Developer settings -> Personal access tokens -> Tokens(classic) -> Generate new token
Note : token 이름 설정
Expiration : No expiration

 

Token check list

  • repo 모두 선택
  • write:packages
  • read:packages

생성된 token은 복사하여 저장합니다. 나중에 다시 확인할 수 없기 때문에 꼭 복사하여 저장합니다.

 

GitHub Action 시작하기

Secret 설정

Secret을 설정하는 이유는 외부에 노출되어서는 안 되는 민감한 정보(예: 비밀번호, API 키, Access Token)를 안전하게 암호화하여 저장하고 GitHub Actions 워크플로우 실행 중에만 제한적으로 사용할 수 있도록 함으로써 코드 저장소에 중요한 정보를 직접 노출시키지 않고도 필요한 인증 및 보안 작업을 자동화할 수 있는 기능입니다.
Secret을 설정하는 방법은 아래와 같습니다.

 

GitHub Repo -> Settings -> Secrets and variables -> Actions -> New repository 에서 총 3개의 secret을 설정합니다.

  • DOCKER_USERNAME : DockerHub username
  • DOCKER_PASSWORD : DockerHub token
  • GH_TOKEN : github token

 

GitHub Action 설정

GitHub Repo -> Actions에서 원하는 workflow를 선택하여 생성합니다. 필자는 Docker Image를 선택하여 작업을 시작하였습니다.
GitHub Action Workflow를 설정하는 방법은 아래와 같습니다.

name: Docker Image CI

on:
  push:
    # 모든 브랜치에 push 이벤트 발생 시 실행
    branches: [ "**" ]

jobs:
  build:
    # ubuntu-latest 환경에서 Action 실행
    runs-on: ubuntu-latest

    # 환경변수 설정
    env:
      DEPLOY_REPO: 깃헙계정/myapp-deploy
      IMAGE_REPO: ${{ secrets.DOCKER_USERNAME }}/myapp

    steps:
    # 소스코드 체크아웃
    - name: Checkout source code
      uses: actions/checkout@v4
    
    # DockerHub 로그인
    - name: Docker login to DockerHub
      run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
    
    # 브랜치를 이용하여 이미지 태그 결정
    # 특수문자(-_.) 제외하고 다 -로 변환
    # main 브랜치는 latest 태그 사용
    # 나머지 브랜치는 브랜치명 그대로 태그
    - name: Determine image tag
      id: vars
      run: |
        BRANCH_NAME=${GITHUB_REF#refs/heads/}
        SAFE_BRANCH_NAME=$(echo $BRANCH_NAME | sed 's#[^a-zA-Z0-9_.-]#-#g')
        if [ "$BRANCH_NAME" = "main" ]; then
          echo "tag=latest" >> $GITHUB_OUTPUT
        else
          echo "tag=$SAFE_BRANCH_NAME" >> $GITHUB_OUTPUT
        fi
    
    # 이미지 빌드
    - name: Build the Docker image
      run: docker build --platform linux/amd64 -t ${{ env.IMAGE_REPO }}:${{ steps.vars.outputs.tag }} .

    # 이미지 푸시
    - name: Push Docker image to DockerHub
      run: docker push ${{ env.IMAGE_REPO }}:${{ steps.vars.outputs.tag }}

    # myapp-deploy repository 체크아웃
    - name: Checkout myapp-deploy repository
      uses: actions/checkout@v4
      with:
        repository: ${{ env.DEPLOY_REPO }}
        token: ${{ secrets.GH_TOKEN }}
        ref: main

    # myapp-deploy repository에 이미지 정보 업데이트
    # 커밋 (변경사항이 없으면 에러를 무시)
    - name: Update image.txt with new image info
      run: |
        echo "${{ env.IMAGE_REPO }}:${{ steps.vars.outputs.tag }}" > image.txt
        git config --global user.name "github-actions"
        git config --global user.email "github-actions@github.com"
        git add image.txt
        git commit -m "Update image to ${{ env.IMAGE_REPO }}:${{ steps.vars.outputs.tag }}" || echo "No changes to commit"
        git push

 

GitHub Action 테스트

GitHub Action이 정상적으로 동작하는지 확인하기 위해서는 myapp repository에 코드를 수정하여 commit하면 됩니다.
GitHub Repo에 Actions 탭을 클릭하면 아래와 같이 Action이 실행되는 것을 확인할 수 있으며 실패 시 로그를 확인하여 문제를 해결할 수 있으며, 이메일을 통해 실패 알림을 받을 수 있습니다.

 

GitHub Action 결과 확인

GitHub Action이 성공적으로 실행되면 DockerHub에 이미지가 push된 것을 확인할 수 있으며, myapp-deploy repository에 image.txt 파일이 생성된 것을 확인하여 정상적으로 동작하였음을 확인할 수 있습니다.

 

참고문서

https://docs.github.com/ko/actions

 

GitHub Actions 설명서 - GitHub Docs

GitHub Actions를 사용하여 리포지토리에서 바로 소프트웨어 개발 워크플로를 자동화, 사용자 지정 및 실행합니다. CI/CD를 포함하여 원하는 작업을 수행하기 위한 작업을 검색, 생성 및 공유하고 완

docs.github.com

 

ArgoCD란

ArgoCD는 쿠버네티스(Kubernetes) 환경에서 애플리케이션을 안전하고 일관성 있게 배포하고 관리할 수 있도록 도와주는 오픈소스 GitOps 도구입니다. 사용자는 애플리케이션의 설정 파일이나 배포 정보를 Git 저장소에 미리 정의해 두고, ArgoCD는 해당 Git 저장소를 지속적으로 모니터링하여 쿠버네티스 클러스터 내 실제 상태와 비교합니다.
만약 Git에 정의된 원하는 상태와 클러스터 내 실제 상태가 다를 경우, ArgoCD는 자동으로 이를 동기화하거나 사용자의 승인 후 동기화를 수행해, 클러스터 상태가 항상 Git 저장소에 정의된 상태와 동일하게 유지되도록 관리합니다.
이를 통해 기존처럼 수동으로 애플리케이션을 배포하거나 kubectl 명령어로 직접 리소스를 생성,수정,삭제하는 방식 대신 모든 변경 사항을 Git 저장소를 통해 관리할 수 있어 배포 이력 추적과 변경 관리가 체계적으로 이루어지며 문제가 발생했을 때 특정 커밋이나 버전으로 빠르게 롤백할 수 있어 운영 안정성이 높아집니다.
이번 글에서는 ArgoCD를 설치하고, Private Repo를 등록하여 GitHub Webhook Event를 연동하는 방법을 설명하겠습니다. 이 글을 통해 ArgoCD의 기본적인 사용법과 GitOps의 개념을 이해할 수 있을 것입니다.

 


테스트 환경 GitHub Repository 구성

먼저 ArgoCD를 설치하기에 앞서 테스트 환경을 구성해야 합니다. 테스트 환경은 GitHub Repository를 Private Repo로 구성하였으며 테스트를 위해 간단하게 Helm Chart를 사용하여 Nginx 배포하는 예제를 작성하였습니다. GitHub Repository는 다음과 같은 구조로 구성되어 있습니다.

본인만의 테스트를 진행할 수 있는 Manifest 또는 Helm을 작성한 Repo가 별도로 있다면 이부분은 생략하셔도 됩니다.

 

디렉토리 구조

test-deploy
├── nginx-chart
│   ├── Chart.yaml
│   ├── templates
│   │   ├── deployment.yaml
│   │   └── service.yaml
│   └── values.yaml
└── README.md

 

Chart.yaml

apiVersion: v2
name: nginx-chart
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.16.0"

 

values.yaml

replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "1.21.6"

service:
  type: ClusterIP
  port: 80

 

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-nginx
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: test-nginx
  template:
    metadata:
      labels:
        app: test-nginx
    spec:
      containers:
        - name: nginx
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          ports:
            - containerPort: 80

 

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: test-nginx
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: 80
  selector:
    app: test-nginx

 

GitHub Personal Access Token 생성

Public Repo는 별도의 인증 없이도 ArgoCD에 등록할 수 있기 때문에 이 과정은 생략하셔도 됩니다.
그렇지만 일반적으로 많은 회사에서 Private Repo를 사용하기 때문에 Private Repo에 대한 인증 방법을 설명하겠습니다. ArgoCD가 Private Repo에 접근하기 위해서는 인증이 필요합니다. GitHub에서는 Personal Access Token을 사용하여 Private Repo에 접근할 수 있습니다. 이 토큰은 GitHub 계정의 권한을 부여받아 Private Repo에 접근할 수 있는 키와 같은 역할을 합니다. 따라서, ArgoCD가 Private Repo에 접근하기 위해서는 이 Personal Access Token을 사용해야 합니다.
다음은 GitHub에서 Personal Access Token을 생성하는 방법입니다.

  1. GitHub에 접속하여 우측 상단의 유저 프로필 아이콘을 클릭하고 `Settings`를 선택합니다.
  2. 좌측 메뉴에서 `Developer settings`를 클릭합니다.
  3. `Personal access tokens`를 클릭합니다.
  4. `Tokens (classic)`을 클릭합니다. (굳이 Classic을 선택하지 않아도 됩니다.)
  5. `Generate new token`을 클릭합니다.
  6. `repo` 원하는 권한을 선택하여 부여합니다.
  7. `Generate token`을 클릭하여 Personal Access Token을 생성합니다.
  8. 생성된 Personal Access Token을 복사합니다.

위 과정을 통해 생성된 Personal Access Token은 다음과 같은 형식입니다.

# GitHub Personal Access Token
ghp_생략...

GitHub Personal Access Token은 잘 저장하되 타인에게는 공유하지 않습니다.

 


ArgoCD 설치하기

ArgoCD를 Kubernetes 클러스터에 설치하는 방법은 여러 가지가 있지만 필자는 Helm을 사용하여 설치하는 방법을 선호하기 때문에 Helm을 이용하여 ArgoCD를 설치하는 방법을 설명하겠습니다. Helm을 사용하면 ArgoCD의 설치 및 업그레이드가 간편해지고, 설정 파일을 관리하기도 용이합니다. Helm이 설치되어 있지 않다면 아래 링크를 참고하여 Helm을 설치하시기 바랍니다.

[Helm 설치하기] : https://helm.sh/docs/intro/install/

# helm repo 추가
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

# ArgoCD Helm 차트 설치
helm upgrade argo-cd argo/argo-cd \
    --install \
    --namespace argocd --create-namespace \
    --version 7.8.23 \
    --set configs.params.server.insecure=true \
    --set server.service.type=NodePort

이번 실습은 개인 로컬 환경에서 테스트용으로 구축하는 것을 목표로 하기 때문에 Service의 Type을 `NodePort`로 설정하였습니다. 실제 현업에서는 NodePort를 이용하지 않습니다.

 

ArgoCD UI 접속

위와 같이 진행을 하였다면 ArgoCD UI는 `NodePort`로 설정되어 있습니다. ArgoCD Helm에서는 기본적으로 http는 `30080`으로 설정되어 있으며, https는 `30443`으로 설정되어 있습니다. 따라서 브라우저에서 `http://<NodeIP>:30080`으로 접속하면 ArgoCD UI에 접속할 수 있습니다. 만약 `NodePort`가 다르게 설정되어 있다면 다음 명령어를 사용하여 확인할 수 있습니다.

# ArgoCD NodePort 확인
kubectl get svc -n argocd

 

ArgoCD 초기 비밀번호 확인

다음 명령어를 사용하여 초기 비밀번호를 확인할 수 있습니다.

# 초기 비밀번호 확인
kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath="{.data.password}" | base64 -d

ArgoCD UI에 로그인할 때, 사용자 이름은 `admin`이고 비밀번호는 위 명령어로 확인한 값을 사용합니다.

 

ArgoCD에 Private Repo 등록

ArgoCD는 Private Repo에 접근하기 위해 위에서 생성한 Personal Access Token을 사용하여 Secret을 생성하여 해당 Secret을 이용해 Private Repo를 등록합니다. 다음은 ArgoCD에 Private Repo를 등록하는 방법입니다.

# GitHub Personal Access Token을 사용하여 Private Repo 등록
kubectl -n argocd apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: my-git-repo                                   # Secret 이름 (ArgoCD에서 구분용)
  namespace: argocd                                   # ArgoCD가 설치된 Namespace (보통 argocd)
  labels:
    argocd.argoproj.io/secret-type: repository        # 중요: 이 label 이 있어야 ArgoCD가 Repository 용도의 Secret으로 인식함
stringData:                                           # 평문 데이터 (적용 시 자동 base64 인코딩 됨)
  type: git                                           # repository 타입 (git, helm 등 지정 가능)
  url: https://github.com/stdhsw/test-deploy.git      # GitHub Repository URL
  username: 유저아이디                                   # GitHub 사용자 이름  
  password: ghp_생략...                                # GitHub Personal Access Token (https 인증용)
EOF

username, password는 GitHub 계정의 사용자 이름과 Personal Access Token을 입력합니다. 위 명령어를 실행하면 `my-git-repo`라는 이름의 Secret이 생성됩니다. 이 Secret은 ArgoCD에서 Private Repo에 접근할 때 사용됩니다.

 

ArgoCD UI에서 정상적으로 Repo가 등록되었는지 확인

브라우저에 http://localhost:30080으로 접속 후 Settings -> Repositories

 

Application 생성

Application은 ArgoCD가 Kubernetes 클러스터 안에 배포하고, 관리할 대상(서비스/앱/시스템)을 정의하는 리소스입니다.
이번 테스트용 예제에서는 `https://github.com/stdhsw/test-deploy.git` 리포지토리의 `charts/nginx` 경로에 있는 Helm Chart를 사용하여 애플리케이션을 배포합니다. 이 예제에서는 `nginx-deploy`라는 이름으로 애플리케이션을 다음과 같이 생성합니다.

kubectl -n argocd apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1    # ArgoCD Application 리소스 API 버전
kind: Application                   # 리소스 종류: Application (ArgoCD 배포 단위)
metadata:
  name: nginx-app                   # ArgoCD에 표시될 Application 이름
  namespace: argocd                 # Application 리소스를 배포할 네임스페이스 (보통 argocd)
spec:
  project: default                  # ArgoCD Project 이름 (별도 설정 안했으면 default 사용)
  source:                           # 어떤 Git Repo에서 가져올 것인지 설정
    repoURL: https://github.com/stdhsw/test-deploy.git  # Git 저장소 URL
    targetRevision: HEAD            # Git 브랜치 (HEAD = 최신 커밋 기준 / 또는 main, develop 등 사용 가능)
    path: nginx-chart               # Chart가 위치한 Git 저장소 내 디렉토리 경로
    helm:                           # Helm 옵션 설정
      valueFiles:                   # 사용할 values.yaml 파일 목록
        - values.yaml               # nginx-chart 디렉토리 내 values.yaml 파일 사용
  destination:                      # Kubernetes 어디에 배포할 것인지 설정
    server: https://kubernetes.default.svc  # Kubernetes API Server 주소 (Cluster 내부 default)
    namespace: default              # 배포할 Kubernetes 네임스페이스 (없으면 위 syncOptions에서 자동 생성)
  syncPolicy:                       # ArgoCD 동기화 정책
    automated:                      # 자동 동기화 설정
      prune: true                   # Git에 없는 리소스 자동 삭제 (Git 기준으로 맞춤)
      selfHeal: true                # 수동으로 변경된 리소스를 자동으로 복구 (Git 상태와 다르면 덮어씀)
    syncOptions:                    # 추가 옵션 설정
    - CreateNamespace=true          # destination.namespace 가 없을 경우 자동 생성
EOF

 

ArgoCD UI에서 정상적으로 Application이 배포되었는지 확인

브라우저에 http://localhost:30080으로 접속 후 Applications 클릭

 

Kubernetes에 정상적으로 배포되었는지 확인

kubectl get po -o wide

# 결과
NAME                          READY   STATUS    RESTARTS   AGE
test-nginx-6748f55849-t7f8z   1/1     Running   0          6m

 


Webhook Event 연동을 위한 Ngrok 설치

Ngrok은 로컬에서 실행 중인 서버를 외부에서 접근할 수 있도록 해주는 도구입니다. 현재 우리는 개인 로컬 환경에서 ArgoCD를 실행하고 있기 때문에 외부에서 접근할 수 없습니다. ArgoCD에서 GitHub Webhook Event를 수신하기 위해서는 Ngrok을 사용하여 로컬에서 실행 중인 ArgoCD 서버를 외부에서 접근할 수 있도록 설정해야 합니다. Ngrok 설치하는 방법은 아래 링크를 참고하시기 바랍니다.

실제 현업에서는 Ngrok을 사용하지 않고 Cloud의 네트워크 설정을 통해 진행합니다.

[Ngrok 설치하기] https://ngrok.com/download

# MacOS에서 Ngrok 설치
brew install --cask ngrok

# Ngrok 확인
ngrok version

# Ngrok 설정
# Ngrok 사이트에 접속하여 [Ngrok 사이트](https://dashboard.ngrok.com/signup)에 회원가입을 하고 로그인합니다.
# 그리고 ngrok config add-authtoken <여기에-발급받은-authtoken>을 입력하여 ngrok을 설정합니다.
# 이때 발급받은 authtoken은 Ngrok 사이트에서 확인할 수 있습니다.
ngrok config add-authtoken <여기에-발급받은-authtoken>

# Ngrok 실행
ngrok http https://localhost:30443

 

 

Ngrok 실핼 결과

Forwarding으로 출력된 빨간 부분을 복사하여 GitHub Repo Webhook에 넣을 예정입니다.

 

GitHub Webhook Event 연동

기본적으로 ArgoCD에서는 GitHub Webhook Event를 지원하지 않아 3분마다 GitHub Repository를 Polling 하여 변경 사항을 확인합니다. 그렇기 때문에 최악의 경우 최대 3분 정도의 딜레이가 발생할 수 있습니다. 하지만 GitHub Webhook Event를 사용하면 GitHub에서 발생하는 이벤트를 즉시 수신하여 ArgoCD에 전달할 수 있습니다. 이를 통해 ArgoCD는 GitHub에서 발생하는 이벤트를 즉시 수신하고, 해당 이벤트에 따라 자동으로 배포를 수행할 수 있습니다.
우리는 Ngrok을 사용하여 로컬에서 실행 중인 ArgoCD 서버를 외부에서 접근할 수 있도록 설정하였으므로, Ngrok에서 제공하는 URL을 GitHub Webhook Event의 Payload URL로 설정합니다. 다음은 GitHub Webhook Event를 설정하는 방법입니다.

Payload URL에는 Ngrok Forwarding으로 출력된 값에 /api/webhook을 추가한 값을 입력하고 Content type에는 `application/json`값을 선택하여 webhook을 생성합니다.

webhook생성이 정상적으로 되었다면 다음과 같이 successful이란느 문구가 출력됩니다.

 

GitHub Webhook 테스트

여기까지 진행을 하였다면 정상적으로 GitHub Webhook Event를 ArgoCD에서 수신할 수 있는지 테스트를 진행하겠습니다.
replicaCount를 3으로 수정하였고, image.tag를 latest로 수정하여 git push를 진행합니다.

 

values.yaml

replicaCount: 3

image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "latest"

service:
  type: ClusterIP
  port: 80

 

테스트 결과 확인

 

Github Webhook 결과 확인

Github repo -> Settings -> Webhooks -> 웹훅선택 -> Recent Deliveries 선택

 

마지막으로

정상적으로 테스트 진행이 완료되었다면 깔끔하게 정리하고 싶은 분들은 아래와 같이 진행하시면 됩니다.

이부분은 선택사항이므로 굳이 진행을 안하셔도 됩니다.

# ArgoCD 삭제
helm uninstall argo-cd -n argocd
kubectl delete namespace argocd

# Ngrok 종료
brew uninstall --cask ngrok

# ArgoCD CLI 삭제
brew uninstall argocd

 

참고

https://argo-cd.readthedocs.io/en/stable/getting_started/

https://artifacthub.io/packages/helm/argo-cd-oci/argo-cd

https://medium.com/@jerome.decoster/argocd-minikube-ngrok-github-webhook-3cd0cc15d559

 

Argo Rollouts란?

Argo Rollouts는 Kubernetes에서 고급 배포 전략(Canary, Blue-Green 등)을 구현할 수 있도록 도와주는 배포 관리 컨트롤러입니다. 기본 Kubernetes의 Deployment는 새로운 버전이 배포될 때 기존 파드를 점진적으로 교체하는 Rolling Update 방식만 제공하는 반면, Argo Rollouts는 Canary, Blue-Green, Recreate 등 다양한 배포 전략을 지원합니다. 이를 통해 애플리케이션의 안정성을 높이고, 배포 과정에서 발생할 수 있는 문제를 최소화할 수 있습니다.
Argo Rollouts는 Argo CD와 함께 사용하여 GitOps 방식으로 배포를 관리할 수 있으며, Argo Workflows와 통합하여 CI/CD 파이프라인을 구축하는 데에도 유용합니다. 또한, Argo Rollouts는 Kubernetes의 Custom Resource Definition(CRD)을 사용하여 배포 리소스를 확장하고, 다양한 배포 전략을 지원합니다. 이번 문서에서는 간단하게 Argo Rollouts의 설치 방법과 Canary, Blue-Green 배포 전략을 사용하는 방법에 대해 알아보겠습니다.

 

Argo Rollouts은 왜 필요한가?

기본 Kubernetes의 Deployment는 Rolling Update 방식만 제공하기 때문에, 새로운 버전의 애플리케이션을 배포할 때 기존 파드를 점진적으로 교체하는 방식으로만 배포가 가능합니다. 이 경우, 새로운 버전의 애플리케이션이 문제가 발생할 경우 롤백이 어렵고, 배포 과정에서 발생할 수 있는 문제를 최소화하기 어렵습니다. Argo Rollouts는 이러한 문제를 해결하기 위해 다양한 배포 전략을 지원합니다.

  • 새 버전을 일부 트래픽만 먼저 받도록 배포하고 문제가 없는지 검증하는 Canary 배포
  • 기존 버전과 새 버전을 완전히 분리된 환경에서 배포한 뒤, 전환 시점을 제어하는 Blue-Green 배포
  • 실시간 모니터링과 메트릭 기반의 자동 판단, 수동 승인 또는 롤백
  • 배포 상태를 실시간으로 확인할 수 있는 CLI 또는 대시보드

 

Argo Rollouts은 어떻게 동작하는가?

Argo Rollouts는 Kubernetes의 Custom Resource Definition(CRD)을 사용하여 Deployment 리소스를 확장하고, 다양한 배포 전략을 지원합니다. 기본 Deployment 대신 Rollout 리소스를 정의하여, 컨테이너 이미지 버전 변경이나 레플리카 수 조정 등을 세밀하게 제어할 수 있습니다.

strategy:
  canary:
    steps:
    - setWeight: 20
    - pause: { duration: 1m }
    - setWeight: 50
    - pause: { duration: 2m }

이 설정은 새 버전을 20% 트래픽으로 먼저 배포한 후, 일정 시간이 지나고 50%로 늘려가며 점진적으로 전체로 확장하는 방식입니다.

 

Argo Rollouts 실습 전 요구 사항

  • Kubernetes 클러스터가 필요합니다. (버전 1.16 이상)
  • Helm이 설치되어 있어야 합니다. (버전 3.0 이상)

 

Argo Rollouts 설치하기

Argo Rollouts는 Helm Chart를 통해 설치할 수 있습니다. 아래의 명령어를 사용하여 Argo Rollouts를 설치합니다.

helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

helm upgrade argo-rollouts argo/argo-rollouts \
    --install \
    --namespace cicd \
    --create-namespace \
    --version 2.39.5 \
    --set dashboard.enabled=true \
    --set dashboard.service.type=NodePort \
    --set dashboard.service.nodePort=31000

NodePort는 선택사항입니다.

 

Argo Rollouts CLI 설치하기

Argo Rollouts CLI는 Argo Rollouts의 배포 상태를 확인하고, 배포 전략을 관리하는 데 사용됩니다. 아래의 명령어를 사용하여 Argo Rollouts CLI를 설치합니다. 필자는 MacOS를 사용하고 있으므로, MacOS에 맞는 설치 방법을 안내합니다. 다른 OS를 사용하고 있다면 아래 공식 문서를 참고하여 설치하시기 바랍니다.

[공식 문서]https://argoproj.github.io/argo-rollouts/installation/

# MacOS 
brew install argoproj/tap/kubectl-argo-rollouts

# 확인
kubectl argo rollouts version

 


Argo Rollouts Canary 배포하기

Argo Rollouts를 사용하여 Canary 배포를 수행하는 방법은 다음과 같습니다. 아래의 명령어를 사용하여 Nginx를 이용한 Canary 배포 예제를 수행해 보겠습니다.

 

canary.yaml 파일 내용

apiVersion: argoproj.io/v1alpha1   # Argo Rollouts에서 사용하는 API 그룹과 버전
kind: Rollout                      # 리소스 종류: Rollout (Deployment와 유사하지만 Rollouts용)
metadata:
  name: canary-nginx               # Rollout 리소스 이름 (kubectl에서 이 이름으로 관리함)
spec:
  replicas: 10                     # 원하는 파드 개수
  selector:
    matchLabels:
      app: canary-nginx
  template:                        # 실제로 배포될 Pod 템플릿 (Deployment와 동일)
    metadata:
      labels:
        app: canary-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16
        ports:
        - containerPort: 80
  strategy:
    canary:                        # 배포 전략을 Canary 방식으로 설정
      steps:                       # 점진적 배포 단계를 정의
      - setWeight: 20              # 새 버전(nginx:1.16 → 변경 시)의 트래픽 비율을 20%로 설정
      - pause: { duration: 1m }    # 1분간 정지 (사용자가 검토 또는 자동 모니터링 가능)
      - setWeight: 50              # 그 다음 50% 트래픽을 새 버전으로 전환
      - pause: { duration: 1m }    # 다시 1분간 정지
      

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: canary-nginx
  name: canary-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30080
  selector:
    app: canary-nginx
  type: NodePort

필자는 테스트를 위해 Service의 타입을 NodePort로 설정하였습니다.

 

canary nginx 배포 및 테스트

# Rollout 생성
kubectl apply -f canary.yaml
# Rollout 상태 확인
kubectl argo rollouts get rollout canary-nginx

# image 업데이트
kubectl argo rollouts set image canary-nginx nginx=nginx:1.19.0
# Rollout 상태 확인
kubectl argo rollouts get rollout canary-nginx --watch

 

canary 결과

kubectl argo rollouts get rollout canary-nginx --watch

 

 

Argo Rollouts Blue-Green 배포하기

Argo Rollouts를 사용하여 Blue-Green 배포를 수행하는 방법은 다음과 같습니다. 아래의 명령어를 사용하여 Nginx를 Blue-Green 배포 예제를 수행해 보겠습니다.

 

blue-green.yaml 파일 내용

# bg-rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: bg-nginx
spec:
  replicas: 10
  selector:
    matchLabels:
      app: bg-nginx
  template:
    metadata:
      labels:
        app: bg-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16
        ports:
        - containerPort: 80
  strategy:
    blueGreen:
      activeService: bg-nginx-active     # 실제 유저 트래픽용 서비스
      previewService: bg-nginx-preview   # 새 버전 미리보기용 서비스
      autoPromotionEnabled: false        # 수동으로 promote 해야만 버전 전환

---
apiVersion: v1
kind: Service
metadata:
  name: bg-nginx-active
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30081
  selector:
    app: bg-nginx
  type: NodePort

---
apiVersion: v1
kind: Service
metadata:
  name: bg-nginx-preview
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30082
  selector:
    app: bg-nginx
  type: NodePort

 

blue-green nginx 배포 및 테스트

# Rollout 생성
kubectl apply -f blue-green.yaml

# image 업데이트
kubectl argo rollouts set image bg-nginx nginx=nginx:1.19
# Rollout 상태 확인
kubectl argo rollouts get rollout bg-nginx --watch
# 새 버전으로 트래픽 전환
# autoPromotionEnabled=false로 설정했기 때문에 수동으로 트래픽을 전환해야 합니다.
kubectl argo rollouts promote bg-nginx

# 롤백 (문제 있을 경우)
kubectl argo rollouts undo bg-nginx

 

blue-green 트래픽 전환 전 모습

kubectl argo rollouts set image bg-nginx nginx=nginx:1.19

 

blue-green 트래픽 전환 후 모습

kubectl argo rollouts promote bg-nginx

 


Argo Rollouts Dashboard 확인

위와 같이 진행을 하였다면 NodePort 31000으로 대시보드 또한 배포되어 localhost:31000으로 rollouts의 결과를 확인할 수 있습니다.

 

kubernetes max pods

Kubernetes 공식 문서에 따르면 기본 설정으로 노드 당 최대 110개의 파드를 생성할 수 있습니다. 이는 노드에서 파드의 IP를 할당하기 위해서입니다. IP 주소 자원은 한정되어 있기 때문에, 노드당 생성할 수 있는 파드 수를 제한하여 네트워크 충돌을 방지하고 안정적인 운영을 보장하고 있습니다.

 

아래 이미지는 Kubernetes 공식 문서에서 제시하는 기본값입니다.

  • 노드는 최대 110개의 파드
  • 클러스터는 최대 5000개의 노드
  • 클러스터는 최대 150000개의 파드
  • 클러스터는 최대 300000개의 컨테이너

 

kubernetes max pods 개수 수정

kubernetes 공식 문서에서 제공하는 기본 값을 사용하는 것을 권장하지만 그래도 상황에 따라 노드의 개수는 늘리지 못하지만 최대 파드의 개수가 더 필요한 경우가 있습니다. 이번 문서에서는 최대 파드의 개수를 수정하는 방법에 대해 알아보겠습니다.

 

현재 노드의 할당할 수 있는 파드의 개수 확인

$ kubectl get nodes -o=custom-columns=NODE:.metadata.name,MAXPODS:.status.capacity.pods
NODE      MAXPODS
master    110
worker1   110
worker2   110

 

해당 worker node kubelet 수정

먼저 worker node에 접속하여 sudo 권한을 부여하고 maxPods의 내용을 추가합니다.

vi /var/lib/kubelet/config.yaml
# 아래 내용 추가
maxPods: 250

 

worker node kubelet 재시작

sudo systemctl daemon-reload
sudo systemctl restart kubelet

 

결과 확인

$ kubectl get nodes -o=custom-columns=NODE:.metadata.name,MAXPODS:.status.capacity.pods
NODE      MAXPODS
master    110
worker1   250
worker2   250

 

 

참고 문서

https://kubernetes.io/docs/setup/best-practices/cluster-large/

https://github.com/kubernetes/kubernetes/issues/23349

 

컨테이너를 실행할 때, 여러 옵션을 사용하여 실행 중인 컨테이너에 리소스 제한을 설정할 수 있습니다. 이를 통해 컨테이너가 사용할 수 있는 CPU, 메모리, 디스크 공간 등과 같은 리소스 사용을 세밀하게 제어할 수 있습니다. Docker는 일반적으로 리소스를 자동으로 관리하지만, 경우에 따라 직접 리소스 제한을 설정하는 것이 필요할 수 있습니다. 이를 통해 컨테이너의 성능을 최적화하고, 다른 컨테이너나 호스트 시스템과의 리소스 경쟁을 관리할 수 있습니다. 예를 들어, CPU 제한을 설정하여 컨테이너가 특정 CPU 점유율을 초과하지 못하도록 할 수 있고, 메모리 제한을 설정하여 컨테이너가 지정된 메모리 양을 초과하지 않도록 할 수 있습니다. 이러한 리소스 제한 옵션을 사용하면 컨테이너의 안정성과 성능을 개선할 수 있습니다.

 

현재 동작하는 컨테이너의 resource 사용량 확인하기

docker stats 명령어를 사용하면 실행 중인 모든 컨테이너의 실시간 리소스 사용량을 확인할 수 있습니다.

docker stats 컨테이너아이디1, 컨테이너아이디2 ...

 

컨테이너 resource 사용 제한하기

--cpus 옵션을 사용하여 컨테이너에 할당할 CPU 코어의 개수를 지정할 수 있습니다.

 docker run -d --cpus=1 --name test-cpus nginx:latest

 

--cpu-shares 옵션은 Docker에서 CPU 리소스를 컨테이너 간에 분배하는 데 사용되는 상대적인 가중치를 설정하는 데 사용됩니다. 아래 설정은 기본값인 1024보다 낮은 가중치를 의미하므로, 다른 컨테이너에 비해 상대적으로 적은 CPU 리소스를 할당받을 수 있습니다.

docker run -d --cpu-shares=512 --name test-cpu-share nginx:latest

 

--memory 옵션을 사용하여 컨테이너에 할당할 메모리 양을 지정할 수 있습니다.

docker run -d --memory=1g --name test-memory nginx:latest

 

위에서 설정한 리소스 사용량 확인

 

기존 컨테이너 리소스 제한하기

앞에서는 컨테이너를 실행할 때 리소스를 제한하는 법에 대해서 알아봤지만 docker update를 이용하여 기존에 동작하고 있던 컨테이너에서도 리소스를 제한할 수 있습니다.

# 테스트용 컨테이너 생성
$ docker run -d --name test-nginx nginx:latest

# 테스트용 컨테이너 상태 확인
$ docker stats --no-stream test-nginx

 

docker update 명령어를 통해 리소스 제한 업데이트

# 리소스 설정 변경
$ docker update --memory-swap 1g --memory 1g test-nginx

# 테스트용 컨테이너 상태 확인
$ docker stats --no-stream test-nginx

도커 컨테이너 파일 시스템의 생명 주기는 컨테이너의 생명 주기와 같습니다. 그렇기 때문에 컨테이너가 지워지면 컨테이너에서 기록한 데이터도 같이 지워지는데요. 이런 경우를 방지하기 위해 컨테이너의 데이터를 유지하고 관리할 수 있어야 합니다. 이런 기능을 제공하는 것이 대표적으로 2가지가 있는데 바로 volume과 bind mount입니다. 이번에는 volume과 bind mount에 대해서 정리하였습니다.

 

Docker volume

volume 생성하기

volume 명령어를 사용하여 직접적으로 volume을 생성하게 되면 /var/lib/docker/volumes/볼륨명으로 해당 볼륨의 디렉토리가 생성됩니다. 컨테이너는 해당 디렉토리를 컨테이너 경로로 마운트 하여 데이터를 읽고 쓰게 되면서 컨테이너가 기록하는 데이터를 유지할 수 있습니다.

$ docker volume create 볼륨명

volume 확인하기

생성된 volume을 `docker volume ls` 를 통하여 확인할 수 있습니다.

$ docker volume ls

volume 컨테이너에 마운트 하기

생성한 볼륨을 컨테이너에 마운트 합니다.

$ docker run 이미지명 --name 컨테이너명 -d -v <볼륨명>:<컨테이너 경로>

volume 삭제하기

`docker volume rm 볼륨명`을 통하여 볼륨을 삭제할 수 있는데 만약 해당 볼륨을 컨테이너가 사용 중이라면 해당 컨테이너부터 삭제하고 볼륨을 삭제해야 합니다.

$ docker volume rm 볼륨명

사용하지 않은 volume 전부 삭제하기

볼륨을 무작위로 생성하다 보면 사용하지 않는 볼륨들이 많이 존재하게 되는데 다음과 같은 명령어를 통하여 사용하지 않는 볼륨을 한 번에 삭제할 수 있습니다.

$ docker volume prune --all --force

dockerfile로 볼륨 생성하기

도커파일에서 생성한 볼륨은 호스트 경로의 /var/lib/docker/volumes/볼륨해쉬에 만들어집니다. Dockerfile로 생성한 volume은 매번 컨테이너를 생성할 때마다 무작위로 생성되기 때문에 사용할 때 주의해야 하며 나중에 사용 안 하는 볼륨을 지워줘야 한다.

FROM ubuntu:latest

# 볼륨을 마운트할 디렉토리 생성
RUN mkdir /app

# 볼륨 마운트 지정
VOLUME /app

# 컨테이너 내부의 파일 생성
RUN echo "Hello, Docker Volume!" > /app/data.txt

--volume-from 옵션 사용하기

Docker 컨테이너에게 다른 컨테이너에서 마운트 된 볼륨을 공유하도록 지시하는 명령어입니다. 이를 통해 볼륨을 한 컨테이너에서 생성하고 다른 컨테이너에서 사용할 수 있습니다.

$ docker volume create my-volume
$ docker run -d --name test-1 ubuntu:20.04 -v my-volume:/data
$ docker run -d --name test-2 ubuntu:20.04 --volume-from test-1

위 명령어를 이용하면 test-1에서 사용 중인 my-volume을 test-2에서도 사용할 수 있습니다.

 

Bind Mount

바인드 마운트는 호스트 시스템의 특정 경로를 컨테이너 내부 경로에 직접 연결을 하기 때문에 호스트와 컨테이너 간에 파일이 실시간으로 동기화할 수 있습니다. 저 같은 경우 개발을 한 애플리케이션의 로그를 확인하기 쉽게 하기 위해 로그 파일의 경로를 바인트 마운트 경로로 잡아서 사용하는 경우가 많습니다.

$ docker run -v 호스트경로:컨테이너경로 이미지:태그

또한 --mount 옵션을 이용하여 Bind Mount를 수행할 수 있는데 --mount를 이용하면 보다 섬세한 설정을 할 수 있습니다.

아래를 --mount 옵션을 이용하여 readonly 설정을 통해 컨테이너는 해당 파일 시스템에 readonly 권한으로 밖에 접근할 수 없도록 설정한 예시입니다.

$ docker run --mount type=bind,source=~/data,target=/data,readonly -d 이미지:태그

그밖에 옵션을 통해 여러가지 형식으로 마운트를 할 수 있습니다.

$ docker run --mount type=bind,source=호스트경로,target=컨테이너경로,옵션=값,옵션=값,...

 

Container 상태는 Run 상태인데 실제 내부적인 문제로 인해 Container가 정상적으로 동작하지 않는 경우가 있다. 이런 경우 Dockerfile을 이용하여 컨테이너 이미지를 빌드할 때 HEALTHCHECK 인스트럭션을 사용하여 컨테이너의 상태를 확인할 수 있습니다. 

 

HEALTHCHECK 작성 형식

HEALTHCHECK [option] CMD 명령어
  • --interval : 헬스 체크 간격을 지정합니다. default 30s
  • --timeout : 명령어의 타임아웃을 설정합니다. default 30s
  • --start-period : 컨테이너가 실행되고 헬스 체크를 시작하기까지 대기하는 시간을 지정합니다. default 0s
  • --retries : 헬스 체크 명령어 실행 실패 시 재시도 횟수를 지정합니다. default 3

 

HEALTHCHECK 예시

FROM nginx:latest
HEALTHCHECK --interval=10s --timeout=3s CMD curl -f http://localhost/ || exit 1

curl -f http://localhost/ 명령어를 통하여 10초 간격으로 3초 이내의 결과가 나타나지 않고 3번 이상 실패 시 unhealthy 하다고 판단합니다. 상태를 확인하는 방법은 "docker ps -a"를 통해 해당 컨테이너의 상태를 확인할 수 있지만 "docker inspect 컨테이너아이디"를 통하여 보다 자세한 상태를 확인할 수 있습니다. 아래는 docker inspect 명령어를 통해 확인한 결과입니다.

(생략...)
	"State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 32813,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2023-07-06T12:18:15.929466969Z",
            "FinishedAt": "0001-01-01T00:00:00Z",
            "Health": {
                "Status": "healthy",
                "FailingStreak": 0,
                "Log": [
                    {
                        "Start": "2023-07-06T12:18:45.930156552Z",
                        "End": "2023-07-06T12:18:46.006446885Z",
                        "ExitCode": 0,
                        "Output": "  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n                                 Dload  Upload   Total   Spent    Left  Speed\n\r  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0\r100   615  100   615    0     0   637k      0 --:--:-- --:--:-- --:--:--  600k\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n\u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n\u003cstyle\u003e\nhtml { color-scheme: light dark; }\nbody { width: 35em; margin: 0 auto;\nfont-family: Tahoma, Verdana, Arial, sans-serif; }\n\u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003ch1\u003eWelcome to nginx!\u003c/h1\u003e\n\u003cp\u003eIf you see this page, the nginx web server is successfully installed and\nworking. Further configuration is required.\u003c/p\u003e\n\n\u003cp\u003eFor online documentation and support please refer to\n\u003ca href=\"http://nginx.org/\"\u003enginx.org\u003c/a\u003e.\u003cbr/\u003e\nCommercial support is available at\n\u003ca href=\"http://nginx.com/\"\u003enginx.com\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003eThank you for using nginx.\u003c/em\u003e\u003c/p\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n"
                    }
                ]
            }
        },
(생략...)
	"Healthcheck": {
                "Test": [
                    "CMD-SHELL",
                    "curl -f http://localhost/ || exit 1"
                ],
                "Interval": 30000000000,
                "Timeout": 3000000000
            },
(생략...)

 

HEALTHCHECK의 상태 값

healthcheck의 상태 값은 3가지 종류로 나뉩니다.

  • starting : 컨테이너가 시작되고 --start-period로 정의된 대기 시간이 경과하기 전의 초기 상태입니다. 이 시간 동안 HEALTHCHECK가 수행되지 않으며, 컨테이너는 자동으로 healthy 상태로 표시됩니다.
  • healthy : HEALTHCHECK 명령이 성공적으로 실행되고 정상적인 상태를 반환한 경우입니다. 컨테이너가 정상적으로 작동하고 있다는 의미입니다.
  • unhealthy : HEALTHCHECK 명령이 실패하거나 비정상적인 상태를 반환한 경우입니다. 이는 컨테이너가 문제가 있거나 제대로 작동하지 않고 있다는 의미입니다.

healthcheck를 통하여 컨테이너의 상태를 표시할 뿐 도커는 컨테이너가 unhealthy 상태여도 컨테이너를 자동으로 재시작하는 기능을 수행하지 않습니다. 그 이유는 컨테이너를 재시작할 경우 애플레케이션이 일시적으로 드랍되면서 서비스에 문제가 발생할 수 있기 때문입니다. 도커의 입장에서 애플리케이션의 드랍으로 더 큰 문제가 발생될 수 있기 때문에 사용자에게 상태만 보고할 뿐 재시작을 수행하지 않습니다.

본 문서는 2023년 7월에 작성된 문서입니다.

Artifact Hub는 Kubernetes 커뮤니티의 중앙 리소스 저장소로서, 다양한 애플리케이션 패키지, Helm 차트, OPA 정책, Falco 규칙 등을 검색, 탐색 및 공유할 수 있는 오픈 소스 플랫폼입니다. 즉 Artifact Hub는 사용자와 Helm chart repository를 중개하는 역할을 수행하고 있습니다. 오늘은 Helm package를 Artifact Hub에 등록하여 사용하는 방법에 대하여 정리하였습니다.

 

시작하기 전에

Helm chart repository는 github으로 구성하고 Artifact Hub를 이용하여 Helm chart repository와 중개하도록 구성하였습니다.

 

1. github repo 생성

자신의 github에 helm package를 등록할 수 있도록 github repository를 생성하여 줍니다. 저는 repository 명을 test-nginx라고 명시하였습니다.

 

2. 실습 디렉토리 구성

helm-nginx 디렉토리는 실제 helm chart를 작성하였고 test-nginx는 방금 생성한 github repo를 clone 한 디렉토리입니다. helm-nginx 디렉토리에서 작성된 helm chart를 test-nginx에 package 하여 github에 push를 할 예정입니다.

 

3. Helm chart 작성

helm-nginx 디렉토리로 이동하여 helm chart를 간단하게 구성도록합니다. 이번 실습에서는 불필요한 부분은 제거하고 values.yaml파일과 templates/deployment.yaml만 작업하였습니다.

values.yaml

위에 사진과 내용이 동일합니다. (실습 복붙용)

name: test-nginx

replicas: 1

imageTag: latest

resources:
  requests:
    memory: "64Mi"
    cpu: "250m"
  limits:
    memory: "128Mi"
    cpu: "500m"

deployment.yaml

위에 사진과 내용이 동일합니다. (실습 복붙용)

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: {{ .Values.name }}
  name: {{ .Values.name }}
spec:
  replicas: {{ .Values.replicas }}
  selector:
    matchLabels:
      app: {{ .Values.name }}
  template:
    metadata:
      labels:
        app: {{ .Values.name }}
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        resources:
{{ toYaml .Values.resources | indent 10 }}

정상적으로 작성되었는지 확인

--dry-run 옵션을 통해 실제로 생성하지 않고 helm이 잘 작성되었는지 확인할 수 있습니다.

$ helm install test --dry-run .
# 결과
NAME: test
LAST DEPLOYED: Sat Jul  1 13:51:49 2023
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: helm-nginx/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test-nginx
  name: test-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-nginx
  template:
    metadata:
      labels:
        app: test-nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        resources:
          limits:
            cpu: 500m
            memory: 128Mi
          requests:
            cpu: 250m
            memory: 64Mi

 

4. helm package 생성

상위 디렉토리인 helm 디렉토리로 이동하여 helm package 명령을 수행하여 package를 생성합니다.

# helm package 생성
$ helm package ./helm-nginx/ --destination ./test-nginx

# helm index 생성
$ helm repo index ./test-nginx

# 결과 확인
$ ls -al ./test-nginx/
total 24
drwxr-xr-x 3 hsw hsw 4096 Jul  1 14:52 .
drwxr-xr-x 4 hsw hsw 4096 Jul  1 14:27 ..
drwxr-xr-x 8 hsw hsw 4096 Jul  1 14:53 .git
-rw-r--r-- 1 hsw hsw    6 Jul  1 14:27 README.md
-rw-r--r-- 1 hsw hsw  799 Jul  1 14:27 helm-nginx-0.1.0.tgz
-rw-r--r-- 1 hsw hsw  397 Jul  1 14:52 index.yaml

 

5. github push

$ git add .
$ git commit -m "create helm package"
$ git push

 

6. github pages 설정

Settings - Pages로 이동하여 다음과 같이 설정합니다. 3번까지 수행한 후 해당 페이지를 새로고침 하면 4번처럼 주소가 나옵니다. 해당 주소를 복사하고 있다가 Artifact Hub 설정에서 사용합니다.

 

7. Artifact Hub에 등록하기

Artifact Hub에 접속하여 로그인합니다.

https://artifacthub.io/

 

Artifact Hub

Find, install and publish Kubernetes packages

artifacthub.io

 

우측 상단 User 아이콘 클릭 후 Control Panel을 선택하여 줍니다.

 

ADD REPOSITORY를 선택하게 되면 다음과 같이 화면이 나오는데 여기서 해당된 값을 입력합니다.

  • Kind : Helm charts
  • Name : 등록될 Repository 이름
  • Display name : 사용자에게 보이는 이름
  • Url : 등록할 github 주소

ADD 버튼을 클릭하여 추가하게 되면 다음과 같이 Repo가 생성됩니다.

Repo 설정이 완료되었다면 일정 시간 간격(약 30분)으로 Repo 스캔을 하게 됩니다. 스캔이 완료되면 해당 Repo를 통하여 helm을 이용해 배포할 수 있습니다.

 

'DevOps' 카테고리의 다른 글

[Docker] resource 설정  (0) 2023.07.27
[Docker] Volume & BindMount  (0) 2023.07.25
[Docker] 컨테이너 HEALTHCHECK  (0) 2023.07.23
[Helm] Helm 기본 명령어  (0) 2023.07.15
2023 CKA(Certified Kubernetes Administrator) 취득 후기  (0) 2023.07.01

본 문서는 2023년 7월에 작성된 문서입니다.

Helm은 Kubernetes 애플리케이션을 배포, 관리 및 업데이트하기 위한 패키지 관리 도구입니다. Helm은 Kubernetes 클러스터에서 애플리케이션을 쉽게 설치하고 관리하기 위한 기능을 제공합니다. Helm은 "차트"라고 하는 패키지 형식을 사용하여 Kubernetes 애플리케이션을 정의합니다. 차트는 Kubernetes 리소스 (파드, 서비스, 볼륨 등)를 정의하는 템플릿 파일과 해당 애플리케이션을 배포하고 구성하는 데 필요한 매개변수 및 값들을 포함합니다. 이러한 차트를 사용하여 애플리케이션을 쉽게 배포하고 업데이트할 수 있습니다.

helm 설치

아래 링크를 통하여 helm 설치를 진행하여 줍니다.

https://helm.sh/docs/intro/install/

 

Installing Helm

Learn how to install and get running with Helm.

helm.sh

helm repository

helm으로 설치를 진행하기 위해서는 chart를 가지고 있는 repository를 등록하여 사용해야 합니다.

# 설치하는데 필요한 chart를 가져오는 repository를 등록합니다.
helm repo add 레포지토리명 레포지토리주소

# 등록한 repository에서 설치할 수 있는 목록을 출력합니다.
helm search 레포지토리명

# 등록한 repository를 최신으로 update합니다.
helm repo update

helm install

앞에서 repo를 등록하였다면 이제는 등록된 repo를 이용하여 kubernets에 설치 작업을 진행할 수 있습니다.

helm install -n 네임스페이스 --create-namespace 앱이름 레포지토리명/설치할앱

helm upgrade

기존에 설치했던 설정값이 변경되었을 경우 helm upgrade를 통하여 변경된 내용을 적용할 수 있습니다.

helm upgrade -n 네임스페이스 앱이름 레포지토리명/설치할앱

helm delete

더 이상 배포한 앱을 사용하지 않는다면 helm delete를 통해 자원을 반납할 수 있습니다.

helm delete -n 네임스페이스 앱이름

 

[실습] helm을 이용하여 kubernetes에 nginx 설치하기

이번에 실습 예시로 helm을 이용하여 kubernets 환경에 nginx를 기본 값으로 설치하는 방법에 대해서 알아보겠습니다. helm의 repository는 ArtifactHub에서 검색할 수 있습니다. 

https://artifacthub.io/

 

Artifact Hub

Find, install and publish Kubernetes packages

artifacthub.io

 

ArtifactHub에서 nginx를 검색하면 다음과 같이 나오는데요 여기서 중요하게 봐야 되는 것 3가지가 있습니다.

먼저 어느 단체에서 만들었는지 그리고 Star를 몇개 받았는지 마지막으로 인증된 helm chart인지를 확인하여 사용자에게 가장 합리적인 것을 선택하여 줍니다.

 

페이지로 들어오면 다음과 같은 화면이 나옵니다. 이 페이지에서 helm chart에 대한 상세한 설명이 나오니 정확한 정보를 확인하기 위해서는 해당 페이지를 참고하는 것을 추천드립니다.

이제 Kubernetes 환경에 nginx를 설치하기 위해서는 INSTALL 버튼을 클릭하여 줍니다.

 

화면에 출력된 명령어를 입력하게 되면 자신의 환경에 nginx가 설치됩니다.

결과 확인

$ kubectl get po
NAME                        READY   STATUS    RESTARTS   AGE
my-nginx-6ff77558fc-qzgw5   1/1     Running   0          15s

설치 내역 삭제하기

helm delete my-nginx

 

 

 

본 문서는 2023년 6월에 작성된 문서입니다. 시간이 지나면 현재 시험 방식과 많이 다를 수 있습니다.


저는 회사에서 2년 넘게 Kubernetes를 사용을 하여 Kubernetes에 익숙한 상태였고 이왕 Kubernetes를 사용할 줄 알게 된 거 이 기회에 CKA를 취득하는 게 좋을 것 같아 시험을 보게 되었습니다. CKA 준비 기간은 2 ~ 3주 정도 걸렸으며 모든 부분을 공부한 것이 아닌 부족한 부분만 골라 보면서 공부를 하였습니다.

결제는 어떻게?

https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/

 

Certified Kubernetes Administrator (CKA) Exam | Linux Foundation

Training in skills, knowledge, and competency to perform the responsibilities of Kubernetes administrators.

training.linuxfoundation.org

결제 진행 방식은 위 링크를 통해 Linux Foundation에 로그인 후 결제를 진행하면 됩니다. 여기서 약간의 팁은 CKA는 자주 할인을 진행하는데 적게는 15%에서 많게는 40%까지 할인을 받을 수 있습니다. 저 같은 경우 40% 해택을 받아 321,256원으로 결제할 수 있었습니다. 여기서 환율이 적용되기 때문에 환율이 좋을 때 구매를 진행하시면 같은 40% 할인이어도 실제 구매한 가격이 다를 수 있습니다.
할인 코드 확인 방법은 https://training.linuxfoundation.org/blog/ Linux Foudation 블로그에 게시물로 업로드가 되는데 그때 코드를 받아 결제를 진행하시면 됩니다.

CKA 공부 방법

저는 회사에서 Kubernetes를 2년 이상 사용하였습니다. 회사에서 사용하였을 때는 "마사야 야오야마"가 지은 "쿠버네티스 완벽 가이드"라는 책으로 공부를 하였고 CKA 준비를 하기 위해서는 Udemy에 "Mumshad Mannambeth"의 "Certified Kubernetes Administrator (CKA) with Practice Tests" 강의를 들었습니다. 저는 어느 정도 Kubernetes를 사용하여 부족한 부분만 골라서 강의를 들었습니다. 여기서 제공하는 실습문제가 실제로 많이 도움이 되었기 때문에 실습문제는 반드시 풀어보는 게 좋습니다. 이 강의 또한 할인을 자주 하기 때문에 관심등록을 통해 할인한다는 알림을 받게 되면 그때 구입하는 것을 추천드립니다. 원래 가격은 99,000원이지만 할인을 받게 되면 15,000에서 20,000원에 결제할 수 있습니다.

https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests/

Killer.sh 후기

CKA 시험을 결제하게 되면 Killer.sh라는 실제 시험 환경과 아주 비슷한 환경을 제공해 줍니다. 세션을 시작하면 36시간 동안 지속적으로 비슷한 시험 환경에서 예상문제를 풀 수 있는 세션을 2개 줍니다. 1개의 세션은 36시간 동안 접속할 수 있기 때문에 주말에 문제를 여러 번 풀어보면 많은 도움이 됩니다. 세션은 2개 주지만 2개의 세션 모두 시험문제가 동일하니 굳이 2개의 세션을 사용하지 않으셔도 됩니다. 참고로 Killer.sh는 실제 CKA 시험 문제보다 어려운 문제가 나오니 여기서 좋지 못한 점수를 받았다고 낙심하지 마세요. 그리고 Killer.sh는 문제와 풀이 과정까지 전부 PDF로 제공하여 부족한 부분을 공부하는데 좋습니다.

CKA 당일!!!

PSI 브라우저 설치

시험 날짜를 정하고 나면 이메일로 PSI 브라우저를 설치할 수 있는 링크를 보내줍니다. PSI 브라우저는 시험 보기 30분 전에 설치할 수 있으며 설치가 완료되고 PSI를 구동하면 PSI와 동시에 동작할 수 없는 프로세서를 강제적으로 종료하고 시험에 입장을 하게 됩니다. 이때 PSI와 같이 동작할 수 없는 프로그램은 대표적으로 크롬입니다. 참고로 PSI에서 버튼을 누르면 PSI가 알아서 프로그램을 종료하니 미리 프로그램을 종료하지 않으셔도 됩니다. 

준비물

폐쇄된 공간(집보다는 주말에 회사에 출근하여 폐쇄된 회의실에서 시험을 보는 것을 추천), 여권, 웹캠(노트북 가능), 최소 15인치 이상의 화면(듀얼모니터 불가능)

감독관과의 소통

PSI 브라우저 설치가 모두 정상적으로 끝나면 감독관과 채팅을 하게 되는데.. 영어를 잘 모르는 저의 입장에서는 모든 시험 통틀어서 가장 힘든 순간이었습니다. 먼저 여권으로 신원을 확인하고 노트북에 달린 웹캠으로 시험 보는 공간을 감독관에게 확인시켜주어야 합니다. 그리고 감독관이 주변에 어떠한 물건을 치우라고 하면 바로바로 치워주면 시험을 시작하게 됩니다. 저는 감독관과 채팅을 시작하자마자 "I am not good english"라고 알려주었더니 제가 영어를 못 알아듣는 거 같으니 감독관 단어 하나씩 채팅에 쳐서 알려주는 친절함을 보여주었습니다. 그러니 영어를 잘 모르더라도 너무 두려워하지 않으셔도 됩니다.

실제 시험 환경

시험장에 들어가면 아래 이미지와 같은 환경에서 시험을 보게 됩니다. 우측 상단에는 응시자(본인)의 얼굴이 나오는데 화면에 반드시 얼굴이 벗어나면 안 됩니다. 얼굴이 화면에 벗어나게 되면 채팅창으로 감독관이 카메라에 얼굴이 나와야 된다는 메시지를 보냅니다. 그리고 가장 중요한 팁은 바로 복사 붙여 넣기인데요 저는 윈도우 노트북으로 시험을 진행하였는데 터미널과 파이어폭스, 메모장의 복붙 단축키가 다릅니다.
터미널 : ctrl + shift + c(복사), ctrl + shift + v(붙여 넣기)
파이어폭스, 메모장 : ctrl + c(복사), ctrl + v(붙여 넣기)
파이어폭스 Kubernets document에서 yaml을 복사할 때는 ctrl + c로 복사하여 터미널에서는 ctrl + shift + v로 붙여 넣어야 합니다.

참고로 현재는 문제의 언어를 선택할 수 있는데 영어, 중국어, 일본어만 제공하고 있습니다.
그리고 정말 인터넷이 아주 느리니 무조건 유선으로 시험 보는 것을 추천드리고 생각보다 PSI 브라우저가 매우 무겁습니다. 그렇기 때문에 어느 정도 성능이 좋은 컴퓨터로 시험을 보는 것을 추천드립니다.

CKA 문제 유형

문제는 15 ~ 20개 정도 나오고 2시간 동안 풀 수 있습니다. 저의 경우 17문제 나왔고 문제의 유형은 아래 리스트처럼 나왔습니다.

  • pod 생성
  • 멀티 컨테이너 pod 생성
  • 사이드카 컨테이너 pod 생성
  • deploy, statefulset, daemonset 등 생성
  • service expose
  • pv, pvc 생성 후 마운트
  • ingress, networkpolicy
  • rbac
  • etcd 백업
  • version upgrade
  • Troubleshooting

CKA Tip

  1. kubectl 자동완성은 기본적으로 적용되어 있습니다.
  2. alias k="kubectl"은 기본적으로 적용되어 있습니다.
  3. etcdctl 이 이미 설치되어 있습니다.
  4. export do="--dry-run=client -o yaml"를 미리 정의해 두면 dry-run을 수행할 때 조금은 더 빠르게 작업할 수 있습니다.
  5. kubectl create --help를 통해 create로 생성할 수 있는 리소스는 create로 생성하고 create로 생성할 수 없는 리소스는 kubernetes document에서 복사하는 게 빠릅니다. (예시로 pv, pvc는 빨리 document에서 복사해 오자)
  6. PSI 브라우저 바탕화면에서 우클릭하여 메모장을 생성 후 사용할 수 있습니다.
  7. 파이어폭스에서 ctrl + f로 검색을 하고 아래에 search highlight 체크박스 선택을 통해 검색을 강조하여 볼 수 있습니다.
  8. 파이어폭스에서 실수로 ctrl + shift + c를 누르면.. 개발자 모드가 나오는데 인터넷이 매우 느려 개발자 모드를 끄는데도 5 ~ 10초 정도 소요됩니다.
  9. 내 얼굴이 나오는 상단 메뉴를 접어 화면을 조금 더 크게 사용할 수 있다.

외우면 좋은 거

  1. etcd 백업 방법
  2. manifest위치 (/etc/kubernetes/manifests)
  3. PKI 위치 (/etc/kubernetes/pki/)
  4. 파드 DNS 확인 (kubectl exec -it 파드명 -- cat /etc/resolv.conf)
  5. kubelet 로그 확인 (journalctl -u kubelet)

CKA 시험 결과

2023년 6월 6일 시험을 봤고 6월 7일에 시험 결과가 나왔고 결과는 한 번에 합격할 수 있었습니다.!!!
CKA에 도전하는 분들 모두 응원합니다.

 

'DevOps' 카테고리의 다른 글

[Docker] resource 설정  (0) 2023.07.27
[Docker] Volume & BindMount  (0) 2023.07.25
[Docker] 컨테이너 HEALTHCHECK  (0) 2023.07.23
[Helm] helm package를 ArtifactHub에 등록하기 (with github)  (0) 2023.07.16
[Helm] Helm 기본 명령어  (0) 2023.07.15

+ Recent posts