Улучшаем и дополняем советы блогеров

Сейчас появилось множество блогеров, которые дают советы по *nix-системам. Большинство из этих советов, как правило, можно улучшить или дополнить, а некоторые вообще по тем или иным причинам некорректны. Наш журнал не мог пройти мимо такого вопиющего недоразумения и в моем лице решил прошерстить блоги, выискивая данные советы и исправляя их.

Сохраняем базы данных в MySQL

Иногда бывает необходимо автоматизировать создание бэкапа БД в MySQL. И ладно бы только одной базы — с этим все просто, использовать команду вида:

$ mysqldump -u user -ppass dbname | gzip -9 > dbname-`date +%Y%m%d%H%M`.sql.gz

но ведь иногда надо все базы сохранить! Что нам предлагается сделать в блоге для этой цели? Предлагается использовать опцию –all-databases, то есть команда будет выглядеть так:

$ mysqldump -u user -ppass --all-databases | gzip -9 > all-db.sql.gz

Однако эта команда не совсем удобна — хотя бы тем, что все базы сохраняет в один файл, а это слегка затрудняет ее восстановление. Что предлагаю сделать я? На выбор два варианта: один — коротенький мини-скрипт, практически двустрочник, который можно легко зазубрить и выполнять в командной строке, и второй — уже полноценный скрипт, куда можно, например, прописывать базы, которые сохранять не требуется. Мини-скрипт выглядит так:

$ for i in `mysql -u root -ppass -e'SHOW DATABASES;' | egrep -v 'information_schema|performance_schema|Database`; do mysqldump -u root -ppass $i > `date +%Y%m%d%H%M`-$i; gzip -9 `date +%Y%m%d%H%M`-$i;done

Разберемся, что делает этот мини-скрипт. Он в цикле просматривает все базы данных, удаляет egrep’ом строчки ненужных баз, таких как information_schema, и создает для каждой базы бэкап.

Бэкап всех баз данных MySQL
Бэкап всех баз данных MySQL

Теперь рассмотрим кусочек полноценного скрипта (целиком его ты можешь найти на диске):

mysqldump_all.sh  for db in $DBS do ... if [ "$skipdb" == "-1" ] ; then MYSQLBACKDIR="$DEST/$db" # Создаем папку для бэкапа с названием базы [ ! -d $MYSQLBACKDIR ] && mkdir -p $MYSQLBACKDIR || : FILE="$MYSQLBACKDIR/$NOW.sql.gz" # Собственно бэкап $MYSQLDUMP --opt -u $MyUSER -h $MyHOST -p$MyPASS $db | $GZIP -9 > $FILE FILECOUNT="$(find $MYSQLBACKDIR/* | wc -l)" if [ $FILECOUMT -ge 0 ] ; then # Удаляем файлы бэкапов, созданные более 20 дней назад find $MYSQLBACKDIR/* -type f -mtime 20 -exec rm -rf {} ; fi fi done

Какой из этих путей использовать — зависит исключительно от цели бэкапа. На мой взгляд, чем проще, тем лучше — но и слишком простые решения зачастую бывают неправильными.

Если у тебя уже есть полный бэкап всех баз данных и ты хочешь восстановить конкретную БД, используй следующую команду:

$ gunzip -c fulldumpname.sql.gz | mysql --one-database -u root -ppass db_to_restore

Восстановление пароля root (RHEL)

Предположим, ты забыл пароль root или вообще его не знаешь. В блогах предлагается следующий путь:

  1. При загрузке нажать пробел, потом «E».
  2. Выделить строчку kernel и, снова нажав «E», добавить в конец строки слово single.
  3. Загрузиться и сменить пароль.

Однако… иногда и в режиме single требуется пароль. Есть другой путь восстановления (конечно, если и на Grub не стоит пароль).

  1. Предыдущие пункты 1 и 2 выполняем без изменений, но вместо single пишем init=/bin/bash, так указываем ядру, что вместо /sbin/init первой программой пользовательского режима будет оболочка.
  2. Перемонтируем корневую ФС в режим rw:
    # /sbin/mount -o remount,rw /
  3. Задаем пароль командой /bin/passwd.
  4. Жмем следующие комбинации клавиш: <Alt + SysRq + s>, <Alt + SysRq + u>, <Alt + SysRq + b> — аварийная синхронизация буферов ФС, перемонтирование ФС в режим ro и перезагрузка. Пароль изменен.

Рулим контекстом SELinux

Известно, что SELinux довольно-таки навороченная и сложная вещь, и в случае непонятных неполадок на него надо бы грешить в первую очередь. Но речь не об этом, а о том, что иногда советуют «просто изменить контекст», используя следующую команду (аргументы далее — в качестве примера):

# chcon -R -t samba_share_t /home/samba

Но все это будет действовать лишь до следующего обновления политик. Чтобы понимать, почему так, давай рассмотрим эту часть SELinux чуть подробнее. Все политики SELinux хранятся в /etc/selinux/targeted/policy, но команды наподобие chcon оперируют не с ними. Они оперируют с расширенными атрибутами файлов. Однако политики иногда обновляются, и все контексты, которые хранятся в расширенных атрибутах, при этом сбрасываются до значений, прописанных в этих политиках. Таким образом, команда chcon устанавливает контекст лишь на время. Для того чтобы его еще и добавить к файлам политик, необходимо использовать команду semanage fcontext — для приведенного выше примера она будет выглядеть так:

# semanage fcontext -a -t samba_share_t /home/samba

Кстати, если говорить о Samba, то, чтобы разрешить лезть в домашние директории без смены контекста, необходимо установить переменную samba_enable_home_dirs, для чего используем следующую команду:

# setsebool -P samba_enable_home_dirs on

Бэкап /etc

Для быстрого бэкапа /etc, пишется в одном блоге, можно использовать команду zip, при необходимости используя ключ ‘-x’ для исключения лишних каталогов — например, так:

# zip -r /home/user/backupfile /etc -x /etc/dev* /etc/selinux* /etc/alternatives*

Данный совет достаточно корректен. Но мне бы хотелось к нему кое-что добавить: в качестве дополнения к резервному копированию (но ни в коем разе не в качестве замены!) можно использовать команды Git.

  1. Если Git еще не стоит в системе — установи его.
  2. Проинициализируй репозиторий Git в /etc и добавь в него все файлы.
    # cd /etc # git init # git add .
  3. Закоммить текущую версию.
    # git commit
  4. По необходимости создай бранч и переключись на него.
    # git checkout -b add_user_joe
  5. Измени все, что хотел изменить, и добавь эти изменения в репозиторий Git с последующим коммитом.
    # useradd joe # passwd joe # git add . -A # git commit
  6. В случае успеха проведи слияние бранчей, а в случае неудачи — переключись на прежний бранч.
    # git chechkout master # git merge add_user_joe

Некоторые тонкости сборки ядра в Ubuntu

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

# make dep && make clean && make && make install && make modules install

Но этот способ достаточно неудобен — он не формирует пакеты, следовательно, новое ядро так просто не удалишь. Да и заголовочные файлы ядра остаются старыми. В системах на основе Debian есть метод получше:

$ sudo apt-get build-dep linux-image $ sudo apt-get install fakeroot kernel-package $ fakeroot make-kpkg --initrd --append-to-version=-custom kernel_image kernel_headers && sudo dpkg -i ../linux-image-version.deb ../linux-headers-version.deb

Разберем эту команду подробнее. Fakeroot используется для того, чтобы перенаправить некоторые изменения владельца файла в случае отсутствия прав root, — эту команду можно и не выполнять, так как современные версии make-kpkg сами вызывают ее, но лишней она не будет. Остальное более-менее понятно.

Кроме того, если ты планируешь часто менять что-то в ядре, то для ускорения пересборки можно использовать ccache, для чего в командной строке перед вызовом fakeroot необходимо поставить CC=ccache.

Сборка ядра с использованием make-kpkg
Сборка ядра с использованием make-kpkg

Просмотр пакетов по дате установки (Ubuntu)

Допустим, тебе понадобилось просмотреть, когда какие пакеты ты устанавливал. В блогах для этого советуют заглянуть в /var/log/apt/history.log. Конечно, это наиболее удобный путь, но, в зависимости от настроек logrotate, старые логи могут быть недоступны. В этом случае придется пошаманить — поскольку в базе данных dpkg по каким-то причинам нет даты установки того или иного пакета. Зато она есть в файловой системе! Итак:

# find /var/lib/dpkg/info -name "*.list" -exec stat -c $'%nt%y' {} ; | sed -e 's,/var/lib/dpkg/info/,,' -e 's,.listt,t,' | sort > ./dpkglist.dates # dpkg --get-selections | sed -ne '/tinstall$/{s/[[:space:]].*//;p}' | sort > ./dpkglist.selections # join -1 1 -2 1 -t $'t' ./dpkglist.selections ./dpkglist.dates > ./dpkglist.selectiondates # cat dpkglist.selectiondates | awk '{print $2" "$3" "$4" " $1}' | sort > ./dpkglist.selectiondates_bydate

Разберемся, что это за трехэтажные команды.

Первая (следом за sudo) команда ищет все файлы с расширением list в каталоге /var/lib/dpkg/info, в котором находится информация о пакетах, смотрит время их создания, соответствующее времени установки пакета, удаляет из получившихся строк ненужную информацию и, сортируя, направляет в файл dpkglist.dates.

Вторая команда просматривает установленные пакеты, удаляет ненужную информацию и, опять же сортируя, направляет в файл dpkglist.selections. Третья команда объединяет два файла в один. Для чего это надо, ведь в первом файле все есть? Для удаления из конечного результата некоторых лишних строк, чтобы результат соответствовал текущему положению дел в системе.

Четвертая команда необязательна, но желательна — она перетасовывает поля файла, делая первыми поля даты и времени, и сортирует по дате установки. К слову, в системах на основе RPM это будет выглядеть гораздо проще:

# rpm -qa --last | tac | less

В пояснении нуждается разве что команда tac — она инвертирует порядок строк, поскольку первая команда выводит пакеты в порядке, обратном порядку их установки.

Сортировка пакетов по дате установки в Ubuntu
Сортировка пакетов по дате установки в Ubuntu
Последние пять установленных пакетов в Scientific Linux
Последние пять установленных пакетов в Scientific Linux

Ограничение процессорного времени для процесса

В блогах для этого рекомендуют применять команду (re)nice. Например, следующая команда запустит поиск с минимальным приоритетом (напомню, что чем больше значение, тем приоритет ниже, отрицательные же значения может присваивать только процесс, запущенный с root-привилегиями, либо процесс с установленным capability CAP_SYS_NICE):

$ nice -n 19 find ./ -name *.odt -print

Но у этой команды есть один недостаток: она принимает на вход некие абстрактные «приоритеты». А это не всегда удобно, в процентах от процессорного времени в большинстве случаев гораздо удобнее. В современных дистрибутивах Linux имеется утилита cpulimit, которая позволяет ограничивать именно на основе процессорного времени. Установим ее:

$ sudo apt-get install cpulimit

Применение этой команды довольно просто — но для пользователей без прав root доступно только ограничение уже запущенного процесса. Например, для команды find это будет выглядеть примерно так:

$ cpulimit -p `pidof find` -l 30

Замечу, что эта команда действует для каждого процессора, то есть если у тебя четыре ядра, то максимальная величина будет не 100, а 400.

Ограничиваем ресурсы find с помощью cpulimit
Ограничиваем ресурсы find с помощью cpulimit

Метод работы программы довольно оригинален: она не использует всякие нововведения наподобие cgroups, вместо этого она мониторит загрузку процессора для конкретного процесса и время от времени посылает ему сигналы SIGSTOP и SIGCONT.

Если говорить об ограничениях пользователя, нельзя не упомянуть файл /etc/security/limits.conf, который позволяет много чего ограничивать. Для его использования необходимо включить модуль pam_limits.

Ограничивать можно, например:

  • размер файла;
  • размер дампа памяти процесса;
  • количество одновременно открытых файлов;
  • количество процессов.

Существует два вида ограничения — жесткое (hard) и мягкое (soft). Жесткое задается суперпользователем и не может быть снято обычным пользователем, мягкое же может задаваться обычным пользователем с помощью команды ulimit и не может превышать жесткое. Синтаксис файла limits.conf:

<домен> <тип> <ограничение> <величина>

где <домен> — субъект ограничения (может быть пользователем, группой, диапазоном UID или GID); <тип> — тип ограничения, мягкое или жесткое; <ограничение> — собственно ограничение и есть, например, для размера файла это будет fsize; <величина> — числовое значение данного ограничения — как правило, для объема данных оно указывается в килобайтах.

Удаление битых симлинков

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

rm-dead-links  #!/bin/bash  if `file $1 | grep -q "broken symbolic link"`; then rm -i $1 fi

Применяя его к файлам с помощью команды find:

# find / -type l -exec ls -l --color {} ; -exec ./rm_dead_links {} ;

На самом деле можно сделать гораздо проще:

# find -L / -type l -not -path '/proc' -exec rm -i {} ;

Опция -L предписывает следовать симлинкам, а в сочетании с -type l ищет битые симлинки — они никуда не следуют, поэтому тип у них остается ссылкой. В каталоге /proc их искать смысла нет, так что этот путь исключен из поиска.

Проксирование трафика

Стоит только заглянуть в любой блог, и там обязательно найдется совет о том, какой же выбрать socks5-прокси. И количество решений про различные прокси можно сравнить с длиной рулона туалетной бумаги. Они не нужны! У нас есть инструмент универсальнее и безопаснее, который умеет создавать шифрованные туннели, — SSH.

Создать скрипт и запустить его на сервере проще простого:

#!/bin/bash  IP=10.1.106.55  while true do ssh -CTNv -D $IP:3128 localhost sleep 1 done

На клиенте остается прописать socks5-прокси: <IP-сервера>:3128.

Конфигурирование туннеля SSH
Конфигурирование туннеля SSH

Готово, мы инкапсулируем socks5 в SSH-туннель! Осталось только разобраться, что означают отдельные ключи. Опция ‘-C’ разрешает компрессию передаваемых данных через gzip, ‘-T’ выключает привязку к TTY-псевдотерминалу, ключ ‘-N’ указывает на то, что нам надо просто передавать данные, а не выполнять команды, ‘-v’ добавляет деталей в stdout вывод от SSH, и, наконец, самая главная опция ‘-D’ организует программный проброс указанного порта в защищенный туннель.

Socks5 — это замечательно, но у меня есть рецепт и для прозрачного проксирования через удаленный хост, без установки на нем дополнительного ПО, — утилита sshuttle (читается как с-шатл). Преимущество подхода в том, что тебе не нужно заботиться о правилах на удаленном сервере, все настройки в файрвол и маршрутизацию удаленного сервера sshuttle внесет сама.

Получим свежую версию с GitHub:

$ git clone git://github.com/apenwarr/sshuttle

Запускаем, указывая в ключе ‘-r’ имяsshпользователя@адрес_сервера:

# ./sshuttle -r username@server 0.0.0.0/0 -vv

Теперь весь трафик нашей машины прозрачно проходит через указанный адрес сервера. По <Ctrl + C> sshuttle заботливо уберет произведенные удаленно изменения. Из дополнительных опций внимание заслуживает ключ ‘–dns’, позволяющий завернуть DNS-трафик в этот же канал.

VPN своими руками

Бывает необходимо быстро настроить VPN — в таких случаях советуют использовать OpenVPN. Но что, если устанавливать что-нибудь на сервер ты не хочешь или не можешь? В OpenSSH уже довольно давно есть поддержка туннелирования. Чтобы его включить, найди (или добавь сам на сервере) следующие строчки в файл конфигурации sshd:

/etc/ssh/sshd_config  # Снижает безопасность, но в данном случае необходимо. В качестве альтернативы вместо yes можешь использовать without-password для key-only-аутентификации root, но далее для упрощения будем считать, что аутентификация проходит по паролю PermitRootLogin yes PermitTunnel yes

Теперь на стороне клиента запускаем следующую команду:

# ssh -w 0:0 root@servername

Ключ ‘-w 0:0’ создает устройства tun0 как на клиенте, так и на сервере. Теперь данные интерфейсы нужно настроить, для чего на клиенте набираем команду:

# ifconfig tun0 10.0.0.2 pointopoint 10.0.0.1

а на сервере, соответственно, наоборот:

# ifconfig tun0 10.0.0.1 pointopoint 10.0.0.2

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

Если хочешь, чтобы адреса присваивались автоматически, — смотри в сторону vtun.

Автоматическое восстановление правил iptables после перезагрузки (Ubuntu)

Имеется множество советов, как это сделать. В основном все они заключаются в создании скриптов. Однако для большинства простых конфигураций гораздо проще поступить следующим образом. Во-первых, поставить пакет iptables-persistent:

$ sudo apt-get install iptables-persistent

Во-вторых, написать скрипт для удобства конфигурирования — со всеми переменными и прочими плюшками bash. Единственное условие — скрипт не должен содержать циклов и условных выражений; в iptables они не сохраняются. После отладки скрипта выполнить следующую команду:

$ sudo service iptables-persistent save

Однако этот метод не всегда подходит для сложных случаев, когда необходимы условные операторы. Я бы посоветовал использовать Shorewall (shorewall.net). Почему не использовать просто скрипт? Если проводить аналогию с языками программирования, то iptables — ассемблер, инструмент очень мощный, но для написания больших и сложных наборов правил малопригодный. Shorewall же — своего рода язык высокого уровня, заметно облегчающий написание сложных правил и объединяющий в себе брандмауэр, роутинг и контроль трафика, но при этом позволяющий в особо критичных случаях использовать «ассемблерные вставки» — прямые вызовы iptables.

Пример правил iptables
Пример правил iptables

Роман Ярыженко rommanio@yandex.ru

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    1 Комментарий
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии