Русский
Веб-версияОткрыть в Telegram
LLinuxSkill - Сводки с прода и Шпаргалки

LinuxSkill - Сводки с прода и Шпаргалки

@LinuxSkill · канал · Технологии · в индексе с 2026-05-29
10 697подписчиков−14 за неделю
895средний охват поста
8.4%ER — охват к подписчикам
12постов за 30 дней
L
LinuxSkill - Сводки с прода и Шпаргалки
Ходовой набор для отладки bash-скрипта известен всем: set -euo pipefail сверху, set -x вокруг мутного места и ловушка DEBUG с read, чтобы останавливаться перед каждой командой. Прогнал этот набор на Ubuntu 24.04, bash 5.2. Три вещи из него ведут себя не так, как ожидаешь. Сначала то, что работает без оговорок: # падаем на ошибке, пустой переменной и в пайпах set -euo pipefail pipefail не декорация: false | true без него даёт код 0, с ним 1. А set -u ловит то, до чего не доберётся проверка синтаксиса: echo "путь: /${UNSET_VAR}/data" # bash: UNSET_VAR: unbound variable Но `set -e` замолкает в условиях. Вызвал функцию через if — код возврата внутри перестал что-либо значить: check() { false; echo "функция продолжила"; } if check; then :; fi # echo выполнился, rc=0 Трассировка. Обычно пишут просто set -x, но дефолтный PS4 печатает голый плюс — в скрипте на 300 строк не поймёшь, где ты: PS4='+ ${BASH_SOURCE}:${LINENO}: ' set -x do_something_risky set +x Теперь в каждой строке трассировки видно файл и номер: + g.sh:4: mkdir -p /tmp/zz Пошаговый режим. Типовой рецепт — функция с read и ловушка DEBUG: dbg() { read -p "$BASH_SOURCE:$LINENO? " _; } trap 'dbg' DEBUG В нём три поломки, и каждая тихая. Первая: $LINENO и $BASH_SOURCE внутри функции указывают на саму функцию. На всех командах печаталось line=3 — строка, где стоит read. Реальные 6 и 7 не появились ни разу. Координаты надо передавать аргументами: dbg() { read -r -p "[$1:$2] $3? " _; } trap 'dbg "$BASH_SOURCE" "$LINENO" "$BASH_COMMAND"' DEBUG Вторая: ловушка не заходит внутрь функций. Без set -T виден только вызов work, а команды в её теле пропадают — как раз там, где обычно и прячется баг. set -T Третья самая злая. read в ловушке читает тот же stdin, что и скрипт. Подал в цикл три строки — дошла одна: printf 'alpha\nbeta\ngamma\n' | bash f.sh получил: beta Две строки съела отладка — отладчик изменил поведение отлаживаемого. Плюс при неинтерактивном stdin приглашение read -p не п
18 · 1.8K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Посмотреть, какие интерфейсы подняты, и не принять погасший порт за живой Краткий статус интерфейсов ip -4 -br address show up Нюанс: up фильтрует по состоянию линка, а не по наличию адреса. Погасил eth0 — с ключом он пропал из вывода совсем, без ключа виден как DOWN со всеми адресами на месте. Пустая строка тут не значит «адреса нет». Второй адрес без алиасов вида eth0:1 ip address add 10.0.0.50/24 dev eth0 ip address del 10.0.0.50/24 dev eth0 Второй адрес встаёт рядом с первым, при удалении линк не дёргается. Узнать, куда реально пойдёт пакет ip route get 8.8.8.8 # 8.8.8.8 via 192.0.2.1 dev eth0 src 192.0.2.2 Не читает таблицу, а спрашивает у ядра готовое решение вместе с исходящим адресом. Для локального ответит local 192.0.2.2 dev lo. Увидеть все таблицы маршрутизации ip route show table all Обычный show дал одну строку, table all — шесть, включая local с broadcast и host-маршрутами. С VPN и контейнерами разница уходит в десятки строк. Посмотреть, кто есть в сети рядом ip -4 neigh show ip -6 neigh show Нюанс: ip neigh — не ARP-таблица, как пишут в шпаргалках, а таблица соседей: ARP плюс IPv6 NDP. Без ключа -4 или -6 получишь обе вперемешку. arp -n показывал только первую, отсюда и путаница. Сбросить кэш соседей ip -s -s neigh flush dev eth0 Нюанс: без -s -s команда молчит и отдаёт код 0 — не отличишь «очистил десять записей» от «там было пусто». С ключом печатает удалённые записи и итог *** Round 1, deleting 1 entries ***. Дать интерфейсу второе имя без даунтайма ip link property add dev eth0 altname eno2 altname eno2 появляется в ip link show eth0, и по новому имени интерфейс находится: ip address show dev eno2 отдаёт eth0. Есть с ядра 5.8 и iproute2 5.8, на RHEL 7 синтаксис не разберётся. Всё, что пишет, требует CAP_NET_ADMIN — в контейнере без --cap-add=NET_ADMIN упадёт. А вы ip route get в отладке применяете или сразу лезете в show? #Linux #iproute2 #Networking #DevOps #Debug
31 · 1.5K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Закрыть системные файлы от правки и не получить молча сломанный useradd Запретить правку файла даже руту chattr +i /etc/passwd Нюанс: useradd после этого выдаёт cannot open /etc/passwd и завершается с кодом 0. Пользователь не создаётся, скрипт не падает, мониторинг молчит. Снял атрибут — создался. Разрешить логу только дозапись chattr +a /var/log/secure Нюанс: ротация делается переименованием, а его атрибут не пускает. Запустил logrotate на таком файле: error: failed to rename: Operation not permitted rc=0 Снова ноль на выходе. Файл не ротировался, cron считает, что всё прошло, логи растут до конца места. Найти файлы с SUID и SGID find / -xdev -perm /6000 -type f -ls 2>/dev/null Нюанс: без -xdev поиск по корню вернул ноль файлов и код 1 — захлебнулся на /proc. С ним нашлось 16 штук. Пустой вывод легко принять за чистую систему. Старый синтаксис +6000 GNU find уже не понимает, отвечает invalid mode. Выдать права одному пользователю setfacl -m u:lisa:rw file setfacl -b file Единственное место без подвоха. После первой команды в ls -l появляется плюс: -rw-rw-r--+, после сброса исчезает — по нему и замечают ACL. Поставить наблюдение за файлом auditctl -w /etc/passwd -p wa -k pwd_change Нюанс: правило живёт до перезапуска auditd. Постоянные пишутся в /etc/audit/rules.d/audit.rules. Закрыть входящий трафик, оставшись в сессии iptables -A INPUT -m conntrack \ --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -P INPUT DROP Порядок именно такой: политика последней. iptables -P INPUT DROP первой командой на удалённом сервере обрывает соединение сразу. И два уточнения: -m state до сих пор принимается, но актуален -m conntrack --ctstate, а iptables -V на 24.04 отвечает v1.8.10 (nf_tables) — правила уезжают в nftables. У двух худших находок общее одно: команда не сработала, а код возврата ноль. Мониторингом такое не ловится. А вы chattr +i на боевых конфигах стави
22 · 1.6K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Пробросить TCP через WebSocket мимо DPI и не собрать по дороге утечку сокетов websocat — консольный клиент вебсокетов на Rust, авторства Виталия Шукелы. Соединение начинается с обычного HTTP-рукопожатия Upgrade, поэтому фильтр видит легитимный веб-трафик. Проверял на версии 1.14.0, скачанной статическим бинарником с релизов. Пробросить локальный TCP-порт в вебсокет websocat --binary -E \ tcp-l:127.0.0.1:8080 ws://example.com/socket Нюанс: без -E websocat печатает предупреждение про утечку сокетов при обслуживании нескольких клиентов. У меня оно вылезало на каждом запуске туннеля, с флагом лог чистый. Держать сессию живой на нестабильной сети websocat -t --ping-interval 10 \ - autoreconnect:ws://example.com/socket Нюанс: autoreconnect: требует двух аргументов. Вариант с одним, который ходит по подборкам, падает: Specify ws:// or wss:// URI to connect to a websocket. Первым аргументом идёт источник данных — - для stdin или tcp-l: для туннеля. Проверил разрыв: поднял клиент раньше сервера, в логе Reconnecting failed, процесс жив. Сервер появился — соединение поднялось само. Отправить одно сообщение и выйти echo "get_metrics" | websocat -1 ws://example.com/socket Отправляет ровно один фрейм из stdin и закрывает сессию. Удобно дёргать из скрипта. Локальный эхо-сервер вернул get_metrics и завершился с кодом 0. Пробить туннель на тестовый сервер с самоподписанным TLS websocat -k wss://staging.example.com/socket Флаг -k отключает проверку сертификата. Для стенда годится, дальше стенда — нет: MITM на таком туннеле не отличить от обычной работы. Из полезного при отладке: websocat -t ws-l:127.0.0.1:1234 mirror: поднимает локальный эхо-сервер, на котором можно проверить свою команду, не выходя наружу. Честный минус — синтаксис. Аргументы это цепочки специферов вида overlay:addrtype:address, и с непривычки половина попыток заканчивается Invalid command-line parameters. Плюс инкапсуляция в кадры съедает скорость, а на больших объёмах приходится крутить
18 · 1.9K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Если гоняешь ansible по сотне серверов, SSH каждый раз делает хендшейк заново Переиспользовать одно TCP-соединение # ~/.ssh/config Host * ControlMaster auto ControlPath ~/.ssh/sockets/%C ControlPersist 10m Замерил на локальном sshd: первое подключение 0.22 секунды, второе и третье — по 0.01. Разница в двадцать раз, и это на loopback, где сети как таковой нет. На реальном канале с задержкой выигрыш будет больше. Каталог ~/.ssh/sockets надо создать заранее, сам он не появится. Не упереться в лимит длины пути Нюанс: %C тут не для красоты. Классический %r@%h:%p на длинных именах хостов выходит за предел, и ssh отказывается работать: ControlPath too long ('/root/.ssh/sockets/xxx... [email protected]:2222' >= 108 bytes) Проверил на пути в 109 байт — ровно на границе. %C даёт хеш фиксированной длины и снимает вопрос совсем. Проверить, жив ли мастер ssh -O check user@host Отвечает Master running (pid=924). Пригодится, когда непонятно, идёт ли новая сессия через кеш или поднимает соединение с нуля. Сбросить залипшую сессию ssh -O exit user@host Печатает Exit request sent. и удаляет файл сокета. Нужно, когда на сервере поменялись ключи или конфиг, а мастер держит старую сессию. Нюанс: если мастер-процесс умер не сам, а был убит, файл сокета остаётся сиротой. Прибил мастера через kill -9 — -O check стал отвечать Connection refused, но новое подключение прошло нормально: ssh увидел мёртвый сокет и поднял соединение заново. Честный минус: ноутбук ушёл в сон с активным сокетом — при пробуждении получишь висящую сессию и таймаут вместо мгновенного входа. Лечится тем же -O exit, но сначала надо догадаться, что дело в нём. А вы ControlPersist держите глобально на Host * или включаете точечно? #Linux #SSH #Ansible #DevOps #Terminal
16 · 1.9K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Как достать пароль из kdbx, когда графика легла и буфер обмена недоступен Всё проверено на keepassxc-cli 2.7.6 из репозитория Ubuntu 24.04. Посмотреть, что вообще есть в базе keepassxc-cli ls -R database.kdbx Нюанс: без -R увидишь только верхний уровень. Вложенные записи в группах не покажет — легко решить, что база пустая. Вытащить конкретный пароль в терминал keepassxc-cli show -a Password database.kdbx "Production/DB" Нюанс: обычный show без ключей выводит Password: PROTECTED вместо значения. Флаг -s раскрывает все поля, -a Password отдаёт только пароль одной строкой — удобно подставлять в скрипт. Открыть базу с файлом ключей keepassxc-cli ls -k keyfile.key database.kdbx Тот же -k работает во всех подкомандах. Если пароля на базе нет вообще, добавь --no-password, иначе утилита будет ждать ввода. Найти запись, когда не помнишь путь keepassxc-cli search database.kdbx "DB" Вернёт полный путь вида /Production/DB, который дальше подставляется в show. Забрать всю базу разом keepassxc-cli export -f csv database.kdbx Отдаёт в stdout все записи вместе с паролями открытым текстом. Полезно при переезде, но перенаправлять это в файл на общей машине — плохая идея. Про clip, который советуют для копирования пароля в буфер. Именно в сценарии «GUI лёг» он и не работает: без графической сессии команда отвечает All clipping programs failed. Tried xclip. Смысл в нём есть только в живой графике, где он же и чистит буфер через 10 секунд. И про совет закрыть GUI перед работой в консоли. Проверил: при открытой базе KeePassXC создаёт рядом файл .kdbx.lock. Утилита о нём знает, так что «гарантированного повреждения» не будет — но менять базу из двух мест одновременно всё равно не стоит, последняя запись затрёт чужие правки. А вы держите пароли в локальных kdbx или переехали на self-hosted Vaultwarden? #Linux #KeePass #Security #CLI #DevOps
19 · 1.7K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Диски гостей раздулись, а внутри места полно. Вернуть его хосту — и не просадить запись Проверить, поддерживает ли диск discard lsblk --discard Нюанс: в подборках советуют hdparm -I /dev/sda | grep -i trim. На virtio-диске это не сработает вовсе — у меня вернуло Operation not permitted, потому что hdparm говорит по протоколу ATA, которого у виртуального диска нет. lsblk --discard показывает нужное для любого типа: NAME DISC-GRAN DISC-MAX vda 4K 1G vdb 0B 0B Ненулевые DISC-GRAN и DISC-MAX означают, что discard проходит. Нули — гипервизор его не отдаёт, дальше можно не настраивать. Отдать блоки хосту прямо сейчас fstrim -av --dry-run fstrim -av Сначала --dry-run: он делает всё то же самое, но без самого discard. У меня показал 0 B (dry run) trimmed on /dev/vda, а боевой запуск вернул 243.1 GiB trimmed. Настроить регулярный TRIM systemctl enable --now fstrim.timer systemctl list-timers fstrim.timer Нюанс: свой скрипт в /etc/cron.weekly писать не нужно — в пакете util-linux уже лежит готовый fstrim.timer с OnCalendar=weekly и разбросом запуска до 100 минут, чтобы виртуалки не пошли в discard одновременно. Если всё-таки делаешь через cron, помни про две вещи. Скрипт без строки #!/bin/sh не выполнится: run-parts: failed to exec: Exec format error. И файл с точкой в имени, вроде fstrim.sh, run-parts молча пропустит. Не включать онлайн-TRIM в fstab UUID=xxxx / ext4 defaults,discard 0 1 Опция discard при монтировании шлёт запрос на очистку при удалении каждого файла. Пакетный TRIM раз в неделю делает то же самое, но одним заходом и в спокойное время. Всё это работает, только если discard включён в настройках диска на самом гипервизоре. Иначе гость честно шлёт команды, а хост их игнорирует и продолжает копить мусор. А вы fstrim по таймеру гоняете или руками, когда место кончилось? #Linux #Virtualization #Proxmox #fstrim #DevOps
14 · 1.7K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Сервис упал ночью, до утра гигабайт логов. Порядок, в котором в них лезть Начать с ошибок текущей загрузки journalctl -p err -b -b отсекает всё, что было до последней перезагрузки, -p err оставляет уровень Error и выше. Цифровой вариант -p 3 делает то же самое, но словом читается лучше. Сузить окно до времени инцидента journalctl --since "2026-08-13 23:00:00" \ --until "2026-08-14 01:00:00" Нюанс: форматы вроде yesterday 23:00:00, которые кочуют по подборкам, systemd не разбирает — получишь Failed to parse timestamp. Проверил на systemd 255: отдельно yesterday работает, -2h работает, 23:00 работает, а вот их комбинация — нет. Надёжнее всегда писать полную дату. Посмотреть, не прибило ли сервис ядро dmesg -T --level=err,warn dmesg -T | grep -i oom-killer -T переводит секунды аптайма в нормальную дату. Фильтр по уровню полезнее грепа: покажет и OOM, и ошибки диска, и отвалившийся сетевой интерфейс. Проверить блокировки SELinux ausearch -m avc -ts recent Нюанс: на Debian и Ubuntu команда чаще всего вернёт пустоту — там AppArmor, а не SELinux, и /sys/fs/selinux просто нет. Шаг актуален для RHEL-семейства; на Debian смотри journalctl -t audit и dmesg | grep -i apparmor. Найти, кто сканирует сайт awk -F'"' '{split($3,a," "); if (a[1]==404) print $1}' access.log | awk '{print $1}' | sort | uniq -c | sort -rn Нюанс: ходовой вариант awk '$9 == 404' разваливается, если в URL попал пробел — поле уезжает, и строка молча не считается. У меня из трёх запросов с 404 такой вариант нашёл два. Разбор по кавычкам берёт код ответа там, где он реально лежит. Для пары серверов этого хватает. Когда машин десятки, CLI перестаёт работать и нужен Loki или ELK — но и там первый вопрос будет тот же: какое окно и какой приоритет. А с чего начинаете вы, когда прод упал и надо быстро локализовать причину? #Linux #Logs #journalctl #Troubleshooting #DevOps
24 · 1.6K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Прокинуть скрипт и каталог на сервер и не собрать по дороге чужие абсолютные пути Всё проверено на OpenSSH 9.6p1, подключением к живому sshd. Увидеть, какие параметры реально применились ssh -G user@host Отдаёт итоговый конфиг после разбора всех Host и Match: порт, пользователя, список шифров, таймауты. Быстрее, чем перечитывать ~/.ssh/config глазами и гадать, какая секция сработала. Если сессия висит — ssh -vvv покажет, на каком этапе. Выполнить локальный скрипт на сервере ssh user@host bash -s arg1 arg2 < ./script.sh Нюанс: -s обязателен, если передаёшь аргументы. Без него bash примет arg1 за имя файла и ответит No such file or directory. И второе: интерактивный read внутри такого скрипта работать не будет — stdin уже занят самим скриптом. Убрать устаревший ключ хоста ssh-keygen -f ~/.ssh/known_hosts -R '[10.0.0.1]:2222' Нюанс: для нестандартного порта нужен формат [host]:port в кавычках. Просто -R 10.0.0.1 строку не найдёт и молча ничего не сделает. Старый файл сохраняется рядом как known_hosts.old. Забрать каталог без промежуточных файлов ssh user@host "tar -cf - -C /data ." | tar -xC ~/bak/ Нюанс: -C на удалённой стороне обязателен. Вариант tar -cf - /data утащит в архив весь абсолютный путь, и локально ты получишь ~/bak/data/... вместо содержимого. Проверил — распаковалось именно так. Уйти в фон сразу после авторизации ssh -f user@host "sleep 300" Управление вернулось через 181 мс, при этом клиентский процесс продолжает висеть, пока команда не отработает. Удобно для проброса портов: ssh -f -N -L 9998:localhost:15672 user@host. Держать ключ в агенте ограниченное время ssh-add -t 30 ~/.ssh/id_ed25519 Через 30 секунд ключ уйдёт из памяти агента сам. Нюанс: без запущенного ssh-agent команда просто скажет Could not open a connection to your authentication agent. Про sshpass из подборок: он кладёт пароль в аргументы процесса, где его видно в ps любому пользователю системы. Для закрытого стенда — ладно, дальше стенда лучше ProxyJump и к
18 · 1.4K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Обойти массив путей с пробелами и не получить вместо одной папки три несуществующих. Перебрать элементы, не разорвав их по пробелам folders=("/var/log/nginx" "/var/log/app with space") for d in "${folders[@]}"; do ls -ld "$d" done Кавычки вокруг ${folders[@]} обязательны. Без них тот же цикл на моём тесте выдал четыре итерации вместо двух: путь распался на /var/log/app, with и space. И не путай @ с *: под кавычками "${folders[*]}" склеивает весь массив в одну строку. Посчитать элементы echo "${#folders[@]}" Нюанс: ${#folders} без [@] — это не размер массива, а длина первого элемента. У меня вернуло 8 вместо 3, и никакой ошибки. Обойти разреженный массив for i in "${!sparse[@]}"; do echo "$i = ${sparse[$i]}" done Нюанс: если удалить элемент через unset, индексы останутся с дырками. Массив с индексами 0, 5, 9 имеет размер 3 — обход по seq 0 2 найдёт один элемент из трёх. Перебирать надо индексы через ${!arr[@]}, а не числа от нуля. Прочитать файл в массив readarray -t lines < /var/log/app.log readarray -t lines < <(grep -v '^$' /var/log/app.log) Нюанс: cat file | readarray -t lines не работает. Пайп запускает readarray в подоболочке, массив заполняется там и умирает вместе с ней. У меня получилось 0 элементов вместо 4, снова без ошибки. Нужен либо редирект, либо подстановка процесса < <(...). Сделать словарь declare -A ports=([nginx]=80 [php-fpm]=9000) Нюанс: declare -A не формальность. Без него bash создаёт обычный индексный массив, все строковые ключи считаются нулём, и каждое присваивание перетирает предыдущее. Проверил: ${ports[nginx]} вернуло 9000 — значение от php-fpm. Общее у всех пяти: bash не ругается, а тихо делает не то. Поэтому shellcheck на скриптах с массивами экономит больше времени, чем кажется. А вы конфиги в bash разбираете ассоциативными массивами или сразу отдаёте jq? #Linux #Bash #Shell #Scripting #DevOps
19 · 1.7K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Выкинуть из скрипта форки awk и cut и не нарваться на подстановку, которая молчит Разобрать путь без basename и dirname path="/var/log/nginx/access.log.tar.gz" name="${path##*/}" # access.log.tar.gz dir="${path%/*}" # /var/log/nginx Замерил тысячу итераций в цикле: basename — 1107 мс, подстановка — 5 мс. Разница в двести раз, и это не про скорость самой утилиты, а про форк процесса на каждый вызов. Собрать файлы в массив вместо ls shopt -s nullglob files=(/var/log/nginx/*.log) cp -- "${files[@]}" /backup/logs/ Нюанс: без nullglob массив по несуществующей маске не пустой. Проверил — в нём оказался один элемент, сама строка /var/log/nginx/*.nosuch, и cp уедет с несуществующим файлом. shopt -s nullglob заставляет пустой glob разворачиваться в ноль элементов. Сравнить вывод двух команд без временных файлов diff <(ls -1 dir1) <(ls -1 dir2) <(...) подставляет путь вида /dev/fd/63, за которым стоит обычный pipe — проверил через ls -l. Нюанс: код возврата команды внутри скобок теряется, diff его не увидит. И это только bash: в dash тот же синтаксис даёт Syntax error, так что для #!/bin/sh не годится. Задать дефолт и проверить обязательные переменные : "${TIMEOUT:=30}" : "${DB_USER:?не задана}" Нюанс: двоеточие в :? обязательно. Вариант ${DB_USER?...} из подборок срабатывает только когда переменная не объявлена вовсе — пустую строку он пропускает, и скрипт идёт дальше с пустым логином. С :? тот же случай падает с кодом 127. То же и с :-: он подставляет дефолт, но не присваивает, переменная остаётся пустой. Собрать тайминги шагов скрипта PS4='+ ${EPOCHREALTIME} ' set -x Нюанс: в подборках сюда пишут PS4='+ $(date "+%s.%N") => ' — и это форк date на каждую строку трассировки, в посте про избавление от форков. Встроенная EPOCHREALTIME даёт то же время с микросекундами и без единого процесса. А что вы чаще выносите из скриптов — cut и awk или всё-таки оставляете, потому что читается понятнее? #Linux #Bash #Shell #Scripting #DevOps
14 · 1.6K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Найти на сервере скрытых рутов и не поверить проверке, которая их не видит. Найти лишние учётки с нулевым UID getent passwd | awk -F: '($3 == 0) {print $1}' Нюанс: в подборках пишут awk -F: '($3 == "0")' — со строковым сравнением. Оно пропускает UID, записанный как 00 или 0000. Проверил: завёл пользователя с -u 00, id показал uid=0(root), то есть для ядра это полноценный рут, а строковая проверка его не увидела. Без кавычек awk сравнивает числа и ловит все варианты. getent вместо cat /etc/passwd нужен, чтобы захватить пользователей из LDAP и SSSD. Убедиться, что root не пускают по SSH sshd -T | grep -i permitrootlogin Нюанс, и он главный. grep по /etc/ssh/sshd_config показывает то, что написано, а не то, что действует. Собрал стенд: в основном конфиге PermitRootLogin no, а в /etc/ssh/sshd_config.d/99-cloud.conf — yes. Строка Include стоит выше, drop-in побеждает: grep -> PermitRootLogin no sshd -T -> permitrootlogin yes Именно так выглядит типовой облачный образ. sshd -T печатает итоговую конфигурацию после всех включений. Проверить sudoers перед сохранением visudo -c -f /etc/sudoers.d/devops visudo без аргументов знают все, а вот -c -f работает с любым файлом и годится для CI или проверки после Ansible. На кривом правиле показывает строку и место ошибки, на нормальном — parsed OK. Заодно sudo -l покажет, что реально разрешено текущему пользователю. Найти SUID-бинарники find / -xdev -perm /6000 -type f -ls 2>/dev/null Нюанс: -perm -4000 -user root из чек-листов пропускает SGID. На моей машине разница 9 файлов против 12 — мимо проверки прошли chage, expiry, ssh-agent. Фильтр -user root тоже лишний: чужой SUID опаснее рутового, а он под этот фильтр не попадёт. И -xdev обязателен, иначе find захлебнётся на /proc. Про sudo -i вместо su спорить не буду, но помнить стоит другое: жёсткие правила в sudoers обходятся через less, find, awk и десяток других утилит — у всех есть побег в шелл. Разрешать по одной команде безопаснее, чем кажется, тол
20 · 1.4K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Смонтировать сетевую шару и не подвесить процессы, когда сервер отвалится. Убрать пароль из fstab mount -t cifs -o credentials=/etc/cifs-creds \ //10.0.0.10/share /mnt/samba Файл /etc/cifs-creds из трёх строк: username=, password=, domain=. Нюанс: chmod 600 на нём — целиком на вашей совести, mount права не проверяет и с файлом 644 отработает молча. Заодно проверьте, что каталог с ним не уезжает в бэкап открытым текстом. Отцепить зависшую шару umount -l /mnt/nfs Проверил на tmpfs: после -l каталог пуст и монтирования в mount больше нет, но процесс, державший файл открытым, спокойно дочитал его по старому дескриптору. Нюанс: -l убирает точку из дерева, а не освобождает ресурсы — пока живы процессы, ФС остаётся. Ищите их через lsof +D до того, как отцепите, иначе искать будет негде. -f имеет смысл только для NFS и только вместе с недоступным сервером, для cifs он почти ничего не даёт. Посмотреть, что отдаёт сервер showmount -e 10.0.0.10 Нюанс: showmount говорит по протоколу MOUNT, которого в NFSv4 нет вообще. На сервере с отключёнными v2 и v3 получите clnt_create: RPC: Program not registered — и это не значит, что сервер мёртв. Для v4 просто монтируйте корень экспорта: mount -t nfs4 10.0.0.10:/ /mnt. Монтировать по требованию, а не при загрузке //10.0.0.10/share /mnt/samba cifs noauto,x-systemd.automount,_netdev, credentials=/etc/creds 0 0 Нюанс: _netdev нужен наравне с x-systemd.automount. Без него systemd не знает, что монтирование сетевое, и может дёрнуть его до поднятия интерфейсов. Плюс x-systemd.idle-timeout= отцепит шару после простоя — на нестабильном канале это лучше, чем висящая точка. Не залипнуть на медленном NFS mount -t nfs -o soft,timeo=50,retrans=2 \ 10.0.0.10:/data /mnt/nfs timeo в децисекундах, так что 50 — это 5 секунд. По умолчанию для TCP стоит 600, то есть минута, да ещё с линейным ростом после каждой переотправки. Нюанс: man про soft пишет прямо — silent data corruption. Приложение получит I/O error, и если оно
22 · 1.4K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Не оставить пароль в bash_history и не удивиться, что он всё равно там оказался. Скрыть команду от истории mysql -u root -p'super_secret' Ведущий пробел, и строка не попадёт в ~/.bash_history. Работает, если в HISTCONTROL есть ignorespace. Нюанс: в Ubuntu это уже настроено, но по-разному. В /etc/skel/.bashrc стоит ignoreboth, а в root-сессии у меня было ignoredups:ignorespace. Проверьте своё: echo "$HISTCONTROL" Если пусто — трюк не сработает вообще, а вы будете уверены в обратном. Исправить опечатку в предыдущей команде systemctl status nginx-confg ^confg^config Заменяет и сразу выполняет. Нюанс: только первое вхождение. Проверил на echo aaa bbb aaa — после ^aaa^XXX получилось XXX bbb aaa. Для всех вхождений другая конструкция: !!:gs/aaa/XXX/ Открыть длинную команду в редакторе fc Вытаскивает последнюю команду в $EDITOR, после сохранения bash её выполняет. Нюанс: порядок поиска редактора — FCEDIT, потом EDITOR, и только потом vi по умолчанию. На голом сервере без vi получите bash: vi: command not found и никакого редактирования. Заранее пропишите export FCEDIT=nano или что вам ближе. Оживить терминал после вывода бинарника reset clear только прокручивает экран, а reset переинициализирует терминал целиком. Если и это не помогает — stty sane возвращает настройки ввода, когда не видно набираемых символов. Отвязать процесс от закрывающейся сессии bg disown -h %1 Нюанс: -h и без него — разные вещи. С -h задача остаётся в jobs, но не получит SIGHUP при закрытии терминала. Без флага задача исчезает из таблицы совсем. Проверил оба варианта, разница именно в этом. И про главное ограничение трюка с пробелом: он прячет команду от файла истории, но не от системы. Пока процесс жив, его аргументы видны в ps -eo args любому пользователю. Пароль в командной строке остаётся паролем в командной строке — читайте его из файла или переменной окружения. А чем вы правите длинные пайплайны — fc или сразу пишете в файл? #Linux #Bash #Terminal #Security #
18 · 1.2K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Собрать дерево каталогов одной строкой и не получить папку с фигурными скобками в имени. Создать вложенную структуру mkdir -p project/src/{configs,utils,tests} Нюанс: раскрытие скобок — фича bash, а не mkdir. В sh строка отработает буквально, создав каталог с именем {configs,utils,tests} — проверил, ошибки при этом никакой. То же будет от пробела после запятой и от одного элемента без запятой: {only} останется как есть. Если скрипт начинается с #!/bin/sh, скобки не использовать. Вернуться в предыдущий каталог cd - Нюанс: cd - печатает путь в stdout. В скрипте это мусор в выводе, а $(cd -) вообще бесполезен — подстановка уходит в подоболочку, и рабочий каталог самого скрипта не меняется. Для скриптов тише так: cd "$OLDPWD" Ходить по каталогам стеком pushd /var/log >/dev/null popd >/dev/null Нюанс: лишний popd возвращает directory stack empty и код 1. Под set -e скрипт на этом падает — а такое легко получить, если между pushd и popd стоит выход по ошибке. Перенаправление в /dev/null тоже нужно: обе команды печатают содержимое стека. Пройти сквозь симлинк cd -P /var/run Проверил на своём симлинке: обычный cd оставляет PWD равным /tmp/dd/link, с -P он становится /tmp/dd/real. Нюанс не в самом переходе, а в том, что будет дальше. Из link/sub команда cd .. вернёт в link, а cd -P .. — в real. Скрипт, который ходит относительными путями через симлинк, легко уедет не туда. Заодно pwd -P показывает физический путь, когда pwd показывает логический. Снести пустую цепочку каталогов rmdir -p a/b/c Поднимается снизу вверх, пока каталоги пустые. Нюанс: наткнувшись на непустой, останавливается с Directory not empty — но то, что успел удалить ниже, уже удалено. Возврата нет, так что для глубоких цепочек лучше сначала посмотреть find a -type d -empty. А вы по дереву каталогов ходите pushd или всё-таки алиасами и cd -? #Linux #Bash #Terminal #Scripting #DevOps
13 · 1.1K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Собрать архив с исключениями и не обнаружить потом, что исключения не сработали. Исключить каталог из архива tar --exclude='data/logs' -czf arch.tgz data Нюанс: --exclude обязан стоять до источника. Поставил после — tar честно предупредил --exclude 'data/logs' has no effect и всё равно упаковал логи. Второе: шаблон сравнивается с тем, как путь записан внутри архива. Упаковываете data, значит исключать надо data/logs, а не /tmp/ta/data/logs — с абсолютным путём совпадения не будет. Достать один файл из архива tar -tf arch.tar | grep app.conf tar -xf arch.tar tmp/ta/data/conf/app.conf Нюанс: при упаковке по абсолютному пути tar срезает ведущий слеш и пишет Removing leading '/' from member names. Поэтому распаковать по тому же абсолютному пути не выйдет — получите Not found in archive. Сначала посмотрите список через -t, потом копируйте путь оттуда. Дописать или удалить файл в архиве tar -rf arch.tar newfile.txt tar --delete -f arch.tar oldfile.txt Нюанс: только для несжатых архивов. На .tgz обе команды падают с Cannot update compressed archives и Error is not recoverable: exiting now. Чтобы поправить сжатый архив, его придётся распаковать целиком. Сжать быстрее и плотнее gzip tar --zstd -cf arch.tar.zst data На моих тестовых данных zstd дал 199 байт против 225 у gzip. Нюанс: если пакета zstd в системе нет, tar создаст файл нулевого размера и завершится с кодом 2. Файл при этом лежит на месте и выглядит как архив — в скрипте бэкапа такое заметят не сразу. Проверяйте код возврата, а не наличие файла. Не перезаписать свежие файлы при распаковке tar -xf arch.tar --keep-newer-files Работает: файл, который новее архивного, остаётся нетронутым, в выводе Current 'data/logs/a.log' is newer or same age. Нюанс: код возврата при этом 2, как при ошибке. Под set -e скрипт упадёт, хотя всё прошло по плану. Про сравнение архива с диском: tar -df arch.tar показывает Mod time differs и Size differs по каждому расхождению. Удобно проверить бэкап, не распаковыва
17 · 1.2K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Добавить пользователя в группу и не выкинуть его при этом из sudo Добавить во вторичную группу usermod -aG developers lisa Нюанс, ради которого стоит перечитать свои скрипты: без -a флаг -G не добавляет, а заменяет весь список. Было sudo,developers,ops — после usermod -G developers lisa осталось только developers. Ни ошибки, ни предупреждения, код возврата 0. Человек узнает об этом, когда в следующий раз наберёт sudo. Удалить из группы gpasswd -d bob developers Печатает Removing user bob from group developers. В отличие от usermod -G, трогает ровно одну группу. Сменить GID существующей группы groupmod -g 2000 developers find / -xdev -nogroup 2>/dev/null chgrp -R developers /data Нюанс: groupmod меняет запись в /etc/group, но файлы на диске остаются со старым числовым GID. У меня после смены ls -ld /data показал вместо имени голое 1004 — каталог стал ничьим. Ищите такие через find -nogroup и чините chgrp -R, иначе доступ к данным потеряется молча. Создать группу в скрипте groupadd -f developers groupadd -r pgsql Нюанс: обычный groupadd на существующей группе возвращает код 9 и роняет скрипт под set -e. Флаг -f делает операцию идемпотентной — то, что нужно для повторных прогонов Ansible или cloud-init. А -r создаёт системную группу: у меня она получила GID 996, обычная — 2002. Удалить группу groupdel testers Нюанс: если группа у кого-то основная, команда откажет — cannot remove the primary group of user 'bob', код 8. Вторичную удалит без вопросов, и у пользователей она просто исчезнет из списка. Про проверку: id -nG lisa показывает актуальный список из базы, а groups в чужой открытой сессии — то, что было на момент входа. Пользователь не увидит новых групп, пока не перелогинится или не выполнит newgrp. А вы группы раскатываете Ansible-модулями или скриптом с groupadd -f? #Linux #Security #Ansible #DevOps #Bash --- Что нашлось при проверке Главную ловушку воспроизвёл. Завёл lisa в sudo, developers, ops. После usermod -G developers lisa ос
18 · 1K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Закрыть периметр правилами iptables и не остаться при этом за дверью вместе с атакующим. Посмотреть, что слушает наружу ss -tulpn Даёт порт, состояние и процесс: 0.0.0.0:8099 users:(("python3",pid=3545,fd=3)). Первое, с чего начинается любой аудит — половина находок обычно в том, что сервис слушает 0.0.0.0 вместо 127.0.0.1. Найти, кто держит больше всего соединений ss -Hntu | awk '{print $5}' | sed 's/:[^:]*$//' | sort | uniq -c | sort -rn Нюанс: в шпаргалках этот однострочник идёт без -H и с cut -d: -f1. Оба места ломаются. Без -H в подсчёт попадает строка заголовка, и в топе появляется несуществующий адрес Local. А cut по первому двоеточию режет IPv6: адрес [2001:db8::2]:54321 превращается в [2001. Отсечение через sed берёт только порт с конца. Закрыть вход по умолчанию iptables -A INPUT -m conntrack \ --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -P INPUT DROP Нюанс: в подборках порядок обратный — сначала -F, потом -P INPUT DROP, а разрешающие правила ниже. Между этими двумя строками сессия уже мертва, и до правил вы не дойдёте. Политика ставится последней, всегда. Заодно -m state там устаревший, актуален -m conntrack --ctstate. Ограничить SSH подсетью и числом сессий iptables -A INPUT -p tcp --dport 22 \ ! -s 10.0.0.0/24 -j DROP iptables -A INPUT -p tcp --dport 22 \ -m connlimit --connlimit-above 3 -j REJECT Оба правила встали. Полезная деталь: iptables -S показывает, что модуль сам дописал --connlimit-mask 32 --connlimit-saddr — лимит считается по одному адресу, а не по подсети. Если нужен другой охват, маску задавайте явно. Отправить подсеть в никуда без файрвола ip route add blackhole 192.168.10.0/24 Нюанс: это не тихий дроп. Локальные попытки получают отлуп сразу — ping вернул connect: Invalid argument, curl завершился с кодом 7. Для исходящего трафика это плюс, ошибка приходит мгновенно вместо таймаута, но маскировки не ждите. И общее: всё э
37 · 1.1K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Разобрать строку штатным <regex.h> и не получить молчаливое «нет совпадения». Проверял на glibc, gcc 13.3, Ubuntu 24.04. Все фрагменты ниже собраны в одну программу и скомпилированы с -Wall -Wextra без единого предупреждения. Скомпилировать шаблон regex_t re; int rc = regcomp(&re, "^([a-z]+)=([0-9]+)$", REG_EXTENDED); REG_EXTENDED включает ERE: скобки и + работают без обратных слешей. Без флага получите BRE, где группа пишется как \(...\). Понять, почему не скомпилировалось char err[256]; if (rc != 0) { regerror(rc, &re, err, sizeof err); fprintf(stderr, "regcomp: %s\n", err); } Буфер обязан быть массивом. На незакрытой скобке [a-z получите Unmatched [, [^, [:, [., or [=. Нюанс: regfree вызывайте только после успешного regcomp, для неудачной компиляции освобождать нечего. Сопоставить и достать группы regmatch_t m[3]; const char *s = "app=100"; if (regexec(&re, s, 3, m, 0) == 0) printf("%.*s\n", (int)(m[1].rm_eo - m[1].rm_so), s + m[1].rm_so); m[0] — всё совпадение, m[1] и дальше — группы по порядку. На app=100 вышло app в первой группе и 100 во второй. Нюанс: смещения в байтах, не в символах. В строке ключ=42 вторая группа начинается с байта 9, хотя символов перед ней пять. И если компилировали с REG_NOSUB, массив m не заполняется вовсе. Не забыть освободить regfree(&re); Замерил: 100 тысяч компиляций в цикле без regfree раздули процесс до 1.4 ГБ, с ним — 1.8 МБ. В демоне, который компилирует шаблон на каждый запрос, это вопрос часов. Где POSIX молчит вместо ошибки Самое неприятное не в том, чего API не умеет, а в том, как он об этом сообщает: \d+ на "abc 123" -> No match <.*?> на "<a><b>" -> <a><b> (?<=x)y -> Invalid preceding regular expression Просмотры и именованные группы падают на компиляции — это честно. А вот \d компилируется и тихо ничего не находит, вместо него нужен [0-9]. И .*? не ошибка, а просто жадный .*: вернул всю строку вместо <a>. Привычки из PCRE здесь ломают логику мо
4 · 1.1K ·
L
LinuxSkill - Сводки с прода и Шпаргалки
🔥 Знаешь только ip a? 10 неочевидных команд ip для Linux Большинство админов знают про ip ровно две команды — ip a и ip r, а дальше ifconfig по старой памяти. Держи 10 команд, которые покажут то, чего не видно в ip a: скрытые маршруты VPN, дропы на интерфейсе и мёртвый шлюз. Проверил на iproute2 6.1. 1️⃣ Вся сеть одним экраном, в цвете: ip -br -c a Интерфейс, состояние и адреса — по строке на каждый. -br работает и с link. 2️⃣ Куда реально уйдёт пакет: ip route get 8.8.8.8 # какая запись в таблице сработала ip route get fibmatch 8.8.8.8 Покажет интерфейс, шлюз и source-адрес. Незаменимо, когда маршрутов много и непонятно, какой победил. 3️⃣ Маршруты, которых нет в ip route: ip rule ip route show table all ВАЖНО: ip route показывает только таблицу main. wg-quick с AllowedIPs = 0.0.0.0/0 уводит дефолт в таблицу 51820, а ip route делает вид, что всё как раньше. 4️⃣ Сменить шлюз без риска потерять сервер: sudo ip route replace default via <gw> Атомарно: нет окна без маршрута, как между del и add. Упадёт с ошибкой — старый маршрут останется на месте. 5️⃣ Дропы и ошибки на интерфейсе: ip -s link show <iface> # двойной -s — ошибки с разбивкой: crc, frame, fifo ip -s -s link show <iface> Растут errors или dropped — копай в кабель, драйвер или буферы, а не в приложение. 6️⃣ Жив ли шлюз на L2: ip neigh show dev <iface> REACHABLE и STALE — норма. Шлюз висит в FAILED или INCOMPLETE — он не отвечает на ARP, и пинговать дальше бесполезно. 7️⃣ Сеть в прямом эфире: ip -ts monitor link route Каждое изменение с меткой времени: упал линк, DHCP или VPN переписали маршрут. Оставь в tmux и лови, кто ломает сеть по ночам. 8️⃣ Отрезать IP без фаервола: sudo ip route add blackhole 203.0.113.5/32 # проверить и убрать ip route show type blackhole sudo ip route del blackhole 203.0.113.5/32 Ответы на этот адрес уходят в никуда, TCP-сессия с ним не установится. ip route get по нему вернёт Invalid argument — так ядро отвечает на blackhole, это не ошибка. 9️⃣ IP интерф
62 · 942 ·
L
LinuxSkill - Сводки с прода и Шпаргалки
💀 CPU под 100%, а в top пусто? Ловим невидимые процессы через eBPF Сервер греется, в шапке top us под 90%, а в списке процессов — никого. Классика: кто-то плодит процессы, которые живут 10–50 мс, а top опрашивает /proc раз в 3 секунды и их просто не застаёт. Показываю, как поймать виновника, не роняя прод. Ловим каждый запуск # 1. В Ubuntu утилита идёт в пакете bpftrace sudo apt install bpftrace # Каждый execve() в реальном времени: # время, PID и PPID родителя. sudo execsnoop.bt TIME PID PPID ARGS 16:55:42.684175 1112 1097 /bin/true 16:55:42.685129 1113 1097 curl --version 16:55:42.691294 1114 1097 sleep 0.05 Один и тот же PPID и новые процессы каждые 50 мс — вот он, виновник. Кто плодит больше всех # 2. Считаем запуски по родителю за 10 секунд. # Подсчёт идёт ПРЯМО в ядре, без потока событий. sudo bpftrace -e ' tracepoint:syscalls:sys_enter_execve { @[comm, curtask->real_parent->tgid] = count(); } interval:s:10 { exit(); }' # Вывод: @[bash, 1097]: 525 # bash с PID 1097 за 10 секунд породил 525 процессов. # 3. Смотрим, кто это и откуда он взялся pstree -sp \<PPID> ps -o pid,etime,cmd -p \<PPID> Почему не strace -f Проверил: dd с bs=1 под strace работает в ~47 раз медленнее. И в ~37 раз — даже если трассировать только accept(), которого dd вообще не вызывает: ptrace останавливает процесс на КАЖДОМ системном вызове. eBPF процесс не останавливает и считает события в ядре. ВАЖНО: bcc-версия execsnoop-bpfcc компилирует программу на лету и без linux-headers-$(uname -r) падает с «Unable to find kernel headers». execsnoop.bt работает через BTF, заголовки ему не нужны. Есть ли BTF в ядре: ls /sys/kernel/btf/vmlinux. Вместо «CPU горит, а кто — непонятно» получаешь имя процесса, аргументы и PID родителя. Дальше дело техники: поправить крон или скрипт. ❗️ Нравится формат? Ставь 👍 👉 Рубрика: #шпаргалка@LinuxSkill #Linux #eBPF #bpftrace #Troubleshooting #SysAdmin #DevOps
18 · 826 ·
L
LinuxSkill - Сводки с прода и Шпаргалки
📊 Диск тормозит, а iostat показывает норму? Ищем хвост задержек Приложение подвисает на записи, в логах таймауты к БД, а iostat рисует w_await в пару миллисекунд. Подвох в том, что iostat показывает среднее: 990 запросов по 0.1 мс и 10 по 200 мс дают в среднем 2 мс. Показываю, как достать хвост, который тонет в среднем. Что на самом деле показывает iostat # 1. -x — расширенные колонки, раз в секунду iostat -x 1 # r_await и w_await — СРЕДНЕЕ за интервал: # редкие зависшие запросы в нём растворяются ВАЖНО: %util под 100% на SSD, NVMe и RAID не значит, что диск упёрся: они обслуживают запросы параллельно. Это прямо написано в man iostat. Гистограмма вместо среднего # 2. В Ubuntu утилита идёт в пакете bpftrace. # Ctrl+C — и получаешь распределение задержек. sudo biolatency.bt @usecs: [16, 32) 426043 [32, 64) 15436 [64, 128) 527 ... [1K, 2K) 24 [2K, 4K) 17 [4K, 8K) 13 Проверил на тестовой нагрузке (столбики убрал, чтобы влезло в экран): iostat в тот же момент показывал w_await 0.02 мс, а в хвосте висели запросы по 4–8 мс — в сотни раз дольше среднего. Чей I/O висит # 3. Каждый запрос дольше 10 мс — с процессом. # Порог подстрой: для HDD 10 мс — норма. # На tracepoint'ах: не сломается с новым ядром. sudo bpftrace -e ' t:block:block_bio_queue { @ts[args->sector] = nsecs; @who[args->sector] = comm; } t:block:block_rq_complete /@ts[args->sector]/ { $ms = (nsecs - @ts[args->sector]) / 1000000; if ($ms >= 10) { printf("%s %d ms\n", @who[args->sector], $ms); } delete(@ts[args->sector]); delete(@who[args->sector]); } END { clear(@ts); clear(@who); }' Видишь kworker или jbd2 вместо своего процесса — это отложенная запись из page cache. Настоящего писателя покажет pidstat -d 1. Среднее говорит «всё хорошо», гистограмма показывает хвост, а третья команда — чей он. Дальше — по месту: вынести бэкап, развести нагрузку или идти к провайдеру с цифрами. ❗️ Нравится формат? Ставь 👍 👉 Рубрик
14 · 624 ·
L
LinuxSkill - Сводки с прода и Шпаргалки
текст ещё не в индексе
20 · 456 ·
L
LinuxSkill - Сводки с прода и Шпаргалки
Фотография
нажмите — покажем
GitOps-практики: развёртываем сервис через ArgoCD Классический CI/CD запускает деплой. Но как сделать так, чтобы состояние Kubernetes после него соответствовало конфигурации в Git? На вебинаре разберём принципы GitOps и посмотрим, как ArgoCD помогает управлять изменениями в кластере. 7 октября в 20:00 МСК на открытом вебинаре OTUS развернём сервис в Kubernetes с помощью ArgoCD и покажет работу подхода на практике. На практике рассмотрим: — чем GitOps отличается от классического CI/CD и когда его применять; — как устроен ArgoCD и какие есть варианты реализации GitOps; — как развернуть сервис в Kubernetes через ArgoCD; — что произойдёт при изменении конфигурации напрямую в кластере; — какие подходы к работе с ArgoCD полезны в проектах. После вебинара вы поймёте принципы GitOps, познакомитесь с возможностями ArgoCD и увидите полный процесс развёртывания сервиса. Полученные подходы сможете применить при работе со своими Kubernetes-кластерами. Урок проходит в преддверии старта курса «DevOps. Экспертный уровень». 👉 Регистрируйтесь: https://otus.pw/wyNA/ Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
4 · 639 ·
L
LinuxSkill - Сводки с прода и Шпаргалки
текст ещё не в индексе
21 · 401 ·

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Границы индекса · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем