mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
dockerize
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
.git
|
||||
.bundle
|
||||
.env*
|
||||
tmp
|
||||
frontend/node_modules
|
||||
# travis
|
||||
vendor/bundle
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
FROM ruby:2.1
|
||||
|
||||
ENV NODE_VERSION="0.12.7"
|
||||
ENV BUNDLER_VERSION="1.10.6"
|
||||
|
||||
# install node + npm
|
||||
RUN curl https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz | tar xzf - -C /usr/local --strip-components=1
|
||||
|
||||
# Using /home/app since npm cache and other stuff will be put there when running npm install
|
||||
# We don't want to pollute any locally-mounted directory
|
||||
RUN useradd -d /home/app -m app
|
||||
RUN mkdir -p /usr/src/app
|
||||
RUN chown -R app /usr/src/app /usr/local/bundle
|
||||
RUN gem install bundler --version "${BUNDLER_VERSION}"
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# https registry breaks so often it's no longer funny
|
||||
RUN echo "registry = 'http://registry.npmjs.org/'" >> /usr/local/etc/npmrc
|
||||
# moar logs
|
||||
RUN echo "loglevel=info" >> /usr/local/etc/npmrc
|
||||
|
||||
COPY Gemfile ./Gemfile
|
||||
COPY Gemfile.* ./
|
||||
RUN chown -R app:app /usr/src/app
|
||||
|
||||
USER app
|
||||
RUN bundle install --jobs 8 --retry 3
|
||||
|
||||
USER root
|
||||
# Then, npm install node modules
|
||||
COPY package.json /tmp/npm/package.json
|
||||
COPY frontend/*.json /tmp/npm/frontend/
|
||||
RUN chown -R app:app /tmp/npm
|
||||
|
||||
USER app
|
||||
RUN cd /tmp/npm && RAILS_ENV=production npm install
|
||||
RUN mv /tmp/npm/frontend /usr/src/app/
|
||||
|
||||
# Finally, copy over the whole thing
|
||||
USER root
|
||||
COPY . /usr/src/app
|
||||
RUN cp docker/Procfile .
|
||||
RUN chown -R app:app /usr/src/app
|
||||
|
||||
USER app
|
||||
RUN DATABASE_URL=sqlite3:///tmp/db.sqlite3 SECRET_TOKEN=foobar RAILS_ENV=production bundle exec rake assets:precompile
|
||||
|
||||
CMD ["./docker/web"]
|
||||
@@ -233,6 +233,16 @@ group :opf_plugins do
|
||||
gem 'openproject-translations', git:'https://github.com/opf/openproject-translations.git', branch: 'release/5.0'
|
||||
end
|
||||
|
||||
gem 'passenger'
|
||||
|
||||
group :production do
|
||||
# Used to easily precompile assets
|
||||
gem 'sqlite3', require: false
|
||||
gem 'rails_12factor', require: !!ENV['HEROKU']
|
||||
gem 'health_check', require: !!ENV['HEROKU']
|
||||
gem 'newrelic_rpm', require: !!ENV['HEROKU']
|
||||
end
|
||||
|
||||
# Load Gemfile.local, Gemfile.plugins and plugins' Gemfiles
|
||||
Dir.glob File.expand_path('../{Gemfile.local,Gemfile.plugins,lib/plugins/*/Gemfile}', __FILE__) do |file|
|
||||
next unless File.readable?(file)
|
||||
|
||||
@@ -278,6 +278,8 @@ GEM
|
||||
virtus (>= 1.0.0)
|
||||
gravatar_image_tag (1.2.0)
|
||||
hashie (3.4.1)
|
||||
health_check (1.5.1)
|
||||
rails (>= 2.3.0)
|
||||
hike (1.2.3)
|
||||
htmldiff (0.0.1)
|
||||
http-cookie (1.0.2)
|
||||
@@ -315,6 +317,7 @@ GEM
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (2.9.2)
|
||||
netrc (0.11.0)
|
||||
newrelic_rpm (3.14.1.311)
|
||||
nokogiri (1.6.6.4)
|
||||
mini_portile (~> 0.6.0)
|
||||
non-stupid-digest-assets (1.0.4)
|
||||
@@ -327,6 +330,9 @@ GEM
|
||||
parallel
|
||||
parser (2.2.2.5)
|
||||
ast (>= 1.1, < 3.0)
|
||||
passenger (5.0.22)
|
||||
rack
|
||||
rake (>= 0.8.1)
|
||||
pg (0.18.3)
|
||||
poltergeist (1.7.0)
|
||||
capybara (~> 2.1)
|
||||
@@ -389,8 +395,13 @@ GEM
|
||||
loofah (~> 2.0)
|
||||
rails-observers (0.1.2)
|
||||
activemodel (~> 4.0)
|
||||
rails_12factor (0.0.3)
|
||||
rails_serve_static_assets
|
||||
rails_stdout_logging
|
||||
rails_autolink (1.1.6)
|
||||
rails (> 3.1)
|
||||
rails_serve_static_assets (0.0.4)
|
||||
rails_stdout_logging (0.0.4)
|
||||
railties (4.2.4)
|
||||
actionpack (= 4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
@@ -490,6 +501,7 @@ GEM
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sqlite3 (1.3.11)
|
||||
structured_warnings (0.2.0)
|
||||
syck (1.0.5)
|
||||
sys-filesystem (1.1.4)
|
||||
@@ -576,6 +588,7 @@ DEPENDENCIES
|
||||
gon (~> 4.0)
|
||||
grape (~> 0.10.1)
|
||||
gravatar_image_tag (~> 1.2.0)
|
||||
health_check
|
||||
htmldiff
|
||||
jruby-openssl
|
||||
json_spec
|
||||
@@ -584,12 +597,14 @@ DEPENDENCIES
|
||||
multi_json (~> 1.11.0)
|
||||
mysql2 (~> 0.3.20)
|
||||
net-ldap (~> 0.8.0)
|
||||
newrelic_rpm
|
||||
nokogiri (~> 1.6.6)
|
||||
non-stupid-digest-assets
|
||||
oj (~> 2.11.4)
|
||||
omniauth
|
||||
openproject-translations!
|
||||
parallel_tests (~> 2.1.2)
|
||||
passenger
|
||||
pg (~> 0.18.3)
|
||||
poltergeist
|
||||
prototype-rails!
|
||||
@@ -607,6 +622,7 @@ DEPENDENCIES
|
||||
rack_session_access
|
||||
rails (= 4.2.4)
|
||||
rails-observers
|
||||
rails_12factor
|
||||
rails_autolink (~> 1.1.6)
|
||||
rb-readline (~> 0.5.1)
|
||||
rdoc (>= 2.4.2)
|
||||
@@ -631,6 +647,7 @@ DEPENDENCIES
|
||||
shoulda-matchers (~> 2.8)
|
||||
simplecov (= 0.8.0.pre)
|
||||
sprockets (~> 2.12.3)
|
||||
sqlite3
|
||||
svg-graph!
|
||||
syck (~> 1.0.5)
|
||||
sys-filesystem (~> 1.1.4)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
web: ./docker/web
|
||||
worker: ./docker/worker
|
||||
cron: ./docker/cron
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
IMAP_SSL=${IMAP_SSL:="true"}
|
||||
IMAP_PORT=${IMAP_PORT:="993"}
|
||||
IMAP_ENABLED="${IMAP_ENABLED:="true"}"
|
||||
IMAP_CHECK_INTERVAL="${IMAP_CHECK_INTERVAL:=600}"
|
||||
|
||||
while true; do
|
||||
if [ "$IMAP_ENABLED" = "true" ]; then
|
||||
echo "[cron] Checking for new emails from IMAP"
|
||||
bundle exec rake redmine:email:receive_imap \
|
||||
host="${IMAP_HOST}" \
|
||||
username="${IMAP_USERNAME}" \
|
||||
password="${IMAP_PASSWORD}" \
|
||||
ssl=${IMAP_SSL} \
|
||||
port=${IMAP_PORT} \
|
||||
allow_override="${IMAP_ALLOW_OVERRIDE}" || true
|
||||
else
|
||||
echo "[cron] IMAP email checking is disabled"
|
||||
fi
|
||||
|
||||
echo "[cron] Rescheduling in ${IMAP_CHECK_INTERVAL}s"
|
||||
sleep ${IMAP_CHECK_INTERVAL}s
|
||||
done
|
||||
@@ -0,0 +1,211 @@
|
||||
##############################################################
|
||||
# Phusion Passenger Standalone uses a template file to
|
||||
# generate an Nginx configuration file. The original template
|
||||
# file can be found by running the following command:
|
||||
#
|
||||
# ls $(passenger-config about resourcesdir)/templates/standalone/config.erb
|
||||
#
|
||||
# You can create a copy of this template file and customize it
|
||||
# to your liking. Just make sure you tell Phusion Passenger Standalone
|
||||
# to use your template file by passing the --nginx-config-template
|
||||
# parameter.
|
||||
#
|
||||
# *** NOTE ***
|
||||
# If you customize the template file, make sure you keep an eye
|
||||
# on the original template file and merge any changes.
|
||||
# New Phusion Passenger features may require changes to the template
|
||||
# file.
|
||||
##############################################################
|
||||
|
||||
|
||||
master_process on;
|
||||
worker_processes 1;
|
||||
daemon on;
|
||||
error_log '<%= @options[:log_file] %>' <% if @options[:log_level] >= LVL_DEBUG %>info<% end %>;
|
||||
pid '<%= @options[:pid_file] %>';
|
||||
|
||||
<% if Process.euid == 0 %>
|
||||
<% if @options[:user] %>
|
||||
<%# Run workers as the given user. The master process will always run as root and will be able to bind to any port. %>
|
||||
user <%= @options[:user] %> <%= default_group_for(@options[:user]) %>;
|
||||
<% else %>
|
||||
<%# Prevent running Nginx workers as nobody. %>
|
||||
user <%= current_user %> <%= default_group_for(current_user) %>;
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
log_format debug '[$time_local] $msec "$request" $status conn=$connection sent=$bytes_sent body_sent=$body_bytes_sent';
|
||||
include '<%= PhusionPassenger.resources_dir %>/mime.types';
|
||||
|
||||
<% if @options[:ruby] %>
|
||||
passenger_ruby <%= @options[:ruby] %>;
|
||||
<% else %>
|
||||
passenger_ruby <%= PlatformInfo.ruby_command %>;
|
||||
<% end %>
|
||||
<% if @options[:nodejs] %>
|
||||
passenger_nodejs <%= @options[:nodejs] %>;
|
||||
<% end %>
|
||||
<% if @options[:python] %>
|
||||
passenger_python <%= @options[:python] %>;
|
||||
<% end %>
|
||||
|
||||
passenger_root '<%= PhusionPassenger.install_spec %>';
|
||||
passenger_abort_on_startup_error on;
|
||||
passenger_ctl cleanup_pidfiles <%= serialize_strset("#{@working_dir}/temp_dir_toucher.pid") %>;
|
||||
passenger_ctl integration_mode standalone;
|
||||
passenger_ctl standalone_engine nginx;
|
||||
passenger_user_switching off;
|
||||
<%= nginx_option :passenger_log_level, :log_level %>
|
||||
<%= nginx_option :passenger_max_pool_size, :max_pool_size %>
|
||||
<%= nginx_option :passenger_min_instances, :min_instances %>
|
||||
<%= nginx_option :passenger_pool_idle_time, :pool_idle_time %>
|
||||
<%= nginx_option :passenger_max_preloader_idle_time, :max_preloader_idle_time %>
|
||||
<%= nginx_option :passenger_turbocaching, :turbocaching %>
|
||||
<% if @options[:user] %>
|
||||
passenger_user <%= @options[:user] %>;
|
||||
passenger_default_user <%= @options[:user] %>;
|
||||
passenger_analytics_log_user <%= @options[:user] %>;
|
||||
<% else %>
|
||||
passenger_user <%= current_user %>;
|
||||
passenger_default_user <%= current_user %>;
|
||||
passenger_analytics_log_user <%= current_user %>;
|
||||
<% end %>
|
||||
<% if @options[:instance_registry_dir] %>passenger_instance_registry_dir '<%= @options[:instance_registry_dir] %>';<% end %>
|
||||
<% if @options[:data_buffer_dir] %>passenger_data_buffer_dir '<%= @options[:data_buffer_dir] %>';<% end %>
|
||||
<% if @options[:rolling_restarts] %>passenger_rolling_restarts on;<% end %>
|
||||
<% if @options[:resist_deployment_errors] %>passenger_resist_deployment_errors on;<% end %>
|
||||
<% if !@options[:load_shell_envvars] %>passenger_load_shell_envvars off;<% end %>
|
||||
|
||||
<% if !@options[:friendly_error_pages].nil? -%>
|
||||
passenger_friendly_error_pages <%= boolean_config_value(@options[:friendly_error_pages]) %>;
|
||||
<% end %>
|
||||
|
||||
<% if @options[:union_station_gateway_address] %>
|
||||
union_station_gateway_address <%= @options[:union_station_gateway_address] %>;
|
||||
<% end %>
|
||||
<% if @options[:union_station_gateway_port] %>
|
||||
union_station_gateway_port <%= @options[:union_station_gateway_port] %>;
|
||||
<% end %>
|
||||
<% if @options[:union_station_gateway_cert] %>
|
||||
union_station_gateway_cert -;
|
||||
<% end %>
|
||||
|
||||
<% @options[:ctls].each do |ctl| %>
|
||||
passenger_ctl '<%= ctl.split("=", 2)[0] %>' '<%= ctl.split("=", 2)[1] %>';
|
||||
<% end %>
|
||||
|
||||
default_type application/octet-stream;
|
||||
types_hash_max_size 2048;
|
||||
server_names_hash_bucket_size 64;
|
||||
client_max_body_size 1024m;
|
||||
access_log off;
|
||||
keepalive_timeout 60;
|
||||
underscores_in_headers on;
|
||||
gzip on;
|
||||
gzip_comp_level 3;
|
||||
gzip_min_length 150;
|
||||
gzip_proxied any;
|
||||
gzip_types text/plain text/css text/json text/javascript
|
||||
application/javascript application/x-javascript application/json
|
||||
application/rss+xml application/vnd.ms-fontobject application/x-font-ttf
|
||||
application/xml font/opentype image/svg+xml text/xml;
|
||||
|
||||
<% if @app_finder.multi_mode? %>
|
||||
# Default server entry for mass deployment mode.
|
||||
server {
|
||||
<% if @options[:ssl] %>
|
||||
<% if @options[:ssl_port] %>
|
||||
listen <%= nginx_listen_address %>;
|
||||
listen <%= nginx_listen_address_with_ssl_port %> ssl;
|
||||
<% else %>
|
||||
listen <%= nginx_listen_address %> ssl;
|
||||
<% end %>
|
||||
<% else %>
|
||||
listen <%= nginx_listen_address %>;
|
||||
<% end %>
|
||||
root '<%= PhusionPassenger.resources_dir %>/standalone_default_root';
|
||||
}
|
||||
<% end %>
|
||||
|
||||
<% for app in @apps %>
|
||||
server {
|
||||
<% if app[:ssl] %>
|
||||
<% if app[:ssl_port] %>
|
||||
listen <%= nginx_listen_address(app) %>;
|
||||
listen <%= nginx_listen_address_with_ssl_port(app) %> ssl;
|
||||
<% else %>
|
||||
listen <%= nginx_listen_address(app) %> ssl;
|
||||
<% end %>
|
||||
<% else %>
|
||||
listen <%= nginx_listen_address(app) %>;
|
||||
<% end %>
|
||||
server_name <%= app[:server_names].join(' ') %>;
|
||||
<% if app[:static_files_dir] %>
|
||||
root '<%= app[:static_files_dir] %>';
|
||||
<% else %>
|
||||
root '<%= app[:root] %>/public';
|
||||
<% end %>
|
||||
passenger_app_root '<%= app[:root] %>';
|
||||
passenger_enabled on;
|
||||
passenger_app_env <%= app[:environment] %>;
|
||||
passenger_spawn_method <%= app[:spawn_method] %>;
|
||||
<% if app[:app_type] %>passenger_app_type <%= app[:app_type] %>;<% end %>
|
||||
<% if app[:startup_file] %>passenger_startup_file <%= app[:startup_file] %>;<% end %>
|
||||
<% if app[:concurrency_model] && app[:concurrency_model] != DEFAULT_CONCURRENCY_MODEL %>passenger_concurrency_model <%= app[:concurrency_model] %>;<% end %>
|
||||
<% if app[:thread_count] && app[:thread_count] != DEFAULT_APP_THREAD_COUNT %>passenger_thread_count <%= app[:thread_count] %>;<% end %>
|
||||
<% if app[:min_instances] %>passenger_min_instances <%= app[:min_instances] %>;<% end %>
|
||||
<% if app[:restart_dir] %>passenger_restart_dir '<%= app[:restart_dir] %>';<% end %>
|
||||
<% if app[:sticky_sessions] %>passenger_sticky_sessions on;<% end %>
|
||||
<% if app[:sticky_sessions_cookie_name] %>passenger_sticky_sessions_cookie_name '<%= app[:sticky_sessions_cookie_name] %>';<% end %>
|
||||
<% if app[:vary_turbocache_by_cookie] %>passenger_vary_turbocache_by_cookie '<%= app[:vary_turbocache_by_cookie] %>';<% end %>
|
||||
<% if app[:union_station_key] %>
|
||||
union_station_support on;
|
||||
union_station_key <%= app[:union_station_key] %>;
|
||||
<% end %>
|
||||
<% if app[:ssl] %>
|
||||
ssl_certificate <%= app[:ssl_certificate] %>;
|
||||
ssl_certificate_key <%= app[:ssl_certificate_key] %>;
|
||||
<% end %>
|
||||
<% if @options[:meteor_app_settings] %>
|
||||
passenger_meteor_app_settings <%= @options[:meteor_app_settings] %>;
|
||||
<% end %>
|
||||
|
||||
<% app[:envvars].each_pair do |name, value| %>
|
||||
passenger_env_var '<%= name %>' '<%= value %>';
|
||||
<% end %>
|
||||
|
||||
# Rails asset pipeline support.
|
||||
location ~ "^/assets/.+-([0-9a-f]{32}|[0-9a-f]{64})\..+" {
|
||||
error_page 490 = @static_asset;
|
||||
error_page 491 = @dynamic_request;
|
||||
recursive_error_pages on;
|
||||
|
||||
if (-f $request_filename) {
|
||||
return 490;
|
||||
}
|
||||
if (!-f $request_filename) {
|
||||
return 491;
|
||||
}
|
||||
}
|
||||
location @static_asset {
|
||||
gzip_static on;
|
||||
expires max;
|
||||
add_header Cache-Control public;
|
||||
add_header ETag "";
|
||||
}
|
||||
location @dynamic_request {
|
||||
passenger_enabled on;
|
||||
}
|
||||
|
||||
<% (ENV['NGINX_ADDITIONAL_SERVER_RULES'] || "").split(";").each do |rule| %>
|
||||
<%= rule.chomp(";") %>;
|
||||
<% end %>
|
||||
}
|
||||
passenger_pre_start <%= listen_url(app) %>;
|
||||
<% end %>
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
BIND="${BIND:=0.0.0.0}"
|
||||
PORT="${PORT:=8080}"
|
||||
RAILS_ENV="${RAILS_ENV:="development"}"
|
||||
MIGRATE="${MIGRATE:="false"}"
|
||||
MIN_INSTANCES="${PASSENGER_MIN_INSTANCES:=1}"
|
||||
MAX_INSTANCES="${PASSENGER_MAX_INSTANCES:=3}"
|
||||
SPAWN_METHOD="${PASSENGER_SPAWN_METHOD:=smart}"
|
||||
|
||||
if [ "$MIGRATE" = "true" ]; then
|
||||
echo "Migrating database..."
|
||||
bundle exec rake db:migrate
|
||||
fi
|
||||
|
||||
exec bundle exec passenger start \
|
||||
-p $PORT \
|
||||
-a "${BIND}" \
|
||||
--min-instances "$MIN_INSTANCES" \
|
||||
--max-pool-size "$MAX_INSTANCES" \
|
||||
--spawn-method "$SPAWN_METHOD" \
|
||||
--nginx-config-template "docker/nginx.conf.erb" \
|
||||
--max-preloader-idle-time 0
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash -e
|
||||
exec bundle exec rake jobs:work
|
||||
Reference in New Issue
Block a user