Docker构建+私有NPM(+私有Docker Hub)

26
我有一个在Docker容器中运行的应用程序。它需要来自公司私有NPM注册表(Sinopia)的某些私有模块,并且访问这些模块需要用户身份验证。 Dockerfile 是 FROM iojs:latest
我尝试过:
1) 在项目根目录创建一个 .npmrc 文件,但没有效果,npm 似乎忽略了它。 2) 使用环境变量 NPM_CONFIG_REGISTRYNPM_CONFIG_USER 等等,但是用户没有登录。
基本上,我似乎没有办法在 docker build 过程中验证用户。我希望有人已经遇到过这个问题(似乎是一个相当明显的问题),并拥有解决此问题的好方法。
(作为锦上添花,我正在使用 Docker Hub 上的自动构建(在推送时触发),以便我们的服务器可以访问具有预构建镜像的私有Docker注册表。)
有没有好的方式: 1) 在构建时注入 NPM 凭据(这样我就不必将凭据提交到我的 Dockerfile) 2) 通过其他方式完成这项工作

1
你解决过这个问题吗?我也遇到了同样的问题 :( - James Hush
是的,我刚刚发布了我的答案! - GTF
7个回答

34

我发现了一个相对优雅的解决方案,可以为你的node.js / io.js容器(you/iojs)创建基础镜像:

  1. 使用要用于docker的用户登录到您的私有npm注册表
  2. 复制生成的.npmrc文件

例如:.npmrc

registry=https://npm.mydomain.com/
username=dockerUser
email=docker@mydomain.com
strict-ssl=false
always-auth=true
//npm.mydomain.com/:_authToken="someAuthToken"
  1. 创建一个Dockerfile,并适当地复制.npmrc文件。

这是我的Dockerfile(基于iojs:onbuild):

FROM iojs:2.2.1

MAINTAINER YourSelf

# Exclude the NPM cache from the image
VOLUME /root/.npm

# Create the app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Copy npm config
COPY .npmrc /root/.npmrc

# Install app
ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
ONBUILD COPY . /usr/src/app

# Run
CMD [ "npm", "start" ]

让你的所有node.js/io.js容器都以FROM you/iojs为基础,然后你就可以开始了。

我今天最终也做了类似的事情。这是所有项目中构建时我需要的唯一秘密密钥 :(。我认为目前这是最好的解决方案,感谢您发布您的答案! - James Hush
这是关于私有npm仓库和Docker的官方文档:https://docs.npmjs.com/private-modules/docker-and-private-modules - magohamote
注意,MAINTAINER已被弃用,请使用LABEL代替。 - Paul T. Rawkeen

18

2020年,我们可以使用BuildKit。您不再需要通过COPYENV传递机密信息,因为这不安全。

示例Dockerfile

# syntax=docker/dockerfile:experimental
FROM node:13-alpine

WORKDIR /app

COPY package.json yarn.lock ./

RUN --mount=type=ssh --mount=type=secret,id=npmrc,dst=$HOME/.npmrc \
  yarn install --production --ignore-optional --frozen-lockfile

# More stuff...

那么,你的构建命令可以是这样的:

docker build --no-cache --progress=plain --secret id=npmrc,src=/path-to/.npmrc .

了解更多详情,请查看:https://docs.docker.com/develop/develop-images/build_enhancements/#new-docker-build-secret-information


您正在使用root用户,安全建议是使用USER node用户。然而这个方法已经失效,请参考https://github.com/docker/for-mac/issues/3668。目前我还没有解决方案。 - Paul S
安全规则是在Dockerfile中使用root用户构建镜像,并在最后设置USER node。这样,运行时用户(node)将无法对文件进行写操作,只能进行读操作。 - undefined

14

对于那些通过Google找到本文并仍在寻找另一种不涉及在Docker镜像和容器中留下私有npm token的替代方法的人:

我们能够通过在docker build之前进行npm install(这样可以让您在图像\容器外部拥有.npmrc)来使此方法有效。一旦私有模块已经在本地安装,您可以将文件复制到镜像中作为构建的一部分:

    # Make sure the node_modules contain only the production modules when building this image
    COPY . /usr/src/app

您还需要确保您的.dockerignore文件没有排除node_modules文件夹。

一旦您将文件夹复制到镜像中,诀窍是使用npm rebuild而不是npm install。这将重新构建任何受您的构建服务器和Docker操作系统之间任何差异影响的本机依赖项:

    FROM nodesource/vivid:LTS

    # For application location, default from nodesource is /usr/src/app
    # Make sure the node_modules contain only the production modules when building this image
    COPY . /usr/src/app
    WORKDIR /usr/src/app
    RUN npm rebuild
    CMD npm start

4
构建工具包的答案是正确的,但它以root身份运行所有内容,这被认为是一种不良的安全实践。
下面是一个工作的Dockerfile,使用正确的用户node作为node Dockerfile设置。请注意,秘密挂载已设置uid参数,否则它将挂载为root,而用户node无法读取。还要注意正确的COPY命令,将其chown为user:groupnode:node
FROM node:12-alpine

USER node

WORKDIR /home/node/app

COPY --chown=node:node package*.json ./

RUN --mount=type=secret,id=npm,target=./.npmrc,uid=1000 npm ci

COPY --chown=node:node index.js .

COPY --chown=node:node src ./src

CMD [ "node", "index.js" ]


docker build中以root身份运行命令何时成为不良实践?这与容器入口点以root身份运行大相径庭。在良好的实践中,您的入口点也不会以“node”用户身份运行,而是使用shadow-utils创建一个新的应用程序用户,遵循最小特权原则。 - ThisGuyCantEven
1
一个用户必须被创建,否则默认为root来运行。这就是nodejs的做法。你有一个能正常工作的例子吗?请提供链接。 - Paul S
没错,但我宁愿自己创建一个节点,而不使用用户“node”,因为该用户的权限可能会受到新镜像拉取上游更改的影响。 - ThisGuyCantEven

4

我建议不要使用.npmrc文件,而是使用npm config set。这种方法非常简洁实用:

ARG AUTH_TOKEN_PRIVATE_REGISTRY

FROM node:latest

ARG AUTH_TOKEN_PRIVATE_REGISTRY
ENV AUTH_TOKEN_PRIVATE_REGISTRY=${AUTH_TOKEN_PRIVATE_REGISTRY}

WORKDIR /home/usr/app

RUN npm config set @my-scope:registry https://my.private.registry && npm config set '//my.private.registry/:_authToken' ${AUTH_TOKEN_PRIVATE_REGISTRY}

RUN npm ci

CMD ["bash"]

无论是哪种方式,$ npm config 都可以处理全局 NPM 配置文件(~/.npmrc)或本地项目配置文件(./.npmrc),它们是相同的,没有性能或安全方面的影响。 - José Pulido

1

@paul-s 现在应该被接受为最佳答案,因为我认为它更加新颖。作为补充,你提到你正在使用 docker/build-push-action 动作,所以你的工作流程必须按照以下步骤进行:

- uses: docker/build-push-action@v3
  with:
    context: .
    # ... all other config inputs
    secret-files: |
      NPM_CREDENTIALS=./.npmrc

当然,你需要使用你指定的ID,在dockerfile中绑定.npmrc文件。在我的情况下,我使用基于Debian的镜像(uid从1000开始)。无论如何:

RUN --mount=type=secret,id=NPM_CREDENTIALS,target=<container-workdir>/.npmrc,uid=1000 \
npm install --only=production

0
对于未来可能尝试解决安装失败的人们,请不要忘记复制 .npmrc 文件,如果您依赖它来解决依赖关系问题。
COPY .npmrc ./

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接