しばやん雑記

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

CircleCI と Docker を使って App Service on Linux へのデプロイを自動化する

App Service on Linux での Docker 対応は Azure Container Service などに比べて、お手軽なので非常に便利なんですが、Elastic Beanstalk のように Dockerfile を含むリポジトリから自動的にビルドをしてくれないので、必然的に何らかの方法で Docker Image を作成する必要があります。

Windows Server Containers な PaaS がリリースされても同じような流れが必要になると思うので、簡単に必要な流れを確認しておくことにしました。単純に Docker を使った CI/CD に興味があったとも言います。

  1. ASP.NET Core アプリケーションをプリコンパイル
  2. プリコンパイル結果を利用して Docker Image を作成
  3. Docker Hub にプッシュ
  4. App Service on Linux にプッシュした Docker Image を使うように設定

Linux なので CircleCI を使います。この一連の流れを CircleCI で実行する circle.yml を書きます。

必要なファイルや情報をあらかじめ試してから circle.yml を書いてビルドすることにします。

ASP.NET Core のプリコンパイルと Docker Image の作成

Docker を使って ASP.NET Core アプリケーションを実行する方法として、ソースコードをイメージに追加して実行時にコンパイルする方法と、プリコンパイルした結果をイメージに追加する方法の二つがあります。

どう考えてもプリコンパイルした方が起動パフォーマンスとサイズが小さくなるので、プリコンパイルした結果を使って Docker Image を作成することにします。手順は以下の記事を参考にしました。

要するに dotnet publish を実行するとビルド出来るので、その出力を使うというだけです。

用意した Dockerfile は少し変更してあります。主にベースイメージを microsoft/aspnetcore にした点です。

FROM microsoft/aspnetcore:1.1.0

WORKDIR /app
COPY . .

EXPOSE 80

ENTRYPOINT  ["dotnet", "AspNetCoreDocker.dll"]

App Service on Linux ではデフォルトで 80 番を見に行くので EXPOSE しておきます。

この Dockerfile を使ってビルドすると、ローカルでも ASP.NET Core アプリケーションは動作します。

App Service on Linux の Docker Image を変更

App Service on Linux の Custom Docker Image は AppSettings で保持しているシンプルな実装なので、基本的にはここの値を変更すると新しいコンテナが起動するようになっています。

新しい Azure CLI 2.0 には変更用のコマンドが用意されているので、これを使うのがシンプルです。

https://docs.microsoft.com/en-us/cli/azure/appservice/web/config/container#update

Azure CLI を使うためのサービスプリンシパルも 2.0 から簡単に作れるようになっているので便利です。

CI では az login を実行後、az appservice web config container update を実行すれば変更できます。

CircleCI で一連の処理を実行

ドキュメントに Docker を使って Docker Hub にプッシュしたり、Elastic Beanstalk にデプロイする方法が書かれているので、殆どそのまま参考にして App Service on Linux 向けにします。

追加要素としては ASP.NET Core アプリケーションをビルドするために .NET Core をインストールしたり、Azure CLI 2.0 をインストールするぐらいです。

以前に書いたことがありますが、ビルド時間の短縮のために環境変数も設定しておきます。

一通りの処理を書いた circle.yml は以下のようになりました。少し長めです。認証情報は環境変数ですが、Web App 名やリソースグループ名は環境変数にするまでもないと思ったので直接書いてあります。

machine:
  services:
    - docker
  environment:
    DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
    NUGET_XMLDOC_MODE: skip

dependencies:
  pre:
    - pip install azure-cli
    - sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list'
    - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893
    - sudo apt-get update; sudo apt-get install dotnet-dev-1.0.0-preview2.1-003177
  override:
    - dotnet restore

compile:
  pre:
    - rm -rf $(pwd)/publish/app
  override:
    - dotnet publish src/AspNetCoreDocker/project.json -c Release -o $(pwd)/publish/app
    - docker build --rm=false -t shibayan/aspnetcore-demo:$CIRCLE_SHA1 $(pwd)/publish/app

test:
  override:
    - docker run -d -p 8080:80 shibayan/aspnetcore-demo:$CIRCLE_SHA1; sleep 10
    - curl --retry 10 --retry-delay 5 -v http://127.0.0.1:8080

deployment:
  appservice:
    branch: master
    commands:
      - docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
      - docker push shibayan/aspnetcore-demo:$CIRCLE_SHA1
      - az login --service-principal -u "$AZURE_USER" -p $AZURE_PASS --tenant $AZURE_TENANT
      - az appservice web config container update -c "shibayan/aspnetcore-demo:$CIRCLE_SHA1" -n aspnetcore-docker -g LinuxAppServiceRG

CircleCI の設定から環境変数を一通り追加しておきます。Docker の扱いだけ心配ですが、実際に使う場合は Azure Container Registry を使ってプライベートな運用をすると良いです。

Azure Container Registry を使う場合、docker login の部分とイメージ名、そして container update に認証情報を渡す部分を変えるだけで済みます。

気を取り直して、実際に CircleCI の設定から環境変数を追加しておきました。

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

ちょっと追加するのが面倒ですが、Git に含めてしまうのはありえないので仕方ないです。

ビルド結果を確認

準備がこれで出来たので、CircleCI でビルドさせてその結果を確認しておきます。ちゃんと Azure CLI の呼び出しまで成功していることが簡単に確認できました。CircleCI は見やすくて良いですね。

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

ちゃんと Docker Hub にはコミットハッシュでタグが切られています。

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

Web App にアクセスすると、ASP.NET Core アプリケーションが動作しているのがわかります。

本当にイメージが切り替わったかはログを確認するしかないので、この辺り GA までにもっとわかりやすくなって欲しいです。ログは /home/LogFiles/docker に書き出されています。

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

ポータルから Docker の設定も確認しました。ちゃんと CircleCI で作成したイメージが使われていました。

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

CircleCI は最初から Docker が入っているので、簡単にビルドして Docker Hub にプッシュまで行うことが出来てかなり楽でした。環境構築に時間がかかるのが少しネックです。

Windows Server Containers でも基本的には同じ流れになると思うのと、Azure Container Service の Windows 対応は今のところ Swarm のみ使えるらしい*1ので、流れを知るいい勉強になりました。