skip to Main Content

This is my Dockerfile

FROM mcr.microsoft.com/dotnet/nightly/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["MyApi.csproj", "."]
RUN dotnet restore "./MyApi.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "MyApi.csproj" -c Release -o /app/build

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

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

RUN chmod +x ./entrypoint.sh
CMD /bin/bash ./entrypoint.sh

This is docker-compose.yml

version: "3"
services:
    api:
        build: 
          context: .
          dockerfile: Dockerfile
        ports:
            - "8888:80"
        depends_on:
            - db
    db:
        image: "mcr.microsoft.com/mssql/server:2022-latest"
        environment:
            SA_PASSWORD: "P@55w0rd"
            ACCEPT_EULA: "Y"
        ports:
            - "1433:1433"

This is entrypoint.sh

#!/bin/bash

set -e
run_cmd="dotnet run --server.urls http://*:80"

until dotnet ef database update; do
>&2 echo "SQL Server is starting up"
sleep 1
done

>&2 echo "SQL Server is up - executing command"
exec $run_cmd
sleep 10

>&2 echo "Creating Database"
/opt/mssql-tools/bin/sqlcmd -S db -U sa -P P@55w0rd -i create-database.sql

This is create-database.sql

USE master
GO

IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'Demo')
BEGIN
  CREATE DATABASE Demo;
END;
GO

I can run docker compose successfully without error. It creates both containers successfully. I can access to the SQL Server container from SQL Management Studio. The issue is the Demo database is not created automatically as expected. May I know what’s wrong?

I notice these errors in the log after running "docker-compose up".

db_1   | /opt/mssql/bin/permissions_check.sh: line 4: [: : integer expression expected
db_1   | SQL Server 2019 will run as non-root by default.
db_1   | This container is running as user mssql.
db_1   | To learn more visit https://go.microsoft.com/fwlink/?linkid=2099216.
db_1   | /opt/mssql/bin/permissions_check.sh: line 59: [: : integer expression expected
db_1   | 2022-09-21 07:32:01.44 Server      Setup step is copying system data file 'C:templatedatamaster.mdf' to '/var/opt/mssql/data/master.mdf'.
2022-09-21 07:32:01.49 Server      Did not find an existing master data file /var/opt/mssql/data/master.mdf, copying the missing default master and other system database files. If you have moved the database location, but not moved the database files, startup may fail. To repair: shutdown SQL Server, move the master database to configured location, and restart.

2022-09-21 12:35:04.15 spid27s Recovery is complete. This is an informational message only. No user action is required.
2022-09-21 12:35:04.26 spid36s The default language (LCID 0) has been set for engine and full-text services.
2022-09-21 12:35:04.50 spid36s The tempdb database has 8 data file(s).

and

api_1  | Unhandled exception. Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 40 - Could not open a connection to SQL Server: Could not open a connection to SQL Server)
api_1  |    at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
api_1  |    at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
api_1  |    at Microsoft.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity, Boolean withFailover, SqlAuthenticationMethod authType)
api_1  |    at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover)
api_1  |    at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
api_1  |    at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
api_1  |    at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool)
api_1  |    at Microsoft.Data.SqlClient.SqlConnectionFactory.Create

Looks like entrypoint.sh is not executed. Does anyone know why?

Looks like the connection string got issue. This is my connection string is appsettings.json

  "ConnectionStrings": {
    "MyServicesConnection": "Server=localhost,1433;Database=Abc;User Id=sa; Password=P@55w0rd#513;Trusted_Connection=True;MultipleActiveResultSets=true"
  },

As you can see the user id is sa. I manually create this connectionstring based on my docker compose file for my SQL image.

2

Answers


  1. Instead of trying to execute the SQL file in entrypoint.sh, you can pass the file as a volume to the database service.

    volumes:
      - <relative-path-to-create-database.sql>:/docker-entrypoint-initdb.d/init.sql
    

    The compose file would look something like

    version: "3"
    services:
        api:
            build: 
              context: .
              dockerfile: Dockerfile
            ports:
                - "8888:80"
            depends_on:
                - db
        db:
            image: "mcr.microsoft.com/mssql/server:2022-latest"
            environment:
                SA_PASSWORD: "P@55w0rd"
                ACCEPT_EULA: "Y"
            ports:
                - "1433:1433"
            volumes:
              - <relative-path-to-create-database.sql>:/docker-entrypoint-initdb.d/init.sql
    

    This could be your entrypoint.sh, only the last line is changed.

    #!/bin/bash
    
    set -e
    run_cmd="dotnet run --server.urls http://*:80"
    
    until dotnet ef database update; do
    >&2 echo "SQL Server is starting up"
    sleep 1
    done
    
    >&2 echo "SQL Server is up - executing command"
    exec $run_cmd
    sleep 10
    
    exec "$@
    

    Try this Dockerfile

    FROM mcr.microsoft.com/dotnet/nightly/aspnet:6.0 AS base
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443
    
    FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
    WORKDIR /src
    COPY ["MyApi.csproj", "."]
    RUN dotnet restore "./MyApi.csproj"
    COPY . .
    WORKDIR "/src/."
    RUN dotnet build "MyApi.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "MyApi.csproj" -c Release -o /app/publish
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    
    COPY entrypoint.sh /usr/bin/
    RUN chmod +x /usr/bin/entrypoint.sh
    
    ENTRYPOINT ["entrypoint.sh"]
    
    CMD ["dotnet", "MyApi.dll"]
    
    Login or Signup to reply.
  2. Maybe you need to change from depends_on to links.

    Some info on SO: link

    I have an aplication require a redis cache server.

    My Docker-composer.yml looks like:

    version: "3.2"
    services:
      app:
          image: "app:latest"
          build: .
          ports:
            - "${APP_PORT}:80"
          volumes:
            - ./public:/var/www/html
    networks:
            - default
          links:
            - redis4
      redis4:
          image: redis:latest
          ports:
            - '${REDIS_PORT}:6379'
    

    Using volumes free me from using COPY comands to docker and do not require to rebuild it if something is changed.

    Docker file is like:

    FROM php:8.0-apache
    
    ... some dependencies
    
    
    # Supervisord
    RUN apt-get update && apt-get install -y supervisor
    RUN mkdir -p /var/log/supervisor && 
        rm -f /etc/supervisord.conf
    COPY supervisord.conf /etc/
    
    ... others dependencies
    
    COPY run_httpd.sh /run_httpd.sh
    RUN chmod -v +x /run_httpd.sh
    
    ... some commands
    
    # run background apps
    CMD ["/usr/bin/supervisord"]
    

    supervisord.conf:

    [supervisord]
    nodaemon=true
    user=root
    logfile=/var/log/supervisor/supervisor.log
    
    [program:httpd]
    startsecs=0
    autorestart=false
    command=/bin/bash -c "/run_httpd.sh"
    
    [program:crond]
    startsecs=0
    autorestart=true
    command=/bin/bash -c "/usr/sbin/cron"
    

    run_https.sh

    #!/bin/bash
    
    # Make sure we're not confused by old, incompletely-shutdown httpd
    # context after restarting the container.  httpd won't start correctly
    # if it thinks it is already running.
    rm -rf /run/httpd/* /tmp/httpd*
    
    exec /usr/sbin/apachectl -DFOREGROUND
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search