카카오클라우드

카카오클라우드 미니 프로젝트 1(쿠버네티스 PVC, HPA 설정 및 부하 테스트)

점프킹 2025. 4. 11. 08:38

1. 프로젝트 flow

step 1) K8SE 클러스터 생성
step 2) 노드 풀 생성
step 3) 파일스토리지 생성 및 NFS Client Provisioner 설정
step 4) CR에 이미지 저장하고, 저장된 이미지로 웹 서비스 띄우기
             CR - KC 서비스 / 각 파드별 볼륨 마운트는 hostpath가 아닌 nfs로 생성한 pvc
step 5) CR에 저장된 이미지로 pod 띄우기
step 6) HPA설정으로 위에 생성된 pod를 최소 1개, 최대 3개로 HPA 구성
             설정 후 부하를 발생시켜서 자동 확장, 축소가 제대로 되는지 체크

2. K8SE 클러스터 및 노드풀 생성

1. 클러스터 생성 

아래 링크를 참조하여 클러스터를 생성한다.

쿠버네티스 버전 : 1.29 / CNI : Calico / 노드풀 : 3개

https://docs.kakaocloud.com/service/container-pack/k8se/how-to-guides/k8se-manage-cluster#create-cluster

 

3. 파일스토리지 생성 및 NFS Client Provisioner 설정

1. 파일 스토리지 생성

https://docs.kakaocloud.com/service/container-pack/k8se/how-to-guides/k8se-nfs

 

2. Helm으로 NFS Client Provisioner 배포

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/

 

3. NFS Client Provisioner 설치 

helm install --kubeconfig=$KUBE_CONFIG nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner --set nfs.server=[File Storage IP] --set nfs.path=[File Storage Mount Path]

 

4. StorageClass 확인

kubectl --kubeconfig=$KUBE_CONFIG get sc

 

5. PersistentVolumeClaim 생성 및 자동 프로비저닝 테스트

PVC 생성 예제 파일 

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi

 

6. File Storage 할당하기

kubectl --kubeconfig=$KUBE_CONFIG get pvc // PVC 확인
kubectl --kubeconfig=$KUBE_CONFIG get pv // PV 확인

 

4. CR에 이미지 저장하고, 저장된 이미지로 웹 서비스 띄우기

https://docs.kakaocloud.com/tutorial/container/cr-basic

 

1. Container Registry 생성

구분 리포지토리 설정값
공개 여부 비공개
리포지토리 이름 cr-felix-test
태그 덮어쓰기 가능
이미지 스캔 자동

 

2. 예제 프로젝트 도커 이미지 빌드

예제 프로젝트를 설치할 디렉터리를 생성하고 작업 디렉터리를 생성한 디렉터리로 설정

mkdir -p ~/Downloads/kakaocloud-library
cd ~/Downloads/kakaocloud-library

 

예제 프로젝트를 설치

git clone -b kakaocloud-library https://github.com/kakaoenterprise/kakaocloud-tutorials

 

작업 디렉터리를 예제 프로젝트 경로로 이동합니다.

예제 프로젝트 파일을 확인합니다.

cd kakaocloud-tutorials
ls

 

 

3. 예제 프로젝트 빌드

Docker 실행 환경 확인

docker info

 

서버 프로젝트를 linux/amd64 환경으로 빌드합니다.

빌드된 서버 컨테이너 이미지를 카카오클라우드 환경에 맞게 태그를 설정합니다.

클라이언트 프로젝트를 linux/amd64 환경으로 빌드합니다.

빌드된 클라이언트 컨테이너 이미지를 카카오클라우드 환경에 맞게 태그를 설정합니다.

docker build -t kakaocloud-library-server:latest --platform linux/amd64 -f ./server/deploy/Dockerfile ./server
docker tag kakaocloud-library-server:latest {PROJECT_NAME}.kr-central-2.kcr.dev/{REPOSITORY_NAME}/kakaocloud-library-server:latest
docker build -t kakaocloud-library-client:latest --platform linux/amd64 -f ./client/deploy/Dockerfile ./client
docker tag kakaocloud-library-client:latest {PROJECT_NAME}.kr-central-2.kcr.dev/{REPOSITORY_NAME}/kakaocloud-library-client:latest

 

4.예제 프로젝트 이미지 업로드

1. Container Registry 로그인

docker login {PROJECT_NAME}.kr-central-2.kcr.dev \
--username {ACCESS_KEY} \
--password {ACCESS_SECRET_KEY}

 

2. 서버 컨테이너 이미지를 업로드합니다.

클라이언트 컨테이너 이미지를 업로드합니다.

docker push {PROJECT_NAME}.kr-central-2.kcr.dev/{REPOSITORY_NAME}/kakaocloud-library-server:latest
docker push {PROJECT_NAME}.kr-central-2.kcr.dev/{REPOSITORY_NAME}/kakaocloud-library-client:latest

 

3. 업로드된 이미지는 아래 명령어를 통해 다운로드할 수 있습니다. 로컬 머신에 입력하여 이미지를 설치합니다.

서버 이미지 클라이언트 이미지 다운로드

docker pull {PROJECT_NAME}.kr-central-2.kcr.dev/{REPOSITORY_NAME}/kakaocloud-library-server:latest
docker pull {PROJECT_NAME}.kr-central-2.kcr.dev/{REPOSITORY_NAME}/kakaocloud-library-client:latest

 

4. docker images로 이미지 다운로드 확인

5. CR에 저장된 이미지로 pod 띄우기

각 파드별 볼륨 마운트는 hostpath가 아닌 nfs로 생성한 pvc로 설정해주기 위해서 

마운트 패스를 hostpath가 아닌 /root로 잡아주었고, 편리한 작업을 위해서 네임스페이스는 felix로 통일

 

서버 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  name: server-deployment
  namespace: felix
spec:
  replicas: 2
  selector:
    matchLabels:
      app: server
  template:
    metadata:
      labels:
        app: server
    spec:
      containers:
      - name: server
        image: {PROJECT_NAME}.kr-central-2.kcr.dev/tutorial/kakaocloud-library-server:latest
        env:
        - name: PROFILE
          value: "local"
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: root-volume
          mountPath: /root
      imagePullSecrets:
      - name: kc-cr-secret
      volumes:
      - name: root-volume
        hostPath:
          path: /root
          type: Directory
---
apiVersion: v1
kind: Service
metadata:
  name: server-service
  namespace: felix
spec:
  type: ClusterIP
  selector:
    app: server
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080

 

서버 service 배포


apiVersion: v1
kind: Service
metadata:
  name: server-service
  namespace: felix
spec:
  type: ClusterIP
  selector:
    app: server
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080

 

클라이언트 deployment 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deployment
  namespace: felix
spec:
  replicas: 2
  selector:
    matchLabels:
      app: client
  template:
    metadata:
      labels:
        app: client
    spec:
      containers:
      - name: client
        image: {PROJECT_NAME}.kr-central-2.kcr.dev/tutorial/kakaocloud-library-client:latest
        env:
        - name: SERVER_ENDPOINT
          value: "http://server-service.felix.svc.cluster.local:8080"
        ports:
        - containerPort: 80
        volumeMounts:
        - name: root-volume
          mountPath: /root
      imagePullSecrets:
      - name: kc-cr-secret
      volumes:
      - name: root-volume
        hostPath:
          path: /root
          type: Directory

 

클라이언트 service 배포

apiVersion: v1
kind: Service
metadata:
  name: client-service
  namespace: felix
spec:
  type: LoadBalancer
  selector:
    app: client
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

 

 콘솔에서 로드 밸런서 설정

예제 프로젝트 클라이언트의 service를 LoadBalancer 유형으로 배포하면서, 카카오클라우드 콘솔에서 Load Balancer 서비스의 로드 밸런서 목록에도 추가된 것을 확인할 수 있습니다. 로드 밸런서 목록 > [더 보기] > 퍼블릭 IP 연결을 클릭해 외부에서 서비스에 접근할 수 있게 만들 수 있습니다.

 

서비스 접속 확인

브라우저에서 등록한 퍼블릭 IP로 접속하여 서비스를 확인합니다. 정상적으로 연결된 경우, '카카오클라우드 도서관' 서비스 화면을 볼 수 있습니다.

 

6. HPA 설정 및 부하 테스트

https://docs.kakaocloud.com/service/container-pack/k8se/how-to-guides/k8se-manage-node#hpa-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EB%B6%80%ED%95%98-%ED%85%8C%EC%8A%A4%ED%8A%B8

HPA(HorizontalPodAutoscale)를 Cluster Autoscaler와 함께 설정하면 더욱 효과적으로 리소스를 관리

 

1. HPA 설정하기 전, Helm client를 설치합니다. 운영체제별 Helm 설치에 대한 자세한 설명은 Helm 공식 문서 > 헬름 설치하기를 참고하시기 바랍니다.

 

2. HPA 부하 테스트를 위해 파드를 모니터링하는 metrics-server를 설치합니다.

# metrics-server 설치 명령어
helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
helm upgrade --install metrics-server metrics-server/metrics-server --set hostNetwork.enabled=true --set containerPort=4443

 

3. 노드의 리소스 사용량을 정상적으로 모니터링하는지 확인합니다. metrics-server 설치 후 모니터링 정보가 수집되기까지 최대 5분 정도 소요될 수 있습니다.

# 노드의 리소스 사용량 확인 명령어
kubectl top node

 

4. HPA와 Cluster Autoscaler을 설정한 후, 부하 테스트를 진행하기 위한 php-server를 배포합니다.

# php-server App 배포 명령어
apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  selector:
    matchLabels:
      run: php-apache
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - name: php-apache
        image: ke-container-registry.kr-central-2.kcr.dev/ke-cr/hpa-example:latest
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 500m

--- 
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  labels:
    run: php-apache
spec:
  ports:
  - port: 80
  selector:
    run: php-apache

 

5. 부하 테스트를 위해 HPA를 생성합니다.

# HPA 생성 명령어
kubectl autoscale deployment php-apache --cpu-percent=10 --min=1 --max=10  // HPA 생성
kubectl get hpa  // HPA 설정 확인
실행 결과
NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   46%/50%   1         10        5          28m

 

6. 테스트를 위해 부하를 일으키는 파드를 실행합니다.

# 파드 실행 명령어
kubectl run -i --tty load-generator --rm --image=ke-container-registry.kr-central-2.kcr.dev/ke-cr/busybox:latest --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

 

7. 부하가 커지며 파드와 노드 개수가 정상적으로 증가하는 것을 확인합니다.

  • php-apache 서버 HPA가 발생하며, 리소스가 부족하여 스케줄링 되지 못한 일부 파드들은 Pending 상태가 됩니다.
  • 일부 파드가 스케줄링 되지 못하므로 리소스 추가를 위해 노드가 3개로 자동 확장됩니다.
# HPA 및 자동 확장 동작 결과 확인 명령어
kubectl get pods -w  // 파드 개수 변경 확인
kubectl get nodes -w // 노드 개수 변경 확인
실행 결과
NAME                             READY   STATUS    RESTARTS      AGE
php-apache-766d5cdd5b-2t5p8      0/1     Pending   0             44s
php-apache-766d5cdd5b-5mhlk      0/1     Pending   0             29s
php-apache-766d5cdd5b-5vjt6      0/1     Pending   0             14s
php-apache-766d5cdd5b-74z87      1/1     Running   0             44s
php-apache-766d5cdd5b-d49g9      0/1     Pending   0             29s
php-apache-766d5cdd5b-fnlld      1/1     Running   0             44s
php-apache-766d5cdd5b-nr5f2      0/1     Pending   0             29s
php-apache-766d5cdd5b-t7zr8      0/1     Pending   0             29s
php-apache-766d5cdd5b-vjjlz      1/1     Running   0             2m49s
php-apache-766d5cdd5b-whjhw      0/1     Pending   0             14s

NAME                STATUS     ROLES    AGE   VERSION
host-10-187-5-177   Ready      <none>   51s    v1.24.6
host-10-187-5-189   Ready      <none>   9m5s   v1.24.6
host-10-187-5-98    Ready      <none>   69s    v1.24.6

7. CI/CD with K8SE(GitHub Actions, ArgoCD)

1. GitHub에서 Private 레포지토리 생성

GitHub에서 Private 레포지토리를 생성한다.

퍼블릭으로 만들어서 하는 방법도 가능하나, 실무 환경에 가깝게 구성하기 위해서 프라이빗으로 레포지토리를

생성해주고 별도 인증을 통해서 접속하도록 구성한다.

 

수동 토큰 발급이 필요한 경우 아래 과정을 참고하면 되고,

야물 배포 시 시크릿 부분을 자동화 하였기때문에 본 프로젝트에서는 별도 토근 발급과정이 필요하지 않습니다.

 

[레포지토리 생성]

GitHub 접속 → 우측 상단 +  New repository

Repository name: my-k8s-app

Private 선택

README, .gitignore는 체크 안 함

Create repository

 

2. GitHub Personal Access Token 발급

ArgoCD가 Private 레포에 접근하려면 토큰이 필요하기 때문에 토큰을 발급해준다.

 

[토큰 발급]

GitHub 우측 상단 프로필  Settings

왼쪽 메뉴에서 Developer settings 클릭

Personal access tokens > Tokens (classic) 클릭

Generate new token (classic) 버튼 클릭

 

[설정 예시]

Note: argo-git-token

체크: repo (read access to private repos)

만료 기간: 90일 또는 custom

Generate 후 토큰 값 복사 (다시 못 봄!)

토큰 값을 다시 보는게 불가능하기 때문에 꼭 별도 저장하는것을 권장한다.

 

3. Kubernetes에 Git 인증용 Secret 생성

먼저 argocd 라는 네임스페이스를 생성한다.

kubectl create namespace argocd

 

Git 인증용 Secret을 생성한다.

kubectl create secret generic github-creds \
  --namespace argocd \
  --from-literal=username=<your_github_username> \
  --from-literal=password=<your_generated_token>

 

 

4. ArgoCD 설치하기 (Helm 사용)

Helm 리포지터리를 추가한다.

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

 

ArgoCD 설치 (Helm)

helm install argocd argo/argo-cd \
  --namespace argocd

 

설치확인

kubectl get pods -n argocd

 

5. ArgoCD 웹 UI 접속

포트포워딩으로 로컬에서 접속

kubectl port-forward svc/argocd-server -n argocd 8080:443

 

브라우저에서 열기

(주의: https, 인증서 경고 뜰 수 있음 → 무시하고 계속)

https://localhost:8080

 

기본 로그인 정보

아이디 : admin

비밀번호 : 아래 명령어로 확인

kubectl get secret argocd-initial-admin-secret -n argocd \
  -o jsonpath="{.data.password}" | base64 -d