我正在构建要通过Azure Devops构建管道进行部署的.NET Core应用程序。该管道将使用Docker容器构建,测试和部署。
我已经使用以下Dockerfile
为我的应用程序成功构建了第一个docker映像,现在正在尝试在管道中使用它之前先在本地计算机上运行它:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
MAINTAINER yummylumpkins <[email protected]>
WORKDIR /app
COPY . ./
RUN dotnet publish MyAPIApp -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "MyAPIApp.dll"]
在docker容器中运行此映像在本地崩溃,因为我的应用程序使用AzureServiceTokenProvider()
尝试从Azure服务中获取令牌,然后将该令牌用于从Azure Key Vault中获取机密。运行映像的本地docker容器无权访问Azure服务。docker容器错误输出如下所示:
---> Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXX-XXXX-XXXX-XXXX. Exception Message: Tried the following 3 methods to get an access token, but none of them worked.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXX-XXXX-XXXX-XXXX. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. Connection refused
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXX-XXXX-XXXX-XXXX. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Environment variable LOCALAPPDATA not set.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXX-XXXX-XXXX-XXXX. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. /bin/bash: az: No such file or directory
[经过大量研究(并在此处获得了一些积极的反馈),看来授权本地运行的Docker容器的最佳方法是在Microsoft的Azure CLI基础映像之上构建映像,然后使用[C0 ]在构建/运行过程中的某个地方授权本地docker容器。
我已成功从Microsoft(az login --service-principal -u <app-url> -p <password-or-cert> --tenant <tenant>
)提取Azure CLI映像,并可以通过docker pull mcr.microsoft.com/azure-cli
运行它。该容器使用Azure CLI命令行运行,我可以通过bash登录,但就我所知。
下一步是在映像构建过程中将此Azure CLI映像分层到我以前的Dockerfile中,但是我不确定这样做。我尝试了以下方法:
docker run -it mcr.microsoft.com/azure-cli
但是这仍然行不通,该过程仍会导致上述相同错误(我认为是因为添加新的# New base image is now Azure CLI
FROM mcr.microsoft.com/azure-cli
RUN az login -u yummylumpkins -p yummylumpkinspassword
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
MAINTAINER yummylumpkins <[email protected]>
WORKDIR /app
COPY . ./
RUN dotnet publish MyAPIApp -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "MyAPIApp.dll"]
层时登录不会持久。我的问题是,我将如何显式构建Azure CLI映像使用dotnet core
命令进入我的dockerfile /映像构建过程以授权docker容器,保留授权,然后设置命令以具有持久授权运行应用程序(MyAPIApp.dll)?
或者,我是否采用完全错误的方法?预先感谢您的任何反馈。
在此处发布带有答案的更新,以防万一其他人遇到类似问题。我还没有找到其他解决方案,所以我不得不自己做。以下是我的Dockerfile。现在,映像的大小为1GB,因此我肯定需要进行优化,但是我将解释自己的工作:
azure login
[第1步-安装.NET Core SDK生成环境:我们首先使用.NET Core SDK作为基础图像来构建我的应用程序。应该注意的是,我有一个具有一个解决方案和多个项目文件的大型应用程序。 API项目依赖于其他项目。
第2步-构建YummyApp:我们将整个项目结构从本地目录复制到docker映像(/ app)中的工作目录。以防万一有人好奇,我的项目是一个基本的API应用程序。看起来像这样:
#1 Install .NET Core SDK Build Environment
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app
#2 Build YummyApp
COPY . ./
RUN dotnet publish YummyAppAPI -c Release -o out
#3 Install Ubuntu Base Image
FROM ubuntu:latest
MAINTAINER yummylumpkins <[email protected]>
WORKDIR /app
ENV ASPNETCORE_URLS=http://+:80
EXPOSE 80
#4 Install package dependencies & .NET Core SDK
RUN apt-get update \
&& apt-get install apt-transport-https \
&& apt-get update \
&& apt-get install -y curl bash dos2unix wget dpkg \
&& wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \
&& dpkg -i packages-microsoft-prod.deb \
&& apt-get install -y software-properties-common \
&& apt-get update \
&& add-apt-repository universe \
&& apt-get update \
&& apt-get install apt-transport-https \
&& apt-get update \
&& apt-get install -y dotnet-sdk-3.1 \
&& apt-get update \
&& rm packages-microsoft-prod.deb
#5 Copy project files from earlier SDK build
COPY --from=build-env /app/out .
#6 Install Azure CLI for AppAuthorization
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash
#7 Login to Azure Services and run application
COPY entrypoint.sh ./
RUN dos2unix entrypoint.sh && chmod +x entrypoint.sh
CMD ["/app/entrypoint.sh"]
复制完所有内容后,我们将构建/发布应用程序的Release配置。
第3步-安装Ubuntu基本映像:我们使用Ubuntu启动一个新层。最初,我尝试使用Alpine Linux,但发现几乎不必在其中进行Azure命令行操作而无需做一些真正的变通办法,因此我选择了Ubuntu,以简化安装。
[第4步-安装程序包依赖项和.NET Core SDK:在Ubuntu层中,我们设置工作目录并安装/更新一堆库,包括.NET Core SDK。应该注意的是,我需要为以后必须运行的shell脚本文件安装[YummyApp]
|-YummyAppDataAccess
|YummyAppDataAccess.csproj
|-YummyAppInfrastructure
|YummyAppInfrastructure.csproj
|-YummyAppAPI
|-YummyAppAPI.csproj
|-YummyAppServices
|-YummyAppServices.csproj
|-YummyApp.sln
。 。我待会再解释。
注意:我最初只是尝试安装.NET Core Runtime,因为它更轻巧,并且可以将映像降低到大约700MB(从1GB开始),但是由于某种原因,当我尝试在文件末尾运行应用程序时(步骤7)我收到一条错误消息,提示未找到任何运行时。所以我回到了SDK。
第5步-从早期的SDK Build复制项目文件:为了节省空间,我将构建的项目文件从第一个“ build image”复制到了Ubuntu层,以节省一些空间(约1GB)。 >
[步骤6-安装Azure CLI:
为了授权我的应用程序从Azure服务中获取令牌,通常我使用dos2unix
。该程序包提供了一种称为Microsoft.Azure.Services.AppAuthentication
的方法,该方法(通过我的IDE)授权我的应用程序连接到Azure服务,以获取令牌,然后该令牌用于访问Azure密钥保管库。 这整个问题开始是因为我的应用程序无法从Docker容器中执行此操作,因为Azure无法识别来自容器本身的请求。因此,要解决此问题,在启动应用程序之前,我们需要通过Azure CLI在容器内的AzureServiceTokenProvider()
登录。
[步骤7-登录到Azure服务并运行应用程序:
现在是放映时间。我在这里要解决两个不同的问题。我必须弄清楚当该容器启动时如何执行az login
和az login
。但是Dockerfile只允许在运行时执行一个dotnet YummyAppAPI.dll
或ENTRYPOINT
,因此我找到了一种解决方法。通过制作一个shell脚本文件(entrypoint.sh),我能够将两个命令都放入该文件中,然后执行该文件。 [设置完成后,CMD
出现错误,内容如下:entrypoint.sh
。我发现我必须使用entrypoint.sh: executable file not found in $PATH
更改此文件的权限,因为否则,我的Docker容器将无法访问它。这使文件可见,但是文件仍然无法执行。我收到另一个错误:chmod
经过一些深入的研究,结果表明,当您尝试在基于Linux的系统上使用Windows中创建的.sh文件时,会发生此问题。因此,我必须安装Standard_init_linux.go:211: exec user process caused “no such file or directory”
才能将此文件转换为与Linux兼容的文件。我还必须确保文件格式正确。对于任何好奇的人,这就是我的dos2unix
样子:
登录名和密码是硬编码的。 。 。我知道这是一个不好的做法(实际上,这很糟糕),但是,这对我的本地计算机来说是[[only,并且永远都看不到产品。下一步将使用服务原理登录名引入环境变量。由于此部署最终将在Azure Devops管道中进行,因此我可以将那些ENV变量直接注入devops管道YAML中,以便所有这些事情都无需我输入凭据即可完成。它们将直接从存储它们的密钥库中来。最后,此容器的大小很大(1GB),如果要定期更新/构建,则必须对其进行优化。我将继续致力于这一工作,但是我愿意就如何最好地做到这一点提出建议。entrypoint.sh
注意:
再次感谢大家。