前言
容器化技术已经从一个新兴概念变成了现代网站部署的标准方案。对于个人站长来说,Docker 不仅仅是一个"高大上"的技术名词,它实际上能解决很多实际问题:环境不一致导致的"在我机器上能运行"问题、服务器迁移时的重复配置痛苦、多站点隔离的安全需求。本文将从零开始,带你一步步掌握 Docker 容器化部署的核心技能,最终搭建一套可直接用于生产环境的个人网站架构。
一、Docker 基础概念
1.1 什么是 Docker
Docker 是一个开源的容器化平台,它允许你将应用程序及其所有依赖打包到一个标准化的单元中——这个单元就是"容器"。与传统的虚拟机不同,容器共享宿主机的操作系统内核,因此更轻量、启动更快、资源占用更少。
容器 vs 虚拟机对比:
- 启动时间:容器毫秒级,虚拟机分钟级
- 磁盘占用:容器 MB 级别,虚拟机 GB 级别
- 性能损耗:容器几乎无损耗,虚拟机有约 5-15% 的性能开销
- 隔离级别:容器为进程级隔离,虚拟机为硬件级虚拟化
1.2 核心组件
- Docker Daemon(dockerd):后台守护进程,负责管理容器的生命周期
- Docker Client(docker CLI):与守护进程通信的命令行工具
- Docker Image(镜像):一个只读模板,包含运行应用所需的文件系统和配置
- Docker Container(容器):镜像的运行实例,可读写
- Docker Registry(仓库):存储和分发镜像的服务,Docker Hub 是最流行的公共仓库
1.3 安装 Docker
在 Ubuntu/Debian 服务器上安装 Docker 非常简单:
# 更新包索引
sudo apt update
# 安装依赖
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
# 添加 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=amd64 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
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
# 将当前用户加入 docker 组(避免每次使用 sudo)
sudo usermod -aG docker $USER
# 验证安装
docker --version安装完成后,运行 docker info 可以查看系统信息,运行 docker run hello-world 测试容器能否正常工作。
二、Dockerfile 编写指南
Dockerfile 是一个文本文件,包含了构建镜像所需的指令序列。下面以一个典型的 PHP + Nginx 个人网站为例。
2.1 基础 Dockerfile 示例
# 使用 PHP 8.2 官方镜像作为基础
FROM php:8.2-fpm-alpine AS php-base
# 安装必要的 PHP 扩展
RUN docker-php-ext-install pdo_mysql mysqli bcmath
# 安装 Redis 扩展
RUN pecl install redis && docker-php-ext-enable redis
# 复制应用代码
COPY . /var/www/html
# 设置工作目录
WORKDIR /var/www/html
# 设置权限
RUN chown -R www-data:www-data /var/www/html
# Nginx 阶段
FROM nginx:alpine AS nginx
# 复制 Nginx 配置文件
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 从 PHP 阶段复制静态文件
COPY --from=php-base /var/www/html /var/www/html2.2 多阶段构建
多阶段构建可以显著减小最终镜像的体积,这是生产环境部署的最佳实践:
# 构建阶段
FROM node:20-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;"]通过多阶段构建,最终镜像只包含 Nginx 和编译后的静态文件,体积从 1GB+ 缩小到不到 100MB。
三、Docker Compose 编排多容器
对于个人网站,通常需要多个服务协同工作:Nginx(反向代理)、PHP-FPM(应用处理)、MySQL(数据库)、Redis(缓存)。Docker Compose 可以一站式管理这些服务。
3.1 编写 docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- app_data:/var/www/html:ro
depends_on:
- php
networks:
- webnet
restart: unless-stopped
php:
build:
context: .
dockerfile: Dockerfile.php
volumes:
- app_data:/var/www/html
environment:
- DB_HOST=mysql
- DB_NAME=myblog
- DB_USER=myuser
- DB_PASS=secret
- REDIS_HOST=redis
depends_on:
- mysql
- redis
networks:
- webnet
restart: unless-stopped
mysql:
image: mysql:8.0
volumes:
- mysql_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=rootpass
- MYSQL_DATABASE=myblog
- MYSQL_USER=myuser
- MYSQL_PASSWORD=secret
networks:
- webnet
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- webnet
restart: unless-stopped
volumes:
app_data:
mysql_data:
redis_data:
networks:
webnet:
driver: bridge3.2 常用 Compose 命令
# 启动所有服务
docker compose up -d
# 查看日志
docker compose logs -f
# 重启某个服务
docker compose restart php
# 重新构建并启动
docker compose up -d --build
# 停止所有服务
docker compose down
# 停止并删除数据卷(谨慎操作)
docker compose down -v四、生产环境最佳实践
4.1 镜像优化
- 尽量使用 Alpine 版本的基础镜像,体积小且安全
- 合并 RUN 命令减少镜像层数
- 使用
.dockerignore文件排除不必要的文件 - 通过多阶段构建分离构建环境和运行环境
.dockerignore 示例:
.git
node_modules
.env
*.md
tests/
logs/4.2 数据持久化
容器的文件系统是临时的,容器删除后数据会丢失。必须使用卷(volume)来持久化重要数据:
# 创建命名卷
docker volume create myblog_data
# 使用命名卷
docker run -v myblog_data:/var/lib/mysql mysql:8.0
# 使用绑定挂载(直接映射主机目录)
docker run -v /host/path:/container/path nginx:alpine4.3 安全加固
- 不要以 root 用户运行容器内的进程
- 使用只读文件系统(
read_only: true) - 限制容器资源使用(CPU/内存限制)
- 定期更新基础镜像以修复安全漏洞
# docker-compose 中的安全配置示例
services:
php:
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M4.4 日志管理
Docker 默认将日志存储在 JSON 文件中,长期运行会占用大量磁盘空间。建议配置日志轮转:
# 全局配置 /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}# 或者在 compose 中按服务配置
services:
nginx:
logging:
driver: "json-file"
options:
max-size: "5m"
max-file: "3"五、实际部署案例
5.1 Typecho 博客容器化
以 Typecho 博客系统为例,完整部署流程:
# 1. 创建项目目录
mkdir typecho-docker && cd typecho-docker
# 2. 下载 Typecho
wget https://github.com/typecho/typecho/releases/latest/download/typecho.zip
unzip typecho.zip
# 3. 创建 docker-compose.yml(参考上面的配置)
vim docker-compose.yml
# 4. 创建 Nginx 配置
cat > nginx.conf << 'EOF'
server {
listen 80;
server_name yourdomain.com;
root /var/www/html;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
EOF
# 5. 启动
docker compose up -d
# 6. 查看日志确认启动成功
docker compose logs5.2 备份策略
容器化部署后,数据库备份仍然至关重要:
#!/bin/bash
# docker-backup.sh
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# 备份 MySQL
docker exec typecho-mysql-1 mysqldump -u root -prootpass myblog | gzip > $BACKUP_DIR/db_$DATE.sql.gz
# 保留最近 30 天的备份
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +30 -delete
echo "Backup completed: $BACKUP_DIR/db_$DATE.sql.gz"将备份脚本加入 crontab,每天凌晨自动执行:
0 3 * * * /root/scripts/docker-backup.sh六、常见问题排查
6.1 容器无法启动
# 查看容器日志
docker logs container_name
# 检查容器状态
docker ps -a
# 进入容器调试
docker exec -it container_name /bin/sh6.2 端口冲突
# 检查端口占用
netstat -tlnp | grep 80
# 修改映射端口
# 在 docker-compose.yml 中将 "80:80" 改为 "8080:80"6.3 磁盘空间不足
# 清理未使用的镜像、容器和数据卷
docker system prune -a
# 查看磁盘使用情况
docker system df
# 仅清理数据卷
docker volume prune结语
容器化部署已经成为个人网站运维的必备技能。通过 Docker,你可以实现环境一致性、快速部署、轻松迁移和高效资源利用。本文涵盖了从基础概念到生产环境部署的完整路径,希望能帮助你在实践中少走弯路。
记住,容器化是一个持续学习的过程,每次遇到问题都是一次提升的机会。建议从一个小项目开始,逐步将现有网站迁移到容器化架构,在实践中积累经验。