3. Docker容器管理:容器生命周期与运维实战

聊完了镜像,咱们该上手容器了。说实话,容器管理是Docker日常操作中最频繁的部分。你想想看,每天创建、启动、停止、删除,这些动作就像吃饭喝水一样平常。但越是基础的操作,越容易踩坑。今天我就把这几年的实战经验掰开揉碎讲给你听。

3.1 容器生命周期:从生到死的完整流程

容器的生命周期,说白了就四个阶段:创建→启动→停止→删除。但每个阶段都有讲究。

3.4.1 创建容器(docker create)

创建容器不等于启动容器。我个人习惯先用 docker create 把容器建好,确认配置没问题再启动。这样能避免启动时才发现参数写错了。

# 创建一个nginx容器,但不启动
docker create --name my-nginx -p 8080:80 nginx:latest

# 创建时指定资源限制
docker create --name web-app \
  --memory="512m" \
  --cpus="0.5" \
  -e DB_HOST=192.168.1.100 \
  nginx:alpine
我的习惯:创建容器时,我总喜欢加上 --restart=always 参数。之前在线上吃过亏,容器因为OOM挂了,没人发现,业务停了半小时。加了自动重启后,至少能保证服务快速恢复。

3.4.2 启动与停止(start/stop)

启动容器很简单,但停止容器有门道。

# 启动容器
docker start my-nginx

# 优雅停止(给进程10秒时间清理)
docker stop -t 10 my-nginx

# 强制停止(慎用!)
docker kill my-nginx
我曾经踩过的坑:有一次线上环境,我直接用 docker kill 停了一个MySQL容器。结果重启后,数据库损坏了,花了两个小时修复。从那以后,我坚持用 docker stop,给进程足够的清理时间。数据库类容器,我甚至会给30秒以上的宽限时间。

3.4.3 删除容器(rm)

删除容器前,一定要确认数据已经备份。我见过太多人删完容器才发现数据没挂载出来。

# 删除已停止的容器
docker rm my-nginx

# 强制删除运行中的容器(危险!)
docker rm -f my-nginx

# 清理所有已停止的容器
docker container prune
重要提醒:删除容器前,务必确认数据卷(volume)是否已备份。容器可以删,但数据是无价的。

3.2 进入容器:exec vs attach

进入容器调试,是日常运维的必备技能。但 execattach 的区别,很多人搞不清楚。

3.2.1 docker exec(推荐方式)

我个人99%的情况都用 exec。它会在容器内启动一个新进程,不会影响容器主进程。

# 进入容器的bash
docker exec -it my-nginx /bin/bash

# 在容器内执行单条命令
docker exec my-nginx cat /etc/nginx/nginx.conf

# 以root身份进入(容器默认用户可能权限不够)
docker exec -u root -it my-nginx /bin/sh
小技巧:如果容器里没有bash,试试 /bin/sh。Alpine镜像默认只有sh,没有bash。我第一次用Alpine时,敲了bash发现没有,还以为是容器坏了。

3.2.2 docker attach(慎用)

attach 是连接到容器的主进程。说白了,你看到的就是容器PID 1的输出。但有个大坑:如果你用 Ctrl+C 退出,可能会把容器也停掉。

# 附加到容器主进程
docker attach my-nginx

# 退出但不停止容器:按 Ctrl+P, Ctrl+Q
我曾经犯过的错:刚用Docker那会儿,我用 attach 连上一个Java应用容器,想看看日志。习惯性地按了 Ctrl+C,结果容器直接停了。生产环境啊,兄弟们!从那以后,看日志我改用 docker logs,调试用 exec,再也没碰过 attach

3.3 容器日志与监控

容器跑起来了,怎么知道它健不健康?日志和监控就是你的眼睛。

3.3.1 查看日志(docker logs)

日志是排查问题的第一手资料。但要注意,默认情况下Docker会把所有标准输出和标准错误都记下来,时间长了会撑爆磁盘。

# 查看最近100行日志
docker logs --tail 100 my-nginx

# 实时跟踪日志(类似tail -f)
docker logs -f my-nginx

# 查看指定时间段的日志
docker logs --since "2024-01-01T00:00:00" --until "2024-01-02T00:00:00" my-nginx
日志管理最佳实践:我建议在生产环境配置日志轮转。在启动容器时加上 --log-opt max-size=10m --log-opt max-file=3,这样每个日志文件最大10MB,保留3个文件。不然你想想看,一个容器跑半年,日志文件可能几十GB,磁盘直接爆掉。

3.3.2 容器监控(docker stats)

想知道容器用了多少CPU、内存?docker stats 是最直接的工具。

# 实时查看所有容器的资源使用情况
docker stats

# 查看指定容器
docker stats my-nginx web-app

# 只查看一次,不持续监控
docker stats --no-stream my-nginx
指标 说明 警戒线
CPU % 容器使用的CPU百分比 持续超过80%需关注
MEM USAGE / LIMIT 当前内存使用量 / 限制量 超过80%需扩容
NET I/O 网络流入/流出量 异常突增可能被攻击
BLOCK I/O 磁盘读写量 持续高I/O需优化
我的监控方案:虽然 docker stats 很方便,但生产环境我建议用cAdvisor + Prometheus。之前有个Java应用内存泄漏,就是靠cAdvisor的曲线图发现的。 docker stats 只能看当前值,历史趋势还得靠专业工具。

3.4 实战:容器生命周期管理脚本

最后,分享一个我常用的容器管理脚本。它能把创建、启动、检查、停止、删除串起来,适合自动化部署场景。

#!/bin/bash
# 容器全生命周期管理脚本

CONTAINER_NAME="my-app"
IMAGE_NAME="nginx:alpine"

# 1. 清理旧容器
echo "清理旧容器..."
docker rm -f $CONTAINER_NAME 2>/dev/null || true

# 2. 创建新容器
echo "创建新容器..."
docker create \
  --name $CONTAINER_NAME \
  --restart=always \
  --memory="256m" \
  --cpus="0.25" \
  -p 8080:80 \
  $IMAGE_NAME

# 3. 启动容器
echo "启动容器..."
docker start $CONTAINER_NAME

# 4. 检查容器状态
echo "检查容器状态..."
sleep 2
if docker ps --filter "name=$CONTAINER_NAME" --filter "status=running" | grep -q $CONTAINER_NAME; then
    echo "容器启动成功!"
    docker stats --no-stream $CONTAINER_NAME
else
    echo "容器启动失败,查看日志..."
    docker logs $CONTAINER_NAME
    exit 1
fi

# 5. 测试访问
echo "测试HTTP访问..."
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080
注意:生产环境不要直接用 docker rm -f 清理容器。我建议先 docker stop 给进程缓冲时间,确认无误后再删除。尤其是数据库、消息队列这类有状态服务,强行删除可能导致数据不一致。

嗯,容器生命周期管理就这些了。说白了,核心就三点:创建时配好参数,停止时给足时间,删除前确认数据。你把这些基础打牢了,后面编排Kubernetes时才能游刃有余。下一章咱们聊聊Docker网络,那可是个有意思的话题。