CKAD exam Preparation Notes -Inject Data Into Applications- Part 2

CKAD exam Preparation Notes -Inject Data Into Applications- Part 2

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

ckad-2-1.png

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

ckad-2-2.png

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 or envFrom field in the configuration file.

  • Environment variables set using env or envFrom 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

ckad-2-3.png

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

ckad-2-4.png

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

ckad-2-5.png

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

ckad-2-6.png

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

ckad-2-7.png

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

ckad-2-8.png

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

ckad-2-9.png

Declarative way

Before creating the configuration, let's encode the data in the base64 format.

echo -n 'user3' | base64
echo -n 'pass3' | base64

ckad-2-10.png

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

ckad-2-11.png

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

ckad-2-12.png

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

ckad-2-13.png

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

ckad-2-14.png

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 the securityContext 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

ckad-2-15.png

Practice Questions

  1. Create a pod with the script while true; do echo hello world; sleep 180;done.

  2. Create a ConfigMap with a list of variables via imperative commands and definition files.

  3. 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

  1. Create a pod with the security context of runAsUser: 2000 and runAsGroup:3000

  2. Create a pod with the following capabilities NET_ADMIN and SYS_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…!!

Did you find this article valuable?

Support Prateek Jain by becoming a sponsor. Any amount is appreciated!