📖 Docker 基础概念
什么是Docker?
镜像(Image): 类似于"程序安装包",包含了运行应用所需的所有文件
容器(Container): 类似于"正在运行的程序",是镜像的运行实例
Docker守护进程: 后台运行的Docker服务,负责管理镜像和容器
类比理解
镜像 = 游戏安装包(.exe文件)
容器 = 正在运行的游戏程序
Docker = 游戏平台(如Steam)🔧 脚本中使用的Docker命令详解
1. 环境检查命令
command -v docker
# 作用:检查docker命令是否存在
# 类似于:which docker
# 返回:如果找到返回路径,否则返回空
if ! command -v docker &> /dev/null; then
echo "Docker未安装"
fidocker info
# 作用:显示Docker系统信息
# 检查:Docker服务是否正在运行
# 输出:Docker版本、容器数量、镜像数量等信息
docker info
# 如果Docker服务未启动,会报错:Cannot connect to the Docker daemon2. 容器管理命令
docker ps
# 作用:列出容器
docker ps # 只显示正在运行的容器
docker ps -a # 显示所有容器(包括已停止的)
# 输出格式:
# CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMESdocker stop
# 作用:优雅停止容器
docker stop container_name
# 工作原理:
# 1. 发送SIGTERM信号给容器内的主进程
# 2. 等待10秒让程序自己关闭
# 3. 如果还没关闭,发送SIGKILL强制终止docker rm
# 作用:删除容器
docker rm container_name
# 注意:
# - 只能删除已停止的容器
# - 删除后容器的所有数据都会丢失(除非使用了数据卷)docker run
# 作用:从镜像创建并启动新容器
# 这是最复杂但最重要的命令
docker run [选项] 镜像名 [命令]
# 常用选项解释:
-d # 后台运行(detached)
--name my-app # 给容器命名
-p 8080:80 # 端口映射:主机端口:容器端口
-e KEY=value # 设置环境变量
--restart unless-stopped # 重启策略
-v /host:/container # 挂载目录(数据持久化)脚本中的完整运行命令:
docker run -d \
--name "stack-game-app" \ # 容器名称
--restart unless-stopped \ # 重启策略
-p "9527:9527" \ # 端口映射
-e NODE_ENV=production \ # 环境变量1
-e PORT="9527" \ # 环境变量2
"stack-game:latest" # 镜像名称3. 镜像管理命令
docker build
# 作用:从Dockerfile构建镜像
docker build -t 镜像名:标签 构建上下文路径
# 参数解释:
-t stack-game:latest # 打标签,格式:名称:版本
. # 构建上下文为当前目录
# 工作流程:
# 1. Docker客户端将当前目录所有文件打包发送给Docker守护进程
# 2. Docker守护进程读取Dockerfile文件
# 3. 按照Dockerfile的指令逐步构建镜像
# 4. 每个指令都会创建一个新的镜像层docker images
# 作用:列出本地镜像
docker images
# 输出格式:
# REPOSITORY | TAG | IMAGE ID | CREATED | SIZEdocker rmi
# 作用:删除镜像
docker rmi 镜像名:标签
# 注意:
# - 不能删除正在被容器使用的镜像
# - 需要先停止并删除使用该镜像的容器4. 日志和调试命令
docker logs
# 作用:查看容器日志
docker logs container_name # 查看所有日志
docker logs container_name -f # 实时跟踪日志(类似tail -f)
docker logs container_name --tail 20 # 只看最后20行
# 日志来源:
# - 容器内应用写入 stdout 和 stderr 的内容
# - 包括console.log、print、echo等输出docker exec
# 作用:在运行的容器内执行命令
docker exec -it container_name sh # 进入容器的shell
docker exec container_name ls /app # 在容器内执行ls命令
# 参数解释:
-i # 交互模式,保持STDIN开放
-t # 分配伪终端,让命令行更友好🚀 脚本执行流程图
开始
↓
检查Docker是否安装 ──→ 未安装 ──→ 退出并提示安装
↓ 已安装
检查Docker服务是否运行 ──→ 未运行 ──→ 退出并提示启动
↓ 正在运行
清理现有容器
↓
清理现有镜像(可选)
↓
构建新镜像 ──→ 构建失败 ──→ 退出并显示错误
↓ 构建成功
启动新容器 ──→ 启动失败 ──→ 退出并显示错误
↓ 启动成功
等待应用启动(10秒)
↓
健康检查(最多10次)──→ 检查失败 ──→ 退出并显示日志
↓ 检查成功
显示成功信息和管理命令
↓
结束🔍 深入理解:为什么这样设计?
1. 为什么要先清理现有容器?
# 问题:如果不清理,会发生什么?
# 1. 端口冲突 - 9527端口已被占用
# 2. 容器名冲突 - stack-game-app 名称已存在
# 3. 资源浪费 - 旧容器继续占用内存
# 解决方案:
docker stop old_container # 优雅停止
docker rm old_container # 删除容器2. 为什么要进行健康检查?
# 容器启动 ≠ 应用可用
# 可能的情况:
# 1. 容器启动了,但应用还在初始化
# 2. 应用启动失败,但容器进程没有退出
# 3. 依赖服务连接失败
# 健康检查确保:
curl http://localhost:9527/health # 应用真正可用3. 为什么使用多阶段构建?
# 阶段1:构建环境(体积大,包含开发工具)
FROM node:18-alpine AS builder
RUN npm install # 安装所有依赖
RUN npm run build # 构建前端
# 阶段2:生产环境(体积小,只包含运行时)
FROM node:18-alpine AS production
COPY --from=builder /app/dist ./dist # 只复制构建结果
# 优势:
# - 最终镜像体积更小
# - 不包含开发工具,更安全
# - 构建过程更清晰🛠️ 实践练习
练习1:基础命令
# 1. 查看Docker版本
docker --version
# 2. 查看系统信息
docker info
# 3. 列出所有容器
docker ps -a
# 4. 列出所有镜像
docker images练习2:运行一个简单容器
# 1. 运行nginx容器
docker run -d --name my-nginx -p 8080:80 nginx
# 2. 访问应用
curl http://localhost:8080
# 3. 查看日志
docker logs my-nginx
# 4. 进入容器
docker exec -it my-nginx bash
# 5. 停止并删除
docker stop my-nginx
docker rm my-nginx练习3:理解端口映射
# 启动容器,映射不同端口
docker run -d --name test1 -p 8081:80 nginx # 主机8081 → 容器80
docker run -d --name test2 -p 8082:80 nginx # 主机8082 → 容器80
# 验证:
curl http://localhost:8081 # 访问第一个容器
curl http://localhost:8082 # 访问第二个容器
# 清理
docker stop test1 test2
docker rm test1 test2💡 常见错误和解决方法
1. 端口已被占用
# 错误信息:bind: address already in use
# 原因:端口9527已被其他程序占用
# 解决方法:
# 查找占用端口的程序
netstat -tlnp | grep 9527
# 或者
lsof -i :9527
# 停止占用端口的程序,或使用其他端口
docker run -p 9528:9527 stack-game:latest2. 镜像构建失败
# 常见原因:
# 1. 网络问题 - 无法下载依赖
# 2. Dockerfile语法错误
# 3. 依赖配置错误
# 调试方法:
# 逐步构建,找到失败的步骤
docker build -t test . --no-cache3. 容器启动后立即退出
# 查看退出原因
docker logs container_name
# 常见原因:
# 1. 应用配置错误
# 2. 缺少必要文件
# 3. 权限问题
# 调试方法:
# 进入容器手动启动应用
docker run -it --entrypoint sh stack-game:latest🎓 学习总结
通过这个脚本,学会了:
Docker环境检查 - 确保Docker可用
容器生命周期管理 - 创建、启动、停止、删除
镜像构建和管理 - 从代码到可运行镜像
网络和端口映射 - 让外部访问容器内应用
日志和调试 - 排查问题的方法
健康检查 - 确保应用真正可用