evening breeze / Taizo
2625 字
13 分钟
Docker 实践指南
1. Docker概述
1.1 什么是Docker
Docker是一个开源的容器化平台,允许开发者将应用程序和其依赖项打包到一个轻量级、可移植的容器中。
Docker的核心特性:
- 一致性:在任何环境中运行都保持一致
- 轻量级:比传统虚拟机更轻量
- 快速部署:秒级启动和停止
- 版本控制:镜像版本化管理
- 资源隔离:容器间相互隔离
1.2 Docker架构
┌─────────────────────────────────────────────────────────────┐│ Docker Client │├─────────────────────────────────────────────────────────────┤│ Docker Daemon │├─────────────────────────────────────────────────────────────┤│ Registry │ Images │ Containers │ Networks │ Volumes │└─────────────────────────────────────────────────────────────┘核心组件:
- Docker Client:命令行工具,与Docker Daemon通信
- Docker Daemon:后台服务,管理容器生命周期
- Registry:镜像仓库(Docker Hub、私有仓库)
- Images:只读模板,用于创建容器
- Containers:运行中的镜像实例
- Networks:容器间通信网络
- Volumes:持久化数据存储
1.3 容器与虚拟机对比
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动时间 | 秒级 | 分钟级 |
| 资源占用 | 轻量 | 较重 |
| 隔离级别 | 进程级 | 系统级 |
| 镜像大小 | MB级 | GB级 |
| 性能 | 接近原生 | 有损耗 |
2. Docker安装与配置
2.1 安装Docker
# Ubuntu/Debiansudo apt updatesudo apt install docker.io docker-composesudo systemctl start dockersudo systemctl enable docker
# CentOS/RHELsudo yum install dockersudo systemctl start dockersudo systemctl enable docker
# macOSbrew install docker# 或下载 Docker Desktop
# Windows# 下载 Docker Desktop for Windows2.2 配置Docker
# 将用户添加到docker组(避免每次使用sudo)sudo usermod -aG docker $USER# 重新登录生效
# 配置镜像加速器(中国用户)bash <(curl -sSL https://xuanyuan.cloud/docker.sh)
# 验证安装docker --versiondocker run hello-worldDocker version 20.10.21, build baeda1fHello from Docker!This message shows that your installation appears to be working correctly.3. 镜像操作
3.1 镜像基础命令
# 搜索镜像docker search nginx
# 拉取镜像docker pull nginx:latestdocker pull ubuntu:20.04docker pull python:3.9-slim
# 查看本地镜像docker imagesdocker image ls
# 查看镜像详细信息docker inspect nginx:latest
# 删除镜像docker rmi nginx:latestdocker image rm ubuntu:20.04
# 强制删除镜像(即使有容器在使用)docker rmi -f nginx:latest
# 清理未使用的镜像docker image prune -a# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEnginx latest f652ca386ed0 2 weeks ago 141MBubuntu 20.04 ba6acccedd29 3 weeks ago 72.8MBpython 3.9-slim a7b92c8b0b1c 4 weeks ago 113MB
# docker search nginxNAME DESCRIPTION STARS OFFICIAL AUTOMATEDnginx Official build of Nginx. 18500 [OK]jwilder/nginx-proxy Automated Nginx reverse proxy for docker c... 2089 [OK]richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable o... 820 [OK]3.2 镜像标签和推送
# 给镜像打标签docker tag nginx:latest my-nginx:v1.0docker tag ubuntu:20.04 mycompany/ubuntu:latest
# 推送镜像到仓库docker push mycompany/ubuntu:latest
# 从私有仓库拉取镜像docker pull registry.example.com/myapp:v1.0
# 登录Docker Hubdocker login# 输入用户名和密码
# 登出docker logout3.3 镜像历史和信息
# 查看镜像构建历史docker history nginx:latest
# 查看镜像详细信息docker inspect nginx:latest | grep -A 10 "Config"
# 导出镜像为tar文件docker save -o nginx.tar nginx:latest
# 从tar文件导入镜像docker load -i nginx.tar
# 查看镜像占用空间docker system df4. 容器管理
4.1 容器基本操作
# 运行容器docker run nginx:latestdocker run -d nginx:latest # 后台运行docker run -it ubuntu:20.04 /bin/bash # 交互式运行
# 查看运行中的容器docker psdocker container ls
# 查看所有容器(包括停止的)docker ps -a
# 停止容器docker stop <container_id>docker stop <container_name>
# 启动已停止的容器docker start <container_id>
# 重启容器docker restart <container_id>
# 删除容器docker rm <container_id>docker container prune # 删除所有停止的容器# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESabc123def456 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 80/tcp nginx-container
# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESabc123def456 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 80/tcp nginx-containerdef456ghi789 ubuntu:20.04 "/bin/bash" 5 minutes ago Exited (0) 3 minutes ago ubuntu-test4.2 容器高级操作
# 进入运行中的容器docker exec -it <container_id> /bin/bashdocker exec -it nginx-container /bin/sh
# 查看容器日志docker logs <container_id>docker logs -f <container_id> # 实时查看日志docker logs --tail 100 <container_id> # 查看最后100行
# 查看容器资源使用情况docker stats
# 复制文件到容器docker cp local_file.txt <container_id>:/path/in/container/
# 从容器复制文件docker cp <container_id>:/path/in/container/file.txt ./
# 提交容器为镜像docker commit <container_id> my-nginx:v1.14.3 容器端口映射与网络
# 端口映射docker run -d -p 8080:80 nginx:latest # 主机8080端口映射到容器80端口docker run -d -p 3000:3000 -p 8080:80 myapp:latest # 多端口映射
# 指定容器名称docker run -d --name my-nginx -p 8080:80 nginx:latest
# 设置环境变量docker run -d -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
# 挂载数据卷docker run -d -v /host/path:/container/path nginx:latestdocker run -d -v nginx_data:/usr/share/nginx/html nginx:latest
# 使用自定义网络docker network create my-networkdocker run -d --network my-network --name web nginx:latestdocker run -d --network my-network --name db mysql:8.05. Dockerfile与镜像构建
5.1 Dockerfile基础语法
# 基础镜像FROM ubuntu:20.04
# 维护者信息LABEL maintainer="your-email@example.com"
# 设置工作目录WORKDIR /app
# 复制文件COPY requirements.txt .COPY src/ ./src/
# 安装依赖RUN apt-get update && apt-get install -y \ python3 \ python3-pip \ && rm -rf /var/lib/apt/lists/*
RUN pip3 install -r requirements.txt
# 暴露端口EXPOSE 8080
# 设置环境变量ENV FLASK_APP=app.pyENV FLASK_ENV=production
# 启动命令CMD ["python3", "app.py"]5.2 多阶段构建
# 构建阶段FROM node:16 AS builderWORKDIR /appCOPY package*.json ./RUN npm installCOPY . .RUN npm run build
# 运行阶段FROM nginx:alpineCOPY --from=builder /app/dist /usr/share/nginx/htmlEXPOSE 80CMD ["nginx", "-g", "daemon off;"]5.3 构建镜像
# 构建镜像docker build -t myapp:v1.0 .docker build -f Dockerfile.prod -t myapp:prod .
# 指定构建参数docker build --build-arg VERSION=1.0 -t myapp:v1.0 .
# 不使用缓存构建docker build --no-cache -t myapp:v1.0 .
# 查看构建历史docker history myapp:v1.0# docker build -t myapp:v1.0 .Sending build context to Docker daemon 2.048kBStep 1/8 : FROM python:3.9-slim ---> a7b92c8b0b1cStep 2/8 : WORKDIR /app ---> Running in abc123def456 ---> def456ghi789Step 3/8 : COPY requirements.txt . ---> abc123def456Step 4/8 : RUN pip install -r requirements.txt ---> Running in def456ghi789Collecting flask==2.0.1 Downloading flask-2.0.1-py3-none-any.whl (94 kB)Installing collected packages: flaskSuccessfully installed flask-2.0.1 ---> ghi789jkl012Step 5/8 : COPY . . ---> jkl012mno345Step 6/8 : EXPOSE 8080 ---> Running in mno345pqr678 ---> pqr678stu901Step 7/8 : ENV FLASK_APP=app.py ---> Running in stu901vwx234 ---> vwx234yza567Step 8/8 : CMD ["python", "app.py"] ---> Running in yza567bcd890 ---> bcd890efg123Successfully built bcd890efg123Successfully tagged myapp:v1.06. Docker Compose编排
6.1 docker-compose.yml基础
version: '3.8'
services: web: build: . ports: - "8080:8080" environment: - DATABASE_URL=postgresql://user:pass@db:5432/myapp depends_on: - db volumes: - ./logs:/app/logs networks: - app-network
db: image: postgres:13 environment: - POSTGRES_DB=myapp - POSTGRES_USER=user - POSTGRES_PASSWORD=pass volumes: - postgres_data:/var/lib/postgresql/data networks: - app-network
redis: image: redis:6-alpine networks: - app-network
volumes: postgres_data:
networks: app-network: driver: bridge6.2 Compose命令操作
# 启动服务docker-compose updocker-compose up -d # 后台运行docker-compose up --build # 重新构建镜像
# 停止服务docker-compose downdocker-compose down -v # 同时删除数据卷
# 查看服务状态docker-compose psdocker-compose logsdocker-compose logs web # 查看特定服务日志
# 进入服务容器docker-compose exec web bashdocker-compose exec db psql -U user -d myapp
# 重启服务docker-compose restart web
# 扩展服务实例docker-compose up --scale web=3# docker-compose up -dCreating network "myapp_app-network" ... doneCreating volume "myapp_postgres_data" ... doneCreating myapp_db_1 ... doneCreating myapp_redis_1 ... doneCreating myapp_web_1 ... done
# docker-compose ps Name Command State Ports--------------------------------------------------------------------------------myapp_db_1 docker-entrypoint.sh postgres Up 5432/tcpmyapp_redis_1 docker-entrypoint.sh redis ... Up 6379/tcpmyapp_web_1 python app.py Up 0.0.0.0:8080->8080/tcp6.3 高级Compose配置
version: '3.8'
services: web: build: context: . dockerfile: Dockerfile.prod args: - VERSION=1.0 deploy: replicas: 3 resources: limits: cpus: '0.50' memory: 512M reservations: cpus: '0.25' memory: 256M healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 restart: unless-stopped
nginx: image: nginx:alpine ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf depends_on: - web7. 网络管理
7.1 Docker网络
# 查看网络列表docker network ls
# 创建自定义网络docker network create my-networkdocker network create --driver bridge --subnet 172.18.0.0/16 my-network
# 连接容器到网络docker network connect my-network container1docker network disconnect my-network container1
# 查看网络详细信息docker network inspect my-network
# 删除网络docker network rm my-networkdocker network prune # 删除未使用的网络# docker network lsNETWORK ID NAME DRIVER SCOPEabc123def456 bridge bridge localdef456ghi789 host host localghi789jkl012 none null localjkl012mno345 my-network bridge local
# docker network inspect bridge[ { "Name": "bridge", "Id": "abc123def456", "Created": "2023-06-30T10:00:00.000000000Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] } }]8. 存储管理
8.1 数据卷管理
# 创建数据卷docker volume create my-data
# 查看数据卷列表docker volume ls
# 查看数据卷详细信息docker volume inspect my-data
# 删除数据卷docker volume rm my-datadocker volume prune # 删除未使用的数据卷
# 备份数据卷docker run --rm -v my-data:/data -v $(pwd):/backup ubuntu tar czf /backup/my-data.tar.gz -C /data .
# 恢复数据卷docker run --rm -v my-data:/data -v $(pwd):/backup ubuntu tar xzf /backup/my-data.tar.gz -C /data8.2 绑定挂载
# 绑定挂载目录docker run -d -v /host/path:/container/path nginx:latest
# 挂载单个文件docker run -d -v /host/config.json:/app/config.json myapp:latest
# 只读挂载docker run -d -v /host/path:/container/path:ro nginx:latest
# 使用命名卷docker run -d -v nginx_data:/usr/share/nginx/html nginx:latest9. 应用容器化示例
9.1 Python Flask应用容器化
from flask import Flask, jsonifyimport os
app = Flask(__name__)
@app.route('/')def hello(): return jsonify({ 'message': 'Hello from Docker!', 'version': os.getenv('VERSION', '1.0') })
@app.route('/health')def health(): return jsonify({'status': 'healthy'})
if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)Flask==2.0.1gunicorn==20.1.0# DockerfileFROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .RUN pip install -r requirements.txt
COPY . .
EXPOSE 8080
ENV VERSION=1.0
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "app:app"]version: '3.8'
services: web: build: . ports: - "8080:8080" environment: - VERSION=1.0 volumes: - ./logs:/app/logs restart: unless-stopped9.2 Node.js应用容器化
# DockerfileFROM node:16-alpine
WORKDIR /app
COPY package*.json ./RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]version: '3.8'
services: app: build: . ports: - "3000:3000" environment: - NODE_ENV=production depends_on: - redis restart: unless-stopped
redis: image: redis:6-alpine volumes: - redis_data:/data
volumes: redis_data:9.3 构建和部署
# 构建镜像docker build -t myapp:v1.0 .
# 运行容器docker run -d -p 8080:8080 --name myapp myapp:v1.0
# 使用Compose部署docker-compose up -d
# 查看应用状态curl http://localhost:8080/curl http://localhost:8080/health
# 查看日志docker logs myappdocker-compose logs web# curl http://localhost:8080/{ "message": "Hello from Docker!", "version": "1.0"}
# curl http://localhost:8080/health{ "status": "healthy"}10. 监控与调试
10.1 容器检查命令
# 查看容器详细信息docker inspect <container_id>
# 查看容器资源使用docker stats --no-stream
# 进入容器调试docker exec -it <container_id> /bin/bash
# 查看容器进程docker top <container_id>10.2 日志管理
# 查看容器日志docker logs <container_id>
# 实时查看日志docker logs -f <container_id>
# 查看最后100行docker logs --tail 100 <container_id># docker-compose.yml 日志配置version: '3.8'
services: web: build: . logging: driver: "json-file" options: max-size: "10m" max-file: "3"11. 最佳实践
11.1 镜像优化
# 多阶段构建优化FROM node:16-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ciCOPY . .RUN npm run build
FROM nginx:alpineCOPY --from=builder /app/dist /usr/share/nginx/htmlEXPOSE 80CMD ["nginx", "-g", "daemon off;"]
# 使用.dockerignore文件node_modulesnpm-debug.log.git.gitignoreREADME.md.env.nyc_outputcoverage11.2 安全实践
# 使用非root用户FROM node:16-alpineRUN addgroup -g 1001 -S nodejsRUN adduser -S nodejs -u 1001USER nodejs
# 最小化攻击面FROM alpine:latestRUN apk add --no-cache nginx
# 扫描镜像漏洞docker scan myapp:v1.011.3 资源限制
# 资源限制docker run -d \ --memory=512m \ --cpus=1.0 \ --pids-limit=100 \ myapp:v1.0
# 清理系统docker system prune -adocker builder prune
# 监控容器资源docker stats12. 高级主题
12.1 Docker Swarm集群
# 初始化Swarmdocker swarm init
# 添加工作节点docker swarm join --token <token> <manager-ip>:2377
# 部署服务docker service create --name web --replicas 3 -p 8080:8080 myapp:v1.0
# 查看服务docker service lsdocker service ps web
# 扩展服务docker service scale web=512.2 私有镜像仓库
# 运行私有仓库docker run -d -p 5000:5000 --name registry registry:2
# 推送镜像到私有仓库docker tag myapp:v1.0 localhost:5000/myapp:v1.0docker push localhost:5000/myapp:v1.0
# 从私有仓库拉取docker pull localhost:5000/myapp:v1.0参考资料
- Docker官方文档:https://docs.docker.com/
- Docker Hub:https://hub.docker.com/
- Docker Compose文档:https://docs.docker.com/compose/