馬勤政,徐中偉,梅 萌
(同濟大學 電子與信息工程學院,上海 201804)
隨著國家鐵路與軌道交通領域的蓬勃發展,高速鐵路與城市軌道交通中基于通信的列控系統技術不斷推陳出新,從而使得相應的測試需求也不斷增加。在傳統的列控系統測試平臺的軟件開發過程中,針對每一個不同的測試任務,均需要開發不同的信號設備仿真對象,對特定的業務邏輯與安全通信功能進行封裝,再令各仿真對象獨立運行,組成測試所需的仿真環境。仿真對象軟件的各類功能均集成在一個應用程序之中,使得各個功能組件之間具有較高的耦合性,難以擴展與更新,使得列控系統測試軟件的開發與運維的時間與維護成本難以降低,也難以對測試平臺中軟件的故障問題進行快速定位與修復。
通過建立容器云平臺,將列控系統測試軟件依照功能拆分為若干服務組件,各個服務之間僅通過通信接口進行耦合,在集群中的一個或多個計算節點上作為進程獨立運行,組件之間通過網絡協議進行通信,通過各類型服務之間的組合對列控系統測試軟件進行開發,能夠大幅降低列控系統測試軟件的內部耦合度,提升開發與維護效率。相較于虛擬機,容器技術作為一種輕量級的虛擬化手段,將服務與其所需的運行環境打包為鏡像文件,便于部署與修改,具有更高的靈活度,同時對I/O、CPU與內存等資源的需求均較低。近年來國內外對于容器及其編排技術均有較多研究成果。為提升研發效率、降低運維與操作成本,該文提出了基于Kubernetes容器編排系統的列控系統測試容器云平臺的設計。
Docker是一種提供輕量級虛擬化解決方案的開源的引擎,建立在Linux操作系統的Cgroup、Namespace以及rootfs等容器技術之上。Docker能夠將服務應用程序及其所需的文件系統按層級打包為一個容器鏡像,容器鏡像不依賴操作系統類型,僅要求操作系統具有相同的內核,這使得Docker鏡像能夠在任何支持Docker的設備中進行遷移。同時,Docker鏡像相對于其他的虛擬化方案具有更快的創建、啟動與停止速度,同時占用更少的操作系統資源,從而降低了應用服務的開發、部署與遷移成本[1]。
Kubernetes是一種用于在多機器云環境,即容器云集群中自動管理、部署與擴展容器應用的開源的容器編排系統。Kubernetes運行在Docker容器之上,由Google公司的Borg系統發展而來[2],能夠按照用戶設定的規則自動化地對集群進行管理,為集群的運行提供了穩定性與效率的保障。
列控系統測試平臺使用計算機軟件與硬件資源對列控系統中的一個或多個通信實體進行模擬,各個模擬對象組成了完整的測試環境。測試環境能夠與被測對象進行信息交互,測試人員通過在測試環境中下達命令以模擬測試大綱要求的運行環境,并觀察被測對象的行為是否與預期一致。各個仿真對象在業務邏輯上具有較大差異,但在本質上均能夠被抽象為應用層、安全層與通信層三個邏輯模塊的組合。其中應用層負責依照測試大綱生成需要發送至被測對象的原始消息或解析接收到的被測對象發送的消息,安全層負責在待發送的原始消息中加入安全相關的數據或驗證收到消息的安全性,而通信層負責測試平臺與被測對象之間消息包的發送與接收。
鐵路安全通信系統的結構抽象如圖1所示[3]。

圖1 鐵路安全通信系統的結構抽象
在鐵路通信信號領域,兩個通信實體之間的消息傳輸都遵循一定的層級式的通信協議。原始消息通過逐層封裝,形成最終的消息報文。以RSSP-I協議與RSSP-II協議為例,兩類通信協議中的每一層都是對某種功能需求的抽象,對下層的輸出進行進一步封裝,供上層使用,且僅對相鄰的上下層負責。依照這種低耦合的關系,能夠將列控系統測試容器云平臺的計算機集群劃分為應用服務子集群、安全服務子集群以及通信服務子集群三個邏輯子集群。基于上述設計,在列控系統測試軟件的開發過程中,可以將待開發的仿真對象按功能拆分為不同的應用層、通信層以及安全層服務,將每個服務打包為若干Docker容器鏡像,并部署在同一個Kubernetes Pod中,同時相同類的Kubernetes Pod均應部署在列控系統測試容器云平臺的對應類型的邏輯子集群之中。
在不同的列控系統測試任務中,應用層服務往往會依據任務的特性進行重新設計,安全層服務則依賴于少量穩定的協議,具有較高的可復用能力。每一個應用層通常會需要一個或多個通信層服務的支持。通信層服務一般可進一步分為軟件協議棧與硬件設備兩部分。這三類服務能夠通過Kubernetes集群提供的內部的網絡通信接口相互進行信息交互,從而實現對測試環境所需的通信實體的仿真。在測試任務執行過程中,應用層服務與通信層服務均需要同列控系統測試容器云平臺外部進行通信。依據被測對象類型的不同,通信層服務與被測對象進行信息交互需要依賴不同的硬件通信設備,因此通信層邏輯子集群需要將通信層服務調度到具備特定網絡接口資源的計算機節點上,并且允許服務實例直接使用宿主計算機節點上的網絡接口。為了向測試平臺下發命令或觀測列控系統測試的過程與結果,測試人員需要在集群以外編寫可視化界面程序,通過Kubernetes提供的外部訪問機制訪問應用層服務。
在列控系統測試過程中,除業務邏輯錯誤導致的通信信號數據包錯誤外,還可能發生潛在的各類故障,從而導致平臺運行異常。為應對此類故障,列控系統測試云平臺還需具有監控服務子集群,負責實時監控平臺的運行狀態,通過訪問Kubernetes的控制平面以及集群中每個工作節點上的Kubelet代理程序提供的應用程序接口(API),實時獲取每個工作節點上的容器以及計算、儲存與網絡資源的健康狀況,對監控信息記錄進行保存,通過對外提供API的方式為平臺運維人員提供服務。列控系統測試容器云平臺的架構如圖2所示。

圖2 列控系統測試容器云平臺的架構
作為列控系統功能測試的基礎設施,列控系統測試容器云平臺一方面需要能夠簡化列控系統測試軟件的開發與部署流程,提高研發效率,另一方面應能夠提升測試流程的自動化程度與穩定性。同時,列控系統是一類安全苛求系統,為了滿足平臺中的仿真對象與真實信號設備的一致性,平臺需要保證各類服務在部署和運行過程中的可靠性與穩定性?;谏鲜鰳I務需求,對列控系統測試云平臺的功能做出如下設計。
(a)服務的部署與發現。
列控系統測試容器云平臺應對Kubernetes提供的API進行再次封裝,為列控系統測試軟件的開發者提供一套簡明完備的命令行界面(CLI),通過CLI命令中的參數支持各層級的應用在其中的部署。開發者能夠通過列控系統測試容器云平臺的CLI將應用程序的容器鏡像部署在集群當中,或是對已經部署在集群上的服務進行下線操作。依據抽象分離的原則,云平臺應成為一個黑盒(black box),能夠在平臺內部自行完成應用的部署或下線,無需開發者了解部署與下線過程的細節,從而降低開發者的成本。
在服務的部署過程中,對于無需與外部應用或設備進行通信的應用(通常為安全層服務),列控系統測試容器云平臺能夠通過Kubernetes的DNS發現服務使之能夠與其集群內部的上下層服務進行通信[4];對于需要與外部設備或應用通信的應用(應用層、通信層或其他負責監控與維護穩定性的服務),云平臺允許開發者在CLI中指定服務所需要使用網絡地址,使用Kubernetes提供的Service或Ingress機制將服務暴露在所指定的網絡地址之上[5]。
在對鐵路信號設備的測試中,通信過程往往需要建立在不同的物理信道上,如運行在以太網上的TCP/UDP通信、串口通信、控制器局域網絡(CAN)通信或使用特殊的通信網卡來模擬特定的網絡環境,如GSM-R、LTE-R等[6]。不同的物理信道要求需要列控系統測試容器云平臺中具有具備各類通信硬件條件的計算機節點,因此Kubernetes集群在建立時需要為具備不同硬件設備的節點做出特定的標識(label)。在通過CLI部署通信層服務時,需要指定所需要部署在其上的節點應具有的硬件資源種類,Kubernetes的節點選擇控制器便能夠按照開發者要求將通信層服務調度到最佳的符合要求的節點上。
(b)測試自動化。
在列控系統的測試任務中,通常需要通過對多種服務的若干實例進行組合實現對多種仿真對象的模擬,從而能夠依照測試大綱中的測試用例對被測對象進行測試。以CTCS-3級的RBC測試為例(見圖3),為了對RBC對象進行測試,需要實現CBI、TSRS、相鄰RBC以及車載ATP設備的仿真對象[7]。這四類對象的應用層各不相同,安全層均依賴RSSP_II通信協議,而在通信功能層面又存在通信協議與通信物理接口的差異。

圖3 CTCS-3級列控系統RBC測試平臺架構
在列控系統測試容器云平臺中,通過對各層級服務的組合,能夠快速實現仿真對象的實現,提升了代碼的利用率,從而提升了測試工作的效率。
為了對真實運行環境中可能出現的變化進行仿真,需要不同的仿真對象進行有序的協同操作。測試用例是對多種仿真對象有序行為以及被測對象的預期行為的描述。每個測試用例的流程均可表達為一個有向無環圖(DAG),這個有向無環圖是全連通的,具有樹的性質,從根節點出發能夠訪問到圖的全部節點。描述各個測試用例的樹能夠構成一個森林,具有時序關系的樹之間具有父子關系。測試任務從樹林的根處開始,并行執行不具備時序關系的測試用例,在執行每個測試用例時,對描述任務的圖進行深度優先搜索,當圖的每條邊均被訪問時,測試用例即執行完畢。全部的測試用例執行完畢后,測試過程即完成執行。在傳統的測試過程中,由于各仿真對象均為集中式的獨立應用程序,難以通過計算機指令協同調度各應用程序。因此測試人員需要依照測試用例的指示,手動對仿真對象下達相應的命令。這一過程繁瑣且容易出錯。為了提高測試的自動化程度,列控系統測試容器云平臺需要提供一種用于描述測試案例中有向無環圖的領域專用語言(DSL)[8]。這一領域專用語言能夠將測試案例描述為計算機可識別的過程,同時能夠對各個測試案例進行優化,依照測試的相關需求對它們的執行順序進行調整,使得整個測試的速度與效率得到提高[9]。通過計算機將從測試大綱轉寫而來的DSL腳本與各仿真對象的應用層服務分別作為容器部署在同一個Kubernetes Pod中,共享相同的Linux Namespace,腳本與各服務即可在云端協同運作[10]。執行該腳本,腳本即可依照測試大綱的要求通過進程間通信(IPC)向各應用層服務順序下達命令并接收反饋,從而實現對各仿真對象的協調。
容器云平臺的自動化測試流程如圖4所示。

圖4 容器云平臺的自動化測試流程
隨著列控系統測試場景的范圍不斷擴大,在一些測試任務中,需要通過較多的測試案例來對列控系統的真實運行場景進行仿真,在一些測試場景中還需要對一些測試數據進行改變以充分模擬可能的運行狀況,僅通過真實的測試數據與測試場景進行測試已不能滿足測試的需要。因此,列控系統測試容器云平臺中還需要具備通用測試案例與測試數據的自動生成的功能,能夠通過對測試場景的建模,使用啟發式或半啟發式的算法根據數據的不同特征生成所需的測試案例[11]。同時,近年來機器學習技術在自動化測試領域中的應用與研究不斷深入,能夠為測試提供更充分的、覆蓋范圍更加完備的數據[12]。列控系統測試容器云平臺也應將人工智能技術引入列控系統的測試過程中,進一步提升列控系統測試的效率與自動化程度。
(c)服務的可靠性保障。
在一個完整的測試任務中需要測試平臺中的各個服務之間協同配合。在列控系統測試過程中,通信層為仿真對象提供與外部被測對象交互信息的接口,通常是無狀態的。安全層服務按照其中安全協議中是否規定了上下文關系,可以是有狀態或無狀態的。而應用層服務通常用來執行仿真對象的業務邏輯,是有狀態服務。通信層服務作為整個測試平臺最基礎的服務,同一類服務在同時可能需要支持多個測試任務同時進行。在多個任務同時執行的場景下,為了滿足測試任務的實時性以及可靠性要求,就需要對熱點通信層服務進行動態擴容,在集群中部署多個服務實例。而在少量任務同時執行的場景下,過多的通信層服務實例會占用集群較多的計算資源,此時需要平臺自動對服務進行縮容。借助通信層服務的無狀態特性與Kubernetes提供的彈性伸縮機制[13],平臺運維人員既能夠在發現通信層服務縮擴容需求時,手動調整服務實例個數,也能夠在集群層面指定自動動態伸縮策略,委托Kubernetes的控制平面代為執行。
為了維護列車信號系統的可靠性,現行的絕大多數鐵路信號協議均應用了冗余技術,在安全層或通信層上使用多機冗余,同時維護一個主系通信信道與多個備系通信信道的正常運行,一旦發生故障,可以立即進行主備系切換,保證鐵路信號設備之間的通信穩定。而在列控系統測試容器云平臺中,應用層服務與部分安全層服務作為有狀態服務,一旦出現故障,難以僅通過替換服務的方式進行恢復。同時,云平臺中還可能存在分布式入侵、系統配置錯誤與網絡故障等可能性[14],因此,列控系統測試容器云平臺需要具備一定的故障恢復能力。列控系統測試容器云平臺能夠通過Kubernetes的持久化儲存機制,將服務的狀態實時保存在節點當中,當某一服務發生故障需要進行恢復時,平臺能夠自動部署新的服務實例,這一實例能夠讀取之前實例故障前的狀態,并將其作為依據對自身狀態進行設置,從而使得云平臺中的應用實例具有了一定的冗余備份能力。進一步提升測試平臺的可靠性。
(d)平臺故障監控與告警。
當前國內外已經提出了多種成熟的云平臺監控方案[15],通過與Kubernetes的API Server交互獲取平臺中各節點的性能指標,并通過各節點上的Kubelet提供的監控接口獲取節點上的容器監控信息。監控平臺獲取到的信息均會被儲存在數據庫中,平臺提供一個對外的圖形化界面,用戶可通過圖形化界面操作監控平臺,生成并查看所需的監控報告。
對于列控系統測試容器云平臺,除計算資源與儲存資源容量過低可能發生的故障外,還包括通信層服務所依賴的通信硬件資源的故障、安全層或應用層服務運行過程中未預期到的潛在故障等。故障監控平臺在監測到常規故障發生的可能性(如計算、儲存資源即將耗盡或某個服務的容器長期異常無法自動恢復等)后,會在平臺提供的可視化界面上進行告警,等待平臺運維人員檢查處理。當故障發生后,監控平臺會暫停故障涉及到的測試任務的運行,并且通過告警機制告知相關運維人員故障的相關信息,包括故障點的位置、故障現象以及可能的解決方案等。運維人員在結合監控平臺的日志信息與現場情況對故障進行排查與修復后,能夠根據故障的嚴重程度命令尚未完成的受影響的相關任務繼續或重新進行。
通過對列控系統測試軟件的各部分進行解耦合,將列控系統測試的各個功能拆封為不同層次的服務后,對邏輯復雜的安全層與涉及硬件層面的通信層服務的開發可以由較為專業的開發者完成,這些服務一旦開發部署完成,就能夠保持穩定,為應用層服務提供支持。開發者在絕大多數只需要進行不同測試任務中所需的仿真對象(應用層與可視化界面)的開發,從而簡化了列控系統測試軟件的研發與部署流程。
在進行通信層服務的開發時,開發者首先需要查詢集群中是否具有具備服務所需的硬件條件,且相關的計算、存儲與網絡資源滿足條件的工作節點。若當前集群中尚不具備上述節點,那么需要向集群中添加新的滿足條件的工作節點,或者在現有的工作節點機器上加裝所需的硬件。服務應用開發完成后,開發者需將服務打包為Docker鏡像,并提供Kubernetes部署服務所需的模板文件。模板文件中應該允許服務使用宿主工作節點的網絡資源,同時允許對服務與其上層服務的內部通信接口以及服務與被測對象之間的外部通信接口進行配置。
在安全層服務的開發過程中需要針對不同的鐵路信號安全協議進行實現。由于安全層服務的有狀態特性,安全層服務除安全相關業務本身的Docker鏡像外,還需一個用于實時記錄服務運行過程中各個狀態的Docker鏡像。這兩個鏡像容器將運行在同一個Kubernetes Pod中。在安全層服務部署所需的模板文件中,除了可配置服務與其上下層服務的內部通信接口外,還需要對持久化儲存的聲明,要求Kubernetes集群提供一定大小的持久化儲存空間,這一空間能夠被該Kubernetes Pod中的全部容器共享,從而使安全層服務主容器能夠將相關狀態信息共享至用于記錄的容器。
應用層服務是對通信對象的仿真。作為測試任務中的邏輯實體,各個應用層服務應具備相互通信的接口、與外部可視化界面進行通信的接口、與日志服務通信的接口以及與自動化測試腳本之間的通信接口。在一次測試任務中,往往需要同時對多個通信對象進行仿真,因此對應用層服務的部署通常是對應用層服務組的部署。這個服務組中除了包含各個應用層服務的Docker鏡像外,還需要一個具備日志記錄功能的Docker鏡像。為此,應用層服務組的部署也要求Kubernetes集群提供一定大小的用于存放日志的持久化儲存空間。此外,測試任務中如果存在進行自動化測試的需求,開發人員還需要編寫相應的DSL腳本,并將其打包為一個Docker鏡像加入應用層服務組之中。日志鏡像與自動化測試鏡像也需要具備與外部可視化程序進行通信的接口。上述鏡像均應作為容器部署在同一個Kubernetes Pod中。在部署應用層服務所需的模板文件中,需要能夠對服務與其下層服務的內部通信接口、服務與可視化界面通信的外部接口以及服務組中應用之間相互通信的接口進行配置。同時,對于每一個應用層服務,文件中均應能夠制定該服務所需的安全層與通信層服務。列控系統測試容器云平臺整體的開發與部署流程如圖5所示。

圖5 列控系統測試容器云平臺的研發部署流程
在列控系統信號設備的測試任務中,測試人員首先需要依照上述部署流程,選擇相應所需的鏡像對各層服務進行部署。通過Kubernetes的就緒探針(readiness probe)機制能夠觀察各服務的就緒情況。在各層服務啟動完畢后,測試人員即可在集群外部啟動可視化界面,與各應用層服務、日志服務與自動化測試服務進行連接。若測試任務具備自動化條件,測試人員可通過圖形化界面執行自動化腳本;反之,測試人員需通過手動操作圖形化界面依照測試大綱完成測試。在測試完成后,測試人員能夠通過圖形化界面獲取測試結果的日志,并根據日志進行分析,完成測試任務。列控系統測試容器云平臺上的測試任務流程如圖6所示。

圖6 列控系統測試容器云平臺上的測試任務流程
列控系統測試容器云平臺將列控系統測試軟件的功能拆分為若干微服務,結合了Docker容器技術以及Kubernetes的容器編排能力,相比于傳統的列控系統計算機測試方案,在開發效率、可靠性、自動化程度等方面均有較大幅度提升。列控系統測試容器云平臺與傳統方案的性能對比如表1所示。

表1 列控系統測試容器云平臺與傳統測試方案的性能指標對比
該文提出了一種基于Docker與Kubernetes集群的列控系統測試云平臺,將列控系統測試軟件的各類功能作為服務打包為Docker鏡像,并在Kubernetes集群中部署,通過DSL編寫的自動化測試腳本與外部的可視化界面進行測試的方案。這一方案降低了列控系統測試中各個組件之間的耦合程度、提升了開發效率與自動化程度,同時也能夠更好地支持多個測試任務的同時進行,推動列控系統測試工作向著規模化與完全自動化的方向發展。