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

我一直试图在Elastic Beanstalk上dockerize我的Rails应用程序。 这里有很多例子,但大多数并不适合我的具体用例。 那是:

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

关于如何部署的过程并不是问题,而是正确的Dockerconfiguration,可以与Amazon Elastic Beanstalk一起使用以上特定条件。

什么是正确的configuration,让这个运行?

这是为我工作…

Dockerfile

在这个例子中,我使用phusion/passenger-ruby22:0.9.16作为基本映像,因为:

  • 您的Dockerfile可以更小。
  • 它减less了编写正确的Dockerfile所需的时间。 你不必担心基本系统和堆栈,你可以专注于你的应用程序。
  • 正确地build立了基础系统。 让基础系统错误是很容易的,但是这个图像正确地处理了一切。 学到更多。
  • 它大大减less了运行docker docker build所需的时间,使您可以更快速地迭代Dockerfile。
  • 它减less了重新configuration过程中的下载时间。 Docker只需要下载一次基础镜像:在第一次部署期间。 在每一个后续的部署中,只有在基本映像上进行的更改才会被下载。

你可以在这里了解更多 …无论如何,到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.con不会在Nginx之外设置任何环境variables,所以你将无法在shell中看到它们(即Dockerfile)。 你将不得不使用不同的方法来为shell设置环境variables。

 # 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; }