Skip to content

Instantly share code, notes, and snippets.

@vsathyak
Last active July 13, 2023 08:54
Show Gist options
  • Save vsathyak/e4875d93d93de2cc2f522a0a41020c30 to your computer and use it in GitHub Desktop.
Save vsathyak/e4875d93d93de2cc2f522a0a41020c30 to your computer and use it in GitHub Desktop.
Kubernetes Architecture
~~~~~~~~~~~~~~~~~~~~~~~
Nodes
-----
. A node is a machine, physical or virtual on which Kubernetes is installed.
. A node is a worker machine and that is where containers will be launched by Kubernetes.
- A worker node is also called as minions
Cluster
-------
. A set of nodes grouped together. So if one fails you have your application still accessible from the other nodes.
. Having multiple nodes helps in sharing load as well
Master Node
-----------
. Master is another node with Kubernetes installed in it and is configured as master.
. The master watches over the nodes in the cluster and is responsible for the actual orchestration of the containers
in the worker nodes.
. The information about the members of the cluster is stored in the master node
. Master node is responsible for monitoring other nodes
. When a node fails, it is the master node which is responsible for moving the workload of the failed node to another
worker node
Components installed as part of Kubernetes installation
--------------------------------------------------------
. API Server : acts as the front end for Kubernetes. The users, management devices, command line interfaces all talk to
the API server to interact with the Kubernetes cluster.
. etcd service : etcd is a distributedm reliable key value store used by Kubernetes to store all data used to manage
the cluster. When you have multiple worker nodes and multiple masters in your cluster, etcd stores all that
information on all the nodes in the cluster in a distributed manner. etcd is responsible for implementing locks
within the cluster to ensure that there are no conflicts between the Masters.
. kubelet service : Kubelet is the agent that runs on each node in the cluster. The agent is responsible for making
sure that the containers are running on the nodes as expected.
. Container Runtime : is the underlying software that is used to run containers. Eg. Docker
. Controllers : are the brain behind orchestration. They are responsible for noticing and responding when nodes,
containers or end points goes down
. Schedulers : is responsible for distributing the work or containers across multiple nodes. It looks for newly created
containers and assign them to nodes. The controller make decision to bring up new containers in such cases.
|---------------------| |----------------------|
| kube-api server<---|-------------------------------|--->kubelet |
| | | |
| etcd | | |
| | | |
| controller | | |
| | | |
| scheduler | | container runtime |
|---------------------| |----------------------|
Master Worker
kubectl
-------
. kubectl tool is used to deploy and manage applications on a Kubernetes cluster.
. To get cluster information, to get the status of other nodes in the cluster and to manage many other things.
. kubectl run command is used to deploy an application on the cluster
. kubectl cluster info command is used to view information about the cluster
. kubectl get nodes is used to list all the nodes part of the cluster
>> kubectl run hello-minikube
>> kubectl cluster-info
>> kubectl get nodes
======================================================================================================================
PODS
~~~~
. Kubernetes doesnot deploy containers directly on the worker nodes.
. Containers are encapsulted into a kubernetes object known as pods.
. A pod is a single instance of an application.
. A pod is the smallest object that you can create in Kubernetes.
Create a pod using an image >> kubectl run <pod_name> --image <image_name>
Eg. kubectl run nginx --image nginx
List all pods >> kubectl get pods
List all pods with labels >> kubectl get pods --show-labels
Get pods info >> kubectl describe pods
List all pods with ip & node info >> kubectl get pods -o wide
List all nodes >> kubectl get nodes
Get node info >> kubectl describe node <nodename>
To datatype info of each key under pods >> kubectl explain pod --recursive | less
======================================================================================================================
PODS with YAML
~~~~~~~~~~~~~~
. Kubernetes definition file always contain four top level fields
>> vim pod-definition.yml ==> |----------------|
| apiVersion: |
| kind: |
| metadata: |
| spec: |
|________________|
. These are the top level or root level properties
. These are also the required files, so you must have them in your configuration file
Explaing the pod-definition file in detail
------------------------------------------
>> vim pod-definition.yml
apiVersion: v1 (Other values : apps/v1, extensions/v1Beta)
kind: Pod (Other values : ReplicaSet, Deployment or Service)
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx
>> kubectl create -f pod-definition.yaml
. apiVersion
- This is the version of the Kubernetes API you are using to create the objects.
. kind
- Kind refers to the type of object we are trying to create which in this case happens to be Pod
. metadata
- Metadata is the data about the object like its name, labels etc
- This will be in the form of dictionary where as the apiVersion and kind shoud always be String
- 'name' and 'label' properties are of sibling tags, so they should be of same level while writing yaml file
- Under metadata, name is a string value where as the labels is a dictionary within the metadata dictionary
- labels can have any key value pairs
. spec :
- Spec is a dictionary
- Information regarding the container is specified under spec
- containers is a list since we can build multiple containers under same pod
Creating the pod >> kubectl create -f pod-definition.yml
Get the list of pods >> kubectl get pods
To see details about a pod >> kubectl describe pod <my_pod_name>
To see list of pods with its node and ip info >> kubectl get pods -o wide
To generate pod definition file from a running pod >> kubectl get pod <pod_name> -o yaml > pod-def.yaml
To delete a pod >> kubectl delete pod <pod_name>
To delete a pod without delay >> kubectl delete pod <pod_name> --grace-period=0 --force
To edit a pod >> kubectl edit pod <pod_name>
To apply a change to a running pod >> First update the pod definition file. Then
>> kubectl apply -f pod-def.yaml
Kubernetes Objects Version based on Kind >> .__________________________.
| Kind | Version |
|--------------------------|
| POD | v1 |
| Service | v1 |
| ReplicaSet | apps/v1 |
| Deployment | apps/v1 |
| DaemonSets | apps/v1 |
|_____________|____________|
Edit PODs
~~~~~~~~~
If you are given a pod definition file, edit that file and use it to create a new pod.
If you are not given a pod definition file, you may extract the definition to a file using the below command:
kubectl get pod <pod-name> -o yaml > pod-definition.yaml
Then edit the file to make the necessary changes, delete and re-create the pod.
OR
Use the kubectl edit pod <pod-name> command to edit pod properties.
======================================================================================================================
Replication Controllers and ReplicaSets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Replication Controller
----------------------
- helps us run multiple instance of a single pod in the kubernetes cluster thus providing high availability
- Even if you have a single pod, the replication controller can help by automatically bringing up a new pod when the
existing one fails
- A Replication Controller is a structure that enables you to easily create multiple pods, then make sure that that
number of pods always exists. If a pod does crash, the Replication Controller replaces it.
- Replication Controllers also provide other benefits, such as the ability to scale the number of pods, and to update
or delete multiple pods with a single command.
>> vim replcontroller-definiton.yml
apiVersion: v1
kind: ReplicationController
metadata: # metadata for Replication Controller
name: myapp-rc
labels:
name: myapp
type: front-end
spec: # spec for Replication Controller
template:
metadata: # metadata for Pods
name: myapp-pod
labels:
app: myapp
type: frontend-app
spec: # spec for Pods
containers:
- name: nginx-container
image: nginx
replicas: 5
When the replication controller is created using the below syntax, it first creates the pod using the pod definition
template as many as required, which is five in this case.
Create Replication Controller >> kubectl create -f repcontroller-definiton.yml
To view the list of created Replication Controller >> kubectl get replicationcontroller
To view the Pods created using Replication Controller >> kubectl get pods
Replica Set
-----------
- The Replication Controller is the original form of replication in Kubernetes. It’s being replaced by Replica Sets,
but it’s still in wide use.
- Replica Sets are declared in essentially the same way as Replication Controllers, except that they have more
options for the selector.
>> vim replicaset-definiton.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp-replicaset
labels:
app: myapp
type: front-end
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp <----|
type: front-end <----|
spec: |
containers: |
- name: nginx-controller |
image: nginx |
|
replicas: 3 |
selector: |
matchLabels: |
type: front-end # The value should be the label defined in the pod definition.
# which could be app or type in this case.
When the replica set is created using the above syntax, it first creates the pod using the pod definition template as
many as required, which is three in this case.
Create Replica Set >> kubectl create -f replicaset-definiton.yml
To view the list of created Replica Set >> kubectl get replicaset
To view the Pods created using Replica Set >> kubectl get pods
To delete Replica Set >> kubectl delete replicaset myapp-replicaset
>> kubectl delete rs myapp-replicaset
To know more about the Replica Set >> kubectl describe replicaset
>> kubectl describe rs
To fix an existing Replica Set >> kubectl get replicaset
>> kubectl edit replicaset <replicaset-name>
Now do edit and save and then delete the existing pods.
Create replicaset def file from running replicaset >> kubectl get replicaset <rs_name> -o yaml > rep-set-def.yaml
This will export/generate the replicaset definition file
Scale ReplicaSet to x number
----------------------------
There are multiple ways
1. Update the number of replicas in the definition file to 'x'. Eg : 3 and then run the following command
>> kubctl replace -f replicaset-definiton.yml
2. The second way to do scaling is to run the kubectl scale command
>> kubectl scale --replicas=6 -f replicaset-definition.yml
>> kubectl scale --replicas=6 replicaset myapp-replicaset
| |
Type name mentioned in metadata
3. The third way is to edit the replicaset
>> kubectl get replicaset
>> kubectl edit replicaset <replicaset-name>
>> Now modify the replicas and save the file
======================================================================================================================
Deployments
~~~~~~~~~~~
Deployment provide the capability to upgrade the underlying instances seamlessly using rolling updates, undo changes and
pause and resume changes as required.
>> vim deployment-definiton.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
labels:
app: myapp
type: front-end
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp <----|
type: front-end <----|
spec: |
containers: |
- name: nginx-controller |
image: nginx | |
|
replicas: 3 |
|
selector: |
matchLabels: |
type: front-end # The value should be the label defined in the pod definition.
Create Deployment >> kubectl create -f deployment-definiton.yml
To view the Deployments >> kubectl get deployments
To view the ReplicaSet >> kubectl get replicaset
To view all the objects >> kubectl get all
To edit an existing deployment >> kubectl edit deployment <deployment_name>
To know more about the Deployment >> kubectl describe deployment
To view a specific deployment info >> kubectl describe deployment <deployment_name>
Note1 : Deployment autmatically creates ReplicaSet and ReplicaSet ultimately create pods
Note2 : In production use cases, you will not creating pod definion files or replica set definition files.
Instead you will be creating deployment definition files.
======================================================================================================================
A quick note on editing PODs and Deployments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Edit a POD
----------
. Extract the pod definition in YAML format to a file using the command
. Then make the changes to the exported file using an editor (vi editor). Save the changes
. Then delete the existing pod
. Then create a new pod with the edited file
>> kubectl get pod webapp -o yaml > my-new-pod.yaml
>> vim my-new-pod.yaml
>> kubectl delete pod webapp
>> kubectl create -f my-new-pod.yaml
Edit Deployments
----------------
>> kubectl edit deployment my-deployment
======================================================================================================================
Namespaces
~~~~~~~~~~
In every cluste, there will be 3 namespaces exist by default.
. default
. kube-system
. kube-public
Assume we have 3 pods in default name space and 2 in dev name space.
Default dev
------- ---
. web-pod . web-pod
. db-service . db-service
. web-deployment
Note : The resources within a namespace can refer to each other simply by their names.
Eg: The web app pod can reach the db service simply using the hostname db service. (Both in default)
>> mysql.connect("db-service")
Resources in 2 different namespaces can communicate and for that we need to apped the name of namespace along with
service name.
Eg: The web pod in default namespace to connect to the database in the dev namespace,
For that use the servicename.namespace.svc.cluster.local format => db-service.dev.svc.cluster.local
>> mysql.connect("db-service.dev.svc.cluster.local")
| | | |__________|
| | | |-----------> domain
| | |--------------------> Service
| |-------------------------> Namespace
|-----------------------------------> Service Name
To get all namespaces >> kubectl get namespaces
To get all pods in default or current namespace >> kubectl get pods
To get all pods in different namespace eg 'kube-system' >> kubectl get pods --namespace=kube-system
To create pods >> kubectl create -f pod-definition.yml
To create pods in a different name space >> kubectl create -f pod-definition.yml --namespace=dev
(or keep the namespace in pod-definition.yml.)
|
>> vi pod-definition.yml <-|
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
namespace: dev ---> NAMESPACE
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx
To create a new name space
--------------------------
>> vim namespace-dev.yml
apiVersion: v1
kind: Namespace
metadata:
name: dev
>> kubectl create -f namespace-dev.yml
OR
>> kubectl create namespace <namespace_name>
Eg. kubectl create namespace dev
Eg. kubectl create namespace qa
Eg. kubectl create namespace prod
Switch namespace to dev >> kubectl config set-context $(kubectl config current-context) --namespace=dev
>> kubectl config set-context <cluster_name> --namespace=dev
Get pods in all namespaces >> kubectl get pods --all-namespaces
To limit resources in a namespaces, create a resource quota
-----------------------------------------------------------
>> vim compute-quota.yml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: dev
spec:
hard:
pods: "10"
requests.cpu: "4"
requests.memory: 5Gi
limits.cpu: "10"
limits.memory: 10Gi
>> kubectl create -f compute-quota.yml
======================================================================================================================
Certification Tip
~~~~~~~~~~~~~~~~~
Reference :: https://kubernetes.io/docs/reference/kubectl/conventions/
Create an NGINX Pod and expose a port
-------------------------------------
>> kubectl run nginx --image=nginx --port=<port_id>
Create an NGINX Pod on a specific namespace
-------------------------------------------
>> kubectl run nginx --image=nginx -n <namespace_name>
>> kubectl run nginx --image=nginx --namespace=<namespace_name>
Generate POD Manifest YAML file (-o yaml). Don't create it(--dry-run=client)
---------------------------------------------------------------------
>> kubectl run nginx --image=nginx --dry-run=client -o yaml
Create a busybox pod with sleep command for 3600 sec
----------------------------------------------------
>> kubectl run busybox --image=busybox --dry-run=client -o yaml --command -- sleep 3600
>> kubectl run busybox --image=busybox --dry-run=client -o yaml --command -- /bin/sh -c ls /root
Create a static pod named static-busybox that uses the busybox image and the command sleep 1000
-----------------------------------------------------------------------------------------------
>> kubectl run --restart=Never --image=busybox static-busybox --dry-run=client -o yaml --command -- sleep 1000 > busybox.yaml
Deploy a redis pod using the redis:alpine image with the labels set to tier=db
------------------------------------------------------------------------------
>> kubectl run redis --image=redis:alpine -l tier=db
OR
>> Use imperative commands to generate the pod definition file,
Then add the labels before creating the pod using the file.
Create a deployment
-------------------
>> kubectl create deployment nginx --image=nginx
Generate Deployment YAML file (-o yaml). Don't create it(--dry-run)
-------------------------------------------------------------------
>> kubectl create deployment nginx --image=nginx --dry-run=client -o yaml
Generate Deployment YAML file (-o yaml). Don't create it(--dry-run) with 4 Replicas (--replicas=4)
--------------------------------------------------------------------------------------------------
>> kubectl create deployment nginx --image=nginx --replicas=4 --dry-run=client -o yaml
# kubectl create deployment does not have a --replicas option. --> Nolonger a valid case.
# You could first create it and then scale it using the kubectl scale command. --> Nolonger a valid case.
Save it to a file - (If you need to modify or add some other details)
---------------------------------------------------------------------
>> kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > nginx-deploy.yaml
Create a Service named redis-service of type ClusterIP to expose pod redis on port 6379
---------------------------------------------------------------------------------------
>> kubectl expose pod redis --port=6379 --name redis-service --dry-run -o yaml
(This will automatically use the pod's labels as selectors)
OR
>> kubectl create service <servicetype> <servicename> --tcp=port:targetport --dry-run=client -o yaml (RECOMMENDED WAY)
>> kubectl create service clusterip redis --tcp=6379:6379 --dry-run=client -o yaml (RECOMMENDED WAY)
(This will not use the pods labels as selectors, instead it will assume selectors as app=redis. You cannot pass in
selectors as an option. So it does not work very well if your pod has a different label set. So generate the file
and modify the selectors before creating the service)
Create a Service named nginx of type NodePort and expose it on port 30080 on the nodes
--------------------------------------------------------------------------------------
>> kubectl expose pod nginx --port=80 --name nginx-service --dry-run -o yaml
(This will automatically use the pod's labels as selectors, but you cannot specify the node port. You have to
generate a definition file and then add the node port in manually before creating the service with the pod.)
Here we have created service using pod nginx. Like that we could create service using deployment and the syntax is
>> kubectl expose deployment <deployment-name> --port=80 --name service-name --dry-run -o yaml
OR
>> kubectl create service <ser_type> <ser_name> --tcp=port:targetport --node-port=port_id --dry-run -o yaml (RECOMMENDED)
>> kubectl create service nodeport nginx --tcp=80:80 --node-port=30080 --dry-run -o yaml
(This will not use the pods labels as selectors)
Both the above commands have their own challenges. While one of it cannot accept a selector the other cannot accept
a node port. I would recommend going with the `kubectl expose` cmd. If you need to specify a node port, generate a
definition file using the same command and manually input the nodeport before creating the service.
>> kubectl expose deployment webapp --name=webapp-service --type=NodePort --port=8080 --dry-run -o yaml
Edit the file and add node port
Create a job
------------
>> kubectl create job <job_name> --image=<image_name>
>> kubectl create job my-job --image=busybox
Create a job with command
-------------------------
>> kubectl create job my-job --image=busybox -- date
Create a job from a CronJob named "a-cronjob"
---------------------------------------------
>> kubectl create job test-job --from=cronjob/a-cronjob
Create a cronjob
----------------
>> kubectl create cronjob my-job --image=busybox
Create a cronjob with command
-----------------------------
>> kubectl create cronjob my-job --image=busybox -- date
Create a cronjob with schedule
------------------------------
>> kubectl create cronjob test-job --image=busybox --schedule="*/1 * * * *"
Create a cronjob with restart option 'OnFailure, Never'
-------------------------------------------------------
>> kubectl create cronjob test-job --image=busybox --restart="Never"
>> kubectl create cronjob test-job --image=busybox --restart="OnFailure"
Create a job with the image busybox that executes the command 'echo hello;sleep 30;echo world'
----------------------------------------------------------------------------------------------
>> kubectl create job busybox --image=busybox -- /bin/sh -c 'echo hello;sleep 30;echo world'
======================================================================================================================
Configurations
~~~~~~~~~~~~~~
Prerequisite - Commands and Arguments in Docker
-----------------------------------------------
Assume the docker file for the ubuntu-sleeper looks as follows.
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["5"]
Create a pod which sleeps 10 seconds by default
-----------------------------------------------
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: ubuntu-sleeper-pod
spec:
containers:
- name: ubuntu
image: ubuntu
command: ["sleep"] <<====== Replaces the ENTRYPOINT command in dockerfile
args: ["10"] <<====== Replaces the CMD command in dockerfile
Create a pod with the ubuntu image to run a container to sleep for 5000 seconds
-------------------------------------------------------------------------------
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: ubuntu-sleeper-2
spec:
containers:
- name: ubuntu
image: ubuntu
command: --|
- "sleep" |- This can also write like this --> command: ["sleep", "5000"]
- "5000" --|
Create a pod with given specs. By default it displays a 'blue' background.
Set the given cmd line arguments to change it to 'green'
-------------------------------------------------------------------------
>> vim pod-def.yaml
apiVersion: v1 Pod Name: webapp-green
kind: Pod Image: kodekloud/webapp-color
metadata: Command line arguments: --color=green
name: webapp-green
spec:
containers:
- name: simple-webapp
image: kodekloud/webapp-color
args: ["--color","green"] --> This can also write as follows args:
- "--color"
- "green"
======================================================================================================================
Environment Variables
~~~~~~~~~~~~~~~~~~~~~
ENV Variables in Kubernetes
---------------------------
>> vim pod-def.yaml
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 <== ENV_NAME
value: pink <== ENV_VALUE
Other way of adding value from Configmaps and Secrets
-----------------------------------------------------
env:
- name: APP_COLOR
valueFrom:
configMapKeyRef: ==> CONFIGMAP
env:
- name: APP_COLOR
valueFrom:
secretKeyRef: ==> SECRETS
======================================================================================================================
ConfigMaps
~~~~~~~~~~
When you have lot of pod definiton files, it will become difficult to manage the environment data stored within the
query files. We can take this information out of pod definition file & manage it centrally using Configuration maps.
ConfigMaps are used to pass configuration data in the form of key value pairs in Kubernetes.
When a pod is created inject the config map into the pod, so the key value pairs that are available as env variable
for the application hosted inside the container in the pod. There are 2 phases involved in configuring ConfigMaps.
1. Create the ConfigMaps
2. Inject them into the pod
2 ways to create a ConfigMaps
a. The imperative way without using a ConfigMap definition file
b. The declarative way by using a ConfigMap definition file
If you donot wish to create a configmap definition file, you could simple use the kubectl create configmap command and
specify the required arguments.
Creating configmap using Imperative way >> kubectl create configmap <config-name> --from-literal=<key>=<value>
Eg. kubectl create configmap app-config --from-literal=APP_COLOR=blue
Note :: from-literal is used to specify the key value pair in the command itself.
Create configmap with muliple keyvalue pair >> kubectl create configmap <config-name> --from-literal=<key1>=<value1>
--from-literal=<key2>=<value2>
Eg. kubectl create configmap app-config --from-literal=APP_COLOR=blue
--from-literal=APP_MODE=prod
Create configmap with input data from a file >> kubectl create configmap <config-name> --from-file=<path_to_file>
Eg. kubectl create configmap app-config --from-file=app_config.properties
Creating configmap using Declarative way
----------------------------------------
>> vim config-map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_COLOR: blue
APP_MODE: prod
>> kubectl create -f config-map.yaml
To view configmaps >> kubectl get configmaps
To describe configmaps >> kubectl describe configmaps
Injecting the configmap into pod
--------------------------------
For the use the key 'envFrom' under the container info in your pod-def file
>> vim pod-def.yaml
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
So the different ways to inject config data into pod are
--------------------------------------------------------
1. Using ConfigMap to inject environment variables
envFrom:
- configMapRef:
name: app-config
2. Inject as single environment variable
env:
- name: APP_COLOR
valueFrom:
ConfigMapKeyRef:
name: app-config
key: APP_COLOR
3. Inject the whole data as files in a volume
volumes:
- name: app-config-volume
configMap:
name: app-config
======================================================================================================================
Secrets
~~~~~~~
. Secrets are similar to configmaps except they are stored in an encoded or hashed format.
. Secreats are used to store sensitive data such as passwords..
There are 2 two steps involved in working with secrets
1. Create Secret
2. Inject them into pod
There are 2 ways to create a Secret
a. Imperative way
b. Declarative way
Creating Secrets using Imperative way >> kubectl create secret generic <secret-name> --from-literal=<key>=<value>
Eg. kubectl create secret generic app-secret --from-literal=DB_Host=mysql
Note :: from-literal is used to specify the key value pair in the command itself.
Create Secret with multi keyvalue pair >> kubectl create secret generic <secret-name> --from-literal=<key>=<value>
--from-literal=<key2>=<value2>
Eg. kubectl create secret generic app-secret --from-literal=DB_Host=mysql
--from-literal=DB_User=root
--from-literal=DB_Password=pwd
Create secret with i/p data from a file >> kubectl create secret generic <secret-name> --from-file=<path_to_file>
Eg. kubectl create secret generic app-secret --from-file=app_secret.properties
Creating secret using Declarative way >> kubectl create -f secret-data.yaml
>> vim secret-data.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secret
data:
DB_Host: bXlzcWw= <-- Here the data is in encoded form, which was converted to
DB_User: cm9vdA== base 64 before passing it here and is explained below. |
DB_Password: cGFzd3Jk |
|
Convert data to base64 on linux host |
------------------------------------ <<-----|
>> echo -n 'mysql' | base64 --> bXlzcWw=
>> echo -n 'root' | base64 --> cm9vdA==
>> echo -n 'pwd' | base64 --> cGFzd3Jk
Convert encoded data to original value on linux host
----------------------------------------------------
>> echo -n 'bXlzcWw=' | base64 --decode --> mysql
>> echo -n 'cm9vdA==' | base64 --decode --> root
>> echo -n 'cGFzd3Jk' | base64 --decode --> pwd
To view secrets >> kubectl get secrets
To view more info about a secret >> kubectl describe secrets
To view more info about a secret with value >> kubectl get secrets <secret_name> -o yaml
Eg. kubectl get secrets app_secret -o yaml
Injecting the secret into pod
--------------------------------
For the use the key 'envFrom' under the container info in your pod-def file
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp-color
spec:
containers:
- name: simple-webapp-color
image: simple-webapp-color
ports:
- containerPort: 8080
envFrom:
- secretRef:
name: app-secret
So the different ways to inject secret data into pod are
--------------------------------------------------------
1. Using Secrets to inject environment variables
envFrom:
- secretRef:
name: app-secret
2. Inject secret as single environment variable
env:
- name: DB_Password --> Environment variable set
valueFrom:
SecretKeyRef:
name: app-secret --> Name of the secret we created
key: DB_Password --> Name of the key from the secret-data which we need to use.
3. Inject the whole secret as files in a volume
volumes:
- name: app-secret-volume
secret:
secretName: app-secret
If we are mounting secrets as a volume in the pod, each attribute in the secret is created as a file with the value of
the secret as its content.
In the above mentioned case three files get create since we have 3 attributes
>> ls /opt/app-secret-volumes
DB_Host DB_Password DB_User
>> cat /opt/app-secret-volumes/DB_Host
mysql
======================================================================================================================
A note about Secrets
~~~~~~~~~~~~~~~~~~~~
Remember that secrets encode data in base64 format. Anyone with the base64 encoded secret can easily decode it. As such
the secrets can be considered as not very safe.
The concept of safety of the Secrets is a bit confusing in Kubernetes. The kubernetes documentation page and a lot of
blogs out there refer to secrets as a "safer option" to store sensitive data. They are safer than storing in plain text
as they reduce the risk of accidentally exposing passwords and other sensitive data. In my opinion it's not the secret
itself that is safe, it is the practices around it.
Secrets are not encrypted, so it is not safer in that sense. However, some best practices around using secrets make it
safer. As in best practices like:
. Not checking-in secret object definition files to source code repositories.
. Enabling Encryption at Rest for Secrets so they are stored encrypted in ETCD.
Also the way kubernetes handles secrets. Such as:
. A secret is only sent to a node if a pod on that node requires it.
. Kubelet stores the secret into a tmpfs so that the secret is not written to disk storage.
. Once the Pod that depends on the secret is deleted, kubelet will delete its local copy of the secret data as well.
Read about the protections and risks of using secrets here
Having said that, there are other better ways of handling sensitive data like passwords in Kubernetes, such as using
tools like Helm Secrets, HashiCorp Vault.
Kubernetes Secret Ref Doc >> https://kubernetes.io/docs/concepts/configuration/secret/
Encrypting Secret Data at Rest Ref Doc >> https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
Protection and Risk of using Secret Ref Doc >> https://kubernetes.io/docs/concepts/configuration/secret/#protections
======================================================================================================================
Security Contexts
~~~~~~~~~~~~~~~~~
When we run a docker container, you have the option to define a set of security standards such as 'ID of the user used
to run the container', the linux capabilities that can be added or removed form the container etc.
Eg1: docker container run --user=1001 ubuntu sleep 3600
Eg2: docker container run --cap-add MAC_ADMIN ubuntu
This can be configured in kubernetes as well. In kubernetes containers are encapsulated in pods. You may choose to
configure the security settings at a container lever or at a pod level.
If you configure it at a pod level, the settings will carry over to all the container within the pod.
If you configure it at both pod & container level, the settings on the container will override the settings on the pod.
>> vim pod-def.yaml
Security Context on Pod Level Security Context on Container Level
----------------------------- -----------------------------------
apiVersion: v1 apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: web-pod name: web-pod
spec: spec:
securityContext: <=== POD LEVEL containers:
runAsUser: 1000 - name: ubuntu
containers: image: ubuntu
- name: ubuntu command: ["sleep", "3600"]
image: ubuntu securityContext: <=== CONTAINER LEVEL
command: ["sleep", "3600"] runAsUser: 1000
capabilities:
add: ["MAC_ADMIN"]
Note : Capabilites are only supported at the container level and not at the POD level.
======================================================================================================================
Resource Requirement and Limits
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
. Each node in a kubernetes cluster has a set of CPU, Memory and Disk resources.
. Every pods consume certain amount of CPU, Memory and Disk spaces.
Resource requirement for each pod
---------------------------------
By default, kubernetes assume a pod requires 0.5 CPU and 256 Mi of memory. This is known as the resource request for a
container, the minimum amount of CPU or memory requested by the container.
By default kubernetes sets a usage limit of 1 vCPU of CPU and 512 Mi of memory for a container.
You can modify these values by modifying them in your pod or definition files
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp-color
spec:
containers:
- name: simple-webapp-color
image: simple-webapp-color
ports:
- containerPort: 8080
resources:
requests:
memory: "1Gi" (if in Mebibyte, it will be something like "256Mi")
cpu: 1
limits:
memory: "2Gi"
cpu: 2
1 count of cpu ==> 1 AWS vCPU
1 GCP Core
1 Azure Core
1 Hyperthread
======================================================================================================================
Service Account
~~~~~~~~~~~~~~~
There are two types of accounts in Kubernetes - a user account and a service account.
. User account is used by humans, eg. for an administrator accessing the cluster to perform administrative tasks or a
developer accessing the cluster to deploy applications etc..
. Service account could be an account used by an application to interact with a Kubernetes cluster. For example a
monitoring application like Prometheus is used as a service account to pull the Kubernetes API for performance
metrics. An automated build tool like Jenkin's uses service accounts to deploy applications on the Kubernetes
cluster.
Create Service Account
----------------------
>> kubectl create serviceaccount <service-account-name>
Eg. kubectl create serviceaccount dashboard-sa
View Service Accounts
---------------------
>> kubectl get serviceaccount
When the service account is created, it also creates a token automatically. The service account token is what must be
used by the external application while authenticating to the Kubernetes API. The token however is stored as a secret
object.
>> kubectl describe serviceaccount dashboard-sa
Name: dashboard-sa
Namespace: default
Labels: <none>
Image pull secrets: <none>
Mountable secrets: dashboard-sa-token-kbbdm
Tokens: dashboard-sa-token-kbbdm <===== In this case it's named dashboard-sa-token-kbbdm.
Events: <none>
So when a service account is created, it first creates the service account object and then generates a token for the
service account. It then creates a secret object and stores that token inside the secret object. The secret object is
then linked to the service account.
To view the token view of the secret object
-------------------------------------------
>> kubectl describe secret <secret-name>
Eg. kubectl describe secret dashboard-sa-token-kbbdm
You can create a service account, assign the right permissions using role-based access control mechanisms and export
your service account tokens and use it to configure your third party application to authenticate to the Kubernetes API.
But what if your third party application is hosted on the Kubernetes cluster itself. For example we can have the
Prometheus application deployed on the Kubernetes cluster itself. In that case this whole process of exporting the
service account token and configuring the third party application to use it can be made simple by automatically
mounting the service token secret as a volume inside the pod hosting the third party application. That way the token to
access the Kubernetes API is already placed inside the pod and can be easily read by the application. You don't have to
provide it manually.
If you go back and look at the list of service accounts, you will see that there is a default service account that
exists already. For every namespace in Kubernetes, a service account named "default" is automatically created. Each
namespace has its own default service account. Whenever a pod is created, the default service account and it's token
are automatically mounted to that pod as a volume mount.
>> kubectl get serviceaccount
NAME SECRETS AGE
default 1 218d
dashboard-sa 1 4d
For example we have a simple pod definition file that creates a pod using my custom Kubernetes dashboard image. We
haven't specified any secrets or Volume mounts in the definition file. However when the pod is created if you look at
the details of the pod by running the kubectl describe pod command you'll see that a volume is automatically created
from the secret named "default-token" which is in fact the secret containing the token for this default service
account. The secret token is mounted at location /var/run/secrets/kubernetes.io/service/account inside the pod.
So from inside the pod if you run the ls command to list the contents of the directory you will see the secret
monitored as three separate files. The one with the actual token is the file named "token".
>> kubectl exec -it <image-name> ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt namespace token
If you view contents of that file you will see the token to be used for accessing the Kubernetes API. A user can use a
different service account such as the one we created by modified the pod definition file to include a service account
field and specify the name of the new service account.
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-kubernetes-dashboard
spec:
containers:
- name: my-kubernetes-dashboard
image: my-kubernetes-dashboard
serviceAccount: dashboard-sa
Remember, you cannot edit the service account of an existing pod. You must delete and recreate the pod. However in case
of a deployment you will be able to get the service account as any changes to pod definition file will automatically
trigger a new rollout for the deployment. So the deployment will take care of deleting and recreating new pods with the
right service account.
When you look at the pod details now you'll see that the new service account is being used. So remember Kubernetes
automatically mount the default service account.
If you haven't explicitly specified any you may choose not to mount a service account automatically by setting the auto
mount service account token field to false in the pod spec section.
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-kubernetes-dashboard
spec:
containers:
- name: my-kubernetes-dashboard
image: my-kubernetes-dashboard
automountServiceAccountToken: false
======================================================================================================================
Taints and Toleration : are only meant to restrict nodes from accepting certain pods.
~~~~~~~~~~~~~~~~~~~~~
Taints(Applied on Nodes)
------
>> kubectl taint nodes node-name key=value:taint-effect
Eg kubectl taint nodes node1 app=blue:NoSchedule
There are 3 taint-effect.
1. NoSchedule : means pods will not be scheduled on the node.
2. PreferNoSchedule : means system will try to avoid placing the pods on the node.
3. NoExecute : means that new pods will not be scheduled on the node and existing pods on the node if any will
be evicted if they do not tolerate the taint.
Toleration(Applied on Pods)
----------
To add toleration to the pod, the pod definition file should have the section called 'tolerations' move the same values
used while creating the taint under this section.
>> vim pod-definition.yml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
containers:
- name: nginx-container
image: nginx
tolerations:
- key: "app" ----> Note :: Remember to keep the values in quotes.
operator: "Equal"
value: "blue"
effect: "NoSchedule"
Master nodes in cluster is tainted by default with taint effect 'NoSchedule' during the setup to prevent application
pods running on it.
To verify this, execute the following command
---------------------------------------------
>> kubectl describe node <name_of_master_node> | grep Taint
Taints: node-role.kubernetes.io/master:NoSchedule
Remove Taints(master node)
-------------
>> kubectl taint nodes master node-role.kubernetes.io/master:NoSchedule-
Remember taints & tolerations are only meant to restrict nodes from accepting certain pods. So remember taints and
tolerations does not tell the pod to go to a particular node. Instead it tells the node to only accept pods with
certain tolerations.
If your requirement is to restrict a pod to certain nodes it is achieved through a concept called as node affinity
======================================================================================================================
Node Selectors
~~~~~~~~~~~~~~
Node Selectors are used to make sure that pods run on a particular node. And it include 2 steps
Step 1. Label Node
Step 2. Create pods or deployments and add the label using 'nodeSelector' in the manifest file.
1. Label Nodes(applied on nodes)
--------------------------------
>> kubectl label nodes <node-name> <label-key>=<label-value>
Eg kubectl label nodes node01 size=Large
2. While creating the pods, we need to apply the node selector on the pod by adding it on the definiton file.
-------------------------------------------------------------------------------------------------------------
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
containers:
- name: data-processor
image: data-processor
nodeSelector:
size: Large
When the pod is created, it will be placed on node01 baced on the nodeSelector key value pair
======================================================================================================================
Node Affinity
-------------
Primary purpose of node affinity feature is to ensure that pods are hosted on particular nodes. And it include 2 steps
Step 1. Label Node
Step 2. Create pods or deployments and add 'nodeAffinity' in its manifest file.
Types of nodeAffinity
---------------------
1. requiredDuringSchedulingIgnoredDuringExecution (means the key value match should be checked during scheduling
2. preferredDuringSchedulingIgnoredDuringExecution and not during execution)
3. requiredDuringSchedulingRequiredDuringExecution
Step 1. Label Nodes(applied on nodes)
-------------------------------------
>> kubectl label nodes <node-name> <label-key>=<label-value>
Eg kubectl label nodes node01 size=Large
Step 2. Creating manifest file with nodeAffinity info
-----------------------------------------------------
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
containers:
- name: data-processor
image: data-processor
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: size
operator: In (Available values for operators : In, NotIn, Exists, DoesNotExist)
values: (If you use the operator value 'Exists', in that case you dont need to pass values)
- Large
- Small
======================================================================================================================
CERTIFICATION TIPS
~~~~~~~~~~~~~~~~~~
Refer : https://www.linkedin.com/pulse/my-ckad-exam-experience-atharva-chauthaiwale/
Refer : https://medium.com/@harioverhere/ckad-certified-kubernetes-application-developer-my-journey-3afb0901014
Refer : https://github.com/lucassha/CKAD-resources
======================================================================================================================
Multi Container PODS
~~~~~~~~~~~~~~~~~~~~
Multi container PODs means means multiple containers with in a POD and they share the same lifecycle which means they
are created together and destroyed together. They share the same network space which means they can refer to each other
as localhost and they have access to the same storage volumes. This way they donot have to establish the volume sharing
or services between the pods to enable communication between them.
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp
spec:
containers:
- name: simple-webapp
image: simple-webapp
ports:
- containerPort: 8080
- name: log-agent
image: log-agent
Multi Container PODs Design Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are 3 common patterns, when it comes to designing multi-container PODs
. SideCar
. Adapter
. Ambassador
======================================================================================================================
InitContainers
~~~~~~~~~~~~~~
In a multi-container pod, each container is expected to run a process that stays alive as long as the POD's lifecycle.
For example in the multi-container pod that we talked about earlier that has a web application and logging agent, both
the containers are expected to stay alive at all times. The process running in the log agent container is expected to
stay alive as long as the web application is running. If any of them fails, the POD restarts.
But at times you may want to run a process that runs to completion in a container. For example a process that pulls a
code or binary from a repository that will be used by the main web application. That is a task that will be run only
one time when the pod is first created. Or a process that waits for an external service or database to be up before
the actual application starts. That's where initContainers comes in.
An initContainer is configured in a pod like all other containers, except that it is specified inside a initContainers
section
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox
command: ['sh', '-c', 'git clone <some-repository-that-will-be-used-by-application> ; done;']
When a POD is first created the initContainer is run, and the process in the initContainer must run to a completion
before the real container hosting the application starts.
You can configure multiple such initContainers as well, like how we did for multi-pod containers. In that case each
init container is run one at a time in sequential order.
If any of the initContainers fail to complete, Kubernetes restarts the Pod repeatedly until the Init Container
succeeds.
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
======================================================================================================================
Observability
~~~~~~~~~~~~~
Readiness and Liveness Probes
-----------------------------
A POD has a pod status and some conditions. The POD status tells us where the POD is in its lifecycle.
When a POD is first created it is in a pending state. Once the POD scheduled, it goes into a container creating status
and once all the containers in a POD starts it goes into a running state
To see the state of POD conditions, Run the kubectl describe pod command and look for the conditions section.
By default, kubernetes assumes that as soon as the container is created, it is ready to serve user traffic. But if the
application within the container took longer to get ready, the service is unaware of it and sends traffic through as
the container is already in a ready state causing users to hit a POD that isn't yet running a live application.
What we need here is a way to tie the ready condition to the actual state of the application inside the container means
for the application to be ready. There are different ways that you can define if an application inside a container is
actually ready. You can set up different kinds of tests. It could be even the API server is up and running. So you
could run it a HTTP test to see if the API server response. In case of a database, you may test to see if a particular
TCP socket is listening or you may simply execute a command within the container to run a custom script that will exit
successfully if the application is ready.
So how do you configure that test. In the POD definition file, Add a new field called readiness probe and use the HTTP
get option. Specify the port and the ready API. Now when the container is created Kubernetes does not immediately set
the ready condition on the container to true. Instead it performs a test to see if the API responds positively. Until
then the service does not forward any traffic to the pod as it sees that the pod is not ready.
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp
labels:
name: simple-webapp
spec:
containers:
- name: simple-webapp
image: simple-webapp
ports:
- containerPorts: 8080
readinessProbe:
httpGet:
path: /api/ready
port: 8080
There are different ways a probe can be configured.
. For a http use httpGet option with the path and the port.
. For TCP use the tcpSocket option with the port
. For executing a command specify the exec option with the command and options in an array format.
HTTP Test : /api/ready TCP Test - 3306 Exec Command
---------------------- --------------- ------------
readinessProbe: readinessProbe: readinessProbe:
httpGet: tcpSocket: exec:
path: /api/ready port: 3306 command:
port: 8080 - cat
- /app/is_ready
There are some additional options as well.
. If you know that your application will take a minimum of say 10 seconds to warm up, you can add an additional delay
to the probe using 'initialDelaySeconds' option.
. If you would like to specify how often to probe, you can do that using the 'periodSeconds' option.
. By default, if the application is not ready after three attempts,the probe will stop. If you would like to make more
attempts use the 'failureThreshold' option.
readinessProbe:
httpGet:
path: /api/ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 8
======================================================================================================================
Liveness Probes
~~~~~~~~~~~~~~~
Assume an application is not really working but the container continues to stay alive. Say for example due to a bug in
the code the application is stuck in an infinite loop. As far as the kubernetes is concerned, the container is up so
the application is assumed to be up but the user hitting the container are not served. In that case the container needs
to be restarted or destroyed and a new container is to be brought up. That is where the liveness probe can help us.
A liveness probe can be configured on the container to periodically test whether the application within the container
is actually healthy. If the test fails, the container is considered unhealthy and is destroyed and recreated. But again
as a developer you get to define what it means for an application to be healthy. In case of a web application, it could
be when the API server is up and running. In case of database you may test to see if a particular TCP socket is
listening or you may simply execute a command to perform a test. The liveness is configured in the pod definition file
similar to readinessprobe.
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp
labels:
name: simple-webapp
spec:
containers:
- name: simple-webapp
image: simple-webapp
ports:
- containerPorts: 8080
livenessProbe:
httpGet:
path: /api/healthy
port: 8080
HTTP Test : /api/healthy TCP Test - 3306 Exec Command
------------------------ --------------- ------------
livenessProbe: readinessProbe: readinessProbe:
httpGet: tcpSocket: exec:
path: /api/healthy port: 3306 command:
port: 8080 - cat
initialDelaySeconds: 10 - /app/is_ready
periodSeconds: 5
failureThreshold: 8
======================================================================================================================
Container Logging
~~~~~~~~~~~~~~~~~
>> kubectl logs -f <name_of_the_pod>
If you are running a multi pod container, then to see the logs, you should specify the container name also
>> kubectl logs -f <name_of_the_pod> <name_of_the_container>
======================================================================================================================
Monitor and Debug Applications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Metric Server is used as a monitoring tool in kubernetes. There will be one metric server per kubernetes cluster. The
Metrics Server retrieves metrics from each of the Kubernetes nodes and pods, aggregates them and store them in memory.
Note that the metric server is only an in-memory monitoring solution and does not store the metrics on the disk and as
a result you cannot see historical performance data.
So how were the metrics generated for the PODs on these nodes?
Kubernetes runs an agent on each node known as the kubelet which is responsible for receiving instructions
from the kubernetes API Master server and running PODs on the nodes. The Kubelet also contains a subcomponent known as
the cAdvisor or Container aAdvisor. cAdvisor is responsible for retrieving performance metrics from pods and exposing
them through the kubelet API to meet the metrics available for the metrics server.
If you're using minikube for your local cluster, run the command
>> minikube addons enable metrics-server.
For all other environments
. deploy the metric server by cloning the metric server deployment files from the Github repository
>> git clone https://github.com/kubernetes-incubator/metrics-server.git
. then deploying the required components using the kubectl create command.
>> kubectl create -f deploy/1.8+/
This command deploys a set of pods, services and roles to enable the metric server to poll for performance metrics from
the nodes in the cluster. Once deployed, give the metrics server some time to collect and process data .
Once processed cluster performance can be viewed by running the command
>> kubectl top node (This provides the CPU and memory consumption of each of the nodes)
>> kubectl top pod (To view performance metrics of pods in Kubernetes.)
======================================================================================================================
POD Design
~~~~~~~~~~
Labels, Selectors and Annotations
---------------------------------
. Labels and Selectors are a standard method to group things together.
. Labels are properties attached to each items.
. Selectors help to filter the items.
Each object in kubernetes (pods, replicaset, deployment etc) have their own labels and selectors.
In a pod definiton file under metadata, there is a section called labels. Under that add the labels in a key value
format.
>> vim pod-definition.yml(sample)
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: App1 <----
function: Front-end <----
spec:
containers:
- name: nginx-container
image: nginx
To select a pod with the labels
-------------------------------
>> kubectl get pods --selector app=App1
>> kubectl get pods --selector env=dev
To get pods with multiple labels(here we use 'prod' environment, finance bu and frontend tier)
--------------------------------
>> kubectl get pods --selector env=prod,bu=finance,tier=frontend
To get all object with a specific label(here we use 'prod' environment)
---------------------------------------
>> kubectl get all --selector env=prod
Annotations
-----------
Annotations are used to record other details for informatory purpose. For example, tool details like name, version,
build, information, etc. or contact details, phone numbers, email IDs, etc. that may be used for some kind of
integration purpose.
>> vim pod--def.yaml
apiVersion: v1
kind: Pod
metadata:
name: annotations-demo
annotations:
buildversion: 1.34
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
=====================================================================================================================
Rolling Updates & Rollbacks in Deployments
------------------------------------------
Rollout Status >> kubectl rollout status <deployment-name>
Eg. kubectl rollout status deployment/myapp-deployment
Rollout History >> kubectl rollout history <deployment-name>
Eg. kubectl rollout history deployment/myapp-deployment
Deployment Strategy
-------------------
. Recreate Strategy : Bring down all the running pods first and then bring up the new pods, causing some downtime.
. Rolling Update Strategy(default) : Bring down old pods and up new pods simultaneously results in no downtime
Upgrading your Deployments
--------------------------
Update includes updating the application version, updating the version of docker container used, updating the labels or
updating the number of replicas etc.Since we have deployment-definition file, update the changes in it & then execute
the updation using the following cmd.
Kubectl apply >> kubectl apply -f deployment-definition.yml
Another way of doing this, say for eg : we need to update the nginx image version from 1.7.1 to 1.9.1
>> kubectl set image <deployment_name> <container_name>=image:new_version
>> kubectl set image deployment/myapp-deployment nginx=nginx:1.9.1
Note : This won't update the definition file, so who ever usig it might be careful about the updates if we use
kubectl set commands.
Rollback / Undo a change >> kubectl rollout undo <deployment-name>
Eg. kubectl rollout undo deployment/myapp-deployment
create deployment using kubectl run >> kubectl run nginx --image=nginx
This will create the deployment, replica set and pods.
Kubernetes Deployment command summary
-------------------------------------
Create >> kubectl create -f deployment-definition.yml
>> kubectl create -f deployment-definition.yml --record
(this will help to record the rollout history)
Get >> kubectl get deployments
Update >> kubectl edit deployment deployment_name
Update >> kubectl apply -f deplyment-definiton.yml
(Do this after updating definiton file)
Update >> kubectl set image deployment/myapp nginx=nginx:1.9.1
(Used without updating definition file)
Status >> kubectl rollout status deployment/myapp
>> kubectl rollout history deployment/myapp
>> kubectl rollout history deployment/myapp --revision=1
Rollback >> kubectl rollout undo deployment/myapp
Rollback to specific revision >> kubectl rollout undo deployment/myapp --to-revision=version_number
=====================================================================================================================
Jobs & CronJobs
~~~~~~~~~~~~~~~
A Job is used to run a set of pods to perform a given task to completion.
>> vim job-def.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: math-add-job
spec:
template:
spec:
containers:
- name: math-add
image: ubuntu
command: ["expr", "1", "+", "2"]
restartPolicy: Never
>> kubectl create -f job-def.yaml
To see the newly created jobs >> kubectl get jobs
To see the pods >> kubectl get pods
To delete the job >> kubectl delete job <job_name>
Creating jobs will result in the creation of pods and deletion of job results in deletion of pods also.
. To run multiple pods, we set a value for 'completions' under the job 'spec' section.
. By default the jobs are done sequentially and so do the pods also. Instead of getting the pods created sequentially,
we can get them created in parallel. For this, add a property called parallelism under job 'spec' section
>> vim job-def.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: math-add-job
spec:
completions: 3 ==> this will result in 3 job creation sequentially by default
parallelism: 3 ==> this will override the default sequential behaviour
template:
spec:
containers:
- name: math-add
image: ubuntu
command: ["expr", "1", "+", "2"]
restartPolicy: Never
>> kubectl create -f job-def.yaml
To see the newly created jobs >> kubectl get jobs
To see the pods >> kubectl get pods
To delete the job >> kubectl delete job <job_name>
Cronjobs
--------
A CronJob is a job that can be scheduled just like Cron tab in Linux. If you're familiar with it, say for example you
have a job that generates a report and sends an email. You can create the job using the Kube control create command,
but it runs instantly. Instead you could create a Cronjob to schedule and run it periodically.
>> vim cron-job-def.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: reporting-cron-job
spec: ==> Spec for CronJob
schedule: "*/1 * * * *"
jobTemplate:
spec: ==> Spec for Job
completions: 3
parallelism: 3
backoffLimit: 100 # This is so the job does not quit before it succeeds.
template:
spec: ==> Spec for Pod
containers:
- name: reporting-tool
image: reporting-tool
restartPolicy: Never
>> kubectl create -f cron-job-def.yaml
To see the newly created cron jobs >> kubectl get cronjob
Schedule Syntax
---------------
* * * * * command to execute
| | | | |
| | | | |-------> day of the week (0 - 6) (Sunday to Saturday, 7 is also Sunday on some systems.)
| | | |-----------> month (1 -12)
| | |---------------> day of the month (1 - 31)
| |-------------------> hour (0 - 23)
|-----------------------> minute (0 - 59)
=====================================================================================================================
Services and Networking
~~~~~~~~~~~~~~~~~~~~~~~
Services
--------
. Kubernetes services enable communication between various components within and outside of the application
. Kubernetes service is an object just like pods, replica set or deployments.
. One of its usecase is to listen to a port on the node and forward request on that port to a port on the pod running
the web application. This type of service is known as a NODE PORT service because the service listens to a port on
the node and forward requests to the pods.
Services Types
--------------
3 Types.
- Node Port : where the service makes an internal pod accessible on a port on the node.
- Cluster IP : In this case, the service creates a virtual IP inside the cluster to enable communication between
different services such as a set of front end servers to a set of back end servers.
- Load Balancer : where it provisions a load balancer for our application in supported cloud providers.
NodePort: Exposes the service on each Node’s IP at a static port (the NodePort). A ClusterIP service, to which the
NodePort service will route, is automatically created. You’ll be able to contact the NodePort service, from outside the
cluster, by requesting <NodeIP>:<NodePort>.
ClusterIP: Exposes the service on a cluster-internal IP. Choosing this value makes the service only reachable from
within the cluster. This is the default ServiceType
LoadBalancer: Exposes the service externally using a cloud provider’s load balancer. NodePort & ClusterIP services, to
which the external load balancer will route, are automatically created.
Service - Node Port
-------------------
There are 3 ports involved.
- Target port : is the port on the pod.
- Port : is the port on the service itself
- Node port : is the port on the node itself, which we used to access the web server externally.
Its default value ranges from 30000 to 32767.
_____________________________________________________________
| |
| |
|-----| ----------------- ------------- |
NODEPORT --> |30008|-*-*-*-| SERVICE | 80 |-*-*-*-*-*-| 80 | POD | |
|-----| ----------------- ------------- |
| ^ ^ |
| | | |
| PORT TARGETPORT |
| NODE |
|_____________________________________________________________|
>> vim service-definiton.yml
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: NodePort # ClusterIP(default), NodePort or LodeBalancer
ports:
- port: 80 # Port is a mandatory field
targetPort: 80 # If we dont allocate a port, it will assume a value same as port
nodePort: 30008 # Value ranges between 30000 to 32767. if we dont allocate, then a value with in the
range is automatically assigned.
selector:
app: myapp # Use the labels from pod definition file
type: frontend-app
Create Service >> kubectl create -f service-definiton.yml
To view the Service >> kubectl get services
======================================================================================================================
Service - ClusterIP
-------------------
>> vim service-definiton.yml
apiVersion: v1
kind: Service
metadata:
name: back-end
spec:
type: ClusterIP # Default type is ClusterIP. So even if you dont specify it, it will be the default
ports:
- port: 80 # port is where the service is exposed
targetPort: 80 # targetPort is the port where the backend is exposed
selector:
app: myapp # To link the service to set of pods, we use selector
type: back-end
======================================================================================================================
Ingress Networking
~~~~~~~~~~~~~~~~~~
Ingress helps users access the application using a single externally accessible URL that you can configure to route to
different services within your cluster based on that URL path and at the same time implement SSL security as well.
Implementation includes 2 step.
1. Deploy Ingress Controller (Eg. NginX)
2. Configure Ingress Resources
Ingress resources are created using definition files, like the ones we use to create pods deployments and services.
Kubernetes cluster does not come with an ingress controller by default. So we must deploy one. Eg for ingress
controller are GCE(Google Cloud HTTP Loadbalancer), Nginx, Contour, HAPROXY, traefik, Istio.Out of this, GCE and NGINX
are currently being supported and maintained by the Kubernetes project
These ingress controllers are not just another load balancer or NGINX server. The load balancer components are just a
part of it. The ingress controllers have additional intelligence built into them to monitor the Kubernetes cluster for
new definitions or ingress resources and configure the NGINX server accordingly.
An NGINX controller is deployed as just another deployment in Kubernetes. So we start with their deployment definition
file named nginx-ingress-controller with one replica and a simple pod definition template. We will label it NGINX
ingress and the image used is nginx-ingress-controller with the right version. This is a special build of NGINX built
specifically to be used as an ingress controller in Kubernetes. The NGINX program is stored at location in
nginx-ingress-controller. So you must pass that as the command to start the nginx-controller service.
======================================================================================================================
1. Deploy Ingress Controller
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Nginx Controlled is deployed as a deployment
--------------------------------------------
>> vim nginx-controller.yaml
apiVersion: apps/v1
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-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration ==> to store and configure logs, ssl-protocols...
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports: ==> the ports used by the ingress controller : 80 and 443.
- name: http
containerPort: 80
- name: https
containerPort: 443
Configmap to feed nginx configuration ==> to store and configure logs, ssl-protocols...
--------------------------------------
>> vim ingress-configmap-def.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configuration
Servie needed to expose the ingress controller to external world
----------------------------------------------------------------
>> vim ingress-service-def.yaml
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 controller also require Service Account with right set of permissions to access all objects
---------------------------------------------------------------------------------------------------
>> vim ingress-service-account-def.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
======================================================================================================================
2. Creating and Configuring Ingress Resources
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ingress resources is a set of rules and configurations applied on the ingress controller. You configure rules to say
simply forward all incoming traffic to a single application or route traffic to different application based on the
url. So if a user goes to my-online-store.com/wear, then route to one app, or if the user visit the /watch url, then
route on to the video app. Or you could route user based on the domain name itself. For example if the user visits
wear.my-online-store.com then route the user to the wear application or else route him to the video app.
Lets look how to configure this in detail.
The ingress resource is created with kubernetes definition file. In this case, ingress-wear.yaml.
--------------------
>> vim ingress-wear.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-wear
spec:
backend:
serviceName: wear-service (If it is single backend, you don't have any rules. you simple specify the service name
servicePort: 80 and port of the backend wear-service)
>> kubectl create -f ingress-wear.yaml
To view the created ingress resources
-------------------------------------
>> kubectl get ingress
We need to use rules, when we need to route based on conditions.
Assume we need to create ingress-resource based on url path (rules)
-------------------------------------------------------------------
>> vim ingress-wear.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-wear-watch
spec:
rules:
- http:
paths:
- path: /wear (Rule based on path : one for /wear.)
backend:
serviceName: wear-service
servicePort: 80
- path: /watch (Rule based on path : one for /watch.)
backend:
serviceName: watch-service
servicePort: 80
>> kubectl create -f ingress-wear.yaml
Once the ingress resource is created, view additional details abpout the ingress resource using the followong cmd
>> kubectl describe ingress ingress-wear-watch
In the o/p there is 'Default backend' ==> this need to be the backend redirect when the routes won't match. means right
now we have /wear and /watch routes. Say if we entered the /eat which is not a valid one, then we need to show the 404
page that need to be configured here.
The third type of configuration is using domain names or host names. Say we have the following domain names
wear.my-online-store.com
watch.my-online-store.com
Assume we need to create ingress-resource based on domain names (rules)
-------------------------------------------------------------------
>> vim ingress-wear-watch.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-wear-watch
spec:
rules:
- host: wear.my-online-store.com (Rule based on domain name / host name : one for each hostname.)
http:
paths:
- backend:
serviceName: wear-service
servicePort: 80
- host: watch.my-online-store.com (Rule based on domain name / host name : one for each hostname.)
http:
paths:
- backend:
serviceName: watch-service
servicePort: 80
>> kubectl create -f ingress-wear-watch.yaml
So let's compare the two. Splitting traffic by URL, had just one rule and we split the traffic with two parts to split
traffic by hostname. We used two rules and one path specification in each rule.
Edit Ingress Resource
---------------------
>> kubectl edit ingress <ingress_resource_name> -n <namespace_name>
=====================================================================================================================
FAQ - What is the rewrite-target option?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Refer :: CKAD udemy course.
=====================================================================================================================
Network Policy
~~~~~~~~~~~~~~
Ingress and Egress Traffic
--------------------------
. An incoming request to a server is considered as Ingress Traffic
. An outgoing request from a server is considered as Egress Traffic
Say we have a web pod, api pod and db pod in a cluster. And if you want to block the web pod talking to db pod directly
and make it happen only via the api pod. Thats where we use the network policy to allow traffic to the DB Server only
from the API Server.
Network Policy is just another object in kubernetes namespace, just like pods, replicasets or services.
How do we apply network policy on a pod?
. Using labels and selectors.
|---------------------| |---------------------| |--------------------|
End User --> | Web POD (Port 80) | --> | API POD (Port 5000) | --> | DB POD (Port 3306) |
|---------------------| |---------------------| |--------------------|
>> vim network-policy-def.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
spec:
podSelector: --> You should use the 'labels' from the pod for which you are writing the network policy.
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
name: api-pod
ports:
- protocols: TCP
port 3306
>> kubectl create -f network-policy-def.yaml
Make sure that you labeld the DB pod as follows before creaing the network policy.
labels: OR labels:
roles: db names: db
Note :
Solutions that support Network Policies are : Solutions that donot support Network Policies are :
- Kube-router - Flannel
- Calico
- Romana
- Wave-net
Get list of network policy >> kubectl get networkpolicy
SAMPLE
------
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: internal-policy
namespace: default
spec:
podSelector:
matchLabels:
name: internal
policyTypes:
- Egress
- Ingress
ingress:
- {}
egress:
- to:
- podSelector:
matchLabels:
name: mysql
ports:
- protocol: TCP
port: 3306
- to:
- podSelector:
matchLabels:
name: payroll
ports:
- protocol: TCP
port: 8080
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
=====================================================================================================================
Developing network policies
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Watch CKAD udemy video.
=====================================================================================================================
State Persistence
~~~~~~~~~~~~~~~~~~
Volumes
-------
Just as in Docker, the PODs created in kubernetes are transient in nature. When a POD is created to process data and
then deleted, the data processed by it gets deleted as well. For this we attach a volume to the POD. The data generated
by the POD is now stored in the volume. And even after the pod is deleted the data remains.
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: random-number-generator
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh", "-c"]
args: ["shuf -i 0-100 in 1 >> /opt/number.out"]
volumeMounts:
- name: data-volume
mountPath: /opt <==== on the pod/container
volumes:
- name: data-volume
hostPath:
path: /data <==== on the host
type: Directory
When we have multiple nodes, we need to use one of the following tech to handle this.
. NFS . scaleio . FibreChannel
. GlusterFS . ceph . FlockerDisk
. public cloud solutions like AWS EBS, Azure disk or Google's Persistent
For eg. To configure an AWS Elastic Block Store volume as the storage or the volume, we need to replace the hostPAth
field of the volume with awsElasticBlockStore field along with the volume id
volumes:
- name: data-volume
awsElasticBlockStore:
volumeID: <volume_id>
fsType: ext4 (file system type)
=====================================================================================================================
Persistent Volumes
------------------
A Persistent volume is a cluster wide pool of storage volumes configured by an administrator to be used by users
deploying applications on the cluster. The users can now select storage from this pool using persistent volume claims.
Creating Persistent Volume >> kubectl create -f pv-def.yaml
--------------------------
>> vim pv-def.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-vol1
spec:
accessModifiers:
- ReadWriteOnce ---> Possible values :: ReadOnlyMany, ReadWriteOnce, ReadWriteMany
capacity:
storage: 1Gi
hostPath:
path: /tmp/data ---> This option is not to be used in a production environment.
List the Persistent Volume
--------------------------
>> kubectl get persistentVolumes
>> kubectl get pv
Replace the hostPath option with one of the supported storage solutions like awsElasticBlockStore
-------------------------------------------------------------------------------------------------
>> vim pv-def.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-vol1
spec:
accessModes:
- ReadWriteOnce ---> Possible values :: ReadOnlyMany, ReadWriteOnce, ReadWriteMany
capacity:
storage: 1Gi
awsElasticBlockStore:
volumeID: <volume_id>
fsType: ext4
=====================================================================================================================
Persistent Volume Claims
~~~~~~~~~~~~~~~~~~~~~~~~
. Persistent Volume and PersistentVolumeClaims are two seperate objects in the Kubernetes namespace.
. An administrator creates a set of Persistent Volumes and a user creates Persistent Volume Claims to use the storage.
. Once the PersistentVolumeClaims are created, kubernetes binds the PersistentVolumes to Claims based on the request
and properties set on the volume.
. Every PersistentVolumeClaims is bound to single PersistentVolume.
. During the binding process, Kubernetes tries to find a PersistentVolume that has sufficient capaccity as requested by
the claim and any other request properties such as access modes, volume modes, storage class etc.
. However if there are multiple possible matches for a single claim and you would like to use a particular volume, you
could still use labels and selectors to bind to the right volumes.
. Also note that a smaller claims may get bound to a larger volume if all other criteria matches and there are no
better options.
. Also if there are no voulmes available, then the persistent volume claims will remain in a 'pending' state until
newer volumes are made available to the cluster.
. Once new volumes are available, the claim would automatically bound to the newly available volume.
Creating PVC
------------
>> vim pvc-def.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
>> kubectl create -f pvc-def.yaml
Get PersistentVolumeClaim
-------------------------
>> kubectl get persistentvolumeclaim (will be in pending state until a persistent volume is bound)
>> kubectl get pvc
Delete PersistentVolumeClaim
----------------------------
>> kubectl delete persistentvolumeclaim <pvc_name>
>> kubectl delete pvc <pvc_name>
Eg. kubectl delete persistentvolumeclaim myclaim
Eg. kubectl delete pvc myclaim
When a PVC is deleted, by default the persistent volume is retained and it cannot be used with any other PVC.
persistentVolumeReclaimPolicy: Retain => means pv will remail until it is manually deleted and cannot be reused with
any other claims.
persistentVolumeReclaimPolicy: Delete => means pv will be deleted when the pvc is deleted. thus freeing up storage on
the storage device.
persistentVolumeReclaimPolicy: Recycle => means data in the pv will be scrubbed before it is made available to
another claims.
=====================================================================================================================
Using PVCs in PODs
~~~~~~~~~~~~~~~~~~
Once you create a PVC use it in a POD definition file by specifying the PVC Claim name under persistentVolumeClaim
section in the volumes section like this:
>> vim pod-def.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
The same is true for ReplicaSets or Deployments. Add this to the pod template section of a Deployment on ReplicaSet.
Ref : https://kubernetes.io/docs/concepts/storage/persistent-volumes/#claims-as-volumes
=====================================================================================================================
Storage Classes
~~~~~~~~~~~~~~~
We use storage classes to provision the volumes automatically when the application requires it. With storage classes, you
can define a provisioner such as Google storage that can automatically provision storage on Google Cloud and attach that to
pods when a claim is made. That's called dynamic provisioning of volumes.
So once the storage class is created and when a user creates PVC, the storage class create PV dynamically and the PVC get
bound to the volume.
We used the GCE provisionar to create a volume on GCP. There are many other provisioner such as for AWSElastic Block Store,
AzureFile, AzureDisk, CephFS, Portworx, ScaleIO etc.
With each of these provisioner you can pass in additional parameters such as the type of desk to provision, app type etc.
Create StorageClass
-------------------
>> vi sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: delayed-volume-sc
provisioner: kubernetes.io/no-provisioner
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
This will create pv by itselt and wait for a user to create a pvc and pod using that pvc to bind it. So we dont need to
create PV but we should create PVC and deploy a POD using that PVC.
Creating PVC
-------------
>> vim pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: local-pvc <----------
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
storageClassName: local-storage
Creating Pod using PVC
----------------------
>> vi nginx_pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: local-pvc <----------
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- mountPath: "/var/www/html"
name: task-pv-storage
=====================================================================================================================
Stateful Sets
~~~~~~~~~~~~~
Stateful Sets is used in place where we need to deploy pods sequentially, means second pod is created only after the
first pod is up and running. Also they are named in a unique way. eg: pod-01, pod-02 like that.
>> vim statefulset-def.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql
replicas: 3
selector:
matchLabels:
app: mysql
serviceName: mysql-h ===> Headless service
podManagementPolicy: Parallel ===> Mentioned about this just before end of this section
>> kubectl create -f statefuleset-def.yaml
Just like how you created a deployment create a deployment definition file with a pod definition template inside it and
then all you need to do is change the kind to state full set instead of deployment. Note that both S's in the
statefullset is uppercase. Apart from that a statefullset also requires a service name specified You must specify the
name of a headless service.
When you create a state full set using this definition file it creates pods one after the other that's ordered graceful
deployment. Now each pod gets a stable unique DNS record on the network that any other application can use to access a
pod.
When we scale the state full set, it scales in an ordered graceful fashion where each pod comes up becomes ready and
only then the next one comes up.
Scale up/down StatefulSet
-------------------------
>> kubectl scale statefulset mysql --replicas=5 (Up)
>> kubectl scale statefulset mysql --replicas=2 (Down)
This helps when you want to scale MySQL databases, as each new instance can clone from the previous instance. It works
in the reverse order, when you scale it down. The last instance is removed first followed by the second last one.
Delete StatefulSet
------------------
>> kubectl delete statefulset mysql
The same is true on termination. When you delete a state full set, the pods are deleted in the reverse order. That's
the default behavior of a statefullset but you can override that behavior to cause statefullset to not follow an order
launch but still have the other benefits of statefullset such as a stable and unique network id.
For that you could set the podManagementPolicy field to parallel to instruct state full set to not follow an ordered
approach, instead deploy all pods in parallel. The default value of this field is ordered ready.
=====================================================================================================================
Headless Services
~~~~~~~~~~~~~~~~~
Ref :: https://www.udemy.com/course/certified-kubernetes-application-developer/learn/lecture/17478630#content
A headless service is a service created like a normal service. But it does not have an IP of its own like a cluster IP
for a normal service. It does not perform any load balancing. All it does is create DNS entries for each pod using the
pod name and a subdomain. So when you create a headless service say with the name my mysql-h, each pod gets a DNS
record created in the form podname.headless-servicename.namespace followed by the cluster domain.
ie: mysql-0.mysql-h.default.svc.cluster.local, mysql-1.mysql-h.default.svc.cluster.local etc
Create a headless service
-------------------------
>> vim headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-h <================|
spec: |
ports:
- port: 3306
selector:
app: mysql
clusterIP: None
What differentiates a headless service from a normal service is setting cluster IP to none.
When the headless service is created, the DNS entries are created for pods only if the two conditions are met while
creating the pod.Under the specs section of a pod definition file. You have two optional fields hostname and subdomain.
You must specify the subdomain to a value the same as the name of the service. When you do that it creates a DNS record
for the name of the service to point to the pod. However it still does not create a record for individual pods. For
that you must specify the hostname option in the pod definition file. Only then does it create a DNS record with a pod
name as well. So those are two properties that are required on the part for a headless service to create a DNS record
for the pod.
When creating a statefullset, you do not need to specify a subdomain or hostname. The statefullset automatically
assigns the right hostname for each pod based on the pod name and it automatically assigns the right subdomain based on
the headless service name
But wait How does a state full set know which headless service we are using. There could be many headless services
created for different applications. How would it know which is the headless service we created for this application.
When creating a state full set you must specify the service name explicitly using the service name option
in the statefullset definition file. That's how it knows what subdomain to assign to the pod.
The statefulset takes the names that we specified and add that to as a subdomain property when the pod is created. All
pods now get a separate DNS record created.
>> vim statefulset-def.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
labels:
app: mysql
spec: |
serviceName: mysql-h <=======|
replicas: 3
matchLabels:
app: mysql
template:
metadata:
name: myapp-pod
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql
=====================================================================================================================
Storage in StatefulSet
~~~~~~~~~~~~~~~~~~~~~~
ref :: https://www.udemy.com/course/certified-kubernetes-application-developer/learn/lecture/17478686#content
=====================================================================================================================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment