StreamlitをAzure App Serviceにデプロイする

Azure App Service で、Streamlitで作成したアプリケーションを動かします。

## 使用した環境
### ローカル開発環境
- Python: 3.12.8
- Streamlit: 1.41.1

### Azure App Service
- SKU: F1
- OS: Linux
- Runtime Stack: Python3.12

## 環境準備
### App Service の作成
クイックスタート[^1] などを参考に、App Service を作成する。

### App Service のカスタマイズ
#### SCM_DO_BUILD_DURING_DEPLOYMENT の有効化
デプロイ時に、requirement.txt に記載したパッケージがインストールされるよう、SCM_DO_BUILD_DURING_DEPLOYMENTにtrueを設定する[^2]。
- Azure Potal
1. 対象のApp Serviceを選択する
1. **Settings** > **Environment variables** を選択する
1. **[+ Add]** を選択し、下記設定を追加する
    Name: SCM_DO_BUILD_DURING_DEPLOYMENT
    Value: true
1. **[Apply]** を選択する
1. **[Apply]** を選択する

#### Startup Command の設定
AppService起動時に、streamlitを起動するためのシェルスクリプトが呼び出されるように設定する。
- Azure Potal
1. 対象のApp Serviceを選択する
1. **Settings** > **Configuration** を選択する
1. **Startup Command** に、下記設定を追加する
    bash /home/site/wwwroot/run.sh
1. **[Save]** を選択する

## アプリケーション作成とデプロイ
### Streamlit アプリケーションの準備
1. 以下の3ファイルを作成し、ZIP形式で圧縮する
    ```text: requirements.txt
    streamlit
    ```

    ```bash: run.sh
    python -m streamlit run app.py --server.port 8000 --server.address 0.0.0.0
    ```

    ```python: app.py
    import streamlit as st
    
    st.write("Hello world!")
    st.caption("This version has been deployed by Azure CLI.")
    
    ```


### App Service へのデプロイ
``` bash: AZ CLI
az login

az webapp deploy `
  --resource-group "<resource group name>" `
  --name "<app service name>" `
  --src-path "<前述の手順で作成したZIPファイル>"
```

### 動作確認
![Screenshot 2024-12-23 at 0.55.46 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525959/59dafd8b-cf5a-3a8c-946a-e662e47d4df2.png)


## Azure Pipelines によるデプロイ自動化
各種ファイルをAzure Reposに配置し、Azure Pipelinesで自動的にデプロイされるようにします。

### Azure Reposにファイルを配置する。
以下のようなディレクトリ構成で、前項で作成したファイルをAzure Reposの任意のリポジトリに配置する。
```bash
.
├── app
│   ├── app.py
│   ├── requirement.zip
│   └── run.sh
└── pipelines
    └── deploy.yml
```

### デプロイを行うためのパイプライン
```yaml: deploy.yml
trigger: 
  branches:
    include:
    - main
  paths:
    include:
    - app

variables:
  azureServiceConnectionId: '<your service connection>'
  webAppName: '<your Azure App Service>'
  projectRoot: $(System.DefaultWorkingDirectory)
  pythonVersion: 'PYTHON|3.12'

pool:
  vmImage: ubuntu-latest

steps:
- task: ArchiveFiles@2
  displayName: 'Archive files'
  inputs:
    rootFolderOrFile: '$(projectRoot)/app'
    includeRootFolder: false
    archiveType: 'zip'
    archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    replaceExistingArchive: true

- task: AzureRmWebAppDeployment@4
  displayName: 'Deploy Azure Web App'
  inputs:
    ConnectionType: 'AzureRM'
    azureSubscription: $(azureServiceConnectionId)
    appType: 'webAppLinux'
    WebAppName: $(webAppName)
    packageForLinux: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    RuntimeStack: '$(pythonVersion)'
```

### app.pyの修正
app.py を修正し、パイプラインを実行させる。
```python: app.py
import streamlit as st
    
st.write("Hello world!")
st.caption("This version has been deployed by Azure Pipelines.")
    
```

### 動作確認
![Screenshot 2024-12-23 at 1.11.47 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525959/38c436cf-b988-0cc5-e74f-e9be833a0dc2.png)


[^1]: [App Serviceのクイックスタート](https://learn.microsoft.com/ja-jp/azure/app-service/quickstart-python?tabs=flask%2Cwindows%2Cazure-cli%2Cazure-cli-deploy%2Cdeploy-instructions-azportal%2Cterminal-bash%2Cdeploy-instructions-zip-azcli)
[^2]: [Customize build automation](https://learn.microsoft.com/en-us/azure/app-service/configure-language-python#customize-build-automation)