Azure CLI ile Sanal Makine Yönetimi: Kapsamlı Bir Rehber
Bulut altyapısını komut satırından yönetmek, GUI’ye tıklaya tıklaya vakit kaybetmekten her zaman daha verimlidir. Azure CLI, Microsoft’un bu ihtiyacı karşılamak için geliştirdiği, hem Linux hem Windows üzerinde çalışan çapraz platform bir araç. Günlük VM operasyonlarını otomatize etmek, toplu işlemler yapmak ya da CI/CD pipeline’larına Azure komutları entegre etmek istiyorsanız, Azure CLI olmadan bu işleri yapmak gerçekten yorucu olabiliyor. Bu yazıda, Azure CLI’yi kullanarak sanal makine yönetimini A’dan Z’ye ele alacağız.
Azure CLI Kurulumu ve Temel Hazırlık
Önce ortamı hazırlayalım. Ubuntu/Debian tabanlı sistemlerde kurulum şu şekilde:
# Microsoft imzalama anahtarını ekle
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Kurulumu doğrula
az version
CentOS/RHEL için ise:
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo dnf install -y azure-cli
Kurulum tamamlandıktan sonra hesabınıza giriş yapmanız gerekiyor:
# Tarayıcı üzerinden interaktif giriş
az login
# Service principal ile giriş (otomasyon için ideal)
az login --service-principal
--username <app-id>
--password <password>
--tenant <tenant-id>
Eğer birden fazla subscription’ınız varsa, hangi subscription üzerinde çalıştığınıza dikkat edin. Bu detayı gözden kaçırmak, yanlış ortamda kaynak oluşturmanıza neden olabilir.
# Tüm subscription'ları listele
az account list --output table
# Aktif subscription'ı değiştir
az account set --subscription "Production-Subscription"
# Hangi subscription'da olduğunu kontrol et
az account show --query "{Name:name, ID:id, State:state}" --output table
--output parametresi oldukça kullanışlı. table, json, tsv ve yaml formatlarını destekliyor. Otomasyon scriptleri için tsv veya json, insan gözüyle okuma için table formatını tercih edin.
Resource Group Oluşturma
VM oluşturmadan önce bir resource group’a ihtiyacınız var. Resource group, Azure kaynaklarını mantıksal olarak gruplandırmanın temel yolu.
# Resource group oluştur
az group create
--name rg-production-eastus
--location eastus
--tags Environment=Production Team=Infrastructure
# Mevcut resource group'ları listele
az group list --output table
# Belirli bir tag'e göre filtrele
az group list --tag Environment=Production --output table
Naming convention konusunda disiplinli olmak ilerleyen süreçte hayat kurtarır. rg-production-eastus formatında bir isimlendirme; resource type, environment ve region bilgisini tek bakışta anlamanızı sağlar.
VM Oluşturma: Temel ve İleri Düzey Senaryolar
Temel VM Oluşturma
az vm create
--resource-group rg-production-eastus
--name vm-webserver-01
--image Ubuntu2204
--size Standard_B2s
--admin-username azureuser
--ssh-key-values ~/.ssh/id_rsa.pub
--vnet-name vnet-production
--subnet subnet-web
--public-ip-sku Standard
--nsg-rule SSH
--output json
Bu komut çalıştıktan sonra VM’in public IP adresini, özel IP adresini ve diğer bilgileri JSON çıktısında göreceksiniz. --ssh-key-values parametresiyle şifre yerine SSH key kullanmak güvenlik açısından zorunluluk sayılmalı. Production ortamında şifreyle VM açmak kabul edilebilir bir pratik değil.
Disk ve Depolama Seçenekleriyle VM Oluşturma
Gerçek dünya senaryolarında genellikle işletim sistemi diskinin yanı sıra ek data diskleri de eklemeniz gerekir:
az vm create
--resource-group rg-production-eastus
--name vm-database-01
--image Ubuntu2204
--size Standard_D4s_v3
--admin-username azureuser
--ssh-key-values ~/.ssh/id_rsa.pub
--os-disk-size-gb 64
--os-disk-sku Premium_LRS
--data-disk-sizes-gb 256 512
--data-disk-sku Premium_LRS
--availability-set avset-database
--no-wait
--no-wait parametresi özellikle toplu VM oluşturma senaryolarında çok işe yarıyor. Komut, VM oluşturma işlemini başlatıp terminali hemen serbest bırakıyor. Böylece birden fazla VM’i paralel olarak oluşturabilirsiniz.
VM Listeme ve Durum Kontrolü
# Resource group içindeki tüm VM'leri listele
az vm list
--resource-group rg-production-eastus
--output table
# Tüm subscription'daki VM'leri çalışma durumuyla birlikte göster
az vm list
--show-details
--query "[].{Name:name, State:powerState, Size:hardwareProfile.vmSize, Location:location}"
--output table
# Belirli bir VM'in detaylarını görüntüle
az vm show
--resource-group rg-production-eastus
--name vm-webserver-01
--output json
--query parametresi JMESPath sözdizimini kullanıyor ve çıktıyı filtrelemek için son derece güçlü bir araç. Büyük ortamlarda yüzlerce VM arasından belirli kriterlere göre filtreleme yapmanız gerektiğinde bu parametre hayat kurtarıcı oluyor.
VM Başlatma, Durdurma ve Yeniden Başlatma
Günlük operasyonların büyük kısmı bu komutlardan oluşuyor. Özellikle maliyet optimizasyonu için dev/test ortamlarındaki VM’leri mesai saatleri dışında kapatmak yaygın bir pratik.
# VM'i başlat
az vm start
--resource-group rg-production-eastus
--name vm-webserver-01
# VM'i durdur (deallocate eder, ücret kesilmez)
az vm deallocate
--resource-group rg-production-eastus
--name vm-webserver-01
# VM'i sadece durdur (deallocate etmez, ücret kesilmeye devam eder)
az vm stop
--resource-group rg-production-eastus
--name vm-webserver-01
# VM'i yeniden başlat
az vm restart
--resource-group rg-production-eastus
--name vm-webserver-01
--no-wait
deallocate ile stop arasındaki farka dikkat edin. stop komutu VM’i kapatır ama Azure’un compute kaynaklarını hâlâ sizin için ayırdığı anlamına gelir ve ücret kesilmeye devam eder. deallocate ise compute kaynaklarını serbest bırakır ve işlem maliyetleri durur. Sadece managed disk maliyeti devam eder.
Toplu VM Kapatma Script’i
Bir senaryo düşünelim: Her gece 20:00’de dev ortamındaki tüm VM’leri kapatmak ve sabah 08:00’de başlatmak istiyorsunuz.
#!/bin/bash
# dev-vms-shutdown.sh
RESOURCE_GROUP="rg-development-eastus"
ACTION=$1
if [ "$ACTION" == "stop" ]; then
echo "Tüm dev VM'leri durduruluyor..."
az vm list
--resource-group $RESOURCE_GROUP
--query "[].name"
--output tsv | while read vm_name; do
echo "Durduruluyor: $vm_name"
az vm deallocate
--resource-group $RESOURCE_GROUP
--name $vm_name
--no-wait
done
echo "Tüm VM'ler için deallocate işlemi başlatıldı."
elif [ "$ACTION" == "start" ]; then
echo "Tüm dev VM'leri başlatılıyor..."
az vm list
--resource-group $RESOURCE_GROUP
--query "[].name"
--output tsv | while read vm_name; do
echo "Başlatılıyor: $vm_name"
az vm start
--resource-group $RESOURCE_GROUP
--name $vm_name
--no-wait
done
echo "Tüm VM'ler için start işlemi başlatıldı."
fi
Bu script’i crontab’a ekleyerek otomatize edebilirsiniz:
# crontab -e
0 20 * * 1-5 /opt/scripts/dev-vms-shutdown.sh stop
0 8 * * 1-5 /opt/scripts/dev-vms-shutdown.sh start
VM Boyutunu Değiştirme (Resize)
Uygulama trafik aldıkça ihtiyaçlar değişebiliyor. VM’i kapatmadan ya da kapatarak yeniden boyutlandırabilirsiniz:
# Mevcut VM size'ını kontrol et
az vm show
--resource-group rg-production-eastus
--name vm-webserver-01
--query "hardwareProfile.vmSize"
--output tsv
# O region'da kullanılabilir VM boyutlarını listele
az vm list-vm-resize-options
--resource-group rg-production-eastus
--name vm-webserver-01
--output table
# VM'i yeniden boyutlandır
az vm resize
--resource-group rg-production-eastus
--name vm-webserver-01
--size Standard_D4s_v3
Resize işlemi sırasında VM’in yeniden başlatılması gerektiğini unutmayın. Bu yüzden maintenance window’a almadan production VM’leri resize etmeyin.
Disk Yönetimi
Yeni Disk Ekleme
# Managed disk oluştur
az disk create
--resource-group rg-production-eastus
--name disk-webserver-01-data
--size-gb 128
--sku Premium_LRS
--zone 1
# Diski VM'e bağla
az vm disk attach
--resource-group rg-production-eastus
--vm-name vm-webserver-01
--name disk-webserver-01-data
--caching ReadWrite
Diski VM’e bağladıktan sonra SSH ile bağlanıp diski formatlamanız ve mount etmeniz gerekiyor. Azure CLI bu kısmı yapmıyor; bu işletim sistemi seviyesinde bir görev.
Disk Snapshot Alma
Özellikle production ortamında yapılan değişiklikler öncesinde snapshot almak iyi bir pratik:
# OS diskinin ID'sini al
DISK_ID=$(az vm show
--resource-group rg-production-eastus
--name vm-webserver-01
--query "storageProfile.osDisk.managedDisk.id"
--output tsv)
# Snapshot al
az snapshot create
--resource-group rg-production-eastus
--name snap-webserver-01-$(date +%Y%m%d)
--source $DISK_ID
--sku Standard_LRS
echo "Snapshot başarıyla alındı: snap-webserver-01-$(date +%Y%m%d)"
Network Security Group (NSG) Yönetimi
VM’in hangi portlarına erişileceğini kontrol etmek için NSG kuralları yönetmek sıkça yapılan bir işlem:
# Mevcut NSG kurallarını listele
az network nsg rule list
--resource-group rg-production-eastus
--nsg-name vm-webserver-01-nsg
--output table
# HTTP portu için kural ekle
az network nsg rule create
--resource-group rg-production-eastus
--nsg-name vm-webserver-01-nsg
--name Allow-HTTP
--protocol tcp
--priority 1010
--destination-port-range 80
--access Allow
--direction Inbound
# HTTPS portu için kural ekle
az network nsg rule create
--resource-group rg-production-eastus
--nsg-name vm-webserver-01-nsg
--name Allow-HTTPS
--protocol tcp
--priority 1020
--destination-port-range 443
--access Allow
--direction Inbound
# Sadece belirli bir IP'den SSH erişimine izin ver
az network nsg rule update
--resource-group rg-production-eastus
--nsg-name vm-webserver-01-nsg
--name default-allow-ssh
--source-address-prefixes "203.0.113.10/32"
SSH erişimini her IP’ye açık bırakmak en yaygın güvenlik hatasından biri. NSG kurallarıyla SSH’ı sadece kendi IP adresinize veya VPN subnet’ine kısıtlamak basit ama etkili bir güvenlik önlemi.
VM Extension Kullanımı
VM Extension’lar, VM oluşturulduktan sonra script çalıştırmak veya agent yüklemek için kullanılıyor. Mesela bir VM oluşturup içine otomatik olarak nginx kurdurmak istiyorsanız:
# Custom Script Extension ile nginx kur
az vm extension set
--resource-group rg-production-eastus
--vm-name vm-webserver-01
--name customScript
--publisher Microsoft.Azure.Extensions
--settings '{"commandToExecute": "apt-get update && apt-get install -y nginx && systemctl enable nginx && systemctl start nginx"}'
# Extension durumunu kontrol et
az vm extension show
--resource-group rg-production-eastus
--vm-name vm-webserver-01
--name customScript
--query "provisioningState"
--output tsv
Daha karmaşık kurulumlar için script dosyasını Azure Blob Storage’a yükleyip oradan çalıştırmak daha temiz bir yaklaşım.
Monitoring ve Diagnostics
VM’in sağlık durumunu izlemek için birkaç kullanışlı komut:
# VM'in boot diagnostics loglarını görüntüle
az vm boot-diagnostics get-boot-log
--resource-group rg-production-eastus
--name vm-webserver-01
# VM'in seri konsol çıktısını görüntüle
az vm boot-diagnostics get-boot-log
--resource-group rg-production-eastus
--name vm-webserver-01 2>&1 | tail -50
# Tüm subscription'daki running VM'leri ve maliyetli size'ları listele
az vm list
--show-details
--query "[?powerState=='VM running'].{Name:name, Size:hardwareProfile.vmSize, RG:resourceGroup}"
--output table
Tag Yönetimi
Tag’ler, maliyet yönetimi ve kaynak organizasyonu için kritik önem taşıyor. Faturanızı ekiplere veya projelere göre bölmek istiyorsanız tag’leri tutarlı kullanmak zorundasınız:
# VM'e tag ekle
az vm update
--resource-group rg-production-eastus
--name vm-webserver-01
--set tags.Environment=Production tags.Team=WebTeam tags.CostCenter=CC-1234
# Belirli tag'e sahip tüm VM'leri bul
az vm list
--query "[?tags.Environment=='Production'].{Name:name, RG:resourceGroup}"
--output table
# Tag'i kaldır
az vm update
--resource-group rg-production-eastus
--name vm-webserver-01
--remove tags.CostCenter
VM’i Silme
VM silmek basit görünse de dikkat edilmesi gereken detaylar var. Varsayılan olarak az vm delete komutu yalnızca VM kaynağını siler; ilişkili diskler, NIC ve public IP gibi kaynaklar silmez.
# Sadece VM'i sil (diskler ve NIC kalır)
az vm delete
--resource-group rg-production-eastus
--name vm-webserver-01
--yes
# VM ile birlikte ilişkili tüm kaynakları sil
az vm delete
--resource-group rg-production-eastus
--name vm-webserver-01
--yes
# İlişkili NIC'leri bul ve sil
az network nic list
--resource-group rg-production-eastus
--query "[?virtualMachine==null].name"
--output tsv | while read nic; do
echo "Silinmeyen NIC temizleniyor: $nic"
az network nic delete
--resource-group rg-production-eastus
--name $nic
done
Production’da VM silerken --yes parametresini dikkatli kullanın. Bu parametre onay adımını atlıyor. Script içinde kullanmak mantıklı, ama interaktif çalışırken onay istemi gelmesine izin vermek daha güvenli.
Pratik: Tam Bir Web Sunucusu Kurulum Script’i
Tüm öğrendiklerimizi birleştirelim. Sıfırdan bir web sunucusu altyapısı kuran bir script:
#!/bin/bash
# setup-webserver.sh
set -e
RG="rg-webproject-eastus"
LOCATION="eastus"
VNET="vnet-webproject"
SUBNET="subnet-web"
VM_NAME="vm-webserver-01"
VM_SIZE="Standard_B2s"
ADMIN_USER="azureuser"
SSH_KEY_PATH="~/.ssh/id_rsa.pub"
echo "=== Resource Group oluşturuluyor ==="
az group create
--name $RG
--location $LOCATION
--tags Project=WebProject Environment=Production
echo "=== VNet ve Subnet oluşturuluyor ==="
az network vnet create
--resource-group $RG
--name $VNET
--address-prefix 10.0.0.0/16
--subnet-name $SUBNET
--subnet-prefix 10.0.1.0/24
echo "=== NSG oluşturuluyor ==="
az network nsg create
--resource-group $RG
--name nsg-web
az network nsg rule create
--resource-group $RG
--nsg-name nsg-web
--name Allow-HTTP
--protocol tcp
--priority 1010
--destination-port-range 80
--access Allow
--direction Inbound
az network nsg rule create
--resource-group $RG
--nsg-name nsg-web
--name Allow-HTTPS
--protocol tcp
--priority 1020
--destination-port-range 443
--access Allow
--direction Inbound
echo "=== VM oluşturuluyor ==="
az vm create
--resource-group $RG
--name $VM_NAME
--image Ubuntu2204
--size $VM_SIZE
--admin-username $ADMIN_USER
--ssh-key-values $SSH_KEY_PATH
--vnet-name $VNET
--subnet $SUBNET
--nsg nsg-web
--public-ip-sku Standard
--os-disk-sku Premium_LRS
echo "=== Nginx kuruluyor ==="
az vm extension set
--resource-group $RG
--vm-name $VM_NAME
--name customScript
--publisher Microsoft.Azure.Extensions
--settings '{"commandToExecute": "apt-get update && apt-get install -y nginx && systemctl enable nginx && systemctl start nginx"}'
echo "=== Public IP adresi ==="
az vm show
--resource-group $RG
--name $VM_NAME
--show-details
--query publicIps
--output tsv
echo "=== Kurulum tamamlandı! ==="
Sonuç
Azure CLI, Azure VM yönetimini hem daha hızlı hem de tekrarlanabilir hale getiriyor. Özellikle onlarca VM’i yönetmek zorunda kaldığınızda, her işlem için portal üzerinde tıklamak yerine birkaç satır komutla ihtiyacınızı karşılamak büyük zaman tasarrufu sağlıyor.
Pratik açıdan bakıldığında, öğrenilmesi gereken en kritik noktalar şunlar: --query parametresiyle çıktıyı filtrelemek, --no-wait ile asenkron işlem yapmak ve deallocate ile stop arasındaki maliyet farkını iyi kavramak. Bu üç noktayı özümsedikten sonra Azure CLI gerçek anlamda verimli bir araç haline geliyor.
Otomasyon konusunda ise küçük başlamak en iyi yaklaşım. Önce sık yaptığınız tekrar eden işlemleri script’e dökün, sonra bu script’leri cron veya Azure Automation ile zamanlayın. Zamanla tüm altyapınızı kod olarak yönetir hale gelirsiniz ki bu da Infrastructure as Code’un temel mantığı. Bir sonraki adım olarak Bicep veya Terraform ile Azure CLI’yi birlikte kullanmak, yönetimi daha da sistematik bir seviyeye taşıyacaktır.
