Docker学习笔记

发布于:2025-05-23 ⋅ 阅读:(20) ⋅ 点赞:(0)

Docker零基础学习手册

📚 目录

  1. Docker是什么?
  2. 为什么要用Docker?
  3. 核心概念
  4. 安装Docker
  5. 基础命令
  6. 制作镜像
  7. Docker Compose
  8. 实战案例
  9. 最佳实践
  10. 常见问题

🤔 Docker是什么?

简单比喻

想象Docker就像是**“集装箱”**:

  • 传统方式:就像散装货物,不同的货物需要不同的运输工具
  • Docker方式:把所有东西都装进标准集装箱,任何船都能运输

技术角度

Docker是一个容器化平台,它可以把你的应用程序和它需要的所有环境(操作系统、库文件、配置等)打包在一起,形成一个轻量级、可移植的容器

没有Docker的世界:
开发环境 ≠ 测试环境 ≠ 生产环境
"在我电脑上好好的啊!" 😭

有了Docker的世界:
开发环境 = 测试环境 = 生产环境
"到哪里都一样!" 😊

🎯 为什么要用Docker?

解决的核心问题

1. 环境一致性问题
传统问题:
- 开发用Windows,服务器用Linux
- 本地Python 3.8,服务器Python 3.6
- 少了某个依赖库,程序跑不起来

Docker解决:
- 环境完全打包,到哪都一样
- 一次构建,到处运行
2. 部署复杂性问题
传统部署:
1. 安装操作系统
2. 安装各种依赖
3. 配置环境变量
4. 部署应用程序
5. 祈祷没有问题 🙏

Docker部署:
1. docker run my-app
2. 完成! ✅
3. 资源利用率问题
虚拟机方式:
[物理服务器]
  ├── [虚拟机1] → [完整OS] → [应用1]
  ├── [虚拟机2] → [完整OS] → [应用2]
  └── [虚拟机3] → [完整OS] → [应用3]
资源浪费,启动慢

Docker方式:
[物理服务器]
  └── [Docker引擎]
      ├── [容器1] → [应用1]
      ├── [容器2] → [应用2]
      └── [容器3] → [应用3]
资源高效,启动快

📖 核心概念

三个核心概念

1. 镜像 (Image) - 🎯

比喻:就像程序安装包或者模板

  • 只读的:不能修改
  • 层级结构:一层层叠加
  • 可共享:多个容器可以使用同一个镜像
镜像的构成:
基层:Ubuntu操作系统
├── 第二层:安装Java环境
├── 第三层:安装Tomcat
├── 第四层:复制应用程序
└── 第五层:设置启动命令
2. 容器 (Container) - 📦

比喻:就像正在运行的程序实例

  • 可读写的:运行时可以修改
  • 隔离的:每个容器相互独立
  • 临时的:删除后数据就没了(除非挂载卷)
镜像 vs 容器:
镜像 = 类 (Class)
容器 = 对象 (Object)

一个镜像可以创建多个容器
就像一个类可以创建多个对象
3. 仓库 (Repository) - 🏪

比喻:就像应用商店

  • Docker Hub:官方应用商店
  • 私有仓库:公司内部应用商店
  • 存储镜像:上传和下载镜像
常见的镜像仓库:
- Docker Hub (官方):docker.io
- 阿里云:registry.cn-hangzhou.aliyuncs.com
- 腾讯云:ccr.ccs.tencentyun.com

重要概念关系图

[开发者] 
    ↓ 编写Dockerfile
[Dockerfile] 
    ↓ docker build
[镜像 Image] 
    ↓ docker run
[容器 Container]
    ↓ docker push
[仓库 Repository]

💻 安装Docker

Windows安装

方法1:Docker Desktop (推荐)
1. 访问 https://www.docker.com/products/docker-desktop
2. 下载 Docker Desktop for Windows
3. 双击安装包,按提示安装
4. 重启电脑
5. 启动Docker Desktop
验证安装
# 打开命令提示符或PowerShell
docker --version
# 应该显示:Docker version 20.10.x

docker run hello-world
# 如果看到 "Hello from Docker!" 说明安装成功

Linux安装 (Ubuntu)

# 1. 更新包管理器
sudo apt update

# 2. 安装必要的包
sudo apt install apt-transport-https ca-certificates curl software-properties-common

# 3. 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 4. 添加Docker仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# 5. 安装Docker
sudo apt update
sudo apt install docker-ce

# 6. 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker

# 7. 验证安装
sudo docker run hello-world

🔨 基础命令

镜像相关命令

查看镜像
# 列出本地所有镜像
docker images

# 或者使用
docker image ls
搜索镜像
# 在Docker Hub搜索镜像
docker search nginx
docker search mysql
拉取镜像
# 拉取最新版本
docker pull nginx

# 拉取指定版本
docker pull nginx:1.20
docker pull mysql:8.0
删除镜像
# 删除指定镜像
docker rmi nginx

# 删除所有未使用的镜像
docker image prune

容器相关命令

运行容器
# 基本运行
docker run nginx

# 后台运行
docker run -d nginx

# 指定名称
docker run -d --name my-nginx nginx

# 端口映射
docker run -d -p 8080:80 nginx

# 环境变量
docker run -d -e MYSQL_ROOT_PASSWORD=123456 mysql

# 挂载卷
docker run -d -v /host/path:/container/path nginx
查看容器
# 查看运行中的容器
docker ps

# 查看所有容器(包括停止的)
docker ps -a

# 查看容器详细信息
docker inspect container-name
容器操作
# 停止容器
docker stop container-name

# 启动容器
docker start container-name

# 重启容器
docker restart container-name

# 删除容器
docker rm container-name

# 强制删除运行中的容器
docker rm -f container-name
进入容器
# 进入运行中的容器
docker exec -it container-name bash

# 或者使用sh(如果容器没有bash)
docker exec -it container-name sh

# 查看容器日志
docker logs container-name

# 实时查看日志
docker logs -f container-name

系统相关命令

# 查看Docker信息
docker info

# 查看Docker版本
docker version

# 清理系统
docker system prune      # 清理未使用的容器、网络、镜像
docker system prune -a   # 清理所有未使用的资源

# 查看资源使用情况
docker stats

🏗️ 制作镜像

Dockerfile详解

Dockerfile是用来构建镜像的文本文件,包含了一系列的指令。

基本结构
# 指定基础镜像
FROM base-image

# 设置工作目录
WORKDIR /app

# 复制文件
COPY source destination

# 运行命令
RUN command

# 暴露端口
EXPOSE port

# 启动命令
CMD ["executable", "param1", "param2"]
常用指令详解
FROM - 指定基础镜像
# 使用官方Python镜像
FROM python:3.9

# 使用特定版本
FROM python:3.9-slim

# 使用Ubuntu作为基础
FROM ubuntu:20.04
WORKDIR - 设置工作目录
# 设置工作目录(如果不存在会自动创建)
WORKDIR /app

# 相当于 cd /app
COPY 和 ADD - 复制文件
# 复制单个文件
COPY app.py /app/

# 复制整个目录
COPY . /app/

# ADD功能更强大,但建议使用COPY
ADD file.tar.gz /app/  # 会自动解压
RUN - 运行命令
# 安装软件包
RUN apt-get update && apt-get install -y python3

# 安装Python依赖
RUN pip install -r requirements.txt

# 多个命令用 && 连接(减少层级)
RUN apt-get update && \
    apt-get install -y python3 && \
    rm -rf /var/lib/apt/lists/*
ENV - 设置环境变量
# 设置环境变量
ENV PYTHON_VERSION 3.9
ENV APP_HOME /app

# 使用环境变量
WORKDIR $APP_HOME
EXPOSE - 暴露端口
# 暴露端口(仅声明,实际映射需要在运行时指定)
EXPOSE 8080
EXPOSE 3000 5000
CMD 和 ENTRYPOINT - 启动命令
# CMD:可以被docker run命令覆盖
CMD ["python", "app.py"]

# ENTRYPOINT:不会被覆盖
ENTRYPOINT ["python", "app.py"]

# 组合使用
ENTRYPOINT ["python"]
CMD ["app.py"]

实战案例:Python Flask应用

1. 准备应用文件

app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello, Docker!'

@app.route('/health')
def health():
    return {'status': 'healthy'}

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

requirements.txt

Flask==2.3.3
2. 编写Dockerfile

Dockerfile

# 使用Python官方镜像
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"]
3. 构建和运行
# 构建镜像
docker build -t my-flask-app .

# 查看构建的镜像
docker images

# 运行容器
docker run -d -p 5000:5000 --name flask-container my-flask-app

# 测试应用
curl http://localhost:5000
# 应该返回:Hello, Docker!

# 查看容器日志
docker logs flask-container

# 进入容器
docker exec -it flask-container bash

优化Dockerfile

多阶段构建
# 构建阶段
FROM python:3.9 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

# 运行阶段
FROM python:3.9-slim
WORKDIR /app

# 从构建阶段复制依赖
COPY --from=builder /root/.local /root/.local

# 复制应用代码
COPY app.py .

# 确保脚本在PATH中
ENV PATH=/root/.local/bin:$PATH

EXPOSE 5000
CMD ["python", "app.py"]
使用.dockerignore
# .dockerignore文件
node_modules
*.log
.git
Dockerfile
.dockerignore
README.md

🎼 Docker Compose

什么是Docker Compose?

Docker Compose是用于定义和运行多容器Docker应用程序的工具。

解决的问题
单容器的限制:
- 只能运行一个服务
- 手动管理多个容器很复杂
- 容器间网络配置繁琐

Docker Compose的优势:
- 一个文件定义整个应用栈
- 一条命令启动所有服务
- 自动处理容器间网络

docker-compose.yml基础

基本结构
version: '3.8'

services:
  service1:
    image: image-name
    ports:
      - "host-port:container-port"
    environment:
      - ENV_VAR=value
    
  service2:
    build: .
    volumes:
      - ./host-path:/container-path

networks:
  default:
    driver: bridge

volumes:
  volume-name:

实战案例:Web应用 + 数据库

项目结构
my-web-app/
├── docker-compose.yml
├── Dockerfile
├── app.py
├── requirements.txt
└── init.sql
docker-compose.yml
version: '3.8'

services:
  # Web应用服务
  web:
    build: .                    # 使用当前目录的Dockerfile构建
    ports:
      - "5000:5000"            # 端口映射
    environment:
      - DB_HOST=db             # 数据库主机名
      - DB_USER=root
      - DB_PASSWORD=123456
      - DB_NAME=myapp
    depends_on:
      - db                     # 依赖数据库服务
    volumes:
      - ./logs:/app/logs       # 日志挂载
    restart: unless-stopped    # 重启策略

  # 数据库服务
  db:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_DATABASE=myapp
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql      # 数据持久化
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    restart: unless-stopped

  # Redis缓存服务
  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    restart: unless-stopped

# 定义卷
volumes:
  db_data:
  redis_data:

# 定义网络
networks:
  default:
    driver: bridge
应用代码 (app.py)
from flask import Flask
import mysql.connector
import redis
import os

app = Flask(__name__)

# 数据库配置
db_config = {
    'host': os.getenv('DB_HOST', 'localhost'),
    'user': os.getenv('DB_USER', 'root'),
    'password': os.getenv('DB_PASSWORD', ''),
    'database': os.getenv('DB_NAME', 'myapp')
}

# Redis配置
redis_client = redis.Redis(host='redis', port=6379, db=0)

@app.route('/')
def hello():
    return 'Hello from Docker Compose!'

@app.route('/db-test')
def db_test():
    try:
        conn = mysql.connector.connect(**db_config)
        cursor = conn.cursor()
        cursor.execute("SELECT VERSION()")
        version = cursor.fetchone()
        conn.close()
        return f'Database version: {version[0]}'
    except Exception as e:
        return f'Database error: {str(e)}'

@app.route('/redis-test')
def redis_test():
    try:
        redis_client.set('test_key', 'Hello Redis!')
        value = redis_client.get('test_key').decode('utf-8')
        return f'Redis value: {value}'
    except Exception as e:
        return f'Redis error: {str(e)}'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)
requirements.txt
Flask==2.3.3
mysql-connector-python==8.1.0
redis==4.6.0
init.sql
-- 初始化数据库脚本
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO users (name, email) VALUES 
('张三', 'zhangsan@example.com'),
('李四', 'lisi@example.com');

Docker Compose常用命令

# 启动所有服务
docker-compose up

# 后台启动
docker-compose up -d

# 重新构建并启动
docker-compose up --build

# 停止所有服务
docker-compose down

# 停止并删除卷
docker-compose down -v

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs

# 查看特定服务日志
docker-compose logs web

# 实时查看日志
docker-compose logs -f

# 进入服务容器
docker-compose exec web bash

# 扩展服务(启动多个实例)
docker-compose up -d --scale web=3

🚀 实战案例

案例1:部署.NET Core API

项目结构
dotnet-api/
├── docker-compose.yml
├── Dockerfile
├── MyAPI.csproj
├── Program.cs
├── Controllers/
│   └── WeatherController.cs
└── appsettings.json
Dockerfile
# 多阶段构建
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src

# 复制项目文件
COPY *.csproj ./
RUN dotnet restore

# 复制源代码并构建
COPY . ./
RUN dotnet publish -c Release -o out

# 运行时镜像
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /src/out .

# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
  CMD curl -f http://localhost:5000/health || exit 1

EXPOSE 5000
ENTRYPOINT ["dotnet", "MyAPI.dll"]
docker-compose.yml
version: '3.8'

services:
  api:
    build: .
    ports:
      - "5000:5000"
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
      - ASPNETCORE_URLS=http://+:5000
      - ConnectionStrings__DefaultConnection=Server=db;Database=MyAPI;User=sa;Password=YourStrong@Passw0rd;
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: mcr.microsoft.com/mssql/server:2019-latest
    environment:
      - ACCEPT_EULA=Y
      - SA_PASSWORD=YourStrong@Passw0rd
    ports:
      - "1433:1433"
    volumes:
      - db_data:/var/opt/mssql
    restart: unless-stopped

volumes:
  db_data:

案例2:前端 + 后端 + 数据库完整应用

docker-compose.yml
version: '3.8'

services:
  # 前端服务
  frontend:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./frontend/dist:/usr/share/nginx/html
      - ./frontend/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - backend
    restart: unless-stopped

  # 后端API服务
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "5000:5000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis
    restart: unless-stopped

  # 数据库服务
  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: unless-stopped

  # 缓存服务
  redis:
    image: redis:alpine
    volumes:
      - redis_data:/data
    restart: unless-stopped

  # 监控服务
  nginx-exporter:
    image: nginx/nginx-prometheus-exporter
    ports:
      - "9113:9113"
    command:
      - -nginx.scrape-uri=http://frontend:80/nginx_status

volumes:
  db_data:
  redis_data:

💡 最佳实践

1. Dockerfile最佳实践

使用合适的基础镜像
# ❌ 不好的做法 - 镜像太大
FROM ubuntu:20.04

# ✅ 好的做法 - 使用精简镜像
FROM python:3.9-slim

# ✅ 更好的做法 - 使用Alpine
FROM python:3.9-alpine
减少层级数量
# ❌ 不好的做法 - 每个RUN创建一层
RUN apt-get update
RUN apt-get install -y python3
RUN apt-get install -y pip
RUN apt-get clean

# ✅ 好的做法 - 合并命令
RUN apt-get update && \
    apt-get install -y python3 pip && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
利用构建缓存
# ✅ 先复制依赖文件,利用缓存
COPY requirements.txt .
RUN pip install -r requirements.txt

# 然后复制应用代码
COPY . .
使用非root用户
# 创建用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nextjs -u 1001

# 切换用户
USER nextjs

2. 安全最佳实践

扫描漏洞
# 使用Docker官方工具扫描
docker scan my-app:latest

# 使用第三方工具
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy image my-app:latest
最小权限原则
# docker-compose.yml
services:
  app:
    image: my-app
    user: "1001:1001"  # 使用非root用户
    read_only: true    # 只读文件系统
    tmpfs:
      - /tmp
      - /var/run

3. 性能优化

多阶段构建
# 构建阶段
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# 运行阶段
FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
CMD ["node", "index.js"]
使用.dockerignore
# .dockerignore
node_modules
*.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
.nyc_output
.coverage
.pytest_cache
__pycache__

4. 日志管理

配置日志驱动
services:
  app:
    image: my-app
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
结构化日志
import logging
import json

# 配置结构化日志
logging.basicConfig(
    format='%(asctime)s %(levelname)s %(message)s',
    level=logging.INFO
)

# 使用JSON格式
logger = logging.getLogger(__name__)
logger.info(json.dumps({
    'event': 'user_login',
    'user_id': 123,
    'timestamp': '2023-10-01T10:00:00Z'
}))

❓ 常见问题

1. 容器访问问题

问题:容器无法访问外部网络
# 解决方案:检查DNS设置
docker run --dns 8.8.8.8 my-app

# 或在docker-compose.yml中设置
services:
  app:
    image: my-app
    dns:
      - 8.8.8.8
      - 8.8.4.4
问题:容器间无法通信
# 确保容器在同一网络中
docker network ls
docker network inspect bridge

# 使用服务名称访问
# 在docker-compose中,可以直接使用服务名
curl http://web:5000/api/health

2. 存储和权限问题

问题:数据持久化
# 使用named volume
services:
  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql  # named volume

volumes:
  db_data:  # 定义volume
问题:权限问题
# 查看文件权限
ls -la /var/lib/docker/volumes/

# 修改权限
sudo chown -R 1001:1001 /path/to/volume

3. 性能问题

问题:容器启动慢
# 检查资源使用
docker stats

# 使用更小的基础镜像
FROM python:3.9-alpine  # 而不是python:3.9
问题:构建慢
# 使用构建缓存
docker build --cache-from my-app:latest .

# 使用BuildKit
export DOCKER_BUILDKIT=1
docker build .

4. 调试技巧

进入运行中的容器
# 进入容器shell
docker exec -it container-name bash

# 如果没有bash,使用sh
docker exec -it container-name sh

# 以root用户进入
docker exec -it --user root container-name bash
查看容器详细信息
# 查看容器配置
docker inspect container-name

# 查看容器进程
docker top container-name

# 查看容器资源使用
docker stats container-name
调试网络问题
# 查看网络配置
docker network ls
docker network inspect bridge

# 测试容器间连通性
docker exec container1 ping container2

🎓 学习路径建议

第一阶段:基础入门(1-2周)

✅ 理解Docker基本概念
✅ 学会基础命令操作
✅ 会写简单的Dockerfile
✅ 能够运行和管理容器

第二阶段:实践应用(2-3周)

✅ 掌握Docker Compose
✅ 能够部署多服务应用
✅ 了解网络和存储
✅ 掌握基本的故障排查

第三阶段:深入优化(2-4周)

✅ 掌握最佳实践
✅ 性能优化和安全加固
✅ CI/CD集成
✅ 监控和日志管理

第四阶段:生产应用(持续)

✅ 容器编排(Kubernetes)
✅ 微服务架构
✅ DevOps实践
✅ 持续学习新特性

📚 推荐资源

官方文档

实践平台

学习书籍

  • 《Docker技术入门与实战》
  • 《Docker容器与容器云》

视频教程

  • Docker官方YouTube频道
  • 各大技术平台的Docker教程

🎯 总结

Docker是现代应用部署的重要技术,掌握Docker可以:

  1. 提高开发效率:环境一致性,避免"在我机器上正常"问题
  2. 简化部署流程:一键部署,减少运维复杂度
  3. 提升资源利用率:容器化应用占用资源更少
  4. 增强应用可移植性:一次构建,到处运行

学习Docker需要理论与实践结合

  • 先理解概念和原理
  • 然后动手实践操作
  • 最后在实际项目中应用

记住:Docker不仅仅是工具,更是一种思维方式的转变

Happy Dockerizing! 🐳


网站公告

今日签到

点亮在社区的每一天
去签到