Случайны выбор дневника Раскрыть/свернуть полный список возможностей
";
echo "";

if($enableUseiconv==1)
$line[0]=iconv("CP1251","UTF-8",urldecode($line[0]));

echo "";

И вместо последней строки вставить следующее:



//Проверяем, HTTPS ресурс в строке или нет (по наличию символа ':')
//Если символа нет, значит это HTTP ресурс, сразу отображаем на страницу
$dv=strpos($line[0], ":") ;
if ($dv < 1) {
echo "
";
} else
{

// Если же все таки символ ':' присутствует, следовательно это HTTPS ресурс, значит
// производим "колдовские" действия...

// Отделяем IP адрес от всей строки, т.е. все символы до ':'
$str1=strpos($line[0], ":");
$row1=substr($line[0], 0, $str1);
$ipaddress = ltrim($ipaddress);
$ipaddress = $row1;

// Производим резолв IP адреса с помощью скрипта gethost.sh
$hostname = shell_exec('/usr/bin/gethost.sh ' . $ipaddress);

// Выводим в таблицу полученную информацию об IP адресе
echo "
";
}


Код писАлся на скорую руку, но вполне работает. А срабатывает он, когда открывается просмотр отчета «Трафик пользователей IP адреса», лично мне по большей части необходим только такой отчет. При желании, можно добавить подобный код на любые другие отчеты.



Сам код довольно прост: сначала определяется, какой в данный момент ресурс выводится на экран в таблицу: HTTP или HTTPS, и если это HTTPS (определяется по наличию символа ":"), то отделяем IP адрес от порта, передаем IP адрес в скрипт gethost.sh, получаем вывод скрипта в виде информации об IP адресе, и выводим на экран.



Были мысли заносить в БД сразу нужные данные, но резолв вышеуказанным образом на этапе заполнения БД приводит к длительному процессу распития кофейных напитков, поэтому я от него отказался.



Ах да, чуть не забыл, скрипт должен быть на том же сервере, где расположен парсер Screen Squid. Ну это так, к слову.



Если есть предложения по улучшению, доработке, переделке данного скрипта, буду рад выслушать.
Original source: habrahabr.ru.

https://habrahabr.ru/post/307686/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best



Найдено 796 сообщений
Cообщения с меткой

bash - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Доработка парсера логов Squid для корректного просмотра посещенных HTTPS ресурсов

Суббота, 14 Августа 2016 г. 02:47 (ссылка)

Всем привет! Я получал, и получаю множество писем от людей с вопросами по Squid, который работает на основе моей статьи. Наиболее часто возникает вопрос про просмотр логов Squid каким-либо парсером. Проблема в том, что версия Squid 3.5.8 с настроенным прозрачным проксированием HTTPS логирует посещаемые HTTPS ресурсы не в виде доменных имен, а в виде IP адресов с портами (прим. 164.16.43.56:443). Соответственно, при просмотре статистики посещений вместо человеческой информации проскакивают эти самые IP адреса. Собирать статистику с такими данными довольно сложно. Я связывался с разработчиками Squid по этому поводу, но внятного ответа так и не получил. Единственное, что я выяснил, нормальное логирование работает в более новых версиях Squid, но на них прозрачное проксирование лично у меня так и не заработало должным образом. Поэтому возник вопрос о том, как сделать резолв IP адресов в самом парсере логов.



Лично я пользуюсь парсером Screen Squid, и именно в нем я решил попробовать сделать нужные изменения. Так как мне подобный резолв бывает нужен просто при работе в терминале с Bash, я решил весь процесс резолва сделать в виде скрипта на Bash, а в Screen Squid уже средствами PHP его использовать, когда это будет нужно.



Итак, для всего задуманного нам нужны:




  1. собственно, сам парсер Screen Squid (инструкцию по его установке печатать не буду, все есть на оф.сайте).

  2. Grep

  3. Sed

  4. Nslookup

  5. Whois

  6. Прямые руки



Сам Bash-скрипт представляет из себя следующее:



#!/bin/bash

#Единственный входной параметр - ip адрес, запишем его в переменную
IP="$1";

#Пробуем резолвить IP адрес с помощью NSLOOKUP, применяя GREP и SED
#для извлечение из результата нужной нам информации
hostname=$(nslookup $IP | grep -m 1 "name" | sed 's|.*= ||'|sed -r 's/ Auth.+//' | sed 's/^[ \t]*//;s/[ \t]*$//' );

#Если попытка резолва с помощью NSLOOKUP не удалась,
#то узнаем информацию об IP адресе с помощью whois, опять же
#применяя GREP и SED для извлечение из результата нужной нам информации
if [[ "$hostname" == '' ]]; then
hostname=$(whois $IP | grep -m 1 "owner\|OrgName\|orgname\|NetName\|netname\|origin" | sed 's|.*: ||'|sed -r 's/. Auth.+//' | sed 's/^[ \t]*//;s/[ \t]*$//')
fi

#Выводим на экран результат резолва
echo "$hostname"

exit 0;


В принципе, он уже откомментирован, описывать здесь особенно и нечего. Мы получаем информацию об IP адресе сначала с помощью Nslookup, параллельно фильтруя вывод команды с помощью grep и sed, чтобы исключить ненужную информацию. Дабы не писать кучу строк, были использованы возможности grep по включению нескольких условий для выборки (символы "\|"). Сохраняйте скрипт в любом удобном месте, назначайте ему права на выполнение. Допустим, он сохранен в /usr/bin под именем gethost.sh.



Скрипт можно использовать просто из терминала:



gethost.sh ip_address 


Далее расскажу, как этот скрипт прикрутить к Screen Squid. Допустим, что установлен он в /var/www/html. В этой папке будет подпапка reports, где находится файл reports.php. Вот именно в нем необходимо сделать изменения. В этом файле необходимо найти строки:



$result=mysql_query($queryOneIpaddressTraffic) or die (mysql_error());
$numrow=1;
$totalmb=0;
while ($line = mysql_fetch_array($result,MYSQL_NUM)) {
echo "
".$numrow." ".$line[0]."
".$line[0]."".$hostname."
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Сопроцессы: -что, -как, -зачем?

Пятница, 12 Августа 2016 г. 20:38 (ссылка)

Многие пользователи Bash знают о существании со-процессов, появившихся в 4-й версии Bash'a. Несколько меньшее количество знает о том, что сопроцессы в Bash не какая-то новая фича, а древний функционал KornShell'a появившийся ещё в реализации ksh88 в 1988 году. Ещё меньшее количество пользователей shell'ов умеющих сопроцессить знают синтаксис и помнят как это делать.

Вероятно, я отношусь к четвёртой группе — знающих о сопроцессах, периодически умеющих ими пользоваться но так и не понимающих «зачем?». Я говорю «периодически», так как иногда я освежаю в голове их синтаксис, но к тому моменту, когда мне кажется что «вот тот случай когда можно применить co-proc» я уже напрочь забываю о том как это делать.

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

В заголовке статьи у нас 3 вопроса. Пойдём по порядку.



Что?

Что же такое co-process?

Со-процессинг — это одновременное выполнение двух процедур, одна из которых считывает вывод другой. Для его реализации необходимо предварительно запустить фоновый процесс выполняющий функционал канала. При запуске фонового процесса его stdin и stdout присваиваются каналам связанными с пользовательскими процессами. Соответственно, один канал для записи, второй для чтения.

Пояснять это проще на примерах, поэтому сразу перейдём ко второму вопросу.



Как?

Реализации со-процессов в шеллах разнятся. Я остановлюсь на 3-х известных мне реализациях в ksh, zsh и bash. Рассмотрим их в хронологическом порядке.

Хоть это и не имеет прямого отношения к вопросам статьи, отмечу, что все нижеприведённые примеры сделаны на

$ uname -opr
FreeBSD 10.1-STABLE amd64


Ksh

$ `echo $0` --version
version sh (AT&T Research) 93u+ 2012-08-01


Синтаксис

cmd |&


кажется мне наиболее логичным. Здесь для выполнения команды cmd в фоновом режиме мы используем специальную операцию |&, выражающую соответвенно:

— "&" — фоновый процесс;

— "|" — каналы.



Запускаем фоновый процесс:

$ tr -u a b |&
[2] 6053


Убедимся, что он жив:

$  ps afx | grep [6]053
6053 4 IN 0:00.00 tr -u a b


Теперь мы можем общаться с нашим фоновым процессом.

Пишем:

$ print -p abrakadabra1
$ print -p abrakadabra2
$ print -p abrakadabra3


и читаем:

$ read -p var; echo $var
bbrbkbdbbrb1
$ read -p var; echo $var
bbrbkbdbbrb2
$ read -p var; echo $var
bbrbkbdbbrb3


или так:

$ print abrakadabra1 >&p
$ print abrakadabra2 >&p
$ print abrakadabra3 >&p
$ while read -p var; do echo $var; done
bbrbkbdbbrb1
bbrbkbdbbrb2
bbrbkbdbbrb3


Закрываем «конец» трубы для записи:

$ exec 3>&p 3>&-


и для чтения:

$ exec 3<&p 3<&-



Zsh

$ `echo $0` --version
zsh 5.2 (amd64-portbld-freebsd10.1)


Синтаксис со-процессов в zsh не слишком отличается от ksh, что не удивительно, т.к. в его man'е сказано «zsh most closely resembles ksh».

Основным отличием является использование ключевого слова coproc вместо оператора |&. В остальном всё очень похоже:

$ coproc tr -u a b
[1] 22810
$ print -p abrakadabra1
$ print abrakadabra2 >&p
$ print -p abrakadabra3
$ read -ep
bbrbkbdbbrb1
$ while read -p var; do echo $var; done
bbrbkbdbbrb2
bbrbkbdbbrb3


Для закрытия каналов чтения/записи можно воспользоваться идиомой exit:

$ coproc exit
[1] 23240
$
[2] - done tr -u a b
$
[1] + done exit


При этом запустился новый фоновый процесс, который тут же завершился.

Это ещё одно отличие от ksh — мы можем не закрывать существующий сопроцесс, а сразу инициировать новый:

$ coproc tr -u a b
[1] 24981
$ print -p aaaaa
$ read -ep
bbbbb
$ coproc tr -u a d
[2] 24982
$
[1] - done tr -u a b
$ print -p aaaaa
$ read -ep
ddddd
$


в ksh мы бы просто получили:

$ tr -u a b |&
[1] 25072
$ tr -u a d |&
ksh93: process already exists


Несмотря на эту возможность рекомендуется, всегда явно убивать фоновый процесс, особенно, при использовании «setopt NO_HUP».

Здесь же стоит упомянуть, что иногда мы можем получить неожиданные результаты связанные с буферизацией вывода, именно поэтому в приведённых выше примерах мы используем tr с опцией -u.

$ man tr | col | grep "\-u"
-u Guarantee that any output is unbuffered.


Хоть это и не имеет оношения исключительно к со-процессам продемонстрирую это поведение примером:

$ coproc tr a b
[1] 26257
$ print -p a
$ read -ep
^C
$
[1] + broken pipe tr a b


Буфер не полон и мы ничего не получаем из нашей трубы. Заполним его «доверху»:

$ coproc tr a b
[1] 26140
$ for ((a=1; a <= 4096 ; a++)) do print -p 'a'; done
$ read -ep
b


Разумеется, если данное поведение нас не устраивает, его можно изменить, например используя stdbuf

$ coproc stdbuf -oL -i0 tr a b
[1] 30001
$ print -p a
$ read -ep
b


Bash

$ `echo $0` --version

GNU bash, version 4.3.42(1)-release (amd64-portbld-freebsd10.1)



Для запуска со-процесса в bash также как и в zsh используется зарезервированное слово coproc, но в отличии от рассмотренных выше shell'ов доступ к сопроцессу осуществляется не с помощью >&p и <&p, а посредством массива $COPROC:

${COPROC[0]} для записи;

${COPROC[1]} для чтения.

Соответственно, процедура записи/чтения будет выглядеть примерно так:

$  coproc tr -u a b
[1] 30131
$ echo abrakadabra1 >&${COPROC[1]}
$ echo abrakadabra2 >&${COPROC[1]}
$ echo abrakadabra3 >&${COPROC[1]}
$ while read -u ${COPROC[0]}; do printf "%s\n" "$REPLY"; done
bbrbkbdbbrb1
bbrbkbdbbrb2
bbrbkbdbbrb3


, а закрытие дескрипторов:

$ exec {COPROC[1]}>&-
$ cat <&"${COPROC[0]}"
[1]+ Done coproc COPROC tr -u a b


Если имя COPROC по каким-то причинам не устраивает можно указать свое:

$ coproc MYNAME (tr -u a b)
[1] 30528
$ echo abrakadabra1 >&${MYNAME[1]}
$ read -u ${MYNAME[0]} ; echo $REPLY
bbrbkbdbbrb1
$ exec {MYNAME[1]}>&- ; cat <&"${MYNAME[0]}"
[1]+ Done coproc MYNAME ( tr -u a b )


Зачем?

Прежде чем попытаться ответить зачем нужны сопроцессы подумаем можно ли реализовать их функционал в shell'ах которые не имеют coproc «из коробки». Например в таком:

$ man sh | col -b | grep -A 4 DESCRIPTION
DESCRIPTION
The sh utility is the standard command interpreter for the system. The
current version of sh is close to the IEEE Std 1003.1 (``POSIX.1'') spec-
ification for the shell. It only supports features designated by POSIX,
plus a few Berkeley extensions.
$ man sh | col -b | grep -A 1 -B 3 AUTHORS
This version of sh was rewritten in 1989 under the BSD license after the
Bourne shell from AT&T System V Release 4 UNIX.

AUTHORS
This version of sh was originally written by Kenneth Almquist.


Именованные каналы никто не отменял:

$ mkfifo in out
$ tr -u a b out &
$ exec 3> in 4< out
$ echo abrakadabra1 >&3
$ echo abrakadabra2 >&3
$ echo abrakadabra3 >&3
$ read var <&4 ; echo $var
bbrbkbdbbrb1
$ read var <&4 ; echo $var
bbrbkbdbbrb2
$ read var <&4 ; echo $var
bbrbkbdbbrb3


Пожалуй, с некоторой натяжкой, можно сказать, что это же реализуемо с помощью псевдотерминалов, но развивать эту тему не стану.



Ну и зачем же нужны сопроцессы? Я процитирую выдержку из перевода статьи Mitch Frazier:

Пока я не могу придумать никаких <...> задач для со-процессов, по крайней мере не являющихся надуманными.


И в действительности я лишь один раз смог с относительной пользой применить со-процессы в своих скриптах. Задумка была реализовать некий «persistent connect» для доступа к MySQL.

Выглядело это примерно так:

$ coproc stdbuf -oL -i0 mysql -pPASS
[1] 19743
$ printf '%s;\n' 'select NOW()' >&${COPROC[1]}
$ while read -u ${COPROC[0]}; do printf "%s\n" "$REPLY"; done
NOW()
2016-04-06 13:29:57


В остальном все мои попытки использовать coproc действительно были надуманными.



Спасибо
Хочется поблагодарить Bart Schaefer, St'ephane Chazelas, Mitch Frazier чьи комментарии, письма и статьи помогли в написании статьи.


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/307562/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Через тернии к сборке

Вторник, 09 Августа 2016 г. 10:31 (ссылка)

Привет, дорогие читатели. Я – разработчик в компании “RTL Service”, в которой мои обязанности по разработке продукта пересекаются с обязанностями DevOps. Конкретнее – я создаю и поддерживаю инфраструктуру сборки и первичного тестирования наших продуктов еще до их попадания в отдел тестирования.



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

В качестве сервера CI (непрерывной интеграции) у нас используется Hudson, можете кидать в меня тапками, но мы руководствуемся принципом «Работает — не трогай».

В дальнейшем есть планы попробовать TeamCity либо Jenkins.



Общая информация о задачах и группах на нашем CI сервере.



Все задачи по сборкам у нас разбиты на 5 больших групп:

https://habrahabr.ru/post/307398/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Открытие API для работы с услугами от российского лоукост-хостера (часть 1)

Пятница, 15 Июля 2016 г. 12:17 (ссылка)

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







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

С начала лета мы получили еще несколько подобных вопросов и поняли, что нельзя оставлять их без ответов. И сегодня я расскажу как работать с API биллинга нашей компании для заказа виртуальных серверов любого количества.





В качестве биллинговой системы мы используем продукт российской компании ИСПсистем — BILLmanager4. Для всех продуктов ИСПсистем есть открытое API и оно описано в большей или меньшей степени на их официальном сайте документации ispdoc.com

Работать с API можно как из командной строки, обращаясь непосредственно к интерпретатору mgrctl, так и через адресную строку браузера (или любое другое приложение, которое будет отправлять запрос на веб-сервер: curl, wget и т.п)

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



Сам запрос для заказа виртуального сервера, к примеру, KVM Ferrum на один месяц с автоматическим помесячным продлением, шаблоном ОС Centos-6.7-x86_64-minimal без использования лицензии ISPmanager, будет выглядеть так:



https://billing.ihor.ru/billmgr?authinfo=:&addon_1101=20&addon_1103=1&addon_1104=1&addon_1110=1&addon_1791=4&enum_1112=21&enum_1106=25&agree=on&domain=test-for.habr&ostempl= Centos-6.7-x86_64-minimal&period=1210&price=1100&autoprolong=1210&payfrom=neworder&func=vds.order.7&sok=ok




Теперь попробуем расшифровать все это нагромождение переменных и цифр.

Сам запрос можно разделить условно на две части: это URL биллинга и передаваемые параметры запроса биллингу.

Сами параметры можно распределить следующим образом:



Описание параметров




  • Авторизация — authinfo



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




  • Тарифный план — price



Каждому тарифному плану соответствует свой идентфикатор в биллинге, берется из таблицы «Тарифные планы».




  • Параметры тарифного плана – addon_



К параметрами тарифного плана относятся параметры виртуального сервера, его ресурсы. Каждый параметр тарифного плана имеет свой идентификатор и свое значение по умолчанию, которое соответствует размеру диска, количеству ядер процессора и оперативной памяти, а так же IPv6- и IPv4-адресам.




  • Дополнительные услуги – enum_



В дополнительные услуги входят DNS-серверы и использование лицензии ISPmananger.





(параметры по умолчанию для KVM Ferrum)




  • Период заказа — period

  • Автопродление – autoprolong



Идентификатор периода заказа и автопродления для каждой из услуг абсолютно одинаковы.




  • Доменное имя сервера – domain



Доменное имя должно быть уникальным. Иначе появится ошибка

Ошибка: The domain is already in use. Specify a different domain name.

При массовом добавлении виртуальных серверов, рекомендую использовать формат +<порядковый номер>.




  • Шаблон ОС – ostempl



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




  • Параметры оплаты – payfrom



В примере я привел значение параметра оплаты — neworder, что соответствует отдельному заказу с оплатой для каждого сервера. payfrom=neworder.




  • Оплата заказа – func



Так как весь заказ виртуального сервера состоит из 7 шагов, то в API, что не особо очевидно на первый взгляд, следует указывать не только саму функцию vds.order, но и номер последнего шага — 7. Таким образом полное значение этого пункта выглядит так: func=vds.order.7




  • Подтверждение пользовательского соглашения – agree



При заказе любой из услуг мы предлагаем ознакомиться с пользовательским соглашением и принять его (тогда заказ уходит на активацию) или не принять его (тогда заказ отменяется). В API этот пункт так же обязателен: agree=on.





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



Чтобы не загромождать текст большими таблицами со всеми тарифными планами, я приведу только ту часть, которая поможет разобраться, как была составлена строка для заказа виртуального сервера с тарифным планом KVM Ferrum. А так же два других младших тарифных плана SSD и OVZ



Тарифные планы








































price period / autoprolong
Тариф ID 1 мес. 3 мес. 6 мес. 1 год
KVM Ferrum 1100 1210 1213 1214 1211
SSD Ferrum 1033 1180 1183 1184 1181
OVZ Ferrum 2061 1758 1761 1762 1759




Параметры тарифного плана

















































addon_ enum_
Тариф / Значение Диск ОЗУ CPU IPv4 IPv6 NS ISPmgr
KVM Ferrum 1101

/ 20

1103

/ 1

1104

/ 1

1110

/ 1

1791

/ 4

1112

/ 21

1106

/ (1/25)

SSD Ferrum 1034

/ 20

1037

/ 1

1043

/ 1

1036

/ 1

1404

/ 4

1045

/ 21

1039

/ (1/25)

OVZ Ferrum 2062

/ 20

2065

/ 1

2071

/ 1

2064

/ 1

2074

/ 4

2073

/ 21

2067

/ (1/25)



Список шаблонов




  • FreeBSD-11-amd64-minimal

  • Centos-6.7-x86_64-minimal

  • Debian-7-x86_64-minimal

  • Debian-8-x86_64-ispconfig

  • Ubuntu-16.04-x86_64-minimal

  • CentOS-7-x86_64-ispmgr5



Если запрос составлен корректно и заявка на активацию новой услуги принята, Вы получите в ответ что-то типа этого:








Ниже в качестве бонуса прикладываю несколько скриптов для заказа произвольного количества виртуальных серверов для консоли Linux и Windows.

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



Пример на BASH

#/bin/bash
#
# Данные для авторизации
USER=user
PASS=password

# Заказать 10 виртуальных серверов
for i in {1..10}
do
/usr/bin/curl https://billing.ihor.ru/billmgr?authinfo=$USER:$PASS&addon_1101=20&addon_1103=1&addon_1104=1&addon_1110=1&addon_1791=4&enum_1112=21&enum_1106=25&agree=on&domain=$USER-$i.ru&ostempl= Centos-6.7-x86_64-minimal&period=1210&price=1100&autoprolong=1210&payfrom=neworder&func=vds.order.7&sok=ok"
done




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



Пример на PowerShell, файл curl.exe должен находиться в той же директории, откуда выполняется скрипт



USER=user
PASS=password

for ($i=1; $i -lt 10; $i++) {
.\curl.exe https://billing.ihor.ru/billmgr?authinfo=$USER:$PASS&addon_1101=20&addon_1103=1&addon_1104=1&addon_1110=1&addon_1791=4&enum_1112=21&enum_1106=25&agree=on&domain=$USER-$i.ru&ostempl= Centos-6.7-x86_64-minimal&period=1210&price=1100&autoprolong=1210&payfrom=neworder&func=vds.order.7&sok=ok"
}

Original source: habrahabr.ru.

https://habrahabr.ru/post/305716/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Запуск cron внутри Docker-контейнера

Вторник, 12 Июля 2016 г. 14:12 (ссылка)



Так уж вышло, что запуск cron в Docker-контейнере — дело весьма специфическое, если не сказать сложное. В сети полно решений и идей на эту тему. Вот один из самых популярных (и простых) способов запуска:

cron -f


Но такое решение (и большинство других тоже) обладает рядом недостатков, которые сходу обойти достаточно сложно:


  • неудобство просмотра логов (команда docker logs не работает)

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

  • невозможно нормально (gracefully) остановить контейнер командой docker stop (в конце концов в контейнер прилетает SIGKILL)

  • контейнер останавливается с ненулевым кодом ошибки





Logs



Проблему просмотра логов с использованием стандартных средств Docker устранить сравнительно легко. Для этого достаточно принять решение о том, в какой файл будут писать свои логи cron-задания. Предположим, что это /var/log/cron.log:

* * * * * www-data task.sh >> /var/log/cron.log 2>&1



Запуская после этого контейнер при помощи команды:

cron && tail -F /var/log/cron.log


мы всегда сможем видеть результаты выполнения заданий при помощи «docker logs».



Аналогичного эффекта можно добиться воспользовавшись перенаправлением /var/log/cron.log в стандартный вывод контейнера:

ln -sf /dev/stdout /var/log/cron.log


Если cron-задания пишут логи в разные файлы, то, скорее всего, предпочтительнее будет вариант с использованием tail, который может «следить» за несколькими логами одновременно:

cron && tail -F /var/log/task1.log /var/log/task2.log




Environment variables



Изучая информацию на тему назначения переменных окружения для задач cron, выяснил, что последний может использовать так называемые подключаемые модули аутентификации (PAM). Что на первый взгляд является не относящимся к сабжу теме фактом. Но у PAM есть возможность определять и переопределять любые переменные окружения для служб, которые его (точнее их, модули аутентификации) используют, в том числе и для cron. Вся настройка производится в файле /etc/security/pam_env.conf (в случае Debian/Ubuntu). То есть любая переменная, описанная в этом файле, автоматически попадает в Environment всех cron-заданий.



Но есть одна проблема, точнее даже две. Синтаксис файла (его описание) при первом взгляде может ввести в ступор обескуражить. Вторая проблема — это как при запуске контейнера перенести переменные окружения внутрь pam_env.conf.



Опытные Docker-пользователи насчет второй проблемы наверняка сразу скажут, что можно воспользоваться лайфхаком под названием docker-entrypoint.sh и будут правы. Суть этого лайфхака заключается в написании специального скрипта, запускаемого в момент старта контейнера, и являющегося входной точкой для параметров, перечисленных в CMD или переданных в командной строке. Скрипт можно прописать внутри Dockerfile, например, так:

ENTRYPOINT ["/docker-entrypoint.sh"]


А его код при этом должен быть написан специальным образом:

docker-entrypoint.sh
#!/usr/bin/env bash
set -e

# код переноса переменных окружения в /etc/security/pam_env.conf

exec "$@"




Вернемся к переносу переменных окружения немного позже, а пока остановимся на синтаксисе файла pam_env.conf. При описании любой переменной в этом файле значение можно указать c помощью двух директив: DEFAULT и OVERRIDE. Первая позволяет указать значение переменной по умолчанию (если та вообще не определена в текущем окружении), а вторая позволяет значение переменной переопределить (если значение этой переменной в текущем окружении есть). Помимо этих двух кейсов, в файле в качестве примера описаны более сложные кейсы, но нас по большому счету интересует только DEFAULT. Итого, чтобы определить значение для какой-нибудь переменной окружения, которая затем будет использовать в cron, можно воспользоваться таким примером:

VAR DEFAULT="value"


Обратите внимание на то, что value в данном случае не должно содержать названий переменных (например, $VAR), потому как контекст файла выполняется внутри целевого Environment, где указанные переменные отсутствуют (либо имеют другое значение).



Но можно поступить еще проще (и такой способ почему-то не описан в примерах pam_env.conf). Если вас устраивает, что переменная в целевом Environment будут иметь указанное значение, независимо от того, определена она уже в этом окружении или нет, то вместо вышеупомянутой строки можно записать просто:

VAR="value"


Тут следует предупредить о том, что $PWD, $USER и $PATH вы не сможете заменить для cron-заданий при любом желании, потому как cron назначает значения этих переменных исходя из своих собственных убеждений. Можно, конечно, воспользоваться различными хаками, среди которых есть и рабочие, но это уже на ваше усмотрение.



Ну и наконец, если нужно перенести все текущие переменные в окружение cron-заданий, то в этом случае можно использовать такой скрипт:

docker-entrypoint.sh
#!/usr/bin/env bash
set -e

# переносим значения переменных из текущего окружения
env | while read -r LINE; do # читаем результат команды 'env' построчно
# делим строку на две части, используя в качестве разделителя "=" (см. IFS)
IFS="=" read VAR VAL <<< ${LINE}
# удаляем все предыдущие упоминания о переменной, игнорируя код возврата
sed --in-place "/^${VAR}/d" /etc/security/pam_env.conf || true
# добавляем определение новой переменной в конец файла
echo "${VAR} DEFAULT=\"${VAL}\"" >> /etc/security/pam_env.conf
done

exec "$@"




Поместив скрипт «print_env» в папку /etc/cron.d внутри образа и запустив контейнер (см. Dockerfile), мы сможем убедиться в работоспособности этого решения:

print_env
* * * * * www-data env >> /var/log/cron.log 2>&1




Dockerfile
FROM debian:jessie

RUN apt-get clean && apt-get update && apt-get install -y rsyslog

RUN rm -rf /var/lib/apt/lists/*

RUN touch /var/log/cron.log \
&& chown www-data:www-data /var/log/cron.log

COPY docker-entrypoint.sh /

COPY print_env /etc/cron.d

ENTRYPOINT ["/docker-entrypoint.sh"]

CMD ["/bin/bash", "-c", "cron && tail -f /var/log/cron.log"]




запуск контейнера
docker build --tag cron_test .
docker run --detach --name cron --env "CUSTOM_ENV=custom_value" cron_test
docker logs -f cron # нужно подождать минуту






Graceful shutdown



Говоря о причине невозможности нормального завершения описанного контейнера с cron, следует упомянуть о способе общения демона Docker с запущенной внутри него службой. Любая такая служба (процесс) запускается с PID=1, и только с этим PID Docker умеет работать. То есть каждый раз, когда Docker посылает управляющий сигнал в контейнер, он адресует его процессу с PID=1. В случае с «docker stop» это SIGTERM и, если процесс продолжает работу, через 10 секунд SIGKILL. Так как для запуска используется "/bin/bash -c" (в случае с «CMD cron && tail -f /var/log/cron.log» Docker все равно использует "/bin/bash -c", просто неявно), то PID=1 получает процесс /bin/bash, а cron и tail уже получают другие PID, предугадать значения которых не представляется возможным по очевидным причинам.



Вот и выходит, что когда мы выполняем команду «docker stop cron» SIGTERM получает процесс "/bin/bash -с", а он в этом режиме игнорирует любой полученный сигнал (кроме SIGKILL, разумеется).



Первая мысль в этом случае обычно — надо как-то «кильнуть» процесс tail. Ну это сделать достаточно легко:

docker exec cron killall -HUP tail


Круто, контейнер тут же прекращает работу. Правда насчет graceful тут есть некоторые сомнения. Да и код ошибки по прежнему отличен от нуля. В общем, я не смог продвинуться в решении проблемы, следуя этим путем.



Кстати, запуск контейнера при помощи команды cron -f также не дает нужного результата, cron в этом случае просто отказывается реагировать на какие-либо сигналы.



True graceful shutdown with zero exit code



Остается только одно — написать отдельный скрипт запуска демона cron, умеющий при этом правильно реагировать на управляющие сигналы. Относительно легко, даже если раньше на bash'е писать не приходилось, можно найти информацию о том, что в нем есть возможность запрограммировать обработку сигналов (при помощи команды trap). Вот как, к примеру, мог бы выглядеть такой скрипт:

start-cron
#!/usr/bin/env bash

# перенаправляем /var/log/cron.log в стандартный вывод
ln -sf /dev/stdout /var/log/cron.log

# запускаем syslog и cron
service rsyslog start
service cron start

# ловим SIGINT или SIGTERM и выходим
trap "service cron stop; service rsyslog stop; exit" SIGINT SIGTERM




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

# запускаем в фоне процесс "tail -f" и ждем его завершения
tail -f /dev/null & wait $!


Или, если cron-задания пишут логи в разные файлы:

# запускаем в фоне процесс "tail -F" и ждем его завершения
tail -F /var/log/task1.log /var/log/task2.log & wait $!




Заключение



В итоге получилось эффективное решение для запуска cron внутри Docker-контейнера, обходящее ограничения первого и соблюдающее правила второго, с возможностью нормальной остановки и перезапуска контейнера.



В конце привожу полные листинги Dockerfile и start-cron, которыми я пользуюсь сейчас.

start-cron
#!/usr/bin/env bash

# переносим значения переменных из текущего окружения
env | while read -r LINE; do # читаем результат команды 'env' построчно
# делим строку на две части, используя в качестве разделителя "=" (см. IFS)
IFS="=" read VAR VAL <<< ${LINE}
# удаляем все предыдущие упоминания о переменной, игнорируя код возврата
sed --in-place "/^${VAR}/d" /etc/security/pam_env.conf || true
# добавляем определение новой переменной в конец файла
echo "${VAR} DEFAULT=\"${VAL}\"" >> /etc/security/pam_env.conf
done

# запускаем syslog и cron
service rsyslog start
service cron start

# ловим SIGINT или SIGTERM и выходим
trap "service cron stop; service rsyslog stop; exit" SIGINT SIGTERM

# запускаем в фоне процесс "tail -f /dev/null" и ждем его завершения
tail -f /dev/null & wait $!




Dockerfile
FROM debian:jessie

RUN apt-get clean && apt-get update && apt-get install -y rsyslog

RUN rm -rf /var/lib/apt/lists/*

RUN touch /var/log/cron.log \
&& chown www-data:www-data /var/log/cron.log \
&& ln -sf /dev/stdout /var/log/cron.log

COPY start-cron /usr/sbin

COPY cron.d /etc

CMD start-cron



Original source: habrahabr.ru.

https://habrahabr.ru/post/305364/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

VIM: зачем, если есть IDE, и как?

Пятница, 17 Июня 2016 г. 18:13 (ссылка)

Сегодня вышел текст о том, как человек перешёл с Sublime на VIM. В комментариях, как обычно это бывает, появились сообщения в духе "Зачем мне тратить время на Vim, если есть IDE, где всё работает?" (люди даже статьи на эти темы пишут). Хотел внести свои пять копеек, но объём написанного плавно перевёл текст из разряда "комментарий" в разряд небольшой статьи.



В целом, всё, что ниже — это вкусовщина, конечно. Нравится вам ваша IDE (или ваш текущий инструмент), да и пожалуйста. Используйте для текущих задач то, чем вы владеете лучше всего, это аксиома эффективной работы. Но если у вас вдруг появилось немного времени на повышение вашей эффективности в целом, то попробую вас заинтересовать именно Vim'ом, сравнивая его с некой обобщенной IDE.





Зачем?



На мой взгляд минусы любой IDE в сравнении с VIM (или, наоборот, преимущества VIM) следующие:




  • IDE значительно тяжелее VIM (даже с плагинами); отсюда очевидный минус, что для IDE — нужна достаточно мощная рабочая станция.

  • IDE обычно поддерживает небольшое число языков/платформ. Vim же единообразно поддерживает всё на свете. В Vim я пишу на Ruby/Rails, Python (или так), C, OpenCL (+PyOpenCL), CUDA (+PyCUDA), bash, Go, XML, YAML, HTML, Markdown, Textile, CSS, .ini, Sage, Magma, GAP (последние 3 — системы компьютерной алгебры), LaTex, а также редактирую специфические конфиги некоторых программ (типа X, mutt и т.п.) и редактирую почту. Конфиги и почта — это специфический пример, но, что касается языков программирования и разметки, то вам понадобится осваивать несколько IDE со своими особенностями, горячими клавишами и т.п. только потому, что IDE обычно имеет узкий круг поддерживаемых технологий. Vim (как и Emacs) умеет почти всё, и вам не надо заново привыкать к инструменту. Кроме того, создателю плагина надо сосредоточиться только на том, чтобы хорошо сделать поддержку специфических для ЯП вещей, а всё остальное Vim уже умеет. Как следствие, при переходе от одной технологии к другой (условно, сегодня пишете на Ruby, завтра на Python, а потом обратно), вы не лишитесь привычных базовых вещей, как это могло быть при смене IDE, т.к. останетесь в Vim.

  • Vim, как следствие из предыдущего, поддерживает вещи, которые никто другой не поддерживает: попробуйте найдите IDE для Magma. А для Vim всё есть. Объясняется это тем, что для редких вещей создавать IDE неоправданно, а написать базовый плагин для Vim не так сложно.

  • Vim может работать в режиме только консоль. Иными словами с Vim ваш компьютер может быть тонким клиентом. Конкретно в моём случае есть 10-ти летний Full HD ноутбук IBM'овский. Ясно, что его уже на нормальное использование как рабочей станции для программирования не хватает ну никак: тесты на нём будут идти вечность, а упомянутые IDE будут ощутимо тормозить. В тоже время есть доступ по ssh к мощному серверу, на котором в результате и ведётся разработка: гоняются тесты, работает редактор и т.п. Кроме того, связка vim + tmux + ssh — это постоянно открытая рабочая сессия. Начал работать на одной машине (к примеру, на работе), отлогинился не закрывая редактора и т.п., продолжил из дома с ноутбука — чрезвычайно удобно. А в моём случае, так ещё и для некоторых задач основное вычислительное оборудование (несколько GPU) физически воткнуто в сервер, т.е. помимо удобства, описанного выше, быть тонким клиентом ещё и необходимость. Попробуйте-ка проделать всё это в своей IDE!

  • Сама идеология Vim — очень мощная штука в сравнении с классической IDE. Есть книга Practical Vim: Edit Text at the Speed of Thought, её название ("редактируй текст на скорости мышления") прекрасно отражает результат, который вы получаете на выходе. К сожалению, в этом сложно убедить человека, который не попробовал (хотя некоторые пытаются). Суть в том, что эта идеология настолько заразна, что хочется перенести её с редактора на все сферы общения с компьютером: браузер, pdf-просмоторщик, почтовый клиент, музыкальный проигрыватель, файловый менеджер и многое другое.

  • С Vim вам не понадобится мышь, если вы конечно этого захотите (если не захотите, то Vim отлично интегрирован с мышью). Мне больно смотреть, как люди мучаются с тачпадами или носят с собой мышки, располагая их на разных поверхностях, при работе с ноутбуком.

  • Vim невероятно расширяем, любая ваша хотелка так и или иначе реализована или может быть реализована в Vim.

  • Ваша конфигурация для VIM вообще без труда переносится с машины на машину. Будет ли так просто с вашей IDE?



Если не хватило, вот ещё немного литературы на тему: раз, два, три.



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



Как?



Не стоит сразу ставить адские комбайны из чьих-то конфигов. Да, они выглядят круто, но там часто неинтуитивные горячие клавиши, много магии и лишнего. Пройдите vimtutor. Затем ставьте голый VIM (обычно он не такой голый, как кажется на первый взгляд) и работайте. Ну, ок, уговорили. Настройте в vimrc set nocompatible (убрать совместимость с VI) или поставьте sensible (супербазовый vimrc с настройками типа nocompatible), или работайте в neovim (новая в основном совместимая с VIM реализация VIM с человеческими настройками по-умолчанию).



В процессе работы у вас будут появляться хотелки. Как только появится хотелка, нужно:




  • Поискать, эта функция может быть среди базовых возможностей VIM (а чаще оно так и есть).

  • Если не нашли, то ищите соответствующий плагин и устанавливайте. Плагины советую ставить с помощью vim-plug.

  • Обязательно читайте документацию к установленному плагину (:help ). Она всегда хорошая и понятная!



Не ставьте много плагинов за раз. Возьмите за правило, не больше 2 плагинов в день, тогда вы всегда будете знать, что есть причина поломки, или наоборот, причина ускорения работы. Да и если сразу поставить 33 плагина, то у вас в голове возникнет каша, и вы не будете использовать ни один из этих 33 даже на половину.



P.S. На всякий случай дополню: я не утверждаю, что VIM круче IDE в любой ситуации. Я утверждаю, что существуют параметры, по которым VIM круче IDE, и поэтому имеет смысл обратить на него своё внимание. Эти параметры лично для меня существенны, и я их перечислил в параграфе "Зачем?".


Original source: habrahabr.ru.

https://habrahabr.ru/post/303554/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<bash - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda