Docker实战指南:从入门到精通
记得刚接触Docker的时候,我就被它的魅力深深吸引。想象一下,你开发的应用在任何环境里都能保持一致,再也不用经历”在我电脑上明明是好的”这种尴尬场面。今天,我想把这些年的实战经验分享给你,帮你真正掌握Docker这个强大的工具。
目录
初识Docker
什么是Docker?
如果你对容器技术还不熟悉,没关系,我用大白话给你解释一下。
简单来说,Docker就像一个标准化的集装箱。你开发的应用和它的依赖(各种库、环境配置等)打包在这个集装箱里,这个集装箱就可以在任何码头(服务器、本地机器等)都能正常运作,不会出现”水土不服”的情况。
为什么我们需要Docker?
想象一下这个场景:
- 你的开发环境:Ubuntu 20.04,Python 3.8,PostgreSQL 12
- 测试环境:CentOS 7,Python 3.7,PostgreSQL 10
- 生产环境:Ubuntu 18.04,Python 3.8,PostgreSQL 12
没有Docker之前,你可能会遇到:
- 开发环境能跑,测试环境报错
- 本地运行正常,服务器上就是不行
- 依赖版本冲突,各种诡异的错误
有了Docker之后,这些问题基本就消失了,因为每个环境都是完全一致的。
Docker vs 传统虚拟化
传统的虚拟机就像每个虚拟机都运行一个完整的操作系统,而Docker容器则是共享宿主机的内核,只隔离进程和文件系统。
| 特性 | Docker容器 | 虚拟机 |
|---|
| 启动时间 | 秒级 | 分钟级 |
| 资源占用 | 小(MB级) | 大(GB级) |
| 性能 | 接近原生 | 有损耗 |
| 隔离性 | 进程级 | 系统级 |
graph TD A[宿主机] --> B[Docker Engine] B --> C[容器1] B --> D[容器2] B --> E[容器3] C --> F[应用+依赖] D --> G[应用+依赖] E --> H[应用+依赖]
|
安装与环境配置
Windows安装
说实话,Windows上的Docker安装曾经是个噩梦,但现在Docker Desktop已经做得相当不错了。
方法一:Docker Desktop(推荐)
下载安装包
- 访问Docker官网
- 下载Windows版本(需要Windows 10 Pro/Enterprise)
安装过程
- 双击安装文件
- 一路点击”下一步”(保持默认设置)
- 安装完成后重启电脑
验证安装
docker --version docker run hello-world
|
常见问题:权限错误
如果遇到”permission denied”错误,右键点击PowerShell,选择”以管理员身份运行”。
net localgroup docker-users "你的用户名" /add
|
macOS安装
macOS用户有几种选择,但最简单的是使用Homebrew。
使用Homebrew安装
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install --cask docker
open /Applications/Docker.app
docker --version
|
小提示
Docker Desktop在macOS上需要系统权限,可能会弹出一个窗口让你确认,一定要允许哦!
Linux安装
Linux用户的福音来了,Docker在Linux上的支持是最好的。
Ubuntu/Debian安装
sudo apt update
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io
sudo usermod -aG docker $USER newgrp docker
docker run hello-world
|
CentOS/RHEL安装
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker sudo systemctl enable docker
sudo usermod -aG docker $USER newgrp docker
docker run hello-world
|
配置国内镜像加速
默认从Docker Hub拉取镜像很慢,特别是国内用户,一定要配置镜像加速。
创建配置文件
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://docker.mirrors.ustc.edu.cn", "https://hub-mirror.c.163.com", "https://mirror.baidubce.com" ], "experimental": true, "storage-driver": "overlay2" } EOF
sudo systemctl restart docker
|
检查配置是否生效
Docker Compose安装
Docker Compose是多容器应用管理的神器,强烈建议安装。
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o ~/docker-compose sudo mv ~/docker-compose /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose
docker-compose --version
|
基本操作入门
镜像操作
镜像就像蛋糕的配方,包含了制作蛋糕的所有材料。镜像是一个只读的模板。
搜索镜像
docker search nginx
docker search --filter is-official=true nginx
docker search --filter stars=1000 nginx
|
拉取镜像
docker pull nginx
docker pull nginx:1.21
docker pull nginx:1.21-alpine
|
查看镜像
docker images
docker image ls
docker inspect nginx
docker history nginx
|
删除镜像
docker rmi nginx:1.21
docker rmi -f nginx
docker rmi $(docker images -q)
docker image prune
|
容器操作
容器是镜像的实例,是真正运行的应用。
运行容器
这是最常用的命令,有几个重要参数:
docker run -it ubuntu /bin/bash
docker run -d nginx
docker run -d --name my-web -p 8080:80 nginx
docker run -d --name my-app -v /path/to/code:/app nginx
docker run -d --name my-db -e MYSQL_ROOT_PASSWORD=my-secret-pw mysql:8
|
参数解释:
-d: 后台运行-p 8080:80: 将宿主机的8080端口映射到容器的80端口-v: 挂载卷-e: 设置环境变量--name: 给容器起个名字
查看容器
docker ps
docker ps -a
docker inspect my-web
docker logs my-web
docker logs -f my-web
|
管理容器
docker stop my-web
docker start my-web
docker restart my-web
docker exec -it my-web bash
docker rm my-web
docker rm -f my-web
docker container prune
|
数据管理
容器默认是临时的,数据需要通过持久化来保存。
数据卷(Volumes)
数据卷是Docker管理的数据存储,最推荐使用。
docker volume create my-data
docker volume ls
docker volume inspect my-data
docker volume rm my-data
docker volume prune
|
使用数据卷
docker run -d --name my-app -v my-data:/app/data nginx
docker run -d --name app1 -v shared-data:/app/data nginx docker run -d --name app2 -v shared-data:/app/data nginx
|
绑定挂载(Bind Mounts)
直接挂载宿主机的目录。
docker run -d -v "$(pwd)":/app nginx
docker run -d -v ./nginx.conf:/etc/nginx/nginx.conf nginx
|
网络管理
默认情况下,Docker会创建一个桥接网络,容器之间可以通过容器名通信。
查看网络
docker network ls
docker network inspect bridge
|
创建自定义网络
docker network create --driver bridge my-network
docker network inspect my-network
|
使用自定义网络
docker run -d --name web --network my-network nginx
docker run -d --name db --network my-network mysql
docker exec -it web ping db
|
进阶技巧
多阶段构建
这是Docker的高级技巧,能有效减小镜像大小。想象一下你做蛋糕,需要烤箱、搅拌器等工具,但最后只需要成品蛋糕,不需要这些工具。
FROM node:16-alpine as builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
|
对比:
- 传统方式:可能包含几百MB的开发依赖
- 多阶段构建:最终只有几十MB的运行环境
Dockerfile最佳实践
1. 选择合适的基础镜像
FROM node:16.14-alpine FROM python:3.9-slim
FROM python:3.9-slim as builder WORKDIR /app COPY requirements.txt . RUN pip install --user -r requirements.txt
FROM python:3.9-slim COPY --from=builder /root/.local /home/app/.local USER app
FROM ubuntu:20.04
|
2. 利用缓存
Docker的构建是分层的,相同的层会被缓存,构建会更快。
FROM node:16-alpine WORKDIR /app
COPY package*.json ./ RUN npm ci --only=production
COPY . .
FROM node:16-alpine WORKDIR /app COPY . . RUN npm ci --only=production
|
3. 清理缓存
RUN apt-get update && \ apt-get install -y \ build-essential \ && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir -r requirements.txt
|
Docker Compose进阶
环境变量管理
NODE_ENV=production PORT=8080 DB_HOST=db DB_USER=appuser DB_PASSWORD=secret
version: '3.8' services: app: build: . ports: - "${PORT}:3000" environment: - NODE_ENV=${NODE_ENV} - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/myapp
|
健康检查
services: web: image: nginx ports: - "80:80" healthcheck: test: ["CMD", "curl", "-f", "http://localhost/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s
|
资源限制
services: app: image: my-app deploy: resources: limits: cpus: '0.5' memory: 512M reservations: cpus: '0.25' memory: 256M
|
日志管理
集中日志收集
services: app: image: my-app logging: driver: "json-file" options: max-size: "10m" max-file: "3"
|
使用外部日志驱动
docker run -d \ --log-driver syslog \ --log-opt syslog-address=udp://192.168.1.1:514 \ my-app
|
实战案例
案例1:本地开发环境搭建
很多开发者都会遇到本地环境配置复杂的问题,用Docker可以完美解决。
项目结构
my-project/ ├── docker-compose.yml ├── .env ├── web/ │ ├── Dockerfile │ ├── app.py │ └── requirements.txt ├── db/ │ └── init.sql └── nginx/ └── nginx.conf
|
应用代码(Flask + MySQL)
from flask import Flask import mysql.connector import os
app = Flask(__name__)
@app.route('/') def hello(): db_host = os.getenv('DB_HOST', 'localhost') return f'Hello from Flask! Connected to database at {db_host}'
@app.route('/users') def get_users(): return {'users': ['Alice', 'Bob']}
if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
|
Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
|
docker-compose.yml
version: '3.8'
services: web: build: ./web ports: - "5000:5000" environment: - DB_HOST=db - DB_USER=root - DB_PASSWORD=password depends_on: db: condition: service_healthy
db: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_DATABASE=appdb ports: - "3306:3306" volumes: - db-data:/var/lib/mysql - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] timeout: 20s retries: 10
nginx: image: nginx:alpine ports: - "80:80" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf depends_on: - web
volumes: db-data:
|
nginx配置
server { listen 80; location / { proxy_pass http://web:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
|
启动应用
docker-compose up -d
docker-compose ps
docker-compose logs -f
|
案例2:部署WordPress博客
这是一个经典的多容器应用案例。
docker-compose.yml
version: '3.8'
services: wordpress: image: wordpress:6.0 depends_on: db: condition: service_healthy ports: - "8080:80" environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: password WORDPRESS_DB_NAME: wordpress volumes: - wordpress_data:/var/www/html - ./custom-theme:/var/www/html/wp-content/themes/custom-theme restart: unless-stopped
db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: password volumes: - mysql_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] timeout: 20s retries: 10 restart: unless-stopped
phpmyadmin: image: phpmyadmin/phpmyadmin depends_on: - db ports: - "8081:80" environment: PMA_HOST: db PMA_USER: wordpress PMA_PASSWORD: password restart: unless-stopped
volumes: wordpress_data: mysql_data:
|
启动WordPress
案例3:开发环境的数据库管理
开发过程中经常需要初始化数据库,使用Docker可以很方便地处理。
MySQL初始化脚本
CREATE DATABASE IF NOT EXISTS myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE myapp;
CREATE USER IF NOT EXISTS 'appuser'@'%' IDENTIFIED BY 'apppassword'; GRANT ALL PRIVILEGES ON myapp.* TO 'appuser'@'%'; FLUSH PRIVILEGES;
CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com'), ('Bob', 'bob@example.com') ON DUPLICATE KEY UPDATE name=name;
|
使用初始化脚本
services: db: image: mysql:8.0 volumes: - db-data:/var/lib/mysql - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql environment: - MYSQL_ROOT_PASSWORD=rootpassword - MYSQL_DATABASE=myapp
|
常见问题解决
1. 安装问题
问题1:权限被拒绝
Got permission denied while trying to connect to the Docker daemon socket
sudo docker run hello-world
sudo usermod -aG docker $USER
newgrp docker
|
问题2:Docker Desktop无法启动
2. 运行时问题
问题1:端口被占用
bind: address already in use
netstat -ano | findstr :8080 lsof -i :8080
docker run -d -p 8081:80 nginx
taskkill /PID <PID> /F
kill -9 <PID>
|
问题2:容器启动失败
docker ps -a
docker logs 容器名
docker exec -it 容器名 bash
|
常见启动失败原因:
- 端口冲突
- 文件权限问题
- 依赖服务未启动
- 内存不足
问题3:网络连接问题
docker network create my-network docker run --name web --network my-network nginx docker run --name db --network my-network mysql
docker network inspect bridge
netsh advfirewall firewall add rule name="Docker" dir=in action=allow protocol=TCP localport=8080
sudo ufw allow 8080
|
3. 构建问题
问题1:构建失败
docker build --no-cache .
docker build -t my-base -f Dockerfile.base .
docker build -t my-app .
|
问题2:镜像过大
FROM node:16 as builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build
FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html
FROM python:3.9-alpine
|
问题3:构建缓存失效
COPY package*.json ./ RUN npm ci --only=production
COPY . .
|
4. 性能问题
问题1:容器运行缓慢
docker stats
docker run --cpus=1 --memory=1g my-app
docker run --cpuset-cpus=0-1 my-app
|
问题2:存储空间不足
docker system df
docker container prune
docker image prune
docker network prune
docker volume prune
docker system prune -a
|
5. 生产环境问题
问题1:容器无法连接外部服务
docker run --network host my-app
docker run --dns 8.8.8.8 my-app
docker network inspect bridge
|
问题2:日志管理
services: app: image: my-app logging: driver: json-file options: max-size: "10m" max-file: "3"
|
问题3:数据备份
docker run --rm \ -v my-data:/source \ -v $(pwd):/backup \ alpine tar czf /backup/backup.tar -C /source .
docker commit my-container my-backup docker save my-backup > backup.tar
|
最佳实践
1. Dockerfile最佳实践
✅ 好的做法
FROM node:16.14-alpine
LABEL maintainer="yourname@example.com"
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && \ npm cache clean --force
COPY . .
ENV NODE_ENV=production
EXPOSE 3000
RUN adduser --disabled-password appuser USER appuser
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "app.js"]
|
❌ 避免的做法
FROM node:latest
USER root
COPY . .
RUN apt-get update && apt-get install -y python RUN apt-get update && apt-get install -y nginx
|
2. 安全最佳实践
最小权限原则
RUN addgroup -g 1001 appgroup && \ adduser -u 1001 -G appgroup -s /bin/sh -D appuser USER appuser
|
安全扫描
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \ aquasecurity/trivy:latest image my-image
FROM python:3.9-slim RUN apt-get update && \ apt-get install -y curl && \ curl -sSf https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list && \ apt-get update && \ apt-get install -y google-chrome-stable && \ rm -rf /var/lib/apt/lists/* && \ apt-get purge -y --auto-remove curl
|
3. 生产环境配置
资源限制
version: '3.8' services: app: image: my-app deploy: resources: limits: cpus: '1.0' memory: 1G reservations: cpus: '0.5' memory: 512M restart: unless-stopped
|
日志配置
services: app: image: my-app logging: driver: json-file options: max-size: "10m" max-file: "3"
|
4. 开发环境优化
热重载配置
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./ RUN npm ci
COPY . .
RUN npm install
CMD ["npm", "run", "dev"]
|
version: '3.8' services: web: build: context: . dockerfile: Dockerfile.dev volumes: - .:/app - /app/node_modules ports: - "3000:3000" environment: - NODE_ENV=development
|
扩展学习
1. 高级网络配置
自定义网络驱动
docker network create --driver overlay --subnet=172.20.0.0/24 my-network
docker run --network my-network my-app
|
跨主机通信
version: '3.8' services: app: image: my-app networks: - frontend - backend
networks: frontend: driver: bridge backend: driver: overlay
|
2. 集群管理
Docker Swarm
docker swarm init
docker service create --name web --publish 8080:80 nginx
docker service scale web=5
docker service ls
|
Docker Compose在Swarm中运行
version: '3.8' services: web: image: nginx ports: - "8080:80" deploy: replicas: 3 update_config: parallelism: 1 delay: 10s restart_policy: condition: on-failure
|
3. 监控和日志
使用Prometheus
version: '3.8' services: prometheus: image: prom/prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.enable-lifecycle' grafana: image: grafana/grafana ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin volumes: - grafana-storage:/var/lib/grafana
|
ELK日志栈
version: '3.8' services: elasticsearch: image: elasticsearch:7.10 ports: - "9200:9200" environment: - discovery.type=single-node - "ES_JAVA_OPTS=-Xms512m -Xmx512m" volumes: - elasticsearch-data:/usr/share/elasticsearch/data logstash: image: logstash:7.10 volumes: - ./logstash/pipeline:/usr/share/logstash/pipeline kibana: image: kibana:7.10 ports: - "5601:5601" environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
volumes: elasticsearch-data: grafana-storage:
|
4. CI/CD集成
GitHub Actions
name: Docker Build and Push on: push: branches: [ main ]
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push uses: docker/build-push-action@v2 with: context: . push: true tags: user/my-app:latest
|
Jenkins Pipeline
pipeline { agent any stages { stage('Build') { steps { sh 'docker build -t my-app:latest .' } } stage('Test') { steps { sh 'docker run --rm my-app:latest npm test' } } stage('Deploy') { steps { sh 'docker-compose up -d' } } } }
|
5. Kubernetes入门
虽然Kubernetes比Docker复杂,但它是容器编排的事实标准。
基本概念
- Pod: 最小的部署单元,包含一个或多个容器
- Deployment: 管理Pod的副本和更新
- Service: 提供网络访问
- Namespace: 资源隔离
示例YAML
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
|
总结
回顾一下我们今天学到的内容:
核心要点
- Docker的基本概念:镜像、容器、仓库、Dockerfile
- 环境搭建:Windows、macOS、Linux的安装和配置
- 基本操作:镜像和容器的管理、数据持久化、网络配置
- 进阶技巧:多阶段构建、Docker Compose、日志管理
- 实战应用:开发环境、WordPress部署、数据库管理
- 问题解决:常见错误的排查和解决
- 最佳实践:安全、性能、生产环境配置
学习建议
- 动手实践:理论很重要,但动手才能真正掌握
- 循序渐进:从简单的单容器开始,逐步过渡到复杂应用
- 文档参考:Docker官方文档是最好的学习资料
- 社区交流:遇到问题多查阅Stack Overflow和GitHub Issues
后续学习方向
- 深入理解容器技术:了解底层原理,如namespace、cgroup等
- 学习Kubernetes:掌握更复杂的容器编排
- 云原生开发:了解Service Mesh、Serverless等新技术
- DevOps实践:结合CI/CD,实现自动化部署
记住,技术学习是一个持续的过程。Docker只是一个工具,真正的价值在于如何用它来提高开发效率和系统可靠性。希望这篇文章能帮你打下坚实的基础,接下来就要靠你在实际项目中不断磨练了。
如果你在学习过程中遇到任何问题,欢迎在评论区留言交流。Happy Dockering!🐳
最后更新:2026年5月14日
分类:Docker | 容器化 | 运维 | 开发工具 | DevOps