NLog 配置从 docker 运行 参数设置连接字符串

NLog config set connection string from docker run argument

我有一个 .NET Core api 项目需要 运行 在 Docker 容器中。该项目使用 NLog 将数据记录到数据库中。我想在 运行 连接容器时在 nlog.config 文件中设置连接字符串 属性。

该应用程序将部署到不同的客户端,并将使用它们的数据库进行日志记录。

这就是我尝试在 nlog.config 文件中配置连接字符串的方式:

...
  <target name="database" xsi:type="Database">
      <connectionString>'${environment:logs_connection_string}'</connectionString>
      <dbProvider>MySql.Data.MySqlClient.MySqlConnection, MySql.Data</dbProvider>
...

这是我的Docker文件:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["Service/Service.csproj", "Service/"]
COPY ["Extensions/CustomExtensions.csproj", "Extensions/"]
RUN dotnet restore "Service/Service.csproj"
COPY . .
WORKDIR "/src/Service"
RUN dotnet build "Service.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Service.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Service.dll"]
ARG log_connection
ENV logs_connection_string=$log_connection

这些是我在 运行 上传递连接字符串的一些尝试:

我没有太多的使用经验Docker,所以这种方法甚至可能行不通。我愿意接受任何建议。

ARGENV 都不是您想要完成的。

您需要的是某种入口点脚本,它将读取您在 运行 命令中设置的环境变量(在您的示例中为 log_connectionlog_connection_string),做出反应错误或将其设置为默认值(如果未设置),最后编辑 nlog.config 并将 <connectionString> 的值设置为变量的值,最后 运行s dotnet Service.dll .

例如,您可以像这样在 nlog.config 中设置您的连接:

<connectionString>log_connection_string</connectionString>

然后创建文件run.ps1,内容如下:

#!/opt/microsoft/powershell/7/pwsh
if (-not (Test-Path env:log_connection_string)) { $env:log_connection_string = 'default value for log_connection_string' }
((Get-Content -Path path\to\nlog.config -Raw) -replace 'log_connection_string',$Env:log_connection_string) | Set-Content -Path path\to\nlog.config
dotnet Service.dll

在映像构建期间将其复制到目录 /app

并将 Dockerfile 的最后三行替换为:

ENTRYPOINT ["./run.ps1"]

编辑: 要在基础映像中安装 Powershell Core,请在 Dockerfile 中使用以下命令(最好在 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base 下方):

RUN curl https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb --output packages-microsoft-prod.deb --silent && \
dpkg -i packages-microsoft-prod.deb && \
rm packages-microsoft-prod.deb && \
apt-get update && \
apt-get install -y powershell && \
apt-get clean

您还需要使 run.ps1 可执行或将入口点更改为:

ENTRYPOINT ["/opt/microsoft/powershell/7/pwsh", "-Command","./run.ps1`enter code here`"] 

或者,您可以在 Bash 中使用等效脚本(我们将其命名为 run.sh):

#!/bin/bash
[[ -z "$log_connection_string" ]] && export log_connection_string="default value for log_connection_string"
sed -i 's/log_connection_string/'"$log_connection_string"'/' path\to\nlog.config
dotnet Service.dll

入口点应设置为:

ENTRYPOINT ["/bin/bash", "-c", "./run.sh"]

最后说明:没有法律禁止人们对环境变量使用小写名称,但是将其全部大写是一种普遍接受的惯例,例如。 LOG_CONNECTION_STRING 而不是 log_connection_string.

@Konrad Botor 的回答是可行的,因为他提供了一个非常好的答案,但对于我的用例,有一种更简单的方法。 @RolfKristensen 的评论为我指明了正确的方向。

ASP.NET 核心应用程序默认加载环境的变量(请参阅 SO 上的此答案:Using AddEnvironmentVariables in .net core 3.1 app)。 运行上传图像时传递的环境变量,可以在应用程序中使用以下方式访问:

Environment.GetEnvironmentVariable("env_name").

如@RolfKristensen 所述,NLog 知道如何加载环境变量。 nlog.config 文件中的连接字符串标记如下所示:

<connectionString>${environment:CONNECTION_STRING}</connectionString>

运行 命令如下所示。

docker run -itd -p 1234:80 --name test -e CONNECTION_STRING="..." app

将从 运行 处传递的变量正确加载连接字符串。

为了传递敏感数据,这种方法存在安全风险,因为 docker 运行 命令将保留在命令历史记录中。但是有人可以使用 composer 文件或将主机的环境变量传递给 运行 命令来降低风险。

编辑

我使用Visual Studio生成的Dockerfile。

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["Service/Service.csproj", "Service/"]
COPY ["Extensions/CustomExtensions.csproj", "Extensions/"]
RUN dotnet restore "Service/Service.csproj"
COPY . .
WORKDIR "/src/Service"
RUN dotnet build "Service.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Service.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Service.dll"]