使用 PodPreset 将信息注入 Pod

FEATURE STATE: Kubernetes v1.6 [alpha]

本页展示如何在创建 Pod 时 使用 PodPreset 对象将类似 SecretSecret 用于存储敏感信息,如密码、OAuth 令牌和 SSH 密钥。 、卷挂载和 环境变量容器环境变量提供了运行容器化应用所必须的一些重要信息。 这类信息注入到 Pod 中。

准备开始

你需要一个运行的 Kubernetes 集群以及配置好与集群通信的 kubectl 命令行工具。 如果你还没有集群,可以使用 Minikube 安装一个。 确保你已经在集群中启用了 PodPreset

使用 PodPreset 来注入环境变量和卷

在这一步中,你要创建一个 PodPreset 对象,其中包含卷挂载和一个环境变量。 下面是 PodPreset 的清单:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

PodPreset 对象的名称必须是一个合法的 DNS 子域名

在清单中,你可以看到 PodPreset 有一个名为 DB_PORT 的环境变量定义, 和一个名为 cache-volume 的卷挂载定义,该卷挂载于 /cache 下。 选择算符选择算符允许用户通过标签对一组资源对象进行筛选过滤。 设定此 PodPreset 将应用于所有匹配 role:frontend 标签的 Pods。

创建 PodPreset:

kubectl apply -f https://k8s.io/examples/podpreset/preset.yaml

检查所创建的 PodPreset:

kubectl get podpreset
NAME             AGE
allow-database   1m

下面的清单定义了一个带有标签 role: frontend 的 Pod(与 PodPreset 的选择算符匹配):

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      ports:
        - containerPort: 80

创建 Pod:

kubectl create -f https://k8s.io/examples/podpreset/pod.yaml

验证 Pod 出于运行状态:

kubectl get pods
NAME      READY     STATUS    RESTARTS   AGE
website   1/1       Running   0          4m

查看被准入控制器更改过的 Pod 规约,以了解 PodPreset 在 Pod 上执行过的操作:

kubectl get pod website -o yaml
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
      env:
        - name: DB_PORT
          value: "6379"
  volumes:
    - name: cache-volume
      emptyDir: {}

Pod 的环境变量 DB_PORTvolumeMountpodpreset.admission.kubernetes.io 注解 表明 PodPreset 确实起了作用。

带有 ConfigMap 的 Pod Spec 示例

这里的示例展示了如何通过 PodPreset 修改 Pod 规约,PodPreset 中定义了 ConfigMap 作为环境变量取值来源。

包含 ConfigMap 定义的清单:

apiVersion: v1
kind: ConfigMap
metadata:
  name: etcd-env-config
data:
  number_of_members: "1"
  initial_cluster_state: new
  initial_cluster_token: DUMMY_ETCD_INITIAL_CLUSTER_TOKEN
  discovery_token: DUMMY_ETCD_DISCOVERY_TOKEN
  discovery_url: http://etcd_discovery:2379
  etcdctl_peers: http://etcd:2379
  duplicate_key: FROM_CONFIG_MAP
  REPLACE_ME: "a value"

创建 ConfigMap:

kubectl create -f https://k8s.io/examples/podpreset/configmap.yaml

引用该 ConfigMap 的 PodPreset 的清单:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
    - name: duplicate_key
      value: FROM_ENV
    - name: expansion
      value: $(REPLACE_ME)
  envFrom:
    - configMapRef:
        name: etcd-env-config
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

创建 PodPreset:

kubectl create -f https://k8s.io/examples/podpreset/allow-db.yaml

下面的清单包含与 PodPreset 匹配的 Pod:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      ports:
        - containerPort: 80

创建 Pod:

kubectl create -f https://k8s.io/examples/podpreset/pod.yaml

查看 Pod 规约被准入控制器修改后的结果,了解 PodPreset 应用之后的效果:

kubectl get pod website -o yaml
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
      env:
        - name: DB_PORT
          value: "6379"
        - name: duplicate_key
          value: FROM_ENV
        - name: expansion
          value: $(REPLACE_ME)
      envFrom:
        - configMapRef:
            name: etcd-env-config
  volumes:
    - name: cache-volume
      emptyDir: {}

Pod 的环境变量 DB_PORTpodpreset.admission.kubernetes.io 注解 表明 PodPreset 确实起了作用。

带有 Pod Spec 的 ReplicaSet 示例

以下示例展示了(通过 ReplicaSet 创建 Pod 后)只有 Pod 规约会被 PodPreset 所修改, 其他资源类型(如 ReplicaSet、Deployment)不受影响。

下面是本例所用 PodPreset 的清单:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

创建 Preset:

kubectl apply -f https://k8s.io/examples/podpreset/preset.yaml

此清单定义了一个管理三个应用 Pod 的 ReplicaSet:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      role: frontend
    matchExpressions:
      - {key: role, operator: In, values: [frontend]}
  template:
    metadata:
      labels:
        app: guestbook
        role: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        env:
          - name: GET_HOSTS_FROM
            value: dns
        ports:
          - containerPort: 80

创建 ReplicaSet:

kubectl create -f https://k8s.io/examples/podpreset/replicaset.yaml

验证 ReplicaSet 所创建的 Pod 处于运行状态:

kubectl get pods

输出显示 Pod 正在运行:

NAME             READY   STATUS    RESTARTS   AGE
frontend-2l94q   1/1     Running   0          2m18s
frontend-6vdgn   1/1     Running   0          2m18s
frontend-jzt4p   1/1     Running   0          2m18s

查看 ReplicaSet 的 spec 内容:

kubectl get replicasets frontend -o yaml
说明:

ReplicaSet 对象的 spec 未被改变,ReplicaSet 也没有被添加 podpreset.admission.kubernetes.io 注解。这是因为,PodPreset 只针对 Pod 对象起作用。

要查看 PodPreset 的应用效果,你需要逐个地查看 Pod。

查看被影响的 Pod 的规约的命令是:

kubectl get pod --selector=role=frontend -o yaml
apiVersion: v1
kind: Pod
metadata:
  name: frontend
  labels:
    app: guestbook
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
spec:
  containers:
  - name: php-redis
    image: gcr.io/google_samples/gb-frontend:v3
    resources:
      requests:
        cpu: 100m
        memory: 100Mi
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
    env:
    - name: GET_HOSTS_FROM
      value: dns
    - name: DB_PORT
      value: "6379"
    ports:
    - containerPort: 80
  volumes:
  - name: cache-volume
    emptyDir: {}

再一次,Pod 的 podpreset.admission.kubernetes.io 注解表明 PodPreset 已经被应用过。

多 PodPreset 示例

这里的示例展示了如何通过多个 PodPreset 对象修改 Pod 规约。

第一个 PodPreset 的清单如下:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

为此例创建第一个 PodPreset:

kubectl apply -f https://k8s.io/examples/podpreset/preset.yaml

下面是第二个 PodPreset 的清单:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: proxy
spec:
  selector:
    matchLabels:
      role: frontend
  volumeMounts:
    - mountPath: /etc/proxy/configs
      name: proxy-volume
  volumes:
    - name: proxy-volume
      emptyDir: {}

创建第二个 PodPreset:

kubectl apply -f https://k8s.io/examples/podpreset/proxy.yaml

下面是包含可被修改的 Pod 定义的清单(此 Pod 同时被两个 PodPreset 匹配到):

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      ports:
        - containerPort: 80

创建 Pod:

kubectl create -f https://k8s.io/examples/podpreset/pod.yaml

查看被准入控制器更改后的 Pod 规约,以了解被两个 PodPreset 一同修改 后的效果:

kubectl get pod website -o yaml
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
    podpreset.admission.kubernetes.io/podpreset-proxy: "resource version"
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
        - mountPath: /etc/proxy/configs
          name: proxy-volume
      ports:
        - containerPort: 80
      env:
        - name: DB_PORT
          value: "6379"
  volumes:
    - name: cache-volume
      emptyDir: {}
    - name: proxy-volume
      emptyDir: {}

Pod 定义中的 DB_PORT 环境变量、proxy-volume 卷挂载以及 两个 podpreset.admission.kubernetes.io 可以证明两个 Preset 都被应用了。

冲突示例

这里的示例展示了 PodPreset 与原 Pod 存在冲突时,Pod 规约不会被修改。 本例中的冲突是指 PodPreset 中的 volumeMount 与 Pod 中定义的卷挂载在 mountPath 上有冲突。

下面是 PodPreset 的清单:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: other-volume
  volumes:
    - name: other-volume
      emptyDir: {}

注意 mountPath 的取值是 /cache。 创建 PodPreset:

kubectl apply -f https://k8s.io/examples/podpreset/conflict-preset.yaml

下面是 Pod 的清单:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
  volumes:
    - name: cache-volume
      emptyDir: {}

注意清单中 volumeMount 元素的取值与 PodPreset 中的路径值相同。

创建 Pod:

kubectl create -f https://k8s.io/examples/podpreset/conflict-pod.yaml

查看 Pod 规约:

kubectl get pod website -o yaml
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
  volumes:
    - name: cache-volume
      emptyDir: {}

这里你可以看到 Pod 上并没有 PodPreset 的注解 podpreset.admission.kubernetes.io`。 这意味着没有 PodPreset 被应用到 Pod 之上。

不过 PodPreset 准入控制器 还是为所发生的冲突留下了一条警告性质的日志。 你可以通过 kubectl 来查看此警告信息:

kubectl -n kube-system logs -l=component=kube-apiserver

输出类似于:

W1214 13:00:12.987884       1 admission.go:147] conflict occurred while applying podpresets: allow-database on pod:  err: merging volume mounts for allow-database has a conflict on mount path /cache:
v1.VolumeMount{Name:"other-volume", ReadOnly:false, MountPath:"/cache", SubPath:"", MountPropagation:(*v1.MountPropagationMode)(nil), SubPathExpr:""}
does not match
core.VolumeMount{Name:"cache-volume", ReadOnly:false, MountPath:"/cache", SubPath:"", MountPropagation:(*core.MountPropagationMode)(nil), SubPathExpr:""}
 in container

注意这里关于卷挂载路径冲突的消息。

删除 Pod Preset

一旦用户不再需要 PodPreset,可以使用 kubectl 将其删除:

kubectl delete podpreset allow-database

输出显示 PodPreset 已经被删除:

podpreset "allow-database" deleted
最后修改 August 17, 2020 at 9:03 AM PST: [zh] Rework PodPreset task (e365b5d3e)