Kubernetes:验证ConfigMap同时引用环境变量与服务名的语法
首先直接给出结论:你当前在ConfigMap里写WORKING_URI: "http://somedomain:${password}@test"的做法行不通——Kubernetes不会自动替换ConfigMap内容里的环境变量占位符,最终你的应用拿到的会是带${password}的原始字符串,而不是Secret里的实际密码值。
为什么原写法失效?
ConfigMap的data字段存储的是静态文本,Kubernetes在创建或加载它的时候,不会解析其中的${xxx}这类环境变量占位符。当你通过envFrom把这个ConfigMap加载到容器环境中时,WORKING_URI的值会原封不动地保留成"http://somedomain:${password}@test",完全不会替换${password}。
另外要顺便提一句:你原来的Deployment配置里apiVersion: v1是错误的,Deployment属于apps API组,正确的apiVersion应该是apps/v1,这个得修正,否则Kubernetes会报错。
两种可行的解决方案
方案1:在Deployment中直接拼接环境变量
最直接的方式是跳过ConfigMap,在Deployment的容器环境变量里直接定义WORKING_URI,利用Kubernetes的环境变量替换机制来拼接密码和Service名:
apiVersion: apps/v1 kind: Deployment metadata: name: test spec: replicas: 1 template: metadata: labels: app: test spec: containers: - name: test image: xxxxxxxxxxx imagePullPolicy: Always env: # 从Secret中加载password变量 - name: password valueFrom: secretKeyRef: name: test key: password # 直接拼接出WORKING_URI,Kubernetes会自动替换$(password) - name: WORKING_URI value: "http://somedomain:$(password)@test" ports: - containerPort: 3000
这里用$(password)是Kubernetes环境变量替换的标准写法,容器启动时会自动把它替换为Secret里的实际密码值;而test作为Service名,Kubernetes内部DNS会自动解析到对应的Service地址,这部分是没问题的。
方案2:通过容器启动命令动态设置
如果你的应用需要从ConfigMap读取配置,或者你更倾向于把URI的格式存在ConfigMap里,那可以在ConfigMap里写占位符,然后在容器启动命令中替换:
首先修改ConfigMap,把占位符写成便于替换的格式:
apiVersion: v1 kind: ConfigMap metadata: name: test labels: app: test data: WORKING_URI_TEMPLATE: "http://somedomain:%s@test"
然后在Deployment的容器启动命令中,用这个模板和环境变量拼接出最终的URI:
apiVersion: apps/v1 kind: Deployment metadata: name: test spec: replicas: 1 template: metadata: labels: app: test spec: containers: - name: test image: xxxxxxxxxxx imagePullPolicy: Always envFrom: - configMapRef: name: test - secretRef: name: test # 用shell命令替换模板中的占位符,然后启动应用 command: ["/bin/sh", "-c"] args: - export WORKING_URI=$(printf "$WORKING_URI_TEMPLATE" "$password") && exec your-actual-app-command ports: - containerPort: 3000
注意把your-actual-app-command换成你容器里实际的启动命令,这样容器启动时会先替换模板得到正确的URI,再启动应用。
内容的提问来源于stack exchange,提问作者userMod2

