【问题标题】:Using ENV var in CMD in the Dockerfile在 Dockerfile 的 CMD 中使用 ENV var
【发布时间】:2020-03-09 04:46:57
【问题描述】:

我正在尝试构建一个图像,我可以使用它来部署具有 Angular 应用程序的多个容器。 目的是让容器运行命令ng server --host ${HOST} --port ${PORT} --disable-host-check 并使用docker rundocker-composes 自定义ENV var,例如:

默认环境变量(在 Dockerfile 中)

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

自定义:

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
将运行ng server --host dev.my-domain.fr --port 4201 --disable-host-check

如果我正确理解了ENTRYPOINTCMD,如果我将两者都用作“执行形式”(JSON 数组),则CMD 将连接在ENTRYPOINT 后面作为参数。

谢谢!

这是我的 Dockerfile(使用我尝试过的 CMD)以及我遇到的不同错误:

# 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

错误 1

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

码头检查

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

错误 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)

码头检查

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

错误 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)

码头检查

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

【问题讨论】:

标签: docker environment-variables dockerfile


【解决方案1】:

当你使用执行列表时,Docker 会按字面意思解释给定的命令(没有变量扩展)。

如果你想扩展变量,你需要在你的CMD 中使用一个shell。您可以替换您的 ENTRYPOINTCMD 以仅使用此:

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

延伸阅读:Dockerfile CMD doesn't understand ENV variables [#5509]

【讨论】:

    【解决方案2】:

    这些东西你都不需要环境变量。

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

    对于端口号,没有什么可以阻止您运行具有相同内部端口号的多个容器。通常,您会选择一个端口号并将其作为图像界面的一部分。您可以完全按照您显示的方式从图像中运行多个容器,使用图像的端口号作为docker run -p 选项中的第二个数字。

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

    对于--host 选项,真正可以将其设置为的三件事是 0.0.0.0(“每个接口”)、127.0.0.1(“无法从该容器外部访问”)或 IP 地址容器最终会有。由于Docker是在你编好命令行后分配IP地址的,所以不能绑定到那个地址,又希望容器可以从外部访问,所以127.0.0.1是错误的。这使得 0.0.0.0 成为唯一可以合理使用的选项。


    如果您真的想为此使用环境变量,查看CMDENTRYPOINT 的Dockerfile 文档很有用。简要回顾一下:

    • 如果同时指定两者,CMD 将作为命令行参数传递给 ENTRYPOINT
    • 如果其中一个或两个都是裸字符串而不是 JSON 数组,Docker 会为您将其包装在 sh -c '...' 中。 (RUN 也是如此。)(如果 ENTRYPOINT 是一个裸字符串,这主要是让它根本不会考虑 CMD。)
    • 如果您使用 JSON 数组形式,传入的是 确切您输入的内容;您负责进行可能需要的任何变量扩展。

    最简单的方法是只使用CMD,而不是使用 JSON 数组形式

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

    Docker 将为您提供一个 sh -c 包装器。您不能在问题中显示ENTRYPOINTCMD 之间将其拆分,因为只有CMD 部分将与sh -c 包装器一起结束——您将得到一个难以理解的ng serve sh -c '--host ...' 命令.

    【讨论】:

      猜你喜欢
      • 2021-08-09
      • 1970-01-01
      • 2022-01-20
      • 2022-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多