Cart

    Sorry, we could not find any results for your search querry.

    Creating Kubernetes objects

    In a Kubernetes cluster, objects are entities used to describe the desired state of the cluster. More specifically, an object describes the desired state of a resource within your Kubernetes cluster, such as a Deployment or Service. This includes specifying what applications should run, with what hardware resources, and what policies. YAML files are almost always used to provide JSON data to the Kubernetes API.

    Within such a YAML file, you describe the desired specification of an object (the so-called object spec), such as a Deployment. In this guide, we will show you how to build a Kubernetes object. To do so, we will discuss some of the most common options you may encounter in different types of Kubernetes objects and provide an example of a Deployment object.

    This article is designed to be as broad as possible, but there is a difference in how certain fields/keys in the YAML file are filled in for each type of resource. If you want to know how the layout of a particular type of resource, such as a Deployment or Service, looks like, take a look at the Kubernetes API documentation for an overview of resources and the options you can use to build an object.


    The structure of a Kubernetes object

    In this section, we discuss in chronological order the most commonly used components that make up a .yaml Kubernetes object. Always pay attention to the indents (spaces/tabs) in the structure of an object. The most important components that must always be present are apiVersion, kind, metadata, and spec:

    apiVersion: 
    kind: 
    metadata: 
    spec: 

    In this article, you will encounter the terms 'key' and 'value' several times. Simply put, the key is the name of an item in an object, such as 'apiVersion' above. The value is the value that is filled in behind a key, such as 'apps/v1'. Not every key, however, gets a value but may also introduce underlying keys.


    ApiVersion

    The apiVersion specifies which version of the Kubernetes API is used to create the object. You use the syntax:

    apiVersion: <groupname>/<version>

    In practice, you will usually use apps/v1 as the group name and version. This is the default option for creating an object for hosting applications such as Nginx or MySQL and looks like this, for example:

    apiVersion: apps/v1

    An overview of available groups and API version numbers can be found here. In addition, the legacy/core group is still available via the group name/version 'api/v1'.


    Kind

    Kind tells you what type of object schema you are creating an object for. A kind can be one of three types:

    Somewhat confusingly, the examples you see behind these three types of kind are also called "Resources," for example, in the Kubernetes API documentation.

    apiVersion: <groupname>/<version>
    kind: <object_type>

    Suppose you want to create a Deployment for an application, then the kind, including apiVersion, might look like this:

    apiVersion: apps/v1
    kind: deployment

    Metadata

    The metadata helps give an object a unique identity. Available options include:

    • name: The name of the object, such as 'nginx-deployment'.
    • UID: Optionally, a unique UID, such as 1234ab-1234-abcde-12345.
    • namespace: A kind of collective name under which Deployments, Services, Persistent Volumes, etc. fall.
    • labels: A combination of a 'key' and a 'value' to add specific attributes that help identify the object, see the section on labels later in this article for more information.
    • annotations: In certain cases, you can add an 'annotation' to an object. This is the case, for example, when you create a load balancer service. For more information, see the section on annotations later in this paragraph.
    • creationTimeStamp: When the object was created, for example with the value 2022-11-11T11:11:11Z (note the T and Z).
    • resourceVersion: An internal version number of the object. This is used by clients to determine when changes have been made. You can perform a 'watch' request via an API call to see changes (in JSON data) made since the version number.

    A 'name' is the minimum requirement for the metadata field, for example (including previous options):

    apiVersion: <groupname>/<version>
    kind: <object_type>
    metadata:
      name: <deployment_name>

    When you combine all the previously mentioned options, this can look like the following for an Nginx deployment, for example:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: default
      name: nginx-deployment
      uid: 12345ab-1234-abcde-12345
      labels:
        app: nginx
      annotations:
        nginx.org/proxy-connect-timeout: 30s
      creationTimestamp: 2022-11-11T11:11:11Z
      resourceVersion: "12345"

    Labels

    Labels are a type of metadata that consist of a key and a value. Labels are used to describe properties of your object. The nice thing about this is that you are free to come up with and fill in your own labels. The only limitation is that the key of a label must be unique per object.

    The structure of a label looks like this:

    metadata:
      labels:
        key1: value1
        key2: value2

    You are free to choose your own labels, but for convenience, we've listed some examples of commonly used labels:

    • app: nameofapp, e.g. mysql.
      Instead of 'app', you will come across the name 'app.kubernetes.io/name' in the Kubernetes documentation, but for simplicity, we recommend using 'app'.
    • instance: nameofapp-uniqueID, e.g. mysql-abcd
    • version: version number, e.g. 8.0
    • component: component type, e.g. database
    • part-of: part of a larger whole, e.g. WordPress
    • managed-by: management tool used, e.g. Helm
    • release: release tier or name, e.g. stable or Jelly
    • environment: environment type, e.g. dev or production
    • tier: code tier, e.g. backend
    • partition: username, e.g. customerA or customerB

    Some of these options combined can look like the following, for example:

    metadata:
      labels:
        app: mysql
        version: 8.0
        part-of: WordPress
        release: production

    Annotations

    By adding an annotation, you can influence the behavior of an application. Note that not all objects can use annotations, and this is typically included in the documentation of the makers of the relevant application, not in the Kubernetes documentation itself. Like labels, annotations use keys and values:

    metadata:
      annotations: 
        key1: value1
        key2: value2

    The annotations you can use vary per application, but a nice example of this is creating a load balancer service. By adding one or more annotations under metadata, you can adjust the behavior of the load balancer, for example, as follows:

    apiVersion: v1
    kind: Service
    metadata:
      name: example-loadbalancer
      annotations:
        service.beta.kubernetes.io/transip-loadbalancer-ptr: mail.jedeomein.nl
        service.beta.kubernetes.io/transip-loadbalancer-ssl-mode: on

    Please note: in addition to the code above, the 'spec' section is also necessary, see the next paragraph. For more information on making load balancer services specific as an object or via Kubectl, see our article on Kubernetes load balancers.


    Spec

     

    The Spec describes the desired state of the object, such as the container image used and where log files are written. There are many keys available under the Spec. This paragraph discusses the most common Spec options for workload and service resources. Note that not all keys in the overview below can be used by all types of resources or are required. Always consult the documentation of the relevant object/resource type for more information.

     

    Workload resources:

    Kubernetes distinguishes between different types of resources. Below is an example of keys that you will encounter most often with workload resources such as Deployments, StatefulSets, and Pods.

    spec: 
      replicas: 
      strategy:
        type:
      selector: 
        matchLabels:
          app:
      template: 
        metadata:
          labels:
            app:
        spec:
          containers:
          - name: 
            image: 
            resources:
              limits: 
                memory: 
              requests:
                cpu: 
                memory: 
            ports: 
            - containerPort: 
              name:
            volumeMounts:
            - mountPath:
              name: 
          volumes: 
          - name:
            persistentVolumeClaim: 
            claimName: 

    At first glance, the Spec block can be intimidating, but many items are optional, or themselves have no value because they introduce one or more other keys (for example, the 'selector' above).

    Please note: If a key is part of a parent structure/tree, it will be distinguished in the overview below with dots, for example: selector.matchlabels.app

    • spec: The first 'spec:' mention opens the spec component and must be present in a Kubernetes object. You do not fill in anything behind 'spec:'
    • replicas: The number of pods that must be active with the specifications included in this .yaml file.
    • strategy: Contains the keys and values related to the rollout strategy. This key does not receive a value and, along with its associated keys, is optional. If you do not specify a rollout strategy, RollingUpdates will be used. Pods are replaced one by one as needed, for example, to roll out an update. You can find an in-depth article about the available options/strategies and how they work here.
    • strategy.type: The type of strategy, for example, RollingUpdate.
    • selector: A selector is a fancy name for the mechanism by which a client/user selects objects based on labels. This is optional and useful, for example, when Kubernetes establishes connections between resources. Suppose you want to establish a connection between a Deployment and a Service. In that case, you use a selector. The selector key itself does not receive a value but introduces other keys.

      Available options are selector, selector.matchExpressions, and selector.matchLabels. Confusingly, the last two are 'sub'-keys of the selector key. Which of these options you choose depends on the type of resource you are creating (e.g., a Deployment or Service) and can be found in the Kubernetes API documentation for the relevant resource.
       
    • selector.matchLabels: This option is often used to address a workload resource object from another object via a selector, or vice versa. The matchLabels key itself does not receive a value but introduces other keys.
    • selector.matchLabels.app: The name of the application for which you are using the matchLabel, for example, nginx. It is essential that if you refer to this application from another object, the value you specify here matches the selectors of those other objects.
    • selector.matchExpressions: An additional list of conditional requirements, see this guide. The matchExpressions key itself does not receive a value but introduces other keys.
    • template: Below, you will find a metadata section that looks very similar to the metadata we discussed in the previous paragraph. The only difference is that the aforementioned metadata is passed to the Deployments, and the metadata under 'template' is passed to the Pods. Additionally, the template also contains a spec section, see below.
    • template.metadata template.metadata.labels & template.metadata.labels.app: see 'template' above.
    • template.spec: Somewhat confusing, but the previous key 'spec' in turn has a key called 'spec'. The latter contains all the data related to the pods that are created, for example, regarding the container image used and health checks. Spec, therefore, does not receive a value but introduces other keys.
    • template.spec.containers: This key introduces all the keys that describe the specifications of your containers and does not receive a value itself. All underlying keys that describe containers refer to the specifications of the container, not those of the Node or Pod. Each unique container is introduced with a - .
    • template.spec.containers.name: The name of your container. You are free to choose, but it usually corresponds to the used application, for example, 'nginx' or 'mysql'.
    • template.spec.containers.image: Here you specify which image is used. This can be just the name, for example, 'nginx' or 'mysql', but it can also contain the specific version as follows: image: nginx:1.22.1.
      By default, the official images offered on Dockerhub are used. An overview can be found here. You are free to create Deployments based on any image you find in this overview.
    • template.spec.containers.resources: Optional possibility to specify how many resources such as CPU and RAM a container needs. These specifications have no influence on Pods or Nodes. The resources key itself does not receive a value.
    • template.spec.containers.resources.limits: Introduces the option to set a maximum on the resources used by a container. This key does not receive a value.
    • template.spec.containers.resources.limits.cpu: The maximum amount of CPU a container can use. This can be expressed in absolute numbers (1, 2), tenths (0.1 0.2), or in m/Mi (100m 2000Mi). With a limit of 1, you limit the container to 1 core, with 0.1 or 100m to 100 milicpu, regardless of the number of cores. 1 core = 1000 milicpu so 2000m sets a maximum of 2 cores. For more information, see Kubernetes Resources documentation.
    • template.spec.containers.resources.limits.memory: The maximum amount of memory that a container has at its disposal. This can be expressed in amounts of E, P, T, G, M, k or Ei, Pi, Ti, Gi, Mi, Ki. 100M is, for example, 100 megabytes.
    • template.spec.containers.resources.requests: Optional field to indicate how much resources a container needs at a minimum. The requests key itself does not receive a value.
    • template.spec.containers.resources.requests.cpu: The minimum amount of CPU that a container needs at its disposal. The same options are available as described above under limits.cpu.
    • template.spec.containers.resources.requests.memory: The minimum amount of RAM that a container needs at its disposal. The same options are available as described above under limits.ram.
    • template.spec.containers.ports: The ports key introduces the block in which you configure the port configuration of your container. This only concerns the port used for communication from the Pod itself, not for the Node on which that Pod is running. So you can have multiple Pods on one Node that have the same port configuration in this section. This key does not receive a value. template.spec.containers.ports.containerPort: The port used by the container, for example, 80 for Nginx. By adding multiple containerPort keys, you can define multiple ports, for example, 80 and 443 for HTTP and HTTPS, respectively.
    • template.spec.containers.ports.containerPort: The port used by the container, for example 80 for Nginx. By adding multiple containerPort keys, you can define multiple ports, for example, 80 and 443 for HTTP and HTTPS, respectively. template.spec.containers.ports.containerPort.name: Optionally, you can add a name in quotes, for example, 'http'

      Please note: Below are keys related to volumeMounts and volumes. These are optional; a process in a container automatically sees/gets a filesystem built based on the contents of the container image (which you specify under spec.containers.image). Volumes are options on top of that to mount additional directories in the container. Additional steps are required for this, in addition to the definitions in, for example, a Deployment or Pod object.

      More information on using popular types of volumes such as a Persistent Volume will be added later in a separate tutorial.

    • template.spec.containers.volumeMounts: The volumeMounts key contains an overview of where you mount a volume within a container. The volume itself is a directory on a disk and is defined in spec.volumes, see further down in this overview. The key leads to other keys and does not receive a value itself.
    • template.spec.containers.volumeMounts.mountPath: The folder where the volume specified under spec.volumes is mounted, for example, /data.
    • template.spec.containers.volumeMounts.name: The name of the mounted volume, for example, nginx-persistent-volume. This must match spec.volumes.name, see further in this hierarchy. template.spec.volumes: A volume is a directory on a disk or in another container. The volumes key makes it available to your pod. In turn, (above) the volumeMounts key and underlying structure make the volume available to a container. An overview of all available volume types can be found here.
      Two of the more important volume types are Persistent Volumes and Ephemeral Volumes. The key also does not receive a value.
    • template.spec.volumes.name: The name of the volume you add, for example, 'nginx-persistent-volume'.
    • template.spec.volumes.name.persistentVolumeClaim: In practice, you encounter persistentVolumeClaim the most among the different types of volumes. A Persistent Volume is nothing more than a piece of storage in your Kubernetes cluster that is separate from your Pods (on our platform, this corresponds to the disk space of your node). A persistentVolumeClaim is, in turn, a request to add a portion of that disk space to your object.

     

    Service resources:

     

    Pods are occasionally replaced by new Pods. To ensure that the frontend side does not notice this, you use service resources. A service is a type of policy that allows you to access applications on Pods.

    spec:
      type: 
      externalName: 
      selector:
        app: 
      ports:
      - protocol: 
        port: 
        targetPort: 
    • spec: See the first spec explanation under workload resources (i.e. the previous paragraph).
    • type: An optional component used only in a Service object to describe the type of service, for example 'type: LoadBalancer'.
    • externalName: An optional key used in Services to associate a DNS name with the service, such as nginx.example.com.
    • selector: See the selector explanation under workload resources. selector.app: See the selector.app explanation under workload resources.
    • ports: The ports key directly under the spec key (note the indentation) is actually only used in objects that define a service. You use the ports key and the underlying keys to bind the port(s) of a service to the port(s) of a Pod. The ports key itself does not get a value.
    • ports.protocol: The protocol used by the respective service, such as TCP or UDP.
    • ports.port: The port used by the respective service, such as 80 for Nginx.
    • ports.targetPort: The port configuration in Pods and other workload resources have names, see spec.containers.ports.containerPort.name under workload resources. You refer to this by specifying the exact same name as the targetPort value (see the next paragraph for an example).

    Creating and using an object within your cluster

     

    You have now seen a range of common keys that you may encounter in a Kubernetes .yaml object, but what does it look like when it is filled in, and how do you use it? We will show you using two objects: an Nginx Deployment resource and an Nginx Service resource.

     

    Step 1

    Create a separate yaml file for each object in a directory of your choice, for example, for the Nginx Deployment itself:

    nano nginx/deployment.yaml

    Give the file the following content, where in this example we have not added options that require additional steps.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: nginx-demo
      name: nginx-deployment
      labels:
        app: nginx
      creationTimestamp: 2022-02-12T11:11:11Z
      resourceVersion: "12345"
    spec: 
      replicas: 3
      strategy:
        type: RollingUpdates
      selector: 
        matchLabels:
          app: nginx
      template: 
        metadata:
          labels:
            app: nginx
        spec: 
          containers:
          - name: nginx
            image: nginx:1.22.1
            resources:
              limits: 
                memory: 1G
              requests:
                cpu: 400m
                memory: 1G
            ports: 
            - containerPort: 80

    Save the changes and exit nano with ctrl + x > y > enter.


     

    Step 2

    Next, define the Service object, for example:

    nano nginx/service.yaml

    Give the file the following content:

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
      namespace: nginx-demo
    spec:
      selector:
        app: nginx
      ports:
      - protocol: TCP
        port: 80
        targetPort: nginx

    Save the changes and exit nano with ctrl + x > y > enter.


     

    Step 3

    You can use both configurations in your Kubernetes cluster by applying them:

    kubectl apply -f nginx/deployment.yaml kubectl apply -f nginx/service.yaml

    Note that in order to access your Nginx deployment from outside, you will need to add a load balancer service. We explain how to do this, view the status of your Deployment, Service, and Pods, and how to delete the Deployment and Service in this tutorial.

     

    Need help?

    Receive personal support from our supporters

    Contact us