将多个 k8s 机密组合到一个 env 变量中



我的k8s命名空间包含一个在部署时(由svcat创建)Secret,因此事先不知道这些值。

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: my-database-credentials
data:
  hostname: ...
  port: ...
  database: ...
  username: ...
  password: ...

Deployment需要以略有不同的格式注入这些值:

...
containers:
  env:
  - name: DATABASE_URL
    valueFrom:
      secretKeyRef:
        name: my-database-credentials
        key: jdbc:postgresql:<hostname>:<port>/<database> // ??
  - name: DATABASE_USERNAME
    valueFrom:
      secretKeyRef:
        name: my-database-credentials
        key: username
  - name: DATABASE_PASSWORD
    valueFrom:
      secretKeyRef:
        name: my-database-credentials
        key: password

DATABASE_URL需要由先前定义的密钥的hostnameport、"数据库"组成。

有没有办法做这个构图?

Kubernetes 允许您使用先前定义的环境变量作为配置中其他地方的后续环境变量的一部分。来自 Kubernetes API 参考文档:

变量引用 $(VAR_NAME) 使用容器中先前定义的环境变量和任何服务环境变量进行扩展。

$(...)语法定义容器的相互依赖的环境变量。

因此,您可以先将所需的机密值提取到环境变量中,然后使用这些变量组成DATABASE_URL

...
containers:
  env:
  - name: DB_URL_HOSTNAME               // part 1
    valueFrom:
      secretKeyRef:
        name: my-database-credentials
        key: hostname
  - name: DB_URL_PORT                   // part 2
    valueFrom:
      secretKeyRef:
        name: my-database-credentials
        key: port
  - name: DB_URL_DBNAME                 // part 3
    valueFrom:
      secretKeyRef:
        name: my-database-credentials
        key: database
  - name: DATABASE_URL                  // combine
    value: jdbc:postgresql:$(DB_URL_HOSTNAME):$(DB_URL_PORT)/$(DB_URL_DBNAME)
...

你可以做几件我能想到的事情:

    使用机密卷
  1. 并创建一个启动脚本,该脚本从卷中读取机密,然后使用 DATABASE_URL 环境变量启动应用程序。

    apiVersion: v1
    kind: Pod
    metadata:
      name: mypod
    spec:
      containers:
      - name: mypod
        image: your_db_container
        command: [ "yourscript.sh" ]
        volumeMounts:
        - name: mycreds
          mountPath: "/etc/credentials"
      volumes:
      - name: mycreds
        secret:
          secretName: my-database-credentials
          defaultMode: 256
    
  2. 在容器规范的command键中传递 env 变量:

    apiVersion: v1
    kind: Pod
    metadata:
      name: mypod
    spec:
      containers:
      - name: mypod
        image: your_db_container
        command: [ "/bin/sh", "-c", "DATABASE_URL=jdbc:postgresql:<hostname>:<port>/<database>/$(DATABASE_USERNAME):$(DATABASE_PASSWORD) /start/yourdb" ]
        env:
        - name: DATABASE_USERNAME
          valueFrom:
            secretKeyRef:
              name: my-database-credentials
              key: username
        - name: DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
            name: my-database-credentials
            key: password
    

如果所有前变量都定义为 env 变量:

-  { name: DATABASE_URL, value: '{{ printf "jdbc:postgresql:$(DATABASE_HOST):$(DATABASE_PORT)/$(DB_URL_DBNAME)" }}'}

使用此语句,您还可以从 values.yaml 文件中引入 vlaues:

例如:

如果可能在值文件中定义了DB_URL_DBNAME:

-  { name: DATABASE_URL, value: '{{ printf "jdbc:postgresql:$(DATABASE_HOST):$(DATABASE_PORT)/%s" .Values.database.DB_URL_DBNAME }}'}

有几种方法可以走(按复杂性递增顺序):

  1. 在将参数放入密钥之前对其进行修改(扩展用于在其中插入信息的任何内容)。

  2. 脚本添加到 Pod/容器中,以将传入参数(环境变量或命令参数)修改为所需的参数。如果不能或不想拥有自己的容器映像,可以将额外的脚本作为卷添加到容器中,并将容器的command字段设置为覆盖容器映像启动命令。

  3. 向 Kubernetes 添加一个
  4. 工具以在"幕后"执行自动管理:您可以添加一个动态准入控制器来执行重整,或者您可以创建一个 Kubernetes 运算符并添加自定义资源定义(CRD 会告诉操作员要监视哪些秘密更改,操作员将读取值并生成您想要的任何其他条目)。

最新更新