Skip to content

Commit

Permalink
Merge pull request #37 from rahu1ramesh/BAH-4127
Browse files Browse the repository at this point in the history
Add docker Compose Orchestration And Setup Guide
  • Loading branch information
bodhish authored Oct 22, 2024
2 parents 8b1bb6c + 30278a8 commit 23c65ae
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 46 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@

/app/assets/builds/*
!/app/assets/builds/.keep
/vendor/
71 changes: 28 additions & 43 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,72 +1,57 @@
# syntax=docker/dockerfile:1
# check=error=true

# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build -t medispeak_backend .
# docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name medispeak_backend medispeak_backend

# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=3.2.2
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base

# Rails app lives here
WORKDIR /rails

# Install base packages
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 libvips postgresql-client && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
apt-get install --no-install-recommends -y \
curl libjemalloc2 libvips postgresql-client && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/cache/apt/archives/*

# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"

# Throw-away build stage to reduce size of final image
# Build stage for gems and precompilation
FROM base AS build

# Install packages needed to build gems
# Install build dependencies and clean up in the same layer
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libpq-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
apt-get install --no-install-recommends -y \
build-essential git libpq-dev pkg-config && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/cache/apt/archives/*

# Install application gems
# Install gems and clean up after installation to save space
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
RUN bundle install --jobs=4 --retry=3 && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}/ruby/*/cache" "${BUNDLE_PATH}/ruby/*/bundler/gems/*/.git" && \
bundle exec bootsnap precompile --gemfile

# Copy application code
# Copy application code after bundle install (for caching purposes)
COPY . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
# Precompile bootsnap and assets
RUN bundle exec bootsnap precompile app/ lib/ && \
SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile




# Final stage for app image
# Final image for running the application
FROM base

ARG RAILS_ENV \
BUNDLE_DEPLOYMENT \
BUNDLE_PATH \
BUNDLE_WITHOUT

# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

# Run and own only the runtime files as a non-root user for security
# Run as non-root user for security
RUN groupadd --system --gid 1000 rails && \
useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
chown -R rails:rails db log storage tmp
USER 1000:1000
USER rails:rails

# Entrypoint prepares the database.
# Entrypoint and default command
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]
EXPOSE 3000
CMD ["./bin/thrust", "./bin/rails", "server"]
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ GEM
bindex (0.8.1)
bootsnap (1.18.4)
msgpack (~> 1.2)
brakeman (6.2.1)
brakeman (6.2.2)
racc
builder (3.3.0)
capybara (3.40.0)
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ This is the backend API for Medispeak, a tool that provides seamless transcripti
## Setup

For detailed setup instructions, please refer to our [Setup Documentation](docs/development_setup.md).

## Docker Setup

For a containerized environment, detailed instructions are available in our [Developer Setup Guide with Docker Compose](docs/docker_setup_guide.md). This guide explains how to bring up the services required for running Medispeak via Docker, ensuring an efficient and scalable development workflow.
54 changes: 54 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
services:
medispeak_db:
image: 'postgres:${POSTGRES_IMAGE_TAG:?}'
container_name: medispeak_db
volumes:
- medispeak_data:/var/lib/postgresql/data:rw
command: postgres -c 'max_connections=500'
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
ports:
- "${DB_PORT}:${DB_PORT}"
restart: unless-stopped
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 30s
timeout: 10s
retries: 5

medispeak_backend:
build:
context: .
dockerfile: Dockerfile
args:
RAILS_ENV: ${RAILS_ENV}
BUNDLE_DEPLOYMENT: ${BUNDLE_DEPLOYMENT}
BUNDLE_PATH: ${BUNDLE_PATH}
BUNDLE_WITHOUT: ${BUNDLE_WITHOUT}
container_name: medispeak_backend
command: "bundle exec rails s -p ${BACKEND_PORT} -b '0.0.0.0'"
environment:
DB_HOST: ${DB_HOST}
DB_NAME: ${DB_NAME}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
OPENAI_ACCESS_TOKEN: ${OPENAI_ACCESS_TOKEN}
OPENAI_ORGANIZATION_ID: ${OPENAI_ORGANIZATION_ID}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
AWS_REGION: ${AWS_REGION}
AWS_BUCKET: ${AWS_BUCKET}
PLUGIN_BASE_URL: ${PLUGIN_BASE_URL}
volumes:
- .:/app:cached
ports:
- "${BACKEND_PORT}:${BACKEND_PORT}"
depends_on:
medispeak_db:
condition: service_healthy
restart: unless-stopped
volumes:
medispeak_data:
driver: local
205 changes: 205 additions & 0 deletions docs/docker_setup_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
# Medispeak Developer Setup Guide with Docker Compose

This guide will walk you through the steps to set up the Medispeak backend using Docker Compose. The configuration includes two main services:

1. **Rails Backend** (`medispeak_backend`): The main application container running the Medispeak Rails backend.
2. **PostgreSQL Database** (`medispeak_db`): A database container that handles data persistence for the Medispeak application.

---

## Prerequisites

Before getting started, make sure you have the following installed on your local machine:

1. **Docker**: For containerizing and running the services.
2. **Docker Compose**: To manage the multi-container setup.

Ensure Docker and Docker Compose are properly installed and running. You can verify the installation by running:

```bash
docker --version
docker-compose --version
```

## 1. Docker Compose Configuration Overview

The `docker-compose.yml` file defines two main services: the PostgreSQL database (`medispeak_db`) and the Rails backend (`medispeak_backend`).

### 1.1 PostgreSQL Database Configuration

The `medispeak_db` service uses the official PostgreSQL image and specifies several key configurations:

- **Environment Variables**:
- `POSTGRES_DB`: Defines the database name.
- `POSTGRES_USER`: Sets the username for the database.
- `POSTGRES_PASSWORD`: Sets the password for the PostgreSQL user.
- **Ports**: The container exposes the PostgreSQL port defined by `DB_PORT`.
- **Volumes**: Data is persisted across container restarts using a Docker volume (`medispeak_data`).

### 1.2 Medispeak Backend Configuration

The `medispeak_backend` service is the core Rails application. It depends on the `medispeak_db` service being healthy before starting. Key aspects:

- **Build Arguments**: The build process takes several arguments, such as `RAILS_ENV`, `BUNDLE_DEPLOYMENT`, and others for bundling gems and preparing the Rails environment.
- **Environment Variables**:
- OpenAI credentials (`OPENAI_ACCESS_TOKEN`, `OPENAI_ORGANIZATION_ID`).
- AWS credentials for file storage (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, etc.).
- PostgreSQL database connection details (`DB_HOST`, `DB_NAME`, `DB_USERNAME`, `DB_PASSWORD`).
- Plugin-related configuration (`PLUGIN_BASE_URL`).
- **Ports**: The Rails backend exposes the port defined by `BACKEND_PORT`.
- **Volumes**: The application code is mounted inside the container using a bind mount to keep it in sync with your local development files.

---

## 2. Setting Up Environment Variables

Before running the services, you’ll need to configure environment variables. These variables control the behavior of both the Rails backend and PostgreSQL database.

1. **Create a `.env` file** in the root directory (where the `docker-compose.yml` file is located) with the following content:

```bash
# OpenAI Credentials
OPENAI_ACCESS_TOKEN=your_openai_access_token
OPENAI_ORGANIZATION_ID=your_openai_organization_id

# Plugin Configuration
PLUGIN_BASE_URL=https://medispeak-app.pages.dev

# Rails Environment
RAILS_ENV=
BUNDLE_DEPLOYMENT=1
BUNDLE_PATH="/usr/local/bundle"
BUNDLE_WITHOUT="development test"
BACKEND_PORT=3000

# AWS S3 Configuration (required for production)
AWS_ACCESS_KEY_ID=your_aws_access_key
AWS_SECRET_ACCESS_KEY=your_aws_secret_key
AWS_REGION=your_aws_region
AWS_BUCKET=your_s3_bucket_name

# Database Configuration (Required)
POSTGRES_IMAGE_TAG=14.2-alpine
DB_NAME=medispeak
DB_NAME_TEST=medispeak_test
DB_HOST=medispeak_db
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_PORT=5432
```

> **Note**: `RAILS_ENV` sets the environment (e.g., development, production), `BUNDLE_DEPLOYMENT` ensures only production gems install, `BUNDLE_PATH` defines the gem directory, `BUNDLE_WITHOUT` skips development/test gems, and `BACKEND_PORT` specifies the port the app runs on (default: 3000).
>
> **Note**: A sample `.env` file has been provided for reference and can be found in the [example.env](../example.env) file. This example will help guide the configuration process by specifying the required environment variables. Please review and adapt it as necessary to meet your project requirements.
>
> **Note**: Replace placeholder values (`your_openai_access_token`, `your_aws_access_key`, etc.) with actual values from your OpenAI and AWS accounts.
---

## 3. Running the Application with Docker Compose

After setting up the environment variables, you're ready to bring up the services.

### Step-by-Step Instructions

1. **Build the services**:
Run the following command to build the Docker images for the services, using the configurations from the `docker-compose.yml` file:

```bash
docker-compose build
```

2. **Start the services**:
Start both the PostgreSQL and Rails backend services by running:

```bash
docker-compose up -d
```

- The **PostgreSQL** service (`medispeak_db`) will start first.
- The **Rails backend** service (`medispeak_backend`) will wait for the database to be healthy before starting.

3. **Verify the setup**:
- Once the services are up and running, the Rails backend will be available at `http://localhost:3000` (or on the port you’ve specified in the `.env` file as `BACKEND_PORT`).
- You can check the logs for any issues or confirmations of successful setup by running:

```bash
docker-compose logs
```

4. **Stopping the services**:
To stop the services gracefully, run:

```bash
docker-compose down
```

This command will stop the running containers and remove them, but the data in your PostgreSQL volume will remain intact for future use.

---

## 4. Additional Configuration Options

- **Running Migrations**:
After the services are running, you may need to run database migrations:

```bash
docker-compose exec medispeak_backend bundle exec rails db:migrate
```

- **Import Seed Data**:
After the services are running, you may need to run the following command to import the seed:

```bash
docker-compose exec medispeak_backend bundle exec rails db:seed
```

- **Accessing the Rails Console**:
If you need to open the Rails console for debugging or testing, you can do so by running:

```bash
docker-compose exec medispeak_backend bundle exec rails console
```

- **Database Health Check**:
The PostgreSQL service has a health check that ensures the database is ready before the Rails backend tries to connect. You can monitor the database’s health by checking the logs:

```bash
docker-compose logs medispeak_db
```

---

## 5. Persistent Data with Docker Volumes

- The PostgreSQL container uses a Docker volume named `medispeak_data` to persist its data. This ensures that your data will be preserved even if the container is stopped or removed.

- The volume configuration is defined at the bottom of the `docker-compose.yml` file:

```yaml
volumes:
medispeak_data:
driver: local
```

To inspect the volume data, you can run:

```bash
docker volume ls
```

---

## 6. Production Considerations

For production deployments, ensure the following:

- **AWS Credentials**: The AWS credentials in your environment variables must be set to properly manage file storage in S3.
- **RAILS_MASTER_KEY**: Ensure that you provide the correct `RAILS_MASTER_KEY` for your encrypted credentials.
- **Secret Management**: Consider using a secure secret management system, such as AWS Secrets Manager, for sensitive information like OpenAI tokens, AWS credentials, and database passwords.

---

## Conclusion

By following this guide, you can get the Medispeak backend and its PostgreSQL database up and running using Docker Compose. The environment is flexible, allowing you to adjust configurations via environment variables and scale for both development and production needs.
Loading

0 comments on commit 23c65ae

Please sign in to comment.