KTOV
KTOV

Reputation: 704

Docker compose not picking up env variables

I have a solution which contains 2 microservices (Product & Review). Each of the 2 API projects have a Dockerfile defined, here is an example of the review dockerfile:

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

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src

ENV ConnectionString:Review="Data Source=db,1433;Initial Catalog=Review;uid=sa;pwd=TesT111t!;Integrated Security=false;MultipleActiveResultSets=True"

COPY ["Review.Api/Review.Api.csproj", "Review.Api/"]
COPY ["Review.Data/Review.Data.csproj", "Review.Data/"]
COPY ["Review.Service/Review.Service.csproj", "Review.Service/"]
RUN dotnet restore "Review.Api/Review.Api.csproj"
COPY . .
WORKDIR "/src/Review.Api"
RUN dotnet build "Review.Api.csproj" -c Release -o /app/build

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

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

As you can see the dockerfile contains an env variable ConnectionString.

I have a breakpoint in the startup of the review api project to inspect what is inside the Configuration, here is what the file looks like:

public class Startup
{
    public IConfiguration Configuration { get; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ReviewDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Review")), ServiceLifetime.Transient);
        services.AddAutoMapper(typeof(FindProductReviews));
        services.AddAutoMapper(typeof(FindReview));
        services.AddAutoMapper(typeof(ReviewController));
        services.AddAutoMapper(typeof(ProductController));
        services.AddMediatR(typeof(FindProductReviews.Handler).Assembly);
        services.AddMediatR(typeof(FindReview.Handler).Assembly);
        services.AddMediatR(typeof(CreateReview.Handler).Assembly);
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapDefaultControllerRoute();
        });
    }
}

My solution has a docker-compose file and when running docker-compose up -d the breakpoint is hit, however when looking inside the Configuration their is no connection string which is defined like the one in the dockerfile.

I feel like im missing something small, I've looked at the documentations and cannot find what I'm missing

Upvotes: 3

Views: 1473

Answers (2)

nunohpinheiro
nunohpinheiro

Reputation: 2269

Application initial configuration

First of all, please confirm that, when your program starts, you are building your configuration such as below (typical setups), in order to bind it with env.variables.

// Defining a configuration that explicitly uses env. variables
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
            ...
            .AddEnvironmentVariables()
            .Build();

or

// The default builder already adds env. variables
public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            ...

Docker

Please, replace ConnectionString:Review by ConnectionString__Review (reference here).

If you want to keep on setting the env.variable in your Dockerfile, you can move it to the last section final, such as:

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENV ConnectionString__Review="Data Source=db,1433;Initial Catalog=Review;uid=sa;pwd=TesT111t!;Integrated Security=false;MultipleActiveResultSets=True"
ENTRYPOINT ["dotnet", "Review.Api.dll"]

However, to enhance decoupling, you may prefer to set the variable in your docker-compose file.

You may also consider using the appsettings JSON files, since they allow much flexibility across environments.

Multiple connection configurations

If your services are able to access shared configurations, but also have their own, then, you can specify proper names to each configuration, to ensure that any mistake happens :)

Upvotes: 1

David Maze
David Maze

Reputation: 159790

You only define the ENV variable in the build image. If you follow the FROM chain, the final image is built FROM base, and COPY --from=build, but the COPY only copies files and not environment variables or other metadata.

Your question title and tags hint at a Compose-based setup. Connection information like the database host name and (especially) credentials need to be configured at deployment time, not part of the image. I'd remove this line from your Dockerfile entirely, and instead include it in your docker-compose.yml:

version: '3.8'
services:
  db: { ... }
  app:
    environment:
      - ConnectionString:Review=Data Source=db,1433;Initial Catalog=Review;uid=sa;pwd=TesT111t!;Integrated Security=false;MultipleActiveResultSets=True
    ...

Upvotes: 0

Related Questions