PostgreSQL数据库容器恢复与简易备份实现

1,730 阅读2分钟

2021.03.10 原发布地址:数据库容器恢复与简易备份实现

前情

同事想给小组内部自用的 outline 文档服务添加mathjax功能,由于不熟悉docker的使用,直接在生产环境大胆执行了docker-compose down,导致postgres和redis容器被直接删除。

数据恢复

调查之后了解到 docker-compose down 没有特别加上 -v option时,是不会删除数据所在的volume的,所以新建postgres容器时 mount 上对应的的volumn就可以了。

# 查看对应volume
ls /var/lib/docker/volumes

# 新建postgres容器
docker run -d --name <Container Name> -e POSTGRES_PASSWORD=<Your Password> -p 5432:5432 --mount source=<Volume Name>,target=/var/lib/postgresql/data postgres

※docker容器创建时,除了容器本身外还有volume,network一并创建。利用docker inspect <container_id> 可以查看具体信息。

反思

同事在不了解部署环境与技术的情况下直接操作是一个问题。

自己也因为是内部搭的自用服务而疏忽了数据备份,平时过多依赖AWS RDS自带的备份服务也没有养成很好的意识。

生产环境中一份保底的备份策略是必须的,不然等问题真正发生就无法挽回了。

以后利用人数增加的话,实现一个primary+standby+pgBackRest架构应该是最优解吧。

简易备份实现

花了20分钟写了一个备份脚本,因为公司是全套AWS云,所以选择了AWS S3作为备份仓库。

直接用了AWS CLI因为熟悉流程实现起来快一点,考虑到云储存服务适配性应该也能用rclone来实现。

需求

  • 每晚进行数据库备份,文件名格式:outline.YYYYMMDD
  • 留下简单的脚本执行日志:/var/log/backup/outline.log
  • 设计简单的恢复策略(恢复时限:4h以内)
  • 备份失败时进行邮件通知

实现

  • 环境:AWS EC2 + postgres in Docker
  • 备份脚本
    • 备份生成:利用docker的容器交互命令直接进行postgres备份
    • 备份上传:AWS S3 (事先准备IAM用户并配置好AWS CLI)
    • 定时执行:crontab
    • 失败通知:利用 crontabMAILTO=,设置mutt邮件客户端。
  • 恢复策略
    • aws cli 拉取S3最新备份
    • drop db,create db, 导入。(基本都是markdown文本数据所以数据量较小)

备份脚本

#!/usr/bin/env bash
#####################################
# Author: xxxx
# Version: v1.0.0
# Date: 2021-03-10
# Description: Backup Database
# Usage: sh <file_name>
#####################################

set -Eeuo pipefail

cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1

trap cleanup SIGINT SIGTERM ERR EXIT

DB_NAME=your_database_name
DB_USER=your_database_user
DB_CONTAINER=your_docker_container_name
S3_BACKUP_PATH=s3://

DT=$(date +'%Y%m%d')

cleanup(){
    rm -f "${DB_NAME}.${DT}"
}

main(){
    # dump
    docker exec -it ${DB_CONTAINER} pg_dump -U ${DB_USER} ${DB_NAME} > ${DB_NAME}.${DT}
    aws s3 cp ${DB_NAME}.${DT} ${S3_BACKUP_PATH}

    # log
    echo "[${DT}] ${DB_NAME}.${DT} uploaded to ${S3_BACKUP_PATH}" >> /var/log/backup/${DB_NAME}.log

    cleanup
}

main "$@"
  • Snippets: pg_dump, pg_restore
# dump to single SQL file
$ pg_dump -d mydb -n public -f mydb.sql
# dump to a custom format file
$ pg_dump -d mydb -n public --format=custom -f mydb.pgdmp

# restoring from a SQL dump file, the simple version
$ psql -d mydb_new < mydb.sql
# restoring from a SQL dump file, the recommended version
$ PGOPTIONS='--client-min-messages=warning' psql -X -q -1 -v ON_ERROR_STOP=1 --pset pager=off -d mydb_new -f mydb.sql -L restore.log

# restoring from a dump written to a custom format file
$ pg_restore -d mydb_new -v -1 mydb.pgdmp
# restore a single table from the dump
$ pg_restore -d mydb_new --table=mytable -v -1 mydb.pgdmp
# restore a single function from the dump
$ pg_restore -d mydb_new --function=myfunc -v -1 mydb.pgdmp