Skip to content

Instantly share code, notes, and snippets.

@jigneshkhokhani
Last active October 9, 2023 05:18
Show Gist options
  • Save jigneshkhokhani/832926c81b8ea22d8a10f131d2ae85e6 to your computer and use it in GitHub Desktop.
Save jigneshkhokhani/832926c81b8ea22d8a10f131d2ae85e6 to your computer and use it in GitHub Desktop.
rails-new-docker-app-creator : Create new rails app from docker itself. It will create full rails directory without installing anything in local system.
// This devcontainer.json file can be generated automatically from the VS-Code itself.
// This is just for reference purposes.
// Additionally, It provides a way of how to install VS-Code extensions automatically after devcontainer launched up
// using "customizations" options
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose
{
"name": "AirBNB-Colne with Existing Docker Compose (Extend)",
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
"dockerComposeFile": [
"../docker-compose.yaml",
"docker-compose.yml"
],
// The 'service' property is the name of the service for the container that VS Code should
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
"service": "web",
// The optional 'workspaceFolder' property is the path VS Code should open by default when
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line if you want start specific services in your Docker Compose config.
// "runServices": [],
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
// "shutdownAction": "none",
// Uncomment the next line to run commands after the container is created.
// "postCreateCommand": "cat /etc/os-release",
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"castwide.solargraph",
"rebornix.Ruby",
"misogi.ruby-rubocop",
"erb-toggle.toggleTags",
"fnando.linter",
"tabnine.tabnine-vscode",
"wingrunr21.vscode-ruby",
"Shopify.ruby-lsp",
"vortizhe.simple-ruby-erb"
]
}
}
// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "devcontainer"
}
# This file is also auto-created by VS-Code with devcontainer.json
# This is an extended configuration for the actual docker-compose.yml file for your project.
# This will override the commands you specified here with your actual docker-compose.yml file.
version: '3.8'
services:
# Update this to the name of the service you want to work with in your docker-compose.yml file
web:
# Uncomment if you want to override the service's Dockerfile to one in the .devcontainer
# folder. Note that the path of the Dockerfile and context is relative to the *primary*
# docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile"
# array). The sample below assumes your primary file is in the root of your project.
#
# build:
# context: .
# dockerfile: .devcontainer/Dockerfile
volumes:
# Update this to wherever you want VS Code to mount the folder of your project
- ..:/workspaces:cached
# Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
# cap_add:
# - SYS_PTRACE
# security_opt:
# - seccomp:unconfined
# Overrides default command so things don't shut down after the process ends.
command: /bin/sh -c "while sleep 1000; do :; done"

How to create new rails app using Dockerfile

  1. Create a new folder for your new rails app

    $ mkdir blog-app
    $ cd blog-app
  2. Create a new Dockerfile.rails file with the below content

    Gist for Docker.rails

    You can use the different ruby image file as per your requirement. If you change the ruby verison then make sure that bundler path also need to change(ENV PATH="/bundle/ruby/3.2.0/bin:${PATH}").

  3. After creating the Dockerfile.rails Run below command to build the Docker image.

    $ docker build -f Dockerfile.rails -t rails-app-creator:latest .
  4. Now you can check the created image by running docker image ls command.

  5. Use newly created image to generate new rails app by running container using that image. Use the seperate storage for gem installation for persistence purposes.

    $ docker run --rm -it -v $(pwd):/rails-app -v blog-app_bundle-cache:/bundle rails-app-creator

    It will open bash shell to run ubuntu command. Now run the rails new . command in container bash shell to generate new rails app.

    # rails new . --database=postgresql -B
  6. Now you can check created directory structure in your local system in the same folder(eg, /blog-app).

# Points to consider :
# -----------------------------------
# 1) Set ENV variable for pg db `username` and `password` either in .env file and give file reference in docker-compose.yml or in docker-compose.yml itself.
#
# 2) Set database.yml `host` name as database service name `db`
# eg,
# development:
# host: db # `db` is the name of docker compose service
# username: <%= ENV["POSTGRES_USER"] %>
# password: <%= ENV["POSTGRES_PASSWORD"] %>
# adapter: postgresql
# encoding: unicode
# database: blog_app_development
#
# 3)Make sure to create rails dabase using `rails db:create` or `rails db:setup` before start application
# $ docker-compose run --rm -it web bundle exec rails db:setup
# or use the entrypoint.sh file to run those command when docker compose up.
version: '3.8'
services:
web:
build:
context: .
container_name: blog_app
command: /bin/bash -c "rm -f tmp/pids/server.pid && bundle exec rails server -b 0.0.0.0 -P tmp/pids/server.pid"
# in case of foreman gem
# command: /bin/bash -c "rm -f tmp/pids/server.pid && bin/dev"
# Eithr add .env file in root and add ENV variable or define here like below
# env_file: .env
environment:
# use this user name in database.yml file `username: <%= ENV["POSTGRES_USER"] %>`
POSTGRES_USER: postgres
# use this password in database.yml file `password: <%= ENV["POSTGRES_PASSWORD"] %>`
POSTGRES_PASSWORD: password
ports:
- 3000:3000
depends_on:
- db
- redis
volumes:
- .:/rails-app
- bundle-cache:/bundle
tty: true
redis:
image: "redis:7-alpine"
container_name: redis_server
ports:
- 6379:6379
volumes:
- redis-cache:/var/lib/redis/data
tty: false
# Replace `db` service name as a database host name in database.yml file
db:
image: postgres:15.2-alpine
container_name: app_db
restart: always
environment:
# Check you timezone from here : https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
TZ: Asia/Tokyo
PGTZ: Asia/Tokyo
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- 5432:5432
volumes:
- postgres-data:/var/lib/postgresql/data
tty: false
# This will create new volume if not exist already with ${project_name}_<specified_volume_name>.
# eg, in case of redis-cache volume it will create "blog-app_redis-cache"
volumes:
redis-cache:
postgres-data:
bundle-cache:
# If you want to give a specific name and do not want to prefix the project name
# blog-app-redis-cache:
# name: 'blog_app_redis_cache'
# blog-app-postgres-data:
# name: 'blog_app_postgres_data'
# blog-app-bundle-cache:
# name: 'blog_app_bundle_cache'
ARG RUBY_VERSION=3.2.2
# ARG NODE_MAJOR=19
# ARG APP_DIR=/rails-app
FROM ruby:$RUBY_VERSION-slim
# Install dependencies
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev libvips gnupg2 curl git
# Ensure node.js 19 is available for apt-get
RUN curl -sL https://deb.nodesource.com/setup_19.x | bash -
# Install node and yarn
RUN apt-get update -qq && apt-get install -y nodejs && npm install -g yarn
# Mount $PWD to this workdir
WORKDIR /rails-app
# To install all gem at the time of image creation
# In case if you change the Gemfile then need to re-build image
# to avoid bundle install every time when container up.
COPY Gemfile* ./
# Ensure gems are installed on a persistent volume and available as bins
VOLUME /bundle
RUN bundle config set --global path '/bundle'
ENV PATH="/bundle/ruby/$RUBY_VERSION/bin:${PATH}"
# Install bundler & install all gems from Gemfile
RUN gem install bundler && bundle install
# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
# Start rails as default command
# Can be overide from docker-compose command or CLI argument
CMD ["rails", "server", "-b", "0.0.0.0"]
# This Docker file is used to create new rails app from Docker.
# No need to install rails or ruby or any other dependecies in local system.
# Just build image, run it and create new rails app from it.
# You can change the versions and path as per your requirements.
# Build image first and then run container and create new app
# $ docker build . -t rails_app_reator
# $ docker run --rm -it -v $PWD:/rails-app rails-app-creator bash
# Inside the container. container id will be differ.
# $ root@549c71cbdb64:/rails-app# rails new . -T -d postgresql -c bootstrap
# Your app directory will be created now.
ARG RUBY_VERSION=3.2.2
FROM ruby:$RUBY_VERSION-slim as rails-app-creator
# Install dependencies
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev libvips gnupg2 curl git
# Ensure node.js 19 is available for apt-get
RUN curl -sL https://deb.nodesource.com/setup_19.x | bash -
# Install node and yarn
RUN apt-get update -qq && apt-get install -y nodejs && npm install -g yarn
# Mount $PWD to this workdir
# Default directory to work in
# Better to replace this directory name same as your project name
# because based on this directory name, rails will set different dynamic value at the time of new project creation.
# Eg, default db name will be rails-app_development, default action cabel channel prefix will be rails-app_production,
# your main application name will be `module RailsApp` in application.rb config file and so on other places.
WORKDIR /rails-app
# Ensure gems are installed on a persistent volume and available as bins
VOLUME /bundle
RUN bundle config set --global path '/bundle'
ENV PATH="/bundle/ruby/$RUBY_VERSION/bin:${PATH}"
# Install rails
RUN gem install rails bundler
# Run a shell
CMD ["/bin/bash"]
#!/bin/bash
# Exit on fail
set -e
# Ensure all gems installed.
bundle check || bundle install
# Remove server.pid if it exists
if [ -f tmp/pids/server.pid ]; then
rm -f tmp/pids/server.pid
fi
# Ensure migration is run & if no then setup db first
if bundle exec rails db:migrate; then
echo "Migrations successful :)"
else
echo "Migrations failed. Seems no DB is created yet. Running intial DB setup ..."
# Run setup if migrations fail
bundle exec rails db:setup
bundle exec rails db:migrate
fi
# Finally call command issued to the docker service
exec "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment