如何加快在EC2上构建docker映像的速度

时间:2020-06-08 06:37:42

标签: docker amazon-ec2 docker-compose docker-machine

我目前正在将Rails应用程序部署到单个EC2实例。我是Docker的新手,所以我可能会缺少一些明显的东西。我有2个Dockerfile-应用程序(Rails应用程序)和Web(nginx):

docker
├── app
│   └── Dockerfile
└── web
    ├── Dockerfile
    └── nginx.conf

docker / app / Dockerfile:

FROM ruby:2.5.8
RUN apt-get update && \
apt-get install -y \
curl \
vim \
netcat \
less \
default-mysql-client \
--no-install-recommends && \
rm -rf /var/lib/apt/lists/*
SHELL ["/bin/bash", "--login", "-i", "-c"]
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
RUN source /root/.bashrc && nvm install 10.19.0
SHELL ["/bin/bash", "--login", "-c"]
RUN npm install -g yarn
RUN yarn install --check-files
RUN mkdir -p /home/ubuntu/zhxword
ENV RAILS_ROOT /home/ubuntu/zhxword
EXPOSE 3000
WORKDIR $RAILS_ROOT
ADD Gemfile $RAILS_ROOT/Gemfile
ADD Gemfile.lock $RAILS_ROOT/Gemfile.lock
ADD . $RAILS_ROOT
RUN gem install bundler
RUN bundle install
RUN bundle exec rake assets:precompile

docker / web / Dockerfile

FROM nginx
RUN apt-get update -qq && apt-get -y install apache2-utils
ENV RAILS_ROOT /var/www/app_name
WORKDIR $RAILS_ROOT
RUN mkdir log
COPY public public/
COPY docker/web/nginx.conf /tmp/docker.nginx
RUN envsubst '$RAILS_ROOT' < /tmp/docker.nginx > /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD [ "nginx", "-g", "daemon off;" ]

MySQL服务器通过docker-compose.yml引入:

version: '3.1'

volumes:
  db_data: {}

# This part is explained below the file
services:
  db:
    image: mysql:5.6
    volumes:
       - db_data:/var/lib/mysql
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --init-connect='SET NAMES UTF8;' --innodb-flush-log-at-trx-commit=0
    environment:
      MYSQL_ROOT_PASSWORD: XXXXXX
      MYSQL_DATABASE: zhxword_production
      MYSQL_USER: zhxword
      MYSQL_PASSWORD: XXXXXX
  app:
    build:
      context: .
      dockerfile: ./docker/app/Dockerfile
    command: /bin/sh -c "bin/wait-for db:3306 -- rm -f /home/ubuntu/zhxword/tmp/pids/server.pid && bundle exec rails server puma -p 3000"
    volumes:
      - $PWD:/zhxword
    ports:
      - "3000:3000"
    links:
      - "db:database"
    env_file:
      - .env.production
    depends_on:
      - db
  web:
    build:
      context: .
      dockerfile: ./docker/web/Dockerfile
    depends_on:
      - app
    ports:
      - "80:80"

我正在使用docker-machine发布到AWS:

docker-machine create --driver amazonec2 --amazonec2-instance-type "t2.micro" production
docker-machine env production
eval $(docker-machine env production)
docker-compose build
docker-compose up -d

问题

针对AWS目标运行docker-compose build大约需要1小时20分钟。

我尝试了t2.microt2.medium实例类型,这似乎花费了相同的时间。应用程序容器中特别慢的步骤之一是安装具有本机扩展的sassc 2.3.0 ,但是通常应用程序和Web容器都需要很长时间。

在本地(在笔记本电脑上)运行docker-compose build的速度要快得多-总共大约7分钟。针对AWS目标运行docker-compose up只需要一两分钟。

我可以采用哪些策略来加快构建过程?

3 个答案:

答案 0 :(得分:2)

  1. 我真的建议您阅读下一页https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
  2. 了解多阶段构建,它可能有助于加快构建速度
一眼看到您的rails docker文件,我发现RUN指令的用法很差。这将创建多余的层。 您将Rails应用程序基于大图像,请尝试搜索更薄的图像,例如2.7.1-alpine3.11

答案 1 :(得分:1)

您应该在本地构建映像,将其推送到Docker注册表(在AWS上下文中,考虑使用ECR),然后从EC2实例运行该映像。

在您的docker-compose.yml文件中,您需要在本地执行的重要操作是为要构建的两个引用(ECR)外部存储库的图像添加image:行。在本地,您可以像现在一样继续docker-compose builddocker-compose up

app容器具有绑定安装,该绑定安装将无法在远程EC2实例上运行(除非您在那里单独复制您的应用程序,这使使用Docker的原因之一无法解决)。在此处删除volumes:。确保您的应用程序仍能按预期(本地)运行。

现在,您可以docker-compose push构建的图像了。从build:文件中删除docker-compose.yml块,并以与现在相同的方式运行它。

我有两个原因可以立即想到您的构建速度很慢。 docker build首先获取本地目录树(构建上下文),并将其通过Docker套接字发送到守护程序;在本地系统上,这将比远程系统快得多。第二个问题是t2共享实例(尤其是t2.micro)在许多应用程序中的功能不足,因此,如果您的yarn install或Rails预编译步骤进行了大量工作,则这些工作可能会花费很多这种最小实例类型的时间要长得多。

答案 2 :(得分:0)

在尝试了多种方法之后,我发现了构建过程缓慢的根本原因。将其张贴在这里,以防其他人碰到它。

我的应用程序是Rails 6应用程序,Rails 6使用Webpacker作为JavaScript编译器。最初,我是在主机笔记本电脑上进行开发的。在开发过程中,Webpacker会在public/packs中创建临时JS文件的 lot ,它不会自动修剪。我是通过在主机笔记本电脑中运行以下命令来发现这一点的:

$ du -skh *
4.0K    Gemfile
8.0K    Gemfile.lock
4.0K    README.md
4.0K    Rakefile
348K    app
4.0K    babel.config.js
 36K    bin
4.0K    commit_message
148K    config
4.0K    config.ru
 28K    db
 24K    docker
4.0K    docker-compose.yml
  0B    lib
3.1M    log
8.0K    misc
101M    node_modules
4.0K    package.json
4.0K    postcss.config.js
136K    public
  0B    storage
 18M    tmp
  0B    vendor
256K    yarn-error.log
240K    yarn.lock

在我的情况下,不需要1.2GB的内容,因为在生产中,JS文件是用RUN bundle exec rake assets:precompile指令预编译的。 (注意:您可以通过运行bundle exec rails webpacker:clobber强制Webpacker手动清除这些临时文件。)

ADD . $RAILS_ROOT中的app/Dockerfile命令将所有放入远程容器中-这就是为什么它这么慢的原因。

要解决此问题,我在.dockerignore中添加了以下两行:

node_modules/*
public/packs/*

这告诉docker在执行ADD命令时忽略这些路径。

通过这些更改,docker-compose build步骤(当使用docker-machine定位远程AWS实例时仅花费了51秒-大约是1小时20分钟!