【Azure】Azure Pipelinesを用いてストレージアカウントを自動デプロイする。

# 1. はじめに
### 1-1 ご挨拶
初めまして、井村と申します。
Azure Pipelinesを用いてストレージアカウントを自動デプロイしてみました。
Azure PipelinesはAzure DevOpsのCI/CDサービス、ストレージアカウントはオブジェクト、ファイル等の各種ストレージを管理するサービスです。

実際に触って色々と気づいた部分がありましたので備忘録として残します。
参考記事は[こちら](https://learn.microsoft.com/ja-jp/training/modules/build-first-bicep-deployment-pipeline-using-azure-pipelines/)になりますので興味がある方は是非チェックしてみてください。

### 1-2 対象読者
- Azureに興味がある
- Bicepに興味がある
- Azure Pipelinesに興味がる

### 1-3 ローカル環境について
私はWindows端末に以下をインストールました。
- [Visual Studio Code](https://code.visualstudio.com/)
- [Visual Studio Code用のbicep拡張機能](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep)
- [Azure CLI](https://learn.microsoft.com/ja-jp/cli/azure/install-azure-cli)
- [Git](https://git-scm.com/download)

初回はAzure、AzureDevOpsそれぞれでサインアップが必要になります。
- [Azureサインアップページ](https://azure.microsoft.com/ja-jp/free/)
- [Azure DevOpsサインアップページ](https://azure.microsoft.com/ja-jp/products/devops/)

# 2. 各サービスおよび検証の流れ
### 2-1 全体像
今回作成する環境は以下になります。

![Azure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/a7e948a2-1bff-7611-c689-153f32c170e7.png)

- Azure ReposとはAzureDevOpsの1つサービスでリポジトリの役目をします。
- Azure PipelinesとはAzureDevOpsの1つサービスでCI/CDの役目をします。
- Storage AccountとはAzureの1つサービスで各ストレージをまとめるサービスです。
- blob storageとはオブジェクトストレージを格納するサービスです。
- file sharesとはファイル共有サービスです。

### 2-2 検証の流れ
ローカル環境で2ファイル作成します。1つ目がStorage Accountを作成するためのBicepファイルです。2つ目はAzure Pipelinesの定義を記載するYAMLファイルです。
2ファイルを格納するためリポジトリはAzure Reposを利用します。Azure PipelinesはAzure Repos上のBicepファイルを読み込んで、Azure上にStorage Accountを作成します。

まずは上記方法でStorage Accountとblob storageを作成します。
次に同様の流れでローカル環境でfile shareの記述をBicepファイルに追記、Azure Reposにプッシュします。Azure PipelinesがAzure Reposが更新されたタイミングでBicepファイルを読み込み自動デプロイするか確認します。

# 3. 構築

### 3-1 Azure DevOpsの組織、プロジェクトの作成
Azure DevOpsを利用するには組織を作成します。会社名や部署名等わかりやすい名前を記入します。今回は「test20230221」です。

![1_newOrganization.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/4d819309-7416-ec29-95e1-498433b8ae2c.png)


組織を作成後、プロジェクトを作成します。組織内で複数のプロジェクトを作成すると思いますのでわかりやすい名前を記入します。今回は「test-project」です。

![2_newProject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/b65d9cd5-df87-8c6f-bc29-b9bf4357f29f.png)

### 3-2 Azure Repos、Git環境の作成
今回の作業用フォルダとしてデスクトップ上に「AzureDevOps」フォルダを作成します。

![4_Desktop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/6e111ff0-ff8f-1915-577f-6b7b82a339aa.png)

左ペインにAzureDevOpsの各種サービスが並んでいます。Azure Repos → Fileです。

![3_AzureRepos.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/618f5ed5-52e2-1835-e67c-c0494c645b91.png)

「Clone in VS Code」を選択します。

![5_Clone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/74db0fec-0fd4-a12c-8baa-5a2c5864083d.png)

ポップアップが表示されたら「Open Visual Studio Code」をクリックします。

![6_Open.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/47647fad-1f67-97c8-dc5b-844805e48a45.png)

Visual Studio Codeが開いたらポップアップが表示されます。「開く」をクリックします。

![7_Allow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/74aac48c-ca9e-b436-bfac-6b0635d33a6b.png)


作業用フォルダを「リポジトリの宛先として選択」をクリックします。

![8_Work.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/8b4c3493-dd4f-31ef-1430-3129456a535c.png)

下記ポップアップが表示されたら「開く」をクリックします。

![9_Open.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/5dd60baf-e066-953c-6584-5ee1962ac769.png)

下記画面のようにgit環境がクローンされました。

![10_Git.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/fe029bf0-a5bf-babc-3b56-dd11b3225488.png)

### 3-3 Azure環境の作成
Azure上にリソースグループを作成するため、下記コマンドを実行します。

```cmd:cmd (Azure CLI)
az login

az group create --name rg-hawk --location japaneast

```

以下画像のようにAzure上にリソースグループが作成されます。

![11_rg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/26fa6bab-6a09-bd1e-4cea-4b217caeb376.png)

### 3-4 Azure Pipelinesのサービス接続の作成
Azure Pipelines でサービス接続を作成するとAzure上にサービス プリンシパルが自動的に作成されます。また、リソースグループの共同作成者権限がサービス プリンシパルに付与されます。よってストレージアカウントを作成できるようになります。

Azure DevOpsの「Project settings」からPipelines → Service connectiosです。

![12_serviceConnection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/dc149d8f-cff5-cc44-32af-d18445ba89fa.png)

「Create service connection」をクリックします。

![13_serviceConnection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/fade6e92-68fb-9ee3-d70b-dc352d2f1d2d.png)

Azure Resource Managerを選んで「Next」をクリックします。

![14_serviceConnection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/ea4ddfdb-0a32-b77b-bafb-73f2b120cb52.png)

Service principal(automatic)を選んで「Next」をクリックします。

![15_serviceConnection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/b6012ee0-3ccc-6890-68ab-57b94d60a4f4.png)

下記画面ではマスクしていますがSubscriptionはご自身のAzureのサブスクリプションを選択します。作成したリソースグループを選択します。Service connection nameもわかりやすい値を入力します。Securityにチェックを入れて「Save」をクリックします。

![16_serviceConnection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/fcbada12-f20e-f5e7-b9b0-cc601e52ec56.png)

Azure Pipelines上にサービス接続が作成されました。

![17_serviceConnection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/a2eb33f9-4921-94b8-9b50-521d0a7083c3.png)

Azure上にサービスプリンシパルが作成されました。

![18_serviceConnection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/945352ff-477b-7450-4215-68069795a827.png)

リソースグループの権限設定を確認すると作成したサービスプリンシパルが共同作成者権限を付与されています。

![19_serviceConnection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/c5d09e94-bf58-a102-caca-04dd641864d6.png)

### 3-5 Bicepファイル、YAMLファイルの作成

ローカルリポジトリ内に「deploy」フォルダを作成し、今回利用するBicepファイル、YAMLファイルを格納します。

```
AzureDevOps
└── test-project
        └── deploy
              ├── main.bicep
              └── azure-pipelines.yml
```

今回利用するYAMLファイルは以下になります。

<details><summary>azure-pipelines.yml</summary>

```yml:azure-pipelines.yml

     1  trigger:
     2    batch: true
     3    branches:
     4      include:
     5        - main
     6
     7  pool:
     8    vmImage: ubuntu-latest
     9
    10  variables:
    11  - name: deploymentDefaultLocation
    12    value: japaneast
    13
    14  jobs:
    15  - job:
    16    steps:
    17    - task: AzureResourceManagerTemplateDeployment@3
    18      inputs:
    19        connectedServiceName: $(ServiceConnectionName)
    20        location: $(DeploymentDefaultLocation)
    21        resourceGroupName: $(ResourceGroupName)
    22        csmFile: deploy/main.bicep

```
</details>

1行目のtriggerはAzure Pipelinesを実行するタイミングを指示するために利用します。手動、スケジュール起動等あります。今回はブランチトリガーを利用します。3行目でブランチトリガーを指定し5行目のmainブランチに変更があるとパイプラインが起動する処理となります。

7行目のpoolとはAzure Pipelinesの実行環境になります。今回はMSが提供する"Microsoft ホステッドエージェント"を使用します。このエージェントはAzure Pipelinesが実行されると自動起動され完了するとエージェントは自動的に削除されます。今回はUbuntuを利用していますが他にも色々な実行環境があり、自前で準備した実行環境である"セルフホステッドエージェント"も利用できます。

10行目のvariablesはYAMLファイルで利用する変数になります。後述説明するlocationで利用します。

14行目のjobsは各jobをグループ化します。

15行目のjobは1つのエージェントで実行されます。

16行目のstepsは17行目taskまたは今回利用はしませんがscriptからなるパイプラインの最小の構成要素です。

パイプラインのコンポーネントは[こちら](https://learn.microsoft.com/ja-jp/azure/devops/pipelines/get-started/key-pipelines-concepts?view=azure-devops)に詳しく説明があります。

17行目のtaskはパイプラインで自動化を定義するための構成要素です。taskは様々な種類がありますが"AzureResourceManagerTemplateDeployment@3"はARMテンプレートをデプロイするために利用します。

19行目のconnectedServiceNameはサービス接続を指定します。後述でブラウザから値を入力します。

20行目のlocationはリソースグループ作成に利用される必須の変数になります。事前に作成しているので今回は利用されません。

21行目のresourceGroupNameはリソースグループ名を指定します。後述でブラウザから値を入力します。

22行目のcsmFileは今回利用するBicepファイルを指定します。

今回利用するBicepファイルは以下になります。

<details><summary>main.bicep</summary>

```bicep:main.bicep

     1  @description('Storage Account type')
     2  @allowed([
     3    'Premium_LRS'
     4    'Premium_ZRS'
     5    'Standard_GRS'
     6    'Standard_GZRS'
     7    'Standard_LRS'
     8    'Standard_RAGRS'
     9    'Standard_RAGZRS'
    10    'Standard_ZRS'
    11  ])
    12  param storageAccountType string = 'Standard_LRS'
    13
    14  @description('The storage account location.')
    15  param location string = resourceGroup().location
    16
    17  @description('system code')
    18  param systemCode string = 'hawk'
    19
    20  // create storage account
    21  resource sa 'Microsoft.Storage/storageAccounts@2022-09-01' = {
    22    name: 'st${systemCode}${uniqueString(resourceGroup().id)}'
    23    location: location
    24    sku: {
    25      name: storageAccountType
    26    }
    27    kind: 'StorageV2'
    28    properties: {}
    29  }
    30
    31  // create blob container
    32  resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2022-05-01' = {
    33    name: '${sa.name}/default/blob-${systemCode}'
    34  }
    35
    36  // create file share
    37  // resource share 'Microsoft.Storage/storageAccounts/fileServices/shares@2022-09-01' = {
    38  //   name: '${sa.name}/default/share-${systemCode}'
    39  // }

```
</details>

1～19行目まではパラメーターを格納しています。
21行目のresourceはストレージアカウントを作成します。
32行目のresourceはblobストレージを作成します。
37行目のresourceはfile shareを作成します。現在はコメントアウトしています。

### 3-6 Azure Reposへプッシュ
それでは各ファイルをプッシュします。

```bash:bash
git add .
git commit -m "initial commit"
git push

```

Azure Repos → Fileを確認するとdeployフォルダ内に各ファイルがプッシュされていることが確認できます。

![20_AzureRepos.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/c115e2b1-6ae5-2bc5-3063-b3fb9d5d4835.png)

### 3-7 Azure Piplelinesの構築
それではAzure Pipelinesを構築します。Pipelines → Pipelinesから「Create Pipeline」をクリックします。

![21_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/05afebe9-1ebc-2bf6-a96b-dced3035da68.png)

Connectタブでは「Azure Repos Git」をクリックします。

![22_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/a75e61c6-6a43-fa37-d843-49f3dbf80092.png)

Selectタブでは「test-project」をクリックします。

![23_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/cdc6aae9-9444-4d31-cf87-b739daea68f2.png)

Configureタブでは「Existing Azure Pipelines YAML file」をクリックします。

![24_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/ecbbd9a5-61f1-d105-df0e-4090f3983432.png)

Pathは先ほどプッシュしたYAMLファイルを選択し「Continue」をクリックします。

![25_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/a699c12d-1bb8-b3d2-fa76-d8f86fff6cde.png)

変数の値を入力するため「Variables」をクリックします。

![26_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/334fb49d-185f-e94a-7d08-71e250a049f9.png)

「New variable」をクリックします。

![27_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/276d9609-5e07-3227-99eb-fbddfaa1e5a4.png)

NameをYAMLファイルで記述した「ServiceConnectionName」にします。Valueは3-4 Azure Pipelinesのサービス接続の作成で作成した値を入力します。「OK」をクリックします。

![28_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/f598d9ca-7749-f430-ef20-15d3b84065be.png)

同様にNameを「ResourceGroupName」、Valueをリソースグループ名を記述します。
変数を設定したら「Save」をクリックします。

![29_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/21cd8c56-4ebb-986d-85bb-5a366e66ed55.png)

それではAzure Pipelinesを実行します。「Run」をクリックします。

![30_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/00b29207-8e74-3e4f-1e5b-c5a15c631d76.png)

想定通りエラーがでました。[公式ドキュメント](https://learn.microsoft.com/ja-jp/training/modules/build-first-bicep-deployment-pipeline-using-azure-pipelines/3-exercise-create-run-basic-pipeline)には以下の記載があります。

 Azure DevOps 組織でパイプラインを初めて使用する場合は、次のエラーが表示されることがあります。
No hosted parallelism has been purchased or granted. (ホステッド並列処理が購入も許可もされていません。)

誤用を防ぐために、Azure DevOps では、新しい組織が Microsoft ホステッド パイプライン エージェントを無料で使用する前に、承認される必要があります。

![31_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/173d4f2e-930a-11b4-c993-18ae05e89f41.png)


パイプラインエージェントが利用できるよう[こちらのフォーム](https://forms.office.com/pages/responsepage.aspx?id=v4j5cvGGr0GRqy180BHbR63mUWPlq7NEsFZhkyH8jChUMlM3QzdDMFZOMkVBWU5BWFM3SDI2QlRBSC4u)に依頼をします。

![32_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/9af9f0c3-89bc-e2e8-9840-ba7a33157bf0.png)

数日後以下メールが届きますので、再度実行を試します。

![33_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/0e957eaa-ff11-3a2f-8eb9-aa6b58c1198b.png)


### 3-8 Azure Piplelinesの実行
それではAzure Pipelinesを実行します。「Run pipeline」をクリックします。

![34_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/c6d9c982-080d-c402-d5b3-20529b6fa9db.png)

「Run」をクリックします。

![35_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/9a390801-6558-f31d-a716-dc572d42cadb.png)

デプロイが完了しました。StatusがSuccessになっています。

![36_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/f1ee1b44-96ef-5f01-d75f-49515947f205.png)

Storage Accountおよびblob storageが作成されました。

![37_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/ecae0d2b-2cda-cfcc-16dc-c2fbf0f55b33.png)

file sharesはまだないですね。それでは次章の自動デプロイ検証を行いましょう。

![38_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/19947aac-5f74-d8e7-593c-51d57350cf2b.png)



# 4. 検証
### 4-1 Bicepファイルの更新
それではAzure Pipelinesが自動デプロイするか検証します。3-5 Bicepファイル、YAMLファイルの作成にて作成したBicepファイルのコメントアウトを外し保存します。


<details><summary>main.bicep</summary>

```bicep:main.bicep

     1  @description('Storage Account type')

    // 省略

    35
    36  // create file share
    37   resource share 'Microsoft.Storage/storageAccounts/fileServices/shares@2022-09-01' = {
    38     name: '${sa.name}/default/share-${systemCode}'
    39   }

```
</details>


### 4-2 Azure Reposへプッシュ
3-6 Azure Reposへプッシュと同様にプッシュします。

```bash:bash
git add .
git commit -m "add file shares"
git push

```


### 4-3 Azure Pipelinesの確認
プッシュ後しばらくすると更新があります。

![39_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/dbbf40e2-dd6b-0bde-3099-55271db10d44.png)


![40_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/299c77eb-f7aa-0bcd-6f8a-e39dec191d0c.png)


確認するとAzure Pipelinesが実行されています。

![41_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/33668995-0862-56bc-63b9-9f8e5aaa689f.png)

完了しました。

![42_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/17164e38-0b22-79a3-c938-805b3d309e0e.png)


Storage Account内にてfile shareが作成されていることが確認できます。

![43_AzurePiplelines.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/4d74f5ed-4abb-d34d-40f1-9bbfced14547.png)


以上で検証は終わりです。

# 5. 終わりに
本記事を最後まで読んで頂きましてありがとうございます。
DevOpsの資格勉強をしていたのですが、実際に触らないとわからないので触ってみました。他にもAzure DevOpsサービスはありますので引き続き試したいと思います。



# 6. 参考記事
- [Azure Pipelines を使用して最初の Bicep デプロイ パイプラインを作成する](https://learn.microsoft.com/ja-jp/training/modules/build-first-bicep-deployment-pipeline-using-azure-pipelines/)
- [パイプラインの主要な概念](https://learn.microsoft.com/ja-jp/azure/devops/pipelines/get-started/key-pipelines-concepts?view=azure-devops)
- [AzureResourceManagerTemplateDeployment@3 - ARM テンプレートのデプロイ v3 タスク](https://learn.microsoft.com/ja-jp/azure/devops/pipelines/tasks/reference/azure-resource-manager-template-deployment-v3?view=azure-pipelines)