> For the complete documentation index, see [llms.txt](https://docs.qpoint.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.qpoint.io/getting-started/qplane/installation/kubernetes-manifest.md).

# Kubernetes Manifest

This guide covers deploying Qtap in cloud-connected mode using a Kubernetes manifest, managed through the Qplane control plane. Use this approach when you need full control over your Kubernetes resources or can't use Helm directly.

## Preflight Check

If you'd like to verify your environment's compatibility, use the [following script](https://github.com/qpoint-io/preflight/tree/main):

{% code overflow="wrap" %}

```bash
curl -sSL https://github.com/qpoint-io/preflight/releases/latest/download/preflight.sh | sudo bash
```

{% endcode %}

## Prerequisites

* Kubernetes cluster on Linux hosts with supported kernel (5.10+)
* `kubectl` configured for your cluster
* `helm` (for generating the base manifest)
* A valid registration token from [app.qpoint.io](https://app.qpoint.io) (Settings → Installation)

## Generating the Base Manifest

Use the Helm chart to generate a static Kubernetes manifest:

```bash
helm repo add qpoint https://helm.qpoint.io/
helm repo update
```

Generate the manifest with your registration token stored in a Kubernetes secret:

```bash
helm template qtap qpoint/qtap \
  --set registrationTokenSecretRefName="qtap-token" \
  --set logLevel=warn \
  > qtap-manifest.yaml
```

To see all available chart values:

```bash
helm show values qpoint/qtap
```

## Creating the Registration Token Secret

Store your registration token as a Kubernetes secret:

```bash
kubectl create namespace qpoint
```

```bash
kubectl create secret generic qtap-token \
  --from-literal=token='<your-registration-token>' \
  -n qpoint
```

{% hint style="warning" %}
Keep your registration token secure. Do not commit it to version control or include it directly in manifest files.
{% endhint %}

## Deploying

Apply the generated manifest:

```bash
kubectl apply -f qtap-manifest.yaml -n qpoint
```

## Verifying the Deployment

1. Check that pods are running:

```bash
kubectl get pods -n qpoint
```

You should see `qtap-xxxx` pods in the Running state — one per node (DaemonSet).

2. Check the logs:

```bash
kubectl logs -n qpoint daemonset/qtap --tail 30
```

Look for a successful registration message indicating the agent has connected to Qplane.

3. Confirm the agent appears in the [Qplane dashboard](https://app.qpoint.io) under your environment.

## Example Manifest

Here's a complete manifest for cloud-connected deployment with a registration token secret. You can use this directly instead of generating from Helm:

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: qtap
  namespace: qpoint
  labels:
    app.kubernetes.io/name: qtap
    app.kubernetes.io/instance: qtap
automountServiceAccountToken: true
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: qtap
  namespace: qpoint
  labels:
    app.kubernetes.io/name: qtap
    app.kubernetes.io/instance: qtap
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: qtap
      app.kubernetes.io/instance: qtap
  template:
    metadata:
      labels:
        app.kubernetes.io/name: qtap
        app.kubernetes.io/instance: qtap
    spec:
      hostPID: true
      hostNetwork: true
      serviceAccountName: qtap
      containers:
        - name: qtap
          image: "us-docker.pkg.dev/qpoint-edge/public/qtap:v0"
          imagePullPolicy: IfNotPresent
          securityContext:
            privileged: true
            allowPrivilegeEscalation: true
            runAsUser: 0
            runAsGroup: 0
            runAsNonRoot: false
            readOnlyRootFilesystem: false
            capabilities:
              add:
                - CAP_BPF
                - CAP_SYS_ADMIN
          env:
            - name: REGISTRATION_TOKEN
              valueFrom:
                secretKeyRef:
                  name: qtap-token
                  key: token
            - name: STATUS_LISTEN
              value: "0.0.0.0:10001"
            - name: LOG_LEVEL
              value: "warn"
            - name: LOG_ENCODING
              value: "json"
            - name: TINI_SUBREAPER
              value: "1"
          ports:
            - name: status
              containerPort: 10001
              protocol: TCP
          startupProbe:
            httpGet:
              path: /readyz
              port: status
            initialDelaySeconds: 3
            periodSeconds: 5
            timeoutSeconds: 2
            successThreshold: 1
            failureThreshold: 20
          readinessProbe:
            httpGet:
              path: /readyz
              port: status
            initialDelaySeconds: 3
            periodSeconds: 5
            timeoutSeconds: 2
            successThreshold: 1
            failureThreshold: 1
          livenessProbe:
            httpGet:
              path: /healthz
              port: status
            initialDelaySeconds: 3
            periodSeconds: 10
            timeoutSeconds: 2
            successThreshold: 1
            failureThreshold: 3
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 1000m
              memory: 1Gi
          volumeMounts:
            - name: sys
              mountPath: /sys
              readOnly: true
            - name: containerd-socket
              mountPath: /run/containerd/containerd.sock
      volumes:
        - name: sys
          hostPath:
            path: /sys
            type: Directory
        - name: containerd-socket
          hostPath:
            path: /run/containerd/containerd.sock
            type: Socket
```

{% hint style="info" %}
No ConfigMap is needed for cloud-connected mode. Qplane pushes configuration (stacks, plugins, filters) to the agent after registration. Any changes you make in the Qplane UI are applied automatically.
{% endhint %}

## Adding Tags

Tags help you filter and organize agents in the Qplane dashboard. Add them as extra arguments in the container spec:

```yaml
          args:
            - "--tags=Environment:Production,Cluster:EKS-1"
```

See [Organizations & Environments](/getting-started/qplane/configuration/organizations-and-environments.md#agent-tags) for when to use tags vs separate installations.

## Adding S3 Credentials

If your Qplane environment uses an S3 object store for payload storage, inject the credentials alongside the registration token:

```bash
kubectl create secret generic qpoint-s3-creds \
  --from-literal=AWS_ACCESS_KEY_ID='<access-key>' \
  --from-literal=AWS_SECRET_ACCESS_KEY='<secret-key>' \
  -n qpoint
```

Add `envFrom` to the container spec:

```yaml
          envFrom:
            - secretRef:
                name: qpoint-s3-creds
```

## Uninstalling

```bash
kubectl delete -f qtap-manifest.yaml -n qpoint
kubectl delete secret qtap-token -n qpoint
```

## Understanding the Manifest

The manifest creates the following resources:

| Resource           | Purpose                                |
| ------------------ | -------------------------------------- |
| **ServiceAccount** | Identity for Qtap pods                 |
| **DaemonSet**      | Runs Qtap on every node in the cluster |

Key DaemonSet settings:

* **`hostPID: true`** and **`hostNetwork: true`** — Required for eBPF to observe host processes and network traffic
* **Privileged security context** — Required for loading BPF programs (`CAP_BPF`, `CAP_SYS_ADMIN`)
* **`/sys` mount** — Access to kernel interfaces for eBPF
* **containerd socket** — Enables container attribution (maps traffic to container names and labels). Optional; remove if not using containerd.
* **Probes** — Startup, readiness, and liveness checks on the `/readyz` and `/healthz` endpoints

## Common Customizations

* **Node selectors or tolerations** — Target specific nodes or schedule on tainted nodes
* **Resource limits** — Adjust CPU and memory based on your traffic volume
* **Container runtime socket** — Change from containerd to CRI-O (`/var/run/crio/crio.sock`) if applicable
* **Image tag** — Pin to a specific version (e.g., `qtap:v0.17.1`) instead of the rolling `v0` tag

## Troubleshooting

1. **Pods not starting:**

```bash
kubectl describe pod -n qpoint -l app.kubernetes.io/name=qtap
```

Check for security policy violations or missing secrets.

2. **Agent not appearing in Qplane:**

```bash
kubectl logs -n qpoint daemonset/qtap --tail 50
```

Verify the registration token is correct and the cluster can reach `api.qpoint.io:443`.

3. **Kernel compatibility:**

```bash
kubectl debug node/<node-name> -it --image=ubuntu -- uname -r
```

Kernel must be 5.10 or later.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.qpoint.io/getting-started/qplane/installation/kubernetes-manifest.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
