しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

Visual Studio Team Services と Web App for Container を使用した ASP.NET Core アプリケーションの CI/CD

最近は仕事で Visual Studio Team Services と Web App for Container を使っていましたが、地味にデプロイ周りで苦労をしたので軽くまとめておきます。

デプロイだけでは面白くないので、ASP.NET Core アプリケーションのビルドから行ってみます。Web App for Container には VSTS を使った CD を設定する機能がありますが、実際に試してみたところ中途半端な感じだったので、手動でビルドタスクを組みました。

VSTS で必要なものは Docker でタスクを検索すると出てきます。

f:id:shiba-yan:20171014225200p:plain

そして ASP.NET Core アプリケーションのビルドに必要なものは、Visual Studio 2017 で Docker サポートを追加すると全て追加されるので、準備することはあまりありません。

f:id:shiba-yan:20171014230118p:plain

VSTS には .NET Core のビルドを行うタスクもありますが、現在のビルドワーカーに入ってるランタイムバージョンなどを調べるのが面倒だったので、Docker Image を使ってビルドを行います。

予めリポジトリを作成して、ASP.NET Core アプリケーションのソースがプッシュされている前提で進めます。あとビルドタスクはテンプレートを使いません。

ASP.NET Core アプリケーションのビルド

Visual Studio 2017 で Docker サポートを有効にしてプロジェクトを作ると、Docker Compose を利用したビルド用の yaml がいくつか追加されます。ちゃんと CI 用の定義も用意されているので、これを使います。

f:id:shiba-yan:20171014235618p:plain

Docker Compose がインストールされている環境であれば、CI 用の定義を読み込んで docker-compose up すればアプリケーションのビルドが完了します。非常にシンプルで良いですね。

出力先は /obj/Docker/publish 固定になっていますが、ここは絶対に変更してはいけないです。

version: '3'

services:
  ci-build:
    image: microsoft/aspnetcore-build:1.0-2.0
    volumes:
      - .:/src
    working_dir: /src
    command: /bin/bash -c "dotnet restore ./WebApplication20.sln && dotnet publish ./WebApplication20.sln -c Release -o ./obj/Docker/publish"

ここで分かりにくいのが microsoft/aspnetcore-build:1.0-2.0 というタグのイメージを使わないと Visual Studio の Docker 向け SDK がインストールされておらず、ビルド時にエラーとなってしまうので注意。

素直に Visual Studio 2017 で生成されたまま使うのが正解という話でした。

VSTS では Docker Compose タスクを追加して、Action を "Run service images" に、Docker Compose File を docker-compose.ci.build.yml に変更するだけです。

f:id:shiba-yan:20171015002118p:plain

ルートにあるので ** は必要ないですが、あっても害はないので追加したままにしてます。

Docker Image のビルドと ACR へのプッシュ

アプリケーションのビルド後は Docker Image を作成します。デフォルトで生成されている Dockerfile は、ちゃんと Docker Compose を使ってビルドされた前提のパスになっているので簡単です。

FROM microsoft/aspnetcore:2.0
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "WebApplication20.dll"]

VSTS では Docker タスクを追加して、Action を "Build an image" にするだけです。Dockerfile のパスは最初から適切な値になっているはずなので、特に弄る必要はありません。

f:id:shiba-yan:20171015002455p:plain

Docker Image のビルド後はそれを ACR にプッシュする必要がありますが、これも Docker タスクを追加して Action を "Push an Image" に変えるだけで完了です。GUI での設定なので、あまりやることがないですね。

App Service へのデプロイ

ASP.NET Core アプリケーションが含まれている Docker Image はここまでで ACR までプッシュされているはずなので、最後は Web App for Container にデプロイを行います。

VSTS には非常に便利な Azure App Service Deploy というタスクがあるので、これを利用します。説明文をよく読むと Linux にも対応していると書いてありました。

f:id:shiba-yan:20171014230523p:plain

App Service on Linux では Staging スロットを使ってスワップする運用が必須なので、デプロイ先のスロットの選択が簡単に行えるのは非常に良いです

CircleCI で同じようにデプロイした時はサービスプリンシパルを用意したり、Azure CLI をインストールしたりと手間がかかりましたが、VSTS だとポチポチと設定すれば終わるのが楽ですね。

f:id:shiba-yan:20171014224721p:plain

今回作成した VSTS のビルド定義は上のようになりました。ビルドからデプロイに必要なのは 4 ステップだけというシンプルさです。App Service へのデプロイタスクのおかげですね。

ビルドを行いデプロイを確認

最後にちゃんとビルドを実行して、Web App for Container にデプロイされることを確認しておきました。

f:id:shiba-yan:20171014230859p:plain

VSTS は Docker Image をキャッシュしてくれないようで、アプリケーションのビルドに地味に時間がかかりましたが、それでも 3,4 分で完了しました。aspnetcore-build とかは予め持っておいて欲しいですね。

Azure Portal で staging スロットにデプロイされている Docker Image を確認すると、ちゃんとビルドされたバージョンに切り替わっていました。

f:id:shiba-yan:20171014231743p:plain

ここで ACR 扱いになっていない場合は、ACR の Admin User が有効になっていないか、Web App に ACR の情報が設定されていないかのどちらかです。予め設定しておく必要があります。

おまけ:自動でスワップを行って本番リリース

VSTS には App Service のスロットをスワップするタスクもあるので、これを使えば新しい Docker Image をデプロイした後、自動的にスワップを実行してリリースすることも出来ます。

f:id:shiba-yan:20171014232921p:plain

Source slot を指定してビルドすれば、Production とスワップされて最新のビルドがリリースされます。

Windows 版の App Service では Auto Swap という機能がありましたが、同じことを Web App for Container でも実現できます。癖のあるデプロイ周りですが、便利に使っていきましょう。