介绍
备份重要数据是管理任何计算机基础架构的重要部分。 尽管在执行备份时每个人的需求都不同,但在非现场维护备份数据是一种好的做法。
将数据副本发送到异地的过程曾经是一个重大的后勤挑战。 但随着Crashplan和Dropbox等基于云存储服务的出现,以及像这样的对象存储解决方案的开发,现在它已经变得非常简单了。 尽管如此,记住备份文件并花时间上传文件仍然是一些障碍。
这就是为什么人们选择使用各种工具来执行重要数据的日常自动备份。 在本教程中,我们将围绕s3cmd
命令行工具构建一个脚本,该脚本可用于将数据快速上传到DigitalOcean空间。 然后,我们将使用crontab
定期调用备份脚本并将文件上传到我们的空间。
先决条件
对于本教程,您将需要:
- 一个Ubuntu 16.04 x64与non-root sudo用户的Droplet。 这可以按照我们最初的Ubuntu 16.04服务器设置指南进行配置。
- DigitalOcean空间和API访问密钥 。
- 。
对shell脚本和cron
作业调度程序有一定的了解也是有帮助的。 有关一些指导和其他上下文,请阅读“ Shell脚本简介 ”和“ 如何在VPS上使用Cron和Anacron安排日常任务 ”。
随着我们的先决条件,我们准备开始我们的备份自动化过程。
建立我们的备份脚本
有许多工具可以用来将备份文件自动并定期上传到对象存储服务。 但是,这些可能难以配置,并且可能不会提供很大的灵活性。 使用一个简单的shell脚本可以是一个更加优雅和直接的方法来自动化对象存储备份。
在本教程中,我们将编写一个基本的bash脚本,它将使用tar
创建一个文件或目录的备份。 然后脚本将使用s3cmd
命令行实用程序将该备份上传到Spaces。
要开始使用,请登录您的Droplet并导航到您的主文件夹:
cd ~
一旦进入home文件夹,我们将使用nano
创建一个空文件,我们可以在脚本中写入:
nano bkupscript.sh
我们现在准备开始在文本编辑器中编写我们的备份脚本。 在我们构建脚本时,我们将按顺序逐一解释它的每个部分。
发起我们的脚本
在这一点上, bkupscript.sh
只是一个空文本文件。 为了让我们的计算机以命令的形式调用我们的可执行文件,我们需要用hashbang来开始我们的脚本。 hashbang是一个解释器指令,允许脚本或数据文件作为命令运行。
在我们的例子中,hashbang将如下所示:
#!/bin/bash
通过将其包含在脚本的顶部,我们告诉shell在bash中运行文件的命令。
声明变量
接下来,我们会告诉我们的脚本需要知道的变量才能正常工作。 我们可以将这些直接添加到文本文件顶部的hashbang下面:
...
DATETIME=`date +%y%m%d-%H_%M_%S`
SRC=$1
DST=$2
GIVENNAME=$3
让我们来看看我们将每个变量分配给:
-
DATETIME
:这个变量包含一个时间戳,用于附加到结果文件名中,这样每个备份到我们空间的文件都有一个唯一的名字。 此时间戳是通过调用date
命令并格式化输出来创建的,以显示年份的最后两位数(%y
),月份的两位数(%m
),日期的两位数(%d
),小时(%H
),分钟(%M
)和秒(%S
)。 -
SRC
:这是我们要备份的文件或文件夹的源路径。$1
表示我们正在从传递给脚本的第一个参数中获取这个值。 -
DST
:这个变量表示文件的目的地 。 在我们的情况下,这是我们上传备份的空间的名称。 该名称将来自传递给脚本的第二个参数,如$2
。 -
GIVENNAME
:这个变量托管目标文件的用户选择的名字。 生成的文件名将以GIVENNAME
开始,GIVENNAME
DATETIME
连接到它。 这个名字来自传递给脚本的第三个参数($3
)。
提供一些帮助
编写脚本时,添加一些提示或一般性建议可帮助用户排除故障,从而帮助用户排除故障。
对于我们的备份脚本,我们将在变量下面添加一个名为showhelp()
的函数。 这将打印一系列消息,以帮助用户在脚本失败的情况下排除故障。 在bash中添加一个函数时,我们的语法如下所示:
...
showhelp(){
}
此功能将通过在屏幕上回显一系列使用说明来提供帮助信息。 每条指令都应该用双引号括起来。 在下面的例子中你会注意到一些字符串在开始或者结束时被写入了\t
或者\n
。 这些是转义字符 ,它们提供了字符串应该如何出现在脚本输出中的具体说明:
-
\t
表示一个标签空间 -
\n
表示换行符
随意在花括号之间添加任何对你有用的使用细节(只要记住在任何带有echo
字符串之前)。 出于演示目的,我们将添加以下内容:
echo "\n\n############################################"
echo "# bkupscript.sh #"
echo "############################################"
echo "\nThis script will backup files/folders into a single compressed file and will store it in the current folder."
echo "In order to work, this script needs the following three parameters in the listed order: "
echo "\t- The full path for the folder or file you want to backup."
echo "\t- The name of the Space where you want to store the backup at."
echo "\t- The name for the backup file (timestamp will be added to the beginning of the filename)\n"
echo "Example: sh bckupscript.sh ./testdir testSpace backupdata\n"<^>
最后的showhelp
函数应该是这样的:
...
showhelp(
echo "\n\n############################################"
echo "# bkupscript.sh #"
echo "############################################"
echo "\nThis script will backup files/folders into a single compressed file and will store it in the current folder."
echo "In order to work, this script needs the following three parameters in the listed order: "
echo "\t- The full path for the folder or file you want to backup."
echo "\t- The name of the Space where you want to store the backup at."
echo "\t- The name for the backup file (timestamp will be added to the beginning of the filename)\n"
echo "Example: sh bckupscript.sh ./testdir testSpace backupdata\n"
}
随着我们的帮助文本,我们可以继续收集我们想要在我们的空间备份的文件。
收集文件
在我们的脚本可以将任何东西传输到我们的空间之前,首先需要收集正确的文件并将它们合并成一个包,供我们上传。 我们可以通过使用tar
实用程序和条件语句来完成此操作。 因为我们使用tar
来创建一个存档文件(有时称为“zip”文件),所以我们将调用这个函数tarandzip()
。
首先声明函数并添加另一个echo
命令,让用户知道脚本已经开始收集文件:
...
tarandzip(){
echo "\n##### Gathering files #####\n"
}
在echo
命令下面,我们可以添加一个tar
命令,它将把文件收集和压缩成单个输出文件。
tarandzip(){
echo "\n##### Gathering files #####\n"
tar -czvf $GIVENNAME-$DATETIME.tar.gz $SRC
}
你会注意到这个tar
命令被调用了几个选项和变量:
-
c
:这个标志告诉tar
压缩输出文件。 -
z
:这指示tar
使用gzip
压缩文件。 -
v
:这表示verbose
选项,它指示tar
在输出中显示更多信息。 -
f
:该标志指示tar
保存下一个指定的文件名。 -
$GIVENNAME-$DATETIME.tar.gz
:脚本调用我们在开头声明的这些变量来创建新的文件名。 它通过组合$GIVENNAME
和$DATETIME
变量并在最后添加.tar.gz
扩展名来形成新的文件名。 -
$SRC
:这个变量表示我们正在指示tar
备份的源文件或文件夹。
这个函数现在应该能够做到我们想要的,但是我们可以添加更多的echo
调用来为用户提供关于脚本如何工作的额外信息。 这可以通过添加一些条件语句来完成,如下所示:
if tar -czvf $GIVENNAME-$DATETIME.tar.gz $SRC; then
echo "\n##### Done gathering files #####\n"
return 0
else
echo "\n##### Failed to gather files #####\n"
return 1
fi
当调用if
子句时,它将执行tar
命令并等待结果。 如果命令的结果是肯定的(意味着它成功运行), then
将执行then
和else
之间的界限。 这些是:
- 回复脚本已成功完成
tar
过程的消息 - 返回一个
0
的错误代码,以便调用这个函数的代码部分知道一切正常。
这个函数的else
部分只有在tar
命令执行时发现错误才会被执行。 在这种情况下,该子句的else
分支将:
- 回显指示
tar
命令失败的消息 - 返回1的错误代码,表示出错了
最后,我们用if/then/else
结束if/then/else
子句,这在bash语言中意味着if
子句已经结束。
完成的tarandzip()
函数如下所示:
tarandzip(){
echo "\n##### Gathering files #####\n"
if tar -czvf $GIVENNAME-$DATETIME.tar.gz $SRC; then
echo "\n##### Done gathering files #####\n"
return 0
else
echo "\n##### Failed to gather files #####\n"
return 1
fi
}
使用我们的tarandzip()
函数,我们准备好设置脚本来移动备份。
将文件传输到对象存储
在这一点上,我们可以通过使用s3cmd
命令来获得我们的备份脚本来传输文件到我们的空间。 和tarandzip
,我们也可以echo
一些字符串,并利用if/then/else
语句让用户了解脚本在运行时的工作方式。
首先我们将宣布我们的功能。 让我们再次保持这个简单,并将其命名为movetoSpace()
:
...
movetoSpace(){
}
现在我们可以使用s3cmd
和我们之前声明的变量来构建将我们的备份文件推送到我们的空间的命令:
movetoSpace(){
~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST
}
以下是这个命令的每个部分的含义:
-
~/s3cmd-2.0.1/s3cmd
:调用s3cmd
,一个的 。 -
put
:这是s3cmd
用于将数据上传到存储桶的命令。 -
$GIVENNAME-$DATETIME.tar.gz
:这是将被上传到我们的空间的备份的名称。 它由我们声明的第四个和第一个变量组成,后面跟着.tar.gz
,由前面的tarandzip()
函数创建。 -
s3://$DST;
:这是我们想要上传文件的位置。s3://
是一个类似于URI的模式,专门用于在线描述对象的存储位置,而$DST;
是我们之前声明的第三个变量。
我们现在有一个功能,可以上传我们的存档文件到我们的空间。 但是,它不会通知用户其状态。 让我们通过在命令前面回显一个字符串来改变它,让用户知道它已经启动,并且在函数完成之后让我们知道它是否成功。
我们首先通知用户该进程已经开始:
movetoSpace(){
echo “\n##### MOVING TO SPACE #####\n”
~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST
}
因为这个命令会成功或者失败(也就是说,它会把文件上传到我们的空间,否则就不会),我们可以让用户知道是否通过回显if/then/else
的两个字符串之一声明,如下所示:
...
if ~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST; then
echo "\n##### Done moving files to s3://"$DST" #####\n"
return 0
else
echo "\n##### Failed to move files to the Space #####\n"
return 1
fi
这个条件语句告诉bash:“如果我们的s3cmd
命令正常工作,那么让用户知道脚本已经完成了将文件移动到我们的空间。 否则,让用户知道该过程失败。“
如果s3cmd
进程成功完成,那么该函数将在屏幕上显示一条消息(在then
语句中的第一个echo
字符串),并返回值0
,通知调用函数操作已完成。 如果进程失败, then
子句只是输出错误信息(第二个echo
字符串),并返回1
以便脚本的其余部分知道发生了错误。
总而言之, movetoSpace()
函数应该如下所示:
movetoSpace(){
echo "\n##### MOVING TO SPACE #####\n"
if ~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST; then
echo "\n##### Done moving files to s3://"$DST" #####\n"
return 0
else
echo "\n##### Failed to move files to the Space #####\n"
return 1
fi
}
通过写入movetoSpace()
函数,我们可以继续确保脚本被设置为通过使用条件语句来控制流量,从而以预期的顺序调用函数。
设置流量控制
虽然我们已经用函数来建立脚本,但是我们还没有提供脚本的命令来完成这些功能。 在这一点上,我们可以引入一个调用函数,它会告诉脚本的其余部分究竟如何以及何时运行我们编写的其他函数。
假设一切都已经正确配置,当我们运行脚本时,它应该读取输入命令,将它的值分配给每个变量,执行tarandzip()
函数,然后使用movetoSpace()
函数进行操作。 如果这些脚本之间的脚本失败,它应该打印我们的showhelp()
函数的输出来帮助用户排除故障。 我们可以通过在文件底部添加一系列if/then/else
语句来排序并捕获错误:
...
if [ ! -z "$GIVENNAME" ]; then
if tarandzip; then
movetoSpace
else
showhelp
fi
else
showhelp
fi
上面第一个if
语句检查第三个变量是否为空。 它按照以下方式进行:
-
[ ]
:方括号表示它们之间的是一个测试 。 在这种情况下,测试是针对特定的变量而不是空的。 -
!
:在这种情况下,这个符号的意思not
。 -
-z
:这个选项表示一个空字符串 。 所以,加上! ,我们要求不是空字符串 。 -
$GIVENNAME
:我们在这里指出,我们不希望为空的字符串是赋给变量$GIVENNAME
的值。 我们选择这种方法的原因是因为从命令行调用脚本时,该变量被分配了第三个参数传递的值。 如果我们向脚本传递的参数少于3个,则代码将不会有第三个参数来将值赋给$ GIVENNAME ,所以它将分配一个空字符串,并且此测试将失败。
假设这个第一个测试是成功的,那么它将进入下一个if
语句等等。 如果任何if
语句返回一个错误, then
子句将调用showhelp
函数,帮助文本将显示在输出中。 从本质上讲,它所做的就是将所有先前写出的函数粘合在一起,并以正确的顺序给出它们需要执行的信息。
我们的脚本现在完成了! 您可以验证您的脚本看起来像我们在下面部分中构建的完整脚本。
完整的脚本
我们创建的完整备份脚本应该如下所示:
#!/bin/bash
DATETIME=`date +%y%m%d-%H_%M_%S`
SRC=$1
DST=$2
GIVENNAME=$3
showhelp(){
echo "\n\n############################################"
echo "# bkupscript.sh #"
echo "############################################"
echo "\nThis script will backup files/folders into a single compressed file and will store it in the current folder."
echo "In order to work, this script needs the following three parameters in the listed order: "
echo "\t- The full path for the folder or file you want to backup."
echo "\t- The name of the Space where you want to store the backup at (not the url, just the name)."
echo "\t- The name for the backup file (timestamp will be added to the beginning of the filename)\n"
echo "Example: sh bkupscript.sh ./testdir testSpace backupdata\n"
}
tarandzip(){
echo "\n##### Gathering files #####\n"
if tar -czvf $GIVENNAME-$DATETIME.tar.gz $SRC; then
echo "\n##### Done gathering files #####\n"
return 0
else
echo "\n##### Failed to gather files #####\n"
return 1
fi
}
movetoSpace(){
echo "\n##### MOVING TO SPACE #####\n"
if ~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST; then
echo "\n##### Done moving files to s3://"$DST" #####\n"
return 0
else
echo "\n##### Failed to move files to the Space #####\n"
return 1
fi
}
if [ ! -z "$GIVENNAME" ]; then
if tarandzip; then
movetoSpace
else
showhelp
fi
else
showhelp
fi
验证完脚本之后,确保在退出nano之前保存并关闭文件( CTRL-x
, y
,然后按ENTER
)。
测试脚本
现在我们已经完成了构建脚本,我们可以继续进行测试。 这不仅会告诉我们,我们是否正确地编写了这个脚本,而且还会给我们一个练习使用这个脚本的机会,并且看到它在行动中。
当测试这样的脚本时,通常使用虚拟文件是一个好主意。 即使我们知道它不能摧毁或删除数据,但通过测试一些不重要的文件来安全地播放它是明智的。 我们将首先使用mkdir
命令创建一个目录:
mkdir backupthis
接下来,我们将使用touch
在该目录中创建两个空文件:
sudo touch backupthis/file1.txt
sudo touch backupthis/file2.txt
我们现在可以通过上传backupthis
目录及其内容到我们的空间来测试脚本。 这是我们需要用来调用脚本的格式:
sh bkupscript.sh ./backupthis name_of_your_space testrun
注意由于movetoSpace()
函数会自动将s3://
movetoSpace()
到目标变量(即空间的名称),因此该变量应该只是空间的名称而不是其完整的URL。 例如,如果你的空间的URL是“https:// example-space-name .nyc3.digitaloceanspaces.com”,你可以这样写测试命令:
sh bkupscript.sh ./backupthis example-space-name testrun
上面的命令将设置脚本运动,你应该看到这样的输出:
Output
##### Gathering files #####
./backupthis/
./backupthis/file1.txt
./backupthis/file2.txt
##### Done gathering files #####
##### MOVING TO SPACE #####
upload: 'testrun-180119-15_09_36.tar.gz' -> 's3://name_of_your_space /testrun-180119-15_09_36.tar.gz' [1 of 1]
162 of 162 100% in 8s 19.81 B/s done
##### Done moving files to s3://name_of_your_space #####
如果您遇到任何错误,请检查您的脚本以确保它符合我们的示例。 此外,请确保已经正确配置了s3cmd
的安装,并且您使用的访问密钥和密钥都是正确的。
使用Crontab自动备份
在成功测试了备份脚本之后,我们可以设置一个cron
作业,它将使用脚本来执行我们的空间的定期备份。 为了本教程的目的,我们将设置它来每分钟执行一次备份脚本。
首先,我们需要使脚本可执行:
chmod +x bkupscript.sh
现在脚本可以作为命令执行,我们可以编辑crontab
文件来每分钟运行脚本:
crontab -e
首次运行crontab -e
,它会要求您从列表中选择一个编辑器:
no crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny
Choose 1-4 [2]:
您可以选择默认的nano,或者您选择的其他文本编辑器。
一旦在crontab
,我们将在已经存在的值的底部添加以下行:
* * * * * ~/bkupscript.sh ~/backupthis nameofyourspace cronupload
要保存更改,请按CTRL-x
,然后按y
,然后按ENTER
。
一分钟左右之后,您将在Space的仪表板中看到一个新文件!
如果您不做任何更改就使cron
作业运行,则每分钟都会将一个新文件复制到您的空间。 一旦您确认cron
运行成功,请随时重新配置crontab
以按照您希望的时间间隔备份文件。
您现在有一个脚本,可以定期压缩并将您的备份发送到DigitalOcean Space!
结论
在本教程中,我们已经介绍了如何使用bash脚本, crontab
和DigitalOcean Spaces定期创建重要文件的异地备份。 尽管本教程中介绍的脚本仅用于演示目的,但可以将其用作构建生产就绪版本的基础,该版本稍后可以与Jenkins , Drone或Travis CI等CI / CD解决方案集成。
如果您想了解有关CI / CD工具的更多信息,请阅读以下教程: