1. Adım: Yeni Proje Klasörü Oluştur
Docker demo’sundan ayrı tutmak için yeni bir klasör açıyoruz.
Komutlar:
cd ~
mkdir terraform-vsphere-demo
cd terraform-vsphere-demoSonuç:
Şu konumda olmalısın: ~/terraform-vsphere-demo
2. Adım: main.tf ve terraform.tfvars Dosyalarını Oluştur
vSphere ortamında güvenlik en önemli konu olduğundan, kullanıcı adı ve şifreyi kodun içinde değil, ayrı bir dosyada tutuyoruz.
1. main.tf Dosyasını Oluştur
Komut (tamamı tek blok halinde çalıştır):
cat <<EOF > main.tf
# --- Değişken Tanımlamaları ---
variable "vsphere_user" {}
variable "vsphere_password" {}
variable "vsphere_server" { default = "vcenter.dataflowx.int" }
# --- vSphere Provider ---
provider "vsphere" {
user = var.vsphere_user
password = var.vsphere_password
vsphere_server = var.vsphere_server
allow_unverified_ssl = true # Self-signed sertifika için gerekli
}
# --- Data Sources: vCenter'daki Nesneleri Bul ---
data "vsphere_datacenter" "dc" {
name = "datacenter"
}
data "vsphere_host" "host" {
name = "192.168.x.x"
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_datastore" "datastore" {
name = "x.x_Datastore4"
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_network" "network" {
name = "vlan1"
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_virtual_machine" "template" {
name = "Template Windows Server"
datacenter_id = data.vsphere_datacenter.dc.id
}
# --- Yeni VM Oluştur (Template'ten Clone) ---
resource "vsphere_virtual_machine" "vm" {
name = "terraform-test-vm"
resource_pool_id = data.vsphere_host.host.resource_pool_id
datastore_id = data.vsphere_datastore.datastore.id
num_cpus = 2
memory = 4096
guest_id = data.vsphere_virtual_machine.template.guest_id
firmware = data.vsphere_virtual_machine.template.firmware
scsi_type = data.vsphere_virtual_machine.template.scsi_type
network_interface {
network_id = data.vsphere_network.network.id
adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0]
}
disk {
label = "disk0"
size = data.vsphere_virtual_machine.template.disks[0].size
thin_provisioned = data.vsphere_virtual_machine.template.disks[0].thin_provisioned
}
clone {
template_uuid = data.vsphere_virtual_machine.template.id
customize {
timeout = 30
windows_options {
computer_name = "TERRAWIN01"
workgroup = "WORKGROUP"
admin_password = "Sifre123!"
time_zone = 90 # Türkiye (GMT+3)
auto_logon = true
auto_logon_count = 1
}
network_interface {
ipv4_address = "192.168.x.x"
ipv4_netmask = 24
}
ipv4_gateway = "192.168.x.1"
dns_server_list = ["8.8.8.8", "8.8.4.4"]
}
}
}
EOF2. terraform.tfvars Dosyasını Oluştur (Gizli Bilgiler Buraya!)
Komut:
cat <<EOF > terraform.tfvars
vsphere_user = "administrator@vsphere.local"
vsphere_password = "BURAYA_GERÇEK_VCENTER_ŞİFRENİ_YAZ"
EOFDİKKAT ÖNEMLİ:
terraform.tfvarsdosyasını açıp (nano terraform.tfvars) şifre kısmını gerçek vCenter şifren ile değiştir.- Eğer kullanıcı adın farklıysa onu da düzelt (örneğin:
user@domain.com). - Bu dosya asla GitHub’a veya başkasına gönderilmemeli.
Ayrıca Kontrol Et:
ipv4_address = "192.168.x.x"→ Bu IP vlan1 segmentinde boş mu?ipv4_gateway = "192.168.x.1"→ Gateway doğru mu?
3. Adım: Terraform’u Başlat (Init)
vSphere provider’ını indirip projeyi hazır hale getiriyoruz.
Komut:
terraform initBeklenen Çıktı:
Initializing provider plugins...
- Finding hashicorp/vsphere versions...
- Installing hashicorp/vsphere vX.X.X...
Terraform has been successfully initialized!4. Adım: Plan Oluştur (Önizleme)
Terraform vCenter’a bağlanıp tüm nesneleri (datacenter, host, datastore, network, template) bulmaya çalışacak.
Komut:
terraform planBeklenen İyi Sonuç:
Plan: 1 to add, 0 to change, 0 to destroy.
+ resource "vsphere_virtual_machine" "vm" { ... }Olası Hatalar ve Çözümleri:
- x509: certificate signed by unknown authority →
allow_unverified_ssl = truezaten var, sorun olmamalı. - Authentication failed → Kullanıcı adı/şifre yanlış.
- Unable to find datacenter/network/datastore/template → İsimleri tam olarak vCenter’daki gibi yazdığından emin ol (büyük/küçük harf duyarlı olabilir).
- Host not found → Host IP yerine host adı (FQDN) deneyebilirsin.
5. Adım: Uygula (Apply)
Her şey düzgünse VM’yi gerçekten oluşturalım.
Komut:
terraform applyNe yapmalısın?
- Plan tekrar gösterilecek.
- En altta
Do you want to perform these actions?sorusu gelecek. yesyazıp Enter’a bas.
Beklenen Sonuç:
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.VM artık vCenter’da terraform-test-vm adıyla görünmeli ve birkaç dakika içinde açılmalı.
6. Adım: Sonuçları Doğrula
vCenter konsoluna girip:
- VM’nin
datacenter→192.168.x.xhost’unda çalıştığını, - IP’sinin
192.168.x.xolduğunu, - Otomatik login ile masaüstünün açıldığını kontrol et.
7. Adım: Temizleme (Destroy)
İşin bittiğinde VM’yi silmeyi unutma!
Komut:
terraform destroyyes yazıp onay ver.
Sonuç:
Destroy complete! Resources: 1 destroyed.Artık:
- vSphere provider ile gerçek bir kurumsal ortamda VM clone’layabiliyorsun.
- Gizli bilgileri güvenli şekilde yönetiyorsun.
- Infrastructure as Code prensibini hipervizör seviyesinde uyguladın.
Bu aynı mantıkla yüzlerce VM, farklı template’ler (Linux/Windows), farklı network’ler ve hatta linked clone ile dev ortamlar kurabilirsin.
Terraform ile vSphere – Daha Modüler ve Yeniden Kullanılabilir Yapı
Bu demo’yu daha profesyonel, bakım yapılabilir ve yeniden kullanılabilir hale getiriyoruz. Tüm sabit değerleri değişkenlere taşıyarak:
- Aynı kodu farklı ortamlar/lab’lar için kolayca kullanabileceksin.
- Gizli bilgileri daha güvenli yöneteceksin.
- Kodun okunabilirliği ve sürdürülebilirliği artacak.
8. Adım: Modüler Yapıya Geçiş – Dosyaları Güncelle
Hâlen ~/terraform-vsphere-demo klasöründeysen devam et. Aşağıdaki 3 dosyayı sırasıyla oluştur/güncelle.
1. variables.tf Dosyasını Oluştur
Bu dosya tüm değişkenleri tanımlar ve açıklama ekler.
Komut:
cat <<EOF > variables.tf
variable "vsphere_user" {
description = "vSphere kullanıcı adı"
type = string
}
variable "vsphere_password" {
description = "vSphere şifresi"
type = string
sensitive = true
}
variable "vsphere_server" {
description = "vCenter sunucu adı veya IP"
type = string
}
variable "vsphere_datacenter" {
description = "Datacenter adı"
type = string
}
variable "vsphere_host" {
description = "ESXi host adı veya IP"
type = string
}
variable "datastore_name" {
description = "Datastore adı"
type = string
}
variable "network_name" {
description = "Network (port group) adı"
type = string
}
variable "template_name" {
description = "Klonlanacak template adı"
type = string
}
variable "vm_name" {
description = "Oluşturulacak VM adı"
type = string
}
variable "num_cpus" {
description = "CPU sayısı"
type = number
default = 2
}
variable "memory" {
description = "RAM miktarı (MB)"
type = number
default = 4096
}
variable "disk_label" {
description = "Disk etiketi"
type = string
default = "disk0"
}
variable "computer_name" {
description = "Guest OS bilgisayar adı"
type = string
}
variable "workgroup" {
description = "Workgroup adı (domain yoksa)"
type = string
default = "WORKGROUP"
}
variable "admin_password" {
description = "Guest OS yönetici şifresi"
type = string
sensitive = true
}
variable "time_zone" {
description = "Zaman dilimi kodu (Türkiye = 90)"
type = number
default = 90
}
variable "auto_logon" {
description = "Otomatik login aktif mi?"
type = bool
default = true
}
variable "auto_logon_count" {
description = "Otomatik login sayısı"
type = number
default = 1
}
variable "ipv4_address" {
description = "VM'ye atanacak statik IP"
type = string
}
variable "ipv4_netmask" {
description = "Netmask (CIDR formatında, örn: 24)"
type = number
}
variable "ipv4_gateway" {
description = "Gateway IP"
type = string
}
variable "dns_server_list" {
description = "DNS sunucu listesi"
type = list(string)
default = ["8.8.8.8", "8.8.4.4"]
}
EOF2. terraform.tfvars Dosyasını Güncelle
Tüm değerleri buraya taşıyoruz. Bu dosya yine gizli kalacak.
Komut:
cat <<EOF > terraform.tfvars
vsphere_user = "administrator@vsphere.local"
vsphere_password = "GERÇEK_VCENTER_ŞİFRENİ_BURAYA_YAZ"
vsphere_server = "vcenter.dataflowx.int"
vsphere_datacenter = "datacenter"
vsphere_host = "192.168.x.x"
datastore_name = "x.x_Datastore4"
network_name = "vlan1"
template_name = "Template Windows Server"
vm_name = "terraform-test-vm"
num_cpus = 2
memory = 4096
computer_name = "TERRAWIN01"
admin_password = "Sifre123!"
ipv4_address = "192.168.x.x"
ipv4_netmask = 24
ipv4_gateway = "192.168.x.1"
dns_server_list = ["8.8.8.8", "8.8.4.4"]
EOFDİKKAT:vsphere_password ve admin_password satırlarını gerçek şifrelerinle güncelle (nano terraform.tfvars ile).
3. main.tf Dosyasını Güncelle
Tüm sabit değerleri değişkenlerle değiştiriyoruz.
Komut:
cat <<EOF > main.tf
# --- vSphere Provider ---
provider "vsphere" {
user = var.vsphere_user
password = var.vsphere_password
vsphere_server = var.vsphere_server
allow_unverified_ssl = true
}
# --- Data Sources ---
data "vsphere_datacenter" "dc" {
name = var.vsphere_datacenter
}
data "vsphere_host" "host" {
name = var.vsphere_host
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_datastore" "datastore" {
name = var.datastore_name
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_network" "network" {
name = var.network_name
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_virtual_machine" "template" {
name = var.template_name
datacenter_id = data.vsphere_datacenter.dc.id
}
# --- VM Resource ---
resource "vsphere_virtual_machine" "vm" {
name = var.vm_name
resource_pool_id = data.vsphere_host.host.resource_pool_id
datastore_id = data.vsphere_datastore.datastore.id
num_cpus = var.num_cpus
memory = var.memory
guest_id = data.vsphere_virtual_machine.template.guest_id
firmware = data.vsphere_virtual_machine.template.firmware
scsi_type = data.vsphere_virtual_machine.template.scsi_type
network_interface {
network_id = data.vsphere_network.network.id
adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0]
}
disk {
label = var.disk_label
size = data.vsphere_virtual_machine.template.disks[0].size
thin_provisioned = data.vsphere_virtual_machine.template.disks[0].thin_provisioned
}
clone {
template_uuid = data.vsphere_virtual_machine.template.id
customize {
timeout = 30
windows_options {
computer_name = var.computer_name
workgroup = var.workgroup
admin_password = var.admin_password
time_zone = var.time_zone
auto_logon = var.auto_logon
auto_logon_count = var.auto_logon_count
}
network_interface {
ipv4_address = var.ipv4_address
ipv4_netmask = var.ipv4_netmask
}
ipv4_gateway = var.ipv4_gateway
dns_server_list = var.dns_server_list
}
}
}
EOF9. Adım: Değişiklikleri Uygula
Dosyaları güncellediğine göre Terraform’un yeni yapıyı tanıması lazım.
Komutlar sırasıyla:
terraform init # Eğer daha önce init yapılmadıysa veya provider güncellendiyse
terraform fmt # Kod formatını otomatik düzelt (isteğe bağlı ama tavsiye edilir)
terraform validate # Syntax kontrolü
terraform plan # Değişiklikleri önizleterraform plan çıktısında yine Plan: 1 to add... görmelisin (eğer VM daha önce silindiyse).
Ardından:
terraform applyyes yazıp onay ver.
Avantajları Neler Oldu?
- Aynı klasörü kopyalayıp sadece
terraform.tfvarsdosyasını değiştirerek **farklı lab’lardaaynı kodu kullanabilirsin. - Yeni bir VM istiyorsan sadece
terraform.tfvars‘a yeni değerler ekleyipapplyyapman yeterli. - Kod çok daha temiz ve profesyonel görünüyor.
10. Adım: Proje Klasör Yapısını İnceleme ve Dosyaları Anlama
Şimdi terraform apply işlemini başarıyla tamamladığımıza göre (ve belki bir destroy da yaptığımıza göre), proje klasörümüz biraz daha kalabalık hale geldi.
Klasörün mevcut durumunu görmek için şu komutu çalıştır:
tree -aTipik Çıktı:
root@srv-netbox:~/terraform-vsphere-demo# tree -a
.
├── main.tf
├── variables.tf
├── terraform.tfvars
├── .terraform
│ └── providers
│ └── registry.terraform.io
│ └── hashicorp
│ └── vsphere
│ └── 2.12.0
│ └── linux_amd64
│ ├── LICENSE.txt
│ └── terraform-provider-vsphere_v2.12.0_x5
├── .terraform.lock.hcl
├── terraform.tfstate
├── terraform.tfstate.backup
└── .terraform.tfstate.backup (bazen olur)
8 directories, 8 filesBiz sadece 3 dosya oluşturduk: main.tf, variables.tf, terraform.tfvars.
Peki geri kalanlar ne işe yarıyor? DevOps dünyasında “temiz repo” yönetimi için bunları bilmek şart.
Hepsini tek tek açıklayalım:
.terraform/ (Klasör)
- Ne işe yarar?
Terraform’uninitkomutuyla indirdiği provider eklentileri (bizim durumumuzda vSphere provider) burada saklanır. - Neden oluşur?
terraform initçalıştırdığın anda otomatik indirilir. İşletim sistemi ve mimariye göre farklı dosyalar olur (Linux_amd64, Darwin_arm64 vs.). - Git’e eklenir mi?
HAYIR. Herkes kendi makinesindeterraform inityaparak bunları kendisi indirir. Git’e atarsan repo şişer ve platform uyumsuzluğu yaratır.
.terraform.lock.hcl (Dosya)
- Ne işe yarar?
Provider’ların tam sürümünü kilitler (örneğin vSphere 2.12.0). Böylece ekipteki herkes aynı sürümü kullanır ve “bende çalışıyor, sende çalışmıyor” sorunu önlenir. - Git’e eklenir mi?
EVET (tavsiye edilir). Özellikle takım çalışmasında mutlaka Git’e commit edilmelidir. Tek kişilik basit projelerde opsiyonel ama iyi alışkanlık için ekle.
terraform.tfstate (En kritik dosya!)
- Ne işe yarar?
Terraform’un hafızası. Oluşturduğun VM’nin gerçek ID’si, IP’si, disk UUID’si, hatta bazı durumlarda şifrelerin hash’lenmiş hali burada saklanır. Terraform bir sonrakiplanveyaapply‘da “ne değişti?” sorusunu bu dosyaya bakarak cevaplar. - Git’e eklenir mi?
**ASLA HAYIR! **
Bu dosya sadece Terraform tarafından yönetilir. Git’e atılırsa state çakışmaları (conflict) olur, yanlışlıkla VM silinebilir veya gizli bilgiler sızabilir.
terraform.tfstate.backup
- Ne işe yarar?
Herapplyveyadestroyişleminden önce Terraform otomatik olarak önceki state’in yedeğini alır. - Git’e eklenir mi?
HAYIR. Aynı nedenlerle: gereksiz ve tehlikeli.
Özet Tablo: Git’e Eklemeli miyiz?
| Dosya/Klasör | Açıklama | Git’e Eklenir mi? |
|---|---|---|
main.tf | Ana konfigürasyon kodu | EVET |
variables.tf | Değişken tanımlamaları | EVET |
terraform.tfvars | Değerler (şifreler dahil) | HAYIR (gizli bilgi var) |
.terraform/ | İndirilen provider’lar | HAYIR |
.terraform.lock.hcl | Provider sürüm kilidi | EVET (takım için) |
terraform.tfstate | Gerçek altyapı durumu | ASLA HAYIR |
terraform.tfstate.backup | State yedeği | ASLA HAYIR |
Temiz Repo İçin .gitignore Önerisi
Git’e “Ben bunları takip etme, yok say” demek için .gitignore dosyası oluştururuz. İçine bilinmeyen, şifreli veya gereksiz dosyaları yazarız.
Sunucunda şu komutu çalıştır:
cat <<EOF > .gitignore
# Terraform Çalışma Dosyaları
.terraform/
.terraform.lock.hcl
# Terraform State (Asla yükleme)
*.tfstate
*.tfstate.*
*.tfstate.backup
crash.log
# Değişken Dosyaları (Şifre içerir)
*.tfvars
!example.tfvars # Örnek (boş) tfvars varsa atabilirsin, ama bizde yok
# Gezici Dosyalar
.terraform/
*.swp
*.swo
*~
EOFBu dosya, Git’e şunu der: _”Lütfen .terraform klasörünü, terraform.tfstate dosyasını ve *.tfvars dosyalarını görmezden gel.”
