在 CI/CD 的世界裡,有一條黃金法則:一次編譯,到處部署。本篇將介紹 MyDeploy.jenkinsfile 的前半段實作,重點在於如何將原始碼轉化為「Immutable Artifacts」,並動態注入各環境所需的設定值。
為什麼不直接將 appsettings.json 寫死在專案中?
我們的策略是:在專案中保留一份 appsettings.template.json,敏感欄位使用佔位符(如 {{DB_PASSWORD}})。部署時,由一個輕量級腳本從 Vault 抓取數值並替換。
我們使用 Python 結合 Jinja2 模板引擎來實作。這能確保 JSON 格式在替換過程中保持正確。
# scripts/render_config.py (核心邏輯精簡版)
import jinja2
import argparse
import hvac # HashiCorp Vault Client
def render(template_path, output_path, env_name, vault_addr, token):
# 1. 初始化 Vault 用戶端
client = hvac.Client(url=vault_addr, token=token)
# 2. 從 Vault 抓取該環境的秘密資訊
# 假設路徑格式為: secret/data/app/config/<env_name>
secret_response = client.secrets.kv.v2.read_secret_version(
path='app/config', mount_point=env_name
)
secrets = secret_response['data']['data']
# 3. 載入模板並渲染
with open(template_path, 'r') as f:
template = jinja2.Template(f.read())
rendered_content = template.render(secrets)
# 4. 產出最終設定檔
with open(output_path, 'w') as f:
f.write(rendered_content)
if __name__ == "__main__":
# 解析參數: --template, --output, --env ...
# 執行 render()
pass
@Library('common-pipeline-library') _
pipeline {
agent { label 'dotnet' }
parameters {
string(name: 'PROJECT_ID', defaultValue: 'user-service')
choice(name: 'DEPLOY_ENV', choices: ['Test', 'Prod'], description: '部署目標環境')
}
stages {
stage('Render Configuration') {
steps {
script {
// 從 Vault 取得 Token 並執行渲染
withVault(configuration: vaultConfig, secrets: vaultSecrets) {
sh "python scripts/render_config.py --template appsettings.template.json --output appsettings.json --env ${params.DEPLOY_ENV}"
}
}
}
}
stage('Build & Publish') {
steps {
// 產出執行所需的所有依賴檔案
sh "dotnet publish -c Release -o ./publish"
}
}
stage('Archive Artifacts') {
steps {
script {
def timestamp = new Date().format("yyyyMMdd-HHmm")
env.ZIP_NAME = "${params.PROJECT_ID}-${timestamp}.zip"
// 打包 publish 目錄,包含剛才渲染好的配置
sh "zip -r ${env.ZIP_NAME} ./publish"
// 產生部署元數據 (Metadata),供目標主機讀取
def deployParams = """{
"AppName": "${params.PROJECT_ID}",
"ZipFileName": "${env.ZIP_NAME}",
"TargetEnv": "${params.DEPLOY_ENV}"
}"""
writeFile file: 'deploy_params.json', text: deployParams
}
}
}
}
}
今天我們完成了「建置」與「配置渲染」。我們現在手上有一份包含環境配置的 Zip 壓縮檔。明天,我們將實作後半段:如何跨越網路邊界,將產出物送達 Windows 伺服器並自動安裝。