Bash Days | Linux | DevOps
23.4K subscribers
157 photos
24 videos
1 file
683 links
Авторский канал от действующего девопса

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

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

MAX: https://max.ru/bashdays

Курс: @tormozilla_bot
Блог: https://bashdays.ru
Download Telegram
Фиксим кривой Exit Code в docker

Во время работы с docker контейнером наткнулся на неочевидный код выхода (exit code).

Про exit codes (коды выхода) писал тут


Суть проблемы: Когда программа внутри контейнера падает с abort(), Docker возвращает неправильный код выхода. Вместо ожидаемого 134 (128 + SIGABRT), контейнер отдаёт 139 (128 + SIGSEGV).

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

Давай проверим:

#include <cstdlib>

int main() {
std::abort();
return 0;
}


Пишем Dockerfile:

FROM ubuntu:22.04

RUN apt-get update \
&& apt-get -y install \
build-essential \
&& rm -rf /var/lib/apt/lists/*

COPY ./ /src/
WORKDIR /src/
RUN g++ main.cpp -o app

WORKDIR /
CMD ["/src/app"]


Собираем и запускаем:

docker build -f ./Dockerfile -t sigabort_test:latest .
docker run --name test sigabort_test:latest ; echo $?


А на выходе у нас код: 139.

В примере выше код выхода — 139 = 128 + 11, где 11 соответствует SIGSEGV (ошибка сегментации), а не 134 = 128 + 6, что был бы SIGABRT (аварийное завершение).

Чтобы это пофиксить, нужно захерачить хак:

CMD ["bash", "-c", "/src/app ; exit $(echo $?)"]


docker run --name test sigabort_test:latest ; echo $?
bash: line 1: 6 Aborted /src/app
134


После этого контейнер будет возвращать корректный код 134.

Вариант рабочий, но костыльный. Правильнее использовать ключ --init.

Если запустить контейнер с флагом --init, используя исходную команду CMD ["/src/app"], мы получим ожидаемый 134 код. Что нам и нужно.

docker run --init --name test sigabort_test:latest ; echo $?

134


Почему init все починил?

Давай копнём глубже. В Linux процесс с PID 1 (init) имеет нестандартную семантику сигналов:

- Если у PID 1 для сигнала стоит действие «по умолчанию» (никакого обработчика), то сигналы с действием terminate игнорируются ядром. Это сделано, чтобы случайным SIGTERM/SIGINT нельзя было «уронить» init.

- PID 1 должен забирать зомби-процессы (делать wait() за умершими детьми). Если этого не делать, накопятся зомби.

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

Когда мы запускаем контейнер без --init, приложение становится PID 1.

Большинство обычных приложений (на C/C++/Go/Node/Java и т.д.) не написаны как «инит-системы», они не настраивают обработку всех сигналов, не занимаются «реапингом» детей и не пробрасывают сигналы. В результате вылазиют баги.


Наш сценарий с abort() (который поднимает SIGABRT) упирается именно в правила для PID 1. abort() внутри процесса поднимает SIGABRT.

Для обычного процесса с PID ≠ 1 это приводит к завершению с кодом 128 + 6 = 134. Но если процесс — PID 1, ядро игнорирует «терминирующие» сигналы при действии по умолчанию. В результате стандартные ожидания вокруг SIGABRT ломаются.

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

На практике это может приводить к тому, что ты видишь 139 (SIGSEGV) вместо ожидаемого 134 (SIGABRT).

И тут проблема не в docker, а в том, что приложение неожиданно оказалось в роли init-процесса и попало под его особые правила.

Вот и вся наука. Изучай.

🛠 #docker #devops #linux #debug

@bashdays @linuxfactory @blog
Please open Telegram to view this post
VIEW IN TELEGRAM
569
Как прокачать Minecraft сервер с помощью Angie

Накидал пост о том, как мы мигрировали minecraft сервер на выделенный сервер и защитились от ботов с помощью Angie, просто и эффективно.

Сюда по классике не влезло, всё в блоге 👇

Читать: https://two.su/bieb4

🛠 #angie #devops #security

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
550
Туалетная бумага по cron’у

Я короче каждый месяц заказываю на WB туалетную бумагу, сразу беру 32 рулона. В чатике ссылки как-то скидывал на этот товар.

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

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


Открытой API у WB нет, но реверс-инженерию никто не отменял. Открываем в браузере режим разработчика, натыкиваем нужные действия на сайте и потом смотрим вкладку Network. Выбираем нужные запросы и рожаем скрипт.

Концепт скрипта:

1. Авторизация. С ней я не стал заморачиваться, авторизовался на сайте, выгрузил кукисы в файл. Полюбому можно и это автоматизировать через curl, но чёт пока лень.

2. Скрипт принимает единственный параметр $1, это ссылка на товар WB, мало ли бумага моя закончится и придется другого поставщика искать.

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

Пример добавления в корзину:

RESPONSE=$(curl -s "https://cart-storage-api.wildberries.ru/api/basket/sync?ts=$TS&device_id=$DEVICE_ID" \
-X POST \
-H 'content-type: application/json' \
-H 'origin: https://www.wildberries.ru' \
-b "$COOKIES_FILE" \
--data-raw "$JSON_PAYLOAD"
)


Все параметры прилетают из $JSON_PAYLOAD, параметр автоматически заполняются нужными данными на основе переданного урла в $1, да, активно используется jq.

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

4. Ну и всё, в телегу мне приходит уведомление, что заказ оформлен, бабло спишут по факту. Ну и пишут примерное число доставки.

5. Как только товар пришел в пункт выдачи, получаю уведомление в телегу. Аналогично curl запросом проверяется статус в личном кабинете.

6. Закидываем скрипт в крон и забываем про эту рутину.

59 23 25 * * /usr/local/sbin/shit_paper.sh https://wb.ru/296/detail.aspx


Вот и вся наука. Теперь когда я возвращаюсь из гаража, захожу по пути в пункт выдачи и забираю свои 32 рулона. Удобно? Да охуенно!

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


Еще бы научить чтобы чайник сам в себя воду наливал, было бы вообще ништяк.

Давай, увидимся! Хороших тебе предстоящих выходных и береги себя!

🛠 #bash #devops

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
12292
Продолжаем ковырять angie, на этот раз посмотрим на Status Page, которая отображает всю статистику по веб-серверу. Выглядит прям хорошо.

Устанавливаем пакет:

sudo apt install angie-console-light


В папке /usr/share/angie-console-light/html появляется статика.

Добавляем локейшен:

location /console/ {
auto_redirect on;

alias /usr/share/angie-console-light/html/;
index index.html;

location /console/api/ {
api /status/;
}
}


Теперь открываем в браузере и видим красивую мордочку. Демо мордочки можешь посмотреть здесь.

Да, не забываем включить Basic Auth чтобы хитрожопые не подглядывали.

У меня на паре пет проектов эта морда включена (графана избыточна), чисто посмотреть статусы раз в сутки, которые возвращают 500ку. Если оно горит красным, значит что-то где-то пошло по пизде.


Подробнее читай в официальной документации.

🛠 #angie #devops

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
534
Load Average на пальцах

Все про него знают, но не все понимают.

Давай рассмотрим такие цифры:

0.30  1.20  0.80


1. За последнюю 1 минуту средняя очередь = 0.30
2. за 5 минут = 1.20
3. за 15 минут = 0.80

Сразу куча вопросов, а что такое «очередь»?

«очередь» == количество задач, которые хотят работать прямо сейчас, но процессоров не хватает, чтобы заняться всеми сразу.

➡️ Главное правило

Сравниваем Load Average с количеством ядер.

- У тебя 4 ядра → нормальная нагрузка = до 4.0
- У тебя 1 ядро → нормальная нагрузка = до 1.0
- У тебя 8 ядер → нормальная нагрузка = до 8.0

🟢 Всё в порядке:

- LA ≤ количество ядер → CPU успевает всё делать, очередей нет.

🟡 Чёт уже не то, подгрузилось:

- LA ≈ количество ядер × 1–2 → процессы начинают стоять в очереди, но система пока еще жива.

🔴 Жопа:

- LA сильно > количества ядер → процессы стоят в очереди, всё тормозит.


➡️ Теперь на котиках

Ты стоишь в магазине:

- 1 касса, 1 человек в очереди → заебись
- 1 касса, 10 человек в очереди → жопа
- 4 кассы, 6 человек → пока норм

CPU = кассы, Load Average == очередь.

LA это не про загрузку CPU в процентах — это просто «очередь».

➡️ Как задебажить

Берем top, htop или подобное и смотрим столбец %CPU, если один процесс жрёт 100% на однопроцессорной системе — он пидарас и забил ядро. Если процесс жрёт 300% на 4-ядерной — он занял 3 ядра.

Смотрим самых прожорливых пидарасов:

ps aux --sort=-%cpu | head


Если ничего не нашел, то смотрим в сторону:

- I/O wait — медленный диск / много дисковых операций
- много процессов, но каждый почти ничего не ест (fork storm)
- сеть или блокировки

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

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


🛠 #linix #devops

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
282
Разбираемся с options и inputs в gitlab

Частенько ребята с LF стали приходить с такой проблемой:

stages:
- deploy
variables:
ENVIRONMENT:
description: "Deployment environment"
value: "N/A"
options:
- "N/A"
- "STAGE"
- "PRODUCTION"
deploy:
stage: deploy
script:
- echo "Выбрано окружение:" "${ENVIRONMENT}"
rules:
- when: manual


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

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


Ошибок синтаксиса в ямликах нет, каких-то разумных сообщений и наводок от гитлаба тоже нет. Чё делать?

➡️ Решение

Идем: Settings → CI/CD → Variables и кликаем в радио-батон — Developer.

Всё! Теперь выпадающие списки вновь начинают работать.

А еще людей смущает новая штука inputs, которая совсем недавно появилась. Работает она с 17й версии.

spec:
inputs:
environment:
description: "Куда деплоим?"
type: string
default: "N/A"
options:
- "N/A"
- "STAGE"
- "PRODUCTION"
---
stages:
- deploy

deploy:
stage: deploy
rules:
- when: manual
script:
- echo "Выбрано окружение: $[[ inputs.environment ]]"


Оно будет пиздеть во внутреннем редакторе - Incorrect type. Expected "string | array".yaml-schema, но будет работать если запустить пайплайн.

Ошибка возникает, потому, что Pipeline Editor использует старый YAML-валидатор. Так что, не обращай внимание на этот пиздёж.


А зачем нам этот input ведь с options и так всё работает?

Ну хотя бы из-за типизированных параметров:

type: string | number | boolean | array


То есть:

- можно сделать чекбокс (boolean)
- можно сделать список (array)
- можно сделать ограничение по диапазону (number)
- можно сделать строгие варианты (options)
- можно сделать regex-валидацию

А обычный variables такого не умеют.

GitLab постепенно превращает CI в настоящий «Pipeline as Functions».

Например, в проекте А:

spec:
inputs:
env:
type: string
options: [stage, prod]
---
deploy-job:
script: deploy_to $[[ inputs.env ]]


И проекте B можно вызвать:

deploy:
trigger:
project: A
inputs:
env: prod


Это как вызов функции с аргументом.

Что еще:

- Inputs работают даже при trigger-пайплайнах
- Inputs могут быть required
- Inputs отображаются отдельно и аккуратно в UI
- Inputs часть нового стандарта GitLab CI Components

Короче одни плюсы. Но есть большое НООООО!

Это пиздец усложняет процесс разработки и отладку пайплайна.

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

Пока тебе хватает обычных options используй их. Не лезь в это ООП, оно пока рано и избыточно, особенно если ты новичок.

Изучай!

Как говорится — и не такие метели в ебало летели!

🛠 #devops #cicd #linuxfactory

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
740
Надоел и приелся VirtualBox/VMWare? Хочется новенького?

Да легко, опять же эта новая херабора как-то мимо многих прошла, включая меня. Нет это не LXC, vagrant и даже не docker.

Дело пахнет писюнами…


Короче, это — Multipass от Canonical. И да, полностью бесплатная и с мордой.

Выдумать ничего не буду, лови нативку с сайта:

Получите по ебалу мгновенную виртуальную машину Ubuntu с помощью одной команды. Multipass может запускать виртуальные машины и настраивать их с помощью cloud-init, как в общедоступном облаке. Прототип вашего облака запускается локально и бесплатно.


Работает под Linux, Wiundows, Mac

Что же это за зверь?

Multipass использует доступный гипервизор в зависимости от платформы:

- Linux — KVM
- macOS — HyperKit или QEMU
- Windows — Hyper-V или VirtualBox (в новых версиях QEMU)

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

Чё прикольно, для него есть Terraform провайдер, ну прям не инструмент, а золото.

terraform {
required_providers {
multipass = {
source = "larstobi/multipass"
version = "~> 1.4.2"
}
}
}


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

Ну либо headless (через командную):

Основные команды:

multipass launch --name foo
multipass exec foo -- lsb_release -a
multipass list
multipass stop foo bar
multipass start foo
multipass delete bar
multipass purge
multipass find
multipass launch -n bar --cloud-init cloud-config.yaml
multipass help


Из дистрибутивов только Ubuntu, но этого достаточно чтобы что-то протестировать либо погонять. Ребята в LF активно этим инструментом пользуются и создают тестовые кубер-кластера, ну и ансибл оттачивают.

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

В общем рекомендую, инструмент зачетный, никакой ёбли как VBox и VMWare.

🛠 #devops #vm #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
560
А вот это нам надо!

TUI админка для Proxmox. И да, ее можно поставить себе локально и цепануть к ней все твои Proxmox кластера, которые находятся где-то в сети.

Называется всё это добро — pvetui

Работает под всеми операционками, так как реализован на GO.

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

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


Установка и запуск:


go install github.com/devnullvoid/pvetui/cmd/pvetui@latest
/home/user/go/bin/pvetui


Под другие ОС:


yay -S pvetui-bin
yay -S pvetui-git
brew install --cask devnullvoid/pvetui/pvetui
scoop bucket add pvetui https://github.com/devnullvoid/scoop-pvetui
scoop install pvetui

# либо из исходников
git clone https://github.com/devnullvoid/pvetui.git
cd pvetui
make install


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

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

Но опять же если у тебя API ключ, делаешь под своё конфигурацию.


Инициализация, закончена, видим сообщение:

 Configuration is ready!
🔄 Please re-run 'pvetui' to start the application with your new configuration.
🚪 Exiting.


Запускаем морду и смотрим что получилось.

/home/user/go/bin/pvetui


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

А получилось у нас прям заебись. Теперь я нажимаю ALT+2 и попадаю в список всех своих виртуальных машин. Стрелочками выбираю нужную мне машину и нажимаю букву «m», открывается менюшка.

В менюшке можно сразу провалиться в машину по SSH, что мне и нужно. Но это еще не всё, там и ребуты и миграции, даже VNC есть (нужен xdg). Короче базовый минимум поадминить присутствует.

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

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

Хорошей тебе рабочей недели! Не болей!

🛠 #selfhosting #linux #devops

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
767
Как я обновил Proxmox и остался жив

Здрасти, приехали. Сегодня будем обновлять proxmox 8 на 9.1 Оно в принципе и необязательно, но очень хотелось потыкать новую фичу с OCI.

OCI это способ запускать контейнеры из Docker-образов. То есть proxmox теперь умеет скачивать Docker-образы (OCI-images) и превращать их в LXC-контейнеры.


А нахуя? Чтобы проще запускать приложения, которые уже существуют в виде Docker-образов. Теперь в LXC не нужно поднимать отдельно докер демон, все работает из коробки.

Ладно, отвлеклись. Про OCI отдельно распишу. Сегодня обновляем всю эту трихомудию до нужной версии.

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

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


По классике сюда всё не влезло, поэтому гоу в блог читать продолжение 👇

🅰️🅰️🅰️🅰️🅰️🅰️🅰️🅰️
➡️ https://two.su/4ui2c
🅰️🅰️🅰️🅰️🅰️🅰️🅰️🅰️

🛠 #proxmox #devops #selfhosting

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
1138
В Proxmox 9.1 завезли OCI. В предыдущем посте про обновление с 8ки на 9ку я это уже упоминал, поэтому повторяться не буду.

➡️ Как я обновлял Proxmox и остался жив


Сегодня посмотрим как OCI работает на практике.

OCI это не какая-то отдельная сущность, это тот же самый LXC контейнер в котором будет запущен нужный тебе контейнер.

Тут важное замечание — тебе не нужно устанавливать руками docker демона в LXC и только затем запускать контейнер. OCI все сделает само. Это не какой-то встроенный docker или k8s. Всё так или иначе работает под управлением LXC.

К примеру возьмем заезженный образ nginx, который валяется в dockerhub:

nginx:latest


Заходим в Proxmox и идем в раздел с шаблонами, там будет кнопка Pull from OCI Registry.

➡️ ЧИТАТЬ ПРОДОЛЖЕНИЕ


🛠 #proxmox #devops #selfhosting

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
622