Bash Days | Linux | DevOps
23.3K subscribers
155 photos
24 videos
676 links
Авторский канал от действующего девопса

Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу.

Автор: Роман Шубин
Реклама: @maxgrue

MAX: https://max.ru/bashdays

Курс: @tormozilla_bot
Блог: https://bashdays.ru
Download Telegram
Как-то давно, в одной компании изначально так получилось, что один СТО мне напихивал задачи через слак, просто хуярил как заводной петух.

Тогда еще все сидели на тяжёлых (слаке и джире).


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

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

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

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

В какой-то момент капнула последняя капля.

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

Нахуй вообще СТО там был нужен вообще не понятно. Наверное чей-то родственник.

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

Не хотите в джиру — идите на хуй! Хотя они и так нахуй пошли спустя пару недель.


Думаете мне кто-то что-то ответил? Да хуй там плавал, CTO мог отвечать только в 3 часа ночи и по выходным, ибо в обычное нормальное человеческое время этот чёрт был заняты чем-то иным. Наверное заряжал свой пулемет срочными задачами.

Ладно чё уж, в любой компании своего дерьма навалом.

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

Ну и береги свои кадры, проебать золото очень легко. Такие дела!

🛠 #рабочиебудни #remains

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
15114
Я тут недавно игрушку написал. Ну, как написал, реализовал.

🔤🔤🔥🔤🔤🔤🔤

Вариант 2048, оптимизированный по занимаемому экранному пространству.

➡️ Ознакомиться с игрушкой можно здесь.


Но у нас тут люди серьезные, поэтому рассмотрим проблемы, возникающие при реализации вывода скриптов.

Простой пример:

for i in {1..100};do
printf "#"
sleep .3
done


Код просто выводит символы #, примерно 3 штуки в секунду. Все работает нормально, пока пользователь не начинает что-то набирать на клавиатуре.

И тогда получаем:

######sb#sf#bg#sfbg#wfgb#wg#fg#b###^[[A#^[[B#^[[D#^[[A#^[[B##


Убрать эхо вывода на терминал просто:

stty -echo


Классная команда. После ее выполнения нажатые клавиши не отображаются.

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

Вернуть все просто:

stty echo


Но в скриптах желательно обрабатывать прерывания:

trap 'exit' INT HUP TERM
trap 'stty echo;tput cnorm' EXIT
# stop terminal echo
stty -echo
#hide cursor
tput civis


Применять исключительно для причинения добра.

man stty
man tput
help trap


🛠 #bash #linux #games

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
51
Самое тупое что можно сделать во время пятничного деплоя это быть трезвым!

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

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

Как я останавливался? Ооо брат, для этого есть охуенная практика.

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

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

Весь процесс у меня занимал примерно 15-30 минут. Как только я понимал, что продолжительное время тупо смотрю в одну точку и ни о чем не думаю, это становилось сигналом, что мои мозги максимально разгружены.

Да, нужно писать руками на аналоговом листике, это важно! Если писать в тот же обсидиан, то ничего не получается. Видимо в этом участвуют еще какие-то другие процессы организма. Ну или просто я долбаёб.


Эту практику я назвал — разгрузка говна.

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

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

Примеры

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

— Кот насрал в лоток. Хуйня! Вычеркиваем, делаем вид, что не заметил, уберет кто-то другой, есть кому. Автоматическое делегирование. Зачеркиваем.

— Новенький сотрудник не может подключиться по ssh к серверу. Так, ключ он мне отдал, я его прописал, должно работать. Скорее всего он душноёб и не указывает приватный ключ при подключении. Пусть идет нахуй. Зачеркиваем.

— Перестали собираться логи с сервера bashdays-b1, не собираются уже 90 дней, хм… Раз никто не пришел, эти логи нахуй никому не нужны. Что делаем? Зачеркиваем!

Ну ты понял! 99% твоих мыслей — ХУЙНЯ! Вычеркивай по максимуму! Обращай внимание только на важное — на вонь, которая будет тебе доставлять дискомфорт.

Ну а если и вонь тебя устраивает — её тоже вычеркиваем! И тогда ты прошел эту практику на 102%, собрал все ачивки, выполнил все квесты, красавчик!

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


Надо попробовать съебаться куда-нибудь и разгрузить говно, которое скопилось. И я уверен, что 99.9999% будет вычеркнуто!

Не благодари, попробуй, практика проверенная!

🛠 #рабочиебудни #remains

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
13146
Закрытие техдолга Q5_2025

Так ли хуёво легаси? Да наверное нет, оно же работает годами, приносит бабло бизнесу. А тут приходишь ты и начинаешь ссать в уши, что все гавно и ты щас все переделываешь.

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

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

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

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

Так что херовая идея приходить в команду и начинать орать — бля у вас тут везде гавно! Ну сделай, ага…

🛠 #рабочиебудни #remains

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
80
Сегодня ребята прикольно упиздякали свой продакшен. Ща расскажу.

В общем пиэм проводил эксперименты на тестовом сервере через вебморду, админка там все дела, чёто включал, удалял, в общем веселился парняга.

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

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

На тестовом сервере при сохранении формы, произошла переадресация на основной домен. Потому, что в nginx был какой-то сука роут.

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

Он был уверен, что все действия он выполняет на тестовой среде. А тестовая среда один в один копия продакшена. Классический кейс.

Такие пироги. И пришлось мне сегодня всё утро разгребать эти конюшни.

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

🛠 #рабочиебудни #remains

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
144
Давненько Bash годноты не было. Лови.

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

Что прикольно, это не 100500 страниц текста, это прям выжимка-концентрат.


Написал её некий Дэйв Эдди в рамках серии статей — YSAP (You Suck at Programming) или по-русски — «Ебать ты лох».

Преисполниться можно тут

Ну и из терминала можно прям почитать так:

curl style.ysap.sh


Ну а кому формат чтива не заходит, на это руководство есть видео ролики от того же иностранного гражданина.

Все ссылки на гитхабы-хуябы найдешь там же. Изучай!

Ну и совсем скоро у меня выходит брошюра, Bash для девопс-инженеров, там аналогичная выжимка-концентрат, но с упором на CI/CD и т.п. Анонс будет отдельно.


🛠 #bash

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
3114
Существует распространенное заблуждение — если сходить в отпуск, то по возвращению, работа заиграет новыми красками.

ХУЙ ТАМ ПЛАВАЛ! Если у тебя появились такие мысли, то ты работаешь на нелюбимой работе. А поход в отпуск для тебя является, мифической чертой, переступив которую тебе кажется, что все изменится.

НИХУЯ!

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

Не думаю, всё это ХУЙНЯ мнимая, игры разума. Отпуск и праздники это обычные дни, ничего не изменится в твоей работе после того как ты отдохнул.

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

Поэтому бери эти мудрые знания себе на заметку и в момент, когда твой выгоревший мозг захочет «похалявить» пару неделек, задай себе вопрос — а изменится ли что-то после моего отдыха? НЕА!

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

Ну и самый действенный способ — высыпаться. Ложиться спать в 10-11 вечера, вставать в 7-8 утра. Ну и естественно сон должен быть трезвым. Тут уже и финансовая подушка не понадобится, хватит обычной из магазина.

Вот и весь секрет успеха. А отпуск это самообман и наёбка.

🛠 #рабочиебудни #remains

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
7127
Поднимаем свой «Хероку»

Наверняка все знают Heroku. Если кратко, эта херотень позволяет запускать приложения. Будь то веб-приложения, докер-контейнеры и т.п. без необходимости настраивать и поддерживать серверную инфраструктуру.

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

У меня раньше телеграм боты в heroku успешно крутились, потом эти письки закрыли бесплатный план и пришлось мигрировать.


Принцип работы простой:

1. Пушишь свой код в git
2. Условный «Heroku» это видит через webhook
3. Забирает код и собирает
4. Запускает в изолированном контейнере
5. Маршрутизирует трафик в контейнер

Чтобы развернуть всё это дело на своих серверах и никому не платить, можно воспользоваться двумя более-менее хорошими opensource проектами.

➡️ Dokploy и Coolify

Coolify более раскручен, но по сути те же яйца, только с боку.


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

Да, можно поднять в докере и не ебать мозги.


Но я предпочитаю всё же использовать k3s либо docker compose, потому что Dekploy и Coolify ты вряд ли встретишь в компаниях, они более нишевые.

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

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


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

🛠 #selfhosting

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
251
Если тебе необходимо изменить файл сервиса в Linux, не нужно пиздовать ручками в папку /etc/systemd искать и править его.

Постоянно вижу этот кейс, чёто там ищут по папкам, ебутся. Правят оригинальный файл и все к хуям ломают.


А бест-практика уже заложена в systemctl!

Достаточно выполнить команду:

sudo systemctl edit nginx


Откроется редактор с нужным сервисом. НО, редактировать ты будешь не корневой юнит, а override. То есть прокладку, которая переопределит параметры основного юнита.

В моём случае с nginx будет открыт файл:

/etc/systemd/system/nginx.service.d/override.conf

В нем я переопределяю нужные параметры для сервиса и НЕ трогаю основной файл юнита.

А если я хочу править корневой?

Да похуй, вот тебе команда:

sudo systemctl edit --full nginx


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

1. Копирует оригинальный юнит-файл из /lib/systemd/system/nginx.service в /etc/systemd/system/nginx.service

2. Открывает его в редакторе.

3. После сохранения — systemd использует именно эту копию в /etc/.

Это безопасный способ редактировать полные юниты, без риска перезаписи при обновлении пакетов.

Есть еще ключ --force, но про него погугли сам.


Как проверить валидность файла юнита?

systemd-analyze verify /etc/systemd/system/nginx.service


В ответ получишь:

/etc/systemd/system/nginx.service:31: Missing '=', ignoring line.


Ага, ошибочка, правим и только после этого можно делать:

sudo systemctl daemon-reload
sudo systemctl restart nginx


Короче учись работать правильно и всё у тебя будет хорошо!

С пятницей! Хороших тебе предстоящих выходных и береги себя!

🛠 #linux #tricks #debug #systemd

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
8211
Сегодня будем профилировать Linux сервисы.

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

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

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


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

systemd-analyze blame


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

17.084s docker.service
10.961s systemd-journal-flush.service
7.595s containerd.service
7.496s cloud-final.service
7.189s cloud-init-local.service
3.260s apt-daily-upgrade.service
2.522s cloud-init.service
2.095s dpkg-db-backup.service
1.991s networkd-dispatcher.service
1.963s chrony.service


В моём примере дольше всего грузится служба с докером.

Отрубаем службу и радуемся приросту в 17 секунд. Но НЕТ! На самом деле тут всё немного сложнее.

Иногда сам юнит стартует достаточно быстро, но сука ждет другой юнит, который «Блиц — скорость без границ».

Смотрим цепочку зависимостей:

systemd-analyze critical-chain


└─docker.socket @13.269s +8ms
└─sysinit.target @13.261s
└─cloud-init.service @10.735s +2.522s
└─systemd-networkd-online.service @12.806s +31ms
└─systemd-networkd.service @12.741s +59ms


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

То есть docker.service зависит от systemd-networkd-wait-online.service, ну и дальше пошли по цепочке.

Почему так?

Docker по умолчанию может иметь After=network-online.target, а при использовании systemd-networkd это приводит к ожиданию systemd-networkd-wait-online.service.

А чё делать?

Выйти из айти, купить яхту и поехать ловить крабов.

Если тебе нужно, чтобы Docker НЕ ждал сеть, поменяй юнит:

sudo systemctl edit docker.service


[Unit]
After=network.target
Wants=network.target


Ну или вообще убрать After=network-online.target, если нет зависимости от сети на старте.

После этого снова смотрим выхлоп через blame:

4.739s cloud-init-local.service
4.041s containerd.service
2.329s dev-sda1.device


Всё блядь! Теперь докер не тормозит загрузку, но после загрузки системы докер исправно работает.

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

Забирай в копилку, для дебага маст-хев!

🛠 #linux #tricks #debug #systemd

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
3128
Как безопасно тестировать юниты

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

Но не знаем как всё это дело тестировать. А для тестирования тебе пригодится ключик --runtime.

Ключ --runtime — создаёт временное переопределение, которое исчезнет после перезагрузки.


Идеально подходит, если ты тестишь, не уверен или не хочешь ничего портить.

А вот и сама команда:

SYSTEMD_EDITOR=vim systemctl edit --runtime nginx


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


Всё! Теперь правим юнит, тестируем. Временный файл с override будет создан тут /run/systemd/.

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

А какая в этом польза?

1. Для временного изменения конфигурации systemd без затрагивания оригинального файла.

2. Для тестов или отладки (например, сменить ExecStart для nginx только на время текущей сессии).

3. Чтобы не создавать перманентные изменения, которые могут повлиять на стабильность после перезагрузки.

Пример с nginx

Хочу временно запустить nginx с другим конфигом! Создаю рантайм.

[Service]
ExecStart=
ExecStart=/usr/sbin/nginx -c /home/user/nginx-bashdays.conf


Перезапускаю nginx и радуюсь результату, теперь nginx запущен с другим конфигом.

А почему ExecStart идет дважды?

Хе брат, это очередная приколюха systemd. Оно очищает предыдущее значение ExecStart из основного юнита. А следующая строка задаёт новое значение.

Без этой хуйни systemd бы просто добавил вторую команду, не заменив первую.

Думаю на этом можно закончить. Я неочевидную базу выдал, а ты стал еще сильнее. Изучай и ничего не бойся!

🛠 #linux #tricks #debug #systemd

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
156
Как разгребать гавно в юнитах

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

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

Короче, все что нам нужно это команда:

sudo systemctl revert nginx


Эта команда отменяет все локальные изменения юнита nginx и возвращает его к состоянию по умолчанию, заданному в оригинальных unit-файлах, поставляемых системой или пакетом.

Короче достаточно прикольная штука, когда нахуевертил, но не знаешь как откатиться.

Команда удаляем override-файлы в:

/etc/systemd/system/nginx.service.d/
/etc/systemd/system/nginx.service


И следом будет использован оригинальный unit-файл, который обычно расположен в /lib/systemd/system/nginx.service.

Когда это полезно?

Если ты вносил изменения через systemctl edit, вручную правил nginx.service, или добавлял drop-in'ы — и хочешь откатиться к дефолтной конфигурации, revert делает это безопасно.

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

Ну а ты носи в это в голове и никогда не бойся экспериментировать. Любой факап — твой опыт.

Предыдущие посты на тему systemd ищи по тегу #systemd


🛠 #linux #tricks #debug #systemd

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
463
Почему в юнитах не работает Environment.

Сразу пример:

[Service]
Environment="FOO=bar"
ExecStart=/bin/bash /usr/local/sbin/bashdays.sh


Сделал юнит, но в скрипт bashdays.sh не передаётся переменная FOO. Хотя логически всё правильно.

Тут снова приколы.

➡️ 1. Скрипт запускается не напрямую, а через интерпретатор.

Если в ExecStart указан скрипт с shebang’ом (#!/bin/bash), systemd запускает его как отдельный процесс, и переменные окружения передаются.

Но если ты укажешь в ExecStart сам интерпретатор, вот так:

ExecStart=/bin/bash /usr/local/sbin/bashdays.sh


То переменная FOO, заданная через Environment=, не попадёт в подскрипт, потому что ExecStart запускает bash, а уже bash запускает — скрипт, и переменные окружения само собой нихуя не передаются.

Как правильно?

Вот так:

[Service]
Environment="FOO=bar"
ExecStart=/usr/local/sbin/bashdays.sh


А сам скрипт:

#!/bin/bash

echo "FOO is $FOO"


Всё! Теперь переменная из юнита будет корректно передаваться в скрипт.

➡️ 2. Использовать EnvironmentFile=

Если у тебя дохуя переменных, то выносим их в отдельный файл, например сюда /etc/bashdays-service.env.

FOO=bar
BAZ=qux


А в самом юните прописываем:

[Service]
EnvironmentFile=/etc/bashdays-service.env
ExecStart=/usr/local/sbin/bashdays.sh


Всё! Теперь переменные считываются из файла и скрипт их видит.

➡️ 3. Передавать переменные прямо в ExecStart

[Service]
ExecStart=/bin/bash -c 'FOO=bar exec /usr/local/sbin/bashdays.sh'


Тут особо и комментировать нечего, всё очевидно.

Как отладить и задебажить?

А вот так:

systemctl show nginx


Вместо nginx подставляешь свой сервис и наблюдаешь все переменные которые передались. В наших примерах увидишь Environment=FOO=bar.

Справедливо не только для собственных юнитов, но и для других, например для того же nginx или docker.

Как вариант, можешь добавить в скрипт такую хуйню:

env > /tmp/env.log


И смотришь, какие переменные реально передаются в твой скрипт.

Еще одна база выдана, вроде очевидные вещи, но так глубоко в это никто не лезет. Пользуйся.

🛠 #linux #tricks #debug #systemd #bash

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
786
Три скрытых героя systemd

А вот и сами герои: timer, path и socket

Это невидимые юниты systemd, которые могут заменить cron, inotify`и даже `xinetd.

➡️ 1. Timer

Про timer ты наверняка слышал. Это альтернатива crontab. Позволяет запускать сервис по расписанию. Вместо того чтобы писать крон-джобы, ты создаёшь .service и .timer.

Пример:

/etc/systemd/system/backup.service

[Unit]
Description=Backup job

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup.sh


/etc/systemd/system/backup.timer

[Unit]
Description=Run backup daily

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target


Активируем:

sudo systemctl enable --now backup.timer


Persistent=true гарантирует запуск пропущенной задачи, если система была выключена.

Всё! Никаких тебе легаси кронтабов, все работает на юнитах, запускается бэкапилка, тикает таймер.

➡️ 2. Path

Работает как inotifywait или File Watcher: следит за файлами/папками и запускает сервис при изменении.

Пример:

/etc/systemd/system/upload.path

[Unit]
Description=Watch upload folder

[Path]
PathModified=/var/www/bashdays/upload
Unit=process-upload.service

[Install]
WantedBy=multi-user.target


/etc/systemd/system/process-upload.service

[Unit]
Description=Process uploaded files

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/process-upload.sh


Теперь каждый раз когда в папке /var/www/bashdays/upload что-то меняется, автоматически запускается скрипт process-upload.sh.

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


➡️ 3. Socket

Заменяет ручной systemctl start, активируя сервис при первом подключении к сокету. Аналог inetd/xinetd

Нихуя не понятно, но на примере сейчас всё прояснится.

Пример:

/etc/systemd/system/echo.socket

[Unit]
Description=Echo socket

[Socket]
ListenStream=12345
Accept=yes

[Install]
WantedBy=sockets.target


/etc/systemd/system/echo@.service

[Unit]
Description=Echo service

[Service]
ExecStart=/usr/bin/nc -l -p 12345 -e /bin/cat
StandardInput=socket


В примере, сервис НЕ работает постоянно, он стартует, только когда кто-то подключается к порту 12345.

Когда ты используешь .socket с Accept=yes, systemd открывает сокет сам и ждёт подключения. А когда подключение приходит — создаёт новый экземпляр сервиса, подставляя туда данные об этом соединении. После завершения — сервис умирает. Всё очень экономно и прозрачно.

Как понять, какой экземпляр стартует?

systemd запускает echo@<ID>.service, где <ID> — уникальный идентификатор подключения (например, PID или номер сокета).

journalctl -u echo@*


Зачем нужны скрытые юниты?

1. Не нужен cron, всё централизовано в systemd.
2. Не нужен inotify-tools.
3. Сервисы не висят без дела, запускаются только когда нужно
4. Журналирование через journalctl

Вот такие пироги. В повседневной работе я применяю timer и path, с сокетами как-то сильно не приходилось париться.

Ну а ты попробуй хотя бы перетащить свои кронджобы в timer и порадоваться бест-практикам.

🛠 #linux #tricks #debug #systemd #bash

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
9107
Продолжаем ковырять systemd

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

Делается это так:

systemctl --user enable bashdays.timer


Ключ --user означает, что команда применяется в пользовательском пространстве, а не на уровне всей системы.

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

Эта штука создаёт символическую ссылку в ~/.config/systemd/user/ в директории default.target.wants/

Если тебе нужно разово запустить такой юнит, то enable меняем на start. Вот и вся наука.

А как отлаживать?

➡️ 1. Сначала нужно убедиться что таймер активен:

systemctl --user status bashdays.timer


Если всё ок, то увидишь Active: active (waiting).

➡️ 2. Смотрим расписание запуска

systemctl --user list-timers


- NEXT — когда следующий запуск
- LEFT — сколько осталось времени
- LAST — когда запускался в прошлый раз
- UNIT — имя таймера

➡️ 3. Проверяем выполнялся ли сервис

journalctl --user-unit bashdays.service --since "1 hour ago"


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

journalctl --user-unit bashdays.service --since today


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

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

🛠 #linux #tricks #debug #systemd #bash

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
362
Продолжаем разбирать systemd на кирпичики. Сегодня про кандишены (условия/ситуации).

Директива ConditionPathExists используется в юнит-файлах systemd и позволяет задать условие для запуска юнита: он будет запущен только если указанный файл или директория существует.

Пример:

[Unit]
Description=Special Service
ConditionPathExists=/etc/bashdays-config

[Service]
ExecStart=/usr/local/bin/bashdays-handler


Этот юнит не запустится, если файл /etc/bashdays-config не существует. В статусе сервиса ты увидишь:

ConditionPathExists=/etc/bashdays-config was not met


Если путь НЕ существует, systemd не будет запускать юнит. Вместо этого он будет считаться пропущенным (skipped), а не проваленным.

Нахуя это надо?

1. Например, если bashdays-config существует, запускается сервис с особым поведением.

2. Можно создавать один юнит, который активируется только при наличии определённого модуля или плагина.

3. Иногда это используют в early boot-юнитах, чтобы запускать их только если что-то доступно (например, том LUKS).

Список основных Condition's (нажми на спойлер)

ConditionPathExists — файл или каталог существует
ConditionPathIsDirectory — путь существует и это каталог
ConditionPathIsMountPoint — путь является точкой монтирования
ConditionFileIsExecutable — файл существует и он исполняемый
ConditionKernelCommandLine — есть ли параметр ядра с указанным значением
ConditionPathExistsGlob — совпадает ли хотя бы один путь по glob-шаблону
ConditionPathIsSymbolicLink — является ли путь символической ссылкой
ConditionFileNotEmpty — существует ли файл и не пуст ли он
ConditionEnvironment — установлена ли переменная окружения
ConditionArchitecture — архитектура CPU (например, x86_64, aarch64)
ConditionVirtualization — nип виртуализации (например, kvm, docker)
ConditionHost — имя хоста
ConditionMachineID — cовпадает ли machine-id
ConditionControlGroupController — есть ли указанный cgroup controller (например, cpu, memory)
ConditionNeedsUpdate — нуждается ли в обновлении (/usr или /etc)
ConditionFirstBoot — Первый ли это запуск после установки
ConditionACPower — Подключено ли питание от сети (для ноутбуков)
ConditionSecurity — Активен ли определённый LSM (например, selinux)
ConditionUser — Запускается ли от указанного пользователя
ConditionGroup — Запускается ли от указанной группы
ConditionCapability — Имеет ли процесс определённую capability
ConditionNetwork — Есть ли сеть (online, configured)
ConditionMemory — Есть ли минимум указанного объёма памяти


Дополнительно

Если заменить Condition на Assert, условие не выполнено — юнит считается проваленным, а не пропущенным.

То есть берем к примеру директиву ConditionPathExists и меняем её на AssertPathExists.

AssertPathExists=/etc/bashdays.conf


И получается:

ConditionPathExists — юнит пропускается (не считается ошибкой)

AssertPathExists — юнит падает (считается ошибкой)

Assert полезен, когда ты строго требуешь, чтобы ресурс (например, внешний диск, NFS, или другой том) был смонтирован перед запуском сервиса. Если его нет — это ошибка, а не «ну и похуй».

[Unit]
Description=Start backup script only if /mnt/backup is mounted
AssertPathIsMountPoint=/mnt/backup

[Service]
ExecStart=/usr/local/bin/backup.sh


Если /mnt/backup не смонтирован, systemd выдаст ошибку, и сервис не запустится.

Статус будет такой:

systemd[1]: Starting backup.service...
systemd[1]: backup.service: Failed with result 'assert'.


Ну и все это дело можно комбинировать:

ConditionPathExists=/mnt/backup
AssertPathIsMountPoint=/mnt/backup


Если /mnt/backup не существует — юнит пропускается.

Если существует, но не смонтирован — юнит заваливается.

Короче systemd не такой уж простой, как кажется с первого взгляда. На нём можно прям заебись логику построить и получить желаемое. Так что недооценивать его явно не стоит, это прям заебись комбайн.

🛠 #linux #tricks #debug #systemd #bash

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
673
This media is not supported in the widget
VIEW IN TELEGRAM
2886
Всем привет. Опять решил поделиться опытом своих провалов.

🔤🔤🔥🔤🔤🔤🔤

Вобщем, как-то раз я решил написать самоучитель по bash.

По традиции все учебники либо в html, либо в pdf. Я решил остановиться на pdf. Я начал писать в libreoffice, там есть экспорт в pdf. Пока писал - познакомился с markdown. И вдруг подумалось, markdown - такой классный, напрямик можно в гитхаб запихнуть. И в pdf конвертнуть с помощью pandoc можно. Вобщем, решил верстать в markdown.

Для начала познакомился с редакторами, которые умеют подсвечивать markdown (pluma, mousepad, geany) Вобщем, жить можно, но подсвечивается не всё.

После этого попробовал Apostrophe. Он уже умеет дополнительно показывать результат. Но работает медленно. Особенно на больших документах.

В общем - перепопробовал, - не нравится. Решил писать в mousepad, а потом конвертить с помощью pandoc.

Написал скрипт для удобства пользования - меняется дата файла - автоматом резервная копия версии и конвертация в фоне.

Начал работать и тут вскрылась куча недостатков markdown;

1. Нет нормального форматирования (заголовок нельзя центрировать)
2. Нет нормальных таблиц, один ущерб какой-то.
3. Проблема с кирилицей (решаемая), но с помощью дополнительного tex-файла настроек.
\usepackage{longtable}\setlength{\LTleft}{2em}
\setmainfont{Liberation Serif}
\setsansfont{Liberation Sans}
\setmonofont{Liberation Mono}
\newfontfamily\cyrillicfont{Liberation Sans}
\defaultfontfeatures{Scale=MatchLowercase, Mapping=tex-text}
\usepackage{polyglossia}
\setmainlanguage{russian}
\setotherlanguage{english}

4. Нет возможности печатать некоторые символы UTF.
5. некоторые символы приходится маскировать, чтобы они не понимались, как управляющие.

Единственный плюс - подсветка синтаксиса bash.

В общем, после 19 главы я понял, что моего терпения не хватит закончить работу. Вернулся к libreoffice. За два дня освоил работу со стилями, и все пошло как по маслу. Кстати, экспорт в pdf тоже быстрее, на мой взгляд.

Может и не все получилось, сами знаете - первый блин комом.

Замечания и комментарии приветствуются.

С результатом можно ознакомиться здесь 👇

🅰️🅰️
➡️ https://github.com/tagd-tagd/self-instruction
🅰️🅰️

🛠 #bash #linux #utilites #markdown

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
395
Сегодня будем убивать неугодные сервисы. Нет, тут будет не про kill и т.п. а будет все тот же systemd.

Короче в юните можно указать параметр RuntimeMaxSec, в нем задаём время жизни сервиса. Если сервис работает дольше указанного времени, то ему песда. Systemd принудительно завершит его.

Удобно применять для сервисов, которые не должны жить вечно. Нет ничего вечного! Например, временные задачи, вспомогательные демоны, скрипты и т.п.

[Service]
RuntimeMaxSec=30s


0s, 5min, 1h, 2d — интервалы
infinity — отключение лимита

А что будет если время вышло?

Как и написал выше — будет песда! Systemd пошлет SIGTERM. А если сервис сука живучий и не завершился, то в ход пойдет тяжелая артиллерия через TimeoutStopSec, тут уже будет послан SIGKILL. Но его нужно предварительно прописать.

TimeoutStopSec= — это время ожидания корректного завершения сервиса после того, как systemd послал ему сигнал SIGTERM.

[Service]
ExecStart=/usr/bin/python3 /opt/scripts/bashdays-task.py
RuntimeMaxSec=60


Этот сервис будет убит через 60 секунд после запуска — даже если скрипт ещё не завершился.

[Service]
ExecStart=/usr/bin/bashdays-daemon
RuntimeMaxSec=60
TimeoutStopSec=10


Если bashdays-daemon работает дольше 60 секунд → SIGTERM
Ждём до 10 секунд → если не завершился → SIGKILL

Частый паттерн

RuntimeMaxSec=300
TimeoutStopSec=5
Restart=on-failure


Сервис работает максимум 5 минут, и если завис — systemd подождёт 5 секунд на аккуратное завершение, а потом прибьёт его нахуй.

А нахуя тут Restart=on-failure?

Оно говорит — «если сервис завершился аварийно — перезапусти его» А завершение по SIGKILL из-за превышения времени жизни это и есть failure.

Если не указать TimeoutStopSec, будет использоваться значение по умолчанию: 90 секунд — порой это дохуя, поэтому предпочтительнее задать его руками.

Важный нюанс!

Если в юните используется Restart=always, то после убийства, сервис будет перезапущен и возможно сразу «помрёт» если не изменит своё поведение.

Такие дела, изучай!

🛠 #linux #tricks #debug #systemd #bash

@bashdays / @linuxfactory / @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
661