Improve Docker setup (PR #497)

pull/26/head
wvengen 2017-10-01 13:57:36 +02:00 committed by GitHub
parent 01950b48a1
commit 0363f2dadc
13 changed files with 236 additions and 108 deletions

View File

@ -1,12 +1,43 @@
.git
.idea
.sass-cache
.gitignore
.bundle
.rake_tasks*
db/*.sqlite3
log
config/database.yml
doc
node_modules
tmp/*
public/assets
public/system
tmp/*
public/uploads
vendor/bundle
# no configuration
config/*.yml
!config/i18n-js.yml
# IDEs, Developer tools
.idea
.loadpath
.project
.sass-cache
.rbenv-version
.get-dump.yml
.bash_history
.localeapp
nbproject/
.*.sw?
*~
coverage
*.sql*
tags
doc/app/
doc/api/
.yarddoc/
rspec.failures
# Capistrano etc.
Capfile
config/deploy
config/deploy.rb
Gemfile.capistrano*

50
.gitignore vendored
View File

@ -1,25 +1,41 @@
log/*.log
tmp/**/*
config/app_config.yml
config/database.yml
config/initializers/secret_token.rb
.bundle
.rake_tasks*
db/*.sqlite3
nbproject/
log
node_modules
tmp
public/assets
public/system
public/uploads
vendor/bundle
# no configuration
config/*.yml
!config/i18n-js.yml
config/environments/development.rb
*.swp
*~
public/**/*_cached.*
# IDEs, Developer tools
.idea
.loadpath
.project
.sass-cache
.rbenv-version
.get-dump.yml
.sass-cache/
.bash_history
.localeapp
nbproject/
.*.sw?
*~
coverage
tags
doc/app/
doc/api/
.yarddoc/
# Deployment tools
Capfile
config/deploy.rb
config/deploy/*
.localeapp
log/localeapp.yml
.bundle
rspec.failures
# Capistrano etc.
Capfile
config/deploy
config/deploy.rb
Gemfile.capistrano*

View File

@ -1,45 +1,58 @@
FROM ruby:2.3
RUN apt-get update && \
apt-get install --no-install-recommends -y cron && \
rm -rf /var/lib/apt/lists/* && \
apt-get clean
RUN supercronicUrl=https://github.com/aptible/supercronic/releases/download/v0.1.3/supercronic-linux-amd64 && \
supercronicBin=/usr/local/bin/supercronic && \
supercronicSha1sum=96960ba3207756bb01e6892c978264e5362e117e && \
curl -fsSL -o "$supercronicBin" "$supercronicUrl" && \
echo "$supercronicSha1sum $supercronicBin" | sha1sum -c - && \
chmod +x "$supercronicBin"
ENV RAILS_ENV=production \
ENV PORT=3000 \
SMTP_SERVER_PORT=2525 \
RAILS_ENV=production \
RAILS_LOG_TO_STDOUT=true \
RAILS_SERVE_STATIC_FILES=true
WORKDIR /usr/src/app
COPY . ./
RUN echo $SOURCE_COMMIT > REVISION
COPY . ./
# install dependencies and generate crontab
RUN buildDeps='libmagic-dev' && \
apt-get update && \
apt-get install --no-install-recommends -y $buildDeps && \
rm -rf /var/lib/apt/lists/* && \
bundle install --deployment --without development test && \
echo 'gem: --no-document' >> ~/.gemrc && \
bundle config build.nokogiri "--use-system-libraries" && \
bundle install --deployment --without development test -j 4 && \
apt-get purge -y --auto-remove $buildDeps && \
echo "Foodsoft::Application.config.secret_token = ENV['SECRET_KEY_BASE']" > config/initializers/secret_token.rb && \
mkdir -p log && \
ln -sfn /dev/stdout log/production.log && \
bundle exec whenever --update-crontab
rm -Rf /var/lib/apt/lists/* /var/cache/apt/* ~/.gemrc ~/.bundle && \
\
bundle exec whenever >crontab
# Add a temporary mysql-server for assets precompilation
# compile assets with temporary mysql server
RUN export DATABASE_URL=mysql2://localhost/temp && \
export SECRET_KEY_BASE=thisisnotimportantnow && \
export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y mysql-server && \
/etc/init.d/mysql start && \
cp config/app_config.yml.SAMPLE config/app_config.yml && \
bundle exec rake db:setup && \
bundle exec rake assets:precompile && \
rm config/app_config.yml && \
rm -rf tmp/* && \
bundle exec rake db:setup assets:precompile && \
rm -Rf config/app_config.yml tmp/* && \
/etc/init.d/mysql stop && \
rm -rf /run/mysqld /tmp/* /var/lib/mysql /var/log/mysql* && \
rm -Rf /run/mysqld /tmp/* /var/tmp/* /var/lib/mysql /var/log/mysql* && \
apt-get purge -y --auto-remove mysql-server && \
rm -rf /var/lib/apt/lists/*
rm -Rf /var/lib/apt/lists/* /var/cache/apt/*
# Make relevant dirs writable for app user
RUN mkdir -p tmp && \
chown nobody tmp
# Run app as unprivileged user
USER nobody
EXPOSE 3000
# cleanup, and by default start web process from Procfile
ENTRYPOINT ["./docker-entrypoint.sh"]
CMD ["rails", "server", "--binding", "0.0.0.0"]
CMD ["./proc-start", "web"]

4
Procfile 100644
View File

@ -0,0 +1,4 @@
web: bundle exec rails server --binding=0.0.0.0 --port=$PORT
worker: QUEUE=foodsoft_notifier bundle exec rake resque:work
mail: bundle exec rake foodsoft:reply_email_smtp_server
cron: supercronic crontab

View File

@ -40,7 +40,7 @@ Foodsoft::Application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
config.force_ssl = ENV["RAILS_FORCE_SSL"] != "false"
# Set to :debug to see everything in the log.
config.log_level = :info
@ -49,7 +49,13 @@ Foodsoft::Application.configure do
# config.log_tags = [ :subdomain, :uuid ]
# Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# https://github.com/heroku/rails_12factor/issues/25#issuecomment-231103483
if ENV["RAILS_LOG_TO_STDOUT"].present?
STDOUT.sync = true
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Use a different cache store in production.
# config.cache_store = :mem_cache_store

View File

@ -0,0 +1,25 @@
# Be sure to restart your server when you modify this file.
# Your secret key for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
Foodsoft::Application.config.secret_key_base = begin
if (token = ENV['SECRET_KEY_BASE']).present?
token
elsif Rails.env.production? || Rails.env.staging?
raise "You must set SECRET_KEY_BASE"
elsif Rails.env.test?
SecureRandom.hex(30) # doesn't really matter
else
sf = Rails.root.join('tmp', 'secret_key_base')
if File.exists?(sf)
File.read(sf)
else
puts "=> Generating initial SECRET_KEY_BASE in #{sf}"
token = SecureRandom.hex(30)
File.open(sf, 'w') { |f| f.write(token) }
token
end
end
end

View File

@ -1,10 +0,0 @@
# Be sure to restart your server when you modify this file.
# Your secret key for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
Foodsoft::Application.config.secret_key_base = 'you really really need to change me!'
# When you're upgrading from Rails 3, it's ok to keep using `secret_token`.
# http://api.rubyonrails.org/classes/ActionDispatch/Session/CookieStore.html

View File

@ -1,8 +1,67 @@
Deployment
=========
# Deployment
Setup
-----
## Docker
_This section is a work in progress._
### Build
To build the docker image, run:
docker build --tag foodsoft:dev --rm .
There is also an [official production docker image](https://hub.docker.com/r/foodcoops/foodsoft/),
which will let you avoid this step.
### Run (basic)
You'll need to set at least the following environment variables:
* `SECRET_KEY_BASE` - random string of 30+ characters, try `rake secret`
* `DATABASE_URL` - pointing to your MySQL installation (`mysql2://user:pass@mysql.host/foodsoftdb?encoding=utf8`)
* `REDIS_URL` - pointing to your Redis instance (`redis://redis.host:6379`)
You'll also need to supply the Foodsoft configuration file, for example by
mounting it as a volume. Copy `config/app_config.yml.SAMPLE` to `config/app_config.yml`
and customize the settings.
Then run the webserver, exposing port 3000 on the current host:
docker run --name foodsoft_web -p 3000 \
-e SECRET_KEY_BASE -e DATABASE_URL -e REDIS_URL -e RAILS_FORCE_SSL=false \
-v `pwd`/config/app_config.yml:/usr/src/app/config/app_config.yml:ro \
foodsoft:dev
This should get you started. But first you'll need to populate the database:
docker run --name foodsoft_setup --rm \
-e SECRET_KEY_BASE -e DATABASE_URL -e REDIS_URL \
-v `pwd`/config/app_config.yml:/usr/src/app/config/app_config.yml:ro \
foodsoft:dev bundle exec rake db:setup
To run the worker (recommended!), supply a different command
(see [Procfile](../Procfile) for other types):
docker run --name foodsoft_worker \
-e SECRET_KEY_BASE -e DATABASE_URL -e REDIS_URL \
-v `pwd`/config/app_config.yml:/usr/src/app/config/app_config.yml:ro \
foodsoft:dev ./proc-start worker
To also run the cronjobs, start the previous command but substituting
`mail` with `cron`. That should give you the ingredients for a production-setup.
With the help of a front-end webserver doing ssl, of course.
### Run (docker-compose)
In practice, you'd probably want to use docker-compose. If you know Docker well enough,
you'll have no problem to set this up. For inspiration, look at the
[foodcoops.net production setup](https://github.com/foodcoops/foodcoops.net).
## Capistrano
### Setup
1. Initialise your [Capistrano](http://capistranorb.com/) setup
@ -16,8 +75,7 @@ Setup
2. Adapt your configuration in `config/deploy.rb` and `config/deploy/*.rb`
Deploy
------
### Deploy
On your first deploy you should run (choose either staging or production)

View File

@ -141,18 +141,7 @@ explained here.
Edit `app_config.yml` to suit your needs or just keep the defaults for now.
4. **Secret token**
The user session are stored in cookies. Do avoid misusing the cookies and
its sensitive information, rails will encrypt it with a token. So copy the
config file
cp config/initializers/secret_token.rb.SAMPLE config/initializers/secret_token.rb
and modify the token!! You can run `bundle exec rake secret`
5. **Create database (schema) and load defaults**
4. **Create database (schema) and load defaults**
rake db:setup
@ -160,7 +149,7 @@ explained here.
password 'secret'.
6. (optional) Get **background jobs** done
5. (optional) Get **background jobs** done
Time intensive tasks may block the web request. To run these in a separate
task, you can install Redis and enable Resque:
@ -173,7 +162,7 @@ explained here.
`resque-web`.
7. (optional) **View mails in browser** instead in your logs
6. (optional) **View mails in browser** instead in your logs
We use mailcatcher in development mode to view all delivered mails in a
browser interface. Just install mailcatcher with gem install mailcatcher

View File

@ -1,13 +1,9 @@
Running foodsoft in production
Running Foodsoft in production
==============================
As you might have noticed, documentation is scarce and insufficient. If you
intend to deploy foodsoft in production, we would love to guide you through the
process. You can contact the mailing list
[foodsoft-discuss](http://foodsoft.51229.x6.nabble.com/foodsoft-discuss-f5.html),
or mail some of us directly at
[developers@foodcoop.nl](mailto:developers@foodcoop.nl) or foodsoft (at)
foodcoops.net.
[foodsoft-discuss](http://foodsoft.51229.x6.nabble.com/foodsoft-discuss-f5.html).
* [Passenger](https://www.phusionpassenger.com/) may be convenient.
* Redis is required for production by default.
Please see our wiki page: [Deployment notes](https://github.com/foodcoops/foodsoft/wiki/Deployment-notes).

View File

@ -1,19 +1,7 @@
#!/bin/sh
set -e
CRONTAB="$(crontab -l)"
CRONTAB_ENV=""
if test -n "$BUNDLE_APP_CONFIG"; then
CRONTAB_ENV="${CRONTAB_ENV}BUNDLE_APP_CONFIG=$BUNDLE_APP_CONFIG\n"
fi
if test -n "$DATABASE_URL"; then
CRONTAB_ENV="${CRONTAB_ENV}DATABASE_URL=$DATABASE_URL\n"
fi
echo "$CRONTAB_ENV$CRONTAB" | crontab -
# allow re-using the instance - https://stackoverflow.com/a/38732187/2866660
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi

View File

@ -33,7 +33,6 @@ namespace :foodsoft do
setup_app_config
setup_development
setup_database
setup_secret_token
start_mailcatcher
puts yellow "All done! Your foodcoft should be running smoothly."
start_server
@ -44,7 +43,6 @@ namespace :foodsoft do
task :stock_config do
setup_app_config
setup_development
setup_secret_token
end
end
end
@ -103,16 +101,6 @@ def setup_development
reminder(file)
end
def setup_secret_token
file = 'config/initializers/secret_token.rb'
return nil if skip?(file)
puts yellow "Generating secret_token and writing to #{file}..."
Rake::Task["secret"].reenable
secret = capture_stdout { Rake::Task["secret"].invoke }
%x( touch #{Rails.root.join("#{file}")}; echo 'Foodsoft::Application.config.secret_key_base = "#{secret.chomp}"' > #{Rails.root.join("#{file}")} )
end
def start_mailcatcher
return nil if ENV['MAILCATCHER_PORT'] # skip when it has an existing Docker container
mailcatcher = ask("Do you want to start mailcatcher?\nOptions:\n(y) Yes\n(n) No", ["y","n"])

24
proc-start 100755
View File

@ -0,0 +1,24 @@
#!/bin/sh
#
# Run single command from Procfile
#
# This script is a basic replacement for foreman when running on Docker. When
# starting the docker instance, specify as command `script/start <type>`.
# `type` is looked up in `Procfile` and the command is started. This allows e.g.
# docker-compose to run multiple process/dyno types from a single image, without
# needing to know the exact command (which may change over time).
#
if [ ! "$1" ]; then
echo "Usage: $0 <process type>" 1>&2
echo
echo "Note that some process types need the PORT environment variable."
exit 1
fi
CMD=`cat Procfile | grep "^$1:" | cut -d: -f2-`
if [ ! "$CMD" ]; then
echo "Process type $1 not found in Procfile" 1>&2
exit 1
fi
exec /bin/sh -c "$CMD"