第一关:优化配置,打好基础

我们从一份基础的 docker-compose.yml 文件开始。它能用,但不够健壮和安全。

原始配置存在的问题:

  1. 密码硬编码:将数据库密码、管理员密码直接写在文件里,有安全风险。
  2. 启动顺序不可靠links 是一个过时的功能,它不能保证在应用启动时,数据库已经完全准备就绪。
  3. 数据管理不便:使用绑定挂载 (./data) 会将数据直接与宿主机目录绑定,不利于迁移和管理。

优化后的配置: 我们引入了 Docker Compose 的几项最佳实践,对配置进行了“现代化改造”,使用 .env 文件来管理敏感信息,通过 healthcheck 确保服务启动顺序,并采用命名卷来管理数据。

优化的 docker-compose.yml

version: '3.8'
services:
  picsur:
    image: ghcr.io/caramelfur/picsur:latest
    container_name: picsur
    restart: always
    ports:
      - "${PICSUR_HOST_PORT:-8383}:8080"
    environment:
      PICSUR_DB_HOST: picsur_postgres
      PICSUR_DB_USERNAME: ${POSTGRES_USER}
      PICSUR_DB_PASSWORD: ${POSTGRES_PASSWORD}
      PICSUR_DB_DATABASE: ${POSTGRES_DB}
      PICSUR_ADMIN_PASSWORD: ${PICSUR_ADMIN_PASSWORD}
    networks:
      - picsur_net
    depends_on:
      picsur_postgres:
        condition: service_healthy
  picsur_postgres:
    image: postgres:17-alpine
    container_name: picsur_postgres
    restart: always
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - picsur_net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  postgres_data:
networks:
  picsur_net:

配套的 .env 文件

# .env 文件
POSTGRES_USER=picsur
POSTGRES_PASSWORD=your_strong_password
PICSUR_ADMIN_PASSWORD=your_admin_password

学习点:通过使用 .env 文件、depends_onhealthcheck 和命名卷,我们的配置变得更安全、更健壮、更专业。这是所有生产环境部署的推荐做法。

第二关:命令不存在?新旧版本的交替

配置完成后,我们信心满满地运行 docker-compose up -d,结果…… Command 'docker-compose' not found

这是一个经典的“环境问题”。它揭示了 Docker Compose 的一个版本变迁:

  • V1 版本:命令是 docker-compose (带连字符)。
  • V2 版本:命令是 docker compose (带空格),作为 Docker 的一个插件存在。

由于服务器上已经有正在运行的 Docker 容器,我们不能粗暴地卸载重装。

解决方案:单独安装 V2 版本的 Compose 插件。

# 只安装缺失的插件不影响现有 Docker 环境
sudo apt-get install docker-compose-plugin

学习点:技术在不断迭代。当遇到“命令不存在”时,除了检查是否安装,还要考虑是否是版本或命令格式发生了变化。使用 docker compose 是目前推荐的方式。

第三关:环境变量去哪了?

解决了命令问题后,我们再次尝试,又遇到了一堆黄色警告和红色错误。

WARN[0000] The "POSTGRES_USER" variable is not set... Error: container picsur_postgres is unhealthy

日志清晰地告诉我们:所有在 .env 文件里设置的变量都没有被加载,导致数据库无法用正确的用户名和密码初始化,最终启动失败。

问题根源:Docker Compose 默认只会在当前目录下寻找名为 .env 的文件。这个问题 99% 的可能性是 .env 文件不存在、放错了位置,或者文件名不对(比如写成了 env.env.txt)。

解决方案

  1. 清理失败的尝试:docker compose down
  2. 检查文件:ls -la,确保能看到一个不多不少,正好名为 .env 的文件。
  3. 确认无误后,重新启动:docker compose up -d

学习点:魔鬼在细节中。一个标点符号、一个文件名的错误都可能导致整个应用启动失败。仔细阅读日志是排错的最快途径。

第四关:终极对决,为何登录不进去?

终于,所有容器都正常运行了!我们激动地打开浏览器,输入在 .env 文件里设置好的管理员账号 admin 和密码,却收到了无情的“Wrong username or password”提示。

这是最迷惑的一个问题,因为从表面看,一切都正常。

问题根源:这与应用的初始化逻辑和 Docker 数据卷的持久化特性有关。

  1. PICSUR_ADMIN_PASSWORD 这个环境变量,只在数据库第一次为空时,用于创建初始管理员。
  2. 在我们解决第三关问题之前,数据库容器可能已经启动过一次。那时由于 .env 文件没加载,应用可能用一个空的密码创建了 admin 用户,并将这个用户数据保存在了 postgres_data 这个数据卷里。
  3. 之后我们虽然修正了 .env 并重启,但应用检测到数据库里已经有 admin 用户了,所以它不会去更新密码。而数据卷是持久的,它会一直保存着那份错误的数据。

解决方案:彻底重置,破釜沉舟!

  1. 停止并移除所有相关容器:docker compose down
  2. 删除被污染的数据库数据卷(这是最关键的一步!):docker volume rm picsur_postgres_data
  3. 从一个完全干净的状态重新启动:docker compose up -d

这一次,应用面对的是一个全新的、空的数据库,它会忠实地使用我们 .env 文件里的正确密码来创建管理员。再次登录,成功!

学习点:理解 Docker 数据卷的持久化生命周期至关重要。当遇到与数据状态相关的奇怪问题时,要想到可能是旧的、错误的数据被持久化了。彻底清除数据卷是解决这类初始化问题的“大招”。

总结

这次部署 Picsur 的经历,完美地串联起了 Docker Compose 的几大核心知识点:配置管理、服务依赖、网络、数据持久化,以及最重要的——排错思路。每一次报错都是一次学习的机会。希望这篇记录能帮助你在 Docker 的世界里走得更远、更稳!