DAN-120 Kubernetes (#98)

Sample Kubernetes deployment with Auth default on
Also includes a bugfix for credentialed connectors with Auth turned on
This commit is contained in:
Yuhong Sun
2023-06-14 00:11:25 -07:00
committed by GitHub
parent 329d0640eb
commit 590fbbc253
34 changed files with 560 additions and 61 deletions

View File

@@ -1,7 +1,7 @@
FROM python:3.11-slim-bullseye
RUN apt-get update \
&& apt-get install -y git cmake pkg-config libprotobuf-c-dev protobuf-compiler \
&& apt-get install -y git cmake pkg-config libprotobuf-c-dev protobuf-compiler \
libprotobuf-dev libgoogle-perftools-dev libpq-dev build-essential cron curl \
supervisor \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -1,6 +1,7 @@
import abc
from typing import Generic
from typing import TypeVar
from uuid import UUID
from danswer.chunking.models import BaseChunk
from danswer.chunking.models import EmbeddedIndexChunk
@@ -14,7 +15,7 @@ IndexFilter = dict[str, str | list[str] | None]
class DocumentIndex(Generic[T], abc.ABC):
@abc.abstractmethod
def index(self, chunks: list[T], user_id: int | None) -> bool:
def index(self, chunks: list[T], user_id: UUID | None) -> bool:
raise NotImplementedError
@@ -23,7 +24,7 @@ class VectorIndex(DocumentIndex[EmbeddedIndexChunk], abc.ABC):
def semantic_retrieval(
self,
query: str,
user_id: int | None,
user_id: UUID | None,
filters: list[IndexFilter] | None,
num_to_retrieve: int,
) -> list[InferenceChunk]:
@@ -35,7 +36,7 @@ class KeywordIndex(DocumentIndex[IndexChunk], abc.ABC):
def keyword_search(
self,
query: str,
user_id: int | None,
user_id: UUID | None,
filters: list[IndexFilter] | None,
num_to_retrieve: int,
) -> list[InferenceChunk]:

View File

@@ -1,4 +1,5 @@
from functools import partial
from uuid import UUID
from danswer.chunking.models import EmbeddedIndexChunk
from danswer.configs.constants import ALLOWED_GROUPS
@@ -86,7 +87,7 @@ def delete_qdrant_doc_chunks(
def index_qdrant_chunks(
chunks: list[EmbeddedIndexChunk],
user_id: int | None,
user_id: UUID | None,
collection: str,
client: QdrantClient | None = None,
batch_upsert: bool = True,

View File

@@ -1,8 +1,7 @@
import uuid
from uuid import UUID
from danswer.chunking.models import EmbeddedIndexChunk
from danswer.chunking.models import InferenceChunk
from danswer.configs.app_configs import NUM_RERANKED_RESULTS
from danswer.configs.app_configs import NUM_RETURNED_HITS
from danswer.configs.app_configs import QDRANT_DEFAULT_COLLECTION
from danswer.configs.constants import ALLOWED_USERS
@@ -27,7 +26,7 @@ logger = setup_logger()
def _build_qdrant_filters(
user_id: int | None, filters: list[IndexFilter] | None
user_id: UUID | None, filters: list[IndexFilter] | None
) -> list[FieldCondition]:
filter_conditions: list[FieldCondition] = []
# Permissions filter
@@ -78,7 +77,7 @@ class QdrantIndex(VectorIndex):
self.collection = collection
self.client = get_qdrant_client()
def index(self, chunks: list[EmbeddedIndexChunk], user_id: int | None) -> bool:
def index(self, chunks: list[EmbeddedIndexChunk], user_id: UUID | None) -> bool:
return index_qdrant_chunks(
chunks=chunks,
user_id=user_id,
@@ -90,7 +89,7 @@ class QdrantIndex(VectorIndex):
def semantic_retrieval(
self,
query: str,
user_id: int | None,
user_id: UUID | None,
filters: list[IndexFilter] | None,
num_to_retrieve: int = NUM_RETURNED_HITS,
page_size: int = NUM_RETURNED_HITS,
@@ -106,7 +105,7 @@ class QdrantIndex(VectorIndex):
page_offset = 0
found_inference_chunks: list[InferenceChunk] = []
found_chunk_uuids: set[uuid.UUID] = set()
found_chunk_uuids: set[UUID] = set()
while len(found_inference_chunks) < num_to_retrieve:
try:
hits = self.client.search(

View File

@@ -1,6 +1,7 @@
import json
from functools import partial
from typing import Any
from uuid import UUID
import typesense # type: ignore
from danswer.chunking.models import EmbeddedIndexChunk
@@ -101,7 +102,7 @@ def delete_typesense_doc_chunks(
def index_typesense_chunks(
chunks: list[IndexChunk | EmbeddedIndexChunk],
user_id: int | None,
user_id: UUID | None,
collection: str,
client: typesense.Client | None = None,
batch_upsert: bool = True,
@@ -171,7 +172,7 @@ def index_typesense_chunks(
def _build_typesense_filters(
user_id: int | None, filters: list[IndexFilter] | None
user_id: UUID | None, filters: list[IndexFilter] | None
) -> str:
filter_str = ""
@@ -205,7 +206,7 @@ class TypesenseIndex(KeywordIndex):
self.collection = collection
self.ts_client = get_typesense_client()
def index(self, chunks: list[IndexChunk], user_id: int | None) -> bool:
def index(self, chunks: list[IndexChunk], user_id: UUID | None) -> bool:
return index_typesense_chunks(
chunks=chunks,
user_id=user_id,
@@ -216,7 +217,7 @@ class TypesenseIndex(KeywordIndex):
def keyword_search(
self,
query: str,
user_id: int | None,
user_id: UUID | None,
filters: list[IndexFilter] | None,
num_to_retrieve: int,
) -> list[InferenceChunk]:

View File

@@ -63,7 +63,7 @@ def create_credential(
) -> ObjectCreationIdResponse:
credential = Credential(
credential_json=credential_data.credential_json,
user_id=int(user.id) if user else None,
user_id=user.id if user else None,
public_doc=credential_data.public_doc,
)
db_session.add(credential)
@@ -83,7 +83,7 @@ def update_credential(
return None
credential.credential_json = credential_data.credential_json
credential.user_id = int(user.id) if user is not None else None
credential.user_id = user.id if user is not None else None
credential.public_doc = credential_data.public_doc
db_session.commit()

View File

@@ -2,6 +2,7 @@ import datetime
from enum import Enum as PyEnum
from typing import Any
from typing import List
from uuid import UUID
from danswer.auth.schemas import UserRole
from danswer.configs.constants import DocumentSource
@@ -105,7 +106,7 @@ class Credential(Base):
id: Mapped[int] = mapped_column(primary_key=True)
credential_json: Mapped[dict[str, Any]] = mapped_column(postgresql.JSONB())
user_id: Mapped[int | None] = mapped_column(ForeignKey("user.id"), nullable=True)
user_id: Mapped[UUID | None] = mapped_column(ForeignKey("user.id"), nullable=True)
public_doc: Mapped[bool] = mapped_column(Boolean, default=False)
time_created: Mapped[datetime.datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now()

View File

@@ -1,4 +1,5 @@
import json
from uuid import UUID
from danswer.chunking.models import InferenceChunk
from danswer.configs.app_configs import NUM_RETURNED_HITS
@@ -34,7 +35,7 @@ def query_processing(query: str) -> str:
@log_function_time()
def retrieve_keyword_documents(
query: str,
user_id: int | None,
user_id: UUID | None,
filters: list[IndexFilter] | None,
datastore: KeywordIndex,
num_hits: int = NUM_RETURNED_HITS,

View File

@@ -1,4 +1,5 @@
import json
from uuid import UUID
import numpy
from danswer.chunking.models import EmbeddedIndexChunk
@@ -58,7 +59,7 @@ def semantic_reranking(
@log_function_time()
def retrieve_ranked_documents(
query: str,
user_id: int | None,
user_id: UUID | None,
filters: list[IndexFilter] | None,
datastore: VectorIndex,
num_hits: int = NUM_RETURNED_HITS,

View File

@@ -4,6 +4,7 @@ from typing import Generic
from typing import Literal
from typing import Optional
from typing import TypeVar
from uuid import UUID
from danswer.configs.constants import DocumentSource
from danswer.connectors.models import InputType
@@ -171,7 +172,7 @@ class CredentialBase(BaseModel):
class CredentialSnapshot(CredentialBase):
id: int
user_id: int | None
user_id: UUID | None
time_created: datetime
time_updated: datetime

View File

@@ -49,7 +49,7 @@ def semantic_search(
filters = question.filters
logger.info(f"Received semantic search query: {query}")
user_id = None if user is None else int(user.id)
user_id = None if user is None else user.id
ranked_chunks, unranked_chunks = retrieve_ranked_documents(
query, user_id, filters, QdrantIndex(collection)
)
@@ -71,7 +71,7 @@ def keyword_search(
filters = question.filters
logger.info(f"Received keyword search query: {query}")
user_id = None if user is None else int(user.id)
user_id = None if user is None else user.id
ranked_chunks = retrieve_keyword_documents(
query, user_id, filters, TypesenseIndex(collection)
)
@@ -99,7 +99,7 @@ def direct_qa(
if use_keyword is None:
use_keyword = predicted_search == SearchType.KEYWORD
user_id = None if user is None else int(user.id)
user_id = None if user is None else user.id
if use_keyword:
ranked_chunks: list[InferenceChunk] | None = retrieve_keyword_documents(
query, user_id, filters, TypesenseIndex(collection)
@@ -165,7 +165,7 @@ def stream_direct_qa(
if use_keyword is None:
use_keyword = predicted_search == SearchType.KEYWORD
user_id = None if user is None else int(user.id)
user_id = None if user is None else user.id
if use_keyword:
ranked_chunks: list[InferenceChunk] | None = retrieve_keyword_documents(
query, user_id, filters, TypesenseIndex(collection)

View File

@@ -1,6 +1,7 @@
from functools import partial
from itertools import chain
from typing import Protocol
from uuid import UUID
from danswer.chunking.chunk import Chunker
from danswer.chunking.chunk import DefaultChunker
@@ -16,7 +17,7 @@ from danswer.search.semantic_search import DefaultEmbedder
class IndexingPipelineProtocol(Protocol):
def __call__(
self, documents: list[Document], user_id: int | None
self, documents: list[Document], user_id: UUID | None
) -> list[EmbeddedIndexChunk]:
...
@@ -28,7 +29,7 @@ def _indexing_pipeline(
vector_index: VectorIndex,
keyword_index: KeywordIndex,
documents: list[Document],
user_id: int | None,
user_id: UUID | None,
) -> list[EmbeddedIndexChunk]:
# TODO: make entire indexing pipeline async to not block the entire process
# when running on async endpoints

View File

@@ -1,16 +1,18 @@
[supervisord]
nodaemon=true
logfile=/dev/null
logfile=/dev/stdout
logfile_maxbytes=0
[program:indexing]
command=python danswer/background/update.py
stdout_logfile=/var/log/supervisor/update.log
stdout_logfile=/var/log/update.log
redirect_stderr=true
stdout_logfile_maxbytes=52428800
autorestart=true
[program:file_deletion]
command=python danswer/background/file_deletion.py
stdout_logfile=/var/log/supervisor/file_deletion.log
stdout_logfile=/var/log/file_deletion.log
redirect_stderr=true
stdout_logfile_maxbytes=52428800
autorestart=true

View File

@@ -1 +1,2 @@
.env*
secrets.yaml

View File

@@ -1,32 +1,77 @@
This serves as an example for how to deploy everything on a single machine. This is
not optimal, but can get you started easily and cheaply. To run:
# Deploying Danswer
The two options provided here are the easiest ways to get Danswer up and running.
- Docker Compose is simpler and default values are already preset to run right out of the box with a single command.
As everything is running on a single machine, this may not be as scalable depending on your hardware, traffic and needs.
- Kubernetes deployment is also provided. Depending on your existing infrastructure, this may be more suitable for
production deployment but there are a few caveats.
- User auth is turned on by default for Kubernetes (with the assumption this is for production use)
so you must either update the deployments to turn off user auth or provide the values shown in the example
secrets.yaml file.
- The example provided assumes a blank slate for existing Kubernetes deployments/services. You may need to adjust the
deployments or services according to your setup. This may require existing Kubernetes knowledge or additional
setup time.
All the features of Danswer are fully available regardless of the deployment option.
For information on setting up connectors, check out https://docs.danswer.dev/connectors/overview
1. Run one of the docker compose commands below depending on your environment:
- For Local:
- `docker compose -f docker-compose.dev.yml -p danswer-stack up -d --build`
- This will start Web/API servers, Postgres (backend DB), Qdrant (vector DB), and the background indexing job.
- Downloading packages/requirements may take 20+ minutes depending on your internet connection.
## Docker Compose:
Docker Compose provides the easiest way to get Danswer up and running.
Requirements: Docker and docker compose
1. To run Danswer, navigate to `docker_compose` directory and run the following:
- `docker compose -f docker-compose.dev.yml -p danswer-stack up -d --build`
- This will start Web/API servers, Postgres (backend DB), Qdrant (vector DB), and the background indexing job.
- Downloading packages/requirements may take 20+ minutes depending on your internet connection and whether it needs
to install packages for GPU.
2. To shut down the deployment run (use stop to stop containers, down to remove containers):
- For Local:
- `docker compose -f docker-compose.dev.yml -p danswer-stack stop`
2. To shut down the deployment, run:
- To stop the containers: `docker compose -f docker-compose.dev.yml -p danswer-stack stop`
- To delete the containers: `docker compose -f docker-compose.dev.yml -p danswer-stack down`
3. To completely remove Danswer (**WARNING, this will also erase your indexed data and all users**) run:
- For Local:
- `docker compose -f docker-compose.dev.yml -p danswer-stack down -v`
3. To completely remove Danswer run:
- **WARNING, this will also erase your indexed data and users**
- `docker compose -f docker-compose.dev.yml -p danswer-stack down -v`
Additional steps for setting up for Prod:
Additional steps for user auth and https if you do want to use Docker Compose for production:
1. Set up a `.env` file in this directory with relevant environment variables.
- Refer to env.dev.template and env.prod.template
- To turn on user auth, set:
- ENABLE_OAUTH=True
- GOOGLE_OAUTH_CLIENT_ID=\<your GCP API client ID\>
- GOOGLE_OAUTH_CLIENT_SECRET=\<associated client secret\>
- Refer to https://developers.google.com/identity/gsi/web/guides/get-google-api-clientid
2. Set up https:
- Set up a `.env.nginx` file in this directory based on `env.nginx.template`.
- `chmod +x init-letsencrypt.sh` + `./init-letsencrypt.sh` to set up https certificate.
3. Follow the above steps but replacing dev with prod.
## Kubernetes:
Depending on your deployment needs Kubernetes may be more suitable. The yamls provided will work out of the box but the
intent is for you to customize the deployment to fit your own needs. There is no data replication or auto-scaling built
in for the provided example.
Requirements: a Kubernetes cluster and kubectl
**NOTE: This setup does not explicitly enable https, the assumption is you would have this already set up for your
prod cluster**
1. To run Danswer, navigate to `kubernetes` directory and run the following:
- `kubectl apply -f .`
2. To remove Danswer, run:
- **WARNING, this will also erase your indexed data and users**'
- `kubectl delete -f .`
- To not delete the persistent volumes (Document indexes and Users), specify the specific `.yaml` files instead of
`.` without specifying delete on persistent-volumes.yaml.

View File

@@ -1,4 +1,4 @@
upstream app_server {
upstream api_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response
@@ -35,7 +35,7 @@ server {
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://app_server;
proxy_pass http://api_server;
}
location / {

View File

@@ -1,4 +1,4 @@
upstream app_server {
upstream api_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response
@@ -35,7 +35,7 @@ server {
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://app_server;
proxy_pass http://api_server;
}
location / {

View File

@@ -2,7 +2,7 @@ version: '3'
services:
api_server:
build:
context: ../backend
context: ../../backend
dockerfile: Dockerfile
depends_on:
- relational_db
@@ -24,7 +24,7 @@ services:
- file_connector_tmp_storage:/home/file_connector_storage
background:
build:
context: ../backend
context: ../../backend
dockerfile: Dockerfile.background
depends_on:
- relational_db
@@ -42,7 +42,7 @@ services:
- file_connector_tmp_storage:/home/file_connector_storage
web_server:
build:
context: ../web
context: ../../web
dockerfile: Dockerfile
depends_on:
- api_server
@@ -97,7 +97,7 @@ services:
- "80:80"
- "3000:80" # allow for localhost:3000 usage, since that is the norm
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ../data/nginx:/etc/nginx/conf.d
command: >
/bin/sh -c "envsubst '$$\{DOMAIN\}' < /etc/nginx/conf.d/app.conf.template.dev > /etc/nginx/conf.d/app.conf
&& while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\""

View File

@@ -2,7 +2,7 @@ version: '3'
services:
api_server:
build:
context: ../backend
context: ../../backend
dockerfile: Dockerfile
depends_on:
- relational_db
@@ -21,7 +21,7 @@ services:
- file_connector_tmp_storage:/home/file_connector_storage
background:
build:
context: ../backend
context: ../../backend
dockerfile: Dockerfile.background
depends_on:
- relational_db
@@ -37,7 +37,7 @@ services:
- file_connector_tmp_storage:/home/file_connector_storage
web_server:
build:
context: ../web
context: ../../web
dockerfile: Dockerfile
depends_on:
- api_server
@@ -82,9 +82,9 @@ services:
- "80:80"
- "443:443"
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
- ../data/nginx:/etc/nginx/conf.d
- ../data/certbot/conf:/etc/letsencrypt
- ../data/certbot/www:/var/www/certbot
command: >
/bin/sh -c "envsubst '$$\{DOMAIN\}' < /etc/nginx/conf.d/app.conf.template > /etc/nginx/conf.d/app.conf
&& while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\""
@@ -95,8 +95,8 @@ services:
image: certbot/certbot
restart: always
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
- ../data/certbot/conf:/etc/letsencrypt
- ../data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
volumes:
local_dynamic_storage:

View File

@@ -0,0 +1,68 @@
apiVersion: v1
kind: Service
metadata:
name: api-server-service
spec:
selector:
app: api-server
ports:
- name: api-server-port
protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server-deployment
spec:
replicas: 1
selector:
matchLabels:
app: api-server
template:
metadata:
labels:
app: api-server
spec:
containers:
- name: api-server
image: danswer/danswer-api-server:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: POSTGRES_HOST
value: relational-db-service
- name: QDRANT_HOST
value: vector-db-service
- name: TYPESENSE_HOST
value: search-engine-service
- name: TYPESENSE_API_KEY
valueFrom:
secretKeyRef:
name: danswer-secrets
key: typesense_api_key
- name: GOOGLE_OAUTH_CLIENT_ID
valueFrom:
secretKeyRef:
name: danswer-secrets
key: google_oauth_client_id
- name: GOOGLE_OAUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: danswer-secrets
key: google_oauth_client_secret
volumeMounts:
- name: dynamic-storage
mountPath: /home/storage
- name: file-connector-storage
mountPath: /home/file_connector_storage
volumes:
- name: dynamic-storage
persistentVolumeClaim:
claimName: dynamic-pvc
- name: file-connector-storage
persistentVolumeClaim:
claimName: file-connector-pvc

View File

@@ -0,0 +1,42 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: background-deployment
spec:
replicas: 1
selector:
matchLabels:
app: background
template:
metadata:
labels:
app: background
spec:
containers:
- name: background
image: danswer/danswer-background:latest
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_HOST
value: relational-db-service
- name: QDRANT_HOST
value: vector-db-service
- name: TYPESENSE_HOST
value: search-engine-service
- name: TYPESENSE_API_KEY
valueFrom:
secretKeyRef:
name: danswer-secrets
key: typesense_api_key
volumeMounts:
- name: dynamic-storage
mountPath: /home/storage
- name: file-connector-storage
mountPath: /home/file_connector_storage
volumes:
- name: dynamic-storage
persistentVolumeClaim:
claimName: dynamic-pvc
- name: file-connector-storage
persistentVolumeClaim:
claimName: file-connector-pvc

View File

@@ -0,0 +1,42 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
data:
nginx.conf: |
upstream api_server {
server api-server-service:80 fail_timeout=0;
}
upstream web_server {
server web-server-service:80 fail_timeout=0;
}
server {
listen 80;
server_name $$DOMAIN;
location ~ ^/api(.*)$ {
rewrite ^/api(/.*)$ $1 break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_buffering off;
proxy_redirect off;
proxy_pass http://api_server;
}
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_redirect off;
proxy_pass http://web_server;
}
}

View File

@@ -0,0 +1,52 @@
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: danswer
protocol: TCP
port: 3000
targetPort: 80
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.23.4-alpine
ports:
- containerPort: 80
env:
- name: DOMAIN
value: localhost
volumeMounts:
- name: nginx-conf
mountPath: /etc/nginx/conf.d
command:
- /bin/sh
- -c
- |
while :; do sleep 6h & wait $$!; nginx -s reload; done & nginx -g "daemon off;"
volumes:
- name: nginx-conf
configMap:
name: nginx-configmap

View File

@@ -0,0 +1,54 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: file-connector-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-volume-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: qdrant-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: typesense-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi

View File

@@ -0,0 +1,50 @@
apiVersion: v1
kind: Service
metadata:
name: relational-db-service
spec:
selector:
app: relational-db
ports:
- protocol: TCP
port: 5432
targetPort: 5432
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: relational-db-deployment
spec:
replicas: 1
selector:
matchLabels:
app: relational-db
template:
metadata:
labels:
app: relational-db
spec:
containers:
- name: relational-db
image: postgres:15.2-alpine
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: danswer-secrets
key: postgres_user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: danswer-secrets
key: postgres_password
ports:
- containerPort: 5432
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: db-volume
volumes:
- name: db-volume
persistentVolumeClaim:
claimName: db-volume-claim

View File

@@ -0,0 +1,40 @@
apiVersion: v1
kind: Service
metadata:
name: vector-db-service
spec:
selector:
app: qdrant
ports:
- name: qdrant-port
protocol: TCP
port: 6333
targetPort: 6333
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: qdrant-deployment
spec:
replicas: 1
selector:
matchLabels:
app: qdrant
template:
metadata:
labels:
app: qdrant
spec:
containers:
- name: qdrant
image: qdrant/qdrant:v1.1.3
ports:
- containerPort: 6333
volumeMounts:
- name: qdrant-storage
mountPath: /qdrant/storage
volumes:
- name: qdrant-storage
persistentVolumeClaim:
claimName: qdrant-pvc

View File

@@ -0,0 +1,12 @@
# The values in this file should be changed
apiVersion: v1
kind: Secret
metadata:
name: danswer-secrets
type: Opaque
data:
postgres_user: cG9zdGdyZXM= # "postgres" base64 encoded
postgres_password: cGFzc3dvcmQ= # "password" base64 encoded
typesense_api_key: bG9jYWxfZGV2X3R5cGVzZW5zZQ== # "local_dev_typesense" base64 encoded
google_oauth_client_id: REPLACE-THIS # You will need to provide this, use echo -n "your-client-id" | base64
google_oauth_client_secret: REPLACE-THIS # You will need to provide this, use echo -n "your-client-id" | base64

View File

@@ -0,0 +1,48 @@
apiVersion: v1
kind: Service
metadata:
name: search-engine-service
spec:
selector:
app: typesense
ports:
- name: typesense-port
protocol: TCP
port: 8108
targetPort: 8108
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: typesense-deployment
spec:
replicas: 1
selector:
matchLabels:
app: typesense
template:
metadata:
labels:
app: typesense
spec:
containers:
- name: typesense
image: typesense/typesense:0.24.1
ports:
- containerPort: 8108
env:
- name: TYPESENSE_API_KEY
valueFrom:
secretKeyRef:
name: danswer-secrets
key: typesense_api_key
- name: TYPESENSE_DATA_DIR
value: /typesense/storage
volumeMounts:
- name: typesense-storage
mountPath: /typesense/storage
volumes:
- name: typesense-storage
persistentVolumeClaim:
claimName: typesense-pvc

View File

@@ -0,0 +1,36 @@
apiVersion: v1
kind: Service
metadata:
name: web-server-service
spec:
selector:
app: web-server
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server-deployment
spec:
replicas: 1
selector:
matchLabels:
app: web-server
template:
metadata:
labels:
app: web-server
spec:
containers:
- name: web-server
image: danswer/danswer-web-server:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
env:
- name: INTERNAL_URL
value: "http://api-server-service:80"