개요

  • 목적: 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-agent

3. 실행

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 nodes
NAME           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 failed SSH 에러
  • 원인: 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. 다음 단계

  1. ArgoCD 설치 및 GitOps 파이프라인 구성
  2. Gitea Actions Runner 연동 (CI/CD)
  3. Helm 차트 기반 애플리케이션 배포
  4. 모니터링: Prometheus + Grafana 스택