├── .dockerignore ├── .env.sample ├── .railsrc ├── Dockerfile.dev ├── Gemfile ├── Gemfile.lock ├── README.md ├── bootstrap.sh ├── docker-compose.yml ├── docker ├── postgres │ └── init-db.sh └── rails │ └── entrypoint-dev.sh └── template.rb /.dockerignore: -------------------------------------------------------------------------------- 1 | # Ignore version control files: 2 | .git/ 3 | .gitignore 4 | 5 | # Ignore docker and environment files: 6 | Dockerfile* 7 | docker-compose*.yml 8 | .env* 9 | .dockerignore 10 | 11 | # Ignore log files: 12 | log/*.log 13 | 14 | # Ignore temporary files: 15 | tmp/ 16 | 17 | # Ignore test files: 18 | .rspec 19 | spec/ 20 | 21 | # Ignore OS artifacts: 22 | **/.DS_Store 23 | 24 | .rspec 25 | 26 | # Ignore Development container's Home artifacts: 27 | .pry_history 28 | 29 | # bundler stuff 30 | .bundle/* 31 | 32 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | # RAILS_MASTER_KEY=secret 2 | DATABASE_URL=postgres://postgres@db/postgres?sslmode=disable 3 | REDIS_URL=redis://redis:6379/0 4 | RAILS_ENV=development 5 | NODE_ENV=development 6 | PORT=3000 7 | RAILS_MAX_THREADS=5 8 | RAILS_LOG_TO_STDOUT=true 9 | WEB_CONCURRENCY=2 10 | EMAIL_URL_HOST=lvh.me 11 | EMAIL_URL_PORT=3000 12 | BUNDLE_JOBS=4 13 | BUNDLE_RETRY=3 14 | -------------------------------------------------------------------------------- /.railsrc: -------------------------------------------------------------------------------- 1 | --force 2 | --no-deps 3 | --database=postgresql 4 | -------------------------------------------------------------------------------- /Dockerfile.dev: -------------------------------------------------------------------------------- 1 | ARG RUBY_VERSION 2 | FROM ruby:$RUBY_VERSION-alpine 3 | 4 | # Configure environment variables 5 | ENV LANG=C.UTF-8 \ 6 | HOME=/app 7 | 8 | # Make a $HOME 9 | RUN mkdir $HOME 10 | WORKDIR $HOME 11 | 12 | # Install dependencies 13 | RUN apk update \ 14 | && apk add --no-cache \ 15 | build-base \ 16 | git \ 17 | netcat-openbsd \ 18 | nodejs \ 19 | postgresql-dev \ 20 | tzdata \ 21 | yarn \ 22 | && rm -rf /var/cache/apk/* 23 | 24 | # Add a script to be executed every time the container starts. 25 | COPY docker/rails/entrypoint-dev.sh /usr/bin/ 26 | RUN chmod +x /usr/bin/entrypoint-dev.sh 27 | 28 | ENTRYPOINT ["entrypoint-dev.sh"] 29 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'rails' 3 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweslley/docker-rails-bootstrap/1933238da0df9e5fbd801869a5de89ecc36821e8/Gemfile.lock -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-rails-bootstrap 2 | 3 | An opinionated docker-compose setup for Rails apps. 4 | 5 | Currently includes ruby 3.1.1, postgres 14, redis 6, node 16, sidekiq, [mailhog][] and [pgweb][]. 6 | 7 | > This setup was created for development. 8 | 9 | ## Requirements 10 | 11 | - docker 12 | - docker-compose 13 | 14 | Due to conflicts in [user permissions][perms], you will need to add the following lines in you `~/.bashrc` or equivalent: 15 | 16 | ```bash 17 | export UID=$(id -u) 2> /dev/null 18 | export GID=$(id -g) 19 | ``` 20 | 21 | ## Usage 22 | 23 | ### Creating new Rails applications 24 | 25 | You don't need ruby installed in your local machine to create new applications. Create your next one using: 26 | 27 | ```bash 28 | git clone https://github.com/jweslley/docker-rails-bootstrap myapp 29 | cd myapp 30 | ./bootstrap.sh 31 | docker-compose up 32 | ``` 33 | 34 | ### Setting up existing Rails applications 35 | 36 | For existing applications, you can to execute the following command after cloning your project: 37 | 38 | ```bash 39 | docker-compose up --build 40 | ``` 41 | 42 | ### Starting up your Rails applications 43 | 44 | After creating or setting up an existing application, in all subsequent run you can do: 45 | 46 | ```bash 47 | docker-compose up 48 | ``` 49 | 50 | ### Stoping the application 51 | 52 | To stop the application, hit `Ctrl+C` and wait the application's shutdown. 53 | 54 | ### Executing rails commands 55 | 56 | To execute any rails command, you can do: 57 | 58 | ```bash 59 | docker-compose run --rm web bundle exec rails 60 | ``` 61 | 62 | Where `` are the arguments for rails. For example, to generate an scaffold you can do: 63 | 64 | ```bash 65 | docker-compose run --rm web bundle exec rails generate scaffold post title content:text 66 | ``` 67 | 68 | It's a lot of typing, this lead us to the next topic. =) 69 | 70 | ### Speeding up your docker-compose command using aliases 71 | 72 | To avoid a lot of typing, I strongly recommend the use of the following aliases in your shell: 73 | 74 | ```bash 75 | alias dc='docker-compose' 76 | alias b='docker-compose run --rm web bundle' 77 | alias be='docker-compose run --rm web bundle exec' 78 | alias bundle='docker-compose run --rm web bundle' 79 | alias rails='docker-compose run --rm web bundle exec rails' 80 | alias webs='docker-compose run --rm web bin/setup' # web Setup 81 | alias webx='docker-compose run --rm web' # web eXecute 82 | ``` 83 | 84 | Using the `rails` alias above, you can generate a scaffold using: 85 | 86 | ```bash 87 | rails generate scaffold post title content:text 88 | ``` 89 | 90 | ### Resetting the database 91 | 92 | All database's data are stored in a local docker volume that persits across application's restarts. To wipe out all data and reset the database, stop the application and remove the docker volume using the following command: 93 | 94 | ```bash 95 | docker volume rm 96 | ``` 97 | 98 | Where `` is the database volume's name, which is a concatenation of application's directory name and `postgres`. For example, if your application is within `myapp` directory you can remove the volume `myapp_postgres`. 99 | 100 | When you start up the application again, a new volume will be automatically created. 101 | 102 | 103 | ### Automatically restoring an database backup in you development environment 104 | 105 | You can restore an database dump to use in your local environment, for this follow the steps below: 106 | 107 | 1. reset the database in your local environment like explained in [Resetting the database](#resetting-the-database) 108 | 2. copy your database dump to `docker/postgres/backup.dump` 109 | 3. start up your application 110 | 111 | You need to reset the database because the dump only will be loaded in fresh installations to avoid overwriting of existing data. 112 | 113 | ### Customizing stack 114 | 115 | Currently this setup includes ruby 3.1.1, postgres 14 and redis 6. However you can customize the version of any of them. 116 | 117 | To customize ruby version, open the file `docker-compose.yml`, locate the following line and edit the version you would like to use. 118 | 119 | ```yaml 120 | RUBY_VERSION: '3.1.1' 121 | ``` 122 | 123 | To customize postgres and/or redis, open `docker-compose.yml` file and change image version as you wish. 124 | 125 | After editing, execute `docker-compose build` to rebuild the application's images. 126 | 127 | 128 | ## Bugs and Feedback 129 | 130 | If you discover any bugs or have some idea, feel free to create an issue on GitHub: 131 | 132 | https://github.com/jweslley/docker-rails-bootstrap/issues 133 | 134 | ## License 135 | 136 | MIT license. Copyright (c) 2020 Jonhnny Weslley 137 | 138 | See the LICENSE file provided with the source distribution for full details. 139 | 140 | 141 | [mailhog]: https://github.com/mailhog/MailHog "Web and API based SMTP testing" 142 | [pgweb]: https://sosedoff.github.io/pgweb "Cross-platform client for PostgreSQL databases" 143 | [perms]: https://github.com/docker/compose/issues/1532 144 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Creating an environment file" \ 4 | && cp .env.sample .env \ 5 | && echo "Building images" \ 6 | && docker-compose build \ 7 | && echo "Installing rails" \ 8 | && docker-compose run --rm web bundle \ 9 | && echo "Creating your application" \ 10 | && docker-compose run --rm web bundle exec rails new . -m template.rb \ 11 | && rm -rf bootstrap.sh template.rb \ 12 | && echo "Your application is ready =)" \ 13 | && echo "Run 'docker-compose up'" 14 | 15 | 16 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | 3 | x-rails: &rails 4 | build: 5 | context: . 6 | dockerfile: Dockerfile.dev 7 | args: 8 | RUBY_VERSION: '3.1.1' 9 | user: $UID:$GID 10 | env_file: .env 11 | tmpfs: 12 | - /tmp 13 | # Keeps the stdin open, so we can attach to our app container's process and 14 | # do stuff such as `byebug` or `binding.pry` 15 | stdin_open: true 16 | # Allows us to send signals (CTRL+C, CTRL+P + CTRL+Q) into the container 17 | tty: true 18 | volumes: 19 | - .:/app:cached 20 | - bundle:/usr/local/bundle 21 | depends_on: 22 | - db 23 | - redis 24 | - mail 25 | 26 | services: 27 | web: 28 | <<: *rails 29 | command: bundle exec rails server -b 0.0.0.0 30 | ports: 31 | - '3000:3000' 32 | 33 | job: 34 | <<: *rails 35 | command: bundle exec sidekiq -C config/sidekiq.yml 36 | 37 | db: 38 | image: postgres:14 39 | volumes: 40 | - postgres:/var/lib/postgresql/data 41 | - ./docker/postgres:/docker-entrypoint-initdb.d/ 42 | environment: 43 | POSTGRES_HOST_AUTH_METHOD: trust 44 | 45 | redis: 46 | image: redis:6 47 | volumes: 48 | - redis:/data 49 | 50 | mail: 51 | image: mailhog/mailhog 52 | ports: 53 | - "1025:1025" 54 | - "8025:8025" 55 | 56 | pgweb: 57 | image: sosedoff/pgweb 58 | env_file: .env 59 | command: /usr/bin/pgweb -s --bind=0.0.0.0 60 | ports: 61 | - '8081:8081' 62 | depends_on: 63 | - db 64 | 65 | volumes: 66 | postgres: 67 | redis: 68 | bundle: 69 | 70 | -------------------------------------------------------------------------------- /docker/postgres/init-db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BACKUP_FILE="/docker-entrypoint-initdb.d/backup.dump" 4 | if [ -f "$BACKUP_FILE" ]; then 5 | pg_restore --verbose --clean --no-acl --no-owner -U "$POSTGRES_USER" -d "$POSTGRES_DB" "$BACKUP_FILE" 6 | fi 7 | exit 8 | -------------------------------------------------------------------------------- /docker/rails/entrypoint-dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Remove a potentially pre-existing server.pid for Rails. 5 | rm -f /app/tmp/pids/server.pid 6 | 7 | # Then exec the container's main process (what's set as CMD in the Dockerfile). 8 | exec "$@" 9 | 10 | -------------------------------------------------------------------------------- /template.rb: -------------------------------------------------------------------------------- 1 | 2 | gem 'sidekiq' 3 | 4 | gem_group :development, :test do 5 | gem 'pry' 6 | end 7 | 8 | after_bundle do 9 | # uncomment_lines 'config/puma.rb', /WEB_CONCURRENCY/ 10 | # uncomment_lines 'config/puma.rb', /preload_app/ 11 | 12 | inject_into_file '.gitignore' do 13 | <<~EOF 14 | /.env 15 | /.cache 16 | /.yarn 17 | /docker/postgres/backup.dump 18 | EOF 19 | end 20 | 21 | environment do <<~RUBY 22 | config.i18n.default_locale = :en 23 | config.time_zone = 'UTC' 24 | 25 | config.active_job.queue_adapter = :sidekiq 26 | 27 | config.generators do |g| 28 | g.assets false 29 | g.helper false 30 | g.jbuilder false 31 | end 32 | RUBY 33 | end 34 | 35 | file 'config/sidekiq.yml', <<~EOF 36 | --- 37 | :verbose: false 38 | :concurrency: 5 39 | :queues: 40 | - [critical, 2] 41 | - default 42 | - mailers 43 | - low 44 | 45 | production: 46 | :concurrency: 5 47 | 48 | staging: 49 | :concurrency: 5 50 | EOF 51 | 52 | file 'config/initializers/action_mailer.rb', <<~EOF 53 | ActionMailer::Base.default_url_options = { 54 | host: ENV['EMAIL_URL_HOST'], 55 | port: ENV['EMAIL_URL_PORT'] 56 | } 57 | if Rails.env.development? 58 | ActionMailer::Base.delivery_method = :smtp 59 | ActionMailer::Base.smtp_settings = { address: 'mail', port: 1025 } 60 | 61 | elsif Rails.env.production? 62 | ActionMailer::Base.delivery_method = :smtp 63 | ActionMailer::Base.perform_deliveries = true 64 | ActionMailer::Base.smtp_settings = { 65 | :port => ENV['SMTP_PORT'], 66 | :address => ENV['SMTP_SERVER'], 67 | :user_name => ENV['SMTP_USERNAME'], 68 | :password => ENV['SMTP_PASSWORD'], 69 | :domain => ENV['EMAIL_URL_HOST'], 70 | :authentication => :plain 71 | } 72 | end 73 | EOF 74 | end 75 | 76 | --------------------------------------------------------------------------------