Skip to content

Instantly share code, notes, and snippets.

@PikachuEXE
Created September 14, 2018 01:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PikachuEXE/dca0fd441df62b807202d919576f6936 to your computer and use it in GitHub Desktop.
Save PikachuEXE/dca0fd441df62b807202d919576f6936 to your computer and use it in GitHub Desktop.
2 stage rails app docker image building
FROM user/baseimage:version-tag
# 1. This is VERY basic
# 2. Need to load RVM first during build
# 3. Create empty folders for runtime files
RUN \
rm /bin/sh && ln -s /bin/bash /bin/sh && \
mkdir -p \
/home/app/webapp \
/home/app/webapp/log \
/home/app/webapp/tmp
# === Prepare folders for app & runtime files ===
# === Bundle Install ===
# Run Bundle in a cache efficient way
WORKDIR /home/app/webapp
# === Copy files that are rarely changed first ===
## Since these files are changed less often than Gemfile Gemfile.lock
## Putting them here for better caching
##
## Note that specifying folders in multiple sources form of "ADD" will only add their content not the folder
## Thus must be one command per folder
## https://stackoverflow.com/questions/30256386/dockerfile-how-to-copy-multiple-files-with-one-copy-directive
ADD \
/config.ru \
/nginx.conf.erb \
/Procfile \
/Rakefile \
/home/app/webapp/
ADD \
/bin \
/home/app/webapp/bin
ADD \
/lib \
/home/app/webapp/lib
# === Copy files that are rarely changed first ===
## The most updated Gemfile & Gemfile.lock
ADD ./Gemfile \
./Gemfile.lock \
/home/app/webapp/
# Install latest required gems
# Cannot use --clean, will throw error code 15
RUN \
bundle install --jobs="$(nproc)"
# === Bundle Install ===
# === Add the rails app ===
## Copy files that are rarely changed first
##
## Note that specifying folders in multiple sources form of "ADD" will only add their content not the folder
## Thus must be one command per folder
## https://stackoverflow.com/questions/30256386/dockerfile-how-to-copy-multiple-files-with-one-copy-directive
ADD \
/db \
/home/app/webapp/db
## Copy files that are changed more frequently later
ADD \
/config \
/home/app/webapp/config
ADD \
/app \
/home/app/webapp/app
ADD \
/public \
/home/app/webapp/public
# === Add the rails app ===
# Use phusion/baseimage as base image. To make your builds reproducible, make
# sure you lock down to a specific version, not to `latest`!
# See https://github.com/phusion/baseimage-docker/blob/master/Changelog.md for
# a list of version numbers.
FROM phusion/baseimage:0.10.2
# This is VERY basic
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Apt-Fast - Faster Apt-Get
#
# - https://github.com/ilikenwf/apt-fast
# - https://www.maketecheasier.com/apt-fast-speed-up-package-download-in-ubuntu/
RUN \
set -x \
&& \
echo "debconf debconf/frontend select Noninteractive" | debconf-set-selections; \
echo "debconf apt-fast/maxdownloads string 16" | debconf-set-selections; \
echo "debconf apt-fast/dlflag boolean true" | debconf-set-selections; \
echo "debconf apt-fast/aptmanager string apt-get" | debconf-set-selections; \
add-apt-repository ppa:apt-fast/stable \
&& \
apt-get update \
&& \
apt-get install -y --no-install-recommends \
axel \
apt-fast \
&& \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# https://unix.stackexchange.com/questions/74618/how-to-change-locale-environment-variable
ENV \
LC_ALL="en_US.utf8" \
LANG="en_US.utf8"
# Upgrade system
# For reference of option(s) used see
# - https://github.com/phusion/baseimage-docker#upgrading_os
# - https://raphaelhertzog.com/2010/09/21/debian-conffile-configuration-file-managed-by-dpkg/
RUN \
set -x \
&& \
apt-fast update \
&& \
apt-fast upgrade -y -o Dpkg::Options::="--force-confold" \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Steps
## Setup build config & define useful function
### https://github.com/phusion/passenger-docker/blob/master/image/buildconfig
### https://askubuntu.com/questions/223811/how-to-apt-get-install-with-only-minimal-components-necessary-for-an-application
## Add NodeJS 6.x repo
## Create a user for the web app.
#### https://github.com/phusion/passenger-docker/blob/master/image/prepare.sh
## Install Utilities
#### https://github.com/phusion/passenger-docker/blob/master/image/utilities.sh
RUN \
set -x \
&& \
curl --fail -ssL -o /tmp/setup-nodejs https://deb.nodesource.com/setup_8.x \
&& \
bash /tmp/setup-nodejs \
&& \
rm -f /tmp/setup-nodejs \
&& \
addgroup --gid 9999 app \
&& \
adduser --uid 9999 --gid 9999 --disabled-password --gecos "Application" app \
&& \
usermod -L app \
&& \
mkdir -p /home/app/.ssh \
&& \
chmod 700 /home/app/.ssh \
&& \
chown app:app /home/app/.ssh \
&& \
chmod 700 /home/app/.ssh \
&& \
chmod 700 /home/app/.ssh \
&& \
apt-fast update \
&& \
apt-fast install -y --no-install-recommends \
build-essential \
nodejs \
git \
curl \
automake \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Use baseimage-docker's init system.
ENTRYPOINT ["/sbin/my_init", "--"]
CMD ["bash"]
# === Download all required system packages & native gems ===
# 1. Development headers for native libraries that tend to be used often by Ruby gems
# see https://github.com/phusion/passenger-docker/blob/master/image/ruby_support/install_ruby_utils.sh
# 2. Gem from https://github.com/docker-library/rails
# see http://guides.rubyonrails.org/command_line.html#rails-dbconsole
#
# Library list:
# - libmagic-dev => File content type detection
# - libjemalloc-dev => Better memory allocation
# https://www.levups.com/en/blog/2017/optimize_ruby_memory_usage_jemalloc_heroku_scalingo.html
RUN \
set -x \
&& \
apt-fast update \
&& \
apt-fast install -y --no-install-recommends \
libxml2-dev libxslt1-dev \
libmysqlclient-dev \
libsqlite3-dev \
libpq-dev \
libcurl4-openssl-dev \
zlib1g-dev \
libreadline6 libreadline6-dev \
libmagic-dev \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# === Download lib for db console ===
# Version number for postgresql-contrib
# is different since 10.x
#
# Search packages in https://www.ubuntuupdates.org/ to get version numbers
RUN \
PG_MAJOR="10"; \
PG_VERSION="10.5-1.pgdg16.04+1"; \
PG_CONTRIB_VERSION="10+192.pgdg16.04+1"; \
set -x \
&& \
#
# Add Repo
#
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
apt-key add - \
&& \
# The repo here must match version of Ubuntu
#
# E.g.
# - "trusty-pgdg" => 14.04
# - "xenial-pgdg" => 16.04
echo 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main' \
> /etc/apt/sources.list.d/pgdg.list \
&& \
#
# Install
#
apt-fast update && \
apt-fast install -y --no-install-recommends \
postgresql-common \
&& \
sed -ri 's/#(create_main_cluster) .*$/\1 = false/' /etc/postgresql-common/createcluster.conf \
&& \
apt-fast install -y --no-install-recommends \
postgresql-$PG_MAJOR=$PG_VERSION \
postgresql-contrib=$PG_CONTRIB_VERSION \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& \
#
# Print Version
#
/usr/lib/postgresql/$PG_MAJOR/bin/postgres --version
# Install GCC 7
# https://askubuntu.com/a/980495
RUN \
set -x \
&& \
apt-fast update \
&& \
apt-fast install -y --no-install-recommends \
software-properties-common\
&& \
add-apt-repository ppa:ubuntu-toolchain-r/test \
&& \
apt-fast update \
&& \
apt-fast install -y --no-install-recommends \
gcc-7 \
g++-7 \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# === Install jemalloc from source ===
RUN \
set -x \
&& \
mkdir -p /usr/src/jemalloc \
&& \
cd /tmp \
&& \
curl -L \
https://github.com/jemalloc/jemalloc/releases/download/5.1.0/jemalloc-5.1.0.tar.bz2 \
-o jemalloc.tar.bz2 \
&& \
tar \
--extract \
--bzip2 \
--verbose \
--file="jemalloc.tar.bz2" \
--directory="/usr/src/jemalloc" \
--strip-components=1 \
&& \
cd /usr/src/jemalloc \
&& \
CC=/usr/bin/gcc-7 \
CXX=/usr/bin/g++-7 \
./configure \
--prefix=/usr/local \
&& \
make -j"$(nproc)" \
&& \
make install \
&& \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/src/*
# === Install jemalloc from source ===
# === Image optimization binaries ===
RUN \
BUILD_DEPENDENCY_PACKAGES="gcc libc6-dev make build-essential autoconf automake"; \
JPEGOPTIM_SOURCE_DOWNLOAD_URL="https://github.com/tjko/jpegoptim/archive/RELEASE.1.4.6.tar.gz"; \
JPEGOPTIM_SOURCE_DOWNLOAD_FILENAME="jpegoptim.tar.gz"; \
OPTIPNG_SOURCE_DOWNLOAD_URL="https://netix.dl.sourceforge.net/project/optipng/OptiPNG/optipng-0.7.7/optipng-0.7.7.tar.gz"; \
OPTIPNG_SOURCE_DOWNLOAD_FILENAME="optipng.tar.gz"; \
PNGQUANT_SOURCE_DOWNLOAD_URL="http://pngquant.org/pngquant-2.12.0-src.tar.gz"; \
PNGQUANT_SOURCE_DOWNLOAD_FILENAME="pngquant.tar.gz"; \
LIBPNG_SOURCE_DOWNLOAD_URL="https://netix.dl.sourceforge.net/project/libpng/libpng16/1.6.35/libpng-1.6.35.tar.gz"; \
LIBPNG_SOURCE_DOWNLOAD_FILENAME="libpng.tar.gz"; \
set -x \
&& \
apt-fast update \
&& \
apt-fast install -y --no-install-recommends \
$BUILD_DEPENDENCY_PACKAGES \
&& \
apt-fast install -y --no-install-recommends \
libjpeg-dev \
&& \
cd /tmp \
&& \
curl -L "$LIBPNG_SOURCE_DOWNLOAD_URL" -o "$LIBPNG_SOURCE_DOWNLOAD_FILENAME" \
&& \
curl -L "$JPEGOPTIM_SOURCE_DOWNLOAD_URL" -o "$JPEGOPTIM_SOURCE_DOWNLOAD_FILENAME" \
&& \
mkdir -p /usr/src/jpegoptim \
&& \
tar -xzf "$JPEGOPTIM_SOURCE_DOWNLOAD_FILENAME" -C /usr/src/jpegoptim --strip-components=1 \
&& \
cd /usr/src/jpegoptim \
&& \
CC=/usr/bin/gcc-7 \
CXX=/usr/bin/g++-7 \
./configure \
&& \
make -j"$(nproc)" \
&& \
make strip -j"$(nproc)" \
&& \
make install -j"$(nproc)" \
&& \
cd /tmp \
&& \
curl -L "$OPTIPNG_SOURCE_DOWNLOAD_URL" -o "$OPTIPNG_SOURCE_DOWNLOAD_FILENAME" \
&& \
mkdir -p /usr/src/optipng \
&& \
tar -xzf "$OPTIPNG_SOURCE_DOWNLOAD_FILENAME" -C /usr/src/optipng --strip-components=1 \
&& \
mkdir -p /usr/src/optipng/src/libpng \
&& \
tar -xzf "$LIBPNG_SOURCE_DOWNLOAD_FILENAME" -C /usr/src/optipng/src/libpng --strip-components=1 \
&& \
cd /usr/src/optipng \
&& \
CC=/usr/bin/gcc-7 \
CXX=/usr/bin/g++-7 \
./configure -with-system-zlib -without-system-libpng \
&& \
make -j"$(nproc)" \
&& \
make install -j"$(nproc)" \
&& \
cd /tmp \
&& \
curl -L "$PNGQUANT_SOURCE_DOWNLOAD_URL" -o "$PNGQUANT_SOURCE_DOWNLOAD_FILENAME" \
&& \
mkdir -p /usr/src/pngquant \
&& \
tar -xzf "$PNGQUANT_SOURCE_DOWNLOAD_FILENAME" -C /usr/src/pngquant --strip-components=1 \
&& \
mkdir -p /usr/src/pngquant/libpng \
&& \
tar -xzf "$LIBPNG_SOURCE_DOWNLOAD_FILENAME" -C /usr/src/pngquant/libpng --strip-components=1 \
&& \
cd /usr/src/pngquant/libpng \
&& \
CC=/usr/bin/gcc-7 \
CXX=/usr/bin/g++-7 \
./configure --enable-static \
&& \
make -j"$(nproc)" \
&& \
cd /usr/src/pngquant \
&& \
CC=/usr/bin/gcc-7 \
CXX=/usr/bin/g++-7 \
./configure \
&& \
make -j"$(nproc)" \
&& \
make install -j"$(nproc)" \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/src/* \
&& \
jpegoptim --version && optipng --version && pngquant --version
# === Image optimization binaries ===
# === Update OpenSSL ===
# DO NOT purge existing openssl package since bundled CA will be also removed
#
# OpenSSL config reference can be found at:
# https://wiki.openssl.org/index.php/Compilation_and_Installation
#
# Linker options are set according to
# See https://github.com/openssl/openssl/issues/1740#issuecomment-254606676
#
# Added `openssl version` at the end to ensure "it works"
RUN \
BUILD_DEPENDENCY_PACKAGES="gcc libc6-dev make build-essential autoconf automake"; \
OPENSSL_SOURCE_DOWNLOAD_URL="https://www.openssl.org/source/openssl-1.1.0i.tar.gz"; \
OPENSSL_SOURCE_SHA256_DOWNLOAD_URL="https://www.openssl.org/source/openssl-1.1.0i.tar.gz.sha256"; \
OPENSSL_SOURCE_DOWNLOAD_FILENAME="openssl.tar.gz"; \
OPENSSL_SOURCE_SHA256_DOWNLOAD_FILENAME="openssl.tar.gz.sha256"; \
OPENSSL_INSTALL_DIR_PATH="/usr/local/ssl"; \
set -x \
&& \
apt-fast update \
&& \
apt-fast install -y --no-install-recommends \
$BUILD_DEPENDENCY_PACKAGES \
&& \
cd /tmp \
&& \
curl "$OPENSSL_SOURCE_DOWNLOAD_URL" -o "$OPENSSL_SOURCE_DOWNLOAD_FILENAME" \
&& \
curl "$OPENSSL_SOURCE_SHA256_DOWNLOAD_URL" -o "$OPENSSL_SOURCE_SHA256_DOWNLOAD_FILENAME" \
&& \
echo "`cat $OPENSSL_SOURCE_SHA256_DOWNLOAD_FILENAME` $OPENSSL_SOURCE_DOWNLOAD_FILENAME" | sha256sum -c - \
&& \
mkdir -p /usr/src/openssl \
&& \
tar -xzf "$OPENSSL_SOURCE_DOWNLOAD_FILENAME" -C /usr/src/openssl --strip-components=1 \
&& \
cd /usr/src/openssl \
&& \
CC=/usr/bin/gcc-7 \
CXX=/usr/bin/g++-7 \
./config \
--prefix="$OPENSSL_INSTALL_DIR_PATH" \
--openssldir="$OPENSSL_INSTALL_DIR_PATH" \
no-zlib \
no-zlib-dynamic \
no-ssl3 \
no-comp \
-Wl,--enable-new-dtags,-rpath,'$(LIBRPATH)' \
&& \
make depend -j"$(nproc)" \
&& \
make -j"$(nproc)" \
&& \
make install -j"$(nproc)" \
&& \
cd /usr/bin \
&& \
rm /usr/bin/openssl \
&& \
ln -s "$OPENSSL_INSTALL_DIR_PATH/bin/openssl" /usr/bin/openssl \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/src/* \
&& \
openssl version
# === Update OpenSSL ===
# === Install Ruby ===
# Using nproc to make the compilation faster
# References:
# - https://github.com/docker-library/ruby/blob/master/2.2/Dockerfile
#
# Note: Rubygems URL will redirect to actual location from CDN
# So `--location` flag need to be used
RUN \
RUBY_SOURCE_DOWNLOAD_URL="https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.1.tar.xz"; \
RUBY_SOURCE_DOWNLOAD_SHA256="886ac5eed41e3b5fc699be837b0087a6a5a3d10f464087560d2d21b3e71b754d"; \
RUBY_SOURCE_DOWNLOAD_FILENAME="ruby.tar.xz"; \
set -x \
&& \
cd /tmp \
&& \
curl "$RUBY_SOURCE_DOWNLOAD_URL" -o "$RUBY_SOURCE_DOWNLOAD_FILENAME" \
&& \
echo "$RUBY_SOURCE_DOWNLOAD_SHA256 *$RUBY_SOURCE_DOWNLOAD_FILENAME" | sha256sum -c - \
&& \
cd /tmp \
&& \
mkdir -p /usr/src/ruby \
&& \
tar --xz --extract --verbose \
--file="$RUBY_SOURCE_DOWNLOAD_FILENAME" \
--directory="/usr/src/ruby" \
--strip-components=1 \
&& \
cd /usr/src/ruby \
&& \
autoconf \
&& \
CC=/usr/bin/gcc-7 \
CXX=/usr/bin/g++-7 \
./configure \
--disable-install-doc \
--with-jemalloc \
--with-openssl-dir=/usr/local/ssl \
&& \
make -j"$(nproc)" \
&& \
make install -j"$(nproc)" \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/src/* \
&& \
echo "gem: --no-document --no-post-install-message" >> "$HOME/.gemrc" \
&& \
ruby -v
# Update rubygems separately since this is more frequently updated than Ruby
RUN \
set -x \
&& \
gem update --system --no-document
# === Install latest ImageMagick ===
# Install libraries as ImageMagick delegates first
RUN \
set -x \
&& \
apt-fast update \
&& \
apt-fast install -y --no-install-recommends \
build-essential \
libx11-dev \
libxext-dev \
zlib1g-dev \
libpng12-dev \
libjpeg-dev \
libwebp-dev \
libxml2-dev \
&& \
apt-fast build-dep -y imagemagick \
&& \
IMAGEMAGICK_SOURCE_DOWNLOAD_URL="https://www.imagemagick.org/download/releases/ImageMagick-7.0.8-11.tar.xz"; \
IMAGEMAGICK_SOURCE_DOWNLOAD_FILENAME="ImageMagick.tar.xz"; \
cd /tmp \
&& \
curl "$IMAGEMAGICK_SOURCE_DOWNLOAD_URL" -o "$IMAGEMAGICK_SOURCE_DOWNLOAD_FILENAME" \
&& \
mkdir -p /usr/src/imagemagick \
&& \
tar --xz --extract --verbose \
--file="$IMAGEMAGICK_SOURCE_DOWNLOAD_FILENAME" \
--directory="/usr/src/imagemagick" \
--strip-components=1 \
&& \
cd /usr/src/imagemagick \
&& \
CC=/usr/bin/gcc-7 \
CXX=/usr/bin/g++-7 \
./configure \
&& \
make -j"$(nproc)" \
&& \
make install -j"$(nproc)" \
&& \
ldconfig /usr/local/lib \
&& \
apt-fast clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/src/* \
&& \
convert -version
# === Install latest ImageMagick ===
# === Bundle Install ===
## Use a slightly outdated Gemfile first, so that it's cached
## So that in the next set of `bundle install`, it only installs the gems missing/with diff version
## Can't run `gem install bundler` since Rubygems 2.7,
## will make `bundler` malfunction
RUN \
set -x \
&& \
gem install --force bundler -v ">= 1.16.4" \
&& \
bundle -v
COPY \
./gems/Gemfile \
./gems/Gemfile.lock \
/tmp/
# This is required for installing some gems
# Might also be required with other network communication with https
# Since we use custom OpenSSL path and unable to find CA with default config
ENV \
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
RUN \
bundle install --jobs="$(nproc)" --gemfile /tmp/Gemfile
# A hack to remove passenger executables
RUN \
set -x \
&& \
gem uninstall passenger-enterprise-server \
&& \
bundle install --jobs="$(nproc)" --gemfile /tmp/Gemfile \
&& \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/src/*
EXPOSE 80 443
# Special Workaround for a security hole in ImageMagick
# References:
# - https://imagetragick.com/
# - https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-3714
# - https://www.imagemagick.org/discourse-server/viewtopic.php?f=4&t=29588
COPY \
./etc/ImageMagick/policy.xml \
/usr/local/etc/ImageMagick-7/policy.xml
# Set envvar $HOME
# Can't set it directly using ENV
# Need to use workaround from
# https://github.com/phusion/baseimage-docker/issues/119
RUN \
echo /root > /etc/container_environment/HOME
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment