1. Shell 与 Docker 自动化管理概述
在现代应用部署环境中,容器化技术已经成为标配。作为一名长期从事运维工作的技术人员,我深刻体会到手动管理容器的痛苦——每次部署新版本都要重复执行几十条命令,半夜被叫起来处理容器崩溃更是家常便饭。直到我开始将 Shell 脚本与 Docker 结合使用,工作效率才得到质的提升。
Shell 脚本能够将繁琐的 Docker 操作封装成可重复执行的自动化流程。比如我们团队现在使用的自动化部署系统,只需要执行一个脚本就能完成从代码拉取、镜像构建到服务上线的全过程,部署时间从原来的2小时缩短到15分钟。更重要的是,这种方案不需要引入复杂的编排系统,特别适合中小规模的生产环境。
2. 基础环境准备
2.1 系统与 Docker 安装
我推荐使用 Ubuntu 22.04 LTS 作为基础系统,它的长期支持特性和稳定的软件源能减少很多不必要的麻烦。以下是经过生产验证的安装步骤:
bash复制# 卸载旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc
# 安装依赖
sudo apt-get update
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 设置稳定版仓库
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker 引擎
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# 验证安装
sudo docker run hello-world
注意:生产环境中建议固定 Docker 版本而非使用最新版,避免因版本更新引入兼容性问题。可以通过
apt-get install docker-ce=<VERSION>指定版本。
2.2 用户权限配置
默认情况下,Docker 需要 root 权限才能运行,这在生产环境中存在安全隐患。我建议将操作用户加入 docker 组:
bash复制sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker # 刷新组权限
验证配置是否生效:
bash复制docker ps # 应该能正常执行而不需要 sudo
3. 容器生命周期自动化管理
3.1 容器启停控制脚本
下面这个脚本封装了容器启动、停止、重启和状态检查的完整流程:
bash复制#!/bin/bash
CONTAINER_NAME="my_app"
IMAGE_NAME="my_app:latest"
PORT_MAPPING="8080:80"
VOLUME_MAPPING="/data:/app/data"
case "$1" in
start)
docker run -d \
--name $CONTAINER_NAME \
-p $PORT_MAPPING \
-v $VOLUME_MAPPING \
$IMAGE_NAME
;;
stop)
docker stop $CONTAINER_NAME
docker rm $CONTAINER_NAME
;;
restart)
$0 stop
$0 start
;;
status)
docker ps -a | grep $CONTAINER_NAME
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
esac
使用方式:
bash复制./container_ctl.sh start # 启动容器
./container_ctl.sh status # 检查状态
经验分享:在实际使用中发现,直接使用
docker restart命令有时会导致容器网络配置异常。更可靠的做法是先 stop 再 start,虽然耗时稍长但稳定性更好。
3.2 容器健康检查与自动恢复
生产环境中容器可能因各种原因崩溃,我们需要实现自动恢复机制:
bash复制#!/bin/bash
CONTAINER_NAME="my_app"
MAX_RETRIES=3
RETRY_INTERVAL=60
is_container_healthy() {
local status=$(docker inspect --format='{{.State.Status}}' $CONTAINER_NAME 2>/dev/null)
[ "$status" = "running" ] && return 0 || return 1
}
for ((i=1; i<=$MAX_RETRIES; i++)); do
if ! is_container_healthy; then
echo "$(date) - 容器异常,尝试重启 ($i/$MAX_RETRIES)"
docker restart $CONTAINER_NAME
sleep $RETRY_INTERVAL
else
echo "$(date) - 容器运行正常"
exit 0
fi
done
echo "$(date) - 达到最大重试次数,发送告警"
# 这里可以添加邮件或短信告警逻辑
exit 1
建议将上述脚本加入 crontab 定期执行:
bash复制crontab -e
# 添加以下内容,每5分钟检查一次
*/5 * * * * /path/to/health_check.sh >> /var/log/container_monitor.log 2>&1
4. 镜像构建自动化
4.1 基础镜像构建优化
一个高效的 Dockerfile 应该遵循以下原则:
- 合理利用构建缓存:将变化频率低的指令放在前面
- 减少镜像层数:合并 RUN 指令
- 使用轻量级基础镜像:如 alpine 版本
dockerfile复制# 使用多阶段构建减少最终镜像体积
FROM golang:1.18 as builder
WORKDIR /app
COPY . .
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/main
# 最终阶段
FROM alpine:3.14
WORKDIR /app
COPY --from=builder /app/main /app/main
COPY --from=builder /app/config /app/config
# 设置非root用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
EXPOSE 8080
ENTRYPOINT ["/app/main"]
构建脚本示例:
bash复制#!/bin/bash
VERSION="1.0.$(date +%Y%m%d)"
IMAGE_NAME="my_app"
docker build -t $IMAGE_NAME:$VERSION .
docker tag $IMAGE_NAME:$VERSION $IMAGE_NAME:latest
4.2 镜像版本管理策略
在实际项目中,我采用以下版本管理方案:
- 每次构建生成带日期戳的版本号(如 1.0.20230615)
- 最新稳定版本标记为 latest
- 重大版本使用语义化版本号(如 2.1.0)
回滚到特定版本的脚本:
bash复制#!/bin/bash
TARGET_VERSION=$1
CONTAINER_NAME="my_app"
docker stop $CONTAINER_NAME
docker rm $CONTAINER_NAME
docker run -d \
--name $CONTAINER_NAME \
-p 8080:80 \
my_app:$TARGET_VERSION
5. 批量部署与管理
5.1 多容器批量操作
当需要管理多个相同类型的容器时(如微服务实例),可以使用如下脚本:
bash复制#!/bin/bash
CONTAINER_PREFIX="app_node"
INSTANCE_COUNT=3
IMAGE_NAME="my_app:latest"
case "$1" in
start)
for i in $(seq 1 $INSTANCE_COUNT); do
docker run -d \
--name ${CONTAINER_PREFIX}_$i \
-p $((8080+i)):80 \
$IMAGE_NAME
done
;;
stop)
for i in $(seq 1 $INSTANCE_COUNT); do
docker stop ${CONTAINER_PREFIX}_$i
docker rm ${CONTAINER_PREFIX}_$i
done
;;
scale)
if [ -z "$2" ]; then
echo "请指定新的实例数量"
exit 1
fi
$0 stop
INSTANCE_COUNT=$2
$0 start
;;
*)
echo "Usage: $0 {start|stop|scale}"
exit 1
esac
5.2 基于配置文件的动态部署
对于更复杂的部署场景,可以使用配置文件定义部署参数:
config.json:
json复制{
"services": [
{
"name": "web",
"image": "nginx:alpine",
"ports": ["80:80"],
"replicas": 2
},
{
"name": "api",
"image": "my_app:latest",
"ports": ["8080:8080"],
"volumes": ["/data:/app/data"],
"replicas": 3
}
]
}
部署脚本:
bash复制#!/bin/bash
CONFIG_FILE="config.json"
jq -c '.services[]' $CONFIG_FILE | while read service; do
name=$(echo $service | jq -r '.name')
image=$(echo $service | jq -r '.image')
replicas=$(echo $service | jq -r '.replicas')
for i in $(seq 1 $replicas); do
container_name="${name}_$i"
# 构造端口映射参数
ports=""
echo $service | jq -r '.ports[]' | while read port; do
ports+=" -p $port"
done
# 构造卷映射参数
volumes=""
echo $service | jq -r '.volumes[]?' | while read volume; do
volumes+=" -v $volume"
done
# 运行容器
docker run -d \
--name $container_name \
$ports \
$volumes \
$image
done
done
6. 高级运维技巧
6.1 资源监控与日志收集
以下脚本可以定期收集容器资源使用情况并生成报告:
bash复制#!/bin/bash
OUTPUT_DIR="/var/log/docker_stats"
mkdir -p $OUTPUT_DIR
DATE=$(date +%Y%m%d)
REPORT_FILE="$OUTPUT_DIR/stats_$DATE.csv"
# 写入CSV头
echo "timestamp,container_name,cpu_percent,memory_usage,memory_limit,network_in,network_out" > $REPORT_FILE
while true; do
TIMESTAMP=$(date +%Y-%m-%dT%H:%M:%S)
docker stats --no-stream --format \
"{{.Container}},{{.Name}},{{.CPUPerc}},{{.MemUsage}},{{.MemPerc}},{{.NetIO}}" | \
while read line; do
echo "$TIMESTAMP,$line" >> $REPORT_FILE
done
sleep 300 # 每5分钟收集一次
done
6.2 自动化日志轮转
Docker 容器日志默认不会自动清理,长期运行可能导致磁盘爆满。这是我使用的日志管理方案:
bash复制#!/bin/bash
# 配置所有容器的日志驱动为json-file,并限制大小
cat <<EOF > /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
EOF
# 重启Docker使配置生效
systemctl restart docker
# 清理历史日志
find /var/lib/docker/containers/ -name "*.log" -size +10M -delete
7. 安全加固措施
7.1 容器安全基线配置
生产环境中必须重视容器安全,以下是我的安全清单:
- 禁止容器使用特权模式
- 限制容器内核能力
- 配置只读文件系统
- 使用用户命名空间隔离
示例安全启动脚本:
bash复制#!/bin/bash
docker run -d \
--name secure_container \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--read-only \
--security-opt no-new-privileges \
--user 1000:1000 \
-v /tmp:/tmp:rw \
my_app:latest
7.2 镜像漏洞扫描
将漏洞扫描集成到CI/CD流程中:
bash复制#!/bin/bash
IMAGE_NAME="my_app:latest"
SCAN_RESULT="/var/log/scan_$(date +%Y%m%d).json"
# 使用Trivy进行漏洞扫描
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $SCAN_RESULT:/result.json \
aquasec/trivy:latest \
image --format json --output /result.json $IMAGE_NAME
# 检查高危漏洞
CRITICAL_COUNT=$(jq '.Results[].Vulnerabilities[] | select(.Severity == "CRITICAL")' $SCAN_RESULT | wc -l)
if [ $CRITICAL_COUNT -gt 0 ]; then
echo "发现 $CRITICAL_COUNT 个CRITICAL级别漏洞,禁止部署!"
exit 1
fi
8. 实际案例分享
8.1 蓝绿部署实现
下面是我们团队使用的蓝绿部署脚本,实现了零停机更新:
bash复制#!/bin/bash
# 当前运行的是蓝色还是绿色环境
CURRENT_COLOR=$(docker ps --format '{{.Names}}' | grep -o 'app_\(blue\|green\)' | head -1 | cut -d'_' -f2)
if [ "$CURRENT_COLOR" = "blue" ]; then
NEW_COLOR="green"
else
NEW_COLOR="blue"
fi
# 构建新版本镜像
docker build -t my_app:$NEW_COLOR .
# 启动新容器
docker run -d --name app_$NEW_COLOR -p 8081:80 my_app:$NEW_COLOR
# 等待新容器就绪
while ! curl -s http://localhost:8081/health; do
sleep 1
done
# 切换流量(这里假设使用Nginx作为反向代理)
sed -i "s/app_\(blue\|green\)/app_$NEW_COLOR/" /etc/nginx/conf.d/app.conf
nginx -s reload
# 停止旧容器
docker stop app_$CURRENT_COLOR
docker rm app_$CURRENT_COLOR
8.2 数据库容器初始化
对于有状态服务如数据库,需要特殊处理数据持久化和初始化:
bash复制#!/bin/bash
DATA_DIR="/data/mysql"
CONFIG_DIR="/etc/mysql/conf.d"
# 准备数据目录
mkdir -p $DATA_DIR
chown -R 999:999 $DATA_DIR # MySQL容器内用户UID为999
# 第一次运行执行初始化
if [ ! -f "$DATA_DIR/mysql" ]; then
docker run -d \
--name mysql_temp \
-v $DATA_DIR:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=temp_password \
mysql:5.7
# 等待初始化完成
while ! docker exec mysql_temp mysqladmin ping -ptemp_password --silent; do
sleep 1
done
# 执行初始化脚本
docker exec -i mysql_temp mysql -uroot -ptemp_password < /scripts/init_db.sql
# 停止临时容器
docker stop mysql_temp
docker rm mysql_temp
fi
# 正式运行
docker run -d \
--name mysql \
-v $DATA_DIR:/var/lib/mysql \
-v $CONFIG_DIR:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=your_secure_password \
-p 3306:3306 \
mysql:5.7
9. 脚本维护与优化建议
在实际运维过程中,我总结了以下脚本维护经验:
- 添加完善的日志记录:每个脚本都应该记录详细的操作日志,便于问题排查
- 实现参数化配置:将硬编码的值提取为配置文件或环境变量
- 添加输入验证:特别是对用户输入的参数要进行严格校验
- 编写单元测试:使用 bats 等工具为关键脚本编写测试用例
- 版本控制:所有脚本都应该纳入Git等版本控制系统管理
示例日志增强版脚本:
bash复制#!/bin/bash
LOG_FILE="/var/log/docker_manage.log"
exec >> $LOG_FILE 2>&1
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
CONTAINER_NAME=${1:-my_app}
if ! docker inspect $CONTAINER_NAME >/dev/null 2>&1; then
log "错误:容器 $CONTAINER_NAME 不存在"
exit 1
fi
case "$2" in
start)
log "启动容器 $CONTAINER_NAME"
docker start $CONTAINER_NAME
;;
stop)
log "停止容器 $CONTAINER_NAME"
docker stop $CONTAINER_NAME
;;
*)
log "无效操作:$2"
exit 1
esac
log "操作完成"
10. 性能调优实战
10.1 容器启动速度优化
通过以下技巧可以将容器启动时间缩短50%以上:
- 使用轻量级基础镜像(如alpine)
- 减少镜像层数
- 预加载依赖项
- 使用Docker的
--tmpfs选项替代磁盘IO
优化后的启动脚本:
bash复制#!/bin/bash
docker run -d \
--name fast_app \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
--memory 512m \
--cpus 1 \
my_optimized_app:latest
10.2 批量操作并行化
当需要操作大量容器时,使用GNU parallel工具实现并行处理:
bash复制#!/bin/bash
# 并行停止所有容器
docker ps -aq | parallel -j 8 docker stop {}
# 并行删除所有容器
docker ps -aq | parallel -j 8 docker rm {}
# 并行启动10个实例
seq 1 10 | parallel -j 4 docker run -d --name app_{} my_app:latest
提示:parallel的-j参数指定并行度,建议设置为CPU核心数的1-2倍
11. 跨主机容器通信
对于多主机环境,我推荐使用以下方案:
11.1 使用Docker overlay网络
bash复制# 在主管理节点上初始化Swarm
docker swarm init --advertise-addr <MANAGER_IP>
# 在工作节点上加入Swarm
docker swarm join --token <TOKEN> <MANAGER_IP>:2377
# 创建overlay网络
docker network create --driver overlay --attachable my_overlay_net
# 在不同主机上启动容器并加入同一网络
docker run -d --name app1 --network my_overlay_net my_app:latest
11.2 基于SSH隧道的跨主机管理
bash复制#!/bin/bash
REMOTE_HOST="user@remote-server"
REMOTE_DOCKER="/var/run/docker.sock"
# 通过SSH隧道远程管理Docker
ssh -nNT -L ./remote.sock:$REMOTE_DOCKER $REMOTE_HOST &
# 设置Docker客户端使用远程socket
export DOCKER_HOST=unix://./remote.sock
# 现在可以像操作本地Docker一样操作远程Docker
docker ps
# 完成后杀死SSH隧道
pkill -f "ssh -nNT"
12. 灾备与恢复策略
12.1 容器配置备份
bash复制#!/bin/bash
BACKUP_DIR="/backup/docker"
mkdir -p $BACKUP_DIR
# 备份所有容器配置
docker ps -aq | while read container; do
docker inspect $container > "$BACKUP_DIR/${container}_config.json"
done
# 备份所有镜像
docker images --format '{{.Repository}}:{{.Tag}}' | while read image; do
filename=$(echo $image | sed 's[/[_]g').tar
docker save $image > "$BACKUP_DIR/$filename"
done
# 备份卷数据
docker volume ls -q | while read volume; do
docker run --rm \
-v $volume:/data \
-v $BACKUP_DIR:/backup \
alpine tar czf /backup/${volume}_$(date +%Y%m%d).tar.gz -C /data .
done
12.2 快速恢复方案
bash复制#!/bin/bash
RESTORE_DIR="/backup/docker"
# 恢复镜像
find $RESTORE_DIR -name "*.tar" | while read image_file; do
docker load -i $image_file
done
# 恢复卷数据
find $RESTORE_DIR -name "*.tar.gz" | grep "_volume_" | while read volume_file; do
volume_name=$(basename $volume_file | cut -d'_' -f1)
docker volume create $volume_name
docker run --rm \
-v $volume_name:/data \
-v $RESTORE_DIR:/backup \
alpine tar xzf /backup/$(basename $volume_file) -C /data
done
# 重新创建容器
find $RESTORE_DIR -name "*_config.json" | while read config_file; do
container_id=$(basename $config_file | cut -d'_' -f1)
docker create $(jq -r '.[0].Config.Image' $config_file)
# 这里需要根据config.json还原完整的容器配置
done
13. 监控告警体系搭建
13.1 Prometheus监控方案
bash复制# 启动Prometheus容器
docker run -d \
--name prometheus \
-p 9090:9090 \
-v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus
# 启动Node Exporter监控主机指标
docker run -d \
--name node_exporter \
--net="host" \
--pid="host" \
-v "/:/host:ro,rslave" \
prom/node-exporter \
--path.rootfs=/host
# 启动cAdvisor监控容器指标
docker run -d \
--name cadvisor \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--volume=/dev/disk/:/dev/disk:ro \
--publish=8080:8080 \
google/cadvisor:latest
13.2 自定义告警规则
prometheus.yml 示例配置:
yaml复制rule_files:
- /etc/prometheus/alert.rules
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
alert.rules 示例:
yaml复制groups:
- name: container_alerts
rules:
- alert: HighMemoryUsage
expr: container_memory_usage_bytes{name!=""} / container_spec_memory_limit_bytes{name!=""} > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "高内存使用率 ({{ $value }}%)"
description: "容器 {{ $labels.name }} 内存使用率超过90%"
14. CI/CD 集成实践
14.1 GitLab CI 集成示例
.gitlab-ci.yml 配置:
yaml复制stages:
- build
- test
- deploy
variables:
IMAGE_NAME: registry.example.com/my_app
TAG: $CI_COMMIT_SHORT_SHA
build_image:
stage: build
script:
- docker build -t $IMAGE_NAME:$TAG .
- docker push $IMAGE_NAME:$TAG
run_tests:
stage: test
script:
- docker run --rm $IMAGE_NAME:$TAG npm test
deploy_prod:
stage: deploy
script:
- echo "部署 $IMAGE_NAME:$TAG 到生产环境"
- scp deploy_script.sh prod-server:/tmp/
- ssh prod-server "/tmp/deploy_script.sh $IMAGE_NAME:$TAG"
only:
- master
14.2 Jenkins 集成示例
Jenkinsfile 配置:
groovy复制pipeline {
agent any
environment {
IMAGE_NAME = "my_app"
TAG = "${env.BUILD_ID}"
}
stages {
stage('Build') {
steps {
script {
docker.build("${IMAGE_NAME}:${TAG}")
}
}
}
stage('Test') {
steps {
script {
docker.image("${IMAGE_NAME}:${TAG}").inside {
sh 'npm test'
}
}
}
}
stage('Deploy') {
steps {
script {
sshagent(['prod-server-key']) {
sh """
scp deploy_script.sh prod-server:/tmp/
ssh prod-server "/tmp/deploy_script.sh ${IMAGE_NAME}:${TAG}"
"""
}
}
}
}
}
}
15. 网络与存储高级配置
15.1 自定义网络配置
bash复制# 创建自定义桥接网络
docker network create \
--driver bridge \
--subnet 172.28.0.0/16 \
--gateway 172.28.0.1 \
--opt com.docker.network.bridge.name=mybridge \
my_network
# 启动容器并指定静态IP
docker run -d \
--name static_ip_container \
--network my_network \
--ip 172.28.0.100 \
my_app:latest
15.2 存储驱动优化
对于IO密集型应用,可以考虑使用更高效的存储驱动:
bash复制# 查看当前存储驱动
docker info | grep "Storage Driver"
# 修改为overlay2 (需要在daemon.json中配置)
cat <<EOF > /etc/docker/daemon.json
{
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF
systemctl restart docker
16. 多架构镜像支持
16.1 构建多平台镜像
使用 buildx 构建支持多种CPU架构的镜像:
bash复制# 创建构建器实例
docker buildx create --name multiarch --use
# 启动构建器
docker buildx inspect --bootstrap
# 构建多平台镜像
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t my_app:multiarch \
--push .
16.2 运行时架构检测
启动脚本中自动选择匹配的镜像:
bash复制#!/bin/bash
ARCH=$(uname -m)
case $ARCH in
x86_64)
IMAGE="my_app:amd64"
;;
aarch64)
IMAGE="my_app:arm64"
;;
*)
echo "不支持的架构: $ARCH"
exit 1
;;
esac
docker run -d --name app $IMAGE
17. 容器安全扫描集成
17.1 使用Clair进行静态扫描
bash复制# 启动Clair服务
docker run -d \
--name clair \
-p 6060-6061:6060-6061 \
-v /path/to/config:/config \
quay.io/coreos/clair:latest \
-config=/config/config.yaml
# 使用clair-scanner扫描本地镜像
docker run -d --name temp_scan my_app:latest
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /tmp:/tmp \
objectiflibre/clair-scanner \
--clair="http://clair:6060" \
--ip="host.docker.internal" \
temp_scan
17.2 运行时安全监控
使用Falco监控容器异常行为:
bash复制# 启动Falco
docker run -d \
--name falco \
--privileged \
-v /var/run/docker.sock:/host/var/run/docker.sock \
-v /dev:/host/dev \
-v /proc:/host/proc:ro \
-v /boot:/host/boot:ro \
-v /lib/modules:/host/lib/modules:ro \
-v /usr:/host/usr:ro \
falcosecurity/falco:latest
18. 性能基准测试
18.1 容器启动时间测试
bash复制#!/bin/bash
TEST_IMAGE="alpine:latest"
TEST_COUNT=100
TOTAL=0
for i in $(seq 1 $TEST_COUNT); do
START=$(date +%s.%N)
docker run --rm $TEST_IMAGE true
END=$(date +%s.%N)
ELAPSED=$(echo "$END - $START" | bc)
TOTAL=$(echo "$TOTAL + $ELAPSED" | bc)
echo "第 $i 次: $ELAPSED 秒"
done
AVERAGE=$(echo "scale=4; $TOTAL / $TEST_COUNT" | bc)
echo "平均启动时间: $AVERAGE 秒"
18.2 网络性能测试
bash复制# 启动iperf3服务器
docker run -d --name iperf_server -p 5201:5201 networkstatic/iperf3 -s
# 运行客户端测试
docker run --rm --network host networkstatic/iperf3 -c localhost -t 30
19. 资源限制与配额管理
19.1 CPU与内存限制
bash复制# 启动带资源限制的容器
docker run -d \
--name limited_container \
--cpus 1.5 \
--memory 1g \
--memory-swap 1.5g \
--blkio-weight 500 \
my_app:latest
19.2 全局资源监控
bash复制#!/bin/bash
# 监控所有容器资源使用
watch -n 5 "docker stats --no-stream --format \
'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}'"
20. 容器日志管理进阶
20.1 结构化日志处理
bash复制# 使用Fluentd收集日志
docker run -d \
--name fluentd \
-p 24224:24224 \
-v /path/to/fluent.conf:/fluentd/etc/fluent.conf \
fluent/fluentd:latest
# 启动应用容器并配置日志驱动
docker run -d \
--name app_with_logging \
--log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag="docker.{{.Name}}" \
my_app:latest
20.2 日志自动归档
bash复制#!/bin/bash
LOG_DIR="/var/lib/docker/containers"
ARCHIVE_DIR="/backup/logs"
DAYS_TO_KEEP=30
# 归档7天前的日志
find $LOG_DIR -name "*.log" -mtime +7 | while read logfile; do
container_id=$(basename $(dirname $logfile))
archive_name="$ARCHIVE_DIR/${container_id}_$(date +%Y%m%d).tar.gz"
tar czf $archive_name $logfile
truncate -s 0 $logfile
done
# 清理旧的归档
find $ARCHIVE_DIR -name "*.tar.gz" -mtime +$DAYS_TO_KEEP -delete
21. 容器内调试技巧
21.1 故障诊断工具包
我通常在基础镜像中包含以下调试工具:
dockerfile复制RUN apt-get update && apt-get install -y \
curl \
dnsutils \
iputils-ping \
net-tools \
tcpdump \
strace \
lsof \
procps \
htop \
vim \
&& rm -rf /var/lib/apt/lists/*
21.2 实时调试会话
bash复制# 进入运行中容器的shell
docker exec -it my_app /bin/bash
# 或者使用nsenter直接进入容器命名空间
PID=$(docker inspect --format '{{.State.Pid}}' my_app)
nsenter -t $PID -n -p -u -i -m
22. 容器化数据库最佳实践
22.1 PostgreSQL容器配置
bash复制#!/bin/bash
DATA_DIR="/data/postgres"
mkdir -p $DATA_DIR
chown -R 999:999 $DATA_DIR
docker run -d \
--name postgres \
-v $DATA_DIR:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=complexpassword \
-e POSTGRES_USER=appuser \
-e POSTGRES_DB=appdb \
-p 5432:5432 \
postgres:13 \
-c shared_buffers=1GB \
-c max_connections=200
22.2 Redis容器优化
bash复制docker run -d \
--name redis \
--memory 2g \
--memory-swap 2g \
--sysctl net.core.somaxconn=1024 \
-v /data/redis:/data \
redis:6 \
--appendonly yes \
--maxmemory 1.5gb \
--maxmemory-policy allkeys-lru
23. GUI应用容器化
23.1 VNC方式运行GUI应用
bash复制#!/bin/bash
XAUTH=/tmp/.docker.xauth
touch $XAUTH
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
docker run -d \
--name gui_app \
-v $XAUTH:$XAUTH \
-e XAUTHORITY=$XAUTH \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
my_gui_app:latest
23.2 浏览器自动化测试
bash复制# 使用Selenium容器
docker run -d \
--name selenium \
-p 4444:4444 \
-p 5900:5900 \
-v /dev/shm:/dev/shm \
selenium/standalone-chrome-debug:latest
# 运行测试脚本
docker run --rm \
--network container:selenium \
-v $(pwd):/tests \
python:3 \
python /tests/test_script.py
24. 容器化机器学习环境
24.1 Jupyter Notebook服务
bash复制#!/bin/bash
NOTEBOOK_DIR="/data/notebooks"
mkdir -p $NOTEBOOK_DIR
docker run -d \
--name jupyter \
-p 8888:8888 \
-