PowerShell 技能连载 - Kubernetes Helm 包管理

适用于 PowerShell 7.0 及以上版本,需要 kubectl 和 helm CLI

背景

Helm 是 Kubernetes 生态中最主流的包管理工具,被誉为 “Kubernetes 的 apt/yum”。它通过 Chart 模板将复杂的应用部署抽象为一组可版本化、可复用的配置文件,极大降低了 Kubernetes 应用的分发和运维门槛。在实际的 DevOps 工作流中,团队往往需要同时管理数十个 Chart 仓库、多套环境配置以及频繁的版本升级与回滚。

PowerShell 凭借强大的对象管道和丰富的字符串处理能力,非常适合用来编排 Helm 工作流。相比 Bash 脚本,PowerShell 能够将 helm 和 kubectl 的输出直接转化为结构化对象,便于筛选、比较和批量操作。本文将围绕 Chart 仓库管理、Values 文件动态生成和批量部署回滚三个场景,展示如何用 PowerShell 打造高效的 Helm 自动化工具链。

Chart 仓库与版本管理

在生产环境中,团队通常会订阅多个 Helm 仓库(如 Bitnami、官方稳定仓库、企业私有仓库等),并且需要追踪 Chart 版本的变化。下面的脚本展示了如何用 PowerShell 统一管理仓库、搜索 Chart 并对比版本差异:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 定义仓库列表
$repos = @(
@{ Name = 'bitnami'; Url = 'https://charts.bitnami.com/bitnami' }
@{ Name = 'ingress-nginx'; Url = 'https://kubernetes.github.io/ingress-nginx' }
@{ Name = 'jetstack'; Url = 'https://charts.jetstack.io' }
)

# 批量添加并更新仓库
foreach ($repo in $repos) {
helm repo add $repo.Name $repo.Url 2>$null
Write-Host "已添加仓库: $($repo.Name)" -ForegroundColor Green
}

helm repo update

# 搜索指定关键词的 Chart,并按版本排序
$searchKeyword = 'nginx'
$charts = helm search repo $searchKeyword --output json |
ConvertFrom-Json

$charts |
Select-Object name, @{N='version';E={ $_.chart_version }}, app_version, description |
Sort-Object name |
Format-Table -AutoSize

# 对比已安装版本与仓库最新版本
$releases = helm list --all-namespaces --output json | ConvertFrom-Json

foreach ($rel in $releases) {
$chartName = $rel.chart -replace '-\d+.*$', ''
$installed = $rel.chart_version
$latest = (helm search repo $chartName --output json |
ConvertFrom-Json |
Select-Object -First 1).chart_version

$status = if ($installed -eq $latest) { '已是最新' } else { "可升级: $installed -> $latest" }
Write-Host ("[{0}] {1} ({2}): {3}" -f $rel.namespace, $rel.name, $chartName, $status)
}

# 更新 Chart 依赖(针对本地 Chart)
$localChartPath = './charts/my-application'
if (Test-Path "$localChartPath/Chart.yaml") {
helm dependency update $localChartPath
Write-Host "依赖已更新: $localChartPath" -ForegroundColor Cyan
}

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
已添加仓库: bitnami
已添加仓库: ingress-nginx
已添加仓库: jetstack
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "bitnami" chart repository
...Successfully got an update from the "ingress-nginx" chart repository
...Successfully got an update from the "jetstack" chart repository
Update Complete.

name version app_version description
---- ------- ----------- -----------
bitnami/nginx 18.2.5 1.25.4 NGINX Open Source...
ingress-nginx/ingress-nginx 4.11.3 1.11.3 Ingress controller...

[default] api-gateway (api-gateway): 可升级: 1.2.0 -> 1.3.1
[production] cert-manager (cert-manager): 已是最新
[staging] my-app (my-app): 可升级: 2.0.1 -> 2.1.0
依赖已更新: ./charts/my-application

Values 文件动态生成

Helm 的灵活性很大程度上来自 values.yaml 文件。在多环境(开发、预发布、生产)部署中,为每个环境维护独立的 Values 文件既繁琐又容易出错。PowerShell 可以基于模板和数据表动态生成 Values 文件,还能安全地处理密码等敏感值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# 定义环境配置矩阵
$environments = @{
dev = @{
replicas = 1
imageTag = 'latest'
resources = @{ cpuRequest = '100m'; memRequest = '128Mi' }
ingress = @{ enabled = $false }
}
staging = @{
replicas = 2
imageTag = 'v2.1.0-rc.1'
resources = @{ cpuRequest = '250m'; memRequest = '256Mi' }
ingress = @{ enabled = $true; host = 'staging.example.com' }
}
production = @{
replicas = 3
imageTag = 'v2.0.1'
resources = @{ cpuRequest = '500m'; memRequest = '512Mi' }
ingress = @{ enabled = $true; host = 'app.example.com'; tls = $true }
}
}

# 为每个环境生成 values 文件
foreach ($envName in $environments.Keys) {
$env = $environments[$envName]
$values = [ordered]@{
replicaCount = $env.replicas
image = [ordered]@{
repository = 'registry.example.com/my-app'
tag = $env.imageTag
pullPolicy = if ($env.imageTag -eq 'latest') { 'Always' } else { 'IfNotPresent' }
}
resources = [ordered]@{
requests = [ordered]@{
cpu = $env.resources.cpuRequest
memory = $env.resources.memRequest
}
}
ingress = $env.ingress
}

$outputPath = "values-$envName.yaml"

# 使用 ConvertTo-Yaml(或手动构建 YAML 字符串)
# 这里用 helm 的 --set 语法验证生成结果
$jsonContent = $values | ConvertTo-Json -Depth 10

# 将 JSON 转为 YAML(利用 yq 或简单字符串替换)
$jsonContent | python3 -c "import sys,yaml,json; yaml.dump(json.load(sys.stdin),open('$outputPath','w'),default_flow_style=False)"

Write-Host "已生成: $outputPath" -ForegroundColor Green
}

# 敏感值处理:从外部密钥管理器获取
function Get-SecretForHelm {
param([string]$SecretName)

# 从环境变量或 Azure Key Vault / HashiCorp Vault 获取
$value = [System.Environment]::GetEnvironmentVariable("HELM_SECRET_$SecretName")
if (-not $value) {
# 尝试从 kubectl secret 获取
$value = kubectl get secret app-secrets -o jsonpath="{.data.$SecretName}" |
base64 -d 2>$null
}
return $value
}

# 合并基础 values 与环境覆盖
function Merge-HelmValues {
param($BasePath, $OverridePath, $OutputPath)

# 使用 yq 合并 YAML 文件
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' `
$BasePath $OverridePath -o yaml > $OutputPath

Write-Host "合并完成: $OutputPath" -ForegroundColor Cyan
}

# 生成包含敏感值的最终 values
$dbPassword = Get-SecretForHelm -SecretName 'DB_PASSWORD'
if ($dbPassword) {
$secretValues = "database:`n password: $dbPassword"
$secretValues | Out-File -FilePath 'values-secrets.yaml' -Encoding utf8
Merge-HelmValues -BasePath 'values-production.yaml' `
-OverridePath 'values-secrets.yaml' `
-OutputPath 'values-production-final.yaml'
}

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
已生成: values-dev.yaml
已生成: values-staging.yaml
已生成: values-production.yaml
合并完成: values-production-final.yaml

# 生成的 values-dev.yaml 内容摘要:
replicaCount: 1
image:
repository: registry.example.com/my-app
tag: latest
pullPolicy: Always
resources:
requests:
cpu: 100m
memory: 128Mi
ingress:
enabled: false

批量部署与回滚

在微服务架构下,一次发布可能涉及多个 Helm Release。手动逐个执行 helm upgrade 既耗时又容易遗漏。下面的脚本实现了多命名空间批量部署、发布状态追踪以及一键回滚功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 定义部署清单
$deployments = @(
@{
Name = 'api-gateway'
Namespace = 'production'
Chart = 'bitnami/nginx'
ValuesFile = 'values-production.yaml'
Wait = $true
}
@{
Name = 'auth-service'
Namespace = 'production'
Chart = './charts/auth-service'
ValuesFile = 'values-auth-production.yaml'
Wait = $true
}
@{
Name = 'frontend'
Namespace = 'production'
Chart = './charts/frontend'
ValuesFile = 'values-frontend-production.yaml'
Wait = $false
}
)

# 确保 namespace 存在
$namespaces = $deployments | Select-Object -ExpandProperty Namespace -Unique
foreach ($ns in $namespaces) {
$exists = kubectl get namespace $ns --ignore-not-found 2>$null
if (-not $exists) {
kubectl create namespace $ns
Write-Host "已创建命名空间: $ns" -ForegroundColor Yellow
}
}

# 批量部署并记录结果
$results = [System.Collections.Generic.List[PSObject]]::new()

foreach ($dep in $deployments) {
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
Write-Host "`n部署: $($dep.Name) -> $($dep.Namespace)" -ForegroundColor Cyan

$waitFlag = if ($dep.Wait) { '--wait' } else { '' }
$command = "helm upgrade --install $($dep.Name) $($dep.Chart) " +
"--namespace $($dep.Namespace) " +
"-f $($dep.ValuesFile) $waitFlag --timeout 5m"

$output = Invoke-Expression $command 2>&1
$stopwatch.Stop()

$success = $LASTEXITCODE -eq 0
$results.Add([PSCustomObject]@{
Name = $dep.Name
Namespace = $dep.Namespace
Status = if ($success) { 'deployed' } else { 'failed' }
Duration = '{0:N1}s' -f $stopwatch.Elapsed.TotalSeconds
Output = $output | Select-Object -First 3
})
}

# 输出部署报告
Write-Host "`n===== 部署报告 =====" -ForegroundColor Yellow
$results |
Select-Object Name, Namespace, Status, Duration |
Format-Table -AutoSize

# 检查是否有失败的部署
$failed = $results | Where-Object { $_.Status -eq 'failed' }
if ($failed) {
Write-Host "`n以下部署失败,准备回滚:" -ForegroundColor Red
$failed | ForEach-Object { Write-Host " - $($_.Name) ($($_.Namespace))" }

# 一键回滚所有失败项
foreach ($f in $failed) {
Write-Host "`n回滚: $($f.Name)" -ForegroundColor Red
helm rollback $f.Name --namespace $f.Namespace
$rollbackStatus = if ($LASTEXITCODE -eq 0) { '回滚成功' } else { '回滚失败' }
Write-Host " $rollbackStatus"
}
}

# 生成当前所有 Release 状态摘要
$allReleases = helm list --all-namespaces --output json | ConvertFrom-Json
$report = $allReleases |
Select-Object name, namespace, @{N='chart';E={ $_.chart -replace '-\d+.*$', '' }},
chart_version, status, updated |
Sort-Object namespace, name

Write-Host "`n===== 当前 Release 状态 =====" -ForegroundColor Green
$report | Format-Table -AutoSize

# 导出报告为 CSV(可选)
$report | Export-Csv -Path "helm-deploy-report-$(Get-Date -Format 'yyyyMMdd-HHmmss').csv" `
-NoTypeInformation -Encoding utf8
Write-Host "报告已导出到 CSV 文件" -ForegroundColor Cyan

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
已创建命名空间: production

部署: api-gateway -> production
Release "api-gateway" has been upgraded. Happy Helming!
NAME: api-gateway
LAST DEPLOYED: Wed Apr 23 10:30:00 2026

部署: auth-service -> production
Release "auth-service" has been upgraded. Happy Helming!
NAME: auth-service
LAST DEPLOYED: Wed Apr 23 10:30:45 2026

部署: frontend -> production
Release "frontend" has been upgraded. Happy Helming!

===== 部署报告 =====
Name Namespace Status Duration
---- --------- ------ --------
api-gateway production deployed 32.5s
auth-service production deployed 41.2s
frontend production deployed 3.1s

===== 当前 Release 状态 =====
name namespace chart chart_version status updated
---- --------- ----- ------------- ------ -------
api-gateway production nginx 18.2.5 deployed 2026-04-23 10:30:00
auth-service production auth-service 1.5.0 deployed 2026-04-23 10:30:45
frontend production frontend 2.1.0 deployed 2026-04-23 10:31:02
报告已导出到 CSV 文件

注意事项

  • Helm 版本兼容性:本文示例基于 Helm 3.x,Helm 2 已停止维护,请确保使用 helm version 确认当前版本为 3.0 以上。Helm 3 移除了 Tiller,安全性显著提升。
  • JSON 输出解析:helm 命令支持 --output json 参数,配合 ConvertFrom-Json 可以将结果转为 PowerShell 对象。但不同 Helm 版本的 JSON 字段名可能略有差异(如 chart_version 与 app_version),使用前建议先检查输出结构。
  • 敏感值管理:不要将密码、Token 等敏感信息硬编码在 Values 文件或脚本中。应结合 Kubernetes Secret、外部密钥管理器(如 HashiCorp Vault、Azure Key Vault)或 Helm Secrets 插件来管理敏感配置。
  • 回滚策略:helm rollback 默认回滚到上一个修订版本。如果需要回滚到更早的版本,先用 helm history <release> 查看修订记录,再指定 helm rollback <release> <revision> 回滚到目标版本。
  • 超时与等待:生产环境部署建议始终使用 --wait 和 --timeout 参数,确保 Helm 等待所有 Pod 就绪后才认为部署成功。合理的超时值通常为 5-10 分钟,具体取决于应用的启动时间。
  • 并发部署限制:虽然 PowerShell 支持并发执行(如 ForEach-Object -Parallel),但 Helm 对同一 Release 的并发操作并不安全。建议对同一 Release 的操作串行执行,不同 Release 之间可以安全地并发部署。

PowerShell 技能连载 - Kubernetes Helm 包管理

https://blog.vichamp.com/2026/04/23/powershell-kubernetes-helm/

作者

Victor Woo

发布于

2026-04-23

更新于

2026-04-23

许可协议

PowerShell 技术 QQ 群