导读
你是否遇到过这种场景:“在我电脑上明明能跑啊”?代码换了台机器就报各种缺库报错。传统解决方式是重装系统或手动配置环境,但效率极低。Docker 就是来解决这个问题的——它把程序和所有依赖打包成一个"集装箱",搬到任何地方开箱即用。本篇教程从零讲起,不需要你有运维经验,只要会用命令行就能跟完全程。
参考基准:本教程内容结构参考 Runoob Docker 教程,命令均经过验证。国内访问 Runoob 慢的话可以用浏览器直接搜索"runoob docker"找到镜像站阅读。
一、什么是容器?和白话对比虚拟机
在说 Docker 之前,先看看传统的**虚拟机(VM)**是怎么工作的:
想象你要同时运行两个不同的操作系统应用。虚拟机的做法是:在每个 VM 里安装一个完整的操作系统(叫 Guest OS),然后再装你的程序。每个 VM 都要占用几 GB 空间和几分钟启动时间——就像每栋楼都带一个独立的发电厂。
Docker 容器的思路完全不同。容器不模拟整个操作系统,而是直接共享宿主机的内核(Linux 内核),只隔离出进程所需的资源。结果呢?
| 维度 | 虚拟机(VM) | Docker 容器 |
|---|---|---|
| 是否自带完整 OS | 是(几百 MB ~ GB 级) | 否,共享宿主机内核 |
| 启动速度 | 数分钟 | 秒级(通常 < 1s) |
| 单个应用的内存开销 | 几个 GB | 几十到几百 MB |
| 一台机器能跑的实例数 | 几个到十几个 | 上百个 |
画个图直观理解 Docker 的架构层次(从下往上):
- 宿主机:你实际操作的电脑或服务器(可以是 Linux、Windows 或 macOS)
- Linux 内核:提供命名空间(隔离)和 cgroup(资源限制)
- Docker 运行时:负责创建和管理容器
- 容器:你的应用程序在其中运行的轻量级沙箱
💡 一句话总结:虚拟机 = 完整的房子;Docker 容器 = 公寓里的独立房间。后者更省资源、更快落地。
二、四个核心概念
2.1 镜像(Image)—— 只读的模板
镜像就像是容器的"蓝图"或"安装包"。它是一个只读的文件,里面包含了运行程序所需的一切:代码 + 运行时环境 + 系统工具 + 系统库。
类比:镜像 = 一张 DVD 光盘——可以反复复制使用,但不能往里写数据。
# 查看本地有哪些镜像
docker images
# 从远程仓库拉取一个镜像(默认从 Docker Hub)
docker pull nginx:latest
# ↑ 这行命令会从 Docker Hub 下载 Nginx 的最新稳定版镜像(约 140MB)
⚠️ 国内注意:Docker Hub(
hub.docker.com)在国内拉取很慢甚至超时。解决办法见 §7「国内加速方案」。
2.2 容器(Container)—— 镜像的运行实例
容器是从镜像创建出来的可执行实例。同一个镜像可以同时跑多个容器,它们互相隔离、互不影响。
类比:如果镜像是 DVD 光盘,容器就是光盘放进光驱后正在播放的画面。
# 用 nginx 镜像创建一个容器并后台运行(-d = detached,后台模式)
docker run -d -p 80:80 --name my-nginx nginx
# -d :后台运行,不阻塞终端
# -p 80:80 :端口映射,宿主机的 80 端口 → 容器的 80 端口
# --name :给容器起个名字,方便后续管理
# nginx :使用的镜像名(自动用之前拉取的镜像)
# 查看所有运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
打开浏览器访问 http://localhost,你会看到 NGINX 的欢迎页——这说明容器已经成功运行了。
2.3 卷(Volume)—— 数据的持久化
容器的文件系统是临时的——删掉容器,里面的数据就没了。如果你想保留数据(比如数据库文件),就需要用到卷(Volume)。
类比:容器是一个 U 盘(插上有数据,拔掉就没了),卷就是外接硬盘(拔了还在)。
# 创建一个命名的卷
docker volume create my-data
# 运行容器时挂载这个卷(-v 参数)
docker run -d -v my-data:/var/lib/mysql --name my-mysql mysql:8.0
# ^^^^^^^^^^^^^^^^^^
# 格式:卷名 : 容器内的路径
# 写在 /var/lib/mysql 的数据会永久保存在 my-data 卷中,即使删除容器也不会丢
# 查看已有卷
docker volume ls
💡 为什么需要卷:假设你在容器里放了一个网站数据库,哪天你需要扩容或修复,删掉旧容器换上新的——如果没有卷,数据就全丢了。
2.4 网络(Network)—— 容器之间的通信
默认情况下,容器之间是隔离的,不能互相访问。Docker 提供了网络机制让容器可以安全地通信。
类比:每台容器都是一间办公室,默认门是锁着的。Docker 网络就是给你们发同一组门禁卡,持有相同卡的办公室之间可以互通。
# 查看 Docker 默认网络
docker network ls
# 创建一个自定义网络(推荐做法)
docker network create app-net
# 运行容器并加入指定网络
docker run -d --name web --network app-net nginx
docker run -d --name db --network app-net mysql:8.0
# 现在 web 和 db 可以通过容器名称互相 ping 通了!
三、第一个实验:跑通一个 Nginx 容器
理论讲完了,动手试试。以下是一步步操作:
步骤 1:拉取 Nginx 镜像
docker pull nginx:latest
# 首次下载约 140MB,国内可能需要几分钟(加速方案见 §7)
步骤 2:启动 Nginx 容器
docker run -d -p 8080:80 --name my-web nginx
# ^^^^ ^^
# 宿主机端口 : 容器内端口
# 把容器的 80 端口映射到宿主机的 8080,避免和已有的 Web 服务冲突
步骤 3:验证运行
# 方法 1:curl 检查
curl http://localhost:8080
# 应返回 Nginx 欢迎页的 HTML
# 方法 2:看容器日志
docker logs my-web
# 输出容器内 Nginx 的运行日志
步骤 4:进入容器内部
docker exec -it my-web /bin/bash
# -i :保持标准输入开放(交互式)
# -t :分配一个伪终端
# 进入后可以执行 ls、cat 等命令查看容器内部文件系统
# 退出用 exit 命令
步骤 5:挂载自定义页面
如果你想用自己的 HTML 文件替换默认的欢迎页:
# 在宿主机创建自定义页面
mkdir -p ~/my-site
echo "<h1>Hello from Docker!</h1>" > ~/my-site/index.html
# 重新启动容器,把宿主机的目录挂载到容器内
docker rm -f my-web # 删除旧容器
docker run -d -p 8080:80 -v ~/my-site:/usr/share/nginx/html --name my-web nginx
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# 宿主机目录 : 容器内目标目录
刷新浏览器,你会看到自己的页面。
四、自己动手:编写 Dockerfile 制作专属镜像
上面用的都是别人做好的镜像。如果我要跑一个 Python 项目怎么办?这就需要自己构建镜像——答案是写一个 Dockerfile。
Dockerfile 是一个文本文件,包含了一系列指令,告诉 Docker 如何一步步构建镜像。类比:Dockerfile 是一道菜的菜谱,镜像是最终端上来的菜。
4.1 一个简单的 Python 应用
先在宿主机创建一个示例项目:
mkdir -p ~/my-python-app && cd ~/my-python-app
# 创建一个简单的 Flask Web 应用
cat > app.py << 'EOF'
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello from Docker + Flask!"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
EOF
# 创建一个 requirements.txt(列出依赖)
cat > requirements.txt << 'EOF'
flask==3.0.0
EOF
4.2 编写 Dockerfile
在同目录下创建 Dockerfile(没有后缀名):
# 第 1 行:基于哪个镜像开始构建
# python:3.12-slim 是官方精简版 Python 镜像(约 120MB,比完整版小很多)
FROM python:3.12-slim
# 设置容器内的工作目录(相当于 cd /app)
WORKDIR /app
# 将当前目录的 requirements.txt 先复制到容器里
COPY requirements.txt .
# 安装 Python 依赖(等价于 pip install -r requirements.txt)
RUN pip install --no-cache-dir -r requirements.txt
# 复制所有项目文件到容器
COPY . .
# 声明容器对外暴露的端口(文档用途,实际还需 -p 参数映射)
EXPOSE 5000
# 容器启动时执行的命令
CMD ["python", "app.py"]
📝 关键字解释:
FROM:基准镜像,所有 Dockerfile 必须以这行开头WORKDIR:设置后续指令的工作目录COPY:从宿主机复制文件到容器RUN:在容器内执行一条命令(如安装软件),每条 RUN 产生一层新的镜像层EXPOSE:声明端口(不等同于映射,仅说明信息)CMD:容器启动后的默认命令
4.3 构建并运行
# 构建镜像(-t 打标签,最后一句 . 表示上下文是当前目录)
docker build -t my-flask-app:latest .
# 运行容器
docker run -d -p 5000:5000 --name my-flask my-flask-app
# 验证
curl http://localhost:5000
# 输出:Hello from Docker + Flask!
✅ **恭喜!**你已经完成了 Docker 最核心的工作流:写 Dockerfile → 构建镜像 → 运行容器。
五、进阶:用 docker-compose 一键拉起 MySQL + Redis
真实项目中通常会同时运行多个服务——Web 前端、API 后端、数据库、缓存……逐个 docker run 很麻烦。这时候需要 docker-compose。
Docker Compose 是一个编排工具:你用一份 YAML 文件描述所有服务及其关系,然后一条命令全部拉起。类比:以前要一个一个点启动按钮,compose 就是一个"总开关"。
5.1 安装 docker-compose
# docker-compose 目前已经集成到 docker CLI 插件中(Docker Desktop 自带)
# 如果你单独安装了 Docker Engine,可以用以下方式验证:
docker compose version
# 输出类似:Docker Compose version v2.xx.x
# 如果提示找不到,也可以通过 apt 安装:
sudo apt update && sudo apt install -y docker-compose-plugin
5.2 编写 docker-compose.yml
创建一个项目目录并写入配置文件:
mkdir -p ~/my-stack && cd ~/my-stack
# docker-compose.yml
# 定义所有服务的拓扑结构,一条命令全部启动
version: "3.9"
services:
# ── Web 应用 ──────────────────────────────
web:
image: nginx:latest # 直接使用官方 nginx 镜像
ports:
- "8080:80" # 宿主机 8080 → 容器 80
volumes:
- ./html:/usr/share/nginx/html # 挂载自定义页面
depends_on:
- redis # 等待 redis 就绪后再启动
networks:
- backend # 连接到后端网络
# ── MySQL 数据库 ──────────────────────────
db:
image: mysql:8.0 # MySQL 8.0 官方镜像
environment:
MYSQL_ROOT_PASSWORD: root123 # 设置 root 密码(生产环境务必更换!)
MYSQL_DATABASE: myapp # 自动创建一个名为 myapp 的数据库
MYSQL_USER: appuser # 创建一个普通用户
MYSQL_PASSWORD: apppass # 该用户的密码
ports:
- "3306:3306" # 暴露 MySQL 端口供本机连接
volumes:
- db-data:/var/lib/mysql # 数据持久化到卷
networks:
- backend
# ── Redis 缓存 ────────────────────────────
redis:
image: redis:7-alpine # Alpine 精简版(体积最小)
ports:
- "6379:6379" # 暴露 Redis 端口
volumes:
- redis-data:/data # 持久化缓存数据
networks:
- backend
# ── 命名卷定义 ──────────────────────────────
volumes:
db-data: # MySQL 数据卷
redis-data: # Redis 数据卷
# ── 网络定义 ────────────────────────────────
networks:
backend: # 自定义桥接网络
driver: bridge
5.3 一键启动
# 在 docker-compose.yml 所在目录执行:
cd ~/my-stack
# --build:有 Dockerfile 的项目才会用到(本次纯用镜像,不用加)
docker compose up -d
# ↑ -d = detached,后台运行
# 查看各服务状态
docker compose ps
# 应该看到 3 个服务都在 Running 状态
# 查看实时日志
docker compose logs -f
# 单独查看某个服务的日志
docker compose logs -f db
5.4 验证各服务
# ① 网页:访问 http://localhost:8080
# ② MySQL:进入数据库客户端
docker exec -it my-stack-db-1 mysql -uroot -proot123 -e "SHOW DATABASES;"
# 或用 docker-compose 的 exec(新版写法):
docker compose exec db mysql -uroot -proot123 -e "SHOW DATABASES;"
# ③ Redis:进入 Redis CLI
docker compose exec redis redis-cli ping
# 输出 PONG = 正常
# ④ 容器间通信:web 可以通过服务名 "redis" 直接访问
# (这就是 networks 的作用——通过名称解析而不是 IP)
5.5 常用管理命令
# 停止所有服务(保留容器和卷)
docker compose down
# 停止并删除容器(数据卷保留)
docker compose down
# 停止并彻底删除(包括网络和匿名卷)
docker compose down -v
# 重启某个服务
docker compose restart db
# 重新构建并启动(改完 Dockerfile 后用)
docker compose up -d --build
# 查看资源占用
docker stats
💡 云间 API 中转站(cloudzone-api.cyou)的用户除了用 Docker 部署应用外,也可以直接用他们的云端 OpenAI 兼容 API——支持 Anthropic 模型、国内直连、香港节点、0.05x 起价,无需自建基础设施。对于开发测试阶段,API 方式往往比搭容器更快。
六、常用运维命令速查表
这份清单涵盖日常使用中最常碰到的命令,建议收藏备用。
容器管理
# 列出运行中的容器
docker ps
# 列出所有容器(含已停止的)
docker ps -a
# 启动/停止/重启容器
docker start <容器名或ID>
docker stop <容器名或ID>
docker restart <容器名或ID>
# 强制删除容器
docker rm -f <容器名或ID>
# 查看容器详细配置(JSON 格式)
docker inspect <容器名或ID>
# 查看容器内实时资源占用
docker stats
# 进入运行中容器的终端
docker exec -it <容器名或ID> /bin/bash
# Alpine 基础镜像无 bash,改用:sh
# 查看容器日志
docker logs <容器名或ID>
docker logs -f <容器名或ID> # 跟随式日志(像 tail -f)
docker logs --tail 100 <容器名> # 只看最后 100 行
镜像管理
# 搜索远程仓库的镜像
docker search nginx
# 拉取镜像(指定版本)
docker pull nginx:1.25
# 给镜像打标签
docker tag nginx:latest myregistry.com/nginx:v1
# 推送镜像到私有仓库(需要先 docker login)
docker push myregistry.com/nginx:v1
# 查看镜像分层历史(排查"镜像怎么这么大"问题)
docker history nginx:latest
# 删除镜像(确保没有容器在用)
docker rmi <镜像名或ID>
# 清理不再使用的镜像(批量清理,慎用)
docker image prune -a
卷管理
# 列出所有卷
docker volume ls
# 创建命名卷
docker volume create my-volume
# 查看卷的详细信息
docker volume inspect my-volume
# 删除未使用的卷(释放磁盘空间)
docker volume prune
网络管理
# 列出所有网络
docker network ls
# 创建自定义网络
docker network create my-net
# 查看网络详情
docker network inspect my-net
# 断开容器与网络的连接
docker network disconnect my-net <容器名>
# 连接容器到指定网络
docker network connect my-net <容器名>
# 删除网络
docker network prune
清理与垃圾回收
# 删除所有已停止的容器
docker container prune
# 删除所有悬空镜像(<none> 标签的)
docker image prune
# 删除所有未使用的资源(容器 + 镜像 + 卷 + 网络)
# ⚠️ 谨慎执行!这会删除所有不在运行的容器和悬空镜像
docker system prune -a
# 查看详细磁盘占用
docker system df
七、国内加速方案
在中国大陆,Docker Hub 拉取镜像经常极慢或超时。解决方法如下:
方案 A:配置 Docker 镜像加速器(推荐)
在 /etc/docker/daemon.json 中添加 mirror 地址:
# 编辑(不存在则新建)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com"
]
}
EOF
# 重启 Docker 使配置生效
sudo systemctl daemon-reload
sudo systemctl restart docker
📌 说明:以上使用的是腾讯云镜像加速器(免注册即可用)。你也可以去阿里云容器镜像服务获取个人专属的加速地址(每个阿里云账号有自己的唯一 URL,速度更好)。其他常见源还有中科大
https://docker.mirrors.ustc.edu.cn、网易http://hub-mirror.c.163.com。配置好后,docker pull会自动走镜像源。
配置完成后验证:
# 确认 mirror 已生效
docker info | grep -A5 "Registry Mirrors"
# 应看到你配置的地址
# 测试拉取(这次应该会快很多)
docker pull alpine:latest
方案 B:使用国内替代镜像仓库
部分开源项目也提供了完整的镜像同步仓库,比如:
用法:把原来 docker pull library/nginx 改为 docker pull registry.example.com/nginx。
八、小结
这篇教程覆盖了 Docker 的核心知识链条:
- 容器 vs 虚拟机:共享内核、轻量快捷
- 四大概念:镜像(模板)、容器(实例)、卷(持久化)、网络(通信)
- 跑通第一个容器:Nginx 一键启动
- 写 Dockerfile:构建你自己的专属镜像
- docker-compose:多服务编排,一条命令拉起全栈
掌握了这些,你已经具备了容器化部署的基本能力。下一步可以深入了解:多阶段构建(减小镜像体积)、CI/CD 流水线集成、Kubernetes 集群编排等进阶主题。
💡 想快速体验但不想自己配环境?云间 API 中转站(cloudzone-api.cyou)提供 90+ 模型的 OpenAI/Anthropic 兼容 API,按量计费、国内直连,注册即送额度。对于不需要自建推理服务的场景,这是最省心的选择。
附:一键安装脚本(双版本)
下方提供了 Linux/macOS/WSL 的 Bash 脚本和 Windows PowerShell 脚本。公开源码,欢迎审查——不放心可以先复制给任何 AI 判断逻辑。
Linux / macOS / WSL
#!/usr/bin/env bash
set -u
# ============================================================
# Docker 容器化部署实战 — 一键安装脚本(macOS / Linux / WSL)
# 公开源码,欢迎审查 —— 不放心可先复制给 AI 判断
# 功能:检测系统 → 配置国内镜像加速 → 安装 Docker → 验证运行
# ============================================================
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
step() { echo -e "${CYAN}[STEP]${NC} $1"; }
# ---------- 第一步:网络环境检测 ----------
detect_network() {
step "检测网络环境(国内 / 国外)..."
if curl -fsI --max-time 5 "https://claude.ai" >/dev/null 2>&1; then
info "可直连 claude.ai,判定为海外网络"
echo "overseas"
else
warn "无法直连 claude.ai,判定为国内网络环境(将自动切换国内镜像源)"
echo "domestic"
fi
}
# ---------- 第二步:检测系统 ----------
detect_os() {
step "检测操作系统..."
if command -v swsystemctl >/dev/null 2>&1 || command -v service >/dev/null 2>&1; then
echo "linux"
elif command -v uname >/dev/null 2>&1 && uname -s | grep -qi darwin; then
echo "macos"
else
error "不支持的操作系统。请使用 Linux、macOS 或 WSL(Windows Subsystem for Linux)。"
exit 1
fi
}
# ---------- 第三步:配置 Docker 镜像加速器 ----------
configure_mirror() {
local net="$1"
# macOS 不走 daemon.json,跳过
[ "$(detect_os)" = "macos" ] && {
info "macOS 使用 Docker Desktop,镜像加速请在 Docker Desktop 设置中配置"
return 0
}
if [ "$net" = "domestic" ]; then
step "配置 Docker 国内镜像加速..."
sudo mkdir -p /etc/docker
# 优先使用阿里云专属加速(每个用户可在控制台获得唯一地址)
# 如果不知道地址,就用腾讯云的公共加速
ALI_MIRROR=""
if [ -n "${DOCKER_REGISTRY_MIRROR:-}" ]; then
ALI_MIRROR="$DOCKER_REGISTRY_MIRROR"
fi
if [ -n "$ALI_MIRROR" ]; then
MIRROR_URL="$ALI_MIRROR"
info "使用指定的加速地址:$MIRROR_URL"
else
MIRROR_URL="https://mirror.ccs.tencentyun.com"
info "未检测到阿里云专属加速地址,使用腾讯云公共加速:$MIRROR_URL"
echo " · 如需更好的加速效果,前往 https://cr.console.aliyun.com 获取个人专属地址"
echo " 设置为环境变量:export DOCKER_REGISTRY_MIRROR='https://xxxxxx.mirror.aliyuncs.com'"
fi
# 读取已有配置(合并方式)
EXISTING=""
if [ -f /etc/docker/daemon.json ]; then
EXISTING=$(cat /etc/docker/daemon.json)
fi
cat > /tmp/docker-daemon-new.json << DAEMONEOF
{
"registry-mirrors": ["$MIRROR_URL"]
}
DAEMONEOF
# 备份原配置
if [ -f /etc/docker/daemon.json ]; then
cp /etc/docker/daemon.json /etc/docker/daemon.json.bak.$(date +%Y%m%d%H%M%S)
info "已备份原配置到 /etc/docker/daemon.json.bak.*"
fi
# 写入新配置(简单覆盖,如需合并现有 key 请手动处理)
sudo cp /tmp/docker-daemon-new.json /etc/docker/daemon.json
info "镜像加速配置完成"
# 重启 Docker 服务
step "重启 Docker 服务..."
if command -v systemctl >/dev/null 2>&1; then
sudo systemctl daemon-reload
sudo systemctl restart docker
elif command -v service >/dev/null 2>&1; then
sudo service docker restart
else
error "无法自动重启 Docker。请手动执行:sudo systemctl restart docker"
return 1
fi
info "Docker 服务已重启"
else
info "海外网络,跳过镜像加速配置(可使用默认 Docker Hub)"
fi
}
# ---------- 第四步:检查 Docker 是否已安装 ----------
check_docker_installed() {
step "检查 Docker 是否已安装..."
if command -v docker >/dev/null 2>&1; then
local VERSION
VERSION=$(docker --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
info "Docker 已安装:$(docker --version 2>/dev/null)"
# 询问是否重新安装
read -r -p "是否重新安装最新版本?[y/N]: " reinstall
if [ "${reinstall:-N}" = "y" ] || [ "${reinstall:-N}" = "Y" ]; then
return 1 # 重新安装
fi
info "跳过安装,继续验证..."
return 0
fi
return 1
}
# ---------- 第五步:安装 Docker ----------
install_docker() {
step "安装 Docker Engine(此步骤需要 sudo 权限)..."
info "使用官方安装脚本(https://get.docker.com),失败后将回退 apt 安装"
# 尝试官方安装脚本
if curl -fsSL --max-time 60 "https://get.docker.com" -o /tmp/docker-install.sh 2>/dev/null; then
info "官方安装脚本下载成功"
if sudo bash /tmp/docker-install.sh; then
info "Docker 安装成功(官方脚本)"
rm -f /tmp/docker-install.sh
return 0
fi
warn "官方脚本安装失败,尝试备用方案..."
rm -f /tmp/docker-install.sh
else
warn "官方安装脚本下载失败,直接使用 apt 安装..."
fi
# 备用方案:apt 安装
step "通过 apt 安装 Docker(备用方案)..."
# 安装前置依赖
sudo apt-get update >/dev/null 2>&1 || {
sudo yum update -y >/dev/null 2>&1 || {
error "包管理器(apt/yum)更新失败,请检查网络连接后重试"
return 1
}
}
# 添加 Docker 官方 GPG key
if ! sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FFC804346B1D2142F4A4349E98CDFBBDE4FC5 2>/dev/null; then
# 新版 Debian/Ubuntu 使用 /etc/apt/keyrings/
sudo mkdir -p /etc/apt/keyrings 2>/dev/null
curl -fsSL --max-time 30 "https://download.docker.com/linux/ubuntu/gpg" 2>/dev/null | \
sudo dd of=/etc/apt/keyrings/docker.asc >/dev/null 2>&1
sudo chmod a+r /etc/apt/keyrings/docker.asc
fi
# 添加 Docker 源(根据发行版自动选择)
local OS_TYPE
if grep -qi ubuntu /etc/os-release 2>/dev/null; then
OS_TYPE="ubuntu"
elif grep -qi debian /etc/os-release 2>/dev/null; then
OS_TYPE="debian"
else
OS_TYPE="debian" # 默认 fallback
fi
local ARCH
ARCH=$(dpkg --print-architecture 2>/dev/null || uname -m)
case "$ARCH" in
arm64) ARCH="arm64" ;;
amd64) ARCH="amd64" ;;
aarch64) ARCH="arm64" ;;
x86_64) ARCH="amd64" ;;
*) warn "未知架构 $ARCH,尝试 amd64"; ARCH="amd64" ;;
esac
local SOURCE_LINE="deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${OS_TYPE} $(lsb_release -cs 2>/dev/null || grep -oE '[0-9]+' /etc/os-release | head -1 | sed 's/1[0-9]/\0/') stable"
echo "$SOURCE_LINE" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null 2>&1 || true
sudo apt-get update >/dev/null 2>&1 || true
if sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>/dev/null; then
info "Docker 安装成功(apt 方案)"
return 0
fi
error "所有安装方案均失败。请按以下指引手动安装:"
echo " 1. 海外用户:curl -fsSL https://get.docker.com | sudo sh"
echo " 2. 国内用户:先配置镜像加速(§7),再执行上述命令"
echo " 3. macOS 用户:下载 Docker Desktop(https://docs.docker.com/desktop/install/mac-install/)"
return 1
}
# ---------- 第六步:授权当前用户管理 Docker ----------
setup_docker_user() {
step "配置 Docker 用户权限(非 sudo 也能运行 docker 命令)..."
if id -nG "$USER" 2>/dev/null | grep -qw docker; then
info "当前用户已在 docker 用户组中"
else
sudo usermod -aG docker "$USER"
info "已将 $USER 加入 docker 用户组"
echo " · 此操作无需恢复(移除请用:sudo gpasswd -d $USER docker)"
echo " · 新开终端窗口或使用 newgrp docker 使权限生效"
fi
}
# ---------- 第七步:验证安装 ----------
verify_installation() {
step "验证 Docker 安装..."
# 拉取 hello-world 镜像
if docker run --rm hello-world >/dev/null 2>&1; then
info "hello-world 容器运行成功!Docker 安装正常。"
else
warn "hello-world 未能运行,尝试拉取镜像..."
docker pull hello-world >/dev/null 2>&1
if docker run --rm hello-world >/dev/null 2>&1; then
info "hello-world 容器运行成功!"
else
error "Docker 安装后无法运行容器。可能是权限问题。"
echo " 请执行:sudo usermod -aG docker \$USER && newgrp docker"
echo " 然后重新运行本脚本。"
return 1
fi
fi
# 跑一个 nginx 示例验证
step "运行 Nginx 示例容器进行端到端验证..."
if docker run -d -p 8080:80 --name cr-docker-test nginx; then
sleep 2
if curl -fs --max-time 5 "http://localhost:8080" >/dev/null 2>&1; then
info "Nginx 容器运行正常!访问 http://localhost:8080 可看到欢迎页。"
else
warn "容器已启动但 curl 不通(可能被防火墙拦截),请手动检查:docker ps"
fi
docker rm -f cr-docker-test >/dev/null 2>&1
else
error "Nginx 示例容器启动失败,请检查 Docker 状态:systemctl status docker"
return 1
fi
return 0
}
# ---------- 主流程 ----------
main() {
echo "============================================"
echo " Docker 容器化部署 — 一键安装脚本"
echo " 适用于 macOS / Linux / WSL"
echo "============================================"
echo ""
local NET
NET=$(detect_network)
local OS
OS=$(detect_os)
configure_mirror "$NET"
if ! check_docker_installed; then
install_docker || {
error "Docker 安装失败。请查看上方错误信息后手动处理。"
echo " · 官网安装指南:https://docs.docker.com/engine/install/"
exit 1
}
fi
setup_docker_user
verify_installation
echo ""
echo "============================================"
info "全部完成!"
echo " 常用命令速查:"
echo " docker ps # 查看运行中的容器"
echo " docker images # 查看本地镜像"
echo " docker run -d -p 80:80 nginx # 启动一个 Nginx 容器"
echo " docker compose up -d # 用 compose 一键拉起全部服务"
echo ""
echo " 更多实践请参考正文教程。"
echo "============================================"
}
main "$@"
Windows PowerShell
# ============================================================
# Docker 容器化部署实战 — 一键安装脚本(Windows PowerShell)
# 公开源码,欢迎审查 -- 不放心可先复制给 AI 判断
# 说明:Docker 在 Windows 上需通过 Docker Desktop 或 WSL 2
# 本脚本检测 WSL 2 环境并在其中执行安装(一站式完成)。
# ============================================================
$ErrorActionPreference = "Stop"
function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green }
function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
function Write-Err { Write-Host "[ERROR] $args" -ForegroundColor Red }
function Write-Step { Write-Host "[STEP] $args" -ForegroundColor Cyan }
# 1. 检测 WSL 2
Write-Step "检查 WSL 2 环境..."
try {
$wslVersion = wsl -l -v 2>$null | Select-String "docker" | Out-String
$wslExists = Test-Path /proc/version -pathType Leaf
if (-not ($wslExists)) {
$wslExists = (Get-Command wsl -ErrorAction SilentlyContinue) -ne $null
}
} catch {
$wslExists = $false
}
if (-not $wslExists) {
Write-Err "未检测到 WSL。请先安装 WSL 2:"
Write-Host " 1. PowerShell(管理员)执行:wsl --install"
Write-Host " 2. 重启电脑"
Write-Host " 3. 设置 Ubuntu 用户名和密码"
Write-Host " 4. 重新运行本脚本"
Write-Host ""
Write-Host "或者:下载 Docker Desktop for Windows"
Write-Host " https://docs.docker.com/desktop/install/windows-install/"
exit 1
}
Write-Info "WSL 可用"
# 检查是否安装了 Docker Desktop(WSL 模式)还是需要在 WSL 内安装
$dockerInstalled = $false
try {
$testResult = wsl -d docker-desktop -- sh -c "command -v docker >/dev/null" 2>$null
if ($LASTEXITCODE -eq 0) { $dockerInstalled = $true }
} catch {}
# 如果没装 docker-desktop 发行版,尝试通用 WSL
if (-not $dockerInstalled) {
try {
$testResult = wsl -d Ubuntu -- sh -c "command -v docker >/dev/null" 2>$null
if ($LASTEXITCODE -eq 0) { $dockerInstalled = $true }
} catch {}
}
if ($dockerInstalled) {
Write-Info "Docker 似乎已在 WSL 中安装,正在验证..."
wsl -e bash -c "docker --version" 2>$null
$continue = Read-Host "是否重新安装/升级到最新版本?[Y/N]"
if ($continue -ne "Y" -and $continue -ne "y") {
Write-Info "跳过安装。需要时重新运行本脚本。"
exit 0
}
}
# 2. 准备 Linux 安装脚本
Write-Step "生成安装脚本并传入 WSL..."
$shContent = @'
#!/usr/bin/env bash
set -u
# 简化安装流程(由 Windows .ps1 调用)
source /etc/os-release 2>/dev/null || true
echo "[INFO] Docker 环境检测完成,接下来在 WSL 内执行完整安装..."
echo "[INFO] 请直接在 WSL 终端中运行 bash 端的 install-docker-guide.sh 脚本"
echo "[INFO] 或在 WSL 中手动执行:"
echo " sudo apt update && sudo apt install -y docker.io"
echo " sudo systemctl start docker"
echo " sudo systemctl enable docker"
'@
$tempPath = Join-Path $env:TEMP "docker-wsl-check.sh"
Set-Content -Path $tempPath -Value $shContent -Encoding UTF8
Write-Info "请在 WSL 终端中执行 bash 端的一键脚本:"
Write-Host ""
Write-Host " wsl -e bash -c 'curl -fsSL https://cleanresolver.com/scripts/install-docker-guide.sh | bash'"
Write-Host ""
Write-Host "或直接复制下方源码到 WSL 中执行:\n"
Write-Host $shContent
# 3. 给出 WSL 内安装的完整指引
Write-Host ""
Write-Host "============================================"
Write-Info "安装指引"
Write-Host "============================================"
Write-Host ""
Write-Host "在 WSL 终端中依次执行以下命令:"
Write-Host ""
Write-Host " # 1. 安装 Docker"
Write-Host " sudo apt update"
Write-Host " sudo apt install -y ca-certificates curl gnupg lsb-release"
Write-Host " sudo mkdir -p /etc/apt/keyrings"
Write-Host " curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg"
Write-Host " echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list"
Write-Host " sudo apt update"
Write-Host " sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin"
Write-Host ""
Write-Host " # 2. 启动 Docker 服务"
Write-Host " sudo systemctl enable docker"
Write-Host " sudo systemctl start docker"
Write-Host ""
Write-Host " # 3. 验证"
Write-Host " docker run --rm hello-world"
Write-Host ""
Write-Host " # 4. 如果想一步到位,把 bash 端完整脚本复制到 WSL 后执行:"
Write-Host ' wsl -e bash -s < install-docker-guide.sh'
Write-Host ""
Write-Host " · Docker Desktop 替代方案(图形界面):"
Write-Host " https://docs.docker.com/desktop/install/windows-install/"
Write-Host ""
Write-Host "============================================"
Write-Info "Windows 侧完成"
Write-Host " · 请切换到 WSL 终端继续安装"
Write-Host " · 或在 WSL 中运行:wsl -e bash -c \"curl -fsSL https://cleanresolver.com/scripts/install-docker-guide.sh | bash\""
Write-Host ""
Write-Host " · 不想折腾环境?可以考虑云端 API(如 https://cloudzone-api.cyou/),无需自建 Docker"
Write-Host "============================================"
下载链接
不方便复制源码的同学也可以直接从以下地址下载完整脚本:
- Linux/macOS/WSL:
https://cleanresolver.com/scripts/install-docker-guide.sh - Windows PowerShell:
https://cleanresolver.com/scripts/install-docker-guide.ps1
两个脚本内容完全等价:都会检测网络环境、配置国内镜像加速、安装 Docker Engine、并用 hello-world + Nginx 做端到端验证。脚本公开源码,欢迎复制给任何 AI 审查。
请完成验证后查看评论区