适用于 Docker 20.10+ 及 PowerShell 7.0+
容器化部署已经从尝鲜走向了主流。无论是微服务架构还是 CI/CD 流水线,Docker 几乎无处不在。然而,日常运维中频繁手动输入 docker run、docker logs 等命令不仅效率低下,而且容易出错。PowerShell 凭借其强大的对象管道和函数封装能力,非常适合用来编排 Docker 操作——把重复性工作交给脚本,让运维人员专注于真正重要的事情。
本文将从环境检查、容器生命周期管理、批量巡检、镜像清理、日志收集五个方面,逐步展示如何用 PowerShell 高效管理 Docker 容器,最后给出一个完整的 Nginx 部署实战示例。
检查 Docker 环境
动手管理容器之前,首先要确认 Docker 引擎是否正常运行、磁盘空间是否充足、当前有多少容器在跑。下面的函数一次性完成这三项检查,并将结果以表格形式输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| function Test-DockerEnvironment { $result = @()
try { $version = docker version --format "{{.Server.Version}}" 2>$null $result += [PSCustomObject]@{ Check = "Docker 引擎" Status = if ($version) { "运行中 v$version" } else { "未运行" } } } catch { $result += [PSCustomObject]@{ Check = "Docker 引擎"; Status = "未安装" } }
$diskUsage = docker system df --format "{{.Type}}: {{.Size}}" 2>$null $result += [PSCustomObject]@{ Check = "磁盘占用"; Status = ($diskUsage -join "; ") }
$running = docker ps -q 2>$null $result += [PSCustomObject]@{ Check = "运行中容器"; Status = "$(@($running).Count) 个" }
return $result | Format-Table -AutoSize }
|
调用该函数后,输出结果一目了然:
1 2 3 4 5
| Check Status ----- ------ Docker 引擎 运行中 v24.0.7 磁盘占用 Images: 1.2GB; Containers: 340MB; Local Volumes: 0B 运行中容器 3 个
|
如果引擎状态显示”未运行”或”未安装”,需要先排查 Docker 服务再继续。
容器生命周期管理
日常操作中,创建容器往往是最频繁的动作。直接拼接 docker run 命令不仅参数冗长,还容易遗漏端口或环境变量。我们将它封装为 PowerShell 函数,通过命名参数来调用。
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
| function New-DockerAppContainer { param( [Parameter(Mandatory)][string]$Name, [Parameter(Mandatory)][string]$Image, [hashtable]$PortMappings, [hashtable]$EnvVars, [string[]]$Volumes, [string]$Network = "bridge", [string]$RestartPolicy = "unless-stopped" )
$args = @("run", "-d", "--name", $Name, "--restart", $RestartPolicy)
foreach ($port in $PortMappings.GetEnumerator()) { $args += @("-p", "$($port.Key):$($port.Value)") } foreach ($env in $EnvVars.GetEnumerator()) { $args += @("-e", "$($env.Key)=$($env.Value)") } foreach ($vol in $Volumes) { $args += @("-v", $vol) }
$args += @("--network", $Network, $Image)
$containerId = & docker $args 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host "容器 $Name 已启动: $containerId" -ForegroundColor Green return $containerId.Substring(0, 12) } else { Write-Host "启动失败: $containerId" -ForegroundColor Red } }
|
使用这个函数创建一个 Nginx 容器,将宿主机 8080 端口映射到容器 80 端口,并挂载自定义网页目录:
1 2 3 4 5
| New-DockerAppContainer -Name "my-nginx" ` -Image "nginx:latest" ` -PortMappings @{ 8080 = 80 } ` -EnvVars @{ NGINX_HOST = "example.com" } ` -Volumes @("/data/nginx/html:/usr/share/nginx/html")
|
执行结果如下,返回截断后的容器 ID 表示创建成功:
1 2
| 容器 my-nginx 已启动: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8g9h0 a1b2c3d4e5f6
|
容器创建之后,停止、重启、移除等操作也很常用:
1 2 3 4 5 6 7 8
| docker stop my-nginx
docker start my-nginx
docker rm my-nginx
|
每个命令都会返回容器名称或 ID,确认操作已生效。
批量容器巡检
当服务器上同时运行着多个容器时,逐个执行 docker stats 查看资源占用效率很低。下面的函数能一次性生成所有容器的 CPU、内存使用报告:
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
| function Get-DockerContainerReport { param([switch]$All)
$format = "{{.ID}}|{{.Names}}|{{.Image}}|{{.Status}}|{{.Ports}}" $filter = if ($All) { "docker ps -a" } else { "docker ps" } $containers = Invoke-Expression "$filter --format '$format'" 2>$null
$report = foreach ($line in $containers) { $parts = $line -split '\|' $id = $parts[0].Substring(0, [Math]::Min(12, $parts[0].Length))
$stats = docker stats --no-stream --format "{{.CPUPerc}}|{{.MemUsage}}" $id 2>$null $statParts = if ($stats) { $stats -split '\|' } else { @("N/A", "N/A") }
[PSCustomObject]@{ Container = $parts[1] Image = $parts[2] Status = $parts[3] CPU = $statParts[0] Memory = $statParts[1] Ports = $parts[4] } } return $report | Format-Table -AutoSize }
|
执行后可以得到一张汇总表格,快速定位资源异常的容器:
1 2 3 4 5
| Container Image Status CPU Memory Ports --------- ----- ------ --- ------ ----- my-nginx nginx:latest Up 2 hours 0.01% 4.2MiB / 16GiB 0.0.0.0:8080->80/tcp my-redis redis:7 Up 5 hours 0.12% 8.5MiB / 16GiB 6379/tcp my-api myapp:v2 Up 1 hour 2.35% 128MiB / 16GiB 0.0.0.0:3000->3000/tcp
|
如果发现某个容器 CPU 或内存占用异常偏高,可以立即用日志函数排查原因。
镜像清理
反复构建镜像会产生大量无标签的悬空镜像(dangling images),它们不参与任何容器的运行,却持续占用磁盘空间。定期清理是保持环境整洁的好习惯。
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
| function Remove-DockerDanglingImages { $dangling = docker images -f "dangling=true" -q 2>$null
if ($dangling) { $size = docker images -f "dangling=true" --format "{{.Size}}" 2>$null $totalMB = ($size | ForEach-Object { if ($_ -match '(\d+\.?\d*)\s*(GB|MB)') { if ($Matches[2] -eq "GB") { [double]$Matches[1] * 1024 } else { [double]$Matches[1] } } } | Measure-Object -Sum).Sum
Write-Host "发现 $($dangling.Count) 个悬空镜像,约 $([math]::Round($totalMB, 0)) MB" -ForegroundColor Yellow $confirm = Read-Host "是否清理? (y/n)"
if ($confirm -eq "y") { docker image prune -f 2>$null Write-Host "清理完成" -ForegroundColor Green } } else { Write-Host "没有悬空镜像,磁盘很干净" -ForegroundColor Green } }
|
执行效果如下,可以看到释放了多少空间:
1 2 3 4 5 6 7
| 发现 7 个悬空镜像,约 1420 MB 是否清理? (y/n): y Deleted Images: untagged: <none>@<none> deleted: sha256:abc123... Total reclaimed space: 1.38GB 清理完成
|
建议将这个函数加入定期维护脚本,避免磁盘被无用镜像占满。
容器日志收集
排查容器故障时,日志是最关键的信息来源。docker logs 命令功能丰富但参数不好记,我们用 PowerShell 函数封装常用选项:按条数截取、按时间过滤、导出到文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function Get-DockerContainerLog { param( [Parameter(Mandatory)][string]$ContainerName, [int]$Tail = 100, [datetime]$Since, [string]$OutputPath )
$args = @("logs", "--tail", $Tail) if ($Since) { $args += @("--since", $Since.ToString("yyyy-MM-ddTHH:mm:ss")) } $args += $ContainerName
$logs = & docker $args 2>&1
if ($OutputPath) { $logs | Out-File -FilePath $OutputPath -Encoding UTF8 Write-Host "日志已保存到: $OutputPath" } else { return $logs } }
|
查看最近 5 条日志:
1
| Get-DockerContainerLog -ContainerName "my-nginx" -Tail 5
|
1 2 3 4
| 192.168.1.100 - - [01/Apr/2025:10:23:45 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" 192.168.1.101 - - [01/Apr/2025:10:24:01 +0000] "GET /api/health HTTP/1.1" 200 2 "-" "curl/7.88.1"
|
如果想一次性导出所有运行中容器的日志用于归档分析,可以使用以下批量导出函数:
1 2 3 4 5 6 7 8 9 10 11 12
| function Export-AllContainerLogs { param([string]$OutputDir = "./container_logs")
New-Item -Path $OutputDir -ItemType Directory -Force | Out-Null
$containers = docker ps --format "{{.Names}}" 2>$null foreach ($name in $containers) { $logFile = Join-Path $OutputDir "${name}_$(Get-Date -Format 'yyyyMMdd').log" Get-DockerContainerLog -ContainerName $name -Tail 1000 -OutputPath $logFile } Write-Host "所有容器日志已导出到: $OutputDir" -ForegroundColor Green }
|
1 2 3 4
| 日志已保存到: ./container_logs/my-nginx_20250401.log 日志已保存到: ./container_logs/my-redis_20250401.log 日志已保存到: ./container_logs/my-api_20250401.log 所有容器日志已导出到: ./container_logs
|
完整实战:部署 Nginx 并验证
最后,我们把前面介绍的功能串联起来,演示一个从环境检查到服务上线的完整流程。
1 2 3 4 5
| Check Status ----- ------ Docker 引擎 运行中 v24.0.7 磁盘占用 Images: 320MB; Containers: 0B; Local Volumes: 0B 运行中容器 0 个
|
环境正常,继续创建容器:
1 2 3 4 5 6
| New-DockerAppContainer -Name "my-nginx" ` -Image "nginx:latest" ` -PortMappings @{ 8080 = 80 } ` -EnvVars @{ NGINX_HOST = "localhost" } ` -Volumes @("/data/nginx/html:/usr/share/nginx/html")
|
1 2
| 容器 my-nginx 已启动: f3a1b2c3d4e5f6a7b8c9d0e1f2a3b4 f3a1b2c3d4e5
|
容器启动后,检查运行状态:
1 2
| Get-DockerContainerReport
|
1 2 3
| Container Image Status CPU Memory Ports --------- ----- ------ --- ------ ----- my-nginx nginx:latest Up 30 secs 0.00% 3.8MiB / 16GiB 0.0.0.0:8080->80/tcp
|
访问服务确认是否正常响应:
1 2 3
| Invoke-WebRequest -Uri "http://localhost:8080" -UseBasicParsing | Select-Object StatusCode, StatusDescription
|
1 2 3
| StatusCode StatusDescription ---------- ------------------ 200 OK
|
收到 200 响应,Nginx 已成功运行。最后查看一下访问日志:
1 2
| Get-DockerContainerLog -ContainerName "my-nginx" -Tail 3
|
1 2
| 192.168.1.50 - - [01/Apr/2025:08:00:12 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
|
小结
通过 PowerShell 封装 Docker 命令,我们获得了几个关键优势:参数化调用取代了冗长的命令行拼接;对象化输出让结果可以直接参与管道操作;函数封装实现了跨场景复用。日常运维中有几条实践建议:始终使用 --restart unless-stopped 保证服务自愈;定期运行镜像清理脚本释放磁盘;将日志导出纳入定时任务,方便事后追溯和审计。