Travis-CI自動化測試並部署至自己的CentOS伺服器

listener發表於2018-03-06

一直都想自己部署一下自動化測試部署,在瞭解了Travis-CI之後終於準備在這次和小夥伴一起做的一個部落格類網站實驗下了。

因為這是一個前後端分離的專案,所以我這裡只管前端工程的自動化部署,前端主要用Vue腳手架搭建的單頁應用。

環境準備

  • Github公開專案(Travis對開源專案是免費,對私有專案是收費的)
  • Linux伺服器(我這裡用的騰訊雲的學生機,系統是CentOS 7.0)
  • 終端聯結器(我用的SecureCRT,自行下載安裝,當然XShell等也可以,主要用於連線伺服器操作)

自動化部署流程

  1. 本地修改程式碼,提交到指定分支
  2. Travis監聽倉庫改變
  3. Travis執行installscript任務(這裡可以做一些安裝測試構建任務的依賴和測試構建命令)
  4. 任務執行成功後,在Travis的 after_success 鉤子裡面用 ssh免密登陸 伺服器
  5. 自動在伺服器上執行配置的指令碼
  6. 完成自動部署

Travis專案配置

一、建立Github倉庫,初始化工程

在Github建立一個公有(public)倉庫。在本地(我的Windows機器)上把倉庫拉到本地來,在本地用 vue-cli 初始化vue單頁應用(其實初始化單頁應用對於這次操作不是必要的,因為我是vue工程,所以先新建一個,後面測試部署的時候方便一點。當然你也可以初始化一些其他的東西,但是後面的install和script需要修改為對應的命令)。

我的目標是在master分支有push的時候才讓Travis自動部署,平時開發程式碼提交到dev分支,某個功能開發完成再提一個PR(Pull Request) 合併至master,所以這裡先在master基礎上新增dev分支。當然這次測試不必每次都去從dev合併至master,這樣太麻煩了,所以我們直接在master分支上面操作

提交程式碼上傳至伺服器。

二、啟用倉庫

用Github賬戶登陸Travis-CI。Travis-CI會同步你的Github上面的所有倉庫資訊。

登陸之後會列出你的所有倉庫:

Travis-CI自動化測試並部署至自己的CentOS伺服器

灰色打叉的表示這個倉庫沒有啟用,選擇你要實現自動化部署的倉庫開啟開關即可啟用這個倉庫。我這裡的lzq4047/blog-front就是我這次要實現自動化部署的倉庫。

三、新增Travis配置檔案

在本地專案根目錄master分支裡面新增 .travis.yml 配置檔案

新增如下配置:

# .travis.yml
language: node_js   #前端工程所以是JavaScript,編譯環境是node_js
node_js:
- '8'   #指定node版本
branchs:
  only:
  - master  #指定只有檢測到master分支有變動時才執行任務
複製程式碼

將該配置檔案推送到伺服器。 返回Travis網站,此時Travis已經檢測到該倉庫的變動(有可能會有點延遲),所以會根據倉庫根目錄下的.travis.yml配置檔案開始執行任務。

Travis-CI自動化測試並部署至自己的CentOS伺服器

上面部分時任務資訊,下面是任務執行時的輸出。你可以在View config的標籤頁下面看到此次任務的配置資訊,包括了你在.travis.yml裡面配置的和Travis自動配置的資訊。

此時,Travis監聽倉庫變化,自動執行任務已經完成了,也就是流程中的前三步已經完成了。

Travis使用SSH免密登陸伺服器

在此之前的步驟其實都基本沒什麼問題,網上有很多教程都說得很好了,也基本沒什麼坑。但是在利用SSH免密登陸Linux伺服器的過程中卻出現了很多問題。

要想通過Travis在執行伺服器得指令碼首先得登陸到我們得伺服器,但是在Travis不像互動式終端。一般利用使用者名稱和密碼登陸是需要輸入使用者名稱,密碼的,但是Travis裡面沒有提供與使用者互動的介面,當然這也與自動化不符,所以我們只有利用其他方式登陸--SSH免密登陸

SSH的登陸原理大家可以看這個:SSH公鑰登陸原理。大概過程就是,在客戶端生成一個公鑰/私鑰對,將公鑰內容儲存到伺服器 ~/.ssh/authrized_keys 中,然後客戶端發起連線請求時,伺服器傳送一個字串給客戶端,客戶端用本地的私鑰對字串進行加密然後傳送給伺服器,伺服器將收到的加密字串用公鑰解密,如果能解密成功就登陸成功。

這裡的公鑰/私鑰對就是登陸的關鍵,我們不能直接操作Travis伺服器,在上面生成公鑰/私鑰對,所以按照上面正常的流程就走不通,這時候就需要讓Travis偽裝成一個受信的客戶端去連線。也就是我們需要有一對公鑰/私鑰對,公鑰已經儲存在我們的Linux伺服器中,私鑰儲存在某個Travis能訪問到的地方,在必要的時候用這個私鑰去連線伺服器,這裡我們可以把私鑰放在Git程式碼倉庫中,但是直接把私鑰放程式碼中不安全,所以Travis提供了對私鑰進行加密的功能,我們可以把私鑰加密之後放在程式碼倉庫,在登陸的時候Travis解密該私鑰用於連線。

瞭解了大概原理,接下來就是具體操作。

生成公鑰/私鑰對

這裡直接在伺服器上面生成金鑰對,理論上在哪裡生成金鑰對都可以,只要是配套的。

用終端連線工具(SecureCRT)登陸伺服器,我這裡專門建立一個使用者來供Travis連線。

root使用者下建立新使用者travis

#新建使用者
useradd travis
#修改密碼(應該不是必要,但是萬一以後需要用密碼登陸呢),按照提示設定密碼。
passwd travis
#為使用者新增新增許可權
vim /etc/sudoers
複製程式碼

找到#Allow root to run any commands anywhere這一段註釋,在下面新增一行:

travis  ALL=(ALL)   ALL
複製程式碼

生成金鑰對

  • 一定要切到travis使用者
  • passphase一定要為空
#切換至使用者travis,注意後面的操作都在該使用者下操作,不然從git上面拉下來的程式碼或者生成的檔案擁有著將不是travis,會造成一些麻煩
[root@VM_156_69_centos ~]# su travis
[travis@VM_156_69_centos root]$ cd ~
# 生成RSA金鑰對,後面所有的直接以預設就行,passphase一定要為空
[travis@VM_156_69_centos ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/travis/.ssh/id_rsa): 
Created directory '/home/travis/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/travis/.ssh/id_rsa.
Your public key has been saved in /home/travis/.ssh/id_rsa.pub.
The key fingerprint is:
8b:1f:5b:c5:b8:e2:09:21:0a:f8:6d:ef:5f:25:84:24 travis@VM_156_69_centos
The key's randomart image is:
+--[ RSA 2048]----+
|      E .        |
|       o .       |
|        . .      |
|.        . o     |
|o   . . S o +    |
| o o . o . =     |
|  o o o + +      |
|   . . + B       |
|     .o.*        |
+-----------------+
複製程式碼

可以看到生成金鑰對在使用者家目錄的.ssh資料夾(/home/travis/.ssh)下面。 由於Linux許可權的控制規則,檔案的許可權不是越大越好,所有需要設定合適的許可權。這裡需要把**.ssh目錄設定為700許可權,給.sshm=目錄下面的檔案設定為600許可權**

#設定.ssh目錄為700
[travis@VM_156_69_centos ~]$ chmod 700 ~/.ssh/
#設定.ssh目錄下的檔案為600
[travis@VM_156_69_centos ~]$ chmod 600 ~/.ssh/*
#可以看到下面的所有目錄和檔案所用者都是travis這個使用者
[travis@VM_156_69_centos ~]$ ls -al
total 28
drwx------  3 travis travis 4096 Mar  6 20:12 .
drwxr-xr-x. 5 root   root   4096 Mar  6 20:03 ..
drwx------  2 travis travis 4096 Mar  6 20:12 .ssh
[travis@VM_156_69_centos ~]$ ls ~/.ssh/ -al
total 16
drwx------ 2 travis travis 4096 Mar  6 20:12 .
drwx------ 3 travis travis 4096 Mar  6 20:12 ..
-rw------- 1 travis travis 1675 Mar  6 20:12 id_rsa
-rw------- 1 travis travis  405 Mar  6 20:12 id_rsa.pub
複製程式碼

將生成的公鑰新增為受信列表(重點)

[travis@VM_156_69_centos ~]$ cd .ssh/
#將公鑰內容輸出到authorized_keys中
[travis@VM_156_69_centos .ssh]$ cat id_rsa.pub >> authorized_keys
[travis@VM_156_69_centos .ssh]$ cat authorized_keys 
# authorized_keys檔案內容類似這樣
ssh-rsa  *************centos
複製程式碼

測試SSH登陸

#在.ssh目錄下新增配置檔案config
[travis@VM_156_69_centos .ssh]$ vim config
#新增下面程式碼段中的內容並儲存
#測試連線
[travis@VM_156_69_centos .ssh]$ ssh test
Bad owner or permissions on /home/travis/.ssh/config
#注意此時的測試是失敗的,因為authorized_keys和config是我們後面新增的檔案,檔案許可權並不是600
[travis@VM_156_69_centos .ssh]$ ls -al
total 28
drwx------ 2 travis travis 4096 Mar  6 20:40 .
drwx------ 3 travis travis 4096 Mar  6 20:38 ..
-rw-rw-r-- 1 travis travis  405 Mar  6 20:40 authorized_keys
-rw-rw-r-- 1 travis travis   91 Mar  6 20:38 config
-rw------- 1 travis travis 1675 Mar  6 20:12 id_rsa
-rw------- 1 travis travis  405 Mar  6 20:12 id_rsa.pub
#修改檔案許可權
[travis@VM_156_69_centos .ssh]$ chmod 600 config 
[travis@VM_156_69_centos .ssh]$ chmod 600 authorized_keys 
#檢視修改後的許可權
[travis@VM_156_69_centos .ssh]$ ls -al
total 28
drwx------ 2 travis travis 4096 Mar  6 20:40 .
drwx------ 3 travis travis 4096 Mar  6 20:38 ..
-rw------- 1 travis travis  405 Mar  6 20:40 authorized_keys
-rw------- 1 travis travis   91 Mar  6 20:38 config
-rw------- 1 travis travis 1675 Mar  6 20:12 id_rsa
-rw------- 1 travis travis  405 Mar  6 20:12 id_rsa.pub
#重新執行測試
[travis@VM_156_69_centos .ssh]$ ssh test 
The authenticity of host '139.199.90.74 (139.199.90.74)' can't be established.
ECDSA key fingerprint is 41:39:50:e1:e7:c2:f5:19:86:dc:70:e5:91:42:bb:56.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '139.199.90.74' (ECDSA) to the list of known hosts.
Last login: Tue Mar  6 20:43:32 2018 from 139.199.90.74
#測試成功,生成了一個known_hosts檔案,以後再登陸時就不需要在輸入yes確認了,你可以再做一次測試
[travis@VM_156_69_centos ~]$ ls .ssh/
authorized_keys  config  id_rsa  id_rsa.pub  known_hosts
複製程式碼

config檔案內容:

Host test
HostName 99.99.99.99(你的伺服器ip)
#登陸的使用者名稱
User travis
IdentitiesOnly yes
#登陸使用的金鑰
IdentityFile ~/.ssh/id_rsa
複製程式碼

在Linux伺服器安裝Travis客戶端工具

Travis的客戶端工具需要用gem來安裝,gem是ruby的管理工具,所以首先安裝ruby。這裡直接採用ruby版本管理工具rvm(類似nvm安裝node),因為rvm或自動收集伺服器的依賴,缺失的依賴會自動安裝,我剛開始用手動安裝的缺少各種依賴,折騰了很久後面用rvm一次成功。

安裝rvm

參考www.rvm.io/

[travis@VM_156_69_centos ~]# curl -sSL https://get.rvm.io | bash -s stable
#安裝完成後測試是否安裝成功
[root@VM_156_69_centos ~]# rvm version
rvm 1.29.3 (master) by Michal Papis, Piotr Kuczynski, Wayne E. Seguin [https://rvm.io]
複製程式碼

安裝ruby

#我用travis使用者安裝時好像有網路錯誤,所以就用root使用者安裝
[root@VM_156_69_centos ~]# rvm install ruby
#測試ruby安裝
[travis@VM_156_69_centos root]$ ruby --version
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
複製程式碼

修改映象源

安裝完ruby之後就可以使用gem包管理工具了,但是好像官方映象源被牆了,所以需要更換gem的映象源。參考gems.ruby-china.org/

[travis@VM_156_69_centos ~]$ gem sources -l
*** CURRENT SOURCES ***

https://rubygems.org/
[travis@VM_156_69_centos ~]$ gem -v
2.6.14
#更換映象源
[travis@VM_156_69_centos ~]$ gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
https://gems.ruby-china.org/ added to sources
https://rubygems.org/ removed from sources
[travis@VM_156_69_centos ~]$ gem sources -l
*** CURRENT SOURCES ***

https://gems.ruby-china.org/
複製程式碼

安裝travis命令列工具

#在travis下面提示沒有許可權,我切到root使用者去安裝
[travis@VM_156_69_centos ~]$ gem install travis
Fetching: multipart-post-2.0.0.gem (100%)
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You dont have write permissions for the /usr/local/rvm/gems/ruby-2.4.1 directory.
#安裝travis
[root@VM_156_69_centos ~]# gem install travis
Successfully installed travis-1.8.8
Parsing documentation for travis-1.8.8
Done installing documentation for travis after 1 seconds
1 gem installed
#切回travis使用者,執行travis命令有以下輸出說明安裝成功
[travis@VM_156_69_centos root]$ travis
Shell completion not installed. Would you like to install it now? |y| y
Usage: travis COMMAND ...
複製程式碼

新增加密的私鑰至程式碼倉庫

切換至travis使用者,在家目錄下拉取程式碼,進入程式碼目錄。一定要切換至travis使用者,要不然將沒有許可權操作這些檔案,導致程式碼都不能提交

執行下面命令生成加密的私鑰檔案

#首先用GitHub賬戶登陸travis
[travis@VM_156_69_centos blog-front]$ travis login
We need your GitHub login to identify you.
This information will not be sent to Travis CI, only to api.github.com.
The password will not be displayed.

Try running with --github-token or --auto if you dont want to enter your password anyway.

Username: lzq4047
Password for lzq4047: ******
Successfully logged in as lzq4047!
#登陸成功後解密私鑰,--add引數會把加密的私鑰解密命令插入到.travis.yml,Travis解密時要用到的
[travis@VM_156_69_centos blog-front]$ travis encrypt-file ~/.ssh/id_rsa --add
Detected repository as lzq4047/blog-front, is this correct? |yes| yes
encrypting /home/travis/.ssh/id_rsa for lzq4047/blog-front
storing result as id_rsa.enc
#由於我之前生成過,所有這裡提示是否覆蓋
DANGER ZONE: Override existing id_rsa.enc? |no| yes
storing secure env variables for decryption

Make sure to add id_rsa.enc to the git repository.
Make sure not to add /home/travis/.ssh/id_rsa to the git repository.
Commit all changes to your .travis.yml.
#可以看到已經生成了加密後的私鑰id_rsa.enc
[travis@VM_156_69_centos blog-front]$ ls -al
total 464
drwxrwxr-x 7 travis travis   4096 Mar  6 21:24 .
drwx------ 7 travis travis   4096 Mar  6 21:24 ..
...
-rw-rw-r-- 1 travis travis   1680 Mar  6 21:27 id_rsa.enc 
...
-rw-rw-r-- 1 travis travis   1286 Mar  6 21:27 .travis.yml
#.travis.yml中也自動新增了解密命令
[travis@VM_156_69_centos blog-front]$ cat .travis.yml 
language: node_js
node_js:
- '8'
branchs:
  only:
  - master
before_install:
- openssl aes-256-cbc -K $encrypted_****_key -iv $encrypted_****_iv
  -in id_rsa.enc -out ~/.ssh/id_rsa -d
複製程式碼

解釋下解密命令中 -in-out 引數:

  • -in 引數指定待解密的檔案,位於倉庫的根目錄(Travis執行任務時會先把程式碼拉到Travis自己的伺服器上,並進入倉庫更目錄)
  • -out 引數指定解密後的金鑰存放在Travis伺服器的~/.ssh/id_rsa,如果你的後面需要的話可以取這個路徑,我看到網上有的SSH登陸方式用到了這個檔案

配置after_success鉤子

前面的所有工作實際上都是為這一步做準備,SSH免密登陸伺服器執行指令碼。

在.travis.yml中新增一些配置,主要是after_success鉤子配置。修改之後的配置如下:

language: node_js
node_js:
- '8'
branchs:
  only:
  - master
install:
- npm install
script:
- npm run build
env:
  global:
    secure: *********
addons:
  ssh_known_hosts:
  - 99.99.99.99 #受信主機,你的Linux伺服器ip
before_install:
- openssl aes-256-cbc -K $encrypted_****_key -iv $encrypted_****_iv
  -in id_rsa.enc -out ~/.ssh/id_rsa -d
after_success:
- chmod 600 ~/.ssh/id_rsa   #還是Linux檔案許可權問題
- ssh blog@139.199.90.74 -o StrictHostKeyChecking=no 'cd ~/blog-front && git pull && npm install && npm run build'   #使用ssh連線伺服器
複製程式碼

注意:使用 ssh 命令連線一定要設定StrictHostKeyChecking=no,否則第一次連線時依然會要求你確認。後面引號的內容就是登陸你的Linux伺服器之後,在你的伺服器執行的命令,你也可以寫成一個指令碼。只要登陸上伺服器之後,就隨你操作了。

after_success是在Travis執行完 installscript 之後執行的鉤子,其他的Travis配置可以參考官方文件。我這裡構建成功之後就簡單的build一下,看能不能build成功,build成功才登陸伺服器,在伺服器上build(當然也可以直接把Travis的build結果通過scp拷貝到伺服器指定目錄)...

最後一步

當然是提交程式碼,看成果了。

將加密的金鑰檔案和修改後的.travis.yml檔案提交到master分支,訪問Travis檢視自動構建過程。

Travis-CI自動化測試並部署至自己的CentOS伺服器

可以看到,還有個錯誤npm:command not found。說明的我的坑還沒填完,不過關鍵的步驟已經完成了,後面自由發揮咯。。

最好,看得見的成果:

Travis-CI自動化測試並部署至自己的CentOS伺服器
實際上就是Travis構建成功之後的頂部的圖片路徑。

Travis-CI自動化測試並部署至自己的CentOS伺服器

總結

最後,還是總結一下。這是本人第一次寫文章,但是肯定不會是最後一次的(最近和小夥伴做完這個Bolg專案會整理下心得),所以寫得不是很好,請各位諒解下,我也會不斷提高自己的,總之明白我意思就OK了 0.0

這次實踐中主要內容還是SSH的免密登陸吧,因為這裡面確實踩了不少的坑,所以花的時間比較長。學習一種技術的時候最好還是需要明白其中的原理,比如使用Travis通過SSH登陸伺服器的原理,起初都不太明白網上教程說的那些指令是什麼意思,就照著敲,然後各種問題,但是瞭解一點原理之後看起來就輕鬆很多了。

給自己:多學多做多總結!

參考連結

相關文章