Làm chủ CI/CD: Cách chúng tôi tự động hóa triển khai Azure App Service trong 6 tháng

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Sự hỗn loạn của việc triển khai thủ công

Sáu tháng trước, quy trình triển khai của nhóm tôi giống như một trò chơi Jenga đầy rủi ro. Mỗi bản cập nhật đều yêu cầu lập trình viên phải build dự án thủ công, nén file ZIP và vừa cầu nguyện vừa upload qua FTP. Nó chậm chạp, dễ sai sót và là một sự lãng phí thời gian khủng khiếp của đội ngũ kỹ sư.

Chúng tôi thường xuyên rơi vào “vòng xoáy hotfix” vì chỉ cần quên một file cấu hình duy nhất cũng có thể gây sập hệ thống. Tự động hóa việc này không chỉ là nâng cấp kỹ thuật; đó là vấn đề sống còn để ngừng làm lỗi Build. Khả năng mở rộng (scalability) chỉ thực sự bắt đầu khi bạn ngừng dùng tay tác động trực tiếp vào máy chủ production.

Điểm tới hạn: Tại sao quy trình triển khai của chúng tôi thất bại

Sau khi xem xét lại các thất bại, tôi đã tìm ra ba nguyên nhân phổ biến ở hầu hết các nhóm IT đang phát triển. Đầu tiên là “sự sai lệch môi trường” (environmental drift). Môi trường production đã trở thành một chiếc hộp đen. Những chỉnh sửa thủ công khiến môi trường live không còn khớp với staging, làm cho các bài test trở nên vô nghĩa.

Tiếp theo là “sự không đồng nhất của artifact”. Một lập trình viên có thể dùng .NET SDK 8.0.1 trong khi người khác dùng 8.0.4. Những khoảng cách phiên bản nhỏ này tạo ra các file binary không đồng nhất, chạy được trên máy này nhưng lại crash khi đưa lên cloud. Cuối cùng, bảo mật là một cơn ác mộng. Việc chia sẻ thông tin đăng nhập FTP hoặc publish profile trong nhóm tạo ra một bề mặt tấn công lớn và không thể kiểm soát. Chúng tôi cần một hệ thống đảm bảo tính nhất quán và thắt chặt quyền truy cập.

Lựa chọn công cụ phù hợp

Chúng tôi không chọn Azure DevOps một cách mù quáng. Jenkins là ý tưởng đầu tiên, nhưng chúng tôi không muốn tốn công quản lý server và vá lỗi cho vô số plugin. GitHub Actions là lựa chọn thứ hai vì mã nguồn của chúng tôi nằm ở đó. Tuy nhiên, vì hạ tầng của chúng tôi đã lún sâu vào hệ sinh thái Azure, Azure DevOps mang lại con đường ít trở ngại nhất.

Nó cung cấp khả năng tích hợp gốc (native) rất khó để bỏ qua. Service Connections xử lý xác thực thông qua Service Principals, nghĩa là chúng tôi không phải đụng đến mật khẩu hay publish profile trong suốt nửa năm qua. Đối với một stack tập trung vào Azure, luồng công việc giữa Repos, Pipelines và App Service là vô cùng liền mạch. Nó loại bỏ các đoạn “code kết nối” thường hay bị lỗi ở các công cụ khác.

Bản thiết kế: Multi-Stage YAML Pipelines

Chiến lược hiện tại của tôi tập trung vào multi-stage YAML pipelines. Bằng cách coi việc triển khai là “Pipeline as Code”, chúng tôi quản lý phiên bản cho logic phát hành giống hệt như mã nguồn ứng dụng. Điều này đảm bảo mọi thay đổi đều được đồng nghiệp review và kiểm chứng.

Bước 1: Kết nối bảo mật

Nền tảng của bạn là Service Connection. Đây là cây cầu bảo mật dẫn tới Azure Subscription của bạn. Tôi luôn sử dụng “Service Principal (automatic)”. Nó tự động tạo một App Registration trong Microsoft Entra ID với quyền Contributor được giới hạn phạm vi. Cách này an toàn hơn nhiều so với việc sử dụng tài khoản cá nhân của lập trình viên.

Bước 2: Logic CI (Build Artifact)

Giai đoạn đầu tiên là Tích hợp liên tục (CI) nhằm tăng tốc CI/CD Pipeline. Chúng ta cần đảm bảo code được biên dịch thành công và vượt qua các bài test trước khi đi tới bất cứ đâu. Dưới đây là đoạn YAML tinh gọn mà tôi dùng cho các dịch vụ .NET, thường hoàn thành trong chưa đầy 5 phút:

trigger:
- main

stages:
- stage: Build
  displayName: 'Build và Đóng gói'
  jobs:
  - job: Build
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - task: DotNetCoreCLI @2
      inputs:
        command: 'publish'
        publishWebProjects: true
        arguments: '--configuration Release --output $(Build.ArtifactStagingDirectory)'
        zipAfterPublish: true

    - task: PublishBuildArtifacts @autocontent.log.1
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'web-app'

Bước 3: Giai đoạn CD (Phát hành lên Production)

Sau khi artifact đã được xác thực, chúng tôi kích hoạt Triển khai liên tục (CD). Tôi sử dụng “Environments” trong Azure DevOps để theo dõi chính xác phiên bản nào đang chạy live. Chiến lược “runOnce” hoạt động hoàn hảo cho 90% các ứng dụng web thông thường.

- stage: Deploy
  displayName: 'Triển khai lên Production'
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: Deploy
    environment: 'production'
    pool:
      vmImage: 'ubuntu-latest'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: AzureWebApp @autocontent.log.1
            inputs:
              azureSubscription: 'My-Azure-Service-Connection'
              appType: 'webAppLinux'
              appName: 'itfromzero-prod-app'
              package: '$(Pipeline.Workspace)/web-app/**/*.zip'

Tối ưu bảo mật cho Pipeline Production

Triển khai code mới chỉ là một nửa chặng đường. Trong vài tháng qua, chúng tôi đã tích hợp Deployment Slots và Variable Groups để loại bỏ rủi ro.

Slots cho phép chúng tôi đẩy code lên “staging” trước. Chúng tôi chạy các bài smoke test trên chính hạ tầng Azure mà không làm phiền bất kỳ người dùng nào. Sau khi xác nhận ổn định, chúng tôi thực hiện “swap tức thì”. Nhờ áp dụng chiến lược triển khai bài bản, kết quả là không có thời gian chết (zero downtime) và không còn áp lực.

Chúng tôi cũng liên kết Variable Groups với Azure Key Vault để quản lý Secret trong CI/CD. Điều này giúp giữ các bí mật nhạy cảm, như chuỗi kết nối cơ sở dữ liệu, nằm ngoài các file YAML. Tách biệt cấu hình khỏi mã nguồn là điều bắt buộc để tuân thủ các tiêu chuẩn bảo mật.

Kết luận sau 6 tháng

Kết quả đến ngay lập tức. Tần suất triển khai của chúng tôi đã tăng từ 2 tuần một lần lên 4-5 lần mỗi ngày. Chúng tôi không còn sợ những ngày thứ Sáu nữa. Lý do “nó chạy tốt trên máy em” đã biến mất hoàn toàn vì mọi bản build đều được thực hiện trên một agent sạch và được host sẵn.

Nếu được bắt đầu lại hôm nay, tôi sẽ thiết lập hệ thống này ngay từ ngày đầu tiên. Khoản đầu tư 3 giờ ban đầu cho YAML đã tự chi trả chỉ trong tuần đầu tiên có các bản phát hành tự động. Nếu bạn làm việc trong hệ sinh thái Microsoft, làm chủ pipeline này là cách nhanh nhất để ngừng làm “lính cứu hỏa” và bắt đầu trở thành một “người xây dựng”.

Share: