In the last part, we have covered the Pods, Deployments, and ReplicaSets. This part will cover different ways to inject data into applications like Commands and Arguments, Environment Variables, ConfigMaps, Secrets and Security Context in Kubernetes.
Commands and Arguments
We can define commands and arguments for the containers that run in the Pod. We must pass the value of command and args in the definition file.
The commands and arguments you define cannot be changed after the Pod is created.
The command and args that we define in the definition file will override the default command and args provided by the container, but if we provide the value of args, it will take the default value of the command with the provided value of args
Using commands and arguments:
Create a definition file commands.yaml
with provided values of command and args:
apiVersion: v1
kind: Pod
metadata:
name: command-and-args
labels:
purpose: demonstrate-command
spec:
containers:
- name: command-and-args
image: debian
command: ["printenv"]
args: ["KUBERNETES_PORT"]
restartPolicy: OnFailure
Now create pod
kubectl apply -f commands.yaml
List running pods and check the Pod logs
kubectl get pods
kubectl logs command-and-args
Here you can see the output of printenv
command,
Run command in shell
Sometimes we need to run a script during the start. You can implement that in this way.
apiVersion: v1
kind: Pod
metadata:
name: command-and-args
labels:
purpose: demonstrate-command
spec:
containers:
- name: command-and-args
image: debian
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
restartPolicy: OnFailure
Environment Variables
While creating a pod, you can set the environment variables for the containers running in the pod.
To set environment variables, include the
env
orenvFrom
field in the configuration file.Environment variables set using
env
orenvFrom
will override any environment variable specified in the container image.
Defining variable with env
Create a file env-pod.yaml
with the definition below
apiVersion: v1
kind: Pod
metadata:
name: env-pod
spec:
containers:
- name: env-pod
image: gcr.io/google-samples/node-hello:1.0
env:
- name: VAR1
value: "Hello"
- name: VAR2
value: "World"
Create pod and check status
kubectl apply -f env-pod.yaml
kubectl get pods
Check environment of container running in the pod
kubectl exec env-pod -- printenv
We will cover the second method envFrom
in the next topic ConfigMaps.
ConfigMaps
A ConfigMaps is an API object that stores the non-confidential data in key-value pair.
Pods can consume this data as environment variables, command line arguments, or volume configuration files.
ConfigMap doesn’t provide any secrecy or confidentiality, thus should only be used for non-confidential data.
Creating ConfigMaps
There are two ways of creating the ConfigMpas, the Imperative command, and the definition file.
ConfigMap with Imperative command:
# Command Format
kubectl create configmap \
<configmap-name> --from-literal=<key>=<value>
ConfigMap app-var
with variable VAR1 = Hello
and VAR2 = World
kubectl create configmap \
app-var-1 --from-literal=VAR1=Hello \
--from-literal=VAR2=World
Check the status and data in ConfigMaps
kubectl get configmap
kubectl describe configmap app-var-1
You can also import the ConfigMap data from a file. The file data should be in key-value format.
Date file app-data.txt
VAR3 = How
VAR4 = Are
VAR5 = You
Now, create a new ConfigMap app-var-2
with the above data
kubectl create configmap \
app-var-2 --from-file=app-data.txt
Again run the same command to check the data
kubectl get configmap
kubectl describe configmap app-var-2
Create ConfigMap in the Declarative way
Create a definition file app-var-3.yaml
with following configuration
apiVersion: v1
kind: COnfigMap
metadata:
name: app-var-3
data:
VAR6: Wake
VAR7: Up
Save this file and apply
kubectl apply -f app-var-3.yaml
Check the ConfigMap status and data
kubectl get configmap
kubectl describe configmap app-var-3
Configure pod with ConfigMap
Now we have three different ConfigMaps app-var-1
, app-var-2
, and app-var-3
. Let's create a pod definition app-var-pod.yaml
and add the ConfigMaps in the env
section
apiVersion: v1
kind: Pod
metadata:
name: app-var-pod
spec:
containers:
- name: app-var
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c"k, "env" ]
envFrom:
- configMapRef:
name: app-var-1
- configMapRef:
name: app-var-2
- configMapRef:
name: app-var-3
restartPolicy: Never
Secrets
A Secret is an object in Kubernetes that we can use to store a small amount of sensitive data like passwords, tokens or keys.
Secrets are similar to ConfigMaps but are specifically intended to store confidential data.
Secrets can be created independently of pods that use them, and there's less risk of exposing data while creating, viewing and editing the pods.
By default, Kubernetes secrets are stored unencrypted in the API server's data store (etcd). Anyone with API server access can access, retrieve or modify the data. Secrets can be kept safe by referring to the following steps:
Enable encryption at rest for secrets
Enable RBAC rule for Secret reading and writing.
Where appropriate, use mechanisms such as RBAC to limit which principals can create new Secrets or replace existing ones.
The data field in the Secrets configuration file should be base64 encoded. The size limit for data is 1MiB.
Creating Secret
Imperative way
# Command Format
kubectl create secret generic \
<secret-name> --from-literal=<key>=<value>
Example
kubectl create secret generic \
user-pass-1 --from-literal=USER1=user1 \
--from-literal=PASS1=pass1
Check the status of secret
kubectl get Secret
kubectl describe secret user-pass-1
Creating Secret with the file Create a file user-2-data.txt
with the following data.
USER2 = user2
PASS2 = pass2
Now run the following command
kubectl create secret generic \
user-pass-2 --from-file=user-2-data.txt
Check the status of Secret
kubectl get Secret
kubectl describe secret user-pass-1
Declarative way
Before creating the configuration, let's encode the data in the base64 format.
echo -n 'user3' | base64
echo -n 'pass3' | base64
Create configuration file user-3-secrets.yaml
with the following configuration and put the encoded values in the data section.
apiVersion: v1
kind: Secret
metadata:
name: user-pass-3
data:
USER = dXNlcjM=
PASS = cGFzczM=
Now run the command to create the secret and check the status
kubectl apply -f user-3-secrets.yaml
kubectl get secret
Describe secret to see the data stored
kubectl describe secret user-pass-3
To view the secret, display the secret in YAML format
kubectl get secret user-pass-3 -o yaml
Decode the secret value
echo -n '' | base64 --decode
echo -n '' | base64 --decode
Using Secret in Pod
Create file pod-secret.yaml
with the following configuration
apiVersion: v1
kind: Pod
metadata:
name: user-secret
spec:
containers:
- name: user-secret
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- secretRef:
name: user-pass-1
restartPolicy: Never
Apply configuration to create the pod
kubectl apply -f pod-secret.yaml
Check Pod logs to view the secrets
kubectl logs user-secret
The above configuration will fetch all the values for single value user secretKeyRef
in the configuration file.
apiVersion: v1
kind: Pod
metadata:
name: user-secret
spec:
containers:
- name: user-secret
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: USER1
valueFrom:
secretKeyRef:
name: user-pass-1
key: USER1
restartPolicy: Never
Secrets are a nice way to manage confidential data, but it's not the best and most recommended way. There are third-party tools like Hashicorp Vault, Helm Secrets, AWS Secret Manager, and others.
Security Context
A security context defines privilege and access control settings for a Pod or Container. In this section, we will cover the implementation part of the security context. If you want to know more about security contexts, please refer:
Configure pod definition security-context.yaml
with the security context
apiVersion: v1
kind: Pod
metadata:
name: security-context
spec:
securityContext:
runAsUser: 1000
containers:
- name: security-context
image: gcr.io/google-samples/node-hello:1.0
securityContext:
runAsUser: 2000
allowPrivilegeEscalation: false
Apply definition to create the Pod and check the status
kubectl apply -f security-context.yaml
kubectl get pods
SSH into the pod and check the user ID of the process
kubectl exec -it security-context -- sh
Run this command in the pod
ps aux
Here you can see the process's user ID is 2000, as mentioned in the pod definition.
Set Capabilities for a Container
With Linux capabilities, you can grant certain privileges to a process without granting all the root user privileges.
To add or remove Linux capabilities for a Container, include the
capabilities
field in thesecurityContext
section of the Container manifest.
Create pod definition capabilities.yaml
with NET_ADMIN
and SYS_TIME
capabilities.
apiVersion: v1
kind: Pod
metadata:
name: capabilities
spec:
containers:
- name: capabilities
image: gcr.io/google-samples/node-hello:1.0
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]
Apply definition to create the Pod and check the status
kubectl apply -f capabilities.yaml
kubectl get pods
Practice Questions
Create a pod with the script
while true; do echo hello world; sleep 180;done
.Create a ConfigMap with a list of variables via imperative commands and definition files.
Create a Secret with the following values via imperative command and definition file. For declarative, encode the secret in base64 before adding it into the definition file.
USER1 = John
PASS1 = shjdfvsdb
USER2 = Mark
PASS2 = jushdfkho
Create a pod with the security context of
runAsUser: 2000
andrunAsGroup:3000
Create a pod with the following capabilities
NET_ADMIN
andSYS_TIME
That's all for the second part of the CKAD series. In the next part, we will discuss more topics like Service Accounts, Taints and Tolerations, Node Affinity, and Multi-Container Pods.
To be continued…!!