<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gabriel Tanner</title>
    <description>The latest articles on DEV Community by Gabriel Tanner (@gabrieltanner).</description>
    <link>https://dev.to/gabrieltanner</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F440018%2Ffd309f05-2775-437c-bdc7-d6a7354a1f29.jpg</url>
      <title>DEV Community: Gabriel Tanner</title>
      <link>https://dev.to/gabrieltanner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gabrieltanner"/>
    <language>en</language>
    <item>
      <title>Modern continuous delivery on Kubernetes for developers</title>
      <dc:creator>Gabriel Tanner</dc:creator>
      <pubDate>Tue, 23 Mar 2021 16:19:15 +0000</pubDate>
      <link>https://dev.to/gabrieltanner/modern-continuous-delivery-on-kubernetes-for-developers-5chf</link>
      <guid>https://dev.to/gabrieltanner/modern-continuous-delivery-on-kubernetes-for-developers-5chf</guid>
      <description>&lt;p&gt;Continuous delivery (CD) in a Kubernetes environment has always been a challenging and daunting task to set up and maintain, but it doesn’t have to be this way. Modern tools can make your application development and deployment process as efficient, quick, and sustainable as possible without requiring a lot of configuration.&lt;/p&gt;

&lt;p&gt;Modern tools not only help you with safely getting a new version of your application into production, they also give you the ability to automatically detect and address any problems that arise so you can minimize their impact and provide the best user experience possible.&lt;/p&gt;

&lt;p&gt;By the end of this article, you’ll understand the most essential concepts of modern continuous delivery and have a working Kubernetes deployment with a complete continuous delivery workflow—all without having to write a single line of pipeline code.&lt;/p&gt;

&lt;p&gt;The CD environment you are going to set up will feature a multi-stage environment with two stages for hardening and production and quality gates that will use Prometheus metrics from your application to check whether the deployment is ready to be promoted into production. The workflow is illustrated in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbzcu66fx0thrv07lg63.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbzcu66fx0thrv07lg63.jpg" alt="Multi-stage delivery with quality gates on Kubernetes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you begin, you’ll need the following&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Kubernetes cluster with at least one node with 4 vCPUs and 16 GB of Memory. To create a GKE cluster suitable for deploying the demo, see the &lt;a href="https://keptn.sh/docs/quickstart/" rel="noopener noreferrer"&gt;GKE Quickstart&lt;/a&gt; of Keptn, the open-source tool that you'll be using in this article.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;kubectl&lt;/code&gt; command line tool installed on your development machine and connected to your cluster. You can find out more about installing kubectl in the &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;git&lt;/code&gt; command line tool installed to clone a demo application from GitHub.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Understand the concepts of modern CD
&lt;/h2&gt;

&lt;p&gt;Before setting up an environment, it's crucial that you are familiar with the most essential concepts regarding modern CD.&lt;/p&gt;

&lt;h3&gt;
  
  
  Declarative
&lt;/h3&gt;

&lt;p&gt;Most companies today are still building their continuous delivery workflows in an imperative way. Writing and maintaining pipeline code can be very difficult and may lead to a lot of manual work for developers; this is time they can’t use to develop actual software.&lt;/p&gt;

&lt;p&gt;A declarative approach however allows developers to define what needs to be done and have the CD tool handle the rest. This not only decreases the time required to write and maintain the configuration, it also benefits developers who are already familiar with defining declarative &lt;br&gt;
configurations using tools like Kubernetes and don’t need to learn complicated tooling.&lt;/p&gt;
&lt;h3&gt;
  
  
  Scalable
&lt;/h3&gt;

&lt;p&gt;Another essential factor is how easy it is to add new services to your existing pipeline or declaratively defined project and how much effort it is to maintain these different configurations for your services. Organizations often have hundreds of microservices to be managed and deployed in their pipelines. &lt;/p&gt;

&lt;p&gt;Most imperative pipelines need a lot of boilerplate code to add new services and can therefore quickly become hard to read and maintain. Declarative definitions on the other hand are easily edited without the need to copy boilerplate code. &lt;/p&gt;
&lt;h3&gt;
  
  
  Extensible
&lt;/h3&gt;

&lt;p&gt;Many companies already have a preexisting technology stack, including observability tools like Prometheus or test automation such as Jmeter or Neoload and therefore want to reuse their already implemented functionality in their CD workflow. Modern CD tools allow organizations to use existing tools to integrate with their CD workflow and provide a framework for implementing new custom functionality along with existing functionality. &lt;/p&gt;
&lt;h3&gt;
  
  
  Quality Gates
&lt;/h3&gt;

&lt;p&gt;To ensure the best user experience, applications need a quality check before they can be deployed in a production environment. Quality gates are used to automatically ensure that specifically defined criteria (like response time, error rate, throughput, etc..) are met before deploying your services into production.&lt;/p&gt;

&lt;p&gt;These criteria can be declaratively defined using Site-Reliability Engineering (SRE) concepts such as SLIs (service level indicators) and SLOs (service level objectives).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service-level indicator (SLI)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A service-level indicator is a quantitative measure (metric) of some aspect of your application like response time, error rate or throughput.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service-level objective (SLO):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A service-level objective defines a certain condition using the SLI that must be met to pass the test. An example of this is a response time on a particular endpoint that needs to remain lower than 200 milliseconds or an error rate that must remain lower than 1%.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2 - Our CD orchestrator of choice: Keptn
&lt;/h2&gt;

&lt;p&gt;Now that you’ve established the essential concepts of modern CD, let's look at an orchestrator that is built upon these concepts and makes them accessible and easy to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://keptn.sh" rel="noopener noreferrer"&gt;Keptn&lt;/a&gt; is an open-source cloud-native application life-cycle orchestrator and a &lt;a href="https://www.cncf.io/" rel="noopener noreferrer"&gt;Cloud Native Computing Foundation&lt;/a&gt; (CNCF) project. Keptn uses a declarative approach that allows you to specify DevOps and SRE automation workflows like delivery or operations automation without scripting all the details. The definitions can then be shared across any number of microservices without the need to build individual pipelines and scripts.&lt;/p&gt;

&lt;p&gt;Keptn also includes built-in quality gates based on SRE principles such as SLIs and SLOs that help you evaluate and score your defined criteria to decide if a new version is allowed to be promoted to the next deployment stage or if it has to be held back or even rolled back.&lt;/p&gt;

&lt;p&gt;Moreover, Keptn provides an excellent integration ecosystem where it translates well-defined cloud events into proprietary vendor APIs. The ecosystem already features many integrations for well-known services like JMeter, LitmusChaos, and Prometheus and allows the user to easily add their own integrations. And thanks to its open-source nature, adding new integrations is possible.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3 - Setting up the platform
&lt;/h2&gt;

&lt;p&gt;Now that you know the essential concepts of modern CD and the advantages that modern CD provides—you’re ready to set up Keptn.&lt;/p&gt;

&lt;p&gt;In this section, you will deploy Keptn on your Kubernetes cluster, and connect the cluster to the Keptn CLI (make sure to follow the prerequisites on top of this article).&lt;/p&gt;

&lt;p&gt;Before setting up Keptn on your Kubernetes cluster, you first need to decide how you want to expose Keptn. You can complete the setup using an ingress server, as described in this article, or by using any of the other options mentioned in the &lt;a href="https://keptn.sh/docs/0.8.x/operate/install/" rel="noopener noreferrer"&gt;Keptn documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, you’ll expose via Istio. Therefore, you’ll get started by downloading the Istio installation script from the official website using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://istio.io/downloadIstio | &lt;span class="nv"&gt;ISTIO_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.8.2 sh -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create a folder with the name &lt;code&gt;istio&lt;/code&gt; followed by the downloaded version in your current directory. You can execute the installer by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./istio-1.8.2/bin/istioctl &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer will create all resources needed in your Kubernetes cluster to use Istio including CRD (Custom resource definitions), Configmaps, and more.&lt;/p&gt;

&lt;p&gt;Next, you’ll download and install the Keptn CLI that can be used to install and manage Keptn. &lt;/p&gt;

&lt;p&gt;If you are using Linux or MacOS you can also install the CLI using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://get.keptn.sh | &lt;span class="nv"&gt;KEPTN_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.8.0 bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want, you can also manually download the binary file from &lt;a href="https://github.com/keptn/keptn/releases/" rel="noopener noreferrer"&gt;Github&lt;/a&gt; and install the CLI by moving it into your path.&lt;/p&gt;

&lt;p&gt;You can now validate the installation using the &lt;code&gt;—help&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keptn consists of a control plane and an execution plane. The control plane allows using Keptn for the quality gates and automated operations use cases while the execution plane adds additional functionality, such as continuous delivery capabilities and services to integrate with testing frameworks such as Jmeter. In this case you will install Keptn by using the continuous-delivery use-case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--endpoint-service-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ClusterIP &lt;span class="nt"&gt;--use-case&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;continuous-delivery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The install process usually takes less than 3 minutes and creates all the basic Kubernetes resources needed to run Keptn. You can verify the status using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployments &lt;span class="nt"&gt;-n&lt;/span&gt; keptn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the installation is finished your output should look similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME                                             READY   UP-TO-DATE   AVAILABLE   AGE
api-gateway-nginx                                1/1     1            1           2m44s
api-service                                      1/1     1            1           2m44s
bridge                                           1/1     1            1           2m44s
configuration-service                            1/1     1            1           2m44s
eventbroker-go                                   1/1     1            1           2m44s
gatekeeper-service                               1/1     1            1           2m44s
helm-service                                     1/1     1            1           2m44s
helm-service-continuous-deployment-distributor   1/1     1            1           2m44s
jmeter-service                                   1/1     1            1           2m44s
lighthouse-service                               1/1     1            1           2m44s
mongodb                                          1/1     1            1           2m44s
mongodb-datastore                                1/1     1            1           2m44s
remediation-service                              1/1     1            1           2m44s
shipyard-service                                 1/1     1            1           2m44s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once Keptn is installed the next step is to configure Istio so that you can access your Keptn instance. Istio is used as the Ingress controller that is responsible for the traffic routing to your cluster.&lt;/p&gt;

&lt;p&gt;To make the setup experience as smooth as possible the Keptn team has provided scripts that automatically configure Istio with standard working settings. If you want to customize the setup yourself please take a look at the &lt;a href="https://keptn.sh/docs/0.8.x/operate/install/" rel="noopener noreferrer"&gt;Keptn documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First you will download the configuration script from Github using curl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; configure-istio.sh https://raw.githubusercontent.com/keptn/examples/release-0.8.0/istio-configuration/configure-istio.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run the configuration script using the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x configure-istio.sh
./configure-istio.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now check that the Ingress has been created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get ingress &lt;span class="nt"&gt;-n&lt;/span&gt; keptn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command will output the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME                HOSTS                  ADDRESS         PORTS   AGE
api-keptn-ingress   &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;-Address&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.nip.io   &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;-Address&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;   80      56d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After successfully configuring Istio, you will authenticate your Keptn CLI against the Keptn control-plane you just installed. For that, you need the endpoint of your Keptn API as well as the API token, both of which can be read using kubectl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;KEPTN_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://&lt;span class="si"&gt;$(&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; keptn get ingress api-keptn-ingress &lt;span class="nt"&gt;-ojsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.rules[0].host}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/api
&lt;span class="nv"&gt;KEPTN_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret keptn-api-token &lt;span class="nt"&gt;-n&lt;/span&gt; keptn &lt;span class="nt"&gt;-ojsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.keptn-api-token}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;kubectl get&lt;/code&gt; command uses the &lt;code&gt;-n&lt;/code&gt; flag to set the namespace where the resource is located and the &lt;code&gt;-ojsonpath&lt;/code&gt; flag to specify the variable that should be read in the returned output. The values returned by the commands are saved directly to environment variables.&lt;/p&gt;

&lt;p&gt;Once the values are stored inside the environment variables the following command can be used to authenticate to the Keptn cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn auth &lt;span class="nt"&gt;--endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$KEPTN_ENDPOINT&lt;/span&gt; &lt;span class="nt"&gt;--api-token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$KEPTN_API_TOKEN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the CLI is successfully authenticated with the Keptn cluster you'll receive output similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Starting to authenticate
Successfully authenticated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4 - Create CD resources and deploy the application
&lt;/h2&gt;

&lt;p&gt;Now that you’ve successfully set up Keptn on your Kubernetes cluster, you'll continue by creating a simple HTTP server application and create all the CD resources necessary to deploy the application using Keptn. We’re going to use a demo application provided by the Cloud-Native Computing Foundation (CNCF) that has been built to showcase different deployment/delivery tool capabilities.&lt;/p&gt;

&lt;p&gt;First, you’ll clone the project's repository, so you have all the resources needed to start deploying your application on Kubernetes using Keptn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/cncf/podtato-head.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will clone the podtato-head repository from Github and create a folder with the name of &lt;code&gt;podtato-head&lt;/code&gt; in your directory. Now you can continue by opening the project in your favorite code editor. You can then find the application in the &lt;code&gt;podtato-server&lt;/code&gt; folder of the repository.&lt;/p&gt;

&lt;p&gt;The application is already dockerized with a Dockerfile and a bash utility file that helps you push different versions of the Docker images onto a registry. &lt;/p&gt;

&lt;p&gt;The registry images will now be used to create the Helm chart that is used to deploy the application on Kubernetes. The Helm chart consists of few files and can be found under &lt;code&gt;delivery&amp;gt;keptn&amp;gt;helm-charts&amp;gt;helloserver&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chart.yaml - This file contains all the chart information, including the name, version number, etc.&lt;/li&gt;
&lt;li&gt;values.yaml - This file is used to define the values that you want to inject into your templates.&lt;/li&gt;
&lt;li&gt;Templates - This is the folder where you store the actual manifests that are deployed with the chart. This example only contains a deployment and service file for the application, but it could also include more Kubernetes configurations like configmaps, secrets, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The manifest of the deployment resource looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloservice
  namespace: &lt;span class="o"&gt;{{&lt;/span&gt; .Release.Namespace &lt;span class="o"&gt;}}&lt;/span&gt; 
spec:
  replicas: &lt;span class="o"&gt;{{&lt;/span&gt; .Values.replicaCount &lt;span class="o"&gt;}}&lt;/span&gt;
  selector:
    matchLabels:
      app: helloservice
  template:
    metadata:
      labels:
        app: helloservice
    spec:
      terminationGracePeriodSeconds: 5
      containers:
      - name: server
        image: &lt;span class="o"&gt;{{&lt;/span&gt; .Values.image&lt;span class="o"&gt;}}&lt;/span&gt;
        imagePullPolicy: Always
        ports:
        - containerPort: 9000
        &lt;span class="nb"&gt;env&lt;/span&gt;:
        - name: PORT
          value: &lt;span class="s2"&gt;"9000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The spec section defines your deployment's desired state containing information like the replica count and information about the created container. Kubernetes then attempts to create the desired state and take action to keep that state if something changes.&lt;/p&gt;

&lt;p&gt;The spec.template key defines the rules that Kubernetes will use to create your pod. Here you define the pods deployment's specifics like the image name, pull policy, and container ports.&lt;/p&gt;

&lt;p&gt;Next, let's look at the Kubernetes service file, which exposes port 9000 of your pod on port 80 of the Kubernetes worker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: helloservice
  namespace: &lt;span class="o"&gt;{{&lt;/span&gt; .Release.Namespace &lt;span class="o"&gt;}}&lt;/span&gt; 
spec:
  selector:
    app: helloservice
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 9000
  &lt;span class="nb"&gt;type&lt;/span&gt;: ClusterIP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that all the Helm and Kubernetes resources are defined, you can continue by creating a Keptn shipyard definition. The shipyard defines a task sequence for the delivery of your application. It can hold multiple dedicated stages, each with a different deployment-, test- and remediation strategy.&lt;/p&gt;

&lt;p&gt;Thanks to the shipyard declarative approach, there is no need to write any imperative pipeline code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: &lt;span class="s2"&gt;"spec.keptn.sh/0.2.0"&lt;/span&gt;
kind: &lt;span class="s2"&gt;"Shipyard"&lt;/span&gt;
metadata:
  name: &lt;span class="s2"&gt;"shipyard-sockshop"&lt;/span&gt;
spec:
  stages:
    - name: &lt;span class="s2"&gt;"hardening"&lt;/span&gt;
      sequences:
        - name: &lt;span class="s2"&gt;"delivery"&lt;/span&gt;
          tasks:
            - name: &lt;span class="s2"&gt;"deployment"&lt;/span&gt;
              properties:
                deploymentstrategy: &lt;span class="s2"&gt;"blue_green_service"&lt;/span&gt;
            - name: &lt;span class="s2"&gt;"test"&lt;/span&gt;
              properties:
                teststrategy: &lt;span class="s2"&gt;"performance"&lt;/span&gt;
            - name: &lt;span class="s2"&gt;"evaluation"&lt;/span&gt;
            - name: &lt;span class="s2"&gt;"release"&lt;/span&gt;
    - name: &lt;span class="s2"&gt;"production"&lt;/span&gt;
      sequences:
        - name: &lt;span class="s2"&gt;"delivery"&lt;/span&gt;
          triggeredOn:
            - event: &lt;span class="s2"&gt;"hardening.delivery.finished"&lt;/span&gt;
          tasks:
            - name: &lt;span class="s2"&gt;"deployment"&lt;/span&gt;
              properties:
                deploymentstrategy: &lt;span class="s2"&gt;"blue_green_service"&lt;/span&gt;
            - name: &lt;span class="s2"&gt;"release"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the file, you are going to create a multi-stage environment with a hardening and a production stage. Keptn performs a blue/green deployment (i.e., two deployments simultaneously with routing of traffic to only one deployment) and triggers a performance test in the hardening stage. Once the tests complete successfully, the deployment moves into the production stage using another blue/green deployment. Note that the tooling definition (such as which testing tool is executing the tests) is not part of the shipyard file; this is defined as part of the Keptn uniform. In this example, you will use the standard tooling that comes with the default Keptn installation.&lt;/p&gt;

&lt;p&gt;Now that you’ve defined the shipyard file, it is time to create your first Keptn project using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;podtato-head/delivery/keptn

keptn create project pod-tato-head &lt;span class="nt"&gt;--shipyard&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./shipyard.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the project is created, you can continue by onboarding helloserver as a service to your project using the &lt;code&gt;keptn onboard service&lt;/code&gt; command and passing the project you want to onboard the service to as well as the Helm chart of the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn onboard service helloservice &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pod-tato-head"&lt;/span&gt; &lt;span class="nt"&gt;--chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helm-charts/helloserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now take a look at the project you just created using the Keptn's Bridge, which is the UI of Keptn. You can find the generated access credentials using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn configure bridge &lt;span class="nt"&gt;--output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now use the credentials and the URL of the following command to access the Keptn's Bridge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;http://&lt;span class="si"&gt;$(&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; keptn get ingress api-keptn-ingress &lt;span class="nt"&gt;-ojsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.rules[0].host}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have successfully signed into the account you should see the following UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuslg3pgmdl5890sh6r3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuslg3pgmdl5890sh6r3.png" alt="Keptn Bridge"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you have created a project and onboarded a service you can continue by deploying your first artifact using the &lt;code&gt;keptn trigger delivery&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn trigger delivery &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pod-tato-head"&lt;/span&gt; &lt;span class="nt"&gt;--service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helloservice &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gabrieltanner/hello-server"&lt;/span&gt; &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v0.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you need to provide the project and service name as well as the image you want to deploy as your artifact.&lt;/p&gt;

&lt;p&gt;After deploying you can go back to the Keptn Bridge to see the event that has been generated for your artifact.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh30b79i5ksovgr0ue4gs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh30b79i5ksovgr0ue4gs.png" alt="Keptn Bridge artifact"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also verify the status of your pods using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;helloservice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This usually takes a couple of minutes, so just refresh until your output reflects something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pod-tato-head-hardening    helloservice-primary-5f779966f9-vjjh4                        2/2     Running   0          4m55s
pod-tato-head-production   helloservice-primary-5f779966f9-kbhz5                        2/2     Running   0          2m52s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the pods are running you can view your service using the URL you get from the following command or visit it over the Keptn Bridge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;http://helloservice.pod-tato-head-hardening.&lt;span class="si"&gt;$(&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; keptn get ingress api-keptn-ingress &lt;span class="nt"&gt;-ojsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.rules[0].host}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should than see a page similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijru1hq2l3fmft9bz4a4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijru1hq2l3fmft9bz4a4.png" alt="Podtatohead deployment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have now successfully deployed your first service on Keptn in a multi-stage delivery without writing a single line of pipeline code. Next, you will add Quality Gates to your project to automatically ensure that specific defined criteria are met before deploying the service into production. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 – Add quality gates to CD
&lt;/h2&gt;

&lt;p&gt;Now that you’ve successfully deployed your application on Kubernetes using Keptn it’s time to add quality gate functionality to ensure that your application is working correctly before it’s deployed to production.&lt;/p&gt;

&lt;p&gt;The application already exposes the following custom Prometheus metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;http_requests_total&lt;/code&gt; - Total number of HTTP request on each site&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;http_server_request_duration_seconds_sum&lt;/code&gt; - Sum of the duration of all HTTP request for each page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;go_routines&lt;/code&gt; - The number of currently running Goroutines&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;request throughput&lt;/code&gt; - The throughput is the number of requests that are successfully executed per time unit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These metrics can now be used to define custom metrics in your SLI file using Prometheus syntax. For example, you define the &lt;code&gt;request_throughput&lt;/code&gt; as the sum of successful requests (200 status code) in a specific time period specified by the &lt;code&gt;$DURATION_SECONDS&lt;/code&gt; environment variable that Keptn automatically sets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;spec_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.0'&lt;/span&gt;
&lt;span class="na"&gt;indicators&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;http_response_time_seconds_main_page_sum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum(rate(http_server_request_duration_seconds_sum{method="GET",route="/",status_code="200",job="$SERVICE-$PROJECT-$STAGE-canary"}[$DURATION_SECONDS])/rate(http_server_request_duration_seconds_count{method="GET",route="/",status_code="200",job="$SERVICE-$PROJECT-$STAGE-canary"}[$DURATION_SECONDS]))&lt;/span&gt;
  &lt;span class="na"&gt;http_requests_total_sucess&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http_requests_total{status="success"}&lt;/span&gt;
  &lt;span class="na"&gt;go_routines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go_goroutines{job="$SERVICE-$PROJECT-$STAGE"}&lt;/span&gt;
  &lt;span class="na"&gt;request_throughput&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum(rate(http_requests_total{status="success"}[$DURATION_SECONDS]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you can define conditions that your SLIs need to meet in order for the deployment to pass the test and be promoted into the next stage. &lt;/p&gt;

&lt;p&gt;The following SLO file holds three objectives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The response time on the main page needs to be less than or equal to 1 second.&lt;/li&gt;
&lt;li&gt;The percentage of successful requests must be between 80% and 100%.&lt;/li&gt;
&lt;li&gt;There can be no more than 20 concurrent Goroutines running.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If all three criteria are satisfied, this objective is fulfilled and receives the full score.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;spec_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.1.0'&lt;/span&gt;
&lt;span class="na"&gt;comparison&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;compare_with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;single_result"&lt;/span&gt;
  &lt;span class="na"&gt;include_result_with_score&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pass"&lt;/span&gt;
  &lt;span class="na"&gt;aggregate_function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;avg&lt;/span&gt;
&lt;span class="na"&gt;objectives&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;sli&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http_response_time_seconds_main_page_sum&lt;/span&gt;
    &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;criteria&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;=1"&lt;/span&gt;
    &lt;span class="na"&gt;warning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;criteria&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;=0.5"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;sli&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;request_throughput&lt;/span&gt;
    &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;criteria&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;=+100%"&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=-80%"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;sli&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go_routines&lt;/span&gt;
    &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;criteria&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;=100"&lt;/span&gt;
&lt;span class="na"&gt;total_score&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;90%"&lt;/span&gt;
  &lt;span class="na"&gt;warning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;75%"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you can use the SLI and SLO files, you need to configure Prometheus monitoring for your Keptn project. You can install the official Keptn Prometheus service using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/keptn-contrib/prometheus-service/release-0.4.0/deploy/service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you’ll set up the Prometheus Alerting Manager rules using the &lt;code&gt;keptn configure monitoring&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn configure monitoring prometheus &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pod-tato-head &lt;span class="nt"&gt;--service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helloservice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prometheus has now automatically set up scrape jobs for your application. Now that you’re scraping the metrics using Prometheus you also need to install the Prometheus SLI service, which will fetch the values for the SLIs referenced in an SLO configuration file during the build evaluation process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/keptn-contrib/prometheus-sli-service/release-0.3.0/deploy/service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that all services are set up correctly you can add the SLI and SLO files as resources to your Keptn project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn add-resource &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pod-tato-head &lt;span class="nt"&gt;--stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hardening &lt;span class="nt"&gt;--service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helloservice &lt;span class="nt"&gt;--resource&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prometheus/sli.yaml &lt;span class="nt"&gt;--resourceUri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prometheus/sli.yaml

keptn add-resource &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pod-tato-head &lt;span class="nt"&gt;--stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hardening &lt;span class="nt"&gt;--service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helloservice &lt;span class="nt"&gt;--resource&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;slo.yaml &lt;span class="nt"&gt;--resourceUri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;slo.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s also useful to generate some traffic to the endpoint of your application when running the tests. This can be done using the already defined JMeter files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn add-resource &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pod-tato-head &lt;span class="nt"&gt;--stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hardening &lt;span class="nt"&gt;--service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helloservice &lt;span class="nt"&gt;--resource&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jmeter/load.jmx &lt;span class="nt"&gt;--resourceUri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jmeter/load.jmx
keptn add-resource &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pod-tato-head &lt;span class="nt"&gt;--stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hardening &lt;span class="nt"&gt;--service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helloservice &lt;span class="nt"&gt;--resource&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jmeter/jmeter.conf.yaml &lt;span class="nt"&gt;--resourceUri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jmeter/jmeter.conf.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you now deploy the same artifact as before all the tests will be executed before promoting the deployment to the production stage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn trigger delivery &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pod-tato-head"&lt;/span&gt; &lt;span class="nt"&gt;--service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helloservice &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gabrieltanner/hello-server"&lt;/span&gt; &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v0.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After sending the artifact you can see the test results in Keptn Bridge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy37gumjg61ux3md832c0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy37gumjg61ux3md832c0.png" alt="Keptn Quality Gates"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the test cases defined in the SLO file have passed and the deployment has been promoted to production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 – Validate the quality gates
&lt;/h2&gt;

&lt;p&gt;Now that you’re working with quality gates, it’s time to validate that they are working by intentionally deploying a slow build that should fail the success criteria that you defined in the last step. The &lt;code&gt;pod-tato-head&lt;/code&gt; application already has a slow build version implemented (v0.1.2) where every request is delayed by 2 seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keptn trigger delivery &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pod-tato-head"&lt;/span&gt; &lt;span class="nt"&gt;--service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helloservice &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gabrieltanner/hello-server"&lt;/span&gt; &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v0.1.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After sending the artifact you can see the test results in Keptn Bridge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp85mqgpxswha0u81w731.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp85mqgpxswha0u81w731.png" alt="Keptn quality gates failing build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can see that some of your defined test cases (for example, the response time) failed because you deployed a slow build that is not suitable for production. Once the test fails, the deployment will not be promoted to production and the hardening stage will return to its original state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, you configured Keptn, deployed your own application, and automatically validated the functionality without writing a single line of pipeline code. You also learned useful terminology and became familiar with the essential concepts of modern CD. &lt;/p&gt;

&lt;p&gt;If you’re interested in learning more, consider checking out the official &lt;a href="https://keptn.sh/" rel="noopener noreferrer"&gt;Keptn website&lt;/a&gt; or join the &lt;a href="https://slack.keptn.sh/" rel="noopener noreferrer"&gt;Slack community&lt;/a&gt;. Also, if you have any questions, feel free to post them in the comments and I will do my best to answer them.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>An Introduction to testing in Javascript</title>
      <dc:creator>Gabriel Tanner</dc:creator>
      <pubDate>Tue, 01 Sep 2020 07:44:17 +0000</pubDate>
      <link>https://dev.to/gabrieltanner/an-introduction-to-testing-in-javascript-54jc</link>
      <guid>https://dev.to/gabrieltanner/an-introduction-to-testing-in-javascript-54jc</guid>
      <description>&lt;p&gt;Today, we are going to discuss testing in Javascript and help you in starting your journey towards understanding and mastering it.&lt;/p&gt;

&lt;p&gt;Testing is one of the most important topics in software development, but a lot of developers still shy away from it. This article is here to change that.&lt;/p&gt;

&lt;p&gt;The primary motivation behind this article is to give a clear overview of the entire world of Javascript testing and making it simple to understand. Even if you have no prior experience in testing, this article will prove to be the perfect start for your journey.&lt;/p&gt;

&lt;p&gt;So, without wasting any further time, let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why testing is important
&lt;/h2&gt;

&lt;p&gt;Before diving into the various types and concepts of software testing, you should first have a clear understanding of why you should actually care about automated testing in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Confidence In Your Code:
&lt;/h3&gt;

&lt;p&gt;To know that your code is working as planned, it needs to be tested in some kind. Manual test work for most small applications but don't provide the security and confidence level you get using automated tests.&lt;/p&gt;

&lt;p&gt;Automated tests make it easy to test almost every possible situation and allow you to run them whenever you are making a change to your code.&lt;/p&gt;

&lt;p&gt;Identifying every success and failure case and writing tests for them will ensure that you are confident with the code you are deploying for production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Minimal Code:
&lt;/h3&gt;

&lt;p&gt;Testing also helps you to reduce the amount of code you are writing for a particular feature. After testing, your main goal is to write the minimal required code to make the tests pass. This coding style where you write tests before you write the actual implementation is also known as TDD (Test-driven development).&lt;/p&gt;

&lt;p&gt;After successfully testing, you can focus on writing clean implementations with as minimal code as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Rid Of Regression Bugs:
&lt;/h3&gt;

&lt;p&gt;Do you know the feeling when you have just finished a new feature of your application and want to release it to production and all of a sudden, an old feature isn't working anymore? You are absolutely clueless about why this is happening and will probably waste a lot of time searching for the issue.&lt;/p&gt;

&lt;p&gt;This situation would have never occurred if you had tested your old features. You could have frequently run those tests to check if your application is still working as expected. The tests would also give you a better idea of what exactly isn't working anymore because the appropriate test cases would fail. &lt;/p&gt;

&lt;h2&gt;
  
  
  Types of tests
&lt;/h2&gt;

&lt;p&gt;There are a few different types of tests, and it is essential to know how they differ from each other. Most applications will require you to write multiple kinds of tests to get the best result possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unit tests:
&lt;/h3&gt;

&lt;p&gt;The purpose of a unit test is to validate the functionality of a relatively small piece of software, independently from other parts. Unit tests are narrow in scope, which allows us to cover all cases to ensure that every single part works correctly.&lt;/p&gt;

&lt;p&gt;They are small and highly focused tests that can efficiently be executed on your local machine because of their fast execution time. You are going to have hundreds, if not thousands of these tests and run them on a regular basis while developing.&lt;/p&gt;

&lt;p&gt;The only downside to these kinds of tests is that they are not executed on real devices and therefore have lower fidelity than the other types of tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration tests:
&lt;/h3&gt;

&lt;p&gt;Integration tests demonstrate that the different parts of your application work together in a real-life production environment. They verify that two separate modules or components are working together in the way they should.&lt;/p&gt;

&lt;p&gt;These tests are of medium size and have a much higher execution time then Unit tests. They aren't executed as often but are still vital for checking the health status of your applications. Their fidelity is also a lot higher because they run on real devices and verify the actual interaction between various components of your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  End-to-End tests:
&lt;/h3&gt;

&lt;p&gt;End-to-End tests validate complex scenarios from end to end, and usually require external resources, like databases or web servers, to be present. Imagine you have an application with a sign-up flow comprising of several steps, and you want to test the entire flow, that’s where End-to-End tests come into play.&lt;/p&gt;

&lt;p&gt;E2E tests will also run on real devices just like integration tests and therefore, will again be quite slow in their execution.&lt;/p&gt;

&lt;p&gt;The only downside to these kinds of tests is that debugging them and finding out what went wrong if a particular test fails becomes very hard because of their vast scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concepts
&lt;/h2&gt;

&lt;p&gt;Before starting to write tests for your code, you first need to be familiar with the most crucial testing concepts and when you need to use them. These concepts will influence the architecture of your application and how you write code in general but more on that in a later section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Matchers:
&lt;/h3&gt;

&lt;p&gt;Matchers let you validate the results and values of your tests in different ways and are used to make sure that the results of the test match your expectations.&lt;/p&gt;

&lt;p&gt;Imagine you have a function that calculates the result of a certain factorial number. Testing the function can then be done using the expect() function and a simple matcher that checks if the result of the function matches the expected value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;factorial of 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;expect()&lt;/code&gt; function checks if the result meets the conditions defined by the matcher. We will make use of different matchers in the Jest testing framework at a later point in this guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mocking:
&lt;/h3&gt;

&lt;p&gt;An object under a test might have dependencies on other objects or services. To isolate the behavior of an object, you want to replace the other objects it interacts with by mocks that simulate the behavior of the real objects.&lt;/p&gt;

&lt;p&gt;Mocks help your tests to avoid test unreliability (flakiness) and improve the speed of your tests. They are also useful if the real objects are impractical to incorporate into tests.&lt;/p&gt;

&lt;p&gt;In short, mocking is creating objects or services that simulate the behavior of real objects (A database, for example).&lt;/p&gt;

&lt;h3&gt;
  
  
  Lifecycle:
&lt;/h3&gt;

&lt;p&gt;When testing, you often execute multiple tests after each other and have some setup work that needs to happen before the tests run. Most frameworks provide helper functions to handle these scenarios.&lt;/p&gt;

&lt;p&gt;Here is an example of lifecycle methods in the Jest testing framework.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Initialize objects&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Tear down objects&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Testable architecture
&lt;/h2&gt;

&lt;p&gt;Before starting to write tests for your code, you first need to make sure that your application's architecture is testable. If it is not, you need to understand why not and what you can do about it.&lt;/p&gt;

&lt;p&gt;Untestable architecture is probably the most common reason why many people find testing tedious and difficult. If your code is not structured properly, you are definitely going to find it difficult to write tests for it.&lt;/p&gt;

&lt;p&gt;Let's explore some important concepts you should know when talking about testable architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency injection:
&lt;/h3&gt;

&lt;p&gt;Dependency injection is a concept where an object supplies the dependencies of another object. Instead of using the new keyword whenever creating a new object, all you need to do is ask the other object to give you the instance you want.&lt;/p&gt;

&lt;p&gt;This concept helps when you need to change the implementation of some object, e.g. when you mock it for a particular test. Many modern frameworks like Angular and Nest.js have dependency injection already build in, but it is still good to know how it functions at a base level.&lt;/p&gt;

&lt;p&gt;For more information on dependency injection, you can visit the &lt;a href="https://www.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it-7578c84fa88f/"&gt;following article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SRP (Single responsibility principle):
&lt;/h3&gt;

&lt;p&gt;The single responsibility principle, also known as SRP, is one of the &lt;a href="https://scotch.io/bar-talk/s-o-l-i-d-the-first-five-principles-of-object-oriented-design"&gt;SOLID principles&lt;/a&gt; and defines that a function should have a single purpose. This makes it far easier to test that each function does its part correctly.&lt;/p&gt;

&lt;p&gt;If your function or service is performing more than one responsibility, then it is time to identify those responsibilities and separate them into individual functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid side effects:
&lt;/h3&gt;

&lt;p&gt;Your functions depend on external variables and services, and you have to set up that variable or service before testing your function. You’ll also have to trust that any other code being run isn’t altering that same variables and states.&lt;/p&gt;

&lt;p&gt;That is why you should avoid writing functions that alter any external state (like writing to a file or saving values to a database). This prevents side effects and allows you to test your code with confidence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Law of Demeter:
&lt;/h3&gt;

&lt;p&gt;The Law of Demeter, which is also known as the “principle of least knowledge” states that a specific unit should have limited knowledge of the other units it coordinates with. The more your code depends on the internal details of the objects it interacts with, the more difficulty you will have when writing tests for them.&lt;/p&gt;

&lt;p&gt;More information about the Law of Demeter can be found &lt;a href="https://dzone.com/articles/the-genius-of-the-law-of-demeter"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the different testing tools
&lt;/h2&gt;

&lt;p&gt;Now that you have an overview of the essential concepts in the testing world and when you need to use them, let's continue by looking at a short summary of the different Javascript testing tools that are available today.&lt;/p&gt;

&lt;p&gt;Note: I will not cover every tool there is but instead look at the most important once to give you a quick overview of there benefits and weaknesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt;:
&lt;/h3&gt;

&lt;p&gt;Jest is an open-source testing framework created by Facebook with a focus on simplicity. Jest makes it faster and easier to write JavaScript tests by having everything included out of the box and needing zero configuration. Jest also runs your tests in parallel, providing a smoother, faster test run.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://mochajs.org/"&gt;Mocha&lt;/a&gt;:
&lt;/h3&gt;

&lt;p&gt;Mocha is a flexible JavaScript testing libraries available and aims to make asynchronous testing simple and fun. It provides developers with a basic test framework and gives them the option to choose which assertion, mocking, and spy libraries they want to use.&lt;/p&gt;

&lt;p&gt;It requires some additional setup and configuration but gives you complete control of your testing framework in return.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.cypress.io/"&gt;Cypress&lt;/a&gt;:
&lt;/h3&gt;

&lt;p&gt;Cypress is an all in one testing tool that is focused on making End-to-End testing easy and modern. Their tests are executed in the browser themself which gives them a better execution time and no network lag.&lt;/p&gt;

&lt;p&gt;Cypress is used to deal with complex UI’s running on modern Javascript stacks. By using their framework and assertion library, it becomes easy to validate states in the UI. Cypress will then automatically wait for your application to reach this state before moving on.&lt;/p&gt;

&lt;p&gt;Cypress is a newer and more modern tool than Jest and Mocha and is an excellent start for beginners and End-to-End testing in general.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Jest
&lt;/h2&gt;

&lt;p&gt;As already mentioned above, this guide will focus on the Jest testing framework because it is the most popular framework out there. But most of the concepts apply to all testing frameworks and can be useful no matter which technology you are using.&lt;/p&gt;

&lt;p&gt;Jest is an open-source project maintained by Facebook and is especially well suited for Unit and Integration testing. Its strengths are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is simplistic and fast&lt;/li&gt;
&lt;li&gt;It provides everything out of the box and thereby doesn't require and configuration (though you can change the configuration if you so choose)&lt;/li&gt;
&lt;li&gt;It can perform snapshot testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we will explore some practical examples so you can put your knowledge into practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Jest can be installed using either npm or yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; jest
&lt;span class="c"&gt;# or&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that this will install Jest as a dev dependency as part of your package.json file in the current project. You can alternatively install it globally if you so choose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn global add jest
&lt;span class="c"&gt;# or&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;jest &lt;span class="nt"&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can also add this line to your package.json to run your test using the test command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Your first test
&lt;/h3&gt;

&lt;p&gt;Now that we have installed Jest it is finally time to write our first test. But before we do that, we will write some basic code that we can test in the first place.&lt;/p&gt;

&lt;p&gt;For that, we will create two files so we can get going.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;maths.js
&lt;span class="nb"&gt;touch &lt;/span&gt;maths.spec.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We will use the following function for calculating a factorial number to write our first test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;factorialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;factorialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;factorialize&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here are some very basic test cases for this small function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;factorialize&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./maths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;factorial of 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factorialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;factorial of 5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factorialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Running the yarn test command in your terminal should give you the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ofg3F7tV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uqe60sjicjhbiqhzf77z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ofg3F7tV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uqe60sjicjhbiqhzf77z.png" alt="Javascript factorial test results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Matchers
&lt;/h3&gt;

&lt;p&gt;As already said above matchers let you validate the results and values of your tests in different ways.&lt;/p&gt;

&lt;p&gt;They are most commonly used to compare the result of the expect() function to the value passed as an argument to the matcher (That is also what we did above).&lt;/p&gt;

&lt;p&gt;Here is a list of the most common matchers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;toBe -  compares for strict equality (e.g. ===)&lt;/li&gt;
&lt;li&gt;toEqual - compares the values of two variables/objects&lt;/li&gt;
&lt;li&gt;toBeNull - checks if the value is null&lt;/li&gt;
&lt;li&gt;toBeDefined - checks if the value is defined&lt;/li&gt;
&lt;li&gt;toBeUndefined - checks if the value is undefined&lt;/li&gt;
&lt;li&gt;toBeTruthy - checks if the value is true (similar to an if statement)&lt;/li&gt;
&lt;li&gt;toBeFalsy - checks if the value is false(similar to an if statement)&lt;/li&gt;
&lt;li&gt;toBeGreaterThan - checks if the result of the expect() function is greater than the argument&lt;/li&gt;
&lt;li&gt;toContain - checks if the result of expect() contains a value&lt;/li&gt;
&lt;li&gt;toHaveProperty -  checks if an object has a property, and optionally checks its value&lt;/li&gt;
&lt;li&gt;toBeInstanceOf - checks if an object is an instance of a class&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These matchers can also be negated using the not statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;factorial of 3 is not 5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factorialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can also use &lt;a href="https://github.com/jest-community/jest-extended"&gt;additional matchers&lt;/a&gt; that are maintained by the Jest community.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup and Teardown
&lt;/h3&gt;

&lt;p&gt;Often when writing tests, you will have to do some kind of setup like initializing variables before tests run and some sort of action after they have finished.&lt;/p&gt;

&lt;p&gt;Jest provides two different ways you can do that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One-Time Setup:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In some cases, you only need to do the setup once, at the beginning of your test file. In that scenario, you can use the &lt;code&gt;beforeAll()&lt;/code&gt; and &lt;code&gt;afterAll()&lt;/code&gt; helper functions that will execute before the tests start and after all have finished.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;initializeDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;clearDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query from database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Florida&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBeTruthy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Repeating setup for each test:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have a setup process that needs to run before each test then you should use the beforeEach() and afterEach() functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;initializeDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;clearDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query from database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Florida&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBeTruthy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note: There will be scenarios where you will use both of these setup processes together to get the best results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grouping tests
&lt;/h3&gt;

&lt;p&gt;You can also group related tests together so you can isolate the setup and teardown functions. Grouping tests will also help you get a better overview of your different test cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testing factorial function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//do something&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nx"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//do something&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;factorial of 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factorialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;factorial of 5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factorialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;factorial of 3 is not 5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factorialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing async functions
&lt;/h2&gt;

&lt;p&gt;It is common for Javascript code to run asynchronously using either promises or callbacks. The problem with testing asynchronous code is knowing when the code that you are testing is actually complete. Jest has several ways to handle this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Promises:
&lt;/h3&gt;

&lt;p&gt;Testing promises is straight forward in Jest. Just return the promise and Jest will wait for the promise to resolve. If the promise fails, the test will automatically fail aswell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// string.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reverseString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Empty string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reverseString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// string.spec.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reverseString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`reverseString 'String' to equal 'gnirtS'`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;reverseString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gnirtS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can also catch rejected promises using the catch() function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`reverseString '' to reject promise`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;reverseString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Empty string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Async await:
&lt;/h3&gt;

&lt;p&gt;Alternatively, we can use async and await for testing promises.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reverseString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`reverseString 'String' to equal 'gnirtS' using await`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reverseString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gnirtS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note: You need to make your testing function async to use async and await.&lt;/p&gt;

&lt;h3&gt;
  
  
  Callbacks:
&lt;/h3&gt;

&lt;p&gt;By default Jest tests complete once they reach the end of their execution which means that the test will be completed before the callback is called. This can be fixed by passing a single argument named done to your test function. Jest will wait until the done callback is called before finishing the test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// string.js&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;reverseStringCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;reverseStringCallback&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// string.spec.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;reverseStringCallback&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`reverseStringCallback 'string' to equal 'gnirts'`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;reverseStringCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gnirts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;done()&lt;/code&gt; is never called, the test will fail with a timeout error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mocking
&lt;/h2&gt;

&lt;p&gt;Mocking is creating objects or services that simulate the behavior of real objects and plays a vital part in testing. The goal for mocking an object or function is to replace something we don’t control like an external service with something we do, that is why it’s essential that what we replace it with something that has all the features we need.&lt;/p&gt;

&lt;p&gt;Using mocks also helps you to inspect information about your code e.g. if a function has already be called and which parameters were used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Passing Mocks to functions:
&lt;/h3&gt;

&lt;p&gt;One of the common ways to use the Mock function is by passing it as an argument to the function you are testing. This allows you to run your tests without importing the real dependencies and objects you would pass in your real application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multiplyNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calls callback with arguments added&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockCallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;multiplyNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mockCallback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockCallback&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This strategy is great but requires that your code supports dependency injection. If that is not the case you will need to mock already existing modules or functions instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mocking a single function:
&lt;/h3&gt;

&lt;p&gt;You can mock a single function using Jest.fn():&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lodash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Test lodash chunk function`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here I create a mock of the &lt;a href="https://lodash.com/docs/4.17.15#chunk"&gt;lodash.chunk&lt;/a&gt; function and test if it gets called and if the parameters are right.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mocking Modules:
&lt;/h3&gt;

&lt;p&gt;Mocking single functions works well if you only use one or two functions of a package or library but can get very cluttered when you need more functions of a module. Here we use jest.mock to automatically set the exports of an entire module instead of mocking the modules manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Test lodash chunk function`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;concatResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see I can now call all functions of the lodash library as mock objects.&lt;/p&gt;

&lt;p&gt;The only disadvantage of this strategy is that it is difficult to access the original implementation of the module. For those use cases, you can use the &lt;code&gt;spyOn&lt;/code&gt; function instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spying packages:
&lt;/h3&gt;

&lt;p&gt;You can also spy on a package without creating a mock for it. This is done using the spyOn() function provided by Jest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lodash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Test lodash chunk function`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chunk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lodash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Important things you should look at
&lt;/h2&gt;

&lt;p&gt;There are a few more concepts you should definitely look at on your way to mastering testing in Javascript. But I would greatly recommend learning the basics first and putting them into practice in your applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://jestjs.io/docs/en/snapshot-testing"&gt;Snapshot testing&lt;/a&gt; - Is used for testing the UI of your application&lt;/li&gt;
&lt;li&gt;CI (Continous Integration) - The practice of automating the integration of code changes from multiple contributors into a single software project&lt;/li&gt;
&lt;li&gt;CD (Continous Deployment) - Is a software release process that uses automated testing to validate if changes to a codebase are correct&lt;/li&gt;
&lt;li&gt;Automated dependency updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is vital to practice testing in your own applications. If you do it long enough, then you will master the art of testing and make your applications more stable and secure in the process.&lt;/p&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;p&gt;Here is a list of the sources I used for this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jestjs.io/"&gt;Official Jest documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flaviocopes.com/jest/#introduction-to-jest"&gt;Introduction to Jest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.aritraroy.in/understanding-and-mastering-the-world-of-android-testing-part-1-32f6a1a06d3b"&gt;Understanding and mastering testing in Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/goldbergyoni/javascript-testing-best-practices"&gt;Testing best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@rickhanlonii/understanding-jest-mocks-f0046c68e53c"&gt;Understanding Jest Mocks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You made it all the way until the end! I hope that this article helped you understand the basics of automated testing in Javascript.&lt;/p&gt;

&lt;p&gt;If you have found this useful, please consider recommending and sharing it with other fellow developers. If you have any questions or feedback, let me know using my contact form or contact me on &lt;a href="https://twitter.com/GabrielTanner14"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>The Definitive Guide to Kubernetes</title>
      <dc:creator>Gabriel Tanner</dc:creator>
      <pubDate>Sat, 25 Jul 2020 07:31:41 +0000</pubDate>
      <link>https://dev.to/gabrieltanner/the-definitive-guide-to-kubernetes-21d7</link>
      <guid>https://dev.to/gabrieltanner/the-definitive-guide-to-kubernetes-21d7</guid>
      <description>&lt;p&gt;In this guide, you will learn everything you need to know about Kubernetes and how you can use it to deploy and manage containers at scale.&lt;/p&gt;

&lt;p&gt;Modern applications are increasingly built using container and microservice architecture. Kubernetes is open-source software for deploying and managing those containers at scale. It groups containers into logical units for easier management, discovery, and scaling of your application.&lt;/p&gt;

&lt;p&gt;The primary motivation behind this article is to give a clear overview of the entire world of Kubernetes and making it simple and easy to understand. This guide will go over all essential concepts of Kubernetes and will then use them all in a practical example.&lt;/p&gt;

&lt;p&gt;Even if you had no prior experience with Kubernetes before, this article will prove to be the perfect start for your journey.&lt;/p&gt;

&lt;p&gt;So, without wasting any further time, let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why care about Kubernetes?
&lt;/h2&gt;

&lt;p&gt;Before we dive into the technical concepts, let's first discuss why a developer should even use Kubernetes in the first place. Here are some reasons why developers should consider implementing Kubernetes in their work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Portability:
&lt;/h3&gt;

&lt;p&gt;Moving containerized applications from development to production is a seeming less process when using Kubernetes. Kubernetes enables developers to orchestrate containers consistently in different environments across on-premises infrastructure and public and hybrid clouds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scalability:
&lt;/h3&gt;

&lt;p&gt;Defining complex containerized applications and deploying them globally across multiple clusters of servers is made simple as Kubernetes optimizes resources according to your desired state. When Kubernetes scales applications horizontally, it will also automatically monitor and maintain container health.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extensibility:
&lt;/h3&gt;

&lt;p&gt;Kubernetes has a vast and ever-growing collection of extensions and plugins created by developers and companies that make it easy to add unique capabilities such as security, monitoring, or management capabilities to your cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes Concepts
&lt;/h2&gt;

&lt;p&gt;Making use of Kubernetes requires an understanding of the different abstractions it uses to represent the state of the system. That is what this section is all about. Getting familiar with the most essential concepts and giving you a clearer picture of the general architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pods:
&lt;/h3&gt;

&lt;p&gt;A Pod is a group of multiple containers of your application that share storage, a unique cluster IP address, and information about how to run them (e.g. container image, ports, restart and failure policies).&lt;/p&gt;

&lt;p&gt;They are the building block of the Kubernetes platform. When we create a deployment or a service, Kubernetes will automatically create a Pod with the container inside.&lt;/p&gt;

&lt;p&gt;Each pod runs on the node it is scheduled on and remains there until termination or deletion. In case the node fails or terminates, Kubernetes will automatically schedule identical Pods on the other available Nodes of the cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5lgpiqvs05xf3tn0j22v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5lgpiqvs05xf3tn0j22v.jpg" alt="Kubernetes pods"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Node:
&lt;/h3&gt;

&lt;p&gt;A node is a worker machine in a Kubernetes cluster and may be either a virtual or a physical machine, depending on the type of cluster. Each node is managed by the so-called master. The master automatically schedules pods across all nodes in the cluster, depending on their available resources and current configuration.&lt;/p&gt;

&lt;p&gt;Each node has to run at least two services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubelet - A process responsible for the communication between the Kubernetes master and the node&lt;/li&gt;
&lt;li&gt;A container runtime - Responsible for pulling and running a container image (Docker for example)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzjc67kvdsf700xbrcaod.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzjc67kvdsf700xbrcaod.jpg" alt="Kubernetes Node"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Services:
&lt;/h3&gt;

&lt;p&gt;A Service is an abstraction that defines a logical set of Pods and a policy by which to access them. Services enable loose coupling between dependent Pods.&lt;/p&gt;

&lt;p&gt;Although each pod has a unique IP-Address, those addresses are still not exposed to the outside of the cluster. A service therefore allows your deployment to receive traffic from outside sources.&lt;/p&gt;

&lt;p&gt;Services can be exposed in multiple ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ClusterIP (standard) - Only expose the port to the internals of the cluster&lt;/li&gt;
&lt;li&gt;NodePort - Expose the service on the same port on every node in the cluster using NAT&lt;/li&gt;
&lt;li&gt;Loadbalancer - Create an external load balancer to export the service on a specific IP Address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft9d4wjd6a9lh5piola5f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft9d4wjd6a9lh5piola5f.jpg" alt="Kubernetes services"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployments:
&lt;/h3&gt;

&lt;p&gt;Deployments contain a description of the desired state of your application. The deployment controller will then try to make sure that the current state of the application meets that description.&lt;/p&gt;

&lt;p&gt;A deployment runs multiple replicas of your application and automatically replaces any instances that fail or become unresponsive. In this way, deployments help ensure that your application is available to serve user requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fopl9n5wo4nzedrro7u54.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fopl9n5wo4nzedrro7u54.jpg" alt="Kubernetes deployments"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Before we can start creating our cluster, we first need to install Kubernetes on our local machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker Desktop:
&lt;/h3&gt;

&lt;p&gt;If you are using Docker desktop on windows or mac, you can install Kubernetes directly in the settings window of the user interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other installation:
&lt;/h3&gt;

&lt;p&gt;If you are not using Docker desktop, I would recommend following the &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/" rel="noopener noreferrer"&gt;official installation guide&lt;/a&gt; for installing Kubectl and Minikube.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes Basics
&lt;/h2&gt;

&lt;p&gt;Now that we have the most essential concepts out of the way let's continue by looking at the practical side of Kubernetes. This chapter will guide you through all the basics you need to know to deploy applications in a cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a cluster:
&lt;/h2&gt;

&lt;p&gt;Minikube automatically creates a cluster when you start it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker desktop should also automatically create a cluster after the installation. You can check if your cluster is running using the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get information about the cluster&lt;/span&gt;
kubectl cluster-info

&lt;span class="c"&gt;# Get all nodes of the cluster&lt;/span&gt;
kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying an application:
&lt;/h3&gt;

&lt;p&gt;Now that we have finished the installation and set up our first cluster, it is time to deploy an application to Kubernetes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create deployment nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the create deployment command and pass the name of the deployment and the container image as arguments. This example creates an Nginx deployment with one container and one replica.&lt;/p&gt;

&lt;p&gt;You can see your running deployments using the get deployments command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get information about your deployments:
&lt;/h3&gt;

&lt;p&gt;Here are a few commands you can use to get more information about your deployments and pods in Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting all pods:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can get a list of all running pods using the kubectl get pods command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should look similar to this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME                     READY   STATUS    RESTARTS   AGE
nginx-7654889675-zskr8   1/1     Running   0          4h29m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Get a detailed description of your pods:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want a more detailed description of your pods, you can use the describe pods command instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Name:         nginx-674ff86d-88rj8
Namespace:    default
Priority:     0
Node:         node-3jis6/10.114.0.3
Start Time:   Fri, 24 Jul 2020 23:50:05 +0200
Labels:       &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx
              pod-template-hash&lt;span class="o"&gt;=&lt;/span&gt;674ff86d
Annotations:  &amp;lt;none&amp;gt;
Status:       Running
IP:           10.244.0.54
IPs:
  IP:           10.244.0.54
Controlled By:  ReplicaSet/nginx-674ff86d
Containers:
  nginx:
    Container ID:   docker://5e91ecc5134de36be301635efdccd1816da4506b33d339ea2e845334acd958e2
    Image:          nginx:latest
    Image ID:       docker-pullable://nginx@sha256:0e188877aa60537d1a1c6484b8c3929cfe09988145327ee47e8e91ddf6f76f5c
    Port:           &amp;lt;none&amp;gt;
    Host Port:      &amp;lt;none&amp;gt;
    State:          Running
      Started:      Fri, 24 Jul 2020 23:50:12 +0200
    Ready:          True
    Restart Count:  0
    Environment:    &amp;lt;none&amp;gt;
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-dn7gb &lt;span class="o"&gt;(&lt;/span&gt;ro&lt;span class="o"&gt;)&lt;/span&gt;
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-dn7gb:
    Type:        Secret &lt;span class="o"&gt;(&lt;/span&gt;a volume populated by a Secret&lt;span class="o"&gt;)&lt;/span&gt;
    SecretName:  default-token-dn7gb
    Optional:    &lt;span class="nb"&gt;false
&lt;/span&gt;QoS Class:       BestEffort
Node-Selectors:  &amp;lt;none&amp;gt;
Tolerations:     node.kubernetes.io/not-ready:NoExecute &lt;span class="k"&gt;for &lt;/span&gt;300s
                 node.kubernetes.io/unreachable:NoExecute &lt;span class="k"&gt;for &lt;/span&gt;300s
Events:
  Type    Reason     Age        From                 Message
  &lt;span class="nt"&gt;----&lt;/span&gt;    &lt;span class="nt"&gt;------&lt;/span&gt;     &lt;span class="nt"&gt;----&lt;/span&gt;       &lt;span class="nt"&gt;----&lt;/span&gt;                 &lt;span class="nt"&gt;-------&lt;/span&gt;
  Normal  Scheduled  &amp;lt;unknown&amp;gt;  default-scheduler    Successfully assigned default/nginx-674ff86d-88rj8 to node-3jis6
  Normal  Pulling    16s        kubelet, node-3jis6  Pulling image &lt;span class="s2"&gt;"nginx:latest"&lt;/span&gt;
  Normal  Pulled     11s        kubelet, node-3jis6  Successfully pulled image &lt;span class="s2"&gt;"nginx:latest"&lt;/span&gt;
  Normal  Created    10s        kubelet, node-3jis6  Created container nginx
  Normal  Started    10s        kubelet, node-3jis6  Started container nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  View the logs of a pod:
&lt;/h3&gt;

&lt;p&gt;The information your application would typically send out to STDOUT become logs of your container. You can access those logs using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs &lt;span class="nv"&gt;$POD_NAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: You can get the name of your pod using either the get pods or describe pods command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Executing a command in the container:
&lt;/h3&gt;

&lt;p&gt;We can execute commands directly in our container using the kubectl exec command, which takes the pod name and the command we want to run as arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;$POD_NAME&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To clarify, let's look at an example where we start a bash terminal in the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nv"&gt;$POD_NAME&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exposing your app publicly:
&lt;/h3&gt;

&lt;p&gt;As we already discussed earlier, a service defines a policy by which the deployment can be accessed with. In this section, we are going to take a look at how this is done and some different options you have when exposing your services to the public.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a service:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can create a service using the &lt;code&gt;create service&lt;/code&gt; command that will take the port we want to expose and the type of port as arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create service nodeport nginx &lt;span class="nt"&gt;--tcp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a service for our Nginx deployment and expose the port 80 of our container to a port on our host machine.&lt;/p&gt;

&lt;p&gt;You can get the port on the host machine using the &lt;code&gt;kubectl get services&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;           AGE
kubernetes   ClusterIP   10.245.0.1      &amp;lt;none&amp;gt;        443/TCP           27h
nginx        NodePort    10.245.74.155   &amp;lt;none&amp;gt;        80:30392/TCP      8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, port 80 of the container is forwarded to port 31041 of my host machine. When you have the port, you can verify your deployment by visiting your localhost on that port.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsbo30drn4ivpopdp0b60.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsbo30drn4ivpopdp0b60.jpg" alt="Nginx Kubernetes deployment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting a service:
&lt;/h3&gt;

&lt;p&gt;We can also remove existing services using the delete service command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete service nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scale up your app:
&lt;/h3&gt;

&lt;p&gt;Scaling your application up and down is extremely simple using Kubernetes. You can change the number of replicas using a single command and Kubernetes will automatically create and maintain everything for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl scale deployments/nginx &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will scale our Nginx service up to five replicas.&lt;/p&gt;

&lt;p&gt;This way of deploying applications works excellent for small one container application but doesn't provide the overview and reusability needed for more prominent applications. This is where YAML files come into play.&lt;/p&gt;

&lt;p&gt;YAML files let you declare your deployment, services and pods using a markup language, so they are reusable and better for scaling. Yaml files will be covered in-depth in the following chapters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declaring Kubernetes object in YAML
&lt;/h2&gt;

&lt;p&gt;Every object in Kubernetes can be represented as a declarative YAML object that provides details about what and how you want to run. These files are often used to increase the reusability of resource configuration like deployments, service, volumes and many more.&lt;/p&gt;

&lt;p&gt;This section will show you the basics of YAML and how you can get a list of all available parameters and attributes of a Kubernetes object. We will also take a look at a deployment and service file to get a better feeling of the syntax and how you can deploy the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting the parameters of the different objects:
&lt;/h3&gt;

&lt;p&gt;There are many different Kubernetes objects and it is hard to remember every setting. That is where the explain command comes into play.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl explain deployment

&lt;span class="c"&gt;# Output&lt;/span&gt;
KIND:     Deployment
VERSION:  extensions/v1beta1

DESCRIPTION:
     DEPRECATED - This group version of Deployment is deprecated by
     apps/v1beta2/Deployment. See the release notes &lt;span class="k"&gt;for &lt;/span&gt;more information.
     Deployment enables declarative updates &lt;span class="k"&gt;for &lt;/span&gt;Pods and ReplicaSets.

FIELDS:
   apiVersion   &amp;lt;string&amp;gt;
     APIVersion defines the versioned schema of this representation of an
     object. Servers should convert recognized schemas to the latest internal
     value, and may reject unrecognized values. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#resources

   kind &amp;lt;string&amp;gt;
     Kind is a string value representing the REST resource this object
     represents. Servers may infer this from the endpoint the client submits
     requests to. Cannot be updated. In CamelCase. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds

   metadata     &amp;lt;Object&amp;gt;
     Standard object metadata.

   spec &amp;lt;Object&amp;gt;
     Specification of the desired behavior of the Deployment.

   status       &amp;lt;Object&amp;gt;
     Most recently observed status of the Deployment.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also get the documentation of a specific field using the following syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl explain deployment.spec.replicas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deployment file:
&lt;/h3&gt;

&lt;p&gt;More complex deployments will normally be written in YAML for easy reusability and changeability.&lt;/p&gt;

&lt;p&gt;Here is the basic file structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# The name and label of your deployment&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# How many copies of each pod do you want&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="c1"&gt;# Which pods are managed by this deployment&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
  &lt;span class="c1"&gt;# Regular pod configuration / Defines containers, volumes and environment variable &lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# label the pod&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo:4.2&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27017&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The YAML file has multiple important sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;apiVersion - Defines the version of the API
-kind - The kind of Kubernetes object defined in the file (e.g. deployment, service, persistentVolume, ...)&lt;/li&gt;
&lt;li&gt;metadata - Description of your YAML component containing name, labels and other information&lt;/li&gt;
&lt;li&gt;spec - Defines the attribute of your deployment e.g. replicas, resource limits&lt;/li&gt;
&lt;li&gt;template - Pod configuration of the deployment file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that you know the basic structure, you can deploy the file using the apply command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deploy.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Service file:
&lt;/h3&gt;

&lt;p&gt;Service files have a similar structure then deployments with minor differences in the parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27017&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27017&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Storage
&lt;/h2&gt;

&lt;p&gt;When a pod is deleted or a container restarts, the whole data of the file system is deleted. In most cases, this is a good thing, because your stateless application doesn't get littered with unneeded data. In other cases, persisting the data of your file system is vital for your application.&lt;/p&gt;

&lt;p&gt;There are a few different kinds of storage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container filesystem - Standard storage that stores the data of a single container for his lifetime&lt;/li&gt;
&lt;li&gt; Volume - Volumes let you save data and share it between different containers as long as the pod exists&lt;/li&gt;
&lt;li&gt;Persistent Volumes - Persistent Volumes save data even after the pod is deleted or restarted. They are the long-term storage in your Kubernetes cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Volumes:
&lt;/h3&gt;

&lt;p&gt;Volumes let you save, share, and preserve data between multiple containers as long as the pod exists. This can be useful if you have pods with multiple containers that need to share data with each other.&lt;/p&gt;

&lt;p&gt;There are two steps for using a volume in Kubernetes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The pod defines the volume&lt;/li&gt;
&lt;li&gt;The container uses the volumeMounts to add the volume to a specific path of the filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can add a volume to your pod using the following syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-storage&lt;/span&gt;
      &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/nginx&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-storage&lt;/span&gt;
    &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The volumes tag is used to define the volume that can then be mounted to a specific directory of the container filesystem (in this case /etc/nginx).&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistent Volumes:
&lt;/h3&gt;

&lt;p&gt;Persistent volumes are almost identical to normal volumes, with the key difference that they preserve the data even after the pod is deleted. That is why they are used for long-term data storage purposes like a database, for example.&lt;/p&gt;

&lt;p&gt;The most common way to define a persistent volume is a so-called Persistent Volume Claim (PVC) object, which connects to backend storage volumes through a series of abstractions.&lt;/p&gt;

&lt;p&gt;Here is an example YAML configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pv-claim&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sampleAppName&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;20Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then use your PVC in your actual Kubernetes deployment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
      &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Recreate&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
        &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:5.6&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;
          &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql-password&lt;/span&gt;
              &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3306&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
        &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql-persistent-storage&lt;/span&gt;
          &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/mysql&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql-persistent-storage&lt;/span&gt;
        &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql-pv-claim&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are more ways to save your data in Kubernetes and automate that process as much as possible. Here is a list of a few interesting topics you should take a look at.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/storage/storage-classes/" rel="noopener noreferrer"&gt;Storage classes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/" rel="noopener noreferrer"&gt;Dynamic volume provision&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Managing compute resources
&lt;/h2&gt;

&lt;p&gt;Managing compute resources of your containers and applications is an important topic when it comes to container orchestration.&lt;/p&gt;

&lt;p&gt;When your containers have a specified amount of resources available, the scheduler can make better decisions about which node to place the pod on. You will also run into fewer contention problems with the resources of different deployments.&lt;/p&gt;

&lt;p&gt;There are two different types of resource specifications that we will cover in detail in the next two sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requests:
&lt;/h3&gt;

&lt;p&gt;Requests tell Kubernetes the requirements of the pod and that it should only place the pod on nodes that have these requirements. Requests are defined under the resources tag on your container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo:4.2&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27017&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;64Mi"&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;250m"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Limits:
&lt;/h3&gt;

&lt;p&gt;Resource limits are used to constrain the memory and CPU usage of a specific pod and provide the maximum value of resources that the pod can never exceed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo:4.2&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27017&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;128Mi"&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500m"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information on managing compute resources visit the &lt;a href="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secrets
&lt;/h2&gt;

&lt;p&gt;Kubernetes secrets allow you to safely store and manage sensitive data like passwords, API tokens or SSH keys.&lt;/p&gt;

&lt;p&gt;To use a secret in your pod, you first need to reference it. This can happen in multiple ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a file in a volume which is mounted to a container&lt;/li&gt;
&lt;li&gt;Using an environment variable&lt;/li&gt;
&lt;li&gt;By kubelet when pulling an image from a private registry&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating a secret:
&lt;/h3&gt;

&lt;p&gt;Creating secrets can either be done using the kubelet command tool or by defining a secret Kubernetes object using YAML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using kubelet:&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Kubelet lets you create secrets using a simple create command where you only have to specify the data and the name of the secret. The data can either be passed in using a file or a literal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic admin-credentials &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;poweruser &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'test123'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same functionality using a file would look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'poweruser'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ./username.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'test123'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ./password.txt
kubectl create secret generic admin-credentials--from-file&lt;span class="o"&gt;=&lt;/span&gt;./username.txt &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./password.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also provide multiple files at once by using a folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic admin-credentials &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/creds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Using definition files:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Like other Kubernetes objects, secrets can also be defined using a YAML file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret-apikey&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apikey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;YWRtaW4=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The secret contains a key-value pair of your sensitive information with apiKey being the key and YWRtaW4= being the base decoded value.&lt;/p&gt;

&lt;p&gt;You can now create the secret using the apply command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; secret.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to provide plain data and let Kubernetes handle the encoding for you, just use the stringData attribute instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;plaintext-secret&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using secrets:
&lt;/h3&gt;

&lt;p&gt;To make secrets useful, we first need to make them accessible to our containers. Let's take a look at the ways we can do that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment variables:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Secret data can be consumed using environment variables in a Pod.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-pod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;API_KEY&lt;/span&gt;
          &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret-apikey&lt;/span&gt;
              &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apikey&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The environment variable can then be used after the pod is in the running state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;nginx-pod &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;env&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use all entries of a secret using the envFrom that and passing the secret.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-pod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Volumes:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Secrets can also be mounted to a pod using a Volume.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-pod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apikey-volume&lt;/span&gt;
          &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/secret&lt;/span&gt;
          &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apikey-volume&lt;/span&gt;
      &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret-apikey&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The apikey-volume refers back to the secret-apikey. We also specify the mountPath directory that the secret will be stored in and set readOnly to true.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ImagePullSecrets:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When pulling from a private registry, you might need to authenticate before pulling your image. An ImagePullSecrets is a file that stores the authentification data and makes it available to all your nodes when they need to pull a specific image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;private-image&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;privateapp&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gabrieltanner/graphqltesting&lt;/span&gt;
  &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;authentification-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More information on private Docker registries can be found in &lt;a href="https://gabrieltanner.org/blog/docker-registry" rel="noopener noreferrer"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespaces
&lt;/h2&gt;

&lt;p&gt;Namespaces are virtual clusters that you can create to manage complex projects and divide cluster resources between multiple users. They provide a scope of names and can be nested within each other.&lt;/p&gt;

&lt;p&gt;Managing and using namespaces with kubectl is straight forward. This section will demonstrate the most common actions and commands concerning namespaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  View existing Namespaces:
&lt;/h3&gt;

&lt;p&gt;To display all currently available namespace of your cluster, you can use the kubectl get namespaces command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get namespaces

&lt;span class="c"&gt;# Output&lt;/span&gt;
NAME                   STATUS   AGE
default                Active   32d
docker                 Active   32d
kube-public            Active   32d
kube-system            Active   32d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get more information about a specific namespace, use the kubectl describe command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe namespace default

&lt;span class="c"&gt;# Output&lt;/span&gt;
Name:         default
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;
Status:       Active

No resource quota.

No resource limits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a Namespace:
&lt;/h3&gt;

&lt;p&gt;Namespaces can be created by either using the kubectl CLI or by creating a Kubernetes object in YAML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace testnamespace

&lt;span class="c"&gt;# Output&lt;/span&gt;
namespace/testnamespace created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the same functionality using a YAML file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;testnamespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then apply the configuration file using the kubectl apply command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; testNamespace.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Filtering by Namespace:
&lt;/h3&gt;

&lt;p&gt;When creating a new object in Kubernetes without adding a custom namespace attribute, it will be added to the default namespace.&lt;/p&gt;

&lt;p&gt;If you want to create your object in another workspace, you can do it like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create deployment &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx nginx &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;testnamespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now filter for your deployment using the get command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;testnamespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change Namespace using context:
&lt;/h3&gt;

&lt;p&gt;You just learned how you can create objects in a namespace that isn't the default one. But writing the namespace to every command you want to execute is time-consuming and can produce errors.&lt;/p&gt;

&lt;p&gt;That is why you can change the default context that your commands will apply by using the set-context command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl config set-context &lt;span class="si"&gt;$(&lt;/span&gt;kubectl config current-context&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;testnamespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify the changes using the get-context command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl config get-contexts

&lt;span class="c"&gt;# Output&lt;/span&gt;
CURRENT   NAME      CLUSTER   AUTHINFO   NAMESPACE
&lt;span class="k"&gt;*&lt;/span&gt;         Default   Default   Default    testnamespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Simplifying Kubernetes with Docker Compose
&lt;/h2&gt;

&lt;p&gt;For those of you coming from the Docker community, it might be easier to write Docker Compose files instead of Kubernetes objects. That is where Kompose comes into play. It lets you convert or deploy your docker-compose file to Kubernetes using a simple CLI (command line interface).&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Kompose:
&lt;/h3&gt;

&lt;p&gt;Kompose can be installed on all three mature operating systems in a very easy and simple manner.&lt;/p&gt;

&lt;p&gt;Linux and Mac users just need to curl the binaries to install Kompose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Linux&lt;/span&gt;
curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://github.com/kubernetes/kompose/releases/download/v1.21.0/kompose-linux-amd64 &lt;span class="nt"&gt;-o&lt;/span&gt; kompose

&lt;span class="c"&gt;# macOS&lt;/span&gt;
curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://github.com/kubernetes/kompose/releases/download/v1.21.0/kompose-darwin-amd64 &lt;span class="nt"&gt;-o&lt;/span&gt; kompose

&lt;span class="nb"&gt;chmod&lt;/span&gt; +x kompose
&lt;span class="nb"&gt;sudo mv&lt;/span&gt; ./kompose /usr/local/bin/kompose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On windows, you can download an &lt;a href="https://github.com/kubernetes/kompose/releases/" rel="noopener noreferrer"&gt;executable&lt;/a&gt; and just run it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying using Kompose:
&lt;/h3&gt;

&lt;p&gt;Kompose takes existing Docker Compose files and deploys them in Kubernetes. Let's look at an example using the following compose file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis-master&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8s.gcr.io/redis:e2e&lt;/span&gt; 
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;6379"&lt;/span&gt;
  &lt;span class="na"&gt;redis-slave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gcr.io/google_samples/gb-redisslave:v1&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;6379"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GET_HOSTS_FROM=dns&lt;/span&gt;
  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gcr.io/google-samples/gb-frontend:v4&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GET_HOSTS_FROM=dns&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;kompose.service.type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As with Docker Compose, Kompose also allows us to deploy our configuration using a simple command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kompose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should see the created resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment,svc,pods,pvc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Converting a Compose file to Kubernetes Objects:
&lt;/h3&gt;

&lt;p&gt;Kompose also has the ability to convert your existing Docker Compose file into the related Kubernetes object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kompose convert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then deploy your application using the apply command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; filenames
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Demo application deployment
&lt;/h2&gt;

&lt;p&gt;Now that you know the theory and all the vital concepts of Kubernetes, it is time to put that knowledge into practice. This chapter will show you how you can deploy a backend application on Kubernetes.&lt;/p&gt;

&lt;p&gt;The specific application in this guide is a GraphQL boilerplate for the Nest.js backend framework.&lt;/p&gt;

&lt;p&gt;Let's start by cloning the repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/TannerGabriel/nestjs-graphql-boilerplate.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pushing the images to a Registry:
&lt;/h3&gt;

&lt;p&gt;Before we can start with creating the Kubernetes objects, we first need to push the images to a publicly available Image Registry. This can either be a public registry like DockerHub or your own private registry.&lt;/p&gt;

&lt;p&gt;If you want to know more about how to set up your own private Docker Image, visit &lt;a href="https://gabrieltanner.org/blog/docker-registry" rel="noopener noreferrer"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To push the image, just add the image tag with the registry you want to push it to in your Compose file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nodejs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gabrieltanner.dev/nestgraphql&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_HOST=mongo&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PORT=3000&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3000:3000'&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;mongo&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;mongo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;27017:27017'&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mongo_data:/data/db&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongo_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I personally used a private registry I set up earlier, but you can just as well use DockerHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Kubernetes objects:
&lt;/h3&gt;

&lt;p&gt;Now that you have pushed your image to a registry let's continue by writing our Kubernetes objects.&lt;/p&gt;

&lt;p&gt;First, create a new directory to store the deployments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;deployments
&lt;span class="nb"&gt;cd &lt;/span&gt;deployments

&lt;span class="nb"&gt;touch &lt;/span&gt;mongo.yaml
&lt;span class="nb"&gt;touch &lt;/span&gt;nestjs.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MongoDB service and deployment will then look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27017&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27017&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27017&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file contains a deployment object with a single MongoDB container that is labeled mongo. It also contains a service that makes port 27017 available to the Kubernetes network (It cannot be accessed on the host machine but only from other containers in the same namespace).&lt;/p&gt;

&lt;p&gt;The Nest.js Kubernetes object is a bit more complicated because the container needs some extra configuration like environment variables and imagePullSecrets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nestgraphql&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nestgraphql&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nestgraphql&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gabrieltanner.dev/nestgraphql"&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DATABASE_HOST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
          &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Always&lt;/span&gt;
      &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regcred&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nestgraphql&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nestgraphql&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service also uses a load balancer to make the port accessible on the host machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the application:
&lt;/h3&gt;

&lt;p&gt;Now that the Kubernetes object files are ready to go, let's deploy them using kubectl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; mongo.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; nestjs.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now be able to access the GraphQL playground on localhost/graphql.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmnn9j2x67qli79isi8g9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmnn9j2x67qli79isi8g9.jpg" alt="GraphQL playground"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you have just deployed your first application on Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;Here is a list of the sources I used for this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/de/docs/concepts/overview/what-is-kubernetes/" rel="noopener noreferrer"&gt;Official documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/itnext/tutorial-how-to-use-kubernetes-secrets-for-storing-sensitive-config-data-3dl5"&gt;Kubernetes Secrets for storing sensitive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://matthewpalmer.net/kubernetes-app-developer/articles/kubernetes-deployment-tutorial-example-yaml.html" rel="noopener noreferrer"&gt;Kubernetes Deployment Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://phoenixnap.com/kb/kubernetes-persistent-volumes" rel="noopener noreferrer"&gt;Introduction to Persitent Volumes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mirantis.com/blog/introduction-to-yaml-creating-a-kubernetes-deployment/" rel="noopener noreferrer"&gt;Introduction to YAML: Creating a Kubernetes deployment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You made it all the way until the end! I hope that this article helped you understand Kubernetes and how you can use it to improve your development and deployment workflow as a developer.&lt;/p&gt;

&lt;p&gt;If you have found this useful, please consider recommending and sharing it with other fellow developers. If you have any questions or feedback, let me know in the comments down below.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://gabrieltanner.org/blog/the-definitive-guide-to-kubernetes" rel="noopener noreferrer"&gt;gabrieltanner.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>docker</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
