개요
- 목적: Terraform으로 생성한 VM에 K3s를 Ansible로 자동 설치 및 클러스터 구성
- 방식: 역할 기반(Role-based) Ansible 플레이북
- 핵심 과제: WSL2 환경에서 Bitwarden SSH Agent 연동
최종 아키텍처
Windows (Bitwarden SSH Agent)
│ npiperelay + socat
▼
WSL2 (Ansible 실행)
│ SSH (BW 키 사용)
▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ k3s-master │ │ k3s-worker-1 │ │ k3s-worker-2 │
│ Control Plane│ │ Agent │ │ Agent │
└──────────────┘ └──────────────┘ └──────────────┘
1. SSH 키 일원화: Bitwarden → WSL 브릿지
문제
WSL2에서 Ansible을 실행하면 Windows의 Bitwarden SSH Agent에 접근할 수 없다. 키를 WSL에 복사하면 관리가 이원화되어 보안적으로 바람직하지 않다.
해결: npiperelay 브릿지
Windows Named Pipe를 Unix Socket으로 변환하여 Bitwarden SSH Agent를 WSL에서 네이티브하게 사용한다.
# scripts/agent-bridge.sh
#!/usr/bin/env bash
# Windows Bitwarden SSH Agent → WSL Unix Socket 포워딩
NPIPERELAY="${NPIPERELAY_PATH:-/mnt/c/Users/fresh/bin/npiperelay.exe}"
SSH_AUTH_SOCK="$HOME/.ssh/agent.sock"
PIPE_PATH='//./pipe/openssh-ssh-agent'
# 기존 소켓 정리
if [[ -e "$SSH_AUTH_SOCK" ]]; then
rm -f "$SSH_AUTH_SOCK"
fi
# socat으로 Named Pipe ↔ Unix Socket 브릿지
(setsid socat UNIX-LISTEN:"${SSH_AUTH_SOCK}",fork \
EXEC:"${NPIPERELAY} -ei -s ${PIPE_PATH}",nofork &) 2>/dev/null
export SSH_AUTH_SOCK설치 방법
# Windows (관리자 불필요)
Invoke-WebRequest -Uri "https://github.com/jstarks/npiperelay/releases/latest/download/npiperelay_windows_amd64.zip" `
-OutFile "$env:TEMP\npiperelay.zip"
Expand-Archive "$env:TEMP\npiperelay.zip" -DestinationPath "$env:USERPROFILE\bin" -Force# WSL
sudo apt install socat
echo 'export NPIPERELAY_PATH="/mnt/c/Users/fresh/bin/npiperelay.exe"' >> ~/.bashrc
echo 'source /mnt/c/Users/fresh/github/homelab-infra/scripts/agent-bridge.sh' >> ~/.bashrc검증
ssh-add -l
# → Bitwarden에 저장된 SSH 키 목록 출력
ssh jw@k3s-master.lan
# → 비밀번호 없이 접속 성공2. Ansible 구조
디렉토리
ansible/
├── ansible.cfg # WSL world-writable 경고 무시, remote_user 설정
├── inventory.yml # 호스트 그룹 정의
├── site.yml # 마스터 플레이북
└── roles/
├── k3s_common/ # sudo, qemu-guest-agent, SSH 보안 강화
├── k3s_master/ # K3s 서버 설치, kubeconfig 권한 설정
└── k3s_worker/ # K3s agent 설치, 클러스터 조인
ansible.cfg
[defaults]
inventory = inventory.yml
host_key_checking = False
timeout = 30
# WSL에서 Windows 파일시스템 world-writable 경고 무시
allow_world_readable_tmpfiles = True
remote_user = jw역할별 핵심 태스크
k3s_common — 공통 보안 강화
- sudo 권한 설정 (NOPASSWD)
- qemu-guest-agent 설치/활성화 (Proxmox 연동)
- SSH 비밀번호 인증 비활성화
k3s_master — Control Plane
- name: K3s 서버 설치
shell: curl -sfL https://get.k3s.io | sh -
args:
creates: /usr/local/bin/k3s
- name: kubeconfig 읽기 권한 설정
file:
path: /etc/rancher/k3s/k3s.yaml
mode: "0644"
- name: kubectl alias 설정 (jw)
lineinfile:
path: "/home/jw/.bashrc"
line: "{{ item }}"
loop:
- "alias k=kubectl"
- "export KUBECONFIG=/etc/rancher/k3s/k3s.yaml"k3s_worker — Agent 조인
- name: 마스터에서 토큰 직접 가져오기
slurp:
src: /var/lib/rancher/k3s/server/node-token
delegate_to: "{{ groups['k3s_master'][0] }}"
- name: K3s agent 설치 (마스터에 조인)
shell: >
curl -sfL https://get.k3s.io |
K3S_URL=https://{{ k3s_master_ip }}:6443
K3S_TOKEN={{ k3s_token }} sh -
args:
creates: /usr/local/bin/k3s-agent3. 실행
cd /mnt/c/Users/fresh/github/homelab-infra/ansible
# 마스터 먼저
ansible-playbook -i inventory.yml site.yml --limit k3s_master
# 워커 조인
ansible-playbook -i inventory.yml site.yml --limit k3s_workers결과 확인
ssh jw@k3s-master.lan
kubectl get nodesNAME STATUS ROLES AGE VERSION
k3s-master Ready control-plane,master 5m v1.31.x+k3s1
k3s-worker-1 Ready <none> 3m v1.31.x+k3s1
k3s-worker-2 Ready <none> 3m v1.31.x+k3s1
4. 트러블슈팅
Cloud-Init 커널 패닉
- 증상: VM 부팅 시 kernel panic — Syncing
- 원인:
terraform.tfvars의 비밀번호에 특수문자($,!등)가 Cloud-Init YAML 파싱을 깨뜨림 - 해결:
user_account.password제거, SSH 키 인증만 사용
getsockname failed: Not a socket
- 증상: Ansible 실행 시
getsockname failedSSH 에러 - 원인: WSL에서 Windows
ssh.exe를 호출하면 Unix socket 호환 문제 발생 - 해결: npiperelay 브릿지로 네이티브 Linux SSH 사용
kubeconfig 권한 거부
- 증상:
kubectl get nodes시 permission denied - 원인:
/etc/rancher/k3s/k3s.yaml이 root 소유 600 권한 - 해결: Ansible에서 자동으로 644 권한 설정 +
jw사용자.bashrc에 KUBECONFIG 환경변수 추가
5. 다음 단계
- ArgoCD 설치 및 GitOps 파이프라인 구성
- Gitea Actions Runner 연동 (CI/CD)
- Helm 차트 기반 애플리케이션 배포
- 모니터링: Prometheus + Grafana 스택