本文最后更新于 1 分钟前,文中所描述的信息可能已发生改变。
容器化技术彻底改变了应用程序的开发、测试和部署方式。Docker 作为最流行的容器平台,提供了一种轻量级、可移植且独立的方式来打包和运行应用程序。本文将详细介绍如何使用 Docker 进行应用程序容器化和部署。
Docker 基础概念
在深入了解部署过程之前,先来理解几个关键概念:
- 容器(Container):轻量级、可执行的软件包,包含应用程序及其所有依赖
- 镜像(Image):容器的不可变模板,用于创建容器
- Dockerfile:构建镜像的脚本文件
- 仓库(Repository):存储和分发 Docker 镜像的地方
- Docker Compose:定义和运行多容器 Docker 应用的工具
- Docker Swarm/Kubernetes:容器编排工具,管理多个容器的部署
安装 Docker
Linux(Ubuntu)
# 更新软件包索引
sudo apt update
# 安装依赖
sudo apt install apt-transport-https ca-certificates curl software-properties-common
# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 添加 Docker 源
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# 再次更新软件包索引
sudo apt update
# 安装 Docker
sudo apt install docker-ce
# 验证 Docker 是否安装成功
docker --version
macOS
最简单的方式是安装 Docker Desktop for Mac:
- 从 Docker 官网 下载 Docker Desktop
- 双击
.dmg
文件并将 Docker 拖到应用程序文件夹 - 启动 Docker Desktop 应用程序
Windows
与 macOS 类似,安装 Docker Desktop for Windows:
- 从 Docker 官网 下载 Docker Desktop
- 运行安装程序
- 启动 Docker Desktop 应用程序
创建 Docker 镜像
编写 Dockerfile
以一个简单的 Node.js 应用为例:
# 使用官方 Node.js 镜像作为基础镜像
FROM node:18-alpine
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json 文件
COPY package*.json ./
# 安装依赖
RUN npm ci
# 复制源代码
COPY . .
# 如果有构建步骤(例如 TypeScript 编译或 Next.js 构建)
RUN npm run build
# 设置环境变量
ENV NODE_ENV=production
# 开放端口
EXPOSE 3000
# 设置启动命令
CMD ["npm", "start"]
Dockerfile 最佳实践
- 使用精简的基础镜像:例如 Alpine 版本的镜像
- 多阶段构建:减小最终镜像的大小
- 合理使用缓存:将变更频率较低的指令放在前面
- 减少层数:合并相关的 RUN 命令
- 使用 .dockerignore:排除不需要的文件
.dockerignore
示例:
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
README.md
构建镜像
# 语法: docker build -t 名称:标签 构建上下文路径
docker build -t myapp:1.0 .
多阶段构建示例(前端应用)
# 构建阶段
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine
# 将构建阶段的产物复制到 Nginx 目录
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
运行 Docker 容器
基本运行
# 语法: docker run [选项] 镜像名 [命令]
docker run -d -p 3000:3000 --name myapp myapp:1.0
常用选项:
-d
:在后台运行容器-p host:container
:端口映射--name
:容器命名-v host:container
:卷挂载-e KEY=VALUE
:环境变量--network
:指定网络--restart
:重启策略
查看容器
# 查看运行中的容器
docker ps
# 查看所有容器
docker ps -a
# 查看容器日志
docker logs myapp
# 实时查看日志
docker logs -f myapp
管理容器
# 停止容器
docker stop myapp
# 启动已停止的容器
docker start myapp
# 重启容器
docker restart myapp
# 删除容器(需要先停止)
docker rm myapp
# 强制删除容器
docker rm -f myapp
使用 Docker Compose 管理多容器应用
创建 docker-compose.yml
version: '3.8'
services:
web:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:80"
depends_on:
- api
environment:
- API_URL=http://api:5000
api:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "5000:5000"
depends_on:
- db
environment:
- DB_HOST=db
- DB_USER=postgres
- DB_PASSWORD=secret
- DB_NAME=myapp
volumes:
- ./uploads:/app/uploads
db:
image: postgres:13-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=myapp
volumes:
postgres_data:
使用 Docker Compose 命令
# 启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs
# 查看特定服务的日志
docker-compose logs api
# 停止所有服务
docker-compose down
# 停止并删除所有卷
docker-compose down -v
数据持久化
挂载卷
Docker 提供三种主要的数据挂载方式:
- 卷(Volumes):由 Docker 管理的持久化存储
- 绑定挂载(Bind mounts):将主机上的目录挂载到容器
- tmpfs 挂载:在内存中存储临时数据
创建和使用命名卷:
# 创建卷
docker volume create mydata
# 使用卷
docker run -v mydata:/app/data myapp:1.0
在 Docker Compose 中使用卷:
services:
app:
image: myapp:1.0
volumes:
- mydata:/app/data
volumes:
mydata:
使用绑定挂载进行开发
在开发环境中,可以使用绑定挂载实现代码热更新:
docker run -v $(pwd):/app myapp:1.0
应用程序配置
环境变量
通过环境变量传递配置是 Docker 的最佳实践:
docker run -e DATABASE_URL=postgres://user:pass@db:5432/dbname myapp:1.0
配置文件
对于复杂配置,可以挂载配置文件:
docker run -v ./config.json:/app/config.json myapp:1.0
使用 Docker Secrets(Swarm 模式)
对于敏感信息,可以使用 Docker Secrets:
# 创建密钥
echo "supersecretpassword" | docker secret create db_password -
# 在服务中使用密钥
docker service create \
--name myapp \
--secret db_password \
myapp:1.0
容器网络
网络类型
Docker 提供了几种不同的网络驱动:
- bridge:默认网络,适用于单机容器通信
- host:使用主机网络,无隔离
- overlay:用于 Swarm 服务,实现跨主机通信
- macvlan:为容器分配 MAC 地址,直接连接物理网络
- none:禁用网络
创建自定义网络
# 创建网络
docker network create mynetwork
# 将容器连接到网络
docker run --network mynetwork myapp:1.0
在 Docker Compose 中:
networks:
frontend:
backend:
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
db:
networks:
- backend
生产环境部署
单主机部署
对于小型应用,可以使用 Docker Compose 进行单主机部署:
- 准备服务器并安装 Docker
- 编写生产环境的
docker-compose.yml
- 使用
docker-compose up -d
启动服务 - 配置反向代理和 HTTPS(如 Nginx)
使用容器编排系统
对于较大规模应用,推荐使用容器编排工具:
Docker Swarm
Docker 内置的编排工具,适合 Docker 重度用户:
# 初始化 Swarm
docker swarm init
# 创建服务
docker service create \
--name myapp \
--replicas 3 \
--publish 80:3000 \
myapp:1.0
使用 Docker Stack 部署多容器应用:
docker stack deploy -c docker-compose.yml mystack
Kubernetes
更强大、更复杂的容器编排平台:
- 准备 Kubernetes 集群(可使用 GKE、AKS、EKS 等托管服务)
- 编写 Kubernetes 资源文件(Deployment、Service、ConfigMap 等)
- 使用
kubectl apply
部署应用
持续集成和持续部署
GitHub Actions 示例
name: Build and Deploy
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: |
username/myapp:latest
username/myapp:${{ github.sha }}
- name: Deploy to production
uses: appleboy/ssh-action@v0.1.10
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/myapp
docker-compose pull
docker-compose up -d
容器监控和日志
监控解决方案
- Prometheus + Grafana:开源监控和可视化方案
- Docker Stats:基本的容器资源使用统计
- cAdvisor:容器资源使用和性能特性分析器
日志管理
- ELK Stack:Elasticsearch, Logstash, Kibana
- Fluentd/Fluent Bit:轻量级日志收集器
安全最佳实践
- 使用官方镜像,避免使用不可信的第三方镜像
- 定期更新基础镜像,确保安全补丁
- 以非 root 用户运行容器
FROM node:18-alpine
# 创建非 root 用户
RUN addgroup -g 1000 appuser && \
adduser -u 1000 -G appuser -s /bin/sh -D appuser
# 设置工作目录
WORKDIR /app
# 复制应用代码
COPY --chown=appuser:appuser . .
# 切换到非 root 用户
USER appuser
# ...其余部分
- 使用只读文件系统
docker run --read-only myapp:1.0
- 限制容器资源
docker run --memory="500m" --cpus="1.5" myapp:1.0
- 使用 Docker Content Trust 签名镜像
# 启用 DCT
export DOCKER_CONTENT_TRUST=1
# 推送签名镜像
docker push myapp:1.0
- 扫描镜像漏洞
# 使用 Docker Scout CLI
docker scout cves myapp:1.0
常见挑战与解决方案
容器化现有应用
- 分析应用依赖:理解应用所需的环境、库和配置
- 确定状态存储:识别需要持久化的数据
- 拆分服务:考虑将单体应用拆分为多个容器
容器化数据库
生产环境中容器化数据库需要特别注意:
- 使用命名卷:确保数据持久化
- 配置适当的内存和 CPU 限制
- 考虑备份策略
- 使用复制和高可用方案
对于生产环境,可能需要考虑使用托管数据库服务(如 RDS、Cloud SQL)而非自行容器化数据库。
调试容器
# 进入运行中的容器
docker exec -it myapp sh
# 查看容器详情
docker inspect myapp
# 查看容器资源使用情况
docker stats myapp
高级主题
多架构构建
为不同的 CPU 架构构建镜像:
# 创建构建器
docker buildx create --use
# 构建多架构镜像
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:1.0 --push .
使用 Docker Registry
搭建私有 Docker Registry:
docker run -d -p 5000:5000 --name registry registry:2
# 标记本地镜像
docker tag myapp:1.0 localhost:5000/myapp:1.0
# 推送到私有仓库
docker push localhost:5000/myapp:1.0
总结
容器化部署为应用程序提供了一致、可靠且可扩展的环境。通过 Docker:
- 开发者可以更专注于代码而非环境
- 应用可以在任何支持 Docker 的地方运行
- 基础设施可以更高效地利用
- 微服务架构变得更加实用
本指南涵盖了 Docker 容器化部署的核心概念和实践。通过遵循这些最佳实践和技巧,你可以充分利用容器技术的优势,简化应用的开发、测试和部署流程。
随着应用规模的增长,可以考虑探索更高级的容器编排平台,如 Kubernetes,以提供更强大的自动化、扩展和自修复能力。