Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chatbot-rag-app: adds Kubernetes manifest and instructions #396

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ Note: If you haven't checked out this repository, all you need is one file:
wget https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/docker/docker-compose-elastic.yml
```

Use docker compose to run Elastic stack in the background:
Before you begin, ensure you have free CPU and memory on your Docker host. If
you plan to use ELSER, assume a minimum of 8 cpus and 6GB memory for the
containers in this compose file.

First, start this Elastic Stack in the background:
```bash
docker compose -f docker-compose-elastic.yml up --force-recreate --wait -d
```
Expand All @@ -20,7 +23,6 @@ Then, you can view Kibana at http://localhost:5601/app/home#/
If asked for a username and password, use username: elastic and password: elastic.

Clean up when finished, like this:

```bash
docker compose -f docker-compose-elastic.yml down
```
4 changes: 1 addition & 3 deletions example-apps/chatbot-rag-app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ COPY frontend ./frontend
RUN cd frontend && yarn install
RUN cd frontend && REACT_APP_API_HOST=/api yarn build

# langchain and vertexai depend on a large number of system packages including
# linux-headers, g++, geos, geos-dev, rust and cargo. These are already present
# on -slim and adding them to -alpine results in a larger image than -slim.
# Use glibc-based image to get pre-compiled wheels for grpcio and tiktoken
FROM python:3.12-slim

WORKDIR /app
Expand Down
62 changes: 60 additions & 2 deletions example-apps/chatbot-rag-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Copy [env.example](env.example) to `.env` and fill in values noted inside.
## Installing and connecting to Elasticsearch

There are a number of ways to install Elasticsearch. Cloud is best for most
use-cases. We also have [docker-compose-elastic.yml](../../docker), that starts
Elasticsearch, Kibana, and APM Server on your laptop with one command.
use-cases. We also have [docker-compose-elastic.yml][docker-compose-elastic],
that starts Elasticsearch, Kibana, and APM Server on your laptop in one step.

Once you decided your approach, edit your `.env` file accordingly.

Expand Down Expand Up @@ -71,6 +71,62 @@ Clean up when finished, like this:
docker compose down
```

### Run with Kubernetes

Kubernetes is more complicated than Docker, but closer to the production
experience for many users. [k8s-manifest.yml](k8s-manifest.yml) creates the
same services, but needs additional configuration first.

First step is to setup your environment. [env.example](env.example) must be
copied to a file name `.env` and updated with `ELASTICSEARCH_URL` and
`OTEL_EXPORTER_OTLP_ENDPOINT` values visible to you Kubernetes deployment.

For example, if you started your Elastic Stack with [k8s-manifest-elastic.yml][k8s-manifest-elastic],
you would update these values:
```
ELASTICSEARCH_URL=http://elasticsearch:9200
OTEL_EXPORTER_OTLP_ENDPOINT=http://apm-server:8200
```

Then, import your `.env` file as a configmap like this:
```bash
kubectl create configmap chatbot-rag-app-env --from-env-file=.env
```

If you are using Vertex AI, make a secret for authentication:
```bash
kubectl create secret generic gcloud-credentials \
--from-file=application_default_credentials.json=$HOME/.config/gcloud/application_default_credentials.json
```

Now that your configuration is applied, create the chatbot-rag-app deployment
and service by applying this manifest:
```bash
kubectl apply -f k8s-manifest.yml
```

Next, block until chatbot-rag-app is available.
```bash
kubectl wait --for=condition=available --timeout=20m deployment/chatbot-rag-app
```

*Note*: The first run may take several minutes to become available. Here's how
to follow logs on this stage:
```bash
kubectl logs deployment.apps/chatbot-rag-app -c create-index -f
```

Next, forward the web UI port:
```bash
kubectl port-forward deployment.apps/chatbot-rag-app 4000:4000 &
```

Clean up when finished, like this:

```bash
kubectl delete -f k8s-manifest.yml
```

### Run with Python

If you want to run this example with Python, you need to do a few things listed
Expand Down Expand Up @@ -196,3 +252,5 @@ docker compose up --build --force-recreate
---
[loader-docs]: https://python.langchain.com/docs/how_to/#document-loaders
[install-es]: https://www.elastic.co/search-labs/tutorials/install-elasticsearch
[docker-compose-elastic]: ../../docker/docker-compose-elastic.yml
[k8s-manifest-elastic]: ../../k8s/k8s-manifest-elastic.yml
6 changes: 5 additions & 1 deletion example-apps/chatbot-rag-app/env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ FLASK_APP=api/app.py
PYTHONUNBUFFERED=1

# How you connect to Elasticsearch: change details to your instance
# This defaults to a Elastic Stack accessible via localhost. When this is
# running inside Kubernetes, update to http://elasticsearch:9200 or similar.
ELASTICSEARCH_URL=http://localhost:9200
ELASTICSEARCH_USER=elastic
ELASTICSEARCH_PASSWORD=elastic
Expand Down Expand Up @@ -68,7 +70,9 @@ OTEL_SDK_DISABLED=true
# Assign the service name that shows up in Kibana
OTEL_SERVICE_NAME=chatbot-rag-app

# Default to send traces to the Elastic APM server
# Default to send logs, traces and metrics to an Elastic APM server accessible
# via localhost. If using running inside k8s, update to http://apm-server:8200
# or similar.
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8200
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

Expand Down
57 changes: 57 additions & 0 deletions example-apps/chatbot-rag-app/k8s-manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: chatbot-rag-app
spec:
replicas: 1
selector:
matchLabels:
app: chatbot-rag-app
template:
metadata:
labels:
app: chatbot-rag-app
spec:
# The below will recreate your secret based on the gcloud credentials file
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally find the GCP-specific instructions in the readme and manifest to be sort of jarring and one point is this is mostly for running locally, while in a cluster the pod should use service account auth provided by the cluster. Similar can be said about using static AWS credentials via env.

"Note for cloud provided backends such as Vertex AI and Bedrock, the pod will need to be authenticated with access to them. This is usually with service account authentication in running clusters, while if testing locally can be with AWS static credentials passed by environment variables or copying a GCP credentials file into a secret mounted as a volume."

Not sure if this is too much information though but I think it would be good if this yaml could avoid the gcloud-specific parts.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, I also was troubled by it. better to leave this out as it is arduous and creates FUD.

# kubectl create secret generic gcloud-credentials \
# --from-file=application_default_credentials.json=$HOME/.config/gcloud/application_default_credentials.json
volumes:
- name: gcloud-credentials
secret:
secretName: gcloud-credentials
initContainers:
- name: create-index
image: &image ghcr.io/elastic/elasticsearch-labs/chatbot-rag-app:latest
args: ["flask", "create-index"]
env:
- name: FLASK_APP
value: api/app.py
# This recreates your configmap based on your .env file:
# kubectl create configmap chatbot-rag-app-env --from-env-file=.env
envFrom: &envFrom
- configMapRef:
name: chatbot-rag-app-env
volumeMounts: &volumeMounts
- name: gcloud-credentials
mountPath: /root/.config/application_default_credentials.json
readOnly: true
containers:
- name: api-frontend
image: *image
ports:
- containerPort: 4000
envFrom: *envFrom
volumeMounts: *volumeMounts
---
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: chatbot-rag-app
ports:
- protocol: TCP
port: 4000
targetPort: 4000
47 changes: 47 additions & 0 deletions k8s/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Running your own Elastic Stack with Kubernetes

If you'd like to start Elastic with Kubernetes, you can use the provided
[manifest-elastic.yml](manifest-elastic.yml) file. This starts
Elasticsearch, Kibana, and APM Server in an existing Kubernetes cluster.

Note: If you haven't checked out this repository, all you need is one file:
```bash
wget https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/docker/docker-compose-elastic.yml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think this is wrong file

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep

```

Before you begin, ensure you have free CPU and memory in your cluster. If you
plan to use ELSER, assume a minimum of 8 cpus and 6GB memory for the containers
in this manifest.

First, start this Elastic Stack in the background:
```bash
kubectl apply -f k8s-manifest-elastic.yml
```

**Note**: For simplicity, this adds an Elastic Stack to the default namespace.
Commands after here are simpler due to this. If you want to choose a different
one, use `kubectl`'s `--namespace` flag!

Next, block until the whole stack is available. First install or changing the
Elastic Stack version can take a long time due to image pulling.
```bash
kubectl wait --for=condition=available --timeout=10m \
deployment/elasticsearch \
deployment/kibana \
deployment/apm-server
```

Next, forward the kibana port:
```bash
kubectl port-forward service/kibana 5601:5601 &
```

Finally, you can view Kibana at http://localhost:5601/app/home#/

If asked for a username and password, use username: elastic and password: elastic.

Clean up when finished, like this:

```bash
kubectl delete -f k8s-manifest-elastic.yml
```
Loading