Skip to content

Commit 72835b0

Browse files
chatbot-rag-app: adds Kubernetes manifest and instructions (#396)
Signed-off-by: Adrian Cole <[email protected]>
1 parent 21cfcc6 commit 72835b0

File tree

8 files changed

+408
-19
lines changed

8 files changed

+408
-19
lines changed

docker/README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ Note: If you haven't checked out this repository, all you need is one file:
99
wget https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/docker/docker-compose-elastic.yml
1010
```
1111

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

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

2225
Clean up when finished, like this:
23-
2426
```bash
2527
docker compose -f docker-compose-elastic.yml down
2628
```

docker/docker-compose-elastic.yml

+9-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ services:
2727
test: # readiness probe taken from kbn-health-gateway-server script
2828
[
2929
"CMD-SHELL",
30-
"curl -s http://localhost:9200 | grep -q 'missing authentication credentials'",
30+
"curl --max-time 1 -s http://localhost:9200 | grep -q 'missing authentication credentials'",
3131
]
3232
start_period: 10s
3333
interval: 1s
@@ -41,12 +41,15 @@ services:
4141
image: docker.elastic.co/elasticsearch/elasticsearch:8.17.2
4242
container_name: elasticsearch_settings
4343
restart: 'no'
44+
# gen-ai assistants in kibana save state in a way that requires system
45+
# access, so set kibana_system's password to a known value.
4446
command: >
45-
bash -c '
46-
# gen-ai assistants in kibana save state in a way that requires security to be enabled, so we need to create
47-
# a kibana system user before starting it.
47+
bash -c '
4848
echo "Setup the kibana_system password";
49-
until curl -s -u "elastic:elastic" -X POST http://elasticsearch:9200/_security/user/kibana_system/_password -d "{\"password\":\"elastic\"}" -H "Content-Type: application/json" | grep -q "^{}"; do sleep 5; done;
49+
until curl --max-time 1 -s -u "elastic:elastic" \
50+
-X POST http://elasticsearch:9200/_security/user/kibana_system/_password \
51+
-d "{\"password\":\"elastic\"}" \
52+
-H "Content-Type: application/json" | grep -q "^{}"; do sleep 5; done;
5053
'
5154
5255
kibana:
@@ -69,7 +72,7 @@ services:
6972
- XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=fhjskloppd678ehkdfdlliverpoolfcr
7073
- SERVER_PUBLICBASEURL=http://127.0.0.1:5601
7174
healthcheck:
72-
test: ["CMD-SHELL", "curl -s http://localhost:5601/api/status | grep -q 'available'"]
75+
test: ["CMD-SHELL", "curl --max-time 1 -s http://localhost:5601/api/status | grep -q 'available'"]
7376
retries: 300
7477
interval: 1s
7578

example-apps/chatbot-rag-app/Dockerfile

+3-8
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ COPY frontend ./frontend
55
RUN cd frontend && yarn install
66
RUN cd frontend && REACT_APP_API_HOST=/api yarn build
77

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

1311
WORKDIR /app
@@ -27,15 +25,12 @@ EXPOSE 4000
2725
# docker invocations to reenable.
2826
ENV OTEL_SDK_DISABLED=true
2927

30-
# https://github.com/elastic/genai-instrumentation/issues/255
31-
# Currently Python SDK has a bug that spams logs when opentelemetry-instrument is used
32-
# with SDK being disabled. Until it is fixed, we handle it in our own entrypoint by
33-
# avoiding opentelemetry-instrument when SDK is disabled.
28+
# TODO remove custom entrypoint when EDOT Python >0.7.0 is released.
3429
RUN echo 'if [ "${OTEL_SDK_DISABLED:-true}" == "false" ]; \
3530
then \
3631
opentelemetry-instrument $@; \
3732
else \
3833
exec $@; \
3934
fi' > entrypoint.sh
4035
ENTRYPOINT [ "bash", "-eu", "./entrypoint.sh" ]
41-
CMD [ "python", "api/app.py"]
36+
CMD [ "python", "api/app.py" ]

example-apps/chatbot-rag-app/README.md

+66-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ Copy [env.example](env.example) to `.env` and fill in values noted inside.
2222
## Installing and connecting to Elasticsearch
2323

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

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

@@ -71,6 +71,68 @@ Clean up when finished, like this:
7171
docker compose down
7272
```
7373

74+
### Run with Kubernetes
75+
76+
Kubernetes is more complicated than Docker, but closer to the production
77+
experience for many users. [k8s-manifest.yml](k8s-manifest.yml) creates the
78+
same services, but needs additional configuration first.
79+
80+
First step is to setup your environment. [env.example](env.example) must be
81+
copied to a file name `.env` and updated with `ELASTICSEARCH_URL` and
82+
`OTEL_EXPORTER_OTLP_ENDPOINT` values visible to you Kubernetes deployment.
83+
84+
For example, if you started your Elastic Stack with [k8s-manifest-elastic.yml][k8s-manifest-elastic],
85+
you would update these values:
86+
```
87+
ELASTICSEARCH_URL=http://elasticsearch:9200
88+
OTEL_EXPORTER_OTLP_ENDPOINT=http://apm-server:8200
89+
```
90+
91+
Then, import your `.env` file as a configmap like this:
92+
```bash
93+
kubectl create configmap chatbot-rag-app-env --from-env-file=.env
94+
```
95+
96+
<details>
97+
<summary>To use Vertex AI, set `LLM_TYPE=vertex` in your `.env` and follow these steps</summary>
98+
The `api-frontend container` needs access to your Google Cloud credentials.
99+
Share your `application_default_credentials.json` as a Kubernetes secret:
100+
```bash
101+
# Logs you into Google Cloud and creates application_default_credentials.json
102+
gcloud auth application-default login
103+
# Adds your credentials to a Kubernetes secret named gcloud-credentials
104+
kubectl create secret generic gcloud-credentials \
105+
--from-file=application_default_credentials.json=$HOME/.config/gcloud/application_default_credentials.json
106+
```
107+
</details>
108+
109+
Now that your configuration is applied, create the `chatbot-rag-app` deployment
110+
and service by applying this manifest:
111+
```bash
112+
kubectl apply -f k8s-manifest.yml
113+
```
114+
115+
Next, block until `chatbot-rag-app` is available.
116+
```bash
117+
kubectl wait --for=condition=available --timeout=20m deployment/chatbot-rag-app
118+
```
119+
120+
*Note*: The first run may take several minutes to become available. Here's how
121+
to follow logs on this stage:
122+
```bash
123+
kubectl logs deployment.apps/chatbot-rag-app -c create-index -f
124+
```
125+
126+
Next, forward the web UI port:
127+
```bash
128+
kubectl port-forward deployment.apps/chatbot-rag-app 4000:4000 &
129+
```
130+
131+
Clean up when finished, like this:
132+
```bash
133+
kubectl delete -f k8s-manifest.yml
134+
```
135+
74136
### Run with Python
75137

76138
If you want to run this example with Python, you need to do a few things listed
@@ -196,3 +258,5 @@ docker compose up --build --force-recreate
196258
---
197259
[loader-docs]: https://python.langchain.com/docs/how_to/#document-loaders
198260
[install-es]: https://www.elastic.co/search-labs/tutorials/install-elasticsearch
261+
[docker-compose-elastic]: ../../docker/docker-compose-elastic.yml
262+
[k8s-manifest-elastic]: ../../k8s/k8s-manifest-elastic.yml

example-apps/chatbot-rag-app/env.example

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ FLASK_APP=api/app.py
66
PYTHONUNBUFFERED=1
77

88
# How you connect to Elasticsearch: change details to your instance
9+
# This defaults to a Elastic Stack accessible via localhost.
10+
#
11+
# When running inside Kubernetes, set to http://elasticsearch.default.svc:9200
12+
# or similar.
913
ELASTICSEARCH_URL=http://localhost:9200
1014
ELASTICSEARCH_USER=elastic
1115
ELASTICSEARCH_PASSWORD=elastic
@@ -68,7 +72,11 @@ OTEL_SDK_DISABLED=true
6872
# Assign the service name that shows up in Kibana
6973
OTEL_SERVICE_NAME=chatbot-rag-app
7074

71-
# Default to send traces to the Elastic APM server
75+
# Default to send logs, traces and metrics to an Elastic APM server accessible
76+
# via localhost.
77+
#
78+
# When running inside Kubernetes, set to http://elasticsearch.default.svc:9200
79+
# or similar.
7280
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8200
7381
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
7482

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
# chatbot-rag-app deploys "create-index" to install ELSER and load values.
3+
# Then, it starts "api-frontend" to serve the application.
4+
apiVersion: apps/v1
5+
kind: Deployment
6+
metadata:
7+
name: chatbot-rag-app
8+
spec:
9+
replicas: 1
10+
selector:
11+
matchLabels:
12+
app: chatbot-rag-app
13+
template:
14+
metadata:
15+
labels:
16+
app: chatbot-rag-app
17+
spec:
18+
# For `LLM_TYPE=vertex`: create a volume for application_default_credentials.json
19+
volumes:
20+
- name: gcloud-credentials
21+
secret:
22+
secretName: gcloud-credentials
23+
optional: true # only read when `LLM_TYPE=vertex`
24+
initContainers:
25+
- name: create-index
26+
image: &image ghcr.io/elastic/elasticsearch-labs/chatbot-rag-app:latest
27+
command: &command [ "bash", "-eu", "./entrypoint.sh" ] # match image
28+
args: [ "flask", "create-index" ]
29+
# This recreates your configmap based on your .env file:
30+
# kubectl create configmap chatbot-rag-app-env --from-env-file=.env
31+
envFrom: &envFrom
32+
- configMapRef:
33+
name: chatbot-rag-app-env
34+
containers:
35+
- name: api-frontend
36+
image: *image
37+
command: *command
38+
args: [ "python", "api/app.py" ]
39+
ports:
40+
- containerPort: 4000
41+
envFrom: *envFrom
42+
# For `LLM_TYPE=vertex`: mount credentials to the path read by the google-cloud-sdk
43+
volumeMounts:
44+
- name: gcloud-credentials
45+
mountPath: /root/.config/gcloud
46+
readOnly: true
47+
---
48+
apiVersion: v1
49+
kind: Service
50+
metadata:
51+
name: api
52+
spec:
53+
selector:
54+
app: chatbot-rag-app
55+
ports:
56+
- protocol: TCP
57+
port: 4000
58+
targetPort: 4000

k8s/README.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Running your own Elastic Stack with Kubernetes
2+
3+
If you'd like to start Elastic with Kubernetes, you can use the provided
4+
[manifest-elastic.yml](manifest-elastic.yml) file. This starts
5+
Elasticsearch, Kibana, and APM Server in an existing Kubernetes cluster.
6+
7+
Note: If you haven't checked out this repository, all you need is one file:
8+
```bash
9+
wget https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/k8s/k8s-manifest-elastic.yml
10+
```
11+
12+
Before you begin, ensure you have free CPU and memory in your cluster. If you
13+
plan to use ELSER, assume a minimum of 8 cpus and 6GB memory for the containers
14+
in this manifest.
15+
16+
First, start this Elastic Stack in the background:
17+
```bash
18+
kubectl apply -f k8s-manifest-elastic.yml
19+
```
20+
21+
**Note**: For simplicity, this adds an Elastic Stack to the default namespace.
22+
Commands after here are simpler due to this. If you want to choose a different
23+
one, use `kubectl`'s `--namespace` flag!
24+
25+
Next, block until the whole stack is available. First install or changing the
26+
Elastic Stack version can take a long time due to image pulling.
27+
```bash
28+
kubectl wait --for=condition=available --timeout=10m \
29+
deployment/elasticsearch \
30+
deployment/kibana \
31+
deployment/apm-server
32+
```
33+
34+
Next, forward the kibana port:
35+
```bash
36+
kubectl port-forward service/kibana 5601:5601 &
37+
```
38+
39+
Finally, you can view Kibana at http://localhost:5601/app/home#/
40+
41+
If asked for a username and password, use username: elastic and password: elastic.
42+
43+
Clean up when finished, like this:
44+
45+
```bash
46+
kubectl delete -f k8s-manifest-elastic.yml
47+
```

0 commit comments

Comments
 (0)