在Kubernetes中,环境变量是一种常见的配置方式,用于将配置信息传递给运行在容器内的应用程序。本教程主要介绍如何为 Kubernetes Pod 中的容器定义相互依赖的环境变量和为容器设置环境变量,并通过环境变量将 Pod 信息呈现给容器。
必须拥有一个 Kubernetes 的集群,同时必须配置 kubectl 命令行工具与集群通信。 建议在至少有两个不作为控制平面主机的节点的集群上运行本教程。
一、定义环境变量
当创建一个 Pod 时,可以为运行在 Pod 中的容器设置相互依赖的环境变量。 若要设置相互依赖的环境变量,可以在配置清单文件的 env 的 value 中使用 $(VAR_NAME)。
在本练习中,会创建一个单容器的 Pod。 此 Pod 的配置文件定义了一个已定义常用用法的相互依赖的环境变量。 下面是此 Pod 的配置清单:
apiVersion: v1 kind: Pod metadata: name: dependent-envars-demo spec: containers: - name: dependent-envars-demo args: - while true; do echo -en '\n'; printf UNCHANGED_REFERENCE=$UNCHANGED_REFERENCE'\n'; printf SERVICE_ADDRESS=$SERVICE_ADDRESS'\n';printf ESCAPED_REFERENCE=$ESCAPED_REFERENCE'\n'; sleep 30; done; command: - sh - -c image: busybox:1.28 env: - name: SERVICE_PORT value: "80" - name: SERVICE_IP value: "172.17.0.1" - name: UNCHANGED_REFERENCE value: "$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)" - name: PROTOCOL value: "https" - name: SERVICE_ADDRESS value: "$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)" - name: ESCAPED_REFERENCE value: "$$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
1、依据清单创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/dependent-envars.yaml pod/dependent-envars-demo created
2、列出运行的 Pod:
kubectl get pods dependent-envars-demo
NAME READY STATUS RESTARTS AGE dependent-envars-demo 1/1 Running 0 9s
3、检查 Pod 中运行容器的日志:
kubectl logs pod/dependent-envars-demo
UNCHANGED_REFERENCE=$(PROTOCOL)://172.17.0.1:80 SERVICE_ADDRESS=https://172.17.0.1:80 ESCAPED_REFERENCE=$(PROTOCOL)://172.17.0.1:80
如上所示,已经定义了 SERVICE_ADDRESS 的正确依赖引用, UNCHANGED_REFERENCE 的错误依赖引用, 并跳过了 ESCAPED_REFERENCE 的依赖引用。如果环境变量被引用时已事先定义,则引用可以正确解析, 比如 SERVICE_ADDRESS 的例子。
请注意,env 列表中的顺序很重要。如果某环境变量定义出现在列表的尾部, 则在解析列表前部环境变量时不会视其为“已被定义”。 这就是为什么 UNCHANGED_REFERENCE 在上面的示例中解析 $(PROTOCOL) 失败的原因。
当环境变量未定义或仅包含部分变量时,未定义的变量会被当做普通字符串对待, 比如 UNCHANGED_REFERENCE 的例子。 注意,解析不正确的环境变量通常不会阻止容器启动。
$(VAR_NAME) 这样的语法可以用两个 $ 转义,即:$$(VAR_NAME)。 无论引用的变量是否定义,转义的引用永远不会展开。 这一点可以从上面 ESCAPED_REFERENCE 的例子得到印证。
二、设置环境变量
创建 Pod 时,可以为其下的容器设置环境变量。通过配置文件的 env 或者 envFrom 字段来设置环境变量。
- env 和 envFrom 字段具有不同的效果;
- env :可以为容器设置环境变量,直接为所给的每个变量指定一个值;
- envFrom :可以通过引用 ConfigMap 或 Secret 来设置容器的环境变量。 使用 envFrom 时,引用的 ConfigMap 或 Secret 中的所有键值对都被设置为容器的环境变量。 也可以指定一个通用的前缀字符串。
本示例中,将创建一个只包含单个容器的 Pod。此 Pod 的配置文件中设置环境变量的名称为 DEMO_GREETING, 其值为 “Hello from the environment”。下面是此 Pod 的配置清单:
apiVersion: v1 kind: Pod metadata: name: envar-demo labels: purpose: demonstrate-envars spec: containers: - name: envar-demo-container image: gcr.io/google-samples/node-hello:1.0 env: - name: DEMO_GREETING value: "Hello from the environment" - name: DEMO_FAREWELL value: "Such a sweet sorrow"
1、基于配置清单创建一个 Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/envars.yaml
2、获取正在运行的 Pod 信息:
kubectl get pods -l purpose=demonstrate-envars
查询结果应为:
NAME READY STATUS RESTARTS AGE envar-demo 1/1 Running 0 9s
3、列出 Pod 容器的环境变量:
kubectl exec envar-demo -- printenv
打印结果应为:
NODE_VERSION=4.4.2 EXAMPLE_SERVICE_PORT_8080_TCP_ADDR=10.3.245.237 HOSTNAME=envar-demo ... DEMO_GREETING=Hello from the environment DEMO_FAREWELL=Such a sweet sorrow
注意:
- 通过 env 或 envFrom 字段设置的环境变量将覆盖容器镜像中指定的所有环境变量;
- 环境变量可以互相引用,但是顺序很重要。 使用在相同上下文中定义的其他变量的变量必须在列表的后面。 同样,请避免使用循环引用。
在 Pod 的配置中定义的、位于 .spec.containers[*].env[*] 下的环境变量 可以在配置的其他地方使用,例如可用在为 Pod 的容器设置的命令和参数中。 在下面的示例配置中,环境变量 GREETING、HONORIFIC 和 NAME 分别设置为 Warm greetings to、 The Most Honorable 和 Kubernetes。 环境变量 MESSAGE 将所有这些环境变量的集合组合起来, 然后再传递给容器 env-print-demo 的 CLI 参数中使用。
apiVersion: v1 kind: Pod metadata: name: print-greeting spec: containers: - name: env-print-demo image: bash env: - name: GREETING value: "Warm greetings to" - name: HONORIFIC value: "The Most Honorable" - name: NAME value: "Kubernetes" command: ["echo"] args: ["$(GREETING) $(HONORIFIC) $(NAME)"]
创建后,命令 echo Warm greetings to The Most Honorable Kubernetes 将在容器中运行。
三、呈现Pod信息
在 Kubernetes 中有两种方式可以将 Pod 和容器字段呈现给运行中的容器:
- 如本任务所述的环境变量;
- 卷文件。
这两种呈现 Pod 和容器字段的方式统称为 downward API。
Service 是 Kubernetes 管理的容器化应用之间的主要通信模式,因此在运行时能发现这些 Service 是很有帮助的。
在这部分练习中,将创建一个包含一个容器的 Pod。并将 Pod 级别的字段作为环境变量投射到正在运行的容器中:
apiVersion: v1 kind: Pod metadata: name: dapi-envars-fieldref spec: containers: - name: test-container image: registry.k8s.io/busybox command: [ "sh", "-c"] args: - while true; do echo -en '\n'; printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE; printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT; sleep 10; done; env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: MY_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: MY_POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: MY_POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: MY_POD_SERVICE_ACCOUNT valueFrom: fieldRef: fieldPath: spec.serviceAccountName restartPolicy: Never
这个清单中,可以看到五个环境变量。env 字段定义了一组环境变量。 数组中第一个元素指定 MY_NODE_NAME 这个环境变量从 Pod 的 spec.nodeName 字段获取变量值。 同样,其它环境变量也是从 Pod 的字段获取它们的变量值。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/dapi-envars-pod.yaml
验证 Pod 中的容器运行正常:
# 如果新创建的 Pod 还是处于不健康状态,请重新运行此命令几次。 kubectl get pods
查看容器日志:
kubectl logs dapi-envars-fieldref
输出信息显示了所选择的环境变量的值:
minikube dapi-envars-fieldref default 172.17.0.4 default
要了解为什么这些值出现在日志中,请查看配置文件中的 command 和 args 字段。 当容器启动时,它将五个环境变量的值写入标准输出。每十秒重复执行一次。
接下来,进入 Pod 中运行的容器,打开一个 Shell:
kubectl exec -it dapi-envars-fieldref -- sh
在 Shell 中,查看环境变量:
# 在容器内的 `shell` 中运行 printenv
输出信息显示环境变量已经设置为 Pod 字段的值。
MY_POD_SERVICE_ACCOUNT=default ... MY_POD_NAMESPACE=default MY_POD_IP=172.17.0.4 ... MY_NODE_NAME=minikube ... MY_POD_NAME=dapi-envars-fieldref
前面的练习中,将 Pod 级别的字段作为环境变量的值。 接下来这个练习中,将传递属于 Pod 定义的字段,但这些字段取自特定容器而不是整个 Pod。
这里是只包含一个容器的 Pod 的清单:
apiVersion: v1 kind: Pod metadata: name: dapi-envars-resourcefieldref spec: containers: - name: test-container image: registry.k8s.io/busybox:1.24 command: [ "sh", "-c"] args: - while true; do echo -en '\n'; printenv MY_CPU_REQUEST MY_CPU_LIMIT; printenv MY_MEM_REQUEST MY_MEM_LIMIT; sleep 10; done; resources: requests: memory: "32Mi" cpu: "125m" limits: memory: "64Mi" cpu: "250m" env: - name: MY_CPU_REQUEST valueFrom: resourceFieldRef: containerName: test-container resource: requests.cpu - name: MY_CPU_LIMIT valueFrom: resourceFieldRef: containerName: test-container resource: limits.cpu - name: MY_MEM_REQUEST valueFrom: resourceFieldRef: containerName: test-container resource: requests.memory - name: MY_MEM_LIMIT valueFrom: resourceFieldRef: containerName: test-container resource: limits.memory restartPolicy: Never
这个清单中,可以看到四个环境变量。env 字段定义了一组环境变量。 数组中第一个元素指定 MY_CPU_REQUEST 这个环境变量从容器的 requests.cpu 字段获取变量值。同样,其它的环境变量也是从特定于这个容器的字段中获取它们的变量值。
创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/inject/dapi-envars-container.yaml
验证 Pod 中的容器运行正常:
# 如果新创建的 Pod 还是处于不健康状态,请重新运行此命令几次。 kubectl get pods
查看容器日志:
kubectl logs dapi-envars-resourcefieldref
输出信息显示了所选择的环境变量的值:
1 1 33554432 67108864