使用.NET 6開發TodoList應用(31)——實現基於Github Actions和ACI的CI/CD


系列導航及源代碼

需求和目標

在這個系列的最后一節中,我們將使用GitHub Actions將TodoList應用部署到Azure Container Instance上。

實現

為了確保部署的應用能夠正確運行,我們需要做以下幾件事:

創建Azure SQL Server實例

選擇最便宜的數據庫規格就可以了,新建一個ResourceGroup名為todolist,並新建數據庫實例,獲得連接字符串:

image

創建Azure Container Registry

用於構建好的鏡像上傳和部署

image

設置GitHub Secrets

首先創建Service Principle認證:

groupId=$(az group show \
  --name todolist \
  --query id --output tsv)

az ad sp create-for-rbac \
  --scope $groupId \
  --role Contributor \
  --sdk-auth

# 會得到類似下面的輸出
{
  "clientId": "xxxx6ddc-xxxx-xxxx-xxx-ef78a99dxxxx",
  "clientSecret": "xxxx79dc-xxxx-xxxx-xxxx-aaaaaec5xxxx",
  "subscriptionId": "xxxx251c-xxxx-xxxx-xxxx-bf99a306xxxx",
  "tenantId": "xxxx88bf-xxxx-xxxx-xxxx-2d7cd011xxxx",
  "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
  "resourceManagerEndpointUrl": "https://management.azure.com/",
  "activeDirectoryGraphResourceId": "https://graph.windows.net/",
  "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
  "galleryEndpointUrl": "https://gallery.azure.com/",
  "managementEndpointUrl": "https://management.core.windows.net/"
}

接下來更新Registry的認證

registryId=$(az acr show \
  --name code4nothing \
  --query id --output tsv)

az role assignment create \
  --assignee <ClientId> \
  --scope $registryId \
  --role AcrPush

最后將Secrets配置到Github Repo的設置里:

image

具體的參數說明請參考:Save credentials to GitHub repo

創建Actions配置

在Github的Repo里選擇Actions,選擇set up a workflow yourself
image

定義以下構建步驟:

on: [push]
name: Linux_Container_Workflow

jobs:
    build-and-deploy:
        runs-on: ubuntu-latest
        steps:
        # checkout the repo
        - name: 'Checkout GitHub Action'
          uses: actions/checkout@main

        - name: 'Login via Azure CLI'
          uses: azure/login@v1
          with:
            creds: ${{ secrets.AZURE_CREDENTIALS }}

        - name: 'Build and push image'
          uses: azure/docker-login@v1
          with:
            login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
            username: ${{ secrets.REGISTRY_USERNAME }}
            password: ${{ secrets.REGISTRY_PASSWORD }}
        - run: |
            docker build -f src/TodoList.Api/Dockerfile.prod . -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/todolist:${{ github.sha }}
            docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/todolist:${{ github.sha }}
        - name: 'Deploy to Azure Container Instances'
          uses: 'azure/aci-deploy@v1'
          with:
            resource-group: ${{ secrets.RESOURCE_GROUP }}
            dns-name-label: ${{ secrets.RESOURCE_GROUP }}${{ github.run_number }}
            image: ${{ secrets.REGISTRY_LOGIN_SERVER }}/todolist:${{ github.sha }}
            registry-login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
            registry-username: ${{ secrets.REGISTRY_USERNAME }}
            registry-password: ${{ secrets.REGISTRY_PASSWORD }}
            name: aci-todolist
            location: 'east asia'

修改項目代碼以進行Production部署

  • Dockerfile.prod
ARG NET_IMAGE=6.0-bullseye-slim
FROM mcr.microsoft.com/dotnet/aspnet:${NET_IMAGE} AS base
WORKDIR /app
EXPOSE 80
ENV ASPNETCORE_ENVIRONMENT=Production

FROM mcr.microsoft.com/dotnet/sdk:${NET_IMAGE} AS build
WORKDIR /src
COPY ["src/TodoList.Api/TodoList.Api.csproj", "TodoList.Api/"]
COPY ["src/TodoList.Application/TodoList.Application.csproj", "TodoList.Application/"]
COPY ["src/TodoList.Domain/TodoList.Domain.csproj", "TodoList.Domain/"]
COPY ["src/TodoList.Infrastructure/TodoList.Infrastructure.csproj", "TodoList.Infrastructure/"]
RUN dotnet restore "TodoList.Api/TodoList.Api.csproj"
COPY ./src .
WORKDIR "/src/TodoList.Api"
RUN dotnet build "TodoList.Api.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish --no-restore "TodoList.Api.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TodoList.Api.dll"]
  • appsettings.Production.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "UseFileToLog": true,
  "ConnectionStrings": {
    "SqlServerConnection": "Server=tcp:code4nothing.database.windows.net,1433;Initial Catalog=TodoListDb;Persist Security Info=False;User ID=code4nothing;Password=TestTodo@123;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
  }
}

將代碼合並到main上以后,自動觸發Actions:
image

ACI實例運行起來后可以看到:
image

驗證

我們從本地的Insomia上訪問API端口,先看看liveness probes是否正常工作:
image

請求的host可以從這里獲取:
image

查詢TodoList后查詢TodoItems結果:
image

一點擴展

微軟新推出的Azure服務Azure Container Apps(preview)是作為容器化服務部署的另一個選擇,簡單的說明:

Deploy containerized apps without managing complex infrastructure. Write code using your preferred programming language or framework, and build microservices with full support for Distributed Application Runtime (Dapr). Scale dynamically based on HTTP traffic or events powered by Kubernetes Event-Driven Autoscaling (KEDA).

來自官方文檔Azure Container Apps

總結

如果在部署ACI的過程中失敗了,尤其是容器在ACI中沒有成功運行,可以參考:Troubleshoot common issues in Azure Container Instances來查看和解決問題。

在本文中我們實現了如何將應用通過Github Actions部署到Azure Container Instance服務中。那么到本節為止,使用.NET 6開發TodoList應用文章索引這個用於串聯.NET Web API開發基礎系列的文章就結束了,感謝各位朋友在此過程中的支持。

在這個系列的寫作和發表中,我們還漏掉了幾篇文章暫時沒有完成,包括有評論指出的幾個沒有填完的坑,我會找時間盡量都補齊。但是更新速度應該不會像寫這個系列的時候那么密集了。

后面的計划是,在正式開始微服務系列實踐文章開始之前,會寫幾個小的系列來預先熟悉一下后面也許會用到的知識點,例如GraphQL,RabbitMQ,gRPC,Envoy以及Dapr等內容。

感謝各位對文章中錯誤的指正,希望我們能繼續一起努力,一步一個腳印地掌握更多的技能。

參考資料

  1. Configure a GitHub action to create a container instance
  2. Troubleshoot common issues in Azure Container Instances
  3. Azure Container Apps


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM