diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c00fcdd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,38 @@ +.git +.gitignore + +.bundle +.rake_tasks* +db/*.sqlite3 +log +node_modules +tmp/* +public/assets +public/system +public/uploads +supplier_assets/** +vendor/bundle + +# no configuration +config/*.yml + +# IDEs, Developer tools +.idea +.loadpath +.project +.sass-cache +.rbenv-version +.get-dump.yml +.bash_history +nbproject/ +.*.sw? +*~ + +coverage +tags + +# Capistrano etc. +Capfile +config/deploy +config/deploy.rb +Gemfile.capistrano* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dc66c0a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +FROM ruby:2.3 + +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 PORT=3000 \ + RAILS_ENV=production \ + RAILS_LOG_TO_STDOUT=true \ + RAILS_SERVE_STATIC_FILES=true + +WORKDIR /usr/src/app + +COPY . ./ + +# install dependencies, recognize database_url, generate crontab +RUN echo 'gem: --no-document' >> ~/.gemrc && \ + bundle config build.nokogiri "--use-system-libraries" && \ + bundle install --deployment --without development test -j 4 && \ + rm -Rf /var/lib/apt/lists/* /var/cache/apt/* ~/.gemrc ~/.bundle && \ + \ + echo "production:\n url: <%= ENV['DATABASE_URL'] %>" >config/database.yml && \ + bundle exec whenever >crontab + +# compile assets with temporary mysql server +RUN export DATABASE_URL=mysql2://localhost/temp && \ + export SECRET_TOKEN=thisisnotimportantnow && \ + export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y mysql-server && \ + /etc/init.d/mysql start && \ + rails db:setup assets:precompile && \ + rm -Rf tmp/* && \ + /etc/init.d/mysql stop && \ + 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/* /var/cache/apt/* + +# Make relevant dirs writable for app user +RUN mkdir -p tmp supplier_assets && \ + chown nobody tmp supplier_assets + +# Run app as unprivileged user +USER nobody + +EXPOSE 3000 + +# cleanup, and by default start web process from Procfile +ENTRYPOINT ["./docker-entrypoint.sh"] +CMD ["./proc-start", "web"] diff --git a/Dockerfile.development b/Dockerfile.development new file mode 100644 index 0000000..b62f07c --- /dev/null +++ b/Dockerfile.development @@ -0,0 +1,20 @@ +FROM alpine:3.5 + +ENV BUILD_PKGS="build-base ruby-dev libffi-dev libxml2-dev mariadb-dev" \ + RUNTIME_PKGS="ruby ruby-json ruby-bigdecimal ruby-irb ruby-bundler ca-certificates mariadb-client" \ + DEVELOPMENT_PKGS="bash" + +RUN apk --no-cache add $BUILD_PKGS $RUNTIME_PKGS $DEVELOPMENT_PKGS + +RUN adduser -D -u 1000 -h /srv/app -s /bin/bash app +WORKDIR /srv/app +USER app + +ENV BUNDLE_JOBS=4 \ + BUNDLE_PATH=/srv/app/vendor/bundle \ + GEM_PATH=/srv/app/vendor/bundle:$GEM_PATH \ + PATH=/srv/app/vendor/bundle/bin:$PATH + +EXPOSE 3000 + +CMD ["bash"] diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..7077398 --- /dev/null +++ b/Procfile @@ -0,0 +1,3 @@ +web: rails server --binding=0.0.0.0 --port=$PORT +mail: rails mail:smtp_server +cron: supercronic crontab diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..16dd6e6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: "2" + +volumes: + mysql: + +services: + app: + build: + context: ./ + dockerfile: Dockerfile.development + command: rails server --bind 0.0.0.0 + volumes: + - ./:/srv/app + ports: + - 3000:3000 + depends_on: + - mysql + + mysql: + image: mariadb:10.1 + volumes: + - mysql:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: secret diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..f76a0d5 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +# allow re-using the instance - https://stackoverflow.com/a/38732187/2866660 +if [ -f tmp/pids/server.pid ]; then + rm tmp/pids/server.pid +fi + +exec "$@" diff --git a/proc-start b/proc-start new file mode 100755 index 0000000..2ca1157 --- /dev/null +++ b/proc-start @@ -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` 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 " 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"