Files
obsidian/infra/compute/k3s-to-incus-migration.md

17 KiB

title, updated, tags, status
title updated tags status
K3s → Incus 이전 플랜
2026-06-01 초안 작성 (kappa 결정 — K3s 운영부담 감축 위해 Incus 전환)
2026-06-01 미결정 사항 확정 — APISIX 서울 유지 / 프로비저닝 OpenTofu+Ansible / kr1 GTX 1080 Ti 유지
infra
compute
k3s
incus
migration
plan
draft

배경

K3s 운영 부담이 누적되어 Incus 전환 결정. 주요 통증:

  • Longhorn 리밸런싱·drain hang·VolumeAttachment 수동 정리
  • kine → HAProxy → Patroni 다단 의존, 장애 cascade (../../history/2026-05-23-kr1-k3s-stuck-cascade)
  • kr2 RAM 30GiB에서 K3s + Incus 동시 호스팅 → OOM freeze (../../history/2026-05-04-amd-iommu-freeze 포함)
  • multus·MetalLB·descheduler 튜닝, kube-system CRD/operator 다수 (cert-manager, ArgoCD 등) 유지비
  • helm/ArgoCD GitOps 학습·디버깅 비용

반대로 Incus는 이미 정착(Vault, Patroni, ops 에이전트 모두 incus), OpenTofu 모듈 보유, OCI 이미지 1급 지원.

목표

  • 서울 K3s 클러스터(kr1·kr2·hp1·hp2) 워크로드를 incus 컨테이너/VM으로 이전
  • K3s 자체 폐기 (kine·Patroni 의존 종료, Longhorn 폐기)
  • 운영 면적 축소: GitOps·CRD·CNI·CSI·CRDS 레이어 제거

비목표

  • jp1 Incus 호스트 그대로 유지 (도쿄, Vault·agents 정본)
  • 서울 4대 Incus 클러스터링은 별도 결정 (infra-hosts 참조). 이전은 호스트 분리 상태로 진행
  • Outline/Slack 등 외부 SaaS 이전 (해당 없음)

디폴트 결정 — 대체 패턴

플랜 단계에서 확정. 변경 시 본 문서 history에 명시.

레이어 K3s 현행 Incus 대체 근거
진입점/라우팅 MetalLB + Traefik + APISIX OpenWrt HAProxy → APISIX 서울 (incus 컨테이너) → 컨테이너 IP APISIX 서울은 유지 (정책·플러그인·SafeLine 통합 가치). MetalLB·Traefik만 폐기. APISIX는 K3s StatefulSet에서 incus 단일 컨테이너 + sqlite/etcd 백엔드로 축소
TLS 인증서 cert-manager + Let's Encrypt acme.sh + Cloudflare DNS-01, HAProxy/APISIX/SafeLine reload CF global key 이미 운영. cert-manager CRD 학습 비용 회피
스토리지 Longhorn (분산 블록) Synology NAS NFS/iSCSI 직접 마운트 + 호스트 btrfs 로컬 분산 복제는 앱 레벨 HA(Patroni)로 한정. NAS는 democratic-csi 없이 직접
프로비저닝 ArgoCD + Helm (Gitea) OpenTofu + Ansible (ops-agents-tofu 패턴 확장 + playbook 표준화) Tofu = 인프라(컨테이너 생성·디스크·네트워크 device), Ansible = 컨테이너 안 OS/앱 설정. 기존 헤임달/씬 Tofu 패턴 위에 Ansible 추가. ArgoCD GitOps는 Gitea 저장소 + Tofu Cloud 또는 atlantis로 PR 기반 plan/apply
시크릿 K8s Secret + Vault Agent Vault API 직접 (envconsul/sidecar/init) Vault는 이전 없음
로깅 VictoriaLogs + vector daemonset VictoriaLogs 컨테이너 + vector systemd unit on host 컨테이너 수집은 console.log tail
메트릭 VictoriaMetrics + node-exporter daemonset VictoriaMetrics 컨테이너 + node-exporter systemd on host 동일 패턴
메시지 큐 RabbitMQ operator + cluster RabbitMQ 단일 incus 컨테이너 (현 사용량 단일로 충분) operator 폐기, 필요 시 페어
WAF SafeLine in K3s (6 컴포넌트) SafeLine docker-compose → incus 단일 컨테이너 묶음 공식 docker-compose 그대로, K3s 분산 가치 적음
HA 정책 Pod 자동 재스케줄 디폴트 active-passive (호스트 다운 시 분 단위 다운타임 수용) Patroni·Vault만 자체 HA. 나머지는 분 단위 다운 허용

확정 사항 (2026-06-01):

  • APISIX 서울 유지: K3s StatefulSet → incus 단일 컨테이너로 축소 이전. etcd 3-replica 폐기, sqlite 또는 단일 etcd. ApisixRoute CRD는 Admin API + Tofu provider 또는 dashboard로 대체
  • OpenTofu + Ansible 조합: Tofu가 incus 컨테이너·디스크·네트워크 device 생성, Ansible이 컨테이너 안 OS 설정·앱 배포. 시범 단계부터 두 도구 동시 적용
  • kr1 GTX 1080 Ti 유지: Incus GPU 컨테이너로 GPU 워크로드 계속. K3s 종료 후에도 docker-gpu/podman-gpu 이미지 활용

배치 정책

호스트 권장 워크로드 사유
kr1 (62GiB + GTX 1080 Ti) GPU 워크로드 (docker-gpu/podman-gpu 이미지 기반), brokkr(현행), postgres-2 replica GPU 자원 유지. control-plane 부담 제거 후 GPU 활용도 확대 가능
kr2 (30GiB) inbest 7컨테이너 유지, mariadb-3/postgres-3 유지, 신규 무거운 워크로드 금지 RAM 작음. K3s 폐기 후에도 OOM 위험
hp1 (188GiB) 메인 호스트 — Gitea, Outline, OpenMemory, SafeLine, VictoriaLogs/Metrics RAM 여유, 베어메탈
hp2 (188GiB) hp1 짝꿍 — jarvis, trader 유지 + 분산 부담 분배, mariadb-1/postgres-1 유지 RAM 여유, Tailscale 가입

Phase 0 — 대체 패턴 인프라 셋업

K3s 워크로드 이전 전 인프라 토대 구축. 약 1~2주.

  • OpenTofu 컨테이너 모듈 작성 (kaffa/ops-agents-tofumodules/incus-service/ 추가): Incus 컨테이너 + 디스크 device + proxy device + cloud-init 표준화
  • Ansible 표준 playbook 셋업: kaffa/ansible-services 신규 저장소 — inventory를 Tofu output으로 자동 생성, 공통 role(base, vector-agent, node-exporter, tailscale, app-runtime 등) 작성. Vault lookup plugin으로 시크릿 주입
  • Tofu ↔ Ansible 연결 패턴 확정: Tofu apply → Ansible playbook 자동 실행 (null_resource + local-exec 또는 별도 CI 단계). 적용 순서·재실행 멱등성 검증
  • 공통 베이스 이미지 (Debian 13 + vector + node-exporter + tailscale 선택적): incus image build, 캐시 push. Ansible playbook으로 이미지 빌드 자체도 코드화
  • acme.sh 인증서 발급기: hp1에 incus 컨테이너 acme 신설, Cloudflare DNS-01 + Vault에서 CF global key 조회. hook으로 HAProxy / APISIX / SafeLine reload
  • HAProxy 확장: OpenWrt의 /etc/haproxy/haproxy.cfg에 신규 backend 추가 검증 (현재 Traefik VIP 192.168.9.53 백엔드 → APISIX 서울 incus 컨테이너 IP 또는 직접 컨테이너 IP로 점진 전환)
  • APISIX 서울 incus 컨테이너 준비: hp1 또는 hp2에 신규 APISIX 컨테이너 생성, sqlite/etcd 백엔드 결정, 현행 K3s APISIX config·플러그인·SafeLine 통합 설정 export → 신규 컨테이너로 import. dual-run으로 검증 (Phase 4까지 K3s APISIX 병행)
  • NAS 마운트 표준: Synology NFS export 디렉터리 구조 결정 (/volume1/incus-data/<service>/), btrfs subvol 옵션, idmap 정책
  • VictoriaLogs/Metrics incus 이전 사전 작업: jp1 monitoring 프로젝트 또는 hp1에 신규 컨테이너 — K3s VictoriaMetrics 데이터 마이그레이션 dry-run
  • 롤백 스냅샷 정책: incus snapshot 자동화 — 이전 후 일정 기간 보관

성공 기준: Phase 1 시범 서비스를 Tofu apply → 컨테이너 RUN → HAProxy 라우팅 → 인증서 발급까지 무인 실행

Phase 1 — 시범 이전 (1~2주)

패턴 검증용. 다운타임 영향 작은 서비스만.

순서 서비스 출처 ns 목표 호스트 메모
1 kroki kroki hp1 stateless, 다이어그램 렌더링. 의존성 없음
2 searxng searxng hp1 stateless 검색 프록시
3 juice-shop juiceshop hp2 테스트용, jp1 default에도 컨테이너 존재 → 통합 검토

검증 항목:

  • OpenTofu 모듈로 컨테이너 생성·재생성 멱등성
  • Ansible playbook으로 컨테이너 안 설정·앱 배포 멱등성 (재실행 시 변경 없음)
  • Tofu output → Ansible inventory 자동 연결 동작
  • OCI 이미지 자동 업데이트 패턴 (blue-green vs in-place restart)
  • HAProxy → APISIX 서울 (또는 컨테이너 IP 직접) 라우팅 + SafeLine 통과 (필요 시)
  • acme.sh 인증서 발급·갱신
  • vector → VictoriaLogs 수집 (K3s 잔존 + 신규 incus 동시 수집)

성공 기준: 3 서비스 정상 가동 + DNS 전환 후 1주 무이슈

Phase 2 — Stateless·단일 컨테이너 이전 (2~3주)

순서 서비스 출처 ns 목표 호스트 메모
1 smtp-relay mail hp1 ArgoCD App, 단순
2 BunnyCDN MCP mcp hp1 ArgoCD App
3 cfb-manager tools hp1 ArgoCD cf-bouncer-manager
4 Namecheap API api hp1 ArgoCD
5 Vultr API api hp1 ArgoCD
6 NocoDB tools hp1 Patroni 사용 — DB 연결만 유지
7 n8n n8n hp1 Helm. Postgres 연결만 유지. workflow 데이터 백업 후 마이그레이션
8 sftpgo sftpgo hp2 SFTP 22 노출 — HAProxy TCP 라우팅
9 sshpiper sshpiper hp2 jp1에 sshpiper 컨테이너도 있음 — 역할 분리 확인 후
10 teleport teleport hp1 auth + proxy 2 컴포넌트, 단일 incus 컨테이너로 통합 가능

각 항목 작업:

  1. OpenTofu apply로 컨테이너 생성
  2. 데이터 이전 (PVC → NAS 또는 컨테이너 disk)
  3. K3s 측에서 동일 DNS로 dual-run, healthcheck
  4. HAProxy backend 전환 (K3s VIP → incus 컨테이너 IP)
  5. 1주 모니터 후 K3s 측 helm uninstall / kubectl delete ns
  6. ArgoCD Application 삭제

Phase 3 — 멀티 컴포넌트 이전 (2~3주)

순서 서비스 출처 ns 목표 호스트 구성
1 Gitea gitea hp1 gitea + valkey 두 컨테이너. PostgreSQL은 Patroni 그대로. valkey는 컨테이너 동거 또는 별도
2 Outline outline hp1 outline + redis 두 컨테이너. PostgreSQL은 Patroni
3 OpenMemory openmemory hp1 mcp + ui + qdrant 세 컨테이너. qdrant 데이터는 NAS NFS
4 SafeLine WAF safeline hp1 공식 docker-compose 기반, 단일 incus 컨테이너 안에서 compose 실행 (예외적 사용) 또는 multi-container profile
5 RabbitMQ mq hp1 단일 컨테이너로 충분. operator·cluster 폐기
6 PgCat/ProxySQL db hp1 또는 jp1 db 프로젝트 Patroni pooler 위치 재검토

작업 패턴 (Phase 2와 동일하나 데이터 마이그레이션 비중 큼):

  • Postgres 의존: 이전 중 connection string만 incus 컨테이너 IP로 전환
  • Redis/valkey/qdrant: 데이터 export → import 또는 NAS 볼륨 통째로 이동
  • Gitea: LFS 데이터 NAS 이전 + clone/push 무중단 테스트

Phase 4 — 게이트웨이 정리 (1~2주)

  • APISIX 서울 incus 컨테이너 전면 전환: Phase 0에서 준비한 incus APISIX 컨테이너로 트래픽 전환. HAProxy backend를 K3s APISIX VIP(192.168.9.50) → incus APISIX 컨테이너 IP로 변경. DNS TTL + 1주 모니터 후 K3s apisix ns 삭제
  • Traefik 폐기: 모든 HTTPRoute/IngressRoute → HAProxy backend(또는 APISIX 라우트)로 이전 완료 확인. K3s Traefik helm uninstall
  • MetalLB 폐기: LoadBalancer Service 없음 확인 후 helm uninstall
  • cert-manager 폐기: 모든 Certificate CR 무사용 확인 (APISIX·HAProxy·SafeLine 인증서 모두 acme.sh로 대체됨) 후 helm uninstall

Phase 5 — K3s 인프라 폐기 (1~2주)

  • Longhorn 데이터 마이그레이션 완료 확인: 모든 PVC가 NAS NFS 또는 호스트 디스크로 이전됨. kubectl get pv 비어있음
  • Longhorn helm uninstall + longhorn-system ns 삭제
  • ArgoCD helm uninstall + argocd ns 삭제: GitOps 저장소(kaffa/k3s-charts 등) 아카이브
  • VictoriaLogs/Metrics 데이터 incus로 이전: jp1 monitoring 또는 hp1 신규 컨테이너에서 단일 인스턴스 운영
  • kube-system 잔여 정리: descheduler, multus, nfs-provisioner 등
  • Patroni → kine 의존 제거: K3s 자체 종료 직전 단계. Patroni는 그대로 유지 (다른 워크로드가 사용)

Phase 6 — K3s 종료 (1주)

  • kr1·kr2 control-plane drain + k3s-uninstall.sh
  • hp1·hp2 agent drain + k3s-agent-uninstall.sh
  • OpenWrt HAProxy에서 K3s 관련 backend 전체 삭제
  • DNS — k3s.inouter.com, *.inouter.com 매핑 정리
  • infra-hosts 업데이트: K3s 섹션 → history로 이동, 호스트 역할 재정의
  • Obsidian K3s 관련 정본 문서 → history/2026-XX-XX-k3s-decommission.md로 이전

서비스 매핑 요약

서비스 현재 (K3s) 이전 후 (Incus) Phase
kroki kroki ns hp1 컨테이너 kroki 1
searxng searxng ns hp1 컨테이너 searxng 1
juice-shop juiceshop ns hp2 컨테이너 (jp1과 통합 검토) 1
smtp-relay mail ns hp1 컨테이너 smtp-relay 2
BunnyCDN MCP mcp ns hp1 컨테이너 bunny-mcp 2
cfb-manager tools ns hp1 컨테이너 cfb-manager 2
Namecheap/Vultr API api ns hp1 컨테이너 dns-api (통합 또는 분리) 2
NocoDB tools ns hp1 컨테이너 nocodb 2
n8n n8n ns hp1 컨테이너 n8n 2
sftpgo sftpgo ns hp2 컨테이너 sftpgo 2
sshpiper sshpiper ns hp2 컨테이너 sshpiper-seoul (jp1과 역할 분리) 2
Teleport teleport ns hp1 컨테이너 teleport (auth+proxy 통합) 2
Gitea gitea ns hp1 컨테이너 gitea + gitea-valkey 3
Outline outline ns hp1 컨테이너 outline + outline-redis 3
OpenMemory openmemory ns hp1 컨테이너 openmemory-mcp + openmemory-ui + openmemory-qdrant 3
SafeLine WAF safeline ns hp1 컨테이너 safeline (compose 내부) 3
RabbitMQ mq ns hp1 컨테이너 rabbitmq 3
PgCat/ProxySQL db ns hp1 또는 jp1 db 프로젝트 3
VictoriaLogs/Metrics logging/monitoring ns hp1 컨테이너 또는 jp1 monitoring 5
APISIX 서울 apisix ns (Deployment x2 + ingress-controller + etcd 3/3) hp1 또는 hp2 단일 컨테이너 apisix-seoul (sqlite/단일 etcd 백엔드) 0 준비 / 4 전환
Traefik kube-system 폐기 4
MetalLB metallb-system 폐기 4
cert-manager cert-manager 폐기 (acme.sh로 대체) 4
Longhorn longhorn-system 폐기 (NAS NFS로 대체) 5
ArgoCD argocd 폐기 (OpenTofu로 대체) 5

롤백 절차

Phase별 롤백 가능. 단 Phase 5 (Longhorn 폐기) 이후 K3s 복귀는 비현실적 — 그 이전 단계는 데이터 손실 없이 복귀 가능.

각 서비스 단위 롤백:

  1. HAProxy backend를 K3s VIP로 되돌림
  2. Incus 컨테이너 stop (삭제 금지 — incus snapshot으로 백업 보존)
  3. K3s 측 Deployment/StatefulSet replica 복원
  4. DNS TTL 안에 트래픽 복귀

전체 롤백 트리거:

  • 이전 후 1주 내 다운타임 > 1시간 누적
  • 데이터 무결성 사고
  • 운영 부담이 예상보다 큼 (incus 자체 OOM, idmap 깨짐 반복 등)

위험요소 / 트레이드오프

위험 완화
HA 손실 (호스트 다운 = 서비스 다운) 디폴트 수용. Patroni·Vault·DNS만 자체 HA. 핵심 외 분 단위 다운타임 허용
이전 중 K3s + Incus 이중 운영 부담 Phase 시간 단축, 시범에서 패턴 확립 후 가속
ArgoCD GitOps 시각화 손실 OpenTofu state + Tofu Cloud 또는 atlantis로 PR 기반 plan/apply. Ansible은 별도 CI 실행 로그
APISIX 서울 단일 컨테이너 — etcd 3-replica 폐기 후 가용성 저하 sqlite 백엔드 시 단일 컨테이너 다운 = 라우팅 중단. NAS 백업 + 빠른 재기동 패턴. 필요 시 hp1·hp2 active-passive 페어
Tofu + Ansible 이중 도구 학습·운영 부담 Phase 0에서 패턴 표준화·문서화. Phase 1 시범으로 마찰 조기 발견
OCI 이미지 자동 업데이트 부재 blue-green 패턴 표준화, renovate-bot으로 tag PR 자동 생성
Longhorn 폐기 후 백업 전략 NAS snapshot + R2 sync 기존 파이프라인 (backup) 활용
kr2 OOM 재발 (Incus 단독에서도) inbest 7컨테이너 + DB 2 + 신규 워크로드 금지. 가벼운 것만
SafeLine WAF Phase 3 단일 컨테이너 통합 — chaitin-waf 트래픽 처리 성능 시범에서 부하 테스트, 필요 시 hp1·hp2 페어 active-passive

일정 추정 (의지적, 실제는 더 길어질 수 있음)

Phase 기간 누적
Phase 0 (인프라 토대) 2주 2주
Phase 1 (시범) 2주 4주
Phase 2 (단일 컨테이너) 3주 7주
Phase 3 (멀티 컴포넌트) 3주 10주
Phase 4 (게이트웨이) 1주 11주
Phase 5 (인프라 폐기) 2주 13주
Phase 6 (K3s 종료) 1주 14주

전체 약 3.5개월. 실제 진행은 다른 작업·인시던트로 6개월~1년 범위 예상.

관련 문서