輕鬆上手 Azure Function App:C# 開發與 Github Action 自動化部署實戰

在雲端原生 (Cloud Native) 的世界裡,無伺服器 (Serverless) 架構已經不是什麼新鮮事。今天,我們就來聊聊微軟 Azure 上的無伺服器解決方案 — Azure Function App,並實際走一遍如何用 C# 開發,最後再透過 GitHub Actions 帥氣地自動部署上去。

開發環境

  • Windows 11
  • WSL2 (Ubuntu 24.04.1).
    • NET 8.0 SDK
    • Azure Functions Core Tools v4
    • Azure CLI
    • VSCode

 

先聊聊 Azure Function App

簡單來說,Azure Function App 是一種讓你專注寫程式碼,而不用煩惱底層伺服器管理的服務。它是一個事件驅動的平台,可以因為一個 HTTP 請求、一個新的儲存體檔案、或是一個排程時間到來而觸發你的程式碼。

為什麼要用它?

  • 成本效益:大部分方案都是「用多少、付多少」,沒執行就幾乎不花錢。
  • 自動擴展:流量高峰來臨時,Azure 會自動幫你增加運算資源,你不用半夜起床開機器。
  • 高度整合:跟 Azure 生態系的其他服務(例如儲存體、資料庫、事件中樞)整合得非常好。

怎麼選方案?挑選適合的託管計畫 (Hosting Plan)

選對方案,可以幫你省下不少錢,同時確保應用程式效能。Azure 提供了多種方案,我們來看看最常見的幾種。

方案冷啟動最長執行時間擴展速度VNet 整合適合場景
Consumption✅ 有10 分鐘低頻率、成本優先、開發測試
Flex Consumption🟡 較少無限制*高併發、需要快速擴展的應用
Premium❌ 無無限制*最快關鍵生產環境、要求穩定效能
Dedicated❌ 無無限制*手動已有閒置 App Service Plan 的情境

⚠️ 重要通知 微軟宣布,Linux Consumption Plan 將在 2028 年 9 月 30 日淘汰,建議大家未來新專案可以優先考慮 Flex Consumption Plan

*備註:所有方案的 HTTP 觸發器都有 230 秒 的回應限制,這是 Azure Load Balancer 的限制。如果你的背景任務需要跑更久,建議研究一下 Durable Functions 的非同步模式。

對於大部分開發和測試情境,免費額度很夠用的 Consumption Plan 是個好起點。


用 C# 建立第一個 Function App

光說不練太空泛,我們直接來看一個用 .NET 8 建立的 C# 專案。

專案結構速覽

這是一個典型的 Azure Functions (.NET Isolated Worker) 專案結構:

AzureWebApp.Functions/
├── Functions/
│   ├── HttpTriggerFunction.cs   # 一般的 HTTP Trigger 範例
│   └── VersionFunction.cs        # 我們今天的重點:版本資訊 API
├── Models/
│   └── VersionInfo.cs            # 版本資訊的資料模型
├── Program.cs                     # 應用程式進入點,用來註冊服務
├── host.json                      # Functions 執行環境的設定檔
└── AzureWebApp.Functions.csproj   # 專案檔,藏了一些小技巧

 

實作一個「版本資訊」API

一個常見的需求是,我想知道現在線上跑的是哪個版本。我們來做一個 /api/version 端點,它會回傳目前的 Git Commit Hash、建置時間和執行環境。

VersionFunction.cs

public class VersionFunction
{
    [Function("version")]
    public static IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "version")] HttpRequest req)
    {
        var assembly = Assembly.GetExecutingAssembly();
        var info = new VersionInfo(assembly);
        return new OkObjectResult(info);
    }
}

 

程式碼很簡單,就是 new 一個 VersionInfo 物件然後回傳。那麼 VersionInfo 怎麼拿到 Git Commit Hash 的?

關鍵技巧:在建置時嵌入 Git 資訊

AzureWebApp.Functions.csproj!我們在裡面加了一個 Target,讓它在每次建置 (Build) 的時候,自動去執行 git 指令,並把結果寫入組件 (Assembly) 的 Metadata。

<PropertyGroup>
  <!-- ... -->
  <!-- 將 Git Commit Hash 設定為 SourceRevisionId -->
  <SourceRevisionId>$(GitCommitHash)</SourceRevisionId>
  <!-- 將版本資訊組合後,嵌入 AssemblyInformationalVersion -->
  <InformationalVersion>$(GitCommitHash)-$(BuildTime)</InformationalVersion>
</PropertyGroup>

<!-- 在建置前自動執行,取得 Git commit hash -->
<Target Name="SetBuildInfo" BeforeTargets="GetAssemblyVersion">
  <!-- 執行 git 指令,並將輸出存到 MSBuild 屬性 -->
  <Exec Command="git rev-parse --short HEAD" ConsoleToMSBuild="true" IgnoreExitCode="true">
    <Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" />
  </Exec>
  <PropertyGroup>
    <!-- 如果抓不到 Git hash (例如在 CI 環境),就給個預設值 -->
    <GitCommitHash Condition="'$(GitCommitHash)' == ''">unknown</GitCommitHash>
    <!-- 記錄建置時間 (UTC) -->
    <BuildTime>$([System.DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"))</BuildTime>
  </PropertyGroup>
</Target>

 

有了這個設定,程式碼裡就可以輕鬆透過 Reflection 讀到這些資訊。這招是不是很實用?

在本地端跑起來

  1. 安裝相依工具:你需要 .NET 8 SDKAzure Functions Core Tools

    # 安裝 Azure Functions Core Tools
    curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
    sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
    sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-$(lsb_release -rs)-prod $(lsb_release -rs) main" > /etc/apt/sources.list.d/dotnetdev.list'
    sudo apt-get update
    sudo apt-get install azure-functions-core-tools-

    這裡使用 isolated worker model

     

    # 安裝 .NET 8 SDK
    wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh
    chmod +x ./dotnet-install.sh
    ./dotnet-install.sh --channel 8.0
  2. 還原、建置、啟動

    # 進入專案目錄
    cd AzureWebApp.Functions
    
    # 還原 NuGet 套件
    dotnet restore
    
    # 建置專案
    dotnet build
    
    # 啟動本地 Functions 主機
    func start

     

  3. 測試 API: 打開瀏覽器或用 curl 測試 http://localhost:7071/api/version,你應該會看到類似下面的 JSON 結果:

    {
      "Version": "70b6a61",
      "BuildTime": "2026-02-01T14:30:00Z",
      "Environment": "Development"
    }

     


把 Function App 部署上 Azure

寫好了,總得部署上去。這裡介紹兩種方法:適合快速測試的「本地手動部署」,以及強烈推薦的「GitHub Actions 自動化部署」。

方法一:從自己電腦部署 (Local Deploy)

有時候只是想快速驗證一下功能,可以用 func 指令直接從本機部署。為了讓過程更順暢,專案裡提供了一個 local-deploy-azure.sh 腳本。

local-deploy-azure.sh

#!/bin/bash
# 配置變數
FUNCTION_APP_NAME="func-yao-lab-938612"
PROJECT_DIR="AzureWebApp.Functions"

# ... (省略檢查與建置步驟) ...

# 部署到 Azure Function App
echo "部署到 Azure Function App: ${FUNCTION_APP_NAME}..."
cd "$PROJECT_DIR"
func azure functionapp publish "$FUNCTION_APP_NAME"

 

這個腳本幫你把建置、發布的指令都包好了,只要確定你已經用 az login 登入 Azure,就可以直接執行它。

# 賦予執行權限
chmod +x ./local-deploy-azure.sh

# 執行部署
./local-deploy-azure.sh

 

部署成功後,腳本還會貼心地幫你抓 Function Key,讓你直接用 curl 測試。

方法二:用 GitHub Actions 玩 CI/CD (推薦)

這才是現代化的開發流程!我們希望每次把程式碼 pushmain 分支時,就自動觸發建置和部署。

專案裡的 .github/workflows/deploy-azure-function.yml 已經幫我們定義好了整個流程。

設定步驟

  1. 建立 Service Principal (服務主體)

    我們不希望把有高權限的 Publish Profile 放在外面,所以改用權限可控的 Service Principal。專案裡也提供了一個 setup-service-principal.sh 腳本,它會幫你:

    • 檢查 azgh (GitHub CLI) 是否安裝登入。
    • 在 Azure AD 建立一個 Service Principal。
    • 授權它只能存取指定的資源群組 (Resource Group)。
    • 最重要的,把產生的憑證 (Credentials) 直接存進 GitHub Secrets,完全不落地。

     

    # 執行腳本,跟著指示操作
    ./setup-service-principal.sh

     

    執行成功後,你的 Github Repo 專案 Secrets 裡就會多一個 AZURE_CREDENTIALS

  2. 檢查 Workflow 檔案

    打開 .github/workflows/deploy-azure-function.yml,確認環境變數 AZURE_FUNCTIONAPP_NAME 是你自己的 Function App 名稱。

    env:
      AZURE_FUNCTIONAPP_NAME: 'func-yao-lab-938612'
      AZURE_FUNCTIONAPP_PACKAGE_PATH: 'AzureWebApp.Functions'
      DOTNET_VERSION: '8.0.x'

     

  3. 觸發部署

    現在,只要 push 任何 commit 到 main 分支,部署就會自動開始。

    # 做一些修改
    git add .
    git commit -m "feat: add new feature"
    git push origin main

     

    你也可以到 GitHub 專案的 Actions 頁面,手動觸發這個 Workflow。或者是 commit 空白的內容 empty-commit.sh 

    #!/bin/bash
    
    # 建立空 commit 以觸發 GitHub Actions 部署
    
    git commit --allow-empty -m "chore: trigger deployment - $(date '+%Y-%m-%d %H:%M:%S')"

     

Workflow 做了什麼事?

整個自動化流程大致如下:

1. Checkout code (拉取程式碼)
   ↓
2. Setup .NET 8.0 (設定 .NET 環境)
   ↓
3. Restore, Build, Publish (還原、建置、發布專案)
   ↓
4. Login to Azure (使用剛剛的 Secret 登入 Azure)
   ↓
5. Deploy to Azure (部署到 Function App)
   ↓
6. Health Check (呼叫 /api/version 確認部署成功)
   ↓
7. ✅ 部署完成

部署完成後,workflow 會自動打 /api/version 確認服務是否正常,如果回傳的 JSON 裡 Environment 變成 Production,就代表成功啦!


總結

今天我們從 Azure Function App 的基本介紹、方案選擇,一路到用 C# 實作出一個包含 Git 版本資訊的 API。最後,我們還介紹了兩種部署方式,特別是透過 GitHub Actions 建立了一套完整的 CI/CD 流程。

把繁瑣的部署工作自動化,不僅能減少人為失誤,也能讓我們更專注在核心的商業邏輯開發上。希望這篇文章對你有幫助!


專案位置

yaochangyu/azure-web-app-func-demo

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo