OpenCSP/MVP 프로젝트

API 요청으로 PVE VM 생성하기

miiml 2026. 3. 25. 19:15

2026.04.13 - [프로젝트/OpenCSP] - [OpenCSP] Index - Provisioning Flow

 

[OpenCSP] Index - Provisioning Flow

2026.03.23 - [프로젝트/OpenCSP] - API 요청으로 Terraform CR 생성하기 2026.03.25 - [프로젝트/OpenCSP] - API 요청으로 PVE VM 생성하기 2026.03.26 - [프로젝트/OpenCSP] - OpenCSP Console로 VM 생성해보기 2026.03.28 - [프로젝

miiml.tistory.com

 


 
이전 글에서 API로 직접 Terraform CR을 생성해봤다.
그리고 snippets 파일을 SSH가 아닌 PVE API를 사용한 전달로 변경하는 게 나을 거 같다고 생각했어서 모듈을 해당 방식으로 수정했다. 


먼저 기존 모듈을 사용해서 구성해둔 인프라에는 영향을 주지 않기 위해 모듈에 버전 tag랑 release note를 남겨줬고,

Core에서 해당 태그의 코드를 사용하도록 지정해줬다. (관련 커밋 : https://github.com/h001-lab/OpenCSP-modules/commit/17f4a557571bfc9b737d47631eadd00e11709ecc)
 

모듈 수정 후 테스트 해보면서 PVE에서 API로 snippets 파일 업로드를 지원하지 않는다는걸 알게됐는데 (2019년 관련 이슈만 있고 아직 개발진행 안됐다고 함, 현재는 iso랑 vztmpl만 지원)
 
생각해보니까 처음 모듈을 구성할 때 SSH로 했던 이유가 이거였는데 다른 작업들을 하다보니 까먹고 한번 더 개발해버렸다.

(그래도 덕분에 모듈에 버저닝이 추가됐으니까 장기적으로는 이득..)
 
아무튼 위에 작업들을 하면서 몇 가지 정리해두고 싶은게 생겨서 2번 글을 따로 작성했다.
 
SSH 방식에서 Terraform 컨테이너에 SSH key와 API 크레덴셜을 전달해야하니까 기존 Tofu-controller Secret에 해당 내용을 추가해준 부분, provision(wrapper) 디렉토리 구조 수정, 테라폼 모듈 버저닝, Release Note 반 자동화 같은 내용들인데
 
일단 여기선 2번째 까지만 적어두고 나머진 나중에 정리해봐야겠다.
 

Modules 수정 작업

먼저 ssh 키 새로 생성해서 host에 등록해주고

# 키 생성
ssh-keygen -t ed25519 -f ~/.ssh/pve-tofu -C "tofu-controller" -N "" 

# host에 키 등록
ssh-copy-id -i ~/.ssh/pve-tofu.pub root@{pve ip}

 
 
위에 생성한 pve-tofu 내용을 기존 secret.yaml에 등록해주면 된다. (sops로 암호화도 해줌)

---
apiVersion: v1
kind: Secret
metadata:
  name: pve-ssh-key
  namespace: flux-system
type: Opaque
stringData:
  id_rsa: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    ~/.ssh/pve-tofu 내용 붙여넣기 
    -----END OPENSSH PRIVATE KEY-----

 
참고로 기존 secret에도 ssh 관련 값이 있으니까 거기도 맞춰주야 됨.
 
저 키를 컨테이너에 마운트 해주는건 Terraform CR이 해준다. 
secret 잘 생성 되었으면 아래처럼 curl을 보내볼 수 있다.

curl -v -k -X POST \
  "${PVE_K3S_API_SERVER}/apis/infra.contrib.fluxcd.io/v1alpha2/namespaces/flux-system/terraforms" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
  "apiVersion": "infra.contrib.fluxcd.io/v1alpha2",
  "kind": "Terraform",
  "metadata": {
    "name": "test-vm-provision",
    "namespace": "flux-system",
    "annotations": {
	  "kustomize.toolkit.fluxcd.io/prune": "disabled"
	}
  },
  "spec": {
    "path": "./bootstrap/terraform/provisions/proxmox-vm",
    "interval": "10m",
    "approvePlan": "auto",
    "destroyResourcesOnDeletion": true,
    "sourceRef": {
      "kind": "GitRepository",
      "name": "flux-system", 
      "namespace": "flux-system"
    },
  "runnerPodTemplate": {
      "spec": {
        "volumes": [{
          "name": "ssh-key",
          "secret": {
            "secretName": "pve-ssh-key",
            "defaultMode": 292
          }
        }],
        "volumeMounts": [{
          "name": "ssh-key",
          "mountPath": "/home/runner/.ssh",
          "readOnly": true
        }]
      }
    },
    "varsFrom": [
      {"kind": "Secret", "name": "terraform-secrets"}
    ],
    "vars": [
      {"name": "vm_name", "value": "test-vm3"},
      {"name": "vm_id", "value": 7003},
      {"name": "cores", "value": 1},
      {"name": "memory", "value": 2048},
      {"name": "disk_size", "value": "50G"},
      {"name": "vm_ip", "value": "{IP}/24"},
      {"name": "vm_gw", "value": "{GW}"},
      {"name": "vm_network_bridge", "value": "vmbr0"},
      {"name": "target_node", "value": "pve"},
      {"name": "template_name", "value": "ubuntu-2404-template"},
      {"name": "storage_pool", "value": "local-lvm"},
      {"name": "snippet_storage_pool", "value": "local"}
    ]
  }
}'

 
 
몇가지 옵션들 설명해보면

"annotations": {
  "kustomize.toolkit.fluxcd.io/prune": "disabled"
}

이건 fluxcd의 prune 옵션인데, 이거 활성화시키고 git에 코드가 없으면(flux가 관리하지 않는 리소스면) 계속 제거해주는 옵션이다. 
클러스터 관리 면에선 켜주는게 좋지만 CR을 BE가 생성해야 해서 꺼줬다.
 

"destroyResourcesOnDeletion": true,

이건 리소스가 삭제될 때 destory를 진행할지에 대한 옵션이고, 이게 켜져있으면 Terraform CR이 제거될 때 생성된 리소스가 같이 제거됨. 
 

"path": "./bootstrap/terraform/provisions/proxmox-vm",
"sourceRef": {
    "kind": "GitRepository",
    "name": "flux-system", 
    "namespace": "flux-system"
},

이 부분이 2번째 항목인데 기존에 tofu-controller가 참조하기 위해 modules/.../provision 으로 만들었던 wrapper를 core로 옮겨줬다. 이렇게 하면 GitRepository CR을 별도로 추가할 필요없고, 모듈에 두는거 보다 Core에 두는게 운영 관점에서 더 맞다.
 

"runnerPodTemplate": {
      "spec": {
        "volumes": [{
          "name": "ssh-key",
          "secret": {
            "secretName": "pve-ssh-key",
            "defaultMode": 292
          }
        }],
        "volumeMounts": [{
          "name": "ssh-key",
          "mountPath": "/home/runner/.ssh",
          "readOnly": true
        }]
      }
    },

 
runnerPodTemplate 부분이 위에서 생성한 ssh 키를 컨테이너에 마운트 시켜주는 부분이고, 권한을 292(read)로 줘서 PVE 접근용 ssh 키를 읽을 수 있게 해줌 
 
참고로 아래 명령어로 필드 구조를 알 수 있다.

kubectl explain terraform.spec.runnerPodTemplate.spec

 
 
실행하면 아래처럼 Apply가 성공하고 VM도 생성된걸 볼 수 있음

 
 
삭제도 잘 된다. (근데 참고로 finalizer를 먼저 제거하면 CR은 잘 지워지지만 VM 리소스가 제거 되지 않는다.)

curl -k -X DELETE \
  "${PVE_K3S_API_SERVER}/apis/infra.contrib.fluxcd.io/v1alpha2/namespaces/flux-system/terraforms/test-vm-provision" \
  -H "Authorization: Bearer ${TOKEN}"