-1

I'm trying to build an image that I can use to deploy multiple containers with an angular application. The purpose is to have the container running the command ng server --host ${HOST} --port ${PORT} --disable-host-check and customizing the ENV var with docker run or docker-composes like :

default env var (in the Dockerfile)

docker run -d --name bar -p 10000:4200 -v /path/to/AngularApp:/www me/ngx-admin:dev
will run ng server --host 0.0.0.0 --port 4200 --disable-host-check

custom :

docker run -d --name foo -e HOST='dev.my-domain.fr' -e PORT='4201' -p 10000:4201 -v /path/to/AngularApp:/www me/ngx-admin:dev
will run ng server --host dev.my-domain.fr --port 4201 --disable-host-check

If I understood ENTRYPOINT and CMD correctly, if I use both as "exec form" (JSON Array), the CMD is concatenated behind ENTRYPOINT as params.

Thanks!

Here is my Dockerfile (with the CMD I tried) and the different errors I have :

# base image
FROM node:12

# install chrome for protractor tests
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
RUN apt-get update && apt-get install -yq google-chrome-stable


# set working directory
WORKDIR /www

# add `/www/node_modules/.bin` to $PATH
ENV PATH /www/node_modules/.bin:$PATH

# install and cache app dependencies
COPY package.json /www/package.json
RUN npm install -g @angular/cli@7.3.9
RUN npm install

# add app
COPY . /www

# default env
ENV HOST 0.0.0.0
ENV PORT 4200

EXPOSE ${PORT}

# start www
ENTRYPOINT ["ng", "serve"]
CMD ["--host",  "0.0.0.0", "--port", "4200", "--disable-host-check"]      # WORKS!!
#CMD ["--host",  "${HOST}", "--port", "${PORT}", "--disable-host-check"]    # cf. ERR 1
#CMD ["--host",  "${HOST}", "--port", ${PORT}, "--disable-host-check"]    # cf. ERR 2
#CMD ["--host",  "${HOST}", "--port", "4200", "--disable-host-check"]      # cf. ERR 3

ERR 1

Cannot parse arguments. See below for the reasons.
    Argument port could not be parsed using value "".Valid type(s) is: number

docker inspect

"Path": "ng",<br>
"Args": [
    "serve",<br>
    "--host",<br>
    "${HOST}",<br>
    "--port",<br>
    "${PORT}",<br>
    "--disable-host-check"
],

ERR 2

Error: Project '/bin/sh' does not support the 'serve' target.
  at ServeCommand.initialize (/www/node_modules/@angular/cli/models/architect-command.js:58:19)<br>
  at async ServeCommand.validateAndRun (/www/node_modules/@angular/cli/models/command.js:127:9)<br>
  at async Object.runCommand (/www/node_modules/@angular/cli/models/command-runner.js:178:24)<br>
  at async default_1 (/www/node_modules/@angular/cli/lib/cli/index.js:32:31)

docker inspect

"Path": "ng",<br>
"Args": [
    "serve",<br>
    "/bin/sh",<br>
    "-c",<br>
    "[\"--host\",  \"${HOST}\", \"--port\", ${PORT}, \"--disable-host-check\"]\t\t# ERR 2"
],

ERR 3

rowserslist: caniuse-lite is outdated. Please run next command `npm update`
    getaddrinfo EAI_AGAIN ${HOST}<br>
    Error: getaddrinfo EAI_AGAIN ${HOST}
        at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26)

docker inspect

"Path": "ng",<br>
"Args": [<br>
    "serve",<br>
    "--host",<br>
    "${HOST}",<br>
    "--port",<br>
    "4200",<br>
    "--disable-host-check"
],
Community
  • 1
  • 1
Firlfire
  • 413
  • 1
  • 6
  • 14
  • Does this answer your question? [How can I use a variable inside a Dockerfile CMD?](https://stackoverflow.com/questions/40454470/how-can-i-use-a-variable-inside-a-dockerfile-cmd) – LinPy Nov 13 '19 at 12:48

2 Answers2

4

When you use an execution list, Docker will interpret the given command literally (without variable expansion).

If you want to expand variables, you need to use a shell in your CMD. You can replace your ENTRYPOINT and CMD to use only this:

CMD ["sh", "-c", "ng serve --host ${HOST} --port ${PORT} --disable-host-check"]

Further reading: Dockerfile CMD doesn't understand ENV variables [#5509]

Eduardo Baitello
  • 10,469
  • 7
  • 46
  • 74
2

You don't need environment variables for either of these things.

EXPOSE 4200
CMD ["ng", "serve", "--host", "0.0.0.0", "--port", "4200", "--disable-host-check"]

For the port number, nothing stops you from running multiple containers that have the same internal port number. Generally you'll pick a single port number and make it part of your image's interface. You can run multiple containers off of the image in exactly the way you show, using the image's port number as the second number in the docker run -p option.

docker run -d --name bar -p 10000:4200 me/ngx-admin:dev
docker run -d --name foo -p 10001:4200 me/ngx-admin:dev

For the --host options, the only three things it's really possible to set it to are 0.0.0.0 ("every interface"), 127.0.0.1 ("not accessible from outside this container"), or the IP address the container will eventually have. Since Docker assigns the IP address after you make up the command line, you can't bind to that address, and you want the container to be accessible from outside, so 127.0.0.1 is wrong. That leaves 0.0.0.0 as the only option it's reasonable to use there.


If you really want to use environment variables for this, reviewing the Dockerfile documentation for CMD and ENTRYPOINT is useful. To recap briefly:

  • If you specify both, the CMD is passed as command-line arguments to the ENTRYPOINT.
  • If either or both is a bare string rather than a JSON array, Docker wraps it in sh -c '...' for you. (Also true of RUN.) (If ENTRYPOINT is a bare string this mostly keeps it from considering CMD at all.)
  • If you use the JSON-array form, what gets passed in is exactly what you type; you are responsible for doing any variable expansions you might need.

The simplest way to do this is to use only CMD, and not to use the JSON-array form

CMD ng serve --host "$HOST" --port "$PORT" --disable-host-check

Docker will provide an sh -c wrapper for you. You can't split it between ENTRYPOINT and CMD as you show in the question because only the CMD part will wind up with the sh -c wrapper -- you'll wind up with an unintelligible ng serve sh -c '--host ...' command.

David Maze
  • 130,717
  • 29
  • 175
  • 215