Kubernetes Deepdive

= Core Concepts =

Kubernetes Components
API Server - Frontend to Kubernetes; Users, Mgmt Devices, CLI talk to this. etcd Key Store - Distributed, Reliable Key Values Store used to store cluster data, implements lock to avoid conflicts for multiple Master nodes scenario. Kubelet - Agent that runs on each Node; responsible to make sure containers are running on nodes as expected. Container Runtime - Underlying software used to run containers(eg: Docker, etc) Controller - Brains behind orchestration; Notice & respond when Nodes, Containers, end points goes down; make decisions to bring up new containers Scheduler - Distributes work or containers across multiple Nodes; looks for newly created containers and assigns them to nodes.


 * Worker nodes were known as Minions earlier.
 * Worker Nodes host the containers

Master Node              Worker Nodes [Kube-ApiServer] ---> [Kubelet] [etcd] [controller] [scheduler]              [Container Runtime]  Docker, Rocket, CRI-O

kubectl run hello-minikube kubectl run nginx --image nginx kubectl cluster-info kubectl get nodes kubectl get pods kubectl describe pod myapp-pod
 * Kubectl used to deploy and manage applications on a Cluster to get cluster information.

PODS
Containers are encapsulated into kubenetes objects call Pods. Pod is a single Instance of Application. Pod is the smallest object that can be created in Kubernetes. If the no of users increases, we do not increase no of app instances(containers) inside pod, we add new Pods. You can deploy new pods in a new node if the capacity reaches for a single pod.

Rarely used Helper Containers can run inside your same pod as the main application pod. {[Python] [Helper pod]}
 * Multi-Container PODs

We run 4 application instances: docker run python-app docker run python-app docker run python-app docker run python-app

Then add 4 helper applications: docker run helper -link app1 docker run helper -link app2 docker run helper -link app3 docker run helper -link app4

Need to take care of networking and shared volumes Also need to monitor the containers.

With Pods, all of this is done automatically.

YAML in Kubernetes
Used as input for creating objects like Pods, Replicasets, depoyments, services, etc. Kubernetes definition file always contains 4 required root/top level properties: apiVersion:   --> version of Kubernetes API; eg: v1, apps/v1-beta, extensions/v1-beta, etc  => String kind:         --> Pod, Service, ReplicaSet, Deployment                                      => String metadata:     --> Data about object - Name, Label, etc; Spacing should be like python       => Dictionary spec:         --> Specify which image to be used, etc. Check documentation of Image         => Dictionary

Kind       Version POD        v1 Service     v1 ReplicaSet  apps/v1 Deployment apps/v1


 * API Version is specific to what we are creating.


 * Example Definition file:

> nano pod-definition.yaml

apiVersion: v1 kind: Pod metadata: name: my-app-pod labels:                ==> Used to identify pods in case you have 100s of them, else it will be difficult to manage them app: myapp type: front-end spec: containers:                     --> List/Array - name: nginx-container       --> '-' Indicates first item in the list. image: nginx

> kubectl create -f pod-definition.yml

ReplicaSets

 * Helps run multiple instances of single Pod
 * Provides High Availability.
 * If only a single instance of POD is running, it will make sure that it continues to run.
 * In case the instance fails, it will run another instance.


 * Replication Controller vs Replica Set:

apiVersion: v1 kind: ReplicationController metadata: name: my-app-rc labels: app: myapp type: front-end spec:                         ==> Replication Controller template:                   ==> Below is data copied from another definition file metadata: name: my-app-pod labels: app: myapp type: front-end spec:                     ==> POD containers: - name: nginx-container image: nginx replicas: 3
 * Replication Controller is older technology.
 * Usage:

Create Replication Controller: kubectl create -f rc-definition.yml kubectl get replicationcontroller

apiVersion: apps/v1 kind: ReplicaSet metadata: name: myapp-replicaset labels: app: myapp type: front-end spec:                         ==> Replication Controller template:                   ==> Below is data copied from another definition file metadata: name: my-app-pod labels: app: myapp type: front-end spec:                     ==> POD containers: - name: nginx-container image: nginx replicas: 3 selector:                   ==> Used because it can also manage pods not created during replication set creation; Mandatory matchLabels: type: front-end
 * ReplicaSet is newer technology.
 * Usage:

Create ReplicaSet: kubectl create -f rs-definition.yml kubectl get replicaset

Labels and Selectors

 * Scaling:

1st Method: Change replicas: => 6 kubectl replace -f rs-definition.yml

2nd Method: kubectl scale --replicas=6 -f rs-definition.yml OR kubectl scale --replicas=6 replicaset myapp-replicaset (type)  (name)

3rd Method: Scaling based on Load

Deployments
Use Case: You do not want to update all of your Webservers at once. Rolling Updates - Upgrade webserver one by one. Deployments allow us to upgrade instances seamlessly using rolling updates, undo changes, pause and resume changes as required.

Containers < POD < Replica Set < Deployment

Usage: apiVersion: apps/v1 kind: Deployment metadata: name: myapp-replicaset labels: app: myapp type: front-end spec: template: metadata: name: my-app-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx replicas: 3 selector: matchLabels: type: front-end

kubectl create -f deployment-definition.yml kubectl get deployments kubectl get relicaset kubectl get pods

Check all objects: kubectl get all

NameSpaces
[Mark Smith]   [Mark Williams]

Kubernetes creates a set of PODs and services for its internal purposes - required by Networking, DNS,etc. To isolate these from users & prevent accidental deletions or modification, kubernetes creates them under different Namespaces. These are created at cluster startup under namespace: kube-system kube-public is also created where resources available to all users are placed. For small environments you can continue using default namespace.

NameSpace Isolation: Use the same cluster for Dev & Production. Isolate them. Also you can apply Quota of resources to them.

Within NameSpace a POD can reach another service by using its hostname: mysql.connect("db-service")

For connecting into another NameSpace called 'dev': mysql.connect("db-service.dev.svc.cluster.local") db-service   =>   service-name dev          =>   namespace svc          =>   service cluster.local =>  domain

This command list pods from default name space only: kubectl get pods

Specify namespace to see its pods: kubectl get pods --namespace=kube-system

POD is created in default name space: kubectl create -f pod-definition.yml

To create it in another namespace: kubectl create -f pod-definition.yml --namespace=dev

Otherwise specify it in the Definition files: apiVersion: v1 kind: Pod metadata: name: my-app-pod namespace: dev labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx


 * Create Namespace:

1st Method:

apiVersion: v1 kind: Namespace metadata: name: dev

kubectl create -f namespace-dev.yml

2nd Method: kubectl create namespace dev

kubectl config set-context $(kubectl config current-context) --namespace=dev kubectl get pods                           ==> This will show pods under 'dev' kubectl get pods --namespace=default       ==> This will show pods under 'default'
 * Permanently change Namespace

To see PODs in all namespaces: kubectl get pods --all-namespaces


 * Create Quota:

apiVersion: v1 kind: ResourceQuota metadata: name: compute-qouta namespace: dev spec: hard: pods: "10" requests.cpu: "4" requests.memory: 5Gi limits.cpu: "10" limits.memory: 10Gi

kubectl create -f compute-qouta.yml

= Configuration =

Commands and Arguments in Docker
Containers are not meant to run OS Thats is why if you run below command it will fail to start container: docker run ubuntu

Docker files of popular containers has: Nginx => CMD ["nginx"] MySql => CMD ["mysqld"]

Ubuntu => CMD ["bash"]

Run Commands in Ubuntu bash: docker run ubuntu [command]

E.g: docker run ubuntu sleep 5

Making this change permanent: FROM Ubuntu CMD sleep 5

Or:

FROM Ubuntu CMD ["sleep", "5"]

Create a custom image from above: docker build -t ubuntu-sleeper. docker run ubuntu-sleeper

Changing the hard-coded values: docker run ubuntu-sleeper sleep 10

Using Default values and applying custom value too: FROM Ubuntu ENTRYPOINT ["sleep"] CMD ["5"]

docker run ubuntu-sleeper      ==> value = 5 (default) docker run ubuntu-sleeper 20

For changing entrypoint on the fly: docker run --entrypoint sleep2.0 ubuntu-sleeper 10    ==> Command run at startup = sleep2.0 10

Commands and Arguments in Kubernetes
Docker command: docker run --name ubuntu-sleeper --entry-point sleep2.0 ubuntu-sleeper 10

Docker file: FROM Ubuntu ENTRYPOINT ["sleep"] CMD ["5"]

Definition File:

apiVersion: v1 kind: Pod metadata: name: ubuntu-sleeper-pod spec: containers: - name: ubuntu-sleeper image: ubuntu-sleeper command: ["sleep2.0"] args: ["10"]

Environment Variables
Docker Command: docker run -e APP_COLOR=pink simple-webapp-color

Definition file: apiVersion: v1 kind: Pod metadata: name: simple-webapp-color spec: containers: - name: simple-webapp-color image: simple-webapp-color ports: - containerPort: 8080 env: - name: APP_COLOR value: pink

env: - name: APP_COLOR value: pink
 * Plain Key Value:

env: - name: APP_COLOR valueFrom: configMapKeyRef:
 * ConfigMap:

env: - name: APP_COLOR valueFrom: secretKeyRef:
 * Secrets:

Config Maps
kubectl create configmap
 * Two methods to create a definition file:
 * Create using Commands line:


 * Definition file:

apiVersion: v1 kind: ConfigMap metadata: name: app-config data: APP_COLOR: blue APP_MODE: prod

Create the config map: kubectl create -f config-map.yml


 * Using Config Maps for a Pod:

apiVersion: v1 kind: Pod metadata: name: simple-webapp-color spec: containers: - name: simple-webapp-color image: simple-webapp-color ports: - containerPort: 8080 envFrom: - configMapRef: name: app-config

kubectl create -f pod-definition.yml

kubectl get configmaps kubectl describe configmaps
 * Check Config Maps:

Secrets

 * Used to store passwords

Using CLI: kubectl create secret generic\ app-secret --from-literal=DB_Host=mysql \ --from-literal=DB_user=root \ --from-literal=DB_Password=passwd
 * 2 ways to create them

Using Definition file: apiVersion: v1 kind: Secret metadata: name: app-secret data: DB_Host=mysql DB_user=root DB_Password=passwd


 * Convert the secrets into encoded format:

$ echo -n 'mysql' | base64 bXlzcWw= $ echo -n 'root' | base64 cm9vdA== $ echo -n 'passwd' | base64 cGFzc3dk

apiVersion: v1 kind: Secret metadata: name: app-secret data: DB_Host=bXlzcWw= DB_user=cm9vdA== DB_Password=cGFzc3dk
 * Now use these values in the Definition file:

apiVersion: v1 kind: Pod metadata: name: simple-webapp-color labels: name: simple-webapp-color
 * Using the secret in a Pod:

spec: containers: - name: simple-webapp-color image: simple-webapp-color ports: - containerPort: 8080 envFrom: - secretRef: name: app-secret

Create the Pod: kubectl create -f pod-definition.yml

kubectl get secrets kubectl describe secrets kubectl get secret app-secret -o yaml        ==> This will show the hash values
 * Check Secrets:

$ echo -n 'bXlzcWw=' | base64 --decode mysql
 * Decode the hash values from above command:

If you mount the secret as a volume, each attribute in secret is created as file with value of secret as its content.
 * Mount secrets as a Volume:

volumes: - name: app-secret-volume secret: secretName: app-secret

Check Volumes: ls /opt/app-secret-volume cat /opt/app-secret-volume/DB_Password

Docker Security

 * Docker runs a process as user 'root' with PID = 1.
 * This process runs on the host in different namespace.
 * It can be seen on host with different PID.
 * But this root account is not having all privileges as a normal process with root privileges.

docker run --user=1001 ubuntu sleep 3600            ==> run as a non root user docker run --cap-add MAC_ADMIN ubuntu sleep 3600    ==> enable custom privileges docker run --privileged ubuntu sleep 3600           ==> run with full fledged root privileges


 * In Kubernetes you may choose to configure security at container level or Pod level.
 * Security applied at container level overrides security applied at Pod level.

apiVersion: v1 kind: Pod metadata: name: web-pod spec: securityContext: runAsUser: 1000 containers: - name: ubuntu image: ubuntu command: ["sleep","10"]
 * Pod Level Security:

apiVersion: v1 kind: Pod metadata: name: web-pod spec: containers: - name: ubuntu image: ubuntu command: ["sleep","10"] securityContext: runAsUser: 1000 capabilities: ["MAC_ADMIN"]
 * Container Level Security:

Service Account
User Account    - Used by Humans; eg - to deploy admin task or to deploy service Service Account - Used by Machines; eg - account used by service to interact with Kubernetes cluster; like Prometheus to monitor Cluster; Jenkins to deploy services.
 * There are two types of accounts in kubernetes:

kubectl create serviceaccount testacnt kubectl get serviceaccount kubectl describe serviceaccount testacnt       => Shows Token object kubectl describe secret testacnt-token-kddbm   => Shows Token
 * Create service account:

curl https://10.12.33.1:6443/api -insecure --header "Authorization: Bearer eyTdgf....."

Create the Service Account Assign right permissions using RBAC - Role Based Access Control. Export tokens and use it in the application.
 * Steps to use Service Accounts in Application:


 * For every namespace, there is a service account 'default' created by itself.

Mount the Secret as a volume inside the Pod running Application.
 * In case the application is hosted inside a Pod in cluster itself, we can simplify the authentication mechanism:

kubectl describe pod my-pod
 * By default every Pod is have a secret - 'default' mounted in it:

Mounts: /var/run/secrets/kubernetes.io/serviceaccount

kubectl exec -it my-pod ls /var/run/secrets/kubernetes.io/serviceaccount => ca.crt namespace  token

kubectl exec -it my-pod cat /var/run/secrets/kubernetes.io/serviceaccount/token eyTdgf.....
 * To view the Token:


 * 'default' service account is very much restrictive; can be used to run very basic kubernetes APIs.


 * Use a custom Service Account for a Pod:

apiVersion: v1 kind: Pod metadata: name: web-pod spec: containers: - name: ubuntu image: ubuntu serviceAccount: testacnt


 * You cannot change the Service Account for a POD. You must delete and recreate a POD.
 * However you can change the Service Account for a deployment. as any change to the POD deployment file will automatically trigger out a new rollout for the deployment.

Resource Requirements

 * Kubernetes Scheduler decides which node a Pod goes to.
 * Schedular takes into account the amount of resources required and amount of resources required.
 * If not enough resources are available, the Pod will remain in 'Pending' stuck state.
 * By default Kubernetes assumes that a Pod or a Container within Pod requires: 0.5 CPU; 256MB RAM

Minimum value = 1m
 * CPU => 0.1 == 100m (mili)

1 CPU => 1 AWS vCPU or         1 GCP Core or          1 Azure Core 1 Hyperthread 256Mi == 268435456 1G 1Gi
 * Memory:


 * Docker do not have any limit on the amount of resources it can consume, suffocating other nodes.
 * By default there is a limit of 1 vCPU & 512Mi RAM to a container.


 * Define Resource Request:

apiVersion: v1 kind: Pod metadata: name: web-pod spec: containers: - name: ubuntu image: ubuntu resources: requests: memory: "1Gi" cpu: 1 limits: memory: "2Gi" cpu: 2

Taints and Tolerations

 * Define what pods are placed on what nodes.
 * If Taint applied to a node, no Pod can be placed on it except for ones where you apply Toleration.

kubectl taint nodes node-name key=value:taint-effect kubectl taint nodes node1 app=blue:NoSchedule
 * Apply Taint:

taint-effect = NoSchedule         => Do not place new Pods PreferNoSchedule   => Try not to place new pods, no guarantees NoExecute          => Evict any Pods that do not tolerate the taint

apiVersion: v1 kind: Pod metadata: name: web-pod spec: containers: - name: ubuntu image: ubuntu tolerations: - keys: "app" operator: "Equal" value: "blue" effect: "NoSchedule"
 * Tolerations are added to Pods:

kubectl describe node kubemaster | grep Taint =>  Taints:      node-role:kubernetes.io/master:NoSchedule
 * Master Node is by dafault run with Taint: NoSchedule

Node Selectors
apiVersion: v1 kind: Pod metadata: name: web-pod spec: containers: - name: ubuntu image: ubuntu nodeSelector: size: Large
 * Used to run Heavy Applications on Bigger Nodes.
 * Define a Pod to be assigned to a Large Node:

kubectl label node  = kubectl label node node1 size=Large
 * Label Nodes:

Taints & Tolerations vs Node Affinity
= Multi-Container PODs =


 * Used when you need 2 services: WebServer + Log Agent
 * Both Apps have same life cycle - created together, destroyed together, Share Network space & have access to same Storage volumes

apiVersion: v1 kind: Pod metadata: name: web-pod spec: containers: - name: web-app image: web-app - name: log-agent image: log-agent
 * Creating Mulit-Container Pods:

Sidecar Adapter Ambassador
 * Design Patterns:

= Observability =

Pending             - run 'kubectl describe pod' to find why it is in pending state. ContainerCreating Running
 * Pod Status

PodScheduled Initialized ContainersReady Ready
 * Pod Conditions

To check the conditions: kubectl describe pod kubectl get pods        ==> READY  ->  Means -> ContainersReady & Ready = True

Readiness and Liveness Probes

 * Some pods (like jenkins) take 15 seconds to become ready.
 * But the Describe command shows it in Ready state during initialization too.
 * This is not correct.
 * Specify below readiness probe, kubernetes will not immediately set Ready state.


 * HTTP Test - /api/ready:

apiVersion: v1 kind: Pod metadata: name: web-pod spec: containers: - name: web-app image: web-app ports: - containerPort: 8080 readynessProbe: httpGet: path: /api/ready port: 8080

readynessProbe: tcpSocket: port: 3306
 * TCP Test - 3306

readynessProbe: exec: command: - cat - /app/is_ready
 * Exec Command

Liveness Probes
docker ps -a container id 4ygre874hufew        Exited(1) 41 seconds ago
 * If web server crashes, Nginx process exists & Container exits as well.

with every crash, "Restart" count increases. e.g: Due to a bug, application is stuck in an infinite loop. For Kubernetes, container is up, so the application is assumed to be up, but the users are not served with application. Now container needs to be restarted or destroyed and a new container needs to be brought up. Http Application - /api/healthy TCP Test - port 3306 Exec Command
 * Since Dockers is not an orchestration engine, Container continues to stay dead & denies services to users until you manually create a new container.
 * If Kubernetes Orchestration is used, every time the application crashes, Kubernetes makes an attempt to restart the container to restore service to the users.
 * Problem occurs if the application is not working but the container continues to stay alive.
 * Liveness probe tests if the application within the container is healthy or not.
 * Parameters to be tested:


 * HTTP Test - /api/healthy:

nano pod-definitaion.yaml

apiVersion: v1 kind: Pod metadata: name: web-pod spec: containers: - name: web-app image: web-app ports: - containerPort: 8080 livenessProbe: httpGet: path: /api/healthy port: 8080 initialDelaySeconds: 10 periodSeconds: 5 failureThreshod: 8

TCP Test - 3306 livenessProbe: tcpSocket: port: 3306

Exec Command livenessProbe: exec: command: - cat - /app/is_ready

Container Logging
docker run kodecloud/event-simulator
 * If you run an application which generates events & send them to standard output:

docker run -d kodecloud/event-simulator
 * If you run the container in background in detached mode, tose logs are not visible:

So you need to run below command to see logs: docker logs  docker logs -f                 shows Live logs

kubectl logs -f event-simulator-pod          shows Live logs
 * In Kubernetes, we can see the logs:

kubectl logs -f event-simulator-pod   event-simulator
 * If there are multiple containers in Pod, then you need to specify the name of the container you want to see the logs:

Monitor and Debug Applications
No of nodes in cluster How many are healthy Cpu,memory & network & Disk utilization No of pod Performance metrics of each pod - cpu, memory usage
 * Resource consumption monitoring


 * Kubernetes does not come with full monitoring tool.


 * There are opensource tools to monitor these resources - Metrics Server, Prometheus, Elastic Stack
 * Proprietary tools: - DataDog, Dynatrace

Heapster was original monitoring tool for Kubernetes, which is not deprecated. Its slim-down version is called Metrics Server. We can have 1 metrics server per Kubernetes Cluster. It retrieves metrics from each Kubernetes Nodes & Pods, aggregates them & stores them in memory. We cannot get historical data from it, need to install one of the other tool for this.
 * Metrics Server:
 * Kubelet is an agent which runs on each node, which takes instructions from kubernetes API master server & runs pods on nodes.
 * Kubelet also contains a sub-component called cAdvisor or Container Advisor.
 * cAdvisor is responsible for retreiving performance metrics from pods & exposing them through Kubelet API to make metrics available for the metrics server.

minikube addons enable metrics-server
 * If you use minikube for local cluster:

git clone https://github.com/kubernetes-incubator/metrics-serve kubectl create -f deploy/1.8+/
 * For other environments:

kubectl top node kubectl top pod
 * Usage:

= POD Design =

Labels, Selectors and Annotations

 * Labels & Selectors are used to group similar objects based on their class or kind.
 * Can filter based on multiple items
 * Labels are properties attached to each item - Class, Kind, Color, etc
 * Selectors help to filter these items. e.g: Class=Mammal; Color=Green


 * Kubernetes has objects like: Pods, Services, Replica Sets, Deployments,etc.
 * Can group objects by their Types(Pods, services,etc), Application(App1, App2,etc), Functionality(Front-End, DB, Auth,etc)
 * Apply labels & Using Selectors:

app = App1 function = Front-End

app = App2 function = Auth

app = App3 function = DB

Filter: app=App1

nano pod-definition.yaml apiVersion: v1 kind: Pod metadata: name: simple-webapp labels: app: App1 function: Front-end spec: containers: - name: simple-webapp image: simple-webapp ports: - containerPort: 8080
 * Applying Labels:

kubectl get pods --selector app=App1
 * Using Selectors:


 * Applying Labels to ReplicaSets:

nano replicaset-definition.yaml

apiVersion: apps/v1 kind: ReplicaSet metadata: name: simple-webapp labels:                               ==> These are labels for Replica Sets app: App1 function: Front-end spec: replicas: 3 selector:                             ==> Selectors matchLabels: app: App1 template:                             ==> These are the labels for Pods metadata: labels: app:App1 function: Front-end spec: containers: - name: simple-webapp image: simple-webapp ports: - containerPort: 8080

Annotations

 * Used to record tool details like Build, Version, name, contact details, etc

apiVersion: apps/v1 kind: ReplicaSet metadata: name: simple-webapp labels:                               ==> These are labels for Replica Sets app: App1 function: Front-end annotations: buildversions: 1.34

Rolling Updates & Rollbacks in Deployments
kubectl rollout status deployment/myapp-deployment Waiting for Rollout to finish: 0 of 10 updated replicas are available...  Waiting for Rollout to finish: 1 of 10 updated replicas are available...   Waiting for Rollout to finish: 2 of 10 updated replicas are available...   ........................................................................   Waiting for Rollout to finish: 9 of 10 updated replicas are available...   deployment "myapp-deployment" successfully rolled out.
 * New Rollout creates new revisions - Revision 1, Revision 2, etc

kubectl rollout history deployment/myapp-deployment

Recreate Startegy - Delete all old version pods & create new ones - Event - Scaled down replica set from 5 to 0. Rollout Update - Default - Updates one by one. - scaled up/down 5,4,3,2,1
 * Deployment Strategy

Creates a new replica set. Deploys new Pods in new Replica set Deletes old Pods one by one from old Replica set
 * Upgrades:

kubectl rollout undo deployment/myapp-deployment
 * Rollback:

Commands Summary
kubectl run nginx --image=nginx
 * Create Deployment by Kubectl run

Create: kubectl create -f deployment-definition.yml

Get: kubectl get deployments

Update: kubectl apply -f deployment-definition.yml kubectl set image deployment/myapp-deployment nginx=nginx:1.9.1

Status: kubectl rollout status deployment/myapp-deployment kubectl rollout history deployment/myapp-deployment

Rollback kubectl rollout undo deployment/myapp-deployment

Jobs
Normal Jobs run long time: App Web DB

Below processes carry out specific task & then finish: Batch Analytics Reporting

E.g of set of workloads meant for a short period of time: Performing a computation. Image processing Performing analytics on a large data set Generating report and sending email

In Docker: docker run ubuntu expr 3 + 2

After finishing this task: docker ps -a STATUS: Exited (0) 41 seconds ago (0 = Task completed successfully)

For Kubernetes:

apiVersion: v1 kind: Pod metadata: name: math-pod spec: containers: - name: math-add image: ubuntu command: ['expr', '3', '+', '2'] restartPolicy: Never

kubectl create -f pod-definition.yml

kubectl get pods STATUS: complete  RESTARTS: 1,2,3,4...... (continues to running because restartPolicy is set to Always by default)


 * ReplicaSet - Helps make sure that specified no of Pods are running all the time.
 * Jobs - Used to run a set of pods to perform a given task to completion.

nano job-definition.yaml

apiVersion: batch/v1 kind: Job metadata: name: math-add-job spec: template: spec: containers: - name: math-add image: ubuntu command: ['expr', '3', '+', '2'] restartPolicy: Never

Create Job: kubectl create -f job0definition.yaml

Check Jobs: kube get jobs

Check Pods: kubectl get pods READY: 0/1    STATUS: Completed     RESTARTS: 0     AGE: 2m

Check Output/logs: kubectl logs math-add-job-ld87pn 5

Delete Job: kubectl delete job math-add-job job.batch "math-add-job" deleted

Multiple Pods nano job-definition.yaml

apiVersion: batch/v1 kind: Job metadata: name: random-error-job spec: completions: 3         ==> Pods run sequentially, one after another's completion parallelism: 3         ==> Creates all 3 pods in parallel template: spec: containers: - name: random-error image: kodekloud/random-error restartPolicy: Never

CronJobs

 * CronJobs can be scheduled and run periodically.

nano cron-job-definition.yaml

apiVersion: batch/v1beta1 kind: CronJob metadata: name: reporting-cron-job spec:                              ==> for Cronjob schedule: "*/1 * * * *" jobTemplate: spec:                        ==> for Job completions: 3 parallelism: 3 template: spec:                  ==> for Pod containers: - name: reproting-tool image: reporting-tool restartPolicy: Never

kubectl create -f cron-job-definition.yaml kubectl get cronjob

= Services & Networking =

Services

 * Enable communication withing and outside of Application.
 * Help to connect application together with other applications or users
 * They enable connectivity between Client & Frontend, Frontend with Backend, Backend with External Datasources.


 * NodePort Service: Listens to a port on the node & forwards the requests to the pods.
 * ClusterIP: Service creates a virtual IP inside the cluster to enable communication between different services such as set of frontend sevrers to a set of backend servers.
 * LoadBalancer: Distributes load across nodes.

NodePort
[PC]-{NodePort-30008}[Kube Node]{Port-80}{TargetPort-80}[POD] 192.168.1.10             192.168.1.2           10.106.1.12                       10.244.0.1

NodePort Service[30008] curl http://192.168.1.2:30008 Node Port Range - 30000 - 32767


 * Labels & Selectors used to connect TargetPort to Pod.

nano service-definition.yml apiVersion:v1 kind: Service metadata: name: myapp-service spec: type: NodePort ports: - targetPort: 80      ==> If not provided, assumed to be same as targetPort port: 80            ==> Mandatory Field nodePort: 30008     ==> If not provided, automatically allocated from range(30000-32767) selector: app: myapp type: front-end
 * Create a NodePort Service:

kubectl create -f service-definition.yml kubectl get services

Check service: curl http://192.168.1.2:30008

curl http://192.168.1.2:30008 curl http://192.168.1.3:30008 curl http://192.168.1.4:30008
 * For Mapping multiple Pods, automatically mapping is created for all matching Pods with correct labels.
 * In case pods are on multiple Nodes:

Cluster IP

 * Full Stack Web Application:

Front-end  [POD-10.244.0.3]  [POD-10.244.0.4]   [POD-10.244.0.5] \       |          /                                  {back-end} Back-end   [POD-10.244.0.6]  [POD-10.244.0.7]   [POD-10.244.0.8] \       |          /                                   {redis} Redis      [POD-10.244.0.9]  [POD-10.244.0.10]  [POD-10.244.0.11]


 * The IPs of PODs are not static, they may change at any time.
 * Therefore Networking cannot be done on 1-1 IP/port basis.
 * Also it is difficult to decide which front end POD connect to which back end POD.
 * ClusterIP Service can be used to map each layer to an IP address/Port.


 * Creating ClusterIP:

nano service-definition.yml apiVersion: v1 kind: Service metadata: name: back-end spec: type: CLusterIP ports: - targetPort: 80 port: 80 selector: app: myapp type: back-end

kubectl create -f service-definition.yml kubectl get services


 * Service can be accessed by the ClusterIP or the Service Name.

Ingress Networking
[MySQL-POD]-[WebApp-POD]--[Client] [service-ClusterIP]             [service-NodePort-38080]
 * Normal Access:

Client access: http://192.168.1.10:38080 DNS Server : http://my-online-store.com:38080

[MySQL-POD]-[WebApp-POD][Proxy-Server]--[Client] [service-ClusterIP]             [service-NodePort-38080]                 [80]
 * Replacing the Port number with standard port:

Client access: http://my-online-store.com

[MySQL-POD]-[WebApp-POD][GCP-LoadBalancer]--[Client] [service-ClusterIP]             [service-NodePort-38080]                 [80]
 * In case hosting is done on Public Cloud, create a service of type LoadBalance, then Cloud (e.g: GCP) will automatically create a GCP-Loadbalancer:

Client access: http://my-online-store.com


 * For multiple services you need multiple GCP-LoadBalncers, Need to pay more & re-configure for every additional service.
 * Also you need to configure SSL for the applications, which becomes difficult to manage in case you have multiple applications, etc
 * Also need to configure firewall rules for each application too.
 * Ingress helps users access application using a single externally accessible URL.
 * It can be configured to route different services and can also provide SSL configuration point.
 * It can be thought of as a L7 LoadBalancer
 * Still it needs to be published as a NodePort or cloud native LoadBalancer, but that is just a one time configuration.

Ingress Controller - Nginx(Supported), HAProxy, Traefik, GCP HTTPS LoadBalancer(GCE)(Supported), Contour, Istio Ingress Resources: Rules
 * Components:

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-ingress-controller spec: replicas: 1 selector: matchLabels: name: nginx-ingress template: metadata: labels: name: nginx-ingress spec: containers: - name: nginx-ingress-controller image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.21.0 args: - /nginx-ingress-controllee - --configmap=$(POD_NAMESPACE)/nginx-configuration                               ==> This is below created ConfigMap env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ports: - name: http containerPort: 80 - name: https containerPort: 443
 * Configuring Nginx Controller


 * In order to decouple Nginx Config data like: error-log-path, keep-alive, ssl-protocols, Config-Map object is created and passed.
 * This blank will also do, because you dont need to change the nginx config files later on.

kind: ConfigMap apiVersion: v1 metadata: name: nginx-configuration
 * Config Map:


 * Service to expose the ingress controller to the external world:

apiVersion: v1 kind: Service metadata: name: nginx-ingress spec: type: NodePort ports: - port: 80 targetPort: 80 protocol: TCP name: http - port: 443 targetPort: 443 protocol: TCP name: https selector: name: nginx-ingress


 * Ingress Controllers monitor the kubernetes cluster for ingress resources and configure the underlying nginx server when something is changed.
 * For this, a service account is needed which has - correct Roles, ClusterRoles & RoleBindings:

apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress-serviceaccount

Deployment Service ConfigMap Auth
 * Therefore below objects are needed for a simple Ingress Controller:

www.mysite.com/wear-->[wear-POD] www.mysite.com/video->[video-POD]
 * Ingress Resources:

wear.mysite.com-->[wear-POD] video.mysite.com->[video-POD]

nano ingress-wear.yaml

apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-wear spec: backend: serviceName: wear-service servicePort: 80

kubectl create -f ingress-wear.yaml kubectl get ingress

nano ingress-wear-watch.yaml
 * Using Paths:

apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-wear-watch spec: rules: - http: paths: - path: /wear backend: serviceName: wear-service servicePort: 80 - path: /watch backend: serviceName: watch-service servicePort: 80

Check the Backends: kubectl describe ingress ingress-wear-watch

nano ingress-wear-watch.yaml
 * Using Host names:

apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-wear-watch spec: rules: - host: wear.mysite.com http: paths: -   backend: serviceName: wear-service servicePort: 80 - host: video.mysite.com http: paths: -   backend: serviceName: watch-service servicePort: 80

Network Policies
= State Persistence =

Persistent Volume Claims
= Kubernetes Challenge Series =