はじめに
はじめまして!花王株式会社の @kunitomo926 と申します。
「Kaoエンジニアコミュニティβ」のメンバーとして参加します。よろしくお願いします!
私たちの組織の社内システムの開発では Azure DevOps を DevOps の基盤として活用しています。
Azure DevOps を選んだ理由は色々ありますが、特にエンタープライズ利用時のライセンス費用が比較的抑えられる点や、Entra ID と連携した権限管理が便利なところになります。
これから数回に分けて Azure DevOps の使い方、特に Pipelines の使い方をご紹介できればと思います。
※ 独学で学んだ部分も多いため、改善点などお気づきのことがありましたらコメントをいただけると嬉しいです。
Azure DevOps
Azure DevOps は多機能なサービスのため、全体的な説明は 公式ページ にお任せします。
私は主にスクラム管理(Boards)、ソースコード管理(Repos)、CI/CD(Pipelines)を使っています。
本記事では特に Azure DevOps 独自の機能性が高い Pipelines を取り上げていきます。
Pipelines
Azure DevOps 内で CI/CD を実現する機能としては "Pipelines" と "Releases" の 2 つあります。
- Pipelines: yaml ファイルを使った設定(コードベース)
- Releases: GUI ベースの設定
私は履歴管理や設定変更の透明性を重視して、主に yaml ファイルベースの Pipelines を使っています。
一方で他チームでは GUI ベースの Releases を活用しており、用途に応じて使い分けています。
本記事のゴール
今回のゴールは、Python(FastAPI)で作成した Web アプリを Azure WebApps にデプロイすることとします。
デプロイする Web アプリについて
Web アプリの中身は本記事の主旨から外れますので、以下のように "Hello World" を返却するシンプルなものを想定します。
ただ CI/CD を行っていく上では、依存するライブラリ(e.g., FastAPI)をどのタイミングでどのようにダウンロードするかを検討していく必要があるかと思います。
私個人は、これまで Python のパッケージ管理として poetry を使っていましたが、最近 uv を使い始めてみました。
uv の詳細な説明は割愛しますが、今回 FastAPI と uvicorn を使いますので、以下のコマンドから 2 つのライブラリを追加できます。
# FastAPI と uvicorn を追加する
uv add fastapi uvicorn
上記のコマンドを実行するとプロジェクト内の .venv フォルダにライブラリが追加され、さらに以下のように pyproject.toml 内の dependencies にライブラリが追記されていることを確認できます。
[project]
name = "my-first-fastapi"
version = "0.1.0"
description = "azure devops pipeline デモ用"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"fastapi>=0.116.1",
"uvicorn>=0.35.0",
]
後述するデプロイ先の Azure WebApps 環境では、この pyproject.toml に記載されているライブラリがダウンロードされます。
以下は、 main.py に "Hello World" を返却するためのコードを参考までに記載します。
from fastapi import FastAPI
app = FastAPI(title="My First FastAPI", version="0.1.0")
@app.get("/")
async def root():
"""Hello World を返却"""
return {"message": "Hello World"}
ローカル環境では以下のコマンドで起動することができます。
uv run uvicorn main:app --reload
デプロイ先の Azure WebApps
上記の Web アプリを Azure WebApps にデプロイしていきます。
今回はシンプルにするため、コンテナを使用せず、閉域化していない Azure WebApps にデプロイします。
※ 閉域化環境にデプロイする方法について、ご要望がありましたら次回以降に説明したいと思います。
Pipelines で実行する処理
実際のデプロイ処理は yaml ファイル(azure-pipelines.yml)に記述します。
以下は Azure WebApps にデプロイするときの一例(簡単のために静的解析、テストなどの処理は割愛)になり、基本的な流れは以下の通りです。
- アプリに必要な資材を zip ファイルに圧縮
- zip ファイルを Azure WebApps にデプロイ
- 初回起動時に実行されるシェル
startup.shを用意、実行されるように設定
※startup.sh内で必要なライブラリをダウンロード
一行毎の解説すると長くなってしまうので割愛させていただきますが、 yaml ファイル内の "steps" ではスクリプトを自由に書くこともできますし、 Microsoft 社などが用意している "task" を活用することで処理を簡略化することもできます。
例えば、 Azure WebApps へのデプロイを一からスクリプトを記述すると大変ですが、既に用意されている "AzureWebApp@1" を活用すると、デプロイ先の情報をセットするだけでデプロイできるようになります。
※ デプロイするための権限設定である Service Connection は次回以降に説明いたします。
# 何をトリガーに pipeline を実行するかどうか(以下は main ブランチに変更があった際に起動するように設定)
trigger:
- main
# 環境変数
variables:
# Azure 内のリソースグループ名
resourceGroupName: 'rg-kunitomo-test'
# Azure WebApps の名称
webAppName: 'web-test'
# Azure DevOps から Azure にデプロイするための権限設定
azureServiceConnectionId: 'service-connection-test'
jobs:
- job: BuildJob
pool:
# 処理を実行する VM 環境の指定
vmImage: 'ubuntu-latest'
steps:
# ① 必要なファイルを zip ファイルに圧縮
- task: ArchiveFiles@2
displayName: 'archive the files.'
inputs:
rootFolderOrFile: $(System.DefaultWorkingDirectory)
includeRootFolder: false
archiveType: zip
archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
replaceExistingArchive: true
# Exclude unnecessary files
excludePaths: |
**/.git/**
**/__pycache__/**
**/.venv/**
# ② zip ファイルを Azure DevOps 内にアップロード
- upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
displayName: 'upload a zip file.'
artifact: drop
# ③ ② でアップロードした zip ファイルをダウンロード
- download: current
displayName: 'download a zip file.'
artifact: drop
# ④ zip ファイルを Azure WebApps にデプロイ
- task: AzureWebApp@1
displayName: 'deploy the zip file to the azure web app.'
inputs:
azureSubscription: $(azureServiceConnectionId)
appType: 'webAppLinux'
appName: $(webAppName)
resourceGroupName: $(resourceGroupName)
package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
runtimeStack: 'PYTHON|3.13'
startUpCommand: './startup.sh'
startup.sh の説明
最後の行に記載している "startUpCommand: './startup.sh'" について、補足します。
"startUpCommand" はアプリが起動したタイミングで処理されるコマンドになり、先述していますように startup.sh という shell をあらかじめ用意して実行するように設定しています。
例えば、以下のように uv をインストールして、 uv を活用してライブラリをインストールするように処理を記述しています。
#!/bin/bash
set -e
echo "=== Starting FastAPI Application with uv ==="
# PATH を追加
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
# uv がインストールされていない環境の場合にインストール
if ! command -v uv &> /dev/null; then
echo "Installing uv..."
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.cargo/bin:$PATH"
# インストールに時間がかかることを見越して 2 秒スリープ
sleep 2
fi
# uv がインストールされているか確認
echo "UV version: $(uv --version)"
# カレントディレクトリとファイルを表示
echo "Current directory: $(pwd)"
echo "Files in current directory:"
ls -la
# dependencies に記載されているライブラリをインストール
echo "Installing dependencies..."
uv sync --frozen || uv sync
# uv を使ってアプリを起動
echo "Starting FastAPI application..."
exec uv run uvicorn main:app --host 0.0.0.0 --port ${PORT:-8000}
startup.sh もふくめて、最終的なプロジェクト構造は以下になります。
📂 project
┣ 📂 .venv
┣ .gitignore
┣ .python-version
┣ azure-pipelines.yml
┣ main.py
┣ pyproject.toml
┣ README.md
┣ startup.sh
┗ uv.lock
Pipeline の作成手順
前項までで準備した資材一式を Azure DevOps のリポジトリ(本記事では "Test" という名前で作成)に push しておきます。
その上で、いよいよ新しい pipeline を作成します。
リポジトリを選択する必要があり、今回は Azure DevOps のリポジトリにソースコードをアップロードしていますので "Azure Repos Git" を選びます。
リポジトリ "Test" を選択します。
今回は予め yaml ファイルを用意していますので、 "Existing Azure Pipelines YAML file" を選択します。
リポジトリ内の azure-pipelines.yml を選択します。
最終的に内容を確認して問題なければ、このまま Run を選択して実行します。
Pipeline の実行結果
今回は無事にデプロイできたことを確認しました。
また、所定の URL を叩いたときに、ローカル開発環境で確認した内容と同じ結果を取得できることも確認しました。
まとめ
説明がやや長くなりましたが、 Azure DevOps の Pipeline を活用して Azure WebApps にデプロイする方法をご紹介しました。
次回以降は省略した箇所の説明や、 Azure DevOps 内の権限設定、 Azure WebApps からデプロイ結果を確認する方法などをご紹介したいと思います。
ご意見やご質問がありましたらお気軽にコメントをお願いします!












