Kubernetes 相当于 Docker 中的环境文件
Kubernetes equivalent of env-file in Docker
背景:
目前我们正在为我们的服务使用 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.env
或test.env
文件:
docker run --env-file prod.env <image>
然后我们的应用程序根据 prod.env
中定义的环境变量选择其配置。
问题:
- 有没有一种方法可以从 Kubernetes 中的文件中提供环境变量(例如在定义 pod 时)而不是像这样对它们进行硬编码:
apiVersion: v1
kind: Pod
metadata:
labels:
context: docker-k8s-lab
name: mysql-pod
name: mysql-pod
spec:
containers:
-
env:
-
name: MYSQL_USER
value: mysql
-
name: MYSQL_PASSWORD
value: mysql
-
name: MYSQL_DATABASE
value: sample
-
name: MYSQL_ROOT_PASSWORD
value: supersecret
image: "mysql:latest"
name: mysql
ports:
-
containerPort: 3306
- 如果这不可能,建议的方法是什么?
使用 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 剧本可以在方便的地方指定变量 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
您可以通过使用 Secrets or 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,一种用于生产,一种用于开发。
开发-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
产品-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 中指定的值填充其环境变量。
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
之间存在差异,如下面的评论所述。
这对我有用:
文件env-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: env-secret
type: Opaque
stringData:
.env: |-
APP_NAME=Laravel
APP_ENV=local
并入deployment.yaml
或pod.yaml
spec:
...
volumeMounts:
- name: foo
mountPath: "/var/www/html/.env"
subPath: .env
volumes:
- name: foo
secret:
secretName: env-secret
````
这是一个老问题,但它有很多观众所以我添加我的答案。
将配置与 K8s 实现分开的最佳方法是使用 Helm。每个 Helm 包都可以有一个 values.yaml
文件,我们可以轻松地在 Helm 图表中使用这些值。如果我们有一个多组件拓扑,我们可以创建一个伞形 Helm 包,父值包也可以覆盖子值文件。
这是一个老问题,但让我为未来的初学者描述一下我的答案。
您可以使用 kustomize configMapGenerator。
configMapGenerator:
- name: example
env: dev.env
并在 pod 定义中引用此 configMap/example
我在 tyhis 上摔了 2 个小时的头。我在文档中找到了一个非常简单的解决方案,可以最大程度地减少我(希望也是您)的痛苦。
保持 env.prod
、env.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
作为一个 rubyist,我个人认为这个解决方案是 DRYest,因为你有一个单一的维护点(ENV bash 文件,它与 Python/Ruby 库兼容,..)然后您在一次执行中将其 YAMLize。
请注意,您需要保持您的 ENV 文件干净(我有很多评论阻止它工作,所以不得不在前面加上 cat config.original | egrep -v "^#" | tee config.cleaned
)但这并没有显着改变复杂性。
全部记录在案here
您可以通过在容器中将它们指定为环境变量来引用 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
您可以尝试以下步骤:
此命令会将您的文件 prod.env
放入机密中。
kubectl create secret generic env-prod --from-file=prod.env=prod.env
然后,您可以在 deployment.yaml 中引用此文件,例如
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-identity
labels:
app.kubernetes.io/name: api-identity
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: api-identity
template:
metadata:
labels:
app.kubernetes.io/name: api-identity
spec:
imagePullSecrets:
- name: docker-registry-credential
containers:
- name: api-identity
image: "api-identity:test"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8005
protocol: TCP
volumeMounts:
- name: env-file-vol
mountPath: "/var/www/html/.env"
subPath: .env
volumes:
- name: env-file-vol
secret:
secretName: env-prod
背景:
目前我们正在为我们的服务使用 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.env
或test.env
文件:
docker run --env-file prod.env <image>
然后我们的应用程序根据 prod.env
中定义的环境变量选择其配置。
问题:
- 有没有一种方法可以从 Kubernetes 中的文件中提供环境变量(例如在定义 pod 时)而不是像这样对它们进行硬编码:
apiVersion: v1 kind: Pod metadata: labels: context: docker-k8s-lab name: mysql-pod name: mysql-pod spec: containers: - env: - name: MYSQL_USER value: mysql - name: MYSQL_PASSWORD value: mysql - name: MYSQL_DATABASE value: sample - name: MYSQL_ROOT_PASSWORD value: supersecret image: "mysql:latest" name: mysql ports: - containerPort: 3306
- 如果这不可能,建议的方法是什么?
使用 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 剧本可以在方便的地方指定变量 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
您可以通过使用 Secrets or 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,一种用于生产,一种用于开发。
开发-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
产品-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 中指定的值填充其环境变量。
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
之间存在差异,如下面的评论所述。
这对我有用:
文件env-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: env-secret
type: Opaque
stringData:
.env: |-
APP_NAME=Laravel
APP_ENV=local
并入deployment.yaml
或pod.yaml
spec:
...
volumeMounts:
- name: foo
mountPath: "/var/www/html/.env"
subPath: .env
volumes:
- name: foo
secret:
secretName: env-secret
````
这是一个老问题,但它有很多观众所以我添加我的答案。
将配置与 K8s 实现分开的最佳方法是使用 Helm。每个 Helm 包都可以有一个 values.yaml
文件,我们可以轻松地在 Helm 图表中使用这些值。如果我们有一个多组件拓扑,我们可以创建一个伞形 Helm 包,父值包也可以覆盖子值文件。
这是一个老问题,但让我为未来的初学者描述一下我的答案。
您可以使用 kustomize configMapGenerator。
configMapGenerator:
- name: example
env: dev.env
并在 pod 定义中引用此 configMap/example
我在 tyhis 上摔了 2 个小时的头。我在文档中找到了一个非常简单的解决方案,可以最大程度地减少我(希望也是您)的痛苦。
保持
env.prod
、env.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
作为一个 rubyist,我个人认为这个解决方案是 DRYest,因为你有一个单一的维护点(ENV bash 文件,它与 Python/Ruby 库兼容,..)然后您在一次执行中将其 YAMLize。
请注意,您需要保持您的 ENV 文件干净(我有很多评论阻止它工作,所以不得不在前面加上 cat config.original | egrep -v "^#" | tee config.cleaned
)但这并没有显着改变复杂性。
全部记录在案here
您可以通过在容器中将它们指定为环境变量来引用 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
您可以尝试以下步骤:
此命令会将您的文件 prod.env
放入机密中。
kubectl create secret generic env-prod --from-file=prod.env=prod.env
然后,您可以在 deployment.yaml 中引用此文件,例如
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-identity
labels:
app.kubernetes.io/name: api-identity
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: api-identity
template:
metadata:
labels:
app.kubernetes.io/name: api-identity
spec:
imagePullSecrets:
- name: docker-registry-credential
containers:
- name: api-identity
image: "api-identity:test"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8005
protocol: TCP
volumeMounts:
- name: env-file-vol
mountPath: "/var/www/html/.env"
subPath: .env
volumes:
- name: env-file-vol
secret:
secretName: env-prod