如何在单个容器Docker环境中的Amazon Elastic Beanstalk上部署Rails应用程序

时间:2015-07-20 12:27:55

标签: ruby-on-rails docker elastic-beanstalk

我一直在尝试将我的Rails应用程序停靠在Elastic Beanstalk上。有很多例子,但大多数都不适合我的具体用例。那就是:

  • 在单个容器Docker环境下运行(因此不需要docker-compose / fig)
  • 在Amazon Elastic Beanstalk上运行。
  • 使用passenger-docker作为基本图像(Ruby变体之一)。
  • 传递Elastic Beanstalk设置的环境变量(通过控制台的CLI)。
  • 容器中的Nginx和Passenger。
  • 能够安装自定义包(扩展它)。
  • 合理的.dockerignore档案。

关于如何部署的过程不是问题,而是适用于具有上述特定标准的Amazon Elastic Beanstalk的正确Docker配置。

使这种运行正确的配置是什么?

1 个答案:

答案 0 :(得分:5)

这对我有用......

<强> Dockerfile

在此示例中,我使用phusion/passenger-ruby22:0.9.16作为基本图像,因为:

  • 您的Dockerfile可以更小。
  • 它减少了编写正确的Dockerfile所需的时间。您不必担心基本系统和堆栈,您可以专注于您的应用程序。
  • 它正确设置基本系统 。很容易让基本系统出错,但是这个图像可以正确地完成所有操作。 Learn more.
  • 它大大减少了运行docker build所需的时间,使您可以更快地迭代Dockerfile。
  • 减少重新部署期间的下载时间。 Docker只需要下载一次基本映像:在第一次部署期间。在每个后续部署中,仅下载您在基础映像之上所做的更改。

您可以learn more about it here ...无论如何,Dockerfile

# The FROM instruction sets the Base Image for subsequent instructions. As such,
# a valid Dockerfile must have FROM as its first instruction. We use
# phusion/baseimage as a base image. To make our builds reproducible, we make
# sure we lock down to a specific version, not to `latest`!
FROM phusion/passenger-ruby22:0.9.16

# The MAINTAINER instruction allows you to set the Author field of the generated
# images.
MAINTAINER "Job King'ori Maina" <yo@kingori.co> (@itsmrwave)

# The RUN instructions will execute any commands in a new layer on top of the
# current image and commit the results. The resulting committed image will be
# used for the next step in the Dockerfile.

# === 1 ===

# Prepare for packages
RUN apt-get update --assume-yes && apt-get install --assume-yes build-essential

# For a JS runtime
# http://nodejs.org/
RUN apt-get install --assume-yes nodejs

# For Nokogiri gem
# http://www.nokogiri.org/tutorials/installing_nokogiri.html#ubuntu___debian
RUN apt-get install --assume-yes libxml2-dev libxslt1-dev

# For RMagick gem
# https://help.ubuntu.com/community/ImageMagick
RUN apt-get install --assume-yes libmagickwand-dev

# Clean up APT when done.
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# === 2 ===

# Set correct environment variables.
ENV HOME /root

# Use baseimage-docker's init process.
CMD ["/sbin/my_init"]

# === 3 ====

# By default Nginx clears all environment variables (except TZ). Tell Nginx to
# preserve these variables. See nginx-env.conf.
COPY nginx-env.conf /etc/nginx/main.d/rails-env.conf

# Nginx and Passenger are disabled by default. Enable them (start Nginx/Passenger).
RUN rm -f /etc/service/nginx/down

# Expose Nginx HTTP service
EXPOSE 80

# === 4 ===

# Our application should be placed inside /home/app. The image has an app user
# with UID 9999 and home directory /home/app. Our application is supposed to run
# as this user. Even though Docker itself provides some isolation from the host
# OS, running applications without root privileges is good security practice.
RUN mkdir -p /home/app/myapp
WORKDIR /home/app/myapp

# Run Bundle in a cache efficient way. Before copying the whole app, copy just
# the Gemfile and Gemfile.lock into the tmp directory and ran bundle install
# from there. If neither file changed, both instructions are cached. Because
# they are cached, subsequent commands—like the bundle install one—remain
# eligible for using the cache. Why? How? See ...
# http://ilikestuffblog.com/2014/01/06/how-to-skip-bundle-install-when-deploying-a-rails-app-to-docker/
COPY Gemfile /home/app/myapp/
COPY Gemfile.lock /home/app/myapp/
RUN chown -R app:app /home/app/myapp
RUN sudo -u app bundle install --deployment --without test development doc

# === 5 ===

# Adding our web app to the image ... only after bundling do we copy the rest of
# the app into the image.
COPY . /home/app/myapp
RUN chown -R app:app /home/app/myapp

# === 6 ===

# Remove the default site. Add a virtual host entry to Nginx which describes
# where our app is, and Passenger will take care of the rest. See nginx.conf.
RUN rm /etc/nginx/sites-enabled/default
COPY nginx.conf /etc/nginx/sites-enabled/myapp.conf

<强> Dockerrun.aws.json

{
  "AWSEBDockerrunVersion": "1",
  "Ports": [
    {
      "ContainerPort": "80"
    }
  ],
  "Logging": "/home/app/myapp/log"
}

<强> .dockerignore

/.bundle
/.DS_Store
/.ebextensions
/.elasticbeanstalk
/.env
/.git
/.yardoc
/log/*
/tmp

!/log/.keep

<强> nginx的-env.conf

请注意rails-env.conf未在Nginx之外设置任何环境变量,因此您将无法在shell中看到它们(即Dockerfile)。您还必须使用不同的方法为shell设置环境变量。

# By default Nginx clears all environment variables (except TZ) for its child
# processes (Passenger being one of them). That's why any environment variables
# we set with docker run -e, Docker linking and /etc/container_environment,
# won't reach Nginx. To preserve these variables, place an Nginx config file
# ending with *.conf in the directory /etc/nginx/main.d, in which we tell Nginx
# to preserve these variables.

# Set by Passenger Docker
env RAILS_ENV;
env RACK_ENV;
env PASSENGER_APP_ENV;

# Set by AWS Elastic Beanstalk (examples, change accordingly)
env AWS_ACCESS_KEY_ID;
env AWS_REGION;
env AWS_SECRET_KEY;
env DB_NAME;
env DB_USERNAME;
env DB_PASSWORD;
env DB_HOSTNAME;
env DB_PORT;
env MAIL_USERNAME;
env MAIL_PASSWORD;
env MAIL_SMTP_HOST;
env MAIL_PORT;
env SECRET_KEY_BASE;

<强> nginx.conf

server {
  listen 80;
  server_name _;
  root /home/app/myapp/public;

  # The following deploys your app on Passenger.

  # Not familiar with Passenger, and used (G)Unicorn/Thin/Puma/pure Node before?
  # Yes, this is all you need to deploy on Passenger! All the reverse proxying,
  # socket setup, process management, etc are all taken care automatically for
  # you! Learn more at https://www.phusionpassenger.com/.
  passenger_enabled on;
  passenger_user app;

  # Ensures that RAILS_ENV, RACK_ENV, PASSENGER_APP_ENV, etc are set to
  # "production" when your application is started.
  passenger_app_env production;

  # Since this is a Ruby app, specify a Ruby version:
  passenger_ruby /usr/bin/ruby2.2;
}