What is Apache Airflow

 Airflow?


Apache airflow is an open source platform for developing, scheduling and monitoring batch oriented workflows. Airflow's extensible python framework allows you to write code and create dag for workflows.

What is Dag?


A dag is called as directed acyclic graph means while creating or designing a dag, Cycle should not be formed. Here for example if I execute a task A and task A executes task B, task B should execute task C. Task C should not be calling task A otherwise there will be a cycle formed and In math you can relate it to transitive dependency. So there shouldn't be a transitive dependency.

Dag represents a workflow which is a collection of tasks. Below is how a dag looks like:




Airflow has a nice GUI by which you can manage creating variables and other admin stuff. You can also view your dag on GUI , trigger it or cancel it. Everything you can manage via GUI.

Use Case for Airflow


Suppose you have a unix job that  processes a text file at specific time and then it calls other job which does it's part. But sometimes you missed the file and your first job would still run and fail and your next dependent job will also run and process no data. So to overcome this scenario we can use Airflow and create a DAG where all tasks will be dependent on each other. So when we get a file then only our first job will be triggered and once first job will be succeeded our next job will run.

Let's write your first dag


from datetime import datetime
from airflow import DAG
from airflow.decorators import task
from airflow.operators.bash import BashOperator

# A DAG represents a workflow, a collection of tasks
with DAG(dag_id="demo", start_date=datetime(2022, 1, 1), schedule="0 0 * * *") as dag:

# Tasks are represented as operators
hello = BashOperator(task_id="hello", bash_command="echo hello")

@task()
def airflow():
print("airflow")

# Set dependencies between tasks
hello >> airflow()

In above code you need to import the DAG from airflow and BashOperator.

When you have a requirement to execute linux commands and you want to create a workflow use BashOperator. Similarly when you have a requirement to write a python function and execute it then use pythonOperator. In a summary BashOperator is used to execute bash commands and pythonOperator is used to execute the python commands.

Now once you have imported everything required the next line would be to define your dag.
When Airflow scheduler runs, it looks for a line which has "with DAG" in it. When it finds it then it creates a dag based on the config you passed.

After that there is BashOperator used where we creating a task with the name "hello" and executing command using BashOperator. You need to give a unique task id to each task keep it remember. And on the last line you can plan your flow like which task has to run first and last. 

Once you save the file the Airflow scheduler will automatically pick the new file and create the DAG. If any error occurs it will be displayed on the top of the Airflow UI.




Conclusion


Airflow is an awesome framework to use. It can be very useful to orchestrate all legacy unix jobs and flows. We just to choose airflow for right use case and it can solve those problems easily.


How to delete a Pod in Kubernetes - Beginner tutorial

Delete a pod using kubectl delete pod





Sometimes we encounter some issues on running pod and then we decide to delete a Pod because we can't create a new pod with the same name. You can't have two pods with same name in a cluster. 

There are two ways to delete a pod: 
  • Using delete command
  • Using delete command with force keyword
The first way of deleting the pod is called a graceful delete. So before deleting any pod we first need to create a new pod.

Create a pod

To create a pod we need to run below command in our terminal.

kubectl run nginx --image=nginx --restart=Never


Above command will run nginx image with pod name nginx itself. 
Here --restart flag says kubernetes to create a single pod not to create a deployment.

Now check if the pod is running using below command

kubectl get pod


Output:

NAME    READY   STATUS              RESTARTS   AGE

nginx   0/1     ContainerCreating   0          8s


Just wait for few seconds and pod will be created.

kubectl get pod

NAME    READY   STATUS    RESTARTS   AGE

nginx   1/1     Running   0          2m6s


Since we have created our pod. Now lets try to delete it. To delete a pod you can use below command.

kubectl delete pods nginx


Here in the syntax you need to pass pod name that's it. In this case I passed nginx.

This may take some time depending upon pod usage. But if you want this to be deleted quickly then we can use force flag in the command.

A pod is not deleted automatically when a node is unreachable.The pods running on an unreachable Node enter the terminating or unknown state after timeout. Pods may also enter these states when user attempts graceful deletion of pod on unreachable node. The only ways in which a pod can be deleted/removed from apiserver are as follows:
  • The node object is deleted.
  • The kubelet on unresponsive node starts responding ,kills the pod and removes the pod from apiserver.
  • Force deletion of pod by user.
The recommended best practice is to follow first two from above. If a node is confirmed to be dead then
delete the node object. Normally system deletes the pod once it's no longer running on a node or the node is deleted by administrator. 

Delete the pod forcefully using below command:

kubectl delete pod nginx --force 

Output:

pod "nginx" force deleted


If even after above command the pod is still stuck on unknown state. You can use the below command to remove the pod from the cluster.

kubectl patch pod nginx -p '{"metadata":{"finalizers":null}}'


That was it about deleting the pod using kubectl command. Be careful while deleting a pod especially using the force keyword.

Note: If you think this helped you and you want to learn more stuff on devops, then I would recommend joining the Kodecloud devops course and go for the complete certification path by clicking this link

SQL query to find duplicate records

Introduction

These days data is growing massively and since the data is growing the amount of bad data is also growing. Today we'll talk about one form of bad data which we can call duplicate data. We use few database management systems to store and process the data ie sql server, postgresql, oracle etc. We store lot of data in these systems but sometimes we get lot duplicate data as well in our systems which can impact the true data and reporting on which lot of businesses and important decisions are dependent.

  So for us working on data, it's very important to identify the duplicates and remove them from the database which help businesses towards better reporting. 

Let's get into the practical to understand the duplicates. First we need to create a table with few columns.

In this tutorial I am using postgresql. 

CREATE TABLE duplicate_data_test(
id int,
name text
)

now let's insert some data with duplicates.

insert into duplicate_data_test values(1,'One');
insert into duplicate_data_test values(1,'One');
insert into duplicate_data_test values(2,'two');
insert into duplicate_data_test values(3,'three');
insert into duplicate_data_test values(4,'four');
insert into duplicate_data_test values(5,'three');

Query the data to see results:

select * from duplicate_data_test;













Let's find the duplicates for entire row.

select id,name,count(*) as count from duplicate_data_test
group by id,name having count(*) > 1;

or

Using CTE as well to get the duplicates.

with cte(id,name)
as
(select id,name,row_number() over (partition by id,name order by id) as rn
from duplicate_data_test)
select * from cte;

Above query will give you the count. You can remove the count in select list if you want and then you will get duplicate record without count number. 















Sometimes we want to find duplicates based on one column. Sometime we don't have entire row is duplicate rather just one column have some duplicate values. 

So we can definitely use partition by clause like below.

select * from (
select id,name,rank() over (partition by name order by id) as rnk
from duplicate_data_test
) as dt where dt.rnk > 1













Conclusion

That was it about duplicates. Always test above code in lower environment before implementing in Production.


How Kubernetes works

 Introduction

Kubernetes is a compact, extensible, open source stage for overseeing containerized jobs and administrations, that works with both explanatory setup and computerization. It has an enormous, quickly developing environment. Kubernetes administrations, backing, and instruments are broadly accessible.


The name Kubernetes begins from Greek, meaning helmsman or pilot. K8s as a condensing comes about because of counting the eight letters between the "K" and the "s". Google publicly released the Kubernetes project in 2014. Kubernetes consolidates more than 15 years of Google's experience running creation jobs at scale with best-of-breed thoughts and practices from the local area.

For associations that work at a gigantic scope, a solitary Linux compartment occasion isn't sufficient to fulfill their applications' all's necessities. It's normal for adequately complex applications, for example, ones that convey through microservices, to require different Linux containers that speak with one another. That design presents another scaling issue: how would you deal with that large number of individual containers? Designers will in any case have to deal with booking the organization of holders to explicit machines, dealing with the systems administration between them, developing the assets allotted under weighty burden, and significantly more.


Enter Kubernetes, a container orchestration framework — a method for dealing with the lifecycle of containerized applications across a whole armada. It's a kind of meta-process that gives the capacity to robotize the organization and scaling of a few compartments without a moment's delay. A few holders running a similar application are gathered together. These compartments go about as reproductions, and effectively load balance approaching solicitations. A compartment orchestrator, then, manages these gatherings, guaranteeing that they are working accurately.

Kubernetes architecture






There are multiple components which are involved to run Kubernetes which are listed below.

Pods

A Kubernetes pod is a group of containers, and is the smallest unit that Kubernetes administers. Pods have a single IP address that is applied to every container within the pod. Containers in a pod share the same resources such as memory and storage. This allows the individual Linux containers inside a pod to be treated collectively as a single application, as if all the containerized processes were running together on the same host in more traditional workloads. If you know about the docker then pod on kubernetes won't surprise you much. You can run multiple containers inside a Pod but keep in mind that you can't run same container twice inside Pod.

Deployments


Deployments describe the number of desired identical pod replicas to run and the preferred update strategy used when updating the deployment.


Service

An abstract way to expose an application running on a set of Pods as a network service.
With Kubernetes you don't need to modify your application to use an unfamiliar service discovery mechanism. Kubernetes gives Pods their own IP addresses and a single DNS name for a set of Pods, and can load-balance across them.

Nodes


A Kubernetes cluster must have at least one compute node, although it may have many, depending on the need for capacity. Pods orchestrated and scheduled to run on nodes, so more nodes are needed to scale up cluster capacity.

Nodes do the work for a Kubernetes cluster. They connect applications and networking, compute, and storage resources.


Control plane

The Kubernetes control plane is the main entry point for administrators and users to manage the various nodes. Operations are issued to it either through HTTP calls or connecting to the machine and running command-line scripts. As the name implies, it controls how Kubernetes interacts with your applications.


Cluster

A cluster is all of the above components put together as a single unit.

API Server

The API server exposes a REST interface to the Kubernetes cluster. All operations against pods, services, and so forth, are executed programmatically by communicating with the endpoints provided by it.

Scheduler

The scheduler is responsible for assigning work to the various nodes. 

Controller manager

The controller-manager is responsible for making sure that the shared state of the cluster is operating as expected. More accurately, the controller manager oversees various controllers which respond to events (e.g., if a node goes down).

Kubelet

A Kubelet tracks the state of a pod to ensure that all the containers are running. It provides a heartbeat message every few seconds to the control plane. If a replication controller does not receive that message, the node is marked as unhealthy.

Kube proxy

The Kube proxy routes traffic coming into a node from the service. It forwards requests for work to the correct containers.

etcd

etcd is a distributed key-value store that Kubernetes uses to share information about the overall state of a cluster. 


Note: If you think this helped you and you want to learn more stuff on devops, then I would recommend joining the Kodecloud devops course and go for the complete certification path by clicking this link

How to search image name in multiple Pods on Kubernetes like a Pro?



Introduction

Sometimes we have a requirement to find a particular image which any pod is using. But you are not sure about the image. In that case we have the describe command to check and see all the information about the pod. The problem occurs when you have multiple pods and you can't write multiple describe commands to find that image. So we'll do it differently using a loop like Pro. 

Prerequisites

You need to have the Kubernetes installed on your machine and it's up and running. You can check it by running below command.

kubectl get pods

If you see some error like command not found then probably you don't have Kubernetes installed on your machine so you need to get it installed. 

Let's start

First we'll create multiple Pods on our cluster with different images. Code is below:

for img in nginx3 alpine alpine2 alpine3
do
kubectl run $img --image=$img
done


Results:
pod/nginx3 created
pod/alpine created
pod/alpine2 created
pod/alpine3 created

So I used a for loop in bash script and passed multiple images name and created multiple Pods at once.

Now I am checking the status of pods. Since i used wrong images so there must be multiple pods in not running status.

kubectl get pods

NAME READY STATUS RESTARTS AGE
alpine 0/1 CrashLoopBackOff 4 (56s ago) 3m10s
alpine2 0/1 ImagePullBackOff 0 3m10s
alpine3 0/1 ImagePullBackOff 0 3m10s
nginx 1/1 Running 0 3h38m
nginx2 1/1 Running 0 3h33m
nginx3 0/1 ImagePullBackOff 0 3m10s

So we have multiple Pods now, we can look for images using our favourite for loop.

Let's list Pod and it's image.

for pds in $(kubectl get pods --no-headers -o custom-columns=":metadata.name")
do
echo "*************Pod_Name: $pds**************"
kubectl describe pods $pds | grep -i image:
done

Results:

********************Pod_Name: alpine***************
Image: alpine
********************Pod_Name: alpine2**************
Image: alpine2
********************Pod_Name: alpine3**************
Image: alpine3
*******************Pod_Name: nginx*****************
Image: nginx
*******************Pod_Name: nginx2****************
Image: nginx
*******************Pod_Name: nginx3****************
Image: nginx3

Now we can see which Pod is using which image. But this solution is still not feasible because this will give me all the pods and images in default namespace. I need to search one image ie. alpine3 among all Pods.

for pds in $(kubectl get pods --no-headers -o custom-columns=":metadata.name")
do
echo "************Pod_Name: $pds**************"
kubectl describe pods $pds | grep -i "image: alpine3"
done


Just search alpine3 in your grep command and see results below. You can use if else to remove extra print from the output.

for pds in $(kubectl get pods --no-headers -o custom-columns=":metadata.name")
do
if kubectl describe pods $pds | grep -q -i "image: alpine3"
then
echo "***********Pod_Name: $pds*****************"
else
echo
fi
done

*************Pod_Name: alpine3**************

Conclusion

Combining your shell scripting skill can be very useful in Kubernetes. You can get multiple things done quickly. This was example to find images in multiple Pods but you can use above script to find other properties as well like variables and configs. Using shell script you can automate lot of stuff on Kubernetes. 


Default memory limits for a Kubernetes Pod

Understanding about memory and other resources consumption is very important in Kubernetes. Whenever we run a Pod it consumes some amount of memory and cpu depending on the load.

By default Pods run with unbounded CPU and memory limits. That means any Pod in the system will be able to consume as much CPU and memory on the node that executes the Pod. So to avoid these situations user can impose some restrictions on the amount of resource a single Pod can use for variety of reasons. 

To impose a memory restrictions we have few options:

1. Either we can define our memory and cpu limits in deployment file

2. Or we can create a limit which will used to set default memory limit to Pods in specific namespace.

Let's create a namespace first by below command.

kubectl create namespace memory-demo

Now create a pod using yaml file.

apiVersion: v1
kind: Pod
metadata:
name: mem-demo
namespace: memory-demo
spec:
containers:
- name: mem-demo-cont
image: polinux/stress
resources:
requests:
memory: "100Mi"
limits:
memory: "200Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

We have provided a memory limit 200Mi. Save it as mempod.yaml and run below command to create the pod.

kubectl create -f mempod.yaml

Note: Mi and MB are different but they are close in size. 
Mi(Mebibyte) = 1024 KB
MB(Megabyte) = 1000 KB

Now let's check the memory consumption of above pod using below command.

kubectl get pod mem-demo -n memory-demo -o yaml | grep -i resources -A 4

O/P:

resources:
limits:
memory: 200Mi
requests:
memory: 100Mi

Let's try to understand what will happen when pod will exceed the memory limit. We'll create a pod again to exceed memory limits. Use the above mempod.yaml file and just change the memory limits to lower and see.

apiVersion: v1
kind: Pod
metadata:
name: mem-demo
namespace: memory-demo
spec:
containers:
- name: mem-demo-cont
image: polinux/stress
resources:
requests:
memory: "50Mi"
limits:
memory: "50Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

Before creating the same again again we need to delete the existing pod first using below command.

kubectl delete pod mem-demo -n memory-demo

kubectl create -f mempod.yaml


Check if new pod created is in running state? by running below command

kubectl get pods -n memory-demo

NAME READY STATUS RESTARTS AGE
mem-demo 0/1 CrashLoopBackOff 6 9m34s

So it's not running and it's failed. Let's debug why it's failed using kubectl describe command.

kubectl describe pods mem-demo -n memory-demo | grep -i state -A 5
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: OOMKilled
Exit Code: 1

It says OOM killed means memory limit was exceeded and it was killed. 

Instead of assigning memory limits and resources to individual pods we can create memory limits in namespace and every pod created in this namespace will have the default memory limit. 

To do this we'll create a limit range in memory-demo namespace. 

apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
- default:
memory: 512Mi
defaultRequest:
memory: 256Mi
type: Container

save it as limit.yaml

kubectl apply -f limit.yaml -n memory-demo

So limit range has been created and we can verify it by below command.

kubectl get limits -n memory-demo

NAME CREATED AT
mem-limit-range 2022-08-07T13:27:36Z

Now create a Pod using imperative command way

kubectl run nginx --image=nginx -n memory-demo

And check the memory limits for the container , it should be default limits by limit range.

spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
resources:
limits:
memory: 512Mi
requests:
memory: 256Mi

That's how we can use the limit range to set default memory limits.

Note: If you think this helped you and you want to learn more stuff on devops, then I would recommend joining the Kodecloud devops course and go for the complete certification path by clicking this link

Understanding the replica set in Kubernetes.

Understanding the replica set in Kubernetes

What is Replica?

Replica means copy so having exact same copy of a running pod is called as Replica. Where as ReplicaSet is a way to maintain the stable set of replica Pods running at any time. It guarantees the availability of specified number of identical Pods.

How does it work

ReplicaSet is defined with fields having a selector that specifies how to identify Pods It can acquire, a number of replicas indicating how many Pods it should be maintaining and a pod template specifying the data of  of new pods which it should be maintaining. When replica-set needs to create a new pod it uses pod template to create a new pod.


ReplicaSet VS ReplicationController

ReplicaSet and Replication Controller both do the same thing. Both of them ensures that a specified number of Pods mentioned in replicas are running at any time. The only difference comes with the usage 
of selectors to replicate Pods.ReplicaSet uses Set-Based selectors while Replication Controller use Equity-Based selectors.

See in below examples:

Replication Controller

apiVersion: v1
kind: ReplicationController
metadata:
name: RepCon
spec:
replicas: 3
selector:
app: RepCon
template:
metadata:
name: RepCon
labels:
app: RepCon
spec:
containers:
- name: RepCon
image: RepCon/rc
ports:
- containerPort: 80


Replica-Set

apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: RS
tier: frontend
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: redis
image: gcr.io/google_samples/gb-frontend:v3


Save it as ReplicaSet.yaml in current directory and run below command.

kubectl apply -f ReplicaSet.yaml

Now you can check the ReplicaSet with below command:

kubectl get rs

or

kubectl get replicaset


Note: If you think this helped you and you want to learn more stuff on devops, then I would recommend joining the Kodecloud devops course and go for the complete certification path by clicking this link

Creating a Pod inside a Namespace

 Creating a Pod inside a Namespace




We are going to understand what is namespace in programming and what is namespace in Kubernetes world. Both are actually very much same. So today we'll talk about the namespace ,how to create it, check it and creating a Pod in a namespace.

Namespace

A namespace is set of signs or names that are used to identify and refer to objects of various kinds. A namespace ensures that all of the objects have unique name so that they can be easily identified. You can 
correlate this with schema in SQL server database where you can have multiple  tables with same name but in different schema. 

Similarly you can have multiple pods with same name but in different namespace.

How to check all available namespaces?

You can run kubectl get namespaces to get all available namespaces on cluster.

kubectl get namespaces

NAME              STATUS   AGE

default           Active   2d

kube-public       Active   2d

kube-system       Active   2d


You can also run kubectl get ns , where ns is short form of namespace.

How to create a namespace

To create a namespace you need to run kubectl create namespace namespace_name

kubectl create namespace test

namespace/test created


kubectl get namespaces         

NAME              STATUS   AGE

default           Active   82d

kube-public       Active   82d

kube-system       Active   82d

test              Active   5s


You can see test namespace has been created. 

Now you'll notice what are these namespaces other than test. I didn't create them. Let me explain.

  • kube-system: Namespace for objects created by kubernetes system
  • default: It's default namespace when you don't specify name then objects will be created in default namespace
  • kube-public: This is created automatically and readable by all users. This namespace is mostly reserved for cluster usage.

Let' create a Pod in test namespace now using below commands.

kubectl run mypod --image=nginx -n test

kubectl run mypod --image=nginx -n test

pod/mypod created


Let's check the pod and make sure you look at test namespace.

kubectl get pods -n test

NAME    READY   STATUS    RESTARTS   AGE

mypod   1/1     Running   0          2m10s


I have created mypod in prod namespace as well. So we can have an application with same name but in different namespace.

kubectl run mypod --image=nginx -n prod

pod/mypod created


kubectl get pods -n prod               

NAME    READY   STATUS    RESTARTS   AGE

mypod   1/1     Running   0          14s



Conclusion

Namespace is very useful when deploying your application on cluster. It's always a best practice to create a namespace and deploy your application. You can think of a scenario where one team creates a pod with name testPod and other team also tries to name a pod testPod. So in this case Pod creation will be failed due to duplicate name. So best practice says create your pod inside a namespace. 

Note: If you think this helped you and you want to learn more stuff on devops, then I would recommend joining the Kodecloud devops course and go for the complete certification path by clicking this link

Debugging your pod on Kubernetes?

 Debugging the pods on Kubernetes




Debugging is very important to identify the issue in Pod. sometimes your application may behave differently /wrong. Your Pod has stopped or some other issues happening inside your Pod. You can always debug that to identify the issue and fix it. 

So the most basic thing we do to debug the issue is to start with checking the logs. Logs are very crucial part and play very important role in any application. If anything goes wrong we can always check the logs and analyse it. Similar to above we are going to check the logs, events and definition of Pod to identify the issues. 

To start with it, we first need to run the pod. You can follow below command to run the pod.


kubectl run mypod --image=nginx


Here mypod is name of the pod and nginx image will be used.

Check if the pod is running. 

kubectl get pods


Result below:

NAME    READY   STATUS              RESTARTS   AGE

mypod   0/1     ContainerCreating   0          5s


It says container creating state. We may wait and see if it is completed and running state.

NAME    READY   STATUS    RESTARTS   AGE

mypod   1/1     Running   0          21s


So it's in running state. We can also use yaml file to create the pod.

Let's break something and see what we issues and status we get. I'll delete the pod and recreate it with the wrong image name.

To delete the Pod use below command:


kubectl delete pod mypod

pod "mypod" deleted


Now since the pod has been delete let's recreate it with wrong image.

kubectl run mypod --image=nginx-myimage-123


Run it and pod will be created successfully. But wait did we check the status if the pod is running. 
Check it using Kubectl get pods command.

kubectl get pods

NAME    READY   STATUS         RESTARTS   AGE

mypod   0/1     ErrImagePull   0          9s


You can identify under the status column that there is an error. It says ErrImagePull. We can guess that there is an error during image pull. We know that because we put that wrong image name. But in real life scenario we don't know about if our image is wrong. So we can check the events. 

To check the events we can use describe command:

kubectl describe pod mypod


Once we run this command it will give us result in key/value pair format. Just scroll to the bottom and look for the events. 

Events:

  Type     Reason     Age                From               Message

  ----     ------     ----               ----               -------

  Normal   Scheduled  34s                default-scheduler  Successfully assigned default/mypod to docker-desktop

  Normal   BackOff    26s                kubelet            Back-off pulling image "nginx-myimage-123"

  Warning  Failed     26s                kubelet            Error: ImagePullBackOff

  Normal   Pulling    12s (x2 over 33s)  kubelet            Pulling image "nginx-myimage-123"

  Warning  Failed     6s (x2 over 27s)   kubelet            Failed to pull image "nginx-myimage-123": rpc error: code = Unknown desc = Error response from daemon: pull access denied for nginx-myimage-123, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

  Warning  Failed     6s (x2 over 27s)   kubelet            Error: ErrImagePull


Here we can see it says either repository does not exist or we don't have access to it. 

So checking the events is very important step. This can tell us what happened when we ran our kubectl run command. There is one more way by which we can check and that is logs. By checking logs can give us some insights. Sometimes we don't get much information from the events and in those scenarios checking logs can be very helpful if we can find something. We can check the log in this case as well but since the issue is only with image. We used wrong image name and this issue was very much understandable from the events. But let's check the logs anyway by running below command.

kubectl logs mypod


Result:

Error from server (BadRequest): container "mypod" in pod "mypod" is waiting to start: trying and failing to pull image


In logs also we can check that its saying "trying and failing to pull image" step.

If we have specific container failing inside the pod then you can run below command.

kubectl logs mypod container_name                           

If our container has ever crashed previously then we can use --previous flag in command.

kubectl logs --previous mypod container_name                 

Conclusion 

These are the basic ways by which we can check and fix the issues in Pod. Events can be very helpful but sometimes logs can be more helpful. So it depends on what is the issue. It's always better to check for events and then go for logs. 

Hope this can be helpful!

Note: If you think this helped you and you want to learn more stuff on devops, then I would recommend joining the Kodecloud devops course and go for the complete certification path by clicking this link

Quantum Computing: The Future of Supercomputing Explained

  Introduction Quantum computing is revolutionizing the way we solve complex problems that classical computers struggle with. Unlike tradi...