diff --git a/recipes/base.rb b/recipes/base.rb index ebb5bdf..9b49706 100644 --- a/recipes/base.rb +++ b/recipes/base.rb @@ -23,5 +23,13 @@ def gems def cook end + + private + + def relative_file_content(path) + caller_path = caller_locations.first.path + puts caller_path + File.read(File.join(File.dirname(caller_path), path)) + end end end diff --git a/recipes/deploy.rb b/recipes/deploy.rb new file mode 100644 index 0000000..4b6bc06 --- /dev/null +++ b/recipes/deploy.rb @@ -0,0 +1,47 @@ +module Recipes + class Deploy < Base + + is_auto_runnable + askable 'Where are you planning to deploy it?' + optionable %w(Cloud66 Docker None) + + def initialize(pathfinder, type: 'none') + super(pathfinder) + end + + def cook + case ask! + when 'Docker' then docker_config_files + when 'Cloud66' then cloud66_config_files + end + end + + private + + def cloud66_config_files + @template.add_file '.cloud66/cache_permissions.sh', + relative_file_content('deploy/cloud66/cache_permissions.sh') + @template.add_file '.cloud66/deploy_hooks.yml', + relative_file_content('deploy/cloud66/deploy_hooks.yml') + end + + def docker_config_files + @template.add_file 'docker/rails-env.conf', + relative_file_content('deploy/docker/rails-env.conf') + @template.add_file '.dockerignore', + relative_file_content('deploy/docker/.dockerignore') + @template.append_file 'README.md', + relative_file_content('deploy/docker/README.md') + add_file_and_replace_app_name('docker/fix_permissions.sh', + 'deploy/docker/fix_permissions.sh') + add_file_and_replace_app_name('Dockerfile', 'deploy/docker/Dockerfile') + add_file_and_replace_app_name('docker/nginx.conf', 'deploy/docker/nginx.conf') + end + + def add_file_and_replace_app_name(target_file, source_file) + @template.add_file target_file, relative_file_content(source_file) + @template.run "sed -i '' 's/app-name/#{@pathfinder.app_name}/g' #{target_file}" + end + + end +end diff --git a/recipes/deploy/cloud66/cache_permissions.sh b/recipes/deploy/cloud66/cache_permissions.sh new file mode 100644 index 0000000..eb6357d --- /dev/null +++ b/recipes/deploy/cloud66/cache_permissions.sh @@ -0,0 +1 @@ +chown nginx:app_writers $STACK_BASE/shared/cache && chmod 775 $STACK_BASE/shared/cache && sudo chmod g+s $STACK_BASE/shared/cache diff --git a/recipes/deploy/cloud66/deploy_hooks.yml b/recipes/deploy/cloud66/deploy_hooks.yml new file mode 100644 index 0000000..c52bc14 --- /dev/null +++ b/recipes/deploy/cloud66/deploy_hooks.yml @@ -0,0 +1,15 @@ +production: + first_thing: + - snippet: cloud66/node + target: rails + execute: true + - snippet: cloud66/newrelic + target: any + execute: true + after_rails: + - source: /.cloud66/cache_permissions.sh + destination: /tmp/cache_permissions.sh + target: rails + run_on: all_servers + execute: true + sudo: true diff --git a/recipes/deploy/docker/.dockerignore b/recipes/deploy/docker/.dockerignore new file mode 100644 index 0000000..d5ef56b --- /dev/null +++ b/recipes/deploy/docker/.dockerignore @@ -0,0 +1,2 @@ +public/uploads +vendor/bundle diff --git a/recipes/deploy/docker/Dockerfile b/recipes/deploy/docker/Dockerfile new file mode 100644 index 0000000..1b69c81 --- /dev/null +++ b/recipes/deploy/docker/Dockerfile @@ -0,0 +1,57 @@ +FROM phusion/passenger-ruby24 +MAINTAINER MarsBased "hola@marsbased.com" + +ENV HOME /home/app/app-name + +# Install software dependencies +RUN apt-get update +RUN apt-get install -y imagemagick + +# Use baseimage-docker's init system. +CMD ["/sbin/my_init"] + +# Expose Nginx HTTP service +EXPOSE 80 +EXPOSE 443 + +# Start Nginx / Passenger +RUN rm -f /etc/service/nginx/down + +# Remove the default site +RUN rm /etc/nginx/sites-enabled/default + +# Create app home dir +RUN mkdir -p $HOME +WORKDIR $HOME + +# Install bundle of gems +ADD Gemfile Gemfile +ADD Gemfile.lock Gemfile.lock +RUN bundle install --without development test + +# Add the nginx site and config +ADD docker/nginx.conf /etc/nginx/sites-enabled/app-name.conf +ADD docker/rails-env.conf /etc/nginx/main.d/rails-env.conf + +# Add the Rails app +ADD . /home/app/app-name + +RUN RAILS_ENV=production SECRET_KEY_BASE=NOT-IMPORTANT bin/rake assets:precompile + +# Add a tmp folder for pids +RUN mkdir -p tmp/pids + +# Define volumes + +VOLUME $HOME/public/uploads +VOLUME $HOME/log + +# Configure init scripts +RUN mkdir -p /etc/my_init.d +ADD docker/fix_permissions.sh /etc/my_init.d/fix_permissions.sh +RUN chmod +x /etc/my_init.d/fix_permissions.sh + +RUN chown -R app:app $HOME + +# Clean up APT and bundler when done. +RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*. diff --git a/recipes/deploy/docker/README.md b/recipes/deploy/docker/README.md new file mode 100644 index 0000000..746b5a7 --- /dev/null +++ b/recipes/deploy/docker/README.md @@ -0,0 +1,17 @@ + +## Docker + +Production deploys are managed with Docker. The Dockerfile makes use of some config files that can be found in the `docker` folder. + +- **fix_permissions.sh**: Makes the mountable volumes writable for the +application user. +- **rails-env.conf**: Makes env variables visible to Nginx. As the +application is running on Passenger through Nginx, every ENV variable +that needs to reach the application must be defined here. +- **nginx.conf**: Base nginx configuration. The file contains +instructions to tune the application performance. + +It's recommended to use Dockerhub (or a private docker repository) to store the application images and then use docker-compose to orchestrate the deployment. + +The docker-compose file is not included in the project and needs to be +configured on a project basis. diff --git a/recipes/deploy/docker/fix_permissions.sh b/recipes/deploy/docker/fix_permissions.sh new file mode 100644 index 0000000..0cc0534 --- /dev/null +++ b/recipes/deploy/docker/fix_permissions.sh @@ -0,0 +1,3 @@ +#!/bin/sh +chown -R app:app /home/app/app-name/public/uploads +chown -R app:app /home/app/app-name/log diff --git a/recipes/deploy/docker/nginx.conf b/recipes/deploy/docker/nginx.conf new file mode 100644 index 0000000..18c4e64 --- /dev/null +++ b/recipes/deploy/docker/nginx.conf @@ -0,0 +1,30 @@ +server { + listen 80 default_server; + root /home/app/app-name/public; + passenger_enabled on; + passenger_user app; + passenger_ruby /usr/bin/ruby2.4; + + ## Configure this with the same value of the passenger_max_pool_size + # passenger_min_instances 10; + + location ~ ^/assets/ { + expires 1y; + add_header Cache-Control public; + add_header ETag ""; + break; + } + + location ~ ^/uploads/ { + expires 24h; + add_header Cache-Control public; + add_header ETag ""; + break; + } +} + +## The number for max_pool_size should be (TOTAL_RAM * 0.75) / RAM_PER_PROCESS +# passenger_max_pool_size 10; + +## Configure this option with the app host url to preload app after deploy +# passenger_pre_start https://app-name.com; diff --git a/recipes/deploy/docker/rails-env.conf b/recipes/deploy/docker/rails-env.conf new file mode 100644 index 0000000..86cb9d2 --- /dev/null +++ b/recipes/deploy/docker/rails-env.conf @@ -0,0 +1,3 @@ +# List here all the ENV variables that need to be available in the application +# Only ENV variable names are expected, not their values. +# env APP_HOST; diff --git a/recipes/simple_form.rb b/recipes/simple_form.rb index d55e91a..364cae5 100644 --- a/recipes/simple_form.rb +++ b/recipes/simple_form.rb @@ -13,9 +13,22 @@ def cook private + def run_generators + case ask_framework_for_forms + when 'marsman' + @template.initializer 'simple_form.rb', + relative_file_content('simple_form/marsman.rb') + when 'bootstrap' + @template.generate 'simple_form:install --bootstrap' + else + @template.generate 'simple_form:install' + end + end + def add_sample_i18n @template.run 'rm config/locales/simple_form.en.yml' - @template.append_to_file 'config/locales/en.yml', simple_form_locale('en.yml') + @template.append_to_file 'config/locales/en.yml', + relative_file_content('simple_form/en.yml') end def simple_form_locale(filename)