Docker基础命令实战:从部署入门到容器生命周期管理

📅 2026/7/9 23:36:29 👁️ 阅读次数 📝 编程学习
Docker基础命令实战:从部署入门到容器生命周期管理

1. 这不是“学命令”,而是掌握现代软件交付的底层操作系统

你打开终端,敲下docker run hello-world,屏幕上跳出一行绿色文字——这短短几秒背后,是过去十年整个软件工程交付范式的一次静默革命。Docker 不是又一个 Linux 工具,它是让“在我机器上能跑”这句话真正失效的第一块基石。我从 2014 年在阿里云 ECS 上手动编译 Nginx + PHP + MySQL 三件套开始做运维,到后来用 Ansible 脚本批量部署,再到今天给客户交付整套 AI 推理服务时,只发一个docker-compose.yml文件加三行说明,中间省掉的不是时间,而是沟通成本、环境差异、权限冲突和凌晨三点的告警电话。

核心关键词docker、部署、基础命令,拆开看:docker是容器运行时引擎,是隔离进程的“轻量级虚拟机内核”;部署在这里已不是“把代码拷到服务器”,而是“把可执行环境连同代码一起打包、验证、分发、启动”的端到端闭环;基础命令更不是背诵清单,而是理解容器生命周期的六个关键控制点——拉取(pull)、运行(run)、查看(ps)、进入(exec)、日志(logs)、停止(stop)。这六条命令,覆盖了 90% 的日常操作场景,而剩下 10%,是它们组合出来的逻辑延伸。

适合谁?如果你还在为“测试环境好好的,一上生产就报错”挠头;如果你每次交接项目都要写三页《环境依赖说明》;如果你用 Python 写了个小工具,却要教同事装 pip、virtualenv、requests 库;或者你正打算本地跑 Dify、Ollama、vLLM 这类大模型服务——那你不是在学 Docker,你是在升级自己的软件交付操作系统。它不挑语言、不挑框架、不挑操作系统,Windows WSL2、Mac M系列芯片、Ubuntu 服务器、甚至树莓派,只要装了 Docker Engine,你就拥有了统一的部署语言。这不是锦上添花的技能,而是当前技术栈里最值得优先投入的“基础设施认知”。

2. 为什么必须从“部署”切入,而不是“镜像构建”或“网络配置”

很多教程一上来就讲Dockerfile语法、FROM指令、COPYRUN的区别,结果新手学完只会写个打印 “Hello World” 的镜像,一碰到真实项目就卡在“怎么把我的 Flask 服务跑起来”“数据库连不上怎么办”。这是典型的本末倒置。Docker 的核心价值,第一层是环境一致性交付,第二层才是可复现的构建流程。对绝大多数人来说,前者的 ROI(投资回报率)远高于后者。

2.1 部署视角下的 Docker 本质:进程沙盒 + 环境快照

你可以把docker run理解成 Linux 的chroot+cgroups+namespaces三件套的自动化封装。它不虚拟硬件,只虚拟“进程能看到的世界”:

  • 文件系统视图:容器内看到的/目录,其实是镜像层叠加 + 一个干净的可写层,宿主机的/etc/passwd/usr/bin对它完全不可见;
  • 进程视图:容器内ps aux只能看到自己启动的那几个进程,宿主机的 nginx、mysql、cron 全部隐身;
  • 网络视图:默认使用 bridge 网络,容器有独立 IP(如 172.17.0.2),通过 NAT 访问外网,宿主机端口需显式映射(-p 8080:80);
  • 用户与权限:容器内 root 用户默认等同于宿主机 root 权限(除非用--user降权),但受限于命名空间隔离,无法操作宿主机进程或挂载点。

这种隔离不是为了安全(容器 ≠ 安全沙箱),而是为了消除环境变量。我曾接手一个遗留 Java 项目,开发用 JDK 11,测试用 JDK 17,生产用 JDK 8——光是 JVM 版本不一致就导致LocalDateTime序列化失败。用 Docker 后,我们直接指定openjdk:17-jre-slim镜像,所有环境用同一份二进制,问题消失。这才是部署层面的“一次构建,处处运行”。

2.2 基础命令不是孤立动作,而是容器生命周期的六个控制点

命令对应生命周期阶段关键参数与实操意图新手最常踩的坑
docker pull获取可执行单元docker pull nginx:alpine—— 拉取精简版 Nginx,比nginx:latest小 60MB;--platform linux/amd64强制指定架构,解决 Apple Silicon Mac 上 x86 镜像兼容问题盲目拉latest标签,导致线上环境因镜像更新意外变更行为;不加--platform在 M1/M2 Mac 上运行 x86 镜像失败
docker run创建并启动实例docker run -d -p 8080:80 --name my-nginx nginx:alpine——-d后台运行,-p端口映射,--name指定易记名称;-v $(pwd)/html:/usr/share/nginx/html:ro挂载本地 HTML 目录为只读静态资源忘加-d导致终端被占住;端口映射写反(-p 80:8080错写成宿主机 80 映射容器 8080);挂载目录权限错误,Nginx 因无读权限报 403
docker ps查看运行态实例docker ps -a查看所有容器(含已退出);docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"自定义输出格式,替代grep筛选docker ps查不到容器就认为没运行,其实该容器可能已退出(docker ps -a才能看到);不加--format时字段过长,grep匹配名称易出错
docker exec进入运行中容器docker exec -it my-nginx sh——-it分配伪 TTY 并保持 STDIN 打开;sh替代bash(Alpine 镜像默认无 bash);-u root切换用户(某些镜像默认非 root)在 Alpine 镜像里敲bash报错“not found”,实际该用sh;忘记-it导致进入后无法输入命令;用docker attach误操作导致容器前台进程被阻塞
docker logs观察运行时输出docker logs -f my-nginx实时跟踪日志;docker logs --tail 100 my-nginx查看最后 100 行;docker logs -t my-nginx加时间戳,便于排查时序问题日志滚动太快,-f后无法退出(按Ctrl+C即可);不加--tail直接查全量日志,大日志文件卡死终端;忽略-t时间戳,多个容器日志混在一起无法定位时间线
docker stop安全终止实例docker stop my-nginx发送 SIGTERM 信号,等待 10 秒后强制 SIGKILL;docker stop -t 30 my-nginx延长等待时间,确保应用优雅关闭(如 Spring Boot 的 shutdown hook)直接docker kill强制终止,导致数据库连接未释放、文件未刷盘;stop后不检查状态,误以为容器已停,实际因应用未响应 SIGTERM 仍在运行

提示:这六个命令构成最小可行闭环。你不需要记住全部 50+ 个 Docker 子命令,先吃透这六个,再根据需求自然延伸。比如docker rm(删除已停止容器)是docker stop的后续动作;docker images(查看本地镜像)是docker pull的配套检查;它们都是生命周期链条上的自然节点。

2.3 部署场景决定命令组合逻辑:从单容器到多服务协同

真实项目极少单容器运行。一个典型 Web 应用至少需要 Web 服务 + 数据库 + 缓存。此时docker run的复杂度指数上升:

  • 网络:需创建自定义 bridge 网络docker network create myapp-net,让容器间用服务名互通(web容器访问db容器只需mysql://db:3306);
  • 数据卷:数据库数据必须持久化,docker volume create mysql-data创建命名卷,避免--rm或容器删除后数据丢失;
  • 环境变量:-e MYSQL_ROOT_PASSWORD=123456传参,比硬编码到镜像更安全灵活;
  • 依赖顺序:必须先启db,再启web,否则 Web 服务启动时连不上数据库报错退出。

这个过程手动敲命令极易出错。于是docker-compose.yml成为部署事实标准——它把上述所有参数声明式地写在一个 YAML 文件里,一条docker compose up -d全部搞定。但请注意:Compose 不是新工具,它是docker run命令的高级封装。你完全可以用 20 行docker run命令实现 Compose 的功能,只是没人愿意维护。所以,学 Compose 前,务必亲手敲一遍等效的docker run组合,否则你永远不知道depends_on解决了什么问题,healthcheck如何防止服务假启动。

3. 基础命令实操详解:从零搭建一个可验证的本地部署环境

我们以部署一个极简但完整的 Python Flask API 服务为例,全程只用基础命令,不碰Dockerfiledocker-compose.yml。目标:本地启动服务,访问http://localhost:5000/health返回{"status":"ok"},并能实时查看日志、进入容器调试、安全停止服务。这个过程将覆盖所有核心命令的真实上下文。

3.1 环境准备:三步确认 Docker 已就绪

第一步永远不是敲命令,而是验证环境。很多人卡在第一步却以为是命令错了。

  1. 确认 Docker Engine 正在运行

    # Linux/macOS systemctl is-active docker # 返回 active 表示正常 # Windows (WSL2) service docker status # 或在 PowerShell 中运行 `Get-Service docker`

    注意:如果提示Unit docker.service could not be found,说明 Docker Desktop 未安装或未启动。Ubuntu 用户注意,apt install docker.io安装的是旧版社区版,推荐用官方脚本:curl -fsSL https://get.docker.com | sh

  2. 验证用户权限

    docker run hello-world

    如果报错Got permission denied while trying to connect to the Docker daemon socket,说明当前用户不在docker用户组。执行:

    sudo usermod -aG docker $USER # 退出终端重新登录,或执行 newgrp docker 生效
  3. 检查镜像源(国内用户必做)
    默认 Docker Hub 国内拉取极慢。编辑/etc/docker/daemon.json(Linux/macOS)或 Docker Desktop 设置(Windows/macOS),添加国内镜像加速器:

    { "registry-mirrors": [ "https://docker.mirrors.ustc.edu.cn", "https://hub-mirror.c.163.com" ] }

    保存后重启 Docker:sudo systemctl restart docker。验证是否生效:docker info | grep "Registry Mirrors"应显示上述地址。

3.2 构建并运行 Flask 服务:pullrunps闭环

我们不自己构建镜像,直接使用官方 Python 镜像运行脚本。这是最快验证部署流程的方式。

  1. 创建项目目录与代码

    mkdir flask-demo && cd flask-demo # 创建 app.py cat > app.py << 'EOF' from flask import Flask import os app = Flask(__name__) @app.route('/health') def health(): return {"status": "ok", "host": os.getenv('HOSTNAME', 'unknown')} if __name__ == '__main__': app.run(host='0.0.0.0:5000', port=5000, debug=False) EOF
  2. 拉取 Python 运行时镜像

    docker pull python:3.11-slim # 查看镜像列表,确认拉取成功 docker images | grep python # 输出应类似:python 3.11-slim abc123... 2 weeks ago 123MB
  3. 运行容器并映射端口

    docker run -d \ --name flask-api \ -p 5000:5000 \ -v $(pwd):/app \ -w /app \ -e FLASK_ENV=production \ python:3.11-slim \ sh -c "pip install flask && python app.py"

    参数详解:

    • -d:后台运行,返回容器 ID;
    • --name flask-api:指定易记名称,替代随机字符串;
    • -p 5000:5000:宿主机 5000 端口映射到容器 5000 端口;
    • -v $(pwd):/app:将当前目录挂载为容器内/app目录,代码实时生效;
    • -w /app:设置工作目录为/apppip installpython命令在此目录执行;
    • -e FLASK_ENV=production:设置环境变量,禁用 Flask 调试模式(安全必需);
    • 最后两段:在容器内执行sh -c "pip install flask && python app.py",即安装依赖并启动服务。
  4. 验证容器是否运行

    docker ps | grep flask-api # 正常输出应包含:flask-api ... Up 2 seconds 0.0.0.0:5000->5000/tcp # 测试访问 curl http://localhost:5000/health # 应返回:{"status":"ok","host":"<容器ID前缀>"}

实操心得:第一次运行时,pip install flask会耗时 10-20 秒,期间curl可能返回 connection refused。这是正常现象,因为容器已启动,但 Python 进程尚未监听端口。稍等几秒再试即可。不要因此怀疑命令失败。

3.3 调试与维护:execlogsstop完整链路

服务跑起来了,但如何确认它真的健康?如何修改代码?如何安全关闭?

  1. 进入容器查看运行状态

    docker exec -it flask-api sh # 进入后执行: ps aux | grep python # 应看到 python app.py 进程 netstat -tuln | grep :5000 # 应看到 0.0.0.0:5000 LISTEN exit # 退出容器

    注意:Alpine 镜像(如python:3.11-slim)默认无bash,必须用sh。如果提示sh: not found,说明镜像不基于 Alpine,可尝试bash

  2. 实时跟踪日志并定位问题

    # 开一个终端窗口,实时跟踪日志 docker logs -f flask-api # 在另一个终端修改代码,触发重启(稍后介绍) echo 'print("Server started")' >> app.py # 日志窗口应立即输出:Server started # 按 Ctrl+C 退出日志跟踪
  3. 安全停止并清理容器

    # 发送 SIGTERM,等待应用优雅关闭 docker stop flask-api # 验证已停止 docker ps -a | grep flask-api # STATUS 应为 Exited (0) ... # 删除已停止容器(可选,释放名称) docker rm flask-api # 删除挂载的卷(本例未用命名卷,无需此步)

常见问题:docker stop后容器状态仍是Up X seconds?这是docker ps缓存问题,执行docker ps -a查看真实状态。若容器长时间不退出(超过 10 秒),说明应用未响应 SIGTERM,此时docker kill flask-api强制终止。

3.4 进阶技巧:用基础命令模拟 Compose 的核心能力

虽然我们主张先学命令,但 Compose 的便利性无可否认。下面用纯docker run实现 Compose 的两个关键特性:

  1. 服务依赖与健康检查
    Compose 的depends_on只控制启动顺序,不保证依赖服务已就绪。真实方案是让 Web 服务启动时检测 DB 是否可连。我们用wait-for-it.sh脚本模拟:

    # 下载 wait-for-it.sh 到项目目录 curl -o wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh chmod +x wait-for-it.sh # 启动 MySQL 容器(使用命名卷持久化数据) docker run -d \ --name mysql-db \ -e MYSQL_ROOT_PASSWORD=123456 \ -v mysql-data:/var/lib/mysql \ -p 3306:3306 \ mysql:8.0 # 启动 Flask 容器,等待 MySQL 就绪后再启动 docker run -d \ --name flask-with-db \ -p 5000:5000 \ -v $(pwd):/app \ -w /app \ --link mysql-db:mysql \ python:3.11-slim \ sh -c "./wait-for-it.sh mysql:3306 -- pip install flask && python app.py"

    这里--link是旧语法(已被用户定义网络取代),但用于单机演示足够清晰。wait-for-it.sh会轮询mysql:3306,直到端口可连才执行后续命令。

  2. 多容器网络互通
    创建自定义网络,让容器用服务名通信:

    docker network create myapp-net # 启动 MySQL 并加入网络 docker run -d \ --name mysql-db \ --network myapp-net \ -e MYSQL_ROOT_PASSWORD=123456 \ -v mysql-data:/var/lib/mysql \ mysql:8.0 # 启动 Flask,并加入同一网络 docker run -d \ --name flask-api-net \ --network myapp-net \ -p 5000:5000 \ -v $(pwd):/app \ -w /app \ python:3.11-slim \ sh -c "pip install flask && python -c \"import socket; print(socket.gethostbyname('mysql-db'))\" && python app.py"

    socket.gethostbyname('mysql-db')会成功解析为容器 IP,证明网络互通。这是docker-compose.ymlnetworks配置的底层原理。

4. 常见问题与排查技巧实录:那些文档不会写的“血泪经验”

以下问题均来自我过去三年带团队、做客户交付时高频遇到的真实场景。它们不会出现在官方文档里,但能帮你节省数小时无效排查。

4.1 端口映射失效:宿主机端口被占用 or 容器内服务未监听正确地址

现象docker run -p 8080:80 nginx:alpine启动后,curl http://localhost:8080返回Connection refused

排查步骤

  1. 确认容器是否真在运行:docker ps | grep nginx。如果没输出,说明容器已退出,查日志:docker logs nginx-container-name
  2. 确认容器内 Nginx 是否监听0.0.0.0:80而非127.0.0.1:80docker exec -it nginx-container-name sh -c "netstat -tuln | grep :80"。Alpine 镜像需先apk add net-tools
  3. 确认宿主机端口未被占用:sudo lsof -i :8080(macOS/Linux)或netstat -ano | findstr :8080(Windows);
  4. 检查防火墙:Ubuntuufw status,CentOSfirewall-cmd --list-ports,临时关闭测试:sudo ufw disable
  5. Windows/macOS 用户特别注意:Docker Desktop 的 Linux VM 可能未启动,检查 Docker Desktop 图标是否为绿色。

实操心得:Nginx 默认配置监听0.0.0.0:80,但某些定制镜像或配置文件可能改成了127.0.0.1。最简单验证法:docker exec nginx-container-name curl -s http://localhost:80,如果容器内能通,说明服务正常,问题在端口映射或宿主机网络。

4.2 挂载目录权限拒绝:容器内进程无法读写宿主机文件

现象:Flask 应用挂载代码目录后启动报错PermissionError: [Errno 13] Permission denied: '/app/app.py'

根本原因:Linux 容器内进程以 UID/GID 运行,若与宿主机文件权限不匹配,则无权访问。例如,Alpine 镜像中python进程默认以 UID 0(root)运行,但宿主机文件属主是普通用户(UID 1000),且文件权限为600(仅属主可读写)。

解决方案

  • 方案一(推荐):修改宿主机文件权限
    chmod 644 app.py # 改为所有者可读写,组和其他人只读 chmod 755 . # 当前目录需有执行权限(允许进入)
  • 方案二:以匹配 UID 启动容器
    docker run -u $(id -u):$(id -g) -v $(pwd):/app python:3.11-slim python app.py
  • 方案三:在 Dockerfile 中创建匹配用户(长期项目)
    FROM python:3.11-slim RUN groupadd -g 1001 -f user && useradd -S -u 1001 -U -m -d /home/user user USER user WORKDIR /app COPY --chown=user:user . . CMD ["python", "app.py"]

注意:Windows/macOS 用户通常无此问题,因为 Docker Desktop 的文件共享机制自动处理了权限映射。该问题高发于 Linux 服务器部署。

4.3 镜像拉取失败:网络超时 or 镜像不存在

现象docker pull ubuntu:22.04卡住,或报错manifest for ubuntu:22.04 not found

排查与解决

  • 检查镜像标签是否存在:访问 Docker Hub Ubuntu 页面 ,确认22.04标签是否列出。很多镜像只提供latestjammy(22.04 代号)、focal(20.04)等标签,而非数字版本;
  • 检查网络与镜像源curl -v https://docker.mirrors.ustc.edu.cn/v2/,看是否返回401 Unauthorized(正常)或超时(网络问题);
  • 清除本地缓存重试docker system prune -a(谨慎,会删所有镜像和容器);
  • 离线环境方案:在有网机器拉取镜像,docker save -o ubuntu.tar ubuntu:jammy,拷贝到目标机器,docker load -i ubuntu.tar

实操心得:永远优先用发行版代号(jammy,focal)而非数字版本(22.04,20.04),因为 Docker Hub 官方镜像维护策略更稳定。latest标签慎用,它可能指向不稳定分支。

4.4 容器内时区错误:日志时间比宿主机快8小时

现象docker logs -t输出的时间戳比宿主机date快8小时(如宿主机2024-05-20 10:00,日志显示2024-05-20 18:00)。

原因:Docker 官方镜像默认使用 UTC 时区,而宿主机是 CST(UTC+8)。容器内date命令显示 UTC 时间,但日志时间戳由 Docker Daemon 注入,也基于 UTC。

永久解决

# 启动容器时挂载宿主机时区文件 docker run -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro ... # 或在 Dockerfile 中设置 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

提示:对于日志分析,建议统一用 UTC 时间,避免时区转换混乱。ELK、Prometheus 等监控系统默认按 UTC 处理时间戳。

4.5 Windows WSL2 环境常见陷阱:Virtualization Support Not Detected

现象:Docker Desktop 启动失败,报错Virtualization support not detectedDocker Engine failed to start because V

根因与修复

  • WSL2 内核未启用:PowerShell 以管理员身份运行:
    dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart wsl --update wsl --set-default-version 2
  • BIOS 中 Virtualization Technology (VT-x/AMD-V) 未开启:重启电脑进 BIOS(通常 Del/F2/F10),找到AdvancedCPU ConfigurationIntel Virtualization Technology,设为Enabled
  • Hyper-V 冲突:Windows 专业版/企业版默认启用 Hyper-V,与 WSL2 冲突。禁用:dism.exe /online /disable-feature /featurename:Microsoft-Hyper-V /all /norestart,然后重启。

实操心得:WSL2 是目前 Windows 上 Docker 开发体验最好的方案。Docker Desktop for Windows 本质就是管理 WSL2 中的 Linux 发行版。放弃旧的“Docker Toolbox”(基于 VirtualBox),那是 2015 年的技术。

5. 从基础命令到生产就绪:三个必须跨越的认知台阶

学完命令,你会发现自己能跑通 demo,但一到真实项目就手足无措。这不是技术问题,而是认知断层。我带过的上百个新人,几乎都卡在这三道坎上。跨过去,你就从“会用 Docker”变成“懂容器化”。

5.1 台阶一:从“运行容器”到“理解镜像分层与存储驱动”

docker images显示的镜像大小,和docker system df显示的磁盘占用,往往差几倍。为什么?因为镜像不是单个文件,而是由多个只读层(layer)叠加而成,共享底层数据。docker pull下载的是这些层,docker run启动时在顶部加一个可写层(container layer)。

  • 分层原理:每条Dockerfile指令(FROM,RUN,COPY)生成一层。RUN apt update && apt install nginx是一层,COPY nginx.conf /etc/nginx/是另一层。层是只读的,按顺序叠加,上层文件覆盖下层同名文件;
  • 存储驱动影响:Linux 默认用overlay2,高效共享层;Windows 用windowsfilter;macOS 通过 HyperKit VM 间接使用overlay2docker info | grep "Storage Driver"查看;
  • 清理磁盘docker system prune -a删除所有未使用的镜像、容器、网络、构建缓存。但注意:它会删掉所有dangling(悬空)镜像,即没有标签且未被任何容器引用的层。生产环境慎用。

实操心得:构建镜像时,把变化少的指令(如apt install)放前面,变化多的(如COPY . /app)放后面。这样代码修改后,只有最后几层需要重建,大幅提升 CI/CD 构建速度。这是Dockerfile优化的核心逻辑。

5.2 台阶二:从“单机部署”到“理解容器编排的本质”

docker run是单机命令,docker-compose是单机编排,Kubernetes是集群编排。它们不是替代关系,而是抽象层级递进:

  • docker run解决“一个进程怎么隔离运行”;
  • docker-compose解决“一组相关进程怎么协同启动、网络互通、依赖管理”;
  • Kubernetes解决“上千个容器怎么跨多台机器调度、自动扩缩容、故障自愈、服务发现”。

一个典型误区:用docker-compose部署生产环境。Compose 设计初衷是开发和测试,它的restart: always不能替代 Kubernetes 的livenessProbe(存活探针)。当容器内进程假死(CPU 100% 但不响应请求),Compose 不会重启它,而 K8s 会。

真实案例:某客户用 Compose 部署 Redis 集群,某节点内存溢出 OOM,容器退出。Compose 自动重启,但新容器启动后因配置错误再次 OOM,形成无限重启循环,而监控系统只看到“容器频繁重启”,无法定位根本原因。迁移到 K8s 后,配置livenessProbe检测redis-cli ping,配合OOMKill事件告警,问题迎刃而解。

5.3 台阶三:从“部署服务”到“构建可审计、可追溯的交付流水线”

docker run是手工操作,docker build是构建环节,docker push是发布环节。真正的生产就绪,是把这三步串成自动化流水线,并确保每个环节可审计。

  • 镜像签名与验证:用cosign对镜像签名,docker trust启用内容信任,确保拉取的镜像是经授权构建的;
  • SBOM(软件物料清单)生成syft扫描镜像,生成 JSON 格式依赖清单,供安全团队审计漏洞;
  • CI/CD 集成:GitHub Actions 中,on: push触发docker build -t $IMAGE_NAME:$GITHUB_SHA .docker push $IMAGE_NAME:$GITHUB_SHA,然后kubectl set image deployment/myapp container=$IMAGE_NAME:$GITHUB_SHA更新 K8s。每次部署都绑定 Git Commit ID,回滚只需kubectl rollout undo deployment/myapp

我的体会:Docker 命令本身很简单,难的是建立一套与之匹配的工程规范。没有规范的docker run,和没有版本管理的git commit一样危险。当你开始思考“这个镜像谁构建的?何时构建的?基于哪个 Git 提交?包含哪些已知漏洞?”,你就真正进入了容器化工程实践的大门。

最后分享一个小技巧:把最常用的docker run命令写成 shell 函数,放在~/.bashrc~/.zshrc里。例如:

# 快速启动一个带 bash 的 Ubuntu 容器,挂载当前目录 dock () { docker run -it --rm -v $(pwd):/workspace -w /workspace ubuntu:22.04 bash }

以后在任意目录下敲dock,就直接进入一个干净的 Ubuntu 环境,exit后容器自动删除。这种“命令即服务”的思维,才是 Docker 真正融入工作流的标志。