Troubleshooting 2026.10.25 7 min read

Terraform으로 vSphere VM을 복제하고 테스트 자원을 정리하기까지

이때 Terraform이 맡은 범위는 vSphere 리소스의 생성과 관리였다. 게스트 안의 패키지와 서비스 설정은 다음 단계의 Ansible로 넘겼다. 우선 VM 생성의 기준을 만들고, 만들어진 서버의 접속 상태는 따로 확인하는 순서로 진행했다.

vSphere에서 VM을 직접 만드는 과정을 반복하다 보니 CPU와 메모리, 디스크와 네트워크를 코드에 남기고 싶어졌다. 이후 Kubernetes 노드도 같은 템플릿에서 준비할 계획이었다. 처음부터 여러 대를 만들기보다 vCenter 조회와 테스트 VM 한 대의 생성부터 확인했다.

이때 Terraform이 맡은 범위는 vSphere 리소스의 생성과 관리였다. 게스트 안의 패키지와 서비스 설정은 다음 단계의 Ansible로 넘겼다. 우선 VM 생성의 기준을 만들고, 만들어진 서버의 접속 상태는 따로 확인하는 순서로 진행했다.

첫 plan은 VM 생성보다 API 조회 확인이었다

당시 출력에 남은 Terraform은 v1.16.6, 설치된 vSphere Provider는 v2.17.1이었다. 이 값은 당시 환경의 기록이다. 구성에서는 Datacenter, Cluster, 공유 NFS datastore, VM Network와 Ubuntu 템플릿을 data source로 조회했다. Cluster에서 얻은 resource pool ID도 VM 배치에 사용할 값으로 확인했다.

Terraform 1.16.6과 vSphere Provider 2.17.1
Terraform 1.16.6과 vSphere Provider 2.17.1.

처음 plan에는 data source와 output만 있었다. API에서 실제 인벤토리를 읽어 왔고 구성 검증도 성공했지만, 새 VM을 선언한 단계는 아니었다. 터미널에 출력된 식별자를 보면서 내가 의도한 Cluster와 datastore를 대상으로 작업하고 있는지부터 확인했다.

Provider에는 실습용 vCenter의 자체 서명 인증서를 허용한 설정이 있었다. 이 연결 설정을 이후 Registry나 애플리케이션 HTTPS에도 그대로 적용한 것은 아니다. 프로젝트 안에서도 연결 대상마다 신뢰 설정은 따로 다뤘다.

최소 Clone으로 확인한 생성 경로

테스트 VM은 CPU 2개와 메모리 2GiB로 만들었다. 템플릿의 guest 유형, firmware, SCSI와 네트워크 어댑터 유형을 가져오고, 20GiB Thin 디스크를 사용했다. 원본 로그에는 EFI, PVSCSI와 VMXNET3가 남아 있다.

Plan: 1 to add, 0 to change, 0 to destroy.
Creation complete after 3m20s
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

처음으로 코드가 vCenter의 VM 생성까지 이어졌다. 다만 이 구성에서는 게스트 IP와 네트워크 대기를 생략했다. 따라서 apply 완료만으로 SSH 접속과 게스트 초기 설정까지 끝났다고 판단할 수는 없었다. 생성한 리소스와 부팅한 게스트의 상태를 이어서 확인해야 했다.

관리·Kubernetes·CI VM을 함께 보여주는 클러스터 인벤토리
클러스터 VM 9개와 관리·Kubernetes·CI 역할 구성.

다음 테스트에서는 별도 VM에 VMware customization을 넣어 호스트명과 정적 네트워크를 지정했다. 이미 만든 VM에 옵션을 추가했을 때 교체가 필요한지 혼동하지 않도록 대상을 나눴다. 계정과 SSH 키까지 이 블록에서 관리한 것은 아니어서 로그인 준비는 템플릿 쪽에서 이어 갔다.

새 셸에서 사라진 인증 환경변수

작업을 다시 시작한 날에는 Terraform이 사용자와 비밀번호를 요구했다. 앞서 API 조회에 성공했는데도 아래 오류가 나왔다.

Error: Missing required argument
The argument "user" is required, but no definition was found.
The argument "password" is required, but no definition was found.

원인은 실행한 셸의 차이였다. 인증 정보는 환경변수로 전달했는데 새 셸이나 sudo -i 이후에는 값이 없었다. Provider가 요청에 필요한 입력을 받지 못한 상태였다. vCenter가 보낸 인증 거절 응답을 받은 상황과는 점검 순서가 달랐다.

처음에는 환경변수를 다시 입력해 진행했다. 이후 같은 문제를 반복하지 않도록 당시에는 root만 읽을 수 있는 설정 파일을 두고 셸에서 불러오게 했다. 권한은 제한했지만 저장 내용은 평문이었다. 셸 시작 파일이 실제로 읽히는지도 확인 대상으로 남겼다. 이 초기 실습 처리를 이후 Jenkins의 Credentials 관리와 같은 방식으로 설명하지는 않았다.

이 오류를 겪은 뒤에는 인증 실패라는 말만 듣고 서버부터 점검하지 않게 됐다. 입력이 빠졌는지, TLS 단계에서 막혔는지, API가 실제로 거절했는지부터 구분했다. 오류가 발생한 위치를 먼저 읽어야 불필요한 변경을 줄일 수 있었다.

state와 선언을 함께 보며 테스트 VM을 정리했다

Kubernetes 노드 준비가 끝난 뒤에는 역할을 마친 테스트 VM 두 대를 정리했다. 여기서도 삭제 대상의 범위를 먼저 확인했다. 같은 작업 디렉터리에 Kubernetes VM 선언이 있었으므로 전체 destroy를 실행할 상황은 아니었다.

terraform state list로 관리 대상을 확인하고 테스트 VM 선언을 Terraform이 읽지 않는 예제 파일로 옮기는 흐름으로 진행했다. 그다음 plan에서 테스트 VM 두 대만 삭제되는지 확인하도록 했다. 목표는 0 to add, 0 to change, 2 to destroy였으며 Kubernetes VM은 유지하는 범위였다. Ansible Inventory의 테스트 전용 그룹 제거와 실제 노드 그룹의 연결 확인도 후속 정리 항목으로 잡았다.

Terraform state의 Kubernetes VM 관리 목록
Terraform state의 Kubernetes VM 관리 목록.

테스트 자원을 정리할 때도 선언을 바꾼 결과를 plan으로 읽고, 대상이 맞을 때 apply하며, 이후 state와 plan을 다시 보는 흐름을 유지했다. 생성과 삭제 모두 변경 범위를 먼저 확인하는 작업이었다.

VM 생성은 한 번의 성공 화면으로 끝나지 않았다. API 대상 확인, Clone, 게스트 접속, 후속 구성, 테스트 자원 정리까지 이어져야 다음 작업의 출발점이 정돈됐다. Terraform을 쓰면서 얻은 변화는 클릭 횟수보다 관리 대상과 변경 범위를 실행 전에 읽을 수 있게 된 점이었다.

증거를 정리한 2026년 10월 19일에는 관리 서버의 Terraform 1.16.6을 확인했다. 최초 Clone 완료 원본 로그도 별도로 보존했다. Terraform 프로젝트 경로와 최신 state·HCL은 추가 확인이 필요하다.

SEARCH JOURNAL

기록 검색

글 제목, 요약, 태그에서 찾습니다.

검색을 준비하고 있어요.

검색어를 입력해 주세요.

    Ctrl/⌘ K 검색 Esc 닫기 ↑ ↓ 결과 이동