Kubernetes

What are Kubernetes Manifest Files? Examples & Best Practices

What are Kubernetes Manifest Files? Examples & Best Practices

As you can’t get far in Kubernetes without encountering manifests, this article will explain what they are, why you should use them instead of imperative commands, and some best practices to follow when authoring your own manifests. Let’s dive in.

We will cover:

  1. What is a Kubernetes manifest file?
  2. Why use Kubernetes manifest files?
  3. How to create Kubernetes manifest files
  4. Kubernetes manifest best practices

What is a Kubernetes manifest file?

Kubernetes manifest files are YAML or JSON files that describe objects in your cluster. They’re the primary way to manage your objects as they let you version configurations alongside your code, then declaratively apply them to your cluster.

For example, the following basic manifest describes a Pod called nginx that runs a container using the nginx:latest image:

apiVersion: apps/v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx:latest

This manifest makes it clear that your cluster has a Pod called nginx with a container that runs the nginx:latest image.

You can use Kubectl to consistently create the Pod from its manifest in any Kubernetes cluster, without having to remember the syntax of imperative commands like kubectl run:

# Using an imperative command
$ kubectl run nginx --image nginx:latest

# Declaratively applying a manifest file
$ kubectl apply -f pod.yaml

This example demonstrates the difference between imperative and declarative configuration. In the imperative example, you must use specific commands to instruct Kubernetes how to complete the Pod creation operation. When you use declarative manifest files, Kubernetes reconciles the file’s content to your cluster’s existing state, then automatically applies any required actions so your cluster reaches the new desired state.

Manifests are usually written in YAML—as in the example above–but you can use raw JSON as an alternative. However, YAML is more readable and supports features such as YAML comments that are missing from JSON. This makes it better suited to Kubernetes manifests, as files are often complex and collaboratively developed by multiple team members.

What is the difference between manifests and deployments in Kubernetes?

Manifests are the files that describe what will be deployed in a Kubernetes cluster. Your actual deployments are created by applying your manifest files to your cluster, typically using Kubectl or a package manager like Helm.

Note that manifests don’t do anything on their own. They’re just static configuration files that define the desired state of your Kubernetes objects. Once you’ve applied them to a cluster, then the objects described by the manifests will exist within the cluster, in the state defined by the manifest.

See how to create a YAML file for Kubernetes deployment.

Why use Kubernetes manifest files?

Writing Kubernetes manifest files for your cluster objects provides several advantages over imperative commands. Here are some of the main reasons why they’re used.

Declarative configuration

Manifests are required to use a declarative configuration in Kubernetes. Although they can be handled imperatively (using commands such as kubectl create -f manifest.yaml and kubectl patch -f manifest.yaml), they’re most powerful when applied to your cluster using the kubectl apply command. For each object defined in your manifest, this command will reconcile the cluster’s state so objects match the versions described by the manifest.

Declarative updates are more predictable and easier to control. You can be sure that your cluster’s state includes all the objects required by your application in the correct states. Moreover, it’s possible to detect and prevent configuration drift by simply reapplying your manifests—Kubernetes will find any discrepancies and restore the state from the manifest.

Versioning objects

Manifests are configured as code for the objects in your Kubernetes cluster. You can check your manifests in your source control repositories to version them alongside your app’s code.

Combined with declarative updates, this ability lets you easily roll back to earlier versions of your application. You can check out a previous source commit, and then reapply the manifests to your cluster. Kubernetes will adjust your cluster’s objects to achieve the state required by the older application version.

Collaborating on objects

The use of manifests also allows you to easily manage collaborative updates to Kubernetes objects. Anyone can contribute to your files and add their changes, then request a review from a relevant team member.

In comparison, imperative commands aren’t suitable for busy collaborative scenarios. Team members running commands at the same time could overwrite each others’ changes or unintentionally introduce conflicts. Centralizing your configuration using manifests ensures everyone has an identical view of each object’s full state.

Facilitating automation

Kubernetes manifest files make it easy to automate changes to your Kubernetes clusters as part of your CI/CD pipelines. You can edit your manifests, commit them to your source repositories, then run the kubectl apply command in your pipelines to deploy the changes to your clusters.

This simplifies the development experience and helps improve throughput. You don’t need to run manual Kubectl commands, so the deployment process is also safer and more consistent.

How to create Kubernetes manifest files

The basic process of creating a Kubernetes manifest file is the same for all supported object types. You must create a new YAML file, write your manifest, and then use Kubectl to apply it to your cluster.

Common Kubernetes manifest fields

All Kubernetes manifests have a few required fields:

  • apiVersion — This states the Kubernetes API that the object type you’re creating belongs to. Top-level objects such as Pods currently belong to the v1 API, whereas other built-ins are scoped to more specific APIs: Deployments live in apps/v1, for example. Custom Resource Definitions (CRDs) define their own API versions that let you reference the objects they provide.
  • kind — This is the type of object that you’re defining, such as Pod or Deployment.
  • metadata — This field contains essential information about the object, including its name and namespace. This is covered in more detail below.
  • spec — Strictly speaking, this isn’t a required field, but it is used by most of the object types that are built into Kubernetes. This is where you’ll typically define the properties of your object—such as the container image used by a Pod or the number of replicas to run in a ReplicaSet.

You can see all these fields in the sample manifest from above:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx:latest

Manifest metadata

The metadata section is used to define your object’s identity and attach any relevant organizational data to it. It includes the following major fields:

  • name — This is the only required metadata field. It’s the name your object will be assigned in Kubernetes.
  • namespace — When set, this references a Kubernetes namespace that the object will be created within. The namespace must already exist in your cluster. When this field’s omitted, the default namespace is used.
  • labels and annotations — Labels and annotations let you add your own metadata to your objects. Labels are intended for information that identifies an object (such as the app or team it belongs to), while annotations store arbitrary values like the time the object was created or the system that it’s being managed by.

Although metadata doesn’t directly affect how Kubernetes configures your objects, labels are the primary way for objects to select each other. It’s therefore important you add correct labels to objects that require them, such as a Pod that will be referenced by a Service.

metadata:
  name: nginx
  labels:
    app: demo-app
  annotations:
    created-by: ci-deploy

Manifest spec fields

Your manifest spec will vary depending on the type of object you’re creating. You should follow the object type’s documentation to check which fields are required and the effects that each one has. Some objects and CRDs won’t use spec and will instead require you to add properties at the top level of the object adjacent to the metadata and kind fields.

Here are a few examples showing a basic spec for different Kubernetes built-in object types.

1. Pod Spec

spec:
  containers:
    - name: nginx
      image: nginx:latest

2. Service Spec

spec:
  selector:
    app: nginx
  ports:
    - port: 80

3. Deployment Spec

spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest

Notice how the Deployment object’s spec includes another manifest within its template field. This defines the Pod manifest that will be used to create the Pods required by the Deployment.

Writing a manifest for multiple objects in one file

Kubernetes objects are often mapped 1:1 with the manifest files that contain them. This is acceptable practice, but it’s also possible to declare multiple objects within a single manifest file. To do this, you should use YAML’s --- sequence to split each object into its own section in the manifest:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app:
      nginx
spec:
  containers:
    - name: nginx
      image: nginx:latest

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - port: 80

Applying this manifest to your cluster will create both the Pod and Service objects.

Using multiple manifest files

When you’re using multiple files, you can bulk apply them to your cluster by passing a directory path to kubectl apply:

$ kubectl apply -f /path/to/manifests

This will apply all the manifests in the directory. You can optionally recurse into subdirectories by setting the --recursive or -R flag.

Kubernetes manifest best practices

Because Kubernetes manifests can become large and complex, it’s possible for errors to occur. From simple typos to more problematic misconfigurations, here are some best practices that will help make your manifests valid, maintainable, and secure:

1. Check for invalid property names/values

Simple typos in your Kubernetes manifests can cause big issues, such as writing imag instead of image. When this happens, you’ll see a BadRequest error in Kubectl that warns you which field in the file is invalid.

2. Avoid YAML syntax issues

YAML is more readable than JSON but its syntax is also more complicated and easier to confuse. YAML syntax errors such as unterminated quotations and bad sequence or mapping values will prevent Kubectl from loading your file. You’ll get an error converting YAML to JSON message when this happens.

3. Check for incorrect field nesting

One particularly prevalent YAML issue concerns incorrect field nesting and indentation levels. If you see an error such as unknown field "containers", then you’ve probably nested the field at the wrong level within your manifest’s structure.

4. Group related resources into a single file

It’s helpful to segment the manifests for large applications into individual files but too many manifests can be difficult to manage. If several resources are directly related (such as if one requires the others), then you can merge them into one file using the --- syntax shown above. This will ensure the objects are always applied together.

5. Keep your manifests organized

Devise a manifest storage system that works for your projects and teams. This will ensure everyone can quickly find the manifest that defines a particular Kubernetes object. You could group manifests by their purpose, for example using apps, storage, and networking directories.

6. Protect manifests against unintentional changes

Changes to Kubernetes manifests should be treated as potentially sensitive actions. This is particularly true if you use CI/CD to automatically deploy manifest changes to your cluster—anyone with access to the manifests could alter your Kubernetes environment. It’s therefore vital to set up proper safeguards, such as by using code owners to require approvals when manifests change.

7. Comment and document your manifest files

Manifests for large applications frequently include many different components. You should document what each manifest is for and how it works to ensure that you and others will be able to maintain them in the future.

8. Use linters to catch common misconfigurations

Linting your manifests using a tool like Kube-Score can catch many potential misconfigurations such as missing resource limits, network policies, and security context settings. Addressing these problems before you apply the manifest to your cluster will improve security and reliability.

9. Use templating tools to make manifests more modular

It’s worth exploring templators such as Helm and Kustomize when you’re authoring longer manifests. These can save time and improve maintainability by reducing duplication. They also make your manifests more flexible by allowing you to customize values before you deploy.

This is not an exhaustive list of possible Kubernetes manifest problems but it gives you a starting point to look for the most common issues. You should also follow broader Kubernetes best practices to ensure individual objects within your manifests are properly configured for security and performance.

Key Points

A Kubernetes manifest file is a text file that defines a desired Kubernetes object specification. Manifests should be your default approach to Kubernetes object management. Compared with imperative commands, they facilitate collaboration, let you track changes over time, and allow you to easily detect errors in advance by using linters and security scanners.

You can use CI/CD to apply infrastructure changes using IaC techniques, either to Kubernetes or other tools such as Terraform and Ansible. Check out Spacelift to collaborate on infrastructure with full control and flexibility. It includes role-based security policies, detailed usage insights, and full visibility into everything running in your cloud accounts. Create a free account today or book a demo with one of our engineers.

Manage Kubernetes Easier and Faster

Spacelift allows you to automate, audit, secure, and continuously deliver your infrastructure. It helps overcome common state management issues and adds several must-have features for infrastructure management.

Start free trial