init
This commit is contained in:
commit
42bb3bed62
8 changed files with 978 additions and 0 deletions
48
Makefile
Normal file
48
Makefile
Normal file
|
@ -0,0 +1,48 @@
|
|||
all: install
|
||||
|
||||
install:
|
||||
install -Dm644 settings.sh /etc/restic_backup/settings.sh
|
||||
install -Dm755 restic_backup /usr/local/bin/restic_backup
|
||||
install -Dm644 restic_backup.timer /etc/systemd/system/restic_backup.timer
|
||||
install -Dm644 restic_backup.service /etc/systemd/system/restic_backup.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable restic_backup.timer
|
||||
|
||||
uninstall:
|
||||
systemctl disable restic_backup.timer
|
||||
rm -v /etc/restic_backup/settings.sh
|
||||
rm -v /usr/local/bin/restic_backup
|
||||
rm -v /etc/systemd/system/restic_backup.timer
|
||||
rm -v /etc/systemd/system/restic_backup.service
|
||||
systemctl daemon-reload
|
||||
|
||||
html:
|
||||
pandoc \
|
||||
--from=markdown \
|
||||
--to=html \
|
||||
README.md \
|
||||
--standalone \
|
||||
--output=README.html \
|
||||
--variable document-css=true \
|
||||
--variable linkcolor='[HTML]{0000ff}' \
|
||||
--metadata lang=ru \
|
||||
--metadata title=''
|
||||
|
||||
pdf:
|
||||
pandoc \
|
||||
--from=markdown-implicit_figures \
|
||||
--to=pdf \
|
||||
README.md \
|
||||
--output=README.pdf \
|
||||
--pdf-engine=xelatex \
|
||||
--variable mainfont='FreeSans' \
|
||||
--variable monofont='FreeMono' \
|
||||
--variable fontsize='12pt' \
|
||||
--variable monofontoptions='Scale=0.9' \
|
||||
--variable urlcolor='[HTML]{0000ff}' \
|
||||
--variable pagestyle=empty \
|
||||
--variable margin-left='20mm' \
|
||||
--variable margin-right='20mm' \
|
||||
--variable margin-top='20mm' \
|
||||
--variable margin-bottom='20mm' \
|
||||
--highlight-style haddock
|
451
README.html
Normal file
451
README.html
Normal file
|
@ -0,0 +1,451 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru" xml:lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||
<title>README</title>
|
||||
<style>
|
||||
html {
|
||||
line-height: 1.5;
|
||||
font-family: Georgia, serif;
|
||||
font-size: 20px;
|
||||
color: #1a1a1a;
|
||||
background-color: #fdfdfd;
|
||||
}
|
||||
body {
|
||||
margin: 0 auto;
|
||||
max-width: 36em;
|
||||
padding-left: 50px;
|
||||
padding-right: 50px;
|
||||
padding-top: 50px;
|
||||
padding-bottom: 50px;
|
||||
hyphens: auto;
|
||||
overflow-wrap: break-word;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-kerning: normal;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
body {
|
||||
font-size: 0.9em;
|
||||
padding: 1em;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
background-color: transparent;
|
||||
color: black;
|
||||
font-size: 12pt;
|
||||
}
|
||||
p, h2, h3 {
|
||||
orphans: 3;
|
||||
widows: 3;
|
||||
}
|
||||
h2, h3, h4 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
}
|
||||
p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
a {
|
||||
color: [HTML]{0000ff};
|
||||
}
|
||||
a:visited {
|
||||
color: [HTML]{0000ff};
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 1.4em;
|
||||
}
|
||||
h5, h6 {
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
}
|
||||
h6 {
|
||||
font-weight: normal;
|
||||
}
|
||||
ol, ul {
|
||||
padding-left: 1.7em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
li > ol, li > ul {
|
||||
margin-top: 0;
|
||||
}
|
||||
blockquote {
|
||||
margin: 1em 0 1em 1.7em;
|
||||
padding-left: 1em;
|
||||
border-left: 2px solid #e6e6e6;
|
||||
color: #606060;
|
||||
}
|
||||
code {
|
||||
font-family: Menlo, Monaco, 'Lucida Console', Consolas, monospace;
|
||||
font-size: 85%;
|
||||
margin: 0;
|
||||
}
|
||||
pre {
|
||||
margin: 1em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
pre code {
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
overflow-wrap: normal;
|
||||
}
|
||||
.sourceCode {
|
||||
background-color: transparent;
|
||||
overflow: visible;
|
||||
}
|
||||
hr {
|
||||
background-color: #1a1a1a;
|
||||
border: none;
|
||||
height: 1px;
|
||||
margin: 1em 0;
|
||||
}
|
||||
table {
|
||||
margin: 1em 0;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
display: block;
|
||||
font-variant-numeric: lining-nums tabular-nums;
|
||||
}
|
||||
table caption {
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
tbody {
|
||||
margin-top: 0.5em;
|
||||
border-top: 1px solid #1a1a1a;
|
||||
border-bottom: 1px solid #1a1a1a;
|
||||
}
|
||||
th {
|
||||
border-top: 1px solid #1a1a1a;
|
||||
padding: 0.25em 0.5em 0.25em 0.5em;
|
||||
}
|
||||
td {
|
||||
padding: 0.125em 0.5em 0.25em 0.5em;
|
||||
}
|
||||
header {
|
||||
margin-bottom: 4em;
|
||||
text-align: center;
|
||||
}
|
||||
#TOC li {
|
||||
list-style: none;
|
||||
}
|
||||
#TOC ul {
|
||||
padding-left: 1.3em;
|
||||
}
|
||||
#TOC > ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
#TOC a:not(:hover) {
|
||||
text-decoration: none;
|
||||
}
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
span.underline{text-decoration: underline;}
|
||||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||
ul.task-list{list-style: none;}
|
||||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||||
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
||||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||||
.sourceCode { overflow: visible; }
|
||||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||||
div.sourceCode { margin: 1em 0; }
|
||||
pre.sourceCode { margin: 0; }
|
||||
@media screen {
|
||||
div.sourceCode { overflow: auto; }
|
||||
}
|
||||
@media print {
|
||||
pre > code.sourceCode { white-space: pre-wrap; }
|
||||
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
||||
}
|
||||
pre.numberSource code
|
||||
{ counter-reset: source-line 0; }
|
||||
pre.numberSource code > span
|
||||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||||
pre.numberSource code > span > a:first-child::before
|
||||
{ content: counter(source-line);
|
||||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||||
border: none; display: inline-block;
|
||||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||||
-khtml-user-select: none; -moz-user-select: none;
|
||||
-ms-user-select: none; user-select: none;
|
||||
padding: 0 4px; width: 4em;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||||
div.sourceCode
|
||||
{ }
|
||||
@media screen {
|
||||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||||
}
|
||||
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
||||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||||
code span.at { color: #7d9029; } /* Attribute */
|
||||
code span.bn { color: #40a070; } /* BaseN */
|
||||
code span.bu { color: #008000; } /* BuiltIn */
|
||||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||||
code span.ch { color: #4070a0; } /* Char */
|
||||
code span.cn { color: #880000; } /* Constant */
|
||||
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
||||
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
||||
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
||||
code span.dt { color: #902000; } /* DataType */
|
||||
code span.dv { color: #40a070; } /* DecVal */
|
||||
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
||||
code span.ex { } /* Extension */
|
||||
code span.fl { color: #40a070; } /* Float */
|
||||
code span.fu { color: #06287e; } /* Function */
|
||||
code span.im { color: #008000; font-weight: bold; } /* Import */
|
||||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||||
code span.op { color: #666666; } /* Operator */
|
||||
code span.ot { color: #007020; } /* Other */
|
||||
code span.pp { color: #bc7a00; } /* Preprocessor */
|
||||
code span.sc { color: #4070a0; } /* SpecialChar */
|
||||
code span.ss { color: #bb6688; } /* SpecialString */
|
||||
code span.st { color: #4070a0; } /* String */
|
||||
code span.va { color: #19177c; } /* Variable */
|
||||
code span.vs { color: #4070a0; } /* VerbatimString */
|
||||
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
||||
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
|
||||
</style>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="restic_backup">restic_backup</h1>
|
||||
<p><strong>restic_backup</strong> это скрипт для бэкапа файлов и баз
|
||||
данных с помощью утилиты <strong>restic</strong>.</p>
|
||||
<p>Ссылки:</p>
|
||||
<ul>
|
||||
<li><a href="https://restic.net/">Сайт проекта restic</a></li>
|
||||
<li><a href="https://restic.readthedocs.io/">Документация restic</a>
|
||||
(англ.)</li>
|
||||
</ul>
|
||||
<h1 id="описание-работы-скрипта">Описание работы скрипта</h1>
|
||||
<p>Скрипт выполняет инкрементальные резервные копии в репозиторий для
|
||||
бэкапов. В качестве репозитория может использоваться S3-севместимое
|
||||
хранилище или другой диск. Все варианты описаны <a
|
||||
href="https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html">здесь</a>.</p>
|
||||
<p>Инкрементальный бэкап означает, что первый бэкап содержит полную
|
||||
копию всех данных, а все последующие копии содержат только изменённые
|
||||
файлы. Поэтому первая резервная копия будет выполняться значительно
|
||||
дольше последующих.</p>
|
||||
<p>Бэкап запускается ежедневно по таймеру systemd
|
||||
<strong>restic_backup.timer</strong>, таймер запускает юнит systemd
|
||||
<strong>restic_backup.service</strong> из которого происходит
|
||||
непосредственнй запуск скрипта <strong>restic_backup</strong>.</p>
|
||||
<p>Просмотреть список таймеров можно командой:</p>
|
||||
<pre><code>systemctl list-timers</code></pre>
|
||||
<p>Уведомления на электронную почту при падении бэкапа могут быть
|
||||
настроены по инструкции <a
|
||||
href="https://wiki.archlinux.org/title/Systemd_(%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9)/Timers_(%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9)#%D0%92_%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B5_%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D1%8B_cron">systemd
|
||||
Timers</a>.</p>
|
||||
<p>Как альтернатива вместо таймеров systemd можно использовать
|
||||
<strong>cron</strong>. Пример cron-задачи:</p>
|
||||
<pre><code>0 1 * * * /usr/bin/local/restic_backup </code></pre>
|
||||
<p>Общий алгоритм работы скрипта такой:</p>
|
||||
<ol type="1">
|
||||
<li>Скрипт вначале выполняет проверку инициализации репозитория и
|
||||
инициализирует его если это не так командой
|
||||
<code>restic init</code>.</li>
|
||||
<li>Запускается удаление старых резервных копий командой
|
||||
<code>restic forget</code>. В скрипте используется опция
|
||||
<code>--keep-last</code>, однако можно переписать
|
||||
<strong>/usr/bin/local/restic_backup</strong> на использование другой
|
||||
опции. Сохраняется то количество резервных копий, которое указано в
|
||||
переменной <code>RESTIC_KEEP</code> в файле
|
||||
<strong>/etc/restic_backup/settings.sh</strong>.</li>
|
||||
<li>Запускается дамп баз данных. SQL-дампы сохраняются во временную
|
||||
директорию <strong>/tmp/restic_dbs_temp</strong>.</li>
|
||||
<li>Выполняется запуск <code>retic backup</code>. В репозиторий
|
||||
загружаются файлы и дампы баз данных.</li>
|
||||
<li>В конце процесса удаляется временная директория с SQL-дампами.</li>
|
||||
</ol>
|
||||
<p>Подробный отладочный лог (xtrace) работы скрипта сохраняется в файл
|
||||
<strong>/var/log/restic_backup.log</strong>. Если запуск бэкапа
|
||||
производится по таймеру systemd, то логи также будут доступны через
|
||||
утилиту <strong>journalctl</strong>:</p>
|
||||
<pre><code>journalctl -u restic_backup.service</code></pre>
|
||||
<p>Список файлов входящих в скрипт <strong>restic_backup</strong>:</p>
|
||||
<ul>
|
||||
<li><strong>/usr/local/bin/restic_backup</strong> — непосредственно
|
||||
скрипт резервного копирования.</li>
|
||||
<li><strong>/etc/restic_backup/settings.sh</strong> — файл с настройками
|
||||
резервного копирования.</li>
|
||||
<li><strong>/etc/systemd/system/restic_backup.timer</strong> — таймер
|
||||
systemd.</li>
|
||||
<li><strong>/etc/systemd/system/restic_backup.service</strong> — юнит
|
||||
systemd запускающий бэкап, запускается через таймер.</li>
|
||||
</ul>
|
||||
<h1 id="подготовка-к-резервному-копированию">Подготовка к резервному
|
||||
копированию</h1>
|
||||
<h2 id="использование-makefile">Использование Makefile</h2>
|
||||
<p><strong>Makefile</strong> это файл для утилиты <strong>GNU
|
||||
make</strong>, помогающий автоматически выполнять некоторые действия по
|
||||
коротким командам.</p>
|
||||
<p>В процессе эксплуатации <strong>restic_backup</strong> Makefile не
|
||||
используется, однако он помогает в установке скрипта. Доступные
|
||||
команды:</p>
|
||||
<ul>
|
||||
<li><strong>make install</strong> — установка скрипта</li>
|
||||
<li><strong>make uninstall</strong> — удаление скрипта вместе со всеми
|
||||
настройками</li>
|
||||
<li><strong>make html</strong> — конвертировать README.md в форат
|
||||
HTML.</li>
|
||||
<li><strong>make pdf</strong> — конвертировать README.md в форат
|
||||
PDF.</li>
|
||||
</ul>
|
||||
<p>Последние две команды требуют установки утилиты
|
||||
<strong>pandoc</strong>.</p>
|
||||
<h2 id="настройка-хранилища">Настройка хранилища</h2>
|
||||
<p>Будет рассмотрена настройка S3-бакета в качестве репозитория для
|
||||
бэкапов.</p>
|
||||
<ol type="1">
|
||||
<li>Создать бакет</li>
|
||||
<li>Указать реквизиты подключения в файле
|
||||
<strong>/etc/restic_backup/settings.sh</strong>. Файл имеет подробные
|
||||
комментарии с описанием всех параметров.</li>
|
||||
</ol>
|
||||
<h1 id="конфигурирование">Конфигурирование</h1>
|
||||
<h2 id="настройка-параметров-бэкапа">Настройка параметров бэкапа</h2>
|
||||
<p>Фрагмент файла <strong>/etc/restic_backup/settings.sh</strong>:</p>
|
||||
<div class="sourceCode" id="cb4"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co"># --------------------------- НАСТРОЙКИ RESTIC ---------------------------- #</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Ключ доступа к бакету S3. Совпадает с логином аккаунта</span></span>
|
||||
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="bu">export</span> <span class="va">AWS_ACCESS_KEY_ID</span><span class="op">=<</span>MY_ACCESS_KEY<span class="op">></span></span>
|
||||
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="co"># Секретный ключ доступа к бакету. Можно скопировать из ПУА.</span></span>
|
||||
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="bu">export</span> <span class="va">AWS_SECRET_ACCESS_KEY</span><span class="op">=<</span>MY_SECRET_ACCESS_KEY<span class="op">></span></span>
|
||||
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="co"># Адрес репозитория, куда будут сохраняться резервные копии</span></span>
|
||||
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="bu">export</span> <span class="va">RESTIC_REPOSITORY</span><span class="op">=</span><span class="st">"s3:https://s3.timeweb.com/restic-demo"</span></span>
|
||||
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="co"># Пароль для доcтупа к бэкапам. Все бэкапы шифруются. В случае утраты этого</span></span>
|
||||
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="co"># пароля получить доступ к резрвным копиям будет невозможно!</span></span>
|
||||
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="bu">export</span> <span class="va">RESTIC_PASSWORD</span><span class="op">=</span><span class="st">"I9n7G7G0ZpDWA3GOcJbIuwQCGvGUBkU5"</span></span>
|
||||
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="co"># Количество бэкпов, которые нужно хранить в репозитории</span></span>
|
||||
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="va">RESTIC_KEEP</span><span class="op">=</span>2</span></code></pre></div>
|
||||
<h2 id="добавление-файлов-в-бэкап">Добавление файлов в бэкап</h2>
|
||||
<div class="sourceCode" id="cb5"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ------------------ СПИСОК ФАЙЛОВ И ДИРЕКТОРИЙ ДЛЯ БЭКАПА ---------------- #</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Пути к файлам и директориям обязательно должны быть абсолютными.</span></span>
|
||||
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Абсолютный путь содержит полный путь до файла/директории начиная от</span></span>
|
||||
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="co"># корневого каталога системы.</span></span>
|
||||
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="co"># Переменная `files` ниже содержит перечень путей. Обратите внимание, что</span></span>
|
||||
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="co"># пути, которые содержат пробелы должны быть обязательно включены в кавычки.</span></span>
|
||||
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="co"># Пример: '/home/user/some dir'</span></span>
|
||||
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="va">files</span><span class="op">=</span><span class="va">(</span></span>
|
||||
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a> /etc</span>
|
||||
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a> /home</span>
|
||||
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="va">)</span></span></code></pre></div>
|
||||
<h2 id="добавление-баз-данных-в-бэкап">Добавление баз данных в
|
||||
бэкап</h2>
|
||||
<div class="sourceCode" id="cb6"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ---------------------- СПИСОК БАЗ ДАННЫХ ДЛЯ БЭКАПА --------------------- #</span></span>
|
||||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Ниже необходимо указать реквизиты подключения к базам данных в формате URI</span></span>
|
||||
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co"># (DSN). Запись должна иметь следующий вид:</span></span>
|
||||
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="co"># mysql://пользователь:пароль@хост:порт/имя_базы_данных</span></span>
|
||||
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="co"># Обратите внимание на разделители между частями URI: ":", "@", "/". Порт</span></span>
|
||||
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="co"># можно опустить, если используется стандартный 3306.</span></span>
|
||||
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="co"># Ниже дан записи для БД bitrix_db и именем пользователя bitrix_usr и</span></span>
|
||||
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="co"># паролем boRpBnhGn7ue.</span></span>
|
||||
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="co"># mysql://bitrix_usr:boRpBnhGn7ue@localhost/bitrix_db</span></span>
|
||||
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="co"># Если пароль пользователя базы данных содержит специальные символы, то такой</span></span>
|
||||
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a><span class="co"># пароль обязательно надо закодировать в percent code. Это можно сделать</span></span>
|
||||
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a><span class="co"># следующей командой в терминале:</span></span>
|
||||
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a><span class="co"># echo 'ваш_пароль' | perl -MURI::Escape -wlne 'print uri_escape $_'</span></span>
|
||||
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a><span class="co"># или через онлайн-сервис https://meyerweb.com/eric/tools/dencoder/</span></span>
|
||||
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
|
||||
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a><span class="co"># Ниже введите URI с реквизитами баз данных так как это показано. Обратите</span></span>
|
||||
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a><span class="co"># внимание, что знак равно не должен юыть отделён пробелами. Формат записи</span></span>
|
||||
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a><span class="co"># строго такой как есть.</span></span>
|
||||
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a><span class="va">databases</span><span class="op">=</span><span class="va">(</span></span>
|
||||
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a> mysql://пользователь:пароль@хост/база_данных</span>
|
||||
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a> mysql://пользователь:пароль@хост/другая_база_данных</span>
|
||||
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a><span class="va">)</span></span></code></pre></div>
|
||||
<h1 id="запуск-резервного-копирования">Запуск резервного
|
||||
копирования</h1>
|
||||
<p>Запустить резервное копирование прямо сейчас можно командой:</p>
|
||||
<pre><code>/usr/bin/local/restic_backup</code></pre>
|
||||
<p>Выполнение бэкапа заблокирует ввод в темнал. Желательно запускать
|
||||
команду в сессии tmux или screen. Пример запуска сессии tmux:</p>
|
||||
<pre><code>tmux new -s restic_backup</code></pre>
|
||||
<p>Весь вывод скрипта отправляется в отладочный лог
|
||||
<strong>/var/log/restic_backup.log</strong>.</p>
|
||||
<p>Отслеживать проесс можно командой:</p>
|
||||
<pre><code>tail -f /var/log/restic_backup.log</code></pre>
|
||||
<h1 id="восстановление-из-резервной-копии">Восстановление из резервной
|
||||
копии</h1>
|
||||
<p>Для удобства работы перед вызовом команд <strong>restic</strong>
|
||||
следует импортировать файл с настройками.</p>
|
||||
<p>Это делается командой:</p>
|
||||
<pre><code>source /etc/restic_backup/settings.sh</code></pre>
|
||||
<p>После чего можно выполнять команды restic без надобности вручную
|
||||
указывать адрес репозитория и пароль.</p>
|
||||
<h2 id="восстановление-файлов">Восстановление файлов</h2>
|
||||
<p>Воспользуйтесь инструкцией из официальной документации утилиты:
|
||||
https://restic.readthedocs.io/en/stable/050_restore.html</p>
|
||||
<p>Сперва вам потребуется узнать ID снапшота (так в restic называются
|
||||
бэкапы). Для этого запустите команду:</p>
|
||||
<pre><code>restic snapshots</code></pre>
|
||||
<p>В терминал будет напечатана таблица со списком всех имеющихся
|
||||
снапшотов.</p>
|
||||
<p>Вы можете восстанавливать снапшоты целиком командой вида:</p>
|
||||
<pre><code>restic restore 79766175 --target /tmp/restore-work</code></pre>
|
||||
<p>где 79766175 это ID снапшота, а /tmp/restore-work директория, куда
|
||||
будут восстанавливаться файлы.</p>
|
||||
<p>Другой вариант восстановления — через монтирование репозитория в
|
||||
качестве сетевого диска. Документация:
|
||||
https://restic.readthedocs.io/en/stable/050_restore.html#restore-using-mount</p>
|
||||
<p>С примонтированного диска вы можете скопировать как все файлы, так и
|
||||
отдельные.</p>
|
||||
<p>Команды для монтирования:</p>
|
||||
<pre><code>mkdir -p /mnt/restic
|
||||
restic mount /mnt/restic</code></pre>
|
||||
<p>restic при помощи FUSE создаст виртуальную файловую систему. При этом
|
||||
терминал будет заблокирован. Можно запустить команду на монтирвоание в
|
||||
сессии tmux или screen и работать с примонтирвоанным диском в другом
|
||||
окне. Либо открыть новую сессию SSH и работать в ней. После можно
|
||||
прервать restic сочетанием клавиш <code>Ctrl+C</code> или выполнить
|
||||
команду:</p>
|
||||
<pre><code>fusermount -u /mnt/restic</code></pre>
|
||||
<p>чтобы отмонтировать бэкапы.</p>
|
||||
<h2 id="восстановление-баз-данных">Восстановление баз данных</h2>
|
||||
<p>Восстановление баз данных почти ничем не отличается от восстановления
|
||||
обычных файлов.</p>
|
||||
<ol type="1">
|
||||
<li>Восстановите дамп в формате <strong>.sql.gz</strong> из репозитория
|
||||
restic</li>
|
||||
<li>Запустите команду для импорта дампа.</li>
|
||||
</ol>
|
||||
<pre><code>zcat имя_дампа.sql.gz | mysql -u'пользователь' имя_базы_данных -p'пароль'</code></pre>
|
||||
<h1 id="удаление-старых-бэкапов">Удаление старых бэкапов</h1>
|
||||
<p>Удаление производится командой <code>restic forget</code>. Смотрите
|
||||
подробное описание в документации
|
||||
https://restic.readthedocs.io/en/stable/060_forget.html</p>
|
||||
</body>
|
||||
</html>
|
275
README.md
Normal file
275
README.md
Normal file
|
@ -0,0 +1,275 @@
|
|||
# restic\_backup
|
||||
|
||||
**restic_backup** это скрипт для бэкапа файлов и баз данных с помощью утилиты
|
||||
**restic**.
|
||||
|
||||
Ссылки:
|
||||
|
||||
- [Сайт проекта restic](https://restic.net/)
|
||||
- [Документация restic](https://restic.readthedocs.io/) (англ.)
|
||||
|
||||
# Описание работы скрипта
|
||||
|
||||
Скрипт выполняет инкрементальные резервные копии в репозиторий для бэкапов. В
|
||||
качестве репозитория может использоваться S3-севместимое хранилище или другой
|
||||
диск. Все варианты описаны [здесь](https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html).
|
||||
|
||||
Инкрементальный бэкап означает, что первый бэкап содержит полную копию всех
|
||||
данных, а все последующие копии содержат только изменённые файлы. Поэтому первая
|
||||
резервная копия будет выполняться значительно дольше последующих.
|
||||
|
||||
Бэкап запускается ежедневно по таймеру systemd **restic_backup.timer**, таймер
|
||||
запускает юнит systemd **restic_backup.service** из которого происходит
|
||||
непосредственнй запуск скрипта **restic_backup**.
|
||||
|
||||
Просмотреть список таймеров можно командой:
|
||||
|
||||
```
|
||||
systemctl list-timers
|
||||
```
|
||||
|
||||
Уведомления на электронную почту при падении бэкапа могут быть настроены по
|
||||
инструкции [systemd Timers](https://wiki.archlinux.org/title/Systemd_(%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9)/Timers_(%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9)#%D0%92_%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B5_%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D1%8B_cron).
|
||||
|
||||
Как альтернатива вместо таймеров systemd можно использовать **cron**. Пример
|
||||
cron-задачи:
|
||||
|
||||
```
|
||||
0 1 * * * /usr/bin/local/restic_backup
|
||||
```
|
||||
|
||||
Общий алгоритм работы скрипта такой:
|
||||
|
||||
1. Скрипт вначале выполняет проверку инициализации репозитория и инициализирует
|
||||
его если это не так командой `restic init`.
|
||||
2. Запускается удаление старых резервных копий командой `restic forget`. В
|
||||
скрипте используется опция `--keep-last`, однако можно переписать
|
||||
**/usr/bin/local/restic_backup** на использование другой опции. Сохраняется то
|
||||
количество резервных копий, которое указано в переменной `RESTIC_KEEP` в файле
|
||||
**/etc/restic_backup/settings.sh**.
|
||||
3. Запускается дамп баз данных. SQL-дампы сохраняются во временную директорию
|
||||
**/tmp/restic_dbs_temp**.
|
||||
4. Выполняется запуск `retic backup`. В репозиторий загружаются файлы и дампы
|
||||
баз данных.
|
||||
5. В конце процесса удаляется временная директория с SQL-дампами.
|
||||
|
||||
Подробный отладочный лог (xtrace) работы скрипта сохраняется в файл
|
||||
**/var/log/restic_backup.log**. Если запуск бэкапа производится по таймеру
|
||||
systemd, то логи также будут доступны через утилиту **journalctl**:
|
||||
|
||||
```
|
||||
journalctl -u restic_backup.service
|
||||
```
|
||||
|
||||
Список файлов входящих в скрипт **restic_backup**:
|
||||
|
||||
- **/usr/local/bin/restic_backup** — непосредственно скрипт резервного копирования.
|
||||
- **/etc/restic_backup/settings.sh** — файл с настройками резервного копирования.
|
||||
- **/etc/systemd/system/restic_backup.timer** — таймер systemd.
|
||||
- **/etc/systemd/system/restic_backup.service** — юнит systemd запускающий бэкап,
|
||||
запускается через таймер.
|
||||
|
||||
# Подготовка к резервному копированию
|
||||
|
||||
## Использование Makefile
|
||||
|
||||
**Makefile** это файл для утилиты **GNU make**, помогающий автоматически выполнять
|
||||
некоторые действия по коротким командам.
|
||||
|
||||
В процессе эксплуатации **restic_backup** Makefile не используется, однако он
|
||||
помогает в установке скрипта. Доступные команды:
|
||||
|
||||
- **make install** — установка скрипта
|
||||
- **make uninstall** — удаление скрипта вместе со всеми настройками
|
||||
- **make html** — конвертировать README.md в форат HTML.
|
||||
- **make pdf** — конвертировать README.md в форат PDF.
|
||||
|
||||
Последние две команды требуют установки утилиты **pandoc**.
|
||||
|
||||
## Настройка хранилища
|
||||
|
||||
Будет рассмотрена настройка S3-бакета в качестве репозитория для бэкапов.
|
||||
|
||||
1. Создать бакет
|
||||
2. Указать реквизиты подключения в файле **/etc/restic_backup/settings.sh**. Файл
|
||||
имеет подробные комментарии с описанием всех параметров.
|
||||
|
||||
# Конфигурирование
|
||||
## Настройка параметров бэкапа
|
||||
|
||||
Фрагмент файла **/etc/restic_backup/settings.sh**:
|
||||
|
||||
```bash
|
||||
# --------------------------- НАСТРОЙКИ RESTIC ---------------------------- #
|
||||
|
||||
# Ключ доступа к бакету S3. Совпадает с логином аккаунта
|
||||
export AWS_ACCESS_KEY_ID=<MY_ACCESS_KEY>
|
||||
|
||||
# Секретный ключ доступа к бакету. Можно скопировать из ПУА.
|
||||
export AWS_SECRET_ACCESS_KEY=<MY_SECRET_ACCESS_KEY>
|
||||
|
||||
# Адрес репозитория, куда будут сохраняться резервные копии
|
||||
export RESTIC_REPOSITORY="s3:https://s3.timeweb.com/restic-demo"
|
||||
|
||||
# Пароль для доcтупа к бэкапам. Все бэкапы шифруются. В случае утраты этого
|
||||
# пароля получить доступ к резрвным копиям будет невозможно!
|
||||
export RESTIC_PASSWORD="tiwfBM4i3jDvMA6ah1AIs2HdoJ9w66OS"
|
||||
|
||||
# Количество бэкпов, которые нужно хранить в репозитории
|
||||
RESTIC_KEEP=2
|
||||
```
|
||||
|
||||
## Добавление файлов в бэкап
|
||||
|
||||
```bash
|
||||
# ------------------ СПИСОК ФАЙЛОВ И ДИРЕКТОРИЙ ДЛЯ БЭКАПА ---------------- #
|
||||
|
||||
# Пути к файлам и директориям обязательно должны быть абсолютными.
|
||||
# Абсолютный путь содержит полный путь до файла/директории начиная от
|
||||
# корневого каталога системы.
|
||||
#
|
||||
# Переменная `files` ниже содержит перечень путей. Обратите внимание, что
|
||||
# пути, которые содержат пробелы должны быть обязательно включены в кавычки.
|
||||
# Пример: '/home/user/some dir'
|
||||
|
||||
files=(
|
||||
/etc
|
||||
/home
|
||||
)
|
||||
```
|
||||
|
||||
## Добавление баз данных в бэкап
|
||||
|
||||
```bash
|
||||
# ---------------------- СПИСОК БАЗ ДАННЫХ ДЛЯ БЭКАПА --------------------- #
|
||||
|
||||
# Ниже необходимо указать реквизиты подключения к базам данных в формате URI
|
||||
# (DSN). Запись должна иметь следующий вид:
|
||||
#
|
||||
# mysql://пользователь:пароль@хост:порт/имя_базы_данных
|
||||
#
|
||||
# Обратите внимание на разделители между частями URI: ":", "@", "/". Порт
|
||||
# можно опустить, если используется стандартный 3306.
|
||||
#
|
||||
# Ниже дан записи для БД bitrix_db и именем пользователя bitrix_usr и
|
||||
# паролем boRpBnhGn7ue.
|
||||
#
|
||||
# mysql://bitrix_usr:boRpBnhGn7ue@localhost/bitrix_db
|
||||
#
|
||||
# Если пароль пользователя базы данных содержит специальные символы, то такой
|
||||
# пароль обязательно надо закодировать в percent code. Это можно сделать
|
||||
# следующей командой в терминале:
|
||||
#
|
||||
# echo 'ваш_пароль' | perl -MURI::Escape -wlne 'print uri_escape $_'
|
||||
#
|
||||
# или через онлайн-сервис https://meyerweb.com/eric/tools/dencoder/
|
||||
#
|
||||
# Ниже введите URI с реквизитами баз данных так как это показано. Обратите
|
||||
# внимание, что знак равно не должен юыть отделён пробелами. Формат записи
|
||||
# строго такой как есть.
|
||||
|
||||
databases=(
|
||||
mysql://пользователь:пароль@хост/база_данных
|
||||
mysql://пользователь:пароль@хост/другая_база_данных
|
||||
)
|
||||
```
|
||||
|
||||
# Запуск резервного копирования
|
||||
|
||||
Запустить резервное копирование прямо сейчас можно командой:
|
||||
|
||||
```
|
||||
/usr/bin/local/restic_backup
|
||||
```
|
||||
|
||||
Выполнение бэкапа заблокирует ввод в темнал. Желательно запускать команду в
|
||||
сессии tmux или screen. Пример запуска сессии tmux:
|
||||
|
||||
```
|
||||
tmux new -s restic_backup
|
||||
```
|
||||
|
||||
Весь вывод скрипта отправляется в отладочный лог **/var/log/restic_backup.log**.
|
||||
|
||||
Отслеживать проесс можно командой:
|
||||
|
||||
```
|
||||
tail -f /var/log/restic_backup.log
|
||||
```
|
||||
|
||||
# Восстановление из резервной копии
|
||||
|
||||
Для удобства работы перед вызовом команд **restic** следует импортировать файл
|
||||
с настройками.
|
||||
|
||||
Это делается командой:
|
||||
|
||||
```
|
||||
source /etc/restic_backup/settings.sh
|
||||
```
|
||||
|
||||
После чего можно выполнять команды restic без надобности вручную указывать адрес
|
||||
репозитория и пароль.
|
||||
|
||||
## Восстановление файлов
|
||||
|
||||
Воспользуйтесь инструкцией из официальной документации утилиты: https://restic.readthedocs.io/en/stable/050_restore.html
|
||||
|
||||
Сперва вам потребуется узнать ID снапшота (так в restic называются бэкапы). Для
|
||||
этого запустите команду:
|
||||
|
||||
```
|
||||
restic snapshots
|
||||
```
|
||||
|
||||
В терминал будет напечатана таблица со списком всех имеющихся снапшотов.
|
||||
|
||||
Вы можете восстанавливать снапшоты целиком командой вида:
|
||||
|
||||
```
|
||||
restic restore 79766175 --target /tmp/restore-work
|
||||
```
|
||||
|
||||
где 79766175 это ID снапшота, а /tmp/restore-work директория, куда будут
|
||||
восстанавливаться файлы.
|
||||
|
||||
Другой вариант восстановления — через монтирование репозитория в качестве сетевого
|
||||
диска. Документация: https://restic.readthedocs.io/en/stable/050_restore.html#restore-using-mount
|
||||
|
||||
С примонтированного диска вы можете скопировать как все файлы, так и отдельные.
|
||||
|
||||
Команды для монтирования:
|
||||
|
||||
```
|
||||
mkdir -p /mnt/restic
|
||||
restic mount /mnt/restic
|
||||
```
|
||||
|
||||
restic при помощи FUSE создаст виртуальную файловую систему. При этом терминал
|
||||
будет заблокирован. Можно запустить команду на монтирвоание в сессии tmux или
|
||||
screen и работать с примонтирвоанным диском в другом окне. Либо открыть новую
|
||||
сессию SSH и работать в ней. После можно прервать restic сочетанием клавиш
|
||||
`Ctrl+C` или выполнить команду:
|
||||
|
||||
```
|
||||
fusermount -u /mnt/restic
|
||||
```
|
||||
|
||||
чтобы отмонтировать бэкапы.
|
||||
|
||||
## Восстановление баз данных
|
||||
|
||||
Восстановление баз данных почти ничем не отличается от восстановления обычных
|
||||
файлов.
|
||||
|
||||
1. Восстановите дамп в формате **.sql.gz** из репозитория restic
|
||||
2. Запустите команду для импорта дампа.
|
||||
|
||||
```
|
||||
zcat имя_дампа.sql.gz | mysql -u'пользователь' имя_базы_данных -p'пароль'
|
||||
```
|
||||
|
||||
# Удаление старых бэкапов
|
||||
|
||||
Удаление производится командой `restic forget`. Смотрите подробное описание в
|
||||
документации https://restic.readthedocs.io/en/stable/060_forget.html
|
BIN
README.pdf
Normal file
BIN
README.pdf
Normal file
Binary file not shown.
115
restic_backup
Executable file
115
restic_backup
Executable file
|
@ -0,0 +1,115 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit # завершать скрипт при возникновении ошибок
|
||||
source /etc/restic_backup/settings.sh # импортировать настройки
|
||||
|
||||
# Создать временную директорию для SQL-дампов
|
||||
dbs_save_dir=/tmp/databases_backup
|
||||
mkdir -p "$dbs_save_dir"
|
||||
|
||||
# Включить подробное логирование скрипта
|
||||
log_file=/var/log/restic_backup.log
|
||||
echo "# --------- BACKUP STARTED AT $(date -R) --------- #" >> "$log_file"
|
||||
exec >> "$log_file"
|
||||
exec 2>&1
|
||||
export PS4='+$0:$LINENO '
|
||||
set -o xtrace
|
||||
|
||||
# ------------------------------------------------------------------------- #
|
||||
# Вспомогательные функции #
|
||||
# ------------------------------------------------------------------------- #
|
||||
|
||||
parse_uri() {
|
||||
# Парсер URI
|
||||
uri="$1"
|
||||
schema="$(cut -d ':' -f 1 <<<"$uri")"
|
||||
user="$(grep -Po '(?<=://)(.*)(?=@)' <<<"$uri" | cut -d ':' -f 1)"
|
||||
password="$(passw=$(grep -Po '(?<=://)(.*)(?=@)' <<<"$uri"); \
|
||||
[[ $passw =~ .+:.+ ]] && echo ${passw##*:})" || true
|
||||
host="$(grep -Po '(?<=@)(.*)' <<<"$uri" |
|
||||
cut -d '/' -f 1 | cut -d ':' -f 1)"
|
||||
port="$(prt=$(grep -Po '(?<=@)(.*)' <<<"$uri" |
|
||||
cut -d '/' -f 1); [[ $prt =~ .+:[0-9]{1,} ]] &&
|
||||
echo ${prt##*:})" || true
|
||||
path="$(pth=$(grep -Po '(?<=@)(.*)' <<<"$uri"); [[ $pth =~ :~ ]] &&
|
||||
cut -d ':' -f 2 <<<"$pth" ||
|
||||
grep -Po '(?<=(:[~/])|/)(.*)' <<<"$pth" |
|
||||
xargs -I {} echo /{} | sed 's%//%/%g')" || true
|
||||
|
||||
# Декодинг пароля
|
||||
__urldecode() {
|
||||
: "${*//+/ }"; echo -e "${_//%/\\x}";
|
||||
}
|
||||
password="$(__urldecode "$password")" || true
|
||||
}
|
||||
|
||||
get_name() {
|
||||
# Фунция печатает на экран имя файла с временной меткой
|
||||
local name="${1##*/}"
|
||||
local ext="$2"
|
||||
local ff="${name_prefix}${name}_%Y%m%d-%H%M"
|
||||
date +"${ff}${ext}"
|
||||
}
|
||||
|
||||
dump_mysql() {
|
||||
# Выполнить дамп базы данных
|
||||
parse_uri "$1"
|
||||
echo "Выполняется дамп БД '${path##*/}' от ${user}@${host} ..."
|
||||
|
||||
dump_name="$dbs_save_dir"/"$(get_name "$path" '.sql.gz')"
|
||||
[ "$port" ] || port=3306 # Устанавливаем порт MySQL по умолчанию
|
||||
|
||||
mysqldump \
|
||||
--no-tablespaces \
|
||||
--host="$host" \
|
||||
--port="$port" \
|
||||
"${path##*/}" \
|
||||
--user="$user" \
|
||||
--password="$password" \
|
||||
| gzip -9c > "$dump_name"
|
||||
|
||||
if [ -s "$dump_name" ]; then
|
||||
echo "Дамп сохранён как: $dump_name"
|
||||
else
|
||||
rm "$dump_name"
|
||||
echo "Что-то пошло не так. Размер дампа 0 байт. Файл $dump_name удалён" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------- #
|
||||
# Запуск резерввного копирования #
|
||||
# ------------------------------------------------------------------------- #
|
||||
|
||||
# Если репозиторий для бэкапов не инициализирован, инициализировать
|
||||
# https://restic.readthedocs.io/en/stable/075_scripting.html
|
||||
echo "Проверка репозитория ..."
|
||||
if ! restic snapshots; then
|
||||
restic init
|
||||
fi
|
||||
|
||||
# Удаление старых бэкапов
|
||||
echo "Удаление старых бэкапов ..."
|
||||
restic forget --keep-last "$RESTIC_KEEP"
|
||||
restic prune
|
||||
|
||||
# Дамп баз данных
|
||||
# Запускается если массив databases непустой
|
||||
if [ -n "$databases" ]; then
|
||||
echo "Запуск дампа баз данных ..."
|
||||
for database in "${databases[@]}"; do
|
||||
dump_mysql "$database"
|
||||
done
|
||||
fi
|
||||
|
||||
# Выполнить резервное копирование в репозиторий
|
||||
echo "Резервное копирование запущено ..."
|
||||
restic backup "${files[@]}" "$dbs_save_dir"
|
||||
|
||||
# Осторожно удаляем временную директорию для SQL-дампов
|
||||
echo "Удаление директории с временными файлами"
|
||||
if [[ "$dbs_save_dir" == "/" ]]; then
|
||||
echo "ПОПЫТКА УДАЛИТЬ КОРНЕВУЮ ФС!" >&2; exit 1
|
||||
fi
|
||||
rm -rf "${dbs_save_dir:-/nonexistent}"
|
||||
echo -e "\e[32mРезервное копирование завершено\e[0m"
|
11
restic_backup.service
Normal file
11
restic_backup.service
Normal file
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=Service for run restic backup
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/local/restic_backup
|
||||
SyslogIdentifier=restic_backup
|
||||
Restart=no
|
||||
TimeoutStopSec=30
|
||||
KillMode=process
|
||||
Type=oneshot
|
10
restic_backup.timer
Normal file
10
restic_backup.timer
Normal file
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Dayly restic backup timer
|
||||
|
||||
[Timer]
|
||||
Unit=restic_backup.service
|
||||
OnCalendar=*-*-* 1:00:00
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
68
settings.sh
Normal file
68
settings.sh
Normal file
|
@ -0,0 +1,68 @@
|
|||
# ------------------------------------------------------------------------- #
|
||||
# ВНИМАНИЕ! Этот файл должен содержать валидный код на Bash #
|
||||
# ------------------------------------------------------------------------- #
|
||||
|
||||
# --------------------------- НАСТРОЙКИ RESTIC ---------------------------- #
|
||||
|
||||
# Ключ доступа к бакету S3. Совпадает с логином аккаунта
|
||||
export AWS_ACCESS_KEY_ID=<MY_ACCESS_KEY>
|
||||
|
||||
# Секретный ключ доступа к бакету. Можно скопировать из ПУА.
|
||||
export AWS_SECRET_ACCESS_KEY=<MY_SECRET_ACCESS_KEY>
|
||||
|
||||
# Адрес репозитория, куда будут сохраняться резервные копии
|
||||
export RESTIC_REPOSITORY="s3:https://s3.timeweb.com/restic-demo"
|
||||
|
||||
# Пароль для доcтупа к бэкапам. Все бэкапы шифруются. В случае утраты этого
|
||||
# пароля получить доступ к резрвным копиям будет невозможно!
|
||||
export RESTIC_PASSWORD="tiwfBM4i3jDvMA6ah1AIs2HdoJ9w66OS"
|
||||
|
||||
# Количество бэкпов, которые нужно хранить в репозитории
|
||||
RESTIC_KEEP=2
|
||||
|
||||
# ------------------ СПИСОК ФАЙЛОВ И ДИРЕКТОРИЙ ДЛЯ БЭКАПА ---------------- #
|
||||
|
||||
# Пути к файлам и директориям обязательно должны быть абсолютными.
|
||||
# Абсолютный путь содержит полный путь до файла/директории начиная от
|
||||
# корневого каталога системы.
|
||||
#
|
||||
# Переменная `files` ниже содержит перечень путей. Обратите внимание, что
|
||||
# пути, которые содержат пробелы должны быть обязательно включены в кавычки.
|
||||
# Пример: '/home/user/some dir'
|
||||
|
||||
files=(
|
||||
/etc
|
||||
/home
|
||||
)
|
||||
|
||||
# ---------------------- СПИСОК БАЗ ДАННЫХ ДЛЯ БЭКАПА --------------------- #
|
||||
|
||||
# Ниже необходимо указать реквизиты подключения к базам данных в формате URI
|
||||
# (DSN). Запись должна иметь следующий вид:
|
||||
#
|
||||
# mysql://пользователь:пароль@хост:порт/имя_базы_данных
|
||||
#
|
||||
# Обратите внимание на разделители между частями URI: ":", "@", "/". Порт
|
||||
# можно опустить, если используется стандартный 3306.
|
||||
#
|
||||
# Ниже дан записи для БД bitrix_db и именем пользователя bitrix_usr и
|
||||
# паролем boRpBnhGn7ue.
|
||||
#
|
||||
# mysql://bitrix_usr:boRpBnhGn7ue@localhost/bitrix_db
|
||||
#
|
||||
# Если пароль пользователя базы данных содержит специальные символы, то такой
|
||||
# пароль обязательно надо закодировать в percent code. Это можно сделать
|
||||
# следующей командой в терминале:
|
||||
#
|
||||
# echo 'ваш_пароль' | perl -MURI::Escape -wlne 'print uri_escape $_'
|
||||
#
|
||||
# или через онлайн-сервис https://meyerweb.com/eric/tools/dencoder/
|
||||
#
|
||||
# Ниже введите URI с реквизитами баз данных так как это показано. Обратите
|
||||
# внимание, что знак равно не должен юыть отделён пробелами. Формат записи
|
||||
# строго такой как есть.
|
||||
|
||||
databases=(
|
||||
mysql://пользователь:пароль@хост/база_данных
|
||||
mysql://пользователь:пароль@хост/другая_база_данных
|
||||
)
|
Loading…
Add table
Reference in a new issue