﻿# 在 Azure 實現 GitOps 的起手式：使用 Bicep 部署 Web 應用程式

我經常需要在 Azure 手動建立許多測試站台，雖然說設定上並沒有很複雜，但是時間一久，累積出將近百來個 Web App 也是蠻難維護的，而且 **組態漂移** ([Configuration Drift](https://www.tripwire.com/state-of-security/security-data-protection/what-is-configuration-drift/)) 的問題也會日趨嚴重，久而久之就不知道服務到底是怎樣設定出來的了。近幾年很夯的 [GitOps](https://about.gitlab.com/topics/gitops/) 觀念興起，讓你可以使用 Git 管理基礎架構的所有設定，用應用程式開發的流程來管理維運的基礎架構，提升基礎架構的可維護性。本篇文章我就簡介一下 Azure 專用的 [Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/?WT.mc_id=DT-MVP-4015686) 語言，教你如何利用 Bicep 實現 Azure 雲端平台的 GitOps 架構。

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/8913be2467a2b576acc4-079693d2-1243-4c5a-b5ab-dbb0a4a3048c.webp)

### 簡介 Bicep

[Bicep](https://github.com/Azure/bicep) 是一個 **領域特定語言** (DSL) (Domain Specific Language)，專門用來部署 Azure 資源。早期 Azure 要做到自動化部署，除了透過 **Azure CLI** 命令列工具外，還可以透過 **ARM Templates** 來定義部署的目標，如果我們要做到 GitOps 的話，只能使用繁瑣的 ARM Templates 來撰寫，較不易維護與撰寫。

微軟在不久前推出 [Bicep](https://github.com/Azure/bicep) 語言，它大幅簡化編寫 ARM 的難處，取代先前 ARM Templates 使用 JSON 作為資源描述的方式，改用 Bicep 這份 DSL 來撰寫，不但撰寫的內容減少非常多，透過模組化的寫法，還可以大幅降低重複的語法描述，且描述的語法也變的更好理解。搭配著 [Visual Studio Code](https://code.visualstudio.com/) 與 [Bicep](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep) 擴充套件，甚至還提供相當完整的 IntelliSense 與錯誤提示，讓撰寫 Azure 自動化的部署腳本變的更加容易，不但讓 Azure 雲端資源變的更方便維護，搭配著 Git 版本控管，更可以記錄下基礎架構完整的變更歷程，大大提升了 Azure 基礎架構的 **可視性** (Visibility)。

**Bicep** 與 **ARM Templates** 完全相容，這意味著現有的任何 ARM Templates 都可以輕易的轉為 Bicep 語法，你可以透過以下 Azure CLI 命令將現有匯出的 **ARM Templates** 轉譯成 **Bicep** 範本：

```bash
az bicep decompile --file app-service.json
```

> 上述命令執行完後，會在同目錄產生一個 `app-service.bicep` 檔案。

其實 Bicep 與 ARM Template 之間的關係，可以看做是 [C#](https://learn.microsoft.com/zh-tw/dotnet/csharp/?WT.mc_id=DT-MVP-4015686) 與 [IL](https://learn.microsoft.com/en-us/dotnet/standard/managed-code?WT.mc_id=DT-MVP-4015686#intermediate-language--execution) (Intermediate Language) 之間的關係，C# 最終會編譯成 IL 中繼組合語言，而 Bicep 最終也會編譯成 ARM Template 語法，然後才會進行 Azure 資源的部署。

所有在 ARM Template 中的可用**資源類型** (`types`)、**API 版本** (`apiVersions`)、**屬性清單** (`properties`)，在 Bicep 中也都是有效的，即便有些 ARM Template 中的屬性在 Bicep 中會顯示警告，但這些屬性依然是可以被部署的。

> 註: 英文的 `Bicep` 是「二頭肌」的意思，意味著強大的肌力可以搬動笨重的基礎架構。

### 準備 Bicep 開發環境

編寫 Bicep 最適合的工具，不外乎就是 Visual Studio Code 了，因為微軟特別針對 Visual Studio Code 開發出了一套 [Bicep](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep) 擴充套件，非常的強大！👍

1.  安裝 [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?WT.mc_id=DT-MVP-4015686) 與 [Bicep CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/install?WT.mc_id=DT-MVP-4015686#install-manually) 命令列工具
    
    ```bash
    choco install azure-cli bicep -y
    ```
    
2.  安裝 [Visual Studio Code](https://code.visualstudio.com/) 與其 [Bicep](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep) 擴充套件
    
    ```bash
    choco install vscode -y
    ```
    
    ```bash
    code --install-extension ms-azuretools.vscode-bicep
    ```
    

### 使用 Bicep 部署 Web 應用程式

> 以下命令皆使用 PowerShell 或 Shell Script 來執行，不要使用 **命令提示字元** (Command Prompt) 來執行命令喔！

1.  登入 Azure CLI
    
    ```bash
    az login --tenant 'TenantId'
    ```
    
2.  切換訂用帳戶
    
    ```bash
    az account set --subscription 'SubscriptionId'
    ```
    
3.  建立資源群組
    
    ```bash
    az group create --name 'GroupName' --location 'Location'
    ```
    
    使用範例：
    
    ```bash
    az group create --name 'GroupName' --location 'eastasia'
    ```
    
    > 你可以透過以下命令查出所有可用的 `--location` 清單：
    
    ```powershell
    az account list-locations
    az account list-locations -o jsonc | ConvertFrom-Json | select 'name'
    az account list-locations -o jsonc | ConvertFrom-Json | select 'name' | where { $_.name -like '*asia*' }
    az account list-locations -o jsonc | ConvertFrom-Json | select 'name' | where { $_.name -like '*japan*' }
    ```
    
4.  建立 Bicep 腳本 (App Service Plan & App Service)
    
    我們建立一個 `app-service.bicep` 檔案，其中最重要的設定，不外乎是 `name` 與 `location` 這兩個必要參數，還有 App Service Plan 的 `sku.name` 也是非常重要的，不能設定錯誤。不過，目前 Azure CLI 還無法列出有效的 SKU 名稱清單([#13466](https://github.com/Azure/azure-cli/issues/13466))，只能透過 [App Service Plans - Get Server Farm Skus](https://learn.microsoft.com/en-us/rest/api/appservice/app-service-plans/get-server-farm-skus?WT.mc_id=DT-MVP-4015686) 這個 RESTful API 才能取得。
    
    ```bicep
    var location = 'eastasia'
    var skuName = 'F1'
    
    resource appServicePlan 'Microsoft.Web/serverfarms@2021-02-01' = {
      name: 'asp-gitops-1'
      location: location
      sku: {
        name: skuName
      }
    }
    
    resource webApp 'Microsoft.Web/sites@2021-02-01' = {
      name: 'webapp-gitops-1'
      location: location
      properties: {
        serverFarmId: appServicePlan.id
      }
    }
    ```
    
5.  先驗證建立 Bicep 腳本會如何套用到 Azure
    
    ```powershell
    az deployment group what-if -g 'GroupName' --template-file 'app-service.bicep'
    ```
    
    > 這裡會預覽你即將建立的全新 Azure 資源有哪些。
    
6.  透過 Bicep 腳本部署 Azure 資源
    
    底下的 `az deployment group create` 意味著你會在特定一個 `group` (資源群組) 下部署資源，這裡的 `-n gitops-1` 是設定一個「部署名稱」，該名稱主要留下本次部署的紀錄，以利日後查閱部署進度與狀況。你可以從 Azure Portal 的 Resource Group 中找到一個 Deployments 頁籤，裡面會有每次的部署紀錄，不過**同名的部署名稱**會覆蓋掉現有的同名的部署紀錄。
    
    ```bash
    az deployment group create -n 'gitops-1' -g 'GroupName' --template-file 'app-service.bicep'
    ```
    
7.  修改 Bicep 腳本
    
    假設我調整 `appServicePlan` 資源，將服務等級 (`sku.name`) 從 `F1` 升級到 `S1`，並且啟用 **Always On** 與 **HTTPS Only** 設定，還有加入一條 `appSettings` 設定：
    
    ```bicep
    var location = 'eastasia'
    var skuName = 'S1'
    
    resource appServicePlan 'Microsoft.Web/serverfarms@2021-02-01' = {
      name: 'asp-gitops-1'
      location: location
      sku: {
        name: skuName
      }
    }
    
    resource webApp 'Microsoft.Web/sites@2021-02-01' = {
      name: 'webapp-gitops-1'
      location: location
      properties: {
        serverFarmId: appServicePlan.id
        httpsOnly: true
        siteConfig: {
          alwaysOn: true
          appSettings: [
            {
              name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
              value: '00000000-0000-0000-0000-000000000000'
            }
          ]
        }
      }
    }
    ```
    
8.  先驗證建立 Bicep 腳本 (App Service Plan & App Service)
    
    ```powershell
    az deployment group what-if -g 'GroupName' --template-file 'app-service.bicep'
    ```
    
    這個 `what-if` 命令會讓你預覽用這份 Bicep 腳本部署的過程會發生什麼變化：
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/c61e89f032846d067451-147871864-3136d96e-916b-430b-b8c5-338bc4da702c.png)
    
9.  透過 Bicep 腳本套用 Azure 資源變更
    
    ```bash
    az deployment group create -n 'gitops-2' -g 'GroupName' --template-file 'app-service.bicep'
    ```
    

### 後記

其實 [Bicep](https://github.com/Azure/bicep) 功能非常強大，短短一篇文章不足以展示其威力，文末的相關連結有許多學習資源，可以幫助大家輕鬆上手。在你開始使用 Bicep 部署資源後，你會發現很容易上手，未來所有的 Azure 資源設定都可以透過 Git 保留歷史紀錄，不但很容易維護，而且還能進版與退版，搭配 GitOps 的觀念，也可以更輕易的實現 CI 與 CD，與應用程式無縫整合！ 👍

### 相關連結

-   [Project Bicep - an ARM DSL](https://github.com/Azure/bicep)
-   [Bicep documentation](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/?WT.mc_id=DT-MVP-4015686)
    -   [Quickstart: Create Bicep files with Visual Studio Code](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/quickstart-create-bicep-use-visual-studio-code?WT.mc_id=DT-MVP-4015686&tabs=CLI)
    -   [Resource group deployments with Bicep files](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-to-resource-group?WT.mc_id=DT-MVP-4015686&tabs=azure-cli)
    -   [Subscription deployments with Bicep files](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-to-subscription?WT.mc_id=DT-MVP-4015686&tabs=azure-cli)
    -   [Tenant deployments with Bicep file](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-to-tenant?WT.mc_id=DT-MVP-4015686&tabs=azure-cli)
-   [Azure - Bicep & ARM templates](https://learn.microsoft.com/en-us/azure/templates/?WT.mc_id=DT-MVP-4015686)
    -   [Microsoft.Web serverfarms 2021-02-01](https://learn.microsoft.com/en-us/azure/templates/microsoft.web/2021-02-01/serverfarms?tabs=bicep&WT.mc_id=DT-MVP-4015686)
    -   [Microsoft.Web sites 2021-02-01](https://learn.microsoft.com/en-us/azure/templates/microsoft.web/2021-02-01/sites?WT.mc_id=DT-MVP-4015686&tabs=bicep)
-   Microsoft Learn
    -   [Fundamentals of Bicep](https://learn.microsoft.com/en-us/learn/paths/fundamentals-bicep/?WT.mc_id=DT-MVP-4015686)
    -   [Intermediate Bicep](https://learn.microsoft.com/en-us/learn/paths/intermediate-bicep/?WT.mc_id=DT-MVP-4015686)
    -   [Advanced Bicep](https://learn.microsoft.com/en-us/learn/paths/advanced-bicep/?WT.mc_id=DT-MVP-4015686)
    -   [Deploy Azure resources by using Bicep and Azure Pipelines](https://learn.microsoft.com/en-us/learn/paths/bicep-azure-pipelines/?WT.mc_id=DT-MVP-4015686)
    -   [Deploy Azure resources by using Bicep and GitHub Actions](https://learn.microsoft.com/en-us/learn/paths/bicep-github-actions/?WT.mc_id=DT-MVP-4015686)
