使用 Docker 和 Gitlab CI 進行開發和測試流程

我建議閱讀 Inventos 的 Alexander Sigachev 的報告“使用 Docker + Gitlab CI 進行開發和測試過程”的文字記錄

那些剛剛開始實施基於 Docker + Gitlab CI 的開發和測試流程的人經常會問一些基本的問題。 從哪裡開始? 如何組織? 如何測試?

這份報告很好,因為它以結構化的方式討論了使用 Docker 和 Gitlab CI 的開發和測試過程。 該報告本身是 2017 年的。 我認為從這個報告中你可以學到基礎知識、方法論、思想、使用體驗。

誰管,請貓下。

我的名字是亞歷山大·西加喬夫。 我在 Inventos 工作。 我給大家講一下我使用Docker的經歷以及我們是如何在公司的項目上逐步落地的。

演示主題:使用 Docker 和 Gitlab CI 的開發流程。

使用 Docker 和 Gitlab CI 進行開發和測試流程

這是我第二次談論 Docker。 在第一份報告發佈時,我們僅在開發人員計算機上使用 Docker 進行開發。 使用Docker的員工人數約為2-3人。 漸漸地,我們積累了經驗,又向前邁進了一步。 鏈接到我們的 第一份報告.

這份報告會包含哪些內容? 我們將分享我們收集了哪些耙子、解決了哪些問題的經驗。 並非所有地方都是美麗的,但允許繼續前進。

我們的座右銘是:對接我們能得到的一切。

使用 Docker 和 Gitlab CI 進行開發和測試流程

我們正在解決什麼問題?

當公司中有多個團隊時,程序員是共享資源。 在某些階段,程序員會退出一個項目,並在一段時間內投入到另一個項目中。

為了讓程序員能夠快速理解,他需要盡快下載項目的源代碼並啟動環境,這將讓他能夠進一步解決這個項目的問題。

通常,如果您從頭開始,那麼項目中的文檔很少。 有關如何設置的信息僅適用於老用戶。 員工在一兩天內自行搭建工作場所。 為了加快速度,我們使用了 Docker。

下一個原因是開發中設置的標準化。 根據我的經驗,開發人員總是採取主動。 每五個案例中都會輸入一個自定義域,例如 vasya.dev。 坐在他旁邊的是他的鄰居 Petya,其域名是 petya.dev。 他們使用該域名開發網站或系統的某些組件。

當系統增長並且這些域名開始進入配置時,會出現開發環境衝突並重寫站點路徑。

數據庫設置也會發生同樣的情況。 有人不關心安全性並使用空的 root 密碼。 在安裝階段,MySQL 要求某人輸入密碼,結果密碼是 123。經常發生數據庫配置根據開發人員的提交而不斷變化的情況。 有人更正,有人沒有更正配置。 當我們取出某種測試配置時,有一些技巧 .gitignore 每個開發人員都必須安裝數據庫。 這使得入門變得困難。 除其他事項外,有必要記住數據庫。 必須初始化數據庫、輸入密碼、註冊用戶、創建表等等。

另一個問題是庫的版本不同。 開發人員經常會處理不同的項目。 有一個五年前開始的遺留項目(從 2017 年開始 - 編者註)。 在發佈時,我們從 MySQL 5.5 開始。 還有一些現代項目,我們嘗試實現更現代版本的 MySQL,例如 5.7 或更早版本(2017 年 - 編者註)

任何使用 MySQL 的人都知道這些庫帶來了依賴關係。 兩個基地一起運行是相當有問題的。 至少,舊客戶端連接新數據庫是有問題的。 這反過來又產生了幾個問題。

下一個問題是,當開發人員在本地計算機上工作時,他使用本地資源、本地文件、本地 RAM。 開發問題解決方案時的所有交互都是在它在一台機器上運行的事實框架內進行的。 一個例子是,當我們在 Production 3 中有後端服務器時,開發人員將文件保存到根目錄,nginx 從那裡獲取文件來響應請求。 當這樣的代碼進入生產環境時,結果表明該文件存在於 3 台服務器之一上。

現在正在發展微服務的方向。 當我們將大型應用程序劃分為一些相互交互的小組件時。 這允許您為特定的任務堆棧選擇技術。 它還允許您在開發人員之間分擔工作和責任。

Frondend-developer,在JS上開發,對Backend幾乎沒有影響。 在我們的例子中,後端開發人員反過來開發 Ruby on Rails,並且不會干擾 Frondend。 交互是使用 API 執行的。

作為獎勵,在 Docker 的幫助下,我們能夠回收 Staging 上的資源。 每個項目由於其具體情況,都需要某些設置。 從物理上講,有必要分配一個虛擬服務器並單獨配置它們,或者共享某種可變環境,並且項目可能會相互影響,具體取決於庫的版本。

使用 Docker 和 Gitlab CI 進行開發和測試流程

工具。 我們用什麼?

  • Docker 本身。 Dockerfile 描述了單個應用程序的依賴關係。
  • Docker-compose 是一個捆綁包,匯集了我們的一些 Docker 應用程序。
  • 我們使用GitLab來存儲源代碼。
  • 我們使用 GitLab-CI 進行系統集成。

使用 Docker 和 Gitlab CI 進行開發和測試流程

報告由兩部分組成。

第一部分將討論 Docker 如何在開發人員的機器上運行。

第二部分將討論如何與 GitLab 交互、如何運行測試以及如何推出 Staging。

使用 Docker 和 Gitlab CI 進行開發和測試流程

Docker 是一種允許(使用聲明性方法)描述必要組件的技術。 這是一個 Dockerfile 示例。 這裡我們聲明我們繼承自官方的 Ruby:2.3.0 Docker 鏡像。 它包含已安裝的 Ruby 版本 2.3。 我們安裝所需的構建庫和 NodeJS。 我們描述我們創建一個目錄 /app。 將應用程序目錄設置為工作目錄。 在此目錄中,我們放置所需的最小 Gemfile 和 Gemfile.lock。 然後我們構建安裝此依賴項映像的項目。 我們指示容器將準備好偵聽外部端口 3000。最後一個命令是直接啟動我們的應用程序的命令。 如果我們執行項目啟動命令,應用程序將嘗試運行並運行指定的命令。

使用 Docker 和 Gitlab CI 進行開發和測試流程

這是 docker-compose 文件的最小示例。 在本例中,我們表明兩個容器之間存在連接。 這是直接進入數據庫服務和Web服務。 在大多數情況下,我們的 Web 應用程序需要某種數據庫作為存儲數據的後端。 由於我們使用的是 MySQL,所以示例是使用 MySQL - 但沒有什麼可以阻止我們使用其他數據庫(PostgreSQL、Redis)。

我們從 Docker hub 的官方來源獲取 MySQL 5.7.14 的鏡像,沒有進行任何更改。 我們從當前目錄收集負責我們的 Web 應用程序的圖像。 它在首次啟動期間為我們收集圖像。 然後它運行我們在這裡執行的命令。 如果我們返回,我們將看到通過 Puma 的啟動命令已被定義。 Puma 是一個用 Ruby 編寫的服務。 在第二種情況下,我們重寫。 根據我們的需要或任務,該命令可以是任意的。

我們還描述了我們需要將開發人員主機上的端口從容器端口上的 3000 轉發到 3000。 這是使用直接嵌入在 Docker 中的 iptables 及其機制自動完成的。

開發者還可以像以前一樣訪問任何可用的IP地址,例如127.0.0.1是機器的本地或外部IP地址。

最後一行表示 Web 容器依賴於 db 容器。 當我們調用web容器的啟動時,docker-compose會首先為我們啟動數據庫。 在數據庫啟動時(事實上,在容器啟動之後!這並不能保證數據庫的準備就緒)將啟動應用程序,即我們的後端。

這可以避免數據庫未啟動時出現錯誤,並在我們停止數據庫容器時節省資源,從而為其他項目釋放資源。

使用 Docker 和 Gitlab CI 進行開發和測試流程

是什麼讓我們在項目上使用數據庫dockerization。 我們為所有開發人員修復了 MySQL 的版本。 這可以避免當版本不同、語法、配置、默認設置更改時可能出現的一些錯誤。 這允許您指定數據庫的通用主機名、登錄名、密碼。 我們正在擺脫之前的配置文件中的名稱和衝突。

我們有機會為開發環境使用更優化的配置,這將不同於默認配置。 MySQL默認配置為弱機器,其開箱即用的性能非常差。

使用 Docker 和 Gitlab CI 進行開發和測試流程

Docker 允許您使用所需版本的 Python、Ruby、NodeJS、PHP 解釋器。 我們不再需要使用某種版本管理器。 以前,Ruby 使用 rpm 包,允許您根據項目更改版本。 借助 Docker 容器,它還允許順利遷移代碼並將其與依賴項一起進行版本控制。 我們可以毫無問題地理解解釋器和代碼的版本。 要更新版本,請降低舊容器併升高新容器。 如果出現問題,我們可以降低新容器,升高舊容器。

構建鏡像後,開發和生產中的容器將是相同的。 對於大型安裝尤其如此。

使用 Docker 和 Gitlab CI 進行開發和測試流程 在前端,我們使用 JavaScipt 和 NodeJS。

現在我們有了 ReacJS 上的最後一個項目。 開發人員在容器中運行所有內容並使用熱重載進行開發。

接下來啟動JavaScipt組裝任務,通過nginx節省資源給出編譯成靜態的代碼。

使用 Docker 和 Gitlab CI 進行開發和測試流程

這裡我給出了我們上一個項目的方案。

解決了哪些任務? 我們需要構建一個與移動設備交互的系統。 他們接收數據。 一種可能性是向該設備發送推送通知。

我們為此做了什麼?

我們將應用程序分為以下組件:JS 上的管理部分,後端,通過 Ruby on Rails 下的 REST 接口工作。 後端與數據庫交互。 生成的結果被提供給客戶端。 管理面板通過 REST 接口與後端和數據庫交互。

我們還需要發送推送通知。 在此之前,我們有一個項目實現了一種負責向移動平台傳遞通知的機制。

我們開發了以下方案:瀏覽器的操作員與管理面板交互,管理面板與後端交互,任務是發送推送通知。

推送通知與 NodeJS 中實現的另一個組件交互。

建立隊列,然後根據其機制發送通知。

這裡畫了兩個數據庫。 目前,在 Docker 的幫助下,我們使用 2 個獨立的數據庫,彼此之間沒有任何關係。 另外,他們有一個共同的虛擬網絡,物理數據存儲在開發者機器上的不同目錄中。

使用 Docker 和 Gitlab CI 進行開發和測試流程

相同,但數量不同。 這就是代碼重用很重要的地方。

如果之前我們討論過以庫的形式重用代碼,那麼在這個例子中,我們響應推送通知的服務被重用為一個完整的服務器。 它提供了一個API。 我們的新開發已經與之互動。

當時,我們使用的是 NodeJS 第 4 版。 現在(2017 年 - 編者註)在最近的開發中我們使用 NodeJS 版本 7。 新組件涉及新版本的庫是沒有問題的。

如有必要,您可以通過推送通知服務重構並提升 NodeJS 版本。

如果我們能夠保持 API 兼容性,那麼就有可能用以前使用的其他項目來替換它。

使用 Docker 和 Gitlab CI 進行開發和測試流程

Docker 需要添加什麼? 我們將 Dockerfile 添加到存儲庫,其中描述了必要的依賴項。 在此示例中,組件按邏輯進行了分解。 這是一個後端開發人員最起碼的一套。

創建新項目時,我們創建一個 Dockerfile,描述所需的生態系統(Python、Ruby、NodeJS)。 在docker-compose中,它描述了必要的依賴項——數據庫。 我們描述我們需要一個這樣那樣版本的數據庫,在那裡存儲數據。

我們使用帶有 nginx 的單獨的第三個容器來提供靜態服務。 可以上傳圖片。 後端將它們放在預先準備好的捲中,該卷也安裝在帶有 nginx 的容器中,這提供了靜態。

為了存儲 nginx、mysql 配置,我們添加了一個 Docker 文件夾,在其中存儲必要的配置。 當開發人員在他的計算機上對存儲庫進行 git 克隆時,他已經有了一個可供本地開發的項目。 毫無疑問要應用什麼端口或什麼設置。

使用 Docker 和 Gitlab CI 進行開發和測試流程

接下來,我們有幾個組件:管理、通知 API、推送通知。

為了開始這一切,我們創建了另一個存儲庫,我們將其稱為 dockerized-app。 目前我們在每個組件之前使用多個存儲庫。 它們只是邏輯上不同 - 在 GitLab 中它看起來像一個文件夾,但在開發人員的機器上,它是特定項目的文件夾。 下一層是將要組合的組件。

使用 Docker 和 Gitlab CI 進行開發和測試流程

這只是 dockerized-app 內容的示例。 我們還將 Docker 目錄引入此處,在其中填寫所有組件交互所需的配置。 有一個 README.md 簡要描述瞭如何運行該項目。

這裡我們應用了兩個 docker-compose 文件。 這樣做是為了能夠逐步運行。 當開發人員使用核心時,他不需要推送通知,他只需啟動一個 docker-compose 文件,相應地,資源就會被保存。

如果需要與推送通知集成,則啟動 docker-compose.yaml 和 docker-compose-push.yaml。

由於 docker-compose.yaml 和 docker-compose-push.yaml 位於一個文件夾中,因此會自動創建單個虛擬網絡。

使用 Docker 和 Gitlab CI 進行開發和測試流程

組件描述。 這是一個更高級的文件,負責組件的收集。 這裡有什麼值得注意的地方? 這裡我們介紹一下平衡器組件。

這是一個現成的 Docker 映像,運行 nginx 和偵聽 Docker 套接字的應用程序。 動態的,當容器打開和關閉時,它會重新生成 nginx 配置。 我們通過三級域名來分發組件的處理。

對於開發環境,我們使用 .dev 域 - api.informer.dev。 具有 .dev 域的應用程序可在開發人員的本地計算機上使用。

此外,配置會傳輸到每個項目,並且所有項目都會同時啟動。

使用 Docker 和 Gitlab CI 進行開發和測試流程

從圖形上看,客戶端是我們的瀏覽器或我們用來向平衡器發出請求的某種工具。

域名平衡器決定聯繫哪個容器。

可以是nginx,它提供了admin JS。 這個可以是nginx,它給出API,也可以是靜態文件,以圖片上傳的形式給nginx。

該圖顯示容器通過虛擬網絡連接並隱藏在代理後面。

在開發者的機器上,知道IP就可以訪問容器,但原則上我們不使用這個。 實際上不需要直接訪問。

使用 Docker 和 Gitlab CI 進行開發和測試流程

要查看哪個示例來對您的應用程序進行 docker 化? 在我看來,MySQL 的官方 docker 鏡像就是一個很好的例子。

這是相當具有挑戰性的。 有很多版本。 但它的功能可以讓您滿足進一步開發過程中可能出現的許多需求。 如果你花時間弄清楚它們是如何相互作用的,那麼我認為你在自我實現上不會有任何問題。

Hub.docker.com 通常包含 github.com 的鏈接,其中直接包含原始數據,您可以從中自行構建鏡像。

此外,在此存儲庫中還有一個 docker-endpoint.sh 腳本,該腳本負責初始初始化和應用程序啟動的進一步處理。

此外,在此示例中,還可以使用環境變量進行配置。 通過在運行單個容器時或通過 docker-compose 定義環境變量,我們可以說我們需要為 docker 設置一個空密碼以在 MySQL 上 root 或任何我們想要的東西。

有一個選項可以創建隨機密碼。 我們說我們需要一個用戶,我們需要給用戶設置一個密碼,我們需要創建一個數據庫。

在我們的項目中,我們稍微統一了Dockerfile,它負責初始化。 在那裡,我們根據需要對其進行了更正,使其成為應用程序使用的用戶權限的擴展。 這使我們稍後可以從應用程序控制台簡單地創建數據庫。 Ruby 應用程序具有用於創建、修改和刪除數據庫的命令。

使用 Docker 和 Gitlab CI 進行開發和測試流程

這是 github.com 上特定版本的 MySQL 的示例。 您可以打開 Dockerfile 並查看安裝情況。

docker-endpoint.sh 是負責入口點的腳本。 在初始初始化期間,需要一些準備步驟,所有這些操作都在初始化腳本中完成。

使用 Docker 和 Gitlab CI 進行開發和測試流程

讓我們繼續第二部分。

為了存儲源代碼,我們切換到了gitlab。 這是一個相當強大的系統,具有可視化界面。

Gitlab CI 是 Gitlab 的組件之一。 它允許您描述一系列命令,稍後將用於組織代碼交付系統或運行自動測試。

Gitlab CI 2 演講 https://goo.gl/uohKjI - 來自 Ruby Russia 俱樂部的報告 - 非常詳細,也許您會感興趣。

使用 Docker 和 Gitlab CI 進行開發和測試流程

現在我們將了解激活 Gitlab CI 需要什麼。 為了啟動 Gitlab CI,我們只需要將 .gitlab-ci.yml 文件放在項目的根目錄中。

在這裡,我們描述了我們想要執行一系列狀態,例如測試、部署。

我們執行直接調用 docker-compose 的腳本來構建我們的應用程序。 這只是一個後端示例。

接下來,我們說需要運行遷移來更改數據庫並運行測試。

如果腳本正確執行並且未返回錯誤代碼,則係統將繼續進行部署的第二階段。

部署階段目前已實施暫存。 我們沒有組織零停機重啟。

我們強行熄滅所有容器,然後再次升起所有容器,這些容器是在測試過程中第一階段收集的。

我們正在為當前環境變量運行開發人員編寫的數據庫遷移。

有一點需要注意的是,這僅適用於 master 分支。

當改變其他分支時不執行。

可以按分支機構組織推出。

使用 Docker 和 Gitlab CI 進行開發和測試流程

為了進一步組織這個,我們需要安裝 Gitlab Runner。

該實用程序是用 Golang 編寫的。 它是一個單個文件,這在 Golang 世界中很常見,不需要任何依賴項。

啟動時,我們註冊 Gitlab Runner。

我們在 Gitlab Web 界面中獲取密鑰。

然後我們在命令行調用初始化命令。

交互式設置 Gitlab Runner(Shell、Docker、VirtualBox、SSH)

Gitlab Runner 上的代碼將在每次提交時執行,具體取決於 .gitlab-ci.yml 設置。

使用 Docker 和 Gitlab CI 進行開發和測試流程

它在 Gitlab 的 Web 界面中的視覺效果如何。 連接 GItlab CI 後,我們有一個標誌顯示當前構建的狀態。

我們看到 4 分鐘前進行了一次提交,它通過了所有測試並且沒有造成任何問題。

使用 Docker 和 Gitlab CI 進行開發和測試流程

我們可以仔細看看構建。 這裡我們看到兩個狀態已經過去了。 測試狀態和臨時部署狀態。

如果我們單擊特定的構建,則會根據 .gitlab-ci.yml 輸出該進程中運行的命令的控制台輸出。

使用 Docker 和 Gitlab CI 進行開發和測試流程

這就是我們的產品歷史。 我們看到有一些成功的嘗試。 提交測試後,不會繼續進行下一步,並且暫存代碼不會更新。

使用 Docker 和 Gitlab CI 進行開發和測試流程

當我們實施 docker 時,我們在 staging 上解決了哪些任務? 我們的系統由組件組成,我們需要重新啟動,只是存儲庫中更新的部分組件,而不是整個系統。

為此,我們必須將所有內容粉碎到單獨的文件夾中。

完成此操作後,我們遇到了一個問題,Docker-compose 為每個爸爸創建了自己的網絡空間,並且看不到鄰居的組件。

為了解決這個問題,我們在 Docker 中手動創建了網絡。 它是用 Docker-compose 編寫的,您可以在這個項目中使用這樣的網絡。

因此,從此網格開始的每個組件都可以看到系統其他部分中的組件。

下一個問題是在多個項目中分割分期。

因為為了讓這一切看起來漂亮並且盡可能接近生產,最好使用端口 80 或 443,這在 WEB 中隨處可見。

使用 Docker 和 Gitlab CI 進行開發和測試流程

我們是如何解決的? 我們為所有主要項目分配了一名 Gitlab Runner。

Gitlab 允許您運行多個分佈式 Gitlab Runner,它將簡單地以混亂的方式依次接收所有任務並運行它們。

由於我們沒有房子,因此我們將項目組限制為一個 Gitlab Runner,它可以毫無問題地處理我們的工作量。

我們將 nginx-proxy 移至單獨的啟動腳本中,並為其中的所有項目添加了網格。

我們的項目有一個網格,平衡器按項目名稱有多個網格。 它可以通過域名進一步代理。

我們的請求通過端口 80 上的域發出,並解析到為該域提供服務的容器組中。

使用 Docker 和 Gitlab CI 進行開發和測試流程

還有哪些其他問題? 這就是所有容器默認以 root 身份運行的情況。 這與系統的根主機不同。

但是,如果你進入容器,它將是root,我們在這個容器中創建的文件將獲得root權限。

如果開發人員進入容器並在那裡發出一些生成文件的命令,然後離開容器,那麼他的工作目錄中有一個他無權訪問的文件。

怎麼解決呢? 您可以添加將在容器中的用戶。

添加用戶時出現了什麼問題?

在創建用戶時,我們常常沒有相同的組ID(UID)和用戶ID(GID)。

為了在容器中解決這個問題,我們使用ID為1000的用戶。

在我們的例子中,這與幾乎所有開發人員都使用 Ubuntu 操作系統的事實相吻合。 在 Ubuntu 上,第一個用戶的 ID 為 1000。

使用 Docker 和 Gitlab CI 進行開發和測試流程

我們有計劃嗎?

閱讀 Docker 文檔。 該項目正在積極開發,文檔正在更改。 兩三個月前收到的數據已經慢慢過時了。

我們解決的一些問題很可能已經通過標準方法解決了。

所以我想更進一步,直接進入編排。

一個例子是 Docker 的內置機制,稱為 Docker Swarm,它是開箱即用的。 我想在生產環境中運行一些基於 Docker Swarm 技術的東西。

生成容器使得處理日誌變得不方便。 現在日誌已被隔離。 它們分散在容器中。 任務之一是通過 Web 界面方便地訪問日誌。

使用 Docker 和 Gitlab CI 進行開發和測試流程

來源: www.habr.com

添加評論