Упаковать сервис в контейнер просто. Сначала хотел использовать базовый образ distroless, но возникли проблемы с созданием папки для логов и правильными правами на неё(потом понял, что сделать это можно, но образ был готов и что-то менять не хотелось), базовым образом стал alpine. Конфиг сервиса закинул прямо в образ, ибо почта и адрес бд меняться не будут
3 виртуальных машины в одной подсети разворачиваются в Яндекс облаке через terraform. Конфиги в terraform/
На этих машинах будет развернут docker swarm кластер(swarm хотя и больше не поддерживается, но в данной задаче хорошо подходит, т.к. позволяет достаточно просто обеспечить отказоустойчивость; k8s разворачивать сложнее). Одна будет manager нодой и на ней будет развернута база данных(ей выделено больше ресурсов, чтобы prepare_db
выполнялось быстрее). 2 другие будут worker нодами и на них будет развернут сервис
Путь к публичному ssh ключу - ./ssh_keys/id_rsa.pub
, может быть изменен в перменной terraform ssh_pub_key_file
Развертывание кластера и все настройки делаются через ansible, inventory файл создаётся terraformом через шаблон и сохраняется в ./ansible/dyn_inventory.tmp
(можно изменить в переменной dynamic_inventory_location
)
Конфигурация разбита на несколько play:
install and ban google
(файлinstall.yml
) - установка docker на всех хостах и бан 8.8.8.8(ускорение запуска сервиса)init docker swarm cluster
(файлsetup-swarm.yml
) - создание docker swarm кластераinitial deploy
(файлinit-stack.yml
) - создание необходимых сетей и развёртывание базы данных и проксиprepare db
(файлprepare-db.yml
) - запуск создания тестовых данных в базе данныхdeploy bingo service
(файлdeploy-service.yml
) - создание индексов в базе данных(ускорение работы нескольких методов) и развертывание самого сервиса
При запуске увидив коды, подумал вытащить все эти коды из бинаря(ctf moment)
strings ./bingo | rg "code:" -B 5
Получаем все коды:
My congratulations.
You were able to start the server.
Here's a secret code that confirms that you did it.
--------------------------------------------------
code: yoohoo_server_launched
--
Congratulations.
You were able to figure out why
the application is slow to start and fix it.
Here's a secret code that confirms that you did it.
--------------------------------------------------
code: google_dns_is_not_http
--
You will need to start a new shell for this setup to take effect.
Hi. Accept my congratulations. You were able to launch this app.
In the text of the task, you were given a list of urls and requirements for their work.
Get on with it. You can do it, you'll do it.
--------------------------------------------------
code: index_page_is_awesome
Первый и последний получил ещё раньше, а второй заинтересовал. Намёк на чтото с google dns, то есть чтото с ip адресом 8.8.8.8. Ищем
strings ./bingo | rg "8.8.8.8"
Среди прочего есть следующая строка
http://8.8.8.8/runtime_version
Скорее всего сервис пытается сделать http запрос к google dns, но сервер не отвечает, и сервис ждёт timeout. Решение - забанить 8.8.8.8) (что и происходит в install.yml
)
Если сделать большую нагрузку на эти пути и посмотреть на загрузку ноды с базой данных, можно увидеть большую проблему - база полностью загружает процессор, а RPS достигает максимум 40. Это кажется странным, т.к. запрос к бд должен быть очень простым(просто достать запись по id). Заходим в базу данных и видим отсутствие индекса на колонке id
в таблицах customers
и sessions
. Добавляем индекс(происходит в deploy-service.yml
), база больше не нагружает сервер, а RPS стабильно 120.
Для reverse proxy был выбран traefik из-за простоты развертывания и использования(ему самому нужно прописать немного опций запуска, а сервисам просто навесить labels). Но с ним возникла проблема - кэширование это функция, доступная только в платной enterprise версии. Я понял это за 2 часа до дедлайна(т.к. проект совпал с соревнованиями и больше было некогда), попытался использовать плагин traefik-simplecache
, однако он не работает(как минимум с 2021 года, issue открыто тогда и решения нет). Менять reverse proxy времени не осталось, поэтому один пункт не выполнен.