前言:为什么选择Docker?

在运营家庭服务器的过程中,想要安装的程序会越来越多。媒体服务器、文件同步、广告拦截、密码管理器……但直接安装程序会产生各种问题。依赖冲突、更新时配置丢失、迁移到其他服务器时需要从头开始配置等都是典型的麻烦。

Docker可以很好地解决这些问题。由于程序在称为容器的隔离环境中运行,它们不会相互影响,而且只需几行配置文件就可以部署复杂的服务。本篇将从Docker的基本概念开始,详细介绍如何部署实际有用的服务。

1. 什么是Docker?

1.1 容器的概念

容器是将应用程序及其运行所需的一切(库、配置文件等)打包在一起的东西。虽然看起来与虚拟机类似,但它更轻量、更快。

  • 虚拟机(VM):包含完整的操作系统,因此较重且启动需要时间。
  • 容器:共享主机操作系统的内核,因此轻量且几乎可以立即启动。

简单打个比方,虚拟机就像整体搬家,而容器则是只把需要的家具装进集装箱搬运。

1.2 Docker的主要概念

  • 镜像(Image):用于创建容器的模板。包含程序和所需的环境。
  • 容器(Container):运行镜像的实例。可以理解为实际运行的程序。
  • 注册表(Registry):存储和分发镜像的仓库。Docker Hub是代表性的例子。
  • 卷(Volume):用于永久存储容器数据的空间。

1.3 Docker的优势

  • 隔离性:每个容器在独立的环境中运行,不会相互影响。
  • 可移植性:创建一次的镜像可以在任何地方以相同方式运行。
  • 可重现性:只要有配置文件,就可以随时重现相同的环境。
  • 高效性:比虚拟机使用更少的资源。
  • 生态系统:Docker Hub上公开了大量镜像,可以直接使用。

2. 安装Docker

2.1 在Ubuntu/Debian上安装

使用官方仓库安装最新版本的Docker。

# 删除现有包
sudo apt remove docker docker-engine docker.io containerd runc

# 安装必要的包
sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release

# 添加Docker GPG密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 添加Docker仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.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 docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 启动服务并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker

2.2 将当前用户添加到docker组

如果不想每次都输入sudo,可以将当前用户添加到docker组。

sudo usermod -aG docker $USER
# 注销后重新登录即可生效

2.3 验证安装

# 检查Docker版本
docker --version

# 检查Docker Compose版本
docker compose version

# 运行测试容器
docker run hello-world

3. Docker基本命令

3.1 镜像相关命令

# 下载镜像
docker pull nginx

# 查看本地镜像列表
docker images

# 删除镜像
docker rmi nginx

# 清理未使用的镜像
docker image prune

3.2 运行容器 (docker run)

docker run是最常用的命令。让我们了解一下主要选项。

# 基本运行
docker run nginx

# 后台运行 (-d)
docker run -d nginx

# 指定容器名称 (--name)
docker run -d --name my-nginx nginx

# 端口映射 (-p 主机端口:容器端口)
docker run -d -p 8080:80 nginx

# 卷挂载 (-v 主机路径:容器路径)
docker run -d -v /my/content:/usr/share/nginx/html nginx

# 设置环境变量 (-e)
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql

# 设置重启策略 (--restart)
docker run -d --restart unless-stopped nginx

# 组合多个选项
docker run -d \
  --name webserver \
  -p 80:80 \
  -v /var/www:/usr/share/nginx/html:ro \
  --restart unless-stopped \
  nginx

3.3 容器管理 (docker ps)

# 查看运行中的容器列表
docker ps

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

# 停止容器
docker stop my-nginx

# 启动容器
docker start my-nginx

# 重启容器
docker restart my-nginx

# 删除容器
docker rm my-nginx

# 强制删除运行中的容器
docker rm -f my-nginx

# 删除所有已停止的容器
docker container prune

3.4 查看日志 (docker logs)

# 查看日志
docker logs my-nginx

# 实时查看日志 (-f: follow)
docker logs -f my-nginx

# 只查看最后100行
docker logs --tail 100 my-nginx

# 包含时间戳
docker logs -t my-nginx

3.5 访问容器内部 (docker exec)

# 在容器内部执行命令
docker exec my-nginx ls /etc/nginx

# 连接容器shell (-it: 交互式终端)
docker exec -it my-nginx /bin/bash

# 如果shell不是bash(如Alpine等)
docker exec -it my-nginx /bin/sh

4. Docker Compose应用

4.1 什么是Docker Compose?

Docker Compose是用于定义和管理多个容器的工具。在YAML文件中定义服务配置后,只需一个命令就可以启动或停止所有服务。

4.2 docker-compose.yml基本结构

version: "3.8"

services:
  web:
    image: nginx:latest
    container_name: my-web
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    restart: unless-stopped

  db:
    image: mariadb:latest
    container_name: my-db
    environment:
      - MYSQL_ROOT_PASSWORD=secretpassword
      - MYSQL_DATABASE=myapp
    volumes:
      - db_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  db_data:

4.3 Docker Compose命令

# 启动服务(后台)
docker compose up -d

# 停止服务并删除容器
docker compose down

# 停止服务(保留容器)
docker compose stop

# 重启服务
docker compose restart

# 查看日志
docker compose logs -f

# 只重启特定服务
docker compose restart web

# 更新镜像后重新部署
docker compose pull
docker compose up -d

4.4 实战示例:WordPress + MariaDB

version: "3.8"

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress
    ports:
      - "8080:80"
    environment:
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=wordpress_password
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: mariadb:latest
    container_name: wordpress-db
    environment:
      - MYSQL_ROOT_PASSWORD=root_password
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=wordpress_password
    volumes:
      - db_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  wordpress_data:
  db_data:

5. 使用Portainer进行Web GUI管理

5.1 Portainer介绍

Portainer是一个可以在Web浏览器中管理Docker的工具。启动/停止容器、查看日志、管理镜像等大部分工作都可以通过GUI完成,对不熟悉终端的用户特别有用。

5.2 安装Portainer

# 创建卷
docker volume create portainer_data

# 运行Portainer
docker run -d \
  -p 9443:9443 \
  --name portainer \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

5.3 Portainer初始设置

  1. 在Web浏览器中访问https://服务器IP:9443
  2. 创建管理员账户(密码至少12个字符)
  3. 选择"Get Started"或"Local"环境
  4. 在仪表板中管理容器、镜像、卷等

5.4 Portainer主要功能

  • 容器管理:启动、停止、重启、删除、查看日志
  • 栈(Stack):在Web上管理docker-compose文件
  • 镜像管理:下载、删除、构建镜像
  • 卷管理:创建、删除、备份卷
  • 网络管理:Docker网络设置
  • 模板:使用预定义的应用模板快速部署

6. 实用Docker应用

6.1 Pi-hole:网络广告拦截

Pi-hole是在DNS级别拦截广告的服务。一次设置后,网络中连接的所有设备都会拦截广告。

version: "3.8"

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    environment:
      TZ: 'Asia/Shanghai'
      WEBPASSWORD: 'your_password_here'
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    restart: unless-stopped

安装后将路由器的DNS服务器更改为Pi-hole服务器IP,即可应用于整个网络。

6.2 Nginx Proxy Manager:反向代理

Nginx Proxy Manager是一个将域名连接到多个服务并自动管理SSL证书的工具。

version: "3.8"

services:
  npm:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    restart: unless-stopped

初始登录信息:Email admin@example.com,Password changeme

6.3 Homepage:家庭服务器仪表板

Homepage是一个可以一目了然地查看家庭服务器所有服务的仪表板。提供简洁的设计和各种服务小部件。

version: "3.8"

services:
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    ports:
      - 3000:3000
    volumes:
      - ./config:/app/config
      - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: unless-stopped

6.4 Uptime Kuma:服务监控

Uptime Kuma是一个监控网站、服务、端口等运行状态并发送通知的工具。

version: "3.8"

services:
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    container_name: uptime-kuma
    ports:
      - "3001:3001"
    volumes:
      - ./data:/app/data
    restart: unless-stopped

发生停机时可以通过Telegram、Discord、邮件等接收通知。

6.5 Vaultwarden:密码管理器

Vaultwarden是兼容Bitwarden的密码管理器。比官方Bitwarden服务器轻量得多,专为自托管优化。

version: "3.8"

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    ports:
      - "8000:80"
    environment:
      - SIGNUPS_ALLOWED=true
      - ADMIN_TOKEN=your_random_admin_token
    volumes:
      - ./data:/data
    restart: unless-stopped

没有HTTPS在安全上会有风险,所以请务必通过反向代理应用SSL。

7. 数据备份和卷管理

7.1 卷的类型

  • 命名卷(Named Volume):由Docker管理的卷。使用docker volume create创建
  • 绑定挂载(Bind Mount):将主机的特定路径挂载到容器

通常,需要备份的配置文件或数据使用绑定挂载会更容易管理。

7.2 卷管理命令

# 查看卷列表
docker volume ls

# 卷详细信息
docker volume inspect volume_name

# 删除卷
docker volume rm volume_name

# 清理未使用的卷
docker volume prune

7.3 数据备份策略

方法1:直接备份绑定挂载目录

# 停止服务后备份
docker compose stop
tar -czvf backup_$(date +%Y%m%d).tar.gz ./data
docker compose start

方法2:从运行中的容器备份

# MySQL/MariaDB备份
docker exec my-db mysqldump -u root -p'password' --all-databases > backup.sql

# PostgreSQL备份
docker exec my-postgres pg_dumpall -U postgres > backup.sql

方法3:命名卷备份

# 使用临时容器备份卷内容
docker run --rm \
  -v volume_name:/source:ro \
  -v $(pwd):/backup \
  alpine tar -czvf /backup/volume_backup.tar.gz -C /source .

7.4 自动备份脚本

#!/bin/bash
# backup.sh

BACKUP_DIR="/backup/docker"
DATE=$(date +%Y%m%d_%H%M%S)

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份各服务数据
for dir in /opt/docker/*/; do
    service=$(basename $dir)
    tar -czvf "$BACKUP_DIR/${service}_${DATE}.tar.gz" -C $dir .
done

# 删除30天以上的备份
find $BACKUP_DIR -type f -mtime +30 -delete

echo "Backup completed: $DATE"

可以注册到crontab中自动执行。

# 每天凌晨3点备份
0 3 * * * /opt/scripts/backup.sh >> /var/log/docker-backup.log 2>&1

8. Docker故障排除

8.1 常见问题

端口已被使用时

# 检查使用端口的进程
sudo lsof -i :80
# 或者在docker-compose.yml中更改为其他端口

因权限问题无法访问卷时

# 检查主机目录权限
ls -la ./data
# 更改权限
sudo chown -R 1000:1000 ./data

容器一直重启时

# 查看日志
docker logs container_name
# 更改重启策略
docker update --restart no container_name

8.2 磁盘空间清理

# 查看Docker使用的磁盘容量
docker system df

# 清理所有未使用的(注意!)
docker system prune -a

# 不包括卷清理
docker system prune

结语

本篇从Docker的基本概念到实际应用进行了广泛的介绍。学会Docker后,家庭服务器运营会变得非常方便。安装新服务时不用担心依赖问题,只需一个docker-compose文件就搞定了,出现问题时只需删除容器重新启动即可。

一开始命令可能会感觉陌生,但配合使用Portainer这样的GUI工具会更容易上手。建议从本文介绍的服务开始,一个个安装,逐渐熟悉Docker。

下一篇我们将学习如何加强家庭服务器的安全。将涵盖防火墙设置、VPN搭建、入侵检测等安全运营家庭服务器所必需的知识。