Mert Özen Her Satırda Daha İleri
Yazılım Tasarımı UML ve Modeling — #13

Deployment Diagram: Node, Artifact, Execution Environment ve Docker/Azure Topolojisi

Mert Özen 7 Kas 2026 10 dk 4 görüntülenme
Deployment Diagram: Node, Artifact, Execution Environment ve Docker/Azure Topolojisi

Deployment diagram, yazılımın hangi node ve execution environment'ta çalıştığını, hangi artifact'in nereye yerleştiğini ve node'ların hangi protokol ve port'la konuştuğunu gösterir. Bu yazıda İK Portalı'nın docker compose geliştirme ortamını ve Azure production topolojisini çizip artifact ile component arasındaki «manifest» köprüsünü kuruyoruz.

Sürüm notu: Bu yazıdaki diyagramlar UML (Unified Modeling Language) 2.5.1 notasyonuyla çizilmiştir; publish çıktısı .NET 10 SDK (software development kit) ile alınmış, compose dosyası Docker Compose v5.1.0 ile doğrulanmıştır.

Önce Tahmin Et: Ops Ekibi Hangi Port'ları Açacak?

İK (insan kaynakları) Portalı ilk kez production'a çıkıyor. Ops ekibinden Linus üç soru soruyor: "API (Application Programming Interface) kaç instance çalışacak, hangi makineden hangi servise hangi port'tan çıkılıyor ve takvim sistemine kim bağlanıyor?" Ekipteki tek dokümantasyon, geliştiricilerin her gün kullandığı compose dosyası:

name: hrportal-dev

services:
  api:
    build:
      context: .
      dockerfile: src/HrPortal.Api/Dockerfile
    image: hrportal-api:dev
    ports:
      - "8080:8080"
    environment:
      ASPNETCORE_ENVIRONMENT: Development
      ConnectionStrings__HrPortal: "Server=sqlserver;Database=HrPortal;User Id=sa;Password=${MSSQL_SA_PASSWORD};TrustServerCertificate=true"
      ConnectionStrings__Redis: "redis:6379"
      ConnectionStrings__ServiceBus: "Endpoint=sb://servicebus;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"
    depends_on: [sqlserver, redis, servicebus]

  worker:
    build:
      context: .
      dockerfile: src/HrPortal.Worker/Dockerfile
    image: hrportal-worker:dev
    environment:
      ConnectionStrings__HrPortal: "Server=sqlserver;Database=HrPortal;User Id=sa;Password=${MSSQL_SA_PASSWORD};TrustServerCertificate=true"
      ConnectionStrings__ServiceBus: "Endpoint=sb://servicebus;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"
    depends_on: [sqlserver, servicebus]

  sqlserver:
    image: mcr.microsoft.com/mssql/server:2025-latest
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_SA_PASSWORD: "${MSSQL_SA_PASSWORD}"
    ports:
      - "1433:1433"

  redis:
    image: redis:7-alpine

  servicebus:
    image: mcr.microsoft.com/azure-messaging/servicebus-emulator:latest
    volumes:
      - "./servicebus-config.json:/ServiceBus_Emulator/ConfigFiles/Config.json"
    environment:
      SQL_SERVER: sqlserver
      MSSQL_SA_PASSWORD: "${MSSQL_SA_PASSWORD}"
      ACCEPT_EULA: "Y"
    depends_on: [sqlserver]

Bu dosyadan bir diyagram çizsen kaç kutu, kaç çizgi olur? Hangi değerler production'da aynen kalır, hangileri tamamen değişir? Ve Linus'un üç sorusundan kaçının cevabı gerçekten bu dosyada?

Deployment Diagram Neyi Cevaplar?

Dosya geçerli; docker compose config --services beş servisi listeliyor:

sqlserver
servicebus
worker
redis
api

Ama Linus'un sorularından yalnız biri, o da kısmen, burada cevaplanıyor: geliştirme ortamındaki port'lar. Production'da SQL (Structured Query Language) Server bir container değil, yönetilen bir veritabanı servisi. Redis 6379 değil 10000 numaralı port'tan ve TLS (Transport Layer Security) ile konuşuyor. Service Bus emülatörü yerine gerçek namespace var, API iki ile beş arasında replica çalışıyor. Compose dosyası bir geliştirme ortamının tarifi; production topolojisinin değil.

Deployment diagram tam bu boşluğu doldurur: yazılımın fiziksel olarak nerede çalıştığını, hangi dosyaların hangi çalışma ortamına konduğunu ve bu ortamların birbirine hangi protokolle bağlandığını gösterir. UML 2.5.1 spesifikasyonunun 19. bölümü (Deployments) bu diyagramın öğelerini tanımlar. Önceki yazıdaki component diagram "hangi modül hangi sözleşmeyle bağlı?" sorusunu cevaplıyordu; deployment diagram ise "bu modüller hangi kutuda çalışıyor ve kutular nasıl konuşuyor?" sorusunu cevaplar. İkisini karıştırmamak, iki ayrı sorunun iki ayrı diyagramı olduğunu kabul etmekle başlar.

Deployment diagram iki seviyede çizilir. Type-level diyagram "bir API container'ı, bir veritabanı" gibi türleri gösterir ve mimari dokümantasyonda en sık kullanılan hali budur. Instance-level diyagram ise gerçek örnekleri gösterir: adlar altı çizili yazılır (api-replica-1 : ContainerApp) ve bir arıza analizinde "hangi replica, hangi zone" sorusu için kullanılır.

Notasyon: Node, Device ve Execution Environment

13-dev-deployment-tr.png

Node, üç boyutlu bir kutu olarak çizilir ve üzerinde yazılım çalıştırılabilen bir hesaplama kaynağını temsil eder. UML iki özel tür tanımlar. «device» fiziksel bir donanımdır: geliştiricinin dizüstü bilgisayarı, bir sunucu, bir telefon. «executionEnvironment» ise bir node'un içinde çalışan ve kendi içine artifact kabul eden yazılım ortamıdır: Docker Engine, Node.js runtime'ı, tarayıcı, .NET runtime'ı, bir veritabanı motoru. Node'lar iç içe çizilebilir; figürde dizüstü bilgisayar Docker Engine'i, Docker Engine de beş container'ı içeriyor.

«container», «cdn», «PaaS» gibi etiketler UML'in standart keyword'leri değil, kullanıcı tanımlı stereotype'lar. UML buna izin veriyor ve sektörde yaygın bir pratik. Kural, diyagramın legend'ında ya da başlığında ne anlama geldiklerini söylemek. Bir Docker container'ı teknik olarak bir execution environment'tır, içine image'dan gelen dosyalar konur. «container» stereotype'ı bunu daha okunur kılıyor.

Artifact, «manifest» ve Deployment

Artifact, deployment'ın somut birimidir: bir dosya ya da bir dosya paketi. Sağ üst köşesi kıvrık doküman ikonu ya da «artifact» keyword'üyle çizilir. UML'in standart profile'ı «executable», «library», «script», «file» gibi alt türler de sunar. Önceki yazının modüllerini publish ettiğimizde ortaya çıkan artifact'ler şunlar:

HrPortal.Api.dll
HrPortal.CalendarIntegration.dll
HrPortal.Leave.Contracts.dll
HrPortal.Leave.dll
HrPortal.Notification.Contracts.dll
HrPortal.Notification.dll
HrPortal.Payroll.dll

Her DLL (dynamic-link library), bir component'in fiziksel karşılığı. UML bu ilişkiyi «manifest» etiketli, artifact'ten component'e giden kesikli bir okla çizer: "HrPortal.Leave.dll, Leave component'ini manifest eder". Artifact'ler iç içe de olabilir. Container image, içinde bu DLL'leri taşıyan bir üst artifact'tir. PlantUML 1.2026.9 ile render ettiğimiz kaynak:

@startuml hr-portal-manifest
artifact "hrportal-api:1.4.0" <<image>> as Image {
  artifact "HrPortal.Api.dll" as ApiDll
  artifact "HrPortal.Leave.dll" as LeaveDll
  artifact "HrPortal.Payroll.dll" as PayrollDll
}
component "Api" as Api
component "Leave" as Leave
component "Payroll" as Payroll
ApiDll ..> Api : <<manifest>>
LeaveDll ..> Leave : <<manifest>>
PayrollDll ..> Payroll : <<manifest>>
@enduml

Bu küçük diyagram, component diagram ile deployment diagram arasındaki köprü. Mantıksal modül (component) bir dosyaya (artifact) dönüşüyor, dosya bir node'a yerleşiyor. Artifact'i node'a yerleştirmenin iki yazımı var: artifact'i node kutusunun içine çizmek ya da artifact'ten node'a «deploy» etiketli kesikli bir ok çekmek. İkisi aynı anlama gelir; kalabalık diyagramlarda iç içe çizim daha okunur.

Bir de deployment specification var: «deployment spec» keyword'lü bir artifact. Bir deployment'ın nasıl yapılandırılacağını taşır ve deployment'a kesikli bir çizgiyle bağlanır. .NET'te en tanıdık örneği appsettings.Production.json ve container platformundaki ortam değişkenleri. Replica sayısı, ortam adı, Key Vault referansları burada yaşar ve aynı image'ı farklı ortamlarda farklı davrandıran şey de bu dosyalardır.

Communication Path ve Protokol Etiketi

Node'lar arasındaki düz çizgi communication path'tir: iki node'un mesaj alışverişi yapabildiği bir bağlantı. UML'de bu bir association'dır, ok başı çizilmez; yön bilgisi gerekiyorsa sequence diagram'a bakılır. Pratikte çizginin üstüne protokol ve port yazmak, diyagramı ops için okunur kılan en önemli ayrıntıdır. Figürdeki etiketler: HTTP (Hypertext Transfer Protocol) 4200 ve 8080, SQL Server'ın protokolü TDS (Tabular Data Stream) 1433, Redis'in RESP (REdis Serialization Protocol) 6379 ve Service Bus'ın AMQP (Advanced Message Queuing Protocol) 5672.

Geliştirme ortamında bu path'lerin hiçbiri TLS kullanmıyor. Emülatör yalnız şifresiz AMQP TCP (Transmission Control Protocol) taşımasını destekliyor. SQL Server'a TrustServerCertificate=true ile bağlanılıyor. Bunları diyagrama yazmak, "production'da da böyle mi?" sorusunu masaya koymanın en ucuz yolu. Bir de servicebus ile sqlserver arasındaki küçük çizgiye dikkat: Service Bus emülatörü durumunu SQL Server'da tutuyor. Compose dosyasındaki depends_on satırını okuyan biri bunu kaçırabilir, diyagramı okuyan kaçırmaz.

Geliştirme Ortamı: docker compose'u Diyagrama Çevirmek

Yukarıdaki figür, açılıştaki compose dosyasının doğrudan çevirisi. Her servis bir «container» node'u. image satırı container'a yerleşen artifact. ConnectionStrings__* değerlerindeki host ve port ise communication path'lerin etiketleri. Dosyada olmayan iki şeyi biz ekledik: Angular uygulamasının ng serve ile Node.js üzerinde çalıştığı ve tarayıcının ona 4200'den bağlandığı bilgisi. Compose dosyası yalnız kendi container'larını bilir; geliştiricinin gerçekte nasıl çalıştığını diyagram anlatır.

Çevirinin bir faydası da tutarsızlık yakalamak. Diyagramı çizerken worker'ın Redis'e bağlanmadığını gördük. Hatırlatma job'ı onay bekleyen talepleri doğrudan veritabanından okuyor, cache'e ihtiyacı yok. Bu bilinçli bir karar mı, unutulmuş bir configuration mı? Soru, kodu açmadan diyagramdan çıktı.

Production Topolojisi: Azure

13-prod-deployment-tr.png

Production'da aynı artifact'ler bambaşka node'lara yerleşiyor. Angular build çıktısı (hr-portal-web/dist) Azure Front Door arkasındaki bir Storage hesabından, yani bir CDN (content delivery network) üzerinden dağıtılıyor ve çalışanın tarayıcısında çalışıyor. API ve worker, aynı Azure Container Apps environment'ında iki ayrı container app. Environment, ağı ve log'ları paylaşan bir sınır olduğu için onu kapsayan bir execution environment olarak çizdik. API'nin replica sayısı 2 ile 5 arasında, worker'ınki sabit. Bu bilgi diyagramda, değeri ise deployment spec'te.

Veri tarafındaki üç node yönetilen servis: Azure SQL Database, Azure Managed Redis ve Azure Service Bus. Bunları «PaaS» (Platform as a Service) stereotype'ıyla işaretledik, çünkü ops için kritik bilgi "bu makineyi biz yönetmiyoruz" demek. Redis seçimi zamana duyarlı bir ayrıntı taşıyor: Microsoft, Azure Cache for Redis'in Basic, Standard ve Premium katmanlarını 30 Eylül 2028'de emekliye ayıracağını duyurdu ve 1 Nisan 2026'dan beri yeni müşteriler bu katmanlarda yeni cache oluşturamıyor. Yeni kurulumların hedefi Azure Managed Redis. Bu servis varsayılan olarak 10000 numaralı port'u ve TLS'i kullanıyor. Diyagramdaki RESP/TLS 10000 etiketi bu yüzden geliştirme ortamındaki RESP 6379'dan farklı.

Diyagramın okunurluğu için veri servislerine giden path'leri tek tek container'lardan değil, Container Apps environment'ından çizdik. Hangi container'ın hangi servise bağlandığı ayrıntısı aşağıdaki PlantUML kaynağında ve bir önceki figürde var. Bu tür sadeleştirmeler meşrudur, yeter ki diyagramın başlığında ya da notunda söylensin. Aynı modelin diagrams-as-code karşılığı (PlantUML 1.2026.9 ile render edildi):

@startuml hr-portal-production
title HR Portal - production deployment (Azure, West Europe)

node "Employee PC" <<device>> {
  node "Web browser" <<executionEnvironment>> as Browser {
    artifact "hr-portal-web" as SpaBundle
  }
}
node "Front Door + Storage" <<cdn>> as Cdn {
  artifact "hr-portal-web/dist" as SpaDist
}
node "Azure Container Apps" <<executionEnvironment>> as Aca {
  node "hrportal-api (replicas 2..5)" <<container>> as Api {
    artifact "hrportal-api:1.4.0" <<image>> as ApiImage
  }
  node "hrportal-worker" <<container>> as Worker {
    artifact "hrportal-worker:1.4.0" <<image>> as WorkerImage
  }
}
artifact "appsettings.Production.json" <<deployment spec>> as Spec
node "Azure SQL DB" <<PaaS>> as Sql
node "Managed Redis" <<PaaS>> as Redis
node "Azure Service Bus" <<PaaS>> as Bus {
  artifact "leave-events" <<topic>> as Topic
}
node "Calendar System" <<external>> as Calendar
node "SMTP relay" <<external>> as Smtp

Api .. Spec
Browser -- Cdn : HTTPS 443
Browser -- Api : HTTPS 443
Api -- Calendar : HTTPS 443
Aca -- Sql : TDS 1433
Aca -- Redis : RESP/TLS 10000
Aca -- Bus : AMQP/TLS 5671
Worker -- Smtp : SMTP 587
@enduml

İki ortamı yan yana koyunca farklar bir tabloya sığıyor. Ops ile yapılacak toplantının gündemi de bu tablo:

KonuGeliştirme (compose)Production (Azure)
SPA (single-page application)ng serve, Node.js, 4200Front Door + Storage, HTTPS (HTTP Secure) 443
API1 container, HTTP 8080Container Apps, 2..5 replica, HTTPS 443
Veritabanımssql 2025 container, TDS 1433, sertifika doğrulanmıyorAzure SQL Database, TDS 1433, TLS zorunlu
Cacheredis:7 container, RESP 6379, TLS yokAzure Managed Redis, 10000, TLS
MesajlaşmaService Bus emülatörü, AMQP 5672, TLS yokAzure Service Bus, AMQP 5671, TLS
Takvim ve e-postaFake implementasyonKurumsal Takvim Sistemi (HTTPS), SMTP (Simple Mail Transfer Protocol) relay 587

Ops Ekibiyle Konuşmak: Ne Kadar Detay?

Linus'un soruları diyagramın detay seviyesini belirliyor. Her node'un adı ve türü, artifact'in adı ve sürümü, her communication path'in protokolü ve port'u, replica sayısı ve dışarıya açılan yüzler (tarayıcıdan gelen 443 ve takvim sistemine giden 443) bu toplantı için yeterli. Firewall kuralı yazacak biri tam olarak bu satırları arar. IP (Internet Protocol) adresleri, VM (virtual machine) boyutları ve subnet maskeleri ise diyagrama değil, infrastructure-as-code dosyalarına aittir. Onlar her deploy'da değişebilir; diyagramı her seferinde güncellemek gerçekçi değil.

Deployment diagram'ın bir de C4 (Context, Containers, Components, Code) karşılığı var. C4 model'inin deployment diagram'ı, UML deployment diagram'ından türetilmiştir. Deployment node'ları iç içe çizilir ve içlerine C4 container'larının instance'ları yerleştirilir. Farkı odakta: C4'te kutunun içindekiler "API Application" gibi C4 container'larıdır, UML'de ise artifact'ler. İkisinden birini seçmek bir zevk meselesi değil, okuyucuya göre karar. Mimari dokümanın geri kalanı C4 ile yazıldıysa deployment da C4 olmalı; release ve paketleme konuşuluyorsa UML'in artifact ve «manifest» dili daha kesin. C4'ün tamamını bir sonraki yazıda işliyoruz. Docker image'ını üreten pipeline ise ASP.NET Core Web API serisinin Docker ve GitHub Actions yazısında.

Sık Düşülen Tuzaklar

Bulut servis ikonlarıyla dolu ama etiketsiz bir resim çizmek. Azure ikonları dikkat çekici, ama çizgilerin üstünde protokol ve port yoksa ops için cevap vermez. Ne kullanırsan kullan, her path'e protokol, her node'a tür yaz.

Component ve artifact'i aynı kutuda eritmek. "Leave modülü SQL Server'a bağlanıyor" demek mantıksal bir ifade. Deployment diagram'da bağlanan şey, Leave'i manifest eden DLL'in içinde çalıştığı container. Bu ayrım, aynı modülün iki farklı container'da (API ve worker) çalıştığı bizim durumumuzda hayati.

Geliştirme ortamını production sanmak. Compose dosyasından otomatik çizilen bir diyagram, production'daki TLS'i, replica'yı ve yönetilen servisleri göstermez. Her ortam için ayrı diyagram çiz ya da en azından farkları yukarıdaki gibi bir tabloda topla.

Ok başı çizip yönü sabitlemek. Communication path bir association'dır. Kimin kimi çağırdığını göstermek istiyorsan bu bir sequence diagram ya da C4 dynamic diagram işidir; deployment diagram'da oklar gereksiz kesinlik ve çoğu zaman yanlış bilgi üretir.

Diyagramı versiyonsuz bırakmak. Artifact'lerde sürüm (hrportal-api:1.4.0) yoksa diyagram hangi release'i anlattığını söyleyemez. Image tag'i ve deployment spec'in adı, diyagramın tarih damgasıdır.

Küçük Bir Deneme

★☆☆ Compose dosyasına bir mailpit container'ı ekleyip worker'ı ona SMTP ile bağla. Geliştirme diyagramına hangi node, hangi artifact ve hangi communication path eklenir? Production tablosundaki "Takvim ve e-posta" satırı nasıl değişir?

★★☆ Production diyagramının instance-level halini çiz: API'nin üç replica'sı iki availability zone'a dağılmış olsun. Adları altı çizili yaz ve type-level diyagramla hangi bilgilerin farklılaştığını listele.

★★★ docker compose config --format json çıktısını okuyup servisleri node, image'ları artifact, connection string'lerdeki host ve port'ları communication path olarak PlantUML deployment diagram'ına çeviren küçük bir C# console uygulaması yaz. Ürettiğin diyagramı elle çizilenle karşılaştır: hangi bilgiler eksik kaldı, neden?

Deployment diagram ops ekibinin dilini konuşuyor ama mimariyi yönetime ya da yeni katılan bir geliştiriciye anlatmak için fazla ayrıntılı. Bir sonraki yazıda C4 model'e geçiyoruz: Context, Container ve Component seviyelerini, "container" kelimesinin neden Docker container olmadığını ve notation checklist'ini İK Portalı üzerinden çizeceğiz.