Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 6

Applying Kubernetes Manifests with Kubectl

Recommended resources

Hello! Welcome to the second module of our course, "Cluster Interaction and Troubleshooting."

In our last module, we built a solid conceptual foundation. We explored the Kubernetes architecture, contrasted declarative and imperative management, and saw how namespaces are used to organize resources. You learned that the declarative approach—defining your desired state in YAML files—is the standard for robust infrastructure management, a concept that should feel familiar from your work with Terraform.

Today, we transition from theory to practice. This lesson focuses on the single most important command for managing Kubernetes applications: kubectl apply. You will learn how to create and update Kubernetes resources from manifest files, which is the core workflow for deploying and managing applications on Kubernetes. Mastering this is fundamental for any Platform Engineer.

1. The Blueprint: Understanding Kubernetes Manifests

Before you can apply a configuration, you need to write one. In Kubernetes, this is done using manifest files, which are typically written in YAML. These files are the "source code" for your infrastructure, describing the desired state of your resources.

Think of a manifest as the blueprint for a Kubernetes object. Just like an architectural blueprint has specific sections (foundation, electrical, plumbing), a Kubernetes manifest has four essential top-level fields:

  • apiVersion: Specifies which version of the Kubernetes API you're using to create this object. Different objects (like Deployments, Services, etc.) can have different API versions (e.g., v1, apps/v1).
  • kind: The type of resource you want to create (e.g., Pod, Deployment, Service).
  • metadata: Data that helps uniquely identify the object, including its name, namespace, and labels (key-value pairs for organization, similar to tags in AWS/Azure).
  • spec: The most important part. This is where you declare the desired state of the resource. For a Pod, this includes what containers to run; for a Deployment, it includes how many replicas you want. This is analogous to the argument block inside a Terraform resource.
A partial YAML manifest for an Nginx Deployment. Note the key fields: `apiVersion`, `kind`, `metadata`, and `spec`.

To get a practical feel for how these fields come together, the following video provides an excellent walkthrough of writing a basic manifest file for a Pod from scratch.

#1 Write 1st Kubernetes manifest file | Create a pod using manifest file | Manifest file Explained

Watch this video from Valaxy Technologies to understand the structure of a manifest file and the meaning of its core fields. The presenter does a great job of explaining the YAML syntax and indentation, which is crucial to get right.

Please watch the following sections: Manifest Components: This introduces the four main fields and how they relate to creating an object. Writing the Manifest: This is a detailed, step-by-step walkthrough of writing a Pod manifest file. Pay close attention to the YAML structure and indentation.


2. The Engine: Declarative Management with kubectl apply

Once you have your manifest file, kubectl apply is the command you use to make it a reality in your cluster. It's the Kubernetes equivalent of terraform apply. It takes your manifest file and tells the Kubernetes API server, "Make the cluster look like this."

The power of kubectl apply lies in its declarative and idempotent nature.

  • Declarative: You declare the end state, and Kubernetes figures out the steps to get there.
  • Idempotent: You can run the same command over and over, and it will only make changes if the live state of the resource is different from the desired state in your file.

This is fundamentally different from imperative commands like kubectl create or kubectl run.

To understand this crucial distinction, please read the following article from Komodor.

Syntax, Examples, and kubectl apply vs. create vs. replace

This article, "Syntax, Examples, and kubectl apply vs. create vs. replace," clearly explains why apply is the preferred method for managing resources in a controlled and predictable manner.

Read the section titled "kubectl apply vs. kubectl create vs. kubectl replace: What Is the Difference?" Below the heading, read the command comparison. It provides a concise comparison of these three commands.

The Create-and-Update Workflow

The workflow with kubectl apply is simple and powerful:

  1. Create a resource: You write your manifest file (e.g., my-app.yaml) and run:

    kubectl apply -f my-app.yaml
    

    If the resource doesn't exist, Kubernetes creates it. The output will show ... created.

  2. Update a resource: You need to change something—for example, update the container image version. You simply edit my-app.yaml and run the exact same command again:

    kubectl apply -f my-app.yaml
    

    Kubernetes detects the resource already exists, compares the new manifest with the live state, and applies only the necessary changes. The output will show ... configured.

This video demonstrates this create-and-update cycle perfectly.

Kubectl Basic Commands - Create and Debug Pod in a Minikube cluster | Kubernetes Tutorial 18

In this clip from 'TechWorld with Nana,' you'll see how kubectl apply is used to both create a Deployment and then update it after a change is made to the manifest file.

Starting around 12 minutes in, watch the YAML demonstration. The presenter first creates a Deployment from a YAML file and then updates the number of replicas in the file and re-applies it, showing how apply intelligently handles the update.

How Does apply Know What to Change? The Three-Way Merge

You might be wondering how kubectl apply is so smart. It works by performing a three-way merge. When you run apply, Kubernetes looks at three things:

  1. The new manifest file you are providing.
  2. The live configuration of the object in the cluster.
  3. The last-applied configuration, which Kubernetes stores as an annotation (kubectl.kubernetes.io/last-applied-configuration) on the object itself.

By comparing these three sources, Kubernetes can figure out exactly which fields you've changed in your manifest and apply only those changes, preserving any other modifications made to the live object (e.g., by an autoscaler). This is a sophisticated mechanism that makes declarative management safe and reliable.

Test your understanding!

You have a Deployment running version 1.0 of your application. You update your deployment.yaml to use version 1.1 and run kubectl apply -f deployment.yaml. Later, your colleague, unaware of your change, runs kubectl apply -f deployment.yaml again using the old file that still specifies version 1.0.

What will happen to the application pods in the cluster after your colleague runs the command?

Show answer

Kubernetes will "roll back" the deployment to version 1.0. Because kubectl apply makes the cluster's state match the state declared in the file, it will see that the live configuration (running 1.1) is different from the desired configuration in the old manifest (specifying 1.0) and will start replacing the pods to match the manifest. This highlights why keeping your manifest files in a version control system like Git is critical to have a single source of truth.


3. Best Practices for Applying Changes

As a Platform Engineer, you want to apply changes safely and predictably. Here are two indispensable flags for kubectl apply:

  • --dry-run=client: This is your safety check. It tells kubectl to process the command and render the resulting object, but not send it to the API server. It's perfect for validating your YAML syntax and catching errors before they affect the cluster. Think of it as the equivalent of terraform plan.

    kubectl apply -f my-app.yaml --dry-run=client
    

    If the command returns ... (dry run), your YAML is likely valid. If it errors out, you have a syntax issue to fix.

  • kubectl diff: This command gives you a diff or git diff style output showing the exact changes that apply would make. This is extremely useful for reviewing changes before pushing the button.

    kubectl diff -f my-app.yaml
    

Let's put this all together with a quick exercise.

Hands-on Exercise

Let's create and update a simple Nginx Deployment.

  1. Create a file named nginx-deployment.yaml with the following content:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.21.0 # Pinned to a specific version
            ports:
            - containerPort: 80
    
  2. First, validate your manifest without applying it:

    kubectl apply -f nginx-deployment.yaml --dry-run=client
    

    It should print deployment.apps/nginx-deployment created (dry run).

  3. Now, create the Deployment for real:

    kubectl apply -f nginx-deployment.yaml
    

    It should print deployment.apps/nginx-deployment created.

  4. Next, let's scale the application. Edit nginx-deployment.yaml and change replicas: 1 to replicas: 3.

  5. Before applying, check what will change:

    kubectl diff -f nginx-deployment.yaml
    

    You should see output indicating the replicas field will change from 1 to 3.

  6. Finally, apply the update:

    kubectl apply -f nginx-deployment.yaml
    

    It should print deployment.apps/nginx-deployment configured. You have now successfully created and updated a resource declaratively!


Conclusion

In this lesson, you've mastered the cornerstone of Kubernetes resource management. You now understand how to define the desired state of your applications in YAML manifests and use kubectl apply to make that state a reality. This declarative workflow is fundamental to building repeatable, reliable, and version-controlled systems on Kubernetes.

Key Takeaways:

  • Kubernetes resources are defined in YAML manifest files with four key fields: apiVersion, kind, metadata, and spec.
  • kubectl apply -f <filename> is the declarative command to create or update resources based on a manifest file.
  • It is idempotent, meaning it only makes changes if the live state differs from the desired state.
  • The apply command works its magic via a three-way merge, ensuring changes are made intelligently.
  • Always use --dry-run=client to validate syntax and kubectl diff to preview changes before applying them to a live cluster.

Now that you know how to create and modify resources, the next step is learning how to inspect them to verify they are running correctly and to debug them when they aren't. In our next lesson, we will cover kubectl get and kubectl describe, the primary tools for observing the state of your cluster.