부제: OS 없는 가벼움, WebAssembly를 내 홈랩에 이식하다
들어가며
안녕하세요, 시스템 엔지니어이자 4남매 아빠 수누다입니다.
13년 동안 엔지니어로 일하며 수많은 컨테이너를 다뤄왔지만, WebAssembly(Wasm)는 확실히 매력적입니다. 무거운 OS 레이어 없이 코드만 덜렁 실행되는 그 극강의 가벼움! 오늘은 제 홈랩(Proxmox LXC 기반 k3s)에 이 최신 기술을 이식해 보기로 했습니다.
하지만 LXC 컨테이너라는 특수한 환경과 k3s의 독특한 설정 구조가 만나니, 예상치 못한 '삽질'의 연속이더군요. 오늘은 그 치열했던 트러블슈팅 기록입니다.
1. 전초전: Portainer와 유령 노드 정리
본격적인 작업 전, 인프라를 먼저 정비했습니다. 기본이 튼튼해야 건물을 올리니까요.
① Portainer 접속 불가 (ERR_SSL_PROTOCOL_ERROR)
- 증상: 웹 브라우저에서 Portainer 접속 시 SSL 프로토콜 에러 발생.
- 원인: HTTP 포트(30777)로 접속하면서 습관적으로 주소창에
https://를 붙인 제 실수였습니다. (엔지니어의 직업병이죠.) - 해결:
http://로 명확히 접속하고, 보안 타임아웃(5분)에 걸린 파드는kubectl delete pod로 재시작하여 해결했습니다.

② 유령 노드 삭제
- 증상: 클러스터에서 이미 제거한 구형 노드가 목록에 계속
NotReady상태로 남아있음. - 해결:
kubectl delete node <이름>으로 장부를 깔끔하게 정리했습니다.
2. 본론: Wasm(Spin) 런타임 구축의 험난한 여정
가장 쉬운 방법인 KWasm 오퍼레이터 자동 설치를 시도했으나, Proxmox LXC 환경의 제약으로 실패했습니다. 결국 '수동 설치(Manual Install)'로 선회했습니다. 여기서부터 고난이 시작됩니다.
난관 1: k3s의 설정 파일 초기화 본능
k3s는 에이전트가 재시작될 때마다 config.toml을 초기화해 버립니다. 제가 열심히 적은 Wasm 설정이 자꾸 사라지는 현상이 발생했죠.
👉 해결: config.toml.tmpl (템플릿 파일)을 생성하여 k3s가 이 파일을 기반으로 설정을 생성하도록 유도했습니다.
난관 2: 네트워크(CNI) 실종 사건
템플릿을 만들었더니, 이번엔 기존 네트워크 설정이 누락되어 NetworkPluginNotReady 에러가 떴습니다. 파드가 인터넷을 못 쓰는 상황.
👉 해결: 순정 config.toml 내용을 복사해 템플릿에 기존 네트워크 설정까지 꼼꼼히 포함시켰습니다.
난관 3: "Unknown runtime handler" (보스급 난이도)
설정을 다 넣었는데도 containerd가 wasmtime-spin-v2라는 런타임을 못 찾겠다고 거부합니다. 알고 보니 내 k3s 버전의 toml 구조가 일반적인 문서와 달랐습니다.
- 남들:
[plugins."io.containerd.grpc.v1.cri"...] - 내 k3s:
[plugins.'io.containerd.cri.v1.runtime'...]
👉 최종 해결책 (Magic Template):
워커 노드 경로(/var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl)에 정확한 섹션 구조를 찾아 넣어줬습니다.
# ... (기존 CNI 네트워크 설정 유지) ...
# [핵심] Wasm 런타임 설정 추가
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes."wasmtime-spin-v2"]
runtime_type = "io.containerd.spin.v2"
3. 결말: Wasm 앱 구동 성공
마지막으로 워커 노드에 라벨(kwasm.sh/kwasm-node=true)을 붙여 스케줄러가 노드를 찾을 수 있게 해 주었습니다.
드디어 wasm-spin 파드가 Running 상태로 변했고, 브라우저에서 접속했을 때 감격스러운 메시지를 확인했습니다.
"Hello world from Spin!"
일반 컨테이너였다면 100MB는 족히 넘었을 웹 서버가, 단 몇 MB의 크기로 순식간에 기동 되는 것을 확인했습니다. 이 짜릿한 맛에 엔지니어링 하는 거죠.

4. Next Step: 모니터링 구축
서버가 안정화되었으니, 이제 건강 검진을 위한 Prometheus + Grafana 스택을 Helm으로 설치했습니다.
- Helm Chart:
kube-prometheus-stack - Grafana 접속: NodePort 31000번 개방
이제 내 홈랩은 하이브리드 컨테이너(Docker + Wasm)를 돌리며, 실시간 관제까지 가능한 완벽한 요새가 되었습니다. 다음 목표는 GitOps(ArgoCD) 자동화입니다.
💡 오늘의 교훈
- 로그(Log)는 거짓말을 하지 않는다:
Unknown runtime handler로그 한 줄이 결정적 힌트였습니다. - 설정 파일은 '경로'가 생명이다: k3s 버전마다 toml 구조가 다를 수 있으니, 무작정 복사-붙여넣기 하지 말고
grep으로 확인합시다. - 안 되면 '순정'에서 다시 시작해라: 설정이 꼬였을 땐 싹 지우고 처음부터 다시 하는 게 가장 빠릅니다.