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:
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: {}
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:
kubectl apply -f https://k8s.io/examples/podpreset/preset.yaml
Verify that the PodPreset has been created:
kubectl get podpreset
NAME CREATED AT
allow-database 2020-01-24T08:54:29Z
This manifest defines a Pod labelled role: frontend
(matching the PodPreset’s selector):
apiVersion: v1
kind: Pod
metadata:
name: website
labels:
app: website
role: frontend
spec:
containers:
- name: website
image: nginx
ports:
- containerPort: 80
Create the Pod:
kubectl create -f https://k8s.io/examples/podpreset/pod.yaml
Verify that the Pod is running:
kubectl get pods
The output shows that the Pod is running:
NAME READY STATUS RESTARTS AGE
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:
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: {}
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:
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"
Create the ConfigMap:
kubectl create -f https://k8s.io/examples/podpreset/configmap.yaml
Here is a PodPreset manifest referencing that ConfigMap:
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: {}
Create the preset that references the ConfigMap:
kubectl create -f https://k8s.io/examples/podpreset/allow-db.yaml
The following manifest defines a Pod matching the PodPreset for this example:
apiVersion: v1
kind: Pod
metadata:
name: website
labels:
app: website
role: frontend
spec:
containers:
- name: website
image: nginx
ports:
- containerPort: 80
Create the Pod:
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:
kubectl get pod website -o yaml
podpreset/allow-db-merged.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: {}
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:
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: {}
Create the preset:
kubectl apply -f https://k8s.io/examples/podpreset/preset.yaml
This manifest defines a ReplicaSet that manages three application Pods:
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
Create the ReplicaSet:
kubectl create -f https://k8s.io/examples/podpreset/replicaset.yaml
Verify that the Pods created by the ReplicaSet are running:
kubectl get pods
The output shows that the Pods are running:
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
View the spec
of the ReplicaSet:
kubectl get replicasets frontend -o yaml
Note:
The ReplicaSet object’s
spec
was not changed, nor does the ReplicaSet contain apodpreset.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:
kubectl get pod --selector=role=frontend -o yaml
podpreset/replicaset-merged.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: {}
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:
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: {}
Create the first PodPreset for this example:
kubectl apply -f https://k8s.io/examples/podpreset/preset.yaml
Here is the manifest for the second 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: {}
Create the second preset:
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):
apiVersion: v1
kind: Pod
metadata:
name: website
labels:
app: website
role: frontend
spec:
containers:
- name: website
image: nginx
ports:
- containerPort: 80
Create the Pod:
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:
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: {}
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
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: {}
Note the mountPath
value of /cache
.
Create the preset:
kubectl apply -f https://k8s.io/examples/podpreset/conflict-preset.yaml
Here is the manifest for the 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: {}
Note the volumeMount element with the same path as in the PodPreset.
Create the Pod:
kubectl create -f https://k8s.io/examples/podpreset/conflict-pod.yaml
View the Pod spec:
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: {}
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
:
kubectl -n kube-system logs -l=component=kube-apiserver
The output should look similar to:
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
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
:
kubectl delete podpreset allow-database
The output shows that the PodPreset was deleted:
podpreset "allow-database" deleted