Skip to content

Commit

Permalink
Dockerfile
Browse files Browse the repository at this point in the history
Severl improvements:
- Make a unique dependencies image: instead of creating 2 dependencies
  images (web and test), create a single one. The web image is slightly
  bigger but caching is more efficient and the Dockerfile is simpler
- Decouple test image from web image so it can cache test specific layers
- Simplify user management: switch unix user at the right time and avoid
  chmod 777 commands
- Move apk add to one line to reduce layers. They change rarely so
  splitting doesn't improve build time
  • Loading branch information
Colin Saliceti committed Sep 26, 2022
1 parent 4d2f51d commit d4eb4e6
Showing 1 changed file with 28 additions and 113 deletions.
141 changes: 28 additions & 113 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,32 @@ FROM ruby:2.7.6-alpine AS base

RUN addgroup -S appgroup && adduser -S appuser -G appgroup

USER root

RUN apk add bash
RUN apk add postgresql-dev
RUN apk add tzdata
RUN apk add nodejs
RUN apk add curl
RUN apk add libc6-compat
RUN apk add shared-mime-info

USER appuser

ENV APP_HOME /app
ENV DEPS_HOME /deps
ARG RAILS_ENV
ENV RAILS_ENV ${RAILS_ENV:-production}
ENV NODE_ENV ${RAILS_ENV:-production}
ENV RAILS_ENV production

RUN apk update
RUN apk add bash postgresql-dev tzdata nodejs curl libc6-compat shared-mime-info

# ------------------------------------------------------------------------------
# dependencies
# ------------------------------------------------------------------------------
FROM base AS dependencies

USER root

RUN apk add build-base
RUN apk add git
RUN apk add yarn
RUN apk update
RUN apk add build-base git yarn

# Set up install environment
RUN mkdir -p ${DEPS_HOME}
WORKDIR ${DEPS_HOME}
RUN chmod -R 777 ${DEPS_HOME}
# End

USER appuser

# Install Ruby dependencies
COPY Gemfile ${DEPS_HOME}/Gemfile
COPY Gemfile.lock ${DEPS_HOME}/Gemfile.lock
RUN gem install bundler
ENV BUNDLE_BUILD__SASSC=--disable-march-tune-native
RUN bundle config set frozen 'true'
RUN if [ ${RAILS_ENV} = "production" ]; then \
bundle config set without 'development test'; \
elif [ ${RAILS_ENV} = "test" ]; then \
bundle config set without 'development'; \
else \
bundle config set without 'test'; \
fi
RUN bundle config set without 'development';
# End

RUN bundle config
Expand All @@ -63,50 +39,34 @@ RUN bundle install --retry 3
# Install JavaScript dependencies
COPY package.json ${DEPS_HOME}/package.json
COPY yarn.lock ${DEPS_HOME}/yarn.lock

USER root

RUN if [ ${RAILS_ENV} = "production" ]; then \
yarn install --frozen-lockfile --production; \
else \
yarn install --frozen-lockfile; \
fi
# End
RUN yarn install --frozen-lockfile

# ------------------------------------------------------------------------------
# web
# ------------------------------------------------------------------------------

FROM base AS web

USER root

# Set up install environment
RUN mkdir -p ${APP_HOME}
WORKDIR ${APP_HOME}
RUN chmod -R 777 ${APP_HOME}

# End
USER appuser
EXPOSE 3000

CMD /filebeat/filebeat -c /filebeat/filebeat.yml & bundle exec rails server

# Download and install filebeat for sending logs to logstash
ENV FILEBEAT_VERSION=7.6.2
ENV FILEBEAT_DOWNLOAD_PATH=/tmp/filebeat.tar.gz
ENV FILEBEAT_CHECKSUM=482304509aed80db78ef63a0fed88e4453ebe7b11f6b4ab3168036a78f6a413e2f6a5c039f405e13984653b1a094c23f7637ac7daf3da75a032692d1c34a9b65

USER root

RUN curl https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-${FILEBEAT_VERSION}-linux-x86_64.tar.gz -o ${FILEBEAT_DOWNLOAD_PATH} && \
[ "$(sha512sum ${FILEBEAT_DOWNLOAD_PATH})" = "${FILEBEAT_CHECKSUM} ${FILEBEAT_DOWNLOAD_PATH}" ] && \
tar xzvf ${FILEBEAT_DOWNLOAD_PATH} && \
rm ${FILEBEAT_DOWNLOAD_PATH} && \
mv filebeat-${FILEBEAT_VERSION}-linux-x86_64 /filebeat && \
rm -f /filebeat/filebeat.yml

RUN chmod -R 777 /filebeat

USER appuser

# Copy our local filebeat config to the installation
COPY filebeat.yml /filebeat/filebeat.yml

Expand All @@ -115,18 +75,8 @@ COPY --from=dependencies ${DEPS_HOME}/Gemfile ${APP_HOME}/Gemfile
COPY --from=dependencies ${DEPS_HOME}/Gemfile.lock ${APP_HOME}/Gemfile.lock
COPY --from=dependencies ${GEM_HOME} ${GEM_HOME}
COPY --from=dependencies ${DEPS_HOME}/node_modules ${APP_HOME}/node_modules
# End

USER root
# Copy app code (sorted by vague frequency of change for caching)
RUN mkdir -p ${APP_HOME}/log
RUN mkdir -p ${APP_HOME}/tmp
RUN chmod -R 777 ${APP_HOME}
RUN chown -hR appuser:appgroup ${APP_HOME}/log
RUN chown -hR appuser:appgroup ${APP_HOME}/tmp

USER appuser

COPY config.ru ${APP_HOME}/config.ru
COPY Rakefile ${APP_HOME}/Rakefile
COPY public ${APP_HOME}/public
Expand All @@ -138,48 +88,20 @@ COPY db ${APP_HOME}/db
COPY app ${APP_HOME}/app
COPY spec ${APP_HOME}/spec

# End
USER root

RUN chmod -R 777 ${APP_HOME}/
RUN chown -hR appuser:appgroup ${APP_HOME}/

RUN if [ ${RAILS_ENV} = "production" ]; then \
DFE_SIGN_IN_API_CLIENT_ID= \
RUN DFE_SIGN_IN_API_CLIENT_ID= \
DFE_SIGN_IN_API_SECRET= \
DFE_SIGN_IN_API_ENDPOINT= \
DQT_CLIENT_HEADERS= \
DQT_CLIENT_HOST= \
DQT_CLIENT_PARAMS= \
ADMIN_ALLOWED_IPS= \
ENVIRONMENT_NAME= \
SUPPRESS_DFE_ANALYTICS_INIT= \
bundle exec rake assets:precompile; \
fi
EXPOSE 3000
bundle exec rake assets:precompile

USER appuser
ARG GIT_COMMIT_HASH
ENV GIT_COMMIT_HASH ${GIT_COMMIT_HASH}
CMD /filebeat/filebeat -c /filebeat/filebeat.yml & bundle exec rails server

# move all app directories and files to appuser and the appgroup
USER root

RUN chmod 777 -R ${APP_HOME}/app

RUN chown -hR appuser:appgroup ${APP_HOME}/log
RUN chown -hR appuser:appgroup ${APP_HOME}/app
RUN chown -hR appuser:appgroup ${APP_HOME}/tmp

RUN touch ${APP_HOME}/log/${RAILS_ENV}.log

RUN chown -hR appuser:appgroup ${APP_HOME}/log/${RAILS_ENV}.log

RUN chmod 777 ${APP_HOME}/log/${RAILS_ENV}.log
RUN chown -hR appuser:appgroup ${APP_HOME} /filebeat

USER appuser

ARG GIT_COMMIT_HASH
ENV GIT_COMMIT_HASH ${GIT_COMMIT_HASH}

# ------------------------------------------------------------------------------
# shellcheck
Expand All @@ -190,39 +112,32 @@ FROM koalaman/shellcheck:stable AS shellcheck
# ------------------------------------------------------------------------------
# test
# ------------------------------------------------------------------------------
FROM web AS test
FROM base AS test

USER root
WORKDIR ${APP_HOME}

ENV RAILS_ENV test
ENV NODE_ENV test
CMD [ "bundle", "exec", "rake" ]

RUN apk add chromium chromium-chromedriver

USER appuser
# Install ShellCheck
COPY --from=shellcheck / /opt/shellcheck/
ENV PATH /opt/shellcheck/bin:${PATH}

# End
COPY --from=dependencies ${GEM_HOME} ${GEM_HOME}

# Copy from web to include generated assets
COPY --from=web ${APP_HOME} ${APP_HOME}

# Copy all files
# This is only for the test target and ensures that all the files that could be linted locally are also linted on CI.
# We need to be mindful of files that get added to the project, if they are secrets or superfluous we should add them
# to the .dockerignore file.
COPY . ${APP_HOME}/
# End
CMD [ "bundle", "exec", "rake" ]

# move all app directories and files to appuser and the appgroup
USER root

RUN chmod 777 -R ${APP_HOME}/app

RUN chown -hR appuser:appgroup ${APP_HOME}/log
RUN chown -hR appuser:appgroup ${APP_HOME}/app
RUN chown -hR appuser:appgroup ${APP_HOME}/tmp

RUN touch ${APP_HOME}/log/${RAILS_ENV}.log

RUN chown -hR appuser:appgroup ${APP_HOME}/log/${RAILS_ENV}.log

RUN chmod 777 ${APP_HOME}/log/${RAILS_ENV}.log
RUN chown -hR appuser:appgroup ${APP_HOME}

USER appuser

0 comments on commit d4eb4e6

Please sign in to comment.