1. 项目概述:从“大机架”到个人数字基础设施的构建

最近在GitHub上看到一个挺有意思的项目,叫 bigrack.dev ,作者是 baptiste-mnh 。光看这个名字,你可能会有点摸不着头脑——“大机架”?这到底是做什么的?点进去一看,发现它其实是一个个人化的、基于容器和自动化工具链的“数字基础设施”项目。简单来说,就是作者把自己日常开发、学习、甚至娱乐所用到的各种服务,比如代码仓库、文档Wiki、自动化构建、监控面板等等,全部打包、容器化,然后通过一套统一的编排和管理工具,部署在自己的服务器(或家庭服务器)上,形成一个完全由自己掌控的、私有的“开发与运维平台”。

这听起来是不是有点像自建一个小型的、功能齐全的“私有云”或“家庭实验室”?没错,其核心精神正是如此。在公有云服务无处不在的今天,为什么还要费劲自己搭建呢? bigrack.dev 项目给出了几个很实在的理由: 完全的数据主权 (你的数据只在你自己的硬件上)、 极致的可定制性 (服务选型、配置、集成方式你说了算)、 深入的学习与实践 (从底层网络、存储到上层应用部署,全流程亲手操作),以及 长期的成本可控 (一次硬件投入,长期免服务费使用,尤其适合需要长期运行的服务)。这个项目非常适合那些对DevOps、SRE(站点可靠性工程)、家庭实验室(Homelab)感兴趣,或者单纯想拥有一个不受第三方约束的、高度集成的个人工作环境的开发者和技术爱好者。

2. 核心架构与设计哲学拆解

2.1 技术栈选型:为什么是它们?

bigrack.dev 的技术选型非常典型,代表了当前自托管领域的主流和最佳实践。理解这些选择背后的逻辑,比单纯记住工具名字更重要。

2.1.1 编排与部署层:Docker & Docker Compose 这是整个项目的基石。Docker提供了轻量级的容器化隔离,确保每个服务(如Gitea、Nextcloud、Prometheus)都运行在独立、可复现的环境中,避免了“在我的机器上能运行”的经典问题。Docker Compose则用于定义和运行多容器的应用。对于个人或小规模部署,Kubernetes(K8s)显得过于重型,而Docker Compose的YAML文件清晰定义了服务、网络、卷之间的关系,一键 docker-compose up -d 就能拉起整个栈,管理和维护的复杂度直线下降。这是平衡功能与复杂性的明智之选。

2.1.2 代码与协作核心:Gitea 为什么是Gitea而不是GitLab或自建Git?GitLab功能强大但资源消耗也大,对于个人服务器可能负担较重。Gitea是一个用Go编写的轻量级、开源Git服务,其设计目标就是快速、低消耗且易于安装。它完美覆盖了个人或小团队的代码托管、Pull Request、Issue跟踪等核心需求。在 bigrack.dev 的语境下,Gitea不仅是代码仓库,更是整个基础设施的“配置即代码”的存储中心,所有服务的Docker Compose文件、部署脚本、甚至这篇文档本身,都应该用Git管理起来。

2.1.3 自动化与CI/CD:Drone CI 有了代码仓库,自动化构建和部署(CI/CD)就是自然延伸。Drone CI是一个基于容器、声明式配置的轻量级CI/CD工具。它与Gitea(或GitHub、GitLab等)深度集成,通过项目根目录下的 .drone.yml 文件来定义流水线。当代码推送到Gitea的特定分支时,Drone会自动触发构建、测试、甚至自动部署到服务器。对于个人项目,这意味着你提交代码后,博客可以自动更新、Docker镜像可以自动构建并推送到私有仓库、服务可以自动滚动更新,极大地提升了效率。

2.1.4 监控与可观测性:Prometheus + Grafana “可观测性”是现代运维的基石。Prometheus负责抓取和存储时间序列数据(如CPU使用率、内存占用、HTTP请求次数、服务健康状态)。Grafana则是一个强大的数据可视化平台,它从Prometheus读取数据,生成直观的仪表盘。在 bigrack.dev 中,你需要监控服务器的硬件资源、各个容器的运行状态、网络服务的可用性等。这套组合让你能一眼看清整个系统的健康状况,在问题影响用户体验前就发现端倪。

2.1.5 反向代理与入口管理:Traefik 或 Caddy 当你有多个Web服务(Gitea的Web界面、Grafana仪表盘、Nextcloud网盘等)运行在同一台服务器的不同端口时,你需要一个“总机接线员”——反向代理。它监听80和443端口,然后根据访问的域名(如 git.yourdomain.com , grafana.yourdomain.com )将请求转发到对应的后端服务容器。Traefik和Caddy都是优秀的现代反向代理,它们最大的特点是能 自动发现容器 并配置路由,并与Let‘s Encrypt集成实现自动化的HTTPS证书申请和续签。这意味着你每新增一个带Web界面的服务,几乎不用手动修改代理配置,服务上线即带HTTPS。

2.2 设计模式:一切皆代码与不可变基础设施

bigrack.dev 项目隐含了两个重要的现代运维理念:

  1. 一切皆代码(Infrastructure as Code, IaC) :服务器配置、服务部署、网络设置都不再是手动在服务器上敲命令,而是通过Docker Compose文件、Drone流水线脚本等代码文件来定义。这些文件被保存在Git仓库中,可以进行版本控制、代码审查和回滚。要重建整个环境?只需一条命令。
  2. 不可变基础设施(Immutable Infrastructure) :一旦服务被部署,就不再直接登录容器去修改配置或更新应用。任何变更都通过更新代码(如Dockerfile或Compose文件中的镜像版本),然后触发CI/CD流程,构建新的镜像并替换旧容器来实现。这保证了环境的一致性和部署的可重复性。

3. 核心服务部署与配置实战

假设我们有一台安装了Ubuntu Server 22.04 LTS的物理机或虚拟机(至少4核CPU,8GB内存,100GB SSD存储),公网IP已配置,域名 yourdomain.com 已指向该IP。下面我们一步步搭建 bigrack.dev 的核心组件。

3.1 基础环境准备与Docker安装

首先,我们需要一个干净、安全的基础操作系统环境。

# 1. 更新系统并安装必要工具
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git vim htop net-tools

# 2. 安装Docker Engine(使用官方脚本)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# 3. 安装Docker Compose Plugin (Docker Compose V2)
sudo apt install -y docker-compose-plugin

# 4. 将当前用户加入docker组,避免每次使用sudo
sudo usermod -aG docker $USER
# 注意:需要退出当前终端重新登录,或执行 `newgrp docker` 使组权限生效

# 5. 验证安装
docker --version
docker compose version

注意 :生产环境务必遵循最小权限原则。如果服务器暴露在公网,需要配置防火墙(如 ufw ),仅开放必要的端口(80, 443, 22),并考虑使用非root用户运行Docker守护进程,或使用 sudo 执行Docker命令。

3.2 编排核心:创建Docker Compose项目结构

我们将在 /opt/bigrack 目录下组织所有内容。清晰的目录结构是管理复杂Compose项目的关键。

sudo mkdir -p /opt/bigrack
sudo chown -R $USER:$USER /opt/bigrack
cd /opt/bigrack

# 创建核心目录结构
mkdir -p {data,configs,logs,scripts,backup}
mkdir -p data/{gitea,postgres,drone,nextcloud,prometheus,grafana}
mkdir -p configs/{traefik,caddy}
mkdir -p logs/{traefik,gitea}

现在,创建主 docker-compose.yml 文件。这里我们以 Traefik 作为反向代理为例。

# /opt/bigrack/docker-compose.yml
version: '3.8'

networks:
  web:
    external: true # 我们将手动创建这个网络,便于Traefik和其他服务通信
  internal:
    driver: bridge # 内部服务间通信网络

volumes:
  gitea_data:
  postgres_data:
  drone_data:
  nextcloud_data:
  prometheus_data:
  grafana_data:
  traefik_certs:

services:
  # 反向代理 - Traefik
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - web
      - internal
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./configs/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./configs/traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
      - traefik_certs:/etc/traefik/certs
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`traefik.yourdomain.com`)"
      - "traefik.http.routers.api.service=api@internal"
      - "traefik.http.routers.api.entrypoints=websecure"
      - "traefik.http.routers.api.tls=true"
      - "traefik.http.routers.api.middlewares=auth"
      # 为Traefik Dashboard添加基础认证(强烈建议!)
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$verylonghashedpassword"

  # 数据库 - PostgreSQL (为Gitea, Drone等服务提供数据库)
  postgres:
    image: postgres:15-alpine
    container_name: postgres
    restart: unless-stopped
    networks:
      - internal
    environment:
      POSTGRES_USER: bigrack_admin
      POSTGRES_PASSWORD: your_strong_postgres_password_here
      POSTGRES_DB: bigrack
      POSTGRES_INITDB_ARGS: "--encoding=UTF8 --lc-collate=C --lc-ctype=C"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U bigrack_admin"]
      interval: 10s
      timeout: 5s
      retries: 5

  # 代码托管 - Gitea
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - internal
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - DB_TYPE=postgres
      - DB_HOST=postgres:5432
      - DB_NAME=gitea
      - DB_USER=bigrack_admin
      - DB_PASSWD=your_strong_postgres_password_here
    volumes:
      - gitea_data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.gitea.rule=Host(`git.yourdomain.com`)"
      - "traefik.http.routers.gitea.entrypoints=websecure"
      - "traefik.http.routers.gitea.tls=true"
      - "traefik.http.services.gitea.loadbalancer.server.port=3000"

  # CI/CD - Drone Server
  drone-server:
    image: drone/drone:latest
    container_name: drone-server
    restart: unless-stopped
    depends_on:
      - gitea
    networks:
      - internal
    environment:
      - DRONE_GITEA_SERVER=https://git.yourdomain.com
      - DRONE_GITEA_CLIENT_ID=your_gitea_oauth_client_id
      - DRONE_GITEA_CLIENT_SECRET=your_gitea_oauth_client_secret
      - DRONE_RPC_SECRET=your_strong_drone_rpc_secret_here
      - DRONE_SERVER_HOST=drone.yourdomain.com
      - DRONE_SERVER_PROTO=https
      - DRONE_USER_CREATE=username:your_username,admin:true
    volumes:
      - drone_data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.drone.rule=Host(`drone.yourdomain.com`)"
      - "traefik.http.routers.drone.entrypoints=websecure"
      - "traefik.http.routers.drone.tls=true"
      - "traefik.http.services.drone-server.loadbalancer.server.port=80"

  # Drone Runner (Docker Runner)
  drone-runner:
    image: drone/drone-runner-docker:latest
    container_name: drone-runner
    restart: unless-stopped
    depends_on:
      - drone-server
    networks:
      - internal
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DRONE_RPC_PROTO=https
      - DRONE_RPC_HOST=drone-server
      - DRONE_RPC_SECRET=your_strong_drone_rpc_secret_here
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_RUNNER_NAME=bigrack-runner

  # 监控 - Prometheus
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    networks:
      - internal
    volumes:
      - prometheus_data:/prometheus
      - ./configs/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.retention.time=30d'
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.prometheus.rule=Host(`prom.yourdomain.com`)"
      - "traefik.http.routers.prometheus.entrypoints=websecure"
      - "traefik.http.routers.prometheus.tls=true"
      - "traefik.http.services.prometheus.loadbalancer.server.port=9090"

  # 可视化 - Grafana
  grafana:
    image: grafana/grafana-oss:latest
    container_name: grafana
    restart: unless-stopped
    depends_on:
      - prometheus
    networks:
      - internal
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=your_strong_grafana_admin_password
      - GF_INSTALL_PLUGINS=grafana-piechart-panel
    volumes:
      - grafana_data:/var/lib/grafana
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.grafana.rule=Host(`grafana.yourdomain.com`)"
      - "traefik.http.routers.grafana.entrypoints=websecure"
      - "traefik.http.routers.grafana.tls=true"
      - "traefik.http.services.grafana.loadbalancer.server.port=3000"

实操心得 :在编写Compose文件时,有几点至关重要:

  1. 密码管理 :永远不要将明文密码硬编码在Compose文件或代码中。上述示例仅为演示。在生产环境中,应使用Docker Secrets(在Swarm模式下)或通过环境变量文件( .env )传入,并将 .env 文件加入 .gitignore 。更好的做法是使用如HashiCorp Vault等密钥管理工具。
  2. 健康检查 :为数据库等关键服务配置 healthcheck ,这样 depends_on condition: service_healthy 才能生效,确保依赖服务真正就绪后再启动应用。
  3. 标签(Labels) :Traefik通过Docker容器的Labels来动态配置路由。确保格式正确,特别是Host规则里的域名要和你实际拥有的域名一致。
  4. 网络隔离 :创建独立的 internal 网络,让后端服务(如Gitea、PostgreSQL)不直接暴露在外部网络,只有Traefik能访问它们,提升安全性。

3.3 关键配置文件详解

光有Compose文件还不够,我们需要为Traefik、Prometheus等服务提供具体的配置。

3.3.1 Traefik 静态配置 ( traefik.yml )

# /opt/bigrack/configs/traefik/traefik.yml
api:
  dashboard: true
  debug: false

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true
  websecure:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false # 非常重要!只有显式设置`traefik.enable=true`的容器才会被暴露
    network: web
  file:
    filename: /etc/traefik/dynamic.yml

certificatesResolvers:
  letsencrypt:
    acme:
      email: your-email@example.com # 替换为你的邮箱
      storage: /etc/traefik/certs/acme.json
      httpChallenge:
        entryPoint: web

这个配置做了几件事:定义HTTP(80)和HTTPS(443)入口点;设置HTTP到HTTPS的自动重定向;配置Docker和文件作为配置提供者;设置Let‘s Encrypt作为证书解析器。

3.3.2 Traefik 动态配置 ( dynamic.yml )

# /opt/bigrack/configs/traefik/dynamic.yml
http:
  middlewares:
    secHeaders:
      headers:
        browserXssFilter: true
        contentTypeNosniff: true
        frameDeny: true
        sslRedirect: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 31536000
        customFrameOptionsValue: "SAMEORIGIN"

  routers:
    # 可以为所有路由默认应用安全头中间件
    # 在Compose文件的labels里引用:`traefik.http.routers.xxx.middlewares=secHeaders`

tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

动态配置通常用于定义公共的中间件(如安全头)和TLS选项,这些配置可以被多个路由复用。

3.3.3 Prometheus 配置 ( prometheus.yml )

# /opt/bigrack/configs/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'docker'
    static_configs:
      - targets: ['host.docker.internal:9323'] # 需要启用Docker引擎的metrics接口
    # 或者使用cAdvisor容器来收集容器指标
    # - targets: ['cadvisor:8080']

  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100'] # 需要部署node-exporter容器来收集主机指标

这个基础配置监控Prometheus自身。要监控Docker容器和主机节点,你需要额外部署 cAdvisor node-exporter 容器,并将它们添加到targets中。

3.4 初始化与启动

在启动一切之前,我们需要创建外部网络并设置一些基础数据。

# 创建Traefik使用的共享网络
docker network create web

# 生成用于Traefik Dashboard的htpasswd密码
echo $(htpasswd -nb admin your_password) | sed -e s/\\$/\\$\\$/g
# 将输出(如 admin:$$apr1$$...)填入Compose文件中traefik的labels里。

# 进入项目目录
cd /opt/bigrack

# 启动所有服务(在后台运行)
docker compose up -d

# 查看所有容器状态
docker compose ps

# 跟踪日志(Ctrl+C退出)
docker compose logs -f

启动后,访问以下地址(将 yourdomain.com 替换为你的域名):

  • https://git.yourdomain.com :首次访问会进入Gitea安装页面。数据库主机填 postgres:5432 ,其他信息根据Compose文件中的环境变量填写。
  • https://drone.yourdomain.com :用Gitea账号登录,完成Drone的OAuth配置。
  • https://grafana.yourdomain.com :默认账号 admin ,密码是你设置的 GF_SECURITY_ADMIN_PASSWORD 。首次登录后添加Prometheus(地址为 http://prometheus:9090 )作为数据源。
  • https://traefik.yourdomain.com :输入之前设置的基础认证账号密码,进入Traefik Dashboard,查看所有路由和服务状态。

4. 进阶集成与自动化工作流

基础服务跑起来只是开始, bigrack.dev 的真正威力在于将这些服务串联成一个自动化的工作流。

4.1 配置Gitea与Drone的OAuth集成

这是打通代码托管和自动化的关键一步。

  1. 登录Gitea,点击右上角头像 -> 设置 -> 应用
  2. 点击 管理OAuth2应用程序 -> 创建新的OAuth2应用程序
  3. 应用名称填 Drone CI ,重定向URI填 https://drone.yourdomain.com/login (务必准确)。
  4. 点击创建,你会得到 客户端ID 客户端密钥
  5. 将这两个值分别填入 docker-compose.yml drone-server 服务的 DRONE_GITEA_CLIENT_ID DRONE_GITEA_CLIENT_SECRET 环境变量。
  6. 重启Drone Server容器: docker compose restart drone-server
  7. 现在访问Drone,应该可以用Gitea账号登录并授权了。

4.2 创建你的第一个自动化流水线

假设你在Gitea上创建了一个名为 my-blog 的仓库,里面是一个静态博客(比如Hugo生成)。你可以通过Drone实现“提交代码 -> 自动构建 -> 自动部署”。

在博客项目根目录创建 .drone.yml 文件:

kind: pipeline
type: docker
name: build-and-deploy

steps:
  - name: build-hugo
    image: alpine:latest
    commands:
      - apk add hugo
      - hugo --minify

  - name: deploy-to-server
    image: alpine:latest
    environment:
      SSH_KEY:
        from_secret: ssh_private_key
    commands:
      - apk add openssh-client rsync
      - mkdir -p ~/.ssh
      - echo "$SSH_KEY" > ~/.ssh/id_rsa
      - chmod 600 ~/.ssh/id_rsa
      - ssh-keyscan -H your-server-ip >> ~/.ssh/known_hosts
      - rsync -avz --delete public/ user@your-server-ip:/var/www/myblog/
    when:
      branch:
        - main

这个流水线做了两件事:

  1. 使用Hugo镜像构建静态网站。
  2. 通过SSH将生成的 public 目录同步到服务器的Web目录。

关键点

  • from_secret: ssh_private_key :这里引用了Drone的一个密钥。你需要在Drone的Web界面中,进入 my-blog 仓库的设置(Settings -> Secrets),添加一个名为 ssh_private_key 的Secret,值是你的服务器SSH私钥。 切勿将私钥直接写在代码里!
  • when : 指定了只有推送到 main 分支时才执行部署步骤。

在Gitea中提交并推送这个 .drone.yml 文件后,Drone会自动检测到并开始执行第一次构建。你可以在Drone的Web界面实时查看构建日志。

4.3 扩展服务:添加Nextcloud(私有云盘)

个人基础设施怎么能少了云盘?在 docker-compose.yml services: 部分添加:

nextcloud:
  image: nextcloud:latest
  container_name: nextcloud
  restart: unless-stopped
  networks:
    - internal
  depends_on:
    postgres:
      condition: service_healthy
  environment:
    - POSTGRES_HOST=postgres
    - POSTGRES_DB=nextcloud
    - POSTGRES_USER=bigrack_admin
    - POSTGRES_PASSWORD=your_strong_postgres_password_here
    - NEXTCLOUD_ADMIN_USER=admin
    - NEXTCLOUD_ADMIN_PASSWORD=your_strong_nextcloud_admin_password
  volumes:
    - nextcloud_data:/var/www/html
    - ./data/nextcloud/apps:/var/www/html/custom_apps
    - ./data/nextcloud/config:/var/www/html/config
    - ./data/nextcloud/data:/var/www/html/data
  labels:
    - "traefik.enable=true"
    - "traefik.http.routers.nextcloud.rule=Host(`cloud.yourdomain.com`)"
    - "traefik.http.routers.nextcloud.entrypoints=websecure"
    - "traefik.http.routers.nextcloud.tls=true"
    - "traefik.http.services.nextcloud.loadbalancer.server.port=80"

然后运行 docker compose up -d nextcloud 即可启动。Traefik会自动为 cloud.yourdomain.com 配置HTTPS并路由到Nextcloud容器。

5. 运维、监控与故障排查实录

5.1 日常运维命令合集

掌握这些命令,管理你的 bigrack 会得心应手。

# 进入项目目录
cd /opt/bigrack

# 查看所有服务状态
docker compose ps

# 查看特定服务日志(如gitea)
docker compose logs gitea
# 实时跟踪日志
docker compose logs -f gitea

# 重启单个服务
docker compose restart gitea

# 更新所有服务到最新镜像(谨慎操作,最好先备份)
docker compose pull
docker compose up -d

# 进入容器内部执行命令(调试用)
docker compose exec gitea sh

# 备份所有数据卷(假设备份到/backup目录)
tar -czf /backup/bigrack-data-$(date +%Y%m%d).tar.gz ./data

# 查看资源使用情况
docker stats

# 清理未使用的镜像、容器、网络、卷(谨慎!)
docker system prune -a

5.2 监控告警配置

光有仪表盘不够,我们需要在出问题时收到通知。这里以Grafana Alerting配合邮件通知为例。

  1. 在Grafana中配置SMTP : 登录Grafana -> Administration -> Settings -> SMTP 。 填写你的邮件服务器信息(如Gmail SMTP,注意可能需要应用专用密码)。

    Host: smtp.gmail.com:587
    User: your-email@gmail.com
    Password: your-app-specific-password
    From Address: your-email@gmail.com
    

    点击 Send Test Email 验证。

  2. 创建告警规则 : 进入Prometheus数据源的一个图表,比如“节点内存使用率”。点击图表标题 -> Edit -> Alert

    • Rule name : High Memory Usage
    • Evaluate every : 1m
    • For : 2m (持续2分钟触发才告警,避免抖动)
    • Condition : WHEN max() OF query(A, 1m, now) IS ABOVE 0.85 (内存使用率超过85%)
    • Notifications : 添加一个通知策略,关联你的邮箱。
  3. 配置通知策略 : Grafana -> Alerting -> Notification policies 。 创建一个策略,匹配所有标签,设置默认联系点为你的邮箱。

现在,当服务器内存持续超过85%时,你就会收到告警邮件。

5.3 常见问题与排查技巧

问题1:Traefik Dashboard无法访问,或服务返回“404”或“Bad Gateway”。

  • 检查点1:网络 。确保 traefik 服务连接到了 web internal 两个网络。 docker network inspect web docker network inspect internal 查看容器是否在其中。
  • 检查点2:标签 。确认服务的labels拼写正确,特别是 traefik.http.routers.xxx.rule=Host() 中的域名。
  • 检查点3:端口 。确认服务容器内部监听的端口(如Gitea是3000)与 traefik.http.services.xxx.loadbalancer.server.port 一致。
  • 检查点4:证书 。检查Traefik日志 docker compose logs traefik ,看Let‘s Encrypt证书申请是否成功。首次访问可能需要几分钟申请证书。
  • 排查命令 docker compose logs traefik 查看路由发现和错误信息。

问题2:Drone无法触发构建。

  • 检查点1:仓库激活 。登录Drone,确保目标仓库是“激活”状态(不是灰色)。
  • 检查点2:Webhook 。在Gitea仓库设置里查看Webhook,Drone应该自动创建了一个。尝试手动推送(Redeliver),看Drone是否有日志。
  • 检查点3:Runner状态 docker compose logs drone-runner 查看Runner是否成功连接到Server。
  • 检查点4: .drone.yml 语法 。使用在线YAML校验器检查语法,确保缩进正确。

问题3:Prometheus无法抓取指标或Grafana无法连接数据源。

  • 检查点1:网络 。确保Prometheus、Grafana以及被监控目标(如node-exporter)在同一个Docker网络(通常是 internal )中。
  • 检查点2:目标状态 。访问Prometheus的Targets页面 ( http://your-server-ip:9090/targets ),查看抓取目标是否为 UP
  • 检查点3:Grafana数据源配置 。在Grafana中检查Prometheus数据源的URL,在容器内应使用服务名 http://prometheus:9090 ,而不是 localhost

问题4:磁盘空间不足。 容器、镜像、日志和卷数据会占用大量空间。

  • 查看占用 docker system df 查看Docker资源使用情况。
  • 清理无用镜像 docker image prune -a 删除所有未被容器使用的镜像。
  • 清理容器日志 :Docker的日志驱动默认是 json-file ,日志会存储在 /var/lib/docker/containers/ 。可以配置日志轮转,或在Compose文件中为服务添加日志限制:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    
  • 备份并清理数据卷 :定期备份重要数据卷(如 gitea_data , postgres_data )到其他存储介质,然后可以清理旧的、不必要的备份。

问题5:服务启动顺序导致依赖问题。 尽管Compose有 depends_on ,但它只控制容器启动顺序,不保证服务(如数据库)在应用启动前就“准备就绪”。

  • 解决方案 :使用 condition: service_healthy (如示例中对PostgreSQL的依赖),并在依赖服务中配置有效的 healthcheck
  • 备选方案 :在应用启动命令中加入等待脚本,例如在应用启动前执行一个循环,检查数据库端口是否可连接。

搭建和维护这样一个 bigrack.dev 式的个人基础设施,是一个持续迭代和学习的旅程。它不仅仅是一堆服务的集合,更是一个理解现代应用部署、网络、安全和自动化的绝佳实践场。从最基础的“服务能访问”,到“数据有备份”,再到“故障能自愈”、“变更可追溯”,每一步的深入都会带来新的挑战和收获。最关键的是,你拥有了一个完全受自己控制的数字基地,无论是用于严肃的项目开发,还是作为探索新技术的沙盒,它都提供了无与伦比的自由度和灵活性。

更多推荐