首页 > 解决方案 > 在 kubernetes 中,如何访问 configmap 里面的环境变量?

问题描述

我有将 pod 名称附加到“ jdbc_db_url ”属性的用例。位于“ common-configmap.config ”文件中。为了实现,我遵循了以下步骤,但不幸的是无法做到。

第一步: common-configmap.config

# Database Properties
jdbc_auto_commit=false

jdbc_postgresql_driverClassName=org.postgresql.Driver
jdbc_db_url=jdbc:postgresql://dev.postgres.database.azure.com/dbname?ApplicationName=${POD_NAME}

第 2 步: 使用以下命令将 configmap 部署到集群中

kubectl create configmap common-configmap --from-env-file /app/conf/common-configmap.config -n default

第 3 步: 使用以下清单文件创建“myapp”容器和服务

部署清单文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
    meta.helm.sh/release-name: master
    meta.helm.sh/release-namespace: default
  generation: 1
  labels:
    app.kubernetes.io/instance: master
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: myapp
    app.kubernetes.io/version: 4.0.0
    helm.sh/chart: myapp-4.0.0
  name: myapp
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 5
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/instance: master
      app.kubernetes.io/name: myapp
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "true"
      labels:
        app.kubernetes.io/instance: master
        app.kubernetes.io/name: myapp
    spec:
      containers:
      - env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        envFrom:
        - configMapRef:
            name: myapp-configmap
        - configMapRef:
            name: common-configmap
        image: docker.com/myapp:4.0.0
        imagePullPolicy: Always
        name: myapp
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        resources: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always

服务清单文件:

apiVersion: v1
kind: Service
metadata:
  annotations:
    meta.helm.sh/release-name: master
    meta.helm.sh/release-namespace: default
  labels:
    app.kubernetes.io/instance: master
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: myapp
    app.kubernetes.io/version: 4.0.0
    helm.sh/chart: myapp-4.0.0
  name: myapp
  namespace: default
spec:
  ports:
 - name: http
    port: 8080
    protocol: TCP
    targetPort: http
  selector:
    app.kubernetes.io/instance: master
    app.kubernetes.io/name: myapp
  sessionAffinity: None
  type: ClusterIP

验证结果我已进入运行 shell 的容器并打印环境变量:

kubectl exec --stdin --tty myapp-d5db776b9-h25q5 -c myapp -- /bin/sh

实际结果:

# printenv

jdbc_auto_commit=false
jdbc_postgresql_driverClassName=org.postgresql.Driver
jdbc_db_url=jdbc:postgresql://dev.postgres.database.azure.com/dbname?ApplicationName=${POD_NAME}

预期结果:

jdbc_auto_commit=false
jdbc_postgresql_driverClassName=org.postgresql.Driver
jdbc_db_url=jdbc:postgresql://dev.postgres.database.azure.com/dbname?ApplicationName=myapp-d5db776b9-h25q5

预先感谢您的帮助。

标签: kuberneteskubernetes-helmkubernetes-pod

解决方案


你可以使用一个 init-container 来做到这一点,emptyDir它在它和你的主容器之间有一个类型的共享卷。

首先,编辑您的部署以添加一个emptyDir卷和一个 init 容器,并将卷挂载到这两个容器:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
    meta.helm.sh/release-name: master
    meta.helm.sh/release-namespace: default
  generation: 1
  labels:
    app.kubernetes.io/instance: master
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: myapp
    app.kubernetes.io/version: 4.0.0
    helm.sh/chart: myapp-4.0.0
  name: myapp
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 5
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/instance: master
      app.kubernetes.io/name: myapp
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "true"
      labels:
        app.kubernetes.io/instance: master
        app.kubernetes.io/name: myapp
    spec:
      volumes: # emptyDir volume for the entire pod
        - name: config-volume
          emptyDir: {}
      initContainers: # an init container that will compile the env var with the pod name
      - name: config-compiler
        image: bash
        volumeMounts:
        - name: config-compiler
          mountPath: /configs
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        envFrom:
        - configMapRef:
            name: common-configmap
        command: 
        - bash
        - -c
        - 'echo $jdbc_db_url | sed "s/POD_NAME/${POD_NAME}/" > /configs/compiled.env'
      containers:
      - volumeMounts:
        - name: config-compiler
          mountPath: /configs
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        envFrom:
        - configMapRef:
            name: myapp-configmap
        - configMapRef:
            name: common-configmap
        image: docker.com/myapp:4.0.0
        imagePullPolicy: Always
        name: myapp
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        resources: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always

然后,您需要确保您的实际 pod 正在读取 env vars 文件 - 您可以通过编辑入口点脚本添加如下行来做到这一点:

source /configs/compiled.env

或将您的 pod 的命令编辑为如下内容:

command: [ 'source', '/configs/compiled.env;', 'previous-command' ]

上面两个都有点hack-ish - 所以我建议做的是查看你的应用程序默认读取的配置文件,并将你的编译脚本与这些文件相匹配。

例如,如果您的应用程序读取/etc/myapp/confs.d/files.env- 将您的空目录安装到/etc/myapp/confs.d并让 init 容器写入到files.env,并以您的应用程序期望的格式执行此操作(例如,如果它是一个 ini 文件而不是 env 文件,则编译它以使其匹配那种格式)

显然有更好的方法来编译配置文件然后使用sed- 但如果你想(并且有能力)保持简短,这是一个选择


推荐阅读