kubernetes.mdx
  1  ---
  2  title: "Kubernetes"
  3  id: kubernetes
  4  slug: "/kubernetes"
  5  description: "Learn how to deploy your Haystack pipelines through Kubernetes."
  6  ---
  7  
  8  import ClickableImage from "@site/src/components/ClickableImage";
  9  
 10  # Kubernetes
 11  
 12  Learn how to deploy your Haystack pipelines through Kubernetes.
 13  
 14  The best way to get Haystack running as a workload in a container orchestrator like Kubernetes is to create a service to expose one or more [Hayhooks](../hayhooks.mdx) instances.
 15  
 16  ## Create a Haystack Kubernetes Service using Hayhooks
 17  
 18  As a first step, we recommend to create a local [KinD](https://github.com/kubernetes-sigs/kind) or [Minikube](https://github.com/kubernetes/minikube) Kubernetes cluster. You can manage your cluster from CLI, but tools like [k9s](https://k9scli.io/) or [Lens](https://k8slens.dev/) can ease the process.
 19  
 20  When done, start with a very simple Kubernetes Service running a single Hayhooks Pod:
 21  
 22  ```yaml
 23  kind: Pod
 24  apiVersion: v1
 25  metadata:
 26    name: hayhooks
 27    labels:
 28      app: haystack
 29  spec:
 30    containers:
 31      - image: deepset/hayhooks:v0.6.0
 32        name: hayhooks
 33        imagePullPolicy: IfNotPresent
 34        resources:
 35          limits:
 36            memory: "512Mi"
 37            cpu: "500m"
 38          requests:
 39            memory: "256Mi"
 40            cpu: "250m"
 41  
 42  ---
 43  
 44  kind: Service
 45  apiVersion: v1
 46  metadata:
 47    name: haystack-service
 48  spec:
 49    selector:
 50      app: haystack
 51    type: ClusterIP
 52    ports:
 53      # Default port used by the Hayhooks Docker image
 54      - port: 1416
 55  
 56  ```
 57  
 58  After applying the above to an existing Kubernetes cluster, a `hayhooks` Pod will show up as a Service called `haystack-service`.
 59  <ClickableImage src="/img/6eb9fb0c7b00367bfbe8182ffc7c3746f3f3d03b720e963df045e28160362d7f-Screenshot_2025-04-15_at_16.15.28.png" alt="Kubernetes Lens interface showing the hayhooks Pod running in the default namespace with status Running" />
 60  
 61  Note that the `Service` defined above is of type `ClusterIP`. That means it's exposed only _inside_ the Kubernetes cluster. To expose the Hayhooks API to the _outside_ world as well, you need a `NodePort` or `Ingress` resource. As an alternative, it's also possible to use [Port Forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to access the `Service` locally.
 62  
 63  To do that, add port `30080` to Host-To-Node Mapping of our KinD cluster. In other words, make sure that the cluster is created with a node configuration similar to the following:
 64  
 65  ```yaml
 66  kind: Cluster
 67  apiVersion: kind.x-k8s.io/v1alpha4
 68  nodes:
 69    - role: control-plane
 70      # ...
 71      extraPortMappings:
 72        - containerPort: 30080
 73          hostPort: 30080
 74          protocol: TCP
 75  ```
 76  
 77  Then, create a simple `NodePort`  to test if Hayhooks Pod is running correctly:
 78  
 79  ```yaml
 80  apiVersion: v1
 81  kind: Service
 82  metadata:
 83    name: haystack-nodeport
 84  spec:
 85    selector:
 86      app: haystack
 87    type: NodePort
 88    ports:
 89    - port: 1416
 90      targetPort: 1416
 91      nodePort: 30080
 92      name: http
 93  ```
 94  
 95  After applying this, `hayhooks` Pod will be accessible on `localhost:30080`.
 96  
 97  From here, you should be able to manage pipelines. Remember that it's possible to deploy multiple different pipelines on a single Hayhooks instance. Check the [Hayhooks docs](../hayhooks.mdx) for more details.
 98  
 99  ## Auto-Run Pipelines at Pod Start
100  
101  Hayhooks can load Haystack pipelines at startup, making them readily available when the server starts. You can leverage this mechanism to have your pods immediately serve one or more pipelines when they start.
102  
103  At startup, it will look for deployed pipelines on the path specified at `HAYHOOKS_PIPELINES_DIR`, then load them.
104  
105  A [deployed pipeline](https://github.com/deepset-ai/hayhooks?tab=readme-ov-file#deploy-a-pipeline) is essentially a directory which must contain a `pipeline_wrapper.py` file and possibly other files. To preload an [example pipeline](https://github.com/deepset-ai/hayhooks/tree/main/examples/pipeline_wrappers/chat_with_website), you need to mount a local folder inside the cluster node, then make it available on Hayhooks Pod as well.
106  
107  First, ensure that a local folder is mounted correctly on the KinD cluster node at `/data`:
108  
109  ```yaml
110  kind: Cluster
111  apiVersion: kind.x-k8s.io/v1alpha4
112  nodes:
113    - role: control-plane
114      # ...
115      extraMounts:
116        - hostPath: /path/to/local/pipelines/folder
117          containerPath: /data
118  ```
119  
120  Next, make `/data` available as a volume and mount it on Hayhooks Pod. To do that, update your previous Pod configuration to the following:
121  
122  ```yaml
123  kind: Pod
124  apiVersion: v1
125  metadata:
126    name: hayhooks
127    labels:
128      app: haystack
129  spec:
130    containers:
131      - image: deepset/hayhooks:v0.6.0
132        name: hayhooks
133        imagePullPolicy: IfNotPresent
134        command: ["/bin/sh", "-c"]
135        args:
136          - |
137            pip install trafilatura && \
138            hayhooks run --host 0.0.0.0
139        volumeMounts:
140          - name: local-data
141            mountPath: /mnt/data
142        env:
143          - name: HAYHOOKS_PIPELINES_DIR
144            value: /mnt/data
145          - name: OPENAI_API_KEY
146            valueFrom:
147              secretKeyRef:
148                name: openai-secret
149                key: api-key
150        resources:
151          limits:
152            memory: "512Mi"
153            cpu: "500m"
154          requests:
155            memory: "256Mi"
156            cpu: "250m"
157    volumes:
158      - name: local-data
159        hostPath:
160          path: /data
161          type: Directory
162  
163  ```
164  
165  Note that:
166  
167  - We changed the Hayhooks container `command` to install `trafilaura` dependency before startup, since it's needed for our [chat_with_website](https://github.com/deepset-ai/hayhooks/tree/main/examples/pipeline_wrappers/chat_with_website) example pipeline. For a real production environment, we recommend creating a custom Hayhooks image as described [here](docker.mdx#customizing-the-haystack-docker-image).
168  - We make Hayhooks container read `OPENAI_API_KEY` from a Kubernetes Secret.
169  
170  Before applying this new configuration, create the `openai-secret`:
171  
172  ```yaml
173  apiVersion: v1
174  kind: Secret
175  metadata:
176    name: openai-secret
177  type: Opaque
178  data:
179    # Replace the placeholder below with the base64 encoded value of your API key
180    # Generate it using: echo -n $OPENAI_API_KEY | base64
181    api-key: YOUR_BASE64_ENCODED_API_KEY_HERE
182  ```
183  
184  After applying this, check your Hayhooks Pod logs, and you'll see that the `chat_with_website` pipelines have already been deployed.
185  <ClickableImage src="/img/2dbf42dd2db1cb355ee7222d7f8e96c45b611200d83ca289be3456264a854c38-Screenshot_2025-04-16_at_09.19.14.png" alt="Kubernetes Lens interface displaying pod logs with application startup messages and deployed pipeline confirmation" />
186  
187  ## Roll Out Multiple Pods
188  
189  Haystack pipelines are usually stateless, which is a perfect use case for distributing the requests to multiple pods running the same set of pipelines. Let's convert the single-Pod configuration to an actual Kubernetes `Deployment`:
190  
191  ```yaml
192  apiVersion: apps/v1
193  kind: Deployment
194  metadata:
195    name: haystack-deployment
196  spec:
197    replicas: 3
198    selector:
199      matchLabels:
200        app: haystack
201    template:
202      metadata:
203        labels:
204          app: haystack
205      spec:
206        initContainers:
207          - name: install-dependencies
208            image: python:3.12-slim
209            workingDir: /mnt/data
210            command: ["/bin/bash", "-c"]
211            args:
212              - |
213                echo "Installing dependencies..."
214                pip install trafilatura
215                echo "Dependencies installed successfully!"
216                touch /mnt/data/init-complete
217            volumeMounts:
218              - name: local-data
219                mountPath: /mnt/data
220            resources:
221              requests:
222                memory: "64Mi"
223                cpu: "100m"
224              limits:
225                memory: "128Mi"
226                cpu: "250m"
227        containers:
228          - image: deepset/hayhooks:v0.6.0
229            name: hayhooks
230            imagePullPolicy: IfNotPresent
231            command: ["/bin/sh", "-c"]
232            args:
233              - |
234                pip install trafilatura && \
235                hayhooks run --host 0.0.0.0
236            ports:
237              - containerPort: 1416
238                name: http
239            volumeMounts:
240              - name: local-data
241                mountPath: /mnt/data
242            env:
243              - name: HAYHOOKS_PIPELINES_DIR
244                value: /mnt/data
245              - name: OPENAI_API_KEY
246                valueFrom:
247                  secretKeyRef:
248                    name: openai-secret
249                    key: api-key
250            resources:
251              requests:
252                memory: "256Mi"
253                cpu: "250m"
254              limits:
255                memory: "512Mi"
256                cpu: "500m"
257        volumes:
258          - name: local-data
259            hostPath:
260              path: /data
261              type: Directory
262  
263  ```
264  
265  Implementing the above configuration will create three pods. Each pod will run a different instance of Hayhooks, all serving the same example pipeline provided by the mounted volume in the previous example.
266  
267  <ClickableImage src="/img/f3f0ac4b22a37039f0837c22b0cb8b640937bbb0db4acfcbdf7bd016b545d84a-Screenshot_2025-04-16_at_09.32.07.png" alt="Kubernetes Lens interface showing three haystack-deployment pods in Running status with their resource configurations" />
268  
269  Note that the `NodePort` you created before will now act as a load balancer and will distribute incoming requests to the three Hayhooks Pods.