Moving to Docker(三)基於Docker的Rails自動化部署

這是本系列的第三篇,整個系列介紹了咱們公司如何把基礎框架從PaaS移植到Docker上。
node

  • 第一篇:介紹了咱們在接觸Docker以前的探索過程。git

  • 第二篇:介紹瞭如何搭建一個內網安全的私有registry。github


在這最後一篇,咱們用一個真實的例子來介紹如何自動化整個部署過程。

web

基本的Rails應用

咱們來進入主題並啓動一個基本的Rails應用。在這個Demo中,我將使用Ruby 2.20 和Rails 4.11。

在終端中運行:
sql

$ rvm use 2.2.0
$ rails new  && cd docker-test



而後咱們來建立個基本的控制器:
docker

$ rails g controller welcome index


而後修改routes.rb文件,使這個項目的根路徑指向咱們剛建立的welcome#index方法:
shell

root 'welcome#index'


在終端執行 rails s來啓動服務並打開http://localhost:3000就能夠看到首頁了。咱們不許備作其它功能了,這只是個例子來證實咱們能夠建立並在容器裏部署且正常工做。
安全

建立webserver

咱們將用Unicorn作咱們的webserver。添加gem 'unicorn'gem 'foreman'到Gemfile而後安裝它們(在終端執行bundle install)。

Unicorn 須要在Rails應用啓動前配置,咱們須要在config文件夾中放入unicorn.rb配置文件。這裏有個關於Unicorn的配置的例子。你能夠直接複製粘貼這個Gist的內容。

而後咱們添加包含下面內容的Procfile到項目的根目錄下,這樣咱們就能夠用foreman來啓動項目了:
ruby

web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb


若是你用foreman start來運行應用,它也能正常工做而且能夠在http://localhost:5000上進行訪問。
服務器

建立Docker鏡像

接下來咱們來建立運行應用的鏡像文件。在Rails項目的根目錄建立個Dockerfile文件,並把下面的內容貼進去:

# Base image with ruby 2.2.0
FROM ruby:2.2.0

# Install required libraries and dependencies
RUN apt-get update && apt-get install -qy nodejs postgresql-client sqlite3 --no-install-recommends && rm -rf /var/lib/apt/lists/*

# Set Rails version
ENV RAILS_VERSION 4.1.1

# Install Rails
RUN gem install rails --version "$RAILS_VERSION"

# Create directory from where the code will run 
RUN mkdir -p /usr/src/app  
WORKDIR /usr/src/app

# Make webserver reachable to the outside world
EXPOSE 3000

# Set ENV variables
ENV PORT=3000

# Start the web app
CMD ["foreman","start"]

# Install the necessary gems 
ADD Gemfile /usr/src/app/Gemfile  
ADD Gemfile.lock /usr/src/app/Gemfile.lock  
RUN bundle install --without development test

# Add rails project (from same dir as Dockerfile) to project directory
ADD ./ /usr/src/app

# Run rake tasks
RUN RAILS_ENV=production rake db:create db:migrate


利用上面提供的Dockerfile,經過下面的命令進行建立鏡像:

$ docker build -t localhost:5000/your_username/docker-test .


若是一切順利,在長長的日誌的最後能看到以下信息:

Successfully built 82e48769506c  
$ docker images
REPOSITORY                                       TAG                 IMAGE ID            CREATED              VIRTUAL SIZE  
localhost:5000/your_username/docker-test         latest              82e48769506c        About a minute ago   884.2 MB


試試運行這個容器:

$ docker run -d -p 3000:3000 --name docker-test localhost:5000/your_username/docker-test


如今應該能夠用經過Boot2Docker虛擬機的3000端口來訪問這個應用了(例如個人:http://192.168.59.103:3000)。

用shell腳原本自動化

經過本系列的第二篇,你應該已經瞭解如何發佈剛纔新建立的鏡像到私有registry並部署在一個機器上了,咱們跳過這一部分直接討論如何自動化這個過程。

接下來將定義3個shell腳本,而後用rake將他們捆綁在一塊兒執行。

Clean

每次咱們建立鏡像並部署時,最後把全部的東西都清除掉。主要包括:

  • 中止(若是已經運行),而後重啓Boot2Docker

  • 移除孤立的Docker鏡像(那些沒有標籤而且再也不使用的容器)


把以下的clean.sh腳本文件放在項目的根目錄。

echo Restarting boot2docker...  
boot2docker down  
boot2docker up

echo Exporting Docker variables...  
sleep 1  
export DOCKER_HOST=tcp://192.168.59.103:2376  
export DOCKER_CERT_PATH=/Users/user/.boot2docker/certs/boot2docker-vm  
export DOCKER_TLS_VERIFY=1

sleep 1  
echo Removing orphaned images without tags...  
docker images | grep "<none>" | awk '{print $3}' | xargs docker rmi


而後給這個文件可執行權限:

$ chmod +x clean.sh


Build

建立的過程基本上是前面的步驟重作一遍。建立一個build.sh文件在項目的根目錄,而後把下面內容貼進去:

docker build -t localhost:5000/your_username/docker-test .


記得給它可執行權限。

Deploy

最後,來建立以下內容的deploy.sh文件:

# Open SSH connection from boot2docker to private registry
boot2docker ssh "ssh -o 'StrictHostKeyChecking no' -i /Users/username/.ssh/id_boot2docker -N -L 5000:localhost:5000 root@your-registry.com &" &

# Wait to make sure the SSH tunnel is open before pushing...
echo Waiting 5 seconds before pushing image.

echo 5...  
sleep 1  
echo 4...  
sleep 1  
echo 3...  
sleep 1  
echo 2...  
sleep 1  
echo 1...  
sleep 1

# Push image onto remote registry / repo
echo Starting push!  
docker push localhost:5000/username/docker-test


若是你對這部分有疑惑,請確認你已經理解了本系列的第二篇文章的相關部分。

一樣,記得給這個文件可執行權限。

用Rake將它們捆綁

將這3個腳本分開依次執行:

  1. clean

  2. build

  3. deploy/push


因爲開發者都是比較懶的,因此這會是一個很大的幫助。

最後一步是將這些打包起來,也就是用rake將三部分合在一塊兒。

爲了簡單,你能夠將這一堆代碼直接粘貼在項目根目錄下的Rakefile後面。打開Rakefile文件,而後把這些粘貼在最後:

namespace :docker do  
desc "Remove docker container"
task :clean do
sh './clean.sh'
end

desc "Build Docker image"
task :build => [:clean] do
sh './build.sh'
end

desc "Deploy Docker image"
task :deploy => [:build] do
sh './deploy.sh'
end
end


儘管你可能不懂這些rake的語法(它們真的很棒!),可是咱們這麼作的目的很明顯。咱們在Docker命名空間下聲明瞭3個任務。他們會建立如下3個任務:

  • rake docker:clean

  • rake docker:build

  • rake docker:deploy


Deploy是依賴build的,而build依賴於clean,因而每次咱們從終端這麼執行:

$ rake docker:deploy


這樣,3個腳本就都會被按順序執行。

測試

爲了驗證它們能夠正常工做,你只須要在應用的代碼中作一點小的改動,而後執行:

$ rake docker:deploy


而後來看看結果。一旦鏡像被上傳(初次執行會比較慢),你能夠SSH進入你的生產環境服務器,而後pull(用SSH隧道)Docker鏡像並執行它。這很是簡單。

好吧,可能它花了一些功夫來讓全部的組成部分工做起來,可是一旦完成,在Heroku上部署的工做就變得很是簡單。

P.S. 跟之前同樣,請讓我知道你的想法。我不肯定這是最好的或者是最快的或者是最安全的方案來用Docker部署應用,可是咱們確實是這麼用它的。

  1. 確認Boot2Docker啓動並在運行。

  2. 若是你不知道你的Boot2Docker虛擬機的IP,執行boot2docker ip

  3. 若是你忘了如何用私有registry,請看本系列第二篇

相關文章
相關標籤/搜索