> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/continuous-delivery/3.0/use-deployments/kubernetes/kubernetes-cd-quickstart.md).

# Kubernetes deployments

This topic shows you how to deploy a publicly-available NGINX Docker image and manifest into your Kubernetes cluster using a [rolling update strategy](/continuous-delivery/use-continuous-delivery/deploy-services-on-different-platforms/kubernetes/kubernetes-executions/create-a-kubernetes-rolling-deployment.md) in Harness.

In this topic, you'll learn how to:

* Set up a Kubernetes pipeline.
* Run the new Kubernetes pipeline and deploy a Docker image to your target cluster.

The following video explains Kubernetes deployments using Harness:

{% embed url="<https://www.loom.com/share/f8cf2e7abe094d08829902831a4081b5?sid=f522eb06-4a86-416a-94ac-24f2a86f7a88>" %}

### Set up a Kubernetes cluster for deployment <a href="#set-up-a-kubernetes-cluster-for-deployment" id="set-up-a-kubernetes-cluster-for-deployment"></a>

You'll need a target Kubernetes cluster for the Harness Delegate and deployment. Ensure your cluster meets the following minimum requirements:

* **Number of nodes:** 2.
* **vCPUs, Memory, Disk Size:** 4vCPUs, 16GB memory, 100GB disk. In GKE, the **e2-standard-4** machine type is enough for this quickstart.
* **Networking:** outbound HTTPS for the Harness connection to **app.harness.io**, **github.com**, and **hub.docker.com**. Allow TCP port 22 for SSH.
* A **Kubernetes service account** with permission to create entities in the target namespace is required. The set of permissions should include `list`, `get`, `create`, and `delete` permissions. In general, the cluster-admin permission or namespace admin permission is enough.\
  For more information, go to [User-Facing Roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) from Kubernetes.

### Create the deploy stage for the Kubernetes pipeline <a href="#create-the-deploy-stage-for-the-kubernetes-pipeline" id="create-the-deploy-stage-for-the-kubernetes-pipeline"></a>

Pipelines are collections of stages. For this topic, we'll create a new pipeline and add a single stage.

{% hint style="info" %}
**Create a project for your new CD pipeline:** if you don't already have a Harness project, create a project for your new CD pipeline. Ensure that you add the **Continuous Delivery** module to the project. Go to [create organizations and projects](/harness-ai/new-to-harness-platform/overview.md#organizations-and-projects) for more information.
{% endhint %}

1. In your Harness project, select **Deployments**, and then select **Create a Pipeline**. ![](/files/TCN1FwPnsK4me0cyAxKY)
2. Enter the name **CD Quickstart** and select **Start**.

   Your pipeline appears.
3. Select **Add Stage** and select **Deploy**.
4. Enter the name **Deploy Service**, make sure **Service** is selected, and then select **Set Up Stage**.

   The new stage settings appear.
5. In the **Service** tab, select **New Service**.

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>Let's take a moment and review Harness services and service definitions (which are explained below). Harness services represent your microservices/apps logically. You can add the same service to as many stages as you need. Service definitions represent your artifacts, manifests, and variables physically. They are the actual files and variable values.</p><p>By separating services and service definitions, you can propagate the same Service across stages while changing the artifacts, manifests, and variables with each stage.</p></div>
6. Give the service the name **nginx** and select **Save**.

Once you have created a service, it is persistent and can be used throughout the stages of this or any other pipeline in the project.

### Add the Kubertnetes manifest for deployment <a href="#add-the-kubertnetes-manifest-for-deployment" id="add-the-kubertnetes-manifest-for-deployment"></a>

Next, we can add a Kubernetes manifest for NGINX. We'll use the [publicly-available manifest](https://github.com/kubernetes/website/blob/master/content/en/examples/application/nginx-app.yaml) available from Kubernetes.

1. In **Service Definition**, in **Deployment Type**, select **Kubernetes**.
2. In **Manifests**, select **Add Manifest**.

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><strong>What about Artifacts?</strong> In this quickstart we are using a publicly-available NGINX Docker image from DockerHub, and the location of the image is hardcoded in the public manifest from Kubernetes. The <strong>Artifacts</strong> section is only used when the public artifact is not hardcoded in the manifest or the repo is private. In those cases, you add the image in <strong>Artifacts</strong> with a Connector for the repo and then reference the image in your values.yaml (<code>image: &#x3C;+artifact.image></code>). For more information, go to <a href="/spaces/y1JhZ4oKIppwY7d5AhPj/pages/7AK15ODD4BdHeiBED8Zd">Add Container Images as Artifacts for Kubernetes Deployments</a>.</p></div>
3. Select **K8s Manifest**, and select **Continue**.
4. In **Select K8sManifest Store**, select **GitHub**, and then select **New GitHub Connector**.
5. The **Git Connector** settings appear. Enter the following settings.
   * **Name:** enter a name for the connector.
   * **URL Type:** select **Repository**.
   * **Connection Type:** select **HTTP**.
   * **Git Repository URL:** enter `https://github.com/kubernetes/website`.
   * **Username and Token:** Enter the username and a Github Personal Access Token (PAT) for your GitHub account. You'll have to create a Harness secret for the password.

     1. In **Personal Access Token**, click **Create or Select a Secret**.
     2. Select **New Secret Text**.
     3. In **Secret Name**, enter a name for the secret like **github-pat**.
     4. In **Secret Value**, paste in a GitHub Personal access token. When you're logged into GitHub, these are typically listed at <https://github.com/settings/tokens>. For steps on setting up a GitHub PAT, go to [creating a personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) from GitHub. Ensure you PAT has the **repo** scope selected:

     ![](/files/uY0yCG9DSk9e6cfIEqaD)
6. Select **Continue**.
7. In **Connect to the provider**, select **Connect through a Harness Delegate**, and then select **Continue**. We don't use the **Connect through Harness Platform** option here simply because you'll need a Delegate later for the connection to your target Kubernetes cluster. Typically, the **Connect through Harness Platform** option is a very quick way to make connections without having to use Delegates.

   Expand the section below to learn more about installing delegates.

<details>

<summary>Use the delegate installation wizard</summary>

1. In your Harness project, select **Project Setup**.
2. Select **Delegates**.
3. Select **Install a Delegate**.
4. Follow the delegate installation wizard.

Use this [delegate installation wizard video](https://www.youtube.com/watch?v=yLMCxs3onH8) to guide you through the process.

</details>

<details>

<summary>Install a delegate using the terminal</summary>

The [Harness Delegate](/harness-ai/use-harness-platform/delegates/delegate/delegate-concepts/delegate-overview.md) is a lightweight worker process that is installed on your infrastructure and communicates only via outbound HTTP/HTTPS to the Harness Platform. This enables the Harness Platform to leverage the delegate to execute the CI/CD and other tasks on your behalf, without any of your secrets leaving your network.

You can install the Harness Delegate on either Docker or Kubernetes.

### Install the default Harness Delegate <a href="#install-the-default-harness-delegate" id="install-the-default-harness-delegate"></a>

#### Create a new delegate token <a href="#create-a-new-delegate-token" id="create-a-new-delegate-token"></a>

You can install delegates from the Account, Project, or Org scope. In this example, we'll create a new token in the Account scope.

To create a new delegate token, do the following:

1. In Harness, select **Account Settings**, then select **Account Resources**. The Account Resources page opens.
2. Select **Delegates**. The Delegates list page opens.
3. Select the **Tokens** tab, then select **+New Token**. The **New Token** dialog opens.
4. Enter a token name, for example `firstdeltoken`.
5. Select **Apply**. Harness generates a new token for you.
6. Select **Copy** to copy and store the token in a temporary file.

   You will provide this token as an input parameter in the next installation step. The delegate will use this token to authenticate with the Harness Platform.

#### Get your Harness account ID <a href="#get-your-harness-account-id" id="get-your-harness-account-id"></a>

Along with the delegate token, you will also need to provide your Harness `accountId` as an input parameter during delegate installation. This `accountId` is present in every Harness URL. For example, in the following URL:

```
https://app.harness.io/ng/#/account/6_vVHzo9Qeu9fXvj-AcQCb/settings/overview
```

`6_vVHzo9Qeu9fXvj-AcQCb` is the `accountId`.

{% hint style="info" %}
**NOTE**

When you install a delegate via the Harness UI, several dependencies in this topic are prefilled for your convenience. This topic explains where to find the required information for CLI-based installation.
{% endhint %}

For more information, go to [View account info and subscribe to downtime alerts](/harness-ai/subscriptions-and-licenses/view-account-info-and-subscribe-to-alerts.md).

PrerequisiteEnsure that you have access to a Kubernetes cluster. For the purposes of this tutorial, we will use minikube.Install minikubeOn Windowschoco install minikubeFor Chocolatey installation instructions, go to Installing Chocolatey in the Chocolatey documentation.For additional options to install minikube on Windows, go to minikube start in the minikube documentation.On macOS:brew install minikubeFor Homebrew installation instructions, go to Installation in the Homebrew documentation.Now start minikube with the following config.minikube start --memory 4g --cpus 4Validate that you have kubectl access to your cluster.kubectl get pods -ANow that you have access to a Kubernetes cluster, you can install the delegate using any of the options below\.Install the Helm chartAs a prerequisite, you must have Helm v3 installed on the machine from which you connect to your Kubernetes cluster.You can now install the delegate using the delegate Helm chart. First, add the harness-delegate Helm chart repo to your local Helm registry.helm repo add harness-delegate <https://app.harness.io/storage/harness-download/delegate-helm-chart/helm> repo updatehelm search repo harness-delegateWe will use the harness-delegate/harness-delegate-ng chart in this tutorial.NAME CHART VERSION APP VERSION DESCRIPTIONharness-delegate/harness-delegate-ng 1.0.8 1.16.0 A Helm chart for deploying harness-delegateNow we are ready to install the delegate. The following example installs/upgrades firstk8sdel delegate (which is a Kubernetes workload) in the harness-delegate-ng namespace using the harness-delegate/harness-delegate-ng Helm chart.You can install delegates from the Account, Project, or Org scope. In this example, we'll install a delegate in the Account scope.To install a delegate, do the following:In Harness, select Account Settings, then select Account Resources. The Account Resources page opens.Select Delegates. The Delegates list page opens.Select New Delegate. The New Delegate dialog opens.Under Select where you want to install your Delegate, select Kubernetes.Under Install your Delegate, select Helm Chart.Copy the helm upgrade command.The command uses the default values.yaml file located in the delegate Helm chart GitHub repo. To make persistent changes to one or more values, you can download and update the values.yaml file according to your requirements. Once you have updated the file, you can use it by running the upgrade command below. helm upgrade -i firstk8sdel --namespace harness-delegate-ng --create-namespace \ harness-delegate/harness-delegate-ng \ -f values.yaml \ --set delegateName=firstk8sdel \ --set accountId=PUT\_YOUR\_HARNESS\_ACCOUNTID\_HERE \ --set delegateToken=PUT\_YOUR\_DELEGATE\_TOKEN\_HERE \ --set managerEndpoint=PUT\_YOUR\_MANAGER\_HOST\_AND\_PORT\_HERE \ --set delegateDockerImage=harness/delegate:yy.mm.verno \ --set replicas=1 --set upgrader.enabled=trueNOTETo install a Helm delegate for Harness Self-Managed Enterprise Edition in an air-gapped environment, you must pass your certificate when you add the Helm repo.helm repo add harness-delegate --ca-file <.PEM\_FILE\_PATH> \<HELM\_CHART\_URL\_FROM\_UI>For more information on requirements for air-gapped environments, go to Install in an air-gapped environment.Run the command.Create main.tf fileHarness uses a Terraform module for the Kubernetes delegate. This module uses the standard Terraform Helm provider to install the Helm chart onto a Kubernetes cluster whose config by default is stored in the same machine at the \~/.kube/config path. Copy the following into a main.tf file stored on a machine from which you want to install your delegate.module "delegate" { source = "harness/harness-delegate/kubernetes" version = "0.1.8" account\_id = "PUT\_YOUR\_HARNESS\_ACCOUNTID\_HERE" delegate\_token = "PUT\_YOUR\_DELEGATE\_TOKEN\_HERE" delegate\_name = "firstk8sdel" namespace = "harness-delegate-ng" manager\_endpoint = "PUT\_YOUR\_MANAGER\_HOST\_AND\_PORT\_HERE" delegate\_image = "harness/delegate:yy.mm.verno" replicas = 1 upgrader\_enabled = false # Additional optional values to pass to the helm chart values = yamlencode({ javaOpts: "-Xms64M" })}provider "helm" { kubernetes { config\_path = "\~/.kube/config" }}Now replace the variables in the file with your Harness account ID and delegate token values. Replace PUT\_YOUR\_MANAGER\_HOST\_AND\_PORT\_HERE with the Harness Manager Endpoint noted below. For Harness SaaS accounts, you can find your Harness Cluster Location on the Account Overview page under the Account Settings section of the left navigation.Run Terraform init, plan, and applyInitialize Terraform. This downloads the Terraform Helm provider to your machine.terraform initRun the following step to view the changes Terraform is going to make on your behalf.terraform planFinally, run this step to make Terraform install the Kubernetes delegate using the Helm provider.terraform applyWhen prompted by Terraform if you want to continue with the apply step, type yes, and then you will see output similar to the following.helm\_release.delegate: Creating...helm\_release.delegate: Still creating... \[10s elapsed]helm\_release.delegate: Still creating... \[20s elapsed]helm\_release.delegate: Still creating... \[30s elapsed]helm\_release.delegate: Still creating... \[40s elapsed]helm\_release.delegate: Still creating... \[50s elapsed]helm\_release.delegate: Still creating... \[1m0s elapsed]helm\_release.delegate: Creation complete after 1m0s \[id=firstk8sdel]Apply complete! Resources: 1 added, 0 changed, 0 destroyed.Download a Kubernetes manifest templatecurl -LO <https://raw.githubusercontent.com/harness/delegate-kubernetes-manifest/main/harness-delegate.yamlReplace> variables in the templateOpen the harness-delegate.yaml file in a text editor and replace PUT\_YOUR\_DELEGATE\_NAME\_HERE, PUT\_YOUR\_HARNESS\_ACCOUNTID\_HERE, and PUT\_YOUR\_DELEGATE\_TOKEN\_HERE with your delegate name (for example, firstk8sdel), Harness accountId, and delegate token values, respectively.Replace the PUT\_YOUR\_MANAGER\_HOST\_AND\_PORT\_HERE variable with the Harness Manager Endpoint noted below. For Harness SaaS accounts, you can find your Harness Cluster Location on the Account Overview page under the Account Settings section of the left navigation.Apply the Kubernetes manifestkubectl apply -f harness-delegate.yamlPrerequisitesEnsure that you have the Docker runtime installed on your host. If not, use one of the following options to install Docker:Docker for MacDocker for CentOSDocker for UbuntuDocker for DebianDocker for WindowsInstall on DockerYou can install delegates from the Account, Project, or Org scope. In this example, we'll install a delegate in the Project scope.To install a delegate, do the following:In Harness, select your project, then select Project Settings.Under Project-level resources, select Delegates.Select Install a Delegate to open the New Delegate dialog.Under Select where you want to install your Delegate, select Docker.Under Install your Delegate, enter a Delegate Name.Copy the docker run command.docker run --cpus=1 --memory=2g \ -e DELEGATE\_NAME=docker-delegate \ -e NEXT\_GEN="true" \ -e DELEGATE\_TYPE="DOCKER" \ -e ACCOUNT\_ID=YOUR\_HARNESS\_ACCOUNTID\_ \ -e DELEGATE\_TOKEN=YOUR\_DELEGATE\_TOKEN \ -e DELEGATE\_TAGS="" \ -e MANAGER\_HOST\_AND\_PORT=YOUR\_MANAGER\_HOST\_AND\_PORT \ harness/delegate:yy.mm.vernoThe docker run command doesn't allow you to select the delegate token. You can replace the token in the command with another token if required.Steps 6 and 7 are optional when installing a delegate using the CLI flow.(Optional) Replace the YOUR\_MANAGER\_HOST\_AND\_PORT\_HERE variable with the Harness Manager Endpoint noted below. For Harness SaaS accounts, to find your Harness cluster location, select Account Settings, and then select Overview. In Account Overview, look in Account Settings. It is listed next to Harness Cluster Hosting Account.For more information, go to View account info and subscribe to downtime alerts.For Harness CDCE, the endpoint varies based on the Docker vs. Helm installation options.Run the command.

### Ephemeral Storage in Delegate Helm Charts <a href="#ephemeral-storage-in-delegate-helm-charts" id="ephemeral-storage-in-delegate-helm-charts"></a>

To manage temporary disk space efficiently, you can configure ephemeral storage for the Harness Delegate using Helm charts. This guide walks you through defining custom volumes and applying the configuration during Helm installation.

The setup is cloud-agnostic and works across providers by adjusting the storage class as needed.

1. Create a `values.yaml` file and add the following configuration to it.

   ```yaml
      custom_mounts:
      - mountPath: "/scratch"
         name: scratch-volume

      custom_volumes:
      - name: scratch-volume
         ephemeral:
            volumeClaimTemplate:
            metadata:
               labels:
                  type: <YOUR-TYPE-REFERENCE>
            spec:
               accessModes: [ "ReadWriteOnce" ]
               storageClassName: "<YOUR-STORAGE-CLASS>"
               resources:
                  requests:
                  storage: <STORAGE-SIZE>
   ```

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>Before proceeding with installation, ensure a suitable StorageClass exists in your cluster. This is required for provisioning ephemeral volumes as defined in your values.yaml.</p><p>You can check the available storage classes using:</p><pre class="language-bash"><code class="lang-bash">kubectl get storageclass
   </code></pre><p>If your cluster doesn’t have a suitable <code>StorageClass</code>, you can create one using:</p><pre class="language-bash"><code class="lang-bash">kubectl apply -f storage-class.yaml
   </code></pre><p>Example <code>storage-class.yaml</code>:</p><pre class="language-yaml"><code class="lang-yaml">apiVersion: storage.k8s.io/v1
   kind: StorageClass
   metadata:
   name: &#x3C;YOUR-STORAGE-CLASS-NAME>
   provisioner: &#x3C;YOUR-STORAGE-PROVISIONER>  # e.g., kubernetes.io/aws-ebs, pd.csi.storage.gke.io
   parameters:
   type: &#x3C;YOUR-VOLUME-TYPE>               # e.g., gp2 for AWS
   reclaimPolicy: &#x3C;YOUR-RECLAIM-POLICY>     # e.g., Retain or Delete
   volumeBindingMode: WaitForFirstConsumer
   </code></pre><p>After creating the <code>StorageClass</code>, configure it in the Helm chart by setting: <code>--set persistence.storageClass=&#x3C;YOUR-STORAGE-CLASS-NAME></code></p></div>
2. Install the Helm chart using the example below, which applies the configuration from `values.yaml` file we created earlier:

   ```yaml
      helm upgrade -i <YOUR-DELEGATE-NAME> --namespace harness-delegate-ng --create-namespace \
      harness-delegate/harness-delegate-ng \
      --set delegateName=<YOUR-DELEGATE-NAME> \
      --set accountId=XXXXXXXXXXXXXXXX \
      --set delegateToken=XXXXXXXXXXXXXXXXXXXXXX \
      --set managerEndpoint=https://<YOUR-URL>.harness.io \
      --set delegateDockerImage=us-west1-docker.pkg.dev/gar-setup/docker/delegate:<DELEGATE-TAG-VERSION> \
      --set replicas=1 --set upgrader.enabled=true \
      -f values.yaml
   ```
3. Verify that the ephemeral storage has been mounted correctly by inspecting the pod’s volume mounts.

   * Get the Pod Name

     ```bash
     kubectl get pods -n harness-delegate-ng
     ```

     Output:

     ```bash
     NAME                                  READY   STATUS    RESTARTS   AGE
     delegate-ephemeral-storage            1/1     Running   0          2m
     ```
   * Describe the Pod

     ```bash
     kubectl describe pod delegate-ephemeral-storage -n harness-delegate-ng
     ```

     Look for the similar section below in your output

     ```bash
     Volumes:
     scratch-volume:
        Type:       PersistentVolumeClaim (a reference to a PVC)
        ClaimName:  scratch-volume-delegate-ephemeral-storage
        ReadOnly:   false

     Mounts:
     /scratch from scratch-volume (rw)
     ```

     This confirms that your ephemeral volume (scratch-volume) is mounted to /scratch in the pod.

   <div data-gb-custom-block data-tag="hint" data-style="warning" class="hint hint-warning"><p><strong>IMPORTANT NOTE:</strong></p><p>Ephemeral storage is automatically deleted when the pod is terminated, and a new volume is created when a new pod starts. This ensures the storage is tied to the pod’s lifecycle and is not persistent.</p></div>

### Deploy using a custom role <a href="#deploy-using-a-custom-role" id="deploy-using-a-custom-role"></a>

During delegate installation, you have the option to deploy using a custom role. To use a custom role, you must edit the delegate YAML file.

Harness supports the following custom roles:

* `cluster-admin`
* `cluster-viewer`
* `namespace-admin`
* custom cluster roles

To deploy using a custom cluster role, do the following:

1. Open the delegate YAML file in your text editor.
2. Add the custom cluster role to the `roleRef` field in the delegate YAML.

   ```yaml
   ---
   apiVersion: rbac.authorization.k8s.io/v1beta1
   kind: ClusterRoleBinding
   metadata:
     name: harness-delegate-cluster-admin
   subjects:
     - kind: ServiceAccount
       name: default
       namespace: harness-delegate-ng
   roleRef:
     kind: ClusterRole
     name: cluster-admin
     apiGroup: rbac.authorization.k8s.io
   ---
   ```

   In this example, the `cluster-admin` role is defined.
3. Save the delegate YAML file.

### Verify delegate connectivity <a href="#verify-delegate-connectivity" id="verify-delegate-connectivity"></a>

Select **Continue**. After the health checks pass, your delegate is available for you to use. Select **Done** and verify your new delegate is listed.

#### Helm chart & Terraform Helm provider <a href="#helm-chart-and-terraform-helm-provider" id="helm-chart-and-terraform-helm-provider"></a>

#### Kubernetes manifest <a href="#kubernetes-manifest" id="kubernetes-manifest"></a>

#### Docker <a href="#docker" id="docker"></a>

You can now route communication to external systems in Harness connectors and pipelines by selecting this delegate via a delegate selector.

### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

The delegate installer provides troubleshooting information for each installation process. If the delegate cannot be verified, select **Troubleshoot** for steps you can use to resolve the problem. This section includes the same information.

Harness asks for feedback after the troubleshooting steps. You are asked, **Did the delegate come up?**

If the steps did not resolve the problem, select **No**, and use the form to describe the issue. You'll also find links to Harness Support and to [Delegate docs](/harness-ai/use-harness-platform/delegates/delegate/delegate-concepts/delegate-overview.md).

Use the following steps to troubleshoot your installation of the delegate using Helm.Verify that Helm is correctly installed:Check for Helm:helmAnd then check for the installed version of Helm:helm versionIf you receive the message Error: rendered manifests contain a resource that already exists..., delete the existing namespace, and retry the Helm upgrade command to deploy the delegate.For further instructions on troubleshooting your Helm installation, go to Helm troubleshooting guide.Check the status of the delegate on your cluster:kubectl describe pods -n \<NAMESPACE>If the pod did not start, check the delegate logs:kubectl logs -f \<DELEGATE\_NAME> -n \<NAMESPACE>If the state of the delegate pod is CrashLoopBackOff, check your allocation of compute resources (CPU and memory) to the cluster. A state of CrashLoopBackOff indicates insufficient Kubernetes cluster resources.If the delegate pod is not healthy, use the kubectl describe command to get more information:kubectl describe \<POD\_NAME> -n \<NAMESPACE>Use the following steps to troubleshoot your installation of the delegate using Terraform.Verify that Terraform is correctly installed:terraform -versionFor further instructions on troubleshooting your installation of Terraform, go to the Terraform troubleshooting guide.Check the status of the delegate on your cluster:kubectl describe pods -n \<namespace>If the pod did not start, check the delegate logs:kubectl logs -f \<DELEGATE\_NAME> -n \<NAMESPACE>If the state of the delegate pod is CrashLoopBackOff, check your allocation of compute resources (CPU and memory) to the cluster. A state of CrashLoopBackOff indicates insufficient Kubernetes cluster resources.If the delegate pod is not healthy, use the kubectl describe command to get more information:kubectl describe \<POD\_NAME> -n \<NAMESPACE>Use the following steps to troubleshoot your installation of the delegate using Kubernetes.Check the status of the delegate on your cluster:kubectl describe pods -n \<NAMESPACE>If the pod did not start, check the delegate logs:kubectl logs -f \<DELEGATE\_NAME> -n \<NAMESPACE>If the state of the delegate pod is CrashLoopBackOff, check your allocation of compute resources (CPU and memory) to the cluster. A state of CrashLoopBackOff indicates insufficient Kubernetes cluster resources.If the delegate pod is not healthy, use the kubectl describe command to get more information:kubectl describe \<POD\_NAME> -n \<NAMESPACE>Use the following steps to troubleshoot your installation of the delegate using Docker:Check the status of the delegate on your cluster:docker container ls -aIf the pod is not running, check the delegate logs:docker container logs \<DELEGATE\_NAME> -fRestart the delegate container. To stop the container:docker container stop \<DELEGATE\_NAME>To start the container:docker container start \<DELEGATE\_NAME>Make sure the container has sufficient CPU and memory resources. If not, remove the older containers:docker container rm \[container id]

</details>

To learn more, watch the [Delegate overview](/harness-ai/use-harness-platform/delegates/delegate/delegate-concepts/delegate-overview.md) video.

6. Back in **Set Up Delegates**, you can select the new Delegate. In the list of Delegates, you can see your new Delegate and its tags.
7. Select the **Connect using Delegates with the following Tags** option.
8. Enter the tag of the new Delegate and select **Save and Continue**. When you are done, the Connector is tested.
9. Select **Continue**.
10. In **Manifest Details**, enter the following settings, test the connection, and click **Submit**. We are going to provide connection and path information for a manifest located at `https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/nginx-app.yaml`.
    * **Manifest Identifier:** enter **nginx**.
    * **Git Fetch Type\*\***:\*\* select \*\*Latest from Branch\*\*.
    * **Branch:** enter **main**.
    * **File/Folder path:**`content/en/examples/application/nginx-app.yaml`. This is the path from the repo root.

The manifest is now listed.

![](/files/PV1bsWXNrguPJ2IIAESg)

11. Select **Next** at the bottom of the **Service** tab.

Now that the artifact and manifest are defined, you can define the target cluster for your deployment.

### Define the target cluster for the Kubernetes deployment <a href="#define-the-target-cluster-for-the-kubernetes-deployment" id="define-the-target-cluster-for-the-kubernetes-deployment"></a>

The target cluster is your own Kubernetes cluster, hosted in your cloud environment. This is where we will deploy the Docker image using the manifest you selected.

Harness connects to all of the common cloud platforms and provides a platform-agnostic Kubernetes cluster connection that can connect to Kubernetes anywhere.

1. In **Infrastructure Details**, in **Specify your environment**, select **New Environment**. Just like with a service, you can create a new environment or selecting an existing one. We'll create a new one.
2. In **New Environment**, enter a name, select **Pre-Production**, and select **Save**. The new environment appears.
3. In **Infrastructure Definition**, select **Kubernetes**.

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>Let's take a moment and review Harness environments and infrastructure definitions. Harness environments represent your deployment targets logically (QA, Prod, etc). You can add the same Environment to as many stages as you need. Infrastructure definitions represent your target infrastructure physically. They are the actual clusters, hosts, etc.</p><p>By separating environments and infrastructure definitions, you can use the same environment in multiple stages while changing the target infrastructure settings with each stage.</p></div>
4. An **Infrastructure Definition** is where you specify the target for your deployment. In this case, your Kubernetes cluster and namespace.
5. In **Cluster Details**, in **Connector**, select **Select a connector**.
6. Select **New Connector**.
7. The Kubernetes cluster connector appears.

   ![](/files/PS3o3Go853Uw0WHvTWNX)

The Kubernetes cluster connector is covered in detail [here](/harness-ai/use-harness-platform/connectors/cloud-providers/ref-cloud-providers/kubernetes-cluster-connector-settings-reference.md), but let's quickly walk through it.

Let's look at the steps:

1. In **Kubernetes Cluster Connector**, in **Name**, enter **Kubernetes Quickstart**, and select **Continue**.
2. In **Details**, select **Use the credentials of a specific Harness Delegate**. We will select the Delegate next.

   ![](/files/1FMn0a6e7E4UM65Rd0F1)
3. Select **Continue**.
4. Select the Kubernetes Delegate you added earlier using its Tags, and then select **Save and Continue**. Harness verifies the Connector.
5. Select **Finish**.
6. Select the new Connector and then select **Apply Selected**.
7. Back in **Cluster Details**, in **Namespace**, enter the target namespace for the deployment. For example, **default**. You can use any namespace in your target cluster.
8. In **Advanced**, in **Release name**, enter `quickstart`. For a release name, you can use a built-in or custom expression or any text you like. Harness requires a release name for tracking. It is applied to the pods as a label. The release name must be unique across the cluster.
9. When you are done, the **Cluster Details** will look something like this:

   ![](/files/6QnJcAvbn2gjilF0tg6I)

   The target infrastructure is complete. Now we can add our stage steps.
10. Select **Next** to move onto **Execution**.

### Add a Kubernetes rollout deployment step to the stage <a href="#add-a-kubernetes-rollout-deployment-step-to-the-stage" id="add-a-kubernetes-rollout-deployment-step-to-the-stage"></a>

Now you can select the [deployment strategy](/continuous-delivery/use-continuous-delivery/manage-deployments/deployment-concepts.md) for this stage of the pipeline.

1. In **Execution Strategies**, select **Rolling**, and then select **Use Strategy**.

   ![](/files/HQUzTQiBVw4x7W4qnYl9)
2. The **Rollout Deployment** step is added.

   ![](/files/uLIlFxvTHAZKyzKgHuYp)

   This is a standard [Kubernetes rolling update](https://kubernetes.io/docs/tutorials/kubernetes-basics/update/update-intro/). By default, Harness uses a `25% max unavailable, 25% max surge` strategy.

That's it. Now the pipeline stage is complete and you can deploy.

### Deploy the Kubernetes pipeline and review <a href="#deploy-the-kubernetes-pipeline-and-review" id="deploy-the-kubernetes-pipeline-and-review"></a>

1. Select **Save** **> Save Pipeline** and then **Run**. Now you can select the specific artifact to deploy.
2. In **Primary Artifact**, select **stable**. This is the same as using `docker pull nginx:stable`.
3. Select **Run Pipeline**. Harness will verify the Pipeline and then run it. You can see the status of the deployment, and pause or abort it.

   ![](/files/bjEbmjr610xljJbKS8XN)
4. Toggle **Console View** to watch the deployment with more detailed logging. Select the **Rollout Deployment** step and expand **Wait for Steady State**.

   You can see `deployment "my-nginx" successfully rolled out`.

   ![](/files/f1YvxGEhyTNZMXhtSetI)

Congratulations! The deployment was successful.

In your project's **Deployments**, you can see the deployment listed:

![](/files/rak2gc2sHtxuVJ4hEinf)

If you run into any errors, it is typically because the cluster does meet the requirements from [Before You Begin](#before_you_begin) section or the cluster's network setting does not allow the Delegate to connect to Docker Hub.In this tutorial, you learned how to:

* Install and launch a Harness Kubernetes Delegate in your target cluster.
* Connect Harness to your Kubernetes cluster and an artifact server.
* Add your manifests to Harness.
* Create an infrastructure definition that targets your cluster and namespace.
* Add a Kubernetes rolling update.
* Deploy your Kubernetes pipeline to your target cluster.

Next, try using Harness [Continuous Integration](/continuous-integration/new-to-harness-ci/onboarding-guide.md) to build a codebase, upload it to a repo, and run unit and integrations tests.

### Detailed diagnostics for K8s Deployment <a href="#detailed-diagnostics-for-k8s-deployment" id="detailed-diagnostics-for-k8s-deployment"></a>

Harness provides detailed log information for pods and container during the Wait For Steady State step in Kubernetes deployments, helping you troubleshoot deployment issues by providing real-time insights into pod statuses.

{% hint style="info" %}
Currently, this feature is behind the feature flag `CDS_K8S_DETAILED_LOGS`. Contact [Harness Support](mailto:support@harness.io) to enable the feature.
{% endhint %}

These logs include detailed information from `status.condition`, `status.containerStatuses`, and `status.initContainerStatuses` during the Wait For Steady State step.

**Key Details**:

* Logs are polled every 30 seconds. If the task completes in less than 30 seconds, no logs will be displayed.
* The log output visually represents the status of the pods and container using color codes. Below is an example of how the container statuses appear in the logs.
  * Red: Terminated ![](/files/OTfeLtrx35bFaNXVmDx1)
  * Yellow: Waiting ![](/files/83QaayrU864TPEqf0I6U)
  * White: Running ![](/files/iESlOue2iDW8FohnOW3d)

### Clean up the deployment <a href="#clean-up-the-deployment" id="clean-up-the-deployment"></a>

For steps on deleting the Delegate, go to [delete a delegate](/harness-ai/use-harness-platform/delegates/delegate/manage-delegates/delete-a-delegate.md).

### Next steps <a href="#next-steps" id="next-steps"></a>

See \[CD tutorials]\(/docs/continuous-delivery/get-started/tutorials/cd-gitops-tutorials for other deployment features.
