> 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/use-continuous-delivery/deploy-services-on-different-platforms/kubernetes/kubernetes-cd-quickstart.md).

# Kubernetes deployments

Deploy a Docker image into your Kubernetes cluster.

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.

## What you will learn from this topic

* How to set up a Kubernetes CD pipeline with a rolling update strategy in Harness
* How to configure a Harness Delegate, Kubernetes connector, service, and environment
* How to run the 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 will 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.\
  Go to [User-Facing Roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) from Kubernetes to review required permissions.

### 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. This topic creates a new pipeline and adds a single stage.

{% hint style="info" %}
**Create a project for your new Continuous Delivery (CD) pipeline**

If a Harness project does not already exist, 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](https://developer.harness.io/docs/platform/new-to-harness-platform/overview#organizations-and-projects) for more information.
{% endhint %}

1. In your Harness project, select **Deployments**, and then select **Create a Pipeline**. ![Create a Pipeline option in the Deployments page](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-b06b01cb4b40ea0d5041db4237f428be578e80d4%2Fkustomize-quickstart-65.png?alt=media)
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>Harness services and service definitions (explained below) are reviewed briefly here. 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 Kubernetes manifest for deployment <a href="#add-the-kubertnetes-manifest-for-deployment" id="add-the-kubertnetes-manifest-for-deployment"></a>

Next, add a Kubernetes manifest for NGINX using the [publicly-available manifest](https://github.com/kubernetes/website/blob/master/content/en/examples/application/nginx-app.yaml) 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></p><p>This quickstart uses 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, 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>). Go to <a href="/continuous-delivery/use-continuous-delivery/deploy-services-on-different-platforms/kubernetes/cd-kubernetes-category/add-artifacts-for-kubernetes-deployments.md">Add Container Images as Artifacts for Kubernetes Deployments</a> to review this scenario.</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. A Harness secret is required 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 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 the PAT has the **repo** scope selected:

     ![GitHub Personal Access Token repo scope selected](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-504b98725a747e6007be0bb9f8d26e39b675641a%2FrepoScope.png?alt=media)
6. Select **Continue**.
7. In **Connect to the provider**, select **Connect through a Harness Delegate**, and then select **Continue**. The **Connect through Harness Platform** option is not used here because a Delegate is needed later for the connection to your target Kubernetes cluster. Typically, the **Connect through Harness Platform** option is a 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](https://developer.harness.io/docs/platform/delegates/delegate/delegate-concepts/delegate-overview) 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 use the delegate to execute the Continuous Integration/Continuous Delivery (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**

You can install delegates from the Account, Project, or Org scope. In this example, 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 uses this token to authenticate with the Harness Platform.

**Get your Harness account ID**

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 %}

Go to [View account info and subscribe to downtime alerts](https://developer.harness.io/docs/platform/subscriptions-and-licenses/view-account-info-and-subscribe-to-alerts) to review your Harness account ID.

**Prerequisite**

Ensure access to a Kubernetes cluster. For the purposes of this tutorial, use minikube.

**Install minikube**

On Windows:

```bash
choco install minikube
```

For 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:

```bash
brew install minikube
```

For Homebrew installation instructions, go to Installation in the Homebrew documentation.

Now start minikube with the following config.

```bash
minikube start --memory 4g --cpus 4
```

Validate that you have `kubectl` access to your cluster.

```bash
kubectl get pods -A
```

Now that you have access to a Kubernetes cluster, install the delegate using any of the options below.

**Install the Helm chart**

As a prerequisite, Helm v3 must be installed on the machine from which you connect to your Kubernetes cluster.

Install the delegate using the delegate Helm chart. First, add the `harness-delegate` Helm chart repo to your local Helm registry.

```bash
helm repo add harness-delegate https://app.harness.io/storage/harness-download/delegate-helm-chart/
helm repo update
helm search repo harness-delegate
```

This tutorial uses the `harness-delegate/harness-delegate-ng` chart.

```
NAME                                   CHART VERSION   APP VERSION     DESCRIPTION
harness-delegate/harness-delegate-ng   1.0.8           1.16.0          A Helm chart for deploying harness-delegate
```

The following example installs/upgrades the `firstk8sdel` delegate (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, install a delegate in the Account scope.

Perform the following steps to install a delegate:

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 **New Delegate**. The New Delegate dialog opens.
4. Under **Select where you want to install your Delegate**, select **Kubernetes**.
5. Under **Install your Delegate**, select **Helm Chart**.
6. 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, download and update the `values.yaml` file according to your requirements. Once the file is updated, use it by running the upgrade command below.

   ```bash
   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=true
   ```

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><strong>Note</strong></p><p>To install a Helm delegate for Harness Self-Managed Enterprise Edition in an air-gapped environment, pass your certificate when you add the Helm repo.</p><pre class="language-bash"><code class="lang-bash">helm repo add harness-delegate --ca-file &#x3C;.PEM_FILE_PATH> &#x3C;HELM_CHART_URL_FROM_UI>
   </code></pre><p>Go to Install in an air-gapped environment to review requirements for air-gapped environments.</p></div>
7. Run the command.

**Create main.tf file**

Harness 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 on the same machine at the `~/.kube/config` path. Copy the following into a `main.tf` file stored on the machine from which you want to install the delegate.

```hcl
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"
  }
}
```

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, find the Harness Cluster Location on the Account Overview page under the Account Settings section of the left navigation.

**Run Terraform init, plan, and apply**

Initialize Terraform. This downloads the Terraform Helm provider to the machine.

```bash
terraform init
```

Run the following step to view the changes Terraform is going to make.

```bash
terraform plan
```

Finally, run this step to make Terraform install the Kubernetes delegate using the Helm provider.

```bash
terraform apply
```

When prompted by Terraform whether to continue with the apply step, type `yes`. Output similar to the following appears.

```
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 template**

```bash
curl -LO https://raw.githubusercontent.com/harness/delegate-kubernetes-manifest/main/harness-delegate.yaml
```

**Replace variables in the template**

Open 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 the 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, find the Harness Cluster Location on the Account Overview page under the Account Settings section of the left navigation.

**Apply the Kubernetes manifest**

```bash
kubectl apply -f harness-delegate.yaml
```

**Prerequisites**

Ensure that the Docker runtime is installed on your host. If not, use one of the following options to install Docker: Docker for Mac, Docker for CentOS, Docker for Ubuntu, Docker for Debian, or Docker for Windows.

**Install on Docker**

You can install delegates from the Account, Project, or Org scope. In this example, install a delegate in the Project scope.

Perform the following steps to install a delegate:

1. In Harness, select your project, then select **Project Settings**.
2. Under **Project-level resources**, select **Delegates**.
3. Select **Install a Delegate** to open the New Delegate dialog.
4. Under **Select where you want to install your Delegate**, select **Docker**.
5. Under **Install your Delegate**, enter a delegate name.
6. Copy the docker run command.

   ```bash
   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.verno
   ```

   The docker run command does not allow you to select the delegate token. You can replace the token in the command with another token if required.
7. (Optional) Replace the `YOUR_MANAGER_HOST_AND_PORT_HERE` variable with the Harness Manager Endpoint noted below. For Harness SaaS accounts, to find the Harness cluster location, select **Account Settings**, then select **Overview**. In Account Overview, look in Account Settings; it is listed next to Harness Cluster Hosting Account. Steps 6 and 7 are optional when installing a delegate using the CLI flow.

   Go to [View account info and subscribe to downtime alerts](https://developer.harness.io/docs/platform/subscriptions-and-licenses/view-account-info-and-subscribe-to-alerts) to review your Harness account ID. For Harness CDCE, the endpoint varies based on the Docker vs. Helm installation options.
8. 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 <code>values.yaml</code>.</p><p>Check the available storage classes using:</p><pre class="language-bash"><code class="lang-bash">kubectl get storageclass
   </code></pre><p>If the cluster does not have a suitable <code>StorageClass</code>, 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 the `values.yaml` file 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</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**

**Kubernetes manifest**

**Docker**

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. Links to Harness Support and to [Delegate docs](https://developer.harness.io/docs/platform/delegates/delegate/delegate-concepts/delegate-overview) are also available.

**Troubleshoot a Helm installation**

Perform the following steps to troubleshoot an installation of the delegate using Helm:

1. Verify that Helm is correctly installed.

   ```bash
   helm
   ```

   Then check for the installed version of Helm.

   ```bash
   helm version
   ```

   If 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 the Helm troubleshooting guide.
2. Check the status of the delegate on your cluster.

   ```bash
   kubectl describe pods -n <NAMESPACE>
   ```
3. If the pod did not start, check the delegate logs.

   ```bash
   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.
4. If the delegate pod is not healthy, use the `kubectl describe` command to get more information.

   ```bash
   kubectl describe <POD_NAME> -n <NAMESPACE>
   ```

**Troubleshoot a Terraform installation**

Perform the following steps to troubleshoot an installation of the delegate using Terraform:

1. Verify that Terraform is correctly installed.

   ```bash
   terraform -version
   ```

   For further instructions on troubleshooting your installation of Terraform, go to the Terraform troubleshooting guide.
2. Check the status of the delegate on your cluster.

   ```bash
   kubectl describe pods -n <namespace>
   ```
3. If the pod did not start, check the delegate logs.

   ```bash
   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.
4. If the delegate pod is not healthy, use the `kubectl describe` command to get more information.

   ```bash
   kubectl describe <POD_NAME> -n <NAMESPACE>
   ```

**Troubleshoot a Kubernetes manifest installation**

Perform the following steps to troubleshoot an installation of the delegate using Kubernetes:

1. Check the status of the delegate on your cluster.

   ```bash
   kubectl describe pods -n <NAMESPACE>
   ```
2. If the pod did not start, check the delegate logs.

   ```bash
   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.
3. If the delegate pod is not healthy, use the `kubectl describe` command to get more information.

   ```bash
   kubectl describe <POD_NAME> -n <NAMESPACE>
   ```

**Troubleshoot a Docker installation**

Perform the following steps to troubleshoot an installation of the delegate using Docker:

1. Check the status of the delegate on your cluster.

   ```bash
   docker container ls -a
   ```
2. If the pod is not running, check the delegate logs.

   ```bash
   docker container logs <DELEGATE_NAME> -f
   ```
3. Restart the delegate container. To stop the container:

   ```bash
   docker container stop <DELEGATE_NAME>
   ```

   To start the container:

   ```bash
   docker container start <DELEGATE_NAME>
   ```
4. Make sure the container has sufficient CPU and memory resources. If not, remove the older containers.

   ```bash
   docker container rm [container id]
   ```

</details>

Go to [Delegate overview](https://developer.harness.io/docs/platform/delegates/delegate/delegate-concepts/delegate-overview) to watch the 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**. These settings 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.

![Manifest listed in the Manifests section of the Service tab](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-047f5b56fc84cb6444d09cc8c97dfde6addfd744%2Fkubernetes-cd-quickstart-87.png?alt=media)

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 the Docker image is deployed 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 select an existing one. This procedure creates 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>Harness environments and infrastructure definitions are reviewed briefly here. Harness environments represent your deployment targets logically (QA, production, and so on). 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.

   ![Kubernetes cluster connector configuration](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-efdcabf62c188bd6d59704dbcc1c8297233dc9b4%2Fkustomize-quickstart-74.png?alt=media)

The Kubernetes cluster connector is covered in detail in the [Kubernetes Cluster Connector Settings Reference](https://developer.harness.io/docs/platform/connectors/cloud-providers/ref-cloud-providers/kubernetes-cluster-connector-settings-reference). The following steps provide a quick walkthrough.

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**. The Delegate is selected next.

   ![Details step with the option to use a specific Harness Delegate's credentials](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-6635b3580a6fb3f3d9e0a8b65b3d5479a958fc2d%2Fkustomize-quickstart-75.png?alt=media)
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:

   ![Completed Cluster Details settings for the target infrastructure](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-c31fb7a1c863dd74b711291cdc5314a0a5edcc61%2Fkubernetes-cd-quickstart-90.png?alt=media)

   The target infrastructure is complete. You can now add the 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**.

   ![Rolling execution strategy selected for the stage](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-e597f6a7fe78352cd90e4eb74b0b3b5432cd38c6%2Fazure-cd-quickstart-107.png?alt=media)
2. The **Rollout Deployment** step is added.

   ![Rollout Deployment step added to the execution](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-4208527944a388b74da85e06a416625409a36b3b%2Fazure-cd-quickstart-108.png?alt=media)

   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 is 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.

   ![Pipeline run status showing deployment progress](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-f8639b718d088d935156a0d756516f4030b7d9ca%2Fazure-cd-quickstart-109.png?alt=media)
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`.

   ![Console view showing the deployment successfully rolled out](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-5be1b8a0aeb6c8a99a4cf55fe2faf235ad84981c%2Fkubernetes-cd-quickstart-94.png?alt=media)

Congratulations. The deployment was successful.

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

![Deployment listed on the project's Deployments page](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-dbffdbc7b6aad3d1ab6284fbcdac751a49e118dc%2Fkubernetes-cd-quickstart-95.png?alt=media)

If you run into any errors, it is typically because the cluster does not meet the requirements described earlier in this topic, 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](https://developer.harness.io/docs/continuous-integration/new-to-harness-ci/onboarding-guide) 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.

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 ![Red color code indicating a terminated container](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-b5fe9455b69d4b8fc18851ff8aeee093d5d3e2b2%2Fkubernetes-logs-3.png?alt=media)
  * Yellow: Waiting ![Yellow color code indicating a waiting container](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-77dd7b4578624350c83c1617c5a3ea5aa1153960%2Fkubernetes-logs.png?alt=media)
  * White: Running ![White color code indicating a running container](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-7f2a4ffd3c2c2bb31f7ba251f0ebcde9040279c3%2Fkubernetes-logs-2.png?alt=media)

### 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](https://developer.harness.io/docs/platform/delegates/delegate/manage-delegates/delete-a-delegate).

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

The CD tutorials cover other deployment features.

{% @harness-feedback/feedback %}
