前言 Docker 是当今最流行的容器化技术。它让”在我机器上能跑啊 “成为历史——将应用及其依赖打包成一个标准化的容器,在任何地方都能一致地运行。
本文将从零开始,带你系统掌握 Docker 的核心操作。
为什么需要 Docker?
痛点
Docker 解决方案
“我电脑上能跑,服务器不行”
环境一致 :容器内环境完全相同
安装 MySQL、Redis 太麻烦
一行命令 跑起来,用完就删
开发环境不一致
共享镜像 ,团队统一环境
微服务部署复杂
Docker Compose 一键编排
资源利用率低
轻量级 ,比虚拟机省资源
核心概念
概念
类比
说明
镜像(Image)
安装光盘 / 类模板
包含运行环境 + 应用的只读模板
容器(Container)
运行中的实例
镜像的运行实例,可启动/停止/删除
仓库(Registry)
App Store
存储和分发镜像(如 Docker Hub)
Dockerfile
配方/菜谱
描述如何构建镜像的文本文件
Docker Compose
编排工具
定义和管理多容器应用
一、环境搭建 1.1 安装 Docker
1 2 3 4 5 6 7 sudo apt updatesudo apt install docker.io docker-compose-v2sudo usermod -aG docker $USER sudo systemctl enable docker --now
1.2 验证安装 1 2 3 4 5 6 7 8 docker --version docker compose version docker run hello-world
二、镜像管理 2.1 搜索镜像 1 2 3 docker search nginx docker search mysql --limit 5
2.2 拉取镜像 1 2 3 4 docker pull nginx docker pull nginx:1.25 docker pull mysql:8.0 docker pull python:3.12-alpine
2.3 查看本地镜像 1 2 3 docker images docker image ls
输出示例:
1 2 3 4 REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 2b7d6430f78d 2 weeks ago 188MB python 3.12-slim 8f1b5a10c8aa 3 weeks ago 152MB hello-world latest d2c94e258dcb 8 months ago 13.3kB
2.4 查看镜像详情 1 2 docker inspect nginx docker history nginx
2.5 删除镜像 1 2 3 4 docker rmi nginx docker rmi 2b7d6430f78d docker image prune docker image prune -a
三、容器操作(最常用)⭐ 3.1 运行容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 docker run nginx docker run -d -p 8080:80 --name my-nginx nginx
实战:一行命令启动 MySQL
1 2 3 4 5 6 7 8 docker run -d \ --name mysql-blog \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=my-secret-pw \ -e MYSQL_DATABASE=my_blog \ -v mysql-data:/var/lib/mysql \ --restart unless-stopped \ mysql:8.0
打开另一个终端测试:
1 2 docker exec -it mysql-blog mysql -u root -p
3.2 查看容器 1 2 3 4 5 docker ps docker ps -a docker ps -a -q docker stats docker top my-nginx
docker ps 输出解读:
1 2 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a1b2c3d4e5f6 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp my-nginx
列
说明
CONTAINER ID
容器唯一标识
IMAGE
使用的镜像
STATUS
运行状态(Up=运行中, Exited=已停止)
PORTS
端口映射关系
3.3 查看容器日志 1 2 3 4 docker logs my-nginx docker logs --tail 50 my-nginx docker logs -f my-nginx docker logs --since 1h my-nginx
3.4 进入容器内部 1 2 3 4 5 6 7 8 9 docker exec -it my-nginx /bin/bash docker exec -it my-nginx /bin/sh ls /etc/nginx/cat /etc/nginx/nginx.conf
3.5 停止、启动、重启 1 2 3 4 5 6 docker stop my-nginx docker stop -t 30 my-nginx docker start my-nginx docker restart my-nginx docker pause my-nginx docker unpause my-nginx
3.6 删除容器 1 2 3 4 docker rm my-nginx docker rm -f my-nginx docker rm $(docker ps -aq) docker container prune
3.7 容器与宿主机之间文件拷贝 1 2 3 4 5 docker cp ./index.html my-nginx:/usr/share/nginx/html/ docker cp my-nginx:/etc/nginx/nginx.conf ./nginx.conf.bak
四、数据卷(Volume)— 持久化数据 容器删除后,容器内的数据也会丢失。数据卷用于持久化数据。
4.1 命名卷(推荐) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker volume create blog-data docker run -d \ --name mysql \ -v blog-data:/var/lib/mysql \ mysql:8.0 docker volume ls docker volume inspect blog-data docker volume rm blog-data docker volume prune
4.2 绑定挂载(开发环境常用) 将宿主机目录直接映射到容器内,实时同步 :
1 2 3 4 5 6 docker run -d \ -p 3000:3000 \ -v $(pwd ):/app \ -v /app/node_modules \ node:20 node /app/index.js
💡 绑定挂载非常适合开发环境——修改代码后容器内自动生效,无需重新构建。
4.3 数据卷对比
方式
适用场景
示例
命名卷
数据库、持久化数据
-v mysql-data:/var/lib/mysql
绑定挂载
开发环境、配置文件
-v ./src:/app/src
tmpfs
临时缓存(内存中)
--tmpfs /tmp
五、Dockerfile — 构建自定义镜像 5.1 第一个 Dockerfile 以 Node.js 项目为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 FROM node:20 -alpine AS builderWORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --production COPY . . RUN npm run build FROM node:20 -alpineWORKDIR /app RUN addgroup -g 1001 app && \ adduser -u 1001 -G app -s /bin/sh -D app COPY --from=builder /app/package.json /app/package-lock.json ./ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist USER appEXPOSE 3000 ENV NODE_ENV=productionCMD ["node" , "dist/main.js" ]
5.2 Dockerfile 常用指令
指令
说明
示例
FROM
基础镜像
FROM python:3.12
WORKDIR
设置工作目录
WORKDIR /app
COPY
复制文件
COPY . /app
ADD
复制文件(支持 URL 和自动解压 tar)
ADD app.tar.gz /app
RUN
构建时执行命令
RUN apt install -y curl
CMD
容器启动时的默认命令
CMD ["python", "app.py"]
ENTRYPOINT
容器入口点(不能被 docker run 后的命令覆盖)
ENTRYPOINT ["nginx"]
ENV
设置环境变量
ENV NODE_ENV=production
EXPOSE
声明端口(文档作用,实际还需 -p 映射)
EXPOSE 80
VOLUME
声明挂载点
VOLUME /data
USER
切换运行用户
USER app
ARG
构建参数
ARG VERSION=1.0
5.3 CMD vs ENTRYPOINT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 CMD ["echo" , "hello" ] ENTRYPOINT ["echo" ] ENTRYPOINT ["python" , "app.py" ] CMD ["--port" , "8000" ]
5.4 构建镜像 1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker build -t my-app:1.0 . docker build -f Dockerfile.prod -t my-app:prod . docker build --build-arg VERSION=2.0 -t my-app:2.0 . docker build --no-cache -t my-app . docker images my-app
5.5 多阶段构建的优势
🪶 镜像体积小 :只保留最终运行需要的文件
🔒 更安全 :不包含编译工具、SDK 等构建依赖
📉 减少攻击面 :只安装运行时依赖
5.6 .dockerignore 类似于 .gitignore,排除不需要的文件,加快构建速度:
1 2 3 4 5 6 7 node_modules .git *.md .DS_Store dist .env .env.local
六、Docker Compose — 多容器编排 当项目需要多个服务(如 Web + MySQL + Redis),Compose 可以一键管理。
6.1 第一个 docker-compose.yml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 version: "3.8" services: web: build: . container_name: my-blog-web ports: - "3000:3000" environment: - DB_HOST=db - DB_USER=root - DB_PASSWORD=${DB_PASSWORD} - REDIS_URL=redis://redis:6379 volumes: - ./src:/app/src - /app/node_modules depends_on: db: condition: service_healthy redis: condition: service_started restart: unless-stopped networks: - blog-network db: image: mysql:8.0 container_name: my-blog-db environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} MYSQL_DATABASE: my_blog volumes: - db-data:/var/lib/mysql - ./init.sql:/docker-entrypoint-initdb.d/init.sql ports: - "3306:3306" healthcheck: test: ["CMD" , "mysqladmin" , "ping" , "-h" , "localhost" ] interval: 10s timeout: 5s retries: 5 restart: unless-stopped networks: - blog-network redis: image: redis:7-alpine container_name: my-blog-redis volumes: - redis-data:/data command: redis-server --appendonly yes restart: unless-stopped networks: - blog-network nginx: image: nginx:alpine container_name: my-blog-nginx ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro depends_on: - web restart: unless-stopped networks: - blog-network volumes: db-data: redis-data: networks: blog-network: driver: bridge
6.2 Compose 常用命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 docker compose up -d docker compose up -d --build docker compose logs docker compose logs -f web docker compose logs --tail =100 docker compose ps docker compose top docker compose stop docker compose down docker compose down -v docker compose restart web docker compose exec web /bin/sh docker compose exec db mysql -u root -p docker compose ls
6.3 .env 文件 1 2 3 4 DB_PASSWORD=my-secret-password NODE_ENV=production DOMAIN=blog.iot2045.cn
6.4 depends_on 与健康检查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 depends_on: - db depends_on: db: condition: service_healthy services: db: image: mysql:8.0 healthcheck: test: ["CMD" , "mysqladmin" , "ping" , "-h" , "localhost" ] interval: 10s timeout: 5s retries: 5 start_period: 30s
七、Docker 网络 7.1 网络类型
网络类型
说明
bridge
默认网络,容器间通过 IP 通信
host
直接使用宿主机网络
none
无网络
overlay
跨主机(Swarm 模式)
7.2 网络命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 docker network ls docker network create my-network docker network inspect my-network docker network connect my-network my-container docker network disconnect my-network my-container docker network rm my-network
7.3 Compose 中的网络 在 docker-compose.yml 中,同一 Compose 文件的服务自动属于同一网络 ,可以通过服务名 互相访问:
1 2 3 4 5 6 7 8 9 services: web: environment: - DB_HOST=db - DB_PORT=3306 db:
八、实战:完整的博客项目 Docker 化 8.1 项目结构 1 2 3 4 5 6 7 8 9 10 my-blog/ ├── docker-compose.yml ├── Dockerfile ├── .dockerignore ├── .env ├── nginx/ │ └── nginx.conf ├── init.sql # 数据库初始化 └── app/ # 应用代码 └── ...
8.2 Nginx 配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 events { worker_connections 1024 ; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local ] ' '"$request " $status $body_bytes_sent ' '"$http_referer " "$http_user_agent " ' 'rt=$request_time ' ; access_log /var/log/nginx/access.log main; upstream web_backend { server web:3000 ; } server { listen 80 ; server_name blog.iot2045.cn; return 301 https://$server_name $request_uri ; } server { listen 443 ssl http2; server_name blog.iot2045.cn; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3 ; location /static/ { root /var/www/html; expires 30d ; add_header Cache-Control "public, immutable" ; } location / { proxy_pass http://web_backend; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; } } }
8.3 数据库初始化脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 CREATE TABLE IF NOT EXISTS articles ( id INT AUTO_INCREMENT PRIMARY KEY , title VARCHAR (200 ) NOT NULL , content LONGTEXT, views INT DEFAULT 0 , created_at DATETIME DEFAULT CURRENT_TIMESTAMP , updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY , username VARCHAR (50 ) NOT NULL UNIQUE , password VARCHAR (255 ) NOT NULL , created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); INSERT IGNORE INTO users (username, password) VALUES ('admin' , '$2y$10$...预先生成的哈希...' );
8.4 启动项目 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 git clone https://gitee.com/yourname/my-blog.git cd my-blogcp .env.example .env docker compose up -d docker compose ps docker compose logs -f curl -I http://localhost
8.5 日常维护命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 docker compose logs -f web docker compose restart web git pull docker compose up -d --build docker compose exec db mysqldump -u root -p my_blog > backup.sql docker compose exec -T db mysql -u root -p my_blog < backup.sql docker system df docker system df -v
九、优化技巧 9.1 减小镜像体积 1 2 3 4 5 6 7 8 9 10 11 12 13 FROM ubuntu:22.04 RUN apt update && apt install -y python3 python3-pip FROM python:3.12 -alpine FROM python:3.12 -slim RUN apt update && apt install -y --no-install-recommends curl \ && rm -rf /var/lib/apt/lists/*
9.2 利用构建缓存 1 2 3 4 5 6 7 8 9 COPY . . RUN npm install COPY package.json package-lock.json ./ RUN npm ci COPY . .
9.3 镜像分层策略 把变化频率最低 的层放在前面:
1 2 基础系统依赖 → 语言运行时 → 依赖安装 → 应用代码 (几乎不变) (偶尔变) (比较常变) (最常变)
十、常用命令速查表
分类
命令
说明
镜像
docker pull image:tag
拉取镜像
镜像
docker images
查看本地镜像
镜像
docker rmi image
删除镜像
镜像
docker build -t name .
构建镜像
容器
docker run -d -p 80:80 --name n nginx
启动容器
容器
docker ps
查看运行中的容器
容器
docker ps -a
查看所有容器
容器
docker stop / start / restart
停/启/重启
容器
docker rm container
删除容器
容器
docker logs -f container
查看日志
容器
docker exec -it container sh
进入容器
容器
docker cp a.txt container:/path
复制文件
系统
docker system prune -a
清理所有无用资源
系统
docker system df
查看磁盘占用
系统
docker stats
资源监控
编排
docker compose up -d
启动服务
编排
docker compose down
停止并删除
编排
docker compose ps
查看服务状态
编排
docker compose logs -f
查看日志
编排
docker compose exec svc sh
进入服务容器
清理命令大全 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 docker system prune docker system prune -a docker container prune docker image prune -a docker volume prune docker system df
十一、部署检查清单 部署到生产环境前,请确认:
进一步学习
Docker Swarm / Kubernetes :容器编排,大规模集群管理
CI/CD 集成 :GitHub Actions + Docker 自动构建部署
镜像仓库 :搭建私有 Registry(如 Harbor)
Docker 网络深入 :overlay、macvlan 等高级网络
安全扫描 :Trivy、Docker Scout 扫描镜像漏洞
结语 Docker 是现代软件开发的标配技能 。它解决了”环境不一致”这一头号痛点,让开发、测试、部署变得简单可控。
本文从零开始,覆盖了 Docker 的核心概念、镜像管理、容器操作、Dockerfile 编写、Compose 编排和实践项目。掌握了这些,你已经可以:
✅ 一键启动 MySQL / Redis / Nginx 等开发环境
✅ 将现有项目 Docker 化
✅ 用 Compose 编排多服务应用
✅ 编写生产级别的 Dockerfile
Build once, run anywhere. 🐳