Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dockerfile unable to execute CMD command (docker for windows)

Unable to execute the CMD command on docker for windows in the dockerfile.

I want to run couple of commands using the CMD, however, unable to run even a single command.

I have tried the follwoing, and nothing works...

1.

CMD "sqlcmd -S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"

2.

RUN ["powershell", "-NoProfile", "-Command", "c:\db\db_scripts\script.ps1"]

3.

CMD ["cmd", "sqlcmd", "-S", "database", "-i", "C:\db\db_scripts\upgradescript.sql", "-U", "sa", "-P", "mypassword"]

4.

ARG arg1=database
ARG arg2=C:\db\db_scripts\upgradescript.sql
ARG arg3=sa
ARG arg4=mypassword!

RUN ["cmd", "-NoProfile", "-Command", "sqlcmd -S $env:arg1 -i $env:arg2 -U $env:arg3 -P $env:arg4"]

5.

RUN powershell.exe  c:\db\db_scripts\script.ps1

6.

ENTRYPOINT ["powershell", "-NoProfile", "-Command", "sqlcmd"]
CMD ["-S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"]

SUPPORTING FILES:

A. Script.ps1 (Used by 2 and 5)

cmd /c "sqlcmd -S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"

B. Dockerfile

# escape=`

FROM microsoft/mssql-server-windows-developer
COPY db\* c:\db\
COPY db_scripts\* c:\db\db_scripts\
ENV attach_dbs="[{'dbName':'ABC','dbFiles':['C:\db\ABC.mdf','C:\db\ABC_Log.ldf']},{'dbName':'XYZ','dbFiles':['C:\db\XYZ.mdf','C:\db\XYZ_Log.ldf']}]"
CMD "sqlcmd -S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"

Please note, I do not need to use "\\" because of the escape character.

OBSERVATIONS

The container starts and disappears after a few seconds.

If I remove the CMD part, the containers work just fine. I can get into the container and can run the above sqlcmd command in cmd shell.

What am I doing wrong, what's missing, any better approach etc. Could anyone give some guidance please? Thanks!

Edit:

Based on Josh's answer, the only way this ENTRYPOINT command is working for me is (sharing so others can benefit or even post better way of doing this)...

ENV arg1 database
ENV arg2 C:\db\db_scripts\upgradescript.sql
ENV arg3 sa
ENV arg4 mypassword
ENTRYPOINT ["powershell sleep(60); sqlcmd"]
CMD ["-S $env:arg1 -i $env:arg2 -U $env:arg3 -P $env:arg4"]
like image 857
wafers Avatar asked Apr 02 '26 14:04

wafers


1 Answers

I think you may be misunderstanding the nature of the CMD versus ENTRYPOINT vs RUN instruction. Both CMD and ENTRYPOINT take effect at container startup/runtime, whereas RUN is a build-time command. Somewhat confusingly, you use RUN to prepare your container image during the docker build process, while the CMD is what gets run in the container.

via the documentation,

The main purpose of a CMD is to provide defaults for an executing container...

Any given container image will only ever have a single CMD instruction.

There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.

If you want to make sure that an executable runs at container start, then you might consider using the ENTRYPOINT instruction; think of ENTRYPOINT as being a command that supplies defaults to the CMD instruction. From the docs:

Dockerfile should specify at least one of CMD or ENTRYPOINT commands. ENTRYPOINT should be defined when using the container as an executable. CMD should be used as a way of defining default arguments for an ENTRYPOINT command or for executing an ad-hoc command in a container. CMD will be overridden when running the container with alternative arguments.

The RUN command is a build-time instruction that you use to prepare your container image with necessary files, configuration, etc.

See this SO question for more on ENTRYPOINT vs CMD.

ED: The case you're looking at, running a SQL script in the container, is a tricky one because the script must not run before the database engine is ready to accept commands. You could run the upgrade script in the ENTRYPOINT instruction as a first step. You may also consider running the SQL upgrade script post-container provisioning, via a docker exec command.

ED2: The example provided:

ENTRYPOINT ["powershell", "-NoProfile", "-Command", "sqlcmd"] CMD ["sqlcmd -S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"]

does not work because it results in what is probably a nonsense command-line instruction. Remember that the CMD supplies parameters to the ENTRYPOINT instruction, so you'll only specify the powershell sqlcmd in the ENTRYPOINT, leaving CMD to supply the parameters (this is untested, OTOMH):

ENTRYPOINT powershell sqlcmd -S database -U sa -P mypassword -i

CMD C:\db\db_scripts\upgradescript.sql

ED 3: By combining the two statements and adding a statement terminator (;) to the ENTRYPOINT, you could then allow the standard SQL container .\Start.ps1 script to run, which enters an infinite loop that prevents the container from stopping immediately (containers run only as long as the executed process in them is running). This guarantees that your startup script is executed, even if the user overrides the CMD instruction at runtime:

ENTRYPOINT powershell "sqlcmd -S database -U sa -P mypassword -i 'C:\db\db_scripts\upgradescript.sql';"

CMD .\Start.ps1

like image 125
Josh E Avatar answered Apr 04 '26 06:04

Josh E