目錄
- Spinnaker 介紹
- 環境、軟件准備
- 安裝 Development Spinnaker
- 配置依賴環境
- 配置並安裝 Spinnaker
- 演示 Spinnaker Pipeline
- 演示 Spinnaker 集成 Jenkins
1、Spinnaker 介紹
Spinnaker 是 Netflix 的開源項目,是一個持續交付平台,它定位於將產品快速且持續的部署到多種雲平台上。Spinnaker 通過將發布和各個雲平台解耦,來將部署流程流水線化,從而降低平台遷移或多雲品台部署應用的復雜度,它本身內部支持 Google、AWS EC2、Microsoft Azure、Kubernetes和 OpenStack 等雲平台,並且它可以無縫集成其他持續集成(CI)流程,如 git、Jenkins、Travis CI、Docker registry、cron 調度器等。簡而言之,Spinnaker 是致力於提供在多種平台上實現開箱即用的集群管理和部署功能的平台。
Spinnaker 官網 文檔可以了解到,Spinnaker 主要包含兩大塊內容,集群管理和部署管理。

集群管理主要用於管理雲上的資源,它分為以下幾個塊:
- Server Group:服務組,是資源管理單位,識別可部署組件和基礎配置設置,它並且關聯了一個負載均衡器和安全組,當部署完畢后,服務組就相當於一組運行中的軟件實例集合,如(VM 實例,Kubernetes pods)。
- Cluster:集群,由用戶定義的,對服務組的邏輯分組。
- Applications:應用,是對集群的邏輯分組。
- Load Balancer:負載均衡,用於將外部網絡流量重定向到服務組中的機器實例,還可以指定一系列規則,用來對服務組中的機器實例做健康監測。
- Security Group:安全組,定義了網絡訪問權限,由IP、端口和通信協議組成的防火牆規則。
部署管理功能用於創建一個持續交付流程,它可分為管道和階段兩大部分。
- 管道

部署管理的核心是管道,在Spinnaker的定義中,管道由一系列的階段(stages)組成。管道可以人工觸發,也可以配置為自動觸發,比如由 Jenkins Job 完成時、Docker Images 上傳到倉庫時,CRON 定時器、其他管道中的某一階段。同時,管道可以配置參數和通知,可以在管道一些階段上執行時發送郵件消息。Spinnaker 已經內置了一些階段,如執行自定義腳本、觸發 Jenkins 任務等。
- 階段 階段在 Spinnaker 中,可以作為管道的一個自動構建模塊的功能組成。我們可以隨意在管道中定義各個階段執行順序。Spinnaker 提供了很多階段供我們選擇使用,比如執行發布(Deploy)、執行自定義腳本 (script)、觸發 Jenkins 任務 (jenkins)等,功能很強大。
- 部署策略

Spinnaker 支持精細的部署策略,比如 紅/黑(藍/綠)部署,多階段環境部署,滾動紅/黑策略,canary 發布等。用戶可以為每個環境使用不同部署策略,比如,測試環境可以使用紅/黑策略,生產環境使用滾動紅/黑策略,它封裝好了必須的步驟,用戶不需要復雜操作,就可以實現企業級上線。
2、環境、軟件准備
Spinnaker 安裝在 官網文檔 中寫的很詳細,可以使用一種全新的 CLI 工具 halyard,它幫助管理員更容易地安裝,配置以及升級用於生產環境的 Spinnaker 實例,但是支持的是 Ubuntu 環境,而且部分資源依賴國外地址,SO 我嘗試了一下,由於網絡的原因,安裝過程中沒有能夠繼續下去。。。 所以,這里我選擇了 Spinnaker GitHub 安裝 Development 版本,配置雖然稍復雜一些,但是作為初試階段,能夠跑起來也是不錯的。Development 版本目前只在 Ubuntu 14.04 LTS 和 Mac OS X 10.11 上測試過,由於手頭沒有現成的 Ubuntu 環境,就直接在本機 Mac OS 上嘗試安裝一下吧。
- git: version 2.10.1
- JDK8: version 1.8.0_91
- Redis: version 4.0.2
- Cassandra: verison 3.11.1
- Packer: version 1.1.2
- Docker: version 17.09.0-ce
- Jenkins: version 2.46.2
注意:Development 版本安裝,需要獲取 GitHub 源碼編譯安裝,其中還需要拉取各個組件模塊源碼,所以需要安裝好 Git。JDK8、Redis、Cassandra、Packer 是安裝 Spinnaker 組件時需要依賴的。Jenkins 非必須安裝,這里我下邊需要演示集成 Jenkins,所以使用 Docker 快速安裝一下。下邊會詳細介紹每個組件的作用,以及安裝方式。
3、安裝 Development Spinnaker
安裝 Spinnaker 之前,有必要詳細描述一下 Spinnaker 架構所依賴的各個組件。

- Deck:面向用戶 UI 界面組件,提供直觀簡介的操作界面,可視化操作發布部署流程。
- API: 面向調用 API 組件,我們可以不使用提供的 UI,直接調用 API 操作,由它后台幫我們執行發布等任務。
- Gate:是 API 的網關組件,可以理解為代理,所有請求由其代理轉發。
- Rosco:是構建 beta 鏡像的組件,需要配置 Packer 組件使用。
- Orca:是核心流程引擎組件,用來管理流程。
- Igor:是用來集成其他 CI 系統組件,如 Jenkins 等一個組件。
- Echo:是通知系統組件,發送郵件等信息。
- Front50:是存儲管理組件,需要配置 Redis、Cassandra 等組件使用。
- Cloud driver 是它用來適配不同的雲平台的組件,比如 Kubernetes,Google、AWS EC2、Microsoft Azure 等。
- Fiat 是鑒權的組件,配置權限管理,支持 OAuth、SAML、LDAP、GitHub teams、Azure groups、 Google Groups 等。
以上組件除了核心組件外,一些組價可選擇配置是否啟動,比如不做權限管理的話,Fiat 就可以不啟動,不集成其他 CI 的話,那就可以不啟動 Igor 組件等。這些都可以在配置文件中配置,下邊會說到。Development 版本,各個組件獨立服務運行,有各自的服務端口,且各個組件都有自己的獨立的項目 GitHub 地址。
好了,講了這么多 Spinnaker 相關的東西了,接下來開始安裝 Spinnaker。
3.1 配置依賴環境
Spinnaker 平台需要依賴部分環境,所以為了防止下邊安裝過程中出現錯誤,可以提前安裝一下。
1、由於 Spinnaker 核心服務是由 SpringBoot 框架寫的,所以需要安裝 JDK8 2、Spinnaker 需要使用 Redis 存儲數據,所以也需要安裝。 3、Cassandra 是非關系型數據庫存儲,默認 Front50 組件和 Echo 組件配置使用該存儲,也需要安裝。 4、Packer 是開源的支持多平台創建鏡像工具,rosco 組件配置使用該工具,也需要安裝。
以上依賴環境可以去官網下載安裝,我這里本機 JDK8 環境已經安裝,其他的因為本機是 Mac OS 環境,那么我選擇使用 homebrew 安裝,非常方便。
$ brew install redis cassandra packer
安裝完畢后,我們啟動 redis 和 cassandra,packer 不需要啟動,Spinnaker 可以連接調用即可。
3.2 配置並安裝 Spinnaker
# clone Spinnaker 代碼
$ mkdir /Users/wanyang3/spinnaker $ cd /Users/wanyang3/spinnaker $ git clone https://github.com/spinnaker/spinnaker.git ... # clone Spinnaker 其他個組件代碼 $ mkdir build $ cd build $ ../spinnaker/dev/refresh_source.sh --pull_origin ...
說明一下,Spinnaker 項目里面包含核心配置文件,但不包含各組件代碼,所以需要創建 build
文件夾,並執行 refresh_source.sh
腳本,會依次 clone 各個組件代碼,這里得花點時間了。執行完畢后,顯示目錄如下:
$ ls -alt /Users/wanyang3/spinnaker/build total 24 drwxr-xr-x 17 wanyang3 staff 578 11 23 14:49 . drwxr-xr-x 7 wanyang3 staff 238 11 28 15:43 .. -rw-r--r--@ 1 wanyang3 staff 6148 11 23 14:49 .DS_Store drwxr-xr-x 14 wanyang3 staff 476 11 17 14:32 citest drwxr-xr-x 45 wanyang3 staff 1530 11 17 14:46 clouddriver drwxr-xr-x 49 wanyang3 staff 1666 11 21 14:32 deck -rw-r--r-- 1 wanyang3 staff 175 11 17 16:24 dump.rdb drwxr-xr-x 32 wanyang3 staff 1088 11 17 15:14 echo drwxr-xr-x 30 wanyang3 staff 1020 11 17 14:32 fiat drwxr-xr-x 35 wanyang3 staff 1190 11 17 14:53 front50 drwxr-xr-x 25 wanyang3 staff 850 11 20 14:13 gate drwxr-xr-x 34 wanyang3 staff 1156 11 17 14:32 halyard drwxr-xr-x 24 wanyang3 staff 816 11 20 17:49 igor drwxr-xr-x 19 wanyang3 staff 646 11 22 11:57 logs drwxr-xr-x 49 wanyang3 staff 1666 11 17 15:11 orca drwxr-xr-x 25 wanyang3 staff 850 11 17 14:46 rosco drwxr-xr-x 18 wanyang3 staff 612 11 17 14:32 spinnaker-monitoring
接下來,我們需要配置一下 Spinnaker。
$ cd /Users/wanyang3/spinnaker $ mkdir -p $HOME/.spinnaker $ touch $HOME/.spinnaker/spinnaker-local.yml $ chmod 600 $HOME/.spinnaker/spinnaker-local.yml $ cp spinnaker/config/spinnaker.yml $HOME/.spinnaker/spinnaker-local.yml # 修改配置文件 $ vim $HOME/.spinnaker/spinnaker-local.yml
注意:這里的文件 spinnaker-local.yml
是 Spinnaker 核心配置文件,這里可以配置各個組件是否啟動或關閉,以及其他參數。同時 <spinnaker_dir>/spinnaker/config/*.yaml
這些配置文件都是各個組件啟動時,需要加載的配置文件。這里我們暫時不做修改,保持默認狀態,下邊演示功能時在做修改。
這里有必要在詳細說一下,通過對 spinnaker-local.yml
配置文件的分析,Spinnaker 各個組件默認啟動端口如下:
組件 |
端口 |
依賴組件 |
端口 |
---|---|---|---|
Clouddriver |
7002 |
Redis |
6379 |
Fiat |
7003 |
||
Front50 |
8080 |
Cassandra |
9042 |
Orca |
8083 |
||
Gate |
8084 |
||
Rosco |
8087 |
||
Igor |
8088 |
||
Echo |
8089 |
||
Deck |
9000 |
接下來可以啟動 Spinnaker 服務了。
$ cd /Users/wanyang3/spinnaker/build $ ../spinnaker/dev/run_dev.sh [service]
注意:[service]
參數可指定一個或多個組件名稱,若指定則只啟動指定組件,若不指定,默認啟動所有組件,這里我們就不指定了,啟動所有配置開啟的組件。如果正常的話,可以看到輸出日志中依次啟動各個組件,然后執行 gradle 編譯,最后完成啟動 Spinnaker。
Starting clouddriver
Starting front50
Starting orca
Starting rosco
Starting echo
Starting igor
Waiting for clouddriver to start accepting requests on port 7002... ... :clouddriver-web:compileJava UP-TO-DATE :clouddriver-web:compileGroovy UP-TO-DATE :clouddriver-web:processResources UP-TO-DATE :clouddriver-web:classes UP-TO-DATE :clouddriver-web:findMainClass :clouddriver-web:bootRun ... 2017-11-28 17:34:06.440 INFO 6648 --- [ main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: getUsingGET_2 2017-11-28 17:34:06.443 INFO 6648 --- [ main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: listUsingGET_8 2017-11-28 17:34:06.445 INFO 6648 --- [ main] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: listUsingGET_9 2017-11-28 17:34:06.498 INFO 6648 --- [ main] c.n.s.c.listeners.OperationsTypeChecker : Found 0 cloud provider annotations: [] 2017-11-28 17:34:06.567 INFO 6648 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 7002 (http) 2017-11-28 17:34:06.578 INFO 6648 --- [ main] com.netflix.spinnaker.clouddriver.Main : Started Main in 19.568 seconds (JVM running for 22.055)
不過這里我發現了幾個問題。
問題一:如果我們啟動之前未啟動 Redis 服務,那么這里日志就會輸出 redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
異常了。
問題二:本機測試時並沒有一次啟動完所有服務,大部分可以正常啟動,Fiat、Gate、Deck 三個組件未啟動,Fiat 未啟動可以理解,是因為配置文件中設置默認不啟動。Gate、Deck 怎么還得自己去手動啟動呢。。。
問題三:第一次啟動時,發現 front50 未啟動,報錯類似 Can not find keyspaces 'front50'
這樣,這是因為未在 Cassandra 中為創建 front50
的 keyspaces。可通過如下方式查看:
$ cqlsh
Connected to Test Cluster at 127.0.0.1:9042. [cqlsh 5.0.1 | Cassandra 3.11.1 | CQL spec 3.4.4 | Native protocol v4] Use HELP for help. cqlsh> describe keyspaces; system_schema system system_traces system_auth system_distributed
可以執行一下命令創建:
cqlsh> CREATE KEYSPACE IF NOT EXISTS front50
WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }; cqlsh> describe keyspaces; system_schema system front50 system_traces system_auth system_distributed
后來查看了下 Spinnaker 執行腳本,發現是有執行創建該 keyspaces 的代碼的,不過好像我第一次安裝的時候並沒有執行。。。
$ cat /Users/wanyang3/spinnaker/spinnaker/pylib/spinnaker/change_cassandra.py ... print 'Installing cassandra keyspaces...' os.system('cqlsh -f "/opt/spinnaker/cassandra/create_echo_keyspace.cql"') os.system('cqlsh -f "/opt/spinnaker/cassandra/create_front50_keyspace.cql"') ...
要是碰到沒有執行安裝 echo 和 front50 keyspace 導致這兩個組件報錯的話,可以手動執行一下,創建語句 Spinnaker 已經提供好了,cqlsh 客戶端執行 <spinnaker_dir>/spinnaker/cassandra/*.sql
語句創建即可。
好了,現在大部分服務已經啟動好了,但是 deck 和 gate 服務還沒有啟動起來呢!分別進入到 build 目錄下 deck 和 gate 目錄,先啟動 gate 在啟動 deck,因為 deck 中請求地址是直接連接 gate,然后 gate 網關在對請求做轉發。
$ cd /Users/wanyang3/spinnaker/build/gate $ ./start_dev.sh
如果確定組件是否啟動成功呢?我們可以簡單的 lsof -i :<port>
查看端口情況 也可以分別查看各個組件的日志,看下各組件啟動時是否有異常信息。
$ ls -alt /Users/wanyang3/spinnaker/build/logs total 46168 drwxr-xr-x 19 wanyang3 staff 646 11 22 11:57 . drwxr-xr-x 17 wanyang3 staff 578 11 29 09:23 .. -rw-r--r-- 1 wanyang3 staff 89 11 28 17:33 clouddriver.err -rw-r--r-- 1 wanyang3 staff 76945 11 29 09:53 clouddriver.log -rw-r--r-- 1 wanyang3 staff 2529 11 22 11:57 deck.err -rw-r--r-- 1 wanyang3 staff 3586 11 22 11:57 deck.log -rw-r--r-- 1 wanyang3 staff 507 11 28 17:33 echo.err -rw-r--r-- 1 wanyang3 staff 3408986 11 29 09:56 echo.log -rw-r--r-- 1 wanyang3 staff 0 11 17 14:40 fiat.err -rw-r--r-- 1 wanyang3 staff 788 11 28 17:33 front50.err -rw-r--r-- 1 wanyang3 staff 62153 11 28 17:34 front50.log -rw-r--r-- 1 wanyang3 staff 450 11 27 17:05 gate.err -rw-r--r-- 1 wanyang3 staff 2192698 11 27 17:05 gate.log -rw-r--r-- 1 wanyang3 staff 89 11 28 17:33 igor.err -rw-r--r-- 1 wanyang3 staff 17736046 11 29 09:56 igor.log -rw-r--r-- 1 wanyang3 staff 89 11 28 17:32 orca.err -rw-r--r-- 1 wanyang3 staff 63183 11 28 17:33 orca.log -rw-r--r-- 1 wanyang3 staff 89 11 28 17:33 rosco.err -rw-r--r-- 1 wanyang3 staff 41101 11 28 17:33 rosco.log
接下來啟動 deck 組件,deck 啟動的話,會稍微麻煩一下,可以參考 Deck GitHub Doc 文檔說明操作。
首先需要安裝依賴環境 node 和 yarn
$ brew install node yarn
這里我們是本地搭建的 develop 版本,所有服務均為 localhost。上邊說了,deck 先需要通過連接本地 gate 連將請求轉發到對應組件上。所以可以通過如下方式啟動 deck
API_HOST=http://localhost:8084 yarn run start
先稍等一會,這里會先執行編譯,啟動完畢之后,我們就可以通過訪問 http://localhost:9000
訪問 Spinnaker deck 組件提供的 UI 頁面了,頁面簡潔明了,非常好操作。

從上圖可以看到,Spinnaker 主要的功能已經列出來了。而且這些功能是可以控制的,當擴展或停止了組件以后,UI 頁面也會跟着展現出來,接入簡單,可擴展性強。
4、演示 Spinnaker Pipeline
Spinnaker 的兩個核心集群管理和部署管理,對於集群管理這塊,它對國外常用的雲平台集成的比較好,如 Google、AWS EC2、Microsoft Azure 等,因為手頭沒有相應的資源,這里暫時沒法嘗試,還要它支持 Kubernates,后期我將繼續研究它如何跟 Kubernetes 結合完成集群管理,剛好最近在研究 Kubernetes,手頭有搭建好的 k8s 集群。針對部署管理這塊,Spinnaker 核心為三大塊 Pipeline、Stage、Deployment Strategies,下邊來詳細演示一下 Spinnaker 提供的強大的 Pipeline 功能。
Spinnaker 平台,是按照 Project 項目分類,每個項目包含多個 Application 應用,每個應用里面包含多個 Pipelines ,每個 Pipeline 包含多個 Stage 階段,在每個階段中可以定義不同的 Deployment Strategies 部署策略。整體是按照這種方式來定義的,這樣既可以很好的先按照項目分類,然后可以根據項目中應用再次細分,最后落實到每個應用的流程上,不同的流程配置不同的部署階段和部署策略,從而使用戶有一個很清晰的脈絡來梳理並配置自己不同業務的部署流程線。
4.1 創建 Project、Application
首先創建一個項目 project_test
,然后創建一個應用 app_test
,並將應用 app_test
跟 project_test
項目關聯起來。
點擊導航欄 “Projects” -> “Actions” -> “Create Project”,輸入名稱 project_test
,Application 下拉選擇項先不選,因為我們還沒創建 Application,等創建完畢之后,在選擇配置。

點擊導航欄 “Applications” -> “Action” -> “Create Application”,輸入名稱 app_test
,選擇代碼倉庫類型,默認有三種:stash、github、bitbucket。這里我選擇 stash,配置自己搭建的 GitLab 代碼倉庫即可,如果項目托管在 github 或 bitbucket 上,可對應選擇。下邊實例端口處填寫端口號,根據提示信息,是要填寫該應用實例端口號,最終可以通過 IP + Port 方式訪問該實例,類似 Kubernetes 中的 Pod。

最后,將 project_test
跟 app_test
關聯起來,點擊導航欄 “Projects” -> “project_test” -> “Project Configuration” -> “Applications”,下拉列表中選擇 app_test
,點擊 “Save” 保存即可。

4.2 創建 Pipeline
接下來創建 Pipeline,進入 app_test
詳情頁面,點擊 “PIPELINES”,目前是沒有任何信息的,點擊 “+ Create”,彈框中選擇類型為 Pipeline,輸入流程名稱,這里我命名為 first_pipeline
。因為第一次創建,下邊 “Copy From” 選擇沒出來,后續在創建時,我們也可以通過 “Copy From” 方式選擇已存在的 Pipeline,非常方便就復制了一個一樣配置的流程了。創建完畢后,就會出現詳細配置 Pipeline State 的頁面了。

4.3 配置 Configuration 項
剛開始這里只有一個 Configuration 選項,可以配置 Automated Triggers、Parameters、Notifications 等,這里說下 Automated Triggers 和 Parameters 這兩個非常有用,我們可以將此視為 Pipeline 啟動前的一些初始化配置,比如啟動需要的參數配置、自動觸發配置等,為后續各階段提供必要的信息。
Automated Triggers 自動觸發,它提供 7 種類型的觸發方式:
- CRON:調度觸發,可以執行一個 cron 調度任務來定時任務觸發該流程。
- Git:當執行 Git push 操作時,觸發該流程
- Jenkins:監聽 Jenkins 的某一個 Job
- Travis:監聽 Travis 的某一個 Job
- Pipeline:監聽另一個 Pipeline 執行
- Pub/Sub:當接受到 pubsub 消息時觸發
- Docker Registry:當 image 更新時觸發。
基本能滿足我們日常持續集成或交付的需求,當然每一個類型都需要配置相應的參數,比如 Cron 類型,需要配置執行頻率、啟動時間等。




這里就不一一截圖列舉,可以親自試驗一下吧,每種類型的配置參數不一樣,一些參數如果需要下拉選擇的時候沒有可選項,說明在啟動 Spinnaker 的時候,配置文件中沒有配置,也或者是配置的信息不完整或不正確導致。例如 Jenkins 類型,選擇 Master 的時候,如果沒有在 $HOME/.spinnaker/spinnaker-local.yml
文件中配置 Jenkins 信息的話,那么這里就肯定不會出現可選信息了。Docker Registry 中 Registry Name 選項也是同理。同時這些觸發方式,可以組合使用的,添加多個 Automated Triggers 組合使用,效果杠杠的。
Parameters 參數,可以配置 Pipeline 參數,在流程啟動是,會要求輸入或選擇對應的參數,並且在后續 Stage 中可以直接獲取使用,這是非常有必要的,我們使用 jenkins Job 時,有構建參數選項配置,這里如果我們要觸發對應的 Jenkins Job,那么可以把對應的必要參數設置在這里,后續 Stage 觸發 Jenkins Job 時,構建參數賦值就可以直接通過表達式來獲取了。


比如這里我設置 ci_version
和 branch
兩個必填參數,並且 branch
帶默認值,且可設置為可選參數。
4.3 配置各個 Stage 項
接下來,給 Pipeline 添加 Stage 了,實際應用中就需要我們結合自己的業務邏輯,合理添加 Stage,來達到期望的持續集成交付功能啦。這里我做一個簡單的的功能演示,先來一個 Manual Judgment 類型 Stage,做人工判斷選擇,根據啟動者選擇的類型,在分別執行對應的 Check Preconditions 類型 Stage,做先決條件檢查,這里得用到表達式判斷(下邊會說到表達式),最后為每條路徑配置不同的類型的 Stage,這里一條使用 Wait 類型,等待固定秒后自動到下一個Stage 或結束,另一條選擇 Webhook 類型,調用一個 API 接口,正常返回后結束流程。下邊一步步介紹每個 Stage 配置,最終完成整個 Pipeline。
4.3.1 配置 Manual Judgment Stage
首先創建一個 Manual Judgment 類型的 Stage,來做人工判斷選擇,顧名思義就是執行 Pipeline 到該 Stage 的時候,會等待用戶選擇配置選項,Stage 才可以繼續執行下去。鼠標點擊 Configuration 選項,使其圖標變綠(意味着對該選中項增加下一步 Stage,后續其他 Stage 增加 Stage 操作一樣)。點擊 “+ Add Stage”,下方區域 Type 選擇 Manual Judgment,Name 名稱我填寫 “Manual Judgment Stage” 直觀明了,Instructions 處填寫該 Stage 的說明信息,實際應用中,一些必要的說明信息是很有必要的,其他人操作該流程時好做參考提示,這里還支持 HTML 代碼,所以我再次輸入提示信息如下:
<div>請選擇條件: <br> <ul> <li>develop environment: 開發環境,將執行 Wait Sate</li> <li>release environment:生產環境,將執行 Webhook Stage </li> </ul> </div>
這樣就算其他人執行這個示例流程,到這一步也知道該如何選擇了吧!接下來 Judgment Inputs 判斷項,這里我添加兩判斷項 develop environment 和 release environment,啟動 Pipeline 執行到該 Stage 時,會等待我們選擇判斷項時,就會顯示這兩項。后續 Stage 也可以通過表達式獲取到選擇的值,來串聯對應其他 Stage 很實用。填寫完畢,點擊 “Save Changes” 保存即可,如下圖所示。

4.3.2 配置 Check Preconditions Stage
上邊 Manual Judgment Stage 配置了兩個 Judgment Inputs 判斷項,接下來我們建兩個 Check Preconditions Stage 來分別對這兩種判斷項做條件檢測,條件檢測成功,則執行對應的后續 Stage 流程。點擊 “Manual Judgment Stage” 使其變綠,點擊 “+ Add Stage”,Type 選擇 Check Preconditions,Name 名稱我填寫 “Check Preconditions develop” 說明是針對條件為 develop environment 類型的驗證,Preconditions 條件配置處點擊 “+ Add Precondition”,彈框 Edit Preconditions 如下圖。

Check 處選擇 Expression 表達式方式,然后在 Expression 文本域填寫表達式 ${ #judgment('Manual Judgment Stage') == 'develop environment' }
,說明一下,這個表達式意思就是從名稱為 “Manual Judgment Stage” 的 Judgment Stage 獲取選擇的值是否為 “develop environment”,如果條件匹配,則返回 true,繼續執行當前 Stage 后續 Stage 流程,否則返回 False,執行前 Stage 的后續其他 Stage,如果未配置其他 Stage,則流程結束。Fail Pipeline 選項,如果勾選,則匹配不成功后,則直接結束流程。根據實際需要配置,這里我不勾選,因為該 Stage 判斷不匹配的時候,我們還需要執行另一個判斷 Stage 呢,可不能結束流程了。配置完畢,如下圖。

接下來配置另一個 Check Preconditions Stage,這里就不用在一步步創建了,可以直接復制 “Check Preconditions develop” ,然后修改下名稱和表達式即可,是不是很方便。點擊 “Manual Judgment Stage” 使其變綠,點擊 “+ Copy existing stage”,彈框選擇 “Check Preconditions develop”,點擊 “Copy Stage” 即可完成創建,彈框如下圖。

然后修改下 Name 為 “Check Preconditions release”,表達式處修改為 ${ #judgment('Manual Judgment Stage') == 'release environment' }
,保存即可。配置完畢,如下圖。

4.3.3 配置 Wait Stage
配置好了 Check Preconditions Stage,接下來我們為 “Check Preconditions develop” stage 配置后續 Stage,使其在驗證成功后,可以繼續執行下去。點擊 “Check Preconditions develop” 使其變綠,點擊 “+ Add Stage”,Type 選擇 Wait,Name 名稱我填寫 “Wait Stage”,這個 Stage 什么都不干,等待固定時間后結束流程使用。Wait Time 設置等待秒數,這里我設置為30s。配置完畢,如下圖。

4.3.4 配置 Webhook Stage
接下來為另一個 “Check Preconditions release” Stage 配置后續 Stage,使其在驗證成功后,可以繼續下去。點擊 “Check Preconditions release” 使其變綠,點擊 “+ Add Stage”,Type 選擇 Webhook,Webhook URL 為需要觸發的 URL 地址,實際應用中用處很大,可以觸發其他接口或者其他流程等等,而且可以配置解析返回值,進行狀態判斷,是否觸發成功還是失敗,來 Fail Pipeline 或其他操作,這里我簡單一點,觸發 http://www.baidu.com
,Method 選擇 Http 請求方式,支持 GET、HEAD、POST、PUT、DELETE 方式,選擇了每一種方式之后,會出現對應該請求方式的其他參數配置,這里我選擇 GET 方式,不需要配置其他參數。Wait for complation 等待完成配置,這下邊有詳細的解析返回值或返回狀態的配置,也可以支持異步接口方式,比如提供一個獲取狀態 Staus 的 URL,然后配置對應信息,那么流程執行到此時,會請求異步接口並解析,直到返回狀態匹配成功,才結束流程等,這里示例簡單些,不配置了。配置完成后,如下圖。

4.3.5 啟動 Pipeline
好了,經過上邊一系列的配置,一個簡單的擁有 5 個 Stage 的 Pipeline 就完成了,接下來我們啟動一下 first_pipeline
試試效果吧!回到 app_test
應用的 PIPELINES 頁面,我們會看到我們所有配置的 Pipeline 列表,找到對應 first_pipeline
的 Pipeline,點擊后邊 “Start Manual Execution” 按鈕,會彈出啟動確認框,如果流程 Configuration 項配置了參數或者 Trigger,這里會一並彈出,在填入對應的值后,就可以啟動流程了。例如該流程,我們配置了 Parameters 參數 ci_version
和 branch
參數,所以啟動彈框如下圖。

輸入 ci_version
參數,以及選擇 branch
參數后,點擊 “RUN” 即可啟動流程啦!啟動后,我們會發現按照之前的設計,流程會卡在第一個 Stage,等待我們人工做判斷,這里我們先選擇 “develop environment” 選項,繼續到下一個 Stage 吧。

說明一下,這里可以鼠標懸停在第一個 Stage 上,就會顯示配置的 Judgment Input 選項,以及 Instructions 說明,也可以點擊 “Details” 下方顯示詳細信息,在此選擇亦可以。
選擇完畢后,流程會自動執行到下一個 Stage,流程會分別走到 “Check Preconditions develop” 和 “Check Preconditions release” Stage,然后做條件判斷,還記得之前我們配置的 Expression 吧,這里就起到作用了,我們選擇的是 “develop environment”, 那么驗證 “Check Preconditions develop” 就會通過,直接繼續到對應的下一個 Stage。驗證 “Check Preconditions release” 失敗,那么該節點狀態就是 STOPPED 狀態,不執行后續 Stage。

此時我們可以看到流程已經到了 Wait Stage 了,這一步什么都不干,等待 30s 流程結束。在等待過程中,也可以人為跳過等待時間,鼠標懸停該 Stage 上,會彈出跳過按鈕。等待完畢后,該流程就成功結束啦!

OK,到目前為止,Pipeline 的一條路線可以成功執行了,接下來驗證一下,選擇 “release environment” 選項后,流程的另一條路線執行情況吧!過程我就不在一一描述了,直接看結果吧!

OK,同樣可以正常運行。Spinnaker Pipeline 還有很多使用高級的用法,比如它可以觸發 Script 腳本、執行 Job、觸發其他 Pipeline 運行、部署項目到配置的雲平台等等,基本能夠滿足我們日常業務需求噠!而且它還在持續更新中,相信以后能更方便更高效的接入更多平台。
5、演示 Spinnaker 集成 Jenkins
對於持續集成流程,我們使用的比較多的開源工具 Jenkins,Spinnaker 設計中就能夠很好的支持第三方工具,通過 Igor 組件就能很好的支持 Jenkins 等工具。下邊我們就演示一下 Spinnaker 如何集成 Jenkins 工具。
5.1 搭建並配置 Jenkins
因為 Spinnaker 本身啟動時並沒有直接啟動一個 Jenkins 服務,所以需要我們自己啟動一個 Jenkins 服務或 Jenkins 集群服務,然后將 Jenkins 信息配置到 Spinnaker 配置文件中,使其可以關聯到對應 Jenkins,然后就可以在 Spinnaker 中盡情使用 Jenkins 服務啦!
Jenkins 服務搭建及配置,這里我就不在詳細說了,具體可以參考之前文章 初試Jenkins2.0 Pipeline持續集成 前半部分 Jenkins 安裝這塊,講的很詳細。這里我用 Docker 方式在本地快速搭建一個 Jenkins 服務。
docker run -d -p 9090:8080 -p 50000:50000 -v /Users/wanyang3/jenkins_home:/var/jenkins_home jenkins
此時 Jenkins 服務就運行在本地 http://127.0.0.1:9090
上了,我們配置管理員賬戶 admin,密碼 admin 為了后邊配置 Spinnaker 使用。接下來我們創建一個普通的測試 Job,名稱為 maven_test
,參數化構建過程處我們配置一個 ci_version
參數,目的很明顯,就是為了接收上邊 Pipeline 啟動參數中的 ci_version
值,讓他們能夠串聯起來。

然后,在源碼管理處,配置我們的代碼倉庫地址及分支 (這里分支也可以配置成參數,從 Spinnaker 啟動參數中獲取哈,這里就不演示了)。最后,我們在配置一下構建,執行一個 shell,簡單打印一下獲取的參數,最后在執行一個 mvn clean
命令。

配置完成后,接下來就需要配置 Spinnaker config 文件,開啟對 Jenkins 的支持以及配置 Jenkins 信息。
5.2 配置 Spinnaker config 集成 Jenkins
上邊提到,Spinnaker 的配置文件為 $HOME/.spinnaker/spinnaker-local.yml
,那么我們需要做一些修改。
$ vim $HOME/.spinnaker/spinnaker-local.yml ... igor: enabled: true # 這里默認為 false,修改為 true host: ${services.default.host} port: 8088 baseUrl: ${services.default.protocol}://${services.igor.host}:${services.igor.port} ... jenkins: enabled: ${services.igor.enabled:false} defaultMaster: name: Jenkins baseUrl: http://localhost:9090 # 配置上邊啟動的 Jenkins 服務地址 username: admin # 管理員用戶名 password: admin # 管理員密碼或管理員對應的 API Token ...
配置完成后,在 Run 一下 Spinnaker 服務,默認 Spinnaker 會檢測各組件如果已經啟動的話,將不再重啟。當然也可以先 Stop,然后在 Run 所有組件服務也可以。
$ cd /Users/wanyang3/spinnaker/build $ ../spinnaker/dev/stop_dev.sh [service] $ ../spinnaker/dev/run_dev.sh [service]
注意:重啟服務后,若某些組件未啟動,需要像上邊一樣,手動啟動組件。上邊我們設置了 Igor 為 true,那么會自動啟動起來,一定要保證 igor 能正常啟動,否則沒法集成 Jenkins。
5.3 配置 Jenkins Stage
我們繼續使用 first_pipeline
這個示例 Pipeline,簡單的在 Wait Stage 后邊追加一個 Jenkins Stage,讓其執行上邊配置的 Jenkins 名稱為 maven_test
的 Job,並且將 參數 ci_version
傳遞過去。
點擊 “Wait Stage” 使其變綠,點擊 “+ Add Stage”,Type 選擇 Jenkins,Master 處選擇剛配置文件中定義的 name: Jenkins
Jenkins,這里也可以配置多個 Master,具體可以參考文檔。Job 處選擇 maven_test
,默認會拉取該 Jenkins 下所有 Job。 Job Parameters 這里就需要傳遞 ci_version
參數了,實際應用中,我們是要動態獲取啟動參數中的參數配置,所以這里可以通過表達式 ${ parameters['ci_version']}
來獲取參數。Wait for results 默認勾選,等待 Jenkins 的執行結果,Jenkins 執行完畢,才結束流程。配置完成后,如下圖。

OK,配置完成。最后我們在來啟動一下 first_pipeline
,輸入 ci_version
參數,選擇 branch
參數啟動,選擇 “develop environment” 繼續,執行完 “Check Preconditions develop” Stage,繼續到 “Wait Stage” 等待 30s 后,執行 “Jenkins Stage”,但是執行失敗了。。。 這是為啥? 看返回的報錯信息是 403 No valid crumb was included in the request
,原因是 Jenkins 默認開啟防止跨站點請求偽造導致的,解決方案就是去 Jenkins —> 系統管理 —> 防止跨站點請求偽造處,去掉勾選即可。再次運行,就可以成功運行啦!

點擊詳情中 “Build #47” 鏈接,查看此次 Build Log,可以看到正常啟動並傳遞參數。
...
[maven_test] $ /bin/sh -xe /tmp/hudson9078124639399895924.sh + echo ci_version: 1.0.1 ci_version: 1.0.1 + sleep 15s + echo hello this is maven-test job trgger by spinnaker hello this is maven-test job trgger by spinnaker [maven_test] $ /var/jenkins_home/tools/.repository/bin/mvn clean [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building qd_api 0.0.1-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ qd_api --- [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.809 s [INFO] Finished at: 2017-12-04T09:00:22+00:00 [INFO] Final Memory: 5M/59M [INFO] ------------