GitHub Actionsを使ってNuxt.jsのSPAページをAzure Storageの静的なWebサイトとして公開する

# はじめに

https://help.github.com/ja/articles/about-github-actions

GitHub Actionsというのをチラホラ見かけるようになりました。

いままで、Nuxt.jsのSPAを生成した後、手動でAzure Storageにアップロードしていたので、これを自動化してみようと思います。

# 作業

Azure Storageのリソースは事前に作成済みとします。

## ベータ版登録

GitHub Actionsはベータ版なので登録の申請をします。すぐに承認されました。

https://github.com/features/actions

## ワークフロー

ワークフローを作っていきます。以下のを参考にします。

https://github.com/Azure/github-actions/blob/master/storage-blob-static-website/EXAMPLES.md

ただ、これはHCL形式で書いてあって、現在はYAML形式を使うみたいなので、変換が必要です。

https://help.github.com/en/articles/migrating-github-actions-from-hcl-syntax-to-yaml-syntax

私はwindowsなので、migrate-actions-windows.zipを使いました。

解凍すると、migrate-actions.exeでてきます。その直下に以下のファイルを作ります。

```hcl:.github/main.workflow
workflow "Build and deploy on push" {
  on = "push"
  resolves = ["AzureDeployToStaticWebsite"]
}

action "Install" {
  uses = "actions/npm@master"
  args = "install"
}

action "Build" {
  needs = "Install"
  uses = "actions/npm@master"
  args = "run build"
}

action "AzureLogin" {
  needs = "Build"
  uses = "Azure/github-actions/login@master"
  env = {
    AZURE_SUBSCRIPTION = "<name of your subscription here>"
  }
  secrets = [
    "AZURE_SERVICE_PASSWORD",
    "AZURE_SERVICE_TENANT",
    "AZURE_SERVICE_APP_ID",
  ]
}

action "AzureDeployToStaticWebsite" {
  needs = "AzureLogin"
  uses = "Azure/github-actions/storage-blob-static-website@master"
  secrets = [
    "AZURE_STORAGE_ACCOUNT",
    "SAS_TOKEN"
  ]
}
```

実行します。

```
>migrate-actions.exe
Created workflow .github\workflows\push.yml

You can now delete your main.workflow file. If you have any .yml files in .github/workflows your main.workflow will be ignored.
    rm .github\main.workflow
    git add -A .github\main.workflow .github\workflows\*.yml
    git commit -m 'converted main.workflow to Actions V2 yml files'

Thanks for being a
  ________.__  __     ___ ___      ___.        _____          __  .__
 /  _____/|__|/  |_  /   |   \ __ _\_ |__     /  _  \   _____/  |_|__| ____   ____   ______
/   \  ___|  \   __\/    ~    \  |  \ __ \   /  /_\  \_/ ___\   __\  |/  _ \ /    \ /  ___/
\    \_\  \  ||  |  \    Y    /  |  / \_\ \ /    |    \  \___|  | |  (  <_> )   |  \\___ \
 \______  /__||__|   \___|_  /|____/|___  / \____|__  /\___  >__| |__|\____/|___|  /____  >
        \/                 \/           \/          \/     \/                    \/     \/
__________        __           ___________              __
\______   \ _____/  |______    \__    ___/___   _______/  |_  ___________
 |    |  _// __ \   __\__  \     |    |_/ __ \ /  ___/\   __\/ __ \_  __ \
 |    |   \  ___/|  |  / __ \_   |    |\  ___/ \___ \  |  | \  ___/|  | \/
 |______  /\___  >__| (____  /   |____| \___  >____  > |__|  \___  >__|
        \/     \/          \/               \/     \/            \/
```

こうなりました。

```yaml:.github/workflows/push.yml
on: push
name: Build and deploy on push
jobs:
  install:
    name: Install
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - name: Install
      uses: actions/npm@master
      with:
        args: install
    - name: Build
      uses: actions/npm@master
      with:
        args: run build
    - name: AzureLogin
      uses: Azure/github-actions/login@master
      env:
        AZURE_SERVICE_APP_ID: ${{ secrets.AZURE_SERVICE_APP_ID }}
        AZURE_SERVICE_PASSWORD: ${{ secrets.AZURE_SERVICE_PASSWORD }}
        AZURE_SERVICE_TENANT: ${{ secrets.AZURE_SERVICE_TENANT }}
        AZURE_SUBSCRIPTION: <name of your subscription here>
    - name: AzureDeployToStaticWebsite
      uses: Azure/github-actions/storage-blob-static-website@master
      env:
        AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }}
        SAS_TOKEN: ${{ secrets.SAS_TOKEN }}
```

これにいくつか変更を加えました。

### AzureDeployToStaticWebsite

まず、`Azure/github-actions/storage-blob-static-website@master`が動かなかったのでフォークしてちょっと編集しました。

https://github.com/planethouki/github-actions/tree/master/storage-blob-static-website

`Dockerfile`と`entrypoint.sh`を変えています。

また、Azure Storageに公開するファイルのディレクトリは、デフォルトで`public`になっているため、`dist`を指定します。

### AzureLogin

サブスクリプション名をそのままコミットしないようにするために、変数化しました。

### Build

ここは`npm run build`する用なのですが、Nuxt.js用に`npm run generate`に変えました。

### 結果

```yaml:.github/workflows/main.yml
name: Azure Blob Deploy

on: [push]

jobs:
  azure_blob_deploy:
    runs-on: ubuntu-latest
    name: Azure Blob Dploy
    steps:
      - uses: actions/checkout@master

      - name: Install
        uses: actions/npm@master
        with:
          args: install

      - name: Generate
        uses: actions/npm@master
        with:
          args: run generate

      - name: AzureLogin
        uses: Azure/github-actions/login@master
        env:
          AZURE_SERVICE_APP_ID: ${{ secrets.AZURE_SERVICE_APP_ID }}
          AZURE_SERVICE_PASSWORD: ${{ secrets.AZURE_SERVICE_PASSWORD }}
          AZURE_SERVICE_TENANT: ${{ secrets.AZURE_SERVICE_TENANT }}
          AZURE_SUBSCRIPTION: ${{ secrets.AZURE_SUBSCRIPTION }}

      - name: AzureDeployToStaticWebsite
        uses: planethouki/github-actions/storage-blob-static-website@master
        env:
          AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }}
          SAS_TOKEN: ${{ secrets.SAS_TOKEN }}
          PUBLIC_FOLDER: dist
```

さて、次はAzureでの権限設定と、ワークフローファイルにある`${{ secrets.XXXX }}`の箇所の定数を取得していきます。

#### 追記

コメント欄で教えていただきましたことを反映いたしました。npmを使う場合、`setp-node`を使うようです。

```yaml:.github/workflows/main.yml
name: Azure Blob Deploy

on: [push]

jobs:
  azure_blob_deploy:
    runs-on: ubuntu-latest
    name: Azure Blob Dploy
    steps:
      - uses: actions/checkout@master

      - name: setup node
        uses: actions/setup-node@v1
        with:
          node-version: '10.16'

      - name: install
        run: npm install

      - name: install
        run: npm run generate

      - name: AzureLogin
        uses: Azure/github-actions/login@master
        env:
          AZURE_SERVICE_APP_ID: ${{ secrets.AZURE_SERVICE_APP_ID }}
          AZURE_SERVICE_PASSWORD: ${{ secrets.AZURE_SERVICE_PASSWORD }}
          AZURE_SERVICE_TENANT: ${{ secrets.AZURE_SERVICE_TENANT }}
          AZURE_SUBSCRIPTION: ${{ secrets.AZURE_SUBSCRIPTION }}

      - name: AzureDeployToStaticWebsite
        uses: planethouki/github-actions/storage-blob-static-website@master
        env:
          AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }}
          SAS_TOKEN: ${{ secrets.SAS_TOKEN }}
          PUBLIC_FOLDER: dist
```


## 権限設定

GitHubからAzureへアクセスするための各種権限設定を行います。その後で、その情報をGitHubへ登録していきます。

azure-cliが必要です。事前に、`az login`でログインしている必要があります。

### AzureLogin

こちらのREADMEにあるように、`az ad sp create-for-rbac`コマンドを使います。

https://github.com/Azure/github-actions/tree/master/login#secrets

```
>az ad sp create-for-rbac
Creating a role assignment under the scope of "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
{
  "appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "displayName": "azure-cli-yyyy-mm-dd-hh-mm-ss",
  "name": "http://azure-cli-yyyy-mm-dd-hh-mm-ss",
  "password": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

appId, password, tenantを使用します。それぞれ、`AZURE_SERVICE_APP_ID`, `AZURE_SERVICE_PASSWORD`, `AZURE_SERVICE_TENANT`として使用します。

サブスクリプションが複数あり、これを指定する必要がある場合は、`az account list`コマンドを使います。

```
>az account list
[
  {
    "cloudName": "AzureCloud",
    "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "isDefault": true,
    "name": "hoge",
    "state": "Enabled",
    "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "user": {
      "name": "xxxx@xxxx.xx.xx",
      "type": "user"
    }
  }
]
```

nameのところを使用します。`AZURE_SUBSCRIPTION`として使用します。

### AzureDeployToStaticWebsite

こちらにあるコマンドを使います。

https://github.com/Azure/github-actions/tree/master/storage-blob-static-website#secrets

`--account-name`のところは、Azure Storageアカウント名を入れます。

```
>az storage account keys list --account-name xxxxx
[
  {
    "keyName": "key1",
    "permissions": "Full",
    "value": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  },
  {
    "keyName": "key2",
    "permissions": "Full",
    "value": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
]
```

ここで出てきた`value`のうちどちらかを、次の`--account-key`に入れます。

```
>az storage account generate-sas --account-name xxxxxxx --account-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --resource-types c --services b --expiry 2020-09-26T00:00Z --permissions adu
"se=xxxxxxxxxxxxxxxxxxx&sp=xxx&sv=xxxxxxxxxx&ss=x&srt=x&sig=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

`--expiry`のところは適宜変更してください。


`se=xxxx....`のところを使います。`SAS_TOKEN`として使います。



## GitHubに変数を登録

`.github/workflows/main.yml`にある`${{ secrets.xxxxx }}`のところの変数をGitHubに登録していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/8bee8a5b-d463-e27d-2e9a-281fde9faa10.png)


## Nuxtアプリを作成

`npx create nuxt app`とかでとりあえずモノを作ります。

## GitHubにPush

Nuxtアプリを作ったら、`.github/workflows/main.yml`にワークフローを作ってPushします。

すると、GitHub上ではこんな感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/df644565-a62a-f6c8-4af2-9ee649c24970.png)

何か間違えていたりすると、このように失敗します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/c113b0b6-9da0-6256-bc70-b879bf70d00c.png)


## 作成された

こんな感じになります。

https://hwnsab.z23.web.core.windows.net/

これで、Pushするたびにデプロイが走るようになりました。

# おわりに

一度設定するともう何もしなくていいので便利です。

いろんな定数を取得してなければならないのは地味に大変でした。