
最近折腾了一下 Metabase,用它来搭建内部的数据看板,顺便踩了几个坑。这篇把部署流程梳理清楚,用 Docker Compose + PostgreSQL + Traefik 在阿里云 ECS 上跑起来,全套自动 HTTPS 配置,开箱即用。
Metabase 会把用户、看板、保存的问题等应用数据存在 PostgreSQL 里。先把项目目录和环境文件准备好。
1. 创建项目目录并进入:
mkdir ~/metabase
cd ~/metabase
2. 生成一个随机密钥,Metabase 用它来加密存储的数据源凭证:
openssl rand -base64 32
把输出结果保存下来,后面要填到环境文件里。
3. 创建环境文件:
nano .env
填入以下配置。把 YOUR_DB_PASSWORD 换成强密码,YOUR_ENCRYPTION_KEY 填上一步 openssl 命令的输出,metabase.example.com 换成你的域名,ADMIN_EMAIL 填一个能收到 Let's Encrypt 续期通知的邮箱。
POSTGRES_DB=metabaseappdb
POSTGRES_USER=metabase
POSTGRES_PASSWORD=YOUR_DB_PASSWORD
MB_ENCRYPTION_SECRET_KEY=YOUR_ENCRYPTION_KEY
MB_SITE_URL=https://metabase.example.com
DOMAIN=metabase.example.com
ACME_EMAIL=ADMIN_EMAIL
保存并退出。
整个架构是 Traefik 做反向代理和证书管理,Metabase 和 PostgreSQL 在一个 bridge 网络里通信。配置里用的是官方镜像 v0.50.21。
1. 创建 Docker Compose 配置文件:
nano docker-compose.yml
services: postgres: image: postgres:16 container_name: metabase-postgres restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 5 mem_limit: 1g logging: driver: "json-file" options: max-size: "10m" max-file: "3" networks: - metabase-network metabase: image: metabase/metabase:v0.50.21 container_name: metabase restart: unless-stopped depends_on: postgres: condition: service_healthy environment: MB_DB_TYPE: postgres MB_DB_DBNAME: ${POSTGRES_DB} MB_DB_PORT: 5432 MB_DB_USER: ${POSTGRES_USER} MB_DB_PASS: ${POSTGRES_PASSWORD} MB_DB_HOST: postgres MB_ENCRYPTION_SECRET_KEY: ${MB_ENCRYPTION_SECRET_KEY} MB_SITE_URL: ${MB_SITE_URL} healthcheck: test: ["CMD", "curl", "--fail", "http://localhost:3000/api/health"] interval: 30s timeout: 10s retries: 5 start_period: 120s mem_limit: 2g logging: driver: "json-file" options: max-size: "10m" max-file: "3" networks: - metabase-network labels: - "traefik.enable=true" - "traefik.http.routers.metabase.rule=Host(`${DOMAIN}`)" - "traefik.http.routers.metabase.entrypoints=websecure" - "traefik.http.routers.metabase.tls.certresolver=letsencrypt" - "traefik.http.services.metabase.loadbalancer.server.port=3000" traefik: image: traefik:v3.7.10 container_name: traefik restart: unless-stopped command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./letsencrypt:/letsencrypt networks: - metabase-network volumes: postgres-data: networks: metabase-network: driver: bridge
保存退出。简单说一下三个服务:postgres 跑 PostgreSQL 16,存 Metabase 的用户、看板、问题等元数据;metabase 是应用服务,等 PostgreSQL 健康检查通过后才启动,Traefik 通过 labels 自动注册并开启 HTTPS;traefik 负责反向代理和 TLS(传输层安全协议)终止,监听 80 和 443 端口。mem_limit 和 logging 分别限制内存占用和日志轮转,防止容器把服务器资源吃光。
2. 启动容器:
docker compose up -d
3. 检查服务状态:
docker compose ps -a
输出应该显示三个容器都是 Up 状态,等健康检查通过后 metabase-postgres 和 metabase 会显示 healthy。
4. 通过域名访问 Metabase 健康检查接口:
curl https://metabase.example.com/api/health
正常情况下返回:
{"status":"ok"}
5. 查看日志确认 Metabase 加载配置正常:
docker compose logs -f metabase
日志里会看到 PostgreSQL 接受连接、Metabase 完成启动迁移的信息,首次启动大概需要一到两分钟。等看到服务启动完成的提示后按 Ctrl+C 退出。
用浏览器打开 Metabase,走一遍首次运行的向导。
https://metabase.example.com
配置完成,Metabase 现在可以用了。注意通过界面连接的数据库跟 PostgreSQL 容器是隔离的,那个容器只存 Metabase 自己的元数据。
Metabase 现在已经在跑,Traefik 自动管理 HTTPS,元数据存在 PostgreSQL 里。接下来可以: