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  
 60  <ClickableImage src="/img/6eb9fb0c7b00367bfbe8182ffc7c3746f3f3d03b720e963df045e28160362d7f-Screenshot_2025-04-15_at_16.15.28.png" alt="None" />
 61  
 62  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.
 63  
 64  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:
 65  
 66  ```yaml
 67  kind: Cluster
 68  apiVersion: kind.x-k8s.io/v1alpha4
 69  nodes:
 70    - role: control-plane
 71      # ...
 72      extraPortMappings:
 73        - containerPort: 30080
 74          hostPort: 30080
 75          protocol: TCP
 76  ```
 77  
 78  Then, create a simple `NodePort`  to test if Hayhooks Pod is running correctly:
 79  
 80  ```yaml
 81  apiVersion: v1
 82  kind: Service
 83  metadata:
 84    name: haystack-nodeport
 85  spec:
 86    selector:
 87      app: haystack
 88    type: NodePort
 89    ports:
 90    - port: 1416
 91      targetPort: 1416
 92      nodePort: 30080
 93      name: http
 94  ```
 95  
 96  After applying this, `hayhooks` Pod will be accessible on `localhost:30080`.
 97  
 98  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.
 99  
100  ## Auto-Run Pipelines at Pod Start
101  
102  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.
103  
104  At startup, it will look for deployed pipelines on the path specified at `HAYHOOKS_PIPELINES_DIR`, then load them.
105  
106  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.
107  
108  First, ensure that a local folder is mounted correctly on the KinD cluster node at `/data`:
109  
110  ```yaml
111  kind: Cluster
112  apiVersion: kind.x-k8s.io/v1alpha4
113  nodes:
114    - role: control-plane
115      # ...
116      extraMounts:
117        - hostPath: /path/to/local/pipelines/folder
118          containerPath: /data
119  ```
120  
121  Next, make `/data` available as a volume and mount it on Hayhooks Pod. To do that, update your previous Pod configuration to the following:
122  
123  ```yaml
124  kind: Pod
125  apiVersion: v1
126  metadata:
127    name: hayhooks
128    labels:
129      app: haystack
130  spec:
131    containers:
132      - image: deepset/hayhooks:v0.6.0
133        name: hayhooks
134        imagePullPolicy: IfNotPresent
135        command: ["/bin/sh", "-c"]
136        args:
137          - |
138            pip install trafilatura && \
139            hayhooks run --host 0.0.0.0
140        volumeMounts:
141          - name: local-data
142            mountPath: /mnt/data
143        env:
144          - name: HAYHOOKS_PIPELINES_DIR
145            value: /mnt/data
146          - name: OPENAI_API_KEY
147            valueFrom:
148              secretKeyRef:
149                name: openai-secret
150                key: api-key
151        resources:
152          limits:
153            memory: "512Mi"
154            cpu: "500m"
155          requests:
156            memory: "256Mi"
157            cpu: "250m"
158    volumes:
159      - name: local-data
160        hostPath:
161          path: /data
162          type: Directory
163  
164  ```
165  
166  Note that:
167  
168  - 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).
169  - We make Hayhooks container read `OPENAI_API_KEY` from a Kubernetes Secret.
170  
171  Before applying this new configuration, create the `openai-secret`:
172  
173  ```yaml
174  apiVersion: v1
175  kind: Secret
176  metadata:
177    name: openai-secret
178  type: Opaque
179  data:
180    # Replace the placeholder below with the base64 encoded value of your API key
181    # Generate it using: echo -n $OPENAI_API_KEY | base64
182    api-key: YOUR_BASE64_ENCODED_API_KEY_HERE
183  ```
184  
185  After applying this, check your Hayhooks Pod logs, and you'll see that the `chat_with_website` pipelines have already been deployed.
186  
187  <ClickableImage src="/img/2dbf42dd2db1cb355ee7222d7f8e96c45b611200d83ca289be3456264a854c38-Screenshot_2025-04-16_at_09.19.14.png" alt="None" />
188  
189  ## Roll Out Multiple Pods
190  
191  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`:
192  
193  ```yaml
194  apiVersion: apps/v1
195  kind: Deployment
196  metadata:
197    name: haystack-deployment
198  spec:
199    replicas: 3
200    selector:
201      matchLabels:
202        app: haystack
203    template:
204      metadata:
205        labels:
206          app: haystack
207      spec:
208        initContainers:
209          - name: install-dependencies
210            image: python:3.12-slim
211            workingDir: /mnt/data
212            command: ["/bin/bash", "-c"]
213            args:
214              - |
215                echo "Installing dependencies..."
216                pip install trafilatura
217                echo "Dependencies installed successfully!"
218                touch /mnt/data/init-complete
219            volumeMounts:
220              - name: local-data
221                mountPath: /mnt/data
222            resources:
223              requests:
224                memory: "64Mi"
225                cpu: "100m"
226              limits:
227                memory: "128Mi"
228                cpu: "250m"
229        containers:
230          - image: deepset/hayhooks:v0.6.0
231            name: hayhooks
232            imagePullPolicy: IfNotPresent
233            command: ["/bin/sh", "-c"]
234            args:
235              - |
236                pip install trafilatura && \
237                hayhooks run --host 0.0.0.0
238            ports:
239              - containerPort: 1416
240                name: http
241            volumeMounts:
242              - name: local-data
243                mountPath: /mnt/data
244            env:
245              - name: HAYHOOKS_PIPELINES_DIR
246                value: /mnt/data
247              - name: OPENAI_API_KEY
248                valueFrom:
249                  secretKeyRef:
250                    name: openai-secret
251                    key: api-key
252            resources:
253              requests:
254                memory: "256Mi"
255                cpu: "250m"
256              limits:
257                memory: "512Mi"
258                cpu: "500m"
259        volumes:
260          - name: local-data
261            hostPath:
262              path: /data
263              type: Directory
264  
265  ```
266  
267  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.
268  
269  <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" />
270  
271  Note that the `NodePort` you created before will now act as a load balancer and will distribute incoming requests to the three Hayhooks Pods.