Azure Container Instances ile Konteyner Çalıştırma

Konteyner teknolojileri artık her yerde. Ama her konteyneri için bir Kubernetes kümesi kurmak zorunda değilsin. Bazen tek bir konteyneri hızlıca çalıştırmak, bir batch iş bitirmek ya da bir API’yi test etmek yeterli. İşte tam burada Azure Container Instances (ACI) devreye giriyor. Kubernetes’in karmaşıklığı olmadan, VM yönetimi derdi çekmeden, saniyeler içinde konteyner çalıştırmanı sağlıyor.

Bu yazıda ACI’yi gerçek dünya senaryolarıyla, ellerin kirlenerek öğreneceğiz.

Azure Container Instances Nedir ve Ne Zaman Kullanılır?

ACI, Azure’un sunduğu en basit konteyner çalıştırma servisi. Herhangi bir altyapı yönetmeden Docker imajını al, ACI’ye ver, çalıştır. Faturalamayı saniye bazında yapıyor, konteyner durduğunda para ödemeyi bırakıyorsun.

Şimdi asıl soru: “Kubernetes varken neden ACI kullanayım?”

Doğru soru bu. ACI’nin parladığı senaryolar şunlar:

  • Batch işler: Geceleri çalışan veri işleme görevleri, sabah durduruluyor.
  • CI/CD pipeline adımları: Test containerları sadece build süresince yaşıyor.
  • Hızlı prototipleme: Yeni bir servis denemek istiyorsun, Kubernetes cluster’ı beklemek istemiyorsun.
  • Event-driven görevler: Tetiklendiğinde çalış, bittiğinde dur.
  • Scheduled tasks: Cron job mantığında periyodik işler.

Yani ACI, “always-on” servislerden çok “çalış ve bit” tipi iş yükleri için ideal.

Ön Gereksinimler

Başlamadan önce şunların hazır olması gerekiyor:

  • Azure aboneliği (ücretsiz deneme de olur)
  • Azure CLI kurulu ve giriş yapılmış (az login)
  • Docker hub hesabı veya Azure Container Registry
  • Temel Docker bilgisi

Azure CLI kurulumunu kontrol edelim:

az --version
az login
az account show

Çıktıda doğru subscription göründüğünden emin ol. Birden fazla subscription varsa:

az account list --output table
az account set --subscription "abonelik-adi-veya-id"

İlk Konteyneri Çalıştırmak

Hemen pratiğe girelim. En basit örnek ile başlayalım:

# Resource group oluştur
az group create 
  --name rg-aci-demo 
  --location westeurope

# İlk konteyneri çalıştır
az container create 
  --resource-group rg-aci-demo 
  --name ilk-konteyner 
  --image nginx:alpine 
  --ports 80 
  --ip-address Public 
  --dns-name-label aci-nginx-demo-benzersiz 
  --cpu 1 
  --memory 1.5

Bu komut çalıştıktan sonra public IP veya DNS adresin üzerinden nginx’e erişebilirsin. Durumu kontrol edelim:

# Konteyner durumunu gör
az container show 
  --resource-group rg-aci-demo 
  --name ilk-konteyner 
  --output table

# IP adresini direkt al
az container show 
  --resource-group rg-aci-demo 
  --name ilk-konteyner 
  --query ipAddress.ip 
  --output tsv

Logları görmek için:

az container logs 
  --resource-group rg-aci-demo 
  --name ilk-konteyner

İşte bu kadar. Kubernetes cluster’ı yok, node pool yok, ingress controller yok. Saf konteyner.

Parametreleri Anlamak

az container create komutunun önemli parametrelerini açıklayalım:

  • –image: Docker hub’dan veya private registry’den imaj adresi
  • –ports: Dışa açılacak portlar
  • –ip-address: Public, Private veya None olabilir
  • –dns-name-label: Public erişim için DNS label, globally unique olmalı
  • –cpu: vCPU miktarı (0.1 ile 4 arası)
  • –memory: GB cinsinden RAM (0.1 ile 16 arası)
  • –os-type: Linux veya Windows
  • –restart-policy: Always, OnFailure, Never
  • –environment-variables: Ortam değişkenleri
  • –secure-environment-variables: Hassas ortam değişkenleri (logda görünmez)
  • –command-line: Container’ın çalıştıracağı komut

Ortam Değişkenleri ile Yapılandırma

Gerçek dünyada konteynerlerini environment variable ile yapılandırırsın. Örneğin bir Node.js API:

az container create 
  --resource-group rg-aci-demo 
  --name api-konteyner 
  --image mcr.microsoft.com/azuredocs/aci-helloworld 
  --ports 80 
  --ip-address Public 
  --dns-name-label aci-api-ornek 
  --environment-variables 
    NODE_ENV=production 
    API_VERSION=v2 
    LOG_LEVEL=info 
  --secure-environment-variables 
    DB_PASSWORD=SuperGizliSifre123 
    API_SECRET_KEY=gizlianahtar456

--secure-environment-variables ile verilen değerler Azure portal’da ve CLI çıktılarında maskeli görünür. az container show yaptığında bu değerleri göremezsin, sadece key isimlerini görürsün.

Azure Container Registry ile Özel İmaj Kullanımı

Gerçek projelerde kendi Docker imajlarını kullanırsın. Azure Container Registry (ACR) burada devreye giriyor:

# ACR oluştur
az acr create 
  --resource-group rg-aci-demo 
  --name acrdemobenzersiz 
  --sku Basic

# ACR'a login ol
az acr login --name acrdemobenzersiz

# Örnek bir imaj tag'le ve push et
docker pull nginx:alpine
docker tag nginx:alpine acrdemobenzersiz.azurecr.io/myapp:v1.0
docker push acrdemobenzensiz.azurecr.io/myapp:v1.0

# ACR credentials al
ACR_USERNAME=$(az acr credential show --name acrdemobenzersiz --query username --output tsv)
ACR_PASSWORD=$(az acr credential show --name acrdemobenzersiz --query passwords[0].value --output tsv)

# ACR'dan imaj ile konteyner oluştur
az container create 
  --resource-group rg-aci-demo 
  --name ozel-imaj-konteyner 
  --image acrdemobenzersiz.azurecr.io/myapp:v1.0 
  --ports 80 
  --ip-address Public 
  --registry-login-server acrdemobenzersiz.azurecr.io 
  --registry-username $ACR_USERNAME 
  --registry-password $ACR_PASSWORD 
  --dns-name-label ozel-imaj-demo

Daha iyi bir yöntem: Managed Identity kullanmak. Bu şekilde şifre yönetmek zorunda kalmazsın:

# Önce ACR için admin erişimini kapat, managed identity kullan
az acr update --name acrdemobenzersiz --admin-enabled false

# ACI için managed identity ile ACR erişimi
az container create 
  --resource-group rg-aci-demo 
  --name mi-konteyner 
  --image acrdemobenzersiz.azurecr.io/myapp:v1.0 
  --acr-identity system 
  --assign-identity [system]

Gerçek Dünya Senaryosu: Gece Batch İşi

Diyelim ki her gece saat 02:00’da veritabanı yedeklemesi yapan ve ardından Azure Blob Storage’a atan bir script çalıştırman gerekiyor. Bu klasik bir ACI kullanım senaryosu.

Önce basit bir backup script’i içeren Dockerfile:

# Bu sefer YAML ile daha karmaşık bir yapı kuralım
cat > backup-job.yaml << 'EOF'
apiVersion: '2021-10-01'
location: westeurope
name: backup-job
properties:
  containers:
  - name: db-backup
    properties:
      image: mcr.microsoft.com/azure-cli:latest
      resources:
        requests:
          cpu: 0.5
          memoryInGb: 0.5
      environmentVariables:
      - name: STORAGE_ACCOUNT
        value: mybackupstorage
      - name: DB_HOST
        value: my-database.postgres.database.azure.com
      - name: DB_NAME
        value: production_db
      - name: DB_USER
        value: dbadmin
      - name: DB_PASSWORD
        secureValue: "gizlisifre"
      - name: SAS_TOKEN
        secureValue: "sas-token-buraya"
      command:
      - /bin/bash
      - -c
      - |
        echo "Backup başlıyor: $(date)"
        pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME > /tmp/backup_$(date +%Y%m%d_%H%M%S).sql
        az storage blob upload 
          --account-name $STORAGE_ACCOUNT 
          --sas-token "$SAS_TOKEN" 
          --container-name backups 
          --file /tmp/backup_*.sql 
          --name backup_$(date +%Y%m%d_%H%M%S).sql
        echo "Backup tamamlandı: $(date)"
  restartPolicy: Never
  osType: Linux
tags: {}
type: Microsoft.ContainerInstance/containerGroups
EOF

# YAML ile konteyner oluştur
az container create 
  --resource-group rg-aci-demo 
  --file backup-job.yaml

Bu iş tamamlandığında (restartPolicy: Never sayesinde) konteyner duracak. Azure Logic Apps veya Azure Automation ile bunu schedule edebilirsin.

Container Groups: Birden Fazla Konteyner

ACI’nin güçlü özelliklerinden biri Container Groups. Bir grup içinde birden fazla konteyner çalıştırabilirsin ve bunlar aynı network namespace’i paylaşır. Nginx + bir sidecar konteyneri örneği:

cat > container-group.yaml << 'EOF'
apiVersion: '2021-10-01'
location: westeurope
name: webapp-group
properties:
  containers:
  - name: nginx
    properties:
      image: nginx:alpine
      ports:
      - port: 80
        protocol: TCP
      resources:
        requests:
          cpu: 0.5
          memoryInGb: 0.5
      volumeMounts:
      - name: nginx-config
        mountPath: /etc/nginx/conf.d
  - name: log-shipper
    properties:
      image: fluent/fluent-bit:latest
      resources:
        requests:
          cpu: 0.25
          memoryInGb: 0.25
      environmentVariables:
      - name: OUTPUT_HOST
        value: logs.example.com
  ipAddress:
    ports:
    - port: 80
      protocol: TCP
    type: Public
    dnsNameLabel: webapp-group-demo
  osType: Linux
  restartPolicy: Always
  volumes:
  - name: nginx-config
    azureFile:
      shareName: nginx-config
      storageAccountName: mystorageaccount
      storageAccountKey: "storage-key-buraya"
type: Microsoft.ContainerInstance/containerGroups
EOF

Burada nginx ve log-shipper aynı network ortamını paylaşıyor. log-shipper, nginx’e localhost üzerinden erişebilir.

Persistent Storage: Azure Files ile Volume Bağlama

Konteynerler stateless’tır ama bazen veri persist etmen gerekir. ACI, Azure Files ile volume mount’ı destekliyor:

# Storage account oluştur
STORAGE_ACCOUNT="acisorageaccount$RANDOM"
az storage account create 
  --name $STORAGE_ACCOUNT 
  --resource-group rg-aci-demo 
  --location westeurope 
  --sku Standard_LRS

# File share oluştur
az storage share create 
  --name aci-data 
  --account-name $STORAGE_ACCOUNT

# Storage key al
STORAGE_KEY=$(az storage account keys list 
  --account-name $STORAGE_ACCOUNT 
  --resource-group rg-aci-demo 
  --query "[0].value" 
  --output tsv)

# Volume ile konteyner oluştur
az container create 
  --resource-group rg-aci-demo 
  --name volume-konteyner 
  --image nginx:alpine 
  --ports 80 
  --ip-address Public 
  --dns-name-label volume-demo-ornek 
  --azure-file-volume-account-name $STORAGE_ACCOUNT 
  --azure-file-volume-account-key $STORAGE_KEY 
  --azure-file-volume-share-name aci-data 
  --azure-file-volume-mount-path /usr/share/nginx/html

Artık Azure Files’taki dosyalar nginx’in web root’una mount edildi. Storage Explorer veya CLI üzerinden dosya ekleyip nginx’ten sunulduğunu görebilirsin.

İzleme ve Hata Ayıklama

Konteynerler bazen sorun çıkarır. ACI’de debug nasıl yapılır?

# Anlık logları takip et
az container logs 
  --resource-group rg-aci-demo 
  --name ilk-konteyner 
  --follow

# Konteyner içine exec ile bağlan
az container exec 
  --resource-group rg-aci-demo 
  --name ilk-konteyner 
  --exec-command "/bin/sh"

# Konteyner events ve state detaylarını gör
az container show 
  --resource-group rg-aci-demo 
  --name ilk-konteyner 
  --query "containers[0].instanceView" 
  --output json

# Metrics - CPU ve Memory kullanımı
az monitor metrics list 
  --resource $(az container show 
    --resource-group rg-aci-demo 
    --name ilk-konteyner 
    --query id --output tsv) 
  --metric "CpuUsage" 
  --output table

Eğer konteyner crash’lıyorsa instanceView altında currentState ve events alanları genellikle sebebi söyler. OOMKilled mı? Exit code nedir? Bunları buradan öğrenirsin.

Maliyet Optimizasyonu

ACI kullanırken para yakmamak için dikkat edilmesi gerekenler:

Doğru kaynak boyutlandırması: CPU ve memory’yi ihtiyacınızdan fazla vermeyin. ACI saniye başına bu değerlere göre fatura kesiyor.

Restart policy’yi doğru ayarla: Batch işlerde Never kullan. Konteyner işi bitince dursun, boşu boşuna çalışmasın.

Durmuş konteynerleri temizle: Durmuş ama silinmemiş konteynerler için depolama maliyeti oluşabilir.

# Tüm durdurulmuş konteynerleri listele
az container list 
  --resource-group rg-aci-demo 
  --query "[?instanceView.state=='Stopped'].name" 
  --output tsv

# Durdurulmuş konteynerleri sil
az container list 
  --resource-group rg-aci-demo 
  --query "[?instanceView.state=='Stopped'].name" 
  --output tsv | xargs -I {} az container delete 
  --resource-group rg-aci-demo 
  --name {} 
  --yes

# Resource group'taki tüm konteynerleri sil (dikkatli!)
az container list 
  --resource-group rg-aci-demo 
  --query "[].name" 
  --output tsv | while read name; do
  echo "Siliniyor: $name"
  az container delete 
    --resource-group rg-aci-demo 
    --name "$name" 
    --yes
done

Bölge seçimi: Batı Avrupa gibi merkezi bölgeler daha ucuz olabilir, iş yüküne göre doğru bölgeyi seç.

Spot/Low priority: ACI şu an spot fiyatlandırması sunmuyor ama mümkün olduğunca minimal kaynak kullan.

Virtual Network ile Private ACI

Production ortamında konteynerlerin internete direkt açık olmasını istemezsin. ACI’yi VNet içine koyabilirsin:

# VNet ve subnet oluştur
az network vnet create 
  --name aci-vnet 
  --resource-group rg-aci-demo 
  --address-prefix 10.0.0.0/16 
  --subnet-name aci-subnet 
  --subnet-prefix 10.0.1.0/24

# Subnet'e ACI delegation ekle
az network vnet subnet update 
  --name aci-subnet 
  --resource-group rg-aci-demo 
  --vnet-name aci-vnet 
  --delegations Microsoft.ContainerInstance/containerGroups

# VNet içinde konteyner oluştur
az container create 
  --resource-group rg-aci-demo 
  --name private-konteyner 
  --image nginx:alpine 
  --vnet aci-vnet 
  --subnet aci-subnet 
  --ip-address Private

Bu kurulumda konteynere sadece aynı VNet içinden veya peered VNet’lerden ulaşabilirsin. Önüne Application Gateway veya Azure Load Balancer koyarak trafiği yönetirsin.

Gerçek Dünya Senaryosu: CI/CD Pipeline’da ACI

GitHub Actions ile ACI’yi CI/CD pipeline’da kullanmak çok yaygın:

# Bu script CI/CD pipeline'da çalışacak
#!/bin/bash
set -e

RESOURCE_GROUP="rg-cicd"
CONTAINER_NAME="test-runner-$GITHUB_RUN_ID"
ACR_NAME="mycompanyacr"
IMAGE_TAG="myapp:$GITHUB_SHA"

echo "Test container'ı oluşturuluyor..."
az container create 
  --resource-group $RESOURCE_GROUP 
  --name $CONTAINER_NAME 
  --image $ACR_NAME.azurecr.io/$IMAGE_TAG 
  --restart-policy Never 
  --environment-variables 
    TEST_ENV=staging 
    RUN_ID=$GITHUB_RUN_ID 
  --cpu 2 
  --memory 4 
  --no-wait

echo "Container başlaması bekleniyor..."
az container wait 
  --resource-group $RESOURCE_GROUP 
  --name $CONTAINER_NAME 
  --condition "terminated"

# Exit code'u al
EXIT_CODE=$(az container show 
  --resource-group $RESOURCE_GROUP 
  --name $CONTAINER_NAME 
  --query "containers[0].instanceView.currentState.exitCode" 
  --output tsv)

echo "Test logları:"
az container logs 
  --resource-group $RESOURCE_GROUP 
  --name $CONTAINER_NAME

echo "Container siliniyor..."
az container delete 
  --resource-group $RESOURCE_GROUP 
  --name $CONTAINER_NAME 
  --yes

if [ "$EXIT_CODE" != "0" ]; then
  echo "Testler başarısız! Exit code: $EXIT_CODE"
  exit 1
fi

echo "Tüm testler başarılı!"

Bu yaklaşımla her CI/CD çalışması için izole bir test ortamı elde ediyorsun. Çalışma bitince temizleniyor, maliyet minimumlda kalıyor.

ACI vs Diğer Seçenekler

Sonuçta hangi servisi ne zaman kullanmalısın? Kısa özet:

  • ACI kullan: Basit, kısa ömürlü, batch işler için
  • Azure Kubernetes Service (AKS) kullan: Mikroservis mimarisi, production at-scale deploymentlar için
  • Azure App Service kullan: Web uygulamaları, API’ler, always-on ihtiyaçlar için
  • Azure Functions kullan: Event-driven, serverless, milisaniye cinsinden çalışan işler için

ACI ile AKS’yi birlikte de kullanabilirsin. AKS üzerinde Virtual Kubelet ile ACI’yi node gibi kullanmak mümkün. Burst kapasitesi gerektiğinde AKS workload’ları ACI’ye taşınabilir.

Sonuç

Azure Container Instances, konteyner dünyasının “al çalıştır” yaklaşımını en saf haliyle sunuyor. Kubernetes karmaşıklığı olmadan konteyner çalıştırmak istediğinde, batch işler için altyapı ayarlamak zorunda kalmadan, ya da CI/CD pipeline’larında izole test ortamları kurmak istediğinde ACI tam istediğin araç.

Özellikle şu senaryolarda ACI’yi ilk seçenek olarak değerlendirmeni öneririm: gece çalışan veri işleme görevleri, düzensiz aralıklarla tetiklenen büyük hesaplama işleri ve development ortamında hızlı test ihtiyaçları. Bu tür iş yükleri için Kubernetes cluster’ı ayakta tutmak hem maliyetli hem de gereksiz.

Sonuçta bulut dünyasındaki en değerli şey doğru araç seçimi. Her şeye Kubernetes demek, her çiviyi çekiçle çakmaya benziyor. ACI, bazen ihtiyacın olan tam da küçük, pratik, hızlı çözümü sunuyor.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir