【问题标题】:How to pull environment variables with Helm charts如何使用 Helm 图表提取环境变量
【发布时间】:2018-09-30 09:56:25
【问题描述】:

我在 Helm 图表的模板目录中有我的 deployment.yaml 文件,其中包含我将使用 Helm 运行的容器的几个环境变量。

现在我希望能够从运行 helm 的任何机器本地提取环境变量,这样我就可以隐藏秘密。

当我使用 Helm 运行应用程序时,如何传入并让 helm 在本地获取环境变量?

这是我的 deployment.yaml 文件的一部分

...
...
    spec:
      restartPolicy: Always
      containers:
        - name: sample-app
          image: "sample-app:latest"
          imagePullPolicy: Always
          env:          
            - name: "USERNAME"
              value: "app-username"
            - name: "PASSWORD"
              value: "28sin47dsk9ik"
...
...

如何在运行 helm 时从本地环境变量中提取 USERNAME 和 PASSWORD 的值?

这可能吗?如果是,那我该怎么做?

【问题讨论】:

标签: kubernetes kubectl kubernetes-helm


【解决方案1】:

您可以export 变量并在运行helm install 时使用它。

在此之前,您必须修改您的图表,以便在安装时该值可以是set

如果您已经知道如何设置模板字段,请跳过此部分。


由于您不想公开数据,因此最好将其保存为 kubernetes 中的秘密。

首先,将这两行添加到你的Values文件中,这样就可以从外部设置这两个值了。

username: root
password: password

现在,在您的 template 文件夹中添加一个 secret.yaml 文件。并且,将此代码 sn-p 复制到该文件中。

apiVersion: v1
kind: Secret
metadata:
  name: {{ .Release.Name }}-auth
data:
  password: {{ .Values.password | b64enc }}
  username: {{ .Values.username | b64enc }}

现在调整您的部署 yaml 模板并在 env 部分进行更改,如下所示

...
...
    spec:
      restartPolicy: Always
      containers:
        - name: sample-app
          image: "sample-app:latest"
          imagePullPolicy: Always
          env:          
          - name: "USERNAME"
            valueFrom:
              secretKeyRef:
                key:  username
                name: {{ .Release.Name }}-auth
          - name: "PASSWORD"
            valueFrom:
              secretKeyRef:
                key:  password
                name: {{ .Release.Name }}-auth
...
...

如果您为--set 标志正确修改了模板, 您可以使用环境变量进行设置。

$ export USERNAME=root-user

现在在运行 helm install 时使用这个变量,

$ helm install --set username=$USERNAME ./mychart

如果您在dry-run 模式下运行此helm install,您可以验证更改,

$ helm install --dry-run --set username=$USERNAME --debug ./mychart
[debug] Created tunnel using local port: '44937'

[debug] SERVER: "127.0.0.1:44937"

[debug] Original chart version: ""
[debug] CHART PATH: /home/maruf/go/src/github.com/the-redback/kubernetes-yaml-drafts/helm-charts/mychart

NAME:   irreverant-meerkat
REVISION: 1
RELEASED: Fri Apr 20 03:29:11 2018
CHART: mychart-0.1.0
USER-SUPPLIED VALUES:
username: root-user

COMPUTED VALUES:
password: password
username: root-user

HOOKS:
MANIFEST:

---
# Source: mychart/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: irreverant-meerkat-auth
data:
  password: password
  username: root-user
---
# Source: mychart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: irreverant-meerkat
  labels:
    app: irreverant-meerkat
spec:
  replicas: 1
  template:
    metadata:
      name: irreverant-meerkat
      labels:
        app: irreverant-meerkat
    spec:
      containers:
      - name: irreverant-meerkat
        image: alpine
        env:
        - name: "USERNAME"
          valueFrom:
            secretKeyRef:
              key:  username
              name: irreverant-meerkat-auth
        - name: "PASSWORD"
          valueFrom:
            secretKeyRef:
              key:  password
              name: irreverant-meerkat-auth

        imagePullPolicy: IfNotPresent
      restartPolicy: Always
  selector:
    matchLabels:
      app: irreverant-meerkat

可以看到username in secret的数据变成了root-user

我已将this example 添加到 github 存储库中。

kubernetes/helm repo 中也对此进行了一些讨论。您可以查看this issue 了解所有其他使用环境变量的方法。

【讨论】:

  • 就像一个魅力......非常感谢......真的很感谢你花时间回答这个问题
  • 一个简单的问题...如果我想提取 50 个环境变量怎么办...当变量很多时有没有办法简化事情?否则 helm install 命令将非常冗长 --set for like 50 个变量
  • @uberrebu 在安装过程中,您必须使用 range 函数一次传递多个环境变量。这些变量可以通过包含所有值的文件设置并通过 -f 标志传递。如果您提出新问题,我可以提供更全面的答案。
  • 问题,如果只有配置数据而没有任何敏感数据,你会怎么做,你应该把不同的数据作为秘密放在哪里?
  • 在命令行上传递值并不理想。我希望 Helm 能够以 Terraform 使用的方式直接提取 env var 值。
【解决方案2】:

您可以通过如下设置部署 yaml 来从值 yaml 传递 env 键值:

spec:
  restartPolicy: Always
  containers:
    - name: sample-app
      image: "sample-app:latest"
      imagePullPolicy: Always
      env:          
        {{- range $name, $value := .Values.env }}
        - name: {{ $name }}
          value: {{ $value }}
        {{- end }}

在 values.yaml 中:

env:          
 - name: "USERNAME"
   value: ""
 - name: "PASSWORD"
   value: ""

安装图表时可以传递用户名密码值

helm install chart_name --name release_name --set env.USERNAME="app-username" --set env.PASSWORD="28sin47dsk9ik"

【讨论】:

  • 不会这样做,因为如果您上传这样的值,每个人都可以在您的 k8s 仪表板中看到密码。这就是发明资源 Secret 的原因:)
  • OP 没有询问最佳实践,只是询问如何去做,所以这个答案是有效的,也是一种很好的方法。一个问题是列表不会被合并,它们会被替换。因此,当以这种方式完成时,每个版本(例如在不同集群中)的值文件必须包含整个环境变量集。通常你会有一组更静态的,你把它放在图表中并引用值文件中的单个值,以及另一组“额外”,即来自这样一个循环的可选环境变量。
【解决方案3】:

对于那些希望使用数据结构而不是列表作为 env 变量文件的人来说,这对我有用:

spec:
  containers:
    - name: {{ .Chart.Name }}
      image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
      imagePullPolicy: {{ .Values.image.pullPolicy }}
      env:          
      {{- range $key, $val := .Values.env }}
        - name: {{ $key }}
          value: {{ $val | quote }}
      {{- end }}

values.yaml:

env:          
 FOO: "BAR"
 USERNAME: "CHANGEME"
 PASWORD: "CHANGEME"

这样我可以在 helm 图表的其他部分按名称访问特定值,并通过 helm 命令行传递敏感值。

【讨论】:

    【解决方案4】:

    为了避免手动设置每个秘密,您可以使用:

    export MY_SECRET=123
    envsubst < values.yaml | helm install my-release . --values -
    

    在您的 values.yaml 文件中引用 ${MY_SECRET} 的位置,例如:

    mychart:
      secrets:
        secret_1: ${MY_SECRET}
    

    【讨论】:

    • 这对我不起作用,因为我的 CI 管道中没有可用的命令“envsubst”。
    【解决方案5】:

    我想问题是如何通过查看环境变量本身而不是通过 --set 传递来在图表中查找环境变量。

    例如:我设置了一个键“my_db_password”,但不支持通过查看 env 变量中的值来更改值。

    我对 GO 模板不是很确定,但我想这已被禁用,正如他们在 helm 文档中解释的那样。 “出于安全原因,我们删除了两个:env 和 expandenv(这将使图表作者可以访问 Tiller 的环境)。” https://helm.sh/docs/developing_charts/#know-your-template-functions

    【讨论】:

      【解决方案6】:

      作为传递本地环境变量的替代方法,我喜欢将这些敏感值存储在您的 VCS 忽略的文件夹中,并使用 Helm .Files 对象读取它们并将值提供给您的模板。

      在我看来,优势在于它不需要将操作 Helm 图表的主机设置任何操作系统特定的环境变量,并使图表自包含,同时不暴露这些值。

      # In a folder not committed, e.g. <chart_base_directory>/secrets
      username: app-username
      password: 28sin47dsk9ik
      

      然后在您的图表模板中:

      # In deployment.yaml file
      ---
      apiVersion: v1
      kind: Secret
      metadata:
        name: {{ .Release.Name }}-auth
      stringData::
      {{ .Files.Get "<chart_base_directory>/secrets" | indent 2 }}
      

      因此,图表所需的所有内容都可以从您定义其他所有内容的目录中访问。而不是设置系统范围的环境变量,它只需要一个文件。

      此文件可以自动生成,也可以从具有虚拟值的已提交模板复制。如果未定义,Helm 也会在安装/更新早期触发错误,而不是在未定义环境变量时使用 username=""password="" 创建您的秘密,只有在您的更改完成后才会变得明显应用于集群。

      【讨论】:

        【解决方案7】:

        我认为一种简单的方法就是直接设置值。例如,在您的 Values.yml 中,您需要传递服务名称:

        ...
        myapp:
          service:
            name: ""
        ...
        

        你的 service.yml 就像往常一样使用这个值:

        {{ .Values.myapp.service.name }}
        

        然后设置值,使用--set,如:--set myapp.service.name=hello


        然后,例如,如果要使用环境变量,请在此之前进行导出:

        #set your env variable 
        export MYAPP_SERVICE=hello
        
        #pass it to helm
        helm install myapp --set myapp.service.name=$MYAPP_SERVICE.
        

        如果你像这样调试:

        helm install myapp --set myapp.service.name=$MYAPP_SERVICE --debug --dry-run ./myapp
        

        您可以在设置“hello”的 yml 开头看到此信息。

        USER-SUPPLIED VALUES:
        myapp:
          service:
            name: hello
        

        【讨论】:

          【解决方案8】:

          Helm 3.1 支持后期渲染 (https://helm.sh/docs/topics/advanced/#post-rendering),它在实际发送到 Kubernetes API 之前将清单传递给脚本。后期渲染允许以多种方式操作清单(例如,在 Helm 之上使用 kustomize)。

          替换预定义环境值的最简单形式的后期渲染器可能如下所示:

          #!/bin/sh
          envsubst <&0
          

          请注意,这将替换 每个 出现的 $&lt;VARNAME&gt;,这可能与模板中的变量(例如活性探针中的 shell 脚本)发生冲突。所以最好明确定义要替换的变量: envsubst '${USERNAME} ${PASSWORD}' &lt;&amp;0

          在 shell 中定义你的环境变量:

          export USERNAME=john PASSWORD=my-secret
          

          在模板中(例如secret.yaml)使用values.yaml中定义的值:

          apiVersion: v1
          kind: Secret
          metadata:
              name: {{ .Release.Name }}-auth
          data:
              username: {{ .Values.username }}
              password: {{ .Values.password }}
          

          请注意,在 Helm 已经处理完所有 YAML 文件后,您不能对字符串应用像 b64enc 这样的字符串转换,因为 get 注入到清单中。相反,如果需要,您可以在后期渲染器中对它们进行编码。

          values.yaml 中使用变量占位符:

          ...
          username: ${USERNAME}
          password: ${PASSWORD}
          

          几个 Helm 命令支持参数 --post-renderer,例如

          helm install --dry-run --post-renderer ./my-post-renderer.sh my-chart
          

          通过使用 post 渲染器,变量/占位符会自动替换为 envsubst,而无需额外编写脚本。

          【讨论】:

            猜你喜欢
            • 2020-07-08
            • 2020-02-25
            • 2020-10-20
            • 2021-10-29
            • 2022-08-17
            • 2019-10-20
            • 2021-09-15
            • 2021-04-06
            • 1970-01-01
            相关资源
            最近更新 更多