Influx и Telegraf

Поначалу я планировал этот пост про InfluxDB. Дескать, вот так поставим, вот так настроим… Однако реальность больно тыкнула вилкой в глаз: поставил, запустил, зашел на influx:8086, установил пароль, завел организацию… и всё. Нет, реально всё. Больше там ничего не потребовалось делать.

А вот с телеграфом пришлось повозиться. Дело в том, что я возжелал с одной машины отправлять разные метрики в разные бакеты. Ну всякие там “загрузка процессора и памяти” в один, а “температура в доме” – в другой. Ну вот захотелось мне так.

Все просто. Для начала прямо в telegraf.conf добавим тег influxdb_database

# Global tags can be specified here in key="value" format.
[global_tags]
  # dc = "us-east-1" # will tag all metrics with dc=us-east-1
  # rack = "1a"
  ## Environment variables can be used as tags, and throughout the config file
  # user = "$USER"
  influxdb_database = "default"

Да, я очень неоригинален в этом плане. Теперь ко всему, что собирает telegraf по умолчанию добавляется тэг influxdb_database со значением default.

Теперь добавляем сборку данных с mqtt. Заполняем файл /etc/telegraf/telegraf.d/mqtt.conf

[[inputs.mqtt_consumer]]
  servers = ["tcp://127.0.0.1:1883"]

  ## Topics that will be subscribed to.
  topics = [
    "/devices/+/controls/temperature",
    "/devices/+/controls/battery",
    "/devices/+/controls/humidity",
    "/devices/+/controls/pressure",
    "/devices/+/controls/co2",
    "/devices/+/controls/MCU Temperature",
    "/devices/+/controls/CPU Temperature",
    "/devices/dark_room_power/controls/voltage",
    "/devices/dark_room_power/controls/power",
    "/devices/sleeping_room_power2/controls/voltage",
    "/devices/sleeping_room_power2/controls/power",
  ]

    data_format = "value"
    data_type = "float"

[inputs.mqtt_consumer.tags]
    influxdb_database = "mqtt"

Тут тоже все просто: указываем адрес сервера, указываем, на какие топики подписаться, их формат и последней строчкой меняем значение тега на mqtt. И теперь самая магия:

[[outputs.influxdb_v2]]
urls = ["http://influxdb.hlevnoe.lan:8086"]
token = "xf3w6SKIPSKIP7z1hPQ=="
organization = "hlevnoe"
bucket = "hlevnoe"
[outputs.influxdb_v2.tagpass]
influxdb_database = ["default"]

И сравните с вторым

[[outputs.influxdb_v2]]
urls = ["http://influxdb.hlevnoe.lan:8086"]
token = "xf3w6nSKIPSKIPvam7z1hPQ=="
organization = "hlevnoe"
bucket = "mqtt"
[outputs.influxdb_v2.tagpass]
influxdb_database = ["mqtt"]

Наверняка для матерых инфлюксоводов это покажестя легкой шуткой, но я честно потратил пару часов на раскуривание функционала tagpass. Больше, правда, на выяснение, как и куда его правильно прописать. В общем, теперь все с influxdb_database = default попадает в бакет hlevnoe, а mqtt в mqtt.

Запустив все это и убедившись в отсутствии ошибок, можно вернуться в influx. Там есть простенький data explorer, позволяющий потыкаться и порисовать графики. Даже можно простейшие дашборды собрать!

Вот, к примеру, график потребления электричества у морозильника.

Или график температуры у меня за окном

В общем, это далеко не графана, но по-быстрому позырить что к чему – можно.

Готовим котёнка

Умная мысля приходит обычно слишком поздно. Вот и тут, я много лет страдал при переходе с одного компа на другой. В каждой операционке своя терминалка, со своими дрючками и глючками. Я ходил, настраивал и пытался их подогнать одну к другой.. Хорошо еще, что хоть чуть-чуть шорткаты устаканились, а то вообще боль была…

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

  • Терминалка должна работать под Linux, MacOS и Windows (WSL)
  • Она должна работать одинаково. То есть один и тот же параметр в конфиге должен приводить к одним и тем же изменениям в поведении.
  • Терминалка должна уметь в truecolor.
  • Терминалка должна уметь в шрифтовые лигатуры.

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

Я не понимаю, чего сложного в подобной конвертации символов -> >> <> != ? Но, например, авторы gnome terminal не осилили подобного и отмазались, что не для всех языков это может работать. Ну сделали бы не для всех…

И, внезапно, всем моим хотелкам удовлетворила только одна терминалка – kitty. Если быть до конца честным, то нет, были и другие, но они не такие гламурные. Ставить котёнка можно 100500 способами, но я предпочел через пакетный менеджер.

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

font_family Fira Code
font_size 12
cursor_shape block
cursor_shape_unfocused hollow
shell_integration no-cursor
scrollback_lines 10000
sync_to_monitor yes
remember_window_size  yes
initial_window_width  800
initial_window_height 600
include theme.conf
tab_bar_style slant
update_check_interval 0
term xterm-256color
paste_actions quote-urls-at-prompt
background_opacity 1
confirm_os_window_close 0
map super+n new_os_window_with_cwd
map super+t new_tab_with_cwd
map super+w close_os_window
map super+c copy_to_clipboard
map super+v paste_from_clipboard

Последние строчки – это дань моей лени, чтобы новые окошки открывались как на макоси. Win+n и не надо пальцы ломать об Ctrl+Shift+n . Мелочь, а удобно. Ну и файлик theme.conf, честно спертый из интернета и имитирующий тему homebrew

# Theme ported from the Mac Terminal application.

background #000000
foreground #00ff00
cursor #23ff18
selection_background #083905
color0 #000000
color8 #666666
color1 #990000
color9 #e50000
color2 #00a600
color10 #00d900
color3 #999900
color11 #e5e500
color4 #0000b2
color12 #0000ff
color5 #b200b2
color13 #e500e5
color6 #00a6b2
color14 #00e5e5
color7 #bebebe
color15 #e5e5e5
selection_foreground #e5e5e5

И вот я уже почти неделю живу на двух операционках и с одним терминалом. Нормально …

Теперь операционко-специфичные штуки.

MacOS: надо в ENV переменные добавить KITTY_CONFIG_DIRECTORY=~/.config/kitty/ , иначе котенок хз где хранит конфиги. А так все в одинаковом месте. Чтобы сменить иконку, надо ее просто рядом с конфигом положить и обозвать kitty.app.png.

Linux: чтобы сменить иконку, надо сделать desktop файл, аналогичный нижеприведенному, и положить его в .local/share/applications/ . Главная боль – путь до иконки должен быть абсолютным.

[Desktop Entry]
Version=1.0
Type=Application
Name=kitty
GenericName=Terminal emulator
Comment=Fast, feature-rich, GPU based terminal
TryExec=kitty
StartupNotify=true
Exec=kitty
Icon=/home/kiltum/.config/kitty/kitty.app

Все 🙂

k8s namespace stuck in terminating stage

При тестировании всяких штук очень часто получается так, что при удалении неймспейсов они замерзают в Terminating. Могут на 5 минут, могут на сутки. Нашел рецепт

for ns in $(kubectl get ns --field-selector status.phase=Terminating -o jsonpath='{.items[*].metadata.name}')
do
  kubectl get ns $ns -ojson | jq '.spec.finalizers = []' | kubectl replace --raw "/api/v1/namespaces/$ns/finalize" -f -
done

for ns in $(kubectl get ns --field-selector status.phase=Terminating -o jsonpath='{.items[*].metadata.name}')
do
  kubectl get ns $ns -ojson | jq '.metadata.finalizers = []' | kubectl replace --raw "/api/v1/namespaces/$ns/finalize" -f -
done

Нашел тут https://stackoverflow.com/questions/65667846/namespace-stuck-as-terminating

Работает

Windows 10 ssh key

Как-то задалбывает под WSL2 постоянно вводить пароль к ssh ключам. Рецепт для ubuntu простой:

sudo apt-get install keychain
cat >> .bash_profile
/usr/bin/keychain -q --nogui $HOME/.ssh/id_rsa
source $HOME/.keychain/$HOSTNAME-sh

Для работы из-под винды надо скопировать ключи в виндовый домашний каталог и сказать следующую магию

Get-Service -Name ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add ~\.ssh\id_ed25519
ssh-add ~\.ssh\id_rsa

Ускоряем повторные соединения в ssh

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

Добавляем следующие строки в .ssh/config

Host *
    ControlMaster auto
    ControlPath ~/.ssh/master-%r@%h:%p.socket
    ControlPersist 30m

Путь может быть любым, но рекомендую выбирать только доступный вам. %r , %h, %p – это пользователь, хост и порт соответственно.

Загоняем маки спать

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

Решение очень простое:

  1. Спрашиваем у мака, сколько раз и когда он просыпается: pmset -g log|grep due
  2. Увидев, что он просыпается практически каждую минуту, запрещаем ему поддерживать соединения: sudo pmset -b tcpkeepalive 0

Плюс: мак теперь переживает ночь, теряя 1-2% заряда батареи

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

Возвращаем четкость маку

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

Если кратко, то в Apple победили менеджеры, которым надо “красиво”, а не “правильно”. В этом оплоте графики и накосячили! Хорошо, что вернуть назад все легко.

Settings-General-Снять галочку с Use font smoothing when available

и в Displays перещелкнуть радиокнопку Resolution на Scaled и выбрать пункт левее от Default. В общем, как на скриншотах выше.

Всё. Эффект офигительный: как будто у тебя снова тот самый первый мак с ретиновским дисплеем, где об засечку у букв можно порезаться!

Обновления. Боль и лечение.

“Обновление необходимо произвести в ночь с субботы на воскресение, в период минимальной нагрузки” – эта фраза знакома любому ИТшнику в любой стране. И точно так же им нелюбима. Что делать, что бы начать спать по ночам?

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

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

Что плохого?

  • Для начала, работа ночью не является самым желаемым временем работы у ИТ подразделения, что бы не говорили об этом мифы, предания и сказания. Мы такие же люди, мы точно так же любим спать.
  • Как ни странно, но повторюсь: ночью большинство людей спят. И если что-то пойдет не так, решение проблемы может застопориться до утра. Просто потому что дежурная смена не может сделать что-то этакое, что потребовалось. Как бы вы не стояли на голове, но часто в 4 утра нельзя сделать то, что после 9 утра делается за 10 минут. В результате время простоя растет, SLA нарушается, мотивация снижается.
  • И наконец, просто стоимость обновления. Ночные работы в воскресенье гораздо дороже тех же самых, но во вторник утром.

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

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

Во-первых, начать в конце-концов применять техники, позволяющие обновляться без остановки основного сервиса. Их много, они описаны очень хорошо и я не буду тут повторяться. Но начальные слова для гугления например CI/CD и canary deployment.

Главная задача: научиться обновляться быстро и однообразно. Поверьте, это больно только в самом начале. При первой попытке обновления “вне графика” вас ждет весь привычный вам набор проблем при обновлении: что-то забыли, где-то не та версия, какое-то место требует ручной работы и так далее. Но стоит руководству (хотя бы на уровне тимлидов) “упереться” и повторять, как каждое новое обновление будет происходить все быстрее и проще. Люди ленивые: одни напишут скрипты, другие немного изменят процесс или вообще добавят новый.

Мой опыт показывает, что переход от “ой, для обновления нам надо Н часов и работа М людей” до “новая версия появляется где надо через 10-15 минут и сама” необходимо примерно полгода. Это без надрывов и резких движений. И да, эти практики применимы к любым системам.

Вторая по важности задача это донести до всех в компании график обновления продакшн систем. Зачем? “Все мы люди, все мы человеки”. И даже если у вас от коммита в репозиторий до выкатки на прод проходит пять минут, то любой очень активный разработчик способен обеспечить увлекательное времяпрепровождение в самый не подходящий момент. Оно нам надо?

На мой взгляд, один из самых правильных графиков звучит примерно так:

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

Откуда пошли эти правила? Конечно, из опыта.

Почему никаких релизов перед праздниками и выходными? Потому что в 99% случаев такие даты – это просто кто-то из менеджеров где-то на каком-то совещании сказал что-то типа “ну, 1го числа систему переводим на новые рельсы”. А другой менеджер не имеет достаточно смелости сказать “Нафига обновлять систему 1 го мая? Там длинные праздники”. 1 процент я оставил, потому что где-то наверное “круглые” и “ровные” даты оправданы. Но лично я ни разу не встречал такого.

Почему большие обновления лучше всего планировать на утро вторника?

  • Все вопросы и проблемы, которые были в выходные, обычно уже решены в понедельник, либо понятны их последствия. И если что, легко отменить обновление вообще.
  • Люди вошли в рабочий ритм и все известные мне организации считают вторник рабочим днем.
  • Если что-то пойдет не так, у нас есть куча рабочих дней с очень малой вероятностью прерывания по личным делам.
  • И наконец, “опоздуны” и “потеряшки” могут протратить свои выходные из-за своей лени.

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

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

Но если выдержать первоначальный наплыв, то буквально через 3-4 недели все заметят сильные позитивные изменения. Предидущие три компании показали: резко снижается напряженность в коллективе и число подъемов ночью на починку сломанного. Остальное думаю у всех свое будет.

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

PS Photo by Andrew Neel on Unsplash

Свой gitlab на centos 7

Получив очередной счет от gitlab и github одновременно, я как-то задумался: а нафига я им плачу, когда я все это могу поднять на своем сервере? “Все это” – это кучку приватных git и простую ci/cd систему. Поставил и решил написать напоминалку, что бы в следующий раз не гуглить.

Процесс установки не вильно отличается от описанного на сайте, но есть несколько НО:

Во-первых, в centos7 nginx идет без поддержки passenger. Поэтому обновляем на версию из “пассажирской” репы.

curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo
yum-config-manager --enable cr
yum install -y passenger
rpm -e nginx-mod-http-perl --nodeps
yum update nginx

Во-вторых, нигде в мануале не указано, что gitlab требует nodejs для работы

yum install nodejs

И наконец, нигде не указано, что gitlab не работает без unicorn. Во всех мануалах написано, что если у вас внешний nginx, отрубите встроенный и unicorn. Так вот, этого делать нельзя, иначе получите неработающий gitlab-workhouse

Из других неочевидных тюнингов стал вынос порта unicorn с 8080 и изменение размера буферов у постгреса. Иначе на моем загруженном сервере он отказывался запускаться.

unicorn['port'] = 8088
postgresql['shared_buffers'] = "100MB"

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

Больше никаких отступлений от официального руководства.

gpg sign пароль не в консоли

Достаточно долгое время все мои коммиты во все репозитории подписываются моим PGP ключем. Но все время доставало то, что при коммите из всяких “гламурных” программ типа PyCharm gpg отказывался подписывать коммит, заставляя открывать консоль и вводить gpg commit там. Сегодня мне это надоело и я нашел вот такое вот простое решение:

brew install pinentry-mac
echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
killall gpg-agent

Если вы под линуксом, то замените brew на yum/apt/чтоеще

Что делать, если …

… что-то упало (как телеграм) или недоступно?

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

ssh -D 8123 -f -C -q -N user@server

Она поднимет socks5 прокси на localhost:8123

И наконец, указать в вашем любимом браузере, телеграмчике и остальном sock5 прокси.

Проверить работоспособность прокси можно командой

httping -x localhost:8123 -5 -g http://google.com
PING google.com:80 (/):
connected to google.com:80 (325 bytes), seq=0 time=636.58 ms 
connected to google.com:80 (325 bytes), seq=1 time=506.72 ms 
connected to google.com:80 (325 bytes), seq=2 time=657.07 ms 

Новый датацентр. Web

Что самое главное во всем этом? Правильно, наши интернетики с кисками и прочим. А значит, надо обеспечить заход снаружи внутрь по https

На данный момент я знаю всего 3 способа: с помощью nginx, apache и traefik. Apache как-то старо, traefik наоборот, слишком новомодно.

Предупреждаю сразу: использовать в докере nginx c nginx-gen и companion, как описано вот тут https://github.com/gilyes/docker-nginx-letsencrypt-sample – нельзя. Проблема простая: генератор тупо мешает ip бэкэндов как ему понравится.

Краткий план: ставим виртуалку

virt-builder centos-7.4 --arch amd64 -o nginx.ka12.co.img --size 20G --format qcow2 --hostname nginx.ka12.co --ssh-inject root:file:/root/multik.sshkey --root-password file:root_pass --copy-in ifcfg-eth0:/etc/sysconfig/network-scripts/ --copy-in resolv.conf:/etc
virt-install --name nginx.ka12.co --network bridge=virbr100 --memory 2048 --disk path=nginx.ka12.co.img --import --os-variant centos7.0 --graphics vnc,listen=172.16.100.1 --noautoconsole

бутстрапим ее

ansible-playbook -i inventory -l nginx* centos-bootstrap.yml

Добавляем в нее нужное

yum -y install freeipa-client && ipa-client-install --mkhomedir
yum install certbot python2-certbot-nginx nginx

И запускаем nginx

openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
systemctl start nginx

Берем из git (https://github.com/kiltum/newdc/tree/master/nginx) и кладем в /opt/www

Там два темплейта – первый для просто “сделай так, что бы nginx узнал о сайте”, а второй – уже готовый полноценный конфиг.

Ну а что делает скрипт new_site, думаю разберетесь сами. Только email правильный пропишите.

Запускаем ./new_site mail.ka12.co и вот результат:

После меняем конфиг сайта как нам надо и вуаля! Теперь по приходу емайла от letsencrypt заходим и обновляем все сразу.

Новый датацентр. Докер

Следующим большим шагом в постройке “датацентра” у меня будет разворачивание докера. Без него нынче никуда, да и удобный он, зараза.

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

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

Добываю/делаю правильный ifcfg фаил

cat ifcfg-eth0
TYPE="Ethernet"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="no"
NAME="eth0"
DEVICE="eth0"
ONBOOT="yes"
IPADDR="172.16.100.11"
PREFIX="24"
GATEWAY="172.16.100.1"
NM_CONTROLLED="no"

Добавляю пароль рута в файл root_pass и кладу рядом свой публичный ключ. Рядом же resolv.conf. Затем создаю образ диска

virt-builder centos-7.4 --arch amd64 -o docker1.ka12.co.img --size 80G --format qcow2 --hostname docker1.ka12.co --ssh-inject root:file:/root/multik.sshkey --root-password file:root_pass --copy-in ifcfg-eth0:/etc/sysconfig/network-scripts/ --copy-in resolv.conf:/etc

И запускаю машину с ним.

virt-install --name docker1.ka12.co --network bridge=virbr100 --memory 8096 --disk path=docker1.ka12.co.img --import --os-variant centos7.0 --graphics vnc,listen=172.16.100.1 --noautoconsole

Минута и виртуалка готова. Меняем ip адрес в конфиге+хостнейм и повторяем так еще два раза. Все, ноды для кластера готовы.

Добавляем их в инвентори и бутсрапим до приемлемого состояния.

ansible-playbook -i inventory -l docker* centos-bootstrap.yml

Делать еще один плейбук лень, поэтому просто прохожу по хостам с командой

yum -y install freeipa-client && ipa-client-install --mkhomedir

ansible-playbook -i inventory docker-install.yml

И на любой машине проверяю, что докер докерит

docker run hello-world

Так как у нас инфраструктура пока из одного хоста, заморачиваться распределенным хранилищем нет смысла от слова совсем. Поэтому просто раскидаю по хостам nfs

На хосте:

mkdir -p /opt/nfs
chmod 777 /opt/nfs
cat /etc/exports
/opt/nfs 172.16.0.0/16(rw,sync,no_root_squash,no_all_squash)
systemctl restart nfs-server

Проверяю, что увидит докер

# showmount -e 172.16.100.1
Export list for 172.16.100.1:
/opt/nfs 172.16.0.0/16

Создаю супер-каталог для volume

mkdir -p /opt/nfs/data
chmod 777 /opt/nfs/data

Теперь на докер-хосте создаю volume


docker volume create --driver local --opt type=nfs --opt o=addr=172.16.100.1,rw --opt device=:/opt/nfs/data --name data

И проверяю

[root@docker1 ~]# docker volume ls
DRIVER VOLUME NAME
local data
[root@docker1 ~]# docker volume inspect data
[
{
"CreatedAt": "2018-01-27T08:46:56-05:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/data/_data",
"Name": "data",
"Options": {
"device": ":/opt/nfs/data",
"o": "addr=172.16.100.1,rw",
"type": "nfs"
},
"Scope": "local"
}
]

Теперь проверяю, как с этим будут работать контейнеры

docker container run -ti -v data:/data alpine sh

Там в /data можно посоздавать файлики и вообще поиграться “как будто в реальной жизни”.

Новый датацентр. Сервер.

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

Но терять кучку удобных штук типа докера нет желания, поэтому буду строить сразу и с запасом. Итак, что мне охота

1. Централизованное управление аккаунтами. Для всяких ssh, git и прочим
2. KVM и докер.
3. Чистый, не засранный хост. Не хочу видеть по интерфейсу и 10 правил на каждый контейнер.
4. Разное.

Итак, стадия номер 1 или “подготовка”. Все использованное мной можно найти тут: https://github.com/kiltum/newdc Ну и я подозреваю, что вы уже имеете опыт администрирования linux, поэтому буду только намечать путь.

Арендую новый сервер. Hetzner, leaseweb – их много. И ставлю туда пустую и голую CentOS 7. Никаких панелей, рюшечек и прочего. Из моих уже личных требований – поставить все на raid1.

Бутстраплю ее с помощью ansible и роли centos-bootstrap.yml. Там снос selinux, firewalld, установка ntp и прочих пакетиков и обновление системы. Самый необходимый минимум.

Ставлю KVM. Эта операция одноразовая, поэтому можно и руками.

yum install qemu-kvm libvirt libvirt-python libguestfs-tools virt-install

Сношу дефаултную сеть от KVM. Это автоматически избавляет меня от кучки правил в iptables.

virsh net-autostart --disable default
virsh net-destroy default

Создаю тупой интерфейс, куда буду цеплять с помощью бриджа виртуалки

modprobe dummy numdummies=1
echo "dummy" > /etc/modules-load.d/dummy.conf
echo "options dummy numdummies=1" >> /etc/modprobe.d/dummy.conf

Генерирую для него мак-адресс (в принципе можно от балды, но лучше что бы с первыми октетами от KVM – так симпатичней)

hexdump -vn3 -e '/3 "52:54:00"' -e '/1 ":%02x"' -e '"\n"' /dev/urandom

И делаю конфиг-фаил для этого интерфейса

cat > /etc/sysconfig/network-scripts/ifcfg-dummy0
DEVICE=dummy0
MACADDR=52:54:00:1b:e1:80
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
IPV6INIT=no
BRIDGE=virbr100

и описываю бридж

cat > /etc/sysconfig/network-scripts/ifcfg-virbr100
DEVICE=virbr100
NAME=virbr100
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Bridge
DELAY=2
STP=on
IPADDR=172.16.100.1
NETMASK=255.255.255.0
IPV6INIT=no

Поднимаю созданное

ifup virbr100

В результате я получил следующее

2: dummy0: mtu 1500 qdisc noqueue master virbr100 state UNKNOWN qlen 1000
link/ether 52:54:00:1b:e1:80 brd ff:ff:ff:ff:ff:ff
inet6 fe80::5054:ff:fe1b:e180/64 scope link
valid_lft forever preferred_lft forever
...
5: virbr100: mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 52:54:00:1b:e1:80 brd ff:ff:ff:ff:ff:ff
inet 172.16.100.1/24 brd 172.16.100.255 scope global virbr100
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe1b:e180/64 scope link
valid_lft forever preferred_lft forever

Разрешаю форвардинг пакетиков между интерфейсами

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
echo "net.ipv4.conf.all.forwarding=1" >> /etc/sysctl.conf
sysctl -p

Для полноценной работы виртуалок я добавляю в стандартный набор правил еще одно, которое обеспечивает виртуалкам выход в интернет. Вместо иксиков подставьте свой внешний ipшник

-A POSTROUTING -o eth0 -j SNAT --to-source x.x.x.x

И в принципе все, я готов создать первую виртуалку.

virt-install --name head.ka12.ko --network bridge=virbr100 --memory 1024 --disk path=head.ka12.co.img,size=30 --cdrom ../iso/CentOS-7-x86_64-Minimal-1708.iso --graphics vnc,listen=172.16.100.1 --noautoconsole

И получаю к ней доступ по VNC

virsh vncdisplay head.ka12.co

Так как пока нету ничего даже похожего на нормальный доступ, пробрасываю VNC порт на локальную машину

ssh -L 5901:172.16.100.1:5900 kiltum@ka12.co

Дальше открываю VNC клиент и по адресу localhost:5901 получаю консоль виртуалки. Дальше как обычно “Далее-далее-подождать и перезагрузить”. Опять же можно было заморочиться и использовать автостарты, но мне лень такое делать на редких и одноразовых операциях.

У этой новой виртуалки будет совершенно ожидаемый адрес 172.16.100.2. После “ребута” инсталлятора снова запускаем и ставим в автозапуск

virsh start head.ka12.co
virsh autostart head.ka12.co

Первым делом надо решить вопрос с доступом в мою “инфраструктуру”. Тут пока ничего лучше не придумали, как openvpn. Запихиваю в /etc/resolv.conf временный адрес DNS сервера и начинаю

yum -y install epel-release mc
yum -y install openvpn easy-rsa

Меняю конфиги openvpn

cat server.conf
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
server 172.16.101.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 172.16.0.0 255.255.0.0"
;push "redirect-gateway def1 bypass-dhcp"
;push "dhcp-option DNS 172.16.100.2"
;push "dhcp-option DOMAIN ka12.co"
duplicate-cn
keepalive 10 120
comp-lzo
user nobody
group nobody
persist-key
persist-tun
verb 3

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

mkdir -p /etc/openvpn/easy-rsa/keys
cp -rf /usr/share/easy-rsa/2.0/* /etc/openvpn/easy-rsa
mcedit /etc/openvpn/easy-rsa/vars
cp /etc/openvpn/easy-rsa/openssl-1.0.0.cnf /etc/openvpn/easy-rsa/openssl.cnf
cd /etc/openvpn/easy-rsa
source ./vars
./clean-all
./build-ca
./build-key-server server
./build-dh
cd /etc/openvpn/easy-rsa/keys
cp dh2048.pem ca.crt server.crt server.key /etc/openvpn
cd /etc/openvpn/easy-rsa
./build-key client

Разрешаю форвардинг

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
echo "net.ipv4.conf.all.forwarding=1" >> /etc/sysctl.conf
sysctl -p

и запускаю openvpn

systemctl enable openvpn@server.service
systemctl start openvpn@server.service

так как там все по умолчанию, очищаю правила фаерволла на виртуалке

iptables -F

Все, теперь на хосте надо открыть порт 1194/udp и пробросить его на виртуалку

-A PREROUTING -d x.x.x.x/32 -i eth0 -p udp --dport 1194 -j DNAT --to-destination 172.16.100.2
-A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT

Добавляю роутинг до подсети vpn

ip route add 172.16.101.0/24 via 172.16.100.2

cat > /etc/sysconfig/network-scripts/route-virbr100
172.16.101.0/24 via 172.16.100.2 dev virbr100

Делаю темплейт клиентского конфига

cat client.template
client
dev tun
proto udp
remote vpn.ka12.co 1194
resolv-retry infinite
nobind
persist-key
persist-tun
comp-lzo
verb 3
key-direction 1
remote-cert-tls server
mssfix
<ca>
ca.crt
</ca>
<cert>
client.crt
</cert>
<key>
client.key
</key>
<tls-auth>
ta.key
</tls-auth>

И заполняю его (в дальнейшем я сделал маленький скрипт gen_config.sh)

sed -e '/ca.crt/rca.crt' -e '/client.crt/reasy-rsa/keys/client.crt' -e '/client.key/reasy-rsa/keys/client.key' -e '/ta.key/rta.key' -e '/crt/d' -e '/\.key/d' client.template | sed -e 's/#.*$//' -e '/^$/d' > cl.ovpn

Цепляюсь и проверяю доступность хоста через vpn

traceroute 172.16.100.1
traceroute to 172.16.100.1 (172.16.100.1), 64 hops max, 52 byte packets
1 172.16.101.1 (172.16.101.1) 53.941 ms 48.797 ms 47.938 ms
2 172.16.100.1 (172.16.100.1) 49.186 ms !Z 48.813 ms !Z 49.865 ms !Z

Пробрасываю ключ, бутстраплю виртуалку и ставлю в ней FreeIPA
ssh-copy-id root@172.16.100.2

ansible-playbook -i inventory -l head.ka12.co centos-bootstrap.yml

yum -y install ipa-server bind bind-dyndb-ldap ipa-server-dns

ipa-server-install --setup-dns --mkhomedir --allow-zone-overlap

Меняю шелл по умолчанию

kinit admin
ipa config-mod --defaultshell=/bin/bash

Внезапно оказалось, что FreeIPA с 1 гигом памяти стартует очень тяжко. Добавляю памяти

virsh setmaxmem head.ka12.co 4G --config
virsh setmem head.ka12.co 2G --config

И включаю VPN на полную

push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 172.16.100.2"
push "dhcp-option DOMAIN ka12.co"

Добавляю pam сервис

cd /etc/pam.d/
ln -s system-auth openvpn

Добавляю группу openvpn и sshd и заношу в нее меня. В принципе все тоже самое можно сделать через веб-интерфес FreeIPA.

ipa hbacsvc-add openvpn
ipa hbacrule-add allow_openvpn
ipa hbacrule-add-service allow_openvpn --hbacsvcs=openvpn
ipa hbacrule-add-user allow_openvpn --user=kiltum
ipa hbacrule-add-service allow_sshd --hbacsvcs=sshd
ipa hbacrule-add-user allow_sshd --user=kiltum
ipa hbacrule-add-host allow_sshd --hosts=head.ka12.co
ipa hbactest --user=kiltum --host=head.ka12.co --service=sshd

Теперь остался последний шаг. Добавляю в конфиг сервера

plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn

а в конфиг клиента

auth-user-pass

И всё.

В случае проблем проверить работу авторизации можно и прямо на стороне сервера:

pamtester openvpn kiltum authenticate

Что же получил на данном этапе?

1. Хост, на котором крутится только KVM и больше ничего. А значит: ошибиться негде, ломать тоже особо нечего.
2. OpenVPN, доступ до которого защищен сразу двумя методами: клиентским сертификатом и логином-паролем.
3. Внутренний DNS, который снаружи никак не виден.
4. Управление пользователями/группами/сервисами. Располагается исключительно во внутренней сети.
5. Даже если опустить везде фаирволлы, то ничего нового не будет доступно снаружи.

Новый сервер на CentOS 7

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

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

Первое, что необходимо сделать – отрубить 99,9% автоподбиральщиков паролей.

# cat /etc/sysconfig/iptables|grep 22
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name DEFAULT --rsource
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 300 --hitcount 4 --name DEFAULT --rsource -j DROP
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT

Затем ставим sslh – мультиплексор протоколов. Его задача – дать доступ до основных сервисов через 443 порт.

# cat /etc/sslh.cfg
# This is a basic configuration file that should provide
# sensible values for "standard" setup.

verbose: false;
foreground: true;
inetd: false;
numeric: false;
transparent: false;
timeout: 2;
user: "sslh";
# Change hostname with your external address name.
listen:
(
{ host: "edge"; port: "443"; }
);
protocols:
(
{ name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; },
{ name: "openvpn"; host: "localhost"; port: "1194"; },
# { name: "xmpp"; host: "localhost"; port: "5222"; },
{ name: "http"; host: "localhost"; port: "80"; },
{ name: "ssl"; host: "localhost"; port: "443"; log_level: 0; },
{ name: "anyprot"; host: "localhost"; port: "443"; }
);

Как видите, конфигурация 100% стандартная, за исключением того, что мне не нужен xmpp. после обкатки можно будет и закрыть “обычный” ssh порт совсем. Минусом станет то, что в логах и утилитах пользователи станут заходить через localhost. Реальные адреса будут видны только через journald

… и все. В остальном инсталляция CentOS 7 не требует дальнейших движений напильником.

Кто такие DevOps?

Слово модное…это да!! Но если публиковать как «Системный администратор», то откликаются мальчики-настройщики компов, если «Программист», то жесткие программеры без фантазии © Объяснения одной дамы

Любой, кто интересовался этой темой, знают, что данное сокращение произошло от Development и Operations. Или если перевести на русский – Программисты и Сисадмины. Да, operations дословно переводится не так, но здесь я использую слово «сисадмины» в самом широком смысле.

Кто такие «сисадмины»? Если кратко, то это именно те люди, на руках которых держится вся инфраструктура. Где-то этим словом называют приходящих «аникейщиков», которые меняют картриджи в принтере и изредка чистят компьютеры от вирусов и троянов. А где-то это целые залы людей, разбитых на свои касты. Кто-то занимается сетями, кто-то базами данных, а кто-то обслуживанием датацентров и их инфраструктуры. Титаны антистрессовых методик.

Точно такое же широкое определение имеют и «программисты». И тот, кто пишет на javascript проверку ввода на сайт и тот, кто добавляет код во внутренний модуль корпоративной системы – все они «программисты». И даже тот, кто пишет на встроенном языке 1С, тоже программист, что бы об этом не думали другие.

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

Для сисадмина самое важное это то, что бы вверенная ему система работала без перебоев. Не обращая внимания на тупых пользователей, идиотов-разработчиков, отключения питания и поломок оборудования. Все, абсолютно все, рассматривается с точки зрения надежности. И венцом этой надежности является достижение времени доступности системы в 99,999% (или «5 девяток»). Поверьте, заставить современные системы работать так, чтобы их время недоступности не превышало 5 минут в год – это очень сложная задача. И когда вы добиваетесь, что максимальное время, когда подчиненная система может сказать «ой, я не могу» – это 6 секунд в сутки, то спокойно можете брать с полки пирожок.

У разработчиков же другое положение. Над ними коршунами вьются кровососы-менеджеры, которые постоянно требуют новый функционал, который должен работать быстрее или лучше. И всё это великолепие не должно поломать уже существующий функционал. И код, который прекрасно работает на твоей машине, почему-то отказывается работать как надо даже в тестовом окружении. А еще эти гамадрилы-сисадмины не дают нормально покопаться в получившейся у них системе и понять, что пошло не так даже после успешно пройденных тестов. Эти чудаки на букву «м» постоянно орут как резанные и набрасывают говен на вентилятор при любом чихе. И никто кроме коллег не способен оценить красоты получившегося кода или изящества алгоритма.

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

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

Вот в горниле этих битв и родилось новая каста – DevOps или девопсы. Как водится, поначалу были перегибы с обоих сторон и презрение к «переметнувшимся». Плюс из-за молодости самого термина у него множество толкований и определений. Кто-то считает девопс методологией, направленной на автоматизацию и увеличение числа релизов, а кто-то – на уменьшение ошибок. Я же считаю, что девопс – это прежде всего человек, главной задачей которого является снижение головной боли у программеров, сисадминов и QAшников. А те уже сами напишут, отконфигурят и оттестируют нужное.

Ибо если поглядеть с любой стороны, девопс будет выглядеть как некий недоучка, лишь в редких случаях способный выдать что-то толковое. Бегает со своими скриптами наперевес, чего-то там курочит в коде и лишь принадлежность к «своим» не позволяет его послать в очень далекое эротическое путешествие. У меня нет ни капли сомнения, что программер переиграет девопса в программировании, сисадмин – в администрировании, а тестировщик – на своем тестировочном поле.

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

Сейчас, в самом начале жизни девопсов (с 2009 года же), самой основной их задачей является автоматизация. Объёмы того, что необходимо автоматизировать – поистине ужасающие. Ведь все (программеры и сисадмины) непрерывно трудятся над увеличением завалов не один десяток лет.

Что обычно автоматизируют?
– Развертывание очередного релиза кода. В тест, в стейджинг, в продакшн. Да хоть на машину разработчика. С необходимыми сервисами и данными. Разных версий.
– Обновление. Сервера, сервисы и сайты. Быстро и еще быстрей.
– Управление инфраструктурой. Сегодня 100 серверов в одном датацентре, завтра 500 в трех, а послезавтра 1000 снова в одном. Мониторинг, сбор логов и куча других мелких задач, которые раньше выполнялись вручную или не выполнялись совсем.

Это самые общие задачи. Где-то спектр для автоматизации побольше, а где-то поменьше.

Широкий характер выполняемых задач автоматически формирует и необходимые требования к девопсам:

– Необходимо знать все используемые продукты, языки и технологии. Только тогда стандартная для девопса задача «скрестить ужа с ежом и заставить их летать» автоматически становится выполнимой. Сисадмин сделал бекап? А девопс должен забрать этот бекап, выкинуть из него всякую конфиденциальную информацию и засунуть в систему (которую построил он же), которая позволит разработчикам и тестировщикам без опаски гонять свои творения на «почти продакшене».

– Наличие знаний (есть еще умное слово «компетенций») по всему процессу разработки. Причем знания должны быть реальными и боевыми. Потому что некому кроме девопса остановить программера, когда он решит напрямую засовывать json в обычную базу данных. Для разработчика в этом нет ничего крамольного (база поддерживает? поддерживает!), для сисадмина тоже (ну растет база и требует больше ресурсов – это нормально), а DBA по привычке обматерит всех и молча пойдет строить индексы и партиционировать базу. А то, что полученная конструкция могла быть быстрее и надежней – это никому не интересно. Кроме девопсов.

Нет ни того, ни другого? Тогда получаются люди, которые прекрасно характеризуются как «чуваки с накачанным ЧСВ и недержанием кода».

Требования большие? Да, большие. Зато и награда велика.

Сама возможность пощупать возведенное твоими трудами, а не какого-нибудь сферического коня в вакууме стоит дорого. Причем ощутить весь процесс возведения от «долбанное ничего» до «обалдеть какая няшка». Ни разработчики, ни сисадмины, ни тестировщики такой возможностью не обладают …

P.S. Ну и денег дают нормально.

Бекапы – фигня. Восстановление – вот это да!

Пару дней назад все и везде прожужжали мантры про всемирный день бекапа и про то, что делать бекапы – это хорошо. Но почему-то никто нигде не жужжит про то, что бекапы сами по себе, без восстановления – фигня полная. Ну лежит где-то резервная копия, место занимает. И что вы с ней будете делать, если что-то случится? А как до неё доберетесь? А ключи и пароли откуда возьмете? И для любой системы таких вопросов можно задать сотни.

Будь готов!

Именно поэтому я изобрел лично для себя свой личный DIRT (Disaster Recovery Test). Где-то раз в месяц (или чаще, под настроение) я тупо сношу все с ноута и ставлю заново операционку и накатываю назад рабочее окружение. Первые разы длились все выходные и без потерь не обходилось. Зато сейчас мне требуется примерно час, что бы вернуться в строй. Около трех часов – что бы вернуть 100% окружения назад. Быстрее не получается, ибо ограничен скоростью ноутбука и интернета. Максимальные потери – с начала рабочего дня. Все, что мне необходимо на данный момент – это ноутбук и быстрый интернет.

Итак, что необходимо для получения аналогичного?

Во-первых, компьютер с нормальной и привычной вам инфраструктурой. Представьте себя в командировке в далеком городе. У вас сгорает синим пламенем ваш любимый ноутбук. Что делать? Лучшее решение: тупо идем в ближайший компьютерный магазин и покупаем новый ноутбук. Попытка ремонта или привоза “трупика” домой – все это потери времени, а его обычно всегда не хватает. Мой выбор на данный момент – MacBook. Просто, удобно и unix внутри.

Во-вторых, приучите себя использовать систему хранения паролей. Все пароли, ключи, сертификаты или конфигурационные файлы должны быть там. Все, что необходимо вам помнить – это как добраться до этой системы и мастер-пароль. В свое время я выбрал 1Password и ни капельки об этом не пожалел за 5 лет.

В-третьих, приучите себя использовать системы контроля версий. SVN, Git, Mercurial – что угодно, но в этой системе должны лежать все документы и файлы, которые представляют для вас хоть какую-то ценность. Да, поначалу будет тяжело, особенно если вы не представитель ИТшной области. Очень ограниченным паллиативом будет покупка аккаунта в дропбоксе или в другом хранилище файлов. Там тоже появляются возможности про сохранение версий документов и их “отката” при необходимости.

Так же очень полезно завести на каком-нибудь облачном хранилище файлов каталог, в который вы будете складывать дистрибутивы программ. Да, сейчас есть много магазинов приложений (например, встроенный в Apple или Steam. Что-то аналогичное есть у Windows), который после ввода заветного логина и пароля дадут поставить вам все назад. Но до сих пор есть куча приложений, авторы которых по каким-то причинам не могут или не хотят публиковаться в таких магазинах.

И когда вам потребуется поставить такое приложение, то легко можно столкнуться со следующими проблемами:

– Нужной версии уже нет. А доступная версия требует покупки. Да, можно списаться с автором или поискать в интернете, но это потеря времени.
– Для скачивания версии необходимо зарегистрироваться/залогиниться на сайте, потом они пришлют ссылку, по которой скачается “качальщик”, который и начнет скачивать нужное.
– Дистрибутив большой или лежит на медленных серверах. Пока скачаешь …

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

И вот только после этого можно поставить какую-нибудь систему резервного копирования (Acronis Backup очень даже, не смотря на мелкие глюки). И натравить её на всё вот это скопом для создания последней “линии обороны”.

Ну и регулярно проводить восстановления накопленного непосильным трудом. Повторюсь, в первые разы вы обязательно что-нибудь потеряете или забудете и это нормально. Еще раз – абсолютно нормально. Это для того и надо, что бы когда это случилось внезапно, у вас был четкий план, что и когда делать.

Вот как у меня происходило это в последний и предпоследний раз (я пролил кофе на ноутбук и просто захотелось)

1. Сносим диск и ставим операционку с нуля.
2. Как только она поставилась, идем в родной магазин приложений и ставим хранилку паролей. Затем клиент для “облачных облаков”.
3. Запускаем все это. Доступ до паролей получен, основные файлы (типа инсталлятора vpn) пошли заливаться на ноутбук.
4. Запускаем установку необходимого из Apple store. Всякие slack, things и прочее.
5. По мере установки всего я уже могу начинать пользоваться ноутбуком. Да, почта не вся засинхронизировалась или индексатор не прошел по всем файлам, но я уже могу что-то делать.
6. Восстанавливаем из системы контроля версий последние проекты и разворачиваем файлы конфигурации.
7. По мере необходимости ставим тот софт, который не требуется “прямо сейчас”, но нужен регулярно.
8. Оцениваем потери и думаем над шагами, которые надо сделать, что бы это не повторилось.

Все. Первый раз сложно, в 10й – просто. Главное тут – регулярность.

Сэм Ньюмен. Создание микросервисов

Дочитал книгу Сэма Ньюмена про микросервисы. Кратко: читать стоит, но аккуратно.

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

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

А вот последние, про тестирование, мониторинг, безопасность и масштабирование … Скажем так, в отличии от первых глав, там налита вода и общие слова. Вот реально никакой конкретики в методах преодоления проблем. И автор явно не мог не знать о них, но таких красивых решений у него не было. Ну как можно строить мониторинг на нагиосе, если он совершенно не приспособлен для постоянно меняющего числа машин? А в безопасности тоже дикая куча проблем связанных с тем же самым. И никакой IDS/IPS/IPTables (да, там именно так, iptables с большой буквы) не поможет в этом.

Скажу честно, у меня тоже нет решений-серебрянных пуль на эти темы. Но почему Сэм не упомянул возможные варианты? Скорее всего потому, что они тупо на них забили …

В общем, слабая 4ка.

Игрища с сервером – 3 или openvpn и ipv6

Сделав очередной openvpn сервер, я задался вопросом: а нафига я его вообще делал? Нет, что бы добираться безопасно до своих ресурсов, это да. Но одна из главных задач – дать клиенту ipv6 в мире ipv4. И именно её он не выполняет. Значит сейчас починим.

Самый простой вариант “в лоб” – перевести сервер в бридж режим и пусть клиенты будут представляться хост-машине как еще одни виртуалки. Минус – замучаюсь с безопасностью. Плюс – тупо и надежно.

Вариант посложнее – выпилить кусочек ipv6 сети и давать её клиентам. Минус тут один – некоторые клиенты почему-то желают видеть у себя /64 и никак иначе. А у меня всего одна /64. Нет, можно получить еще через любого туннельного брокера, но не хочу.

Значит вариант остается один: взять приватную ipv6 подсеть и сделать раздачу из него. Для выбора сетки мы можем брать все что нам понравится, главное что бы первый байт адреса был fd. Вот тут можно даже побаловаться, просто обновляя страничку.

Я возьму для своих крамольных целей сеть fdab:cdef:1234:5678::/64

Почитав маны, добавляю следующие строчки в конфиг сервера

server-ipv6 fdab:cdef:1234:5678::/64
tun-ipv6
push tun-ipv6

И перезагружаю сервер

systemctl restart openvpn@server.service

Переподключаю клиента и смотрю в логи. Вижу заветную строку.

Fri Jan 29 03:12:31 2016 /usr/sbin/ip addr add dev tun0 local 10.100.2.6 peer 10.100.2.5
Fri Jan 29 03:12:31 2016 /usr/sbin/ip -6 addr add fdab:cdef:1234:5678::1000/64 dev tun0
Fri Jan 29 03:12:31 2016 /usr/sbin/ip route add 10.100.0.0/24 via 10.100.2.5

Пробую с клиента пингануть сервер

$ ping6 fdab:cdef:1234:5678::1 -c 2
PING fdab:cdef:1234:5678::1(fdab:cdef:1234:5678::1) 56 data bytes
64 bytes from fdab:cdef:1234:5678::1: icmp_seq=1 ttl=64 time=48.1 ms
64 bytes from fdab:cdef:1234:5678::1: icmp_seq=2 ttl=64 time=48.2 ms

Работает! Теперь осталось самая мелочь – запушить правило роутинга, адрес ДНС и собственно роутинг сделать.

Строчка конфига

push "route-ipv6 2000::/3"

Заставит маршрутизировать весь ipv6 трафик через openvpn. Почти как redirect-gateway def1, но только для ipv6.

Но так как у нас приватная сеть, то я могу пинговать только openvpn. Другие хосты согласно правилам хорошего тона, такие поползновения обламывают.

К сожалению, тут опять на белый свет выползает firewalld, а вернее его хипстерские правила, которые не умеют ничего, кроме открытия и закрытия портов. Выносим его

systemctl stop firewalld
yum -y install iptables-services
systemctl enable iptables
systemctl enable ip6tables
systemctl start iptables
systemctl start ip6tables

Добавляем правила для SNAT и открываем 1194/udp на вход
-A POSTROUTING -s 10.100.2.0/24 -o eth0 -j SNAT --to-source 10.100.0.133
-A POSTROUTING -s fdab:cdef:1234:5678::/64 -o eth0 -j SNAT --to-source 2a01:4f8:171:1a43:5054:ff:fe0d:da49

-A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT

И удаляем мешающееся

-A FORWARD -j REJECT --reject-with icmp6-adm-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited

Теперь последний шаг – sysctl.conf

net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding=1

То, что надо перечитать – перечитываем, то, что надо перезагрузить – перезагружаем.

Если все сделано правильно, клиент VPN начнет пинговать внешние ipv6 ресурсы. traceroute у меня почему-то обламывался на первом же хопе. Посмотрел tcpdump – видимо, не до конца допилили модуль, отвечающий за NAT: адреса не переписываются. Но с другой стороны – ну и пофиг: если очень надо, то я смогу зайти прямо на хост.

Последняя проверка: а файлики-то клиент утащит?

$ wget -6 google.com
--2016-01-29 04:07:49-- http://google.com/
Resolving google.com (google.com)... 2607:f8b0:4005:800::1002
Connecting to google.com (google.com)|2607:f8b0:4005:800::1002|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://www.google.de/?gfe_rd=cr&ei=5SurVtbrKeaD8Qeu6YvACw [following]
--2016-01-29 04:07:49-- http://www.google.de/?gfe_rd=cr&ei=5SurVtbrKeaD8Qeu6YvACw
Resolving www.google.de (www.google.de)... 2607:f8b0:4010:800::101f
Connecting to www.google.de (www.google.de)|2607:f8b0:4010:800::101f|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘index.html’

[ <=> ] 19,066 97.8KB/s in 0.2s

2016-01-29 04:07:50 (97.8 KB/s) - ‘index.html’ saved [19066]

Утащил!

Значит, можно удовлетворенно потирать руки и идти спать

Игрища с сервером – 2 (openvpn, ssh и freeipa)

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

Ставим удобности.

yum -y install epel-release mc

Для начала подниму для проверки просто сервер. Без каких-либо излишеств.

yum -y install openvpn easy-rsa
cp /usr/share/doc/openvpn-*/sample/sample-config-files/server.conf /etc/openvpn
mcedit /etc/openvpn/server.conf

Конфиг после удаления лишнего получился примерно такой

port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
server 10.100.2.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 10.100.0.0 255.255.255.0"
;push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 10.100.0.10"
push "dhcp-option DOMAIN local.multik.org"
duplicate-cn
keepalive 10 120
comp-lzo
user nobody
group nobody
persist-key
persist-tun
verb 3

Полностью по мануалу, без каких-либо отклонений. Значение каждой строчки можно посмотреть в документации.

Теперь ключи. Опять же, не отходя от канонов.

mkdir -p /etc/openvpn/easy-rsa/keys
cp -rf /usr/share/easy-rsa/2.0/* /etc/openvpn/easy-rsa
mcedit /etc/openvpn/easy-rsa/vars

Тут я поправил строки “по умолчанию”

export KEY_COUNTRY="RU"
export KEY_PROVINCE="RU"
export KEY_CITY="Moscow"
export KEY_ORG="VseMoe"
export KEY_EMAIL="multik@multik.org"
export KEY_OU="Internet"
...
export KEY_NAME="Server"
...
export KEY_CN="vpn.vsemoe.com"

Дальше просто лог команд, везде давим Enter.

cp /etc/openvpn/easy-rsa/openssl-1.0.0.cnf /etc/openvpn/easy-rsa/openssl.cnf
cd /etc/openvpn/easy-rsa
source ./vars
./clean-all
./build-ca
./build-key-server server
./build-dh
cd /etc/openvpn/easy-rsa/keys
cp dh2048.pem ca.crt server.crt server.key /etc/openvpn
cd /etc/openvpn/easy-rsa
./build-key client

Разрешаем форвард

mcedit /etc/sysctl.conf
net.ipv4.ip_forward = 1
sysctl -p

И стартуем сервер

systemctl enable openvpn@server.service
systemctl start openvpn@server.service

Теперь на хосте надо открыть порт 1194/udp и перебросить его на виртуалку с openvpn

-A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT
-A PREROUTING -d 136.243.151.196/32 -i eth0 -p udp --dport 1194 -j DNAT --to-destination 10.100.0.133

И на самой виртуалке открыть тем или иным образом порт

firewall-cmd --add-service=openvpn --permanent
firewall-cmd --permanent --add-port=53/udp
firewall-cmd --reload

Теперь перетаскиваем на клиента все client* файлы и ca.crt и делаем конфиг (обычный текстовый файл)

client
dev tun
proto udp
remote 136.243.151.196 1194
resolv-retry infinite
nobind
persist-key
persist-tun
comp-lzo
verb 3
ca ca.crt
cert client.crt
key client.key

Пробуем соедениться

$ sudo openvpn --config confif.vpn
Wed Jan 27 03:55:22 2016 OpenVPN 2.3.8 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6] built on Aug 4 2015
Wed Jan 27 03:55:22 2016 library versions: OpenSSL 1.0.1e-fips 11 Feb 2013, LZO 2.06
Wed Jan 27 03:55:22 2016 WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info.
Wed Jan 27 03:55:22 2016 Socket Buffers: R=[212992->131072] S=[212992->131072]
Wed Jan 27 03:55:22 2016 UDPv4 link local: [undef]
Wed Jan 27 03:55:22 2016 UDPv4 link remote: [AF_INET]136.243.151.196:1194
Wed Jan 27 03:55:22 2016 TLS: Initial packet from [AF_INET]136.243.151.196:1194, sid=3dd59a35 34ce24da
Wed Jan 27 03:55:22 2016 VERIFY OK: depth=1, C=RU, ST=RU, L=Moscow, O=VseMoe, OU=Internet, CN=vpn.vsemoe.com, name=Server, emailAddress=multik@multik.org
Wed Jan 27 03:55:22 2016 VERIFY OK: depth=0, C=RU, ST=RU, L=Moscow, O=VseMoe, OU=Internet, CN=server, name=Server, emailAddress=multik@multik.org
Wed Jan 27 03:55:23 2016 Data Channel Encrypt: Cipher 'BF-CBC' initialized with 128 bit key
Wed Jan 27 03:55:23 2016 Data Channel Encrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Wed Jan 27 03:55:23 2016 Data Channel Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
Wed Jan 27 03:55:23 2016 Data Channel Decrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Wed Jan 27 03:55:23 2016 Control Channel: TLSv1.2, cipher TLSv1/SSLv3 DHE-RSA-AES256-GCM-SHA384, 2048 bit RSA
Wed Jan 27 03:55:23 2016 [server] Peer Connection Initiated with [AF_INET]136.243.151.196:1194
Wed Jan 27 03:55:25 2016 SENT CONTROL [server]: 'PUSH_REQUEST' (status=1)
Wed Jan 27 03:55:25 2016 PUSH: Received control message: 'PUSH_REPLY,route 10.100.0.0 255.255.255.0,dhcp-option DNS 10.100.0.10,route 10.100.2.1,topology net30,ping 10,ping-restart 120,ifconfig 10.100.2.14 10.100.2.13'
Wed Jan 27 03:55:25 2016 OPTIONS IMPORT: timers and/or timeouts modified
Wed Jan 27 03:55:25 2016 OPTIONS IMPORT: --ifconfig/up options modified
Wed Jan 27 03:55:25 2016 OPTIONS IMPORT: route options modified
Wed Jan 27 03:55:25 2016 OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified
Wed Jan 27 03:55:25 2016 ROUTE_GATEWAY 172.16.137.2/255.255.255.0 IFACE=eno16777736 HWADDR=00:0c:29:fa:0a:54
Wed Jan 27 03:55:25 2016 TUN/TAP device tun1 opened
Wed Jan 27 03:55:25 2016 TUN/TAP TX queue length set to 100
Wed Jan 27 03:55:25 2016 do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
Wed Jan 27 03:55:25 2016 /usr/sbin/ip link set dev tun1 up mtu 1500
Wed Jan 27 03:55:25 2016 /usr/sbin/ip addr add dev tun1 local 10.100.2.14 peer 10.100.2.13
Wed Jan 27 03:55:25 2016 /usr/sbin/ip route add 10.100.0.0/24 via 10.100.2.13
Wed Jan 27 03:55:25 2016 /usr/sbin/ip route add 10.100.2.1/32 via 10.100.2.13
Wed Jan 27 03:55:25 2016 Initialization Sequence Completed

Как видно по последней строчке, соединение установилось. Пробуем добраться до любого хоста “внутри” сети.

$ ssh root@10.100.0.10
ssh: connect to host 10.100.0.10 port 22: No route to host

Облом. По простой причине – ничего в сети 10.100.0 не знает про сеть 10.100.2, которую я отдал под VPN. Самое простое решение – включить маскарадинг на выходе

firewall-cmd --permanent --add-masquerade
firewall-cmd --reload

Пробую еще раз

$ ssh root@10.100.0.10
The authenticity of host '10.100.0.10 (10.100.0.10)' can't be established.
ECDSA key fingerprint is fb:c1:72:a2:9a:a1:df:f5:d0:95:09:a4:3b:2e:9d:68.

Сработало. Это хорошо. Теперь немного добавим безопасности путем добавление пре-авторизационного ключа. Опять же, по мануалу

openvpn --genkey --secret ta.key
tls-auth ta.key 0

В принципе, тут можно остановиться. Сервер работает, создаешь по ключу на клиента и вперед. Но мне так не охота. Я хочу сделать так, что бы конфигурационный файл был у всех одинаковый, а пользователи авторизовались по классическому логину и паролю. А логины и пароли брались бы из FreeIPA.

Опять же, вариантов много. Самый распространенный – это использование freeipa как ldap сервера. Мне лично лень. Я решил воспользоваться вариантом, когда freeipa авторизует пользователей в системе (так как это стандартный способ), а openvpn авторизовать уже через пользователей в системе.

Ставим на vpn все необходимое и подключаемся к ипе (подробности в ранних постах).

yum install -y ipa-client
ipa-client-install --mkhomedir

И тут оно обламывается. По простой причине – для vpn.local.multik.org нет адреса в базе. А у машины два локальных интерфейса и какой использовать для чего – непонятно.

Идем в виртуалку с ipa и добавляем

[root@ipa ~]# kinit admin
Password for admin@LOCAL.MULTIK.ORG:
[root@ipa ~]# ipa dnsrecord-add
Record name: vpn
Zone name: local.multik.org
Please choose a type of DNS resource record to be added
The most common types for this type of zone are: A, AAAA

DNS resource record type: A
A IP Address: 10.100.0.133
Record name: vpn
A record: 10.100.0.133

И снова пробуем – теперь все получится.

Теперь небольшой трюк. Что бы не давать по умолчанию доступ до VPN всем, я создам новый “сервис”.

cd /etc/pam.d/
ln -s system-auth openvpn

Теперь Осталось мелочь – создать в ипе HBAC сервис openvpn и установить правила. Создаем сервис, группу для него и соединяем вместе

[root@ipa ~]# ipa hbacsvc-add openvpn
----------------------------
Added HBAC service "openvpn"
----------------------------
Service name: openvpn

[root@ipa ~]# ipa hbacrule-add allow_openvpn
-------------------------------
Added HBAC rule "allow_openvpn"
-------------------------------
Rule name: allow_openvpn
Enabled: TRUE

[root@ipa ~]# ipa hbacrule-add-service allow_openvpn --hbacsvcs=openvpn
Rule name: allow_openvpn
Enabled: TRUE
Services: openvpn
-------------------------
Number of members added 1
-------------------------

Проверяю, что натворил.

[root@ipa ~]# ipa hbacrule-find allow_openvpn
-------------------
1 HBAC rule matched
-------------------
Rule name: allow_openvpn
Enabled: TRUE
Services: openvpn
----------------------------
Number of entries returned 1
----------------------------

Добавляю к правилу пользователя и хост

[root@ipa ~]# ipa hbacrule-add-user allow_openvpn --user=multik
Rule name: allow_openvpn
Enabled: TRUE
Users: multik
Services: openvpn
-------------------------
Number of members added 1
-------------------------

[root@ipa ~]# ipa hbacrule-add-host allow_openvpn --hosts=vpn.local.multik.org
Rule name: allow_openvpn
Enabled: TRUE
Users: multik
Hosts: vpn.local.multik.org
Services: openvpn
-------------------------
Number of members added 1
-------------------------

Проверяю, что сработает на меня и на админа (который вроде как и не должен иметь доступ)

[root@ipa ~]# ipa hbactest --user=admin --host=vpn.local.multik.org --service=openvpn
--------------------
Access granted: True
--------------------
Matched rules: allow_all
Not matched rules: allow_openvpn

[root@ipa ~]# ipa hbactest --user=multik --host=vpn.local.multik.org --service=openvpn
--------------------
Access granted: True
--------------------
Matched rules: allow_all
Matched rules: allow_openvpn

Как вижу, в системе есть правило по умолчанию, которое дает доступ всем до всего. Но если его просто выкусить, то я тупо лишусь доступа И по ssh тоже. Поэтому надо сделать аналогичное для ssh

[root@ipa pam.d]# cd
[root@ipa ~]# ipa hbacsvc-add sshd
ipa: ERROR: HBAC service with name "sshd" already exists

Опс, сервис такой уже по умолчанию есть. Ну пойду дальше

[root@ipa ~]# ipa hbacrule-add allow_sshd
----------------------------
Added HBAC rule "allow_sshd"
----------------------------
Rule name: allow_sshd
Enabled: TRUE
[root@ipa ~]# ipa hbacrule-add-service allow_sshd --hbacsvcs=sshd
Rule name: allow_sshd
Enabled: TRUE
Services: sshd
-------------------------
Number of members added 1
-------------------------
[root@ipa ~]#

ipa hbacrule-add-user allow_sshd --user=multik
ipa hbacrule-add-host allow_sshd --hosts=vpn.local.multik.org

Проверяю

[root@ipa ~]# ipa hbactest --user=admin --host=vpn.local.multik.org --service=sshd
--------------------
Access granted: True
--------------------
Matched rules: allow_all
Not matched rules: allow_openvpn
Not matched rules: allow_sshd
[root@ipa ~]# ipa hbactest --user=multik --host=vpn.local.multik.org --service=sshd
--------------------
Access granted: True
--------------------
Matched rules: allow_all
Matched rules: allow_sshd
Not matched rules: allow_openvpn

Все на месте. Выкусываю нафиг
[root@ipa ~]# ipa hbacrule-disable allow_all
------------------------------
Disabled HBAC rule "allow_all"
------------------------------

Согласно выводу выше, я теперь не могу залогиниться на хост vsemoe-com пользователем multik.

[root@ipa ~]# ssh multik@vsemoe-com
multik@vsemoe-com's password:
Connection closed by UNKNOWN

Не соврала система. “Не пущаит”. Проверяю почему

[root@ipa ~]# ipa hbactest --user=multik --host=vsemoe-com.local.multik.org --service=sshd
---------------------
Access granted: False
---------------------
Not matched rules: allow_openvpn
Not matched rules: allow_sshd

Добавляю хост, как разрешенный к коннекту на него по ssh

[root@ipa ~]# ipa hbacrule-add-host allow_sshd --hosts=vsemoe-com.local.multik.org
Rule name: allow_sshd
Enabled: TRUE
Users: multik
Hosts: vpn.local.multik.org, vsemoe-com.local.multik.org
Services: sshd
-------------------------
Number of members added 1
-------------------------

Будет пускать?

[root@ipa ~]# ipa hbactest --user=multik --host=vsemoe-com.local.multik.org --service=sshd
--------------------
Access granted: True
--------------------
Matched rules: allow_sshd
Not matched rules: allow_openvpn

Должно. Проверяю

[root@ipa ~]# ssh multik@vsemoe-com
multik@vsemoe-com's password:
Last failed login: Thu Jan 28 12:53:43 MSK 2016 from 2a01:4f8:171:1a43:5054:ff:fea4:8c6 on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Mon Jan 25 16:51:46 2016 from 10.100.0.254

Как говорится, работает. Теперь последняя проверка: пустит ли пользователя multik на хосте vpn для сервиса openvpn?

[root@ipa ~]# ipa hbactest --user=multik --host=vpn.local.multik.org --service=openvpn
--------------------
Access granted: True
--------------------
Matched rules: allow_openvpn
Not matched rules: allow_sshd

Для vpn пустит, а по ssh не пустит. Теперь остались сущие мелочи. Добавялем в конфиг сервера

plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn

а в конфиг клиента

auth-user-pass

и пробуем

$ sudo openvpn --config confif.vpn
Thu Jan 28 04:57:42 2016 OpenVPN 2.3.8 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6] built on Aug 4 2015
Thu Jan 28 04:57:42 2016 library versions: OpenSSL 1.0.1e-fips 11 Feb 2013, LZO 2.06
Enter Auth Username: ******
Enter Auth Password: ***********

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

Сделаем обычный текстовый файлик из 2х строчек: логина и пароля. И укажем его имя сразу после auth-user-pass. Если все сделано правильно, то openvpn ничего не будет спрашивать, а просто возьмет и прицепится.

Теоретически, на этом можно и закончить процесс. Но некрасиво как-то. “Клиентами” моего сервиса будут люди, далекие от техники. Дизайнеры всякие и менеджеры. Пока им объяснишь, чего куда совать и на что нажимать …

Технология очень простая. Берем исходный конфиг для клиента, и добавляем к нему следующие строки

key-direction 1

<ca>
—–BEGIN CERTIFICATE—–
ca.crt
—–END CERTIFICATE—–
</ca>

<cert>
—–BEGIN CERTIFICATE—–
client.crt
—–END CERTIFICATE—–
</cert>

<key>
—–BEGIN PRIVATE KEY—–
client.key
—–END PRIVATE KEY—–
</key>

<tls-auth>
—–BEGIN OpenVPN Static key V1—–
ta.key
—–END OpenVPN Static key V1—–
</tls-auth>

Внутрь просто копируем содержимое соответствующих файлов. Любым текстовым редактором. Ну и убираем строки

ca ca.crt
cert client.crt
key client.key

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

Всё. Я получил в свое распоряжение VPN сервер. Управляемый хоть из консоли, хоть из веб-морды (как? я не писал? сходите браузером на адрес ipa сервера). Ну вообще-то не только VPN сервер, но в этой рассказке я писал только про VPN.

Удачи!