通过 kubernetes/skaffold 将私有 npm 存储库拉入 docker 容器

问题描述

我是 skaffold、k8s、docker set 的新手,我在本地集群上构建应用程序时遇到了问题。

我有一个代码存储库,它试图提取私有 NPM 包,但在构建它时丢失了 .npmrc 文件或 npm 机密。

npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/@sh1ba%2fcommon - Not found
npm ERR! 404 
npm ERR! 404  '@sh1ba/common@^1.0.3' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404 
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball,folder,http url,or git url.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2021-06-02T06_08_57_246Z-debug.log
unable to stream build output: The command '/bin/sh -c npm install' returned a non-zero code: 1. Please fix the Dockerfile and try again..

理想情况下,我希望避免将秘密硬编码到文件中,并使用 k8s 环境变量将密钥作为秘密传递给 docker。我可以(有点)使用 docker build 命令来做到这一点:

  • 使用“--build-args”和 npm 秘密(不安全的方式)
  • 使用“--secret”和 npm secret(更好的方法
  • 直接复制 .npmrc 文件,然后npm install立即将其删除

当我尝试使用 kubernetes/skaffold 构建它时出现问题。运行后,似乎没有找到任何 args、env 变量,甚至 .npmrc 文件。在检查 dockerfile 以获取线索时,我能够确定没有任何内容从清单(定义的 args、.npmrc 文件等)传递到 dockerfile。

以下是应用程序的清单:

apiVersion: apps/v1
kind: Deployment
Metadata:
  name: auth-depl
spec:
  replicas: 1
  selector: 
    matchLabels:
      app: auth
  template:
    Metadata:
      labels:
        app: auth
    spec:
      containers:
        - name: auth
          image: auth
          env:
            - name: NPM_SECRET
              valueFrom:
                secretKeyRef:
                  name: npm-secret
                  key: NPM_SECRET
          args: ["--no-cache","--progress=plain","--secret","id=npmrc,src=.npmrc"]

这是 dockerfile 中的代码

# Syntax=docker/dockerfile:1.2
# --------------> The build image
FROM node:alpine AS build
workdir /app
copY package*.json .
RUN --mount=type=secret,mode=0644,id=npmrc,target=/app/.npmrc \
  npm install

# --------------> The production image
FROM node:alpine

workdir /app
copY package.json .
copY tsconfig.json .
copY src .
copY prisma .

copY --chown=node:node --from=build /app/node_modules /app/node_modules
copY --chown=node:node . /app
s
RUN npm run build

CMD ["npm","start"]

还有脚手架文件

apiVersion: skaffold/v2alpha3
kind: Config
deploy:
  kubectl:
    manifests:
      - ./infra/k8s/*
      - ./infra/k8s-dev/*
build:
  local:
    push: false
  artifacts:
    - image: auth
      context: auth
      docker:
        dockerfile: Dockerfile
      sync:
        manual:
          - src: 'src/**/*.ts'
            dest: .

一些注意事项:

  • 无论我将 .npmrc 文件复制并粘贴到何处(在身份验证、清单、脚手架和 ~/ 目录中),我都无法找到它
  • 我也想让它在生产中半可用(非常可重用),这样我就不需要在可能的情况下进行彻底的检修(但如果这是不好的做法,我想听听更多关于它的信息)
  • 我已经能够使其与 skaffold.yaml 文件中的 buildArgs 一起使用,但我不确定这将如何转化为生产环境,因为我无法将构建 args 从 kubernetes 传递到 docker(并且我阅读了它不安全,应该使用秘密)
  • 清单中的参数也抛出了这个错误(如果参数被注释掉,服务器就会运行):
 - deployment/auth-depl: container auth terminated with exit code 9
    - pod/auth-depl-85fb8975d8-4rh9r: container auth terminated with exit code 9
      > [auth-depl-85fb8975d8-4rh9r auth] node: bad option: --progress=plain
      > [auth-depl-85fb8975d8-4rh9r auth] node: bad option: --secret
 - deployment/auth-depl Failed. Error: container auth terminated with exit code 9.

任何见解都会令人惊叹,我已经摆弄这个太久了。

谢谢!

解决方法

构建镜像并将其部署到 Kubernetes 分为三个级别:

  1. 您开始构建映像的本地系统
  2. 填充图像然后将该图像存储在某处的 Docker 构建
  3. 加载并开始运行该映像的 Kubernetes 集群

#3 中没有涉及 Docker。 (这只是部分正确,因为一些集群也使用 Docker 来运行容器,但这是一个隐藏的细节,而且也在发生变化。)

您可以在两个地方交流秘密:

  • 在映像构建时(第 1 步到第 2 步):您可​​以使用 Docker --build-args 或使用 --secret 挂载机密(都需要 Buildkit)
  • 在部署时(第 3 步):您使用 Kubernetes 机密或配置映射,它们与映像构建分开配置

Skaffold 支持使用 Docker 的 --build-args--secret 标志传递构建时机密,例如您的 npm 密码,尽管它们略有重命名。

buildArgs 支持 Go 风格的模板,因此您可以将 MYSECRET 等环境变量引用为 {{.MYSECRET}}:

build:
  local:
    useBuildkit: true
  artifacts:
    - image: auth
      context: auth
      docker:
        buildArgs:
          MYSECRET: "{{.MYSECRET}}"

然后您可以在您的 MYSECRET 中引用 Dockerfile

ARG MYSECRET
RUN echo MYSECRET=${MYSECRET}

请注意,除非您通过 ENV MYSECRET=${MYSECRET} 明确分配,否则 build-args 不会传播到您的容器中。

如果机密在本地文件中,您可以使用 skaffold.yaml 中的 secret 字段:

build:
  local:
    useBuildkit: true
  artifacts:
    - image: auth
      context: auth
      docker:
        secret:
          id:   npmrc
          src: /path/to/.npmrc

然后您将在 Dockerfile 中引用该机密:

RUN --mount=type=secret,mode=0644,id=npmrc,target=/app/.npmrc \
  npm install

现在在您的 Deployment 中,您正在尝试为您的容器设置 args

          args: ["--no-cache","--progress=plain","--secret","id=npmrc,src=.npmrc"]

args 字段会覆盖图像中设置的 CMD 指令。此字段用于提供提供给图像入口点的命令行参数,这可能是 node。如果您想引用集群上正在运行的容器中的机密,您可以使用 SecretConfigMap