Inject Information into Pods Using a PodPreset

FEATURE STATE: Kubernetes v1.6 [alpha]

This page shows how to use PodPreset objects to inject information like Secrets, volume mounts, and environment variables into Pods at creation time.

Before you begin

You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one using Minikube. Make sure that you have enabled PodPreset in your cluster.

Use Pod presets to inject environment variables and volumes

In this step, you create a preset that has a volume mount and one environment variable. Here is the manifest for the PodPreset:

podpreset/preset.yaml Inject Information into Pods Using a PodPreset - 图1

  1. apiVersion: settings.k8s.io/v1alpha1
  2. kind: PodPreset
  3. metadata:
  4. name: allow-database
  5. spec:
  6. selector:
  7. matchLabels:
  8. role: frontend
  9. env:
  10. - name: DB_PORT
  11. value: "6379"
  12. volumeMounts:
  13. - mountPath: /cache
  14. name: cache-volume
  15. volumes:
  16. - name: cache-volume
  17. emptyDir: {}

The name of a PodPreset object must be a valid DNS subdomain name.

In the manifest, you can see that the preset has an environment variable definition called DB_PORT and a volume mount definition called cache-volume which is mounted under /cache. The selector specifies that the preset will act upon any Pod that is labeled role:frontend.

Create the PodPreset:

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

Verify that the PodPreset has been created:

  1. kubectl get podpreset
  1. NAME CREATED AT
  2. allow-database 2020-01-24T08:54:29Z

This manifest defines a Pod labelled role: frontend (matching the PodPreset’s selector):

podpreset/pod.yaml Inject Information into Pods Using a PodPreset - 图2

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: website
  5. labels:
  6. app: website
  7. role: frontend
  8. spec:
  9. containers:
  10. - name: website
  11. image: nginx
  12. ports:
  13. - containerPort: 80

Create the Pod:

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

Verify that the Pod is running:

  1. kubectl get pods

The output shows that the Pod is running:

  1. NAME READY STATUS RESTARTS AGE
  2. website 1/1 Running 0 4m

View the Pod spec altered by the admission controller in order to see the effects of the preset having been applied:

  1. kubectl get pod website -o yaml

podpreset/merged.yaml Inject Information into Pods Using a PodPreset - 图3

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: website
  5. labels:
  6. app: website
  7. role: frontend
  8. annotations:
  9. podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
  10. spec:
  11. containers:
  12. - name: website
  13. image: nginx
  14. volumeMounts:
  15. - mountPath: /cache
  16. name: cache-volume
  17. ports:
  18. - containerPort: 80
  19. env:
  20. - name: DB_PORT
  21. value: "6379"
  22. volumes:
  23. - name: cache-volume
  24. emptyDir: {}

The DB_PORT environment variable, the volumeMount and the podpreset.admission.kubernetes.io annotation of the Pod verify that the preset has been applied.

Pod spec with ConfigMap example

This is an example to show how a Pod spec is modified by a Pod preset that references a ConfigMap containing environment variables.

Here is the manifest containing the definition of the ConfigMap:

podpreset/configmap.yaml Inject Information into Pods Using a PodPreset - 图4

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: etcd-env-config
  5. data:
  6. number_of_members: "1"
  7. initial_cluster_state: new
  8. initial_cluster_token: DUMMY_ETCD_INITIAL_CLUSTER_TOKEN
  9. discovery_token: DUMMY_ETCD_DISCOVERY_TOKEN
  10. discovery_url: http://etcd_discovery:2379
  11. etcdctl_peers: http://etcd:2379
  12. duplicate_key: FROM_CONFIG_MAP
  13. REPLACE_ME: "a value"

Create the ConfigMap:

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

Here is a PodPreset manifest referencing that ConfigMap:

podpreset/allow-db.yaml Inject Information into Pods Using a PodPreset - 图5

  1. apiVersion: settings.k8s.io/v1alpha1
  2. kind: PodPreset
  3. metadata:
  4. name: allow-database
  5. spec:
  6. selector:
  7. matchLabels:
  8. role: frontend
  9. env:
  10. - name: DB_PORT
  11. value: "6379"
  12. - name: duplicate_key
  13. value: FROM_ENV
  14. - name: expansion
  15. value: $(REPLACE_ME)
  16. envFrom:
  17. - configMapRef:
  18. name: etcd-env-config
  19. volumeMounts:
  20. - mountPath: /cache
  21. name: cache-volume
  22. volumes:
  23. - name: cache-volume
  24. emptyDir: {}

Create the preset that references the ConfigMap:

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

The following manifest defines a Pod matching the PodPreset for this example:

podpreset/pod.yaml Inject Information into Pods Using a PodPreset - 图6

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: website
  5. labels:
  6. app: website
  7. role: frontend
  8. spec:
  9. containers:
  10. - name: website
  11. image: nginx
  12. ports:
  13. - containerPort: 80

Create the Pod:

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

View the Pod spec altered by the admission controller in order to see the effects of the preset having been applied:

  1. kubectl get pod website -o yaml

podpreset/allow-db-merged.yaml Inject Information into Pods Using a PodPreset - 图7

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: website
  5. labels:
  6. app: website
  7. role: frontend
  8. annotations:
  9. podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
  10. spec:
  11. containers:
  12. - name: website
  13. image: nginx
  14. volumeMounts:
  15. - mountPath: /cache
  16. name: cache-volume
  17. ports:
  18. - containerPort: 80
  19. env:
  20. - name: DB_PORT
  21. value: "6379"
  22. - name: duplicate_key
  23. value: FROM_ENV
  24. - name: expansion
  25. value: $(REPLACE_ME)
  26. envFrom:
  27. - configMapRef:
  28. name: etcd-env-config
  29. volumes:
  30. - name: cache-volume
  31. emptyDir: {}

The DB_PORT environment variable and the podpreset.admission.kubernetes.io annotation of the Pod verify that the preset has been applied.

ReplicaSet with Pod spec example

This is an example to show that only Pod specs are modified by Pod presets. Other workload types like ReplicaSets or Deployments are unaffected.

Here is the manifest for the PodPreset for this example:

podpreset/preset.yaml Inject Information into Pods Using a PodPreset - 图8

  1. apiVersion: settings.k8s.io/v1alpha1
  2. kind: PodPreset
  3. metadata:
  4. name: allow-database
  5. spec:
  6. selector:
  7. matchLabels:
  8. role: frontend
  9. env:
  10. - name: DB_PORT
  11. value: "6379"
  12. volumeMounts:
  13. - mountPath: /cache
  14. name: cache-volume
  15. volumes:
  16. - name: cache-volume
  17. emptyDir: {}

Create the preset:

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

This manifest defines a ReplicaSet that manages three application Pods:

podpreset/replicaset.yaml Inject Information into Pods Using a PodPreset - 图9

  1. apiVersion: apps/v1
  2. kind: ReplicaSet
  3. metadata:
  4. name: frontend
  5. spec:
  6. replicas: 3
  7. selector:
  8. matchLabels:
  9. role: frontend
  10. matchExpressions:
  11. - {key: role, operator: In, values: [frontend]}
  12. template:
  13. metadata:
  14. labels:
  15. app: guestbook
  16. role: frontend
  17. spec:
  18. containers:
  19. - name: php-redis
  20. image: gcr.io/google_samples/gb-frontend:v3
  21. resources:
  22. requests:
  23. cpu: 100m
  24. memory: 100Mi
  25. env:
  26. - name: GET_HOSTS_FROM
  27. value: dns
  28. ports:
  29. - containerPort: 80

Create the ReplicaSet:

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

Verify that the Pods created by the ReplicaSet are running:

  1. kubectl get pods

The output shows that the Pods are running:

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

View the spec of the ReplicaSet:

  1. kubectl get replicasets frontend -o yaml

Note:

The ReplicaSet object’s spec was not changed, nor does the ReplicaSet contain a podpreset.admission.kubernetes.io annotation. This is because a PodPreset only applies to Pod objects.

To see the effects of the preset having been applied, you need to look at individual Pods.

The command to view the specs of the affected Pods is:

  1. kubectl get pod --selector=role=frontend -o yaml

podpreset/replicaset-merged.yaml Inject Information into Pods Using a PodPreset - 图10

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: frontend
  5. labels:
  6. app: guestbook
  7. role: frontend
  8. annotations:
  9. podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
  10. spec:
  11. containers:
  12. - name: php-redis
  13. image: gcr.io/google_samples/gb-frontend:v3
  14. resources:
  15. requests:
  16. cpu: 100m
  17. memory: 100Mi
  18. volumeMounts:
  19. - mountPath: /cache
  20. name: cache-volume
  21. env:
  22. - name: GET_HOSTS_FROM
  23. value: dns
  24. - name: DB_PORT
  25. value: "6379"
  26. ports:
  27. - containerPort: 80
  28. volumes:
  29. - name: cache-volume
  30. emptyDir: {}

Again the podpreset.admission.kubernetes.io annotation of the Pods verifies that the preset has been applied.

Multiple Pod presets example

This is an example to show how a Pod spec is modified by multiple Pod presets.

Here is the manifest for the first PodPreset:

podpreset/preset.yaml Inject Information into Pods Using a PodPreset - 图11

  1. apiVersion: settings.k8s.io/v1alpha1
  2. kind: PodPreset
  3. metadata:
  4. name: allow-database
  5. spec:
  6. selector:
  7. matchLabels:
  8. role: frontend
  9. env:
  10. - name: DB_PORT
  11. value: "6379"
  12. volumeMounts:
  13. - mountPath: /cache
  14. name: cache-volume
  15. volumes:
  16. - name: cache-volume
  17. emptyDir: {}

Create the first PodPreset for this example:

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

Here is the manifest for the second PodPreset:

podpreset/proxy.yaml Inject Information into Pods Using a PodPreset - 图12

  1. apiVersion: settings.k8s.io/v1alpha1
  2. kind: PodPreset
  3. metadata:
  4. name: proxy
  5. spec:
  6. selector:
  7. matchLabels:
  8. role: frontend
  9. volumeMounts:
  10. - mountPath: /etc/proxy/configs
  11. name: proxy-volume
  12. volumes:
  13. - name: proxy-volume
  14. emptyDir: {}

Create the second preset:

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

Here’s a manifest containing the definition of an applicable Pod (matched by two PodPresets):

podpreset/pod.yaml Inject Information into Pods Using a PodPreset - 图13

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: website
  5. labels:
  6. app: website
  7. role: frontend
  8. spec:
  9. containers:
  10. - name: website
  11. image: nginx
  12. ports:
  13. - containerPort: 80

Create the Pod:

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

View the Pod spec altered by the admission controller in order to see the effects of both presets having been applied:

  1. kubectl get pod website -o yaml

podpreset/multi-merged.yaml Inject Information into Pods Using a PodPreset - 图14

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: website
  5. labels:
  6. app: website
  7. role: frontend
  8. annotations:
  9. podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
  10. podpreset.admission.kubernetes.io/podpreset-proxy: "resource version"
  11. spec:
  12. containers:
  13. - name: website
  14. image: nginx
  15. volumeMounts:
  16. - mountPath: /cache
  17. name: cache-volume
  18. - mountPath: /etc/proxy/configs
  19. name: proxy-volume
  20. ports:
  21. - containerPort: 80
  22. env:
  23. - name: DB_PORT
  24. value: "6379"
  25. volumes:
  26. - name: cache-volume
  27. emptyDir: {}
  28. - name: proxy-volume
  29. emptyDir: {}

The DB_PORT environment variable, the proxy-volume VolumeMount and the two podpreset.admission.kubernetes.io annotations of the Pod verify that both presets have been applied.

Conflict example

This is an example to show how a Pod spec is not modified by a Pod preset when there is a conflict. The conflict in this example consists of a VolumeMount in the PodPreset conflicting with a Pod that defines the same mountPath.

Here is the manifest for the PodPreset:

podpreset/conflict-preset.yaml Inject Information into Pods Using a PodPreset - 图15

  1. apiVersion: settings.k8s.io/v1alpha1
  2. kind: PodPreset
  3. metadata:
  4. name: allow-database
  5. spec:
  6. selector:
  7. matchLabels:
  8. role: frontend
  9. env:
  10. - name: DB_PORT
  11. value: "6379"
  12. volumeMounts:
  13. - mountPath: /cache
  14. name: other-volume
  15. volumes:
  16. - name: other-volume
  17. emptyDir: {}

Note the mountPath value of /cache.

Create the preset:

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

Here is the manifest for the Pod:

podpreset/conflict-pod.yaml Inject Information into Pods Using a PodPreset - 图16

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: website
  5. labels:
  6. app: website
  7. role: frontend
  8. spec:
  9. containers:
  10. - name: website
  11. image: nginx
  12. volumeMounts:
  13. - mountPath: /cache
  14. name: cache-volume
  15. ports:
  16. - containerPort: 80
  17. volumes:
  18. - name: cache-volume
  19. emptyDir: {}

Note the volumeMount element with the same path as in the PodPreset.

Create the Pod:

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

View the Pod spec:

  1. kubectl get pod website -o yaml

podpreset/conflict-pod.yaml Inject Information into Pods Using a PodPreset - 图17

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: website
  5. labels:
  6. app: website
  7. role: frontend
  8. spec:
  9. containers:
  10. - name: website
  11. image: nginx
  12. volumeMounts:
  13. - mountPath: /cache
  14. name: cache-volume
  15. ports:
  16. - containerPort: 80
  17. volumes:
  18. - name: cache-volume
  19. emptyDir: {}

You can see there is no preset annotation (podpreset.admission.kubernetes.io). Seeing no annotation tells you that no preset has not been applied to the Pod.

However, the PodPreset admission controller logs a warning containing details of the conflict. You can view the warning using kubectl:

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

The output should look similar to:

  1. 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:
  2. v1.VolumeMount{Name:"other-volume", ReadOnly:false, MountPath:"/cache", SubPath:"", MountPropagation:(*v1.MountPropagationMode)(nil), SubPathExpr:""}
  3. does not match
  4. core.VolumeMount{Name:"cache-volume", ReadOnly:false, MountPath:"/cache", SubPath:"", MountPropagation:(*core.MountPropagationMode)(nil), SubPathExpr:""}
  5. in container

Note the conflict message on the path for the VolumeMount.

Deleting a PodPreset

Once you don’t need a PodPreset anymore, you can delete it with kubectl:

  1. kubectl delete podpreset allow-database

The output shows that the PodPreset was deleted:

  1. podpreset "allow-database" deleted