Управление каталогом /etc с использованием tar и git — перепланировка

0
222

Управление каталогом /etc с использованием tar и git

Директория /etc является одним из ключевых мест Linux-системы. Каждый, кто любит поэкспериментировать с системой, знает как часто бывает так: отредактируешь несколько конфигурационных файлов, а потом спустя день-два обнаруживается, что что-то перестало работать. И не каждый обладает такой прекрасной памятью, чтобы вспомнить какие файлы редактировал и что конкретно менял. Хорошая привычка сохранять оригинальные конфигурационные файлы перед их редактированием приходит обычно с опозданием . Многие бывалые системные администраторы сталкивались с подобными проблемами. Поэтому назревает вопрос — а есть ли такое средство, которое позволяло бы отслеживать изменения сразу в нескольких файлах, вело бы своеобразную историю изменений? Как следует из одной хорошей поговорки (авторство, к сожалению, не помню) «если у вас появилась идея как решить какую-то проблему, то в мире Linux ее уже скорее всего решили или работают над этим» ;) . В данной статье приведены принципы, которые позволяют достичь если не 100% надежности (таких гарантий не даст никто), то уж 90% проблем решат точно.

Первым таким средством является популярный инструмент разработчиков — git. Разработчикам часто приходится отслеживать изменения сразу во многих файлах, поэтому git умеет это делать легко и быстро. git написан самим Линусом Торвальдсом для ведения разработки ядра Linux (и уж конечно это не главное достоинство этой программы :) ). Раньше для этого использовалось коммерческая программа Bit Keeper, за что Торвальдса постоянно упрекали. Когда ему надоели эти упреки, он и написал git. В данной стать пойдет речь о том, как такое средство для разработки как git могут использовать обычные администраторы.

git превращает директорию с файлами в репозиторий, за состоянием которого он будет следить. git умеет:

  • отслеживать изменения во всех файлах своего репозитория (естественно, включая файлы во вложенных директориях);
  • выполнять «коммиты», т. е. подтверждения изменения файлов (от слова commit), т. е. вести контрольные точки внесения изменений в конфигурационные файлы;
  • вести несколько ветвей (branches), которые можно будет независимо редактировать и переключаться между ними по мере необходимости.

Далее я буду приводить все команды и их результат со своего домашнего компьютера, поэтому все изменения буду проводить над резервной копией директории /etc, находящейся в /root. Создание такой копии делается следующим образом:

[[email protected] ~]# mkdir /root/etc
[[email protected] ~]# cp -R /etc/* /root/etc/

Под термином «репозиторий» будет пониматься именно директория /etc, превращенная в репозиторий git.

Кстати говоря, ознакомление с работой git, я рекомендую делать на резервной копии /etc, до тех пор пока вы не поймете назначения команд и то, что они делают. И только с приходом уверенности – переносить все на «живой» каталог /etc !!! В противном случае возможны непредсказуемые изменения файлов внутри /etc, цунами, торнадо, землетрясения и прочие неприятные последствия.
Вы предупреждены!

Перед созданием репозитория нужно создать список исключений, то есть список файлов, изменения которых git будет игнорировать. Сделать это нужно потому, что при нормальной работе системы некоторые файлы внутри /etc меняются сами. Перечень таких файлов определяется обычно используемым дистрибутивом. Обычно это файлы blkid.tab и mtab. Первый содержит служебную информацию об изменениях состояния блочных устройств, а второй – актуальную информацию о смонтированных файловых системах. Создание списка исключений делается созданием файла .gitignore в директории нашего будущего репозитория:

[[email protected]:~/etc]# cat .gitignore
blkid.tab
mtab
*[bB]ak
asound.state

Строчкой *[bB]ak я исключаю из-под контроля git файлы резервных копий, которые могут заканчиваться на bak или Bak. Последний часто меняется при изменении настроек громкости звука. Названия прочих файлов, которые следует исключить из-под контроля git, подскажет опыт эксплуатации системы (такие файлы будут часто самостоятельно меняться).

Также можно проинформировать git о том, кто мы такие (необязательно), эта информация будет использоваться в качестве подписи при выполнении подтверждений изменений в директории. Для этого в своем домашнем каталоге нужно создать файл .gitconfig, следующего содержания:

[[email protected]:~]# cat .gitconfig
[user] name = Anton Chernyshov
email = [email protected]

Для превращения какой-либо директории в репозиторий git, необходимо зайти в нее и выполнить следующие команды:

[[email protected]:~/etc]# cd /root/etc/
[email protected]:~/etc# git init
Initialized empty Git repository in /root/etc/.git/

Команда git init создает директорию .git в нашем репозитории, которая будет содержать всю служебную информацию обо всех изменениях. Поскольку мы будем работать над каталогом /etc, а он содержит приватную информацию (самой критичной является наличие хешей паролей пользователей системы), то хорошим тоном будет сделать этот каталог недоступным для рядовых пользователей системы:

[[email protected]:~/etc]# chmod o-rwx .git
[email protected]:~/etc# ls -al | grep git
drwxr-x— 8 root root 4096 2009-12-27 17:57 .git

Если все сделано правильно, то в правах доступа на директорию последние три символа будут «-», показывая, что никто кроме пользователя root и членов группы root не сможет зайти в данную директорию. Понятно, что глупо делать это сейчас, ведь мы работаем над резервной копией /etc внутри каталога /root, который и так не доступен пользователям системы. Однако об этом стоит помнить при работе с реальным /etc.

[[email protected]:~/etc]# git add .

Команда git add . ставит в очередь на «коммит» все файлы, об изменении которых нет информации в репозитории. В данном случае это вообще все файлы, которые есть в /etc, включая все поддиректории со всеми их файлами, потому что репозиторий пока пуст. Коммитом (от английского слова commit) называется подтверждение изменений в файлах репозитория. Давайте выполним наш первый коммит:

[[email protected]:~/etc]# git commit

После ввода данной команды git попросит указать информацию о выполняемом коммите. Стесняться не стоит, нужно указать столько информации, сколько будет необходимо для того, чтобы потом вспомнить, какие именно изменения фиксирует данный коммит. Посмотреть информацию о коммитах можно выполнив следующую команду:

[[email protected] ~/etc]# git log
commit 0f97eb7b8f46bcdadf000bff1b12e5e29ac02a27
Author: Anton Chernyshov
Date: Sun Dec 27 17:57:38 2009 +0300

Инициализация репозитория

В строке commit указан уникальный идентификатор коммита (это хеш, выполненный по алгоритму SHA). Далее указаны автор (тот, кто сделал коммит, см. выше про файл .gitconfig), дата и набранный на предыдущем шаге комментарий.

Следующей полезной возможностью git является использование ветвей. Ветвь (branch) – это независимое состояние контролируемого репозитория. Редактирование одной ветви никак не влияет на другую, что и будет проиллюстрировано ниже. Использование ветвей необходимо тем, кто любит поэкспериментировать с системой. Можно иметь гарантированно работающую ветвь (в качестве нее можно оставить ветвь по умолчанию master) и ветвь для экспериментов (и назвать ее working). А затем, ту конфигурацию, которая показала себя работоспособной, переносить в первую. Создадим ветвь working:

[[email protected]:~/etc]# git branch working
[[email protected]:~/etc]# git branch
* master
working

Команда git branch working создает ветвь working. git branch выводит список имеющихся ветвей. Звездочкой отмечена текущая ветвь master, которая автоматически создается при инициализации репозитория. Для переключения между ветвями нужно использовать команду git checkout:

[[email protected] ~/etc]# git checkout working
Switched to branch ‘working’
[[email protected] ~/etc]# git branch
master
* working

Теперь звездочкой отмечена ветка working. Меняем один файл в директории и смотрим, что поменялось:

[[email protected] ~/etc]# git diff
diff —git a/exports b/exports
index e69de29..9a0f871 100644
— a/exports
+++ b/exports
@@ -0,0 +1,2 @@
+/srv/data 192.168.0.0/255.255.255.0
+

Теперь при изменении любых файлов git нам будет показывать их изменения в таком вот виде, аналогичном выводу команды diff (за подробностями см. man diff). Для подтверждения данного изменения и внесения его в журнал нужно сделать следующее:

[[email protected] ~/etc]# git add exports

Этим мы ставим файл в очередь на коммит. Таким способом можно вносить информацию об изменениях отдельных файлов. Фиксируем информацию об изменениях:

[[email protected] ~/etc]# git commit
[working 4beda47] Экспортирование директории /srv/data через NFS 1 files changed, 2 insertions(+), 0 deletions(-)

Смотрим информацию об изменениях:

[[email protected] ~/etc]# git log
commit 4beda47f709af7d8695a73bd1f69d3e319d34ba7
Author: Anton Chernyshov
Date: Sun Dec 27 18:37:39 2009 +0300

Экспортирование директории /srv/data через NFS

commit 0f97eb7b8f46bcdadf000bff1b12e5e29ac02a27
Author: Anton Chernyshov
Date: Sun Dec 27 17:57:38 2009 +0300

Инициализация репозитория

Следующая команда скажет чуть больше об изменениях:

[[email protected] ~/etc]# git show
commit 4beda47f709af7d8695a73bd1f69d3e319d34ba7
Author: Anton Chernyshov
Date: Sun Dec 27 18:37:39 2009 +0300

Экспортирование директории /srv/data через NFS

diff -git a/exports b/exports
index e69de29..9a0f871 100644
— a/exports
+++ b/exports
@@ -0,0 +1,2 @@
+/srv/data 192.168.0.0/255.255.255.0
+

Мы видим здесь информацию аналогичную сделанной ранее git diff (см. выше). По-умолчанию, git show показывает информацию о последнем коммите. Естественно, что можно попросить ее сделать это и для любого другого. Для этого в качестве параметра ей нужно передать идентификатор commit’а. Да, да, тот самый длинный SHA-хэш. Но не пугайтесь, его не нужно набирать целиком (эту же программу делали умные люди для таких же умных людей ;) ). Достаточно указать первые 5-6 символов (по сути достаточно, чтобы указанный идентификатор коммита был уникальным).
Проиллюстрируем это примером. Меняем еще один файл:

[[email protected] ~/etc]# vim /etc/hosts

Смотрим изменения:

[[email protected] ~/etc]# git diff
diff —git a/hosts b/hosts
index 2556c5d..97d301d 100644
— a/hosts
+++ b/hosts
@@ -3,3 +3,5 @@
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 localhost 192.168.0.254 rivendale

+192.168.0.35 rohan
+

Подтверждаем изменения:

[[email protected] ~/etc]# git add hosts
[[email protected] ~/etc]# git commit
[working 63468c4] Добавление в сеть новых хостов
1 files changed, 2 insertions(+), 0 deletions(-)
[[email protected] ~/etc]# git log
commit 63468c4c541603e23d69dfb5ac43525f3eaab040
Author: Anton Chernyshov
Date: Sun Dec 27 18:51:32 2009 +0300

Добавление в сеть новых хостов

commit 4beda47f709af7d8695a73bd1f69d3e319d34ba7
Author: Anton Chernyshov
Date: Sun Dec 27 18:37:39 2009 +0300

Экспортирование директории /srv/data через NFS

commit 0f97eb7b8f46bcdadf000bff1b12e5e29ac02a27
Author: Anton Chernyshov
Date: Sun Dec 27 17:57:38 2009 +0300

Инициализация репозитория

Теперь команда git show покажет нам информацию о последнем коммите:

[[email protected] ~/etc]# git show

commit 63468c4c541603e23d69dfb5ac43525f3eaab040
Author: Anton Chernyshov
Date: Sun Dec 27 18:51:32 2009 +0300

Добавление в сеть новых хостов

diff -git a/hosts b/hosts
index 2556c5d..97d301d 100644
— a/hosts
+++ b/hosts
@@ -3,3 +3,5 @@
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 localhost 192.168.0.254 rivendale

+192.168.0.35 rohan
+

Посмотреть информацию о предыдущем коммите, можно следующей командой:

[[email protected] ~/etc]# git show 4beda47
commit 4beda47f709af7d8695a73bd1f69d3e319d34ba7
Author: Anton Chernyshov
Date: Sun Dec 27 18:37:39 2009 +0300

Экспортирование директории /srv/data через NFS

diff -git a/exports b/exports
index e69de29..9a0f871 100644
— a/exports
+++ b/exports
@@ -0,0 +1,2 @@
+/srv/data 192.168.0.0/255.255.255.0
+

Выделение здесь мое, им я показал использованную часть идентификатора коммита.

А что насчет использования разных веток? К ним мы сейчас как раз вернемся. Напомню, что сейчас мы работали с ветвью working. Переключаемся обратно в master:

[[email protected] ~/etc]# git checkout master
Switched to branch ‘master’
[[email protected] ~/etc]# git log
commit 0f97eb7b8f46bcdadf000bff1b12e5e29ac02a27
Author: Anton Chernyshov
Date: Sun Dec 27 17:57:38 2009 +0300

Инициализация репозитория

А куда делись все наши изменения? А все просто — их тут и не было. Мы работали с другой ветвью и вносили изменения туда. Можно проверить содержимое файлов, которые мы меняли ранее:

[[email protected] ~/etc]# cat exports
[[email protected] ~/etc]#

Файл exports, как мы видим, пустой.

Предположим мы решили, что изменения внесенные в ветвь working достаточно хорошо протестированы и их можно переносить в рабочую ветку:

[[email protected] ~/etc]# git merge working
Updating 0f97eb7..63468c4
Fast forward
exports | 2 ++
hosts | 2 ++
2 files changed, 4 insertions(+), 0 deletions(-)

Команда git merge производит слияние указанной ей в качестве параметров ветки с текущей, т.е команда git merge working переносит ее содержимое в текущую ветку. И, кстати говоря, еще показывает какие-именно файлы поменялись.

[[email protected] ~/etc]# git log
commit 63468c4c541603e23d69dfb5ac43525f3eaab040
Author: Anton Chernyshov
Date: Sun Dec 27 18:51:32 2009 +0300

Добавление в сети новых хостов

commit 4beda47f709af7d8695a73bd1f69d3e319d34ba7
Author: Anton Chernyshov
Date: Sun Dec 27 18:37:39 2009 +0300

Экспортирование директории /srv/data через NFS

commit 0f97eb7b8f46bcdadf000bff1b12e5e29ac02a27
Author: Anton Chernyshov
Date: Sun Dec 27 17:57:38 2009 +0300

Инициализация репозитория

Как мы видим, что теперь вывод команды git log для данной ветки аналогичен выводу данной команды для ветки working.

Таким образом, используя приведенный набор команд можно достаточно легко вести историю изменений в директории /etc, самое главное не лениться и не забывать почаще вызывать для этого команду git. Да и экспериментировать с системой теперь можно гораздо смелее :) . Ниже приведено резюме упомянутых команд git:

Резюме команд:

  • git init – создание репозитория в текущей директории
  • git addfilename – постановка файла filename в очередь на коммит. Если вместо filename указать точку, в очередь встанут все файлы, информации об изменении которых нет в репозиториях
  • git commit – подтверждение сделанных изменений.
  • git commit -a – то же, что и выше, плюс подтверждение удалений файлов.
  • git branchbranchname – создание ветви branchname в репозитории.
  • git branch – вывод информации об имеющихся ветвях
  • git checkoutbranchname — переключение на работу с ветвью branchname.
  • git log – вывести список коммитов.
  • git show – показать информацию о последнем коммите
  • git mergebranchname – производит перенос изменений из ветки branchname в текущую.
  • git showcommit_id — покажет изменения подтвержденные последним коммитом.

Подробности работы с git можно посмотреть в его официальной документации:man -k git , в директории /usr/share/doc/git и на официальном сайте git.

Для защиты директории /etc в качестве средства «второго эшелона» можно использовать хорошо известную команду tar. Сохраненные архивы файлов позволят восстановить несколько файлов, не редактируя их. Ниже приведен скрипт для выполнения регулярного резервного копирования директории /etc :

#!/bin/bash

# This file in UTF-8 encoding
# Комментарием выше мы указываем используемую кодировку,
# потому что для русского языка их существует очень много.

# Задание директории для создания резервных копий
BACKUP_DIR=/home/root/backup

# Задаем количество резервных копий
BACKUP_COUNT=10

# Проверяем существование директории для резервных копий
# и если ее не существует — создаем ее
if [ ! -d $BACKUP_DIR ]; then
mkdir -p $BACKUP_DIR
fi

# Проверяем код выполнения предыдущей операции
EXIT_STATUS=$?

# Если код выполнения не равен нулю (операция НЕ завершилась успешно),
# то завершаем работу скрипта
if [ $EXIT_STATUS -ne 0 ]; then
echo «Невозможно создать директорию»
echo «Завершение работы»
exit $EXIT_STATUS
fi

# Архивация директории /etc
tar -cpjf $BACKUP_DIR/etc_$(date +%d_%b).tar.bz2 /etc

# Удаление резервных копий возрастом старше указанного
find $BACKUP_DIR/ -type f -ctime +$BACKUP_COUNT -delete

# Возвращаем код успешного завершения работы операционной системе
exit 0

Комментарии к скрипту:

Переменная $? обычно хранит статус выполнения предыдущей команды. Если команда завершилась успешно, то он обычно равен нулю. Правила хорошего тона обычно требуют выполнять проверку успешного выполнения критически важных операций.

В команде tar используется следующий набор опций tar -cpjf, означающих следующее:

  • c — создание архива;
  • p — сохранение при архивации прав доступа;
  • j — для сжатия архива использовать архиватор bzip, как вариант можно было бы указать z для использования gzip;
  • f — имя файла для создаваемого архива (данная опция должна быть последней).

Полный список возможных опций можно посмотреть в man tar. В качестве имени архива мы используем следующее etc_$(date +%d_%b).tar.bz2 .
Здесь мы, для создания гарантированно разных имен файлов, используем автоподстановку, применяя для этого команду date. Те опции, которые используются здесь создают следующие имена файлов:

[[email protected] /home/root]# ls -1 /home/root/backup
etc_13_Dec.tar.bz2
etc_14_Dec.tar.bz2
etc_15_Dec.tar.bz2
etc_18_Dec.tar.bz2
etc_20_Dec.tar.bz2
etc_21_Dec.tar.bz2
etc_22_Dec.tar.bz2
etc_27_Dec.tar.bz2

Полный список возможных вариантов вывода команды date можно посмотреть в man date. Завершает скрипт команда find, используемая со следующими опциями: find $BACKUP_DIR/ -type f -ctime +$BACKUP_COUNT -delete

Ее опции означают следующее:

  • она выполняет поиск в директории, заданной переменной $BACKUP_DIR
  • ищет обычные файлы – опция -type f
  • поиск файлов имеющих возраст более заданного количества дней задается опцией -ctime , например, опция -ctime +10 найдет файлы старше 10 дней
  • опция -delete говорит команде find, что найденные файлы следует удалять.

Данный скрипт нужно добавить как задание для cron, чтобы он выполнялся регулярно. Сделать это можно или через crontab -e (man crontab), или добавить его в каталог /etc/cron.daily.
Еще можно сделать так, чтобы данные резервные копии отправлялись через ssh на другой хост сети, но это уже совсем отдельная тема и об этом мы поговорим позже.

Спасибо Антону Чернышеву.

Все кто делал капитальный ремонт в своей квартире знают, что перепланировка согласование ее и дальнейшее внедрение изменений процесс трудоемкий и хлопотный. Чтобы сохранить свои нервы лучше обратиться к специалистам в этой сфере. По ссылке вы найдете таких специалистов.