Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
05.05.2023
Роблю перехід з глобуса на локальну карту
Продовжую змагатись з 3D-графікою, а саме, намагаюсь зробити перехід від глобуса до локальної карти. На перший погляд, задача не тільки проста, але й незрозуміло, що то взагалі за перехід, якщо фактично карта залишається тією самою.
Ось тільки рідко так буває, що 3D “сцена” відтворює реальну структуру фізичних обʼєктів, які вона відображає. Так, хоч локальна карта і є, теоретично, частиною глобуса, але для відображення її в 3D використовувати ту саму модель недоцільно. Глобус складається з тисячі трикутників, тож сторона кожного з них десь близько 500 км. А локальна карта має сторону у 25 разів менше. Тому навіть думати про глобус та карту в одній системі координат незручно.
Отже, після повного наближення “з космосу” до місця треба зробити фокус та підмінити глобус на карту. Цим трюком я й займаюсь. Потрібно зорієнтувати карту в таке саме місце та в такому самому масштабі, та задача зроблена.
От тільки виникла проблема. Який саме масштаб я хочу показати? В попередньому демо локальною картою є просто одна плитка текстури. Але ж для кінцевого варіанту треба вирізати з неї шматок, що відповідає заданому треку. Тут довелося знову пірнати в математику. Координати, що обмежують трек, відомі. По координатах можна вийти на розмір в метрах. Далі в метрах можна обвести трек квадратом, а цей квадрат знову перевести в координати. (Ще цікава річ — координати не відповідають кілометрам однорідно, бо довжина градуса довготи залежить від широти, на якій його вимірювати.)
Потім, маючи координати границь видимої області, можна знайти їх в межах координат плитки (які можна обчислити оберненою формулою від меркаторівської проєкції), та, нарешті, побудувати відповідні координати текстури та висоти нашої локальної карти. Фух! І це ще без анімації.
Чому навчився: налагодити всю цю складну математику легше, коли текстури відображають щось наочне; в мене був прямо прорив, коли я просто намалював на карті коло на місці треку та стрілочку на південь — якийсь компас. Але взагалі існує цілий клас допоміжних текстур в кліточку, по якім можна помітити недоліки текстурних координат.
04.05.2023
DNS сервер Knot
Раптом після вчорашнього посту знайшовся ще один локальний рекурентний DNS сервер - Knot Resolver. Чим він гарний — це той самий сервер, який використовує Cloudflare для свого відкритого DNS 1.1.1.1
. Це цікаво, бо самі автори Knot не гарантують його підтримку “в продакшні”, а тільки для простих споживацьких потреб. Втім, як бачиш, для Cloudflare його функціоналу вистачає (хоча Cloudflare додали власний кеш та ще дещо; кеш Knot не масштабується та обмежений однією машиною.)
Рекомендація від Cloudflare багато значить саме тому, що такий сервер буде давати результати, схожі на їхні. А значить, можна очікувати, що не буде незрозумілої клієнтам розбіжності, яку створював unbound. Взагалі це найбільший ризик з локальними DNS серверами — що невідомо, як вони себе поведуть в складній ситуації.
Щодо технічних деталей, то Knot Resolver встановлюється хоч на Linux, хоч на macOS, хоч в Docker; цікаво він конфігурується — файл конфігурації є скриптом на Lua. Можна кешувати запити, можна навпаки, кеш вимкнути. Можна використати в інтерактивному режимі, на кшталт dig
.
Найбільші граблі, на які я наступив, поки налаштовував — це те, що DNS працює за протоколом UDP, та порти для нього треба відкривати окремо. Наприклад, в Docker: docker -p 35353:53/udp
. Причому — підтримка TCP теж є — але як резервний варіант. Тому без відкритого UDP ваш DNS сервер працювати буде, тільки не з кожним клієнтом, та майже напевно з затримками. Піди та здогадайся, чому.
🇨🇿 До речі, Knot - продукт чеського доменного реєстратора CZ.NIC; на їхньому акаунті в GitHub можна знайти ще багато цікавого.
03.05.2023
Чому всі перевірялки DNS такі повільні?
Якщо тобі доводилось додавати домен до якогось SaaS, будь то Heroku, Firebase, Cloudflare, і так далі — то ти, напевно, знаєш, що для підтвердження власності треба додати DNS запис. А потім зазвичай довго чекати, поки SaaS його перевірить. Деколи це займає хвилини, а деколи прямо кажуть приходити завтра.
DNS - протокол, яким ми користуємось постійно, без нього неможливо вийти в Інтернет. Однак коли ти відкриваєш сайт, то чомусь отримуєш адресу миттєво, а не завтра. Чому ж тоді верифікація домену це такий довгий процес?
Винний, як завжди, кеш. Поняття кешу закладене в основу протоколу DNS. Чому так? Бо записи DNS не сидять всі на одному сервері. Як я вже писав, пошук адреси в DNS - процес рекурсивний — рухаючись від центральних вузлів Інтернету до більш детальних серверів, аж допоки не знайде конкретний запис. Робити так щоразу дуже витратно, бо будь-який з серверів на шляху може бути повільним чи навіть недоступним. Тому проміжні та кінцеві результати пошуку DNS кешуються. Коли створюєш запис, вказуєш параметр TTL - Time-To-Live. Він і показує (або принаймні натякає), скільки цей запис можна тримати в кеші.
Це вже дає зрозуміти, чому ми можемо бачити застарілі результати. Особливо якщо сервіс вже встиг перевірити запис до того, як ми його створили, та тепер побачить тільки вже закешовану хибну версію.
Можна спитати — а чому тоді сервіс не ходить щоразу до DNS сервера, що містить запис (це називається SOA - Source of Authority), та не перевіряє без всякого кешу? Це не так просто. По-перше, сам авторитетний DNS-сервер може мінятись, хоча це не так часто трапляється. По-друге, проміжні сервери теж можуть мати кеш.
По-третє, і найгірше, цей кеш може розрізнятись між собою, та тоді перевірка буде стрибати з одного результату на інший. Бо DNS-сервери зазвичай мають декілька копій. Наприклад, кореневих серверів зараз аж 1696. Ясно, що коренева конфігурація (тобто адреси DNS-серверів доменів верхнього рівня) не так часто змінюється. Та сервери провайдерів, такі, як GoDaddy або NameCheap, теж мають багато копій — інакше б вони не були надійними. І звісно, свіжо доданий запис ніяк не може синхронно зʼявитися на всіх копіях.
Мине час, та думка DNS серверів про твій домен зійдеться до однієї. Але поки він свіжий, проблем не минути. Або затримка — через кеш. Або результат, що стрибає.
02.05.2023
Медитація та метакогніція
🧘 Практика медитації відома мені багато років, але власне практикую я дедалі рідше. Але, знаєте, здається знайшов привід це робити.
Взагалі медитація — поняття широке, та назвати так можна хоч праці Марка Аврелія. Я зазвичай під медитацією розумію так звану на Заході mindfulness meditation, тобто медитацію на свідомість. Суть її в тому, щоб… сидіти та усвідомлено дихати зазначений термін, від 5 хвилин та.. я, здається, у своїй практиці до 25 хвилин доходив, але це не точно.
З першого погляду це надзвичайно безглузде заняття, та цьому не допомагає те, що вчителі медитації так відверто й кажуть, що ніякого змісту та мети в ньому немає, просто треба сидіти та від цього буде багато користі. Я вірю, але для спонукання на дію цього було недостатньо, тому медитація поступалася часом всім іншим діяльностям.
Втім, останнім часом я багато цікавлюся підходами, що потребують уваги до власного мисленнєвого процесу. Це й відстежування відволікань, і керування емоціями, і здатність помітити, що робота зайшла в тупик. Ця увага по-розумному називається метакогніція. Насправді більшість засобів щось покращити у своєму житті так чи інакше долучають метакогніцію. Проте вона не дається без зусиль, а подекуди зовсім не дається; навички метакогніції варто тренувати.
Саме це й робить медитація на свідомість. Інструкція про дихання — то програма максимум. На практиці час медитації буде зайнятий випадковими думками, які зазвичай здатні унести нас далеко від запланованого заняття. Задача медитатора — помітити думки, та повернутись до дихання. Тобто виходить, що весь час медитації на свідомість присвячений спостереженню за думками, тобто розвитку метакогніції. Цим вона й відрізняється від “просто сидіння.” Раджу спробувати.
До речі, якщо потрібні інструкції, то можу порекомендувати тільки англійською, від Стіва Хагена. Він ще написав мою улюблену книжку про буддизм.
01.05.2023
AWS Parameter Store, Secrets Manager, та KMS: порівняння
Попросили порівняти ці схожі сервіси, які нібито всі зберігають різні ключі. Але насправді сервіси дуже різні.
AWS KMS (Key Management Service) - це сервіс шифрування, де ключі сховані “в чорний ящик”. Тобто за допомогою AWS IAM можна надати певним ролям дозвіл шифрувати або дешифрувати свої дані. Але — і це головне — при цьому ролі не отримують доступ до самих ключів. Ключі взагалі ніхто не може отримати, тільки сам AWS. Ми маємо тільки API для їх використання. Таким чином, за допомогою KMS можна не тільки поділитися доступом до зашифрованої інформації, а ще й потім цей доступ прибрати — бо якби ми поділилися самим ключем, то забрати його назад вже технічно неможливо.
KMS широко використовується в інших сервісах AWS як єдине рішення для шифрування даних. Всюди, де є шифрування — там є KMS та права доступу до нього. В тому числі й в наступних двох сервісах.
AWS Parameter Store - це сервіс збереження конфігурації. Про нього я вже писав. Але коротко, Parameter Store заміняє вам конфігураційні файли. Причому тут є і детальне керування доступом, і шифрування за бажанням, і навіть прості можливості аудиту. Проміж іншого, з Parameter Store можна вичитувати значення змінних оточення ECS та Lambda, або ж просто забирати значення через API. Дуже зручно “склеювати” сервіси до купи через значення Parameter Store, які автоматично записує Terraform.
Parameter Store розрахований для збереження великої кількості ключів, тому сховище Parameter Store безплатне. Обмежена тільки частота запитів (тому NoSQL базу з нього не зробиш, хаха), та розмір значення (до 4KB - далі платно).
AWS Secrets Manager - це спеціалізоване сховище для паролів. Причому так само як і Parameter Store, має таке саме шифрування та керування доступом. Чому ж тоді ключ Secrets Manager коштує $0.40 на місяць? Як я розумію, то фішка в тому, що Secrets Manager містить в собі автоматичну ротацію ключів. Причому ротацію не просто у вигляді тривіальної заміни ключа на новий, а з оновленням клієнта та сервера, тобто наживу, без простою, та в теорії безпечно. Тому також Secrets Manager інтегрується в сервіси AWS, що ці ключі споживають, наприклад, в AWS RDS.
Таким чином, в Secrets Manager має сенс розміщати ключі до баз даних та API, які підлягають ротації. Якщо ротацію ви не робите — то Parameter Store такий само безпечний, але ще й при цьому нічого не коштує. Тільки чомусь Secrets Manager - сервіс “першого рівня”, а Parameter Store “прихований” як частина Systems Manager. Та, якщо ти знайдеш перший, а не останній, то, як завжди, AWS про зайві витрати не попередить, та з радістю буде зберігати твої секрети по 40 центів за штуку. Caveat emptor.
30.04.2023
Тривимірна карта нарешті працює
Вийшло зробити ті ілюстрації, які хотів — наближення з глобуса до локальної карти, та демонстрація треку на тривимірній карті. Звісно, ще є над чим працювати, але база є.
Щодо глобуса: розібрався з формулою для меркаторівських координат і все запрацювало. Допоміг аркуш паперу та ця сторінка з вікі OSM. Наступний етап — плавне наближення до точки. Окрім інтерполяції камери, що досить просто, треба підміняти текстуру на більш деталізовану. Для цього треба розвʼязати, які текстурні координати будуть у деталізованої текстури — над цим теж довелося помізкувати. (Я заздалегідь завантажив кожний рівень деталізації для даної точки на карті. Для цього є ще скрипт на Ruby, що вміє звантажити плитки карти та зшити їх разом за допомогою ImageMagick.)
Щодо локальної тривимірної карти: для цього починаю з локальної карти (такої самої, як останній рівень деталізації глобуса), та додаю до неї Terrain RGB. З даних висоти легко побудувати квадратну поверхню; наклеїти на неї локальну текстуру карти тривіально, бо вона збігається один в один.
Далі, трек; він в мене вже був у форматі масиву координат (які я власноруч записав в поході). Але при переході до локальної карти географічні координати втрачають дійсність, та заміняються системою координат плитки локальної карти, яку ми взяли за основу. Тому тепер довелося розписати формулу, по якій від меркаторівських координат плитки можна перейти назад до граничних значень широти та довготи для неї. А коли є граничні значення, то привʼязати до них трек — задача простого перенесення та масштабування. Надзвичайно приємно, коли трек та карта, взяті з абсолютно різних джерел, сходяться в єдине зображення.
На наступний раз — збагачення карти маркерами, покращення стилю треку, та обʼєднання глобуса та тривимірної карти в єдину сцену.
29.04.2023
Роблю глобус на three.js
Для постів про подорожі намагаюся зробити красиву тривимірну карту. Причому через мої дикі вимоги “просто” карта на кшталт Google Maps або Leaflet не подобається — роблю свою. Ідея в тому, що замість повноцінної карти це буде обмежена та зрежисована анімація.
Вирішив робити на three.js - бібліотеці тривимірної графіки на JavaScript. На сучасних пристроях вона повністю прискорена технологією WebGL та графічним процесором, тому працює все дуже добре і можна робити речі набагато складніше, ніж глобус.
Перший крок — власне, намалювати глобус. Для цього знайшов класну статтю; код з неї запрацював майже без корекції на сучасну версію three.js. Потім достатньо легко зʼясував, як перекладати географічні координати на “графічні” (для цього дуже корисним є клас Spherical) та орієнтувати глобус на той бік, що мені потрібно. Навіть анімувати переліт з однієї точки в іншу.
Далі задача була така, щоб камера наближувалась до об’єкта, а карта збільшувала масштаб в міру наближення. Як всі нормальні карти роблять — але в мене ідея завантажувати потрібні мені шари карти заздалегідь, щоб це було гладенько. Власне, зображення плиток можна взяти багато де, наприклад, на MapTiler. Залишається накласти їх на глобус. І тут все пішло не так…
Якщо дуже коротко, то стандартна проєкція онлайн-карт — Меркатор — не сходиться зі стандартним способом накладання текстури на сферу. Меркаторівська проєкція витягується біля полюсів. Тому просто накласти текстуру на глобус — як це зробив автор статті-прикладу — можна тільки якщо карта підготована “в форматі текстури”. Щоб відображати карти, треба обчислювати текстурні координати для всіх точок на сфері. Тут вже починається серйозна тригонометрія, на якій я поки застряг — може тому, що вже друга година ночі.
А ще, сфера Three.js хороша, як сфера, але не як глобус. ЇЇ розподіл на полігони більш нагадує волейбольний мʼяч, ніж глобус. Тому я й генерацію глобуса переписав. Алгоритм досить простий — біжиш по широті та довготі, генеруєш трикутники парами. А ось тригонометрія складна. На ній поки й залишаю.
28.04.2023
Про наше локальне Docker-хазяйство
Хочу ще розказати про те, як зробив локальну емуляцію складної інфраструктури з продакшна — для інтеграційних тестів або ж просто для розробки.
Для того потрібний Docker Compose. Це доповнення до Docker, яке оркеструє багато контейнерів у вигляді сталої схеми. За допомогою Docker Compose можна всі контейнери відразу зібрати, запустити, звʼязати між собою, подивитися журнал, видалити, і ще багато всього.
(Docker Compose мій другий вибір подібного рішення; першим буде Foreman - утиліта, що може запускати декілька процесів з одного терміналу та збирати їх вивід в один. Але Foreman рішення обмежене — наприклад, з ним не вдасться підмінити DNS, звертатись до сервісів за хостом або IP, або запускати на macOS програми, що є тільки під Linux.)
Все це можна робити з Docker Compose. Наприклад, у нас все середовище складає на цей час 19 контейнерів. Частина з них — власні сервіси, але є й загальнодоступні — наприклад, бази даних, або dnsmasq
. Вони всі розташовані в віртуальній мережі. Для деяких функцій потрібно звертатись до фіксованого IP, то це легко зробити.
Конфігураційний формат Docker Compose гнучкий. Оскільки це YAML, в ньому можна вживати якірі, тобто виносити частини конфігурації, що повторюються. Можна навіть посилатися на інший файл. Так можна суттєво знизити кількість копіпасти.
Щоб ще узагальнити конфігурацію, можна використати змінні оточення. Наприклад, завдяки змінним, можна легко зробити дві копії інфраструктури — одну для тестів, одну для ручного використання. Або виправити мілкі незручності, які заважають запускати конфігурацію як на macOS, так і на Linux (для CI) - а такі незручності трапляються.
А щоб сховати довжелезні команди docker-compose
з купою параметрів, я написав Rakefile. Rake - то аналог класичного Make, написаний на Ruby, та я нерідко вживаю його за межами проєктів на Ruby, щоб спростити скрипти. Адже системні скрипти — це вроджений талант Ruby.
27.04.2023
Зручна маршрутизація для Docker Compose
В продовження вчорашньої теми про створення повноцінного тестового середовища - стала задача відтворити маршрутизацію, яку в продакшні робить AWS Load Balancer. В залежності від шляху в URL він направляє запити на один сервіс, або на інший. Оскільки AWS ALB ми, звісно, локально не запустимо, то поки що цей фрагмент інфраструктури не відповідав продакшну, та тести його обминали.
Що робити? Вірний вибір, безумовно, nginx. Якби не можливості ALB, то він би в нас і в продакшні маршрутизував та балансував. Ось тільки налаштовувати nginx - окрема праця, як зараз, так і потім в підтримці. Тому пошукав готові рішення вищого рівня. Знайшов nginx-proxy. Це як раз маршрутизатор для середовища Docker, який конфігурується напівавтоматично на основі змінних оточення, назначених контейнерах. Вміє він й назначати віртуальні хости, й робити TLS шифрування (разом, наприклад, з mkcert).
Проте все, що було потрібно мені — це зібрати два сервіси під єдиною адресою, та до того ж на localhost за визначеним портом. Для цього корисні дві опції nginx-proxy:
-
DEFAULT_HOST
назначає той хост, який буде використовуватись, коли ніякий не підійшов; на локалхості це саме те, що треба. Сюди пишу аби що. Але головне, що він має збігатись з налаштуваннямVIRTUAL_HOST
на моїх сервісах. -
VIRTUAL_PATH
дозволяє як раз маршрутизувати за шляхом; причому, по-перше, шлях використовується як префікс, а по-друге, один з сервісів може бути за замовчуванням з порожнім шляхом.
Далі, nginx-proxy встановлюється на потрібний порт, сервіси отримують налаштування VIRTUAL_HOST
, VIRTUAL_PATH
та можливо VIRTUAL_PORT
, запускається docker-compose, і все працює само по собі! Дуже зручне рішення, краще й уявити не міг.
26.04.2023
Неочевидні переваги інтеграційних тестів
В підсумках року я колись писав, що в нас дуже крутий пакет інтеграційних тестів. Сьогодні його ще розширив, покрив додаткову підсистему. До речі, раніше вона була не покрита тому, що сиділа в іншому репозиторії, а це суттєво все ускладнює. Згодом підсистема перепливла в головну репу, та тестувати її стало простіше. Втім, розповідь не про переваги підходу “монорепо”, а про переваги тестів.
Інтеграційні тести мають покривати якнайбільшу частину вашої системи. Якщо це додаток та база, то це легко, але зі створенням мікросервісів та впровадженням всіляких білінгів та черг задача ускладнюється. Проте мета залишається — інтеграційні тести мають вміти відтворити програмно будь-які дії користувача.
Тепер, про переваги. Ясно, що мати можливість перевірити всю систему у звʼязці — дуже корисно та допомагає виявити найбільш приховані баги. Окрім того, інтеграційні тести допомагають в документації. Я не раз відкривав тести, щоб нагадати собі ту чи іншу поведінку системи. Та для того їх навіть не потрібно запускати — гарні тести описують всі очікування.
Також наявність тестової запряжки дозволяє моделювати поведінку через програмування. Це корисно не тільки при пошуці багів (хоча це в першу чергу!), а й для дослідження. Чим складніша система, тим важче зрозуміти, що вона зробить в той чи іншій ситуації. Тоді замість того, щоб відтворювати вручну складну або навіть неможливу ситуацію, можна просто написати тест і подивитись, що станеться. Так я теж постійно роблю.
Тому дуже радий, що ще один аспект продукту тепер перетворився з загадкового “треба буде перевірити на продакшені” в зрозумілий “ось як воно все працює”.