데브코스 수료에 따라 AWS 지원이 종료되어 서버 이전이 필요했다.
처음에는 AWS 프리티어 인스턴스를 여러 개 만들어서 다시 구축할까 싶었지만
나만의 홈 서버를 구축하고 싶은 욕심에 자연스럽게 쿠버네티스에 관심이 가게 됐다.
바로 쿠버네티스 책 구입해서 공부를 시작했고 최종적으로는 k3s 단일 노드로 클러스터를 구축할 수 있었다.
따라서 이번 포스팅은 그에 대한 구축기를 남기려 한다.
최종 프로젝트에서 데브옵스 역할을 맡으면서 컨테이너 관리가 가장 큰 고민이었다.
프로젝트에서 필요한 애플리케이션은 다음과 같다.
9개가 적으면 적다고 할 수도 있지만 하나하나 모두 컨테이너로 배포를 해야했다.
그리고 모든 애플리케이션이 하나의 EC2 인스턴스가 아닌 여러 인스턴스에 나눠서 배포됐기에 관리에 상당한 불편함이 있었다.
SpringBoot API Server는 GitHub Actions를 통해 블루/그린 배포를 구현해놨기에 큰 상관은 없었지만 나머지는 그렇지 못했다.
따라서 애플리케이션에 변경사항이 발생하면 직접 인스턴스에 SSH 연결을 해서 docker compose up -d 명령어를 입력해서 적용시켜야 했다.
이에 대한 해결책으로 자연스레 쿠버네티스가 생각났고 집에 굴러다니는 10년된 게이밍 노트북을 고문시키기로 결정했다..!
고문에 사용된 노트북의 스펙은 다음과 같다.
ASUS GL552VWi7-6700HQ (2.6GHz), 쿼드코어GTX960MDDR4, 16GB128GB SSD, 1TB HD무려 10년(?)이 지나긴 했지만 관리를 나름 잘해줬기에 쌩쌩하게 굴러가신다.
K3S는 Rancher Labs에서 개발한 경량화된 쿠버네티스 배포판이다.
기존 쿠버네티스가 대규모 프로덕션 환경에 최적화되어 있다면 K3S는 IoT, 엣지 컴퓨팅, 그리고 개발 환경에 특화되어 있다. 특히 리소스가 제한적인 환경에서도 쿠버네티스의 핵심 기능을 모두 사용할 수 있다는 것이 가장 큰 장점이다.
경량화: 기존 쿠버네티스 대비 메모리 사용량이 절반 이하로 줄어들었다. 내 10년된 노트북에도 부담 없이 굴리기에는 적당했다.
단순한 설치: 복잡한 과정 없이 단일 바이너리로 설치가 가능하다. 말 그대로 스크립트 하나면 끝이다.
완전한 쿠버네티스: 경량화되었다고 해서 기능이 빠진 건 아니다. 표준 쿠버네티스 API를 100% 지원하기 때문에 kubectl 명령어도 그대로 사용 가능하다.
K3S 클러스터는 단일 노드로 구축했다.
프로덕션 환경에서는 고가용성과 장애 복구를 위해 멀티 노드 구성이 권장되지만 학습 목적과 리소스 제약을 고려해 먼저 단일 노드로 안정적인 환경을 구축하기로 했다.
추후 라즈베리파이나 추가 하드웨어를 확보하면 워커 노드를 하나씩 추가해 멀티 노드 클러스터로 확장할 예정이다.
이번 포스팅은 구축에 초점을 두기에 K3S에 대한 더 자세한 내용은 다음 포스팅에서 다뤄보자.
우선 노트북에 우분투 24.04 LTS 버전을 다운받았다.
우분투 다운로드: https://ubuntu.com/download/desktop
rufus: https://rufus.ie/ko/
다운받은 후에는 rufus를 이용해서 설치용 USB를 만들고 노트북에 우분투를 설치했다.
K3S 설치는 매우 간단하다. 아래의 명령어를 실행해준다.
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik" sh -
K3S를 설치할 때 처음에는 기본 제공되는 Traefik을 제외해서 설치한다.
Traefik 을 사용하지 않은 이유?
기존 프로젝트에서 NGINX를 리버스 프록시로 사용하고 있었기 때문에 동일한 환경을 유지하기 위해 Traefik 대신 NGINX Ingress Controller를 사용하기로 결정했다. 일관성 있는 인프라 환경을 구성하는 것이 운영과 디버깅에 더 유리하다고 판단했다.
설치가 완료되면 자동으로 K3S 서비스가 시작된다.
설치 상태 확인은 다음과 같이 할 수 있다.
sudo systemctl status k3s
쿠버네티스에 대한 기초를 학습한 후 애플리케이션을 배포하면서 느꼈던 가장 큰 문제점은 배포 일관성이었다. 각 애플리케이션마다 kubectl 명령어를 직접 실행해야 했고 설정 변경이 있을 때마다 수동으로 매니페스트를 수정하고 적용해야 했다.
또한 최종 프로젝트에서 데브옵스 역할을 맡으면서 Infrastructure as Code(IaC) 의 중요성을 느꼈다.
모든 인프라 설정이 Git 저장소에 관리되고 변경사항이 자동으로 반영되는 환경을 구축하고 싶었다.
ArgoCD의 특징은 다음과 같다.
ArgoCD 설치는 공식 매니페스트를 사용했다.
# ArgoCD 네임스페이스 생성
kubectl create namespace argocd
# ArgoCD 설치
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
설치 후 모든 Pod가 Running 상태인지 확인한다.
kubectl get pods -n argocd
ArgoCD를 효율적으로 관리하기 위해 CLI 도구도 함께 설치했다.
# ArgoCD CLI 다운로드 및 설치
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64
ArgoCD UI에 접근하기 위해 NGINX Ingress를 통해 도메인으로 접근할 수 있도록 설정했다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server
namespace: argocd
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
tls:
- hosts:
- your.domain.com
secretName: argocd-server-tls
rules:
- host: your.domain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 443
로그인을 위한 초기 관리자 비밀번호 확인은 아래의 명령어를 사용한다.
argocd admin initial-password -n argocd

이제 도메인에 접속해서 ArgoCD UI를 사용할 수 있다.
모든 쿠버네티스 매니페스트를 관리하기 위해 별도의 Git 저장소를 생성했다.
실제 구성한 저장소 구조는 다음과 같다.
homelab-k3s-gitops/
├── applications/
│ ├── observability/ # 모니터링 관련 애플리케이션
│ │ ├── grafana/
│ │ ├── prometheus/
│ │ ├── loki/
│ │ ├── tempo/
│ │ ├── node-exporter/
│ │ ├── otel-collector/
│ │ ├── kube-state-metrics/
│ │ ├── namespace.yaml
│ │ └── kustomization.yaml
│ ├── automation/ # 자동화 도구
│ │ ├── n8n/
│ │ ├── namespace.yaml
│ │ └── kustomization.yaml
│ └── wiki/ # 문서화 도구
│ ├── bookstack/
│ ├── mariadb/
│ ├── namespace.yaml
│ └── kustomization.yaml
├── core/
│ ├── cert-manager/ # SSL 인증서 관리
│ │ ├── cluster-issuer.yaml
│ │ └── kustomization.yaml
│ ├── ingress/ # 인그레스 설정
│ │ ├── argocd-ingress.yaml
│ │ ├── grafana-ingress.yaml
│ │ ├── bookstack-ingress.yaml
│ │ ├── n8n-ingress.yaml
│ │ └── kustomization.yaml
│ └── storage/ # 스토리지 설정
│ ├── storage-classes.yaml
│ ├── local-path-config.yaml
│ └── kustomization.yaml
└── kustomization.yaml # 루트 kustomization
Kustomize를 활용해 환경별 설정 관리가 가능하도록 구성했다.
ArgoCD에 접속한 후 다음 단계를 따라 애플리케이션을 생성했다.
NEW APP 버튼 클릭
Application 정보 입력
your-project-namedefaultManualSource 정보 입력
https://github.com/your-username/yout-repo.gitHEAD.Destination 정보 입력
https://kubernetes.default.svc (기본값)Sync Options 설정
✅ 체크 (네임스페이스 자동 생성)
이후에 Sync 버튼을 누르면 동기화가 시작된다.
GitOps 기반 자동화: 이제 모든 애플리케이션을 ArgoCD 하나로 관리할 수 있다. 리포지토리에 push하면 모든 변경사항이 적용되며 더 이상 여러 인스턴스에 SSH로 접속하거나 수동으로 kubectl 명령어를 실행할 필요가 없다.
자동 복구: Pod가 죽으면 자동으로 재시작된다. 이전에는 수동으로 컨테이너를 재시작해야 했다.
리소스 효율성: 노드 전체 리소스를 효율적으로 사용할 수 있게 됐다. 메모리나 CPU를 더 효율적으로 분배할 수 있다.
스케일링: 나중에 노드를 추가하거나 Pod 수를 늘리는 것도 간단하다.
학습 곡선: 쿠버네티스 개념을 익히는 데 시간이 꽤 걸렸다. 특히 네트워킹 부분이 복잡했다.
디버깅 복잡성: 문제가 발생했을 때 어디서 문제인지 찾기가 어려웠다. 로그를 확인하는 것부터 새로운 명령어들을 익혀야 했다.
YAML 지옥: 모든 설정을 YAML로 작성해야 하는데 오타 하나라도 있으면 동작하지 않는다.
이번 홈랩 구축을 통해 쿠버네티스와 GitOps에 대한 이해도를 높일 수 있었고 실무에서 요구되는 컨테이너 오케스트레이션 역량을 기를 수 있었다. 현재는 단일 노드로 운영하고 있지만 취업 후에 번 돈으로 라즈베리파이를 구입해서 멀티 노드 클러스터로 확장할 예정이다!