1. Anasayfa
  2. Uncategorized

Azure DevOps Cloud’dan Azure DevOps Server’a Geçiş


Bulut bilişim esneklik ve hız sağlasa da her kurum için en doğru çözüm olmayabilir. Özellikle güvenlik politikaları, regülasyon zorunlulukları ve tam kontrol ihtiyacı söz konusu olduğunda buluttaki verilerin kurum içi (on-premise) ortamlara taşınması kritik bir adım haline gelir.

Biz de bu ihtiyaçlarla Azure DevOps Cloud üzerinde tuttuğumuz verileri kendi Azure DevOps Server ortamımıza taşıma kararı aldık.

Ancak şunu en baştan kabul etmek gerekir Microsoft Cloud → Server migration sürecini resmi olarak desteklemiyor. Dolayısıyla süreç doğru planlama yapılmadığında oldukça karmaşık olabilir.

Neden Migration Gerekli Oldu?

  • Veri Güvenliği: Cloud ortamında barınan veriler bazı sektör regülasyonlarıyla uyumlu olmayabiliyor.
  • Tam Kontrol: Server ortamında özelleştirme esnekliği daha fazla. Özellikle process’lerde ve entegrasyonlarda.
  • Yasal Gereklilikler: Bazı sektörlerde verilerin ülke sınırları içinde kalması zorunlu.

Eğer kurumunuz bu üç başlıktan en az birinde risk yaşıyorsa migration ciddi şekilde değerlendirilmelidir.

Kolay Kısım: Git Depolarının Taşınması

Git migration sürecin en zahmetsiz kısmıydı.

  • git clone --mirror yöntemiyle tüm branch, commit, tag ve referanslar eksiksiz aktarıldı.
  • Script ve otomasyon sayesinde yüzlerce repo kısa sürede taşındı.

Önemli Not: Migration öncesinde repolardaki “orphan branch” veya kullanılmayan branch’leri temizlemek süreci hızlandırır.

Zor Kısım: Work Items (Boards)

Asıl meydan okuma Work Item’lar tarafında başladı. Çünkü:

  • Cloud’da Basic Process üzerine manuel eklenmiş Bug ve Error tipleri vardı.
  • Custom field’lar farklı tanımlanmıştı.
  • Tarihçe (history), bağlantılar (links) ve ekler (attachments) kaybolmamalıydı.

Yerleşik yöntemler bu ihtiyaçları karşılamadığı için, özel araçlara yöneldik.

Araç Seçimi: Neden nkdAgility Migration Tools?

Microsoft’un resmi araçları özellikle farklı process template kullanan ya da büyük veri seti taşıyan projelerde yetersiz kalıyor.

Bizim için öncelikler:

  1. Work Item geçmişinin eksiksiz korunması
  2. Custom field eşleşmelerinin doğru yapılması
  3. Link ve eklerin güvenle taşınması
  4. Büyük veri setlerinde stabilite

Tüm bu kriterleri sağlayan çözüm:
nkdAgility – Azure DevOps Migration Tools

Bu araç sayesinde:

  • Eksiksiz migration yapabildik.
  • Takıldığımız noktalarda topluluk desteği aldık.
  • Süreci şeffaf bir şekilde yönetebildik.

Önemli Not: nkdAgility aracının topluluk desteği çok aktif. GitHub üzerinde issue açarak kısa sürede çözümler alabiliyorsunuz.

Migration Öncesi Hazırlıklar

Sistem Gereksinimleri

  • Windows 10/11 veya Windows Server 2016+
  • .NET Framework 4.7.2+, .NET 6.0 Runtime
  • PowerShell 5.1+
  • 8 GB RAM önerilir
  • İnternet bağlantısı

Yetkilendirme

  • Cloud: Full Access PAT token
  • Server: Collection Administrator yetkisi
  • Eğer Server HTTP çalışıyorsa domain-user bilgisi

Çalışma Dizini

New-Item -ItemType Directory -Path "C:\AzureDevOpsMigration\Logs" -Force
New-Item -ItemType Directory -Path "C:\AzureDevOpsMigration\Configs" -Force
New-Item -ItemType Directory -Path "C:\AzureDevOpsMigration\Attachments" -Force

PAT Token Üretimi

  • Cloud: https://dev.azure.com/YOUR_ORG/_usersSettings/tokens
  • Server: http://YOUR_SERVER/DefaultCollection/_usersSettings/tokens

Kurulum Yöntemleri

  1. WinGet ile (önerilen) winget install nkdAgility.AzureDevOpsMigrationTools devopsmigration version
  2. .NET Tool ile dotnet tool install -g devopsmigration
  3. Manuel İndirme (GitHub) Invoke-WebRequest -Uri "https://github.com/nkdAgility/azure-devops-migration-tools/releases/download/v16.2.9/MigrationTools-16.2.9.zip" -OutFile "C:\Tools\MigrationTools.zip" Expand-Archive -Path C:\Tools\MigrationTools.zip -DestinationPath "C:\Tools\MigrationTools"

7. Konfigürasyon ve Çalıştırma

Örnek config.json:

"Processors": [
  {
    "ProcessorType": "TfsWorkItemMigrationProcessor",
    "WIQLQuery": "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = @TeamProject AND [System.WorkItemType] IN ('Issue','Task','Epic','Bug','Error') ORDER BY [System.Id]",
    "LinkMigration": true,
    "AttachmentMigration": true
  }
]
{
  "$schema": "https://raw.githubusercontent.com/nkdAgility/azure-devops-migration-tools/main/src/MigrationTools/_configuration/configuration.schema.json",
  "MigrationTools": {
    "Version": "16.0",
    "Endpoints": {
      "Source": {
        "EndpointType": "TfsTeamProjectEndpoint",
        "Collection": "https://dev.azure.com/SOURCE_ORG",
        "Project": "SOURCE_PROJECT",
        "Authentication": {
          "AuthenticationMode": "AccessToken",
          "AccessToken": "SOURCE_PAT_TOKEN"
        },
        "ReflectedWorkItemIdField": "Custom.ReflectedWorkItemId",
        "AllowCrossProjectLinking": false
      },
      "Target": {
        "EndpointType": "TfsTeamProjectEndpoint",
        "Collection": "http://TARGET_SERVER/DefaultCollection",
        "Project": "TARGET_PROJECT",
        "Authentication": {
          "AuthenticationMode": "Windows",
          "NetworkCredentials": {
            "Domain": "DOMAIN",
            "UserName": "USERNAME",
            "Password": "PASSWORD"
          }
        },
        "ReflectedWorkItemIdField": "Custom.ReflectedWorkItemId",
        "AllowCrossProjectLinking": false
      }
    },
    "CommonTools": {
      "FieldMappingTool": {
        "Enabled": true,
        "FieldMaps": [
          {
            "FieldMapType": "FieldValueMap",
            "WorkItemTypeName": "*",
            "sourceField": "System.State",
            "targetField": "System.State",
            "defaultValue": "To Do",
            "valueMapping": {
              "New": "To Do",
              "Active": "Doing",
              "In Progress": "Doing",
              "Resolved": "Done",
              "Closed": "Done",
              "Done": "Done"
            }
          }
        ]
      },
      "TfsWorkItemTypeValidatorTool": {
        "Enabled": false,
        "IncludeWorkItemtypes": [
          "Shared Steps",
          "Test Case",
          "Test Plan",
          "Test Suite",
          "Bug",
          "Task",
          "User Story",
          "Feature",
          "Epic"
        ]
      }
    },
    "Processors": [
      {
        "ProcessorType": "TfsWorkItemMigrationProcessor",
        "SourceName": "Source",
        "TargetName": "Target",
        "Enabled": true,
        "UpdateCreatedDate": true,
        "UpdateCreatedBy": true,
        "WIQLQuery": "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = @TeamProject AND [System.WorkItemType] IN ('Issue', 'Task', 'Epic', 'Bug', 'Error') AND [System.WorkItemType] NOT IN ('Test Case', 'Test Plan', 'Test Suite', 'Shared Steps', 'Shared Parameter', 'Code Review Request', 'Code Review Response', 'Feedback Request', 'Feedback Response') ORDER BY [System.Id]",
        "LinkMigration": true,
        "AttachmentMigration": true,
        "AttachmentWorkingPath": "C:\\AzureDevOpsMigration\\Attachments",
        "FilterWorkItemsThatAlreadyExistInTarget": true,
        "PauseAfterEachWorkItem": false,
        "WorkItemCreateRetryLimit": 5,
        "GenerateMigrationComment": true,
        "BypassRules": true,
        "MaxGracefulFailures": 100
      }
    ],
    "CommonEnrichersConfig": [
      {
        "$type": "WorkItemTypeMappingEnricherOptions",
        "Enabled": true,
        "Mappings": {
          "Issue": "Issue",
          "Task": "Task",
          "Epic": "Epic",
          "Bug": "Bug",
          "Error": "Error"
        }
      }
    ],
    "Serilog": {
      "MinimumLevel": "Information",
      "WriteTo": [
        {
          "Name": "File",
          "Args": {
            "path": "logs/migration-test-.txt",
            "rollingInterval": "Day"
          }
        },
        {
          "Name": "Console",
          "Args": {
            "outputTemplate": "{Timestamp:HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}"
          }
        }
      ]
    }
  }
}

Burada WIQL sorgusu ile sadece gerekli Work Item tiplerini seçiyoruz. Feedback Response gibi sorun çıkaran tipler hariç tutuluyor.

Migration başlatma:

devopsmigration execute --config "C:\AzureDevOpsMigration\config.json"

Karşılaşılan Zorluklar ve Çözümler

  1. Field Validation Hataları
    • Bazı custom field’lar Server’da yoktu.
    • Çözüm: Gereksiz tipler hariç tutuldu.
  2. Process Uyumsuzlukları
    • Cloud’daki Bug/Error tipleri Server’da yoktu.
    • Çözüm: WorkItemTypeMapping ile eşleştirme yapıldı.
  3. Authentication Sorunları
    • PAT token kapsamı yanlış olduğunda bağlantı koptu.
    • Çözüm: Scope → Full Access yapıldı.
  4. Stabilite Sorunları
    • Büyük veri setlerinde performans düştü.
    • Çözüm: Migration küçük part’lar halinde yapıldı.

Önemli Not: Migration öncesi test ortamında küçük bir subset ile deneme yapmak büyük zaman kazandırır.

Loglama ve İzlenebilirlik

Serilog entegrasyonu ile:

  • Konsolda gerçek zamanlı log
  • Dosya tabanlı log arşivi

Bu sayede hataları hızlı tespit ettik ve raporlama kolaylaştı.

Kaynak https://medium.com/@devopsfatihh/azure-devops-clouddan-on-premise-server-a-migration-e02b5845e1da