构建Docker容器时,最佳实践是构建小型容器映像。较小的Docker映像往往具有更快的构建时间和拉取时间。此外,使用小型Docker映像也有安全优势-与大型Docker容器相比,小型容器的受攻击面较小。
Rails docker容器应该有多小?每个应用程序都是不同的。我的经验法则是将容器大小保持为300MB(压缩后为100MB)。功能齐全的 Rails应用程序docker映像很容易具有大约1GB的大小!这是一个例子:
rails new myapp -d postgresql -m https://raw.githubusercontent.com/excid3/jumpstart/master/template.rb
将基本的Dockerfile与ruby: 2.5.1基本映像一起使用:
FROM ruby:2.5.1
RUN apt-get update \
&& apt-get install -y apt-transport-https \
&& curl --silent --show-error --location \
https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key
add - \
&& echo "deb https://deb.nodesource.com/node_6.x/ stretch main"
> /etc/apt/sources.list.d/nodesource.list \
&& curl --silent --show-error --location
https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" >
/etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
postgresql-client nodejs apt-transport-https yarn \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
WORKDIR /usr/src/app
ENV RAILS_ENV=production
ENV NODE_ENV=production
COPY Gemfile* package.json yarn.lock ./
RUN bundle install
RUN yarn install
COPY . .
RUN bin/rails assets:precompile
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
我们最终得到一个大小为1.48GB 的docker镜像:
REPOSITORY TAG SIZE
small-docker-images v1 1.48GB
那么如何控制Docker映像大小呢?
在第一个版本中v1
,我们使用ruby:2.5.1
非常方便但又很大的基本镜像。
REPOSITORY TAG SIZE
ruby 2.5.1 869MB
从较小的基本镜像开始可以减小最终镜像的大小。较小的基本镜像的示例是ruby-alpine
:
REPOSITORY TAG SIZE
ruby 2.5.1-alpine 45.3MB
删除了大约820MB!
使用Alpine映像作为基本镜像可能会涉及更多,您必须运行一些命令并安装更多软件包:
FROM ruby:2.5.1-alpine
RUN apk update \
&& apk upgrade \
&& apk add --update --no-cache \
build-base curl-dev git postgresql-dev \
yaml-dev zlib-dev nodejs yarn
WORKDIR /usr/src/app
ENV RAILS_ENV=production
ENV NODE_ENV=production
COPY Gemfile* package.json yarn.lock ./
RUN bundle install
RUN yarn install
COPY . .
RUN bin/rails assets:precompile
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
使用alpine镜像后,我们最终得到一个小的最终v2
图像,约占一半v1
REPOSITORY TAG SIZE
small-docker-images v2 810MB
但是我们可以进一步减少它!
正如git repo的大小随提交/更改次数的增加而增加一样,最终docker映像的大小也取决于层数。您可以通过减少RUN
和COPY
语句的数量或执行类似于“ git squash”的多步骤构建来减少层数。
这是我使用多步骤构建方法的新Dockerfile:
FROM ruby:2.5.1-alpine AS build-env
ARG RAILS_ROOT=/app
ARG BUILD_PACKAGES="build-base curl-dev git"
ARG DEV_PACKAGES="postgresql-dev yaml-dev zlib-dev nodejs yarn"
ARG RUBY_PACKAGES="tzdata"
ENV RAILS_ENV=production
ENV NODE_ENV=production
ENV BUNDLE_APP_CONFIG="$RAILS_ROOT/.bundle"
WORKDIR $RAILS_ROOT
# install packages
RUN apk update \
&& apk upgrade \
&& apk add --update --no-cache $BUILD_PACKAGES $DEV_PACKAGES \
$RUBY_PACKAGES
COPY Gemfile* package.json yarn.lock ./
RUN bundle config --global frozen 1 \
&& bundle install --path=vendor/bundle
RUN yarn install
COPY . .
RUN bin/rails assets:precompile
############### Build step done ###############
FROM ruby:2.5.1-alpine
ARG RAILS_ROOT=/app
ARG PACKAGES="tzdata postgresql-client nodejs bash"
ENV RAILS_ENV=production
ENV BUNDLE_APP_CONFIG="$RAILS_ROOT/.bundle"
WORKDIR $RAILS_ROOT
# install packages
RUN apk update \
&& apk upgrade \
&& apk add --update --no-cache $PACKAGES
COPY --from=build-env $RAILS_ROOT $RAILS_ROOT
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
这将尺寸减小了一半!
REPOSITORY TAG SIZE
small-docker-images v3 360MB
这大约是我理想的docker大小,但是仍然可以进行一些清理以进一步减小大小。
一些在开发中使用的文件从未在生产中使用,下面是一些示例:
1. app/assets vendor/assets node_modules - If you precompile your assets/webpack, these folders become irrelevant in prod
2. tmp/cache spec are also not needed in production
3. remove the gems cache and *.c and *.o files
删除这些文件后,这是我的新Dockerfile:
FROM ruby:2.5.1-alpine AS build-env
ARG RAILS_ROOT=/app
ARG BUILD_PACKAGES="build-base curl-dev git"
ARG DEV_PACKAGES="postgresql-dev yaml-dev zlib-dev nodejs yarn"
ARG RUBY_PACKAGES="tzdata"
ENV RAILS_ENV=production
ENV NODE_ENV=production
ENV BUNDLE_APP_CONFIG="$RAILS_ROOT/.bundle"
WORKDIR $RAILS_ROOT
# install packages
RUN apk update \
&& apk upgrade \
&& apk add --update --no-cache $BUILD_PACKAGES $DEV_PACKAGES $RUBY_PACKAGES
COPY Gemfile* package.json yarn.lock ./
# install rubygem
COPY Gemfile Gemfile.lock $RAILS_ROOT/
RUN bundle config --global frozen 1 \
&& bundle install --without development:test:assets -j4 --retry 3 --path=vendor/bundle \
# Remove unneeded files (cached *.gem, *.o, *.c)
&& rm -rf vendor/bundle/ruby/2.5.0/cache/*.gem \
&& find vendor/bundle/ruby/2.5.0/gems/ -name "*.c" -delete \
&& find vendor/bundle/ruby/2.5.0/gems/ -name "*.o" -delete
RUN yarn install --production
COPY . .
RUN bin/rails webpacker:compile
RUN bin/rails assets:precompile
# Remove folders not needed in resulting image
RUN rm -rf node_modules tmp/cache app/assets vendor/assets spec
############### Build step done ###############
FROM ruby:2.5.1-alpine
ARG RAILS_ROOT=/app
ARG PACKAGES="tzdata postgresql-client nodejs bash"
ENV RAILS_ENV=production
ENV BUNDLE_APP_CONFIG="$RAILS_ROOT/.bundle"
WORKDIR $RAILS_ROOT
# install packages
RUN apk update \
&& apk upgrade \
&& apk add --update --no-cache $PACKAGES
COPY --from=build-env $RAILS_ROOT $RAILS_ROOT
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
大小约:
REPOSITORY TAG SIZE
small-docker-images v4 162MB
从1.5G缩小到162MB,减少很多。
构建小型Docker容器可以提高build/pull的性能以及应用程序的安全性。通过利用小型基础镜像和多步骤构建模式,可以轻松开始减少rails docker映像的大小。