Skip to content

Commit

Permalink
feat: Add support for Docker in production
Browse files Browse the repository at this point in the history
  • Loading branch information
blms committed Sep 2, 2021
1 parent 602b4b8 commit 68fae86
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 18 deletions.
63 changes: 57 additions & 6 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,18 +1,69 @@
## Required for all environments
# -----------------------------------------------------------------------------
# Required for all environments
# -----------------------------------------------------------------------------

## Email address from which system emails will be sent
EMAIL_FROM=[email protected]

## The hostname of this instance, e.g. localhost:3000 or my-app.my-domain.com
HOSTNAME=localhost:3000

## Unicode Locale string for multilingual support; at present, only en_US.UTF-8 is supported
LANG=en_US.UTF-8

## The protocol this instance is served on (http or https)
PROTOCOL=http

## The environment for this instance; set to 'development' or 'production'
RACK_ENV=development
RAILS_ENV=development

## Rails configurations that can be changed per this instance's needs
RAILS_LOG_TO_STDOUT=enabled
RAILS_SERVE_STATIC_FILES=enabled

## A secure key used to encrypt passwords
SECRET_KEY_BASE=

## SendGrid configuration for system emails; see README for instructions
SENDGRID_PASSWORD=
SENDGRID_USERNAME=apikey

## Required if ACTIVE_STORAGE_SERVICE: 'amazon' in config/application.yml
# AWS_ACCESS_KEY_ID
# AWS_BUCKET
# AWS_REGION
# AWS_SECRET_ACCESS_KEY
# -----------------------------------------------------------------------------
# Required for production environments
# -----------------------------------------------------------------------------

## Database credentials to use on this production instance
# DM2_DATABASE_USER=
# DM2_DATABASE_PASSWORD=

# -----------------------------------------------------------------------------
# Required for running Docker Compose in a production environment
# -----------------------------------------------------------------------------

## Local filesystem mount point for PostgreSQL database. It is recommended to
## change this to something persistent on your local filesystem that is regularly backed up.
# DATABASE_FS_MOUNT=./tmp/prod-db

## Port for the Rails backend. Should be 443 to use provided Docker image and Docker
## Compose yml files.
# PORT=443

# -----------------------------------------------------------------------------
# Required if using an external PostgreSQL database
# -----------------------------------------------------------------------------

## External PostgreSQL database URL
## - Development env will look for or create a database called dm2_staging
## - Production env will look for or create a database called dm2_production
# DATABASE_URL=postgres://user:pass@hostname

# -----------------------------------------------------------------------------
# Required if ACTIVE_STORAGE_SERVICE: 'amazon' in config/application.yml
# -----------------------------------------------------------------------------

## AWS credentials to use for storage
# AWS_ACCESS_KEY_ID=
# AWS_BUCKET=
# AWS_REGION=
# AWS_SECRET_ACCESS_KEY=
10 changes: 7 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ FROM ruby:2.5.7 AS dm2-dev

# Install node.js and yarn
RUN apt-get update -qq && apt-get install -y curl sudo
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
RUN curl -fsSL https://deb.nodesource.com/setup_12.x | sudo -E bash -
RUN apt-get install -y nodejs
RUN npm install -g yarn
RUN npm install -g yarn@1.7.0

# Install bundler and API
ENV INSTALL_PATH /opt/app
Expand All @@ -19,12 +19,16 @@ RUN bundle install
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 443
EXPOSE 3000
EXPOSE 3001

# Install frontend
WORKDIR $INSTALL_PATH/client
RUN yarn install
RUN yarn install && NODE_OPTIONS="--max_old_space_size=2560" yarn build-craco
WORKDIR $INSTALL_PATH
RUN cp -a $INSTALL_PATH/client/build/. $INSTALL_PATH/public/
RUN yarn deploy

# Run shell
CMD ["/bin/sh"]
1 change: 1 addition & 0 deletions Procfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: bundle exec puma -p $PORT -C config/puma.rb
60 changes: 59 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ DM2 design was inspired by the DM project (https://github.com/performant-softwar
* [Set up database](#set-up-database)
- [Local installation](#local-installation)
* [With Docker Compose](#with-docker-compose)
+ [Development environment](#development-environment)
+ [Production environment](#production-environment)
* [With Heroku local development environment](#with-heroku-local-development-environment)
* [Manually](#manually)
- [Active Storage](#active-storage)
Expand Down Expand Up @@ -141,6 +143,8 @@ cp .env.sample .env
cp config/application.sample.yml config/application.yml
```

#### Development environment

Edit the environment variables as necessary. The sample values are all standard for a development environment, except for those left blank: `SECRET_KEY_BASE` should be a secure encryption key, and `SENDGRID_PASSWORD` should be a SendGrid API Key. For more information about these variables, see above section on [configuration variables](#configuration-variables).

Then, use Docker Compose to build the necessary Docker images:
Expand All @@ -150,21 +154,75 @@ docker-compose build

Run any pending database migrations:
```sh
docker-compose run --rm rails db:migrate
docker-compose run --rm app rails db:migrate
```

And finally, boot the application:
```sh
docker-compose up
```

If you wish to mount the code directory from your local filesystem onto the Docker container in order to develop on it and use hot-reloading features, you can use the following command:
```sh
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
```

After boot completes, the app should be up and running on `localhost:3000`.

You may stop the application at any time by opening another shell in the same `dm-2` directory and running:
```sh
docker-compose down
```

#### Production environment

Edit the environment variables as necessary. In addition to those listed for the development environment, it is necessary to uncomment and set the variables listed under "Required for production environments" and "Required for running Docker Compose in a production environment." The following are also required:

```env
RAILS_ENV=production
RACK_ENV=production
PROTOCOL=https
```

<details>
<summary>
Note about HTTPS and production
</summary>

As you have set the three above variables to `production` and `https`, the app will be served from port 443 over HTTPS.

You will need a valid HTTPS certificate to run the app in production. You may also need to run Nginx with a reverse proxy, etc. to run from a hostname other than localhost. That is outside the scope of this README.

It is **not recommended** and **not supported**, but if you wish to just get the app up and running quickly over localhost, you may change `/config/environments/production.rb:41` to `config.force_ssl = false`, and set `PROTOCOL` back to `http`. This is not secure, but will allow you to run the app over plain HTTP without a certificate.
</details>

Then, use Docker Compose to build the necessary Docker images:
```sh
docker-compose build
```

Run any pending database migrations using the `docker-compose.prod.yml` overrides:
```sh
docker-compose -f docker-compose.yml -f docker-compose.prod.yml run --rm app rails db:migrate
```

And finally, boot the application in detached mode using the same overrides:
```sh
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```

During boot, you may wish to view logs for the application:
```sh
docker-compose logs -f -t
```

After boot completes, the app should be up and running on `localhost:443`.

You may stop the application at any time by opening another shell in the same `dm-2` directory and running:
```sh
docker-compose down
```

### With Heroku local development environment

DM2 is a pretty standard Ruby on Rails 5.x application. It uses a PostgreSQL and has been developed using PostgreSQL v11.1. It was developed using Ruby 2.5.7 and Bundler 2.2.23. Setting up PostgresSQL, Ruby, and Bundler are beyond the scope of this README, but plenty of information is available online about these tools.
Expand Down
5 changes: 5 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
version: "3.9"
services:
app:
volumes:
- .:/opt/app
21 changes: 21 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: "3.9"
services:
db:
env_file:
- .env
environment:
POSTGRES_DB: dm2_production
POSTGRES_USER: "${DM2_DATABASE_USER}"
POSTGRES_PASSWORD: "${DM2_DATABASE_PASSWORD}"
volumes:
- "${DATABASE_FS_MOUNT}:/var/lib/postgresql/data"

app:
restart: always
command: bash -c "rm -f tmp/pids/server.pid && cd /opt/app && foreman start -f Procfile.prod"
environment: # May be overridden by values in .env
DATABASE_URL: postgres://${DM2_DATABASE_USER}:${DM2_DATABASE_PASSWORD}@db
RACK_ENV: production
RAILS_ENV: production
ports:
- "443:443"
17 changes: 9 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ services:
db:
image: postgres:11.12
environment:
POSTGRES_USER: dm2_staging
POSTGRES_PASSWORD: dm2_staging_password
POSTGRES_DB: dm2_staging
POSTGRES_USER: dm2_dev_user
POSTGRES_PASSWORD: dm2_dev_password
command: postgres -c listen_addresses='*'
volumes:
- ./tmp/db:/var/lib/postgresql/data
- ./tmp/dev-db:/var/lib/postgresql/data
app:
build: .
command: bash -c "rm -f tmp/pids/server.pid && cd /opt/app && foreman start -f Procfile.dev"
volumes:
- .:/opt/app
command: bash -c "rm -f tmp/pids/server.pid && cd /opt/app && bundle exec foreman start -f Procfile.dev"
ports:
- "3001:3001"
- "3000:3000"
depends_on:
- db
env_file:
- .env
environment:
DATABASE_URL: postgres://dm2_staging:dm2_staging_password@db
environment: # May be overridden by values in .env
DATABASE_URL: postgres://dm2_dev_user:dm2_dev_password@db
RACK_ENV: development
RAILS_ENV: development

0 comments on commit 68fae86

Please sign in to comment.