如何在已发布的Docker容器中设置.NET Core 7环境变量?
背景
我有一个用于多站点设备故障排查的ASP.NET Core 7 Web API,希望通过Docker部署简化更新分发。在Visual Studio 2022的launchSettings.json中,以下传递连接字符串作为环境变量的方式运行正常:
"Docker": { "commandName": "Docker", "launchBrowser": true, "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/ScanstationTest", "publishAllPorts": true, "httpPort": 5001, "environmentVariables": { "ReportConnectionString": "Server=1.2.3.4;Initial Catalog=Report;Persist Security Info=True;User Id = user; Password=<its a secret>;Encrypt=False", "SorterAConnectionString": "Server=5.6.7.8\\SQLEXP2012; Database=SorterA;User Id = user; Password=<its a secret>;Encrypt=False" } }
但部署镜像后,尝试Docker Compose中所有设置环境变量的方法均无效。查看Visual Studio创建的调试容器,发现其中没有我设置的环境变量,似乎.NET Core不使用全局环境变量,仅依赖dotnet进程专属变量。
我当前使用Environment.GetEnvironmentVariable("ReportConnectionString")读取变量,是否有其他方式读取全局/用户/进程环境变量?
更新补充
查阅相关文档得知,非Windows系统不支持读取全局环境变量,因此需要找到在Docker镜像中设置dotnet进程环境变量的方法,猜测可能需要脚本或配置文件将全局环境变量复制到进程中,但不清楚这些文件的位置。
当前我的docker-compose.yml内容:
services: reportapi: image: myprivaterepository/reportapi7:202307100307 ports: - "5001:80" restart: always environment: - ReportConnectionString = Server=1.2.3.4;Initial Catalog=Report;Persist Security Info=True;User Id = user; Password=<its a secret>;Encrypt=False - HarmonySorterAConnectionString = Server=5.6.7.8\SQLEXP2012; Database=SorterA;User Id = user; Password=<its a secret>;Encrypt=False
Visual Studio生成的Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base WORKDIR /app EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /src COPY ["ReportAPI7/ReportAPI7.csproj", "ReportAPI7/"] RUN dotnet restore "ReportAPI7/ReportAPI7.csproj" COPY . . WORKDIR "/src/ReportAPI7" RUN dotnet build "ReportAPI7.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "ReportAPI7.csproj" -c Release -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "ReportAPI7.dll"]
解决方案
1. 修复Docker Compose环境变量格式
你当前的docker-compose.yml中环境变量写法有误:变量名与值之间不能有空格,且SQL Server实例名的反斜杠需转义为\\,否则YAML解析会出错。正确写法:
environment: - ReportConnectionString=Server=1.2.3.4;Initial Catalog=Report;Persist Security Info=True;User Id=user; Password=<its a secret>;Encrypt=False - HarmonySorterAConnectionString=Server=5.6.7.8\\SQLEXP2012; Database=SorterA;User Id=user; Password=<its a secret>;Encrypt=False
2. 验证容器环境变量
启动容器后,执行以下命令进入容器查看环境变量是否已正确传递:
docker exec -it <容器ID或名称> printenv
若能看到设置的ReportConnectionString和HarmonySorterAConnectionString,说明变量已成功传递。
3. 推荐使用ASP.NET Core配置系统读取变量
在ASP.NET Core中,更推荐通过内置配置系统读取环境变量,而非直接调用Environment.GetEnvironmentVariable,配置系统会自动读取环境变量,且支持多配置源。示例代码(Program.cs):
var builder = WebApplication.CreateBuilder(args); // 直接读取连接字符串 var reportConnString = builder.Configuration["ReportConnectionString"]; var sorterAConnString = builder.Configuration["HarmonySorterAConnectionString"]; // 注册数据库上下文时直接使用 builder.Services.AddDbContext<ReportDbContext>(options => options.UseSqlServer(builder.Configuration["ReportConnectionString"]));
4. 自定义启动脚本(可选)
若需额外处理变量逻辑,可修改Dockerfile使用shell脚本启动应用:
- 在项目根目录创建
start.sh脚本:
#!/bin/sh # 可在此添加变量处理逻辑 dotnet ReportAPI7.dll
- 修改
Dockerfile最后部分:
FROM base AS final WORKDIR /app COPY --from=publish /app/publish . COPY start.sh . RUN chmod +x start.sh ENTRYPOINT ["./start.sh"]
注:此步骤通常无需执行,Docker设置的环境变量会直接传递给dotnet进程。
内容的提问来源于stack exchange,提问作者RoboDave

