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

GCP one click deployment #153

Merged
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fe1f9f1
GCP one click deployment changes - DRAFT
EugeneLightsOn May 23, 2024
ae92ed1
GCP one click deployment changes
EugeneLightsOn May 23, 2024
b7efa5a
GCP one click deployment changes
EugeneLightsOn May 23, 2024
284d376
Merge branch 'main' into EXT2-55-GCP_one_click_deployment
EugeneLightsOn May 29, 2024
adfcc01
GCP one click deployment changes
EugeneLightsOn May 29, 2024
01c675f
GCP one click deployment changes
EugeneLightsOn May 29, 2024
c116bb5
GCP one click deployment changes
EugeneLightsOn May 29, 2024
57bfaaa
GCP one click deployment changes
EugeneLightsOn May 29, 2024
d97b862
GCP one click deployment changes
EugeneLightsOn May 29, 2024
f95c27c
GCP one click deployment changes
EugeneLightsOn May 29, 2024
b1361fa
GCP one click deployment changes
EugeneLightsOn May 29, 2024
f227632
GCP one click deployment changes
EugeneLightsOn May 29, 2024
1b014a0
GCP one click deployment postcreate hook
EugeneLightsOn May 30, 2024
e8802d1
GCP one click deployment postcreate hook
EugeneLightsOn May 30, 2024
4df41fd
GCP one click deployment postcreate hook
EugeneLightsOn May 30, 2024
8055edd
GCP one click deployment postcreate hook
EugeneLightsOn May 30, 2024
6a1778b
GCP one click deployment postcreate hook
EugeneLightsOn May 30, 2024
60ab1a1
GCP one click deployment postcreate hook
EugeneLightsOn May 30, 2024
614a404
GCP one click deployment postcreate hook - final
EugeneLightsOn May 30, 2024
d774fa4
GCP one click deployment postcreate hook - final
EugeneLightsOn May 30, 2024
eb042e4
GCP one click deployment postcreate hook - final
EugeneLightsOn May 30, 2024
501cefa
Merge branch 'refs/heads/main' into EXT2-55-GCP_one_click_deployment
EugeneLightsOn May 30, 2024
ffbd560
GCP one click deployment postcreate hook - review fixes
EugeneLightsOn May 31, 2024
25d12c2
Merge branch 'refs/heads/main' into EXT2-55-GCP_one_click_deployment
EugeneLightsOn May 31, 2024
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
76 changes: 37 additions & 39 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,62 +1,48 @@
# This Dockerfile is intended for One-Click deployment to Google Cloud Run
# ------------------------------------------------------------------------
FROM ghcr.io/cohere-ai/terrarium:latest as terrarium

FROM buildpack-deps:buster
FROM python:3.11
LABEL authors="Cohere"

## set ENV for python
ENV PG_APP_HOME=/etc/docker-app
ENV PYTHON_VERSION=3.11.8
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PYTHONIOENCODING=utf-8
ENV LANG C.UTF-8
ENV PYTHONPATH=/workspace/src/
# "Activate" the venv manually for the context of the container
ENV VIRTUAL_ENV=/workspace/.venv
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
# Keep the poetry venv name and location predictable
ENV POETRY_VIRTUALENVS_IN_PROJECT=true
ENV APP_HOME=/workspace
COPY docker_scripts/gcp-entrypoint.sh /sbin/gcp-entrypoint.sh

# Install python
RUN cd /usr/src \
&& wget https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz \
&& tar -xzf Python-$PYTHON_VERSION.tgz \
&& cd Python-$PYTHON_VERSION \
&& ./configure --enable-optimizations \
&& make install \
&& ldconfig \
&& rm -rf /usr/src/Python-$PYTHON_VERSION.tgz /usr/src/Python-$PYTHON_VERSION \
&& update-alternatives --install /usr/bin/python python /usr/local/bin/python3 1
RUN chmod 755 /sbin/gcp-entrypoint.sh \
&& curl -sL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get update \
&& apt-get install --no-install-recommends -y nginx nodejs \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& npm install -g pnpm \
&& npm install -g pm2

# Install poetry
RUN pip3 install --no-cache-dir poetry==1.6.1
# Copy nginx config \
COPY docker_scripts/nginx.conf /etc/nginx/nginx.conf

WORKDIR /workspace

# Copy dependency files to avoid cache invalidations
COPY pyproject.toml poetry.lock ./

# Install dependencies
RUN poetry install
RUN pip3 install --no-cache-dir poetry==1.6.1 \
&& poetry config installer.max-workers 10 \
&& poetry install --without setup \
&& (poetry cache clear --all --no-interaction PyPI || true) \
&& (poetry cache clear --all --no-interaction _default_cache || true)

# Copy the rest of the code
COPY src/backend src/backend

COPY docker_scripts/ ${APP_HOME}/
COPY docker_scripts/cloudrun-entrypoint.sh /sbin/entrypoint.sh
RUN chmod 755 /sbin/entrypoint.sh

# Install nodejs
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash -
RUN apt-get install -y nodejs
RUN npm install -g pnpm
# pm2 to start frontend
RUN npm install -g pm2

# ENV for frontend
ENV NEXT_PUBLIC_API_HOSTNAME="http://localhost:8000"
ENV PYTHON_INTERPRETER_URL="http://terrarium:8080"
COPY docker_scripts/ ${PG_APP_HOME}/

# Install frontend dependencies
WORKDIR /workspace/src/interfaces/coral_web
Expand All @@ -70,10 +56,22 @@ COPY src/interfaces/coral_web/package.json src/interfaces/coral_web/yarn.lock* s
COPY src/interfaces/coral_web/.env.development .
COPY src/interfaces/coral_web/.env.production .

RUN pnpm install
ENV NEXT_PUBLIC_API_HOSTNAME='/api'
RUN pnpm install \
&& pnpm next:build

# Terrarium
WORKDIR /usr/src/app
COPY --from=terrarium /usr/src/app/package*.json ./
RUN npm install -g ts-node \
&& npm install \
&& npm prune --production
COPY --from=terrarium /usr/src/app/. .
ENV ENV_RUN_AS "docker"

EXPOSE 9000/tcp
EXPOSE 3000/tcp
WORKDIR ${APP_HOME}
# Ports to expose
EXPOSE 4000/tcp
EXPOSE 8000/tcp
EXPOSE 8090/tcp

CMD ["/sbin/entrypoint.sh"]
CMD ["/sbin/gcp-entrypoint.sh"]
29 changes: 24 additions & 5 deletions app.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
{
"name": "one-click-demo",
"name": "toolkit-deploy",
"env": {
"DATABASE_URI": {
"description": "URI for your Postgres database",
"default": "postgresql+psycopg2://postgre:postgre@localhost:5432/toolkit"
"DATABASE_URL": {
"description": "URL for your Postgres database"
},
"COHERE_API_KEY": {
"description": "Your Cohere API key"
}
},
"hooks": {
"prebuild": {
"commands": [
"gcloud auth configure-docker"
]
},
"postcreate": {
"commands": [
"chmod +x ./gcp_postcreate_hook.sh",
"./gcp_postcreate_hook.sh"
]
}
},
"options": {
"allow-unauthenticated": true
"allow-unauthenticated": true,
"memory": "12288Mi",
"cpu": "4",
"port": 4000,
"max-instances": 2
}
}
2 changes: 1 addition & 1 deletion docker_scripts/env-defaults
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ DB_EXTENSION=${DB_EXTENSION:-}

# Defaults for the toolkit
export NEXT_PUBLIC_API_HOSTNAME=${NEXT_PUBLIC_API_HOSTNAME:-http://localhost:8000}
export PYTHON_INTERPRETER_URL=${PYTHON_INTERPRETER_URL:-http://terrarium:8080}
export PYTHON_INTERPRETER_URL=${PYTHON_INTERPRETER_URL:-http://localhost:8080}
export DATABASE_URL=${DATABASE_URL:-postgresql+psycopg2://postgre:postgre@localhost:5432/toolkit}
33 changes: 28 additions & 5 deletions docker_scripts/functions
Original file line number Diff line number Diff line change
Expand Up @@ -237,23 +237,46 @@ run_postgre() {
echo "PostgreSQL ${PG_VERSION} started"
}

run_nginx() {
echo "Starting Nginx Proxy..."
nginx
echo "Nginx Proxy started"
}


run_backend() {
cd /workspace
source /workspace/.venv/bin/activate
cd /workspace
echo "Migration started..."
echo "DATABASE_URL: $DATABASE_URL"
alembic -c src/backend/alembic.ini upgrade head
echo "Migration finished..."
echo "Starting FastAPI..."
exec uvicorn backend.main:app --host 0.0.0.0 --port 8000 --loop asyncio
}

run_backend_poetry() {
cd /workspace
poetry install --without setup
source .venv/bin/activate
echo "Migration started..."
alembic -c src/backend/alembic.ini upgrade head
echo "Migration finished..."
echo "Starting FastAPI..."
exec uvicorn backend.main:app --host 0.0.0.0 --port 8000 --loop asyncio
}

run_frontend_proxy() {
cd /workspace/src/interfaces/coral_web
echo "Starting Frontend..."
pm2 start pnpm -- start:single-docker-proxy
echo "Frontend started..."
}

run_frontend() {
cd /workspace/src/interfaces/coral_web
if [[ ${NEXT_PUBLIC_API_HOSTNAME} != *"localhost:8000"* ]]; then
echo "Building Frontend when we are not in a localhost environment"
pnpm next:build
fi
echo "Building Frontend when we are not in a localhost environment"
pnpm next:build
echo "Starting Frontend..."
pm2 start pnpm -- start:single-docker
echo "Frontend started..."
Expand Down
17 changes: 17 additions & 0 deletions docker_scripts/gcp-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
set -e

# shellcheck source=runtime/functions
source "${PG_APP_HOME}/functions"

[[ ${DEBUG} == true ]] && set -x

# default behaviour is to launch apps
if [[ -z ${1} ]]; then
run_nginx
run_frontend_proxy
run_terrarium
run_backend
else
exec "$@"
fi
85 changes: 85 additions & 0 deletions docker_scripts/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
worker_connections 768;
# multi_accept on;
}

http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 50M;
# server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

upstream backend {
server 127.0.0.1:8000;
}

upstream frontend {
server 127.0.0.1:8090;
}

server {
listen 4000 default_server;
listen [::]:4000 default_server;

location /api {
rewrite /api/(.*) /$1 break;
proxy_pass http://backend;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}

location / {
proxy_pass http://frontend;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}

##
# SSL Settings
##

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;

##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
# Gzip Settings
##

gzip on;

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Binary file added docs/assets/cloud_shell_stuck.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions docs/deployment_guides/gcp_one_click_deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Google Cloud Platform One Click Deployment Guide

Before deploying to Google Cloud Run, you'll need a postgres database accessible to your Google Cloud Project, authenticated by a username and password. You'll be prompted for a `DATABASE_URL` before the container builds.

[![Run on Google Cloud](https://deploy.cloud.run/button.svg)](https://deploy.cloud.run?dir=/)

## Deployment Steps

After clicking the button above, you'll be taken to the Google Cloud Console. Follow these steps to deploy the Toolkit:
- **Select a Project**: Choose the Google Cloud Project you want to deploy the Toolkit to. If you don't have a project, you need to create [one](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
- **Set the Region**: Choose the region you want to deploy the Toolkit to.
- **Set the DATABASE_URL environment variable**: Enter the connection string of the format `postgresql+psycopg2://USERNAME:PASSWORD@HOST:PORT/DB_NAME`. The `HOST` value here is the Public IP address of your provisioned PostgreSQL database, and the default `PORT` is 5432. Make sure to use the username and password pair you set when creating your SQL instance. For example, `postgresql+psycopg2://myuser:mypassword@<your-db-public-ip-address>:5432/toolkit`.
- **Set the Cohere API Key**: Enter your Cohere API key, you can create one on the [Cohere Dashboard](https://dashboard.cohere.com).
- **Allow access to the git registries**: Click 'yes' to allow access to the git registries.

## Post-Deployment Steps

After the deployment process is complete, you'll be able to access the Toolkit by navigating to the URL provided in the Google Cloud Shell.
Optionally you can get this URL using GCP console, to do it follow these steps:
- Click on the "Cloud Run" button on the left side of the screen
- Click on the toolkit-deploy service
- Click on the "URL" link to open the Toolkit in a new tab

## Possible Deployment Errors

If the deployment is stuck on pushing the image to the Container Registry close the shell and try to redeploy the service.

If the deployment is stuck in a pending state or the connection to your Google Cloud Shell was lost like it shown on the image below:
![](/docs/assets/cloud_shell_stuck.png)

or you get the nginx 502 error when you try to access the Toolkit URL,
it means that the deployment process was not completed successfully, and we need to create a new revision for our deployment with correct settings.

Cloud Run does not set the startupProbe settings to the correct value, so we need to set it in the new revision.

To do it follow next steps:
- Navigate to the Google Cloud Console
- Click on the "Cloud Run" button on the left side of the screen
- Click on the toolkit-deploy service
- Click on the "Edit & Deploy New Revision" button
- Scroll down to the "Health checks" section
- Delete the existing health check
- Click on the "Add health check" button
- Select health check type: Startup check
- Select probe type: HTTP
- Path (e.g./ready): /api/health
- Port: 4000
- Initial delay: 0
- Period: 1
- Failure threshold: 120
- Timeout: 1
- Click "Add" button
- Click "Deploy" button

3 changes: 2 additions & 1 deletion docs/service_deployments.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ Looking to serve your application in production? Deploy the Toolkit to your pref
- click on the container name
- click on "Logs" tab to see the logs
2) Navigate to the "Overview" tab to see the FQDN of the container instance
3) Open the \<FQDN\>:4000 in your browser to access the Toolkit
3) Open the \<FQDN\>:4000 in your browser to access the Toolkit
- [One Click Deploy to GCP](deployment_guides/gcp_one_click_deployment.md): Help setup your container to Cloud Run.
16 changes: 16 additions & 0 deletions gcp_postcreate_hook.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash
echo "Region $GOOGLE_CLOUD_REGION"
echo "Project $GOOGLE_CLOUD_PROJECT"
echo "Service $K_SERVICE"
echo "URL $SERVICE_URL"
gcloud run services describe toolkit-deploy --project $GOOGLE_CLOUD_PROJECT --region $GOOGLE_CLOUD_REGION --format export > service.yaml
sed -i '/template:/,/spec:/s/^\(\s*name:\).*/\1 ""/' service.yaml
sed -i '/startupProbe:/,/timeoutSeconds: 240/c\
startupProbe:\
timeoutSeconds: 1\
periodSeconds: 1\
failureThreshold: 120\
httpGet:\
path: /api/health\
port: 4000' service.yaml
gcloud run services replace service.yaml --project $GOOGLE_CLOUD_PROJECT --region $GOOGLE_CLOUD_REGION
Loading
Loading