问题描述
我正在研究operator-sdk,在控制器中,我们经常需要创建一个Deployment对象,并且Deployment资源具有很多配置项,例如环境变量或端口定义或其他如下配置。我想知道获取这些值的最佳方法是什么,我不想对它们进行硬编码,例如,variable_a或variable_b。
可能您可以将它们作为规范放入CRD中,然后将其传递给Operator Controller。或者,您可以将它们放入configmap中,然后将configmap名称传递给Operator Controller,Operator Controller可以访问configmap来获取它们;或者,您可以放入模板文件,然后在操作员控制器中,控制器必须读取该模板文件。
处理这种情况的最佳方法或最佳做法是什么?感谢您分享您的想法或观点。
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name,Namespace: m.Namespace,Labels: ls,},Spec: appsv1.DeploymentSpec{
Replicas: &replicas,Selector: &metav1.LabelSelector{
MatchLabels: ls,Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: ls,Spec: corev1.PodSpec{
Containers: []corev1.Container{{
Image: "....",Name: m.Name,Ports: []corev1.ContainerPort{{
ContainerPort: port_a,Name: "tcpport",}},Env: []corev1.EnvVar{
{
Name: "aaaa",Value: variable_a,{
Name: "bbbb",Value: variable_b,
解决方法
使用环境变量
应用程序将数据作为环境变量获取会很方便。
ConfigMap
中的环境变量
对于非敏感数据,可以将变量存储在ConfigMap
中,然后使用ConfigMap
数据定义容器环境变量。
首先创建ConfigMap
。文件configmaps.yaml
:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
---
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
创建ConfigMap:
kubectl create -f ./configmaps.yaml
然后在Pod
规范pod-multiple-configmap-env-variable.yaml
中定义环境变量:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh","-c","env" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
restartPolicy: Never
创建Pod
:
kubectl create -f ./pod-multiple-configmap-env-variable.yaml
现在,您可以在控制器中读取以下环境变量SPECIAL_LEVEL_KEY
(将从special.how
special-config
中获得ConfigMap
的值)和LOG_LEVEL
(将从log_level
env-config
给您ConfigMap
的价值):
例如:
specialLevelKey := os.Getenv("SPECIAL_LEVEL_KEY")
logLevel := os.Getenv("LOG_LEVEL")
fmt.Println("SPECIAL_LEVEL_KEY:",specialLevelKey)
fmt.Println("LOG_LEVEL:",logLevel)
Secret
中的环境变量
如果您的数据敏感,则可以将其存储在Secret
中,然后将Secret
用作环境变量。
您首先需要使用base64
对字符串进行编码。
# encode username
$ echo -n 'admin' | base64
YWRtaW4=
# encode password
$ echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
然后使用上述数据创建一个Secret
:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
使用Secret
创建一个kubectl apply
:
$ kubectl apply -f ./secret.yaml
请注意,还有其他方法可以创建一个秘密,选择最适合您的秘密:
- Creating a
Secret
usingkubectl
- Creating a
Secret
from a generator - Creating a
Secret
from files - Creating a
Secret
from string literals
现在您可以use this created Secret
for environment variables了。
要在Pod中的环境变量中使用机密信息:
- 创建一个秘密或使用现有的秘密。多个Pod可以引用相同的秘密。
- 在每个您希望使用密钥值的容器中修改Pod定义,以便为您希望使用的每个密钥添加环境变量。使用秘密密钥的环境变量应在
env[].valueFrom.secretKeyRef
中填充秘密的名称和密钥。- 修改图像和/或命令行,以便程序在指定的环境变量中查找值。
这是Kubernetes文档中的一个Pod
示例,展示了如何对环境变量使用Secret
:
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: mycontainer
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
restartPolicy: Never
最后,如文档所述:
在一个在环境变量中使用秘密的容器中,秘密密钥显示为包含秘密数据的base64解码值的普通环境变量。
现在,您可以在控制器中读取以下环境变量SECRET_USERNAME
(将从username
mysecret
中获得Secret
的值)和SECRET_PASSWORD
(将从password
mysecret
给您Secret
的价值):
例如:
username := os.Getenv("SECRET_USERNAME")
password := os.Getenv("SECRET_PASSWORD")
使用卷
您还可以将ConfigMap
和Secret
都作为卷安装到您的Pod。
Populate a Volume with data stored in a ConfigMap:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh","ls /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
# Provide the name of the ConfigMap containing the files you want
# to add to the container
name: special-config
restartPolicy: Never
Using Secrets as files from a Pod:
要在Pod中的某个卷中使用秘密:
- 创建一个秘密或使用现有的秘密。多个Pod可以引用相同的秘密。
- 修改您的Pod定义以在.spec.volumes []下添加一个体积。将该卷命名为任何名称,并具有一个.spec.volumes []。secret.secretName字段,该字段等于Secret对象的名称。
- 向每个需要机密的容器添加
.spec.containers[].volumeMounts[]
。将.spec.containers[].volumeMounts[].readOnly = true
和.spec.containers[].volumeMounts[].mountPath
指定为您要显示机密的未使用目录名称。 修改您的图像或命令行,以便程序在该目录中查找文件。秘密data
映射中的每个密钥都变成mountPath
下的文件名。
将Pod
装入卷中的Secret
的示例:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret