利用 Jinja2 產生 gitlab-ci-yaml 並自動化 trigger pipeline
介紹如何透過 Jinja2 套件動態產生 gitlab-ci.yml 檔,並透過 gitlab-ci.yml 來自動化 trigger 下一個 pipeline。
Jinja2 是一種 python package 可以用來動態產生程式碼,僅需先寫好要產生內容的 template 檔,再透過 Jinja2 的 render() 方法來產生想要的內容。
為什麼我會需要動態產生 gitlab-ci.yml 檔?主因是 CD 過程需要分不同的環境佈署(ex: DEV/STAGING/PROD),我希望可以一次產生不同的環境的 gitlab-ci.yaml 檔案,讓使用者自行選擇要佈署的環境。
我知道,也許您會想到另一種方式,例如:
1 | variables: |
讓使用者在觸發 pipeline 的時候,自己再給值就好了。
確實上述的方式是我一開始的作法,但考量到未來環境愈來愈多或是 gitlab runner 有不同環境時,不斷地用 rules 去判斷並不是一個好的維讀方式。
因此,我需要 Jinja2 來幫助我完成這個需求。
舉例來說:準備 gitlab-ci.yaml 的 template 將基本的任務寫上,並將會動態切換的內容用 Jinja2 語法保留起來。
定義 template
1 | variables: |
template 定義要使用的 yaml 檔,並且在撰寫的時候要記得它是使用 python dict 的結構來進行(也可以想像成 json)並將需要依不同環境的地方保留下來,例如∶
- job name
- job script
- job tag
其中用了 {% for %}
迴圈,將 data.deploy_env
的每一項目依序渲染出來。
如何 redner 內容
有了 template 之後,我們需要定義 data 內容與要如何使用 Jinja2 python library 將需要的內容組合出來。
data 內容
1 | { |
嘗試把實際的 data 先寫成一份 json,然後在經過 python 把它讀進來。如果要動態產生這份 data 的結構也沒有問題的。
python code
1 | import jinja2 |
程式碼裡最重要的是先準備 jinja2.Environment()
再將寫好的 template 與 data 傳給它請它進行渲染。最後將渲染的結果寫到 output.yaml 如下的內容:
1 | variables: |
如何串接在 repo 的 gitlab-ci.yaml 讓產生的內容能被 trigger
從上述了解如何使用 Jinja2 動態產生一份 yaml 後,那我們嘗試將它串回到原有的 repo 的 gitlab-ci.yaml 裡。
舉例來說目前的 gitlab-ci.yaml 有以下的內容:
1 | stages: |
內容有負責利用 Jinja2 產生的 output.yaml,接著把 output.yaml 放入 artifacts 裡,提供給下一個 job 使用。
接著加入一個新的 job,並使用上一個 job 所建立的 output.yaml 來觸發 trigger pipeline:
1 | deploy-trigger: |
最後的結果就會產生如下的 pipeline 結果:
以上是分享如何使用 Jinja2 動態產生 yaml 最後再串接至既有的 gitlab-ci.yaml 之間的流程。
最後備註 Jinja2 的一些常用寫法。
基本語法介紹
{% %}
: 表示 Jinja2 的開始與結束,內容會被視為程式碼執行{{ }}
: 代表一個變數或字串{% %}
: 代表一段程式碼{% if %}
: 判斷式{% for %}
: 迴圈{% set %}
: 設定變數{% include %}
: 引入檔案{% extends %}
: 繼承{% block %}
: 覆蓋父模板的區塊{% macro %}
: 定義宏{% call %}
: 呼叫{% import %}
: 匯入模組{% from %}
: 從模組中引入變數{% with %}
: 設定變數{% set %}
: 設定變數
常用的 filter
{{ | safe }}
: 將 HTML 標籤轉換為安全的 HTML 標籤{{ | striptags }}
: 去除 HTML 標籤{{ | replace('a', 'b') }}
: 替換字串{{ | replace('a', 'b', count=n) }}
: 替換字串,限制 n 次{{ | int }}
: 轉換為整數{{ | float }}
: 轉換為浮點數{{ | trim }}
: 去除前後空白