Shalabh Negi
Shalabh Negi

Reputation: 662

Can we pass ARG to CMD in DockerFile?

How can i pass ENV variable while using docker run command and also Can you tell me if i'm passing the ENV variable correctly in CMD?

Main thing which i want to achieve is that I have uploaded my code on gitlab and creating a docker image so that i can create my web application container. In that code we have a file Core.js which takes 2 arguments 1. Organization name and Port number. For that i need to run node Core.js Org1 1401, node Core.js Org2 1402, etc. There is a shell script which is pulled in via docker file i need to give name of that file as an argument so that it should use same docker image but i can create multiple container for different organization

FROM alpine

LABEL MAINTAINER "CoE"
WORKDIR /

ARG proxy
ARG username
ARG pswd
ENV ORG_SCRIPT

RUN export http_proxy=$proxy                                                                    && \
    export https_proxy=$proxy                                                                   && \
    git clone -b master https://$username:[email protected]/dlr_ui         && \
    npm install                     

 EXPOSE 1401 1402 1403 1404 1405 1406 1407 1408
 WORKDIR /applications/package/ui_servers 
CMD ["sh","./${ORG_SCRIPT}"]    // It is not getting the script name over here. Can you tell if it is correct way or not. OR i should do:
CMD ["sh","./$ORG_SCRIPT"]

I'm getting error for both. Value is not coming to that variable.

Buid:
 docker build --no-cache --build-arg proxy=$http_proxy --build-arg username=dfadf--build-arg pswd=dsfadsf --build-arg -t uinodetest .


RUN:
docker run  -d -it -p 1401:1401 -e ORG_SCRIPT runOrg1.sh --name="Org1_UI" uinodetest

OR Other method i'm using is

FROM alpine

LABEL MAINTAINER "CoE"
WORKDIR /

ARG proxy
ARG username
ARG pswd
ENV ORG_NAME
ENV ORG_PORT

RUN export http_proxy=$proxy                                                                    && \
    export https_proxy=$proxy                                                                   && \
    git clone -b master https://$username:[email protected]/dlr_ui         && \
    npm install                     

 EXPOSE 1401 1402 1403 1404 1405 1406 1407 1408
 WORKDIR /applications/package/ui_servers 
CMD ["node","Core.js","$ORG_NAME","ORG_PORT"]



Buid:
 docker build --no-cache --build-arg proxy=$http_proxy --build-arg username=dfadf--build-arg pswd=dsfadsf --build-arg -t uinodetest .


RUN:
docker run  -d -it -p 1401:1401 -e ORG_NAME ORG1 -r ORG_PORT 1401 --name="Org1_UI" uinodetest

Tell me if i'm missing something or my syntax is wrong.

Upvotes: 2

Views: 13146

Answers (3)

Mostafa Hussein
Mostafa Hussein

Reputation: 11940

I think a better approach would be using ENTRYPOINT and then add CMD to execute help or something similar

ENTRYPOINT ["node","Core.js"]
CMD ["--help"]

Then when you start the container pass the $ORG_NAME and $ORG_PORT to it. In this case docker will keep your entry point and overrides the default CMD which is --help in this case to the other options that you have passed and make sure to keep the command between quotes to be treated as single command

So in this case you will run the container as the following:

docker run -it --name my_container myimage:latest "$ORG_NAME $ORG_PORT"

Same scenario can be done with docker compose.

Upvotes: 0

David Maze
David Maze

Reputation: 158898

There's a couple of moving parts here.

For the things that need to be configurable, it's probably easiest to refer to them using process.env in Node and not pass them as command-line arguments. In your second example, refer to process.env.ORG_NAME, for example.

Some things don't need to be configurable. In your second example, you can pick a fixed TCP port for your service; even if you use the Express default port 3000, you can docker run -p 1401:3000, docker run -p 1402:3000, etc. to assign different ports to different containers running the same image. In your first example, you're trying to use an environment variable to specify the entire command; don't bother doing this and just use the standard Docker command line.

That would give you a routine Dockerfile like

FROM node:alpine
# Generally don't "git clone" in a Dockerfile.
WORKDIR /dlr_ui
COPY package.json package-lock.json ./
RUN npm install
COPY . ./
EXPOSE 3000
CMD ["node", "Core.js"]

And you don't need to worry about this particular problem at all. You'd run it like

docker run -d -p 1401:3000 -e ORG_NAME=ORG1 --name="Org1_UI" uinodetest

There are two syntaxes for the CMD, ENTRYPOINT, and RUN commands. The form that looks like a JSON array (but isn't actually) directly runs the command that's given, without invoking any kind of shell or interpreter or variable expansion. In your second example the script will be invoked with the literal strings $ORG_NAME and ORG_PORT as parameters. If you just write something that looks like a command, not using the JSONish syntax, it gets automatically wrapped in sh -c.

I would expect, syntactically, that the first example does what you want (but see @BMitch's answer); but it would be simpler to just pass the command directly

docker run -d -p 1401:1401 --name="Org1_UI" uinodetest ./runOrg1.sh

Upvotes: 1

BMitch
BMitch

Reputation: 263627

Docker will pass the environment variable to your container, but you need a shell to parse the ${var} syntax into that variable. You got close with:

CMD ["sh","./${ORG_SCRIPT}"]

I suspect the reason this didn't work is because the arg passed to sh hasn't been expanded yet, and sh isn't processing that arg, it's just running it. Instead you need:

CMD ["sh","-c","./${ORG_SCRIPT}"]

That is almost exactly the same as the string/shell syntax, which I'd recommend instead:

CMD ./${ORG_SCRIPT}

Upvotes: 4

Related Questions