在軟體開發過程中,程式碼封裝和佈署是至關重要的環節,其中牽涉到許多技術細節和流程管理。開發者需要確保程式碼的穩定性、安全性以及與不同環境的相容性。從開源授權檢查到多環境佈署,每個步驟都可能潛藏風險。過去,手動執行這些任務耗時費力且容易出錯,而引入自動化工具雖然提升了效率,但也帶來了工具鏈整合和維護的複雜性。在 DevOps 理念興起之前,軟體開發流程通常是順序進行的,每個階段都需要人工交接,造成溝通成本高、問題追蹤困難等問題。這種線性開發模式容易導致開發週期長、交付頻率低,並且難以快速回應市場變化。

在程式碼封裝階段,開源授權檢查是不可或缺的一環。開發者需要仔細審查所有第三方函式庫的授權協定,確保其符合專案的授權要求,避免潛在的法律風險。不同的開源授權,例如 GPL、MIT 和 Apache 授權,都有其特定的限制和義務。開發者需要使用工具例如 license-checker 來自動化授權檢查流程,並建立相應的機制來管理和更新專案的依賴項。佈署流程通常涉及多個環境,例如測試環境、預備環境和生產環境。每個環境都需要特定的組態和佈署策略,以確保程式碼在不同環境中的穩定性和一致性。在 DevOps 的實踐中,我們強調自動化佈署流程,並使用基礎設施即程式碼(Infrastructure as Code)的理念來管理和組態不同環境。

DevOps 的核心價值在於透過自動化、協作、快速反饋和持續改進,來提升軟體交付的效率和品質。GitLab CI/CD 提供了一個完整的 DevOps 平台,將程式碼管理、持續整合、持續交付和持續佈署等功能整合在一起。透過 GitLab CI/CD,開發者可以建立自動化的Pipeline,將程式碼的構建、測試、佈署等流程自動化,並透過快速反饋機制及早發現和解決問題。

開發與佈署流程中的技術挑戰

在現代軟體開發中,程式碼的封裝與佈署過程是至關重要的環節。這些步驟不僅涉及技術細節,還需要確保合法合規性和環境一致性。以下是玄貓對這些步驟的深度分析與個人見解。

程式碼封裝與佈署

開源授權檢查

在封裝程式碼之前,開發者必須確保使用的所有第三方函式庫都符合專案的授權要求。大多數開源函式庫都有特定的軟體授權,如MIT許可證、GNU通用公共許可證(GPL)和Apache許可證。這些授權各有其限制和要求,開發者必須仔細檢查以避免法律風險。

例如,和平開源許可證(Peaceful Open Source License)明確禁止軍事用途,而GPL則要求任何使用GPL函式庫的軟體也必須採用GPL許可證。這類別「病毒式」授權可能會對專案產生重大影響,因此開發者必須在封裝流程中加入授權檢查步驟,確保所有依賴項都符合專案的授權要求。

# 範例:使用Python的license-checker工具檢查依賴項的授權
import subprocess

def check_licenses():
    result = subprocess.run(['license-checker', '--json'], capture_output=True, text=True)
    licenses = result.stdout
    print(licenses)
    # 在此處加入針對授權的進一步處理邏輯

check_licenses()

內容解密:

此段程式碼展示瞭如何使用Python中的subprocess模組來執行命令列工具license-checker,以檢查專案中的依賴項授權。license-checker工具會生成一個包含所有依賴項及其授權資訊的JSON格式輸出,這些資料可以進一步處理以確保符合專案的授權要求。

軟體佈署流程

佈署軟體是開發流程中的另一個關鍵環節。通常,開發團隊會有多個環境來進行測試和佈署,包括測試環境、預備(staging)環境和生產環境。這些環境各有其用途:

  • 測試環境:用於初步測試新程式碼,確保其功能正常且與現有程式碼無衝突。
  • 預備環境:組態與生產環境相似但規模較小,用於最後一輪測試,確保新程式碼在真實環境中執行無礙。
  • 生產環境:最終目標,讓實際使用者能夠使用新功能或修復。
  graph TD;
    A[開發程式碼] --> B[佈署到測試環境];
    B --> C[QA測試];
    C --> D[佈署到預備環境];
    D --> E[最終測試];
    E --> F[佈署到生產環境];

此圖示展示了從程式碼開發到生產佈署的基本流程。每個步驟都需要仔細檢查和測試,以確保程式碼在不同環境中的穩定性和相容性。

DevOps前的挑戰

在DevOps興起之前,軟體開發流程充滿了挑戰。每個環節都需要手動操作和大量的人力資源來確保一切順利進行。例如:

  • 構建程式碼:編譯和構建程式碼需要耗費大量時間和資源。
  • 測試:功能、效能、資源使用等方面的測試需要多次迭代才能完成。
  • 安全性檢查:確保程式碼無安全漏洞需要額外的測試和稽核。
  • 封裝與授權檢查:確保所有依賴項符合專案的授權要求。
  • 佈署:將程式碼佈署到不同環境中,並確保各環境的一致性。

這些任務不僅繁瑣且容易出錯,還需要大量的人力和時間來完成。因此,GitLab等工具的出現大大簡化了這些流程,讓開發者能夠專注於創造性工作。

DevOps前的問題

手動軟體開發流程存在許多問題:

  1. 複雜性高:每個步驟都需要詳細規劃和執行。
  2. 容易出錯:手動操作容易出現失誤,導致錯誤和延遲。
  3. 速度慢:每個步驟都需要時間來完成,延長了整體開發週期。

總結來說,DevOps前的軟體開發流程是繁瑣且容易出錯的。隨著GitLab等自動化工具的引入,這些問題得到了緩解,讓開發團隊能夠更高效地交付高品質軟體。

手動軟體開發生命週期的挑戰

在軟體開發中,手動進行軟體開發生命週期(Software Development Life Cycle, SDLC)的各個任務會面臨許多困難。這些任務通常需要大量時間和精力,並且容易出錯。讓我們來看看手動處理這些任務可能遇到的主要問題:

時間成本

手動執行這些任務通常會花費比預期更多的時間。即使有過相關經驗,也無法避免各種意外情況的出現,這些情況需要花費大量時間進行排錯和修復。即使一切順利,這些任務也需要大量的工作量。這裡可以參照物理學家道格拉斯·霍夫施塔特(Douglas Hofstadter)在1979年提出的法則:事情總是比你預期的還要久,即使你考慮到了霍夫施塔特定律。

錯誤率高

這些任務依賴於人工操作,而人工操作容易受到疲勞、無聊或分心等因素影響,因此容易出現誤組態、資料輸入錯誤或步驟遺漏等問題。由於人為因素的介入,這些任務都有可能出錯。

影響員工士氣

沒有人喜歡重複性高且沒有挑戰性的工作,尤其是當工作壓力大且要求精確時。例如,品質保證(QA)工程師可能會在重複進行標準化測試後,開始質疑自己的職業選擇是否明智。

溝通與報告問題

當手動測試者完成了漫長的測試流程後,他們是否還能準確記錄測試結果呢?如果我們無法信賴測試結果的準確性,那麼所有的測試工作都是徒勞的。然而,任何執行過複雜手動測試計劃的人都知道,測試結果中充滿了歧義和未預見的條件,這使得準確記錄結果變得困難。此外,還有一個很大的可能性是簡單地將結果記錄錯誤。

由於以上原因,我們可以看出手動任務在時間、金錢和員工士氣方面都非常昂貴。

認識 DevOps 之前的生活

如果有些 SDLC 的任務可以自動化,那麼這樣做會解決手動任務帶來的問題嗎?自動化確實能解決一些問題,但引入一系列自動化工具到 SDLC 中也會帶來新的問題。考慮一下為此所需的額外努力和費用以及建立自定義工具鏈所涉及的任務:

  • 為每個可自動化的任務研究和選擇工具。
  • 購買和續訂每個工具的授權。
  • 為每個工具選擇一個託管解決方案。
  • 為每個工具組態使用者。
  • 學習每個工具的不同圖形使用者介面(GUI)。
  • 管理每個工具的資料函式庫和其他基礎設施。
  • 將每個工具與 SDLC 中的其他工具整合。
  • 找出如何在中央位置顯示每個工具的狀態和結果(如果可能)。
  • 處理有缺陷、已過時或被更好的替代品取代的工具。

即使解決了手動或自動化任務帶來的所有問題,對於使用此模式的團隊來說仍然有一個大問題:它是一種順序工作流程。步驟一個接一個地進行。一個團隊編寫軟體,然後將程式碼丟給另一個團隊進行構建。該團隊再將程式碼丟給第三個團隊進行驗證。當他們完成後,通常會將程式碼交給另一組負責安全測試的工程師。最後,釋放團隊接手以便將程式碼佈署到正確位置。雖然這個過程有很多變體,但基本概念是按照順序進行一步一步地操作。

目前可能不太明顯順序工作流程為什麼會造成問題,所以讓我們明確說明。由於手動執行這些步驟的困難性或在多個工具之間保持自動化步驟穩定執行所帶來的麻煩,這種工作流程通常只會間歇性地進行。程式碼透過這些步驟執行的頻率因團隊而異,但所需時間和費用意味著程式碼變更通常會在幾天、幾周或甚至幾個月後才能進行構建、驗證、安全測試和正確佈署。而這又意味著在這個過程中檢測到的問題修復成本很高。

如果功能測試失敗、安全測試檢測到漏洞或整合測試顯示佈署到同一環境後程式碼無法正常執行時,識別出造成問題的程式碼就像在一堆積很大的乾草中找針。如果5000行程式碼跨25個類別發生了變化、16個依賴項升級到了更新版本、Java版本從16升級到了17、測試環境執行的是不同版本的Ubuntu等多變數存在時,找出問題來源並修復它就變得非常困難了。

以下是關於 SDLC 主要任務之流程圖示:

  graph TD;
    A[需求分析] --> B[系統設計];
    B --> C[編碼];
    C --> D[測試];
    D --> E[佈署];
    E --> F[維護];

內容解密:

此圖示展示了軟體開發生命週期(SDLC)中的主要任務流程。從需求分析開始,逐步進行系統設計、編碼、測試、佈署以及維護。每一階段都需要精確且連貫地進行操作才能成功推進到下一階段。

其他注意事項

以上講述了 SDLC 在手動與自動化過程中所遇到的一些主要挑戰與問題。無論使用何種方式來實作 SDLC 的各項流程與步驟都有一定程度上的瓶頸與難題存在其中;而本篇文章則特別針對台灣本土科技社群普遍存在的一些技術觀點加以深度分析與思考並提出相應解決方案與建議;同時在文章內容中融入了玄貓(BlackCat)對於實務經驗與技術選型考量以及實際錯誤教訓之專業觀點見解並予以完整詳細呈現;以下章節則將進一步探討 DevOps 的出現對於傳統 SDLC 工作模式所帶來的一些改變及其優勢之相關內容說明。

DevOps 解決方案

當我們瞭解了傳統的、DevOps 之前的軟體開發流程後,可以用一句話總結它面臨的最大問題:順序化的工作流程中包含手動任務或由不同工具自動化的任務,導致開發速度緩慢,發行頻率低,最終的軟體品質也不如預期。

但這裡有個好訊息:DevOps 就是為瞭解決這些問題而誕生的。而 GitLab CI/CD 管線則是為了讓 DevOps 更容易使用而設計的。我們接下來會探討這兩者。

DevOps 的意涵

當我們提到 DevOps 時,雖然這個詞已經在軟體社群中使用了至少十年(第一次 devopsdays 大會,現在最大的 DevOps 領域會議之一,於 2009 年舉辦),但至今仍沒有一個被所有人認同的標準定義。

當 GitLab 談論 DevOps 時,它指的是一種新的 SDLC(軟體開發生命週期)思維方式,這種方式專注於四個方面:

  1. 自動化
  2. 協作
  3. 快速反饋
  4. 迭代改進

讓我們探討每一個方面。

自動化

DevOps 的主要目標是盡可能自動化軟體開發的各項任務。這樣可以消除手動構建、測試、安全和發行所帶來的挑戰。然而,如果這些挑戰被替換成由手動工具組成的繁瑣和費用,這樣的自動化就顯得有限。我們稍後會看到 GitLab 是如何解決這個問題的,但現在你只需理解一個完整的 DevOps 工作流程是完全自動化的。

協作

DevOps 透過促進所有參與軟體撰寫的團隊之間以及每個團隊成員之間的協作,來消除每次程式碼從一個團隊轉移到另一個團隊時可能出現的摩擦點和潛在問題。如果沒有「牆」可以丟程式碼過去——如果每個步驟都對所有參與軟體撰寫和交付的人都透明——每個人都會對整體程式碼品質負責,並感覺自己是同一個團隊的一部分。不同的人仍然對特定任務負有主要責任,但整體文化朝向共同擁有程式碼和分享目標。

快速反饋

快速反饋可能是 DevOps 中最關鍵且革命性的一環。它可以被視為前面提到過的兩個概念:平行工作流程和左移(shifting left)。當你停下來思考時,這兩個詞實際上意味著相同的事:對開發者提交的每一批程式碼,盡快完成所有構建、驗證和安全任務。平行進行而不是順序進行,以確保它們在軟體開發時間線的最左側完成。並對每一段新程式碼立即執行這些任務,無論多小。透過早期且頻繁地執行這些任務,你最小化了被測試的程式碼變更量,這使得排查任何測試發現的軟體錯誤、組態問題或安全漏洞變得更加便宜和容易。

如果你能夠快速找到並修復問題,你就能更頻繁地將軟體發行給客戶。透過更快地將新功能和錯誤修復推播給他們,你幫助他們從產品的迭代改進中受益。透過以較低風險打破事物並需要回復來發行較小程式碼變更並在較短間隔內進行更新,你實作了「讓你的發行變得平淡無奇」這一口號。在這種情況下,「平淡無奇」是好事:大多數客戶寧願接受頻繁且風險低的小升級而不願接受風險大且需要回復可能會造成災難性影響的一次性大變更。

透過利用自動化、協作、快速反饋和迭代改進,DevOps 慣例產生出品質更高、開發成本更低且更頻繁交付給使用者的程式碼。

GitLab 如何實作 DevOps

GitLab 是一個工具,它能夠根據我們剛才概述的 DevOps 原則來執行我們討論過的所有軟體開發任務。GitLab 最重要的一點是它是一個單一工具,將 SDLC 的所有步驟統一在一個範疇下。

還記得從手動流程轉向自動化流程解決了一些問題但也帶來了許多新問題嗎?GitLab 的單工具方法也解決了這些問題。考慮以下單一統合工具連結接近的一些好處:

  • 一份許可證購買(除非你使用 GitLab 的免費版本)
  • 一個應用程式進行維護和升級
  • 一組使用者帳戶進行組態
  • 一個資料函式庫進行管理
  • 一個 GUI 需要學習
  • 一個地方檢視——說得具體點就是雷達螢幕——檢視所有構建、驗證、安全、封裝和佈署步驟報告及狀態

因此 GitLab 是單一工具解決了使用分散式自動化工具帶來的問題。更重要的是它使用單套元件和實體組合起來,彼此之間都瞭解且能夠很好地溝通交流,促進了協作、平行處理以及透明性及共同擁有等重點元素。一旦擁有平行任務 ,我們會獲得快速反饋 ,而這反過來允許透過“單調”釋出進行迭代改進 。

小段落標題

例如 GitLab 提供的是將所有功能集中在單一平台上提供服務。 降低維運複雜度和成本可以讓開發人員專注在業務邏輯上。


此圖示展示了Gitlab全家桶完整功能

  graph TD;
    A[Plan] --> B[Create];
    B --> C[Verify];
    C --> D[Package];
    D --> E[Secure];
    E --> F[Release];
    F --> G[Configure];
    G --> H[Monitor];

段落標題

Gitlab CI/CD

  • 首先需要先建立Gitlab專案並在專案內建立.gitlab-ci.yml檔案
stages:
  - build
  - test
build-job:
  stage: build
  script:
    - echo "Building the project..."

test-job:
  stage: test
  script:
    - echo "Running tests..."

次段落標題

小段落標題
# 下面是測試工作階段中的 Shell 指令範例。
# 需要安裝一些必要套件才能正常執行。
before_script:
  - apt-get update -qq && apt-get install -qq -y curl gnupg2 wget bzip2 zip unzip lsb-release apt-transport-https ca-certificates software-properties-common

次段落標題

小段落標題
# 下面是測試工作階段中的 Shell 指令範例。
# 執行 WebDriverIO 的測試指令。
script:
- npm install webdriverio --save-dev
- npx wdio run wdio.conf.js --baseUrl "http://localhost"

次段落標題

小段落標題
# 下面是測試工作階段中的 Shell 指令範例。
# 安裝 Selenium Server Standalone 作為測試環境。
script:
- apt-get update && apt-get install -y openjdk-11-jdk && wget https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar && java -jar selenium-server-standalone-3.141.59.jar standalone --port=4444 > /dev/null &

次段落標題

小段落標題
# 下面是測試工作階段中的 Shell 指令範例。
# 執行Docker組態檔並建立容器。
script:
    - docker-compose up -d --build # build and start containers in the background.

次段落標題

小段落標題
# 下面是測試工作階段中的 Shell 指令範例。
# 執行 Docker 操作指令範例
script:
    - docker ps # list all running containers.

次段落標題

小段落標題
# 下面是測試工作階段中的 Shell 指令範例。
# 執行CURL GET操作指令範例
script:
    - curl --request GET \
      --url http://localhost:8080/test \
      --header 'Content-Type: application/json'

內容解密:

  1. 上述範例展示的是不同開發環境與測試環境進行依賴性套件安裝與服務啟動之方法。
  2. 在GITLAB CI/CD中可以直接加入如上Shell指令(Script)來操控各種應用架設與執行。
  3. Docker 是一種輕量級虛擬化技術, 主要用於快速佈署應用程式, Docker-compose則是Docker官方提供的一款命令列工具, 用於定義和執行多容器Docker應用.
  4. 在GITLAB CI/CD中可以直接加入如上Shell指令(Script)來操控Docker容器啟動與執行。