Azure Pipeline を使っているとタスクによせたくなるのですが、あんまりそういうのもアレなのでほどほどにというのはもうちょっと言われてもいい気がします。 Docker はその最たる例で コマンドで3行で済むようなものがDockerタスクを使うといたずらに時間を取られる傾向にあります。
今回は Azure DevOps Pipeline でDocker ビルドを行って、Azure Container Repository に push する流れを見てみましょう。 Azure DevOps Pipeline を使っていないなら、これでやるメリットはアカウント統合程度で特にない感じです。(アカウント統合も統合できていない感がつよい)
目次
[:contents:]
TL;DR
ビルドマシンは hosted が楽でよい。 docker build は、dockerタスクではなく docker コマンドでやるほうがいい docker push は、docker タスクを使って認証を透過的に行おう。
何をDockerで動かすの
ASP.NET Core 2.2 を対象にdockerで動かしてみましょう。 例えばAzure Container Instance で動かすのもいいのです。 しかし、container じゃなくてもAzure Web Apps for Linux にデプロイすれば たいがいはいいのでWebアプリのdocker展開はポータビリティをどこまで担保したいか、どう動かしたいかの相談なのでほどほどに。
Azure DevOps Pipeline の Docker タスク
Docker Module は、0 と 1と2があります。
0 を利用するのがおすすめです。
1 は妙な挙動をして不安定なためお勧めしません。
2 は、コンセプトが変わっててACRで使うならあんまりいらなさそう。というか、余計な手間が増えてて微妙。
ローカルでの docker build
なにはともあれlocal で通しておきましょう。 これがCIで通るようにします。
適当にこんな構成とします。 ASPNETCOREにcsprojの名前を、YOUR_PROJECT_DIR にプロジェクトのフォルダ名を指定しておきます。
. └ src └ YOUR_PROJECT_DIR ├ Dockerfile └ ASPNETCORE.csproj
Dockerfileはこのような感じになるかと思います。
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build WORKDIR /src/YOUR_PROJECT_DIR COPY ["YOUR_PROJECT_DIR/ASPNETCORE.csproj", "ASPNETCORE.csproj"] RUN dotnet restore "ASPNETCORE.csproj" WORKDIR /src COPY . . WORKDIR /src/YOUR_PROJECT_DIR ARG conf="Debug" RUN dotnet build "ASPNETCORE.csproj" -c $conf -o /app RUN dotnet publish "ASPNETCORE.csproj" -c $conf -o /app FROM base AS final WORKDIR /app COPY --from=build /app . ENTRYPOINT ["dotnet", "ASPNETCORE.dll"]
あとは実行時に ASPNETCORE_ENVIRONMENT
を Development | Staging | Production で指定すれば挙動が切り替わるのでokですね。
docker build
特にWindows系のhosted|private agent がそうですが、build をする場合、Dockerタスクではなく docker コマンドをたたくほうが安定します。 dockerタスクで行おうとすると、docker build中にイメージが見つかったり見つからなかったり、COPYが実行できたりできなかったり構成を変えていないのに実行ごとに挙動が変わりました。(これでDockerfile や設定がおかしいかと思って試行錯誤で数時間消費した)
variables: BuildConfiguration: Debug DockerImageName: ASPNETCORE DockerFile: YOUR_PROJECT_DIR/Dockerfile steps: - bash: 'docker build -t youraspnetcoreregistry.azurecr.io/$(DockerImageName):$(Build.SourceVersion)_$(Build.BuildId) -t $(Registry).azurecr.io/$(DockerImageName):latest -f YOUR_PROJECT_DIR/Dockerfile .' displayName: 'docker build'
これでビルドが実行できます。 ACRに挙げるにあたって、ビルドごとにバージョンが一意に特定できる必要があるので、git hash + build id で毎ビルドで一意にしています。
docker push
push は簡単です。 local でいうところの、docker login しておいて docker push です。 ただし、CIでやるに伴ってレジストリのログインを認証情報を出さずに透過的に行いたいでしょう。
docker@0
タスク を使うと ACRへの認証情報を事前に解決しておけるので便利です。
先ほど docker build で指定した tag を指定してpush してあげましょう。
この時、ACRを対象にしている場合、ACRのアドレス "youraspnetcoreregistry.azurecr.io"
部分は自動的に解決されるため、tagで指定する必要がありません。docker build でyouraspnetcoreregistry.azurecr.io/$(DockerImageName):$(Build.SourceVersion)_$(Build.BuildId)
と指定した場合、$(DockerImageName):$(Build.SourceVersion)_$(Build.BuildId)
でokです。(.... なんと余計なことを)
- task: Docker@0 displayName: 'Push an image' inputs: azureSubscription: YOUR_SUBSCRIPTION azureContainerRegistry: '{"loginServer":"youraspnetcoreregistry.azurecr.io", "id" : "/subscriptions/abcdefg-1234-abcd-56789ghijklmn/resourceGroups/AWESOME-RESOURCE/providers/Microsoft.ContainerRegistry/registries/youraspnetcoreregistry"}' action: 'Push an image' imageName: '$(DockerImageName):$(Build.SourceVersion)_$(Build.BuildId)' includeLatestTag: true
これで無事にdocker build -> push ができるでしょう。