skip to Main Content

UPDATE
It appears the problem is specifically related to the RUN command in the Dockerfile. If I remove it, the build works fine and the environment variables are clearly being picked up since the password gets applied and I can connect using it. Not sure why the login fails in the RUN command, I’ve seen many examples using similar code.

I’m working on a very basic docker compose file to setup a dev environment for an app and I started with the database server, which is MS SQL. Here’s what the docker-compose.yml file looks like:

version: '3.8'

services:
  mssql:
    build:
      context: .
      dockerfile: docker/mssql/Dockerfile
    ports:
      - '1434:1433'
    environment:
      ACCEPT_EULA: "Y"
      SA_PASSWORD: "YourStrong!Passw0rd"
    volumes:
      - mssql-data:/var/opt/mssql

As you can see from my dockerfile path, that’s in a sub-path and looks like this:

FROM mcr.microsoft.com/mssql/server:2019-latest

COPY ./docker/mssql/TESTDB.bak /var/opt/mssql/backup/TESTDB.bak

RUN ( /opt/mssql/bin/sqlservr --accept-eula & ) | grep -q "Service Broker manager has started" && /opt/mssql-tools/bin/sqlcmd -S localhost,1433 -U SA -P "YourStrong!Passw0rd" -Q 'RESTORE DATABASE TESTDB FROM DISK = "/var/opt/mssql/backup/TESTDB.bak" WITH MOVE "TESTDB_Data" to "/var/opt/mssql/data/TESTDB.mdf", MOVE "TESTDB_Log" to "/var/opt/mssql/data/TESTDB_log.ldf"'

(Yes, I realize that the password in the RUN command is redundant, I had tried to use a variable there earlier and since it wasn’t working I hard coded it.)

When I run docker-compose up -d, I always get this error: Login failed for user ‘SA’

I wasted way too much time thinking there was actually something wrong with the password until I realized that if I add the environment variables directly in the Dockerfile, it works. So in my Dockerfile, above the RUN command, I can just do this:

ENV ACCEPT_EULA=Y
ENV SA_PASSWORD=YourStrong!Passw0rd

So I concluded that my environment variables simply aren’t being read. I tried with quotes, without quotes, using env_file instead, nothing seems to work. I also tried the following format, no luck:

environment
  - ACCEPT_EULA=Y
  - SA_PASSWORD=YourStrong!Passw0rd

I also tried using MSSQL_SA_PASSWORD instead of SA_PASSWORD, as well as having both in there. I assumed that was unlikely to be the problem though given SA_PASSWORD works fine. Lastly, I tried using a 2017 image in case it was image specific, that didn’t work either.

I’m assuming it must be something silly I’m missing. I saw a lot of talk of .env in the root being different, but if I understood correctly people go wrong with that when they try to use environment values in their docker-compose.yml file, which is not what I’m doing here. So I’m about ready to lose my mind on this as it seems like such a simple, basic thing.

4

Answers


  1. In your docker-compose.yml, have you tried:

      - ACCEPT_EULA=Y
      - SA_PASSWORD=YourStrong!Passw0rd
    
    Login or Signup to reply.
  2. I think you’re confusing the ENV statement in Dockerfile with the environment variables set when running an image. The key is still in the details of the docs. It notes that they are the same as saying docker run -e, not docker build.

    What’s causing more confusion, when you use ENV, you are setting defaults for when the image runs later:

    https://docs.docker.com/engine/reference/builder/#env

    If you haven’t yet, I very much recommend getting familiar with building and running your image with docker run and docker build before moving on to compose, it’s much less confusing that way.

    Login or Signup to reply.
  3. Both responses above are fine, just a few more things:

    SA_PASSWORD is deprecated instead use MSSQL_SA_PASSWORD

    It is always nice to define .env files with the variables for instance:

    sapassword.env

    MSSQL_SA_PASSWORD=YourStrong!Passw0rd
    

    sqlserver.env

    ACCEPT_EULA=Y
    MSSQL_DATA_DIR=/var/opt/sqlserver/data
    MSSQL_LOG_DIR=/var/opt/sqlserver/log
    MSSQL_BACKUP_DIR=/var/opt/sqlserver/backup
    

    And in docker-compose.yml instance the env files the following way:

    environment:
          - sqlserver.env
          - sapassword.env
    
    Login or Signup to reply.
  4. The issue with your build here stems from a confusion between the build-time and run-time environment variables: with the environment or env_file properties you specify the environment variables to be set for the service container.

    But the RUN command in your Dockerfile is executed at the build-time of the image! To pass variables when building a new image you should use build args instead, as you already mentioned in your comment:

    services:
      mssql:
        build:
          context: .
          dockerfile: docker/mssql/Dockerfile
          args:
            SA_PASSWORD: "YourStrong!Passw0rd"
        # ...
    

    With this you can use the SA_PASSWORD as a build ARG:

    FROM mcr.microsoft.com/mssql/server:2019-latest
    
    COPY ./docker/mssql/TESTDB.bak /var/opt/mssql/backup/TESTDB.bak
    
    ARG SA_PASSWORD
    RUN ( /opt/mssql/bin/sqlservr --accept-eula & ) | grep -q "Service Broker manager has started" && /opt/mssql-tools/bin/sqlcmd -S localhost,1433 -U SA -P "$SA_PASSWORD" -Q 'RESTORE DATABASE TESTDB FROM DISK = "/var/opt/mssql/backup/TESTDB.bak" WITH MOVE "TESTDB_Data" to "/var/opt/mssql/data/TESTDB.mdf", MOVE "TESTDB_Log" to "/var/opt/mssql/data/TESTDB_log.ldf"'
    

    If you want to move the actual password to a .env file you can use variable substitution in the compose.yml:

    services:
      mssql:
        build:
          # ...
          args:
            SA_PASSWORD: "$SA_PASSWORD"
        # ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search