第一節介紹了gitolite mirror,使得代碼能夠被傳送到服務器組的內部網絡中,但是接下來如何將代碼再部署到上千臺服務器上,而且還能夠實現代碼回滾呢?
capistrano使用ruby語言開發,所以懂得ruby就可以熟練使用capistrano了。鑑於capistrano3.x需要使用ruby1.9以上的ruby版本,所以我還是選擇了2.x。
我使用的是CentOS6.4,自帶"ruby-1.8.7.352-7.el6_2.x86_64":
# yum install ruby # yum intall rubygems # gem install capistrano -v 2.15.5 # gem install capistrano-ext
capistrano2.x與3.x版本有很大的不同,所以2.x上面的命令不能直接在3.x上面直接運行,比如工作目錄的初始化就不同:
# mkdir /tmp/test3 # cap install # mkdir /tmp/test2 # cd /tmp/test2 # capify . # tree 這裏是初始化後的工作目錄,deploy.rb是主配置文件。 . ├── Capfile └── config └── deploy.rb
管理端capistrano執行後,會給app服務器帶來什麼改變呢?
首先會在目標目錄中創建release目錄,主要用來存放代碼,而且所有的代碼均以不同的版本號命名。另外還會創建share目錄。最後創建的是current軟連接,current用來指向release目錄中最新的代碼版本號。
# tree . ├── current -> /data/capistrano/pandaarcher/releases/20150107020401 ├── releases │ └── 20150107020401 │ ├── a │ ├── config.json │ ├── db.js │ ├── def.js │ ├── Deploy.txt │ ├── log -> /data/capistrano/pandaarcher/shared/log │ ├── log.js │ ├── panda_score.js │ ├── public │ │ └── system -> /data/capistrano/pandaarcher/shared/system │ ├── REVISION │ ├── tmp │ │ └── pids -> /data/capistrano/pandaarcher/shared/pids │ └── worker.js └── shared ├── log ├── pids └── system 12 directories, 9 files
capistrano的回滾功能:
當我們執行rollback以後,就會將release目錄中最近一次部署的代碼版本刪除,同時將current重新連接到上次的版本號目錄。最後還會幫助我們restart服務。所以我們要使用rollback功能,你的配置文件中必須有restart功能,否則會報錯奧!
capistrano的工作原理很簡單,與ansible一樣都是基於SSH從capistrano管理主機傳遞命令到app服務器。所以執行賬戶必須能夠使用app服務器上面已有的賬號(其shell不能是/sbin/nologin)執行命令。
在這裏明確下我們最終的需求:將程序猿提交到公司內部git服務器的代碼通過gitolite mirror主動傳輸到線上服務器所在的內網git服務器,然後運維人員搭建對應項目的capistrano工作目錄,對其做好配置,確保其能夠正常工作。然後在Hudson上面建立此項目,添加此項目的程序猿的工作賬號並授權。當代碼需要更新時,程序猿自己就可以通過網頁界面直接更新此項目,而無需去再和運維協調。
在這裏再簡單的描述下Hudson,我們需要的只是Hudson可以執行shell命令的功能,它在執行後不僅可以返回執行結果,而且還可以返回詳細執行過程。所以,我們讓Hudson去調用capistrano中對應的項目即可,其中需要注意的是權限問題:
(1)管理機Hudson用戶必須有足夠的權限去進入capistrano工作目錄並執行命令,所以我會直接將此工作目錄的屬主、屬組定爲Hudson用戶。
(2)管理機Hudson賬號必須能夠通過ssh連接到app服務器指定的賬號去啓動,比如在app服務器建立capistrano賬號,然後將管理主機的Hudson賬號的公鑰添加到app服務器的capistrano賬號的authorized_keys中建立單向密鑰認證,當然你也可以每次執行輸入密碼。
(3)當將代碼推送到app後,所有的文件的屬主、屬組必然是capistrano用戶的,作爲web主機,一般向外提供服務時爲了安全起見,是不能夠讓啓動者有登錄權限的。所以capistrano用戶不能作爲web服務器的啓動者。所以需要賦予capistrano用戶可以執行/sbin/runuser的sudo權限,使得capistrano可以調用www(web啓動者)啓動服務。
(4)但是權限問題依然存在,由於代碼的屬主、數組都屬於capistrano,所以www能不能進入代碼目錄並執行代碼依然是個問題。同時由於需要對代碼可以進行回滾,capistrano用戶也必須同時具有代碼的RWX權限。所以sgid和setfacl功能是解決此問題的好辦法。
(5)考慮到app會產生日誌,所以我們還需要額外建立log目錄,並設定其屬主、屬組爲www。
回到capistrano,默認情況下,它會一次性併發向所有的服務器發送對應的指令,此過程是阻塞的,也就是我們會一直等待capistrano給我們返回結果。對於update代碼,對線上的業務是沒有影響的,但是對於restart操作,那麼如果你指定了LVS後面的所有的app服務器,那麼此app在此期間是完全不可用的。我的處理方法是寫多個stage文件,然後分別執行,或者在restart代碼中加上一些很醜的代碼。
具體環境和操作方法如下:
10.0.5.90:公司內部git服務器,本機root管理gitolite-admin
10.0.5.91:線上gitolite mirror服務器,本機root管理gitolite-admin;同時也是capistrano+Hudson服務器
10.0.6.153:線上app服務器
我們希望將代碼部署到app服務器的/data/capistrano/car/目錄中,然後實際的對外發布的目錄是/data/html/。而且這裏啓動服務是以capistrano用戶啓動的,暫時不使用上面提到的www用戶。
at 10.0.6.153: # useradd capistrano # mkdir /data/capistrano/car # mkdir /data/car # mkdir /data/logs/car # chown capistrano.capistrano /data/capistrano/car # chown capistrano.capistrano /data/html/ # chown capistrano.capistrano /data/logs/car # sudo su - capistrano # ssh-keygen -b 2048 # scp /home/capistrano/.ssh/id_rsa [email protected]:/root/10.0.6.153.capistrano.pub 賦予capistrano用戶訪問git倉庫的權限
at 10.0.5.91: # rpm -ivh hudson # usermod -s /bin/bash hudson # sudo su - hudson # ssh-keygen -b 2048 # scp /var/lib/hudson/.ssh/id_rsa.pub [email protected]:/root/10.0.5.91.hudson.pub hudson用戶在調用capistrano時也必須具有訪問git倉庫的權限 # exit # cd /root/gitolite-admin # mv /root/{10.0.5.91.hudson.pub,10.0.6.153.capistrano.pub} key/ # vim conf/gitolite.conf repo gitolite-admin RW+ = admin repo car RW+ = server-zhu R = 10.0.6.153.capistrano R = 10.0.5.91.hudson option mirror.master = zhu option mirror.slaves = cong
所以capistrano項目部署如下:
set :application, "car" app服務器代碼部署目錄 set :repository, "[email protected]:car" 指定git服務器, role :app, "10.0.6.153","10.0.6.155" 指定app服務器的ip 這裏可以指定多個role set :keep_releases, 30 指定保存多少個版本,默認是5個 set :scm, :git 這裏可以使用git、svn等。甚至可以不使用,也就是從file調用 set :deploy_to, "/data/capistrano/#{application}" 部署到我們指定的位置 set :user, "capistrano" 指定在app服務器上的用戶 set :runner, "capistrano" 指定運行用戶 default_run_options[:pty] = true 當我們下面需要sudo時,就必須使用一個pty。 set :use_sudo, false 這個與執行命令中的sudo無關。 加上後,app主機中的capistrano執行的操作都是以sudo權限運行的。 set :normalize_asset_timestamps, false namespace :deploy do task :default, :roles => :app do 這裏":roles => :app",可以省略,但加上以後使得配置更加直觀。 update link stop start end task :link, :roles => :app do run "ln -nfs #{deploy_to}/current/ /data/html/car" 強制建立/data/capistrano/car/current到/data/car的軟連接。 另外由於軟連接的權限是777,所以如果你是第一次部署,其屬主爲root, capistrano也可以強制奧 另外,由於ruby會自動的在#{deploy_to}/current/下面生成一些沒用的東西, 所以如果想要/data/html/car比較乾淨的話,可以在程序猿一開始提交時, 就提交一整個的目錄,而不是散列的東西到git倉庫。 然後做軟連接時,可以是ln -nfs #{deploy_to}/current/realcode /data/html/car end task :start, :roles => :app do run "cd /data/html/#{applicate} && (nohup node car.js >/dev/null 2>&1 &)" 這裏是設定啓動car服務的命令 如果car服務是啓動在1024以下的端口,那麼必須以root用戶啓動了,stop亦然 end task :stop, :roles => :app do run "ps aux | grep car | grep -vw grep | awk '{print $2}' | xargs sudo /bin/kill && sleep 3" end task :restart, :roles => :app do find_servers_for_task(current_task).each do |server| run "ps aux | grep car | grep -vw grep | awk '{print $2}' | xargs sudo /bin/kill && sleep 3 && cd /data/html/#{application} && (nohup node car.js >/dev/null 2>&1 &)",:hosts => server.host end 以上命令只是上面的stop,start重新寫了一遍, 如果不需要逐個主機的重啓,那麼我們可以直接寫stop回車後start end end
當你的源不是git,而是本地的文件,可以這麼寫:
set :repository, "127.0.0.1:/source/" set :deploy_via, :copy
當你需要處理git分支時:
set :branch, 'staging'
stage的多段處理:
(1)當你一個項目中又包含多個子項目,所有子項目需要分別的管理,那麼就需要stage了。
(2)或者你不希望使用上面restart中那樣格式的追個重啓主機,那麼你也可以使用stage將各個主機分別寫入一個文件中。方法如下:
(1)修改deploy.rb文件,刪除namespace以後的內容和role行,並添加如下內容: require "capistrano/ext/multistage" set :stages, %w(app1 app2) set :default_stage, "app1" 制定默認,可以省略 (2)在config目錄下創建deploy目錄,並在在其下面創建app1.rb、app2.rb文件。 在app1.rb文件中添加namespace內容,並且添加對應的role。 執行方法:cap app1 deploy:start
cap命令:
(1)cap deploy:setup,初始化,創建release和share目錄
(2)cap deploy:update,上傳代碼目錄到release並命名爲日期格式的數字名稱目錄名,同時創建其軟連接到#{delploy_to}/current
(3)cap deploy:start,啓動服務
(4)cap deploy:stop,關閉服務
(5)cap deploy:rollback,回滾
(6)cap deploy:check,檢查
最後說Hudson,Hudson功能很強大,但是我們只利用其shell功能。同樣,Hudson是安裝在管理主機10.0.5.91上面的。
# rpm -ivh hudson-3.2.1-1.1.noarch.rpm
然後使用瀏覽器訪問:http://10.0.5.91:8080
(1)登錄後,首先會讓我們在線安裝Hudson組件,這裏只選核心組件。安裝過程十分漫長。
(2)用戶授權:
首先需要註冊一個用戶,這第一個用戶其實就是具有supper權限,然後"系統管理"→"Configure Security”→“Hudson專有用戶數據庫”→"項目矩陣授權策略"
上面的user1、user2也是先註冊後授權的奧!
(3)對項目car進行用戶權限管理
這樣,管理員新建的這個項目car,在只授予user1權限時,其他用戶是看不到此項目的
而且,此項目只能被執行,不能被修改
(4)最後是如何讓Hudson執行命令:
(5)讓程序猿進入此項目,直接點擊構建就可以更新代碼了。