MySQL是如何做容器測試的?

weixin_33858249發表於2018-09-27

傳統的基礎設施管理是一項手動任務,由系統管理員管理靜態伺服器。現代雲平臺的自動化能力改變了這種工作方式:基礎設施通常被描述為“程式碼”,基礎設施管理系統會對基礎設施自動做出變更。因此,基礎設施的變得更加動態,週轉時間也要短得多。

\\

基礎設施測試框架通常被用於驗證機器映象的狀態(Amazon Machine Images、Google Compute Images或Oracle OCI Images)。隨著容器基礎設施的出現,容器基礎設施的測試變得與機器映象的測試一樣重要。

\\

在MySQL,我們有很多基礎設施,我們越來越多地使用容器來代替真實(虛擬)機器。此外,越來越多的核心基礎設施執行在Oracle的雲基礎設施(OCI)上。這要求我們實現多個級別的自動化,並且可以利用基礎設施測試來驗證我們的伺服器(或虛擬機器、容器)的狀態。基礎設施測試還用於驗證我們釋出的一些工件的狀態。

\\

在這篇博文中,我們將重點介紹如何使用自動化基礎設施測試來驗證MySQL Server Docker映象。我們將比較三個可用於進行容器測試的框架,並給出示例程式碼。

\\

自動化基礎設施測試

\\

基礎設施測試用於測試基礎設施的狀態:Apache伺服器是否在監聽80埠?是否正確配置了DNS伺服器,這些設定是否正確反映在resolv.conf檔案中?要安裝的二進位制檔案是否都已經存在於機器映象中?

\\

這類測試可以作為bash指令碼的一部分,因此通常被用於配置任務,或者在(手動)建立例項後進行手動驗證。自動化基礎設施測試更進一步,它假設需要對很多基礎設施和指令碼的正確性做出驗證,以及動態的現代雲環境有很多東西需要通過手動的方式處理。

\\

基礎設施測試工具通常與Ansible、Puppet或Chef等配置工具結合使用。配置工具在機器上安裝軟體,測試框架則確保它們能夠正常執行。然後,任何東西都可以通過程式碼來表示,並使用工具進行自動化。

\\

我們的重點是測試Docker映象,對我們來說,這些工作有點偏向底層。由於我們所有的Docker映象主要是由經過測試併發布的yum軟體包層組成,這些層位於非常可靠的OS層之上,我們主要想要驗證軟體包的版本是否正確,以及這些二進位制檔案的功能是否正常。在映象構建期間,可能會發生網路故障,出現軟體包安裝不完整的情況,我們想要通過自動化測試來捕捉它們。

\\

在評估測試工具時,需要考慮到以下兩個方面的問題:

\\
  • 配置語言,即想要測試的內容(可用包、必要的檔案等)\\t
  • 測試執行,即如何執行測試(local/ssh/container)\

對於以下的工具,我們將關注這兩個方面的問題。這個領域最常見的工具包括:

\\
  • InSpec/Serverspec\\t
  • Goss\\t
  • Container Structure Test\

接下來,我們將逐個簡要介紹它們。

\\

InSpec

\\

InSpec基於RSpec(Ruby)測試框架,並借鑑了Serverspec(也是基於RSpec構建,並被廣泛採用)的經驗。它是Chef生態系統的一部分,用於配置和測試基礎設施。它的配置儲存在一個ruby檔案中。

\\

可以通過resources指定多種配置語言

\\

通過targets(local/ssh/docker)來測試執行

\\

Goss

\\

Goss是Serverspec的一個快速而簡單的替代品,是使用Go語言開發的一個伺服器測試和驗證框架。它的配置儲存在一個yaml檔案中,這個檔案可以很方便地從當前系統狀態生成。

\\

支援多種配置語言

\\

支援在本地和Docker容器中執行測試(通過dgoss指令碼)

\\

Container Structure Test

\\

Container Structure Test是一個用於驗證容器映象結構的框架。與Goss一樣,它也是用Go語言編寫,並使用了yaml配置檔案。該專案於今年早些時候釋出,它的應用範圍相對較窄(只支援容器),但它提供了足夠的功能來測試映象。

\\
  • 支援的配置語言較少\\t
  • 測試執行僅限於本地容器\

示例:MySQL Server Images

\\

接下來,我們將演示如何安裝所需工具,解釋各個配置檔案,並在本地執行測試。我們針對最新的MySQL Server容器(latest或8.0標籤)執行測試。為了方便起見,我們跳過構建步驟,從公共登錄檔下載容器並在本地執行測試。在我們的構建管道中,我們首先構建容器,執行測試,在執行成功之後才會推送到公共登錄檔。可以通過輸入以下命令來獲取最新版本的mysql-server映象:

\\
\docker pull mysql/mysql-server
\\

總的來說,我們想測試兩個東西:

\\
  • 容器是否存在主機上,幷包含正確的後設資料\\t
  • 容器是否包含所有的包和二進位制檔案\

先決條件

\\

除了可用的Docker環境之外,執行該示例還需要在本地安裝InSpec、Goss和Container Structure Test。

\\

InSpec的說明可以在這裡找到:https://downloads.chef.io/inspec。在Linux平臺上,可以通過執行以下命令安裝Goss和Container Structure Test二進位制檔案:

\\
\curl -L https://github.com/aelsabbahy/goss/releases/download/v0.3.6/goss-linux-amd64 -o goss \u0026amp;\u0026amp; chmod +x goss\curl -L https://raw.githubusercontent.com/aelsabbahy/goss/master/extras/dgoss/dgoss -o dgoss \u0026amp;\u0026amp; chmod +x dgoss\curl -L https://storage.googleapis.com/container-structure-test/latest/container-structure-test-linux-amd64 -o container-structure-test \u0026amp;\u0026amp; chmod +x container-structure-test
\\

安裝好所有二進位制檔案並將它們新增到系統路徑中,然後就可以通過shell指令碼執行測試。

\\

測試配置

\\

為了比較配置和測試執行過程的不同之處,我們提供了用於測試這三個框架的MySQL Server Docker映象的示例檔案:https://github.com/neumayer/mysql-server-image-tests

\\

可以通過以下命令來克隆它:

\\
\git clone https://github.com/neumayer/mysql-server-image-tests.git
\\

儲存庫中包含的配置檔案:

\\
  • mysql-server-inspec.rb\\t
  • goss.yaml\\t
  • mysql-server-container-structure-test.yml\

讓我們來依次檢視這些檔案,先從InSpec配置檔案開始:

\\
\control 'container' do                                                                                             \    impact 0.5                                                                                                       \    describe docker_container('mysql-server') do                                                                     \      it { should exist }                                                                                            \      it { should be_running }                                                                                       \      its('repo') { should eq 'mysql/mysql-server' }                                                                 \      its('ports') { should eq '3306/tcp, 33060/tcp' }                                                               \      its('command') { should match '/entrypoint.sh mysqld' }                                                        \    end                                                                                                              \  end                                                                                                                \  control 'server-package' do                                                                                        \    impact 0.5                                                                                                       \    describe package('mysql-community-server-minimal') do                                                            \      it { should be_installed }                                                                                     \      its ('version') { should match '8.0.12.*' }                                                                    \    end                                                                                                              \  end                                                                                                                \  control 'shell-package' do                                                                                         \    impact 0.5                                                                                                       \    describe package('mysql-shell') do                                                                               \      it { should be_installed }                                                                                     \      its ('version') { should match '8.0.12.*' }                                                                    \    end                                                                                                              \  end
\\

InSpec通過profile和control來組織測試用例,其中control是較小的單元,是與給定主題相關的一組測試。第一個control叫“container”,針對宿主機器執行,與執行在localhost上的Docker守護程式通訊,驗證容器是否正在執行。另外兩個control檢查容器內的包。這種區別很重要,因為後兩個control可以針對localhost、ssh主機或Docker容器執行。在我們的例子中,我們讓它們針對容器執行,這樣可以帶來非常好的可重用性和靈活性。雖然我們在示例中只使用了Docker和包資源,但實際上control可以使用任何現有的InSpec資源。

\\

下面是執行流程:

\\
  • 啟動容器\\t
  • 針對localhost執行 “container” control\\t
  • 針對容器執行剩餘的control\

指令碼看起來是這樣的:

\\
\docker run -d --name mysql-server mysql/mysql-server\inspec exec mysql-server-inspec.rb --controls container\inspec exec mysql-server-inspec.rb -t docker://mysql-server --controls server-package
\\

如果執行成功,InSpec將輸出以下內容:

\\
\Profile: tests from mysql-server-inspec.rb (tests from mysql-server-inspec.rb)\Version: (not specified)\Target:  local://\\  ✔  container: Docker Container mysql-server\     ✔  Docker Container mysql-server should exist\     ✔  Docker Container mysql-server should be running\     ✔  Docker Container mysql-server repo should eq \"mysql/mysql-server\"\     ✔  Docker Container mysql-server ports should eq \"3306/tcp, 33060/tcp\"\     ✔  Docker Container mysql-server command should match \"/entrypoint.sh mysqld\"\\\Profile Summary: 1 successful control, 0 control failures, 0 controls skipped\Test Summary: 5 successful, 0 failures, 0 skipped\\Profile: tests from mysql-server-inspec.rb (tests from mysql-server-inspec.rb)\Version: (not specified)\Target:  docker://d06da2588b80a4ee9b839b55c2f719ab9e860904eeb831b71488704f50f8b994\\  ✔  server-package: System Package mysql-community-server-minimal\     ✔  System Package mysql-community-server-minimal should be installed\     ✔  System Package mysql-community-server-minimal version should match \"8.0.12.*\"\\\Profile Summary: 1 successful control, 0 control failures, 0 controls skipped\Test Summary: 2 successful, 0 failures, 0 skipped
\\

Goss的配置檔案如下所示:

\\
\file:                                                                                                              \    /usr/sbin/mysqld:                                                                                                \      exists: true                                                                                                   \      contains: []                                                                                                   \  package:                                                                                                           \    mysql-community-server-minimal:                                                                                  \      installed: true                                                                                                \    mysql-shell:                                                                                                     \      installed: true                                                                                                \  port:                                                                                                              \    tcp6:3306:                                                                                                       \      listening: true                                                                                                \      ip: []                                                                                                         \    tcp6:33060:                                                                                                      \      listening: true                                                                                                \      ip: []                                                                                                         \  user:                                                                                                              \    mysql:                                                                                                           \      exists: true                                                                                                   \  process:                                                                                                           \    mysqld:                                                                                                          \      running: true
\\

除了mysqld檔案,我們還要檢查所需的軟體包是否已安裝、公開埠是否正確以及所需的程式是否在執行。Goss將為我們啟動容器:

\\
\GOSS_SLEEP=10 dgoss run -p 3306:3306 mysql/mysql-server
\\

因為設定了GOSS_SLEEP,所以我們的伺服器有足夠時間完成初始化,其餘引數被傳給docker run。輸出如下:

\\
\INFO: Starting docker container\INFO: Container ID: 75bc8869\INFO: Sleeping for 10\INFO: Running Tests\File: /usr/sbin/mysqld: exists: matches expectation: [true]\User: mysql: exists: matches expectation: [true]\Process: mysqld: running: matches expectation: [true]\Port: tcp6:33060: listening: matches expectation: [true]\Port: tcp6:33060: ip: matches expectation: [[]]\Port: tcp6:3306: listening: matches expectation: [true]\Port: tcp6:3306: ip: matches expectation: [[]]\Package: mysql-shell: installed: matches expectation: [true]\Package: mysql-community-server-minimal: installed: matches expectation: [true]\\Total Duration: 0.038s\Count: 9, Failed: 0, Skipped: 0\INFO: Deleting container
\\

Container Structure Test的yaml配置片段如下:

\\
\schemaVersion: \"2.0.0\"                                                                                             \  metadataTest:                                                                                                      \    exposedPorts: [ \"3306\

相關文章