利用Github Action备份Docker容器中的数据库

news2025/1/22 12:21:38

Image

利用Github Action备份Docker容器中的数据库

本文方案仅供技术参考与娱乐!

前言

数据很重要,所以我们要经常备份。

那么怎么备份呢?假如我们使用云厂商的数据库,里面已经自带了快照和备份功能了,只要你愿意花钱,就能帮你解决大部分技术问题。它们这些数据库往往是部署在单独一/多台主机实例上,不会放在容器里去跑。为什么?俺也不是专业的运维,俺也不知道。这里给个知乎链接作为参考

对于我们个人项目而言,一般不会去购买昂贵的数据库实例,往往 云主机容器部署 + serverless + oss/cdn 就能满足绝大部分开发的需求了。很多时候简单的 docker compose up -d 就够用了,然后再加个开源的BAAS平台:supabase 一起组网,开发爽的不要不要的。

说远了,接下来进入本篇的正题:如何设计一个方案,把 Github Repo 转化为我们数据库备份的对象存储,并利用CI持续化集成呢?

方案设计与拆解

显然,思考如何把大象装进冰箱,我们要把整个过程拆解成以下几个步骤:

  • 链接远程机器
  • 导出数据库文件
  • 下载与上传数据库备份文件
  • 数据库备份的增删管理

这样我们只需要依次实现对应的功能,再把功能串联起来就达到我们的目标了。

本文运行环境:云主机为 华为云,数据库为 postgres

数据库备份方案

备份数据库通常非常简单,主要分为 2 步:

  1. db dump
  2. upload to Amazon S3/Aliyun OSS/Tencent Cloud COS /…

这个很容易理解,写个 shell 脚本,导出数据库,上传到 OSS。然后把它设置成定时任务就行。

然而本文的邪道方案中,我们需要使用 github action 来远程连上云主机,然后执行脚本获取数据库备份,再同步到 git 仓库。

这显然要复杂许多,于是我就学习了一会shell编程,写了一段脚本,具体思考调试过程可以见注释:

#!/bin/sh
FILENAME=$(date +"%Y%m%d-%H%M%S") # 时间戳文件名
BASENAME="${FILENAME}.dump" # +后缀
KEY_PATH=./xxx.pem # ssh私钥路径
DESTINATION=root@xxx.xxx.xxx.xxx # 云主机登录用户以及ip地址
DUMP_FILE_PATH=/path/to/${BASENAME} # 云主机 dump 文件路径
CONTAINER_NAME=container-name # 云主机数据库容器名称
PG_USER=postgres # 云主机数据库容器登录用户

# Permissions 0400 for './*.pem' are too open
# 修改私钥权限,避免 Permissions too open 问题
chmod 400 $KEY_PATH

echo "   -> Connecting $DESTINATION and Dumping"
# dump datebase from docker container
# option StrictHostKeyChecking=accept-new for ssh key prompt
# 这里设置 StrictHostKeyChecking=accept-new 来避免初次由于 .ssh/known_hosts 不存在,导致的 prompt 问题
# 相当于执行了3个命令,ssh <command> / docker exec <command> / sh -c "db_dump"
# 把 dump 出来的数据文件,放到docker的挂载卷中
ssh -o StrictHostKeyChecking=accept-new -i $KEY_PATH $DESTINATION "docker exec -u $PG_USER $CONTAINER_NAME sh -c \"pg_dump -Fc postgres > /var/lib/postgresql/data/${BASENAME}\""

echo "   -> Downloading $DUMP_FILE_PATH"
# download dump file to git repo
# 把dump文件下载到本地
scp -i $KEY_PATH $DESTINATION:$DUMP_FILE_PATH ./${BASENAME}

echo "   -> Deleting $DUMP_FILE_PATH"
# delete dump file
# 下载完成后,删除服务器上的 dump 文件
ssh -i $KEY_PATH $DESTINATION rm $DUMP_FILE_PATH

echo ""
echo "...done!"
echo ""

其中,使用秘钥和 StrictHostKeyChecking=accept-new 都是为了免 prompt 登录。在执行备份数据库命令时要注意字符串的转义。

另外在调试时,还遇到了一个问题,我们 docker exec -it <c_name>,进入容器中执行 su <user> 是可行的,但是直接 docker exec <c_name> <command> 里面 su,生成出来的 dump 文件所属却是 root! 必须要使用 -u 参数,指定 <user> 才行。这里我并不理解,希望懂的人可以告诉我这个问题的原因。

通过这些步骤,就顺利的把数据库备份文件,给下载到了 git 仓库里了。

删除数据库Blob文件方案

既然我们已经下载到了数据库文件了,我们就要对这些文件进行管理。

比如我们目标是,保存最近 7 次备份的文件,那么显然我们要把比较旧的数据库文件给删除掉,那么怎么做呢?

这里我也做了一个简单设计:

DUMPS=$(ls | grep ".dump$") # 获取当前目录所有的 .dump
COUNT=$(echo "$DUMPS" | wc -l) # .dump文件个数
SORTED_LIST=$(echo "$DUMPS" | sort -k1.1n) # 按照时间排个序

KEEP_BLOB_COUNT=7 # 保留数据文件的个数

if [ "$COUNT" -gt "${KEEP_BLOB_COUNT}" ]; then
    DEL_COUNT=$(expr $COUNT - ${KEEP_BLOB_COUNT}) # 删除个数
    echo "DELETE COUNT:${DEL_COUNT}"
    DEL_LIST=$(echo "$SORTED_LIST" | head -n $DEL_COUNT) # 删除文件名列表

    for i in $DEL_LIST; do
        echo "DELETEING ${i}..."
        rm $i # 删除过时的数据
        echo "DELETE ${i} SUCCESSFUL!"
    done
fi

避免Git仓库过大方案

我们知道 git 仓库一直是在增大的,当我们删除一个文件的时候,看似这个文件从我们的工作目录中消失了,实际上这个文件并没有被删除,而是跑到了 git history 里面去,久而久之这个项目就越来越大了,因为之前所以被删除的文件,还是被保存在 .git 文件夹里。

那么怎么避免这个问题呢?

Github给了一个解决方案见 removing-sensitive-data-from-a-repository。文章里,给我们介绍了 2 种工具,分别是 java 写的 BFG Repo-Cleanerpython 写的 git-filter-repo

然而我都不想用…

我回想起了很多年前,看到的一则谣言:程序员枪杀四名同事的新闻。

霎时,想到了一个天怒人怨的命令:git push -f !

我们可以使用这个方式,强制更新我们的 git 仓库,把它当成一个 OSS 来用啊!

那么脚本就很容易设计出来了:

git config --global user.email "your_name@gmail.com"
git config --global user.name "icebreaker-bot"
git checkout --orphan latest_branch # 创建个纯洁的孤儿分支
git add -A
git commit -am "project recreate"
git branch -D main
git branch -m main
git push -fu origin main # 嘿嘿

当然,这段脚本只适合在自己把控范围内去使用。切勿在工作中使用,不然就会出现几把机械键盘直接砸到脸上的暴力场景。

Github Action CI

最后,我们接下来把上述这三段脚本,串联起来。然后写一个 yml 文件交给 action 定时执行就大功告成啦!

name: Sync_Datebase

on:
  schedule:
    # UTC时间触发
    - cron: "0 0 * * *"
  workflow_dispatch:

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run sync script
        run: |
          chmod 755 ./bak.sh
          chmod 755 ./del.sh
          chmod 755 ./git-clear.sh
          ./bak.sh

这样每次执行完这个脚本,整个仓库焕然一新,历史永远就只有一条了。(笑~)

尾言

这种方式去备份数据库,显然是一种邪魔歪道,有点钻牛角尖,不过思考实现的过程却比较有趣,有兴趣的同学可以参照本文实现一下。

还有 Github ssh 下载实际上速度是很快的,但是由于某些zg特色因素,大概率网速会变成小水管。这种情况可以转而使用某些国内代码托管商,来尝试这个方案。

最后方案并不完美,欢迎建议和意见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/527191.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

golang 使用 OpenTelemetry 实现跨服务 全链路追踪

使用 OpenTelemetry 链路追踪说明 工作中常常会遇到需要查看服务调用关系,比如用户请求了一个接口接口会调用其他grpc,http接口,或者内部的方法这样的调用链路,如果出现了问题,我们需要快速的定位问题,这时候就需要一个工具来帮助我们查看调用链路OpenTelemetry就是这样一个工…

力扣总结,深度优先题

LCP 67. 装饰树 –链接– 中等 10 相关企业 力扣嘉年华上的 DIY 手工展位准备了一棵缩小版的 二叉 装饰树 root 和灯饰&#xff0c;你需要将灯饰逐一插入装饰树中&#xff0c;要求如下&#xff1a; 完成装饰的二叉树根结点与 root 的根结点值相同 若一个节点拥有父节点&#x…

用Java开发的建站神器JPress

什么是 JPress &#xff1f; JPress 是一个使用 Java 开发的、类似 WordPress 的产品&#xff0c;支持多站点、多语种自动切换等。&#xff08;JPress 始于2015 年&#xff09; 目前已经有 10w 网站使用 JPress 进行驱动&#xff0c;其中包括多个政府机构&#xff0c;200 上市公…

HashMap 扰动函数、负载因子、扩容链表拆分

文章目录 1.扰动函数2.初始容量3.负载因子4.扩容链表拆分 1.扰动函数 在jdk8中&#xff0c;hashmap有这样一段代码&#xff0c;他叫扰动函数&#xff0c;目的是优化散列效果 static final int hash(Object key) {int h;return (key null) ? 0 : (h key.hashCode()) ^ (h &…

初识Java多线程编程

文章目录 一、线程的状态二、线程的常见属性三、多线程编程Thread类常用构造方法1.继承Thread类2.实现Runnable接口3.匿名内部类实现4.lambda 表达式创建 Runnable 子类对象 四、线程的常见方法 一、线程的状态 //线程的状态是一个枚举类型 Thread.State public class ThreadS…

【C语言】结构体——基础篇

结构体 为什么需要结构体&#xff1f;结构体类型的定义结构体变量结构体变量的定义结构体变量的引用结构体变量的初始化 结构体嵌套 为什么需要结构体&#xff1f; &#x1f4ab;首先&#xff0c;来举一个例子看一下为什么需要结构体。   在学籍管理系统中&#xff0c;要存储…

驱动开发:内核远程堆分配与销毁

在开始学习内核内存读写篇之前&#xff0c;我们先来实现一个简单的内存分配销毁堆的功能&#xff0c;在内核空间内用户依然可以动态的申请与销毁一段可控的堆空间&#xff0c;一般而言内核中提供了ZwAllocateVirtualMemory这个函数用于专门分配虚拟空间&#xff0c;而与之相对应…

MATLAB绘制动画(二)擦除动画

如果我们在绘制图形之后将原有的图形擦除&#xff0c;并重新绘制&#xff0c;看上去就像动画了 示例: t 0; m [sin(t);cos(t)]; p plot(t,m,EraseMode,background,MarkerSize,5); x -1.5*pi; axis([x x2*pi -1.5 1.5]); grid onfor i 1:100t [t 0.1*i];m [m [sin(0.1*i…

【LeetCode: 97. 交错字符串 | 暴力递归=>记忆化搜索=>动态规划 | 位置对应】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

校园安全,一键报警主机助力保障

校园安全&#xff0c;一键报警主机助力保障 随着社会发展和科技进步&#xff0c;校园安全问题日益受到重视。如何保障师生们的安全成为了学校一项重要任务。而校园可视一键报警主机就是一种非常有效的安保设备。 这种报警主机集合了视频监控、安全防范、数据处理等多个功能&a…

asm 加盘 udev 重启 导致网络异常

Network interface going down when dynamically adding disks to storage using udev in RHEL 6 (Doc ID 1569028.1)正在上传…重新上传取消To Bottom In this Document APPLIES TO: Oracle Database - Enterprise Edition - Version 11.2.0.3 and later Oracle Net Servi…

阿里国际、Lazada、eBay如何提高转化率?测评养号优化方式是什么

转化率是卖家在分析复盘时非常关键的因素&#xff0c;转化率的高低直接影响着卖家目前的关键词listing或者商品描述是否符合&#xff0c;消费者的满意度。 1.调查获客&#xff0c;明确分析市场需求 这是在产品上架之前必须明确的重要环节。如果市场上对于一个产品接受率低&am…

ChatGPT有中文版吗?

2023年最热的技术话题是什么&#xff1f;毫无疑问是人工智能&#xff0c;特别是AIGC领域。其中又以ChatGPT为最热门产品。ChatGPT是一个革命性的人工智能产品&#xff0c;能对我们的生产生活产生巨大的影响。然而&#xff0c;有网友担心ChatGPT是西方开发的AI工具&#xff0c;能…

若依管理系统RuoYi-Vue:登录和鉴权的实现

文章目录 摘要spring-boot-starter-security验证码生成是否开启验证码配置验证码类型CaptchaController的getCode来生成验证码 用户登录SysLoginController的login验证登录是否正确用户名密码是否正确Spring Security 的用户名密码验证机制在SecurityConfig中配置PasswordEncod…

聚观早报|恒大公告许家印成被执行人;特斯拉回应召回超百万辆车

今日要闻&#xff1a;恒大公告&#xff1a;许家印成被执行人&#xff1b;特斯拉回应召回超百万辆车&#xff1b;ChatGPT联网插件下周开放票&#xff1b;天翼物联发布首个3AZ亿级物联网平台&#xff1b;苹果MR头显功能预计远超竞争对手 恒大公告&#xff1a;许家印成被执行人 12…

【沐风老师】3DMAX一键种草插件GrassScatter使用方法详解

GrassScatter for 3dMax一键种草插件使用教程 3DMAX一键种草插件GrassScatter&#xff0c;用于控制草的创建和散布&#xff0c;快速生成草坪&#xff01; 【版本要求】 3dMax2012及更高版本 【安装方法】 方法一&#xff1a;本插件无需安装&#xff0c;使用时直接拖动插件脚…

什么是独享数据库(Database per Microservice)?解决了什么问题?

独享数据库&#xff08;Database per Microservice&#xff09;是一种微服务架构模式&#xff0c;涉及为每个微服务创建单独的数据库。在这种模式下&#xff0c;每个微服务都有自己的数据库&#xff0c;这允许更大的可扩展性、灵活性和自治性。 使用这种模式&#xff0c;每个微…

考考驾照(安卓)

软件安装好后&#xff0c;不用注册登录直接就可以用&#xff0c;软件里主要包含有科目一&#xff0c;科目二&#xff0c;科目三&#xff0c;科目四等等学习的知识内容和一些技巧。 像科目一和科目四有考前须知&#xff0c;考试技巧&#xff0c;和学车流程&#xff0c;还有考试一…

JavaScript学习-DOM事件基础

DOM事件基础 事件监听(绑定)事件监听案例&#xff1a;关闭广告随机点名案例事件监听版本 事件类型类型鼠标经过与鼠标离开轮播图完整版焦点事件键盘事件与文本事件评论字数统计 事件对象获取事件对象事件对象常用属性案例&#xff1a;评论回车发布 环境对象回调函数综合案例&am…

MPLS格式和802.1q帧格式,ISL格式

一.MPLS IETF开发的多协议标记交换&#xff08;MPLS)把第2层的链路状态信息&#xff08;带宽、延迟、利用率等&#xff09;集成到第3层的协议数据单元中&#xff0c;从而简化和改进了第3层分组的交换过程 。理论上&#xff0c;MPLS支持任何第2层和第3层协议。MPLS包头的位置界…