加载中...
加载中...
在现代软件开发中,应用的部署和环境管理一直是一个复杂而繁琐的挑战。传统的部署方式需要手动配置服务器环境、安装依赖、处理版本冲突,这个过程不仅耗时,还容易出错。更糟糕的是,"在我的机器上能运行"的问题屡见不鲜,开发环境、测试环境和生产环境之间的差异导致部署失败、bug难以复现等问题。
Docker 容器化技术的出现,彻底改变了应用部署和管理的模式。Docker 通过容器化技术,将应用程序及其所有依赖项打包到一个轻量级、可移植的容器中,实现了"一次构建,到处运行"的理想。无论是开发、测试还是生产环境,容器都能保证应用运行的一致性,消除了环境差异带来的问题。
Docker 的核心价值不仅在于简化部署流程,更在于它带来的开发效率提升、资源利用率优化和运维成本降低。通过容器化,开发者可以快速搭建开发环境,运维人员可以轻松扩展应用规模,企业可以更高效地利用计算资源。从单体应用到微服务架构,从本地开发到云原生部署,Docker 已经成为现代软件开发和运维不可或缺的工具。
容器化技术的优势是多方面的。首先,它提供了环境一致性,确保应用在不同环境中表现一致;其次,它实现了资源隔离,多个容器可以在同一台机器上运行而互不干扰;再次,它简化了依赖管理,应用的所有依赖都打包在容器中;最后,它提高了可移植性,容器可以在任何支持 Docker 的平台上运行。
本文将带您全面深入地了解 Docker 容器化技术的方方面面,从基础概念到核心操作,从 Dockerfile 编写到 Docker Compose 编排,从网络存储配置到生产环境部署,从最佳实践到故障排查。无论您是刚开始接触 Docker 的新手,还是希望深入理解容器化技术的资深开发者,都能从本文中获得有价值的知识和实践指导。我们将重点关注实用操作,提供大量可直接使用的命令示例、配置文件和工作流脚本,帮助您在实际工作中快速应用 Docker 的强大功能。
容器化技术是一种操作系统级别的虚拟化技术,它允许在单一操作系统内核上运行多个隔离的用户空间实例。与传统的虚拟机技术不同,容器不需要为每个应用分配完整的操作系统,而是共享宿主机的操作系统内核,这使得容器更加轻量级、启动更快、资源占用更少。
容器化 vs 虚拟化
传统的虚拟化技术(如 VMware、VirtualBox)通过 Hypervisor 在物理硬件上创建完整的虚拟机,每个虚拟机都包含完整的操作系统。这种方式虽然提供了完全的隔离,但也带来了显著的资源开销:
容器化技术则采用了不同的方法:
容器化的优势
容器化技术带来了多方面的优势:
镜像(Image)是 Docker 的核心概念之一,它是一个只读的模板,用于创建容器。镜像包含了运行应用所需的所有内容:代码、运行时环境、库、环境变量和配置文件。
镜像的分层结构
Docker 镜像采用分层存储机制,每个镜像由多个只读层(Layer)叠加而成。这种设计的优势包括:
例如,一个 Node.js 应用的镜像可能包含以下层:
应用代码层(可变化)
Node.js 运行时层(可复用)
操作系统基础层(可复用)
镜像的标识
Docker 镜像通过名称和标签(Tag)来标识:
[仓库地址/]用户名/镜像名latest示例:
nginx:latest:Nginx 的最新版本node:16-alpine:Node.js 16 版本,基于 Alpine Linuxubuntu:20.04:Ubuntu 20.04 版本镜像仓库
镜像仓库(Repository)是存储和分发镜像的地方。Docker Hub 是最常用的公共镜像仓库,提供了大量官方和社区维护的镜像。除了 Docker Hub,还有:
容器(Container)是镜像的运行实例。当您运行一个镜像时,Docker 会创建一个容器,这个容器包含了镜像的所有内容以及一个可写的层(Container Layer)。
容器的生命周期
容器的生命周期包括以下几个阶段:
容器的特点
容器 vs 虚拟机
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动时间 | 秒级 | 分钟级 |
| 资源占用 | 低 | 高 |
| 隔离程度 | 进程级 | 系统级 |
| 性能开销 | 低 | 较高 |
| 可移植性 | 高 | 中等 |
Docker 采用客户端-服务器(C/S)架构,主要组件包括:
Docker 守护进程(Docker Daemon)
Docker 守护进程(dockerd)是 Docker 的核心组件,负责:
守护进程在后台运行,监听来自客户端的请求。
Docker 客户端(Docker Client)
Docker 客户端(docker)是用户与 Docker 交互的命令行工具。客户端通过 Docker API 与守护进程通信,执行各种操作。
Docker 镜像仓库(Registry)
镜像仓库用于存储和分发 Docker 镜像。Docker Hub 是默认的公共仓库,也可以使用私有仓库。
Docker 对象
Docker 管理的主要对象包括:
Docker 的底层技术
Docker 基于 Linux 内核的以下技术实现:
Docker 容器化技术广泛应用于各种场景:
应用部署
开发环境
CI/CD 流水线
云原生应用
Docker 支持多种操作系统平台,安装方法因平台而异。
在 Linux 上安装
大多数 Linux 发行版都可以通过包管理器安装 Docker:
Ubuntu/Debian:
# 更新包索引
sudo apt update
# 安装必要的依赖
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加 Docker 仓库
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
# 安装 Docker Engine
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 启动 Docker 服务
sudo systemctl start docker
sudo systemctl enable docker
# 将当前用户添加到 docker 组(可选,避免每次使用 sudo)
sudo usermod -aG docker $USER
CentOS/RHEL/Fedora:
# 安装必要的工具
sudo yum install -y yum-utils
# 添加 Docker 仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装 Docker Engine
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 启动 Docker 服务
sudo systemctl start docker
sudo systemctl enable docker
Arch Linux:
sudo pacman -S docker
sudo systemctl start docker
sudo systemctl enable docker
在 macOS 上安装
macOS 上推荐使用 Docker Desktop:
或者使用 Homebrew:
brew install --cask docker
在 Windows 上安装
Windows 上推荐使用 Docker Desktop:
使用官方安装脚本(Linux)
Docker 提供了便捷的安装脚本:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
安装完成后,验证 Docker 是否正常工作:
# 查看 Docker 版本
docker --version
# 查看 Docker 详细信息
docker info
# 运行测试容器
docker run hello-world
如果 hello-world 容器能够正常运行,说明 Docker 安装成功。
镜像操作
# 搜索镜像
docker search nginx
# 拉取镜像
docker pull nginx:latest
# 查看本地镜像列表
docker images
# 查看镜像详细信息
docker inspect nginx
# 删除镜像
docker rmi nginx
# 删除所有未使用的镜像
docker image prune -a
容器操作
# 运行容器(前台运行)
docker run nginx
# 运行容器(后台运行)
docker run -d nginx
# 运行容器并指定名称
docker run -d --name my-nginx nginx
# 运行容器并映射端口
docker run -d -p 8080:80 --name my-nginx nginx
# 运行容器并挂载数据卷
docker run -d -v /host/path:/container/path nginx
# 运行容器并设置环境变量
docker run -d -e ENV_VAR=value nginx
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 查看容器日志
docker logs my-nginx
# 实时查看容器日志
docker logs -f my-nginx
# 进入运行中的容器
docker exec -it my-nginx /bin/bash
# 停止容器
docker stop my-nginx
# 启动已停止的容器
docker start my-nginx
# 重启容器
docker restart my-nginx
# 删除容器
docker rm my-nginx
# 强制删除运行中的容器
docker rm -f my-nginx
# 删除所有已停止的容器
docker container prune
常用命令组合
# 运行容器并在退出后自动删除
docker run --rm nginx
# 运行交互式容器
docker run -it ubuntu /bin/bash
# 在容器中执行命令
docker exec my-nginx ls /usr/share/nginx/html
# 复制文件到容器
docker cp file.txt my-nginx:/path/in/container
# 从容器复制文件
docker cp my-nginx:/path/in/container/file.txt ./
理解容器的生命周期对于有效使用 Docker 至关重要。
创建容器
# 创建但不启动容器
docker create --name my-container nginx
# 创建并启动容器
docker run -d --name my-container nginx
启动和停止
# 启动容器
docker start my-container
# 停止容器(发送 SIGTERM,等待进程优雅退出)
docker stop my-container
# 强制停止容器(发送 SIGKILL)
docker kill my-container
# 暂停容器(暂停进程但不释放资源)
docker pause my-container
# 恢复暂停的容器
docker unpause my-container
重启容器
# 重启容器
docker restart my-container
删除容器
# 删除已停止的容器
docker rm my-container
# 强制删除运行中的容器
docker rm -f my-container
# 删除所有已停止的容器
docker container prune
交互式容器允许您与容器进行交互,这对于调试和开发非常有用。
运行交互式容器
# 运行交互式 Ubuntu 容器
docker run -it ubuntu /bin/bash
# 运行交互式容器并指定工作目录
docker run -it -w /app ubuntu /bin/bash
# 运行交互式容器并挂载当前目录
docker run -it -v $(pwd):/app ubuntu /bin/bash
在运行中的容器中执行命令
# 在容器中执行命令
docker exec my-container ls -la
# 进入容器的交互式 shell
docker exec -it my-container /bin/bash
# 以 root 用户执行命令
docker exec -u root -it my-container /bin/bash
实用技巧
# 查看容器资源使用情况
docker stats my-container
# 查看容器的进程
docker top my-container
# 查看容器的详细信息
docker inspect my-container
# 查看容器的端口映射
docker port my-container
Dockerfile 是一个文本文件,包含了一系列指令,用于自动化构建 Docker 镜像。通过 Dockerfile,您可以定义镜像的构建过程,包括基础镜像、依赖安装、文件复制、环境配置等。
Dockerfile 的基本结构
一个典型的 Dockerfile 包含以下部分:
# 指定基础镜像
FROM node:16-alpine
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY package*.json ./
# 安装依赖
RUN npm install
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 定义启动命令
CMD ["node", "server.js"]
FROM
FROM 指令指定基础镜像,这是 Dockerfile 的第一条指令(注释除外)。
# 使用官方 Node.js 镜像
FROM node:16
# 使用 Alpine Linux 版本(更小)
FROM node:16-alpine
# 使用特定标签
FROM ubuntu:20.04
# 使用多阶段构建的基础镜像
FROM node:16 AS builder
RUN
RUN 指令在镜像构建过程中执行命令,每一条 RUN 指令都会创建一个新的镜像层。
# 执行单个命令
RUN apt-get update
# 执行多个命令(推荐,减少层数)
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 使用 shell 形式
RUN echo "Hello, Docker!"
# 使用 exec 形式(推荐)
RUN ["/bin/bash", "-c", "echo Hello, Docker!"]
COPY 和 ADD
COPY 和 ADD 都用于复制文件到镜像中,但 ADD 支持 URL 和自动解压。
# 复制文件
COPY package.json /app/
# 复制多个文件
COPY package.json package-lock.json /app/
# 复制整个目录
COPY . /app/
# 使用通配符
COPY *.txt /app/
# ADD 支持 URL(不推荐,使用 RUN wget/curl 更好)
ADD https://example.com/file.tar.gz /tmp/
# ADD 自动解压(COPY 不会)
ADD archive.tar.gz /app/
WORKDIR
WORKDIR 指令设置工作目录,后续的指令都会在这个目录下执行。
# 设置工作目录
WORKDIR /app
# 后续命令都在 /app 目录下执行
RUN npm install
COPY . .
ENV
ENV 指令设置环境变量,可以在构建过程和容器运行时使用。
# 设置单个环境变量
ENV NODE_ENV=production
# 设置多个环境变量
ENV NODE_ENV=production \
PORT=3000
# 在后续指令中使用
ENV PATH=/app/node_modules/.bin:$PATH
ARG
ARG 指令定义构建时的变量,只在构建过程中有效。
# 定义构建参数
ARG NODE_VERSION=16
# 使用构建参数
FROM node:${NODE_VERSION}
# 构建时传递参数
# docker build --build-arg NODE_VERSION=18 .
EXPOSE
EXPOSE 指令声明容器运行时监听的端口,这只是文档说明,不会实际打开端口。
# 暴露单个端口
EXPOSE 3000
# 暴露多个端口
EXPOSE 3000 8080
# 指定协议
EXPOSE 3000/tcp
EXPOSE 53/udp
CMD
CMD 指令定义容器启动时执行的默认命令,只能有一条 CMD 指令。
# Shell 形式
CMD npm start
# Exec 形式(推荐)
CMD ["node", "server.js"]
# 带参数
CMD ["node", "server.js", "--port", "3000"]
ENTRYPOINT
ENTRYPOINT 指令定义容器启动时的入口点,与 CMD 类似但更固定。
# Exec 形式(推荐)
ENTRYPOINT ["node"]
# 与 CMD 结合使用
ENTRYPOINT ["node"]
CMD ["server.js"]
# 这样运行容器时可以传递参数
# docker run my-image app.js
USER
USER 指令指定运行容器的用户,默认是 root。
# 切换到非 root 用户
USER node
# 使用 UID
USER 1000
VOLUME
VOLUME 指令创建数据卷挂载点。
# 创建数据卷
VOLUME ["/data"]
# 多个数据卷
VOLUME ["/data", "/logs"]
HEALTHCHECK
HEALTHCHECK 指令定义健康检查。
# 健康检查
HEALTHCHECK \
CMD curl -f http://localhost:3000/health || exit 1
使用 docker build 命令构建镜像:
# 基本构建
docker build -t my-app:latest .
# 指定 Dockerfile 路径
docker build -f Dockerfile.prod -t my-app:prod .
# 传递构建参数
docker build --build-arg NODE_ENV=production -t my-app:prod .
# 不使用缓存构建
docker build --no-cache -t my-app:latest .
# 查看构建过程
docker build --progress=plain -t my-app:latest .
多阶段构建允许在 Dockerfile 中使用多个 FROM 指令,每个阶段可以使用不同的基础镜像,最终只保留最后一个阶段的内容。这样可以显著减小最终镜像的大小。
单阶段构建示例
FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 最终镜像包含构建工具和源代码,体积较大
多阶段构建示例
# 构建阶段
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 运行阶段
FROM node:16-alpine
WORKDIR /app
# 只复制构建产物
COPY /app/dist ./dist
COPY /app/package*.json ./
RUN npm install --production
EXPOSE 3000
CMD ["node", "dist/server.js"]
多阶段构建的优势
实际应用示例
# 编译阶段
FROM golang:1.19 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app
# 运行阶段
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY /app/app .
CMD ["./app"]
1. 利用构建缓存
Docker 会缓存每一层的构建结果,如果某一层没有变化,就会使用缓存。合理组织 Dockerfile 可以充分利用缓存:
# 不好的做法:依赖变化会导致所有层重建
COPY . .
RUN npm install
RUN npm run build
# 好的做法:依赖文件单独处理,利用缓存
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
2. 合并 RUN 指令
减少镜像层数可以减小镜像体积:
# 不好的做法:多个层
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean
# 好的做法:合并为单层
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
3. 使用 .dockerignore
创建 .dockerignore 文件排除不需要的文件:
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
4. 选择合适的基础镜像
latest# 推荐
FROM node:16-alpine
# 不推荐
FROM node:latest
5. 清理不必要的文件
在构建过程中清理临时文件:
RUN apt-get update && \
apt-get install -y build-essential && \
# 构建应用
make build && \
# 清理构建工具
apt-get remove -y build-essential && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/*
Node.js 应用 Dockerfile
FROM node:16-alpine AS builder
WORKDIR /app
# 复制依赖文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制源代码
COPY . .
# 构建应用
RUN npm run build
# 运行阶段
FROM node:16-alpine
WORKDIR /app
# 复制依赖和构建产物
COPY /app/node_modules ./node_modules
COPY /app/dist ./dist
COPY /app/package*.json ./
# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
USER nodejs
EXPOSE 3000
HEALTHCHECK \
CMD node healthcheck.js
CMD ["node", "dist/server.js"]
Python 应用 Dockerfile
FROM python:3.9-slim AS builder
WORKDIR /app
# 安装构建依赖
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装 Python 依赖
RUN pip install --user --no-cache-dir -r requirements.txt
# 运行阶段
FROM python:3.9-slim
WORKDIR /app
# 复制 Python 依赖
COPY /root/.local /root/.local
# 复制应用代码
COPY . .
# 确保脚本可执行
RUN chmod +x app.py
ENV PATH=/root/.local/bin:$PATH
EXPOSE 8000
CMD ["python", "app.py"]
Go 应用 Dockerfile
# 构建阶段
FROM golang:1.19-alpine AS builder
WORKDIR /app
# 安装依赖
COPY go.mod go.sum ./
RUN go mod download
# 复制源代码
COPY . .
# 构建应用
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
# 运行阶段
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# 复制二进制文件
COPY /app/app .
EXPOSE 8080
CMD ["./app"]
Docker Compose 是 Docker 官方提供的用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 配置文件,您可以定义应用的各个服务、网络、数据卷等,然后使用一条命令启动整个应用栈。
Docker Compose 的优势
适用场景
基本结构
version: '3.8'
services:
web:
build: .
ports:
- '3000:3000'
db:
image: postgres:13
environment:
POSTGRES_PASSWORD: password
volumes:
db-data:
networks:
default:
driver: bridge
版本说明
Docker Compose 文件格式有多个版本,推荐使用 3.8 或更高版本,它支持最新的 Docker 功能。
基本服务定义
services:
web:
image: nginx:latest
container_name: my-nginx
ports:
- '8080:80'
volumes:
- ./html:/usr/share/nginx/html
environment:
- NGINX_HOST=localhost
restart: unless-stopped
构建服务
services:
web:
build:
context: .
dockerfile: Dockerfile
args:
NODE_ENV: production
ports:
- '3000:3000'
使用 Dockerfile
services:
app:
build:
context: ./app
dockerfile: Dockerfile.prod
ports:
- '3000:3000'
环境变量
services:
web:
image: node:16
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/mydb
env_file:
- .env
- .env.production
依赖关系
services:
web:
build: .
depends_on:
- db
- redis
db:
image: postgres:13
redis:
image: redis:6-alpine
健康检查
services:
web:
image: nginx
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost']
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
资源限制
services:
web:
image: nginx
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
默认网络
Docker Compose 会为每个项目创建一个默认网络,服务可以通过服务名相互访问。
services:
web:
image: nginx
api:
image: node:16
# 可以通过 http://web 访问 web 服务
自定义网络
services:
web:
image: nginx
networks:
- frontend
api:
image: node:16
networks:
- frontend
- backend
db:
image: postgres:13
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
网络别名
services:
web:
image: nginx
networks:
frontend:
aliases:
- www
- website
命名数据卷
services:
db:
image: postgres:13
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
绑定挂载
services:
web:
image: nginx
volumes:
- ./html:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/nginx.conf:ro
匿名卷
services:
db:
image: postgres:13
volumes:
- /var/lib/postgresql/data
完整的 Web 应用栈
version: '3.8'
services:
# 前端服务
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- '3000:3000'
environment:
- REACT_APP_API_URL=http://backend:8000
depends_on:
- backend
networks:
- app-network
# 后端服务
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- '8000:8000'
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
volumes:
- ./backend:/app
networks:
- app-network
# 数据库服务
db:
image: postgres:13
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
# Redis 服务
redis:
image: redis:6-alpine
ports:
- '6379:6379'
volumes:
- redis-data:/data
networks:
- app-network
volumes:
db-data:
redis-data:
networks:
app-network:
driver: bridge
微服务应用
version: '3.8'
services:
# API 网关
gateway:
image: nginx:alpine
ports:
- '80:80'
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- user-service
- order-service
networks:
- microservices
# 用户服务
user-service:
build: ./services/user
environment:
- DATABASE_URL=postgresql://user:pass@user-db:5432/users
depends_on:
- user-db
networks:
- microservices
# 订单服务
order-service:
build: ./services/order
environment:
- DATABASE_URL=postgresql://user:pass@order-db:5432/orders
depends_on:
- order-db
networks:
- microservices
# 用户数据库
user-db:
image: postgres:13
environment:
POSTGRES_DB: users
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- user-db-data:/var/lib/postgresql/data
networks:
- microservices
# 订单数据库
order-db:
image: postgres:13
environment:
POSTGRES_DB: orders
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- order-db-data:/var/lib/postgresql/data
networks:
- microservices
volumes:
user-db-data:
order-db-data:
networks:
microservices:
driver: bridge
基本命令
# 启动所有服务
docker-compose up
# 后台启动所有服务
docker-compose up -d
# 构建并启动
docker-compose up --build
# 启动特定服务
docker-compose up web db
# 停止所有服务
docker-compose stop
# 停止并删除容器
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 ls -la
# 进入容器
docker-compose exec web /bin/bash
# 扩展服务实例
docker-compose up -d --scale web=3
Docker 提供了多种网络模式,每种模式适用于不同的场景。
Bridge 模式(默认)
Bridge 模式是 Docker 的默认网络模式,创建一个内部网络,容器通过虚拟网桥连接到这个网络。
# 创建自定义 bridge 网络
docker network create my-network
# 运行容器并连接到网络
docker run -d --name web --network my-network nginx
# 查看网络信息
docker network inspect my-network
Host 模式
Host 模式直接使用宿主机的网络,容器不会获得独立的网络命名空间。
# 使用 host 网络模式
docker run -d --name web --network host nginx
None 模式
None 模式禁用网络,容器只有回环接口。
# 使用 none 网络模式
docker run -d --name web --network none nginx
Overlay 模式
Overlay 模式用于 Docker Swarm 集群,允许不同主机上的容器通信。
# 创建 overlay 网络(需要 Swarm 模式)
docker network create --driver overlay my-overlay
Macvlan 模式
Macvlan 模式允许容器直接使用物理网络接口,每个容器有独立的 MAC 地址。
# 创建 macvlan 网络
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
my-macvlan
创建网络
# 创建 bridge 网络
docker network create my-bridge
# 创建网络并指定子网
docker network create --subnet=172.20.0.0/16 my-network
# 创建网络并指定网关
docker network create --subnet=172.20.0.0/16 --gateway=172.20.0.1 my-network
# 创建网络并启用 IPv6
docker network create --ipv6 --subnet=2001:db8::/64 my-network
连接容器到网络
# 运行容器时连接到网络
docker run -d --name web --network my-network nginx
# 将运行中的容器连接到网络
docker network connect my-network web
# 断开容器与网络的连接
docker network disconnect my-network web
网络管理
# 列出所有网络
docker network ls
# 查看网络详细信息
docker network inspect my-network
# 删除网络
docker network rm my-network
# 删除所有未使用的网络
docker network prune
数据卷是 Docker 管理的数据持久化机制,独立于容器的生命周期。
创建数据卷
# 创建命名数据卷
docker volume create my-volume
# 查看所有数据卷
docker volume ls
# 查看数据卷详细信息
docker volume inspect my-volume
# 删除数据卷
docker volume rm my-volume
# 删除所有未使用的数据卷
docker volume prune
使用数据卷
# 运行容器并使用数据卷
docker run -d --name web -v my-volume:/data nginx
# 使用绑定挂载
docker run -d --name web -v /host/path:/container/path nginx
# 只读挂载
docker run -d --name web -v /host/path:/container/path:ro nginx
绑定挂载直接将宿主机的目录或文件挂载到容器中。
# 挂载目录
docker run -d --name web -v /host/html:/usr/share/nginx/html nginx
# 挂载文件
docker run -d --name web -v /host/nginx.conf:/etc/nginx/nginx.conf nginx
# 只读挂载
docker run -d --name web -v /host/html:/usr/share/nginx/html:ro nginx
策略选择
最佳实践
# docker-compose.yml
services:
db:
image: postgres:13
volumes:
# 使用命名数据卷(推荐)
- db-data:/var/lib/postgresql/data
# 使用绑定挂载配置文件
- ./postgresql.conf:/etc/postgresql/postgresql.conf:ro
# 使用 tmpfs 挂载临时数据
- type: tmpfs
target: /tmp
volumes:
db-data:
备份数据卷
# 备份数据卷
docker run --rm -v my-volume:/data -v $(pwd):/backup \
ubuntu tar czf /backup/backup.tar.gz /data
# 使用容器备份
docker run --rm -v my-volume:/data -v $(pwd):/backup \
postgres:13 pg_dump -U user mydb > /backup/backup.sql
恢复数据卷
# 恢复数据卷
docker run --rm -v my-volume:/data -v $(pwd):/backup \
ubuntu tar xzf /backup/backup.tar.gz -C /data
# 使用容器恢复
docker run --rm -v my-volume:/data -v $(pwd):/backup \
postgres:13 psql -U user mydb < /backup/backup.sql
自动化备份脚本
#!/bin/bash
# backup-volume.sh
VOLUME_NAME=$1
BACKUP_DIR="./backups"
DATE=$(date +%Y%m%d_%H%M%S)
if [ -z "$VOLUME_NAME" ]; then
echo "Usage: $0 <volume-name>"
exit 1
fi
mkdir -p $BACKUP_DIR
docker run --rm \
-v $VOLUME_NAME:/data \
-v $(pwd)/$BACKUP_DIR:/backup \
ubuntu tar czf /backup/${VOLUME_NAME}_${DATE}.tar.gz -C /data .
echo "Backup completed: ${BACKUP_DIR}/${VOLUME_NAME}_${DATE}.tar.gz"
选择合适的基础镜像
# 使用 Alpine Linux(推荐,体积小)
FROM node:16-alpine
# 而不是完整版本
# FROM node:16
多阶段构建
# 构建阶段
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 运行阶段(只保留必要文件)
FROM node:16-alpine
WORKDIR /app
COPY /app/dist ./dist
COPY /app/package*.json ./
RUN npm install --production
CMD ["node", "dist/server.js"]
清理不必要的文件
RUN apt-get update && \
apt-get install -y build-essential && \
# 构建应用
make build && \
# 清理
apt-get remove -y build-essential && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/*
使用 .dockerignore
创建 .dockerignore 文件:
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
*.log
.DS_Store
合理组织 Dockerfile
# 好的做法:依赖文件单独处理
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 不好的做法:所有文件一起复制
COPY . .
RUN npm install
RUN npm run build
利用构建参数
ARG BUILDKIT_INLINE_CACHE=1
FROM node:16-alpine AS builder
# ...
使用非 root 用户
FROM node:16-alpine
# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 切换到非 root 用户
USER nodejs
WORKDIR /app
COPY . .
CMD ["node", "server.js"]
最小权限原则
# 只暴露必要的端口
EXPOSE 3000
# 只复制必要的文件
COPY dist/ ./dist/
COPY package*.json ./
# 不要复制敏感文件
# COPY .env ./
扫描镜像漏洞
# 使用 Docker Scout(Docker Desktop 内置)
docker scout quickview my-image
# 使用 Trivy
trivy image my-image
# 使用 Snyk
snyk test --docker my-image
定期更新基础镜像
# 使用特定版本标签
FROM node:16-alpine
# 定期检查并更新
# FROM node:18-alpine
Go 应用示例
# 构建阶段
FROM golang:1.19-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app .
# 运行阶段
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY /app/app .
CMD ["./app"]
Node.js 应用示例
# 依赖安装阶段
FROM node:16-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
# 构建阶段
FROM node:16-alpine AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
RUN npm run build
# 运行阶段
FROM node:16-alpine
WORKDIR /app
COPY /app/dist ./dist
COPY /app/package*.json ./
RUN npm ci --only=production
CMD ["node", "dist/server.js"]
基本健康检查
HEALTHCHECK \
CMD curl -f http://localhost:3000/health || exit 1
使用健康检查脚本
HEALTHCHECK \
CMD /healthcheck.sh || exit 1
在 Docker Compose 中配置
services:
web:
image: nginx
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost']
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
配置日志驱动
# 使用 JSON 文件日志驱动(默认)
docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 nginx
# 使用 syslog
docker run --log-driver syslog --log-opt syslog-address=udp://localhost:514 nginx
# 禁用日志
docker run --log-driver none nginx
在 Dockerfile 中配置
# 无法在 Dockerfile 中直接配置,需要在运行时指定
在 Docker Compose 中配置
services:
web:
image: nginx
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '3'
Docker Swarm
Docker Swarm 是 Docker 原生的集群管理工具,简单易用。
# 初始化 Swarm
docker swarm init
# 加入节点
docker swarm join --token <token> <manager-ip>:2377
# 部署服务
docker service create --replicas 3 --name web nginx
# 扩展服务
docker service scale web=5
# 更新服务
docker service update --image nginx:latest web
Kubernetes
Kubernetes 是更强大的容器编排平台,适合大规模生产环境。
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
使用 Prometheus 监控
# docker-compose.yml
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- '9090:9090'
node-exporter:
image: prom/node-exporter
ports:
- '9100:9100'
使用 ELK 栈收集日志
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
environment:
- discovery.type=single-node
ports:
- '9200:9200'
logstash:
image: docker.elastic.co/logstash/logstash:7.14.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
kibana:
image: docker.elastic.co/kibana/kibana:7.14.0
ports:
- '5601:5601'
GitHub Actions 示例
name: Build and Push Docker Image
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Docker image
run: docker build -t my-app:${{ github.sha }} .
- name: Push to Registry
run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
docker push my-app:${{ github.sha }}
GitLab CI 示例
# .gitlab-ci.yml
build:
stage: build
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- main
镜像安全扫描
# 使用 Trivy 扫描
trivy image my-app:latest
# 使用 Docker Scout
docker scout quickview my-app:latest
运行时安全
# docker-compose.yml
services:
web:
image: nginx
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
read_only: true
tmpfs:
- /tmp
- /var/cache/nginx
网络安全
# 创建隔离网络
docker network create --internal isolated-network
# 限制容器间通信
docker run --network isolated-network nginx
资源限制
services:
web:
image: nginx
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
优化启动时间
# 使用健康检查避免过早流量
HEALTHCHECK \
CMD curl -f http://localhost || exit 1
优化镜像拉取
# 使用镜像代理
docker pull --platform linux/amd64 nginx:latest
# 预拉取镜像
docker pull nginx:latest
查看容器日志
# 查看日志
docker logs container-name
# 实时查看日志
docker logs -f container-name
# 查看最近 100 行
docker logs --tail 100 container-name
检查容器状态
# 查看容器详细信息
docker inspect container-name
# 查看容器进程
docker top container-name
# 查看资源使用
docker stats container-name
进入容器调试
# 进入运行中的容器
docker exec -it container-name /bin/bash
# 如果容器没有 shell,使用其他工具
docker exec -it container-name sh
网络问题排查
# 查看网络配置
docker network inspect network-name
# 测试容器间连通性
docker exec container1 ping container2
# 查看端口映射
docker port container-name
常见问题解决
Docker 容器化技术已经成为现代软件开发和运维的标准工具,它通过简化部署流程、提高环境一致性、优化资源利用,为开发者和运维人员带来了巨大的价值。从开发环境的快速搭建,到生产环境的自动化部署,Docker 在各个阶段都发挥着重要作用。
通过本文的全面介绍,我们从基础概念到核心操作,从 Dockerfile 编写到 Docker Compose 编排,从网络存储配置到生产环境部署,系统地学习了 Docker 的各个方面。掌握这些知识,不仅能够提升开发效率,还能为构建现代化的应用架构打下坚实基础。
核心要点回顾
学习路径建议
实践建议
资源推荐
持续学习
Docker 和容器化技术正在快速发展,新的工具和最佳实践不断涌现。建议:
希望本文能够帮助您全面掌握 Docker 容器化技术,在实际工作中充分发挥其强大功能,提升开发效率和运维能力。记住,容器化不仅仅是技术工具,更是一种思维方式,它要求我们重新思考应用的构建、部署和管理方式。通过持续学习和实践,您将能够构建出更加现代化、高效、可靠的应用系统。
祝您在容器化的道路上越走越远,构建出优秀的应用!
发表评论
请登录后发表评论
评论 (0)