Azure Pipelineを使っているとタスクによせたくなるのですが、あんまりそういうのもアレなのでほどほどにというのはもうちょっと言われてもいい気がします。 Dockerはその最たる例です。コマンド3行で済むようなものがDockerタスクを使うといたずらに時間を取られる傾向にあります。
今回はAzure DevOps PipelineでDockerビルドを行って、Azure Container Repositoryにpushする流れを見てみましょう。 Azure DevOps Pipelineを使っていないなら、これでやるメリットはアカウント統合程度で特にない感じです。(アカウント統合も統合できていない感がつよい)
[:contents:]
概要
ビルドマシンは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タスクで行おうとすると、構成を変えていないのに実行ごとに挙動が変わりました。(これで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ができるでしょう。