-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ENH]: DO deployment blueprint (#1171)
## Description of changes *Summarize the changes made by this PR.* - Improvements & Bug fixes - Full deployment of a Chroma on a DO droplet with attached volume ## Test plan *How are these changes tested?* Manually tested. ## Documentation Changes Docs are in the deployment README.md
- Loading branch information
Showing
4 changed files
with
475 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#! /bin/bash | ||
|
||
# Note: This is run as root | ||
|
||
cd ~ | ||
export enable_auth="${enable_auth}" | ||
export basic_auth_credentials="${basic_auth_credentials}" | ||
export auth_type="${auth_type}" | ||
export token_auth_credentials="${token_auth_credentials}" | ||
apt-get update -y | ||
apt-get install -y ca-certificates curl gnupg lsb-release | ||
mkdir -m 0755 -p /etc/apt/keyrings | ||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg | ||
echo \ | ||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ | ||
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null | ||
apt-get update -y | ||
chmod a+r /etc/apt/keyrings/docker.gpg | ||
apt-get update -y | ||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin git | ||
usermod -aG docker ubuntu | ||
git clone https://github.com/chroma-core/chroma.git && cd chroma | ||
git fetch --tags | ||
git checkout tags/${chroma_release} | ||
|
||
if [ "$${enable_auth}" = "true" ] && [ "$${auth_type}" = "basic" ] && [ ! -z "$${basic_auth_credentials}" ]; then | ||
username=$(echo $basic_auth_credentials | cut -d: -f1) | ||
password=$(echo $basic_auth_credentials | cut -d: -f2) | ||
docker run --rm --entrypoint htpasswd httpd:2 -Bbn $username $password > server.htpasswd | ||
cat <<EOF > .env | ||
CHROMA_SERVER_AUTH_CREDENTIALS_FILE="/chroma/server.htpasswd" | ||
CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider' | ||
CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider' | ||
EOF | ||
fi | ||
|
||
if [ "$${enable_auth}" = "true" ] && [ "$${auth_type}" = "token" ] && [ ! -z "$${token_auth_credentials}" ]; then | ||
cat <<EOF > .env | ||
CHROMA_SERVER_AUTH_CREDENTIALS="$${token_auth_credentials}" \ | ||
CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.token.TokenConfigServerAuthCredentialsProvider' | ||
CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.token.TokenAuthServerProvider' | ||
EOF | ||
fi | ||
|
||
cat <<EOF > docker-compose.override.yaml | ||
version: '3.8' | ||
services: | ||
server: | ||
volumes: | ||
- /chroma-data:/chroma/chroma | ||
EOF | ||
|
||
COMPOSE_PROJECT_NAME=chroma docker compose up -d --build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
# Digital Ocean Droplet Deployment | ||
|
||
This is an example deployment using Digital Ocean Droplet using [terraform](https://www.terraform.io/). | ||
|
||
This deployment will do the following: | ||
|
||
- 🔥 Create a firewall with required ports open (22 and 8000) | ||
- 🐳 Create Droplet with Ubuntu 22 and deploy Chroma using docker compose | ||
- 💿 Create a data volume for Chroma data | ||
- 🗻 Mount the data volume to the Droplet instance | ||
- ✏️ Format the data volume with ext4 | ||
- 🏃 Start Chroma | ||
|
||
## Requirements | ||
|
||
- [Terraform CLI v1.3.4+](https://developer.hashicorp.com/terraform/tutorials/gcp-get-started/install-cli) | ||
|
||
## Deployment with terraform | ||
|
||
This deployment uses Ubuntu 22 as foundation, but you'd like to use a different image for your Droplet ( | ||
see https://slugs.do-api.dev/ for a list of available images) | ||
|
||
### Configuration Options | ||
|
||
|
||
### 1. Init your terraform state | ||
|
||
```bash | ||
terraform init | ||
``` | ||
|
||
### 2. Deploy your application | ||
|
||
Generate SSH key to use with your chroma instance (so you can log in to the Droplet): | ||
|
||
> Note: This is optional. You can use your own existing SSH key if you prefer. | ||
```bash | ||
ssh-keygen -t RSA -b 4096 -C "Chroma DO Key" -N "" -f ./chroma-do && chmod 400 ./chroma-do | ||
``` | ||
|
||
Set up your Terraform variables and deploy your instance: | ||
|
||
```bash | ||
#take note of this as it must be present in all of the subsequent steps | ||
export TF_VAR_do_token=<DIGITALOCEAN_TOKEN> | ||
#path to the public key you generated above (or can be different if you want to use your own key) | ||
export TF_ssh_public_key="./chroma-do.pub" | ||
#path to the private key you generated above (or can be different if you want to use your own key) - used for formatting the Chroma data volume | ||
export TF_ssh_private_key="./chroma-do" | ||
#set the chroma release to deploy | ||
export TF_VAR_chroma_release="0.4.12" | ||
# DO region to deploy the chroma instance to | ||
export TF_VAR_region="ams2" | ||
#enable public access to the chroma instance on port 8000 | ||
export TF_VAR_public_access="true" | ||
#enable basic auth for the chroma instance | ||
export TF_VAR_enable_auth="true" | ||
#The auth type to use for the chroma instance (token or basic) | ||
export TF_VAR_auth_type="token" | ||
terraform apply -auto-approve | ||
``` | ||
|
||
> Note: Basic Auth is supported by Chroma v0.4.7+ | ||
### 4. Check your public IP and that Chroma is running | ||
|
||
Get the public IP of your instance | ||
|
||
```bash | ||
terraform output instance_public_ip | ||
``` | ||
|
||
Check that chroma is running (It should take up several minutes for the instance to be ready) | ||
|
||
```bash | ||
export instance_public_ip=$(terraform output instance_public_ip | sed 's/"//g') | ||
curl -v http://$instance_public_ip:8000/api/v1/heartbeat | ||
``` | ||
|
||
#### 4.1 Checking Auth | ||
|
||
##### Token | ||
|
||
When token auth is enabled you can check the get the credentials from Terraform state by running: | ||
|
||
```bash | ||
terraform output chroma_auth_token | ||
``` | ||
|
||
You should see something of the form: | ||
|
||
```bash | ||
PVcQ4qUUnmahXwUgAf3UuYZoMlos6MnF | ||
``` | ||
|
||
You can then export these credentials: | ||
|
||
```bash | ||
export CHROMA_AUTH=$(terraform output chroma_auth_token | sed 's/"//g') | ||
``` | ||
|
||
Using the credentials: | ||
|
||
```bash | ||
curl -v http://$instance_public_ip:8000/api/v1/collections -H "Authorization: Bearer ${CHROMA_AUTH}" | ||
``` | ||
|
||
##### Basic | ||
|
||
When basic auth is enabled you can check the get the credentials from Terraform state by running: | ||
|
||
```bash | ||
terraform output chroma_auth_basic | ||
``` | ||
|
||
You should see something of the form: | ||
|
||
```bash | ||
chroma:VuA8I}QyNrm0@QLq | ||
``` | ||
|
||
You can then export these credentials: | ||
|
||
```bash | ||
export CHROMA_AUTH=$(terraform output chroma_auth_basic | sed 's/"//g') | ||
``` | ||
|
||
Using the credentials: | ||
|
||
```bash | ||
curl -v http://$instance_public_ip:8000/api/v1/collections -u "${CHROMA_AUTH}" | ||
``` | ||
|
||
> Note: Without `-u` you should be getting 401 Unauthorized response | ||
#### 4.2 SSH to your instance | ||
|
||
To SSH to your instance: | ||
|
||
```bash | ||
ssh -i ./chroma-do root@$instance_public_ip | ||
``` | ||
|
||
### 5. Destroy your Chroma instance | ||
|
||
```bash | ||
terraform destroy -auto-approve | ||
``` | ||
|
||
## Extras | ||
|
||
You can visualize your infrastructure with: | ||
|
||
```bash | ||
terraform graph | dot -Tsvg > graph.svg | ||
``` | ||
|
||
> Note: You will need graphviz installed for this to work | ||
### Digital Ocean Resource Types | ||
|
||
Refs: https://slugs.do-api.dev/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
terraform { | ||
required_providers { | ||
digitalocean = { | ||
source = "digitalocean/digitalocean" | ||
version = "~> 2.0" | ||
} | ||
} | ||
} | ||
|
||
# Define provider | ||
variable "do_token" {} | ||
|
||
# Configure the DigitalOcean Provider | ||
provider "digitalocean" { | ||
token = var.do_token | ||
} | ||
|
||
|
||
resource "digitalocean_firewall" "chroma_firewall" { | ||
name = "chroma-firewall" | ||
|
||
droplet_ids = [digitalocean_droplet.chroma_instance.id] | ||
|
||
inbound_rule { | ||
protocol = "tcp" | ||
port_range = "22" | ||
source_addresses = var.mgmt_source_ranges | ||
} | ||
|
||
dynamic "inbound_rule" { | ||
for_each = var.public_access ? [1] : [] | ||
content { | ||
protocol = "tcp" | ||
port_range = var.chroma_port | ||
source_addresses = var.source_ranges | ||
} | ||
} | ||
|
||
outbound_rule { | ||
protocol = "tcp" | ||
port_range = "1-65535" | ||
destination_addresses = ["0.0.0.0/0", "::/0"] | ||
} | ||
|
||
outbound_rule { | ||
protocol = "icmp" | ||
port_range = "1-65535" | ||
destination_addresses = ["0.0.0.0/0", "::/0"] | ||
} | ||
|
||
outbound_rule { | ||
protocol = "udp" | ||
port_range = "1-65535" | ||
destination_addresses = ["0.0.0.0/0", "::/0"] | ||
} | ||
|
||
tags = local.tags | ||
|
||
} | ||
|
||
resource "digitalocean_ssh_key" "chroma_keypair" { | ||
name = "chroma_keypair" | ||
public_key = file(var.ssh_public_key) | ||
} | ||
|
||
|
||
#Create Droplet | ||
resource "digitalocean_droplet" "chroma_instance" { | ||
image = var.instance_image | ||
name = "chroma" | ||
region = var.region | ||
size = var.instance_type | ||
ssh_keys = [digitalocean_ssh_key.chroma_keypair.fingerprint] | ||
|
||
user_data = data.template_file.user_data.rendered | ||
|
||
tags = local.tags | ||
} | ||
|
||
|
||
resource "digitalocean_volume" "chroma_volume" { | ||
region = digitalocean_droplet.chroma_instance.region | ||
name = "chroma-volume" | ||
size = var.chroma_data_volume_size | ||
description = "Chroma data volume" | ||
tags = local.tags | ||
} | ||
|
||
resource "digitalocean_volume_attachment" "chroma_data_volume_attachment" { | ||
droplet_id = digitalocean_droplet.chroma_instance.id | ||
volume_id = digitalocean_volume.chroma_volume.id | ||
|
||
provisioner "remote-exec" { | ||
inline = [ | ||
"export VOLUME_ID=${digitalocean_volume.chroma_volume.name} && sudo mkfs -t ext4 /dev/$(lsblk -o +SERIAL | grep $VOLUME_ID | awk '{print $1}')", | ||
"sudo mkdir /chroma-data", | ||
"export VOLUME_ID=${digitalocean_volume.chroma_volume.name} && sudo mount /dev/$(lsblk -o +SERIAL | grep $VOLUME_ID | awk '{print $1}') /chroma-data", | ||
"cat <<EOF | sudo tee /etc/fstab >> /dev/null", | ||
"/dev/disk/by-id/scsi-0DO_Volume_${digitalocean_volume.chroma_volume.name} /chroma-data ext4 defaults,nofail,discard 0 0", | ||
"EOF", | ||
] | ||
|
||
connection { | ||
host = digitalocean_droplet.chroma_instance.ipv4_address | ||
type = "ssh" | ||
user = "root" | ||
private_key = file(var.ssh_private_key) | ||
} | ||
} | ||
} | ||
|
||
|
||
output "instance_public_ip" { | ||
value = digitalocean_droplet.chroma_instance.ipv4_address | ||
description = "The public IP address of the Chroma instance" | ||
} | ||
|
||
output "instance_private_ip" { | ||
value = digitalocean_droplet.chroma_instance.ipv4_address_private | ||
description = "The private IP address of the Chroma instance" | ||
} | ||
|
||
output "chroma_auth_token" { | ||
description = "The Chroma static auth token" | ||
value = random_password.chroma_token.result | ||
sensitive = true | ||
} | ||
|
||
output "chroma_auth_basic" { | ||
description = "The Chroma basic auth credentials" | ||
value = "${local.basic_auth_credentials.username}:${local.basic_auth_credentials.password}" | ||
sensitive = true | ||
} |
Oops, something went wrong.