Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deployment with Capistrano

張旭
March 22, 2016

Deployment with Capistrano

張旭

March 22, 2016
Tweet

More Decks by 張旭

Other Decks in Programming

Transcript

  1. Deployment × Capistrano
    張旭
    @zx1986

    View full-size slide

  2. 部署是什麽?
    Deployment ?

    View full-size slide

  3. 簡單說,部署就是將您開發的程式,傳
    送到指定環境,並視需求進行參數設
    定,使其提供服務。

    View full-size slide

  4. 更簡單地說,部署就是將程式更新到
    指定環境。

    View full-size slide

  5. 比較傳統的部署手法:
    1. 在本機開發,修改程式檔案。
    2. 透過 FTP 軟體將修改過的檔案上傳到伺服器。
    3. 視需求修改伺服器上的設定檔。
    4. 視需要重啟服務以載入新的設定值。

    View full-size slide

  6. 比較傳統的部署手法 (劣勢):
    ● 檔案數量多時,上傳容易遺漏
    ● 沒有版本變動與發佈記錄
    ● 沒有快速的回復 (Rollback) 機制
    ● 手動修改或重載,繁瑣易出錯
    ● 主機數量增加時,重複工作與出錯率都倍增

    View full-size slide

  7. 簡單地使用 Git 的部署手法:
    1. 在本機開發,修改程式檔案。
    2. 執行 git push 遞交變更。
    3. 登入伺服器,在專案目錄執行 git pull 更新。
    4. 視需求修改伺服器上的設定檔。
    5. 視需要重啟服務以載入新的設定值。

    View full-size slide

  8. 簡單地使用 Git 的部署手法 (劣勢):
    ● .git 目錄有曝露的風險
    ● Git Repository 的金鑰管理
    ● 手動修改或重載,繁瑣易出錯
    ● 主機數量增加時,重複工作與出錯率都倍增

    View full-size slide

  9. 當專案變複雜,使用了各種工具跟框
    架,部署時就會出現各種花式指令跟
    後續任務 (post-deploy tasks) ...

    View full-size slide

  10. EXAMPLE
    Rails
    - rake db:migrate RAILS_ENV=development
    - rake assets:precompile RAILS_ENV=production
    - touch tmp/restart.txt
    Yii 2
    - composer install
    - yii migrate
    CodeIgniter
    - composer install
    - gulp TASK_NAME

    View full-size slide

  11. 假設有 N 個後續任務,有 M 臺主機,
    那麽就需要執行 N×M 次動作 ...

    View full-size slide

  12. 假設有不同的主機角色,例如
    App,Web,Database;不同類型的
    主機部署動作存在差異 ...

    View full-size slide

  13. 出錯了,所有主機要還原 ...

    View full-size slide

  14. Capistrano
    A deployment tool written in Ruby

    View full-size slide

  15. 只要有 Ruby 環境 (使用 RubyGems) 就
    可以安裝 Capistrano,它通常安裝在您
    的開發主機 (PC 或 Laptop) 上。

    View full-size slide

  16. Ruby, RubyGems, rbenv
    Ruby 是一款程式語言,演進相當快速,版本眾多。
    RubyGems 是套件管理工具,管理 Ruby 語言開發的套件。
    - 如同 npm 之於 NodeJS
    - 如同 Pip 之於 Python
    - 如同 Composer 之於 PHP
    rbenv 則是管理不同版本的 Ruby 的工具,顧名思義。
    - 如同 nvm 之於 NodeJS
    - 如同 virtualenv 之於 Python
    - 如同 phpbrew 之於 PHP

    View full-size slide

  17. 檢查主機是否已經有 Ruby 環境
    $ which ruby # 檢查是否已安裝 Ruby
    $ which gem # 檢查是否已安裝 RubyGems 套件管理工具

    View full-size slide

  18. Mac 主機安裝與設定 Ruby 環境
    $ brew update
    $ brew install rbenv ruby-build
    $ rbenv install 2.3.0
    $ rbenv global 2.3.0
    $ rbenv rehash

    View full-size slide

  19. Ubuntu 主機安裝與設定 Ruby 環境
    $ sudo apt-get update
    # 參考 https://github.com/sstephenson/rbenv#installation
    https://github.com/sstephenson/ruby-build#readme
    $ rbenv install 2.3.0
    $ rbenv global 2.3.0
    $ rbenv rehash

    View full-size slide

  20. ❖ Tips
    1. 執行 gem install 之前,先編輯 ~/.gemrc 寫入:
    install: --no-rdoc --no-ri
    update: --no-rdoc --no-ri
    2. 安裝新的 gem 之後,執行 rbenv rehash 重新載入。

    View full-size slide

  21. 使用 RubyGems 安裝 Capistrano
    $ gem install capistrano # 安裝 Capistrano 主程式
    $ gem install capistrano-hipchat # 安裝 Capistrano HipChat 外掛
    $ gem install capistrano-composer
    $ gem install capistrano-rails
    $ gem install capistrano-ssh-doctor
    $ gem install capistrano-db-tasks

    View full-size slide

  22. Capistrano 程式在本機運行。實際上,它
    只是根據您的設定,遵循既有的流程,登入
    指定的主機 (們),執行一系列的 Shell 指
    令,以達成目的。

    View full-size slide

  23. Capistrano 運作時預設會顯示執行的指
    令及其輸出,類似這樣:

    View full-size slide

  24. 初始化 Capistrano
    $ cd my_project
    $ cap install # 初始化 Capistrano 環境建立必要的設定檔
    $ cap --tasks # 顯示目前可以執行的 Capistrano 任務
    $ cap --help # 顯示基本的使用方法
    $ git status # 偷看一下多出了哪些檔案

    View full-size slide

  25. Capistrano 設定檔 (1)
    ├── Capfile
    └── config/
    ├── deploy.rb
    └── deploy/
    ├── production.rb
    └── staging.rb
    http://capistranorb.com/documentation/getting-started/configuration/

    View full-size slide

  26. Capistrano 設定檔 (2)
    ● Capfile 是基礎設施宣告,宣告要引用的外掛、自訂任務等。
    ● deploy.rb 是一個全域的變數設定檔,裡面的設定會被各個 Stage 引用。
    ● Stage 指不同的部署環境,各別對應到 config/deploy/stage_name.rb,
    例如 staging.rb 跟 production.rb。
    ● Stage 是可以自訂或更名的,例如 staging.rb 可以改成 dev.rb。

    View full-size slide

  27. Capfile
    # 初始化程式
    require 'capistrano/setup'
    # 載入預設的部署流程
    require 'capistrano/deploy'
    # 載入其他外掛
    require 'capistrano/hipchat'
    # 從 lib/capistrano/tasks 載入其他自定義的任務
    Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

    View full-size slide

  28. deploy.rb (1)
    # 限定 Capistrano 的版本
    lock '3.4.0'
    set :application, 'my_app_name'
    # 設定版本控制工具以及專案的 Git 程式庫路徑,注意遠端主機對程式庫的讀取權限問題
    set :scm, :git
    set :repo_url, '[email protected]:me/my_repo.git'
    # 設定部署到遠端主機的目錄,使用
    絕對路徑,做為程式部署時的根目錄
    set :deploy_to, '/path/to/project/directory/'
    # 利用 ask 函式,搭配 git 指令抓取當前所在的 branch 做為要部署的版本
    ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

    View full-size slide

  29. deploy.rb (2)
    # 將要共享的檔案或目錄分別添加到 :linked_files 跟 :linked_dirs 變數中
    # 多個檔案或目錄可以用逗號 (,) 區隔
    # 注意!路徑是相對路徑,用以在 current 目錄底下建立 symbolic link
    # 真正的檔案或目錄需要使用者實際手動在 shared 目錄下建立 (後面會提到)
    set :linked_files, fetch(:linked_files, []).push('path/to/file')
    set :linked_dirs, fetch(:linked_dirs, []).push('path/to/directory')
    # 定義 Capistrano 在遠端主機內運作時的環境變數
    set :default_env, { MY_VAR1: "my_value1", MY_VAR2: "my_value2" }
    # 需要保留的舊版本數量,預設是 5
    set :keep_releases, 2

    View full-size slide

  30. deploy.rb (3)
    # 在預設的部署流程中添加自訂的任務
    namespace :deploy do
    desc 'description of my_task'
    task :my_task do
    # roles 是所要部署的主機角色,通常定義在 stage_name.rb 中
    on roles(:role_name) do
    # do something
    end
    end
    after 'deploy:finished', 'deploy:my_task'
    end

    View full-size slide

  31. staging.rb 與 production.rb
    # 通常會在 stage_name.rb 中設定不同的目標主機與登入資訊
    # staging.rb
    server 'dev.server.my', user: 'deploy', roles: %w{app web}, port: 22
    # production.rb
    server 'prod1.server.my', user: 'admin', roles: %w{web}, port: 8022
    server 'prod2.server.my', user: 'admin', roles: %w{app}, port: 8022
    # 所有在 deploy.rb 中的設定,都可以在這裡覆寫或擴充,
    # 但任務 (Tasks) 的覆寫需要使用 .clear_actions 函數,請參考:
    http://capistranorb.com/documentation/advanced-features/overriding-capistrano-tasks/

    View full-size slide

  32. 編寫 Capistrano 的 Tasks
    編寫在遠端主機執行的任務:
    http://capistranorb.com/documentation/getting-started/tasks/
    編寫在本機執行的任務:
    http://capistranorb.com/documentation/getting-started/local-
    tasks/

    View full-size slide

  33. Capistrano 部署出去的目錄結構 (1)
    ├─ current -> /path/to/project/directory/releases/20150908300022/
    ├─ releases/
    │ ├── 20150807250011/ # {YYYYMMDDhhmmss}
    │ ├── 20150903080022/
    ├─ repo/
    │ └── <版本控制軟體的原始檔案>
    ├─ revisions.log
    └─ shared/
    └──

    View full-size slide

  34. Capistrano 部署出去的目錄結構 (2)
    ● current 是一個 symbolic link,指向 releases 內的當前發佈目錄。
    ● releases 存放每次部署所產生的目錄,其源自於 repo。
    ● repo 是一個 Bare Git Repository,部署時使用 git archive 指令,從裡面取
    出檔案放到 releases 目錄之下。
    ● revisions.log 是一個版本記錄檔,記錄每次部署所對應的 git hash。
    ● shared 存放共享的檔案跟目錄,如果有設定,在每個 releases 內的目錄都會
    有 symbolic link 指向 shared 內的檔案或目錄。最常見的就是 config 檔、
    upload 目錄、tmp 目錄、cache 目錄等。

    View full-size slide

  35. 執行 Capistrano 部署與還原
    $ cap staging deploy
    $ cap staging deploy:rollback
    $ cap production deploy
    $ cap production deploy:rollback
    # rollback 實際上是將 current 指向 releases 底下前一版的目錄而已,非常快速。

    View full-size slide

  36. Back to the story
    Someone else’s Story ...
    https://speakerdeck.com/aleiphoenix/automate-deploying-using-capistrano

    View full-size slide

  37. cap wherever deploy

    View full-size slide