Skip to main content

Creating Your First Pod in Kubernetes

Updated 13 min readMarkdown
   Creating Your First Pod in Kubernetes

A Step-by-Step Blog Tutorial

Kubernetes “Node NotReady” Explained | by Farhan Muntasir | Feb, 2026 | Medium

Kubernetes is a powerful platform for running and managing containerized applications. One of its most important building blocks is the Pod — the smallest deployable unit in Kubernetes.

In this hands-on lab, you will create an NGINX Pod in two ways: first with an imperative kubectl command, then with a declarative YAML manifest. You will inspect the Pod, review its logs and events, open a shell inside its container, and understand when each approach is useful.

The steps below follow your assignment's required order and resource names.

1. Project objectives and expected outcome

By the end of this lab, you will be able to:

  • Explain what a Pod is and how it relates to a container.
  • Create a Pod with kubectl run.
  • Verify and delete a Pod.
  • Define a Pod using YAML and apply it with kubectl apply.
  • Inspect Pod configuration, status, events, and logs.
  • Execute commands inside a running container.
  • Explain the difference between imperative and declarative workflows.

Real world scenario: Imagine you are a junior DevOps engineer and need to test whether NGINX can run on a Kubernetes cluster. An imperative command allows you to launch a quick test. A YAML manifest gives your team a repeatable definition that can be reviewed, stored in version control, and applied again.

2. Prerequisites and cluster safety

You need:

  • A working Kubernetes learning or lab cluster.
  • kubectl installed and configured.
  • Permission to create, inspect, delete, and execute into Pods.
  • Terminal access and a text editor such as Nano or Vim.
  • Internet connectivity from the cluster's nodes, or access to a registry mirror, to pull the official NGINX image when needed.

This lab does not require a cloud-specific cluster. You can use an existing training cluster, Minikube, kind, or another supported Kubernetes environment.

Step 1 — Confirm your Kubernetes connection

Before creating resources, check which cluster and namespace kubectl will use:

Bash

kubectl config current-context
kubectl cluster-info
kubectl get nodes
kubectl config view --minify

Review the output and make sure the active context is your learning or lab cluster, not production. The minified config shows the selected cluster and user configuration; avoid sharing credentials or sensitive configuration details.

Check that the nodes are ready:

Bash

kubectl get nodes

Expected result: your lab cluster's nodes should normally show Ready. If kubectl cluster-info cannot connect, resolve the cluster connection before continuing.

Step 2 — Verify permissions

Bash

kubectl auth can-i create pods
kubectl auth can-i get pods
kubectl auth can-i delete pods
kubectl auth can-i create pods/exec
kubectl auth can-i get pods/log

3. Task 1 — Set up your lab folder

Step 1 — Create the working directory

Run:

Bash

mkdir -p ~/k8s-labs/pods
cd ~/k8s-labs/pods

Verify your current directory:

Bash

pwd
ls -la

Expected directory:

~/k8s-labs/pods

This directory will hold your Pod manifest and other files related to the lab.

Bash

echo "Full Name: YOUR FULL NAME"

Replace the placeholder with your actual full name. Do not include passwords, access tokens, or other credentials in screenshots.

4. Task 2 — Create a Pod imperatively

An imperative command tells Kubernetes what action to perform directly, without first saving a complete resource definition in a manifest file.

Step 1 — Create the NGINX Pod

Make sure you are in the lab directory, then run:

Bash

cd ~/k8s-labs/pods

echo "Full Name: YOUR FULL NAME"
kubectl run nginx-pod --image=nginx

This instructs Kubernetes to create a Pod named nginx-pod using the official nginx image.

Expected output will resemble:

pod/nginx-pod created

The exact output can vary depending on your Kubernetes version and cluster state.

Step 2 — Check the Pod status

Run:

Bash

kubectl get pods

At first, you might see ContainerCreating while Kubernetes downloads the image and starts the container. Wait until the Pod becomes ready:

Bash

kubectl wait --for=condition=Ready pod/nginx-pod --timeout=120s

Then check again:

Bash

echo "Full Name: YOUR FULL NAME"
kubectl get pods

Expected output resembles:

NAME        READY   STATUS    RESTARTS   AGE
nginx-pod   1/1     Running   0          ...

The Pod may take a little time to reach Running. If it does not, use the troubleshooting section below before proceeding.

Step 3 — Delete the imperative Pod

Your assignment requires deleting this Pod before creating another Pod with the same name from YAML.

Run:

Bash

echo "Full Name: YOUR FULL NAME"
kubectl delete pod nginx-pod

Expected output:

pod "nginx-pod" deleted

Confirm it has been removed:

Bash

kubectl get pods

The nginx-pod resource should no longer appear in the current namespace. If deletion is still in progress, wait and check again:

Bash

kubectl wait --for=delete pod/nginx-pod --timeout=60s

If it has already disappeared, Kubernetes may report that the resource was not found; that simply means there is nothing left to wait for.

Learning checkpoint: You have now created, checked, and deleted a Pod using imperative commands. Next, you will define the same workload in a reusable YAML file.

5. Task 3 — Create the Pod declaratively using YAML

The declarative approach describes the desired state of a resource in a file. You then use kubectl apply to ask Kubernetes to create or update resources to match that definition.

Step 1 — Create the YAML manifest

Make sure the required directory exists:

Bash

mkdir -p ~/k8s-labs/pods
cd ~/k8s-labs/pods
touch nginx-pod.yaml
nano nginx-pod.yaml

Paste the following manifest into the editor. YAML indentation matters: use spaces, not tabs.

YAML

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
    - name: nginx-container
      image: nginx
      ports:
        - containerPort: 80

Save and exit Nano:

  1. Press Ctrl + O to save.
  2. Press Enter to confirm the filename.
  3. Press Ctrl + X to exit.

If you prefer not to use an interactive editor, you can create the same file with this shell script:

cat > ~/k8s-labs/pods/nginx-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
    - name: nginx-container
      image: nginx
      ports:
        - containerPort: 80
EOF

Step 2 — Verify the manifest before applying it

Run:

echo "Full Name: YOUR FULL NAME"
cat ~/k8s-labs/pods/nginx-pod.yaml

Check that the file contains the required name, label, container name, image, and port.

You can ask Kubernetes to validate the manifest without saving the resource:

kubectl apply --dry-run=server -f ~/k8s-labs/pods/nginx-pod.yaml

This server-side dry run requires a reachable cluster and appropriate permissions. It validates the manifest against the cluster but does not create the Pod. If server-side dry run is unavailable in your environment, review the YAML and continue with kubectl apply.

Step 3 — Apply the YAML manifest

First, confirm that the imperative Pod was deleted:

kubectl get pods

Then apply the declarative manifest:

cd ~/k8s-labs/pods

echo "Full Name: YOUR FULL NAME"
kubectl apply -f nginx-pod.yaml

Expected output resembles:

pod/nginx-pod created

Step 4 — Verify the declarative Pod

Check its status:

kubectl get pods

Wait for it to become ready

kubectl wait --for=condition=Ready pod/nginx-pod --timeout=120s

Then run:

echo "Full Name: YOUR FULL NAME"
kubectl get pods -o wide

Expected output resembles:

NAME        READY   STATUS    RESTARTS   AGE   IP       NODE
nginx-pod   1/1     Running   0          ...   ...      ...

The Pod's IP address and node name depend on your cluster. The Pod's status should be Running and its ready count should be 1/1.

Step 5 — Understand the YAML manifest

Field Meaning
apiVersion: v1 Uses the Kubernetes core API version for Pods.
kind: Pod Defines the resource type as a Pod.
metadata.name Names the Pod nginx-pod.
metadata.labels Assigns the label app: nginx.
spec Defines the desired Pod configuration.
spec.containers Lists the containers that run inside the Pod.
name: nginx-container Names the container inside the Pod.
image: nginx Specifies the official NGINX image.
containerPort: 80 Documents the container port used by NGINX.

Important: containerPort: 80 declares the port the container uses; it does not automatically expose the application to the public internet or create a Kubernetes Service. This lab only requires creating and inspecting the Pod.

6. Task 4 — Inspect and access the Pod

Now that nginx-pod has been created from the YAML manifest, you will inspect its configuration, view its logs, and explore the NGINX container's default web files.

Step 1 — Describe the Pod

Run:

echo "Full Name: YOUR FULL NAME"
kubectl describe pod nginx-pod

This command displays detailed information, including:

  • Pod name, namespace, and labels.
  • Pod IP and the node where it is running.
  • Container name and image.
  • Container state and readiness.
  • Restart count.
  • Events related to scheduling, image pulling, and startup.

Pay particular attention to the Conditions, Containers, and Events sections. These are especially useful when a Pod fails to start.

Step 2 — View the NGINX container logs

Run:

echo "Full Name: YOUR FULL NAME"
kubectl logs nginx-pod

The command retrieves the container's standard output and standard error.

It may return little or no output if NGINX has not yet received a request. That does not necessarily indicate a problem.

To generate an HTTP request from within the cluster, you can use the Pod's IP address:

kubectl get pod nginx-pod -o wide

If your cluster provides a shell with curl, try this command from your terminal, replacing POD_IP with the displayed Pod IP:

kubectl run nginx-test \
  --image=curlimages/curl \
  --restart=Never \
  --rm -i \
  -- curl -I --max-time 10 http://POD_IP/

This optional test creates a temporary client Pod and removes it after the command completes. It requires the cluster to be able to pull the curlimages/curl image and the Pod network to permit the connection. You can skip it if you want to follow only the required lab steps.

After generating a request, check the NGINX logs again:

kubectl logs nginx-pod

You should see the request in the access log output if NGINX is configured to send its access logs to standard output, as the official image normally does.

Step 3 — Open a shell inside the NGINX container

Run the command specified by your assignment:

echo "Full Name: YOUR FULL NAME"
kubectl exec -it nginx-pod -- /bin/bash

You should now be inside the running NGINX container. Your terminal prompt will change to indicate the container shell.

If Bash is unavailable in your image, use /bin/sh instead:

kubectl exec -it nginx-pod -- /bin/sh

Step 4 — Explore the default NGINX web directory

Run these commands inside the container shell:

cd /usr/share/nginx/html
ls -la

You should see the files that make up the default NGINX welcome page, commonly including index.html.

To inspect the default HTML file:

cat index.html

This demonstrates where the default web content is stored inside the container's filesystem.

Step 5 — Exit the container shell

When you finish inspecting the files, run:

exit

You will return to your original terminal. This exits the interactive shell; it does not delete the Pod or stop NGINX.

Verify that the Pod is still running:

kubectl get pods

Expected status:

NAME        READY   STATUS    RESTARTS   AGE
nginx-pod   1/1     Running   0          ...

7. Troubleshooting and error handling guide

Use the following checks if your results differ from the expected output.

Error or symptom Possible cause What to do
kubectl cannot connect Cluster is stopped or configuration is incorrect Run kubectl config current-context and kubectl cluster-info. Confirm the correct lab cluster is running.
nginx-pod already exists A previous Pod was not deleted Inspect it with kubectl get pod nginx-pod. If it is your lab Pod, delete it before proceeding.
Pod remains Pending Scheduling issue, insufficient resources, or node problems Run kubectl describe pod nginx-pod and review the events.
ImagePullBackOff Registry access or image-pull problem Check the image name, node connectivity, and Pod events.
ErrImagePull Kubernetes cannot download the image Review the image-pull error in kubectl describe pod nginx-pod.
YAML parsing error Incorrect indentation or malformed YAML Check the manifest carefully. Use spaces, not tabs.
kubectl logs shows no output NGINX has not received a request, or logs are directed elsewhere Confirm the Pod is running and generate a request.
kubectl exec fails Pod is not running or the command is unavailable Check kubectl get pods and use /bin/sh if Bash is unavailable.
Pod restarts repeatedly Container startup or runtime issue Run kubectl describe pod nginx-pod and kubectl logs nginx-pod --previous if a previous container instance exists.

Essential diagnostic commands

If something goes wrong, run these commands in order:

kubectl get pods -o wide
kubectl describe pod nginx-pod
kubectl logs nginx-pod
kubectl get events --sort-by=.metadata.creationTimestamp

If the container has restarted, check the previous instance's logs:

kubectl logs nginx-pod --previous

Do not repeatedly delete and recreate the Pod without examining the error. The events and logs usually provide the best starting point for identifying the cause.

8. Industry insight — Imperative vs. declarative Kubernetes

Imperative workflow

kubectl run nginx-pod --image=nginx

You issue a direct command to create the Pod. This is convenient for quick experiments, temporary testing, and troubleshooting.

Declarative workflow

kubectl apply -f nginx-pod.yaml

You describe the desired resource configuration in a file. This is better suited to repeatable environments, peer review, version control, and team collaboration.

In production environments, standalone Pods are generally not the preferred way to run long lived applications. Kubernetes Deployments typically manage replicated Pods, replace failed instances, and support controlled application updates.

This lab intentionally uses a standalone Pod because its purpose is to teach the fundamentals of Kubernetes resources and kubectl.

9. Final verification

Run the following commands from your terminal:

Bash

cd ~/k8s-labs/pods

echo "Full Name: YOUR FULL NAME"
kubectl get pods
kubectl describe pod nginx-pod
kubectl logs nginx-pod
kubectl get pod nginx-pod -o yaml

The Pod should be running, and its configuration should reflect the YAML manifest. Remember that kubectl logs may be empty if no request has been received.

key takeaways

You have followed the required workflow:

  1. Created the lab folder.
  2. Created, checked, and deleted nginx-pod using kubectl run.
  3. Created nginx-pod.yaml with the required labels, container name, image, and port.
  4. Applied the YAML manifest and verified the resulting Pod.
  5. Inspected the Pod, reviewed logs, accessed the container shell, explored the default NGINX files, and exited the shell.

You now understand the difference between creating a resource with an imperative command and managing it using a declarative manifest. These are foundational skills for working with Kubernetes in real-world DevOps environments.

P.S. This post is part of the DevOps Micro Internship (DMI) with Agentic AI — Cohort 3 — by [Pravin Mishra](https://www.linkedin.com/in/pravin-mishra-aws-trainer/). My graded progress is public: https://dmi.pravinmishra.com/s/wisegeorge1.html · Start your DevOps journey: https://dmi.pravinmishra.com/?utm_source=student&utm_medium=ps-linkedin&utm_campaign=cohort3

1 view

No comments yet. Be the first to comment.