【问题标题】:Best Practice for Operators for how to get Deployment's configurationOperator 获取 Deployment 配置的最佳实践
【发布时间】:2020-09-04 15:17:43
【问题描述】:

我在做operator-sdk,在控制器中,我们经常需要创建一个Deployment对象,而Deployment资源有很多配置项,比如环境变量或者端口定义等等。我想知道获取这些值的最佳方法是什么,我不想对它们进行硬编码,例如 variable_a 或 variable_b。

也许,您可以将它们作为规范放入 CRD,然后将它们传递给 Operator Controller;或者你可以把它们放在 configmap 中,然后将 configmap 名称传递给 Operator Controller,Operator Controller 可以访问 configmap 来获取它们;或者你可以放入模板文件,然后在 Operator Controller 中,控制器必须读取该模板文件。

处理这种情况的最佳方法或最佳做法是什么?感谢您分享您的想法或观点。

    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,
                            },

【问题讨论】:

    标签: kubernetes kubernetes-custom-resources operator-sdk


    【解决方案1】:

    使用环境变量

    您的应用将数据作为环境变量获取会很方便。

    来自ConfigMap 的环境变量

    对于非敏感数据,您可以将变量存储在 ConfigMap 中,然后使用 ConfigMap 数据定义容器环境变量。

    Example from Kubernetes docs:

    首先创建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-configConfigMapspecial.how 值)和LOG_LEVEL(这将为您提供来自env-configlog_levelConfigMap):

    例如:

    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 用作环境变量。

    To create a Secret manually:

    您首先需要使用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
    

    kubectl apply 创建一个Secret

    $ kubectl apply -f ./secret.yaml
    

    请注意,还有其他方法可以创建秘密,请选择最适合您的方法:

    现在你可以use this created Secret for environment variables

    在 Pod 的环境变量中使用密钥:

    1. 创建一个秘密或使用现有的。多个 Pod 可以引用同一个 Secret。
    2. 修改您希望使用密钥值的每个容器中的 Pod 定义,以便为您希望使用的每个密钥添加环境变量。使用密钥的环境变量应在 env[].valueFrom.secretKeyRef 中填充密钥的名称和密钥。
    3. 修改您的图像和/或命令行,以便程序在指定的环境变量中查找值。

    这是来自 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(这将为您提供来自mysecret Secretusername 值)和SECRET_PASSWORD(这将为您提供来自mysecretpasswordSecret):

    例如:

    username := os.Getenv("SECRET_USERNAME")
    password := os.Getenv("SECRET_PASSWORD")
    

    使用卷

    您还可以将 ConfigMapSecret 作为卷安装到您的 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", "-c", "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 的卷中使用 Secret:

    1. 创建一个秘密或使用现有的。多个 Pod 可以引用同一个 Secret。
    2. 修改您的 Pod 定义以在 .spec.volumes[] 下添加一个卷。将卷命名为任何名称,并有一个 .spec.volumes[].secret.secretName 字段等于 Secret 对象的名称。
    3. 为每个需要密钥的容器添加.spec.containers[].volumeMounts[]。将 .spec.containers[].volumeMounts[].readOnly = true.spec.containers[].volumeMounts[].mountPath 指定为您希望在其中显示机密的未使用目录名称。 修改您的图像或命令行,以便程序在该目录中查找文件。秘密 data 映射中的每个密钥都成为 mountPath 下的文件名。

    Secret 挂载到卷中的Pod 示例:

    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
    

    【讨论】:

    • 嗨@NIkola,谢谢你的回答,我知道如何创建配置映射并传递给 contianer。但是,我的问题是,当我使用 Operator-sdk 创建 Deployment 资源时,operator Controller 是如何获取这些值的?
    • 嗨,乔,我已经修改了上面的答案,在golang 中包含示例,这些示例演示了如何在控制器中获取值。基本上,在配置您的Deployment 以便您的容器将ConfigMap 和/或Secret 作为环境变量之后,在您的控制器代码中您将获得具有标准Go 函数的环境变量,例如username := os.Getenv("SECRET_USERNAME")username, ok := os.LookupEnv("SECRET_USERNAME")
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 2011-12-13
    • 2019-01-07
    • 1970-01-01
    相关资源
    最近更新 更多