Posterous theme by Cory Watilo

Filed under: Linux

Samba, AFP and OS X

Настраивал файлохранилище. В качестве эксперимента – добавил поддержку AFP. Поставить самбу – нетяжело, и особо вдаваться в детали я не стану. Все коробочное, кроме общей шары:

[storage]
  comment = General storage area
  path = /home/storage
  guest ok = yes
  browseable = yes
  create mask = 0666
  directory mask = 0777
  read only = no

Попробуйте на такую шару скопировать файл из-под винды. Правильно, права будут 0666. А теперь из-под линукса/мака. Права совсем не 0666, а скорее 0644 или 600. Кроме того, файл создастся от имени залогиненого пользователя. То есть пользователи не смогут удалить файлы оставленные им другими пользователями. Я долго копался, и благодаря Роману нашел решение:

[global]
  ...
  unix extensions = no
  ...

Это решает проблему с правами. Но чуть позже я вернул unix extensions и добавил в шару опцию

force user = nobody

Но на OS X 10.6.3 внезапно явилась проблема: при загрузке папки она ставит на нее расширенные аттрибуты. Ругается, и не дает загрузить файлы. Вручную же файлы именно вовнутри папки загружаются. Все это сопровождается сообщением “operation can’t be completed because you don’t have permission to access…” (раз, два). Решением стало добавление

[global]
  ...
  acl check permissions = no
  ...

С AFP в Ubuntu 10.04 все хорошо – пакет пересобирать не надо, он собран уже с шифрованой передачей пароля. Однако конфиг подровнять пришлось. В /etc/netatalk/afpd.conf в конце пишем:

- -transall -uamlist uams_dhx.so,uams_dhx2.so,uams_guest.so -nosavepassword

Кроме варианта по-умолчанию сюда добавлен uams_guest.so для доступа к анонимной свалке. Рядом в файле /etc/netatalk/AppleVolumes.default пишем:

~/              "Home Directory"                        options:usedots
/home/storage/  "Common storage" dperm:0777 fperm:0666  options:usedots

Как принудительно заставить писать от имени nobody в storage я не нашел, потому выставил соответствующие права. Опция usedots не дает преобразовывать точку в “:2e”.

Финальным шагом был анонс сервисов через бонжур при помощи avahi-daemon. В /etc/avahi/services/afpd.service:

<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">

<service-group>
    <name replace-wildcards="yes">%h</name>
    <service>
        <type>_afpovertcp._tcp</type>
        <port>548</port>
    </service>
    <service>
        <type>_device-info._tcp</type>
        <port>0</port>
        <txt-record>model=Xserve</txt-record>
    </service>
</service-group>

В /etc/avahi/services/samba.service:

<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">

<service-group>
    <name replace-wildcards="yes">%h</name>
    <service>
        <type>_smb._tcp</type>
        <port>139</port>
    </service>
</service-group>

Enjoy!

Plesk and virtual FTP users

В Plesk для каждого домена заводится FTP путем создания обычного системного юзеря. Дополнительный фтп можно сделать не иначе как через под-домен. Но иногда возникает необходимость дать ftp-доступ в под-папку домена.

Так как плеск использует proftpd, то конфигурация чертовски проста.

Создаем /etc/proftpd.authuserfile.

Правим /etc/proftpd.include и добавляем:

AuthUserFile /etc/proftpd.authuserfile

Правим /etc/proftpd.authuserfile и добавляем записсь вида:

username:crypted_pass:uid:gid:gekos:home:shell

Пример:

someacc:xhppo.NGU0Fjw:10065:2523::/var/www/vhosts/example.org/private/someacchome:/bin/false

crypted_pass можно получить вызвав

openssl passwd -crypt passwordhere

Или просто вызвав системный crypt.

Подсмотреть UID/GID можно в /etc/passwd. Нужен он для раздачи прав, чтобы владелец домена также мог править/удалять файлы, загруженные виртуальным пользователем.

UPD:

На cybercity упоминается утилита ftpasswd, при помощи которой легко генерируются записи:

ftpasswd --passwd --name {username} --file /etc/ftpd.passwd --uid {UID} --gid {GID} --home {HOME} --shell /bin/false

Monitoring apache with GOD

“Посчастливилось” мне заполучить VPS с сайтом на битриксе. Из-за Zend Optimizer (сорсы закриптованы) нет возможности установить APC. Вроде бы xcache умеет работать вместе с ZO, еще не проверял. Периодически апач съедает всю память, свап, и машинка умирает окончательно. Хуже то, что апач работает с mpm-prefork, то есть он порождает не потоки, а процессы. И при мониторинге виден родительский процесс, который занимает всего 13М памяти.

Вначале для рестарта апача в период дикого роста я пытался использовать monit, но результат был неадекватный – при указании memory > 90% он убивал его когда памяти была занята всего треть.

После monit я попробовал использовать god. Но он мониторит только один процесс, без его чайлдов.

Вроде бы есть проект bluepill, который идейно растет из god. Но примеры найти оказалось проблематично, да и в процессе решил таки остаться с god.

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

ps -e -o pmem,cmd | grep apache2 | grep -v grep | awk '{sum += $1;}END{print sum;}'

что сразу переродилось в

w.restart_if do |restart|
  restart.condition(:lambda) do |c|
    c.lambda = lambda{`ps -e -o pmem,cmd | grep apache2 | grep -v grep | awk '{sum += \$1;}END{print sum;}'`.to_i > 90}
  end
end

Итого конфиг для апача выглядит так:

God::Contacts::Email.delivery_method = :sendmail

God.contact(:email) do |c|
  c.name = 'maintainer'
  c.email = 'pager@sms.gate.isp'
end


God::Contacts::Email.format = lambda do |name, email, message, time, priority, category, host|
  <<-EOF
From: god
To: #{name} <#{email}>
Subject: Alert!
Date: #{Time.now.httpdate}
Message-Id: < #{rand(1000000000).to_s(36)}.#{$$}.#{self.message_settings[:from]}>

#{host} (#{priority}): #{message}
  EOF
end


%w{80}.each do |port|
  God.watch do |w|
    w.name = "apache2"
    w.pid_file = "/var/run/apache2.pid"
    w.interval = 10.seconds # default
    w.start = "/etc/init.d/apache2 start"
    w.stop = "/etc/init.d/apache2 stop"
    w.restart = "/etc/init.d/apache2 restart"
    w.start_grace = 10.seconds
    w.restart_grace = 20.seconds

    w.start_if do |start|
      start.condition(:process_running) do |c|
          c.interval = 5.seconds
          c.running = false
      end
    end
    w.restart_if do |restart|
      restart.condition(:lambda) do |c|
        c.lambda = lambda{`ps -e -o pmem,cmd | grep apache2 | grep -v grep | awk '{sum += \$1;}END{print sum;}'`.to_i > 90}
        c.notify = 'maintainer'
      end
    end
  end
end

LAMP through fcgid with suexec

Взглянем на Apache+mod_php. Плюсы:

  • настраивается максимально просто
  • интерпретатор стартует вместе с каждым форком апача

Минусы:

  • mpm_prefork далеко не самый быстрый
  • все работает под одним пользователем (да-да, можно накрутить mod_itk)

В попытках сделать секьюрно и по возможности быстро я решил скрутить apache (mpm_worker) + mod_fcgid + suexec. Сам по себе CGI очень небыстр за счет того, что при каждом запросе подымается интерпретатор. FastCGI быстрее, так как интерпретатор держится отдельным процессом. А mod_fcgid – модуль, бинарно совместимый с mod_fastcgi, с новой стратегией управления процессами.

Suexec в свою очередь позволяет выполнять CGI/FastCGI/SSI с указанными uid/gid. Да-да, в системе будут заводиться реальные пользователи.

Расстановкой прав можно добиться того, что даже взломав один сайт злоумышленник не сможет увидеть другие сайты.

Приступим.

apt-get install apache2-mpm-worker apache2-suexec ache2-threaded-dev libapache2-mod-fcgid php5-cgi

Теперь когда у нас все есть, создадим скелет для будущих площадок.

mkdir -p /root/web/skel
cd /root/web/skel
mkdir {cgi-bin,etc,logs,tmp,www}
chmod 770 tmp
chmod 751 {etc,logs,www}
cp /etc/php5/cgi/php.ini ./etc

Правим php.ini на предмет вывода ошибок и прочих мелких твиков.

Теперь сделаем враппер для самого обработчика (cgi-bin/php-cgi):

#!/bin/bash

cd $CGI_BIN_DIR
PHP_INI=../etc/php.ini

if [ ! -f $PHP_INI ]; then
    PHP_INI=/etc/php5/cgi/php.ini
fi

exec /usr/bin/php5-cgi -c $PHP_INI

И делаем

chown -R 755 cgi-bin
cd /root/web
touch {adduser,awstats,vhost}.skel
touch add_site.sh && chmod +x add_site.sh

adduser.skel:

DSHELL=/bin/false
DHOME=/var/www
GROUPHOMES=no
LETTERHOMES=no
SKEL=/root/web/skel
FIRST_SYSTEM_UID=2000
LAST_SYSTEM_UID=2999
FIRST_SYSTEM_GID=2000
LAST_SYSTEM_GID=2999
FIRST_UID=2000
LAST_UID=29999
FIRST_GID=2000
LAST_GID=2999
USERGROUPS=yes
USERS_GID=100
DIR_MODE=0751
SETGID_HOME=no
QUOTAUSER=""
SKEL_IGNORE_REGEX="dpkg-(old|new|dist)"

awstats.skel:

LogFile="/var/www/#USER/logs/#SITE-access.log"
SiteDomain="#SITE"
HostAliases="localhost 127.0.0.1 REGEX[#SITE$]"
Include "/etc/awstats/awstats.conf.local"

vhost.skel:

<virtualhost *>
    ServerName #SITE
    ServerAlias www.#SITE
    DocumentRoot /var/www/#USER/www/#SITE/public_html

    SuexecUserGroup #USER #USER

    ScriptAlias /cgi-bin/ /var/www/#USER/cgi-bin/
    <directory /var/www/#USER/www/#SITE/public_html>
    Options -Indexes +ExecCGI
    AllowOverride All
    AddHandler fcgid-script .php
    FCGIWrapper /var/www/#USER/cgi-bin/php-cgi .php
    Order allow,deny
    Allow from all
    </directory>

    ErrorLog /var/www/#USER/logs/#SITE-error.log
    CustomLog /var/www/#USER/logs/#SITE-access.log combined

    SetEnv AWSTATS_FORCE_CONFIG #SITE
    <location /cgi-bin/awstats.pl >
    AuthUserFile /var/www/#USER/etc/awstats.passwd
    AuthName "Website stats for #SITE"
    AuthType Basic
    require valid-user
    </location>
</virtualhost>

add_site.sh:

#!/bin/bash

if [ -z $1 ] || [ -z $2 ]; then
    echo "Oops. Some param not given."
    exit 1
fi

# If no such user exists - add one right now
if [ ! -d /var/www/$2 ]; then
    adduser --conf ./adduser.skel --disabled-login --gecos '' $2 || exit 1
fi

# Buld generic folders
mkdir -p /var/www/$2/www/$1/public_html
chown -R $2:$2 /var/www/$2/www/$1

# Build generic vhost for apache
cat vhost.skel | sed "s/#USER/${2}/g;s/#SITE/${1}/g" > ${2}_${1}

# Activate vhost
a2ensite ${2}_${1}

# Build generic awstats config
cat awstats.skel | sed "s/#USER/${2}/g;s/#SITE/${1}/g" >> /etc/awstats/awstats.${1}.conf

echo "Restart apache..."
apache2ctl configtest && apache2ctl restart

Вот таким нехитрым образом можно добавить сайт:

cd /root/web
./add_site example.org web_example

В результате будет создан пользователь web_example и у него сайт – example.org.

Tip

Иногда надо позволить скрипту выполяться боее 30 секунд. Думаете для этого достаточно подправить php.ini? Нет, в таком случае fcgid отстрелит скрипт по достижении 40 секунд. Для этих случаев в конфиге vhost’а требуется задать значение IPCCommTimeout в секундах (например, 300). Есть баг – глобальное значение отчего-то не хочет применяться к vhost’у, потому надо указать его непосредственно в vhost’е.

В общем и целом – конфиги показал, идею донес (надеюсь). Enjoy.

Exim mail forwarding

Стоял у меня MTA Exim4 для отправки почты. И вдруг на этот сервер перенесли MX-запись одного домена (например, example.org), и он вынужден был что-то делать с почтой. Решено было перенаправить всю почту для этого домена на другой ящик на время разбирательств кто прав, а кто виноват.

Для этого в Ubuntu пришлось сделать следующие правки.

В /etc/exim4/update-exim4.conf.conf в dc_other_hostnames и dc_relay_domains был добавлен example.org.

А сам форвард выглядел так (/etc/exim4/conf.d/router/099_exim4-config_redirects):

forward:
    driver = redirect
    domains = example.org
    data = tmp_example.org@somemail.com

В теории должна была сработать запись вида

sender_redirect:
  driver = redirect
  data = ${lookup{$sender_address}lsearch{/etc/exim4/sender_redirects}}
  domains = example.org

И в файле /etc/exim4/sender_redirects были бы

someone@example.org: where.to@forward.com

Но почему-то этот вариант не сработал как ожидалось.

Возможно я допустил какие-то ошибки в конфигурировании, но задача выполнена и почта не потеряна.

PowerDNS - master and slave

В связи с переездом на новый сервер пришлось переносить и кучу сервисов, которые крутились на старом. Одним из них был DNS.

Настоятельно рекомендуется делать master и slave (primary и secondary) на разных машинах, дабы в случае отказа одного из них второй мог полноценно работать. Ну это в теории, на практике все несколько упрощается до одного сервера, который если ляжет – то DNS будет уже не столь важен.

Начал подымать master на OpenSuSE 11.1. Конфиг простой и незамысловатый:

#each slave should be put here (space separated) to allow zone details transfer
allow-axfr-ips=1.1.1.2
disable-axfr=no
daemon=yes
guardian=yes
default-ttl=3600
soa-refresh-default=3600
lazy-recursion=yes
local-address=0.0.0.0
master=yes
recursor=127.0.0.1:5300
launch=gmysql
gmysql-host=localhost
gmysql-port=3306
gmysql-dbname=powerdns
gmysql-user=powerdns
gmysql-password=powerdns
gmysql-socket=/var/run/mysql/mysql.sock

и рекурсор:

chroot=/var/lib/pdns
local-address=127.0.0.1
local-port=5300
setgid=pdns
setuid=pdns

Базу для него создавал из PowerDNS on Rails, хотя можно ограничиться и той, что в документации.

И напоролся на первый занятный баг – со включенным режимом master он взлетает и долбит базу одинаковыми запросами (пытается получить все записи). На стоящей рядом ubuntu с той же версией такого не наблюдается. Долго пытался отловить что, где и почему – и решил пересобрать из сорсов. Когда обнаружилась нехватка boost я решил проверить, а нет ли готового свеженького пакета с собраным powerdns? Таки есть – надо было всего лишь добавить в списки репо вот этот:

http://download.opensuse.org/repositories/server:/dns/openSUSE_11.1/

и была установлена версия pdns-2.9.22-1.1. Проблема с нагрузкой на БД полечилась, но появилась новая – с репликацией на slave.

В PowerDNS есть такое понятие как supermaster. В общем случае нужно прописывать зону на мастере и слейве. Когда слейв получит от мастера notify, он запросит у мастера записи из этой зоны. Но если сервер, от которого пришел notify, будет обнаружен в списке supermasters, и такой зоны на слейве не будет описано, она создастся автоматически. И потом в нее будут добавлены записи с мастера. Это приятно упрощает жизнь.

В табличке запись довольно простая – ip мастера, имя слейва (ns2.example.org), имя аккаунта (на работу никак не влияет – просто будет фигурировать в описании зоны; удобно для указания клиента, например).

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

pdns_control notify example.org

С первого раза не заработало потому, что в PowerDNS on Rails в имя поддомена по привычке вписал “@”, и потом получил записи вида “@.example.org” вместо “example.org” либо “@”. Прошелся простым апдейтом по базе и убрал этот баг.

PS: Хочу выразить благодарность Патрику Фею за его недавний пост, который помог постичь смысл supermaster'ов.

PPS: конфиг pdns для слейва мало чем отличается от мастера:

config-dir=/etc/powerdns
daemon=yes
disable-axfr=yes
guardian=yes
launch=gmysql
lazy-recursion=yes
local-address=0.0.0.0
local-port=53
module-dir=/usr/lib/powerdns
setgid=pdns
setuid=pdns
slave=yes
socket-dir=/var/run
version-string=powerdns
gmysql-host=localhost
gmysql-port=3306
gmysql-dbname=powerdns
gmysql-user=powerdns
gmysql-password=powerdns

Having fun with RRD and architecture

Переезжал на новый сервер, и наигрался вволю со всеми мониторингами и прочим. Была обнаружена неприятная особенность RRD: бд платформозависима. Пришлось на старом сервере делать дамп

for i in *.rrd; do rrdtool dump $i > $i.xml; done

тащить на новый (tar, scp либо nc) и там разворачивать:

for i in *.xml; do A=`echo $i|sed 's/\.xml//'`; rrdtool restore -f $i $A; done

Копирование ninja way

На стороне получателя

netcat -l -p 7000 | tar x

На стороне отправителя

tar cf - * | netcat otherhost 7000

Ссылки по теме:

OpenVZ on Ubuntu 8.10

Только-что закончил эксперименты с OpenVZ на Ubuntu 8.10 (intrepid). Успешно. Итак, задача: создать виртуальную (для начала одну) машину с Ubuntu 8.10, которая будет доступна в локальной сети. Хост-система - Ubuntu 8.10, выступает в роли роутера для локальной сети, имеет на себе DHCP-сервер. Настройки сети виртуальная машинка должна получать по DHCP, роутиться другим роутером (два провайдера). Задача осложняется тем, что из intrepid убрали поддержку виртуализации посредством OpenVZ и сделали упор на KVM. Так как имеем машинку на базе AMD Duron (900MHz) то приходится выкручиваться. Опыт, как говорится, бесценен. Пару слов о состоянии виртуализации в Ubuntu:
  • KVM. В 8.10 сделали упор на KVM, который требует аппаратной поддержки виртуализации процессором. В данном случае процессор устаревший, так что KVM отпадает.
  • VServer. Выглядит неплохо, но у меня не удалось при помощи make-kpkg собрать ядро (2.6.27-15, наиболее близкое к имеющемуся в 8.10 - 2.6.27-11).
  • OpenVZ. Неплохое решение, но ядро с поддержкой виртуализации было в 8.04, в 8.10 от него отказались в пользу KVM.
  • Xen. Не горел желанием использовать решения полной виртуализации, так как вируализировать оборудование мне не требовалось - это дополнительные накладные расходы. Вроде бы поддержка есть... но, как оказалось, лишь в качестве гостевой ОС (DomU - гостевая, Dom0 - хост-система). А сервером (Dom0) - увы. В 8.04 было ядро умеющее быть сервером.
  • VMWare Server. Также полная виртуализация, тяжеловесное решение. Но хорошо тем, что не требует хаков с ядром.
Итогом чтения доки стала установка VMWare Server, и обошлось без косяков. Но снес его через несколько часов. Во-первых, одновременно с VMWare Server нельзя пользоваться комплектом netatalk. Во-вторых, теперь у VMWare Server появилась вебморда. И все бы ничего, если б не ее тормознутость. Посмотрев список процессов - sun-jre, apache-tomcat. Не знаю у кого как, но на столь небыстрой машинке вебморда тормозила и лагала безбожно. Некогда был Remote Console, но я так и не смог его найти. Таким образом я пришел к OpenVZ. Для начала я прописал в /etc/apt/sources.list репозиторий от 8.04: [cc lang="text"] deb http://de.archive.ubuntu.com/ubuntu/ hardy main restricted universe multiverse deb http://de.archive.ubuntu.com/ubuntu/ hardy-updates main restricted universe multiverse deb http://de.archive.ubuntu.com/ubuntu/ hardy-backports main restricted universe multiverse [/cc] Далее - по учебнику: [cc lang="text"] apt-get install linux-openvz vzctl [/cc] Получил ядро linux-image-2.6.24-23-openvz и проверил, что пакет linux-restricted-modules-openvz потянул за собой linux-restricted-modules-common. Пользуясь aptitude установил версию 2.6.24.16-23.56. Так как сервер уже работал роутером, то изменений в /etc/sysctl.conf я не вносил - более-менее с рекомендациями мои значения совпали. Со странички шаблонов стянул ubuntu-8.10-x86.tar.gz: [cc lang="text"] cd /var/lib/vz/template/cache && wget http://download.openvz.org/template/precreated/ubuntu-8.10-x86.tar.gz [/cc] Затем создал виртуальный контейнер [cc lang="text"] vzctl create 101 --ostemplate ubuntu-8.10-x86 --config vps.basic [/cc] задал виртуальной машине hostname [cc lang="text"] vzctl set 101 --hostname gretchin --save [/cc] и добавил запуск этой VPS вместе с запуском OpenVZ (/etc/init.d/vz) [cc lang="text"] vzctl set 101 --onboot yes --save [/cc] Чудесно. На данный момент имеем виртуальную машину без сети. Для того чтоб она была видна в локальной сети нужно соорудить bridge. Для этого понадобится пакет bridge-utils: [cc lang="text"] apt-get install bridge-utils [/cc] Теперь подправил /etc/network/interfaces: [cc lang="text"] auto lo iface lo inet loopback #Inet iface auto eth0 iface eth0 inet dhcp #eth1 - LAN auto br0 iface br0 inet static address 192.168.1.1 netmask 255.255.255.0 bridge_ports eth1 [/cc] Заодно подправил интерфейс в /etc/default/dhcp3-server: [cc lang="bash"] INTERFACES="br0" [/cc] Затем применил настройки: [cc lang="text"] /etc/init.d/network restart [/cc] ...и лишился сети. Сам не понял что и как, но после ребута роутера и сидения перед его консолью все заработало самостоятельно. Хм. Добавил сетевой интерфейс в виртуальную машину: [cc lang="text"] vzctl set 101 --netif_add eth0 --save [/cc] В vzctl версии >3.0.22 можно указать еще и bridge, к которому присоединяться. Но в ubuntu 8.10 версия 3.0.22, и поэтому пришлось дописывать небольшой скрипт. А заодно исправить мелкий баг. Итак, в /etc/vz/conf/101.conf нужно дописать [cc lang="bash"] CONFIG_CUSTOMIZED="yes" VZHOSTBR="br0" [/cc] Теперь создадим скрипт /etc/vz/bin/vznetaddbr [cc lang="bash"] mkdir /etc/vz/bin touch /etc/vz/bin/vznetaddbr chmod 700 /etc/vz/bin/vznetaddbr [/cc] с таким содержимым [cc lang="bash"] #!/bin/bash # /etc/vz/bin/vznetaddbr # a script to add virtual network interfaces (veth-s) in a CT to a bridge on CT0 CONFIGFILE=/etc/vz/conf/$VEID.conf . $CONFIGFILE VZHOSTIF=`echo $NETIF |sed 's/^.*host_ifname=\(.*\),.*$/\1/g'` if [ ! -n "$VZHOSTIF" ]; then echo "According to $CONFIGFILE CT$VEID has no veth interface configured." exit 1 fi if [ ! -n "$VZHOSTBR" ]; then echo "According to $CONFIGFILE CT$VEID has no bridge interface configured." exit 1 fi echo "Adding interface $VZHOSTIF to bridge $VZHOSTBR on CT0 for CT$VEID" /sbin/ifconfig $VZHOSTIF 0 echo 1 > /proc/sys/net/ipv4/conf/$VZHOSTIF/proxy_arp echo 1 > /proc/sys/net/ipv4/conf/$VZHOSTIF/forwarding /usr/sbin/brctl addif $VZHOSTBR $VZHOSTIF exit 0 [/cc] и затем создадим /etc/vz/vznet.conf со следующим содержимым: [cc lang="bash"] #!/bin/bash EXTERNAL_SCRIPT="/etc/vz/bin/vznetaddbr" [/cc] Теперь про баг (устраненный в 3.0.23): в процессе старта при наличии vznet.conf вызывается скрипт /usr/sbin/vznetcfg. Так как в debian/ubuntu используется dash (/bin/sh), то там по чистой случайности нету команды source, а оттого ошибка появляется на строке 20: [cc lang="bash"] [ -f "$VZNETCFG" ] && source "$VZNETCFG" [/cc] Решение - заменить на [cc lang="bash"] [ -f "$VZNETCFG" ] && ."$VZNETCFG" [/cc] Заменить можно через sed (I'm loving it!): [cc lang="bash"] cp -p /usr/sbin/vznetcfg /usr/sbin/vznetcfg.orig sed -i 's/source "$VZNETCFG"/\. "$VZNETCFG"/' /usr/sbin/vznetcfg [/cc] Соответственно теперь выполним [cc lang="bash"] vzctl stop 101 vzctl start 101 brctl show [/cc] В конце мы должны увидеть нечто похожее на veth101.0: [cc lang="text"] bridge name bridge id STP enabled interfaces br0 8000.00024494a7ac no eth1 veth101.0 [/cc] Если все удалось - то можно смело идти в виртуальную машину [cc lang="bash"] vzctl enter 101 [/cc] и делать все чего хочется. По поводу роутинга через другого провайдера: подсмотрев в ifconfig -a внутри виртуальной машинки мак-адрес сетевого интерфейса достаточно в /etc/dhcp3/dhcpd.conf на хост-машине (я же говорил - она еще и роутер) прописать что-то вроде: [cc lang="text"] host gretchin { hardware ethernet 00:18:51:80:8A:D9; fixed-address 192.168.1.101; server-name "gretchin"; option routers 192.168.1.2; } [/cc] где 192.168.1.2 - второй роутер в той же сети. По материалам:
  1. help.ubuntu.com
  2. ubuntuforums.org
  3. Howtoforge
  4. forum.openvz.org
  5. Gentoo Wiki
  6. OpenVZ-Users-Guide.pdf
PS: не забывайте про GNU Screen. Это избавляет от многих проблем, особенно при конфигурации сети.

LVM Rocks

Давно заметил что в Ubuntu (server edition) во время инсталляции начали предлагать использовать LVM. Но я все не решался поставить production на него. Затем пообщался со теми кто его использовал, почитал доку - и последний год стал его использовать, так как постиг скрытую в нем мощь :) Допустим, у нас есть простенький бюджетный сервер. Мы развернули новое приложение, и его база стала расти весьма стремительно. Итого - база, веб-файлы и система живут на одном физическом диске. Был куплен диск WD Razor, и на него перенесли базу. Нагрузка диска (iostat -x -m 1) составила 1-2%. Решено перенести туда же и веб-файлы, однако решение это пришло лишь через пару дней. Так что получилось наглядно продемонстрировать возможности LVM.

Part1. Creating...

Когда поставили разор на нем создали один раздел - LVM: [cc lang="bash"] # fdisk -l Disk /dev/sdb: 74.3 GB, 74355769344 bytes 255 heads, 63 sectors/track, 9039 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/sdb1 1 9039 72605736 8e Linux LVM [/cc] Пару слов об организации LVM. Уровень 1: volume group (vg). Это наивысший уровень абстракции, объединяющий в себе logical volumes и physical volumes. Уровень 2: physical volume (pv). Это некое блочное устройство, способное хранить данные (HDD, RAID, ...) Уровень 3: logical volume (lv). Это эквивалент раздела на жестком диске. Таким образом в группу добавляются физические тома (pv), и потом во всем этом пространстве свободного места создаются разделы (lv), на которых уже создается файловая система. Итак, сначала создавался pv: [cc lang="bash"] pvcreate /dev/sdb1 [/cc] Затем vg: [cc lang="bash"] vgcreate sys_vg /dev/sdb1 [/cc] И затем на все свободное место указанного pv (/dev/sdb1) создали lv с именем var_lib_mysql: [cc lang="bash"] lvcreate -L 100%PVS -nvar_lib_mysql sys_vg /dev/sdb1 [/cc] Дело за малым: [cc lang="bash"] mkreiserfs /dev/mapper/sys_vg-var_lib_mysql mount /dev/mapper/sys_vg-var_lib_mysql /mnt /etc/init.d/mysql stop mv /var/lib/mysql/* /mnt/ mv /var/lib/mysql/.* /mnt/ umount /mnt mount /dev/mapper/sys_vg-var_lib_mysql /var/lib/mysql chown -R mysql:mysql /var/lib/mysql /etc/init.d/mysql start [/cc] Вот собственно и почти все. Последний штрих - прописать монтирование раздела в fstab, дабы это происходило при загрузке автоматом. Можно скучно сделать это через blkid, увидеть там нужный UUID (например, f6946e54-c7d6-4688-8fac-05dcb1bf9973), скопировать его, открыть /etc/fstab и вставить туда строку вида: [cc lang="bash"] UUID=f6946e54-c7d6-4688-8fac-05dcb1bf9973 /var/lib/mysql reiserfs defaults 0 2 [/cc] а можно сделать так: [cc lang="bash"] printf "\nUUID=`blkid | grep sys_vg-var_lib_mysql | sed -r 's/.*UUID="([^"]*).*/\1/i'`\t/var/lib/mysql reiserfs defaults 0 2\n" >> /etc/fstab [/cc] Да, если сделать umount /var/lib/mysql && mount /var/lib/mysql до ребута - то /dev/disk/by-uuid/f6946e54-c7d6-4688-8fac-05dcb1bf9973 (или какой там получится) там еще не будет. Для того чтоб появился до ребута надо перезапустить udev: [cc lang="bash"] /etc/init.d/udev restart [/cc]

Part2. Resizing...

Как я говорил раньше, с опозданием пришла мысль о том, что неплохо бы вынести и статические файлы на этот же винт. И сделать это совсем просто! Для этого от того lv что был создан раньше (и именуется var_lib_mysql) откусим немного места. Сначала остановим все службы (говорят, reiserfs увеличивается/уменьшается без проблем налету, но я этого пока не пробовал на себе): [cc lang="bash"] /etc/init.d/mysql stop umount /var/lib/mysql [/cc] Затем уменьшим файловую систему, а затем и lv на 20ГБ: [cc lang="bash"] resize_reiserfs -s-20G /dev/mapper/sys_vg-var_lib_mysql lvreduce -L-20G /dev/mapper/sys_vg-var_lib_mysql [/cc] На всякий случай я предпочел проверить фс на ошибки (а вдруг!): [cc lang="bash"] reiserfsck /dev/mapper/sys_vg-var_lib_mysql [/cc] Ну и возвращаем обратно MySQL: [cc lang="bash"] mount /var/lib/mysql /etc/init.d/mysql start [/cc] Теперь создадим lv для веб-файлов, и так как их намного меньше 20ГБ, я решил оставить 5ГБ про запас, никому их не присвоив. Потом можно будет налету добавить туда где закончится место. [cc lang="bash"] lvcreate -L 15G -nvar_www sys_vg mkreiserfs /dev/mapper/sys_vg-var_www [/cc] Далее - перенос файлов: [cc lang="bash"] /etc/init.d/nginx stop /etc/init.d/apache2 stop mount /dev/mapper/sys_vg-var_www /mnt mv /var/www/* /mnt/ mv /var/www/.* /mnt/ umount /mnt mount /dev/mapper/sys_vg-var_www /var/www /etc/init.d/apache2 start /etc/init.d/nginx start [/cc] И опять не забываем про fstab: [cc lang="bash"] printf "\nUUID=`blkid | grep sys_vg-var_www | sed -r 's/.*UUID="([^"]*).*/\1/i'`\t/var/lib/mysql reiserfs defaults 0 2\n" >> /etc/fstab [/cc] По материалам:
  1. http://wiki.linuxquestions.org/wiki/LVM#example
  2. http://www.tldp.org/HOWTO/LVM-HOWTO/reducelv.html
PS: после изменения размера мог измениться UUID для lv var_lib_mysql, хотя я и не уверен в этом. Но проверить не помешает. PS2: если работаете удаленно - не забывайте про screen. PS3: писалось по памяти, так что могут быть некоторые неточности. Тупой копипаст без вовлечения мыслительного процесса чреват боком. Я предупредил ;)

git, gitosis, tailor, and bzr

git

До общения с Oleganza я не видел у git каких-либо ярких преимуществ перед bzr. И, наверное, не увидел бы, если бы не Олег. Первое что было самым необычным - git полностью децентрализованый. И привычный svn-like workflow тут не работает. Надо было привыкать к branch-style. Второе - это то, что команды с теми же названиями что и у svn имеют другой смысл. Жутко понравилось что ветки git держит в себе, то есть не надо плодить по 3-4 папки для разных фичей.

gitosis

Также я задумался о совместной работе. github - это, конечно, хорошо, но у меня уже есть багтракер понимающий git. Отчего бы не попробовать git на своем сервере? Был заведен юзерь git без пароля [cc lang="bash"] sudo adduser --shell /bin/sh --gecos 'git version control' --disabled-password --home /home/git git [/cc] поставлен gitosis [cc lang="bash"] sudo apt-get install gitosis [/cc] сделаны небольшие правки его сорсов (дело в том, что по умолчанию gitosis создает репо с маской 0750, мне же надо было с 0755 - чтоб www-data мог его читать): правим [cc lang="bash"] /var/lib/python-support/python2.5/gitosis-0.2-py2.5.egg/gitosis/repository.py [/cc] и заменяем 0750 на 0755. Подробнее описано в блоге разработчика gitosis.

tailor and bzr

Когда все взлетело с git, решил попробовать отконвертировать при помощи утилиты tailor старые репо из bzr в git. Конфиг получился примерно такой (замечания приветствуются): [cc lang="ini"] [DEFAULT] verbose = True [project] target = git:target start-revision = INITIAL root-directory = /home/dm/tmp/bzr2git state-file = tailor.state source = bzr:source subdir = bzr2git.tmp [bzr:source] repository = /home/dm/bzr/BZR_PROJECT_HERE [git:target] repository = /home/dm/tmp/bzr2git/tmp/.git [/cc] и после запуска [cc lang="bash"] tailor bzr2git.conf [/cc] в /home/dm/tmp/bzr2git/bzr2git.tmp появляется вполне живой git-репозитарий. Его я уже стягивал к себе и вливал в gitosis от себя.

Примечание

git не отслеживает пустые папки, и в процессе конвертации теряются "log", "tmp", etc... Чтоб отслеживал достаточно [cc lang="bash"] mkdir log touch log/.empty [/cc]