Study Guide 2023+

kub

Warning: These notes are partial, ongoing, incomplete, and may contain typos/inaccuracies. (They are kept factually accurate, time permitting.)

They are being united from many disparate notes created in the past and the layout/organization will gradually improve with time!

Please view them on a computer as they are not optimized for mobile (although you can still view them on Mobile along with the Flashcards at your own risk)!

Topics and code examples are lazy-loaded and may require two-clicks from the TOC to correctly calculate the updated x,y coordinates (after rendering). Thanks!

Kubernetes: Overview

This section summarizes several specific introductory concepts/topics.

https://kubernetes.io/docs/reference/kubectl/quick-reference/

Syntax

Full reference: https://kubernetes.io/docs/reference/kubectl/generated/

Some commonly encountered Command verbs of interest:

Some commonly encountered Entity Kinds of interest:

Kind Name     Shortname    
pod
pods
po
node
nodes
no
namespace
namespaces
ns
service
services
svc
deployment
deployments
deploy
# Display all Kinds, Names, Shortnames, ApiVersions (for config yaml)
kubectl api-resources

Generally, kubectl COMMAND ENTITY defines a valid operation where:

  1. COMMAND is one of the above Command verbs; and
  2. ENTITY is one of the above Entity Kinds.

Note: A Shortname can be substituted for any associated Kind or Name.

  1. https://kubernetes.io/docs/reference/kubectl/quick-reference/
  2. https://kubernetes.io/docs/reference/kubectl/generated/

Kubernetes: Main Entities Overview

I divide Kubernetes entities into a few kinds:

  1. Meta-level, organizational, groupings.
  2. Kubernetes Kinds (think primitives).
  3. Kubernetes Workload Management that assist in deploying and managing Pods.

Groupings

Grouping entities. These group and help manage Kubernetes Pods and Kubernetes Nodes.

Namespace

Cluster

Service

Basic

Think the basic conceptual units, primitives, or entities.

Node

Pod

Container

Image

Workload Management

ReplicaSets

Deployment

Kubernetes: Kubectl Inspection Quick Reference Sheet

Some common and useful kubectl commands to inspect running or deployed Resources.

minikube will install the default namespace automatically.

Commands

# See all resources
kubectl get all
# Display all Pods in every Namespace
kubectl get po --all-namespaces
# Display all pods in the `default` Namespace (will be empty by default)
kubectl get po -n default
# Display all Pods
kubectl get pods

# Display all Pods with the Label "label: example"
kubectl get po --selector label=example
# Display all Pods with the Labels "label: example" and "x: y"
kubectl get po --selector label=example,x=y
# Display all Namespace
kubectl get namespaces

# Display all services in every Namespace
kubectl get services --all-namespaces
# Display detailed information about test - Containers, status, etc.
kubectl describe namespace test

# Display detailed information about pod newpods-4npfh
kubectl describe po newpods-4npfh 

Syntax

Generally:

  1. kubectl get KIND or kubectl get NAME defines a valid operation.
  2. kubectl describe KIND or kubectl describe NAME defines a valid operation.
  1. https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#get
  2. https://kubernetes.io/docs/reference/kubectl/generated/kubectl_describe/

Kubernetes: Kubectl Create Quick Reference Sheet

Some common and useful kubectl commands supporting the creation of Resources.

Commands

# Create Namespace test
kubectl create namespace test

# Then review the created resource
kubectl get namespaces
# Create a Pod from a file (see below)
kubectl create -f pod-definition.yaml

# Create or update Pod from a file (see below)
kubectl apply -f pod-definition.yaml

Create vs. Apply

kubectl create kubectl apply
Imperative - a specific operation. Declarative - specifies a target state.
Creates a Resource from a file or directly from within the CLI. Creates a Resource by way of a manifest or configuration file.
Will error if Resource already exists. Won't error if Resource already exists.
Creates a new Resource if it doesn't exist. Updates a Resource if it exists, creates one if it doesn't.

https://theserverside.com/answer/Kubectl-apply-vs-create-Whats-the-difference

Note: both kubectl create and kubectl apply require configuration files to create Pods with a specific Docker Image. --image is supported for kubectl create deployment.

Syntax

Generally:

  1. kubectl create KIND and kubectl create NAME defines a valid operation.
  1. https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#create
  2. https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#apply
  3. https://theserverside.com/answer/Kubectl-apply-vs-create-Whats-the-difference

Kubernetes: Kubectl Run Quick Reference Sheet

Some common and useful kubectl run commands.

Commands

# Create and run a Pod named nginx using the Image nginx w/out a config file
kubectl run nginx --image=nginx

Syntax

Generally, kubectl run POD_NAME --image=DOCKER_IMAGE defines a valid operation.

  1. https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#run

Kubernetes: Kubectl Delete and Update Quick Reference Sheet

Some common and useful kubectl commands supporting the deletion and updating of Resources.

Commands

# Delete Pod webapp
kubectl delete pod webapp

# Delete and recreate a resource using a modified configuration file
kubectl replace --force -f mypodconfig.yaml

# Create or update Pod from a file (see below)
kubectl apply -f pod-definition.yaml

# See the YAML config for a resource and edit it
kubectl edit rs new-replica-set

Note: Kubernetes Pods aren't "moved" (say from one Kubernetes Node to another) they are deleted in the first and recreated in the second.

Apply vs Replace

kubectl apply kubectl replace
Updates a Resource if it exists, creates one if it doesn't. Updates if a Resource exists.
Won't typically error. Will error if the Resource doesn't exist.

Consider the following scenario:

  1. kubectl create deployment --image=nginx nginx --dry-run=client -o yaml > nginx-deployment.yaml which creates the following YAML output:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    name: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      strategy: {}
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
            resources: {}
    status: {}
    
  2. kubectl apply -f nginx-deployment.yaml
  3. kubectl describe deployment nginx displays:
    Name:                   nginx
    Namespace:              default
    CreationTimestamp:      Thu, 19 Dec 2024 15:37:38 -0600
    Labels:                 app=nginx
    Annotations:            deployment.kubernetes.io/revision: 1
    Selector:               app=nginx
    Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
      Containers:
       nginx:
        Image:         nginx
        Port:          <none>
        Host Port:     <none>
        Environment:   <none>
        Mounts:        <none>
      Volumes:         <none>
      Node-Selectors:  <none>
      Tolerations:     <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   nginx-676b6c5bbc (1/1 replicas created)
    Events:
      Type    Reason             Age    From                   Message
      ----    ------             ----   ----                   -------
      Normal  ScalingReplicaSet  2m11s  deployment-controller  Scaled up replica set nginx-676b6c5bbc to 1
    
  4. Modifying the YAML document like so:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      creationTimestamp: null
    name: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      strategy: {}
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
            resources: {}
    status: {}
    
  5. Then reapplying: kubectl apply -f nginx-deployment.yaml and inspecting via kubectl describe deployment nginx:
    Name:                   nginx
    Namespace:              default
    CreationTimestamp:      Thu, 19 Dec 2024 15:37:38 -0600
    Labels:                 <none>
    Annotations:            deployment.kubernetes.io/revision: 1
    Selector:               app=nginx
    Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
      Containers:
       nginx:
        Image:         nginx
        Port:          <none>
        Host Port:     <none>
        Environment:   <none>
        Mounts:        <none>
     Volumes:         <none>
      Node-Selectors:  <none>
      Tolerations:     <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   nginx-676b6c5bbc (1/1 replicas created)
    Events:
      Type    Reason             Age   From                   Message
      ----    ------             ----  ----                   -------
      Normal  ScalingReplicaSet  104s  deployment-controller  Scaled up replica set nginx-676b6c5bbc to 1
    

Omitting a field and kubectl applying will remove the fields on running Resources. (It's not a Patch operation per se - fields that aren't supplied aren't ignored or automatically populated in most cases.)

Edit

kubectl edit allows for:

  1. The live editing of a Resource through its YAML configuration. This configuration needn't be saved (but most be done so explicitly if updated YAML is required).
  2. Automatic updating of the Resource post-YAML modification. One doesn't need to run a second command to apply the new changes or remove prior Resource versions.

For this reason, kubectl edit is likely to be the preferred way to quickly modify Resources.

Syntax

Generally:

  1. kubectl delete KIND and kubectl delete NAME defines a valid operation.
  2. kubectl edit KIND and kubectl edit NAME defines a valid operation.
  1. https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#delete
  2. https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#replace
  3. https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#apply
  4. https://kubernetes.io/docs/reference/kubectl/generated/kubectl_edit/
  5. https://medium.com/@grpeto/kubectl-edit-performing-magic-in-kubernetes-684669a8bccd

Kubernetes: Install Minikube

I've chosen minikube here since it's the Kubernetes distribution that's used during the CKA exam and probably the easiest to get set up locally. It's a bit underpowered for Enterprisey stuff but suffices for these purposes.

Gotcha's

  1. You must have docker installed for the typical (and default) minikube installation.
  2. To install minikube in a cloud VM you'll need at least 2 CPU cores (Medium size on AWS).

Minikube Installation

Basically follow this: https://minikube.sigs.k8s.io/docs/start/

Download the correct version after installing docker.

# Verify install 
minikube version

# Start minikube
minikube start

Minikube Removal

Some relevant commands:

# Stop your local cluster
minikube stop

# Removes your local minikube cluster (and start over)
minikube delete

# Removes all local clusters
minikube delete --all
minikube delete --purge

Helpful Minikube Commands

Helpful commands when using minikube.

Display minikube resources with a UI:

minikube dashboard

Display addons and common tools that can be enabled and added:

minikube addons list

https://minikube.sigs.k8s.io/docs/handbook/controls/

Kubectl

Installing kubectl directly is likely a test question: https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/

Kubernetes: Kubectl Docker Discussion

Discussion and example highlighting major differences between using Docker Images in Docker and using them in Kubernetes.

Docker

Terminal One:

# Download image
docker pull elixir

# Open an interactive terminal through Elixir in Docker
## Note that calling this without -it will not allow commands to be passed to iex
docker run -it elixir

Terminal Two (Admin Console - use as needed)

# Display the container and obtain the CONTAINER ID
docker stats

# Display the downloaded images and obtain the IMAGE ID
docker images --all

# Remove container
docker stop CONTAINER_ID
docker rm CONTAINER_ID

# Remove downloaded image
docker rmi -f IMAGE_ID

# Remove all containers and volumes
docker system prune

# Remove all containers and volumes
docker system prune --volumes

So, in the above, one is able to pull elixir and run bash terminal.

Local Docker With Kubernetes

Close the other terminals and check out this awesome blog: https://www.yeahshecodes.com/docker/run-docker-images-locally-with-minikube

I've also found that using docker pull directly through kubectl will often result in Backoff Errors (CrashLoopBackOff) when using minikube. For example (in minikube dashboard):

Name Reason Message Source Sub-object Count First Seen Last Seen
elixir.1803b10a81941af5
BackOff
Back-off restarting failed container elixir in pod elixir_default(cf328542-5b03-4e76-b690-7f65ca8f3db2)
kubelet
minikube
spec.containers{elixir}
6
a minute ago
...
...
...
...
...
...
...
...
elixir.1803b0fec8dc0e33
Pulling
Pulling image "elixir"
kubelet minikube
spec.containers{elixir}
5
16 minutes ago
14 minutes ago
...
...
...
...
...
...
...
...

One might think using kubectl run elixir --image=elixir --namespace=test without additional configs would spin up a viable Pod but this is not the case for nearly every official Docker Image I tested in minikube.

After some further tinkering and research, additional careful configuration is indeed required (e.g. - creating a Deployment resource file in YAML) and is explained in further detail here: https://spacelift.io/blog/kubernetes-imagepullpolicy

However, there is another work around. Per the blog post above and some personal tinkering, one can use a docker-compose.yaml file with supplied "alias" (really a customized and conforming Image name):

version: "3.9"
services:
  nginx:
    image: localtest:v0.0.1
      build: .
      ports:
        - "80:80"

and, a dockerfile:

FROM nginx:latest
EXPOSE 80

I tinkered with the config supplied in the above blog post and narrowed it down to just the above. That appears to be the most minimal config to use regulard Dockerfiles and Docker builds with minikube + Kubernetes (since minikube is the Kubernetes distribution for local development).

Now in an additional terminal:

# Ensure both minikube and docker are in the same env
eval $(minikube docker-env)

# Build from dockerfile
docker-compose up -d

# View Docker Images ages (from within minikube!)
docker images --all

# Create Namespace test
kubectl create namespace test

# Set namespace context
kubectl config set-context --current --namespace=test

# Review all resources in Namespace
kubectl --namespace test get all

# Deploy the Docker Image as a Pod to the Container
kubectl run localtest --image=localtest:v0.0.1 --image-pull-policy=Never --namespace test

# Review all resources in Namespace
kubectl --namespace test get all

Make sure that both minikube and docker are in the same env and visible to each other otherwise one will also encounters Backoff Errors via the command: eval $(minikube docker-env).

Also, do make sure that you supply --image-pull-policy=Never or --image-pull-policy=IfNotPresent as needed along with the appropriate and supplied tag version on the image per: https://spacelift.io/blog/kubernetes-imagepullpolicy

Kubernetes: Docker Compose Translation

Translating Docker Compose to Kubernetes.

Configuration Files

Kubernetes deployment.yml's and service.yml's are typically configured and applied together (kubectl apply -f python-deployment.yaml,python-service.yaml):

  1. deployment.yml - defines Volumes, Commands to be executed, Docker Images, and Containers.
    • Contains many of the configuration settings one would find in docker-compose.yml.
  2. service.yml - specifies Ports, Port Mappings, and generally connects Pods in a Deployment to shared Network resources.
  3. configmap.yml - injects Secrets, Environment Variables, initialization scripts, and files into the Kubernetes context.
    • Associated with a Deployment within deployment.yml.
  1. https://github.com/Thoughtscript/python_pyramid_kub_2024
  2. https://github.com/Thoughtscript/python_pyramid_kub_2024/tree/main/kubernetes

Linux Foundation CKA: Overview

Note: These notes will do "double duty" for both the KCNA and CKA exams.

The CKA is being rewritten 1/15/2025-ish.

I strongly recommend taking the excellent KodeKloud KNCA and CKA courses!

Cluster Architecture

  1. Control Plane - manage, plan, schedule, and monitor Nodes
    • etcd - Key value persistence store used to back all Kubernetes Cluster data.
      • Listens on Port 2379 by default.
      • Typically, only kube-apiserver will directly interact with etcd.
    • kube-apiserver - exposes the Kubernetes API to allow the following functionalities to be performed: reference.
    • kube-scheduler - Control Plane component that listens for newly created Kubernetes Pods with no assigned Kubernetes Node and assignes them one.
    • kube-controller-manager - runs and manages Kubernetes Control Plane Controllers.
      • Example: Node Controller - responsible for noticing and responding when Nodes fail.
      • Example: Job Controller - watches for Kubernetes Job objects that represent one-off tasks then creates Pods to run those tasks to completion.
    • Cloud Controller Manager (Optional) - embeds Cloud Provider-specific control logic.
  2. Nodes - used to group Resources, run one or more Kubernetes Pods, and managed by the Control Plane. Node components run on every Node.
    • kubelet - an Agent that runs on every Node in the Cluster.
      • Ensures that Containers are running in a Pod.
    • kube-proxy (Optional) - maintains Network rules on Nodes allowing communication to and between Pods (inside or outside the Cluster).
    • Container Runtime - manages the execution and lifecycle of Containers within the Kubernetes environment.
      • Supports any Container Runtime implementing the Kubernetes Container Runtime Interface (CRI).
      • Note: support for Docker through Dockershim is now deprecated. containerD has been targeted as the go to for Docker going forward.

Nodes, Pods, and Containers

  1. Many Containers can run in a single Kubernetes Pod.
  2. Many Kubernetes Pods can run in a single Kubernetes Node.

kube-proxy vs. kubectl proxy

  1. kube-proxy (Optional) - maintains Network rules on Nodes allowing communication to and between Pods (inside or outside the Cluster).
    • Exists on Nodes.
  2. kubectl proxy - proxy for kube-apiserver.
    • Exists in the Control Plane.

Namespaces

  1. Some Kubernetes Resources can be organized, isolated, and grouped into Kubernetes Namespaces. Examples:

    • Kubernetes Deployments
    • Kubernetes Service Accounts
    • Kubernetes Nodes
  2. Some Resources are Global (available regardless of the current Kubernetes Namespace or accessible within any of them). Examples:

    • Kubernetes Volumes
    • Kubernetes Services (not to be confused with Kubernetes Service Accounts)
    • Kubernetes User Accounts

Default Namespaces

These are automatically created when a Kubernetes Cluster is created through normal means:

https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/

  1. https://kubernetes.io/docs/concepts/architecture/#etcd
  2. https://kubernetes.io/docs/concepts/architecture/#kube-apiserver
  3. https://kubernetes.io/docs/concepts/architecture/#kube-controller-manager
  4. https://kubernetes.io/docs/concepts/architecture/cloud-controller
  5. https://kubernetes.io/docs/concepts/architecture/#node-components
  6. https://kubernetes.io/docs/concepts/architecture/#container-runtime
  7. https://kubernetes.io/docs/reference/kubectl/generated/kubectl_proxy
  8. https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/

Linux Foundation CKA: etcd

etcd is the backing store for Kubernetes Clusters. It's typically provisioned automatically (along with other Control Plane Resources) but can be manually added (say in a Kubernetes Cluster that's manually provisioned and/or with customized/custom coded Resources, Controllers, etc.).

Typically, only kube-apiserver will directly interact with etcd.

etcd listens on Port 2379 by default (both within and outside of Kubernetes).

Useful Commands

etcdctl put mykey myvalue # add a key value pair
etcdctl get mykey # read key value
etcdctl del mykey # delete pair mykey, myvalue by key
etcdctl watch mykey  # prints out changes to mykey's value
etcdctl lease grant 60 # create a Lease
## prints Lease ID
# > lease 32695410dcc0ca06 granted with TTL(60s)

# automatically add mykey with auto eviction
etcdctl put mykey myvalue --lease=1234abcd ## --lease is assigned to a the Lease ID, not the chronotype itself

https://etcd.io/docs/v3.4/dev-guide/interacting_v3/

  1. https://etcd.io/docs/v3.4/dev-guide/interacting_v3/

Linux Foundation CKA: Pods

YAML

# pod-definition.yaml
apiVersion: v1
kind: Pod
metatdata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
    - name: nginx-container
      image: nginx

Required fields (for any Resource):

  1. apiVersion - typically v1 but there are some outliers.
  2. kind - specifies the kind of Resource (Pod, Service, Deployment, etc.)
  3. metatdata - name of the Resource and any user-specified labels
  4. spec - configuration, attached Resources, etc.

Creating

# Create a Pod from a YAML configuration
## Note: there's no way to pass an Image in as a flag with create!
kubectl create -f pod-definition.yaml
kubectl apply -f pod-definitional.yaml

# Create and run a Pod named nginx using the Image nginx w/out a config file
kubectl run nginx --image=nginx

Inspection

# Get all Pods regardless of Namespace
kubectl get po --all-namespaces

# Detailed inspection of Pod
kubectl describe po myapp-pod

Updating

To update a Pod configuration file you can first destroy the running Pod then recreate the new Pod with new configuration:

# Using the above config
kubectl delete pod myapp-pod

kubectl create -f pod-definition.yaml

Or, use:

  1. kubectl replace -f pod-definition.yaml - to replace with a Resource using a modified configuration file.
  2. kubectl edit rs new-replica-set - to both display the config for the Resource (in YAML format) and edit it. (Editing alone may not be sufficient to update the actually running Resources - in a Replica Set, you'd want to delete the running Pods so they deploy with the updated configuration.)

Deployments

  1. See Deployments.
  2. Can be deployed as Kubernetes Static Pods that can be tracked by the Control Plane but otherwise exist independently. When using Kubernetes Static Pods, one will be restricted to a single Kubernetes Node and its local kubectl (and while the Control Plane can be made aware of the Kubernetes Static Pod, it has no other control over managing, modifying, or interacting with it).

Linux Foundation CKA: Deployments

Kubernetes Pods will typically be deployed with the following considerations:

  1. A certain number of Kubernetes Pods will need to be available at all times.
  2. Updates to Kubernetes Pods must be careful sequenced.

The above requirements are typically satisfied by:

  1. Kubernetes Replica Sets which allow a number of Kubernetes Pods to be specified through the replicas field.
  2. Kubernetes Rollout Strategies

Kubernetes Deployments therefore wrap both Kubernetes Replica Sets and provide the additional management tooling required for carefully deploying new changes.

Kubernetes Deployments will be assigned to various available Kubernetes Nodes based on configured Affinities, Taints, Tolerations, etc.

Deployment YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-pyramid
  labels:
    app: python-pyramid-postgres
    service: python-pyramid
spec:
  replicas: 3
  selector:
    matchLabels:
      app: python-pyramid-postgres
      service: python-pyramid
  template:
    metadata:
      labels:
        app: python-pyramid-postgres
        service: python-pyramid
    spec:
      containers:
      - name: python-pyramid
        image: python-pyramid:v0.1
        imagePullPolicy: Never
        ports:
        - containerPort: 8000
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1

Rollout Strategies

  1. RollingUpdate
    • Default.
    • Will gradually update Kubernetes Pods a few at a time (depending on the configured settings).
  2. Recreate
    • Kills all Kubernetes Pods before new ones (with the applied updates) are created.

Two optional fields help to control this process:

Stateful Sets and DaemonSets

  1. Kubernetes Stateful Sets
    • Are distinct from Kubernetes Replica Sets but are akin in certain specific ways. (e.g. - can specify replicas and used to manage a group of Kubernetes Pods). Is not a subkind of rs.
    • Stateful information is retained about a Kubernetes Stateful Set as it recreated and destroyed.
    • This guarantees certain settings remain invariant (Kubernetes Volume Claims, Kubernetes Network settings, etc.).
    • Does not guarantee that only one Kubernetes Pod managed by the Kubernetes Stateful Set is deployed to each Kubernetes Node.
    • https://docs.rafay.co/learn/quickstart/kubernetes/deployments-daemonsets-statefulsets/
  2. Kubernetes Daemon Sets
    • Are distinct from Kubernetes Replica Sets but are akin in certain specific ways. (e.g. - can specify replicas and used to manage a group of Kubernetes Pods). Is not a subkind of rs.
    • Specifies that one, a particular, Kubernetes Pod must be present in all (or some specified) Kubernetes Nodes.
    • Ideal for observability tooling, logging, or Agent-based installations.
    • https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/

Commands

# Check the rollout status
kubectl rollout status deployment python-pyramid

# Rollback the update
## Note the /
kubectl rollout undo deployment/python-pyramid

https://kubernetes.io/docs/reference/kubectl/generated/kubectl_rollout/kubectl_rollout_undo/

  1. https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
  2. https://kubernetes.io/docs/reference/kubectl/generated/kubectl_rollout/kubectl_rollout_undo/
  3. https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
  4. https://docs.rafay.co/learn/quickstart/kubernetes/deployments-daemonsets-statefulsets/
  5. https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/

Code samples:

  1. https://github.com/Thoughtscript/python_pyramid_kub_2024/tree/main/kubernetes

Linux Foundation CKA: Services

Maps Kubernetes Pod Ports to Node Ports by listening on specified Ports and forwarding them.

YAML

apiVersion: v1
kind: Service
metadata:
  name: myServiceName

spec:
  type: NodePort
  ports:
    - targetPort: 80
      port: 80
      nodePort: 31000 # 30000-32767
    - port: 8080
      # port is the only required field
      ## if solely provided, targetPort is assumed to be the same as port
      ## and an available port in range 30000-32767 is selected

  select:
    app: myPod # Match a pod
    type: someMetadataType

Kubernetes Ports:

  1. Inbound port is mapped to internal targetPort.
  2. nodePort is exposed externally as a Static IP Address.

Kubernetes Service YAML config type values:

  1. LoadBalancer
    • Load balances external traffic into the Kubernetes Cluster.
    • Requires that an external Load Balancer exists (such as an AWS ALB).
  2. ClusterIP
    • Default value.
    • Facilitates communications within the Kubernetes Cluster.
  3. NodePort
    • Enables a Kubernetes Node to be accessible from outside a Kubernetes Cluster.
  4. ExternalName
    • An internal Alias for an external DNS Name.
  5. None
    • A Headless Kubernetes Service.
    • Unlike the others, this isn't configured in the spec.type field.
    • Instead it's configured like so: spec.clusterIP: None.

Load Balancing

  1. A Kubernetes Service will Load Balance multiple Kubernetes Pods in the same Kubernetes Node (of the same Kubernetes Cluster).
  2. It will also do so for multiple Kubernetes Pods in different Kubernetes Node within the same Kubernetes Cluster.

DNS Names

  1. Internal to the same Kubernetes Namespace, Kubernetes Pods can access another Kubernetes Service by its name.
  2. Kubernetes Pods can access another Kubernetes Service in another Kubernetes Namespace by its fully qualified name: <SERVICE_NAME>.<NAMESPACE_NAME>.svc.cluster.local.

Commands

# Create a Service named redis-service with Pod redis associated on Port 6379
kubectl expose pod redis --port=6379 --name redis-service
  1. https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport

Linux Foundation CKA: Scheduling

Kubernetes Scheduling assigns Kubernetes Pods to Kubernetes Nodes.

Schedule Matching and Constraints

There are several considerations and ways that Kubernetes Schedules Pods:

  1. The inbuilt kube-scheduler typically and automatically manages assigning Kubernetes Pods to Kubernetes Nodes.
  2. Manually setting the nodeName field.
  3. nodeSelector matching against Node Labels.
  4. affinity
  5. Taints and Tolerations.
kube-scheduler
nodeName
nodeSelector
affinity
Taints and Tolerations
Default. No user control. Automatic. Managed Scheduling. Manual. Set in YAML or through JSON API. Associates a Node Label with a Pod nodeSelector. An affinity field is specified in Pod YAML. Taints are set on Nodes and Tolerations are set on Pods.
First available (given the other constraints). Most precise but requires exact Node name. Assigns by single Label (think CSS Selector). More precise than nodeSelector. Supports multiple Labels. Assigns a Taint to a Node that will be avoid by any Pod without a toleration.
Attracting association. Attracting association. Attracting association. Attracting or repelling association. Repelling association.
API-centric. Field. Key Value pair. Field. Key Value pair. Fields. Supports predicates, Labels, and complex expressions. Fields. Supports predicates and complex expressions.
Random. Exact Node. Restricted to range of Nodes. Restricted to narrower range of (or avoids certain) Nodes. Pods are restricted to range of Nodes.

Selectors and Labels

Selectors are used to pair Resources with other Resources.

Below, a Kubernetes ReplicaSet is associated with Kubernetes Pods with Label App1.

 apiVersion: apps/v1
 kind: ReplicaSet
 metadata:
   name: simple-webapp
   labels:
     app: App1
     function: Front-end
 spec:
  replicas: 3
  selector:
    matchLabels:
     app: App1 # Selector looks for matches on one of more labels
  template:
    metadata:
      labels:
        app: App1 # template labels specify the labels on each deployed Pod
        function: Front-end
    spec:
      containers:
      - name: simple-webapp
        image: simple-webapp   
# Display all Pods with the Label "label: example"
kubectl get po --selector label=example
# Display all Pods with the Labels "label: example" and "x: y"
kubectl get po --selector label=example,x=y

Manually Assign a Pod to a Node

To manually Schedule a Kubernetes Pod (assigning it to a Kubernetes Node).

# find all nodes
kubectl get nodes

Displaying:

NAME           STATUS   ROLES           AGE   VERSION
controlplane   Ready    control-plane   25m   v1.31.0
abcNode        Ready    <none>          24m   v1.31.0

Edit the config:

nano mypodconfig.yaml
# mypodconfig.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  -  image: nginx
     name: nginx
  nodeName: abcNode # Add 
  ## kube-scheduler schedules a Pod by assigning it the field nodeNode with a valid Node 
  ## This can be done manually too!

Recreate the Pod:

# Delete and recreate in two commands
kubectl delete pod nginx
kubectl create -f mypodconfig.yaml

# Delete and recreate in one command
kubectl replace --force -f mypodconfig.yaml

nodeSelector

Labels are added to Kubernetes Nodes:

# Show all Labels
kubectl get nodes --show-labels

# Create a new Label on a Node
kubectl label nodes my-node-name x=y

nodeSelector is specified on Kubernetes Pods:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd

Any Kubernetes Pod with a valid nodeSelector will be paired with an available Kubernetes Node with a matching Kubernetes Node label.

Affinity

  1. Supports complex, multi, Label associations.
  2. Supports Labels (see nodeSelector).
  3. Can define repellent Anti-Affinities.
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: topology.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: topology.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: registry.k8s.io/pause:3.8

affinity goes under template in Kubernetes Deployment config YAML.

Taints and Tolerations

Kubernetes Taints restrict which Kubernetes Pods can be assigned to which Kubernetes Nodes (which Kubernetes Nodes can accept which Kubernetes Pods).

Kubernetes Taints and Tolerations do not guarantee that Kubernetes Pod will be assigned to a specific Kubernetes Node(s)!

  1. Kubernetes Taints are set on Kubernetes Nodes
    • kubectl taint nodes my-node-name key=value:taint-effect
    • If Kubernetes Pod isn't Tolerant (it's Intolerant), it's behavior is determined by a specified Taint Effect.
    • Taint Effects: NoSchedule, PreferNoSchedule, NoExecute.
    • A Taint is repelling - negatively associated.
  2. Kubernetes Tolerations are set on Kubernetes Pods
    • Must be coded with " " and viewed with |grep.
      apiVersion: v1
      kind: Pod
      metadata:
      name: myapp-pod
      spec:
      containers:
      - name: nginx-container
        image: nginx
      tolerations:
      - key: "app"
        operator: "Equal"
        value: "blue"
        effect: "NoSchedule"
      
  3. kubectl describe node myapp-node |grep Taint
# Taint
kubectl taint nodes controlplane x=y:NoSchedule

# View Taints
kubectl describe node controlplane |grep Taint

# Use the fully qualified name to remove (note the - at the end)
kubectl taint nodes controlplane x=y:NoSchedule-
kubectl taint nodes controlplane node-role.kubernetes.io/control-plane:NoSchedule-

Scheduling Algorithm

The default kube-scheduler uses the following two-step algorithm to assign Kubernetes Pods to Kubernetes Nodes:

  1. Filtering
    • Uses the affinity, Taints and Tolerations, nodeSelector, and so on to identify a range of Kubernetes Node to assign a Kubernetes Pod to.
  2. Scoring
    • Bin Packing - optimization scenario to maximize the number of "packages" that fit into a "bin" (hence "bin packing").
    • Determines available Resources and if the Kubernetes Pod can be added.
  1. https://kubernetes.io/docs/concepts/scheduling-eviction/
  2. https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/
  3. https://kubernetes.io/docs/concepts/scheduling-eviction/resource-bin-packing/

Linux Foundation CKA: Resource Limits

Kubernetes supports setting Resource limits (primarily CPU, Memory).

Requests and Limits

  1. A LimitRange Request specifies the maximum that a Resource can ask for and have allotted to it.
  2. A LimitRange Limit is used to enforce minimum and maximum compute resource usages.

For example: you may want to specify a 500M memory Limit but a 250M memory Request to allow some extra memory buffer (pun) for other dependencies and services (including the Operating System itself).

Values

Standardized Resource values apply and simplifying resourcing whether a Container or Pod is run on a single-core, multi-core, or 48-core machine.

  1. cpu
  2. memory

YAML

Such constraints can be set as a standalone LimitRange Kind:

apiVersion: v1
kind: LimitRange
metadata:
  name: testLimit
  namespace: ns1
spec:
  limits:
    - default:
        cpu: 200m
        memory: 500m
      defaultRequest:
        cpu: 100m
        memory: 250m
      type: Container

The Kubernetes Limit Range is applied to a Kubernetes Namespace (and its Kubernetes Pods only indirectly) like so:

kubectl apply -f cpu-constraint.yaml --namespace=my-name-space

https://kubernetes.io/docs/concepts/policy/limit-range/

Spec Configuration

They can also be set within another Resource definition:

  1. Since Kubernetes 1.32, Pods can set this under spec.resources. This sets the overall limits for the entire Kubernetes Pod (and not just a single Container):

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-resources-demo
      namespace: pod-resources-example
    spec:
      resources:
        limits:
          cpu: "1"
          memory: "200M"
        requests:
          cpu: "1"
          memory: "100M"
      containers:
       - name: pod-resources-demo-ctr-1
         image: nginx
         resources:
           limits:
             cpu: "0.5"
             memory: "100M"
           requests:
             cpu: "0.5"
             memory: "50M"
    

    Note: This feature is Disabled by default and is in Alpha as of 12/2024.

  2. Via spec.containers[].resources which specifies limits for each Container:

    apiVersion: v1
    kind: Pod
    metadata:
      name: frontend
    spec:
      containers:
      - name: app
        image: images.my-company.example/app:v4
        resources:
          requests:
            memory: "64M"
            cpu: "250m"
          limits:
            memory: "128M"
            cpu: "500m"
    

https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-requests-and-limits-of-pod-and-container

  1. https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-cpu
  2. https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-memory
  3. https://kubernetes.io/docs/concepts/policy/limit-range/
  4. https://kubernetes.io/docs/tasks/configure-pod-container/assign-pod-level-resources/
  5. https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/
  6. https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-requests-and-limits-of-pod-and-container

Linux Foundation CKA: Security

An excellent read: https://kubernetes.io/blog/2018/07/18/11-ways-not-to-get-hacked/ for Kubernetes security best practices.

Some Kubernetes security best practices:

  1. Disable Root Access.
  2. To close and/or disable all unneeded Container Ports.
  3. To disable any default password-based authentication (and use some stronger alternative).
  4. To move all Credentials and Secrets out of plaintext, configuration, and/or files into something more secure (third-party vault, temporary and in-memory tokens, etc.) as described here.
  5. To restrict access by RBAC and SSH Key only (Jump Bastion style).

TLS

  1. Using openssl one will typically generate an SSL Certificate in the following way:
    • A Key: .key
    • A Certificate Signing Request (CSR): .csr
    • Which in turn are used to sign and generate a Certificate: .crt, .pem (Privacy Enhanced Mail data and file format)
  2. The above steps are performed to generate a Certicate Authority Root Certificate that's used to generate valid Client Certificates.
    # simple openssl to generate root cert for Kubernetes Cluster CA
    openssl genrsa -out ca.key 2048
    # subj CN is Certificate Name
    openssl req -new -key ca.key -subj "/CN=KUBERNETES-CA" -out ca.csr
    openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
    
  3. Generate Certifcates for each Client and Signed with the Root Certificate and Key created above:
    openssl genrsa -out client.key 2048
    openssl req -new -key client.key -subj "/CN=my-client" -out client.csr
    # using the above root CA cert and key
    openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -out client.crt
    
  4. It's good practice to generate a Certifcates for each Resource in the Kubernetes Cluster (in similar fashion):
    • So that all communication between Resources is encrypted.
    • Each Certificate can be associated with a single Client or kind of access aiding with proper RBAC.

https://docs.openssl.org/1.0.2/man1/x509/#signing-options

Multi-Cluster Config

Defines and controls access from one Kubernetes Cluster to others:

apiVersion: v1
kind: Config
preferences: {}

clusters:
- cluster:
  name: development
    # Here, the Authentication Strategy is through valid Certificates.
    certificate-authority: dev-ca-file
    server: https://5.6.7.8
- cluster:
  name: production
    # And here.
    certificate-authority: prod-ca-file
    server: https://1.2.3.4

contexts:
- context:
  name: development
  namespace: development
  user: dev-env-user
- context:
  name: production
  namespace: production
  user: prod-env-user

users:
- name: dev-env-user
  user:
    client-certificate: dev-cert-file
    client-key: dev-key-file
- name: prod-env-user
  user:
    client-certificate: prod-cert-file
    client-key: prod-key-file
kubectl config view

Kubernetes Users are not Kinds - they are not created. For example, there is no kubectl creater user username command.

https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/

Users and Service Accounts

Kubernetes Users, therefore, aren't represented by Kinds or standalone objects but only indirectly through the specified Authentication Strategy.

Kubernetes Service Accounts are managed through the Kubernetes API and are bound to specific Kubernetes Namespaces.

Role-Based Access Control

Unlike Kubernetes Users, Kubernetes Roles are bona fide objects, that are managed through Kubernetes API, and which have an associated Kind:

# dev-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["list", "get", "create", "update", "delete"]
kubectl create -f dev-role.yaml

Kubernetes Roles are then bound (through a Kubernetes Role Binding) to a Kubernetes User:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-role-binding-for-dev-user
subjects:
# Not a Kubernetes Kind per se
- kind: User # field is kind but not object
  name: dev-user
roleRef:
  kind: Role
  name: developer

Kubernetes Secrets

Kubernetes Secrets are akin to Kubernetes Config Maps but are specifically intended to store Secrets.

  1. Values stored as such are unencrypted by default and anyone can view, modify, or retrieve them.
  2. Additional security is strongly encouraged per: https://kubernetes.io/docs/concepts/security/secrets-good-practices/

https://kubernetes.io/docs/concepts/configuration/secret/

Impersonation and Authorization

Authentication involves gaining, obtaining, or having access to some Resource.

Authorization involves what a Resource or User can do once they have authenticated.

Administrators can check whether other Users can perform certain actions like so:

kubectl auth can-i list pods --as=system:serviceaccount:dev:foo -n prod

Users can see if they can for themselves:

# Check to see if I can create pods in any namespace
kubectl auth can-i create pods --all-namespaces

https://kubernetes.io/docs/reference/kubectl/generated/kubectl_auth/kubectl_auth_can-i/

  1. https://kubernetes.io/blog/2018/07/18/11-ways-not-to-get-hacked/
  2. https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authentication-strategies
  3. https://docs.openssl.org/1.0.2/man1/x509/#signing-options
  4. https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
  5. https://kubernetes.io/docs/reference/access-authn-authz/authentication/#users-in-kubernetes
  6. https://kubernetes.io/docs/reference/access-authn-authz/rbac/
  7. https://kubernetes.io/docs/concepts/security/secrets-good-practices/
  8. https://kubernetes.io/docs/concepts/configuration/secret/
  9. https://kubernetes.io/docs/reference/kubectl/generated/kubectl_auth/kubectl_auth_can-i/

Linux Foundation CKA: Networking

DNS

  1. Kubernetess will automatically provision a DNS Server for a new Kubernetes Cluster.
  2. Kubernetes DNS will be managed and created for Kubernetes Pods and Kubernetes Services.
    • Kubernetes Services are automatically assigned a DNS Record.
    • Kubernetes Pods can be exposed directly or through a Kubernetess Service (and the way they are exposed determines what the DNS Record is)

Kubernetes DNS will create DNS Records and map IP Addresses like so:

  1. Kubernetes Service: my-svc.my-namespace.svc.cluster-domain.example
  2. Kubernetes Pod: pod-ipv4-address.my-namespace.pod.cluster-domain.example
    • By convention Kubernetes Pods replace dots with dashes in the IP Address.
  3. The above will be mapped to a Network IP Address.
  4. cluster-domain.example is typically thought of as the top-level Domain (despite the dot between cluster-domain and example) for all Resources within the Kubernetes Cluster:
    • The last item example can be thought of as the top-level Domain.
    • cluster-domain can be thought of as a Subdomain (created for the Kubernetes Cluster). Especially in a multi-Cluster deployment.
  5. svc or pod are properly part of the Domain and Subdomain Names and are dependent on the Kubernetes Kind the DNS Record is created for.

https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/

Container Network Interface

  1. Containers running in a Kubernetes Pod will communicate using a Container Network Interface (CNI).
  2. CNI Plugins are stored in the CNI bin directory as executables on the kubelet service in each Kubernetes Node of the Kubernetes Cluster.
  3. Each Kubernetes Node must have at least one CNI to connect to a network.
  4. Configuration is handled through CNI-specific JSON configuration files.

https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/

Pod Networking

  1. Kubernetes Pod networking requires a third-party tool and isn't available out of the box.
    • Flannel
    • Cilium
    • WeaveWorks
    • The above tools install Agents on each Kubernetes Pod to facilitate direct Kubernetes Pod to Kubernetes Pod intercommunication.
  2. Kubernetes Pod networking requirements:
    • Kubernetes Pods within the same Kubernetes Node should be able to communicate using their IP Addresses.
    • Each Kubernetes Pods should have a unique IP Address.
    • Kubernetes Pods should be able to communicate across different Kubernetes Nodes using their IP Addresses.
  3. Kubernetes Pods can only access a Kubernetes Service by its shorthand service name if they are in the same Kubernetess Namespace. (Otherwise, use the FQDN.)

Kubernetes Endpoints

Kubernetes Endpoints lack a glossary entry but are supported using kubectl syntax.

They appear to refer to an assigned IP Address and Port combination (e.g. - the traditional use of the term as opposed to say an AWS API Gateway Endpoint which associates a specific DNS, URL Context Path, and API REST Method). As such, Kubernetes Endpoints can be associated with Kubernetes Pods or external Resources.

Example Minikube:

kubectl get endpoints

# NAME         ENDPOINTS           AGE
# kubernetes   192.168.49.2:8443   5h12m

Network Policies

  1. Ingress Policies - specify rules for inbound traffic.
  2. Egress Policies - specify rules for outbound traffic.

Configured through the NetworkPolicy Kind that's associated with one or more Kubernetes Pods through podSelector matchLabels.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Ingress
  - Egress

A variety of values can be supplied:

  1. Default Policies:
    • default-deny-ingress
    • allow-all-ingress
    • default-deny-egress
    • allow-all-egress
    • default-deny-all
  2. Kubernetes Namespaces through the namespaceSelector field.
  3. Port ranges.

https://kubernetes.io/docs/concepts/services-networking/network-policies/

Ports

Important Kubernetes Port numbers: https://kubernetes.io/docs/reference/networking/ports-and-protocols/

Port(s) or Range Resource Required Description
2379, 2380 etcd, also kube-apiserver Yes. (Inbound.) etcd default listening and API.
6443 kube-apiserver Yes. (Inbound.) Used by everything.
10250 kubelet/kubelet API Yes. (Inbound.) Used on Control Plane and kubelet on all worker Nodes.
10256 kube-proxy Yes. (Inbound.) Load balancers on worker Nodes.
10257 kube-controller-manager Yes. (Inbound.) HTTPS on Control Plane.
10259 kube-scheduler Yes. (Inbound.) Default listening on Control Plane.
30000-32767 Everything. Yes. (Inbound.) NodePort Services on all worker Nodes.
  1. https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
  2. https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/
  3. https://kubernetes.io/docs/concepts/services-networking/network-policies/
  4. https://stackoverflow.com/questions/52857825/what-is-an-endpoint-in-kubernetes
  5. https://kubernetes.io/docs/reference/networking/ports-and-protocols/

Linux Foundation CKA: Storage

Volumes and Volume Claims

  1. Kubernetes Volume Claims are singly attached to a Kubernetes Volume:
    • Only one Kubernetes Volume Claim can bind to a Kubernetes Volume.
    • Kubernetes Volumes without a Kubernetes Volume Claim are Unbound.
    • Kubernetes Volume Claims that have no available Kubernetes Volumes remaining in a Pending state until a new Kubernetes Volume becomes available.
  2. PersistentVolumeClaim, pvc is the Kubernetes Volume Claim Kind
  3. PersistentVolume, pv is the Kubernetes Volume Kind.

Kubernetes Volume example YAML:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: postgres-volume
  labels:
    type: local
    app: python-pyramid-postgres
    service: postgres
spec:
  storageClassName: local-storage
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: /data/postgresql

Kubernetes Volume Claim example YAML:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-volume-claim
  labels:
    type: local
    app: python-pyramid-postgres
    service: postgres
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 4Gi
  volumeName: postgres-volume
  storageClassName: local-storage

Reclaimation Policies

https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaiming

Kubernetes Volume Reclaimation Policies specify what action(s) should occur when an associated Kubernetes Claim is Deleted:

  1. Retain
  2. Recycle
  3. Delete

Access Modes

Kubernetes Volume access modes:

  1. readonlymany
  2. readwriteonce
  3. readwritemany
  1. https://kubernetes.io/docs/concepts/storage/persistent-volumes/
  2. https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaiming

Code samples:

  1. https://github.com/Thoughtscript/python_pyramid_kub_2024/tree/main/kubernetes

Linux Foundation CKA: Auto-Scaling

  1. Kubernetes Auto-Scaling is managed by dedicated Kubernetes Pods equipped with Controllers that track specified Metrics.
    • Recommendations are then made on the basis of those Metrics and other specified Resource Limits/configurations.
    • Default Resource Limits and/or Kubernetes Pod counts are intercepted and overridden based on those recommendations.
  2. Kubernetes Auto-Scaling comes in three varieties:
    • Vertical Pod Autoscaler (VPA) for scaling the number of Kubernetes Pods that exist in a Kubernetes Deployment.
    • Horizontal Pod Autoscaler (HPA) for dynamically modifying CPU and Memory Requests based on actual use.
    • Cluster Autoscaler manages and scales Kubernetes Nodes based on use and demand.
VPA HPA Cluster Autoscaler
Resource Requests Pods Nodes
CPU, RAM Number of Pods Number of Nodes

Vertical Pod Autoscaler

Specifies how CPU and Memory Requests are updated based on actual use.

  1. Must first be independently installed
    • Download and run the install script: ./hack/vpa-up.sh
  2. Given an existing Kubernetes Deployment (say, my-example-deployment), kubectl apply -f vpa-example.yaml using a YAML configuration:
    # vpa-example.yaml
    apiVersion: autoscaling.k8s.io/v1
    kind: VerticalPodAutoscaler
    metadata:
      name: my-example-deployment-vpa
    spec:
      targetRef:
        apiVersion: "apps/v1"
        kind:       Deployment
        # Associate the HPA with the Deployment
        name:       my-example-deployment
      updatePolicy:
        # Take care here...
        updateMode: "Auto"
    
  3. updateMode can be set in four modes:
    • "Auto"
    • "Recreate"
    • "Initial"
    • "Off"
  4. kubectl get vpa to retrieve information about VerticalPodAutoscaler objects.

https://kubernetes.io/docs/concepts/workloads/autoscaling/#scaling-workloads-vertically

Horizontal Pod Autoscaler

Specifies a minReplicas to maxReplicas ranged controlled by specified metrics along with automatic auto-scaling to and from those quantities.

Given an existing Kubernetes Deployment (say, my-example-deployment):

  1. Create an HPA imperatively: kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
  2. Here's the declarative way to do so kubectl apply -f hpa-example.yaml using YAML:
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: my-example-deployment-hpa
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        # Associate the HPA with the Deployment
        name: my-example-deployment
      minReplicas: 1
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 50
    
  3. kubectl get hpa to retrieve information about HorizontalPodAutoscaler objects.

Note: Kubernetes Replica Set replicas values are overridden by HPA minReplicas and maxReplicas. The number specified by replicas is provisioned first, and is then adjusted by HPA to the desired min and max amounts.

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/

Cluster Autoscaler

Typically used with a specific Cloud Provider.

Manages the number of and scaling for Kubernetes Nodes.

https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler

https://medium.com/tensult/cluster-autoscaler-ca-and-horizontal-pod-autoscaler-hpa-on-kubernetes-f25ba7fd00b9

  1. https://github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/docs/installation.md
  2. https://technologyconversations.com/2018/10/10/to-replicas-or-not-to-replicas-in-kubernetes-deployments-and-statefulsets/
  3. https://stackoverflow.com/questions/66431556/what-is-the-relationship-between-the-hpa-and-replicaset-in-kubernetes
  4. https://github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/docs/quickstart.md
  5. https://kubernetes.io/docs/concepts/workloads/autoscaling/#scaling-workloads-vertically
  6. https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
  7. https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler
  8. https://medium.com/tensult/cluster-autoscaler-ca-and-horizontal-pod-autoscaler-hpa-on-kubernetes-f25ba7fd00b9

Linux Foundation CKA: GitOps

GitOps: tracking, versioning, and handling configuration code for infrasture.

Versioning

Versioning (in the context of Kubernetes) typically involves:

  1. Versioning Docker Images - handled through one's Docker Repository and Dockerfile (including but not limited to Docker Hub).
  2. Versioning of Kubernetes configuration - typically handled indirectly (through Docker Image versions mentioned above) or through a dedicated Package Manager like Helm.
    • Kubernetes Labels might also suffice but I haven't personally seen them used for that purpose.

Helm

Helm is the primary Package Manager for Kubernetes.

Packages are organized into Helm Charts that add to standard Kubernetes YAML configuration templating features, built-in functions, more flexible syntax, etc.:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Greetings Celestial Sphere!"

Push vs. Pull Approachs

Both approaches:

A good read: https://thenewstack.io/push-vs-pull-in-gitops-is-there-really-a-difference/

Benefits of GitOps CI/CD

  1. Can use Git to track both Source Code and infrastructure configuration.
  2. Supports automated rollbacks (to specific Git Commits, Tags, or prior Releases).
  3. Git is already used in most CI/CD Pipelines.

CI/CD Tools

Continuous Improvement is typically implemented using either:

CI/CD tools specific to Kubernetes:

https://dev.to/ariefwara/jenkins-argo-cd-4ld5

  1. https://thenewstack.io/push-vs-pull-in-gitops-is-there-really-a-difference/
  2. https://helm.sh/
  3. https://helm.sh/docs/chart_template_guide/getting_started/
  4. https://fluxcd.io/flux/
  5. https://argo-cd.readthedocs.io/
  6. https://earthly.dev/blog/flux-vs-argo-cd/
  7. https://blog.aenix.io/argo-cd-vs-flux-cd-7b1d67a246ca
  8. https://dev.to/ariefwara/jenkins-argo-cd-4ld5

Linux Foundation CKA: Useful Commands

Commands that are useful for the exam itself.

Core Commands

# Switch Namespace context
kubectl config set-context --current --namespace=test

# Get all Resources
kubectl get all

# Get all Pods regardless of Namespace
kubectl get po --all-namespaces
## Inspect specific Pod
kubectl get pod mypod
### Detailed info
kubectl describe pod mypod 

# Dry run/don't actually create and output a YAML file with filename
kubectl create deployment --image=nginx nginx --dry-run=client -o yaml > nginx-deployment.yaml

# See the YAML config for a Resource, edit it live w/out saving, and automatically apply those changes
kubectl edit rs new-replica-set

# Create or update Pod from a file (see below)
kubectl apply -f pod-definition.yaml
## kubectl apply is often preferred over create and/or replace

# Create and run a Pod named nginx using the Image nginx w/out a config file
kubectl run nginx --image=nginx

# Print out config to YAML
kubectl get deploy nginx -o yaml > nginx.yaml

# Create a Service named redis-service with Pod redis associated on Port 6379
kubectl expose pod redis --port=6379 --name redis-service
kubectl expose pod httpd --port=80 --name=httpd --type=ClusterIP

# Check to see if I can create pods in any namespace
kubectl auth can-i create pods --all-namespaces

# Show all Labels
kubectl get nodes --show-labels
# Create a new Label on a Node
kubectl label nodes my-node-name x=y

# Add a taint
kubectl taint nodes controlplane x=y:NoSchedule
# Remove a taint
kubectl taint nodes controlplane x=y:NoSchedule-
# View taints
kubectl describe node controlplane |grep Taint
## These are present in `kubectl describe` 

Techniques

If a YAML is needed as a baseline one can be generated like so:

# Print out config to YAML 
kubectl get deploy nginx -o yaml > nginx.yaml
# Then override and update current Resources 
kubectl replace -f nginx.yml --force

Sometimes a field is protected (containers[0].name). This can nevertheless be updated by recreating:

# Edit some Resource
kubectl edit pod my-pod
# Even if it errors out a copy is saved to /tmp/
## /tmp/kubectl-edit-12345667.yml

# Update through recreation
kubectl delete pod my-pod
kubectl apply -f /tmp/kubectl-edit-12345667.yml
touch my.yaml
vi my.yaml # Vim if nano not present in env
nano my.yaml # Nano text editor