强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

AgensGraph 完全指南 / 第 12 章:Docker 与容器化部署

第 12 章:Docker 与容器化部署

12.1 Docker 基础回顾

12.1.1 Docker 核心概念

概念说明AgensGraph 场景
Image只读模板bitnine/agensgraph:v2.13
Container运行实例正在运行的 AgensGraph 实例
Volume持久化存储数据库数据文件
Network容器网络客户端连接
Compose多容器编排完整的图数据库环境

12.1.2 官方镜像使用

# 拉取镜像
docker pull bitnine/agensgraph:v2.13

# 查看镜像信息
docker inspect bitnine/agensgraph:v2.13

# 快速启动
docker run -d --name ag \
  -p 5432:5432 \
  -e AG_PASSWORD=secret123 \
  bitnine/agensgraph:v2.13

# 连接测试
docker exec -it ag agens -U agens

12.2 自定义 Dockerfile

12.2.1 基础 Dockerfile

# Dockerfile - AgensGraph 自定义镜像
FROM bitnine/agensgraph:v2.13

# 维护者信息
LABEL maintainer="admin@example.com"

# 设置环境变量
ENV AG_HOME=/home/agens/AgensGraph
ENV PGDATA=${AG_HOME}/data
ENV PATH=${AG_HOME}/bin:${PATH}

# 创建自定义配置目录
RUN mkdir -p /docker-entrypoint-initdb.d && \
    mkdir -p /etc/agens

# 复制自定义配置
COPY config/agens.conf /etc/agens/agens.conf
COPY config/pg_hba.conf /etc/agens/pg_hba.conf

# 复制初始化脚本
COPY init/ /docker-entrypoint-initdb.d/

# 设置脚本权限
RUN chmod +x /docker-entrypoint-initdb.d/*.sh 2>/dev/null || true

# 数据持久化目录
VOLUME ${PGDATA}

# 暴露端口
EXPOSE 5432

# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD pg_isready -U agens || exit 1

# 启动命令
CMD ["postgres", "-D", "/home/agens/AgensGraph/data"]

12.2.2 生产级 Dockerfile

# Dockerfile.production
FROM bitnine/agensgraph:v2.13 AS base

LABEL maintainer="admin@example.com"
LABEL version="1.0"
LABEL description="AgensGraph Production Image"

# 安装额外工具
USER root
RUN apt-get update && apt-get install -y \
    curl \
    wget \
    jq \
    && rm -rf /var/lib/apt/lists/*

# 复制配置文件
COPY config/postgresql.conf /etc/agens/postgresql.conf
COPY config/pg_hba.conf /etc/agens/pg_hba.conf
COPY config/setup.sh /docker-entrypoint-initdb.d/01-setup.sh

# 性能优化配置
RUN echo "kernel.shmmax = 17179869184" >> /etc/sysctl.conf

USER agens
WORKDIR /home/agens

EXPOSE 5432

VOLUME ["/home/agens/AgensGraph/data", "/var/log/agens"]

HEALTHCHECK --interval=10s --timeout=5s --start-period=30s --retries=5 \
  CMD pg_isready -U agens -d agens || exit 1

CMD ["postgres", "-D", "/home/agens/AgensGraph/data", "-c", "config_file=/etc/agens/postgresql.conf"]

12.2.3 初始化脚本

#!/bin/bash
# init/setup.sh
set -e

echo "=== AgensGraph Initialization ==="

# 创建图数据库
agens -U agens <<-EOSQL
    CREATE GRAPH IF NOT EXISTS mygraph;
    CREATE GRAPH IF NOT EXISTS social_network;
EOSQL

# 创建用户
agens -U agens <<-EOSQL
    CREATE USER app_user WITH PASSWORD 'app_pass123';
    GRANT ALL PRIVILEGES ON DATABASE agens TO app_user;
EOSQL

# 设置默认图路径
agens -U agens -d agens <<-EOSQL
    ALTER DATABASE agens SET graph_path = 'mygraph';
EOSQL

echo "=== Initialization Complete ==="
-- init/02-schema.sql
-- 设置图路径
SET graph_path = mygraph;

-- 创建约束
CREATE CONSTRAINT person_name_unique
  ON (p:Person)
  ASSERT p.name IS UNIQUE;

-- 创建索引
CREATE INDEX ON :Person(name);
CREATE INDEX ON :Person(email);
CREATE INDEX ON :KNOWS(since);

12.3 Docker Compose 编排

12.3.1 开发环境

# docker-compose.dev.yml
version: '3.8'

services:
  agensgraph:
    image: bitnine/agensgraph:v2.13
    container_name: agensgraph-dev
    ports:
      - "5432:5432"
    environment:
      AG_PASSWORD: dev123
      AG_GRAPH_PATH: mygraph
    volumes:
      - ag_dev_data:/home/agens/AgensGraph/data
      - ./init:/docker-entrypoint-initdb.d
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U agens"]
      interval: 10s
      timeout: 5s
      retries: 5

  # 管理界面(可选)
  adminer:
    image: adminer:latest
    ports:
      - "8080:8080"
    depends_on:
      agensgraph:
        condition: service_healthy

volumes:
  ag_dev_data:

12.3.2 生产环境

# docker-compose.prod.yml
version: '3.8'

services:
  agensgraph:
    build:
      context: .
      dockerfile: Dockerfile.production
    container_name: agensgraph-prod
    ports:
      - "5432:5432"
    environment:
      AG_PASSWORD_FILE: /run/secrets/ag_password
    volumes:
      - ag_prod_data:/home/agens/AgensGraph/data
      - ag_prod_log:/var/log/agens
      - ./config/postgresql.conf:/etc/agens/postgresql.conf
      - ./config/pg_hba.conf:/etc/agens/pg_hba.conf
    secrets:
      - ag_password
    deploy:
      resources:
        limits:
          cpus: '4.0'
          memory: 8G
        reservations:
          cpus: '2.0'
          memory: 4G
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U agens"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "5"

  # 连接池
  pgbouncer:
    image: edoburu/pgbouncer:latest
    container_name: agens-pgbouncer
    ports:
      - "6432:5432"
    environment:
      DB_HOST: agensgraph
      DB_PORT: 5432
      DB_USER: agens
      DB_PASSWORD: ${AG_PASSWORD}
      POOL_MODE: transaction
      MAX_CLIENT_CONN: 1000
      DEFAULT_POOL_SIZE: 50
    depends_on:
      agensgraph:
        condition: service_healthy
    restart: always

  # 监控(可选)
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    restart: always

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin123
    volumes:
      - grafana_data:/var/lib/grafana
    restart: always

volumes:
  ag_prod_data:
    driver: local
  ag_prod_log:
    driver: local
  grafana_data:
    driver: local

secrets:
  ag_password:
    file: ./secrets/ag_password.txt

12.3.3 主从复制架构

# docker-compose.repl.yml
version: '3.8'

services:
  agensgraph-primary:
    image: bitnine/agensgraph:v2.13
    container_name: ag-primary
    ports:
      - "5432:5432"
    environment:
      AG_PASSWORD: primary_pass
    volumes:
      - ag_primary_data:/home/agens/AgensGraph/data
      - ./config/primary.conf:/home/agens/AgensGraph/data/postgresql.conf
      - ./config/pg_hba_repl.conf:/home/agens/AgensGraph/data/pg_hba.conf
    command: >
      postgres
        -D /home/agens/AgensGraph/data
        -c wal_level=replica
        -c max_wal_senders=3
        -c hot_standby=on
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U agens"]
      interval: 10s
      timeout: 5s
      retries: 5

  agensgraph-replica:
    image: bitnine/agensgraph:v2.13
    container_name: ag-replica
    ports:
      - "5433:5432"
    environment:
      AG_PASSWORD: replica_pass
    volumes:
      - ag_replica_data:/home/agens/AgensGraph/data
    depends_on:
      agensgraph-primary:
        condition: service_healthy
    command: >
      bash -c "
        until pg_basebackup -h agensgraph-primary -U replicator -D /tmp/base -Fp -Xs -P; do
          echo 'Waiting for primary...';
          sleep 5;
        done;
        cp -r /tmp/base/* /home/agens/AgensGraph/data/;
        touch /home/agens/AgensGraph/data/standby.signal;
        echo 'primary_conninfo = ''host=agensgraph-primary port=5432 user=replicator password=repl_pass''' >> /home/agens/AgensGraph/data/postgresql.conf;
        postgres -D /home/agens/AgensGraph/data
      "

volumes:
  ag_primary_data:
  ag_replica_data:

12.4 环境变量与密钥管理

12.4.1 环境变量

变量说明默认值
AG_PASSWORD超级用户密码(必须设置)
AG_GRAPH_PATH默认图路径(空)
AG_EXTRA_ARGS额外启动参数(空)

12.4.2 Docker Secrets

# 使用 Docker Swarm Secrets
version: '3.8'

services:
  agensgraph:
    image: bitnine/agensgraph:v2.13
    secrets:
      - ag_password
    environment:
      AG_PASSWORD_FILE: /run/secrets/ag_password

secrets:
  ag_password:
    external: true

12.4.3 环境变量文件

# .env
AG_PASSWORD=secure_password_here
AG_GRAPH_PATH=mygraph
POSTGRES_MAX_CONNECTIONS=200
POSTGRES_SHARED_BUFFERS=2GB
# docker-compose.yml 使用 .env
services:
  agensgraph:
    env_file:
      - .env

12.5 数据备份与恢复

12.5.1 备份策略

#!/bin/bash
# backup.sh - 自动备份脚本

BACKUP_DIR="/backup/agensgraph"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CONTAINER="agensgraph-prod"
BACKUP_FILE="${BACKUP_DIR}/agens_backup_${TIMESTAMP}"

mkdir -p ${BACKUP_DIR}

# 逻辑备份(pg_dump)
docker exec ${CONTAINER} pg_dump -U agens -Fc -f /tmp/backup.dump
docker cp ${CONTAINER}:/tmp/backup.dump ${BACKUP_FILE}.dump

# 图数据备份(Cypher 导出)
docker exec ${CONTAINER} agens -U agens -c "
  SET graph_path = mygraph;
  MATCH (n) RETURN n;
" > ${BACKUP_FILE}_graph.json

# 压缩
gzip ${BACKUP_FILE}.dump

# 清理 7 天前的备份
find ${BACKUP_DIR} -name "*.gz" -mtime +7 -delete

echo "Backup completed: ${BACKUP_FILE}.dump.gz"

12.5.2 恢复操作

# 逻辑恢复
docker exec -i ${CONTAINER} pg_restore -U agens -d agens < backup.dump

# 物理恢复(从基础备份)
docker stop ${CONTAINER}
docker run --rm \
  -v ag_prod_data:/data \
  -v /backup/base:/backup \
  bitnine/agensgraph:v2.13 \
  bash -c "rm -rf /data/* && cp -r /backup/base/* /data/"
docker start ${CONTAINER}

12.5.3 定时备份(Cron)

# docker-compose.yml 中添加备份服务
services:
  backup:
    image: bitnine/agensgraph:v2.13
    volumes:
      - ./scripts/backup.sh:/backup.sh
      - /backup:/backup
    environment:
      AG_HOST: agensgraph
      AG_PASSWORD: ${AG_PASSWORD}
    entrypoint: /bin/bash
    command: >
      -c "
      echo '0 2 * * * /backup.sh' > /etc/cron.d/backup &&
      cron -f
      "
    depends_on:
      - agensgraph

12.6 容器监控

12.6.1 Prometheus 指标采集

# monitoring/prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'postgres'
    static_configs:
      - targets: ['postgres-exporter:9187']

  - job_name: 'pgbouncer'
    static_configs:
      - targets: ['pgbouncer-exporter:9127']
# docker-compose.yml 中添加监控服务
services:
  postgres-exporter:
    image: prometheuscommunity/postgres-exporter:latest
    environment:
      DATA_SOURCE_NAME: "postgresql://agens:password@agensgraph:5432/agens?sslmode=disable"
    ports:
      - "9187:9187"

12.6.2 关键监控指标

指标来源告警阈值
连接数pg_stat_activity> max_connections × 80%
缓冲区命中率pg_stat_database< 99%
事务等待锁pg_locks> 10
复制延迟pg_stat_replication> 10s
死锁数pg_stat_database> 0
磁盘使用率系统指标> 85%

12.7 Kubernetes 部署

12.7.1 基本 Deployment

# k8s/agensgraph-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: agensgraph
  namespace: database
spec:
  replicas: 1
  selector:
    matchLabels:
      app: agensgraph
  template:
    metadata:
      labels:
        app: agensgraph
    spec:
      containers:
      - name: agensgraph
        image: bitnine/agensgraph:v2.13
        ports:
        - containerPort: 5432
        env:
        - name: AG_PASSWORD
          valueFrom:
            secretKeyRef:
              name: agensgraph-secret
              key: password
        volumeMounts:
        - name: data
          mountPath: /home/agens/AgensGraph/data
        resources:
          requests:
            memory: "2Gi"
            cpu: "1000m"
          limits:
            memory: "8Gi"
            cpu: "4000m"
        readinessProbe:
          exec:
            command:
            - pg_isready
            - -U
            - agens
          initialDelaySeconds: 10
          periodSeconds: 5
        livenessProbe:
          exec:
            command:
            - pg_isready
            - -U
            - agens
          initialDelaySeconds: 30
          periodSeconds: 10
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: agensgraph-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: agensgraph
  namespace: database
spec:
  selector:
    app: agensgraph
  ports:
  - port: 5432
    targetPort: 5432
  type: ClusterIP
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: agensgraph-pvc
  namespace: database
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 100Gi

12.8 本章小结

要点说明
官方镜像bitnine/agensgraph:v2.13
自定义镜像基于官方镜像添加配置和初始化脚本
Compose开发/生产环境一键部署
备份pg_dump + 定时任务
监控Prometheus + Grafana + postgres_exporter
K8sStatefulSet 更适合有状态服务

12.9 练习

  1. 编写一个包含 AgensGraph + PgBouncer + 监控的 Docker Compose 文件。
  2. 编写自动备份脚本并配置定时任务。
  3. 使用 Docker 构建一个包含测试数据的 AgensGraph 镜像。
  4. 编写 Kubernetes 的 StatefulSet 部署文件。

12.10 扩展阅读