Привет! Я Саша Хренников, руководитель DevOps-юнита в KTS.
Новогоднее испытание для DevOps-инженеров подошло к концу, и сегодня я пошагово разберу решение задачи. Но сначала я сделаю два объявления.
Во-первых, с этого дня мы открываем доступ ко всем архивным челленджам. Если вы не успели поучаствовать, но хотите проверить свои силы и подготовиться к будущим испытаниям, вы можете перейти в нашего бота, и он расскажет, что делать. Главное — попробуйте разобраться самостоятельно, не спойлерите себе решение.
Почитать описания архивных челленджей можно здесь:
Назад в прошлое: запускаем k8s v.0.1 из 2014 и анонсируем челлендж
DevOps Challenge: восстановите работу MySQL и выиграйте крутой мерч
Во-вторых, я с радостью поздравляю победителей текущего испытания — тринадцать участников, которые быстрее всех справились с заданием и уже освобождают место в шкафу для нашего мерча. Итак, поздравляем с победой:
Konstantin aka @526***: 5 мин 42 сек
Chatbot aka @mr_hightlook: 5 мин 51 сек
ne0ba aka @ne0ba: 5 мин 53 сек
Alexey AnyOps aka @mozgoo: 9 мин 1 сек
ssch aka @ssch1337: 10 мин 22 сек
Dmitry Tigrov aka @dmitrytiger: 15 мин 26 сек
Alexandr Boltris aka @AlexandrBoltris: 17 мин 41 сек
Alexander Evsikov aka @Evsikov: 18 мин 33 сек
Igor Dronov aka @Benosa19: 19 мин 33 сек
Кирилл aka @kirill_serguta: 20 мин 26 сек
Azat aka @nevmetovazat: 22 мин 26 сек
Sergei D aka @sergei0d: 26 мин 0 сек
Vladimir Fedorov aka @FdrvVldmr: 26 мин 0 сек
Именно им, а не своим оленям, Деду Морозу стоило поручать развертывание приложения. А пока Дедушка развозит подарки, я предлагаю разобраться с тем, что натворили наши парнокопытные.
Оглавление
Диагностика
Сперва посмотрим, что запущено в кластере и какие ошибки мы видим при запуске.
#kubectl get po
NAME READY STATUS RESTARTS AGE
newyear-76ccb4dffd-kxtc5 0/1 CrashLoopBackOff 4 (49s ago) 2m32s
#kubectl logs newyear-76ccb4dffd-kxtc5
2024/12/31 23:59:59 err
Похоже, что для отладки придется погружаться в под. Для этого отредактируем deployment, предварительно сохранив его.
#kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
newyear 0/1 1 0 4m27s
#kubectl get deploy newyear -o yaml > ./deploy.yaml
#kubectl edit deploy newyear
Во время редактирования стоит удалить livenessProbe и заменить параметр command на что-то, что не будет падать при запуске. Например, так:
Исходный вариант:
spec:
containers:
- command:
- /build/newyaer
image: cr.yandex/crpeghj733dngql9boeu/challenges-new-year-disk:0.0.1
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /status
port: 8080
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
Результат:
spec:
containers:
- command:
- tail
- -f
- /etc/hosts
image: cr.yandex/crpeghj733dngql9boeu/challenges-new-year-disk:0.0.1
imagePullPolicy: IfNotPresent
Теперь можно попасть в запущенный под через exec
и сразу воспроизвести проблему.
#kubectl get po
NAME READY STATUS RESTARTS AGE
newyear-559dd4766f-dcbtz 1/1 Running 0 26s
#kubectl exec -it newyear-559dd4766f-dcbtz -- /bin/bash
root@newyear-559dd4766f-dcbtz:/build# /build/newyaer
2024/12/31 23:59:59 err
Далее есть два способа разобраться, что же не так с приложением.
Первый — для староверов и любителей низкоуровневой отладки:
root@newyear-559dd4766f-dcbtz:/build# strace /build/newyaer
openat(AT_FDCWD, "/opt/storage/2024HNY.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = -1 ENOSPC (No space left on device)
Второй для тех, кто верит, что даже олени способны на разумные действия:
root@newyear-559dd4766f-dcbtz:/build# /build/newyaer -h
You can add -v
2024/12/31 23:59:59 err
root@newyear-559dd4766f-dcbtz:/build# /build/newyaer -v
2024/12/31 23:59:59 open /opt/storage/2024HNY.txt: no space left on device
В обоих случаях мы узнаем, что приложение не может создать файл /opt/storage/2024HNY.txt из-за нехватки места на диске. Видимо, стоит посмотреть, что происходит со свободным местом.
root@newyear-559dd4766f-dcbtz:/build# df -h
Filesystem Size Used Avail Use% Mounted on
…
/dev/vdb 488M 129M 349M 28% /opt/storage
…
Странная ситуация. Непохоже, что места недостаточно. Но и в этом случае стоит проверить еще один вариант — индексные дескрипторы, они же inode.
root@newyear-559dd4766f-dcbtz:/build# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
…
/dev/vdb 32768 32768 0 100% /opt/storage
…
Вот и наша проблема. Все дескрипторы загружены, и приложение не может запуститься.
Фикс
Сначала нужно посмотреть, чем же заняты все дескрипторы.
ls -lah /opt/storage/ | head -n 10
total 129M
drwxr-xr-x 3 root root 928K Dec 16 20:56 .
drwxr-xr-x 1 root root 4.0K Dec 16 21:05 ..
-rw-r--r-- 1 root root 2 Dec 16 20:56 0.txt
-rw-r--r-- 1 root root 2 Dec 16 20:56 1.txt
-rw-r--r-- 1 root root 3 Dec 16 20:56 10.txt
-rw-r--r-- 1 root root 4 Dec 16 20:56 100.txt
-rw-r--r-- 1 root root 5 Dec 16 20:56 1000.txt
-rw-r--r-- 1 root root 6 Dec 16 20:56 10000.txt
-rw-r--r-- 1 root root 6 Dec 16 20:56 10001.txt
Большое количество мусорных файлов. Скорее всего, чистить все и сразу не стоит. В качестве эксперимента попробуем удалить один и запустить приложение:
root@newyear-559dd4766f-dcbtz:/build# cd /opt/storage/
root@newyear-559dd4766f-dcbtz:/opt/storage# rm ./1.txt
root@newyear-559dd4766f-dcbtz:/opt/storage# /build/newyaer -v
2024/12/31 23:59:59 open /opt/storage/2025HNY.txt: no space left on device
Любопытно, ошибка сохраняется, но имя файла поменялось. Похоже, что приложение хочет создать больше одного файла. Что ж, давайте попробуем удалить весь мусор.
root@newyear-559dd4766f-dcbtz:/opt/storage# rm ./*.txt
root@newyear-559dd4766f-dcbtz:/opt/storage# ls -lah
total 952K
drwxr-xr-x 3 root root 928K Dec 16 21:12 .
drwxr-xr-x 1 root root 4.0K Dec 16 21:05 ..
-rw-r--r-- 1 root root 69 Dec 16 20:56 2025conf.yaml
Увлекательно. Оказывается, у приложения был еще и конфиг. Кстати, если его удалить, то с ключом -v
вы получите подсказки по его восстановлению.
root@newyear-559dd4766f-dcbtz:/opt/storage# rm ./2025conf.yaml
root@newyear-559dd4766f-dcbtz:/opt/storage# /build/newyaer -v
2024/12/31 23:59:59 open /opt/storage/2025conf.yaml: no such file or directory
root@newyear-559dd4766f-dcbtz:/opt/storage# > ./2025conf.yaml
root@newyear-559dd4766f-dcbtz:/opt/storage# /build/newyaer
2024/12/31 23:59:59 config error
/build/newyaer -v
2024/12/31 23:59:59 Please fill out the configuration in the following format:
config:
timeout: 5
year: 2025
greeting: "Happy New Year"
Наконец, когда проблема с файлами решена, мы можем проверить, что приложение перестало падать. Для этого запустим и прервем оригинальный бинарник /build/newyear.
И теперь, когда мы убедились, что приложение не падает, можно вернуть исходную конфигурацию deployment и проверить его работоспособность.
#kubectl edit deploy newyear
#kubectl get po
NAME READY STATUS RESTARTS AGE
newyear-559dd4766f-dcbtz 1/1 Terminating 0 12m
newyear-76ccb4dffd-zgg28 1/1 Running 0 3s
#kubectl exec -it newyear-76ccb4dffd-zgg28 -- /bin/bash
root@newyear-76ccb4dffd-zgg28:/build# curl 127.0.0.1:8080/status
Happy New Year
Заключение
Вот, собственно, и все решение. На этот раз мы постарались не перегибать со сложностью, но все же оставить простор для гипотез и рассуждений. Будем благодарны, если вы поделитесь впечатлениями в комментариях и расскажете, что стоит улучшить к следующему разу.
Если же вам не хватает задач, вы уже прорешали все архивные челленджи и хотите окончательно преисполниться в своем познании перед новогодними праздниками, рекомендую почитать наши статьи для DevOps-инженеров. Там мы с коллегами делимся опытом и описываем технологии, которыми сами пользуемся в работе:
JupyterHub на стероидах: реализация KubeFlow фич без масштабных интеграций
Поднимаем динамические окружения для stateless- и stateful-сервисов
И желаем вам удачи с любыми испытаниями в наступающем году!