skip to Main Content

I have an ASP.NET Core 7 app that uses SQL Server as a database. I want to dockerize the app and connect to Microsoft SQL Server image to use the database. When I run docker-compose and build the image from my local dockerfile, it works fine, but when I run the docker-compose from a dockerhub image, I get an error. The connection string I use to connect to the database in .Net is:

"Server=sql_server,1433;Database=TicketApplicationDb;User Id=sa;Password=ticketAppPassword77%;MultipleActiveResultSets=true;Encrypt=True;TrustServerCertificate=True"

This is the error I get in the console:

fail: Microsoft.EntityFrameworkCore.Database.Connection[20004] An error occurred using the connection to database ‘TicketApplicationDB’ on server ‘(localdb)mssqllocaldb’.

Dockerfile for .NET Core 7 image:

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 TicketApplication/TicketApplication.csproj .
RUN dotnet restore "./TicketApplication.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "TicketApplication/TicketApplication.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "TicketApplication/TicketApplication.csproj" -c Release -o /app/publish /p:UseAppHost=false

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

docker-compose-dev.yml (it works when using this):

version: "3.9"
services:
  database:
    image: "mcr.microsoft.com/mssql/server:latest"
    container_name: sql_server 
    environment:
      - ACCEPT_EULA=y
      - MSSQL_SA_PASSWORD=ticketAppPassword77%
    restart: always
    ports:
      - "1433:1433"
  web_app:
    build: 
      dockerfile: Dockerfile
      context: .
    container_name: web_app_application
    ports:
      - "8080:80"
    depends_on:
      - database

docker-compose.yml (doesn’t work):

version: "3.9"
services:
  database:
    image: "mcr.microsoft.com/mssql/server:latest"
    container_name: sql_server 
    environment:
      - ACCEPT_EULA=y
      - MSSQL_SA_PASSWORD=ticketAppPassword77%
    restart: always
    ports:
      - "1433:1433"
  web_app:
    image: "borjanob/ticket_app:latest"
    container_name: web_app_application
    ports:
      - "8080:80"
    depends_on:
      - database

I tried removing the 1433 in the connection string and changing the name of the container but nothing changes

2

Answers


  1. When using a docker-compose file your db host must be equal to the db service name try to use : Server=database also try to use the container_name same as the service name

    Login or Signup to reply.
  2. A lot of things going on here. Let’s try to break it down

    I made some changes to your docker-compose.yaml (see below). But even after fixing the stuff I found, it looks like your application is still using/choosing the SQLite database. You need to somehow choose which database you want in each environment. A possible approach is something like this on the ConfigureServices method:

    if (_env.IsDevelopment())
    {
        services.AddSqlLite(_configuration.GetConnectionString("SQLiteConnection"));
    }
    else
    { 
        services.AddPostgresql(_configuration.GetConnectionString("DefaultConnection"));
    }
    

    When running on your IDE it will choose the sqlite database and when running on Docker it will run with the MS SQL database. You control the environment using the ASPNETCORE_ENVIRONMENT environment variable. ASPNETCORE_ENVIRONMENT=Development vs ASPNETCORE_ENVIRONMENT=Production (by default, if not set, it will assume Production).

    Note that, personally, I don’t like this approach very much. You will be testing one type of database locally and then, when deploying, another type of database which might have issues that you didn’t anticipate. My suggestion is to choose one type of database and use that one (at least when starting), unless you make sure to test all supported databases locally.

    Docker compose changes

    version: "3.9"
    services:
      database:
        image: "mcr.microsoft.com/mssql/server:2022-latest"
        user: root
        container_name: sql_server
        hostname: database
        volumes:
          - sql_server_data:/var/opt/mssql/data
          - sql_server_log:/var/opt/mssql/log
          - sql_server_secrets:/var/opt/mssql/secrets
        environment:
          - ACCEPT_EULA=y
          - MSSQL_SA_PASSWORD=e65e2709-9b47-44dc-a0f8-780830ff000f
          - MSQL_PID=Express
        restart: always
        ports:
          - "1433:1433"
      web_app:
        image: "borjanob/ticket_app:latest"
        container_name: web_app_application
        ports:
          - "8080:80"
        depends_on:
          - database
        volumes:
          - ./appsettings.json:/app/appsettings.json
    
    volumes:
      sql_server_data:
      sql_server_log:
      sql_server_secrets:
    

    Create a appsettings.json file next to docker-compose.yaml with the following contents

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
        "DefaultConnection": "Server=database,1433;Database=TicketApplicationDB;User Id=sa;Password=e65e2709-9b47-44dc-a0f8-780830ff000f;",
      }
    }
    

    Explaning the changes:

    • Create volumes for the database, otherwise you will lose all data every time the container is recreated
    • Database image targeting specific MS SQL version for clarity
    • user:root is necessary to use docker volumes on Windows. When deploying on Linux, you can delete this line
    • I kept the 1433:1433 port mapping, but just to be able to check the database with SSMS or SQL Electron. The docker containers communicate using the internal docker network. This means they use the port on the "right side" and the defined hostnames (I used database hostname for the database container).
    • Volume on the application to override the appsettings.json inside the container (the appsettings.json inside the container was the default one I assume you have on your repo or something, but anyway this is a best practice anyway)

    A tip on debugging docker containers: Docker desktop is not great but can be useful when starting with Docker because you can see the files inside the container and use a terminal inside it very easily. As an alternative, you can use the following to commands to help you:

    # Get inside the container terminal. Useful to check the appsettings.json for example
    docker exec -it web_app_application /bin/bash
    
    # Check logs of the container
    docker logs web_app_application
    

    References:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search