Kubernetes 相当于 Docker 中的 env-file

Posted

技术标签:

【中文标题】Kubernetes 相当于 Docker 中的 env-file【英文标题】:Kubernetes equivalent of env-file in Docker 【发布时间】:2016-02-02 09:23:58 【问题描述】:

背景:

目前我们正在使用 Docker 和 Docker Compose 来提供我们的服务。我们已将不同环境的配置外部化为定义应用程序读取的环境变量的文件。例如prod.env 文件:

ENV_VAR_ONE=Something Prod
ENV_VAR_TWO=Something else Prod

还有一个test.env 文件:

ENV_VAR_ONE=Something Test
ENV_VAR_TWO=Something else Test

因此我们可以在启动容器时简单地使用prod.envtest.env 文件:

docker run --env-file prod.env <image>

然后,我们的应用程序会根据prod.env 中定义的环境变量获取其配置。

问题:

    有没有办法从 Kubernetes 中的文件中提供环境变量(例如在定义 pod 时),而不是像这样硬编码它们:
api版本:v1 种类:豆荚 元数据: 标签: 上下文:docker-k8s-lab 名称:mysql-pod 名称:mysql-pod 规格: 容器: - 环境: - 名称:MYSQL_USER 值:mysql - 名称:MYSQL_PASSWORD 值:mysql - 名称:MYSQL_DATABASE 值:样本 - 名称:MYSQL_ROOT_PASSWORD 值:超级机密 图片:“mysql:最新” 名称:mysql 端口: - 容器端口:3306
    如果这不可能,建议的方法是什么?

【问题讨论】:

我也在寻找这样的东西。我不想创建SecretConfigMap 资源,因为这只是临时的并用于测试。我在 k8s 集群中的权限有限。我也许可以创建一个 Secret 资源,但一旦创建,我将无法删除它们。 【参考方案1】:

您可以通过在容器中将 K8S 值指定为环境变量来引用它们。

让您的部署为 mongo.yml,如下所示:

--
kind: Deployment
   --
      --
      containers:
        --
        env:
        - name: DB_URL
          valueFrom:
            configMapKeyRef:
              name: mongo-config
              key: mongo-url
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-password  

mongo-secret 用于敏感数据,例如:密码或证书

apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
type: Opaque
data:
  mongo-user: bW9uZ291c2Vy
  mongo-password: bW9uZ29wYXNzd29yZA==

mongo-config 用于非敏感数据

apiVersion: v1
kind: ConfigMap
metadata:
  name: mongo-config
data:
  mongo-url: mongo-service

【讨论】:

【参考方案2】:

Kubernetes(v1.6) 的新更新 满足您的要求(多年前)。

您现在可以在 yaml 文件中像这样使用envFrom

  containers:
  - name: django
    image: image/name
    envFrom:
      - secretRef:
         name: prod-secrets

其中 development-secrets 是您的秘密,您可以通过以下方式创建它:

kubectl create secret generic prod-secrets --from-env-file=prod/env.txt`

其中txt文件内容为key-value:

DB_USER=username_here
DB_PASSWORD=password_here

文档仍然是大量示例,我不得不在这些地方非常努力地搜索:

Secrets docs,搜索--from-file - 表明该选项可用。 The equivalent ConfigMap docs 展示了如何使用它的示例。

注意:--from-file--from-env-file 在创建秘密时有所不同,如下面的 cmets 所述。

【讨论】:

你能分享这方面的 Kubernetes 文档吗? @ArtemDolobanko 已编辑,请记住,这仍然是新的文档湖,如果您想了解更多详细信息,可以在 Github 的问题跟踪器上找到许多讨论。 @Or Duan 我如何使用 env 将版本号传递给 docker 映像 如果我们必须将该文本文件挂载到某个位置,应用程序会从那里自动创建环境 应该是--from-env-file吗?使用--from-file 会产生一个带有文件内容的键(以输入文件命名)。使用--from-env-file 将文件内的密钥扩展为机密。请参阅this Google documentation 了解更多信息。【参考方案3】:

我现在用 tyhis 砸了我的头 2 个小时。我在文档中找到了一个非常简单的解决方案,可以最大程度地减少我(也希望是您的)痛苦。

保留env.prodenv.dev 原样。

使用 oneliner 脚本将它们导入 yaml:

kubectl create configmap my-dev-config --from-env-file=env.dev

kubectl create configmap my-prod-config --from-env-file=env.prod

你可以看到结果(即时满足):

# You can also save this to disk
kubectl get configmap my-dev-config -o yaml

作为一名 ruby​​ist,我个人认为这个解决方案是最干燥的,因为您只需维护一个点(ENV bash 文件,它与 Python/Ruby 库兼容,..),然后您在一次执行中对其进行 YAML 化。

请注意,您需要保持 ENV 文件干净(我有很多 cmets 阻止了此操作,因此必须在前面加上 cat config.original | egrep -v "^#" | tee config.cleaned),但这并不会显着改变复杂性。

全部记录在案here

【讨论】:

【参考方案4】:

这是一个老问题,但让我为未来的初学者描述我的答案。

您可以使用 kustomize configMapGenerator。

configMapGenerator:
  - name: example
    env: dev.env

并在 pod 定义中引用此 configMap/example

【讨论】:

【参考方案5】:

这是一个老问题,但它有很多观众,所以我添加了我的答案。 将配置与 K8s 实现分离的最佳方法是使用 Helm。每个 Helm 包都可以有一个 values.yaml 文件,我们可以轻松地在 Helm 图表中使用这些值。如果我们有一个多组件拓扑,我们可以创建一个伞形 Helm 包,并且父值包也可以覆盖子值文件。

【讨论】:

【参考方案6】:

您可以通过使用Secrets 或ConfigMaps 来填充容器的环境变量。当您使用的数据是敏感数据(例如密码)时使用 Secrets,如果不是敏感数据则使用 ConfigMaps。

在您的 Pod 定义中指定容器应从 Secret 中提取值:

apiVersion: v1
kind: Pod
metadata: 
  labels: 
    context: docker-k8s-lab
    name: mysql-pod
  name: mysql-pod
spec: 
  containers:
  - image: "mysql:latest"
    name: mysql
    ports: 
    - containerPort: 3306
    envFrom:
      - secretRef:
         name: mysql-secret

请注意,此语法仅在 Kubernetes 1.6 或更高版本中可用。在早期版本的 Kubernetes 上,您必须手动指定每个值,例如:

env: 
- name: MYSQL_USER
  valueFrom:
    secretKeyRef:
      name: mysql-secret
      key: MYSQL_USER

(注意env取一个数组作为值)

并为每个值重复。

无论您使用哪种方法,您现在都可以定义两种不同的 Secret,一种用于生产,一种用于开发。

dev-secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  MYSQL_USER: bXlzcWwK
  MYSQL_PASSWORD: bXlzcWwK
  MYSQL_DATABASE: c2FtcGxlCg==
  MYSQL_ROOT_PASSWORD: c3VwZXJzZWNyZXQK

prod-secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  MYSQL_USER: am9obgo=
  MYSQL_PASSWORD: c2VjdXJlCg==
  MYSQL_DATABASE: cHJvZC1kYgo=
  MYSQL_ROOT_PASSWORD: cm9vdHkK

并将正确的密钥部署到正确的 Kubernetes 集群:

kubectl config use-context dev
kubectl create -f dev-secret.yaml

kubectl config use-context prod
kubectl create -f prod-secret.yaml

现在,每当 Pod 启动时,它都会根据 Secret 中指定的值填充其环境变量。

【讨论】:

这是我目前的方法,但是我有 3 个不同的 pod,它们使用与 EnvVars 相同的秘密列表。是否可以定义一次并将它们暴露给 3 个 pod? 我不知道。 那太好了...似乎分配了样板文件以将环境变量放入容器中。 @PixelElephant @jävi 你的意思是复制控制器吗?无论如何,没有任何东西将 secret/config 映射绑定到单个 pod/RC/Deployment。它只是在上面的清单中定义,可以安装到任意数量的东西上。 我认为在 Secret 的定义中提到值必须是 base64 编码是很重要的。我刚刚用我的学习集群尝试过这个,我得到错误,除非值都是 base64 编码的【参考方案7】:

这对我有用:

文件env-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: env-secret
type: Opaque
stringData:
  .env: |-
    APP_NAME=Laravel
    APP_ENV=local

并进入deployment.yamlpod.yaml

spec:
  ...
        volumeMounts:
        - name: foo
          mountPath: "/var/www/html/.env"
          subPath: .env
      volumes:
      - name: foo
        secret:
          secretName: env-secret
````

【讨论】:

如何将 env 用于 docker 映像,这样我就不必每次需要增加版本时都更新 deployment.yaml【参考方案8】:

使用 YAML 文件为 Kubernetes 定义 pod 时,没有直接的方法可以为容器指定包含环境变量的不同文件。 Kubernetes 项目表示他们将在未来改进这一领域(参见Kubernetes docs)。

同时,我建议使用配置工具并将 pod YAML 设为模板。例如,使用 Ansible,您的 pod YAML 文件将如下所示:

文件my-pod.yaml.template:

apiVersion: v1
kind: Pod
...
spec:
  containers:
  ...
    env:
    - name: MYSQL_ROOT_PASSWORD
      value:  mysql_root_pasword 
    ...

然后你的 Ansible playbook 可以在方便的地方指定变量 mysql_root_password,并在创建资源时替换它,例如:

文件my-playbook.yaml:

- hosts: my_hosts
  vars_files: 
  - my-env-vars- deploy_to .yaml
  tasks:
  - name: create pod YAML from template
    template: src=my-pod.yaml.template dst=my-pod.yaml
  - name: create pod in Kubernetes
    command: kubectl create -f my-pod.yaml

文件my-env-vars-prod.yaml:

mysql_root_password: supersecret

文件my-env-vars-test.yaml:

mysql_root_password: notsosecret

现在你通过运行来创建 pod 资源,例如:

ansible-playbook -e deploy=test my-playbook.yaml

【讨论】:

理想情况下,您应该能够定义一个 Secret(或我们将拥有的最终配置对象)并将其作为环境变量注入。不幸的是,这项工作还没有完成,所以我投票赞成。 如果你使用 ansible,我们有一个共同的角色可以部署在 kubernetes 上:github.com/ansibl8s/k8s-common。然后很容易准备新的应用程序,请参阅如何在其他 repo 中使用它的示例:github.com/ansibl8s 我希望我们能在 1.2 的环境变量中做秘密 注意有模板的提议:github.com/kubernetes/kubernetes/blob/master/docs/proposals/… 如果我想使用kubectl-run传递20个环境变量该怎么办???那么为什么不做 12factor 更容易呢??

以上是关于Kubernetes 相当于 Docker 中的 env-file的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes之三 k8s中的pod

docker 入门(二):docker 和 沙盒、虚拟机以及 Kubernetes 的关系

Kubernetes 集群中 Docker 镜像中的环境变量

为啥 OpenJDK Docker 容器会忽略 Kubernetes 中的内存限制?

Docker 和 Kubernetes 中的容器网络图书资料分享

为啥 Kubernetes 的容器在 runsc (gVisor) 上作为 Docker 中的运行时运行时会失败?