Docker 完全指南:从入门到日常使用
本文涵盖 Docker 的核心概念、安装配置、常用命令以及实际工作中的使用场景,适合开发者日常参考。
目录
什么是 Docker
Docker 是一个开源的容器化平台,让你可以将应用及其所有依赖打包进一个轻量级、可移植的容器中,实现”一次构建,到处运行”。
与虚拟机的区别:
| 对比项 |
Docker 容器 |
虚拟机 |
| 启动速度 |
秒级 |
分钟级 |
| 资源占用 |
极低(共享宿主内核) |
较高(独立操作系统) |
| 隔离性 |
进程级隔离 |
完全隔离 |
| 镜像大小 |
MB 级别 |
GB 级别 |
| 可移植性 |
极强 |
一般 |
核心概念
镜像(Image)
镜像是容器的只读模板,类似于系统安装盘。镜像是分层构建的,每一层都基于上一层叠加。
容器(Container)
容器是镜像的运行实例,类似于虚拟机实例。容器是独立的、隔离的运行环境,可以启动、停止、删除。
仓库(Registry)
仓库用于存储和分发镜像。Docker Hub 是最大的公共仓库,也可以搭建私有仓库。
Docker Compose
用于定义和运行多容器应用的工具,通过 docker-compose.yml 文件统一管理。
数据卷(Volume)
用于容器数据持久化的机制,容器删除后数据依然保留。
安装 Docker
macOS
1 2 3 4 5
|
brew install --cask docker
|
Ubuntu / Debian
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
| sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
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 > /dev/null
sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo usermod -aG docker $USER newgrp docker
|
CentOS / RHEL
1 2 3 4 5
| sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl start docker sudo systemctl enable docker
|
验证安装
1 2 3 4 5
| docker --version
docker run hello-world
|
镜像操作
搜索镜像
1 2
| docker search nginx docker search --filter=stars=1000 python
|
拉取镜像
1 2 3
| docker pull nginx docker pull nginx:1.25 docker pull ubuntu:22.04
|
查看本地镜像
1 2 3
| docker images docker images -a docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
|
删除镜像
1 2 3 4
| docker rmi nginx docker rmi nginx:1.25 docker image prune docker image prune -a
|
导出 / 导入镜像
1 2 3 4 5
| docker save -o myapp.tar myapp:latest
docker load -i myapp.tar
|
给镜像打标签
1
| docker tag myapp:latest myregistry.com/myapp:v1.0
|
容器操作
运行容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| docker run nginx
docker run -d \ --name my-nginx \ -p 8080:80 \ -v /data/html:/usr/share/nginx/html \ -e NGINX_PORT=80 \ --restart unless-stopped \ nginx:latest
docker run -it ubuntu:22.04 bash
docker run --rm ubuntu:22.04 echo "hello"
|
查看容器
1 2 3
| docker ps docker ps -a docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
启动 / 停止 / 重启
1 2 3 4
| docker start my-nginx docker stop my-nginx docker kill my-nginx docker restart my-nginx
|
进入运行中的容器
1 2 3
| docker exec -it my-nginx bash docker exec -it my-nginx sh docker exec my-nginx ls /etc/nginx
|
查看容器日志
1 2 3 4
| docker logs my-nginx docker logs -f my-nginx docker logs --tail 100 my-nginx docker logs --since 1h my-nginx
|
查看容器详情
1 2 3
| docker inspect my-nginx docker stats docker top my-nginx
|
文件拷贝
1 2 3 4 5
| docker cp ./config.conf my-nginx:/etc/nginx/conf.d/
docker cp my-nginx:/var/log/nginx/access.log ./
|
删除容器
1 2 3
| docker rm my-nginx docker rm -f my-nginx docker container prune
|
数据持久化
数据卷(Volume)— 推荐方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| docker volume create mydata
docker run -d \ --name mysql \ -v mydata:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0
docker volume ls docker volume inspect mydata
docker volume rm mydata docker volume prune
|
绑定挂载(Bind Mount)
1 2 3 4
| docker run -d \ -v /home/user/html:/usr/share/nginx/html:ro \ nginx
|
两种方式对比
| 对比项 |
Volume |
Bind Mount |
| 管理方式 |
Docker 管理 |
用户管理 |
| 可移植性 |
好 |
依赖宿主机路径 |
| 适用场景 |
数据库、应用数据 |
开发时代码热更新 |
网络管理
网络类型
| 类型 |
说明 |
bridge |
默认,容器间可通信,与宿主机隔离 |
host |
共享宿主机网络,性能最好 |
none |
完全隔离,无网络 |
| 自定义 bridge |
推荐,容器间可通过名称互相访问 |
常用命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| docker network ls
docker network create mynet
docker run -d --name app --network mynet myapp docker run -d --name db --network mynet mysql:8.0
docker network inspect mynet
docker network rm mynet docker network prune
|
Dockerfile 编写
Dockerfile 是构建镜像的脚本文件。
常用指令
| 指令 |
说明 |
FROM |
基础镜像 |
WORKDIR |
设置工作目录 |
COPY |
复制文件(推荐) |
ADD |
复制文件(支持 URL 和 tar 解压) |
RUN |
构建时执行命令 |
ENV |
设置环境变量 |
EXPOSE |
声明容器端口(文档作用) |
CMD |
容器启动默认命令(可被覆盖) |
ENTRYPOINT |
容器入口命令(不易被覆盖) |
ARG |
构建参数 |
LABEL |
添加元数据 |
USER |
切换运行用户 |
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
| FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]
|
Python 应用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| FROM python:3.11-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \ gcc \ && rm -rf /var/lib/apt/lists/*
COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
构建镜像
1 2 3
| docker build -t myapp:latest . docker build -t myapp:v1.0 -f Dockerfile.prod . docker build --no-cache -t myapp:latest .
|
Dockerfile 最佳实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| RUN apt-get update \ && apt-get install -y curl wget \ && rm -rf /var/lib/apt/lists/*
FROM node:20-alpine AS builder WORKDIR /app COPY . . RUN npm ci && npm run build
FROM node:20-alpine AS runtime WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules CMD ["node", "dist/server.js"]
|
Docker Compose
安装
1 2 3 4 5
| docker compose version
sudo apt-get install docker-compose-plugin
|
docker-compose.yml 示例
Web 应用 + 数据库 + Redis
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
| version: '3.9'
services: app: build: . container_name: myapp ports: - "3000:3000" environment: - NODE_ENV=production - DB_HOST=db - REDIS_HOST=redis depends_on: db: condition: service_healthy networks: - mynet restart: unless-stopped
db: image: mysql:8.0 container_name: myapp-db environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: myapp MYSQL_USER: user MYSQL_PASSWORD: userpass volumes: - db_data:/var/lib/mysql - ./init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 networks: - mynet restart: unless-stopped
redis: image: redis:7-alpine container_name: myapp-redis volumes: - redis_data:/data networks: - mynet restart: unless-stopped
volumes: db_data: redis_data:
networks: mynet: driver: bridge
|
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
| docker compose up -d
docker compose up -d --build
docker compose ps
docker compose logs -f docker compose logs -f app
docker compose stop
docker compose down
docker compose down -v
docker compose exec app bash
docker compose up -d --scale app=3
docker compose restart app
|
实战示例
场景一:快速启动 MySQL
1 2 3 4 5 6 7 8 9 10 11
| docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -e MYSQL_DATABASE=mydb \ -v mysql_data:/var/lib/mysql \ --restart unless-stopped \ mysql:8.0
docker exec -it mysql8 mysql -uroot -p123456
|
场景二:快速启动 Redis
1 2 3 4 5
| docker run -d \ --name redis \ -p 6379:6379 \ -v redis_data:/data \ redis:7-alpine redis-server --requirepass 123456
|
场景三:Nginx 静态站点
1 2 3 4 5 6
| docker run -d \ --name website \ -p 80:80 \ -v $(pwd)/html:/usr/share/nginx/html:ro \ -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \ nginx:alpine
|
场景四:临时调试工具
1 2 3 4 5 6 7 8
| docker run --rm -it alpine sh
docker run --rm curlimages/curl https://example.com
docker run --rm -v $(pwd):/app -w /app python:3.11 python script.py
|
场景五:私有镜像仓库
1 2 3 4 5 6 7 8 9 10 11 12 13
| docker run -d \ --name registry \ -p 5000:5000 \ -v registry_data:/var/lib/registry \ registry:2
docker tag myapp:latest localhost:5000/myapp:latest docker push localhost:5000/myapp:latest
docker pull localhost:5000/myapp:latest
|
常用技巧与最佳实践
清理空间
1 2 3 4 5
| docker system prune -a
docker system df
|
限制容器资源
1 2 3 4 5
| docker run -d \ --memory="512m" \ --cpus="1.5" \ --memory-swap="1g" \ myapp
|
环境变量管理
1 2 3 4
| docker run --env-file .env myapp
|
健康检查
1 2
| HEALTHCHECK --interval=30s --timeout=10s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1
|
查看镜像构建历史
1
| docker history myapp:latest
|
查看容器 IP
1
| docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
|
容器内时区设置
1 2
| ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
常见问题排查
容器启动失败
1 2 3
| docker logs my-container docker inspect my-container | grep -A 5 '"State"'
|
端口被占用
1 2 3 4
| lsof -i :8080
netstat -tlnp | grep 8080
|
镜像拉取慢
1 2 3 4 5 6 7 8 9 10 11
| { "registry-mirrors": [ "https://mirror.ccs.tencentyun.com", "https://hub-mirror.c.163.com" ] }
sudo systemctl daemon-reload sudo systemctl restart docker
|
容器间无法通信
1 2 3 4 5
| docker network inspect mynet
docker exec app ping db
|
磁盘空间不足
1 2 3
| docker system df docker system prune -a -f docker volume prune -f
|
权限问题
1 2 3 4
| sudo chmod 666 /var/run/docker.sock
sudo usermod -aG docker $USER
|
速查表
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
| docker pull <image> docker images docker rmi <image> docker build -t <name> . docker push <image>
docker run -d -p 80:80 --name x img docker ps / docker ps -a docker start/stop/restart <name> docker exec -it <name> bash docker logs -f <name> docker rm -f <name> docker stats
docker compose up -d docker compose down docker compose logs -f docker compose exec <svc> bash
docker system prune -a docker volume prune
|
最后更新:2025 年 | 适用 Docker 25.x