[{"data":1,"prerenderedAt":16543},["ShallowReactive",2],{"navigation_docs":3,"-tools-kubernetes-services-networking":3099,"-tools-kubernetes-services-networking-surround":16538},[4,1657,1810,2264,2445,2652,2774,2824,2881,2915,3041,3058,3095],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","/csharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1346,1636,1653],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp/index",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","/csharp/fundamentals","01.csharp/01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","/csharp/fundamentals/introduction-to-ecosystem","01.csharp/01.fundamentals/01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","/csharp/fundamentals/program-structure","01.csharp/01.fundamentals/02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","/csharp/fundamentals/variables-data-types","01.csharp/01.fundamentals/03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","/csharp/fundamentals/arrays","01.csharp/01.fundamentals/04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","/csharp/fundamentals/strings-text-handling","01.csharp/01.fundamentals/05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","/csharp/fundamentals/dates-time-handling","01.csharp/01.fundamentals/06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","/csharp/fundamentals/control-flow","01.csharp/01.fundamentals/07.control-flow",{"title":48,"path":49,"stem":50},"Методи","/csharp/fundamentals/methods","01.csharp/01.fundamentals/08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","/csharp/fundamentals/debugging-basics","01.csharp/01.fundamentals/09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","/csharp/fundamentals/interactive-console","01.csharp/01.fundamentals/10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","/csharp/oop","01.csharp/02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","/csharp/oop/package-management","01.csharp/02.oop/01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","/csharp/oop/classes-objects","01.csharp/02.oop/02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","/csharp/oop/properties-fields","01.csharp/02.oop/03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","/csharp/oop/oop-pillars","01.csharp/02.oop/04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","/csharp/oop/advanced-types","01.csharp/02.oop/05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","/csharp/oop/namespaces","01.csharp/02.oop/06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","/csharp/advanced-core","01.csharp/03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","/csharp/advanced-core/generics","01.csharp/03.advanced-core/01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","/csharp/advanced-core/delegates-events-lambdas","01.csharp/03.advanced-core/02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","/csharp/advanced-core/interfaces-deep-dive","01.csharp/03.advanced-core/03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","/csharp/advanced-core/exception-handling","01.csharp/03.advanced-core/04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","/csharp/advanced-core/pattern-matching","01.csharp/03.advanced-core/05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","/csharp/advanced-core/additional-features","01.csharp/03.advanced-core/06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","/csharp/architecture-best-practices","01.csharp/04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","/csharp/architecture-best-practices/software-design-principles","01.csharp/04.architecture-best-practices/01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","/csharp/architecture-best-practices/design-patterns","01.csharp/04.architecture-best-practices/02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","/csharp/architecture-best-practices/design-patterns/creational","01.csharp/04.architecture-best-practices/02.design-patterns/creational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","/csharp/architecture-best-practices/design-patterns/creational/singleton","01.csharp/04.architecture-best-practices/02.design-patterns/creational/01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","/csharp/architecture-best-practices/design-patterns/creational/builder","01.csharp/04.architecture-best-practices/02.design-patterns/creational/02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","/csharp/architecture-best-practices/building-professional-clis","01.csharp/04.architecture-best-practices/03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","/csharp/architecture-best-practices/validation-flow-control","01.csharp/04.architecture-best-practices/04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","/csharp/architecture-best-practices/modern-dotnet-host","01.csharp/04.architecture-best-practices/05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","/csharp/architecture-best-practices/data-mapper-part1","01.csharp/04.architecture-best-practices/06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","/csharp/architecture-best-practices/data-mapper-part2","01.csharp/04.architecture-best-practices/07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","/csharp/architecture-best-practices/di-ioc","01.csharp/04.architecture-best-practices/08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","/csharp/architecture-best-practices/di-ioc/the-dependency-problem","01.csharp/04.architecture-best-practices/08.di-ioc/01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","/csharp/architecture-best-practices/di-ioc/build-your-own-container","01.csharp/04.architecture-best-practices/08.di-ioc/02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","/csharp/architecture-best-practices/di-ioc/service-locator-pattern","01.csharp/04.architecture-best-practices/08.di-ioc/03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","/csharp/architecture-best-practices/di-ioc/dependency-injection-patterns","01.csharp/04.architecture-best-practices/08.di-ioc/04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","/csharp/architecture-best-practices/di-ioc/microsoft-di-deep-dive","01.csharp/04.architecture-best-practices/08.di-ioc/05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","/csharp/architecture-best-practices/di-ioc/service-lifetimes-and-scopes","01.csharp/04.architecture-best-practices/08.di-ioc/06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","/csharp/architecture-best-practices/di-ioc/di-anti-patterns-and-best-practices","01.csharp/04.architecture-best-practices/08.di-ioc/07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","/csharp/standard-library","01.csharp/05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","/csharp/standard-library/collections","01.csharp/05.standard-library/01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","/csharp/standard-library/high-performance-types","01.csharp/05.standard-library/02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","/csharp/standard-library/linq","01.csharp/05.standard-library/03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","/csharp/system-internals-concurrency","01.csharp/06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","/csharp/system-internals-concurrency/memory-management","01.csharp/06.system-internals-concurrency/01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","/csharp/system-internals-concurrency/reflection-fundamentals","01.csharp/06.system-internals-concurrency/02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","/csharp/system-internals-concurrency/attributes-dynamic","01.csharp/06.system-internals-concurrency/03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","/csharp/system-internals-concurrency/expression-trees-compiled","01.csharp/06.system-internals-concurrency/04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","/csharp/system-internals-concurrency/source-generators","01.csharp/06.system-internals-concurrency/05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","/csharp/system-internals-concurrency/multithreading-fundamentals","01.csharp/06.system-internals-concurrency/06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","/csharp/system-internals-concurrency/synchronization-primitives","01.csharp/06.system-internals-concurrency/07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","/csharp/system-programming-windows","01.csharp/07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","/csharp/system-programming-windows/how-os-works","01.csharp/07.system-programming-windows/01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","/csharp/system-programming-windows/processes-in-dotnet","01.csharp/07.system-programming-windows/02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","/csharp/system-programming-windows/02a.processes-ipc","01.csharp/07.system-programming-windows/02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","/csharp/system-programming-windows/appdomains-assemblies","01.csharp/07.system-programming-windows/03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","/csharp/system-programming-windows/03a.appdomains-plugin-system","01.csharp/07.system-programming-windows/03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","/csharp/system-programming-windows/thread-fundamentals","01.csharp/07.system-programming-windows/04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","/csharp/system-programming-windows/04a.thread-lifecycle-priorities","01.csharp/07.system-programming-windows/04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","/csharp/system-programming-windows/shared-state-problems","01.csharp/07.system-programming-windows/05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","/csharp/system-programming-windows/05a.shared-state-memory-model","01.csharp/07.system-programming-windows/05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","/csharp/system-programming-windows/synchronization-fundamentals","01.csharp/07.system-programming-windows/06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","/csharp/system-programming-windows/06a.synchronization-walkthrough","01.csharp/07.system-programming-windows/06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","/csharp/system-programming-windows/synchronization-advanced","01.csharp/07.system-programming-windows/07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","/csharp/system-programming-windows/07a.synchronization-advanced-walkthrough","01.csharp/07.system-programming-windows/07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","/csharp/system-programming-windows/interlocked-cas-lockfree","01.csharp/07.system-programming-windows/08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","/csharp/system-programming-windows/08a.volatile-memory-model","01.csharp/07.system-programming-windows/08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","/csharp/system-programming-windows/thread-pool","01.csharp/07.system-programming-windows/09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","/csharp/system-programming-windows/09a.thread-pool-advanced","01.csharp/07.system-programming-windows/09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","/csharp/system-programming-windows/concurrent-collections","01.csharp/07.system-programming-windows/10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","/csharp/system-programming-windows/tpl-parallel-plinq","01.csharp/07.system-programming-windows/11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","/csharp/system-programming-windows/11a.tpl-parallel-plinq-advanced","01.csharp/07.system-programming-windows/11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async/Await — Фундамент Асинхронного Програмування","/csharp/system-programming-windows/async-fundamentals","01.csharp/07.system-programming-windows/12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","/csharp/system-programming-windows/async-context-configureawait","01.csharp/07.system-programming-windows/13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","/csharp/system-programming-windows/async-advanced","01.csharp/07.system-programming-windows/14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","/csharp/system-programming-windows/channels","01.csharp/07.system-programming-windows/15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","/csharp/system-programming-windows/async-synchronization","01.csharp/07.system-programming-windows/16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","/csharp/system-programming-windows/unsafe-code","01.csharp/07.system-programming-windows/17.unsafe-code",{"title":364,"path":365,"stem":366},"P/Invoke та Windows API — Міст між .NET та Native Code","/csharp/system-programming-windows/pinvoke-winapi","01.csharp/07.system-programming-windows/18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","/csharp/system-programming-windows/windows-registry","01.csharp/07.system-programming-windows/19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","/csharp/system-programming-windows/windows-hooks-services","01.csharp/07.system-programming-windows/20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","/csharp/system-programming-windows/implementation_plan","01.csharp/07.system-programming-windows/implementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","/csharp/io","01.csharp/08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","/csharp/io/file-system-basics","01.csharp/08.io/01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","/csharp/io/streams-serialization","01.csharp/08.io/02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","/csharp/io/json-serialization","01.csharp/08.io/03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","/csharp/io/xml-serialization","01.csharp/08.io/04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","/csharp/io/binary-serialization","01.csharp/08.io/05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","/csharp/ado-net","01.csharp/09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","/csharp/ado-net/introduction-to-adonet","01.csharp/09.ado-net/01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","/csharp/ado-net/connection","01.csharp/09.ado-net/02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","/csharp/ado-net/command-and-queries","01.csharp/09.ado-net/03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","/csharp/ado-net/datareader","01.csharp/09.ado-net/04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","/csharp/ado-net/parameters-and-sql-injection","01.csharp/09.ado-net/05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","/csharp/ado-net/transactions","01.csharp/09.ado-net/06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","/csharp/ado-net/provider-factory","01.csharp/09.ado-net/07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","/csharp/ado-net/async-data-access","01.csharp/09.ado-net/08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","/csharp/ado-net/disconnected-mode-dataset","01.csharp/09.ado-net/09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","/csharp/ado-net/data-adapter","01.csharp/09.ado-net/10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","/csharp/ado-net/data-mapper-repository","01.csharp/09.ado-net/11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","/csharp/ado-net/advanced-patterns","01.csharp/09.ado-net/12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","/csharp/ef-core","01.csharp/10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","/csharp/ef-core/what-is-orm","01.csharp/10.ef-core/01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","/csharp/ef-core/first-project","01.csharp/10.ef-core/02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","/csharp/ef-core/dbcontext-deep-dive","01.csharp/10.ef-core/03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","/csharp/ef-core/database-providers","01.csharp/10.ef-core/04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","/csharp/ef-core/conventions","01.csharp/10.ef-core/05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","/csharp/ef-core/fluent-api-vs-annotations","01.csharp/10.ef-core/06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","/csharp/ef-core/relationships-basics","01.csharp/10.ef-core/07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","/csharp/ef-core/relationships-advanced","01.csharp/10.ef-core/08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","/csharp/ef-core/property-configuration-part1","01.csharp/10.ef-core/09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","/csharp/ef-core/property-configuration-part2","01.csharp/10.ef-core/09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","/csharp/ef-core/complex-types-owned-part1","01.csharp/10.ef-core/10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","/csharp/ef-core/complex-types-owned-part2","01.csharp/10.ef-core/10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","/csharp/ef-core/json-columns-part1","01.csharp/10.ef-core/11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","/csharp/ef-core/json-columns-part2","01.csharp/10.ef-core/11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","/csharp/ef-core/inheritance-part1","01.csharp/10.ef-core/12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","/csharp/ef-core/inheritance-part2","01.csharp/10.ef-core/12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","/csharp/ef-core/indexes-constraints-part1","01.csharp/10.ef-core/13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","/csharp/ef-core/indexes-constraints-part2","01.csharp/10.ef-core/13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","/csharp/ef-core/seeding-part1","01.csharp/10.ef-core/14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","/csharp/ef-core/seeding-part2","01.csharp/10.ef-core/14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","/csharp/ef-core/global-query-filters-part1","01.csharp/10.ef-core/15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","/csharp/ef-core/global-query-filters-part2","01.csharp/10.ef-core/15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","/csharp/ef-core/linq-queries-part1","01.csharp/10.ef-core/16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","/csharp/ef-core/linq-queries-part2","01.csharp/10.ef-core/16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","/csharp/ef-core/loading-related-data-part1","01.csharp/10.ef-core/17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","/csharp/ef-core/loading-related-data-part2","01.csharp/10.ef-core/17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","/csharp/ef-core/raw-sql-part1","01.csharp/10.ef-core/18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","/csharp/ef-core/raw-sql-part2","01.csharp/10.ef-core/18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","/csharp/ef-core/advanced-queries-part1","01.csharp/10.ef-core/19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","/csharp/ef-core/advanced-queries-part2","01.csharp/10.ef-core/19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","/csharp/ef-core/change-tracking-part1","01.csharp/10.ef-core/20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","/csharp/ef-core/change-tracking-part2","01.csharp/10.ef-core/20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","/csharp/ef-core/saving-data-part1","01.csharp/10.ef-core/21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","/csharp/ef-core/saving-data-part2","01.csharp/10.ef-core/21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","/csharp/ef-core/concurrency-part1","01.csharp/10.ef-core/22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","/csharp/ef-core/concurrency-part2","01.csharp/10.ef-core/22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","/csharp/ef-core/migrations-basics-part1","01.csharp/10.ef-core/23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","/csharp/ef-core/migrations-basics-part2","01.csharp/10.ef-core/23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","/csharp/ef-core/migrations-advanced-part1","01.csharp/10.ef-core/24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","/csharp/ef-core/migrations-advanced-part2","01.csharp/10.ef-core/24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","/csharp/ef-core/schema-management-part1","01.csharp/10.ef-core/25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","/csharp/ef-core/schema-management-part2","01.csharp/10.ef-core/25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","/csharp/ef-core/performance-fundamentals-part1","01.csharp/10.ef-core/26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","/csharp/ef-core/interceptors-part1","01.csharp/10.ef-core/29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","/csharp/ef-core/interceptors-part2","01.csharp/10.ef-core/29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","/csharp/ef-core/implementation_plan","01.csharp/10.ef-core/implementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","/csharp/aspnet","01.csharp/11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","/csharp/aspnet/minimal-api","01.csharp/11.aspnet/01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","/csharp/aspnet/minimal-api/introduction","01.csharp/11.aspnet/01.minimal-api/01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","/csharp/aspnet/minimal-api/first-application","01.csharp/11.aspnet/01.minimal-api/02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","/csharp/aspnet/minimal-api/webapplication-builder","01.csharp/11.aspnet/01.minimal-api/03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","/csharp/aspnet/minimal-api/request-pipeline-middleware","01.csharp/11.aspnet/01.minimal-api/04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/routing-basics","01.csharp/11.aspnet/01.minimal-api/05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","/csharp/aspnet/minimal-api/routing-advanced","01.csharp/11.aspnet/01.minimal-api/06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","/csharp/aspnet/minimal-api/static-files","01.csharp/11.aspnet/01.minimal-api/07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","/csharp/aspnet/minimal-api/static-assets","01.csharp/11.aspnet/01.minimal-api/08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/configuration-fundamentals","01.csharp/11.aspnet/01.minimal-api/09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","/csharp/aspnet/minimal-api/configuration-options","01.csharp/11.aspnet/01.minimal-api/10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/logging-basics","01.csharp/11.aspnet/01.minimal-api/11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","/csharp/aspnet/minimal-api/logging-advanced","01.csharp/11.aspnet/01.minimal-api/12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","/csharp/aspnet/minimal-api/state-management","01.csharp/11.aspnet/01.minimal-api/13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","/csharp/aspnet/minimal-api/session-state","01.csharp/11.aspnet/01.minimal-api/14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","/csharp/aspnet/minimal-api/project-structure","01.csharp/11.aspnet/01.minimal-api/15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","/csharp/aspnet/minimal-api/scalar-openapi-fluent","01.csharp/11.aspnet/01.minimal-api/16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger / Swashbuckle у Minimal API: окремий класичний шлях","/csharp/aspnet/minimal-api/swagger-swashbuckle","01.csharp/11.aspnet/01.minimal-api/17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","/csharp/aspnet/api","01.csharp/11.aspnet/02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","/csharp/aspnet/api/what-is-api","01.csharp/11.aspnet/02.api/01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","/csharp/aspnet/api/data-formats","01.csharp/11.aspnet/02.api/02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","/csharp/aspnet/api/api-paradigms-rest","01.csharp/11.aspnet/02.api/03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","/csharp/aspnet/api/http-methods-status-codes","01.csharp/11.aspnet/02.api/04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","/csharp/aspnet/api/rest-organizing","01.csharp/11.aspnet/02.api/05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","/csharp/aspnet/api/url-nomenclature-crud","01.csharp/11.aspnet/02.api/06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","/csharp/aspnet/api/api-design-naming","01.csharp/11.aspnet/02.api/07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","/csharp/aspnet/api/api-design-validation","01.csharp/11.aspnet/02.api/08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","/csharp/aspnet/api/error-handling-http","01.csharp/11.aspnet/02.api/09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","/csharp/aspnet/api/idempotency-sync","01.csharp/11.aspnet/02.api/10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","/csharp/aspnet/api/pagination-lists","01.csharp/11.aspnet/02.api/11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","/csharp/aspnet/api/security-auth","01.csharp/11.aspnet/02.api/12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","/csharp/aspnet/api/api-design-process","01.csharp/11.aspnet/02.api/13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","/csharp/aspnet/api/openapi","01.csharp/11.aspnet/02.api/14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","/csharp/aspnet/auth","01.csharp/11.aspnet/03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","/csharp/aspnet/auth/auth-fundamentals","01.csharp/11.aspnet/03.auth/01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","/csharp/aspnet/auth/jwt-authentication","01.csharp/11.aspnet/03.auth/02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","/csharp/aspnet/auth/authorization-policies","01.csharp/11.aspnet/03.auth/03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","/csharp/aspnet/auth/cookie-auth-identity","01.csharp/11.aspnet/03.auth/04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","/csharp/aspnet/auth/04b.identity-auth-jwt","01.csharp/11.aspnet/03.auth/04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","/csharp/aspnet/auth/identity-email-confirmation","01.csharp/11.aspnet/03.auth/05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","/csharp/aspnet/auth/identity-two-factor","01.csharp/11.aspnet/03.auth/06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","/csharp/aspnet/auth/identity-internals","01.csharp/11.aspnet/03.auth/07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","/csharp/aspnet/auth/oauth-external-providers","01.csharp/11.aspnet/03.auth/08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","/csharp/aspnet/auth/security-hardening","01.csharp/11.aspnet/03.auth/09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","/csharp/aspnet/auth/oauth-theory","01.csharp/11.aspnet/03.auth/10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","/csharp/aspnet/auth/oidc-keycloak","01.csharp/11.aspnet/03.auth/10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","/csharp/aspnet/auth/api-keys","01.csharp/11.aspnet/03.auth/11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","/csharp/aspnet/auth/rate-limiting","01.csharp/11.aspnet/03.auth/12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","/csharp/aspnet/auth/refresh-token-rotation","01.csharp/11.aspnet/03.auth/13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","/csharp/aspnet/auth/certificate-auth","01.csharp/11.aspnet/03.auth/14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","/csharp/aspnet/auth/rbac-abac-rebac","01.csharp/11.aspnet/03.auth/15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","/csharp/aspnet/auth/multi-tenancy","01.csharp/11.aspnet/03.auth/16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","/csharp/aspnet/notifications","01.csharp/11.aspnet/04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","/csharp/aspnet/notifications/in-app-database-notifications","01.csharp/11.aspnet/04.notifications/01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","/csharp/aspnet/notifications/polling","01.csharp/11.aspnet/04.notifications/02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","/csharp/aspnet/notifications/server-sent-events","01.csharp/11.aspnet/04.notifications/03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","/csharp/aspnet/notifications/websockets","01.csharp/11.aspnet/04.notifications/04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","/csharp/aspnet/notifications/signalr","01.csharp/11.aspnet/04.notifications/05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","/csharp/aspnet/notifications/background-services","01.csharp/11.aspnet/04.notifications/06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","/csharp/aspnet/notifications/web-push","01.csharp/11.aspnet/04.notifications/07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","/csharp/aspnet/notifications/email-notifications","01.csharp/11.aspnet/04.notifications/08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","/csharp/aspnet/notifications/choosing-the-right-approach","01.csharp/11.aspnet/04.notifications/09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","/csharp/aspnet/notifications/hangfire","01.csharp/11.aspnet/04.notifications/10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","/csharp/aspnet/notifications/hangfire-image-webp","01.csharp/11.aspnet/04.notifications/11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","/csharp/aspnet/notifications/hangfire-video-hls","01.csharp/11.aspnet/04.notifications/12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","/csharp/aspnet/notifications/telegram-notifications","01.csharp/11.aspnet/04.notifications/13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","/csharp/aspnet/i18n","01.csharp/11.aspnet/05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","/csharp/aspnet/i18n/internationalization","01.csharp/11.aspnet/05.i18n/01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","/csharp/aspnet/i18n/humanizer","01.csharp/11.aspnet/05.i18n/02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","/csharp/aspnet/caching","01.csharp/11.aspnet/06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","/csharp/aspnet/caching/caching","01.csharp/11.aspnet/06.caching/01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","/csharp/aspnet/caching/memory-cache","01.csharp/11.aspnet/06.caching/02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","/csharp/aspnet/caching/distributed-cache","01.csharp/11.aspnet/06.caching/03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","/csharp/aspnet/caching/response-cache","01.csharp/11.aspnet/06.caching/04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","/csharp/aspnet/caching/output-cache","01.csharp/11.aspnet/06.caching/05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","/csharp/aspnet/testing","01.csharp/11.aspnet/07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","/csharp/aspnet/testing/what-is-testing","01.csharp/11.aspnet/07.testing/01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","/csharp/aspnet/testing/testing-pyramid","01.csharp/11.aspnet/07.testing/02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","/csharp/aspnet/testing/testing-schools","01.csharp/11.aspnet/07.testing/03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","/csharp/aspnet/testing/tdd-and-bdd","01.csharp/11.aspnet/07.testing/04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","/csharp/aspnet/testing/what-to-test","01.csharp/11.aspnet/07.testing/05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","/csharp/aspnet/testing/test-frameworks","01.csharp/11.aspnet/07.testing/06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","/csharp/aspnet/testing/xunit-basics","01.csharp/11.aspnet/07.testing/07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","/csharp/aspnet/testing/xunit-advanced","01.csharp/11.aspnet/07.testing/08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","/csharp/aspnet/testing/mocking-with-moq","01.csharp/11.aspnet/07.testing/09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","/csharp/aspnet/testing/database-testing","01.csharp/11.aspnet/07.testing/10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","/csharp/aspnet/testing/integration-testing","01.csharp/11.aspnet/07.testing/11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","/csharp/aspnet/testing/11a.integration-testing-practice","01.csharp/11.aspnet/07.testing/11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","/csharp/aspnet/testing/integration-testing-advanced","01.csharp/11.aspnet/07.testing/12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","/csharp/aspnet/testing/postman-professional","01.csharp/11.aspnet/07.testing/13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","/csharp/aspnet/testing/httpclient-testing","01.csharp/11.aspnet/07.testing/14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","/csharp/aspnet/testing/wiremock-net","01.csharp/11.aspnet/07.testing/15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","/csharp/aspnet/testing/testing-patterns","01.csharp/11.aspnet/07.testing/16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","/csharp/aspnet/testing/advanced-testing-tools","01.csharp/11.aspnet/07.testing/17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","/csharp/aspnet/testing/architecture-testing","01.csharp/11.aspnet/07.testing/18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","/csharp/aspnet/testing/performance-testing","01.csharp/11.aspnet/07.testing/19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","/csharp/aspnet/testing/remaining_plan","01.csharp/11.aspnet/07.testing/remaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","/csharp/aspnet/payments","01.csharp/11.aspnet/08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","/csharp/aspnet/payments/payment-fundamentals","01.csharp/11.aspnet/08.payments/01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","/csharp/aspnet/payments/payment-methods-ukraine","01.csharp/11.aspnet/08.payments/02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","/csharp/aspnet/payments/pci-dss-security","01.csharp/11.aspnet/08.payments/03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","/csharp/aspnet/payments/payment-architecture","01.csharp/11.aspnet/08.payments/04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","/csharp/aspnet/payments/liqpay-integration","01.csharp/11.aspnet/08.payments/05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","/csharp/aspnet/payments/monobank-acquiring","01.csharp/11.aspnet/08.payments/06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","/csharp/aspnet/payments/stripe-integration","01.csharp/11.aspnet/08.payments/07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","/csharp/aspnet/payments/webhooks-deep-dive","01.csharp/11.aspnet/08.payments/08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","/csharp/aspnet/payments/subscriptions-recurring","01.csharp/11.aspnet/08.payments/09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","/csharp/aspnet/payments/refunds-disputes","01.csharp/11.aspnet/08.payments/10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","/csharp/aspnet/payments/testing-payments","01.csharp/11.aspnet/08.payments/11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","/csharp/aspnet/payments/production-checklist","01.csharp/11.aspnet/08.payments/12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","/csharp/aspnet/libraries","01.csharp/11.aspnet/09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","/csharp/aspnet/libraries/fluent-validation","01.csharp/11.aspnet/09.libraries/01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","/csharp/aspnet/libraries/mapster","01.csharp/11.aspnet/09.libraries/02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","/csharp/aspnet/libraries/erroror-result-pattern","01.csharp/11.aspnet/09.libraries/03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","/csharp/aspnet/libraries/serilog","01.csharp/11.aspnet/09.libraries/04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","/csharp/aspnet/libraries/mediatr","01.csharp/11.aspnet/09.libraries/05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","/csharp/aspnet/libraries/polly","01.csharp/11.aspnet/09.libraries/06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","/csharp/aspnet/libraries/health-checks","01.csharp/11.aspnet/09.libraries/07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","/csharp/aspnet/libraries/feature-management","01.csharp/11.aspnet/09.libraries/08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","/csharp/aspnet/libraries/fluent-email","01.csharp/11.aspnet/09.libraries/09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","/csharp/aspnet/libraries/quest-pdf","01.csharp/11.aspnet/09.libraries/10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","/csharp/aspnet/libraries/bogus","01.csharp/11.aspnet/09.libraries/11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","/csharp/aspnet/libraries/humanizer-guard","01.csharp/11.aspnet/09.libraries/12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","/csharp/aspnet/libraries/plan","01.csharp/11.aspnet/09.libraries/plan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","/csharp/aspnet/razor-pages","01.csharp/11.aspnet/10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","/csharp/aspnet/razor-pages/from-minimal-api","01.csharp/11.aspnet/10.razor-pages/01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","/csharp/aspnet/razor-pages/page-model","01.csharp/11.aspnet/10.razor-pages/02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","/csharp/aspnet/razor-pages/razor-syntax","01.csharp/11.aspnet/10.razor-pages/03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","/csharp/aspnet/razor-pages/tag-helpers","01.csharp/11.aspnet/10.razor-pages/04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","/csharp/aspnet/razor-pages/forms-validation","01.csharp/11.aspnet/10.razor-pages/05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","/csharp/aspnet/razor-pages/project-task-manager","01.csharp/11.aspnet/10.razor-pages/06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","/csharp/aspnet/mvc","01.csharp/11.aspnet/11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","/csharp/aspnet/mvc/mvc-pattern","01.csharp/11.aspnet/11.mvc/01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","/csharp/aspnet/mvc/from-razor-pages","01.csharp/11.aspnet/11.mvc/02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","/csharp/aspnet/mvc/controllers-actions","01.csharp/11.aspnet/11.mvc/03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","/csharp/aspnet/mvc/routing-mvc","01.csharp/11.aspnet/11.mvc/04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","/csharp/aspnet/mvc/model-binding","01.csharp/11.aspnet/11.mvc/05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","/csharp/aspnet/mvc/views-viewdata-tempdata","01.csharp/11.aspnet/11.mvc/06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","/csharp/aspnet/mvc/filters","01.csharp/11.aspnet/11.mvc/07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","/csharp/aspnet/mvc/areas","01.csharp/11.aspnet/11.mvc/08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","/csharp/aspnet/mvc/view-components","01.csharp/11.aspnet/11.mvc/09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","/csharp/aspnet/mvc/display-editor-templates","01.csharp/11.aspnet/11.mvc/10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","/csharp/aspnet/mvc/validation-advanced","01.csharp/11.aspnet/11.mvc/11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","/csharp/aspnet/mvc/htmx","01.csharp/11.aspnet/11.mvc/12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","/csharp/aspnet/mvc/ajax-htmx-mvc","01.csharp/11.aspnet/11.mvc/13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","/csharp/aspnet/mvc/htmx-project","01.csharp/11.aspnet/11.mvc/14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","/csharp/aspnet/mvc/file-upload","01.csharp/11.aspnet/11.mvc/15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","/csharp/aspnet/mvc/globalization-localization","01.csharp/11.aspnet/11.mvc/16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","/csharp/aspnet/mvc/mvc-project","01.csharp/11.aspnet/11.mvc/17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","/csharp/aspnet/mvc/plan","01.csharp/11.aspnet/11.mvc/plan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","/csharp/aspnet/web-api","01.csharp/11.aspnet/12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","/csharp/aspnet/web-api/from-minimal-api-to-controllers","01.csharp/11.aspnet/12.web-api/01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","/csharp/aspnet/web-api/controller-base-actionresult","01.csharp/11.aspnet/12.web-api/02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","/csharp/aspnet/web-api/content-negotiation","01.csharp/11.aspnet/12.web-api/03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","/csharp/aspnet/web-api/api-versioning","01.csharp/11.aspnet/12.web-api/04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","/csharp/aspnet/web-api/problemdetails-error-handling","01.csharp/11.aspnet/12.web-api/05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","/csharp/aspnet/web-api/filters-for-api","01.csharp/11.aspnet/12.web-api/06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","/csharp/aspnet/web-api/pagination-filtering-sorting","01.csharp/11.aspnet/12.web-api/07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","/csharp/aspnet/web-api/hateoas-resource-expansion","01.csharp/11.aspnet/12.web-api/08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","/csharp/aspnet/web-api/minimal-api-vs-controllers-hybrid","01.csharp/11.aspnet/12.web-api/09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","/csharp/aspnet/web-api/api-documentation-generation","01.csharp/11.aspnet/12.web-api/10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","/csharp/aspnet/web-api/health-checks-monitoring","01.csharp/11.aspnet/12.web-api/11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","/csharp/aspnet/web-api/web-api-project","01.csharp/11.aspnet/12.web-api/12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","/csharp/aspnet/web-api/plan","01.csharp/11.aspnet/12.web-api/plan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Desktop UI","i-lucide-app-window","/csharp/desktop-ui","01.csharp/12.desktop-ui",[1352,1356,1360,1364,1368,1372,1376,1380,1384,1388,1392,1396,1400,1404,1408,1412,1416,1420,1424,1428,1432,1436,1440,1444,1448,1452,1456,1460,1464,1468,1472,1476,1480,1484,1488,1492,1496,1500,1504,1508,1512,1516,1520,1524,1528,1532,1536,1540,1544,1548,1552,1556,1560,1564,1568,1572,1576,1580,1584,1588,1592,1596,1600,1604,1608,1612,1616,1620,1624,1628,1632],{"title":1353,"path":1354,"stem":1355},"Що таке десктопна розробка?","/csharp/desktop-ui/what-is-desktop-dev","01.csharp/12.desktop-ui/01.what-is-desktop-dev",{"title":1357,"path":1358,"stem":1359},"Архітектура WPF — як влаштований графічний інтерфейс","/csharp/desktop-ui/wpf-architecture","01.csharp/12.desktop-ui/02.wpf-architecture",{"title":1361,"path":1362,"stem":1363},"Перший WPF-проєкт — від нуля до вікна","/csharp/desktop-ui/first-wpf-app","01.csharp/12.desktop-ui/03.first-wpf-app",{"title":1365,"path":1366,"stem":1367},"Перший Avalonia-проєкт: WPF для всіх платформ","/csharp/desktop-ui/03a.first-avalonia-app","01.csharp/12.desktop-ui/03a.first-avalonia-app",{"title":1369,"path":1370,"stem":1371},"XAML: декларативний інтерфейс","/csharp/desktop-ui/xaml-basics","01.csharp/12.desktop-ui/04.xaml-basics",{"title":1373,"path":1374,"stem":1375},"Fluent UI у WPF — сучасний дизайн Windows 11","/csharp/desktop-ui/04a.wpf-fluent-ui","01.csharp/12.desktop-ui/04a.wpf-fluent-ui",{"title":1377,"path":1378,"stem":1379},"WPF UI — сучасна бібліотека Fluent контролів","/csharp/desktop-ui/04b.wpf-ui-library","01.csharp/12.desktop-ui/04b.wpf-ui-library",{"title":1381,"path":1382,"stem":1383},"HandyControl — велика бібліотека UI контролів для WPF","/csharp/desktop-ui/04c.handycontrol-library","01.csharp/12.desktop-ui/04c.handycontrol-library",{"title":1385,"path":1386,"stem":1387},"Простори імен та ресурси XAML","/csharp/desktop-ui/xaml-namespaces-resources","01.csharp/12.desktop-ui/05.xaml-namespaces-resources",{"title":1389,"path":1390,"stem":1391},"XAML в Avalonia: ключові відмінності від WPF","/csharp/desktop-ui/05a.avalonia-xaml-differences","01.csharp/12.desktop-ui/05a.avalonia-xaml-differences",{"title":1393,"path":1394,"stem":1395},"Розширення розмітки XAML (Markup Extensions)","/csharp/desktop-ui/xaml-markup-extensions","01.csharp/12.desktop-ui/06.xaml-markup-extensions",{"title":1397,"path":1398,"stem":1399},"Панелі Layout: StackPanel, WrapPanel, DockPanel","/csharp/desktop-ui/layout-panels-part1","01.csharp/12.desktop-ui/07.layout-panels-part1",{"title":1401,"path":1402,"stem":1403},"Grid, Canvas, UniformGrid","/csharp/desktop-ui/layout-panels-part2","01.csharp/12.desktop-ui/07.layout-panels-part2",{"title":1405,"path":1406,"stem":1407},"Просунуті техніки Layout","/csharp/desktop-ui/layout-advanced","01.csharp/12.desktop-ui/08.layout-advanced",{"title":1409,"path":1410,"stem":1411},"Адаптивний Layout та найкращі практики","/csharp/desktop-ui/layout-responsive","01.csharp/12.desktop-ui/09.layout-responsive",{"title":1413,"path":1414,"stem":1415},"Layout в Avalonia: відмінності та нові можливості","/csharp/desktop-ui/09a.layout-avalonia","01.csharp/12.desktop-ui/09a.layout-avalonia",{"title":1417,"path":1418,"stem":1419},"Button, Image, ProgressBar та інші базові контроли","/csharp/desktop-ui/basic-controls","01.csharp/12.desktop-ui/10.basic-controls",{"title":1421,"path":1422,"stem":1423},"Контроли в Avalonia: відмінності від WPF","/csharp/desktop-ui/10a.controls-avalonia","01.csharp/12.desktop-ui/10a.controls-avalonia",{"title":1425,"path":1426,"stem":1427},"Текстові контроли — TextBlock, TextBox, RichTextBox","/csharp/desktop-ui/text-controls","01.csharp/12.desktop-ui/11.text-controls",{"title":1429,"path":1430,"stem":1431},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","/csharp/desktop-ui/selection-controls","01.csharp/12.desktop-ui/12.selection-controls",{"title":1433,"path":1434,"stem":1435},"Content Model — GroupBox, Expander, TabControl, StatusBar","/csharp/desktop-ui/content-controls","01.csharp/12.desktop-ui/13.content-controls",{"title":1437,"path":1438,"stem":1439},"UI/UX принципи десктопних застосунків","/csharp/desktop-ui/13a.ui-ux-principles","01.csharp/12.desktop-ui/13a.ui-ux-principles",{"title":1441,"path":1442,"stem":1443},"Dependency Properties — Концепція та Value Resolution","/csharp/desktop-ui/dependency-properties-part1","01.csharp/12.desktop-ui/14.dependency-properties-part1",{"title":1445,"path":1446,"stem":1447},"Avalonia Property System — StyledProperty та DirectProperty","/csharp/desktop-ui/14a.avalonia-property-system","01.csharp/12.desktop-ui/14a.avalonia-property-system",{"title":1449,"path":1450,"stem":1451},"Attached Properties — Властивості без меж","/csharp/desktop-ui/attached-properties","01.csharp/12.desktop-ui/15.attached-properties",{"title":1453,"path":1454,"stem":1455},"Routed Events — Маршрутизація подій у WPF","/csharp/desktop-ui/routed-events","01.csharp/12.desktop-ui/16.routed-events",{"title":1457,"path":1458,"stem":1459},"Data Binding — Від Code-Behind до Декларативності","/csharp/desktop-ui/data-binding-basics-part1","01.csharp/12.desktop-ui/17.data-binding-basics-part1",{"title":1461,"path":1462,"stem":1463},"INotifyPropertyChanged — Живе оновлення UI","/csharp/desktop-ui/data-binding-basics-part2","01.csharp/12.desktop-ui/17.data-binding-basics-part2",{"title":1465,"path":1466,"stem":1467},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","/csharp/desktop-ui/17a.avalonia-compiled-bindings","01.csharp/12.desktop-ui/17a.avalonia-compiled-bindings",{"title":1469,"path":1470,"stem":1471},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","/csharp/desktop-ui/data-binding-advanced","01.csharp/12.desktop-ui/18.data-binding-advanced",{"title":1473,"path":1474,"stem":1475},"Value Converters — Перетворення типів даних у Data Binding","/csharp/desktop-ui/value-converters","01.csharp/12.desktop-ui/19.value-converters",{"title":1477,"path":1478,"stem":1479},"Data Templates — Візуалізація об'єктів у WPF","/csharp/desktop-ui/data-templates","01.csharp/12.desktop-ui/20.data-templates",{"title":1481,"path":1482,"stem":1483},"Collections Binding Part 1 — ObservableCollection та ItemsControl","/csharp/desktop-ui/collections-binding-part1","01.csharp/12.desktop-ui/21.collections-binding-part1",{"title":1485,"path":1486,"stem":1487},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","/csharp/desktop-ui/collections-binding-part2","01.csharp/12.desktop-ui/21.collections-binding-part2",{"title":1489,"path":1490,"stem":1491},"MVVM Pattern — Від Spaghetti Code до архітектури","/csharp/desktop-ui/mvvm-pattern","01.csharp/12.desktop-ui/22.mvvm-pattern",{"title":1493,"path":1494,"stem":1495},"ViewModel Implementation — Від BaseViewModel до валідації","/csharp/desktop-ui/viewmodel-implementation","01.csharp/12.desktop-ui/23.viewmodel-implementation",{"title":1497,"path":1498,"stem":1499},"Commands — Від event handlers до декларативних команд","/csharp/desktop-ui/commands","01.csharp/12.desktop-ui/24.commands",{"title":1501,"path":1502,"stem":1503},"MVVM Toolkit — MVVM без boilerplate через Source Generators","/csharp/desktop-ui/mvvm-toolkit","01.csharp/12.desktop-ui/25.mvvm-toolkit",{"title":1505,"path":1506,"stem":1507},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","/csharp/desktop-ui/messenger-pattern","01.csharp/12.desktop-ui/26.messenger-pattern",{"title":1509,"path":1510,"stem":1511},"Стилі WPF — CSS для десктопу","/csharp/desktop-ui/styles-basics","01.csharp/12.desktop-ui/27.styles-basics",{"title":1513,"path":1514,"stem":1515},"CSS-like стилі Avalonia","/csharp/desktop-ui/27a.avalonia-css-styling","01.csharp/12.desktop-ui/27a.avalonia-css-styling",{"title":1517,"path":1518,"stem":1519},"Control Templates — Частина 1. Концепція та TemplateBinding","/csharp/desktop-ui/control-templates-part1","01.csharp/12.desktop-ui/28.control-templates-part1",{"title":1521,"path":1522,"stem":1523},"Control Templates — Частина 2. Named Parts та ContentPresenter","/csharp/desktop-ui/control-templates-part2","01.csharp/12.desktop-ui/28.control-templates-part2",{"title":1525,"path":1526,"stem":1527},"Control Themes в Avalonia — нова ера стилізації","/csharp/desktop-ui/28a.avalonia-control-themes","01.csharp/12.desktop-ui/28a.avalonia-control-themes",{"title":1529,"path":1530,"stem":1531},"Triggers та Visual State Manager у WPF","/csharp/desktop-ui/triggers-visual-states","01.csharp/12.desktop-ui/29.triggers-visual-states",{"title":1533,"path":1534,"stem":1535},"Pseudo-classes в Avalonia — замість WPF Triggers","/csharp/desktop-ui/29a.avalonia-pseudo-classes","01.csharp/12.desktop-ui/29a.avalonia-pseudo-classes",{"title":1537,"path":1538,"stem":1539},"Теми та ресурсні словники у WPF","/csharp/desktop-ui/resources-themes","01.csharp/12.desktop-ui/30.resources-themes",{"title":1541,"path":1542,"stem":1543},"Avalonia Themes — Fluent Design та система тематизації","/csharp/desktop-ui/30a.avalonia-themes-fluent","01.csharp/12.desktop-ui/30a.avalonia-themes-fluent",{"title":1545,"path":1546,"stem":1547},"Контроли колекцій — глибоке занурення","/csharp/desktop-ui/collection-controls","01.csharp/12.desktop-ui/31.collection-controls",{"title":1549,"path":1550,"stem":1551},"DataGrid — колонки та базове відображення","/csharp/desktop-ui/datagrid-part1","01.csharp/12.desktop-ui/32.datagrid-part1",{"title":1553,"path":1554,"stem":1555},"DataGrid — сортування, фільтрація, редагування","/csharp/desktop-ui/datagrid-part2","01.csharp/12.desktop-ui/32.datagrid-part2",{"title":1557,"path":1558,"stem":1559},"TreeView та GridView","/csharp/desktop-ui/treeview-listview","01.csharp/12.desktop-ui/33.treeview-listview",{"title":1561,"path":1562,"stem":1563},"Меню, Toolbar, ContextMenu, StatusBar","/csharp/desktop-ui/menus-toolbars","01.csharp/12.desktop-ui/34.menus-toolbars",{"title":1565,"path":1566,"stem":1567},"Навігація та керування вікнами. Частина 1: вікна та сторінки","/csharp/desktop-ui/navigation-windows-part1","01.csharp/12.desktop-ui/35.navigation-windows-part1",{"title":1569,"path":1570,"stem":1571},"Навігація та керування вікнами. Частина 2: MVVM-навігація","/csharp/desktop-ui/navigation-windows-part2","01.csharp/12.desktop-ui/35.navigation-windows-part2",{"title":1573,"path":1574,"stem":1575},"Avalonia — Навігація та діалоги","/csharp/desktop-ui/35a.avalonia-navigation-dialogs","01.csharp/12.desktop-ui/35a.avalonia-navigation-dialogs",{"title":1577,"path":1578,"stem":1579},"Діалоги та File Pickers у WPF","/csharp/desktop-ui/dialogs-file-pickers","01.csharp/12.desktop-ui/36.dialogs-file-pickers",{"title":1581,"path":1582,"stem":1583},"UserControl: компонентний підхід у WPF","/csharp/desktop-ui/user-controls","01.csharp/12.desktop-ui/37.user-controls",{"title":1585,"path":1586,"stem":1587},"Custom Controls: Lookless Controls у WPF","/csharp/desktop-ui/custom-controls","01.csharp/12.desktop-ui/38.custom-controls",{"title":1589,"path":1590,"stem":1591},"Avalonia TemplatedControl — Lookless Controls","/csharp/desktop-ui/38a.avalonia-templated-controls","01.csharp/12.desktop-ui/38a.avalonia-templated-controls",{"title":1593,"path":1594,"stem":1595},"Анімації у WPF: Storyboard та Easing Functions","/csharp/desktop-ui/animations-transitions","01.csharp/12.desktop-ui/39.animations-transitions",{"title":1597,"path":1598,"stem":1599},"Анімації в Avalonia","/csharp/desktop-ui/39a.avalonia-animations","01.csharp/12.desktop-ui/39a.avalonia-animations",{"title":1601,"path":1602,"stem":1603},"2D Графіка та Мультимедіа у WPF","/csharp/desktop-ui/media-graphics","01.csharp/12.desktop-ui/40.media-graphics",{"title":1605,"path":1606,"stem":1607},"Dependency Injection у WPF та Avalonia","/csharp/desktop-ui/di-integration","01.csharp/12.desktop-ui/41.di-integration",{"title":1609,"path":1610,"stem":1611},"SQLite та EF Core у десктопних додатках","/csharp/desktop-ui/data-persistence-part1","01.csharp/12.desktop-ui/42.data-persistence-part1",{"title":1613,"path":1614,"stem":1615},"Repository Pattern та Unit of Work","/csharp/desktop-ui/data-persistence-part2","01.csharp/12.desktop-ui/43.data-persistence-part2",{"title":1617,"path":1618,"stem":1619},"Тестування ViewModels","/csharp/desktop-ui/viewmodel-testing","01.csharp/12.desktop-ui/44.viewmodel-testing",{"title":1621,"path":1622,"stem":1623},"Avalonia Headless Testing — тестування UI без вікон","/csharp/desktop-ui/44a.avalonia-headless-testing","01.csharp/12.desktop-ui/44a.avalonia-headless-testing",{"title":1625,"path":1626,"stem":1627},"Кросплатформна розробка з Avalonia","/csharp/desktop-ui/avalonia-cross-platform","01.csharp/12.desktop-ui/45.avalonia-cross-platform",{"title":1629,"path":1630,"stem":1631},"Пакування та розгортання Avalonia додатків","/csharp/desktop-ui/avalonia-packaging-deployment","01.csharp/12.desktop-ui/46.avalonia-packaging-deployment",{"title":1633,"path":1634,"stem":1635},"Розгортання WPF застосунків","/csharp/desktop-ui/wpf-packaging-deployment","01.csharp/12.desktop-ui/47.wpf-packaging-deployment",{"title":1637,"icon":658,"path":1638,"stem":1639,"children":1640,"page":59},"Network Programming","/csharp/network-programming","01.csharp/13.network-programming",[1641,1645,1649],{"title":1642,"path":1643,"stem":1644},"Основи комп'ютерних мереж","/csharp/network-programming/foundations","01.csharp/13.network-programming/01.foundations",{"title":1646,"path":1647,"stem":1648},"Модель OSI та стек TCP/IP","/csharp/network-programming/osi-model","01.csharp/13.network-programming/02.osi-model",{"title":1650,"path":1651,"stem":1652},"IP-протокол та адресація","/csharp/network-programming/ip-addressing","01.csharp/13.network-programming/03.ip-addressing",{"title":1654,"path":1655,"stem":1656},"C# & .NET: The Ultimate Roadmap","/csharp/roadmap","01.csharp/roadmap",{"title":1658,"icon":1659,"path":1660,"stem":1661,"children":1662,"page":59},"C++","i-devicon-cplusplus","/cpp","02.cpp",[1663,1667,1671,1675,1679,1683,1687,1691,1695,1698,1702,1706,1710,1714,1718,1722,1726,1730,1734,1738,1742,1746,1750,1754,1758,1762,1766,1770,1774,1778,1782,1786,1790,1794,1798,1802,1806],{"title":1664,"path":1665,"stem":1666},"Вступ у програмування та алгоритми","/cpp/intro-algorithms","02.cpp/01.intro-algorithms",{"title":1668,"path":1669,"stem":1670},"Code Style: угоди про оформлення коду","/cpp/code-style","02.cpp/02.code-style",{"title":1672,"path":1673,"stem":1674},"Середовище розробки та перший проєкт","/cpp/ide-setup","02.cpp/03.ide-setup",{"title":1676,"path":1677,"stem":1678},"Вивід даних на екран","/cpp/data-output","02.cpp/04.data-output",{"title":1680,"path":1681,"stem":1682},"Типи даних, змінні та константи","/cpp/data-types-variables","02.cpp/05.data-types-variables",{"title":1684,"path":1685,"stem":1686},"Ввід даних з клавіатури","/cpp/data-input","02.cpp/06.data-input",{"title":1688,"path":1689,"stem":1690},"Оператори, перетворення типів та логічні операції","/cpp/operators-type-conversion","02.cpp/07.operators-type-conversion",{"title":1692,"path":1693,"stem":1694},"Цикли","/cpp/loops","02.cpp/08.loops",{"title":32,"path":1696,"stem":1697},"/cpp/arrays","02.cpp/09.arrays",{"title":1699,"path":1700,"stem":1701},"Алгоритми сортування та аналіз складності","/cpp/sorting","02.cpp/10.sorting",{"title":1703,"path":1704,"stem":1705},"Алгоритми пошуку","/cpp/searching","02.cpp/11.searching",{"title":1707,"path":1708,"stem":1709},"Функції: основи","/cpp/functions-basics","02.cpp/12.functions-basics",{"title":1711,"path":1712,"stem":1713},"Функції: прототипи, область видимості та додаткові можливості","/cpp/functions-scope","02.cpp/13.functions-scope",{"title":1715,"path":1716,"stem":1717},"Функції: перевантаження та шаблони","/cpp/functions-overloading-templates","02.cpp/14.functions-overloading-templates",{"title":1719,"path":1720,"stem":1721},"Вказівники: основи","/cpp/pointers-basics","02.cpp/15.pointers-basics",{"title":1723,"path":1724,"stem":1725},"Посилання (References)","/cpp/references","02.cpp/16.references",{"title":1727,"path":1728,"stem":1729},"Вказівники, const і масиви","/cpp/pointers-const-arrays","02.cpp/17.pointers-const-arrays",{"title":1731,"path":1732,"stem":1733},"Адресна арифметика","/cpp/pointer-arithmetic","02.cpp/18.pointer-arithmetic",{"title":1735,"path":1736,"stem":1737},"Динамічна пам'ять","/cpp/dynamic-memory","02.cpp/19.dynamic-memory",{"title":1739,"path":1740,"stem":1741},"Вказівники типу void","/cpp/void-pointers","02.cpp/20.void-pointers",{"title":1743,"path":1744,"stem":1745},"Вказівники на вказівники","/cpp/pointers-to-pointers","02.cpp/21.pointers-to-pointers",{"title":1747,"path":1748,"stem":1749},"Оператор доступу до членів через вказівник (->)","/cpp/member-access-operator","02.cpp/22.member-access-operator",{"title":1751,"path":1752,"stem":1753},"Цикл for-each (Range-based for)","/cpp/foreach-loop","02.cpp/23.foreach-loop",{"title":1755,"path":1756,"stem":1757},"Вказівники на функції","/cpp/function-pointers","02.cpp/24.function-pointers",{"title":1759,"path":1760,"stem":1761},"Лямбда-вирази","/cpp/lambdas","02.cpp/25.lambdas",{"title":1763,"path":1764,"stem":1765},"Лямбда-захоплення","/cpp/lambda-captures","02.cpp/26.lambda-captures",{"title":1767,"path":1768,"stem":1769},"Еліпсис","/cpp/ellipsis","02.cpp/27.ellipsis",{"title":1771,"path":1772,"stem":1773},"Аргументи командного рядка","/cpp/command-line-arguments","02.cpp/28.command-line-arguments",{"title":1775,"path":1776,"stem":1777},"Перерахування (enum)","/cpp/enum","02.cpp/29.enum",{"title":1779,"path":1780,"stem":1781},"Класи-перерахування (enum class)","/cpp/enum-class","02.cpp/30.enum-class",{"title":1783,"path":1784,"stem":1785},"Псевдоніми типів (typedef і using)","/cpp/type-aliases","02.cpp/31.type-aliases",{"title":1787,"path":1788,"stem":1789},"Системи числення та двійкова арифметика","/cpp/number-systems","02.cpp/32.number-systems",{"title":1791,"path":1792,"stem":1793},"Структури (struct): агрегування даних","/cpp/struct","02.cpp/33.struct",{"title":1795,"path":1796,"stem":1797},"Структури у функціях","/cpp/struct-functions","02.cpp/34.struct-functions",{"title":1799,"path":1800,"stem":1801},"Масиви структур і вкладені структури","/cpp/struct-arrays","02.cpp/35.struct-arrays",{"title":1803,"path":1804,"stem":1805},"Патерни struct та межі застосування","/cpp/struct-patterns","02.cpp/36.struct-patterns",{"title":1807,"path":1808,"stem":1809},"План навчання: Курс C++ — Продовження (Статті 29–60+)","/cpp/curriculum-plan","02.cpp/curriculum-plan",{"title":1811,"icon":1812,"path":1813,"stem":1814,"children":1815,"page":59},"JavaScript","i-devicon-javascript","/javascript","03.javascript",[1816,1842,1896,1918,2222,2260],{"title":1817,"icon":1818,"path":1819,"stem":1820,"children":1821,"page":59},"Events","i-lucide-mouse-pointer-click","/javascript/events","03.javascript/01.events",[1822,1826,1830,1834,1838],{"title":1823,"path":1824,"stem":1825},"Вступ до подій браузера","/javascript/events/intro","03.javascript/01.events/01.intro",{"title":1827,"path":1828,"stem":1829},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","/javascript/events/bubbling-capturing","03.javascript/01.events/02.bubbling-capturing",{"title":1831,"path":1832,"stem":1833},"Делегування подій (Event Delegation)","/javascript/events/delegate-events","03.javascript/01.events/03.delegate-events",{"title":1835,"path":1836,"stem":1837},"Типові дії браузера та preventDefault()","/javascript/events/prevent-default","03.javascript/01.events/04.prevent-default",{"title":1839,"path":1840,"stem":1841},"Запуск користувацьких подій (Custom Events)","/javascript/events/custom-events","03.javascript/01.events/05.custom-events",{"title":1843,"icon":1844,"path":1845,"stem":1846,"children":1847,"page":59},"Network","i-lucide-globe","/javascript/network","03.javascript/02.network",[1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892],{"title":1849,"path":1850,"stem":1851},"Fetch API - Сучасний підхід до HTTP-запитів","/javascript/network/01-fetch-api","03.javascript/02.network/01-fetch-api",{"title":1853,"path":1854,"stem":1855},"FormData - Робота з формами та файлами","/javascript/network/02-formdata","03.javascript/02.network/02-formdata",{"title":1857,"path":1858,"stem":1859},"Відстеження прогресу завантаження","/javascript/network/03-download-progress","03.javascript/02.network/03-download-progress",{"title":1861,"path":1862,"stem":1863},"Переривання fetch-запитів","/javascript/network/04-abort-requests","03.javascript/02.network/04-abort-requests",{"title":1865,"path":1866,"stem":1867},"CORS - Запити між різними джерелами","/javascript/network/05-cors","03.javascript/02.network/05-cors",{"title":1869,"path":1870,"stem":1871},"Fetch API - Повний довідник опцій","/javascript/network/06-fetch-options","03.javascript/02.network/06-fetch-options",{"title":1873,"path":1874,"stem":1875},"URL Objects - Робота з посиланнями","/javascript/network/07-url-objects","03.javascript/02.network/07-url-objects",{"title":1877,"path":1878,"stem":1879},"XMLHttpRequest - AJAX та низькорівневі запити","/javascript/network/08-xmlhttprequest","03.javascript/02.network/08-xmlhttprequest",{"title":1881,"path":1882,"stem":1883},"Відновлюване завантаження файлів","/javascript/network/09-resumable-upload","03.javascript/02.network/09-resumable-upload",{"title":1885,"path":1886,"stem":1887},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","/javascript/network/10-cookies","03.javascript/02.network/10-cookies",{"title":1889,"path":1890,"stem":1891},"js-cookie: Керування Cookies без Болю","/javascript/network/11-js-cookie","03.javascript/02.network/11-js-cookie",{"title":1893,"path":1894,"stem":1895},"Axios: Потужний HTTP-клієнт для JavaScript","/javascript/network/12-axios","03.javascript/02.network/12-axios",{"title":1897,"icon":1898,"path":1899,"stem":1900,"children":1901,"page":59},"Bom","i-lucide-monitor","/javascript/bom","03.javascript/03.bom",[1902,1906,1910,1914],{"title":1903,"path":1904,"stem":1905},"LocalStorage, SessionStorage та patterns збереження даних","/javascript/bom/01-localstorage","03.javascript/03.bom/01-localstorage",{"title":1907,"path":1908,"stem":1909},"Location Object - Керування адресою сторінки","/javascript/bom/02-location-object","03.javascript/03.bom/02-location-object",{"title":1911,"path":1912,"stem":1913},"History API - Керування історією браузера","/javascript/bom/03-history-api","03.javascript/03.bom/03-history-api",{"title":1915,"path":1916,"stem":1917},"Navigator Object - Ідентифікація та Можливості Пристрою","/javascript/bom/04-navigator-object","03.javascript/03.bom/04-navigator-object",{"title":1919,"icon":1920,"path":1921,"stem":1922,"children":1923},"React","i-devicon-react","/javascript/react","03.javascript/04.react/index",[1924,1925,1929,1933,1937,1941,2004,2039,2191],{"title":1919,"path":1921,"stem":1922},{"title":1926,"path":1927,"stem":1928},"Робота з Формами в React","/javascript/react/react-forms","03.javascript/04.react/01.react-forms",{"title":1930,"path":1931,"stem":1932},"React Hook Form: Професійна Робота з Формами","/javascript/react/react-hook-form","03.javascript/04.react/02.react-hook-form",{"title":1934,"path":1935,"stem":1936},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","/javascript/react/react-hook-form-new","03.javascript/04.react/02.react-hook-form-new",{"title":1938,"path":1939,"stem":1940},"Axios та React: Професійна Архітектура Запитів","/javascript/react/data-fetching-axios","03.javascript/04.react/03.data-fetching-axios",{"title":1942,"icon":132,"path":1943,"stem":1944,"children":1945},"Tanstack Query","/javascript/react/tanstack-query","03.javascript/04.react/04.tanstack-query/index",[1946,1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000],{"title":1947,"path":1943,"stem":1944},"TanStack Query: Майстерність Керування Станом Сервера",{"title":1949,"path":1950,"stem":1951},"Парадигма Server State: Чому useEffect недостатньо","/javascript/react/tanstack-query/server-state-paradigm","03.javascript/04.react/04.tanstack-query/01.server-state-paradigm",{"title":1953,"path":1954,"stem":1955},"Встановлення та Налаштування: Фундамент","/javascript/react/tanstack-query/installation-and-devtools","03.javascript/04.react/04.tanstack-query/02.installation-and-devtools",{"title":1957,"path":1958,"stem":1959},"Основи Запитів та Магія Ключів","/javascript/react/tanstack-query/query-basics-and-keys","03.javascript/04.react/04.tanstack-query/03.query-basics-and-keys",{"title":1961,"path":1962,"stem":1963},"Синхронізація Даних: Життєвий Цикл Запиту","/javascript/react/tanstack-query/data-synchronization","03.javascript/04.react/04.tanstack-query/04.data-synchronization",{"title":1965,"path":1966,"stem":1967},"Мутації та Інвалідація: Зміна Даних","/javascript/react/tanstack-query/mutations-and-invalidation","03.javascript/04.react/04.tanstack-query/05.mutations-and-invalidation",{"title":1969,"path":1970,"stem":1971},"Оптимістичні Оновлення: Швидше за Світло","/javascript/react/tanstack-query/optimistic-updates","03.javascript/04.react/04.tanstack-query/06.optimistic-updates",{"title":1973,"path":1974,"stem":1975},"Пагінація та Infinite Scroll","/javascript/react/tanstack-query/pagination-and-load-more","03.javascript/04.react/04.tanstack-query/07.pagination-and-load-more",{"title":1977,"path":1978,"stem":1979},"Просунуті Патерни та Оптимізація","/javascript/react/tanstack-query/advanced-patterns","03.javascript/04.react/04.tanstack-query/08.advanced-patterns",{"title":1981,"path":1982,"stem":1983},"Архітектура та Best Practices","/javascript/react/tanstack-query/architecture-and-best-practices","03.javascript/04.react/04.tanstack-query/09.architecture-and-best-practices",{"title":1985,"path":1986,"stem":1987},"Server-Side Rendering (SSR) та Гідратація","/javascript/react/tanstack-query/server-side-rendering","03.javascript/04.react/04.tanstack-query/10.server-side-rendering",{"title":1989,"path":1990,"stem":1991},"Стратегії Тестування","/javascript/react/tanstack-query/testing-strategies","03.javascript/04.react/04.tanstack-query/11.testing-strategies",{"title":1993,"path":1994,"stem":1995},"Аутентифікація та Обробка Помилок","/javascript/react/tanstack-query/authentication-and-errors","03.javascript/04.react/04.tanstack-query/12.authentication-and-errors",{"title":1997,"path":1998,"stem":1999},"React Suspense та Майбутнє","/javascript/react/tanstack-query/react-suspense","03.javascript/04.react/04.tanstack-query/13.react-suspense",{"title":2001,"path":2002,"stem":2003},"Глибоке Занурення в Продуктивність","/javascript/react/tanstack-query/performance-deep-dive","03.javascript/04.react/04.tanstack-query/14.performance-deep-dive",{"title":2005,"icon":1920,"path":2006,"stem":2007,"children":2008},"React Router","/javascript/react/react-router","03.javascript/04.react/05.react-router/index",[2009,2011,2015,2019,2023,2027,2031,2035],{"title":2010,"path":2006,"stem":2007},"React Router: Навігаційна система сучасного вебу",{"title":2012,"path":2013,"stem":2014},"Налаштування та Базовий Роутинг","/javascript/react/react-router/setup-and-basic-routing","03.javascript/04.react/05.react-router/01.setup-and-basic-routing",{"title":2016,"path":2017,"stem":2018},"Динамічна Навігація","/javascript/react/react-router/navigation-and-links","03.javascript/04.react/05.react-router/02.navigation-and-links",{"title":2020,"path":2021,"stem":2022},"Вкладені Маршрути та Макети","/javascript/react/react-router/nested-routes-and-layouts","03.javascript/04.react/05.react-router/03.nested-routes-and-layouts",{"title":2024,"path":2025,"stem":2026},"Динамічні Маршрути та Параметри","/javascript/react/react-router/dynamic-routing","03.javascript/04.react/05.react-router/04.dynamic-routing",{"title":2028,"path":2029,"stem":2030},"Data APIs: Loaders та Actions","/javascript/react/react-router/data-loading","03.javascript/04.react/05.react-router/05.data-loading",{"title":2032,"path":2033,"stem":2034},"Просунуті Патерни","/javascript/react/react-router/advanced-patterns","03.javascript/04.react/05.react-router/06.advanced-patterns",{"title":2036,"path":2037,"stem":2038},"Legacy Routing: Компонентний підхід","/javascript/react/react-router/legacy-routing","03.javascript/04.react/05.react-router/07.legacy-routing",{"title":2040,"icon":132,"path":2041,"stem":2042,"children":2043},"Redux","/javascript/react/redux","03.javascript/04.react/06.redux/index",[2044,2046,2062,2091,2100,2121,2137,2166],{"title":2045,"path":2041,"stem":2042},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2047,"stem":2048,"children":2049,"page":59},"/javascript/react/redux/fundamentals","03.javascript/04.react/06.redux/01.fundamentals",[2050,2054,2058],{"title":2051,"path":2052,"stem":2053},"Вступ до State Management","/javascript/react/redux/fundamentals/intro-state-management","03.javascript/04.react/06.redux/01.fundamentals/01.intro-state-management",{"title":2055,"path":2056,"stem":2057},"Філософія Redux та Три Принципи","/javascript/react/redux/fundamentals/redux-philosophy","03.javascript/04.react/06.redux/01.fundamentals/02.redux-philosophy",{"title":2059,"path":2060,"stem":2061},"Чисті функції та Іммутабельність","/javascript/react/redux/fundamentals/pure-functions-immutability","03.javascript/04.react/06.redux/01.fundamentals/03.pure-functions-immutability",{"title":2063,"icon":132,"path":2064,"stem":2065,"children":2066,"page":59},"Classic Redux","/javascript/react/redux/classic-redux","03.javascript/04.react/06.redux/02.classic-redux",[2067,2071,2075,2079,2083,2087],{"title":2068,"path":2069,"stem":2070},"Створення Store (Classic Redux)","/javascript/react/redux/classic-redux/store-setup","03.javascript/04.react/06.redux/02.classic-redux/01.store-setup",{"title":2072,"path":2073,"stem":2074},"Actions, Constants та Action Creators","/javascript/react/redux/classic-redux/actions-constants","03.javascript/04.react/06.redux/02.classic-redux/02.actions-constants",{"title":2076,"path":2077,"stem":2078},"Логіка Reducers","/javascript/react/redux/classic-redux/reducers","03.javascript/04.react/06.redux/02.classic-redux/03.reducers",{"title":2080,"path":2081,"stem":2082},"Комбінування Reducers (Root Reducer)","/javascript/react/redux/classic-redux/data-flow","03.javascript/04.react/06.redux/02.classic-redux/04.data-flow",{"title":2084,"path":2085,"stem":2086},"Підключення до React (React-Redux)","/javascript/react/redux/classic-redux/react-redux-connection","03.javascript/04.react/06.redux/02.classic-redux/05.react-redux-connection",{"title":2088,"path":2089,"stem":2090},"Middleware та Асинхронність (Redux Thunk)","/javascript/react/redux/classic-redux/middleware-thunk","03.javascript/04.react/06.redux/02.classic-redux/06.middleware-thunk",{"title":2092,"icon":132,"path":2093,"stem":2094,"children":2095,"page":59},"Transition To Rtk","/javascript/react/redux/transition-to-rtk","03.javascript/04.react/06.redux/03.transition-to-rtk",[2096],{"title":2097,"path":2098,"stem":2099},"Проблеми класичного Redux","/javascript/react/redux/transition-to-rtk/problems-with-classic","03.javascript/04.react/06.redux/03.transition-to-rtk/01.problems-with-classic",{"title":2101,"icon":132,"path":2102,"stem":2103,"children":2104,"page":59},"Redux Toolkit","/javascript/react/redux/redux-toolkit","03.javascript/04.react/06.redux/04.redux-toolkit",[2105,2109,2113,2117],{"title":2106,"path":2107,"stem":2108},"Налаштування Store з configureStore","/javascript/react/redux/redux-toolkit/configure-store","03.javascript/04.react/06.redux/04.redux-toolkit/01.configure-store",{"title":2110,"path":2111,"stem":2112},"createSlice: Революція в Redux","/javascript/react/redux/redux-toolkit/create-slice","03.javascript/04.react/06.redux/04.redux-toolkit/02.create-slice",{"title":2114,"path":2115,"stem":2116},"Асинхронність з createAsyncThunk","/javascript/react/redux/redux-toolkit/async-thunks","03.javascript/04.react/06.redux/04.redux-toolkit/03.async-thunks",{"title":2118,"path":2119,"stem":2120},"04. Entity Adapter: Керування нормалізованим станом","/javascript/react/redux/redux-toolkit/entity-adapter","03.javascript/04.react/06.redux/04.redux-toolkit/04.entity-adapter",{"title":2122,"icon":92,"path":2123,"stem":2124,"children":2125,"page":59},"Advanced","/javascript/react/redux/advanced","03.javascript/04.react/06.redux/05.advanced",[2126,2130,2134],{"title":2127,"path":2128,"stem":2129},"Мемоізація та Селектори: Повний Гайд по Reselect","/javascript/react/redux/advanced/selectors-reselect","03.javascript/04.react/06.redux/05.advanced/01.selectors-reselect",{"title":2131,"path":2132,"stem":2133},"RTK Query: Архітектура Серверного Кешу","/javascript/react/redux/advanced/rtk-query-intro","03.javascript/04.react/06.redux/05.advanced/02.rtk-query-intro",{"title":1981,"path":2135,"stem":2136},"/javascript/react/redux/advanced/architecture-best-practices","03.javascript/04.react/06.redux/05.advanced/03.architecture-best-practices",{"title":2138,"icon":132,"path":2139,"stem":2140,"children":2141,"page":59},"Project Kanban","/javascript/react/redux/project-kanban","03.javascript/04.react/06.redux/06.project-kanban",[2142,2146,2150,2154,2158,2162],{"title":2143,"path":2144,"stem":2145},"Проєкт: Kanban Board (Trello Clone)","/javascript/react/redux/project-kanban/project-overview","03.javascript/04.react/06.redux/06.project-kanban/01.project-overview",{"title":2147,"path":2148,"stem":2149},"Налаштування та Типізація","/javascript/react/redux/project-kanban/setup-and-types","03.javascript/04.react/06.redux/06.project-kanban/02.setup-and-types",{"title":2151,"path":2152,"stem":2153},"Board Slice: Серце Дошки","/javascript/react/redux/project-kanban/board-slice","03.javascript/04.react/06.redux/06.project-kanban/03.board-slice",{"title":2155,"path":2156,"stem":2157},"Логіка Drag & Drop","/javascript/react/redux/project-kanban/drag-and-drop-logic","03.javascript/04.react/06.redux/06.project-kanban/04.drag-and-drop-logic",{"title":2159,"path":2160,"stem":2161},"Інтеграція з RTK Query","/javascript/react/redux/project-kanban/rtk-query-integration","03.javascript/04.react/06.redux/06.project-kanban/05.rtk-query-integration",{"title":2163,"path":2164,"stem":2165},"Optimistic Updates","/javascript/react/redux/project-kanban/optimistic-updates","03.javascript/04.react/06.redux/06.project-kanban/06.optimistic-updates",{"title":2167,"icon":132,"path":2168,"stem":2169,"children":2170,"page":59},"Testing","/javascript/react/redux/testing","03.javascript/04.react/06.redux/07.testing",[2171,2175,2179,2183,2187],{"title":2172,"path":2173,"stem":2174},"Тестування Redux","/javascript/react/redux/testing/intro-testing","03.javascript/04.react/06.redux/07.testing/01.intro-testing",{"title":2176,"path":2177,"stem":2178},"Тестування Reducers","/javascript/react/redux/testing/testing-reducers","03.javascript/04.react/06.redux/07.testing/02.testing-reducers",{"title":2180,"path":2181,"stem":2182},"Тестування Селекторів","/javascript/react/redux/testing/testing-selectors","03.javascript/04.react/06.redux/07.testing/03.testing-selectors",{"title":2184,"path":2185,"stem":2186},"Тестування Компонентів (Integration)","/javascript/react/redux/testing/testing-components","03.javascript/04.react/06.redux/07.testing/04.testing-components",{"title":2188,"path":2189,"stem":2190},"Тестування Async Thunks","/javascript/react/redux/testing/testing-thunks","03.javascript/04.react/06.redux/07.testing/05.testing-thunks",{"title":2192,"icon":132,"path":2193,"stem":2194,"children":2195},"Ui Libraries","/javascript/react/ui-libraries","03.javascript/04.react/07.ui-libraries/index",[2196,2198,2202,2206,2210,2214,2218],{"title":2197,"path":2193,"stem":2194},"UI Бібліотеки в React",{"title":2199,"path":2200,"stem":2201},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","/javascript/react/ui-libraries/introduction-to-ui-libraries","03.javascript/04.react/07.ui-libraries/01.introduction-to-ui-libraries",{"title":2203,"path":2204,"stem":2205},"Філософія shadcn/ui: \"Not a Component Library\"","/javascript/react/ui-libraries/shadcn-philosophy","03.javascript/04.react/07.ui-libraries/02.shadcn-philosophy",{"title":2207,"path":2208,"stem":2209},"Установка та Налаштування shadcn/ui","/javascript/react/ui-libraries/shadcn-installation","03.javascript/04.react/07.ui-libraries/03.shadcn-installation",{"title":2211,"path":2212,"stem":2213},"Базові Компоненти shadcn/ui: Фундамент Інтерфейсу","/javascript/react/ui-libraries/shadcn-components-basics","03.javascript/04.react/07.ui-libraries/04.shadcn-components-basics",{"title":2215,"path":2216,"stem":2217},"Компоненти Форм: Побудова Інтерактивних Form","/javascript/react/ui-libraries/shadcn-components-forms","03.javascript/04.react/07.ui-libraries/05.shadcn-components-forms",{"title":2219,"path":2220,"stem":2221},"Складні Компоненти: Dialog, Dropdown, Table та Command","/javascript/react/ui-libraries/shadcn-components-advanced","03.javascript/04.react/07.ui-libraries/06.shadcn-components-advanced",{"title":2223,"icon":2224,"path":2225,"stem":2226,"children":2227,"page":59},"TypeScript","i-devicon-typescript","/javascript/typescript","03.javascript/05.typescript",[2228,2232,2236,2240,2244,2248,2252,2256],{"title":2229,"path":2230,"stem":2231},"TypeScript: Броня для вашого коду","/javascript/typescript/intro-and-basic-types","03.javascript/05.typescript/01.intro-and-basic-types",{"title":2233,"path":2234,"stem":2235},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","/javascript/typescript/interfaces-and-advanced-types","03.javascript/05.typescript/02.interfaces-and-advanced-types",{"title":2237,"path":2238,"stem":2239},"Алхімія Типів: Generics та Utility Types","/javascript/typescript/generics-and-utilities","03.javascript/05.typescript/03.generics-and-utilities",{"title":2241,"path":2242,"stem":2243},"Архітектура та Шаблони: Класи в TypeScript","/javascript/typescript/classes-and-oop","03.javascript/05.typescript/04.classes-and-oop",{"title":2245,"path":2246,"stem":2247},"Продакшн та Екосистема: Advanced Config & Workflow","/javascript/typescript/advanced-patterns-and-config","03.javascript/05.typescript/05.advanced-patterns-and-config",{"title":2249,"path":2250,"stem":2251},"TypeScript у світі React","/javascript/typescript/react-basics","03.javascript/05.typescript/06.react-basics",{"title":2253,"path":2254,"stem":2255},"React + TypeScript: Продвинуті патерни","/javascript/typescript/react-advanced","03.javascript/05.typescript/07.react-advanced",{"title":2257,"path":2258,"stem":2259},"React + TypeScript: Екосистема та бібліотеки","/javascript/typescript/react-ecosystem","03.javascript/05.typescript/08.react-ecosystem",{"title":2261,"path":2262,"stem":2263},"Atomic Design","/javascript/atomic-design","03.javascript/2.atomic-design",{"title":2265,"icon":2266,"path":2267,"stem":2268,"children":2269,"page":59},"Java","i-devicon-java","/java","04.java",[2270,2273,2276,2280,2284,2288,2292],{"title":162,"path":2271,"stem":2272},"/java/data-mapper-part1","04.java/01.data-mapper-part1",{"title":166,"path":2274,"stem":2275},"/java/data-mapper-part2","04.java/02.data-mapper-part2",{"title":2277,"path":2278,"stem":2279},"Service Layer: Організація бізнес-логіки","/java/service-layer","04.java/03.service-layer",{"title":2281,"path":2282,"stem":2283},"Rich Domain Model та State Pattern","/java/rich-domain-model","04.java/04.rich-domain-model",{"title":2285,"path":2286,"stem":2287},"Патерни для складної бізнес-логіки","/java/business-logic-patterns","04.java/05.business-logic-patterns",{"title":2289,"path":2290,"stem":2291},"Обробка помилок та валідація","/java/error-handling-validation","04.java/06.error-handling-validation",{"title":2293,"path":2294,"stem":2295,"children":2296,"page":59},"Проектування баз даних","/java/pr2","04.java/pr2",[2297,2301,2305,2309,2313,2317,2321,2325,2329,2333,2337,2341,2345,2349,2353,2357,2361,2365,2369,2373,2377,2381,2385,2389,2393,2397,2401,2405,2409,2413,2417,2421,2425,2429,2433,2437,2441],{"title":2298,"path":2299,"stem":2300},"Концептуальне моделювання: Мистецтво розуміння предметної області","/java/pr2/conceptual-modeling","04.java/pr2/01.conceptual-modeling",{"title":2302,"path":2303,"stem":2304},"Логічне моделювання: Від бізнес-ідей до структур даних","/java/pr2/logical-modeling","04.java/pr2/02.logical-modeling",{"title":2306,"path":2307,"stem":2308},"Нормалізація: Гігієна даних та боротьба з аномаліями","/java/pr2/normalization","04.java/pr2/03.normalization",{"title":2310,"path":2311,"stem":2312},"Фізична схема: Від абстракції до DDL","/java/pr2/physical-schema","04.java/pr2/04.physical-schema",{"title":2314,"path":2315,"stem":2316},"Архітектурна класифікація таблиць","/java/pr2/table-classification","04.java/pr2/05.table-classification",{"title":2318,"path":2319,"stem":2320},"Database Migrations: Версіонування схеми з Flyway","/java/pr2/database-migrations","04.java/pr2/06.database-migrations",{"title":2322,"path":2323,"stem":2324},"А що, якби це була не реляційна БД?","/java/pr2/beyond-relational","04.java/pr2/07.beyond-relational",{"title":2326,"path":2327,"stem":2328},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","/java/pr2/impedance-mismatch","04.java/pr2/09.impedance-mismatch",{"title":2330,"path":2331,"stem":2332},"JDBC: Перший контакт із базою даних","/java/pr2/jdbc-fundamentals","04.java/pr2/10.jdbc-fundamentals",{"title":2334,"path":2335,"stem":2336},"Якість коду: Spotless, SpotBugs та SonarQube","/java/pr2/10a.code-quality","04.java/pr2/10a.code-quality",{"title":2338,"path":2339,"stem":2340},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","/java/pr2/connection-pool","04.java/pr2/11.connection-pool",{"title":2342,"path":2343,"stem":2344},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","/java/pr2/row-data-gateway","04.java/pr2/12.row-data-gateway",{"title":2346,"path":2347,"stem":2348},"Table Data Gateway: Фасад таблиці як архітектурний відступ","/java/pr2/table-data-gateway","04.java/pr2/13.table-data-gateway",{"title":2350,"path":2351,"stem":2352},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","/java/pr2/repository-data-mapper","04.java/pr2/14.repository-data-mapper",{"title":2354,"path":2355,"stem":2356},"Identity Map: Кешування сутностей у рамках сесії","/java/pr2/identity-map","04.java/pr2/15.identity-map",{"title":2358,"path":2359,"stem":2360},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","/java/pr2/unit-of-work","04.java/pr2/16.unit-of-work",{"title":2362,"path":2363,"stem":2364},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","/java/pr2/strategy-sql","04.java/pr2/17.strategy-sql",{"title":2366,"path":2367,"stem":2368},"Proxy: Lazy Loading для One-To-Many колекцій","/java/pr2/proxy-lazy-loading","04.java/pr2/18.proxy-lazy-loading",{"title":2370,"path":2371,"stem":2372},"Generic Repository через Java Reflection: анотації та динамічний SQL","/java/pr2/generic-repository-reflection","04.java/pr2/19.generic-repository-reflection",{"title":2374,"path":2375,"stem":2376},"Specification Pattern: Композиція бізнес-правил для складних запитів","/java/pr2/specification-pattern","04.java/pr2/20.specification-pattern",{"title":2378,"path":2379,"stem":2380},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","/java/pr2/20a.advanced-specifications","04.java/pr2/20a.advanced-specifications",{"title":2382,"path":2383,"stem":2384},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","/java/pr2/asynchronous-jdbc","04.java/pr2/21.asynchronous-jdbc",{"title":2386,"path":2387,"stem":2388},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","/java/pr2/integration-testing-h2","04.java/pr2/22.integration-testing-h2",{"title":2390,"path":2391,"stem":2392},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","/java/pr2/integration-testing-testcontainers","04.java/pr2/23.integration-testing-testcontainers",{"title":2394,"path":2395,"stem":2396},"Google Guice: Впровадження залежностей у JavaFX-проєкті","/java/pr2/dependency-injection-guice","04.java/pr2/24.dependency-injection-guice",{"title":2398,"path":2399,"stem":2400},"JavaFX: Основи побудови графічних інтерфейсів","/java/pr2/javafx-fundamentals","04.java/pr2/25.javafx-fundamentals",{"title":2402,"path":2403,"stem":2404},"Properties та Bindings: Реактивність у JavaFX","/java/pr2/javafx-properties-bindings","04.java/pr2/26.javafx-properties-bindings",{"title":2406,"path":2407,"stem":2408},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","/java/pr2/ui-architecture-patterns","04.java/pr2/27.ui-architecture-patterns",{"title":2410,"path":2411,"stem":2412},"MVVM на практиці: Побудова ViewModel","/java/pr2/mvvm-viewmodel-implementation","04.java/pr2/28.mvvm-viewmodel-implementation",{"title":2414,"path":2415,"stem":2416},"View та Controller: Зв'язування з ViewModel через FXML","/java/pr2/mvvm-view-controller","04.java/pr2/29.mvvm-view-controller",{"title":2418,"path":2419,"stem":2420},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","/java/pr2/mvvm-guice-integration","04.java/pr2/30.mvvm-guice-integration",{"title":2422,"path":2423,"stem":2424},"Валідація та обробка помилок у MVVM","/java/pr2/mvvm-validation-error-handling","04.java/pr2/31.mvvm-validation-error-handling",{"title":2426,"path":2427,"stem":2428},"Навігація та управління екранами у JavaFX MVVM","/java/pr2/mvvm-navigation-screen-management","04.java/pr2/32.mvvm-navigation-screen-management",{"title":2430,"path":2431,"stem":2432},"Тестування JavaFX MVVM-додатків","/java/pr2/mvvm-testing","04.java/pr2/33.mvvm-testing",{"title":2434,"path":2435,"stem":2436},"Стилізація та теми у JavaFX: CSS та User Experience","/java/pr2/javafx-styling-themes","04.java/pr2/34.javafx-styling-themes",{"title":2438,"path":2439,"stem":2440},"AtlantaFX: Сучасні теми для JavaFX додатків","/java/pr2/atlantafx-modern-themes","04.java/pr2/35.atlantafx-modern-themes",{"title":2442,"path":2443,"stem":2444},"Пакування та розповсюдження JavaFX-додатків","/java/pr2/jar-packaging-distribution","04.java/pr2/36.jar-packaging-distribution",{"title":2446,"icon":2447,"path":2448,"stem":2449,"children":2450,"page":59},"Бази даних","i-lucide-database","/databases","06.databases",[2451,2481,2504,2541,2570,2588,2622,2634,2643],{"title":2452,"icon":2453,"path":2454,"stem":2455,"children":2456,"page":59},"Intro","i-lucide-play","/databases/intro","06.databases/01.intro",[2457,2461,2465,2469,2473,2477],{"title":2458,"path":2459,"stem":2460},"Введення в теорію баз даних","/databases/intro/introduction-to-databases","06.databases/01.intro/01.introduction-to-databases",{"title":2462,"path":2463,"stem":2464},"Реляційна модель даних","/databases/intro/relational-model-theory","06.databases/01.intro/02.relational-model-theory",{"title":2466,"path":2467,"stem":2468},"ER-моделювання","/databases/intro/er-modeling","06.databases/01.intro/03.er-modeling",{"title":2470,"path":2471,"stem":2472},"Логічне проектування БД","/databases/intro/logical-schema","06.databases/01.intro/04.logical-schema",{"title":2474,"path":2475,"stem":2476},"Класифікація таблиць","/databases/intro/table-classification","06.databases/01.intro/05.table-classification",{"title":2478,"path":2479,"stem":2480},"PlantUML для баз даних","/databases/intro/plantuml-diagrams","06.databases/01.intro/06.plantuml-diagrams",{"title":2482,"icon":2447,"path":2483,"stem":2484,"children":2485,"page":59},"MS SQL Server Start","/databases/ms-sql-server-start","06.databases/02.ms-sql-server-start",[2486,2490,2496,2500],{"title":2487,"path":2488,"stem":2489},"Типи даних у MS SQL Server","/databases/ms-sql-server-start/data-types","06.databases/02.ms-sql-server-start/01.data-types",{"title":2491,"path":2492,"stem":2493,"children":2494},"Індекси у MS SQL Server","/databases/ms-sql-server-start/sql-indexes","06.databases/02.ms-sql-server-start/02.sql-indexes",[2495],{"title":2491,"path":2492,"stem":2493},{"title":2497,"path":2498,"stem":2499},"Системні бази даних MS SQL Server","/databases/ms-sql-server-start/system-databases","06.databases/02.ms-sql-server-start/03.system-databases",{"title":2501,"path":2502,"stem":2503},"Огляд мови SQL та запитів","/databases/ms-sql-server-start/sql-queries-overview","06.databases/02.ms-sql-server-start/04.sql-queries-overview",{"title":2505,"icon":2447,"path":2506,"stem":2507,"children":2508,"page":59},"SQL","/databases/sql","06.databases/03.sql",[2509,2513,2517,2521,2525,2529,2533,2537],{"title":2510,"path":2511,"stem":2512},"Налаштування демонстраційної бази даних","/databases/sql/sample-database-setup","06.databases/03.sql/00.sample-database-setup",{"title":2514,"path":2515,"stem":2516},"DDL - Створення таблиць (CREATE TABLE)","/databases/sql/ddl-create-table","06.databases/03.sql/01.ddl-create-table",{"title":2518,"path":2519,"stem":2520},"DDL - Зміна та видалення таблиць (ALTER, DROP)","/databases/sql/ddl-alter-drop-table","06.databases/03.sql/02.ddl-alter-drop-table",{"title":2522,"path":2523,"stem":2524},"SELECT запити - Основи","/databases/sql/select-queries-fundamentals","06.databases/03.sql/03.select-queries-fundamentals",{"title":2526,"path":2527,"stem":2528},"SELECT запити - Розширені можливості","/databases/sql/select-queries-advanced","06.databases/03.sql/04.select-queries-advanced",{"title":2530,"path":2531,"stem":2532},"INSERT запити - Додавання даних","/databases/sql/insert-queries","06.databases/03.sql/05.insert-queries",{"title":2534,"path":2535,"stem":2536},"UPDATE та DELETE запити","/databases/sql/update-delete-queries","06.databases/03.sql/06.update-delete-queries",{"title":2538,"path":2539,"stem":2540},"Транзакції в SQL","/databases/sql/transactions","06.databases/03.sql/07.transactions",{"title":2542,"icon":2447,"path":2543,"stem":2544,"children":2545,"page":59},"Multi Table Databases","/databases/multi-table-databases","06.databases/04.multi-table-databases",[2546,2550,2554,2558,2562,2566],{"title":2547,"path":2548,"stem":2549},"Зв'язки та нормалізація БД","/databases/multi-table-databases/relationships-and-normalization","06.databases/04.multi-table-databases/00.relationships-and-normalization",{"title":2551,"path":2552,"stem":2553},"INNER JOIN - З'єднання таблиць","/databases/multi-table-databases/inner-join","06.databases/04.multi-table-databases/01.inner-join",{"title":2555,"path":2556,"stem":2557},"OUTER JOINs - LEFT, RIGHT, FULL","/databases/multi-table-databases/outer-joins","06.databases/04.multi-table-databases/02.outer-joins",{"title":2559,"path":2560,"stem":2561},"CROSS та SELF JOINs","/databases/multi-table-databases/cross-self-joins","06.databases/04.multi-table-databases/03.cross-self-joins",{"title":2563,"path":2564,"stem":2565},"Підзапити (Subqueries)","/databases/multi-table-databases/subqueries","06.databases/04.multi-table-databases/04.subqueries",{"title":2567,"path":2568,"stem":2569},"Агрегації з JOIN","/databases/multi-table-databases/aggregations-with-joins","06.databases/04.multi-table-databases/05.aggregations-with-joins",{"title":2571,"icon":2572,"path":2573,"stem":2574,"children":2575,"page":59},"Aggregate Functions","i-lucide-calculator","/databases/aggregate-functions","06.databases/05.aggregate-functions",[2576,2580,2584],{"title":2577,"path":2578,"stem":2579},"Функції агрегування в MS SQL Server","/databases/aggregate-functions/introduction-aggregate-functions","06.databases/05.aggregate-functions/01.introduction-aggregate-functions",{"title":2581,"path":2582,"stem":2583},"Групування даних в MS SQL Server","/databases/aggregate-functions/grouping-data","06.databases/05.aggregate-functions/02.grouping-data",{"title":2585,"path":2586,"stem":2587},"Підзапити з агрегатними функціями","/databases/aggregate-functions/subqueries-aggregates","06.databases/05.aggregate-functions/03.subqueries-aggregates",{"title":2589,"icon":2590,"path":2591,"stem":2592,"children":2593,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","/databases/triggers-stored-procedures","06.databases/07.triggers-stored-procedures",[2594,2598,2602,2606,2610,2614,2618],{"title":2595,"path":2596,"stem":2597},"DML-тригери","/databases/triggers-stored-procedures/dml-triggers","06.databases/07.triggers-stored-procedures/01.dml-triggers",{"title":2599,"path":2600,"stem":2601},"DDL-тригери","/databases/triggers-stored-procedures/ddl-triggers","06.databases/07.triggers-stored-procedures/02.ddl-triggers",{"title":2603,"path":2604,"stem":2605},"Transact-SQL розширення","/databases/triggers-stored-procedures/transact-sql-extensions","06.databases/07.triggers-stored-procedures/03.transact-sql-extensions",{"title":2607,"path":2608,"stem":2609},"Транзакції","/databases/triggers-stored-procedures/transactions","06.databases/07.triggers-stored-procedures/04.transactions",{"title":2611,"path":2612,"stem":2613},"Зберігаємі процедури","/databases/triggers-stored-procedures/stored-procedures","06.databases/07.triggers-stored-procedures/05.stored-procedures",{"title":2615,"path":2616,"stem":2617},"Користувацькі функції","/databases/triggers-stored-procedures/user-defined-functions","06.databases/07.triggers-stored-procedures/06.user-defined-functions",{"title":2619,"path":2620,"stem":2621},"Безпека баз даних","/databases/triggers-stored-procedures/security","06.databases/07.triggers-stored-procedures/08.security",{"title":2619,"icon":793,"path":2623,"stem":2624,"children":2625,"page":59},"/databases/security","06.databases/08.security",[2626,2630],{"title":2627,"path":2628,"stem":2629},"Вступ до безпеки баз даних","/databases/security/introduction","06.databases/08.security/01.introduction",{"title":2631,"path":2632,"stem":2633},"Системні представлення та метадані","/databases/security/system-views","06.databases/08.security/02.system-views",{"title":2635,"icon":2636,"path":2637,"stem":2638,"children":2639,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","/databases/backup-recovery","06.databases/09.backup-recovery",[2640],{"title":2635,"path":2641,"stem":2642},"/databases/backup-recovery/backup-restore","06.databases/09.backup-recovery/01.backup-restore",{"title":2644,"icon":2645,"path":2646,"stem":2647,"children":2648,"page":59},"Повнотекстовий пошук","i-lucide-search","/databases/full-text-search","06.databases/10.full-text-search",[2649],{"title":2644,"path":2650,"stem":2651},"/databases/full-text-search/full-text-search","06.databases/10.full-text-search/01.full-text-search",{"title":2653,"icon":2654,"path":2655,"stem":2656,"children":2657,"page":59},"Tools","i-lucide-wrench","/tools","07.tools",[2658,2734],{"title":2659,"icon":2660,"path":2661,"stem":2662,"children":2663},"Docker","i-simple-icons-docker","/tools/docker","07.tools/01.docker/index",[2664,2666,2670,2674,2678,2682,2686,2690,2694,2698,2702,2706,2710,2714,2718,2722,2726,2730],{"title":2665,"path":2661,"stem":2662},"Docker: від нуля до production",{"title":2667,"path":2668,"stem":2669},"Контейнеризація — від проблеми до рішення","/tools/docker/containerization-concept","07.tools/01.docker/01.containerization-concept",{"title":2671,"path":2672,"stem":2673},"Docker — що це і навіщо?","/tools/docker/docker-what-and-why","07.tools/01.docker/02.docker-what-and-why",{"title":2675,"path":2676,"stem":2677},"Архітектура Docker Engine","/tools/docker/docker-architecture","07.tools/01.docker/03.docker-architecture",{"title":2679,"path":2680,"stem":2681},"Встановлення Docker","/tools/docker/installation","07.tools/01.docker/04.installation",{"title":2683,"path":2684,"stem":2685},"Перший контейнер — docker run","/tools/docker/first-container","07.tools/01.docker/05.first-container",{"title":2687,"path":2688,"stem":2689},"Життєвий цикл контейнера","/tools/docker/container-lifecycle","07.tools/01.docker/06.container-lifecycle",{"title":2691,"path":2692,"stem":2693},"Docker Images — фундаментальні концепції","/tools/docker/docker-images-fundamentals","07.tools/01.docker/07.docker-images-fundamentals",{"title":2695,"path":2696,"stem":2697},"Dockerfile — основи","/tools/docker/dockerfile-basics","07.tools/01.docker/08.dockerfile-basics",{"title":2699,"path":2700,"stem":2701},"Dockerfile — просунуті техніки","/tools/docker/dockerfile-advanced","07.tools/01.docker/09.dockerfile-advanced",{"title":2703,"path":2704,"stem":2705},"Build Context та кешування шарів","/tools/docker/build-context-and-cache","07.tools/01.docker/10.build-context-and-cache",{"title":2707,"path":2708,"stem":2709},"Реєстри Docker-образів","/tools/docker/image-registries","07.tools/01.docker/11.image-registries",{"title":2711,"path":2712,"stem":2713},"Контейнеризація .NET додатків","/tools/docker/dotnet-containerization","07.tools/01.docker/12.dotnet-containerization",{"title":2715,"path":2716,"stem":2717},"Томи та збереження даних","/tools/docker/volumes-and-data","07.tools/01.docker/13.volumes-and-data",{"title":2719,"path":2720,"stem":2721},"Основи мережі в Docker","/tools/docker/networking-basics","07.tools/01.docker/14.networking-basics",{"title":2723,"path":2724,"stem":2725},"Змінні оточення та конфігурація","/tools/docker/environment-and-configuration","07.tools/01.docker/15.environment-and-configuration",{"title":2727,"path":2728,"stem":2729},"Docker Compose — оркестрація контейнерів","/tools/docker/docker-compose-basics","07.tools/01.docker/16.docker-compose-basics",{"title":2731,"path":2732,"stem":2733},"Docker Compose — Multi-Service застосунки","/tools/docker/compose-multi-service","07.tools/01.docker/17.compose-multi-service",{"title":2735,"icon":2736,"path":2737,"stem":2738,"children":2739},"Kubernetes","simple-icons:kubernetes","/tools/kubernetes","07.tools/02.kubernetes/index",[2740,2742,2746,2750,2754,2758,2762,2766,2770],{"title":2741,"path":2737,"stem":2738},"Kubernetes: від розробки до production",{"title":2743,"path":2744,"stem":2745},"Kubernetes — коли Docker Compose більше не вистачає","/tools/kubernetes/why-kubernetes","07.tools/02.kubernetes/01.why-kubernetes",{"title":2747,"path":2748,"stem":2749},"Архітектура Kubernetes — анатомія кластера","/tools/kubernetes/kubernetes-architecture","07.tools/02.kubernetes/02.kubernetes-architecture",{"title":2751,"path":2752,"stem":2753},"Локальне середовище — minikube, kind та k3s","/tools/kubernetes/local-environment","07.tools/02.kubernetes/03.local-environment",{"title":2755,"path":2756,"stem":2757},"Pod — атомарна одиниця Kubernetes","/tools/kubernetes/pods-and-containers","07.tools/02.kubernetes/04.pods-and-containers",{"title":2759,"path":2760,"stem":2761},"Патерни використання Pod","/tools/kubernetes/pod-patterns","07.tools/02.kubernetes/05.pod-patterns",{"title":2763,"path":2764,"stem":2765},"Deployment — декларативне управління Pod","/tools/kubernetes/deployment-basics","07.tools/02.kubernetes/06.deployment-basics",{"title":2767,"path":2768,"stem":2769},"Rolling Updates та управління життєвим циклом Deployment","/tools/kubernetes/deployment-rolling-updates","07.tools/02.kubernetes/07.deployment-rolling-updates",{"title":2771,"path":2772,"stem":2773},"Service — мережева абстракція для Pod","/tools/kubernetes/services-networking","07.tools/02.kubernetes/08.services-networking",{"title":2775,"icon":2776,"path":2777,"stem":2778,"children":2779,"page":59},"Software Engineering","i-lucide-code-2","/software-engineering","09.software-engineering",[2780,2784,2788,2792,2796,2800,2804,2808,2812,2816,2820],{"title":2781,"path":2782,"stem":2783},"1. Аналіз предметної області. Експертні знання та складність","/software-engineering/intro-subdomains","09.software-engineering/01.intro-subdomains",{"title":2785,"path":2786,"stem":2787},"2. Обмежені контексти. Інтеграція обмежених контекстів","/software-engineering/integrating-limited-contexts","09.software-engineering/02.integrating-limited-contexts",{"title":2789,"path":2790,"stem":2791},"3. Реалізація простої бізнес-логіки","/software-engineering/simple","09.software-engineering/03.simple",{"title":2793,"path":2794,"stem":2795},"4. Опрацювання складної бізнес-логіки","/software-engineering/complex-business-logic","09.software-engineering/04.complex-business-logic",{"title":2797,"path":2798,"stem":2799},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","/software-engineering/modelling-the-time-factor","09.software-engineering/05.modelling-the-time-factor",{"title":2801,"path":2802,"stem":2803},"6. Архітектурні патерни","/software-engineering/architectural-patterns","09.software-engineering/06.architectural-patterns",{"title":2805,"path":2806,"stem":2807},"Паттерни взаємодії","/software-engineering/patterns-of-interaction","09.software-engineering/07.patterns-of-interaction",{"title":2809,"path":2810,"stem":2811},"Евристика проєктування","/software-engineering/design-heuristics","09.software-engineering/08.design-heuristics",{"title":2813,"path":2814,"stem":2815},"Еволюція проєктних рішень","/software-engineering/evolution-of-design-solutions","09.software-engineering/09.evolution-of-design-solutions",{"title":2817,"path":2818,"stem":2819},"EventStorming","/software-engineering/eventstorming","09.software-engineering/10.eventstorming",{"title":2821,"path":2822,"stem":2823},"DDD на практиці","/software-engineering/ddd-in-practice","09.software-engineering/11.ddd-in-practice",{"title":2825,"icon":943,"path":2826,"stem":2827,"children":2828,"page":59},"DDD","/ddd","10.ddd",[2829,2833,2837,2841,2845,2849,2853,2857,2861,2865,2869,2873,2877],{"title":2830,"path":2831,"stem":2832},"Аналіз предметної області","/ddd/domain-analysis","10.ddd/01.domain-analysis",{"title":2834,"path":2835,"stem":2836},"Експертні знання про предметну область","/ddd/domain-expert-knowledge","10.ddd/02.domain-expert-knowledge",{"title":2838,"path":2839,"stem":2840},"Як осмислити складність предметної області","/ddd/managing-domain-complexity","10.ddd/03.managing-domain-complexity",{"title":2842,"path":2843,"stem":2844},"Інтеграція обмежених контекстів","/ddd/bounded-context-integration","10.ddd/04.bounded-context-integration",{"title":2846,"path":2847,"stem":2848},"Реалізація простої бізнес-логіки","/ddd/simple-business-logic","10.ddd/05.simple-business-logic",{"title":2850,"path":2851,"stem":2852},"Обробка складної бізнес-логіки","/ddd/complex-business-logic","10.ddd/06.complex-business-logic",{"title":2854,"path":2855,"stem":2856},"Моделювання фактора часу","/ddd/time-modeling","10.ddd/07.time-modeling",{"title":2858,"path":2859,"stem":2860},"Глава 8. Архітектурні Патерни","/ddd/architectural-patterns","10.ddd/08.architectural-patterns",{"title":2862,"path":2863,"stem":2864},"Глава 9. Патерни Взаємодії","/ddd/interaction-patterns","10.ddd/09.interaction-patterns",{"title":2866,"path":2867,"stem":2868},"Глава 10. Проектні Евристики","/ddd/design-heuristics","10.ddd/10.design-heuristics",{"title":2870,"path":2871,"stem":2872},"Глава 11. Еволюція Проектних Рішень","/ddd/evolution-of-design-decisions","10.ddd/11.evolution-of-design-decisions",{"title":2874,"path":2875,"stem":2876},"Глава 12. EventStorming","/ddd/event-storming","10.ddd/12.event-storming",{"title":2878,"path":2879,"stem":2880},"Глава 13. DDD на Практиці","/ddd/ddd-in-practice","10.ddd/13.ddd-in-practice",{"title":2882,"icon":2883,"path":2884,"stem":2885,"children":2886,"page":59},"Media Streaming","i-lucide-video","/media-streaming","11.media-streaming",[2887,2891,2895,2899,2903,2907,2911],{"title":2888,"path":2889,"stem":2890},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","/media-streaming/introduction","11.media-streaming/01.introduction",{"title":2892,"path":2893,"stem":2894},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","/media-streaming/audio-video-anatomy","11.media-streaming/02.audio-video-anatomy",{"title":2896,"path":2897,"stem":2898},"03. The Gym: FFmpeg Deep Dive","/media-streaming/ffmpeg-gym","11.media-streaming/03.ffmpeg-gym",{"title":2900,"path":2901,"stem":2902},"04. HLS Protocol: HTTP Live Streaming у Деталях","/media-streaming/hls-protocol","11.media-streaming/04.hls-protocol",{"title":2904,"path":2905,"stem":2906},"05. DASH Protocol: Відкритий Стандарт","/media-streaming/dash-protocol","11.media-streaming/05.dash-protocol",{"title":2908,"path":2909,"stem":2910},"06. Масштабування: CDN та Adaptive Bitrate","/media-streaming/cdn-and-adaptive-bitrate","11.media-streaming/06.cdn-and-adaptive-bitrate",{"title":2912,"path":2913,"stem":2914},"07. Війна із Затримкою (Latency)","/media-streaming/realtime-latency","11.media-streaming/07.realtime-latency",{"title":2916,"icon":2917,"path":2918,"stem":2919,"children":2920,"page":59},"HTML & CSS","i-devicon-html5","/html-css","12.html-css",[2921,2925,2929,2933,2937,2941,2945,2949,2953,2957,2961,2965,2969,2973,2977,2981,2985,2989,2993,2997,3001,3005,3009,3013,3017,3021,3025,3029,3033,3037],{"title":2922,"path":2923,"stem":2924},"Вступ до HTML. Структура документа","/html-css/intro-html-structure","12.html-css/01.intro-html-structure",{"title":2926,"path":2927,"stem":2928},"Форматування тексту в HTML","/html-css/html-text-formatting","12.html-css/02.html-text-formatting",{"title":2930,"path":2931,"stem":2932},"Посилання та зображення в HTML","/html-css/html-links-images","12.html-css/03.html-links-images",{"title":2934,"path":2935,"stem":2936},"Списки та таблиці в HTML","/html-css/html-lists-tables","12.html-css/04.html-lists-tables",{"title":2938,"path":2939,"stem":2940},"Форми в HTML","/html-css/html-forms","12.html-css/05.html-forms",{"title":2942,"path":2943,"stem":2944},"Семантичні елементи HTML5","/html-css/html-semantic-elements","12.html-css/06.html-semantic-elements",{"title":2946,"path":2947,"stem":2948},"Мультимедіа та розширені елементи HTML","/html-css/html-multimedia-advanced","12.html-css/07.html-multimedia-advanced",{"title":2950,"path":2951,"stem":2952},"Мікророзмітка та SEO в HTML","/html-css/html-microdata-seo","12.html-css/08.html-microdata-seo",{"title":2954,"path":2955,"stem":2956},"Вступ до CSS. Селектори та специфічність","/html-css/css-intro-selectors","12.html-css/09.css-intro-selectors",{"title":2958,"path":2959,"stem":2960},"Блокова модель CSS. Відступи. Box Sizing","/html-css/css-box-model","12.html-css/10.css-box-model",{"title":2962,"path":2963,"stem":2964},"Розміри у CSS: повний довідник одиниць і ключових слів","/html-css/10a.css-sizing","12.html-css/10a.css-sizing",{"title":2966,"path":2967,"stem":2968},"Типографіка в CSS. Шрифти та текст","/html-css/css-typography","12.html-css/11.css-typography",{"title":2970,"path":2971,"stem":2972},"Кольори та фони в CSS","/html-css/css-colors-backgrounds","12.html-css/12.css-colors-backgrounds",{"title":2974,"path":2975,"stem":2976},"Тіні та фільтри в CSS","/html-css/12b.css-shadows-filters","12.html-css/12b.css-shadows-filters",{"title":2978,"path":2979,"stem":2980},"CSS Flexbox: Фундамент гнучких макетів","/html-css/css-flexbox-fundamentals","12.html-css/13.css-flexbox-fundamentals",{"title":2982,"path":2983,"stem":2984},"CSS Flexbox: Вирівнювання та Позиціонування","/html-css/css-flexbox-alignment-sizing-and-patterns","12.html-css/14.css-flexbox-alignment-sizing-and-patterns",{"title":2986,"path":2987,"stem":2988},"CSS Grid. Двовимірний макет. Частина 1","/html-css/css-layout-grid","12.html-css/15.css-layout-grid",{"title":2990,"path":2991,"stem":2992},"CSS Grid. Двовимірний макет. Частина 2","/html-css/css-layout-grid-advanced","12.html-css/16.css-layout-grid-advanced",{"title":2994,"path":2995,"stem":2996},"Позиціонування в CSS. Z-index. Stacking Context","/html-css/css-positioning","12.html-css/17.css-positioning",{"title":2998,"path":2999,"stem":3000},"CSS Анімації та Переходи","/html-css/css-animations-transitions","12.html-css/18.css-animations-transitions",{"title":3002,"path":3003,"stem":3004},"Адаптивний дизайн. Media Queries. Частина 1","/html-css/css-responsive-media-queries","12.html-css/19.css-responsive-media-queries",{"title":3006,"path":3007,"stem":3008},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","/html-css/css-responsive-advanced","12.html-css/20.css-responsive-advanced",{"title":3010,"path":3011,"stem":3012},"CSS Custom Properties. Методології. Сучасний CSS","/html-css/css-variables-methodologies","12.html-css/21.css-variables-methodologies",{"title":3014,"path":3015,"stem":3016},"Сучасний CSS 2023–2025: Нові можливості","/html-css/css-modern-features","12.html-css/22.css-modern-features",{"title":3018,"path":3019,"stem":3020},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","/html-css/22a.css-nesting-modern-syntax","12.html-css/22a.css-nesting-modern-syntax",{"title":3022,"path":3023,"stem":3024},"CSS для форм та інтерактивних станів","/html-css/css-forms-interactive-states","12.html-css/23.css-forms-interactive-states",{"title":3026,"path":3027,"stem":3028},"Доступність у CSS (CSS Accessibility)","/html-css/css-accessibility","12.html-css/24.css-accessibility",{"title":3030,"path":3031,"stem":3032},"CSS-функції та сучасні sizing primitives","/html-css/css-functions-sizing","12.html-css/25.css-functions-sizing",{"title":3034,"path":3035,"stem":3036},"Rendering Pipeline і CSS Performance","/html-css/css-rendering-performance","12.html-css/26.css-rendering-performance",{"title":3038,"path":3039,"stem":3040},"CSS Best Practices: типові ситуації та правильні рішення","/html-css/css-best-practices","12.html-css/27.css-best-practices",{"title":3042,"path":3043,"stem":3044,"children":3045,"page":59},"AWS","/aws","13.aws",[3046,3050,3054],{"title":3047,"path":3048,"stem":3049},"Реєстрація AWS акаунту та студентські програми","/aws/account-registration","13.aws/00.account-registration",{"title":3051,"path":3052,"stem":3053},"Вступ до хмарних обчислень та AWS","/aws/introduction-to-cloud","13.aws/01.introduction-to-cloud",{"title":3055,"path":3056,"stem":3057},"AWS IAM — Identity and Access Management","/aws/iam","13.aws/02.iam",{"title":3059,"path":3060,"stem":3061,"children":3062,"page":59},"Tailwind","/tailwind","21.tailwind",[3063,3067,3071,3075,3079,3083,3087,3091],{"title":3064,"path":3065,"stem":3066},"Що таке Tailwind CSS і навіщо він потрібен","/tailwind/tailwind-intro-philosophy","21.tailwind/01.tailwind-intro-philosophy",{"title":3068,"path":3069,"stem":3070},"Встановлення та налаштування Tailwind CSS v4","/tailwind/tailwind-installation-setup","21.tailwind/02.tailwind-installation-setup",{"title":3072,"path":3073,"stem":3074},"Utility-класи: основи та система Tailwind","/tailwind/tailwind-utility-classes-core","21.tailwind/03.tailwind-utility-classes-core",{"title":3076,"path":3077,"stem":3078},"Layout: Flexbox та Grid через Tailwind","/tailwind/tailwind-flexbox-grid","21.tailwind/04.tailwind-flexbox-grid",{"title":3080,"path":3081,"stem":3082},"Кастомізація теми через @theme у Tailwind v4","/tailwind/tailwind-theme-customization","21.tailwind/05.tailwind-theme-customization",{"title":3084,"path":3085,"stem":3086},"Варіанти: hover, focus, responsive, dark mode та нові v4","/tailwind/tailwind-variants-states","21.tailwind/06.tailwind-variants-states",{"title":3088,"path":3089,"stem":3090},"Типографіка та система кольорів у Tailwind v4","/tailwind/tailwind-typography-colors","21.tailwind/07.tailwind-typography-colors",{"title":3092,"path":3093,"stem":3094},"Компоненти та повторюваність: @apply, @utility та патерни","/tailwind/tailwind-components-patterns","21.tailwind/08.tailwind-components-patterns",{"title":3096,"path":3097,"stem":3098},"Тестування компонентів діаграм","/test-components","98.test-components",{"id":3100,"title":2771,"body":3101,"description":16532,"extension":16533,"links":16534,"meta":16535,"navigation":3167,"path":2772,"seo":16536,"stem":2773,"__hash__":16537},"docs/07.tools/02.kubernetes/08.services-networking.md",{"type":3102,"value":3103,"toc":16461},"minimark",[3104,3108,3113,3121,3126,3129,3366,3371,3534,3538,3541,3574,3581,3584,3588,3601,3680,3684,3980,3985,4021,4023,4027,4030,4165,4168,4442,4446,4453,4658,4663,4699,4704,4783,4786,4911,4915,4921,5034,5039,5047,5049,5053,5056,5060,5066,5087,5092,5182,5187,5207,5212,5397,5402,5413,5417,5424,5427,5435,5440,5449,5498,5504,5509,5691,5696,5752,5754,5758,5769,5792,5796,5897,5901,5922,5926,6140,6145,6151,6155,6169,6174,6185,6190,6294,6329,6331,6335,6338,6361,6365,6453,6457,6471,6475,6733,6737,6748,6752,6762,6766,6858,6904,6909,6912,6931,6938,6940,6944,6951,6985,6989,7050,7054,7078,7082,7254,7258,7276,7280,7344,7349,7464,7468,7482,7525,7527,7531,7650,7655,7776,7778,7782,7792,7796,8017,8021,8024,8244,8248,8251,8313,8318,8338,8343,8354,8357,8362,8385,8396,8400,8617,8622,8648,8650,8654,8663,8667,8672,8862,8866,8869,8875,8879,8910,8915,8968,8972,8975,9129,9133,9136,9160,9165,9182,9187,9193,9216,9222,9226,9364,9368,9371,9521,9523,9527,9541,9545,9588,9592,9687,9691,9702,9706,9870,9875,9901,9905,9995,9999,10004,10237,10242,10390,10392,10396,10401,10405,10411,10613,10617,10637,10642,10703,10708,10728,10732,10735,10976,10993,10997,11003,11012,11213,11218,11238,11243,11263,11291,11293,11297,11303,11314,11323,11327,11332,11403,11408,11495,11499,11523,11527,11685,11689,11700,11704,11715,11717,11721,11724,11728,11959,11963,11968,12240,12245,12334,12338,12343,12611,12616,12711,12715,12720,12923,12928,13068,13073,13161,13166,13264,13268,13427,13430,13496,13498,13502,13505,13509,13515,13520,13555,13561,14270,14272,14276,14281,14285,14333,14338,14639,14641,14645,14650,14654,14678,14683,15242,15244,15248,15253,15257,15275,15280,15800,15802,15806,15812,15854,15858,15902,15906,15909,15940,15942,15946,15949,16410,16412,16416,16441,16443,16451,16457],[3105,3106,2771],"h1",{"id":3107},"service-мережева-абстракція-для-pod",[3109,3110,3112],"h2",{"id":3111},"проблема-ефемерні-ip-адреси-pod","Проблема: ефемерні IP-адреси Pod",[3114,3115,3116,3117],"p",{},"У попередніх статтях ми навчилися створювати Deployment з кількома репліками Pod. Але залишилося критично важливе питання: ",[3118,3119,3120],"strong",{},"як інші компоненти застосунку можуть звертатись до цих Pod?",[3122,3123,3125],"h3",{"id":3124},"сценарій-frontend-потребує-доступу-до-api","Сценарій: frontend потребує доступу до API",[3114,3127,3128],{},"Уявіть типову архітектуру веб-застосунку:",[3130,3131,3132],"plant-uml",{},[3133,3134,3139],"pre",{"className":3135,"code":3136,"language":3137,"meta":3138,"style":3138},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Kubernetes Cluster\" {\n    package \"Frontend Deployment\" #e3f2fd {\n        component \"Frontend Pod 1\" as fe1\n        component \"Frontend Pod 2\" as fe2\n    }\n    \n    package \"API Deployment\" #fff3e0 {\n        component \"API Pod 1\\n10.244.1.10\" as api1\n        component \"API Pod 2\\n10.244.1.11\" as api2\n        component \"API Pod 3\\n10.244.1.12\" as api3\n    }\n}\n\nfe1 -[dashed]-> api1 : HTTP GET /todos?\nfe1 -[dashed]-> api2\nfe1 -[dashed]-> api3\n\nfe2 -[dashed]-> api1\nfe2 -[dashed]-> api2\nfe2 -[dashed]-> api3\n\nnote right of api1\n    Проблема: IP-адреси Pod\n    змінюються при кожному\n    перезапуску або rolling update\nend note\n\nnote left of fe1\n    Питання: Як frontend\n    знає IP-адреси всіх\n    API Pod?\nend note\n\n@enduml\n","plantuml","",[3140,3141,3142,3150,3156,3162,3169,3175,3181,3187,3193,3199,3205,3211,3217,3223,3229,3234,3240,3245,3251,3257,3263,3268,3274,3280,3286,3291,3297,3303,3309,3315,3321,3326,3332,3338,3344,3350,3355,3360],"code",{"__ignoreMap":3138},[3143,3144,3147],"span",{"class":3145,"line":3146},"line",1,[3143,3148,3149],{},"@startuml\n",[3143,3151,3153],{"class":3145,"line":3152},2,[3143,3154,3155],{},"skinparam style plain\n",[3143,3157,3159],{"class":3145,"line":3158},3,[3143,3160,3161],{},"skinparam backgroundColor #ffffff\n",[3143,3163,3165],{"class":3145,"line":3164},4,[3143,3166,3168],{"emptyLinePlaceholder":3167},true,"\n",[3143,3170,3172],{"class":3145,"line":3171},5,[3143,3173,3174],{},"package \"Kubernetes Cluster\" {\n",[3143,3176,3178],{"class":3145,"line":3177},6,[3143,3179,3180],{},"    package \"Frontend Deployment\" #e3f2fd {\n",[3143,3182,3184],{"class":3145,"line":3183},7,[3143,3185,3186],{},"        component \"Frontend Pod 1\" as fe1\n",[3143,3188,3190],{"class":3145,"line":3189},8,[3143,3191,3192],{},"        component \"Frontend Pod 2\" as fe2\n",[3143,3194,3196],{"class":3145,"line":3195},9,[3143,3197,3198],{},"    }\n",[3143,3200,3202],{"class":3145,"line":3201},10,[3143,3203,3204],{},"    \n",[3143,3206,3208],{"class":3145,"line":3207},11,[3143,3209,3210],{},"    package \"API Deployment\" #fff3e0 {\n",[3143,3212,3214],{"class":3145,"line":3213},12,[3143,3215,3216],{},"        component \"API Pod 1\\n10.244.1.10\" as api1\n",[3143,3218,3220],{"class":3145,"line":3219},13,[3143,3221,3222],{},"        component \"API Pod 2\\n10.244.1.11\" as api2\n",[3143,3224,3226],{"class":3145,"line":3225},14,[3143,3227,3228],{},"        component \"API Pod 3\\n10.244.1.12\" as api3\n",[3143,3230,3232],{"class":3145,"line":3231},15,[3143,3233,3198],{},[3143,3235,3237],{"class":3145,"line":3236},16,[3143,3238,3239],{},"}\n",[3143,3241,3243],{"class":3145,"line":3242},17,[3143,3244,3168],{"emptyLinePlaceholder":3167},[3143,3246,3248],{"class":3145,"line":3247},18,[3143,3249,3250],{},"fe1 -[dashed]-> api1 : HTTP GET /todos?\n",[3143,3252,3254],{"class":3145,"line":3253},19,[3143,3255,3256],{},"fe1 -[dashed]-> api2\n",[3143,3258,3260],{"class":3145,"line":3259},20,[3143,3261,3262],{},"fe1 -[dashed]-> api3\n",[3143,3264,3266],{"class":3145,"line":3265},21,[3143,3267,3168],{"emptyLinePlaceholder":3167},[3143,3269,3271],{"class":3145,"line":3270},22,[3143,3272,3273],{},"fe2 -[dashed]-> api1\n",[3143,3275,3277],{"class":3145,"line":3276},23,[3143,3278,3279],{},"fe2 -[dashed]-> api2\n",[3143,3281,3283],{"class":3145,"line":3282},24,[3143,3284,3285],{},"fe2 -[dashed]-> api3\n",[3143,3287,3289],{"class":3145,"line":3288},25,[3143,3290,3168],{"emptyLinePlaceholder":3167},[3143,3292,3294],{"class":3145,"line":3293},26,[3143,3295,3296],{},"note right of api1\n",[3143,3298,3300],{"class":3145,"line":3299},27,[3143,3301,3302],{},"    Проблема: IP-адреси Pod\n",[3143,3304,3306],{"class":3145,"line":3305},28,[3143,3307,3308],{},"    змінюються при кожному\n",[3143,3310,3312],{"class":3145,"line":3311},29,[3143,3313,3314],{},"    перезапуску або rolling update\n",[3143,3316,3318],{"class":3145,"line":3317},30,[3143,3319,3320],{},"end note\n",[3143,3322,3324],{"class":3145,"line":3323},31,[3143,3325,3168],{"emptyLinePlaceholder":3167},[3143,3327,3329],{"class":3145,"line":3328},32,[3143,3330,3331],{},"note left of fe1\n",[3143,3333,3335],{"class":3145,"line":3334},33,[3143,3336,3337],{},"    Питання: Як frontend\n",[3143,3339,3341],{"class":3145,"line":3340},34,[3143,3342,3343],{},"    знає IP-адреси всіх\n",[3143,3345,3347],{"class":3145,"line":3346},35,[3143,3348,3349],{},"    API Pod?\n",[3143,3351,3353],{"class":3145,"line":3352},36,[3143,3354,3320],{},[3143,3356,3358],{"class":3145,"line":3357},37,[3143,3359,3168],{"emptyLinePlaceholder":3167},[3143,3361,3363],{"class":3145,"line":3362},38,[3143,3364,3365],{},"@enduml\n",[3114,3367,3368],{},[3118,3369,3370],{},"Проблеми прямого звернення до Pod за IP:",[3372,3373,3374,3413,3434,3487],"card-group",{},[3375,3376,3379,3386,3399],"card",{"icon":3377,"title":3378},"i-heroicons-arrow-path","Ефемерність IP-адрес",[3114,3380,3381,3382,3385],{},"Кожен Pod отримує унікальну IP-адресу при створенні. Але ця адреса ",[3118,3383,3384],{},"не стабільна",":",[3387,3388,3389,3393,3396],"ul",{},[3390,3391,3392],"li",{},"Pod перезапустився → нова IP-адреса",[3390,3394,3395],{},"Rolling update → старі Pod видалені, нові мають інші IP",[3390,3397,3398],{},"Масштабування → нові Pod з новими IP",[3114,3400,3401,3404,3405,3408,3409,3412],{},[3118,3402,3403],{},"Приклад:"," API Pod мав IP ",[3140,3406,3407],{},"10.244.1.10",". Після rolling update він має ",[3140,3410,3411],{},"10.244.2.15",". Frontend продовжує звертатись до старої адреси → помилки.",[3375,3414,3417,3420,3431],{"icon":3415,"title":3416},"i-heroicons-scale","Відсутність балансування навантаження",[3114,3418,3419],{},"Якщо у вас 3 репліки API, frontend має самостійно розподіляти запити між ними. Це означає:",[3387,3421,3422,3425,3428],{},[3390,3423,3424],{},"Вручну підтримувати список IP-адрес",[3390,3426,3427],{},"Реалізувати логіку балансування (round-robin, least connections)",[3390,3429,3430],{},"Відстежувати здоров'я кожного Pod",[3114,3432,3433],{},"Це складно, схильно до помилок та дублює функціональність, яку має надавати платформа.",[3375,3435,3438,3441,3481],{"icon":3436,"title":3437},"i-heroicons-magnifying-glass","Немає service discovery",[3114,3439,3440],{},"У Docker Compose ви використовували DNS-імена сервісів:",[3133,3442,3446],{"className":3443,"code":3444,"language":3445,"meta":3138,"style":3138},"language-yaml shiki shiki-themes light-plus dark-plus dark-plus","services:\n  frontend:\n    environment:\n      - API_URL=http://api:8080\n","yaml",[3140,3447,3448,3458,3465,3472],{"__ignoreMap":3138},[3143,3449,3450,3454],{"class":3145,"line":3146},[3143,3451,3453],{"class":3452},"sKtos","services",[3143,3455,3457],{"class":3456},"sHH4Y",":\n",[3143,3459,3460,3463],{"class":3145,"line":3152},[3143,3461,3462],{"class":3452},"  frontend",[3143,3464,3457],{"class":3456},[3143,3466,3467,3470],{"class":3145,"line":3158},[3143,3468,3469],{"class":3452},"    environment",[3143,3471,3457],{"class":3456},[3143,3473,3474,3477],{"class":3145,"line":3164},[3143,3475,3476],{"class":3456},"      - ",[3143,3478,3480],{"class":3479},"su9tN","API_URL=http://api:8080\n",[3114,3482,3483,3486],{},[3140,3484,3485],{},"api"," автоматично резолвився у IP-адресу контейнера. У Kubernetes немає автоматичного DNS для Pod — потрібен механізм service discovery.",[3375,3488,3491,3494,3531],{"icon":3489,"title":3490},"i-heroicons-cog","Складність конфігурації",[3114,3492,3493],{},"Якщо frontend має знати IP кожного API Pod, конфігурація стає кошмаром:",[3133,3495,3497],{"className":3443,"code":3496,"language":3445,"meta":3138,"style":3138},"env:\n  - name: API_ENDPOINTS\n    value: \"10.244.1.10,10.244.1.11,10.244.1.12\"\n",[3140,3498,3499,3506,3520],{"__ignoreMap":3138},[3143,3500,3501,3504],{"class":3145,"line":3146},[3143,3502,3503],{"class":3452},"env",[3143,3505,3457],{"class":3456},[3143,3507,3508,3511,3514,3517],{"class":3145,"line":3152},[3143,3509,3510],{"class":3456},"  - ",[3143,3512,3513],{"class":3452},"name",[3143,3515,3516],{"class":3456},": ",[3143,3518,3519],{"class":3479},"API_ENDPOINTS\n",[3143,3521,3522,3525,3527],{"class":3145,"line":3158},[3143,3523,3524],{"class":3452},"    value",[3143,3526,3516],{"class":3456},[3143,3528,3530],{"class":3529},"sbdoH","\"10.244.1.10,10.244.1.11,10.244.1.12\"\n",[3114,3532,3533],{},"Після кожного rolling update потрібно оновлювати цю конфігурацію. Це не масштабується.",[3122,3535,3537],{"id":3536},"що-потрібно-замість-прямого-доступу","Що потрібно замість прямого доступу",[3114,3539,3540],{},"Нам потрібен механізм, який:",[3542,3543,3544,3550,3556,3562,3568],"ol",{},[3390,3545,3546,3549],{},[3118,3547,3548],{},"Надає стабільну точку доступу"," — одна IP-адреса або DNS-ім'я, яке не змінюється",[3390,3551,3552,3555],{},[3118,3553,3554],{},"Автоматично балансує навантаження"," — розподіляє запити між усіма здоровими Pod",[3390,3557,3558,3561],{},[3118,3559,3560],{},"Відстежує здоров'я Pod"," — не надсилає трафік на Pod, які не готові",[3390,3563,3564,3567],{},[3118,3565,3566],{},"Підтримує service discovery"," — DNS-ім'я автоматично резолвиться у IP",[3390,3569,3570,3573],{},[3118,3571,3572],{},"Оновлюється автоматично"," — при додаванні/видаленні Pod список endpoints оновлюється",[3114,3575,3576,3577,3580],{},"Саме це і робить ",[3118,3578,3579],{},"Service",".",[3582,3583],"hr",{},[3109,3585,3587],{"id":3586},"що-таке-service-формальне-визначення","Що таке Service: формальне визначення",[3114,3589,3590,3592,3593,3596,3597,3600],{},[3118,3591,3579],{}," — це абстракція Kubernetes, яка визначає ",[3118,3594,3595],{},"логічний набір Pod"," та ",[3118,3598,3599],{},"політику доступу"," до них. Service надає стабільну мережеву точку доступу (IP-адресу та DNS-ім'я) для групи ефемерних Pod.",[3602,3603,3604,3621,3626,3629,3675],"note",{},[3114,3605,3606,3609,3610,3613,3614,3616,3617,3620],{},[3118,3607,3608],{},"Ключова ідея:"," Service — це ",[3118,3611,3612],{},"не"," Pod і ",[3118,3615,3612],{}," контейнер. Це мережевий об'єкт, який діє як ",[3118,3618,3619],{},"стабільний проксі"," перед групою Pod. Коли ви звертаєтесь до Service, Kubernetes автоматично перенаправляє запит на один з Pod, які відповідають селектору Service.",[3114,3622,3623],{},[3118,3624,3625],{},"Аналогія з Docker Compose:",[3114,3627,3628],{},"У Compose ви використовували DNS-імена сервісів:",[3133,3630,3632],{"className":3443,"code":3631,"language":3445,"meta":3138,"style":3138},"services:\n  api:\n    image: myapi:1.0\n    deploy:\n      replicas: 3\n",[3140,3633,3634,3640,3647,3657,3664],{"__ignoreMap":3138},[3143,3635,3636,3638],{"class":3145,"line":3146},[3143,3637,3453],{"class":3452},[3143,3639,3457],{"class":3456},[3143,3641,3642,3645],{"class":3145,"line":3152},[3143,3643,3644],{"class":3452},"  api",[3143,3646,3457],{"class":3456},[3143,3648,3649,3652,3654],{"class":3145,"line":3158},[3143,3650,3651],{"class":3452},"    image",[3143,3653,3516],{"class":3456},[3143,3655,3656],{"class":3479},"myapi:1.0\n",[3143,3658,3659,3662],{"class":3145,"line":3164},[3143,3660,3661],{"class":3452},"    deploy",[3143,3663,3457],{"class":3456},[3143,3665,3666,3669,3671],{"class":3145,"line":3171},[3143,3667,3668],{"class":3452},"      replicas",[3143,3670,3516],{"class":3456},[3143,3672,3674],{"class":3673},"sJj4R","3\n",[3114,3676,3677,3679],{},[3140,3678,3485],{}," автоматично резолвився у IP одного з 3 контейнерів. Kubernetes Service робить те саме, але з більшим контролем та гнучкістю.",[3122,3681,3683],{"id":3682},"основні-компоненти-service","Основні компоненти Service",[3130,3685,3686],{},[3133,3687,3689],{"className":3135,"code":3688,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Service Architecture\" {\n    component \"Service\\n(api-service)\" as svc #e3f2fd {\n        [ClusterIP: 10.96.0.10]\n        [DNS: api-service.default.svc.cluster.local]\n        [Port: 80]\n    }\n    \n    component \"Selector\" as sel #fff3e0 {\n        [app: api]\n        [version: v1]\n    }\n    \n    component \"Endpoints\" as ep #e8f5e9 {\n        [10.244.1.10:8080]\n        [10.244.1.11:8080]\n        [10.244.1.12:8080]\n    }\n    \n    package \"Pods\" {\n        component \"Pod 1\\n10.244.1.10\" as p1\n        component \"Pod 2\\n10.244.1.11\" as p2\n        component \"Pod 3\\n10.244.1.12\" as p3\n    }\n}\n\nsvc --> sel : uses\nsel --> p1 : matches\nsel --> p2 : matches\nsel --> p3 : matches\nsvc --> ep : maintains\nep --> p1\nep --> p2\nep --> p3\n\nnote right of svc\n    Service надає:\n    - Стабільну ClusterIP\n    - DNS-ім'я\n    - Балансування навантаження\nend note\n\nnote right of sel\n    Selector визначає,\n    які Pod належать\n    до цього Service\nend note\n\nnote right of ep\n    Endpoints — список\n    IP:Port всіх Pod,\n    які відповідають селектору\nend note\n\n@enduml\n",[3140,3690,3691,3695,3699,3703,3707,3712,3717,3722,3727,3732,3736,3740,3745,3750,3755,3759,3763,3768,3773,3778,3783,3787,3791,3796,3801,3806,3811,3815,3819,3823,3828,3833,3838,3843,3848,3853,3858,3863,3867,3873,3879,3885,3891,3897,3902,3907,3913,3919,3925,3931,3936,3941,3947,3953,3959,3965,3970,3975],{"__ignoreMap":3138},[3143,3692,3693],{"class":3145,"line":3146},[3143,3694,3149],{},[3143,3696,3697],{"class":3145,"line":3152},[3143,3698,3155],{},[3143,3700,3701],{"class":3145,"line":3158},[3143,3702,3161],{},[3143,3704,3705],{"class":3145,"line":3164},[3143,3706,3168],{"emptyLinePlaceholder":3167},[3143,3708,3709],{"class":3145,"line":3171},[3143,3710,3711],{},"package \"Service Architecture\" {\n",[3143,3713,3714],{"class":3145,"line":3177},[3143,3715,3716],{},"    component \"Service\\n(api-service)\" as svc #e3f2fd {\n",[3143,3718,3719],{"class":3145,"line":3183},[3143,3720,3721],{},"        [ClusterIP: 10.96.0.10]\n",[3143,3723,3724],{"class":3145,"line":3189},[3143,3725,3726],{},"        [DNS: api-service.default.svc.cluster.local]\n",[3143,3728,3729],{"class":3145,"line":3195},[3143,3730,3731],{},"        [Port: 80]\n",[3143,3733,3734],{"class":3145,"line":3201},[3143,3735,3198],{},[3143,3737,3738],{"class":3145,"line":3207},[3143,3739,3204],{},[3143,3741,3742],{"class":3145,"line":3213},[3143,3743,3744],{},"    component \"Selector\" as sel #fff3e0 {\n",[3143,3746,3747],{"class":3145,"line":3219},[3143,3748,3749],{},"        [app: api]\n",[3143,3751,3752],{"class":3145,"line":3225},[3143,3753,3754],{},"        [version: v1]\n",[3143,3756,3757],{"class":3145,"line":3231},[3143,3758,3198],{},[3143,3760,3761],{"class":3145,"line":3236},[3143,3762,3204],{},[3143,3764,3765],{"class":3145,"line":3242},[3143,3766,3767],{},"    component \"Endpoints\" as ep #e8f5e9 {\n",[3143,3769,3770],{"class":3145,"line":3247},[3143,3771,3772],{},"        [10.244.1.10:8080]\n",[3143,3774,3775],{"class":3145,"line":3253},[3143,3776,3777],{},"        [10.244.1.11:8080]\n",[3143,3779,3780],{"class":3145,"line":3259},[3143,3781,3782],{},"        [10.244.1.12:8080]\n",[3143,3784,3785],{"class":3145,"line":3265},[3143,3786,3198],{},[3143,3788,3789],{"class":3145,"line":3270},[3143,3790,3204],{},[3143,3792,3793],{"class":3145,"line":3276},[3143,3794,3795],{},"    package \"Pods\" {\n",[3143,3797,3798],{"class":3145,"line":3282},[3143,3799,3800],{},"        component \"Pod 1\\n10.244.1.10\" as p1\n",[3143,3802,3803],{"class":3145,"line":3288},[3143,3804,3805],{},"        component \"Pod 2\\n10.244.1.11\" as p2\n",[3143,3807,3808],{"class":3145,"line":3293},[3143,3809,3810],{},"        component \"Pod 3\\n10.244.1.12\" as p3\n",[3143,3812,3813],{"class":3145,"line":3299},[3143,3814,3198],{},[3143,3816,3817],{"class":3145,"line":3305},[3143,3818,3239],{},[3143,3820,3821],{"class":3145,"line":3311},[3143,3822,3168],{"emptyLinePlaceholder":3167},[3143,3824,3825],{"class":3145,"line":3317},[3143,3826,3827],{},"svc --> sel : uses\n",[3143,3829,3830],{"class":3145,"line":3323},[3143,3831,3832],{},"sel --> p1 : matches\n",[3143,3834,3835],{"class":3145,"line":3328},[3143,3836,3837],{},"sel --> p2 : matches\n",[3143,3839,3840],{"class":3145,"line":3334},[3143,3841,3842],{},"sel --> p3 : matches\n",[3143,3844,3845],{"class":3145,"line":3340},[3143,3846,3847],{},"svc --> ep : maintains\n",[3143,3849,3850],{"class":3145,"line":3346},[3143,3851,3852],{},"ep --> p1\n",[3143,3854,3855],{"class":3145,"line":3352},[3143,3856,3857],{},"ep --> p2\n",[3143,3859,3860],{"class":3145,"line":3357},[3143,3861,3862],{},"ep --> p3\n",[3143,3864,3865],{"class":3145,"line":3362},[3143,3866,3168],{"emptyLinePlaceholder":3167},[3143,3868,3870],{"class":3145,"line":3869},39,[3143,3871,3872],{},"note right of svc\n",[3143,3874,3876],{"class":3145,"line":3875},40,[3143,3877,3878],{},"    Service надає:\n",[3143,3880,3882],{"class":3145,"line":3881},41,[3143,3883,3884],{},"    - Стабільну ClusterIP\n",[3143,3886,3888],{"class":3145,"line":3887},42,[3143,3889,3890],{},"    - DNS-ім'я\n",[3143,3892,3894],{"class":3145,"line":3893},43,[3143,3895,3896],{},"    - Балансування навантаження\n",[3143,3898,3900],{"class":3145,"line":3899},44,[3143,3901,3320],{},[3143,3903,3905],{"class":3145,"line":3904},45,[3143,3906,3168],{"emptyLinePlaceholder":3167},[3143,3908,3910],{"class":3145,"line":3909},46,[3143,3911,3912],{},"note right of sel\n",[3143,3914,3916],{"class":3145,"line":3915},47,[3143,3917,3918],{},"    Selector визначає,\n",[3143,3920,3922],{"class":3145,"line":3921},48,[3143,3923,3924],{},"    які Pod належать\n",[3143,3926,3928],{"class":3145,"line":3927},49,[3143,3929,3930],{},"    до цього Service\n",[3143,3932,3934],{"class":3145,"line":3933},50,[3143,3935,3320],{},[3143,3937,3939],{"class":3145,"line":3938},51,[3143,3940,3168],{"emptyLinePlaceholder":3167},[3143,3942,3944],{"class":3145,"line":3943},52,[3143,3945,3946],{},"note right of ep\n",[3143,3948,3950],{"class":3145,"line":3949},53,[3143,3951,3952],{},"    Endpoints — список\n",[3143,3954,3956],{"class":3145,"line":3955},54,[3143,3957,3958],{},"    IP:Port всіх Pod,\n",[3143,3960,3962],{"class":3145,"line":3961},55,[3143,3963,3964],{},"    які відповідають селектору\n",[3143,3966,3968],{"class":3145,"line":3967},56,[3143,3969,3320],{},[3143,3971,3973],{"class":3145,"line":3972},57,[3143,3974,3168],{"emptyLinePlaceholder":3167},[3143,3976,3978],{"class":3145,"line":3977},58,[3143,3979,3365],{},[3114,3981,3982],{},[3118,3983,3984],{},"Компоненти:",[3542,3986,3987,3993,4003,4009,4015],{},[3390,3988,3989,3992],{},[3118,3990,3991],{},"ClusterIP"," — стабільна внутрішня IP-адреса Service (не змінюється)",[3390,3994,3995,3998,3999,4002],{},[3118,3996,3997],{},"DNS-ім'я"," — автоматично створюється CoreDNS (формат: ",[3140,4000,4001],{},"\u003Cservice-name>.\u003Cnamespace>.svc.cluster.local",")",[3390,4004,4005,4008],{},[3118,4006,4007],{},"Selector"," — мітки для вибору Pod (як у Deployment)",[3390,4010,4011,4014],{},[3118,4012,4013],{},"Endpoints"," — список IP:Port всіх Pod, які відповідають селектору",[3390,4016,4017,4020],{},[3118,4018,4019],{},"Port mapping"," — маппінг портів Service → Pod",[3582,4022],{},[3109,4024,4026],{"id":4025},"анатомія-service-структура-yaml","Анатомія Service: структура YAML",[3114,4028,4029],{},"Розглянемо базовий приклад Service:",[3133,4031,4033],{"className":3443,"code":4032,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: api-service\n  namespace: default\nspec:\n  selector:\n    app: api\n  ports:\n    - name: http\n      protocol: TCP\n      port: 80\n      targetPort: 8080\n  type: ClusterIP\n",[3140,4034,4035,4045,4055,4062,4072,4082,4089,4096,4106,4113,4125,4135,4145,4155],{"__ignoreMap":3138},[3143,4036,4037,4040,4042],{"class":3145,"line":3146},[3143,4038,4039],{"class":3452},"apiVersion",[3143,4041,3516],{"class":3456},[3143,4043,4044],{"class":3479},"v1\n",[3143,4046,4047,4050,4052],{"class":3145,"line":3152},[3143,4048,4049],{"class":3452},"kind",[3143,4051,3516],{"class":3456},[3143,4053,4054],{"class":3479},"Service\n",[3143,4056,4057,4060],{"class":3145,"line":3158},[3143,4058,4059],{"class":3452},"metadata",[3143,4061,3457],{"class":3456},[3143,4063,4064,4067,4069],{"class":3145,"line":3164},[3143,4065,4066],{"class":3452},"  name",[3143,4068,3516],{"class":3456},[3143,4070,4071],{"class":3479},"api-service\n",[3143,4073,4074,4077,4079],{"class":3145,"line":3171},[3143,4075,4076],{"class":3452},"  namespace",[3143,4078,3516],{"class":3456},[3143,4080,4081],{"class":3479},"default\n",[3143,4083,4084,4087],{"class":3145,"line":3177},[3143,4085,4086],{"class":3452},"spec",[3143,4088,3457],{"class":3456},[3143,4090,4091,4094],{"class":3145,"line":3183},[3143,4092,4093],{"class":3452},"  selector",[3143,4095,3457],{"class":3456},[3143,4097,4098,4101,4103],{"class":3145,"line":3189},[3143,4099,4100],{"class":3452},"    app",[3143,4102,3516],{"class":3456},[3143,4104,4105],{"class":3479},"api\n",[3143,4107,4108,4111],{"class":3145,"line":3195},[3143,4109,4110],{"class":3452},"  ports",[3143,4112,3457],{"class":3456},[3143,4114,4115,4118,4120,4122],{"class":3145,"line":3201},[3143,4116,4117],{"class":3456},"    - ",[3143,4119,3513],{"class":3452},[3143,4121,3516],{"class":3456},[3143,4123,4124],{"class":3479},"http\n",[3143,4126,4127,4130,4132],{"class":3145,"line":3207},[3143,4128,4129],{"class":3452},"      protocol",[3143,4131,3516],{"class":3456},[3143,4133,4134],{"class":3479},"TCP\n",[3143,4136,4137,4140,4142],{"class":3145,"line":3213},[3143,4138,4139],{"class":3452},"      port",[3143,4141,3516],{"class":3456},[3143,4143,4144],{"class":3673},"80\n",[3143,4146,4147,4150,4152],{"class":3145,"line":3219},[3143,4148,4149],{"class":3452},"      targetPort",[3143,4151,3516],{"class":3456},[3143,4153,4154],{"class":3673},"8080\n",[3143,4156,4157,4160,4162],{"class":3145,"line":3225},[3143,4158,4159],{"class":3452},"  type",[3143,4161,3516],{"class":3456},[3143,4163,4164],{"class":3479},"ClusterIP\n",[3114,4166,4167],{},"Розберемо кожне поле детально.",[4169,4170,4171,4185,4191,4206,4210,4304,4408],"field-group",{},[4172,4173,4176,4177,4180,4181,4184],"field",{"name":4039,"type":4174,"required":4175},"string","true","Для Service використовується ",[3140,4178,4179],{},"v1"," (core API group). На відміну від Deployment (",[3140,4182,4183],{},"apps/v1","), Service — це базовий ресурс Kubernetes, який існує з самого початку.",[4172,4186,4187,4188,4190],{"name":4049,"type":4174,"required":4175},"Тип ресурсу — ",[3140,4189,3579],{},". Це вказує Kubernetes, що ви створюєте мережевий об'єкт для доступу до Pod.",[4172,4192,4194,4200],{"name":4193,"type":4174,"required":4175},"metadata.name",[3114,4195,4196,4197,3580],{},"Унікальне ім'я Service у межах namespace. Це ім'я буде використовуватись у DNS: ",[3140,4198,4199],{},"\u003Cname>.\u003Cnamespace>.svc.cluster.local",[3114,4201,4202,4205],{},[3118,4203,4204],{},"Важливо:"," Ім'я має відповідати DNS-стандарту (малі літери, цифри, дефіси). Максимум 63 символи.",[4172,4207,4209],{"name":4208,"type":4174,"default":3167},"metadata.namespace","Namespace, у якому буде створено Service. Service може звертатись лише до Pod у тому самому namespace (якщо не використовується ExternalName).",[4172,4211,4215,4218,4232,4236],{"name":4212,"type":4213,"required":4214},"spec.selector","map","true (для більшості типів)",[3114,4216,4217],{},"Мітки для вибору Pod, які належать до цього Service. Kubernetes автоматично знаходить всі Pod з цими мітками та додає їх до Endpoints.",[3114,4219,4220,4223,4224,4227,4228,4231],{},[3118,4221,4222],{},"Критично важливо:"," Мітки у ",[3140,4225,4226],{},"selector"," мають збігатись з мітками у ",[3140,4229,4230],{},"template.metadata.labels"," Deployment.",[3114,4233,4234],{},[3118,4235,3403],{},[3133,4237,4239],{"className":3443,"code":4238,"language":3445,"meta":3138,"style":3138},"# Service\nselector:\n  app: api\n\n# Deployment\ntemplate:\n  metadata:\n    labels:\n      app: api  # ← Має збігатись!\n",[3140,4240,4241,4247,4253,4262,4266,4271,4278,4285,4292],{"__ignoreMap":3138},[3143,4242,4243],{"class":3145,"line":3146},[3143,4244,4246],{"class":4245},"spJ8K","# Service\n",[3143,4248,4249,4251],{"class":3145,"line":3152},[3143,4250,4226],{"class":3452},[3143,4252,3457],{"class":3456},[3143,4254,4255,4258,4260],{"class":3145,"line":3158},[3143,4256,4257],{"class":3452},"  app",[3143,4259,3516],{"class":3456},[3143,4261,4105],{"class":3479},[3143,4263,4264],{"class":3145,"line":3164},[3143,4265,3168],{"emptyLinePlaceholder":3167},[3143,4267,4268],{"class":3145,"line":3171},[3143,4269,4270],{"class":4245},"# Deployment\n",[3143,4272,4273,4276],{"class":3145,"line":3177},[3143,4274,4275],{"class":3452},"template",[3143,4277,3457],{"class":3456},[3143,4279,4280,4283],{"class":3145,"line":3183},[3143,4281,4282],{"class":3452},"  metadata",[3143,4284,3457],{"class":3456},[3143,4286,4287,4290],{"class":3145,"line":3189},[3143,4288,4289],{"class":3452},"    labels",[3143,4291,3457],{"class":3456},[3143,4293,4294,4297,4299,4301],{"class":3145,"line":3195},[3143,4295,4296],{"class":3452},"      app",[3143,4298,3516],{"class":3456},[3143,4300,3485],{"class":3479},[3143,4302,4303],{"class":4245},"  # ← Має збігатись!\n",[4172,4305,4308,4311,4346,4350,4398],{"name":4306,"type":4307,"required":4175},"spec.ports","array",[3114,4309,4310],{},"Список портів, які експонує Service. Кожен порт має наступні поля:",[3387,4312,4313,4318,4334,4340],{},[3390,4314,4315,4317],{},[3140,4316,3513],{}," — ім'я порту (опціонально, але рекомендується для багатопортових Service)",[3390,4319,4320,4323,4324,4327,4328,4331,4332,4002],{},[3140,4321,4322],{},"protocol"," — протокол (",[3140,4325,4326],{},"TCP"," або ",[3140,4329,4330],{},"UDP",", за замовчуванням ",[3140,4333,4326],{},[3390,4335,4336,4339],{},[3140,4337,4338],{},"port"," — порт Service (на якому Service слухає)",[3390,4341,4342,4345],{},[3140,4343,4344],{},"targetPort"," — порт Pod (на який перенаправляється трафік)",[3114,4347,4348],{},[3118,4349,3403],{},[3133,4351,4353],{"className":3443,"code":4352,"language":3445,"meta":3138,"style":3138},"ports:\n  - name: http\n    port: 80        # Service слухає на порту 80\n    targetPort: 8080  # Трафік йде на порт 8080 Pod\n",[3140,4354,4355,4362,4372,4385],{"__ignoreMap":3138},[3143,4356,4357,4360],{"class":3145,"line":3146},[3143,4358,4359],{"class":3452},"ports",[3143,4361,3457],{"class":3456},[3143,4363,4364,4366,4368,4370],{"class":3145,"line":3152},[3143,4365,3510],{"class":3456},[3143,4367,3513],{"class":3452},[3143,4369,3516],{"class":3456},[3143,4371,4124],{"class":3479},[3143,4373,4374,4377,4379,4382],{"class":3145,"line":3158},[3143,4375,4376],{"class":3452},"    port",[3143,4378,3516],{"class":3456},[3143,4380,4381],{"class":3673},"80",[3143,4383,4384],{"class":4245},"        # Service слухає на порту 80\n",[3143,4386,4387,4390,4392,4395],{"class":3145,"line":3164},[3143,4388,4389],{"class":3452},"    targetPort",[3143,4391,3516],{"class":3456},[3143,4393,4394],{"class":3673},"8080",[3143,4396,4397],{"class":4245},"  # Трафік йде на порт 8080 Pod\n",[3114,4399,4400,4401,4404,4405,3580],{},"Це означає: запит до ",[3140,4402,4403],{},"api-service:80"," перенаправляється на ",[3140,4406,4407],{},"\u003Cpod-ip>:8080",[4172,4409,4411,4414,4439],{"name":4410,"type":4174,"default":3991},"spec.type",[3114,4412,4413],{},"Тип Service, який визначає, як Service експонується. Доступні типи:",[3387,4415,4416,4421,4427,4433],{},[3390,4417,4418,4420],{},[3140,4419,3991],{}," — внутрішній IP, доступний лише всередині кластера (за замовчуванням)",[3390,4422,4423,4426],{},[3140,4424,4425],{},"NodePort"," — експонує Service на статичному порту кожного вузла",[3390,4428,4429,4432],{},[3140,4430,4431],{},"LoadBalancer"," — створює зовнішній load balancer (у хмарних провайдерів)",[3390,4434,4435,4438],{},[3140,4436,4437],{},"ExternalName"," — маппінг на зовнішнє DNS-ім'я",[3114,4440,4441],{},"Детально розглянемо кожен тип далі.",[3122,4443,4445],{"id":4444},"як-працює-маппінг-портів","Як працює маппінг портів",[3114,4447,4448,4449,3596,4451,3385],{},"Розберемо детально, як працює ",[3140,4450,4338],{},[3140,4452,4344],{},[3130,4454,4455],{},[3133,4456,4458],{"className":3135,"code":4457,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Client\" as client\ncomponent \"Service\\napi-service\" as svc #e3f2fd {\n    [ClusterIP: 10.96.0.10]\n    [Port: 80]\n}\n\ncomponent \"Pod 1\" as p1 #e8f5e9 {\n    [IP: 10.244.1.10]\n    [Container Port: 8080]\n}\n\ncomponent \"Pod 2\" as p2 #e8f5e9 {\n    [IP: 10.244.1.11]\n    [Container Port: 8080]\n}\n\ncomponent \"Pod 3\" as p3 #e8f5e9 {\n    [IP: 10.244.1.12]\n    [Container Port: 8080]\n}\n\nclient --> svc : GET http://api-service:80/todos\nsvc --> p1 : GET http://10.244.1.10:8080/todos\nsvc --> p2 : GET http://10.244.1.11:8080/todos\nsvc --> p3 : GET http://10.244.1.12:8080/todos\n\nnote right of svc\n    Service слухає на порту 80\n    (port: 80)\n    \n    Перенаправляє на порт 8080 Pod\n    (targetPort: 8080)\nend note\n\nnote right of p1\n    Контейнер слухає на порту 8080\n    (containerPort: 8080 у Pod spec)\nend note\n\n@enduml\n",[3140,4459,4460,4464,4468,4472,4476,4481,4486,4491,4496,4500,4504,4509,4514,4519,4523,4527,4532,4537,4541,4545,4549,4554,4559,4563,4567,4571,4576,4581,4586,4591,4595,4599,4604,4609,4613,4618,4623,4627,4631,4636,4641,4646,4650,4654],{"__ignoreMap":3138},[3143,4461,4462],{"class":3145,"line":3146},[3143,4463,3149],{},[3143,4465,4466],{"class":3145,"line":3152},[3143,4467,3155],{},[3143,4469,4470],{"class":3145,"line":3158},[3143,4471,3161],{},[3143,4473,4474],{"class":3145,"line":3164},[3143,4475,3168],{"emptyLinePlaceholder":3167},[3143,4477,4478],{"class":3145,"line":3171},[3143,4479,4480],{},"actor \"Client\" as client\n",[3143,4482,4483],{"class":3145,"line":3177},[3143,4484,4485],{},"component \"Service\\napi-service\" as svc #e3f2fd {\n",[3143,4487,4488],{"class":3145,"line":3183},[3143,4489,4490],{},"    [ClusterIP: 10.96.0.10]\n",[3143,4492,4493],{"class":3145,"line":3189},[3143,4494,4495],{},"    [Port: 80]\n",[3143,4497,4498],{"class":3145,"line":3195},[3143,4499,3239],{},[3143,4501,4502],{"class":3145,"line":3201},[3143,4503,3168],{"emptyLinePlaceholder":3167},[3143,4505,4506],{"class":3145,"line":3207},[3143,4507,4508],{},"component \"Pod 1\" as p1 #e8f5e9 {\n",[3143,4510,4511],{"class":3145,"line":3213},[3143,4512,4513],{},"    [IP: 10.244.1.10]\n",[3143,4515,4516],{"class":3145,"line":3219},[3143,4517,4518],{},"    [Container Port: 8080]\n",[3143,4520,4521],{"class":3145,"line":3225},[3143,4522,3239],{},[3143,4524,4525],{"class":3145,"line":3231},[3143,4526,3168],{"emptyLinePlaceholder":3167},[3143,4528,4529],{"class":3145,"line":3236},[3143,4530,4531],{},"component \"Pod 2\" as p2 #e8f5e9 {\n",[3143,4533,4534],{"class":3145,"line":3242},[3143,4535,4536],{},"    [IP: 10.244.1.11]\n",[3143,4538,4539],{"class":3145,"line":3247},[3143,4540,4518],{},[3143,4542,4543],{"class":3145,"line":3253},[3143,4544,3239],{},[3143,4546,4547],{"class":3145,"line":3259},[3143,4548,3168],{"emptyLinePlaceholder":3167},[3143,4550,4551],{"class":3145,"line":3265},[3143,4552,4553],{},"component \"Pod 3\" as p3 #e8f5e9 {\n",[3143,4555,4556],{"class":3145,"line":3270},[3143,4557,4558],{},"    [IP: 10.244.1.12]\n",[3143,4560,4561],{"class":3145,"line":3276},[3143,4562,4518],{},[3143,4564,4565],{"class":3145,"line":3282},[3143,4566,3239],{},[3143,4568,4569],{"class":3145,"line":3288},[3143,4570,3168],{"emptyLinePlaceholder":3167},[3143,4572,4573],{"class":3145,"line":3293},[3143,4574,4575],{},"client --> svc : GET http://api-service:80/todos\n",[3143,4577,4578],{"class":3145,"line":3299},[3143,4579,4580],{},"svc --> p1 : GET http://10.244.1.10:8080/todos\n",[3143,4582,4583],{"class":3145,"line":3305},[3143,4584,4585],{},"svc --> p2 : GET http://10.244.1.11:8080/todos\n",[3143,4587,4588],{"class":3145,"line":3311},[3143,4589,4590],{},"svc --> p3 : GET http://10.244.1.12:8080/todos\n",[3143,4592,4593],{"class":3145,"line":3317},[3143,4594,3168],{"emptyLinePlaceholder":3167},[3143,4596,4597],{"class":3145,"line":3323},[3143,4598,3872],{},[3143,4600,4601],{"class":3145,"line":3328},[3143,4602,4603],{},"    Service слухає на порту 80\n",[3143,4605,4606],{"class":3145,"line":3334},[3143,4607,4608],{},"    (port: 80)\n",[3143,4610,4611],{"class":3145,"line":3340},[3143,4612,3204],{},[3143,4614,4615],{"class":3145,"line":3346},[3143,4616,4617],{},"    Перенаправляє на порт 8080 Pod\n",[3143,4619,4620],{"class":3145,"line":3352},[3143,4621,4622],{},"    (targetPort: 8080)\n",[3143,4624,4625],{"class":3145,"line":3357},[3143,4626,3320],{},[3143,4628,4629],{"class":3145,"line":3362},[3143,4630,3168],{"emptyLinePlaceholder":3167},[3143,4632,4633],{"class":3145,"line":3869},[3143,4634,4635],{},"note right of p1\n",[3143,4637,4638],{"class":3145,"line":3875},[3143,4639,4640],{},"    Контейнер слухає на порту 8080\n",[3143,4642,4643],{"class":3145,"line":3881},[3143,4644,4645],{},"    (containerPort: 8080 у Pod spec)\n",[3143,4647,4648],{"class":3145,"line":3887},[3143,4649,3320],{},[3143,4651,4652],{"class":3145,"line":3893},[3143,4653,3168],{"emptyLinePlaceholder":3167},[3143,4655,4656],{"class":3145,"line":3899},[3143,4657,3365],{},[3114,4659,4660],{},[3118,4661,4662],{},"Важливі моменти:",[3542,4664,4665,4675,4685],{},[3390,4666,4667,4671,4672,4674],{},[3118,4668,4669],{},[3140,4670,4338],{}," — це порт, на якому ",[3118,4673,3579],{}," слухає. Клієнти звертаються до Service на цьому порту.",[3390,4676,4677,4671,4681,4684],{},[3118,4678,4679],{},[3140,4680,4344],{},[3118,4682,4683],{},"Pod"," слухає. Service перенаправляє трафік на цей порт.",[3390,4686,4687,4692,4693,4696,4697,3580],{},[3118,4688,4689],{},[3140,4690,4691],{},"containerPort"," (у Pod spec) — це порт, який ",[3118,4694,4695],{},"контейнер"," експонує. Має збігатись з ",[3140,4698,4344],{},[3114,4700,4701],{},[3118,4702,4703],{},"Типова помилка новачків:",[3133,4705,4707],{"className":3443,"code":4706,"language":3445,"meta":3138,"style":3138},"# Service\nports:\n  - port: 80\n    targetPort: 8080\n\n# Pod (у Deployment)\ncontainers:\n  - name: api\n    ports:\n      - containerPort: 80  # ← ПОМИЛКА! Має бути 8080\n",[3140,4708,4709,4713,4719,4729,4737,4741,4746,4753,4763,4770],{"__ignoreMap":3138},[3143,4710,4711],{"class":3145,"line":3146},[3143,4712,4246],{"class":4245},[3143,4714,4715,4717],{"class":3145,"line":3152},[3143,4716,4359],{"class":3452},[3143,4718,3457],{"class":3456},[3143,4720,4721,4723,4725,4727],{"class":3145,"line":3158},[3143,4722,3510],{"class":3456},[3143,4724,4338],{"class":3452},[3143,4726,3516],{"class":3456},[3143,4728,4144],{"class":3673},[3143,4730,4731,4733,4735],{"class":3145,"line":3164},[3143,4732,4389],{"class":3452},[3143,4734,3516],{"class":3456},[3143,4736,4154],{"class":3673},[3143,4738,4739],{"class":3145,"line":3171},[3143,4740,3168],{"emptyLinePlaceholder":3167},[3143,4742,4743],{"class":3145,"line":3177},[3143,4744,4745],{"class":4245},"# Pod (у Deployment)\n",[3143,4747,4748,4751],{"class":3145,"line":3183},[3143,4749,4750],{"class":3452},"containers",[3143,4752,3457],{"class":3456},[3143,4754,4755,4757,4759,4761],{"class":3145,"line":3189},[3143,4756,3510],{"class":3456},[3143,4758,3513],{"class":3452},[3143,4760,3516],{"class":3456},[3143,4762,4105],{"class":3479},[3143,4764,4765,4768],{"class":3145,"line":3195},[3143,4766,4767],{"class":3452},"    ports",[3143,4769,3457],{"class":3456},[3143,4771,4772,4774,4776,4778,4780],{"class":3145,"line":3201},[3143,4773,3476],{"class":3456},[3143,4775,4691],{"class":3452},[3143,4777,3516],{"class":3456},[3143,4779,4381],{"class":3673},[3143,4781,4782],{"class":4245},"  # ← ПОМИЛКА! Має бути 8080\n",[3114,4784,4785],{},"У цьому випадку Service перенаправляє трафік на порт 8080 Pod, але контейнер слухає на порту 80. Запити не доходять до застосунку.",[4787,4788,4789,4800,4805],"warning",{},[3114,4790,4791,4793,4794,4796,4797,4799],{},[3118,4792,4222],{}," ",[3140,4795,4344],{}," у Service має збігатись з ",[3140,4798,4691],{}," у Pod spec. Інакше трафік не дійде до застосунку.",[3114,4801,4802],{},[3118,4803,4804],{},"Правильна конфігурація:",[3133,4806,4808],{"className":3443,"code":4807,"language":3445,"meta":3138,"style":3138},"# Service\nspec:\n  ports:\n    - port: 80\n      targetPort: 8080\n\n# Deployment\nspec:\n  template:\n    spec:\n      containers:\n        - name: api\n          ports:\n            - containerPort: 8080  # ← Збігається з targetPort\n",[3140,4809,4810,4814,4820,4826,4836,4844,4848,4852,4858,4865,4872,4879,4890,4897],{"__ignoreMap":3138},[3143,4811,4812],{"class":3145,"line":3146},[3143,4813,4246],{"class":4245},[3143,4815,4816,4818],{"class":3145,"line":3152},[3143,4817,4086],{"class":3452},[3143,4819,3457],{"class":3456},[3143,4821,4822,4824],{"class":3145,"line":3158},[3143,4823,4110],{"class":3452},[3143,4825,3457],{"class":3456},[3143,4827,4828,4830,4832,4834],{"class":3145,"line":3164},[3143,4829,4117],{"class":3456},[3143,4831,4338],{"class":3452},[3143,4833,3516],{"class":3456},[3143,4835,4144],{"class":3673},[3143,4837,4838,4840,4842],{"class":3145,"line":3171},[3143,4839,4149],{"class":3452},[3143,4841,3516],{"class":3456},[3143,4843,4154],{"class":3673},[3143,4845,4846],{"class":3145,"line":3177},[3143,4847,3168],{"emptyLinePlaceholder":3167},[3143,4849,4850],{"class":3145,"line":3183},[3143,4851,4270],{"class":4245},[3143,4853,4854,4856],{"class":3145,"line":3189},[3143,4855,4086],{"class":3452},[3143,4857,3457],{"class":3456},[3143,4859,4860,4863],{"class":3145,"line":3195},[3143,4861,4862],{"class":3452},"  template",[3143,4864,3457],{"class":3456},[3143,4866,4867,4870],{"class":3145,"line":3201},[3143,4868,4869],{"class":3452},"    spec",[3143,4871,3457],{"class":3456},[3143,4873,4874,4877],{"class":3145,"line":3207},[3143,4875,4876],{"class":3452},"      containers",[3143,4878,3457],{"class":3456},[3143,4880,4881,4884,4886,4888],{"class":3145,"line":3213},[3143,4882,4883],{"class":3456},"        - ",[3143,4885,3513],{"class":3452},[3143,4887,3516],{"class":3456},[3143,4889,4105],{"class":3479},[3143,4891,4892,4895],{"class":3145,"line":3219},[3143,4893,4894],{"class":3452},"          ports",[3143,4896,3457],{"class":3456},[3143,4898,4899,4902,4904,4906,4908],{"class":3145,"line":3225},[3143,4900,4901],{"class":3456},"            - ",[3143,4903,4691],{"class":3452},[3143,4905,3516],{"class":3456},[3143,4907,4394],{"class":3673},[3143,4909,4910],{"class":4245},"  # ← Збігається з targetPort\n",[3122,4912,4914],{"id":4913},"targetport-як-імя-порту","targetPort як ім'я порту",[3114,4916,4917,4918,3385],{},"Замість числа можна використовувати ",[3118,4919,4920],{},"ім'я порту",[3133,4922,4924],{"className":3443,"code":4923,"language":3445,"meta":3138,"style":3138},"# Deployment\nspec:\n  template:\n    spec:\n      containers:\n        - name: api\n          ports:\n            - name: http  # ← Ім'я порту\n              containerPort: 8080\n\n# Service\nspec:\n  ports:\n    - port: 80\n      targetPort: http  # ← Посилання на ім'я\n",[3140,4925,4926,4930,4936,4942,4948,4954,4964,4970,4984,4993,4997,5001,5007,5013,5023],{"__ignoreMap":3138},[3143,4927,4928],{"class":3145,"line":3146},[3143,4929,4270],{"class":4245},[3143,4931,4932,4934],{"class":3145,"line":3152},[3143,4933,4086],{"class":3452},[3143,4935,3457],{"class":3456},[3143,4937,4938,4940],{"class":3145,"line":3158},[3143,4939,4862],{"class":3452},[3143,4941,3457],{"class":3456},[3143,4943,4944,4946],{"class":3145,"line":3164},[3143,4945,4869],{"class":3452},[3143,4947,3457],{"class":3456},[3143,4949,4950,4952],{"class":3145,"line":3171},[3143,4951,4876],{"class":3452},[3143,4953,3457],{"class":3456},[3143,4955,4956,4958,4960,4962],{"class":3145,"line":3177},[3143,4957,4883],{"class":3456},[3143,4959,3513],{"class":3452},[3143,4961,3516],{"class":3456},[3143,4963,4105],{"class":3479},[3143,4965,4966,4968],{"class":3145,"line":3183},[3143,4967,4894],{"class":3452},[3143,4969,3457],{"class":3456},[3143,4971,4972,4974,4976,4978,4981],{"class":3145,"line":3189},[3143,4973,4901],{"class":3456},[3143,4975,3513],{"class":3452},[3143,4977,3516],{"class":3456},[3143,4979,4980],{"class":3479},"http",[3143,4982,4983],{"class":4245},"  # ← Ім'я порту\n",[3143,4985,4986,4989,4991],{"class":3145,"line":3195},[3143,4987,4988],{"class":3452},"              containerPort",[3143,4990,3516],{"class":3456},[3143,4992,4154],{"class":3673},[3143,4994,4995],{"class":3145,"line":3201},[3143,4996,3168],{"emptyLinePlaceholder":3167},[3143,4998,4999],{"class":3145,"line":3207},[3143,5000,4246],{"class":4245},[3143,5002,5003,5005],{"class":3145,"line":3213},[3143,5004,4086],{"class":3452},[3143,5006,3457],{"class":3456},[3143,5008,5009,5011],{"class":3145,"line":3219},[3143,5010,4110],{"class":3452},[3143,5012,3457],{"class":3456},[3143,5014,5015,5017,5019,5021],{"class":3145,"line":3225},[3143,5016,4117],{"class":3456},[3143,5018,4338],{"class":3452},[3143,5020,3516],{"class":3456},[3143,5022,4144],{"class":3673},[3143,5024,5025,5027,5029,5031],{"class":3145,"line":3231},[3143,5026,4149],{"class":3452},[3143,5028,3516],{"class":3456},[3143,5030,4980],{"class":3479},[3143,5032,5033],{"class":4245},"  # ← Посилання на ім'я\n",[3114,5035,5036],{},[3118,5037,5038],{},"Переваги:",[3387,5040,5041,5044],{},[3390,5042,5043],{},"Якщо змінюється номер порту у Pod (8080 → 9090), не потрібно оновлювати Service",[3390,5045,5046],{},"Більш читабельно — зрозуміло, що це HTTP-порт",[3582,5048],{},[3109,5050,5052],{"id":5051},"типи-service-clusterip-nodeport-loadbalancer-externalname","Типи Service: ClusterIP, NodePort, LoadBalancer, ExternalName",[3114,5054,5055],{},"Kubernetes підтримує чотири типи Service, кожен для різних сценаріїв.",[3122,5057,5059],{"id":5058},"_1-clusterip-за-замовчуванням","1. ClusterIP (за замовчуванням)",[3114,5061,5062,5063,3580],{},"Тип сервісу, який виділяє для вашого набору Pod'ів єдину внутрішню IP-адресу (ClusterIP), доступну ",[3118,5064,5065],{},"виключно всередині самого Kubernetes-кластера",[3387,5067,5068,5074],{},[3390,5069,5070,5073],{},[3118,5071,5072],{},"Простими словами (з іншого ракурсу):"," Це приватна внутрішня телефонна лінія вашої компанії. Хтось зовні не може на неї набрати напрямую, але колеги з інших кабінетів (інші Pod'и) можуть дзвонить за цим коротким номером без перешкод.",[3390,5075,5076,5079,5080,5082,5083,5086],{},[3118,5077,5078],{},"Конкретний приклад:"," Уявіть, що у вас є мікросервісний додаток: веб-фронтенд та база даних PostgreSQL. Ви не хочете, щоб будь-хто з інтернету міг напряму достукатися до вашої бази даних. Тому ви створюєте для PostgreSQL сервіс із типом ",[3140,5081,3991],{},". Тепер ваш фронтенд-контейнер, що працює всередині кластера, може спокійно звертатися до бази за адресою ",[3140,5084,5085],{},"postgres-service",", тоді як будь-які зовнішні запити з інтернету будуть заблоковані на рівні мережі кластера. Це стандарт де-факто для безпечної внутрішньої взаємодії.",[3114,5088,5089],{},[3118,5090,5091],{},"YAML:",[3133,5093,5095],{"className":3443,"code":5094,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: api-service\nspec:\n  type: ClusterIP  # За замовчуванням, можна не вказувати\n  selector:\n    app: api\n  ports:\n    - port: 80\n      targetPort: 8080\n",[3140,5096,5097,5105,5113,5119,5127,5133,5144,5150,5158,5164,5174],{"__ignoreMap":3138},[3143,5098,5099,5101,5103],{"class":3145,"line":3146},[3143,5100,4039],{"class":3452},[3143,5102,3516],{"class":3456},[3143,5104,4044],{"class":3479},[3143,5106,5107,5109,5111],{"class":3145,"line":3152},[3143,5108,4049],{"class":3452},[3143,5110,3516],{"class":3456},[3143,5112,4054],{"class":3479},[3143,5114,5115,5117],{"class":3145,"line":3158},[3143,5116,4059],{"class":3452},[3143,5118,3457],{"class":3456},[3143,5120,5121,5123,5125],{"class":3145,"line":3164},[3143,5122,4066],{"class":3452},[3143,5124,3516],{"class":3456},[3143,5126,4071],{"class":3479},[3143,5128,5129,5131],{"class":3145,"line":3171},[3143,5130,4086],{"class":3452},[3143,5132,3457],{"class":3456},[3143,5134,5135,5137,5139,5141],{"class":3145,"line":3177},[3143,5136,4159],{"class":3452},[3143,5138,3516],{"class":3456},[3143,5140,3991],{"class":3479},[3143,5142,5143],{"class":4245},"  # За замовчуванням, можна не вказувати\n",[3143,5145,5146,5148],{"class":3145,"line":3183},[3143,5147,4093],{"class":3452},[3143,5149,3457],{"class":3456},[3143,5151,5152,5154,5156],{"class":3145,"line":3189},[3143,5153,4100],{"class":3452},[3143,5155,3516],{"class":3456},[3143,5157,4105],{"class":3479},[3143,5159,5160,5162],{"class":3145,"line":3195},[3143,5161,4110],{"class":3452},[3143,5163,3457],{"class":3456},[3143,5165,5166,5168,5170,5172],{"class":3145,"line":3201},[3143,5167,4117],{"class":3456},[3143,5169,4338],{"class":3452},[3143,5171,3516],{"class":3456},[3143,5173,4144],{"class":3673},[3143,5175,5176,5178,5180],{"class":3145,"line":3207},[3143,5177,4149],{"class":3452},[3143,5179,3516],{"class":3456},[3143,5181,4154],{"class":3673},[3114,5183,5184],{},[3118,5185,5186],{},"Що відбувається:",[3542,5188,5189,5195,5204],{},[3390,5190,5191,5192,4002],{},"Kubernetes виділяє IP-адресу з внутрішнього діапазону (наприклад, ",[3140,5193,5194],{},"10.96.0.10",[3390,5196,5197,5198,5201,5202],{},"CoreDNS створює DNS-запис: ",[3140,5199,5200],{},"api-service.default.svc.cluster.local"," → ",[3140,5203,5194],{},[3390,5205,5206],{},"Будь-який Pod у кластері може звертатись до Service за DNS-іменем або IP",[3114,5208,5209],{},[3118,5210,5211],{},"Візуалізація:",[3130,5213,5214],{},[3133,5215,5217],{"className":3135,"code":5216,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Kubernetes Cluster\" {\n    component \"Frontend Pod\" as fe #e3f2fd\n    \n    component \"Service\\napi-service\" as svc #fff3e0 {\n        [ClusterIP: 10.96.0.10]\n        [DNS: api-service.default.svc.cluster.local]\n    }\n    \n    package \"API Pods\" #e8f5e9 {\n        component \"Pod 1\\n10.244.1.10:8080\" as p1\n        component \"Pod 2\\n10.244.1.11:8080\" as p2\n        component \"Pod 3\\n10.244.1.12:8080\" as p3\n    }\n}\n\nactor \"Зовнішній користувач\" as user #ffebee\n\nfe --> svc : GET http://api-service/todos\nsvc --> p1\nsvc --> p2\nsvc --> p3\n\nuser -[dashed]-> svc : ❌ Недоступний ззовні\n\nnote right of svc\n    ClusterIP доступний\n    ЛИШЕ всередині кластера\nend note\n\nnote bottom of user\n    Зовнішні користувачі\n    не можуть звертатись\n    до ClusterIP Service\nend note\n\n@enduml\n",[3140,5218,5219,5223,5227,5231,5235,5239,5244,5248,5253,5257,5261,5265,5269,5274,5279,5284,5289,5293,5297,5301,5306,5310,5315,5320,5325,5330,5334,5339,5343,5347,5352,5357,5361,5365,5370,5375,5380,5385,5389,5393],{"__ignoreMap":3138},[3143,5220,5221],{"class":3145,"line":3146},[3143,5222,3149],{},[3143,5224,5225],{"class":3145,"line":3152},[3143,5226,3155],{},[3143,5228,5229],{"class":3145,"line":3158},[3143,5230,3161],{},[3143,5232,5233],{"class":3145,"line":3164},[3143,5234,3168],{"emptyLinePlaceholder":3167},[3143,5236,5237],{"class":3145,"line":3171},[3143,5238,3174],{},[3143,5240,5241],{"class":3145,"line":3177},[3143,5242,5243],{},"    component \"Frontend Pod\" as fe #e3f2fd\n",[3143,5245,5246],{"class":3145,"line":3183},[3143,5247,3204],{},[3143,5249,5250],{"class":3145,"line":3189},[3143,5251,5252],{},"    component \"Service\\napi-service\" as svc #fff3e0 {\n",[3143,5254,5255],{"class":3145,"line":3195},[3143,5256,3721],{},[3143,5258,5259],{"class":3145,"line":3201},[3143,5260,3726],{},[3143,5262,5263],{"class":3145,"line":3207},[3143,5264,3198],{},[3143,5266,5267],{"class":3145,"line":3213},[3143,5268,3204],{},[3143,5270,5271],{"class":3145,"line":3219},[3143,5272,5273],{},"    package \"API Pods\" #e8f5e9 {\n",[3143,5275,5276],{"class":3145,"line":3225},[3143,5277,5278],{},"        component \"Pod 1\\n10.244.1.10:8080\" as p1\n",[3143,5280,5281],{"class":3145,"line":3231},[3143,5282,5283],{},"        component \"Pod 2\\n10.244.1.11:8080\" as p2\n",[3143,5285,5286],{"class":3145,"line":3236},[3143,5287,5288],{},"        component \"Pod 3\\n10.244.1.12:8080\" as p3\n",[3143,5290,5291],{"class":3145,"line":3242},[3143,5292,3198],{},[3143,5294,5295],{"class":3145,"line":3247},[3143,5296,3239],{},[3143,5298,5299],{"class":3145,"line":3253},[3143,5300,3168],{"emptyLinePlaceholder":3167},[3143,5302,5303],{"class":3145,"line":3259},[3143,5304,5305],{},"actor \"Зовнішній користувач\" as user #ffebee\n",[3143,5307,5308],{"class":3145,"line":3265},[3143,5309,3168],{"emptyLinePlaceholder":3167},[3143,5311,5312],{"class":3145,"line":3270},[3143,5313,5314],{},"fe --> svc : GET http://api-service/todos\n",[3143,5316,5317],{"class":3145,"line":3276},[3143,5318,5319],{},"svc --> p1\n",[3143,5321,5322],{"class":3145,"line":3282},[3143,5323,5324],{},"svc --> p2\n",[3143,5326,5327],{"class":3145,"line":3288},[3143,5328,5329],{},"svc --> p3\n",[3143,5331,5332],{"class":3145,"line":3293},[3143,5333,3168],{"emptyLinePlaceholder":3167},[3143,5335,5336],{"class":3145,"line":3299},[3143,5337,5338],{},"user -[dashed]-> svc : ❌ Недоступний ззовні\n",[3143,5340,5341],{"class":3145,"line":3305},[3143,5342,3168],{"emptyLinePlaceholder":3167},[3143,5344,5345],{"class":3145,"line":3311},[3143,5346,3872],{},[3143,5348,5349],{"class":3145,"line":3317},[3143,5350,5351],{},"    ClusterIP доступний\n",[3143,5353,5354],{"class":3145,"line":3323},[3143,5355,5356],{},"    ЛИШЕ всередині кластера\n",[3143,5358,5359],{"class":3145,"line":3328},[3143,5360,3320],{},[3143,5362,5363],{"class":3145,"line":3334},[3143,5364,3168],{"emptyLinePlaceholder":3167},[3143,5366,5367],{"class":3145,"line":3340},[3143,5368,5369],{},"note bottom of user\n",[3143,5371,5372],{"class":3145,"line":3346},[3143,5373,5374],{},"    Зовнішні користувачі\n",[3143,5376,5377],{"class":3145,"line":3352},[3143,5378,5379],{},"    не можуть звертатись\n",[3143,5381,5382],{"class":3145,"line":3357},[3143,5383,5384],{},"    до ClusterIP Service\n",[3143,5386,5387],{"class":3145,"line":3362},[3143,5388,3320],{},[3143,5390,5391],{"class":3145,"line":3869},[3143,5392,3168],{"emptyLinePlaceholder":3167},[3143,5394,5395],{"class":3145,"line":3875},[3143,5396,3365],{},[3114,5398,5399],{},[3118,5400,5401],{},"Коли використовувати:",[3387,5403,5404,5407,5410],{},[3390,5405,5406],{},"Внутрішня комунікація між сервісами (frontend → API, API → database)",[3390,5408,5409],{},"Сервіси, які не мають бути доступні ззовні (бази даних, черги повідомлень)",[3390,5411,5412],{},"Більшість Service у production — це ClusterIP",[3122,5414,5416],{"id":5415},"як-працює-dns-імя-в-kubernetes-coredns","Як працює DNS-імя в Kubernetes (CoreDNS)",[3114,5418,5419,5420,5423],{},"Коли ви створюєте Service у Kubernetes, вбудована служба DNS (зазвичай ",[3118,5421,5422],{},"CoreDNS",") автоматично створює для нього внутрішній DNS-запис. Це дозволяє Pod'ам спілкуватися між собою не за IP-адресами (які постійно змінюються при перезапуску контейнерів), а за постійними, зрозумілими іменами.",[3114,5425,5426],{},"Повне доменне ім'я (FQDN) для будь-якого сервісу формується за шаблоном:",[3133,5428,5433],{"className":5429,"code":5431,"language":5432,"meta":3138},[5430],"language-text","[назва-сервісу].[namespace].svc.cluster.local\n","text",[3140,5434,5431],{"__ignoreMap":3138},[3114,5436,5437,5438,3580],{},"Для нашого сервісу повна адреса буде: ",[3140,5439,5200],{},[5441,5442,5444,5445,5448],"h4",{"id":5443},"чому-в-коді-ми-пишемо-просто-httpapi-service","Чому в коді ми пишемо просто ",[3140,5446,5447],{},"http://api-service","?",[3542,5450,5451,5471],{},[3390,5452,5453,5456,5457,5460,5461,5464,5465,5470],{},[3118,5454,5455],{},"Суфікси пошуку (DNS Search Paths):","\nКоли Kubernetes створює будь-який Pod, він автоматично прописує у його конфігурацію DNS (файл ",[3140,5458,5459],{},"/etc/resolv.conf",") суфікси пошуку. Вони включають поточний namespace (наприклад, ",[3140,5462,5463],{},"default.svc.cluster.local",").\nТому, якщо ваші контейнери знаходяться в одному namespace, DNS-клієнт автоматично підставить суфікс. Вам достатньо написати лише коротку назву сервісу — ",[3118,5466,5467],{},[3140,5468,5469],{},"api-service"," — і CoreDNS успішно розпізнає повну адресу.",[3390,5472,5473,5476,5477,5479,5480,5483,5484,5486,5487,5490,5491,5493,5494,5497],{},[3118,5474,5475],{},"Стандартний порт HTTP:","\nУ нашому YAML-файлі для ",[3140,5478,5469],{}," ми вказали зовнішній порт сервісу ",[3140,5481,5482],{},"port: 80",". Оскільки порт ",[3140,5485,4381],{}," є стандартним для протоколу ",[3140,5488,5489],{},"http://",", його не потрібно вказувати явно в URL.\nРядок ",[3140,5492,5447],{}," під капотом резолвиться в запит до IP-адреси сервісу на 80-й порт (наприклад, ",[3140,5495,5496],{},"http://10.96.0.10:80",").",[3602,5499,5500,5503],{},[3118,5501,5502],{},"Це фундаментальна перевага Kubernetes:"," вам абсолютно не потрібно знати динамічні IP-адреси Pod'ів чи сервісів. Ви просто звертаєтесь до імені сервісу, а Kubernetes автоматично бере на себе всю роботу з пошуку контейнерів, перевірки їхньої готовності та балансування навантаження!",[3114,5505,5506],{},[3118,5507,5508],{},"Приклад використання у .NET:",[3133,5510,5514],{"className":5511,"code":5512,"language":5513,"meta":3138,"style":3138},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","var builder = WebApplication.CreateBuilder(args);\n\n// Frontend звертається до API через Service DNS\nvar apiUrl = builder.Configuration[\"ApiUrl\"] ?? \"http://api-service\";\n\nbuilder.Services.AddHttpClient(\"ApiClient\", client =>\n{\n    client.BaseAddress = new Uri(apiUrl);\n});\n\nvar app = builder.Build();\napp.Run();\n","csharp",[3140,5515,5516,5547,5551,5556,5588,5592,5620,5625,5651,5656,5660,5679],{"__ignoreMap":3138},[3143,5517,5518,5522,5526,5529,5532,5534,5538,5541,5544],{"class":3145,"line":3146},[3143,5519,5521],{"class":5520},"su1O8","var",[3143,5523,5525],{"class":5524},"siwwj"," builder",[3143,5527,5528],{"class":3456}," = ",[3143,5530,5531],{"class":5524},"WebApplication",[3143,5533,3580],{"class":3456},[3143,5535,5537],{"class":5536},"s8Opu","CreateBuilder",[3143,5539,5540],{"class":3456},"(",[3143,5542,5543],{"class":5524},"args",[3143,5545,5546],{"class":3456},");\n",[3143,5548,5549],{"class":3145,"line":3152},[3143,5550,3168],{"emptyLinePlaceholder":3167},[3143,5552,5553],{"class":3145,"line":3158},[3143,5554,5555],{"class":4245},"// Frontend звертається до API через Service DNS\n",[3143,5557,5558,5560,5563,5565,5568,5570,5573,5576,5579,5582,5585],{"class":3145,"line":3164},[3143,5559,5521],{"class":5520},[3143,5561,5562],{"class":5524}," apiUrl",[3143,5564,5528],{"class":3456},[3143,5566,5567],{"class":5524},"builder",[3143,5569,3580],{"class":3456},[3143,5571,5572],{"class":5524},"Configuration",[3143,5574,5575],{"class":3456},"[",[3143,5577,5578],{"class":3529},"\"ApiUrl\"",[3143,5580,5581],{"class":3456},"] ?? ",[3143,5583,5584],{"class":3529},"\"http://api-service\"",[3143,5586,5587],{"class":3456},";\n",[3143,5589,5590],{"class":3145,"line":3171},[3143,5591,3168],{"emptyLinePlaceholder":3167},[3143,5593,5594,5596,5598,5601,5603,5606,5608,5611,5614,5617],{"class":3145,"line":3177},[3143,5595,5567],{"class":5524},[3143,5597,3580],{"class":3456},[3143,5599,5600],{"class":5524},"Services",[3143,5602,3580],{"class":3456},[3143,5604,5605],{"class":5536},"AddHttpClient",[3143,5607,5540],{"class":3456},[3143,5609,5610],{"class":3529},"\"ApiClient\"",[3143,5612,5613],{"class":3456},", ",[3143,5615,5616],{"class":5524},"client",[3143,5618,5619],{"class":3456}," =>\n",[3143,5621,5622],{"class":3145,"line":3183},[3143,5623,5624],{"class":3456},"{\n",[3143,5626,5627,5630,5632,5635,5637,5640,5644,5646,5649],{"class":3145,"line":3189},[3143,5628,5629],{"class":5524},"    client",[3143,5631,3580],{"class":3456},[3143,5633,5634],{"class":5524},"BaseAddress",[3143,5636,5528],{"class":3456},[3143,5638,5639],{"class":5520},"new",[3143,5641,5643],{"class":5642},"sN1BT"," Uri",[3143,5645,5540],{"class":3456},[3143,5647,5648],{"class":5524},"apiUrl",[3143,5650,5546],{"class":3456},[3143,5652,5653],{"class":3145,"line":3195},[3143,5654,5655],{"class":3456},"});\n",[3143,5657,5658],{"class":3145,"line":3201},[3143,5659,3168],{"emptyLinePlaceholder":3167},[3143,5661,5662,5664,5667,5669,5671,5673,5676],{"class":3145,"line":3207},[3143,5663,5521],{"class":5520},[3143,5665,5666],{"class":5524}," app",[3143,5668,5528],{"class":3456},[3143,5670,5567],{"class":5524},[3143,5672,3580],{"class":3456},[3143,5674,5675],{"class":5536},"Build",[3143,5677,5678],{"class":3456},"();\n",[3143,5680,5681,5684,5686,5689],{"class":3145,"line":3213},[3143,5682,5683],{"class":5524},"app",[3143,5685,3580],{"class":3456},[3143,5687,5688],{"class":5536},"Run",[3143,5690,5678],{"class":3456},[3114,5692,5693],{},[3118,5694,5695],{},"ConfigMap для frontend:",[3133,5697,5699],{"className":3443,"code":5698,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: frontend-config\ndata:\n  ApiUrl: \"http://api-service\"  # DNS-ім'я Service\n",[3140,5700,5701,5709,5718,5724,5733,5740],{"__ignoreMap":3138},[3143,5702,5703,5705,5707],{"class":3145,"line":3146},[3143,5704,4039],{"class":3452},[3143,5706,3516],{"class":3456},[3143,5708,4044],{"class":3479},[3143,5710,5711,5713,5715],{"class":3145,"line":3152},[3143,5712,4049],{"class":3452},[3143,5714,3516],{"class":3456},[3143,5716,5717],{"class":3479},"ConfigMap\n",[3143,5719,5720,5722],{"class":3145,"line":3158},[3143,5721,4059],{"class":3452},[3143,5723,3457],{"class":3456},[3143,5725,5726,5728,5730],{"class":3145,"line":3164},[3143,5727,4066],{"class":3452},[3143,5729,3516],{"class":3456},[3143,5731,5732],{"class":3479},"frontend-config\n",[3143,5734,5735,5738],{"class":3145,"line":3171},[3143,5736,5737],{"class":3452},"data",[3143,5739,3457],{"class":3456},[3143,5741,5742,5745,5747,5749],{"class":3145,"line":3177},[3143,5743,5744],{"class":3452},"  ApiUrl",[3143,5746,3516],{"class":3456},[3143,5748,5584],{"class":3529},[3143,5750,5751],{"class":4245},"  # DNS-ім'я Service\n",[3582,5753],{},[3122,5755,5757],{"id":5756},"_2-nodeport","2. NodePort",[3114,5759,5760,5761,5764,5765,5768],{},"Тип сервісу, який відкриває певний фіксований порт (у діапазоні ",[3140,5762,5763],{},"30000-32767",") на ",[3118,5766,5767],{},"абсолютно кожному сервері (вузлі/node)"," вашого Kubernetes-кластера. Будь-який зовнішній трафік, що приходить на цей порт будь-якого сервера, автоматично перенаправляється на ваші Pod'и.",[3387,5770,5771,5776],{},[3390,5772,5773,5775],{},[3118,5774,5072],{}," Це схоже на виділений домофонний код у кожному під'їзді одного великого житлового комплексу. У який би під'їзд ви не підійшли (Node IP), якщо ви наберете цей спеціальний код (NodePort), дзвінок піде в ту саму конкретну квартиру (ваш Pod).",[3390,5777,5778,5780,5781,5783,5784,5787,5788,5791],{},[3118,5779,5078],{}," Уявіть, що ви запустили веб-сайт у локальному кластері Minikube на вашому комп'ютері і хочете показати його колезі в офісі. Оскільки IP-адреси Pod'ів є внутрішніми для кластера, колега не зможе зайти на сайт. Якщо ви створите сервіс із типом ",[3140,5782,4425],{}," та вкажете ",[3140,5785,5786],{},"nodePort: 32000",", ваш сайт стане доступним за адресою комп'ютера у локальній мережі: наприклад, ",[3140,5789,5790],{},"http://192.168.1.150:32000",". Будь-яка Node кластера візьме цей запит і перенаправить його до потрібного контейнера.",[3114,5793,5794],{},[3118,5795,5091],{},[3133,5797,5799],{"className":3443,"code":5798,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: api-service\nspec:\n  type: NodePort\n  selector:\n    app: api\n  ports:\n    - port: 80\n      targetPort: 8080\n      nodePort: 30080  # Опціонально, Kubernetes виділить автоматично (30000-32767)\n",[3140,5800,5801,5809,5817,5823,5831,5837,5846,5852,5860,5866,5876,5884],{"__ignoreMap":3138},[3143,5802,5803,5805,5807],{"class":3145,"line":3146},[3143,5804,4039],{"class":3452},[3143,5806,3516],{"class":3456},[3143,5808,4044],{"class":3479},[3143,5810,5811,5813,5815],{"class":3145,"line":3152},[3143,5812,4049],{"class":3452},[3143,5814,3516],{"class":3456},[3143,5816,4054],{"class":3479},[3143,5818,5819,5821],{"class":3145,"line":3158},[3143,5820,4059],{"class":3452},[3143,5822,3457],{"class":3456},[3143,5824,5825,5827,5829],{"class":3145,"line":3164},[3143,5826,4066],{"class":3452},[3143,5828,3516],{"class":3456},[3143,5830,4071],{"class":3479},[3143,5832,5833,5835],{"class":3145,"line":3171},[3143,5834,4086],{"class":3452},[3143,5836,3457],{"class":3456},[3143,5838,5839,5841,5843],{"class":3145,"line":3177},[3143,5840,4159],{"class":3452},[3143,5842,3516],{"class":3456},[3143,5844,5845],{"class":3479},"NodePort\n",[3143,5847,5848,5850],{"class":3145,"line":3183},[3143,5849,4093],{"class":3452},[3143,5851,3457],{"class":3456},[3143,5853,5854,5856,5858],{"class":3145,"line":3189},[3143,5855,4100],{"class":3452},[3143,5857,3516],{"class":3456},[3143,5859,4105],{"class":3479},[3143,5861,5862,5864],{"class":3145,"line":3195},[3143,5863,4110],{"class":3452},[3143,5865,3457],{"class":3456},[3143,5867,5868,5870,5872,5874],{"class":3145,"line":3201},[3143,5869,4117],{"class":3456},[3143,5871,4338],{"class":3452},[3143,5873,3516],{"class":3456},[3143,5875,4144],{"class":3673},[3143,5877,5878,5880,5882],{"class":3145,"line":3207},[3143,5879,4149],{"class":3452},[3143,5881,3516],{"class":3456},[3143,5883,4154],{"class":3673},[3143,5885,5886,5889,5891,5894],{"class":3145,"line":3213},[3143,5887,5888],{"class":3452},"      nodePort",[3143,5890,3516],{"class":3456},[3143,5892,5893],{"class":3673},"30080",[3143,5895,5896],{"class":4245},"  # Опціонально, Kubernetes виділить автоматично (30000-32767)\n",[3114,5898,5899],{},[3118,5900,5186],{},[3542,5902,5903,5906,5915],{},[3390,5904,5905],{},"Kubernetes виділяє ClusterIP (як у ClusterIP Service)",[3390,5907,5908,5909,5912,5913,4002],{},"Kubernetes відкриває порт на ",[3118,5910,5911],{},"кожному вузлі"," кластера (наприклад, ",[3140,5914,5893],{},[3390,5916,5917,5918,5921],{},"Трафік на ",[3140,5919,5920],{},"\u003CNodeIP>:30080"," перенаправляється на Service, який перенаправляє на Pod",[3114,5923,5924],{},[3118,5925,5211],{},[3130,5927,5928],{},[3133,5929,5931],{"className":3135,"code":5930,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Зовнішній користувач\" as user\n\npackage \"Kubernetes Cluster\" {\n    component \"Node 1\\n192.168.1.10\" as node1 #e3f2fd {\n        [NodePort: 30080]\n    }\n    \n    component \"Node 2\\n192.168.1.11\" as node2 #e3f2fd {\n        [NodePort: 30080]\n    }\n    \n    component \"Service\\napi-service\" as svc #fff3e0 {\n        [ClusterIP: 10.96.0.10]\n        [NodePort: 30080]\n    }\n    \n    package \"API Pods\" #e8f5e9 {\n        component \"Pod 1\\n10.244.1.10:8080\" as p1\n        component \"Pod 2\\n10.244.1.11:8080\" as p2\n    }\n}\n\nuser --> node1 : GET http://192.168.1.10:30080/todos\nuser --> node2 : GET http://192.168.1.11:30080/todos\n\nnode1 --> svc\nnode2 --> svc\n\nsvc --> p1\nsvc --> p2\n\nnote right of node1\n    Кожен вузол слухає\n    на порту 30080\n    та перенаправляє\n    на Service\nend note\n\nnote bottom of user\n    Користувач може звертатись\n    до будь-якого вузла на порту 30080\nend note\n\n@enduml\n",[3140,5932,5933,5937,5941,5945,5949,5954,5958,5962,5967,5972,5976,5980,5985,5989,5993,5997,6001,6005,6009,6013,6017,6021,6025,6029,6033,6037,6041,6046,6051,6055,6060,6065,6069,6073,6077,6081,6086,6091,6096,6101,6106,6110,6114,6118,6123,6128,6132,6136],{"__ignoreMap":3138},[3143,5934,5935],{"class":3145,"line":3146},[3143,5936,3149],{},[3143,5938,5939],{"class":3145,"line":3152},[3143,5940,3155],{},[3143,5942,5943],{"class":3145,"line":3158},[3143,5944,3161],{},[3143,5946,5947],{"class":3145,"line":3164},[3143,5948,3168],{"emptyLinePlaceholder":3167},[3143,5950,5951],{"class":3145,"line":3171},[3143,5952,5953],{},"actor \"Зовнішній користувач\" as user\n",[3143,5955,5956],{"class":3145,"line":3177},[3143,5957,3168],{"emptyLinePlaceholder":3167},[3143,5959,5960],{"class":3145,"line":3183},[3143,5961,3174],{},[3143,5963,5964],{"class":3145,"line":3189},[3143,5965,5966],{},"    component \"Node 1\\n192.168.1.10\" as node1 #e3f2fd {\n",[3143,5968,5969],{"class":3145,"line":3195},[3143,5970,5971],{},"        [NodePort: 30080]\n",[3143,5973,5974],{"class":3145,"line":3201},[3143,5975,3198],{},[3143,5977,5978],{"class":3145,"line":3207},[3143,5979,3204],{},[3143,5981,5982],{"class":3145,"line":3213},[3143,5983,5984],{},"    component \"Node 2\\n192.168.1.11\" as node2 #e3f2fd {\n",[3143,5986,5987],{"class":3145,"line":3219},[3143,5988,5971],{},[3143,5990,5991],{"class":3145,"line":3225},[3143,5992,3198],{},[3143,5994,5995],{"class":3145,"line":3231},[3143,5996,3204],{},[3143,5998,5999],{"class":3145,"line":3236},[3143,6000,5252],{},[3143,6002,6003],{"class":3145,"line":3242},[3143,6004,3721],{},[3143,6006,6007],{"class":3145,"line":3247},[3143,6008,5971],{},[3143,6010,6011],{"class":3145,"line":3253},[3143,6012,3198],{},[3143,6014,6015],{"class":3145,"line":3259},[3143,6016,3204],{},[3143,6018,6019],{"class":3145,"line":3265},[3143,6020,5273],{},[3143,6022,6023],{"class":3145,"line":3270},[3143,6024,5278],{},[3143,6026,6027],{"class":3145,"line":3276},[3143,6028,5283],{},[3143,6030,6031],{"class":3145,"line":3282},[3143,6032,3198],{},[3143,6034,6035],{"class":3145,"line":3288},[3143,6036,3239],{},[3143,6038,6039],{"class":3145,"line":3293},[3143,6040,3168],{"emptyLinePlaceholder":3167},[3143,6042,6043],{"class":3145,"line":3299},[3143,6044,6045],{},"user --> node1 : GET http://192.168.1.10:30080/todos\n",[3143,6047,6048],{"class":3145,"line":3305},[3143,6049,6050],{},"user --> node2 : GET http://192.168.1.11:30080/todos\n",[3143,6052,6053],{"class":3145,"line":3311},[3143,6054,3168],{"emptyLinePlaceholder":3167},[3143,6056,6057],{"class":3145,"line":3317},[3143,6058,6059],{},"node1 --> svc\n",[3143,6061,6062],{"class":3145,"line":3323},[3143,6063,6064],{},"node2 --> svc\n",[3143,6066,6067],{"class":3145,"line":3328},[3143,6068,3168],{"emptyLinePlaceholder":3167},[3143,6070,6071],{"class":3145,"line":3334},[3143,6072,5319],{},[3143,6074,6075],{"class":3145,"line":3340},[3143,6076,5324],{},[3143,6078,6079],{"class":3145,"line":3346},[3143,6080,3168],{"emptyLinePlaceholder":3167},[3143,6082,6083],{"class":3145,"line":3352},[3143,6084,6085],{},"note right of node1\n",[3143,6087,6088],{"class":3145,"line":3357},[3143,6089,6090],{},"    Кожен вузол слухає\n",[3143,6092,6093],{"class":3145,"line":3362},[3143,6094,6095],{},"    на порту 30080\n",[3143,6097,6098],{"class":3145,"line":3869},[3143,6099,6100],{},"    та перенаправляє\n",[3143,6102,6103],{"class":3145,"line":3875},[3143,6104,6105],{},"    на Service\n",[3143,6107,6108],{"class":3145,"line":3881},[3143,6109,3320],{},[3143,6111,6112],{"class":3145,"line":3887},[3143,6113,3168],{"emptyLinePlaceholder":3167},[3143,6115,6116],{"class":3145,"line":3893},[3143,6117,5369],{},[3143,6119,6120],{"class":3145,"line":3899},[3143,6121,6122],{},"    Користувач може звертатись\n",[3143,6124,6125],{"class":3145,"line":3904},[3143,6126,6127],{},"    до будь-якого вузла на порту 30080\n",[3143,6129,6130],{"class":3145,"line":3909},[3143,6131,3320],{},[3143,6133,6134],{"class":3145,"line":3915},[3143,6135,3168],{"emptyLinePlaceholder":3167},[3143,6137,6138],{"class":3145,"line":3921},[3143,6139,3365],{},[3114,6141,6142],{},[3118,6143,6144],{},"Діапазон NodePort:",[3114,6146,6147,6148,6150],{},"За замовчуванням Kubernetes виділяє порти з діапазону ",[3118,6149,5763],{},". Це можна змінити у конфігурації API Server, але не рекомендується.",[3114,6152,6153],{},[3118,6154,5401],{},[3387,6156,6157,6160,6163,6166],{},[3390,6158,6159],{},"Локальна розробка (Minikube, kind) — швидкий доступ до сервісу ззовні",[3390,6161,6162],{},"Тестування — не потрібен зовнішній load balancer",[3390,6164,6165],{},"On-premise кластери без підтримки LoadBalancer",[3390,6167,6168],{},"Debugging — тимчасовий доступ до сервісу",[3114,6170,6171],{},[3118,6172,6173],{},"Коли НЕ використовувати:",[3387,6175,6176,6179,6182],{},[3390,6177,6178],{},"Production у хмарі — використовуйте LoadBalancer або Ingress",[3390,6180,6181],{},"Багато сервісів — NodePort займає порти на всіх вузлах",[3390,6183,6184],{},"Потрібен HTTPS — NodePort не підтримує TLS termination",[3114,6186,6187],{},[3118,6188,6189],{},"Приклад використання:",[6191,6192,6194,6203,6213,6221,6224,6231,6240,6244,6248,6251,6258,6267,6271,6274,6281,6290],"terminal-preview",{"title":6193},"Доступ до NodePort Service",[6195,6196,6198],"div",{"className":6197},[3145],[3143,6199,6202],{"className":6200},[6201],"opacity-40","# Створення NodePort Service",[6195,6204,6206,4793,6210],{"className":6205},[3145],[3143,6207,6209],{"className":6208},[6201],"$",[3118,6211,6212],{},"kubectl apply -f api-nodeport-service.yaml",[6195,6214,6216],{"className":6215},[3145],[3143,6217,6220],{"className":6218},[6219],"text-green-400","service/api-service created",[6195,6222],{"className":6223},[3145],[6195,6225,6227],{"className":6226},[3145],[3143,6228,6230],{"className":6229},[6201],"# Перегляд Service",[6195,6232,6234,4793,6237],{"className":6233},[3145],[3143,6235,6209],{"className":6236},[6201],[3118,6238,6239],{},"kubectl get service api-service",[6195,6241,6243],{"className":6242},[3145],"NAME          TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE",[6195,6245,6247],{"className":6246},[3145],"api-service   NodePort   10.96.0.10    \u003Cnone>        80:30080/TCP   10s",[6195,6249],{"className":6250},[3145],[6195,6252,6254],{"className":6253},[3145],[3143,6255,6257],{"className":6256},[6201],"# Отримання IP вузла (Minikube)",[6195,6259,6261,4793,6264],{"className":6260},[3145],[3143,6262,6209],{"className":6263},[6201],[3118,6265,6266],{},"minikube ip",[6195,6268,6270],{"className":6269},[3145],"192.168.49.2",[6195,6272],{"className":6273},[3145],[6195,6275,6277],{"className":6276},[3145],[3143,6278,6280],{"className":6279},[6201],"# Доступ до Service ззовні",[6195,6282,6284,4793,6287],{"className":6283},[3145],[3143,6285,6209],{"className":6286},[6201],[3118,6288,6289],{},"curl http://192.168.49.2:30080/todos",[6195,6291,6293],{"className":6292},[3145],"{\"todos\":[],\"count\":0}",[6295,6296,6297,6302,6305,6323],"tip",{},[3114,6298,6299],{},[3118,6300,6301],{},"Minikube service команда:",[3114,6303,6304],{},"Minikube надає зручну команду для відкриття NodePort Service у браузері:",[3133,6306,6310],{"className":6307,"code":6308,"language":6309,"meta":3138,"style":3138},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","minikube service api-service\n","bash",[3140,6311,6312],{"__ignoreMap":3138},[3143,6313,6314,6317,6320],{"class":3145,"line":3146},[3143,6315,6316],{"class":5536},"minikube",[3143,6318,6319],{"class":3529}," service",[3143,6321,6322],{"class":3529}," api-service\n",[3114,6324,6325,6326,5497],{},"Це автоматично відкриє браузер з правильною URL (",[3140,6327,6328],{},"http://\u003Cminikube-ip>:\u003Cnode-port>",[3582,6330],{},[3122,6332,6334],{"id":6333},"_3-loadbalancer","3. LoadBalancer",[3114,6336,6337],{},"Тип сервісу, який інтегрується з хмарним провайдером (наприклад AWS, Google Cloud, Azure) і автоматично замовляє у нього реальний, зовнішній мережевий балансувальник навантаження. Провайдер виділяє публічну статичну IP-адресу, і весь трафік з інтернету через цю IP надходить безпосередньо у ваш Kubernetes-кластер.",[3387,6339,6340,6345],{},[3390,6341,6342,6344],{},[3118,6343,5072],{}," Це як найняти професійного швейцара чи хостес на вході до ресторану. Клієнтам (користувачам в інтернеті) не потрібно шукати службові входи чи дзвонити на внутрішні номери — вони просто приходять на центральний вхід (публічний IP), а швейцар (Load Balancer) сам бережно проводить їх за потрібний вільний столик (Pod) всередині залу.",[3390,6346,6347,6349,6350,6352,6353,6356,6357,6360],{},[3118,6348,5078],{}," Ви розгорнули свій інтернет-магазин у хмарі AWS. Якщо ви створите сервіс типу ",[3140,6351,4431],{},", AWS автоматично запустить для вас сервіс Classic/Network Load Balancer та надасть публічну адресу (наприклад, ",[3140,6354,6355],{},"http://a84729...us-east-1.elb.amazonaws.com"," або статичний IP ",[3140,6358,6359],{},"1.2.3.4","). Тепер будь-який користувач у світі може зайти на цей сайт. Балансувальник прийме запит, рівномірно розподілить його між працюючими репліками вашого застосунку і забезпечить відмовостійкість: якщо один із серверів (Node) раптово вимкнеться, балансувальник миттєво перенаправить трафік на інші робочі машини.",[3114,6362,6363],{},[3118,6364,5091],{},[3133,6366,6368],{"className":3443,"code":6367,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: api-service\nspec:\n  type: LoadBalancer\n  selector:\n    app: api\n  ports:\n    - port: 80\n      targetPort: 8080\n",[3140,6369,6370,6378,6386,6392,6400,6406,6415,6421,6429,6435,6445],{"__ignoreMap":3138},[3143,6371,6372,6374,6376],{"class":3145,"line":3146},[3143,6373,4039],{"class":3452},[3143,6375,3516],{"class":3456},[3143,6377,4044],{"class":3479},[3143,6379,6380,6382,6384],{"class":3145,"line":3152},[3143,6381,4049],{"class":3452},[3143,6383,3516],{"class":3456},[3143,6385,4054],{"class":3479},[3143,6387,6388,6390],{"class":3145,"line":3158},[3143,6389,4059],{"class":3452},[3143,6391,3457],{"class":3456},[3143,6393,6394,6396,6398],{"class":3145,"line":3164},[3143,6395,4066],{"class":3452},[3143,6397,3516],{"class":3456},[3143,6399,4071],{"class":3479},[3143,6401,6402,6404],{"class":3145,"line":3171},[3143,6403,4086],{"class":3452},[3143,6405,3457],{"class":3456},[3143,6407,6408,6410,6412],{"class":3145,"line":3177},[3143,6409,4159],{"class":3452},[3143,6411,3516],{"class":3456},[3143,6413,6414],{"class":3479},"LoadBalancer\n",[3143,6416,6417,6419],{"class":3145,"line":3183},[3143,6418,4093],{"class":3452},[3143,6420,3457],{"class":3456},[3143,6422,6423,6425,6427],{"class":3145,"line":3189},[3143,6424,4100],{"class":3452},[3143,6426,3516],{"class":3456},[3143,6428,4105],{"class":3479},[3143,6430,6431,6433],{"class":3145,"line":3195},[3143,6432,4110],{"class":3452},[3143,6434,3457],{"class":3456},[3143,6436,6437,6439,6441,6443],{"class":3145,"line":3201},[3143,6438,4117],{"class":3456},[3143,6440,4338],{"class":3452},[3143,6442,3516],{"class":3456},[3143,6444,4144],{"class":3673},[3143,6446,6447,6449,6451],{"class":3145,"line":3207},[3143,6448,4149],{"class":3452},[3143,6450,3516],{"class":3456},[3143,6452,4154],{"class":3673},[3114,6454,6455],{},[3118,6456,5186],{},[3542,6458,6459,6462,6465,6468],{},[3390,6460,6461],{},"Kubernetes створює ClusterIP Service (внутрішній доступ)",[3390,6463,6464],{},"Kubernetes створює NodePort (доступ через вузли)",[3390,6466,6467],{},"Kubernetes запитує у хмарного провайдера створення зовнішнього load balancer",[3390,6469,6470],{},"Load balancer отримує публічну IP-адресу та перенаправляє трафік на NodePort",[3114,6472,6473],{},[3118,6474,5211],{},[3130,6476,6477],{},[3133,6478,6480],{"className":3135,"code":6479,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Зовнішній користувач\" as user\n\ncloud \"Cloud Provider\" {\n    component \"Load Balancer\\n34.123.45.67\" as lb #e3f2fd\n}\n\npackage \"Kubernetes Cluster\" {\n    component \"Node 1\\n10.0.1.10\" as node1 #fff3e0 {\n        [NodePort: 31234]\n    }\n    \n    component \"Node 2\\n10.0.1.11\" as node2 #fff3e0 {\n        [NodePort: 31234]\n    }\n    \n    component \"Service\\napi-service\" as svc #e8f5e9 {\n        [ClusterIP: 10.96.0.10]\n        [Type: LoadBalancer]\n    }\n    \n    package \"API Pods\" {\n        component \"Pod 1\" as p1\n        component \"Pod 2\" as p2\n        component \"Pod 3\" as p3\n    }\n}\n\nuser --> lb : GET http://34.123.45.67/todos\nlb --> node1 : Балансування\nlb --> node2 : Балансування\n\nnode1 --> svc\nnode2 --> svc\n\nsvc --> p1\nsvc --> p2\nsvc --> p3\n\nnote right of lb\n    Load Balancer:\n    - Публічна IP-адреса\n    - Health checks\n    - SSL termination (опціонально)\n    - DDoS protection\nend note\n\nnote right of svc\n    Service автоматично\n    отримує EXTERNAL-IP\n    від load balancer\nend note\n\n@enduml\n",[3140,6481,6482,6486,6490,6494,6498,6502,6506,6511,6516,6520,6524,6528,6533,6538,6542,6546,6551,6555,6559,6563,6568,6572,6577,6581,6585,6590,6595,6600,6605,6609,6613,6617,6622,6627,6632,6636,6640,6644,6648,6652,6656,6660,6664,6669,6674,6679,6684,6689,6694,6698,6702,6706,6711,6716,6721,6725,6729],{"__ignoreMap":3138},[3143,6483,6484],{"class":3145,"line":3146},[3143,6485,3149],{},[3143,6487,6488],{"class":3145,"line":3152},[3143,6489,3155],{},[3143,6491,6492],{"class":3145,"line":3158},[3143,6493,3161],{},[3143,6495,6496],{"class":3145,"line":3164},[3143,6497,3168],{"emptyLinePlaceholder":3167},[3143,6499,6500],{"class":3145,"line":3171},[3143,6501,5953],{},[3143,6503,6504],{"class":3145,"line":3177},[3143,6505,3168],{"emptyLinePlaceholder":3167},[3143,6507,6508],{"class":3145,"line":3183},[3143,6509,6510],{},"cloud \"Cloud Provider\" {\n",[3143,6512,6513],{"class":3145,"line":3189},[3143,6514,6515],{},"    component \"Load Balancer\\n34.123.45.67\" as lb #e3f2fd\n",[3143,6517,6518],{"class":3145,"line":3195},[3143,6519,3239],{},[3143,6521,6522],{"class":3145,"line":3201},[3143,6523,3168],{"emptyLinePlaceholder":3167},[3143,6525,6526],{"class":3145,"line":3207},[3143,6527,3174],{},[3143,6529,6530],{"class":3145,"line":3213},[3143,6531,6532],{},"    component \"Node 1\\n10.0.1.10\" as node1 #fff3e0 {\n",[3143,6534,6535],{"class":3145,"line":3219},[3143,6536,6537],{},"        [NodePort: 31234]\n",[3143,6539,6540],{"class":3145,"line":3225},[3143,6541,3198],{},[3143,6543,6544],{"class":3145,"line":3231},[3143,6545,3204],{},[3143,6547,6548],{"class":3145,"line":3236},[3143,6549,6550],{},"    component \"Node 2\\n10.0.1.11\" as node2 #fff3e0 {\n",[3143,6552,6553],{"class":3145,"line":3242},[3143,6554,6537],{},[3143,6556,6557],{"class":3145,"line":3247},[3143,6558,3198],{},[3143,6560,6561],{"class":3145,"line":3253},[3143,6562,3204],{},[3143,6564,6565],{"class":3145,"line":3259},[3143,6566,6567],{},"    component \"Service\\napi-service\" as svc #e8f5e9 {\n",[3143,6569,6570],{"class":3145,"line":3265},[3143,6571,3721],{},[3143,6573,6574],{"class":3145,"line":3270},[3143,6575,6576],{},"        [Type: LoadBalancer]\n",[3143,6578,6579],{"class":3145,"line":3276},[3143,6580,3198],{},[3143,6582,6583],{"class":3145,"line":3282},[3143,6584,3204],{},[3143,6586,6587],{"class":3145,"line":3288},[3143,6588,6589],{},"    package \"API Pods\" {\n",[3143,6591,6592],{"class":3145,"line":3293},[3143,6593,6594],{},"        component \"Pod 1\" as p1\n",[3143,6596,6597],{"class":3145,"line":3299},[3143,6598,6599],{},"        component \"Pod 2\" as p2\n",[3143,6601,6602],{"class":3145,"line":3305},[3143,6603,6604],{},"        component \"Pod 3\" as p3\n",[3143,6606,6607],{"class":3145,"line":3311},[3143,6608,3198],{},[3143,6610,6611],{"class":3145,"line":3317},[3143,6612,3239],{},[3143,6614,6615],{"class":3145,"line":3323},[3143,6616,3168],{"emptyLinePlaceholder":3167},[3143,6618,6619],{"class":3145,"line":3328},[3143,6620,6621],{},"user --> lb : GET http://34.123.45.67/todos\n",[3143,6623,6624],{"class":3145,"line":3334},[3143,6625,6626],{},"lb --> node1 : Балансування\n",[3143,6628,6629],{"class":3145,"line":3340},[3143,6630,6631],{},"lb --> node2 : Балансування\n",[3143,6633,6634],{"class":3145,"line":3346},[3143,6635,3168],{"emptyLinePlaceholder":3167},[3143,6637,6638],{"class":3145,"line":3352},[3143,6639,6059],{},[3143,6641,6642],{"class":3145,"line":3357},[3143,6643,6064],{},[3143,6645,6646],{"class":3145,"line":3362},[3143,6647,3168],{"emptyLinePlaceholder":3167},[3143,6649,6650],{"class":3145,"line":3869},[3143,6651,5319],{},[3143,6653,6654],{"class":3145,"line":3875},[3143,6655,5324],{},[3143,6657,6658],{"class":3145,"line":3881},[3143,6659,5329],{},[3143,6661,6662],{"class":3145,"line":3887},[3143,6663,3168],{"emptyLinePlaceholder":3167},[3143,6665,6666],{"class":3145,"line":3893},[3143,6667,6668],{},"note right of lb\n",[3143,6670,6671],{"class":3145,"line":3899},[3143,6672,6673],{},"    Load Balancer:\n",[3143,6675,6676],{"class":3145,"line":3904},[3143,6677,6678],{},"    - Публічна IP-адреса\n",[3143,6680,6681],{"class":3145,"line":3909},[3143,6682,6683],{},"    - Health checks\n",[3143,6685,6686],{"class":3145,"line":3915},[3143,6687,6688],{},"    - SSL termination (опціонально)\n",[3143,6690,6691],{"class":3145,"line":3921},[3143,6692,6693],{},"    - DDoS protection\n",[3143,6695,6696],{"class":3145,"line":3927},[3143,6697,3320],{},[3143,6699,6700],{"class":3145,"line":3933},[3143,6701,3168],{"emptyLinePlaceholder":3167},[3143,6703,6704],{"class":3145,"line":3938},[3143,6705,3872],{},[3143,6707,6708],{"class":3145,"line":3943},[3143,6709,6710],{},"    Service автоматично\n",[3143,6712,6713],{"class":3145,"line":3949},[3143,6714,6715],{},"    отримує EXTERNAL-IP\n",[3143,6717,6718],{"class":3145,"line":3955},[3143,6719,6720],{},"    від load balancer\n",[3143,6722,6723],{"class":3145,"line":3961},[3143,6724,3320],{},[3143,6726,6727],{"class":3145,"line":3967},[3143,6728,3168],{"emptyLinePlaceholder":3167},[3143,6730,6731],{"class":3145,"line":3972},[3143,6732,3365],{},[3114,6734,6735],{},[3118,6736,5401],{},[3387,6738,6739,6742,6745],{},[3390,6740,6741],{},"Production у хмарі (AWS, GCP, Azure)",[3390,6743,6744],{},"Потрібен публічний доступ до сервісу",[3390,6746,6747],{},"Один сервіс на один load balancer (для багатьох сервісів використовуйте Ingress)",[3114,6749,6750],{},[3118,6751,6173],{},[3387,6753,6754,6757,6760],{},[3390,6755,6756],{},"Локальна розробка (Minikube не підтримує LoadBalancer, використовуйте NodePort)",[3390,6758,6759],{},"Багато сервісів — кожен LoadBalancer коштує грошей (використовуйте Ingress)",[3390,6761,6165],{},[3114,6763,6764],{},[3118,6765,6189],{},[6191,6767,6769,6778,6784,6787,6794,6802,6806,6810,6813,6820,6828,6832,6836,6839,6846,6855],{"title":6768},"LoadBalancer Service",[6195,6770,6772,4793,6775],{"className":6771},[3145],[3143,6773,6209],{"className":6774},[6201],[3118,6776,6777],{},"kubectl apply -f api-loadbalancer-service.yaml",[6195,6779,6781],{"className":6780},[3145],[3143,6782,6220],{"className":6783},[6219],[6195,6785],{"className":6786},[3145],[6195,6788,6790],{"className":6789},[3145],[3143,6791,6793],{"className":6792},[6201],"# Перегляд Service (EXTERNAL-IP спочатку \u003Cpending>)",[6195,6795,6797,4793,6800],{"className":6796},[3145],[3143,6798,6209],{"className":6799},[6201],[3118,6801,6239],{},[6195,6803,6805],{"className":6804},[3145],"NAME          TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE",[6195,6807,6809],{"className":6808},[3145],"api-service   LoadBalancer   10.96.0.10    \u003Cpending>     80:31234/TCP   5s",[6195,6811],{"className":6812},[3145],[6195,6814,6816],{"className":6815},[3145],[3143,6817,6819],{"className":6818},[6201],"# Через 1-2 хвилини load balancer готовий",[6195,6821,6823,4793,6826],{"className":6822},[3145],[3143,6824,6209],{"className":6825},[6201],[3118,6827,6239],{},[6195,6829,6831],{"className":6830},[3145],"NAME          TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE",[6195,6833,6835],{"className":6834},[3145],"api-service   LoadBalancer   10.96.0.10    34.123.45.67    80:31234/TCP   2m",[6195,6837],{"className":6838},[3145],[6195,6840,6842],{"className":6841},[3145],[3143,6843,6845],{"className":6844},[6201],"# Доступ через публічну IP",[6195,6847,6849,4793,6852],{"className":6848},[3145],[3143,6850,6209],{"className":6851},[6201],[3118,6853,6854],{},"curl http://34.123.45.67/todos",[6195,6856,6293],{"className":6857},[3145],[3602,6859,6860,6865,6872,6885,6897],{},[3114,6861,6862],{},[3118,6863,6864],{},"LoadBalancer у Minikube:",[3114,6866,6867,6868,6871],{},"Minikube не підтримує LoadBalancer Service нативно. Service залишається у стані ",[3140,6869,6870],{},"\u003Cpending>",". Для локальної розробки використовуйте:",[3542,6873,6874,6879],{},[3390,6875,6876,6878],{},[3118,6877,4425],{}," — найпростіший спосіб",[3390,6880,6881,6884],{},[3118,6882,6883],{},"minikube tunnel"," — емулює LoadBalancer:",[3133,6886,6888],{"className":6307,"code":6887,"language":6309,"meta":3138,"style":3138},"minikube tunnel\n",[3140,6889,6890],{"__ignoreMap":3138},[3143,6891,6892,6894],{"class":3145,"line":3146},[3143,6893,6316],{"class":5536},[3143,6895,6896],{"class":3529}," tunnel\n",[3114,6898,6899,6900,6903],{},"Це створює мережевий тунель та призначає EXTERNAL-IP з діапазону ",[3140,6901,6902],{},"127.0.0.1/8",". Команда має працювати постійно у фоні.",[3114,6905,6906],{},[3118,6907,6908],{},"Вартість LoadBalancer:",[3114,6910,6911],{},"Кожен LoadBalancer Service створює окремий load balancer у хмарі, що коштує грошей:",[3387,6913,6914,6920,6926],{},[3390,6915,6916,6919],{},[3118,6917,6918],{},"AWS ELB:"," ~$16-25/місяць + трафік",[3390,6921,6922,6925],{},[3118,6923,6924],{},"GCP Load Balancer:"," ~$18/місяць + трафік",[3390,6927,6928,6925],{},[3118,6929,6930],{},"Azure Load Balancer:",[3114,6932,6933,6934,6937],{},"Якщо у вас 10 сервісів, це $180-250/місяць лише за load balancers. Для економії використовуйте ",[3118,6935,6936],{},"Ingress"," (один load balancer для багатьох сервісів).",[3582,6939],{},[3122,6941,6943],{"id":6942},"_4-externalname","4. ExternalName",[3114,6945,6946,6947,6950],{},"Особливий тип сервісу, який виступає в ролі внутрішнього DNS-аліасу (псевдоніма) і перенаправляє запити на якесь ",[3118,6948,6949],{},"зовнішнє доменне ім'я"," (поза межами вашого кластера). Він не виділяє жодних IP-адрес і не проксує трафік самостійно — замість цього він просто повертає стандартний DNS CNAME-запис.",[3387,6952,6953,6958],{},[3390,6954,6955,6957],{},[3118,6956,5072],{}," Це внутрішня переадресація чи закладка в телефонній книзі вашої компанії. Замість того, щоб вчити кожного співробітника набирати довгий складний номер зовнішнього партнера, ви створюєте для нього внутрішній короткий псевдонім. Якщо партнер зміниться, ви просто оновить запис в одному місці (у маніфесті сервісу), а код ваших додатків залишиться незмінним.",[3390,6959,6960,6962,6963,6966,6967,6969,6970,3596,6973,6976,6977,6980,6981,6984],{},[3118,6961,5078],{}," Ваша програма працює в кластері Kubernetes, але використовує сторонню базу даних MongoDB Atlas, розміщену на зовнішньому хостингу за адресою ",[3140,6964,6965],{},"prod-db-948a.mongodb.net",". Замість того, щоб зашивати це довге і нестабільне ім'я прямо в конфігураційні файли вашого коду, ви створюєте сервіс типу ",[3140,6968,4437],{}," із назвою ",[3140,6971,6972],{},"my-database",[3140,6974,6975],{},"externalName: prod-db-948a.mongodb.net",". Тепер у вашому .NET-коді рядок підключення буде виглядати максимально просто: ",[3140,6978,6979],{},"mongodb://my-database",". Якщо ви вирішите змінити базу даних на інший сервер або переїдете на іншого провайдера, ви просто зміните значення ",[3140,6982,6983],{},"externalName"," в одному YAML-маніфесті, не перезбираючи та не перезапускаючи сам додаток.",[3114,6986,6987],{},[3118,6988,5091],{},[3133,6990,6992],{"className":3443,"code":6991,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: external-api\nspec:\n  type: ExternalName\n  externalName: api.example.com\n",[3140,6993,6994,7002,7010,7016,7025,7031,7040],{"__ignoreMap":3138},[3143,6995,6996,6998,7000],{"class":3145,"line":3146},[3143,6997,4039],{"class":3452},[3143,6999,3516],{"class":3456},[3143,7001,4044],{"class":3479},[3143,7003,7004,7006,7008],{"class":3145,"line":3152},[3143,7005,4049],{"class":3452},[3143,7007,3516],{"class":3456},[3143,7009,4054],{"class":3479},[3143,7011,7012,7014],{"class":3145,"line":3158},[3143,7013,4059],{"class":3452},[3143,7015,3457],{"class":3456},[3143,7017,7018,7020,7022],{"class":3145,"line":3164},[3143,7019,4066],{"class":3452},[3143,7021,3516],{"class":3456},[3143,7023,7024],{"class":3479},"external-api\n",[3143,7026,7027,7029],{"class":3145,"line":3171},[3143,7028,4086],{"class":3452},[3143,7030,3457],{"class":3456},[3143,7032,7033,7035,7037],{"class":3145,"line":3177},[3143,7034,4159],{"class":3452},[3143,7036,3516],{"class":3456},[3143,7038,7039],{"class":3479},"ExternalName\n",[3143,7041,7042,7045,7047],{"class":3145,"line":3183},[3143,7043,7044],{"class":3452},"  externalName",[3143,7046,3516],{"class":3456},[3143,7048,7049],{"class":3479},"api.example.com\n",[3114,7051,7052],{},[3118,7053,5186],{},[3542,7055,7056,7059,7068],{},[3390,7057,7058],{},"Kubernetes НЕ створює ClusterIP",[3390,7060,7061,7062,5201,7065],{},"CoreDNS створює CNAME-запис: ",[3140,7063,7064],{},"external-api.default.svc.cluster.local",[3140,7066,7067],{},"api.example.com",[3390,7069,7070,7071,7074,7075,7077],{},"Запити до ",[3140,7072,7073],{},"external-api"," резолвяться у ",[3140,7076,7067],{}," та йдуть напряму до зовнішнього сервісу",[3114,7079,7080],{},[3118,7081,5211],{},[3130,7083,7084],{},[3133,7085,7087],{"className":3135,"code":7086,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Kubernetes Cluster\" {\n    component \"Frontend Pod\" as fe #e3f2fd\n    \n    component \"Service\\nexternal-api\" as svc #fff3e0 {\n        [Type: ExternalName]\n        [externalName: api.example.com]\n        [NO ClusterIP]\n    }\n}\n\ncloud \"Зовнішній світ\" {\n    component \"api.example.com\\n34.56.78.90\" as external #e8f5e9\n}\n\nfe --> svc : GET http://external-api/data\nsvc --> external : DNS CNAME redirect\n\nnote right of svc\n    ExternalName Service\n    не має ClusterIP\n    \n    Це просто DNS alias\n    для зовнішнього сервісу\nend note\n\nnote right of external\n    Трафік йде напряму\n    до зовнішнього сервісу,\n    без проксування через\n    Kubernetes\nend note\n\n@enduml\n",[3140,7088,7089,7093,7097,7101,7105,7109,7113,7117,7122,7127,7132,7137,7141,7145,7149,7154,7159,7163,7167,7172,7177,7181,7185,7190,7195,7199,7204,7209,7213,7217,7222,7227,7232,7237,7242,7246,7250],{"__ignoreMap":3138},[3143,7090,7091],{"class":3145,"line":3146},[3143,7092,3149],{},[3143,7094,7095],{"class":3145,"line":3152},[3143,7096,3155],{},[3143,7098,7099],{"class":3145,"line":3158},[3143,7100,3161],{},[3143,7102,7103],{"class":3145,"line":3164},[3143,7104,3168],{"emptyLinePlaceholder":3167},[3143,7106,7107],{"class":3145,"line":3171},[3143,7108,3174],{},[3143,7110,7111],{"class":3145,"line":3177},[3143,7112,5243],{},[3143,7114,7115],{"class":3145,"line":3183},[3143,7116,3204],{},[3143,7118,7119],{"class":3145,"line":3189},[3143,7120,7121],{},"    component \"Service\\nexternal-api\" as svc #fff3e0 {\n",[3143,7123,7124],{"class":3145,"line":3195},[3143,7125,7126],{},"        [Type: ExternalName]\n",[3143,7128,7129],{"class":3145,"line":3201},[3143,7130,7131],{},"        [externalName: api.example.com]\n",[3143,7133,7134],{"class":3145,"line":3207},[3143,7135,7136],{},"        [NO ClusterIP]\n",[3143,7138,7139],{"class":3145,"line":3213},[3143,7140,3198],{},[3143,7142,7143],{"class":3145,"line":3219},[3143,7144,3239],{},[3143,7146,7147],{"class":3145,"line":3225},[3143,7148,3168],{"emptyLinePlaceholder":3167},[3143,7150,7151],{"class":3145,"line":3231},[3143,7152,7153],{},"cloud \"Зовнішній світ\" {\n",[3143,7155,7156],{"class":3145,"line":3236},[3143,7157,7158],{},"    component \"api.example.com\\n34.56.78.90\" as external #e8f5e9\n",[3143,7160,7161],{"class":3145,"line":3242},[3143,7162,3239],{},[3143,7164,7165],{"class":3145,"line":3247},[3143,7166,3168],{"emptyLinePlaceholder":3167},[3143,7168,7169],{"class":3145,"line":3253},[3143,7170,7171],{},"fe --> svc : GET http://external-api/data\n",[3143,7173,7174],{"class":3145,"line":3259},[3143,7175,7176],{},"svc --> external : DNS CNAME redirect\n",[3143,7178,7179],{"class":3145,"line":3265},[3143,7180,3168],{"emptyLinePlaceholder":3167},[3143,7182,7183],{"class":3145,"line":3270},[3143,7184,3872],{},[3143,7186,7187],{"class":3145,"line":3276},[3143,7188,7189],{},"    ExternalName Service\n",[3143,7191,7192],{"class":3145,"line":3282},[3143,7193,7194],{},"    не має ClusterIP\n",[3143,7196,7197],{"class":3145,"line":3288},[3143,7198,3204],{},[3143,7200,7201],{"class":3145,"line":3293},[3143,7202,7203],{},"    Це просто DNS alias\n",[3143,7205,7206],{"class":3145,"line":3299},[3143,7207,7208],{},"    для зовнішнього сервісу\n",[3143,7210,7211],{"class":3145,"line":3305},[3143,7212,3320],{},[3143,7214,7215],{"class":3145,"line":3311},[3143,7216,3168],{"emptyLinePlaceholder":3167},[3143,7218,7219],{"class":3145,"line":3317},[3143,7220,7221],{},"note right of external\n",[3143,7223,7224],{"class":3145,"line":3323},[3143,7225,7226],{},"    Трафік йде напряму\n",[3143,7228,7229],{"class":3145,"line":3328},[3143,7230,7231],{},"    до зовнішнього сервісу,\n",[3143,7233,7234],{"class":3145,"line":3334},[3143,7235,7236],{},"    без проксування через\n",[3143,7238,7239],{"class":3145,"line":3340},[3143,7240,7241],{},"    Kubernetes\n",[3143,7243,7244],{"class":3145,"line":3346},[3143,7245,3320],{},[3143,7247,7248],{"class":3145,"line":3352},[3143,7249,3168],{"emptyLinePlaceholder":3167},[3143,7251,7252],{"class":3145,"line":3357},[3143,7253,3365],{},[3114,7255,7256],{},[3118,7257,5401],{},[3387,7259,7260,7263,7266],{},[3390,7261,7262],{},"Міграція з зовнішнього сервісу у Kubernetes — спочатку ExternalName, потім заміна на ClusterIP",[3390,7264,7265],{},"Доступ до зовнішніх API (наприклад, AWS RDS, зовнішній Redis)",[3390,7267,7268,7269,7272,7273],{},"Абстракція зовнішніх залежностей — код звертається до ",[3140,7270,7271],{},"database-service",", а не до ",[3140,7274,7275],{},"prod-db.us-east-1.rds.amazonaws.com",[3114,7277,7278],{},[3118,7279,6189],{},[3133,7281,7283],{"className":3443,"code":7282,"language":3445,"meta":3138,"style":3138},"# ExternalName для зовнішньої бази даних\napiVersion: v1\nkind: Service\nmetadata:\n  name: postgres-service\nspec:\n  type: ExternalName\n  externalName: prod-db.us-east-1.rds.amazonaws.com\n",[3140,7284,7285,7290,7298,7306,7312,7321,7327,7335],{"__ignoreMap":3138},[3143,7286,7287],{"class":3145,"line":3146},[3143,7288,7289],{"class":4245},"# ExternalName для зовнішньої бази даних\n",[3143,7291,7292,7294,7296],{"class":3145,"line":3152},[3143,7293,4039],{"class":3452},[3143,7295,3516],{"class":3456},[3143,7297,4044],{"class":3479},[3143,7299,7300,7302,7304],{"class":3145,"line":3158},[3143,7301,4049],{"class":3452},[3143,7303,3516],{"class":3456},[3143,7305,4054],{"class":3479},[3143,7307,7308,7310],{"class":3145,"line":3164},[3143,7309,4059],{"class":3452},[3143,7311,3457],{"class":3456},[3143,7313,7314,7316,7318],{"class":3145,"line":3171},[3143,7315,4066],{"class":3452},[3143,7317,3516],{"class":3456},[3143,7319,7320],{"class":3479},"postgres-service\n",[3143,7322,7323,7325],{"class":3145,"line":3177},[3143,7324,4086],{"class":3452},[3143,7326,3457],{"class":3456},[3143,7328,7329,7331,7333],{"class":3145,"line":3183},[3143,7330,4159],{"class":3452},[3143,7332,3516],{"class":3456},[3143,7334,7039],{"class":3479},[3143,7336,7337,7339,7341],{"class":3145,"line":3189},[3143,7338,7044],{"class":3452},[3143,7340,3516],{"class":3456},[3143,7342,7343],{"class":3479},"prod-db.us-east-1.rds.amazonaws.com\n",[3114,7345,7346],{},[3118,7347,7348],{},"У .NET коді:",[3133,7350,7352],{"className":5511,"code":7351,"language":5513,"meta":3138,"style":3138},"var builder = WebApplication.CreateBuilder(args);\n\n// Код звертається до Service, а не до зовнішнього DNS\nvar connectionString = builder.Configuration.GetConnectionString(\"DefaultConnection\");\n// \"Host=postgres-service;Database=mydb;Username=user;Password=pass\"\n\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseNpgsql(connectionString));\n",[3140,7353,7354,7374,7378,7383,7410,7415,7419,7446],{"__ignoreMap":3138},[3143,7355,7356,7358,7360,7362,7364,7366,7368,7370,7372],{"class":3145,"line":3146},[3143,7357,5521],{"class":5520},[3143,7359,5525],{"class":5524},[3143,7361,5528],{"class":3456},[3143,7363,5531],{"class":5524},[3143,7365,3580],{"class":3456},[3143,7367,5537],{"class":5536},[3143,7369,5540],{"class":3456},[3143,7371,5543],{"class":5524},[3143,7373,5546],{"class":3456},[3143,7375,7376],{"class":3145,"line":3152},[3143,7377,3168],{"emptyLinePlaceholder":3167},[3143,7379,7380],{"class":3145,"line":3158},[3143,7381,7382],{"class":4245},"// Код звертається до Service, а не до зовнішнього DNS\n",[3143,7384,7385,7387,7390,7392,7394,7396,7398,7400,7403,7405,7408],{"class":3145,"line":3164},[3143,7386,5521],{"class":5520},[3143,7388,7389],{"class":5524}," connectionString",[3143,7391,5528],{"class":3456},[3143,7393,5567],{"class":5524},[3143,7395,3580],{"class":3456},[3143,7397,5572],{"class":5524},[3143,7399,3580],{"class":3456},[3143,7401,7402],{"class":5536},"GetConnectionString",[3143,7404,5540],{"class":3456},[3143,7406,7407],{"class":3529},"\"DefaultConnection\"",[3143,7409,5546],{"class":3456},[3143,7411,7412],{"class":3145,"line":3171},[3143,7413,7414],{"class":4245},"// \"Host=postgres-service;Database=mydb;Username=user;Password=pass\"\n",[3143,7416,7417],{"class":3145,"line":3177},[3143,7418,3168],{"emptyLinePlaceholder":3167},[3143,7420,7421,7423,7425,7427,7429,7432,7435,7438,7441,7444],{"class":3145,"line":3183},[3143,7422,5567],{"class":5524},[3143,7424,3580],{"class":3456},[3143,7426,5600],{"class":5524},[3143,7428,3580],{"class":3456},[3143,7430,7431],{"class":5536},"AddDbContext",[3143,7433,7434],{"class":3456},"\u003C",[3143,7436,7437],{"class":5642},"AppDbContext",[3143,7439,7440],{"class":3456},">(",[3143,7442,7443],{"class":5524},"options",[3143,7445,5619],{"class":3456},[3143,7447,7448,7451,7453,7456,7458,7461],{"class":3145,"line":3189},[3143,7449,7450],{"class":5524},"    options",[3143,7452,3580],{"class":3456},[3143,7454,7455],{"class":5536},"UseNpgsql",[3143,7457,5540],{"class":3456},[3143,7459,7460],{"class":5524},"connectionString",[3143,7462,7463],{"class":3456},"));\n",[3114,7465,7466],{},[3118,7467,5038],{},[3387,7469,7470,7476,7479],{},[3390,7471,7472,7473,7475],{},"Легко змінити зовнішній endpoint — просто оновити ",[3140,7474,6983],{}," у Service",[3390,7477,7478],{},"Код не залежить від конкретного DNS-імені зовнішнього сервісу",[3390,7480,7481],{},"Можна легко мігрувати: ExternalName → ClusterIP (коли база даних переїде у Kubernetes)",[4787,7483,7484,7489,7515],{},[3114,7485,7486],{},[3118,7487,7488],{},"Обмеження ExternalName:",[3542,7490,7491,7497,7503,7509],{},[3390,7492,7493,7496],{},[3118,7494,7495],{},"Немає балансування навантаження"," — Kubernetes не проксує трафік, лише резолвить DNS",[3390,7498,7499,7502],{},[3118,7500,7501],{},"Немає health checks"," — Kubernetes не перевіряє доступність зовнішнього сервісу",[3390,7504,7505,7508],{},[3118,7506,7507],{},"Немає TLS termination"," — трафік йде напряму, без можливості додати TLS",[3390,7510,7511,7514],{},[3118,7512,7513],{},"Працює лише з DNS"," — не можна використовувати IP-адресу",[3114,7516,7517,7518,7521,7522,7524],{},"Якщо потрібен більший контроль, використовуйте ",[3118,7519,7520],{},"Service без selector"," + ",[3118,7523,4013],{}," (розглянемо далі).",[3582,7526],{},[3109,7528,7530],{"id":7529},"порівняння-типів-service","Порівняння типів Service",[3372,7532,7533,7565,7595,7623],{},[3375,7534,7536,7542,7548,7554,7560],{"icon":7535,"title":3991},"i-heroicons-server",[3114,7537,7538,7541],{},[3118,7539,7540],{},"Використання:"," Внутрішня комунікація між сервісами",[3114,7543,7544,7547],{},[3118,7545,7546],{},"Доступність:"," Лише всередині кластера",[3114,7549,7550,7553],{},[3118,7551,7552],{},"IP-адреса:"," Внутрішня ClusterIP",[3114,7555,7556,7559],{},[3118,7557,7558],{},"Вартість:"," Безкоштовно",[3114,7561,7562,7564],{},[3118,7563,3403],{}," API → Database, Frontend → API",[3375,7566,7568,7573,7581,7586,7590],{"icon":7567,"title":4425},"i-heroicons-server-stack",[3114,7569,7570,7572],{},[3118,7571,7540],{}," Локальна розробка, debugging, on-premise",[3114,7574,7575,7577,7578],{},[3118,7576,7546],{}," Через ",[3140,7579,7580],{},"\u003CNodeIP>:\u003CNodePort>",[3114,7582,7583,7585],{},[3118,7584,7552],{}," ClusterIP + порт на кожному вузлі",[3114,7587,7588,7559],{},[3118,7589,7558],{},[3114,7591,7592,7594],{},[3118,7593,3403],{}," Доступ до API з локальної машини",[3375,7596,7598,7603,7608,7613,7618],{"icon":7597,"title":4431},"i-heroicons-cloud",[3114,7599,7600,7602],{},[3118,7601,7540],{}," Production у хмарі, публічний доступ",[3114,7604,7605,7607],{},[3118,7606,7546],{}," Через публічну IP load balancer",[3114,7609,7610,7612],{},[3118,7611,7552],{}," ClusterIP + NodePort + зовнішня IP",[3114,7614,7615,7617],{},[3118,7616,7558],{}," ~$18-25/місяць за load balancer",[3114,7619,7620,7622],{},[3118,7621,3403],{}," Публічний API, веб-сайт",[3375,7624,7626,7631,7636,7641,7645],{"icon":7625,"title":4437},"i-heroicons-arrow-top-right-on-square",[3114,7627,7628,7630],{},[3118,7629,7540],{}," Доступ до зовнішніх сервісів",[3114,7632,7633,7635],{},[3118,7634,7546],{}," DNS CNAME до зовнішнього сервісу",[3114,7637,7638,7640],{},[3118,7639,7552],{}," Немає (лише DNS alias)",[3114,7642,7643,7559],{},[3118,7644,7558],{},[3114,7646,7647,7649],{},[3118,7648,3403],{}," AWS RDS, зовнішній API",[3114,7651,7652],{},[3118,7653,7654],{},"Таблиця порівняння:",[7656,7657,7658,7676],"table",{},[7659,7660,7661],"thead",{},[7662,7663,7664,7668,7670,7672,7674],"tr",{},[7665,7666,7667],"th",{},"Характеристика",[7665,7669,3991],{},[7665,7671,4425],{},[7665,7673,4431],{},[7665,7675,4437],{},[7677,7678,7679,7694,7708,7721,7734,7747,7761],"tbody",{},[7662,7680,7681,7684,7687,7689,7691],{},[7682,7683,3991],"td",{},[7682,7685,7686],{},"✅ Так",[7682,7688,7686],{},[7682,7690,7686],{},[7682,7692,7693],{},"❌ Ні",[7662,7695,7696,7698,7700,7703,7706],{},[7682,7697,4425],{},[7682,7699,7693],{},[7682,7701,7702],{},"✅ Так (30000-32767)",[7682,7704,7705],{},"✅ Так (автоматично)",[7682,7707,7693],{},[7662,7709,7710,7713,7715,7717,7719],{},[7682,7711,7712],{},"Зовнішня IP",[7682,7714,7693],{},[7682,7716,7693],{},[7682,7718,7686],{},[7682,7720,7693],{},[7662,7722,7723,7726,7728,7730,7732],{},[7682,7724,7725],{},"Балансування",[7682,7727,7686],{},[7682,7729,7686],{},[7682,7731,7686],{},[7682,7733,7693],{},[7662,7735,7736,7739,7741,7743,7745],{},[7682,7737,7738],{},"Health checks",[7682,7740,7686],{},[7682,7742,7686],{},[7682,7744,7686],{},[7682,7746,7693],{},[7662,7748,7749,7752,7754,7756,7758],{},[7682,7750,7751],{},"Доступ ззовні",[7682,7753,7693],{},[7682,7755,7686],{},[7682,7757,7686],{},[7682,7759,7760],{},"N/A",[7662,7762,7763,7766,7769,7771,7774],{},[7682,7764,7765],{},"Вартість",[7682,7767,7768],{},"Безкоштовно",[7682,7770,7768],{},[7682,7772,7773],{},"$18-25/міс",[7682,7775,7768],{},[3582,7777],{},[3109,7779,7781],{"id":7780},"як-працює-service-kube-proxy-та-iptables","Як працює Service: kube-proxy та iptables",[3114,7783,7784,7785,7788,7789,3580],{},"Тепер розберемо, ",[3118,7786,7787],{},"як саме"," Kubernetes перенаправляє трафік від Service до Pod. За це відповідає компонент ",[3118,7790,7791],{},"kube-proxy",[3122,7793,7795],{"id":7794},"архітектура-kube-proxy","Архітектура kube-proxy",[3130,7797,7798],{},[3133,7799,7801],{"className":3135,"code":7800,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Kubernetes Node\" {\n    component \"kube-proxy\" as proxy #e3f2fd {\n        [Watches API Server]\n        [Updates iptables/IPVS]\n    }\n    \n    component \"iptables/IPVS\" as ipt #fff3e0 {\n        [Routing rules]\n        [Load balancing]\n    }\n    \n    component \"Pod 1\\n10.244.1.10\" as p1 #e8f5e9\n    component \"Pod 2\\n10.244.1.11\" as p2 #e8f5e9\n}\n\ncomponent \"API Server\" as api\ncomponent \"Service\\napi-service\\n10.96.0.10\" as svc\n\napi --> proxy : Watch Services/Endpoints\nproxy --> ipt : Update rules\n\nactor \"Client\" as client\n\nclient --> ipt : GET http://10.96.0.10/todos\nipt --> p1 : DNAT to 10.244.1.10:8080\nipt --> p2 : DNAT to 10.244.1.11:8080\n\nnote right of proxy\n    kube-proxy працює\n    на кожному вузлі\n    \n    Не проксує трафік,\n    а налаштовує iptables\nend note\n\nnote right of ipt\n    iptables виконує:\n    - DNAT (зміна IP:Port)\n    - Load balancing (random)\n    - Health checks (через Endpoints)\nend note\n\n@enduml\n",[3140,7802,7803,7807,7811,7815,7819,7824,7829,7834,7839,7843,7847,7852,7857,7862,7866,7870,7875,7880,7884,7888,7893,7898,7902,7907,7912,7916,7920,7924,7929,7934,7939,7943,7948,7953,7958,7962,7967,7972,7976,7980,7985,7990,7995,8000,8005,8009,8013],{"__ignoreMap":3138},[3143,7804,7805],{"class":3145,"line":3146},[3143,7806,3149],{},[3143,7808,7809],{"class":3145,"line":3152},[3143,7810,3155],{},[3143,7812,7813],{"class":3145,"line":3158},[3143,7814,3161],{},[3143,7816,7817],{"class":3145,"line":3164},[3143,7818,3168],{"emptyLinePlaceholder":3167},[3143,7820,7821],{"class":3145,"line":3171},[3143,7822,7823],{},"package \"Kubernetes Node\" {\n",[3143,7825,7826],{"class":3145,"line":3177},[3143,7827,7828],{},"    component \"kube-proxy\" as proxy #e3f2fd {\n",[3143,7830,7831],{"class":3145,"line":3183},[3143,7832,7833],{},"        [Watches API Server]\n",[3143,7835,7836],{"class":3145,"line":3189},[3143,7837,7838],{},"        [Updates iptables/IPVS]\n",[3143,7840,7841],{"class":3145,"line":3195},[3143,7842,3198],{},[3143,7844,7845],{"class":3145,"line":3201},[3143,7846,3204],{},[3143,7848,7849],{"class":3145,"line":3207},[3143,7850,7851],{},"    component \"iptables/IPVS\" as ipt #fff3e0 {\n",[3143,7853,7854],{"class":3145,"line":3213},[3143,7855,7856],{},"        [Routing rules]\n",[3143,7858,7859],{"class":3145,"line":3219},[3143,7860,7861],{},"        [Load balancing]\n",[3143,7863,7864],{"class":3145,"line":3225},[3143,7865,3198],{},[3143,7867,7868],{"class":3145,"line":3231},[3143,7869,3204],{},[3143,7871,7872],{"class":3145,"line":3236},[3143,7873,7874],{},"    component \"Pod 1\\n10.244.1.10\" as p1 #e8f5e9\n",[3143,7876,7877],{"class":3145,"line":3242},[3143,7878,7879],{},"    component \"Pod 2\\n10.244.1.11\" as p2 #e8f5e9\n",[3143,7881,7882],{"class":3145,"line":3247},[3143,7883,3239],{},[3143,7885,7886],{"class":3145,"line":3253},[3143,7887,3168],{"emptyLinePlaceholder":3167},[3143,7889,7890],{"class":3145,"line":3259},[3143,7891,7892],{},"component \"API Server\" as api\n",[3143,7894,7895],{"class":3145,"line":3265},[3143,7896,7897],{},"component \"Service\\napi-service\\n10.96.0.10\" as svc\n",[3143,7899,7900],{"class":3145,"line":3270},[3143,7901,3168],{"emptyLinePlaceholder":3167},[3143,7903,7904],{"class":3145,"line":3276},[3143,7905,7906],{},"api --> proxy : Watch Services/Endpoints\n",[3143,7908,7909],{"class":3145,"line":3282},[3143,7910,7911],{},"proxy --> ipt : Update rules\n",[3143,7913,7914],{"class":3145,"line":3288},[3143,7915,3168],{"emptyLinePlaceholder":3167},[3143,7917,7918],{"class":3145,"line":3293},[3143,7919,4480],{},[3143,7921,7922],{"class":3145,"line":3299},[3143,7923,3168],{"emptyLinePlaceholder":3167},[3143,7925,7926],{"class":3145,"line":3305},[3143,7927,7928],{},"client --> ipt : GET http://10.96.0.10/todos\n",[3143,7930,7931],{"class":3145,"line":3311},[3143,7932,7933],{},"ipt --> p1 : DNAT to 10.244.1.10:8080\n",[3143,7935,7936],{"class":3145,"line":3317},[3143,7937,7938],{},"ipt --> p2 : DNAT to 10.244.1.11:8080\n",[3143,7940,7941],{"class":3145,"line":3323},[3143,7942,3168],{"emptyLinePlaceholder":3167},[3143,7944,7945],{"class":3145,"line":3328},[3143,7946,7947],{},"note right of proxy\n",[3143,7949,7950],{"class":3145,"line":3334},[3143,7951,7952],{},"    kube-proxy працює\n",[3143,7954,7955],{"class":3145,"line":3340},[3143,7956,7957],{},"    на кожному вузлі\n",[3143,7959,7960],{"class":3145,"line":3346},[3143,7961,3204],{},[3143,7963,7964],{"class":3145,"line":3352},[3143,7965,7966],{},"    Не проксує трафік,\n",[3143,7968,7969],{"class":3145,"line":3357},[3143,7970,7971],{},"    а налаштовує iptables\n",[3143,7973,7974],{"class":3145,"line":3362},[3143,7975,3320],{},[3143,7977,7978],{"class":3145,"line":3869},[3143,7979,3168],{"emptyLinePlaceholder":3167},[3143,7981,7982],{"class":3145,"line":3875},[3143,7983,7984],{},"note right of ipt\n",[3143,7986,7987],{"class":3145,"line":3881},[3143,7988,7989],{},"    iptables виконує:\n",[3143,7991,7992],{"class":3145,"line":3887},[3143,7993,7994],{},"    - DNAT (зміна IP:Port)\n",[3143,7996,7997],{"class":3145,"line":3893},[3143,7998,7999],{},"    - Load balancing (random)\n",[3143,8001,8002],{"class":3145,"line":3899},[3143,8003,8004],{},"    - Health checks (через Endpoints)\n",[3143,8006,8007],{"class":3145,"line":3904},[3143,8008,3320],{},[3143,8010,8011],{"class":3145,"line":3909},[3143,8012,3168],{"emptyLinePlaceholder":3167},[3143,8014,8015],{"class":3145,"line":3915},[3143,8016,3365],{},[3122,8018,8020],{"id":8019},"режими-роботи-kube-proxy","Режими роботи kube-proxy",[3114,8022,8023],{},"kube-proxy підтримує три режими:",[4169,8025,8026,8079,8211],{},[4172,8027,8029,8034,8048,8052,8063,8068],{"name":8028},"iptables (за замовчуванням)",[3114,8030,8031],{},[3118,8032,8033],{},"Як працює:",[3542,8035,8036,8039,8042,8045],{},[3390,8037,8038],{},"kube-proxy стежить за Service та Endpoints через API Server",[3390,8040,8041],{},"Для кожного Service створюються правила iptables",[3390,8043,8044],{},"Коли пакет надходить на ClusterIP, iptables виконує DNAT (Destination NAT) — змінює IP:Port на IP:Port одного з Pod",[3390,8046,8047],{},"Балансування: random (випадковий вибір Pod)",[3114,8049,8050],{},[3118,8051,5038],{},[3387,8053,8054,8057,8060],{},[3390,8055,8056],{},"Стабільний, перевірений часом",[3390,8058,8059],{},"Низьке споживання ресурсів",[3390,8061,8062],{},"Працює на рівні ядра Linux (швидко)",[3114,8064,8065],{},[3118,8066,8067],{},"Недоліки:",[3387,8069,8070,8073,8076],{},[3390,8071,8072],{},"Погана масштабованість (багато правил iptables при тисячах Service)",[3390,8074,8075],{},"Балансування не ідеальне (random, а не round-robin)",[3390,8077,8078],{},"Складно діагностувати проблеми",[4172,8080,8082,8086,8097,8101,8112,8116,8124,8129],{"name":8081},"IPVS (IP Virtual Server)",[3114,8083,8084],{},[3118,8085,8033],{},[3542,8087,8088,8091,8094],{},[3390,8089,8090],{},"kube-proxy створює віртуальний сервер IPVS для кожного Service",[3390,8092,8093],{},"IPVS виконує балансування навантаження на рівні ядра",[3390,8095,8096],{},"Підтримує різні алгоритми: round-robin, least connections, source hashing",[3114,8098,8099],{},[3118,8100,5038],{},[3387,8102,8103,8106,8109],{},[3390,8104,8105],{},"Краща масштабованість (тисячі Service)",[3390,8107,8108],{},"Кращі алгоритми балансування",[3390,8110,8111],{},"Вища продуктивність при великій кількості Service",[3114,8113,8114],{},[3118,8115,8067],{},[3387,8117,8118,8121],{},[3390,8119,8120],{},"Потребує модуль ядра IPVS (не завжди доступний)",[3390,8122,8123],{},"Складніше налаштування",[3114,8125,8126],{},[3118,8127,8128],{},"Увімкнення IPVS:",[3133,8130,8132],{"className":3443,"code":8131,"language":3445,"meta":3138,"style":3138},"# kube-proxy ConfigMap\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: kube-proxy\n  namespace: kube-system\ndata:\n  config.conf: |\n    mode: \"ipvs\"\n    ipvs:\n      scheduler: \"rr\"  # round-robin\n",[3140,8133,8134,8139,8147,8155,8161,8170,8179,8185,8196,8201,8206],{"__ignoreMap":3138},[3143,8135,8136],{"class":3145,"line":3146},[3143,8137,8138],{"class":4245},"# kube-proxy ConfigMap\n",[3143,8140,8141,8143,8145],{"class":3145,"line":3152},[3143,8142,4039],{"class":3452},[3143,8144,3516],{"class":3456},[3143,8146,4044],{"class":3479},[3143,8148,8149,8151,8153],{"class":3145,"line":3158},[3143,8150,4049],{"class":3452},[3143,8152,3516],{"class":3456},[3143,8154,5717],{"class":3479},[3143,8156,8157,8159],{"class":3145,"line":3164},[3143,8158,4059],{"class":3452},[3143,8160,3457],{"class":3456},[3143,8162,8163,8165,8167],{"class":3145,"line":3171},[3143,8164,4066],{"class":3452},[3143,8166,3516],{"class":3456},[3143,8168,8169],{"class":3479},"kube-proxy\n",[3143,8171,8172,8174,8176],{"class":3145,"line":3177},[3143,8173,4076],{"class":3452},[3143,8175,3516],{"class":3456},[3143,8177,8178],{"class":3479},"kube-system\n",[3143,8180,8181,8183],{"class":3145,"line":3183},[3143,8182,5737],{"class":3452},[3143,8184,3457],{"class":3456},[3143,8186,8187,8190,8192],{"class":3145,"line":3189},[3143,8188,8189],{"class":3452},"  config.conf",[3143,8191,3516],{"class":3456},[3143,8193,8195],{"class":8194},"sCDza","|\n",[3143,8197,8198],{"class":3145,"line":3195},[3143,8199,8200],{"class":3479},"    mode: \"ipvs\"\n",[3143,8202,8203],{"class":3145,"line":3201},[3143,8204,8205],{"class":3479},"    ipvs:\n",[3143,8207,8208],{"class":3145,"line":3207},[3143,8209,8210],{"class":3479},"      scheduler: \"rr\"  # round-robin\n",[4172,8212,8214,8218,8226,8230,8238],{"name":8213},"userspace (застарілий)",[3114,8215,8216],{},[3118,8217,8033],{},[3542,8219,8220,8223],{},[3390,8221,8222],{},"kube-proxy сам проксує трафік (працює як reverse proxy)",[3390,8224,8225],{},"Трафік йде через user space, а не kernel space",[3114,8227,8228],{},[3118,8229,8067],{},[3387,8231,8232,8235],{},[3390,8233,8234],{},"Повільний (трафік проходить через user space)",[3390,8236,8237],{},"Застарілий, не рекомендується",[3114,8239,8240,8243],{},[3118,8241,8242],{},"Статус:"," Deprecated, не використовується у production",[3122,8245,8247],{"id":8246},"детальний-розбір-iptables-режиму","Детальний розбір iptables режиму",[3114,8249,8250],{},"Давайте подивимося, які саме правила створює kube-proxy:",[6191,8252,8254,8261,8270,8274,8277,8284,8293,8297,8301,8305,8309],{"title":8253},"iptables правила для Service",[6195,8255,8257],{"className":8256},[3145],[3143,8258,8260],{"className":8259},[6201],"# Перегляд iptables правил для Service",[6195,8262,8264,4793,8267],{"className":8263},[3145],[3143,8265,6209],{"className":8266},[6201],[3118,8268,8269],{},"sudo iptables -t nat -L KUBE-SERVICES | grep api-service",[6195,8271,8273],{"className":8272},[3145],"KUBE-SVC-XXXXX  tcp  --  anywhere  10.96.0.10  /* default/api-service cluster IP */ tcp dpt:http",[6195,8275],{"className":8276},[3145],[6195,8278,8280],{"className":8279},[3145],[3143,8281,8283],{"className":8282},[6201],"# Детальний перегляд правил для конкретного Service",[6195,8285,8287,4793,8290],{"className":8286},[3145],[3143,8288,6209],{"className":8289},[6201],[3118,8291,8292],{},"sudo iptables -t nat -L KUBE-SVC-XXXXX",[6195,8294,8296],{"className":8295},[3145],"Chain KUBE-SVC-XXXXX (1 references)",[6195,8298,8300],{"className":8299},[3145],"target     prot opt source               destination",[6195,8302,8304],{"className":8303},[3145],"KUBE-SEP-AAAA  all  --  anywhere  anywhere  /* default/api-service */ statistic mode random probability 0.33333",[6195,8306,8308],{"className":8307},[3145],"KUBE-SEP-BBBB  all  --  anywhere  anywhere  /* default/api-service */ statistic mode random probability 0.50000",[6195,8310,8312],{"className":8311},[3145],"KUBE-SEP-CCCC  all  --  anywhere  anywhere  /* default/api-service */",[3114,8314,8315],{},[3118,8316,8317],{},"Що означають ці правила:",[3542,8319,8320,8326,8332],{},[3390,8321,8322,8325],{},[3118,8323,8324],{},"KUBE-SERVICES"," — головний ланцюжок для всіх Service",[3390,8327,8328,8331],{},[3118,8329,8330],{},"KUBE-SVC-XXXXX"," — ланцюжок для конкретного Service (api-service)",[3390,8333,8334,8337],{},[3118,8335,8336],{},"KUBE-SEP-AAAA/BBBB/CCCC"," — ланцюжки для кожного Pod (Service Endpoint)",[3114,8339,8340],{},[3118,8341,8342],{},"Балансування:",[3387,8344,8345,8348,8351],{},[3390,8346,8347],{},"Перший Pod: ймовірність 33.33% (1/3)",[3390,8349,8350],{},"Другий Pod: ймовірність 50% з решти (1/2 від 66.67%)",[3390,8352,8353],{},"Третій Pod: решта 33.33%",[3114,8355,8356],{},"Це дає рівномірний розподіл 33.33% / 33.33% / 33.33%.",[3114,8358,8359],{},[3118,8360,8361],{},"DNAT правило для Pod:",[6191,8363,8365,8374,8378,8381],{"title":8364},"DNAT правило",[6195,8366,8368,4793,8371],{"className":8367},[3145],[3143,8369,6209],{"className":8370},[6201],[3118,8372,8373],{},"sudo iptables -t nat -L KUBE-SEP-AAAA",[6195,8375,8377],{"className":8376},[3145],"Chain KUBE-SEP-AAAA (1 references)",[6195,8379,8300],{"className":8380},[3145],[6195,8382,8384],{"className":8383},[3145],"DNAT       tcp  --  anywhere  anywhere  /* default/api-service */ tcp to:10.244.1.10:8080",[3114,8386,8387,8388,8391,8392,8395],{},"Це правило змінює destination IP:Port з ",[3140,8389,8390],{},"10.96.0.10:80"," (Service) на ",[3140,8393,8394],{},"10.244.1.10:8080"," (Pod).",[3122,8397,8399],{"id":8398},"візуалізація-потоку-трафіку","Візуалізація потоку трафіку",[3130,8401,8402],{},[3133,8403,8405],{"className":3135,"code":8404,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nparticipant \"Client Pod\\n10.244.1.5\" as client\nparticipant \"iptables\" as ipt\nparticipant \"Service\\n10.96.0.10:80\" as svc\nparticipant \"Pod 1\\n10.244.1.10:8080\" as p1\nparticipant \"Pod 2\\n10.244.1.11:8080\" as p2\nparticipant \"Pod 3\\n10.244.1.12:8080\" as p3\n\nclient -> ipt : SYN to 10.96.0.10:80\nactivate ipt\n\nipt -> ipt : Match KUBE-SERVICES rule\nipt -> ipt : Jump to KUBE-SVC-XXXXX\nipt -> ipt : Random selection (33.33% each)\nipt -> ipt : Jump to KUBE-SEP-AAAA (Pod 1 selected)\nipt -> ipt : DNAT: 10.96.0.10:80 → 10.244.1.10:8080\n\ndeactivate ipt\n\nipt -> p1 : SYN to 10.244.1.10:8080\np1 -> ipt : SYN-ACK from 10.244.1.10:8080\n\nactivate ipt\nipt -> ipt : SNAT: 10.244.1.10:8080 → 10.96.0.10:80\ndeactivate ipt\n\nipt -> client : SYN-ACK from 10.96.0.10:80\n\nclient -> ipt : GET /todos\nipt -> p1 : GET /todos (DNAT)\np1 -> ipt : 200 OK\nipt -> client : 200 OK (SNAT)\n\nnote right of ipt\n    iptables виконує:\n    1. DNAT (вхідний трафік)\n    2. SNAT (вихідний трафік)\n    \n    Клієнт не знає про Pod,\n    бачить лише Service IP\nend note\n\n@enduml\n",[3140,8406,8407,8411,8415,8419,8423,8428,8433,8438,8443,8448,8453,8457,8462,8467,8471,8476,8481,8486,8491,8496,8500,8505,8509,8514,8519,8523,8527,8532,8536,8540,8545,8549,8554,8559,8564,8569,8573,8577,8581,8586,8591,8595,8600,8605,8609,8613],{"__ignoreMap":3138},[3143,8408,8409],{"class":3145,"line":3146},[3143,8410,3149],{},[3143,8412,8413],{"class":3145,"line":3152},[3143,8414,3155],{},[3143,8416,8417],{"class":3145,"line":3158},[3143,8418,3161],{},[3143,8420,8421],{"class":3145,"line":3164},[3143,8422,3168],{"emptyLinePlaceholder":3167},[3143,8424,8425],{"class":3145,"line":3171},[3143,8426,8427],{},"participant \"Client Pod\\n10.244.1.5\" as client\n",[3143,8429,8430],{"class":3145,"line":3177},[3143,8431,8432],{},"participant \"iptables\" as ipt\n",[3143,8434,8435],{"class":3145,"line":3183},[3143,8436,8437],{},"participant \"Service\\n10.96.0.10:80\" as svc\n",[3143,8439,8440],{"class":3145,"line":3189},[3143,8441,8442],{},"participant \"Pod 1\\n10.244.1.10:8080\" as p1\n",[3143,8444,8445],{"class":3145,"line":3195},[3143,8446,8447],{},"participant \"Pod 2\\n10.244.1.11:8080\" as p2\n",[3143,8449,8450],{"class":3145,"line":3201},[3143,8451,8452],{},"participant \"Pod 3\\n10.244.1.12:8080\" as p3\n",[3143,8454,8455],{"class":3145,"line":3207},[3143,8456,3168],{"emptyLinePlaceholder":3167},[3143,8458,8459],{"class":3145,"line":3213},[3143,8460,8461],{},"client -> ipt : SYN to 10.96.0.10:80\n",[3143,8463,8464],{"class":3145,"line":3219},[3143,8465,8466],{},"activate ipt\n",[3143,8468,8469],{"class":3145,"line":3225},[3143,8470,3168],{"emptyLinePlaceholder":3167},[3143,8472,8473],{"class":3145,"line":3231},[3143,8474,8475],{},"ipt -> ipt : Match KUBE-SERVICES rule\n",[3143,8477,8478],{"class":3145,"line":3236},[3143,8479,8480],{},"ipt -> ipt : Jump to KUBE-SVC-XXXXX\n",[3143,8482,8483],{"class":3145,"line":3242},[3143,8484,8485],{},"ipt -> ipt : Random selection (33.33% each)\n",[3143,8487,8488],{"class":3145,"line":3247},[3143,8489,8490],{},"ipt -> ipt : Jump to KUBE-SEP-AAAA (Pod 1 selected)\n",[3143,8492,8493],{"class":3145,"line":3253},[3143,8494,8495],{},"ipt -> ipt : DNAT: 10.96.0.10:80 → 10.244.1.10:8080\n",[3143,8497,8498],{"class":3145,"line":3259},[3143,8499,3168],{"emptyLinePlaceholder":3167},[3143,8501,8502],{"class":3145,"line":3265},[3143,8503,8504],{},"deactivate ipt\n",[3143,8506,8507],{"class":3145,"line":3270},[3143,8508,3168],{"emptyLinePlaceholder":3167},[3143,8510,8511],{"class":3145,"line":3276},[3143,8512,8513],{},"ipt -> p1 : SYN to 10.244.1.10:8080\n",[3143,8515,8516],{"class":3145,"line":3282},[3143,8517,8518],{},"p1 -> ipt : SYN-ACK from 10.244.1.10:8080\n",[3143,8520,8521],{"class":3145,"line":3288},[3143,8522,3168],{"emptyLinePlaceholder":3167},[3143,8524,8525],{"class":3145,"line":3293},[3143,8526,8466],{},[3143,8528,8529],{"class":3145,"line":3299},[3143,8530,8531],{},"ipt -> ipt : SNAT: 10.244.1.10:8080 → 10.96.0.10:80\n",[3143,8533,8534],{"class":3145,"line":3305},[3143,8535,8504],{},[3143,8537,8538],{"class":3145,"line":3311},[3143,8539,3168],{"emptyLinePlaceholder":3167},[3143,8541,8542],{"class":3145,"line":3317},[3143,8543,8544],{},"ipt -> client : SYN-ACK from 10.96.0.10:80\n",[3143,8546,8547],{"class":3145,"line":3323},[3143,8548,3168],{"emptyLinePlaceholder":3167},[3143,8550,8551],{"class":3145,"line":3328},[3143,8552,8553],{},"client -> ipt : GET /todos\n",[3143,8555,8556],{"class":3145,"line":3334},[3143,8557,8558],{},"ipt -> p1 : GET /todos (DNAT)\n",[3143,8560,8561],{"class":3145,"line":3340},[3143,8562,8563],{},"p1 -> ipt : 200 OK\n",[3143,8565,8566],{"class":3145,"line":3346},[3143,8567,8568],{},"ipt -> client : 200 OK (SNAT)\n",[3143,8570,8571],{"class":3145,"line":3352},[3143,8572,3168],{"emptyLinePlaceholder":3167},[3143,8574,8575],{"class":3145,"line":3357},[3143,8576,7984],{},[3143,8578,8579],{"class":3145,"line":3362},[3143,8580,7989],{},[3143,8582,8583],{"class":3145,"line":3869},[3143,8584,8585],{},"    1. DNAT (вхідний трафік)\n",[3143,8587,8588],{"class":3145,"line":3875},[3143,8589,8590],{},"    2. SNAT (вихідний трафік)\n",[3143,8592,8593],{"class":3145,"line":3881},[3143,8594,3204],{},[3143,8596,8597],{"class":3145,"line":3887},[3143,8598,8599],{},"    Клієнт не знає про Pod,\n",[3143,8601,8602],{"class":3145,"line":3893},[3143,8603,8604],{},"    бачить лише Service IP\n",[3143,8606,8607],{"class":3145,"line":3899},[3143,8608,3320],{},[3143,8610,8611],{"class":3145,"line":3904},[3143,8612,3168],{"emptyLinePlaceholder":3167},[3143,8614,8615],{"class":3145,"line":3909},[3143,8616,3365],{},[3114,8618,8619],{},[3118,8620,8621],{},"Ключові моменти:",[3542,8623,8624,8630,8636,8642],{},[3390,8625,8626,8629],{},[3118,8627,8628],{},"DNAT (Destination NAT)"," — зміна destination IP:Port з Service на Pod",[3390,8631,8632,8635],{},[3118,8633,8634],{},"SNAT (Source NAT)"," — зміна source IP:Port у відповіді з Pod на Service",[3390,8637,8638,8641],{},[3118,8639,8640],{},"Прозорість"," — клієнт не знає про існування Pod, бачить лише Service",[3390,8643,8644,8647],{},[3118,8645,8646],{},"Stateful"," — iptables відстежує з'єднання (connection tracking), тому відповіді йдуть до того самого клієнта",[3582,8649],{},[3109,8651,8653],{"id":8652},"coredns-та-service-discovery","CoreDNS та Service Discovery",[3114,8655,8656,8657,8660,8661,3580],{},"Одна з найважливіших можливостей Service — ",[3118,8658,8659],{},"автоматичний service discovery"," через DNS. За це відповідає ",[3118,8662,5422],{},[3122,8664,8666],{"id":8665},"що-таке-coredns","Що таке CoreDNS",[3114,8668,8669,8671],{},[3118,8670,5422],{}," — це DNS-сервер, який працює у Kubernetes кластері та автоматично створює DNS-записи для всіх Service.",[3130,8673,8674],{},[3133,8675,8677],{"className":3135,"code":8676,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Kubernetes Cluster\" {\n    component \"CoreDNS Pod\" as dns #e3f2fd {\n        [DNS Server]\n        [Watches API Server]\n    }\n    \n    component \"API Server\" as api #fff3e0\n    \n    component \"Client Pod\" as client #e8f5e9\n    \n    component \"Service\\napi-service\" as svc {\n        [ClusterIP: 10.96.0.10]\n    }\n}\n\napi --> dns : Watch Services\ndns --> dns : Create DNS records\n\nclient --> dns : DNS query: api-service.default.svc.cluster.local\ndns --> client : Response: 10.96.0.10\n\nclient --> svc : HTTP GET http://10.96.0.10/todos\n\nnote right of dns\n    CoreDNS автоматично\n    створює DNS-записи\n    для всіх Service\nend note\n\nnote right of client\n    Pod налаштовані\n    використовувати CoreDNS\n    як DNS-сервер\n    (через /etc/resolv.conf)\nend note\n\n@enduml\n",[3140,8678,8679,8683,8687,8691,8695,8699,8704,8709,8713,8717,8721,8726,8730,8735,8739,8744,8748,8752,8756,8760,8765,8770,8774,8779,8784,8788,8793,8797,8802,8807,8812,8817,8821,8825,8830,8835,8840,8845,8850,8854,8858],{"__ignoreMap":3138},[3143,8680,8681],{"class":3145,"line":3146},[3143,8682,3149],{},[3143,8684,8685],{"class":3145,"line":3152},[3143,8686,3155],{},[3143,8688,8689],{"class":3145,"line":3158},[3143,8690,3161],{},[3143,8692,8693],{"class":3145,"line":3164},[3143,8694,3168],{"emptyLinePlaceholder":3167},[3143,8696,8697],{"class":3145,"line":3171},[3143,8698,3174],{},[3143,8700,8701],{"class":3145,"line":3177},[3143,8702,8703],{},"    component \"CoreDNS Pod\" as dns #e3f2fd {\n",[3143,8705,8706],{"class":3145,"line":3183},[3143,8707,8708],{},"        [DNS Server]\n",[3143,8710,8711],{"class":3145,"line":3189},[3143,8712,7833],{},[3143,8714,8715],{"class":3145,"line":3195},[3143,8716,3198],{},[3143,8718,8719],{"class":3145,"line":3201},[3143,8720,3204],{},[3143,8722,8723],{"class":3145,"line":3207},[3143,8724,8725],{},"    component \"API Server\" as api #fff3e0\n",[3143,8727,8728],{"class":3145,"line":3213},[3143,8729,3204],{},[3143,8731,8732],{"class":3145,"line":3219},[3143,8733,8734],{},"    component \"Client Pod\" as client #e8f5e9\n",[3143,8736,8737],{"class":3145,"line":3225},[3143,8738,3204],{},[3143,8740,8741],{"class":3145,"line":3231},[3143,8742,8743],{},"    component \"Service\\napi-service\" as svc {\n",[3143,8745,8746],{"class":3145,"line":3236},[3143,8747,3721],{},[3143,8749,8750],{"class":3145,"line":3242},[3143,8751,3198],{},[3143,8753,8754],{"class":3145,"line":3247},[3143,8755,3239],{},[3143,8757,8758],{"class":3145,"line":3253},[3143,8759,3168],{"emptyLinePlaceholder":3167},[3143,8761,8762],{"class":3145,"line":3259},[3143,8763,8764],{},"api --> dns : Watch Services\n",[3143,8766,8767],{"class":3145,"line":3265},[3143,8768,8769],{},"dns --> dns : Create DNS records\n",[3143,8771,8772],{"class":3145,"line":3270},[3143,8773,3168],{"emptyLinePlaceholder":3167},[3143,8775,8776],{"class":3145,"line":3276},[3143,8777,8778],{},"client --> dns : DNS query: api-service.default.svc.cluster.local\n",[3143,8780,8781],{"class":3145,"line":3282},[3143,8782,8783],{},"dns --> client : Response: 10.96.0.10\n",[3143,8785,8786],{"class":3145,"line":3288},[3143,8787,3168],{"emptyLinePlaceholder":3167},[3143,8789,8790],{"class":3145,"line":3293},[3143,8791,8792],{},"client --> svc : HTTP GET http://10.96.0.10/todos\n",[3143,8794,8795],{"class":3145,"line":3299},[3143,8796,3168],{"emptyLinePlaceholder":3167},[3143,8798,8799],{"class":3145,"line":3305},[3143,8800,8801],{},"note right of dns\n",[3143,8803,8804],{"class":3145,"line":3311},[3143,8805,8806],{},"    CoreDNS автоматично\n",[3143,8808,8809],{"class":3145,"line":3317},[3143,8810,8811],{},"    створює DNS-записи\n",[3143,8813,8814],{"class":3145,"line":3323},[3143,8815,8816],{},"    для всіх Service\n",[3143,8818,8819],{"class":3145,"line":3328},[3143,8820,3320],{},[3143,8822,8823],{"class":3145,"line":3334},[3143,8824,3168],{"emptyLinePlaceholder":3167},[3143,8826,8827],{"class":3145,"line":3340},[3143,8828,8829],{},"note right of client\n",[3143,8831,8832],{"class":3145,"line":3346},[3143,8833,8834],{},"    Pod налаштовані\n",[3143,8836,8837],{"class":3145,"line":3352},[3143,8838,8839],{},"    використовувати CoreDNS\n",[3143,8841,8842],{"class":3145,"line":3357},[3143,8843,8844],{},"    як DNS-сервер\n",[3143,8846,8847],{"class":3145,"line":3362},[3143,8848,8849],{},"    (через /etc/resolv.conf)\n",[3143,8851,8852],{"class":3145,"line":3869},[3143,8853,3320],{},[3143,8855,8856],{"class":3145,"line":3875},[3143,8857,3168],{"emptyLinePlaceholder":3167},[3143,8859,8860],{"class":3145,"line":3881},[3143,8861,3365],{},[3122,8863,8865],{"id":8864},"формат-dns-імен-service","Формат DNS-імен Service",[3114,8867,8868],{},"Kubernetes створює DNS-записи у наступному форматі:",[3133,8870,8873],{"className":8871,"code":8872,"language":5432},[5430],"\u003Cservice-name>.\u003Cnamespace>.svc.\u003Ccluster-domain>\n",[3140,8874,8872],{"__ignoreMap":3138},[3114,8876,8877],{},[3118,8878,3984],{},[3387,8880,8881,8889,8895,8901],{},[3390,8882,8883,8886,8887,4002],{},[3118,8884,8885],{},"service-name"," — ім'я Service (з ",[3140,8888,4193],{},[3390,8890,8891,8894],{},[3118,8892,8893],{},"namespace"," — namespace, у якому створено Service",[3390,8896,8897,8900],{},[3118,8898,8899],{},"svc"," — константа (означає \"service\")",[3390,8902,8903,8906,8907,4002],{},[3118,8904,8905],{},"cluster-domain"," — домен кластера (за замовчуванням ",[3140,8908,8909],{},"cluster.local",[3114,8911,8912],{},[3118,8913,8914],{},"Приклади:",[7656,8916,8917,8929],{},[7659,8918,8919],{},[7662,8920,8921,8923,8926],{},[7665,8922,3579],{},[7665,8924,8925],{},"Namespace",[7665,8927,8928],{},"Повне DNS-ім'я",[7677,8930,8931,8942,8955],{},[7662,8932,8933,8935,8938],{},[7682,8934,5469],{},[7682,8936,8937],{},"default",[7682,8939,8940],{},[3140,8941,5200],{},[7662,8943,8944,8947,8950],{},[7682,8945,8946],{},"postgres",[7682,8948,8949],{},"database",[7682,8951,8952],{},[3140,8953,8954],{},"postgres.database.svc.cluster.local",[7662,8956,8957,8960,8963],{},[7682,8958,8959],{},"redis",[7682,8961,8962],{},"cache",[7682,8964,8965],{},[3140,8966,8967],{},"redis.cache.svc.cluster.local",[3122,8969,8971],{"id":8970},"скорочені-форми-dns-імен","Скорочені форми DNS-імен",[3114,8973,8974],{},"Kubernetes підтримує скорочені форми для зручності:",[4169,8976,8977,9033,9084],{},[4172,8978,8980,8986,8990,9012,9017,9028],{"name":8979},"\u003Cservice-name> (найкоротша форма)",[3114,8981,8982,8985],{},[3118,8983,8984],{},"Працює:"," Лише у тому самому namespace",[3114,8987,8988],{},[3118,8989,3403],{},[3133,8991,8993],{"className":5511,"code":8992,"language":5513,"meta":3138,"style":3138},"// Pod у namespace \"default\" звертається до Service \"api-service\" у \"default\"\nvar apiUrl = \"http://api-service\";\n",[3140,8994,8995,9000],{"__ignoreMap":3138},[3143,8996,8997],{"class":3145,"line":3146},[3143,8998,8999],{"class":4245},"// Pod у namespace \"default\" звертається до Service \"api-service\" у \"default\"\n",[3143,9001,9002,9004,9006,9008,9010],{"class":3145,"line":3152},[3143,9003,5521],{"class":5520},[3143,9005,5562],{"class":5524},[3143,9007,5528],{"class":3456},[3143,9009,5584],{"class":3529},[3143,9011,5587],{"class":3456},[3114,9013,9014],{},[3118,9015,9016],{},"DNS resolution:",[3542,9018,9019,9025],{},[3390,9020,9021,9022,9024],{},"Спроба: ",[3140,9023,5200],{}," ✅",[3390,9026,9027],{},"Якщо не знайдено: помилка",[3114,9029,9030,9032],{},[3118,9031,5401],{}," Більшість випадків (якщо Service у тому самому namespace)",[4172,9034,9036,9041,9045,9069,9073,9079],{"name":9035},"\u003Cservice-name>.\u003Cnamespace>",[3114,9037,9038,9040],{},[3118,9039,8984],{}," З будь-якого namespace",[3114,9042,9043],{},[3118,9044,3403],{},[3133,9046,9048],{"className":5511,"code":9047,"language":5513,"meta":3138,"style":3138},"// Pod у namespace \"frontend\" звертається до Service \"postgres\" у \"database\"\nvar dbHost = \"postgres.database\";\n",[3140,9049,9050,9055],{"__ignoreMap":3138},[3143,9051,9052],{"class":3145,"line":3146},[3143,9053,9054],{"class":4245},"// Pod у namespace \"frontend\" звертається до Service \"postgres\" у \"database\"\n",[3143,9056,9057,9059,9062,9064,9067],{"class":3145,"line":3152},[3143,9058,5521],{"class":5520},[3143,9060,9061],{"class":5524}," dbHost",[3143,9063,5528],{"class":3456},[3143,9065,9066],{"class":3529},"\"postgres.database\"",[3143,9068,5587],{"class":3456},[3114,9070,9071],{},[3118,9072,9016],{},[3542,9074,9075],{},[3390,9076,9021,9077,9024],{},[3140,9078,8954],{},[3114,9080,9081,9083],{},[3118,9082,5401],{}," Міжнамespace комунікація (frontend → database)",[4172,9085,9087,9092,9096,9114,9118],{"name":9086},"\u003Cservice-name>.\u003Cnamespace>.svc.cluster.local (повна форма)",[3114,9088,9089,9091],{},[3118,9090,8984],{}," Завжди, з будь-якого місця",[3114,9093,9094],{},[3118,9095,3403],{},[3133,9097,9099],{"className":5511,"code":9098,"language":5513,"meta":3138,"style":3138},"var apiUrl = \"http://api-service.default.svc.cluster.local\";\n",[3140,9100,9101],{"__ignoreMap":3138},[3143,9102,9103,9105,9107,9109,9112],{"class":3145,"line":3146},[3143,9104,5521],{"class":5520},[3143,9106,5562],{"class":5524},[3143,9108,5528],{"class":3456},[3143,9110,9111],{"class":3529},"\"http://api-service.default.svc.cluster.local\"",[3143,9113,5587],{"class":3456},[3114,9115,9116],{},[3118,9117,5401],{},[3387,9119,9120,9123,9126],{},[3390,9121,9122],{},"Явна специфікація (для документації)",[3390,9124,9125],{},"Уникнення конфліктів імен",[3390,9127,9128],{},"Зовнішні системи (якщо вони мають доступ до CoreDNS)",[3122,9130,9132],{"id":9131},"як-pod-налаштовані-використовувати-coredns","Як Pod налаштовані використовувати CoreDNS",[3114,9134,9135],{},"Кожен Pod автоматично налаштовується використовувати CoreDNS як DNS-сервер:",[6191,9137,9139,9148,9152,9156],{"title":9138},"/etc/resolv.conf у Pod",[6195,9140,9142,4793,9145],{"className":9141},[3145],[3143,9143,6209],{"className":9144},[6201],[3118,9146,9147],{},"kubectl exec -it api-pod-xxx -- cat /etc/resolv.conf",[6195,9149,9151],{"className":9150},[3145],"nameserver 10.96.0.10",[6195,9153,9155],{"className":9154},[3145],"search default.svc.cluster.local svc.cluster.local cluster.local",[6195,9157,9159],{"className":9158},[3145],"options ndots:5",[3114,9161,9162],{},[3118,9163,9164],{},"Що означають ці рядки:",[3387,9166,9167,9172,9177],{},[3390,9168,9169,9171],{},[3118,9170,9151],{}," — IP-адреса CoreDNS Service (kube-dns)",[3390,9173,9174,9176],{},[3118,9175,9155],{}," — список доменів для автоматичного додавання",[3390,9178,9179,9181],{},[3118,9180,9159],{}," — якщо у DNS-запиті менше 5 крапок, додавати search domains",[3114,9183,9184],{},[3118,9185,9186],{},"Як працює search:",[3114,9188,9189,9190,9192],{},"Коли Pod робить DNS-запит ",[3140,9191,5469],{},", резолвер пробує:",[3542,9194,9195,9200,9206,9211],{},[3390,9196,9197,9199],{},[3140,9198,5200],{}," ✅ (знайдено)",[3390,9201,9202,9203],{},"Якщо не знайдено: ",[3140,9204,9205],{},"api-service.svc.cluster.local",[3390,9207,9202,9208],{},[3140,9209,9210],{},"api-service.cluster.local",[3390,9212,9202,9213,9215],{},[3140,9214,5469],{}," (як є)",[3114,9217,9218,9219,9221],{},"Це дозволяє використовувати короткі імена (",[3140,9220,5469],{}," замість повного DNS-імені).",[3122,9223,9225],{"id":9224},"dns-записи-для-різних-типів-service","DNS-записи для різних типів Service",[3372,9227,9228,9270,9320],{},[3375,9229,9231,9237,9241,9264],{"icon":7535,"title":9230},"ClusterIP Service",[3114,9232,9233,9236],{},[3118,9234,9235],{},"DNS-запис:"," A-запис (IP-адреса)",[3114,9238,9239],{},[3118,9240,3403],{},[3133,9242,9244],{"className":6307,"code":9243,"language":6309,"meta":3138,"style":3138},"nslookup api-service.default.svc.cluster.local\n# Name:    api-service.default.svc.cluster.local\n# Address: 10.96.0.10\n",[3140,9245,9246,9254,9259],{"__ignoreMap":3138},[3143,9247,9248,9251],{"class":3145,"line":3146},[3143,9249,9250],{"class":5536},"nslookup",[3143,9252,9253],{"class":3529}," api-service.default.svc.cluster.local\n",[3143,9255,9256],{"class":3145,"line":3152},[3143,9257,9258],{"class":4245},"# Name:    api-service.default.svc.cluster.local\n",[3143,9260,9261],{"class":3145,"line":3158},[3143,9262,9263],{"class":4245},"# Address: 10.96.0.10\n",[3114,9265,9266,9269],{},[3118,9267,9268],{},"Що повертається:"," ClusterIP Service",[3375,9271,9274,9279,9283,9315],{"icon":9272,"title":9273},"i-heroicons-queue-list","Headless Service (ClusterIP: None)",[3114,9275,9276,9278],{},[3118,9277,9235],{}," A-записи для кожного Pod",[3114,9280,9281],{},[3118,9282,3403],{},[3133,9284,9286],{"className":6307,"code":9285,"language":6309,"meta":3138,"style":3138},"nslookup postgres.database.svc.cluster.local\n# Name:    postgres.database.svc.cluster.local\n# Address: 10.244.1.10  (Pod 1)\n# Address: 10.244.1.11  (Pod 2)\n# Address: 10.244.1.12  (Pod 3)\n",[3140,9287,9288,9295,9300,9305,9310],{"__ignoreMap":3138},[3143,9289,9290,9292],{"class":3145,"line":3146},[3143,9291,9250],{"class":5536},[3143,9293,9294],{"class":3529}," postgres.database.svc.cluster.local\n",[3143,9296,9297],{"class":3145,"line":3152},[3143,9298,9299],{"class":4245},"# Name:    postgres.database.svc.cluster.local\n",[3143,9301,9302],{"class":3145,"line":3158},[3143,9303,9304],{"class":4245},"# Address: 10.244.1.10  (Pod 1)\n",[3143,9306,9307],{"class":3145,"line":3164},[3143,9308,9309],{"class":4245},"# Address: 10.244.1.11  (Pod 2)\n",[3143,9311,9312],{"class":3145,"line":3171},[3143,9313,9314],{"class":4245},"# Address: 10.244.1.12  (Pod 3)\n",[3114,9316,9317,9319],{},[3118,9318,9268],{}," IP-адреси всіх Pod (детально розглянемо далі)",[3375,9321,9323,9328,9332,9359],{"icon":7625,"title":9322},"ExternalName Service",[3114,9324,9325,9327],{},[3118,9326,9235],{}," CNAME-запис",[3114,9329,9330],{},[3118,9331,3403],{},[3133,9333,9335],{"className":6307,"code":9334,"language":6309,"meta":3138,"style":3138},"nslookup external-api.default.svc.cluster.local\n# external-api.default.svc.cluster.local canonical name = api.example.com\n# Name:    api.example.com\n# Address: 34.56.78.90\n",[3140,9336,9337,9344,9349,9354],{"__ignoreMap":3138},[3143,9338,9339,9341],{"class":3145,"line":3146},[3143,9340,9250],{"class":5536},[3143,9342,9343],{"class":3529}," external-api.default.svc.cluster.local\n",[3143,9345,9346],{"class":3145,"line":3152},[3143,9347,9348],{"class":4245},"# external-api.default.svc.cluster.local canonical name = api.example.com\n",[3143,9350,9351],{"class":3145,"line":3158},[3143,9352,9353],{"class":4245},"# Name:    api.example.com\n",[3143,9355,9356],{"class":3145,"line":3164},[3143,9357,9358],{"class":4245},"# Address: 34.56.78.90\n",[3114,9360,9361,9363],{},[3118,9362,9268],{}," CNAME на зовнішнє DNS-ім'я",[3122,9365,9367],{"id":9366},"тестування-dns-resolution","Тестування DNS resolution",[3114,9369,9370],{},"Давайте протестуємо DNS resolution у реальному кластері:",[6191,9372,9374,9381,9390,9393,9400,9409,9413,9417,9420,9424,9428,9431,9438,9447,9450,9453,9456,9460,9464,9467,9474,9483,9486,9489,9492,9495,9498,9501,9508,9517],{"title":9373},"Тестування DNS",[6195,9375,9377],{"className":9376},[3145],[3143,9378,9380],{"className":9379},[6201],"# Створення тестового Pod з curl та nslookup",[6195,9382,9384,4793,9387],{"className":9383},[3145],[3143,9385,6209],{"className":9386},[6201],[3118,9388,9389],{},"kubectl run test-dns --image=curlimages/curl:latest --rm -it --restart=Never -- sh",[6195,9391],{"className":9392},[3145],[6195,9394,9396],{"className":9395},[3145],[3143,9397,9399],{"className":9398},[6201],"# Тест 1: Коротка форма (той самий namespace)",[6195,9401,9403,4793,9406],{"className":9402},[3145],[3143,9404,6209],{"className":9405},[6201],[3118,9407,9408],{},"nslookup api-service",[6195,9410,9412],{"className":9411},[3145],"Server:    10.96.0.10",[6195,9414,9416],{"className":9415},[3145],"Address:   10.96.0.10:53",[6195,9418],{"className":9419},[3145],[6195,9421,9423],{"className":9422},[3145],"Name:      api-service.default.svc.cluster.local",[6195,9425,9427],{"className":9426},[3145],"Address:   10.96.0.15",[6195,9429],{"className":9430},[3145],[6195,9432,9434],{"className":9433},[3145],[3143,9435,9437],{"className":9436},[6201],"# Тест 2: З namespace (міжнамespace)",[6195,9439,9441,4793,9444],{"className":9440},[3145],[3143,9442,6209],{"className":9443},[6201],[3118,9445,9446],{},"nslookup postgres.database",[6195,9448,9412],{"className":9449},[3145],[6195,9451,9416],{"className":9452},[3145],[6195,9454],{"className":9455},[3145],[6195,9457,9459],{"className":9458},[3145],"Name:      postgres.database.svc.cluster.local",[6195,9461,9463],{"className":9462},[3145],"Address:   10.96.0.20",[6195,9465],{"className":9466},[3145],[6195,9468,9470],{"className":9469},[3145],[3143,9471,9473],{"className":9472},[6201],"# Тест 3: Повна форма",[6195,9475,9477,4793,9480],{"className":9476},[3145],[3143,9478,6209],{"className":9479},[6201],[3118,9481,9482],{},"nslookup api-service.default.svc.cluster.local",[6195,9484,9412],{"className":9485},[3145],[6195,9487,9416],{"className":9488},[3145],[6195,9490],{"className":9491},[3145],[6195,9493,9423],{"className":9494},[3145],[6195,9496,9427],{"className":9497},[3145],[6195,9499],{"className":9500},[3145],[6195,9502,9504],{"className":9503},[3145],[3143,9505,9507],{"className":9506},[6201],"# Тест 4: HTTP-запит через DNS-ім'я",[6195,9509,9511,4793,9514],{"className":9510},[3145],[3143,9512,6209],{"className":9513},[6201],[3118,9515,9516],{},"curl http://api-service/health",[6195,9518,9520],{"className":9519},[3145],"{\"status\":\"healthy\",\"version\":\"1.0.0\"}",[3582,9522],{},[3109,9524,9526],{"id":9525},"headless-service-прямий-доступ-до-pod","Headless Service — прямий доступ до Pod",[3114,9528,9529,9532,9533,9536,9537,9540],{},[3118,9530,9531],{},"Headless Service"," — це Service ",[3118,9534,9535],{},"без ClusterIP"," (",[3140,9538,9539],{},"clusterIP: None","). Замість балансування навантаження через Service IP, DNS повертає IP-адреси всіх Pod напряму.",[3122,9542,9544],{"id":9543},"навіщо-потрібен-headless-service","Навіщо потрібен Headless Service",[3372,9546,9547,9565,9576],{},[3375,9548,9550,9560],{"icon":7567,"title":9549},"StatefulSet",[3114,9551,9552,9553,9556,9557,3580],{},"Для stateful застосунків (бази даних, черги) потрібен доступ до ",[3118,9554,9555],{},"конкретного Pod"," за стабільним DNS-іменем. Headless Service надає DNS-запис для кожного Pod: ",[3140,9558,9559],{},"\u003Cpod-name>.\u003Cservice-name>.\u003Cnamespace>.svc.cluster.local",[3114,9561,9562,9564],{},[3118,9563,3403],{}," PostgreSQL primary/replica — клієнт має звертатись до primary для запису, до replica для читання.",[3375,9566,9568,9571],{"icon":3436,"title":9567},"Service Discovery",[3114,9569,9570],{},"Застосунок сам хоче керувати балансуванням навантаження або вибором Pod. Headless Service надає список всіх IP-адрес Pod, а застосунок сам вирішує, до якого звертатись.",[3114,9572,9573,9575],{},[3118,9574,3403],{}," Elasticsearch cluster — клієнт отримує список всіх вузлів та сам розподіляє запити.",[3375,9577,9580,9583],{"icon":9578,"title":9579},"i-heroicons-users","Peer Discovery",[3114,9581,9582],{},"Застосунки, які потребують знати про всіх інших членів кластера (наприклад, для формування quorum або gossip protocol).",[3114,9584,9585,9587],{},[3118,9586,3403],{}," Kafka, Cassandra, etcd — кожен вузол має знати про інших.",[3122,9589,9591],{"id":9590},"створення-headless-service","Створення Headless Service",[3133,9593,9595],{"className":3443,"code":9594,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: postgres-headless\nspec:\n  clusterIP: None  # ← Це робить Service headless\n  selector:\n    app: postgres\n  ports:\n    - port: 5432\n      targetPort: 5432\n",[3140,9596,9597,9605,9613,9619,9628,9634,9647,9653,9662,9668,9679],{"__ignoreMap":3138},[3143,9598,9599,9601,9603],{"class":3145,"line":3146},[3143,9600,4039],{"class":3452},[3143,9602,3516],{"class":3456},[3143,9604,4044],{"class":3479},[3143,9606,9607,9609,9611],{"class":3145,"line":3152},[3143,9608,4049],{"class":3452},[3143,9610,3516],{"class":3456},[3143,9612,4054],{"class":3479},[3143,9614,9615,9617],{"class":3145,"line":3158},[3143,9616,4059],{"class":3452},[3143,9618,3457],{"class":3456},[3143,9620,9621,9623,9625],{"class":3145,"line":3164},[3143,9622,4066],{"class":3452},[3143,9624,3516],{"class":3456},[3143,9626,9627],{"class":3479},"postgres-headless\n",[3143,9629,9630,9632],{"class":3145,"line":3171},[3143,9631,4086],{"class":3452},[3143,9633,3457],{"class":3456},[3143,9635,9636,9639,9641,9644],{"class":3145,"line":3177},[3143,9637,9638],{"class":3452},"  clusterIP",[3143,9640,3516],{"class":3456},[3143,9642,9643],{"class":3479},"None",[3143,9645,9646],{"class":4245},"  # ← Це робить Service headless\n",[3143,9648,9649,9651],{"class":3145,"line":3183},[3143,9650,4093],{"class":3452},[3143,9652,3457],{"class":3456},[3143,9654,9655,9657,9659],{"class":3145,"line":3189},[3143,9656,4100],{"class":3452},[3143,9658,3516],{"class":3456},[3143,9660,9661],{"class":3479},"postgres\n",[3143,9663,9664,9666],{"class":3145,"line":3195},[3143,9665,4110],{"class":3452},[3143,9667,3457],{"class":3456},[3143,9669,9670,9672,9674,9676],{"class":3145,"line":3201},[3143,9671,4117],{"class":3456},[3143,9673,4338],{"class":3452},[3143,9675,3516],{"class":3456},[3143,9677,9678],{"class":3673},"5432\n",[3143,9680,9681,9683,9685],{"class":3145,"line":3207},[3143,9682,4149],{"class":3452},[3143,9684,3516],{"class":3456},[3143,9686,9678],{"class":3673},[3114,9688,9689],{},[3118,9690,5186],{},[3542,9692,9693,9696,9699],{},[3390,9694,9695],{},"Kubernetes НЕ виділяє ClusterIP",[3390,9697,9698],{},"CoreDNS створює A-записи для кожного Pod",[3390,9700,9701],{},"DNS-запит повертає список IP-адрес всіх Pod",[3122,9703,9705],{"id":9704},"dns-записи-headless-service","DNS-записи Headless Service",[3130,9707,9708],{},[3133,9709,9711],{"className":3135,"code":9710,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ncomponent \"CoreDNS\" as dns #e3f2fd\n\ncomponent \"Headless Service\\npostgres-headless\" as svc #fff3e0 {\n    [clusterIP: None]\n}\n\npackage \"StatefulSet Pods\" {\n    component \"postgres-0\\n10.244.1.10\" as p0 #e8f5e9\n    component \"postgres-1\\n10.244.1.11\" as p1 #e8f5e9\n    component \"postgres-2\\n10.244.1.12\" as p2 #e8f5e9\n}\n\ndns --> svc : Create DNS records\n\nnote right of dns\n    DNS-записи:\n    \n    postgres-headless.default.svc.cluster.local\n    → 10.244.1.10, 10.244.1.11, 10.244.1.12\n    \n    postgres-0.postgres-headless.default.svc.cluster.local\n    → 10.244.1.10\n    \n    postgres-1.postgres-headless.default.svc.cluster.local\n    → 10.244.1.11\n    \n    postgres-2.postgres-headless.default.svc.cluster.local\n    → 10.244.1.12\nend note\n\n@enduml\n",[3140,9712,9713,9717,9721,9725,9729,9734,9738,9743,9748,9752,9756,9761,9766,9771,9776,9780,9784,9789,9793,9797,9802,9806,9811,9816,9820,9825,9830,9834,9839,9844,9848,9853,9858,9862,9866],{"__ignoreMap":3138},[3143,9714,9715],{"class":3145,"line":3146},[3143,9716,3149],{},[3143,9718,9719],{"class":3145,"line":3152},[3143,9720,3155],{},[3143,9722,9723],{"class":3145,"line":3158},[3143,9724,3161],{},[3143,9726,9727],{"class":3145,"line":3164},[3143,9728,3168],{"emptyLinePlaceholder":3167},[3143,9730,9731],{"class":3145,"line":3171},[3143,9732,9733],{},"component \"CoreDNS\" as dns #e3f2fd\n",[3143,9735,9736],{"class":3145,"line":3177},[3143,9737,3168],{"emptyLinePlaceholder":3167},[3143,9739,9740],{"class":3145,"line":3183},[3143,9741,9742],{},"component \"Headless Service\\npostgres-headless\" as svc #fff3e0 {\n",[3143,9744,9745],{"class":3145,"line":3189},[3143,9746,9747],{},"    [clusterIP: None]\n",[3143,9749,9750],{"class":3145,"line":3195},[3143,9751,3239],{},[3143,9753,9754],{"class":3145,"line":3201},[3143,9755,3168],{"emptyLinePlaceholder":3167},[3143,9757,9758],{"class":3145,"line":3207},[3143,9759,9760],{},"package \"StatefulSet Pods\" {\n",[3143,9762,9763],{"class":3145,"line":3213},[3143,9764,9765],{},"    component \"postgres-0\\n10.244.1.10\" as p0 #e8f5e9\n",[3143,9767,9768],{"class":3145,"line":3219},[3143,9769,9770],{},"    component \"postgres-1\\n10.244.1.11\" as p1 #e8f5e9\n",[3143,9772,9773],{"class":3145,"line":3225},[3143,9774,9775],{},"    component \"postgres-2\\n10.244.1.12\" as p2 #e8f5e9\n",[3143,9777,9778],{"class":3145,"line":3231},[3143,9779,3239],{},[3143,9781,9782],{"class":3145,"line":3236},[3143,9783,3168],{"emptyLinePlaceholder":3167},[3143,9785,9786],{"class":3145,"line":3242},[3143,9787,9788],{},"dns --> svc : Create DNS records\n",[3143,9790,9791],{"class":3145,"line":3247},[3143,9792,3168],{"emptyLinePlaceholder":3167},[3143,9794,9795],{"class":3145,"line":3253},[3143,9796,8801],{},[3143,9798,9799],{"class":3145,"line":3259},[3143,9800,9801],{},"    DNS-записи:\n",[3143,9803,9804],{"class":3145,"line":3265},[3143,9805,3204],{},[3143,9807,9808],{"class":3145,"line":3270},[3143,9809,9810],{},"    postgres-headless.default.svc.cluster.local\n",[3143,9812,9813],{"class":3145,"line":3276},[3143,9814,9815],{},"    → 10.244.1.10, 10.244.1.11, 10.244.1.12\n",[3143,9817,9818],{"class":3145,"line":3282},[3143,9819,3204],{},[3143,9821,9822],{"class":3145,"line":3288},[3143,9823,9824],{},"    postgres-0.postgres-headless.default.svc.cluster.local\n",[3143,9826,9827],{"class":3145,"line":3293},[3143,9828,9829],{},"    → 10.244.1.10\n",[3143,9831,9832],{"class":3145,"line":3299},[3143,9833,3204],{},[3143,9835,9836],{"class":3145,"line":3305},[3143,9837,9838],{},"    postgres-1.postgres-headless.default.svc.cluster.local\n",[3143,9840,9841],{"class":3145,"line":3311},[3143,9842,9843],{},"    → 10.244.1.11\n",[3143,9845,9846],{"class":3145,"line":3317},[3143,9847,3204],{},[3143,9849,9850],{"class":3145,"line":3323},[3143,9851,9852],{},"    postgres-2.postgres-headless.default.svc.cluster.local\n",[3143,9854,9855],{"class":3145,"line":3328},[3143,9856,9857],{},"    → 10.244.1.12\n",[3143,9859,9860],{"class":3145,"line":3334},[3143,9861,3320],{},[3143,9863,9864],{"class":3145,"line":3340},[3143,9865,3168],{"emptyLinePlaceholder":3167},[3143,9867,9868],{"class":3145,"line":3346},[3143,9869,3365],{},[3114,9871,9872],{},[3118,9873,9874],{},"DNS-записи:",[3542,9876,9877,9889],{},[3390,9878,9879,9882,9883],{},[3118,9880,9881],{},"Service DNS"," — повертає всі Pod:",[3133,9884,9887],{"className":9885,"code":9886,"language":5432},[5430],"postgres-headless.default.svc.cluster.local\n→ 10.244.1.10, 10.244.1.11, 10.244.1.12\n",[3140,9888,9886],{"__ignoreMap":3138},[3390,9890,9891,9894,9895],{},[3118,9892,9893],{},"Pod DNS"," (лише для StatefulSet) — повертає конкретний Pod:",[3133,9896,9899],{"className":9897,"code":9898,"language":5432},[5430],"postgres-0.postgres-headless.default.svc.cluster.local → 10.244.1.10\npostgres-1.postgres-headless.default.svc.cluster.local → 10.244.1.11\npostgres-2.postgres-headless.default.svc.cluster.local → 10.244.1.12\n",[3140,9900,9898],{"__ignoreMap":3138},[3122,9902,9904],{"id":9903},"тестування-headless-service","Тестування Headless Service",[6191,9906,9908,9916,9919,9926,9935,9938,9941,9944,9948,9952,9956,9960,9963,9970,9979,9982,9985,9988,9992],{"title":9907},"DNS resolution для Headless Service",[6195,9909,9911,4793,9914],{"className":9910},[3145],[3143,9912,6209],{"className":9913},[6201],[3118,9915,9389],{},[6195,9917],{"className":9918},[3145],[6195,9920,9922],{"className":9921},[3145],[3143,9923,9925],{"className":9924},[6201],"# DNS-запит до Headless Service (повертає всі Pod)",[6195,9927,9929,4793,9932],{"className":9928},[3145],[3143,9930,6209],{"className":9931},[6201],[3118,9933,9934],{},"nslookup postgres-headless.default.svc.cluster.local",[6195,9936,9412],{"className":9937},[3145],[6195,9939,9416],{"className":9940},[3145],[6195,9942],{"className":9943},[3145],[6195,9945,9947],{"className":9946},[3145],"Name:      postgres-headless.default.svc.cluster.local",[6195,9949,9951],{"className":9950},[3145],"Address:   10.244.1.10",[6195,9953,9955],{"className":9954},[3145],"Address:   10.244.1.11",[6195,9957,9959],{"className":9958},[3145],"Address:   10.244.1.12",[6195,9961],{"className":9962},[3145],[6195,9964,9966],{"className":9965},[3145],[3143,9967,9969],{"className":9968},[6201],"# DNS-запит до конкретного Pod (StatefulSet)",[6195,9971,9973,4793,9976],{"className":9972},[3145],[3143,9974,6209],{"className":9975},[6201],[3118,9977,9978],{},"nslookup postgres-0.postgres-headless.default.svc.cluster.local",[6195,9980,9412],{"className":9981},[3145],[6195,9983,9416],{"className":9984},[3145],[6195,9986],{"className":9987},[3145],[6195,9989,9991],{"className":9990},[3145],"Name:      postgres-0.postgres-headless.default.svc.cluster.local",[6195,9993,9951],{"className":9994},[3145],[3122,9996,9998],{"id":9997},"використання-у-net","Використання у .NET",[3114,10000,10001],{},[3118,10002,10003],{},"Приклад: PostgreSQL primary/replica:",[3133,10005,10007],{"className":5511,"code":10006,"language":5513,"meta":3138,"style":3138},"var builder = WebApplication.CreateBuilder(args);\n\n// Primary для запису\nvar primaryHost = \"postgres-0.postgres-headless.default.svc.cluster.local\";\nvar primaryConnectionString = $\"Host={primaryHost};Database=mydb;Username=user;Password=pass\";\n\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseNpgsql(primaryConnectionString));\n\n// Replica для читання\nvar replicaHost = \"postgres-1.postgres-headless.default.svc.cluster.local\";\nvar replicaConnectionString = $\"Host={replicaHost};Database=mydb;Username=user;Password=pass\";\n\nbuilder.Services.AddDbContext\u003CReadOnlyDbContext>(options =>\n    options.UseNpgsql(replicaConnectionString));\n\nvar app = builder.Build();\napp.Run();\n",[3140,10008,10009,10029,10033,10038,10052,10079,10083,10105,10120,10124,10129,10143,10165,10169,10192,10207,10211,10227],{"__ignoreMap":3138},[3143,10010,10011,10013,10015,10017,10019,10021,10023,10025,10027],{"class":3145,"line":3146},[3143,10012,5521],{"class":5520},[3143,10014,5525],{"class":5524},[3143,10016,5528],{"class":3456},[3143,10018,5531],{"class":5524},[3143,10020,3580],{"class":3456},[3143,10022,5537],{"class":5536},[3143,10024,5540],{"class":3456},[3143,10026,5543],{"class":5524},[3143,10028,5546],{"class":3456},[3143,10030,10031],{"class":3145,"line":3152},[3143,10032,3168],{"emptyLinePlaceholder":3167},[3143,10034,10035],{"class":3145,"line":3158},[3143,10036,10037],{"class":4245},"// Primary для запису\n",[3143,10039,10040,10042,10045,10047,10050],{"class":3145,"line":3164},[3143,10041,5521],{"class":5520},[3143,10043,10044],{"class":5524}," primaryHost",[3143,10046,5528],{"class":3456},[3143,10048,10049],{"class":3529},"\"postgres-0.postgres-headless.default.svc.cluster.local\"",[3143,10051,5587],{"class":3456},[3143,10053,10054,10056,10059,10061,10064,10068,10071,10074,10077],{"class":3145,"line":3171},[3143,10055,5521],{"class":5520},[3143,10057,10058],{"class":5524}," primaryConnectionString",[3143,10060,5528],{"class":3456},[3143,10062,10063],{"class":3529},"$\"Host=",[3143,10065,10067],{"class":10066},"sD7JJ","{",[3143,10069,10070],{"class":5524},"primaryHost",[3143,10072,10073],{"class":10066},"}",[3143,10075,10076],{"class":3529},";Database=mydb;Username=user;Password=pass\"",[3143,10078,5587],{"class":3456},[3143,10080,10081],{"class":3145,"line":3177},[3143,10082,3168],{"emptyLinePlaceholder":3167},[3143,10084,10085,10087,10089,10091,10093,10095,10097,10099,10101,10103],{"class":3145,"line":3183},[3143,10086,5567],{"class":5524},[3143,10088,3580],{"class":3456},[3143,10090,5600],{"class":5524},[3143,10092,3580],{"class":3456},[3143,10094,7431],{"class":5536},[3143,10096,7434],{"class":3456},[3143,10098,7437],{"class":5642},[3143,10100,7440],{"class":3456},[3143,10102,7443],{"class":5524},[3143,10104,5619],{"class":3456},[3143,10106,10107,10109,10111,10113,10115,10118],{"class":3145,"line":3189},[3143,10108,7450],{"class":5524},[3143,10110,3580],{"class":3456},[3143,10112,7455],{"class":5536},[3143,10114,5540],{"class":3456},[3143,10116,10117],{"class":5524},"primaryConnectionString",[3143,10119,7463],{"class":3456},[3143,10121,10122],{"class":3145,"line":3195},[3143,10123,3168],{"emptyLinePlaceholder":3167},[3143,10125,10126],{"class":3145,"line":3201},[3143,10127,10128],{"class":4245},"// Replica для читання\n",[3143,10130,10131,10133,10136,10138,10141],{"class":3145,"line":3207},[3143,10132,5521],{"class":5520},[3143,10134,10135],{"class":5524}," replicaHost",[3143,10137,5528],{"class":3456},[3143,10139,10140],{"class":3529},"\"postgres-1.postgres-headless.default.svc.cluster.local\"",[3143,10142,5587],{"class":3456},[3143,10144,10145,10147,10150,10152,10154,10156,10159,10161,10163],{"class":3145,"line":3213},[3143,10146,5521],{"class":5520},[3143,10148,10149],{"class":5524}," replicaConnectionString",[3143,10151,5528],{"class":3456},[3143,10153,10063],{"class":3529},[3143,10155,10067],{"class":10066},[3143,10157,10158],{"class":5524},"replicaHost",[3143,10160,10073],{"class":10066},[3143,10162,10076],{"class":3529},[3143,10164,5587],{"class":3456},[3143,10166,10167],{"class":3145,"line":3219},[3143,10168,3168],{"emptyLinePlaceholder":3167},[3143,10170,10171,10173,10175,10177,10179,10181,10183,10186,10188,10190],{"class":3145,"line":3225},[3143,10172,5567],{"class":5524},[3143,10174,3580],{"class":3456},[3143,10176,5600],{"class":5524},[3143,10178,3580],{"class":3456},[3143,10180,7431],{"class":5536},[3143,10182,7434],{"class":3456},[3143,10184,10185],{"class":5642},"ReadOnlyDbContext",[3143,10187,7440],{"class":3456},[3143,10189,7443],{"class":5524},[3143,10191,5619],{"class":3456},[3143,10193,10194,10196,10198,10200,10202,10205],{"class":3145,"line":3231},[3143,10195,7450],{"class":5524},[3143,10197,3580],{"class":3456},[3143,10199,7455],{"class":5536},[3143,10201,5540],{"class":3456},[3143,10203,10204],{"class":5524},"replicaConnectionString",[3143,10206,7463],{"class":3456},[3143,10208,10209],{"class":3145,"line":3236},[3143,10210,3168],{"emptyLinePlaceholder":3167},[3143,10212,10213,10215,10217,10219,10221,10223,10225],{"class":3145,"line":3242},[3143,10214,5521],{"class":5520},[3143,10216,5666],{"class":5524},[3143,10218,5528],{"class":3456},[3143,10220,5567],{"class":5524},[3143,10222,3580],{"class":3456},[3143,10224,5675],{"class":5536},[3143,10226,5678],{"class":3456},[3143,10228,10229,10231,10233,10235],{"class":3145,"line":3247},[3143,10230,5683],{"class":5524},[3143,10232,3580],{"class":3456},[3143,10234,5688],{"class":5536},[3143,10236,5678],{"class":3456},[3114,10238,10239],{},[3118,10240,10241],{},"Приклад: Service Discovery (отримання всіх Pod):",[3133,10243,10245],{"className":5511,"code":10244,"language":5513,"meta":3138,"style":3138},"using System.Net;\n\nvar serviceName = \"postgres-headless.default.svc.cluster.local\";\nvar addresses = await Dns.GetHostAddressesAsync(serviceName);\n\nforeach (var address in addresses)\n{\n    Console.WriteLine($\"Pod IP: {address}\");\n}\n\n// Output:\n// Pod IP: 10.244.1.10\n// Pod IP: 10.244.1.11\n// Pod IP: 10.244.1.12\n",[3140,10246,10247,10262,10266,10280,10307,10311,10331,10335,10362,10366,10370,10375,10380,10385],{"__ignoreMap":3138},[3143,10248,10249,10252,10255,10257,10260],{"class":3145,"line":3146},[3143,10250,10251],{"class":8194},"using",[3143,10253,10254],{"class":5642}," System",[3143,10256,3580],{"class":3456},[3143,10258,10259],{"class":5642},"Net",[3143,10261,5587],{"class":3456},[3143,10263,10264],{"class":3145,"line":3152},[3143,10265,3168],{"emptyLinePlaceholder":3167},[3143,10267,10268,10270,10273,10275,10278],{"class":3145,"line":3158},[3143,10269,5521],{"class":5520},[3143,10271,10272],{"class":5524}," serviceName",[3143,10274,5528],{"class":3456},[3143,10276,10277],{"class":3529},"\"postgres-headless.default.svc.cluster.local\"",[3143,10279,5587],{"class":3456},[3143,10281,10282,10284,10287,10289,10292,10295,10297,10300,10302,10305],{"class":3145,"line":3164},[3143,10283,5521],{"class":5520},[3143,10285,10286],{"class":5524}," addresses",[3143,10288,5528],{"class":3456},[3143,10290,10291],{"class":5520},"await",[3143,10293,10294],{"class":5524}," Dns",[3143,10296,3580],{"class":3456},[3143,10298,10299],{"class":5536},"GetHostAddressesAsync",[3143,10301,5540],{"class":3456},[3143,10303,10304],{"class":5524},"serviceName",[3143,10306,5546],{"class":3456},[3143,10308,10309],{"class":3145,"line":3171},[3143,10310,3168],{"emptyLinePlaceholder":3167},[3143,10312,10313,10316,10318,10320,10323,10326,10328],{"class":3145,"line":3177},[3143,10314,10315],{"class":8194},"foreach",[3143,10317,9536],{"class":3456},[3143,10319,5521],{"class":5520},[3143,10321,10322],{"class":5524}," address",[3143,10324,10325],{"class":8194}," in",[3143,10327,10286],{"class":5524},[3143,10329,10330],{"class":3456},")\n",[3143,10332,10333],{"class":3145,"line":3183},[3143,10334,5624],{"class":3456},[3143,10336,10337,10340,10342,10345,10347,10350,10352,10355,10357,10360],{"class":3145,"line":3189},[3143,10338,10339],{"class":5524},"    Console",[3143,10341,3580],{"class":3456},[3143,10343,10344],{"class":5536},"WriteLine",[3143,10346,5540],{"class":3456},[3143,10348,10349],{"class":3529},"$\"Pod IP: ",[3143,10351,10067],{"class":10066},[3143,10353,10354],{"class":5524},"address",[3143,10356,10073],{"class":10066},[3143,10358,10359],{"class":3529},"\"",[3143,10361,5546],{"class":3456},[3143,10363,10364],{"class":3145,"line":3195},[3143,10365,3239],{"class":3456},[3143,10367,10368],{"class":3145,"line":3201},[3143,10369,3168],{"emptyLinePlaceholder":3167},[3143,10371,10372],{"class":3145,"line":3207},[3143,10373,10374],{"class":4245},"// Output:\n",[3143,10376,10377],{"class":3145,"line":3213},[3143,10378,10379],{"class":4245},"// Pod IP: 10.244.1.10\n",[3143,10381,10382],{"class":3145,"line":3219},[3143,10383,10384],{"class":4245},"// Pod IP: 10.244.1.11\n",[3143,10386,10387],{"class":3145,"line":3225},[3143,10388,10389],{"class":4245},"// Pod IP: 10.244.1.12\n",[3582,10391],{},[3109,10393,10395],{"id":10394},"endpoints-та-endpointslices","Endpoints та EndpointSlices",[3114,10397,10398,10400],{},[3118,10399,4013],{}," — це об'єкт Kubernetes, який містить список IP:Port всіх Pod, які відповідають селектору Service.",[3122,10402,10404],{"id":10403},"що-таке-endpoints","Що таке Endpoints",[3114,10406,10407,10408,10410],{},"Коли ви створюєте Service, Kubernetes автоматично створює об'єкт ",[3118,10409,4013],{}," з тим самим іменем:",[3130,10412,10413],{},[3133,10414,10416],{"className":3135,"code":10415,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ncomponent \"Service\\napi-service\" as svc #e3f2fd {\n    [selector: app=api]\n}\n\ncomponent \"Endpoints\\napi-service\" as ep #fff3e0 {\n    [10.244.1.10:8080]\n    [10.244.1.11:8080]\n    [10.244.1.12:8080]\n}\n\npackage \"Pods\" {\n    component \"Pod 1\\napp=api\\n10.244.1.10\" as p1 #e8f5e9\n    component \"Pod 2\\napp=api\\n10.244.1.11\" as p2 #e8f5e9\n    component \"Pod 3\\napp=api\\n10.244.1.12\" as p3 #e8f5e9\n}\n\ncomponent \"Endpoints Controller\" as ctrl\n\nctrl --> svc : Watch\nctrl --> p1 : Watch\nctrl --> p2 : Watch\nctrl --> p3 : Watch\nctrl --> ep : Update\n\nnote right of ctrl\n    Endpoints Controller\n    стежить за Pod та Service\n    \n    Автоматично оновлює\n    Endpoints при зміні Pod\nend note\n\nnote right of ep\n    Endpoints містить\n    список IP:Port\n    всіх готових Pod\nend note\n\n@enduml\n",[3140,10417,10418,10422,10426,10430,10434,10438,10443,10447,10451,10456,10461,10466,10471,10475,10479,10484,10489,10494,10499,10503,10507,10512,10516,10521,10526,10531,10536,10541,10545,10550,10555,10560,10564,10569,10574,10578,10582,10586,10591,10596,10601,10605,10609],{"__ignoreMap":3138},[3143,10419,10420],{"class":3145,"line":3146},[3143,10421,3149],{},[3143,10423,10424],{"class":3145,"line":3152},[3143,10425,3155],{},[3143,10427,10428],{"class":3145,"line":3158},[3143,10429,3161],{},[3143,10431,10432],{"class":3145,"line":3164},[3143,10433,3168],{"emptyLinePlaceholder":3167},[3143,10435,10436],{"class":3145,"line":3171},[3143,10437,4485],{},[3143,10439,10440],{"class":3145,"line":3177},[3143,10441,10442],{},"    [selector: app=api]\n",[3143,10444,10445],{"class":3145,"line":3183},[3143,10446,3239],{},[3143,10448,10449],{"class":3145,"line":3189},[3143,10450,3168],{"emptyLinePlaceholder":3167},[3143,10452,10453],{"class":3145,"line":3195},[3143,10454,10455],{},"component \"Endpoints\\napi-service\" as ep #fff3e0 {\n",[3143,10457,10458],{"class":3145,"line":3201},[3143,10459,10460],{},"    [10.244.1.10:8080]\n",[3143,10462,10463],{"class":3145,"line":3207},[3143,10464,10465],{},"    [10.244.1.11:8080]\n",[3143,10467,10468],{"class":3145,"line":3213},[3143,10469,10470],{},"    [10.244.1.12:8080]\n",[3143,10472,10473],{"class":3145,"line":3219},[3143,10474,3239],{},[3143,10476,10477],{"class":3145,"line":3225},[3143,10478,3168],{"emptyLinePlaceholder":3167},[3143,10480,10481],{"class":3145,"line":3231},[3143,10482,10483],{},"package \"Pods\" {\n",[3143,10485,10486],{"class":3145,"line":3236},[3143,10487,10488],{},"    component \"Pod 1\\napp=api\\n10.244.1.10\" as p1 #e8f5e9\n",[3143,10490,10491],{"class":3145,"line":3242},[3143,10492,10493],{},"    component \"Pod 2\\napp=api\\n10.244.1.11\" as p2 #e8f5e9\n",[3143,10495,10496],{"class":3145,"line":3247},[3143,10497,10498],{},"    component \"Pod 3\\napp=api\\n10.244.1.12\" as p3 #e8f5e9\n",[3143,10500,10501],{"class":3145,"line":3253},[3143,10502,3239],{},[3143,10504,10505],{"class":3145,"line":3259},[3143,10506,3168],{"emptyLinePlaceholder":3167},[3143,10508,10509],{"class":3145,"line":3265},[3143,10510,10511],{},"component \"Endpoints Controller\" as ctrl\n",[3143,10513,10514],{"class":3145,"line":3270},[3143,10515,3168],{"emptyLinePlaceholder":3167},[3143,10517,10518],{"class":3145,"line":3276},[3143,10519,10520],{},"ctrl --> svc : Watch\n",[3143,10522,10523],{"class":3145,"line":3282},[3143,10524,10525],{},"ctrl --> p1 : Watch\n",[3143,10527,10528],{"class":3145,"line":3288},[3143,10529,10530],{},"ctrl --> p2 : Watch\n",[3143,10532,10533],{"class":3145,"line":3293},[3143,10534,10535],{},"ctrl --> p3 : Watch\n",[3143,10537,10538],{"class":3145,"line":3299},[3143,10539,10540],{},"ctrl --> ep : Update\n",[3143,10542,10543],{"class":3145,"line":3305},[3143,10544,3168],{"emptyLinePlaceholder":3167},[3143,10546,10547],{"class":3145,"line":3311},[3143,10548,10549],{},"note right of ctrl\n",[3143,10551,10552],{"class":3145,"line":3317},[3143,10553,10554],{},"    Endpoints Controller\n",[3143,10556,10557],{"class":3145,"line":3323},[3143,10558,10559],{},"    стежить за Pod та Service\n",[3143,10561,10562],{"class":3145,"line":3328},[3143,10563,3204],{},[3143,10565,10566],{"class":3145,"line":3334},[3143,10567,10568],{},"    Автоматично оновлює\n",[3143,10570,10571],{"class":3145,"line":3340},[3143,10572,10573],{},"    Endpoints при зміні Pod\n",[3143,10575,10576],{"class":3145,"line":3346},[3143,10577,3320],{},[3143,10579,10580],{"class":3145,"line":3352},[3143,10581,3168],{"emptyLinePlaceholder":3167},[3143,10583,10584],{"class":3145,"line":3357},[3143,10585,3946],{},[3143,10587,10588],{"class":3145,"line":3362},[3143,10589,10590],{},"    Endpoints містить\n",[3143,10592,10593],{"class":3145,"line":3869},[3143,10594,10595],{},"    список IP:Port\n",[3143,10597,10598],{"class":3145,"line":3875},[3143,10599,10600],{},"    всіх готових Pod\n",[3143,10602,10603],{"class":3145,"line":3881},[3143,10604,3320],{},[3143,10606,10607],{"class":3145,"line":3887},[3143,10608,3168],{"emptyLinePlaceholder":3167},[3143,10610,10611],{"class":3145,"line":3893},[3143,10612,3365],{},[3122,10614,10616],{"id":10615},"перегляд-endpoints","Перегляд Endpoints",[6191,10618,10620,10629,10633],{"title":10619},"kubectl get endpoints",[6195,10621,10623,4793,10626],{"className":10622},[3145],[3143,10624,6209],{"className":10625},[6201],[3118,10627,10628],{},"kubectl get endpoints api-service",[6195,10630,10632],{"className":10631},[3145],"NAME          ENDPOINTS                                         AGE",[6195,10634,10636],{"className":10635},[3145],"api-service   10.244.1.10:8080,10.244.1.11:8080,10.244.1.12:8080   5m",[3114,10638,10639],{},[3118,10640,10641],{},"Детальна інформація:",[6191,10643,10645,10654,10658,10662,10669,10673,10677,10681,10687,10691,10695,10699],{"title":10644},"kubectl describe endpoints",[6195,10646,10648,4793,10651],{"className":10647},[3145],[3143,10649,6209],{"className":10650},[6201],[3118,10652,10653],{},"kubectl describe endpoints api-service",[6195,10655,10657],{"className":10656},[3145],"Name:         api-service",[6195,10659,10661],{"className":10660},[3145],"Namespace:    default",[6195,10663,10665,10666],{"className":10664},[3145],"Labels:       ",[10667,10668],"none",{},[6195,10670,10672],{"className":10671},[3145],"Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2026-05-10T17:30:00Z",[6195,10674,10676],{"className":10675},[3145],"Subsets:",[6195,10678,10680],{"className":10679},[3145],"  Addresses:          10.244.1.10,10.244.1.11,10.244.1.12",[6195,10682,10684,10685],{"className":10683},[3145],"  NotReadyAddresses:  ",[10667,10686],{},[6195,10688,10690],{"className":10689},[3145],"  Ports:",[6195,10692,10694],{"className":10693},[3145],"    Name  Port  Protocol",[6195,10696,10698],{"className":10697},[3145],"    ----  ----  --------",[6195,10700,10702],{"className":10701},[3145],"    http  8080  TCP",[3114,10704,10705],{},[3118,10706,10707],{},"Важливі поля:",[3387,10709,10710,10716,10722],{},[3390,10711,10712,10715],{},[3118,10713,10714],{},"Addresses"," — список IP-адрес готових Pod (пройшли readiness probe)",[3390,10717,10718,10721],{},[3118,10719,10720],{},"NotReadyAddresses"," — список IP-адрес Pod, які ще не готові",[3390,10723,10724,10727],{},[3118,10725,10726],{},"Ports"," — порти, на яких слухають Pod",[3122,10729,10731],{"id":10730},"як-endpoints-оновлюються","Як Endpoints оновлюються",[3114,10733,10734],{},"Endpoints Controller постійно стежить за Pod та автоматично оновлює Endpoints:",[3130,10736,10737],{},[3133,10738,10740],{"className":3135,"code":10739,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nparticipant \"Endpoints\\nController\" as ctrl\nparticipant \"API Server\" as api\nparticipant \"Endpoints\\napi-service\" as ep\n\n== Pod стає Ready ==\n\napi -> ctrl : Event: Pod api-xxx Ready=True\nactivate ctrl\nctrl -> ctrl : Pod має мітку app=api\\nта пройшов readiness probe\nctrl -> api : PATCH Endpoints/api-service\\nAdd: 10.244.1.10:8080\ndeactivate ctrl\n\napi -> ep : Update\nep -> ep : Addresses: [10.244.1.10:8080]\n\n== Pod стає NotReady ==\n\napi -> ctrl : Event: Pod api-xxx Ready=False\nactivate ctrl\nctrl -> ctrl : Pod не пройшов readiness probe\nctrl -> api : PATCH Endpoints/api-service\\nMove to NotReadyAddresses\ndeactivate ctrl\n\napi -> ep : Update\nep -> ep : Addresses: []\\nNotReadyAddresses: [10.244.1.10:8080]\n\n== Pod видалено ==\n\napi -> ctrl : Event: Pod api-xxx Deleted\nactivate ctrl\nctrl -> ctrl : Видалити Pod з Endpoints\nctrl -> api : PATCH Endpoints/api-service\\nRemove: 10.244.1.10:8080\ndeactivate ctrl\n\napi -> ep : Update\nep -> ep : Addresses: []\\nNotReadyAddresses: []\n\nnote right of ctrl\n    Endpoints Controller\n    реагує на зміни Pod\n    у реальному часі\n    \n    Це гарантує, що Service\n    надсилає трафік лише\n    на готові Pod\nend note\n\n@enduml\n",[3140,10741,10742,10746,10750,10754,10758,10763,10768,10773,10777,10782,10786,10791,10796,10801,10806,10811,10815,10820,10825,10829,10834,10838,10843,10847,10852,10857,10861,10865,10869,10874,10878,10883,10887,10892,10896,10901,10906,10910,10914,10918,10923,10927,10931,10935,10940,10945,10949,10954,10959,10964,10968,10972],{"__ignoreMap":3138},[3143,10743,10744],{"class":3145,"line":3146},[3143,10745,3149],{},[3143,10747,10748],{"class":3145,"line":3152},[3143,10749,3155],{},[3143,10751,10752],{"class":3145,"line":3158},[3143,10753,3161],{},[3143,10755,10756],{"class":3145,"line":3164},[3143,10757,3168],{"emptyLinePlaceholder":3167},[3143,10759,10760],{"class":3145,"line":3171},[3143,10761,10762],{},"participant \"Endpoints\\nController\" as ctrl\n",[3143,10764,10765],{"class":3145,"line":3177},[3143,10766,10767],{},"participant \"API Server\" as api\n",[3143,10769,10770],{"class":3145,"line":3183},[3143,10771,10772],{},"participant \"Endpoints\\napi-service\" as ep\n",[3143,10774,10775],{"class":3145,"line":3189},[3143,10776,3168],{"emptyLinePlaceholder":3167},[3143,10778,10779],{"class":3145,"line":3195},[3143,10780,10781],{},"== Pod стає Ready ==\n",[3143,10783,10784],{"class":3145,"line":3201},[3143,10785,3168],{"emptyLinePlaceholder":3167},[3143,10787,10788],{"class":3145,"line":3207},[3143,10789,10790],{},"api -> ctrl : Event: Pod api-xxx Ready=True\n",[3143,10792,10793],{"class":3145,"line":3213},[3143,10794,10795],{},"activate ctrl\n",[3143,10797,10798],{"class":3145,"line":3219},[3143,10799,10800],{},"ctrl -> ctrl : Pod має мітку app=api\\nта пройшов readiness probe\n",[3143,10802,10803],{"class":3145,"line":3225},[3143,10804,10805],{},"ctrl -> api : PATCH Endpoints/api-service\\nAdd: 10.244.1.10:8080\n",[3143,10807,10808],{"class":3145,"line":3231},[3143,10809,10810],{},"deactivate ctrl\n",[3143,10812,10813],{"class":3145,"line":3236},[3143,10814,3168],{"emptyLinePlaceholder":3167},[3143,10816,10817],{"class":3145,"line":3242},[3143,10818,10819],{},"api -> ep : Update\n",[3143,10821,10822],{"class":3145,"line":3247},[3143,10823,10824],{},"ep -> ep : Addresses: [10.244.1.10:8080]\n",[3143,10826,10827],{"class":3145,"line":3253},[3143,10828,3168],{"emptyLinePlaceholder":3167},[3143,10830,10831],{"class":3145,"line":3259},[3143,10832,10833],{},"== Pod стає NotReady ==\n",[3143,10835,10836],{"class":3145,"line":3265},[3143,10837,3168],{"emptyLinePlaceholder":3167},[3143,10839,10840],{"class":3145,"line":3270},[3143,10841,10842],{},"api -> ctrl : Event: Pod api-xxx Ready=False\n",[3143,10844,10845],{"class":3145,"line":3276},[3143,10846,10795],{},[3143,10848,10849],{"class":3145,"line":3282},[3143,10850,10851],{},"ctrl -> ctrl : Pod не пройшов readiness probe\n",[3143,10853,10854],{"class":3145,"line":3288},[3143,10855,10856],{},"ctrl -> api : PATCH Endpoints/api-service\\nMove to NotReadyAddresses\n",[3143,10858,10859],{"class":3145,"line":3293},[3143,10860,10810],{},[3143,10862,10863],{"class":3145,"line":3299},[3143,10864,3168],{"emptyLinePlaceholder":3167},[3143,10866,10867],{"class":3145,"line":3305},[3143,10868,10819],{},[3143,10870,10871],{"class":3145,"line":3311},[3143,10872,10873],{},"ep -> ep : Addresses: []\\nNotReadyAddresses: [10.244.1.10:8080]\n",[3143,10875,10876],{"class":3145,"line":3317},[3143,10877,3168],{"emptyLinePlaceholder":3167},[3143,10879,10880],{"class":3145,"line":3323},[3143,10881,10882],{},"== Pod видалено ==\n",[3143,10884,10885],{"class":3145,"line":3328},[3143,10886,3168],{"emptyLinePlaceholder":3167},[3143,10888,10889],{"class":3145,"line":3334},[3143,10890,10891],{},"api -> ctrl : Event: Pod api-xxx Deleted\n",[3143,10893,10894],{"class":3145,"line":3340},[3143,10895,10795],{},[3143,10897,10898],{"class":3145,"line":3346},[3143,10899,10900],{},"ctrl -> ctrl : Видалити Pod з Endpoints\n",[3143,10902,10903],{"class":3145,"line":3352},[3143,10904,10905],{},"ctrl -> api : PATCH Endpoints/api-service\\nRemove: 10.244.1.10:8080\n",[3143,10907,10908],{"class":3145,"line":3357},[3143,10909,10810],{},[3143,10911,10912],{"class":3145,"line":3362},[3143,10913,3168],{"emptyLinePlaceholder":3167},[3143,10915,10916],{"class":3145,"line":3869},[3143,10917,10819],{},[3143,10919,10920],{"class":3145,"line":3875},[3143,10921,10922],{},"ep -> ep : Addresses: []\\nNotReadyAddresses: []\n",[3143,10924,10925],{"class":3145,"line":3881},[3143,10926,3168],{"emptyLinePlaceholder":3167},[3143,10928,10929],{"class":3145,"line":3887},[3143,10930,10549],{},[3143,10932,10933],{"class":3145,"line":3893},[3143,10934,10554],{},[3143,10936,10937],{"class":3145,"line":3899},[3143,10938,10939],{},"    реагує на зміни Pod\n",[3143,10941,10942],{"class":3145,"line":3904},[3143,10943,10944],{},"    у реальному часі\n",[3143,10946,10947],{"class":3145,"line":3909},[3143,10948,3204],{},[3143,10950,10951],{"class":3145,"line":3915},[3143,10952,10953],{},"    Це гарантує, що Service\n",[3143,10955,10956],{"class":3145,"line":3921},[3143,10957,10958],{},"    надсилає трафік лише\n",[3143,10960,10961],{"class":3145,"line":3927},[3143,10962,10963],{},"    на готові Pod\n",[3143,10965,10966],{"class":3145,"line":3933},[3143,10967,3320],{},[3143,10969,10970],{"class":3145,"line":3938},[3143,10971,3168],{"emptyLinePlaceholder":3167},[3143,10973,10974],{"class":3145,"line":3943},[3143,10975,3365],{},[3114,10977,10978,10980,10981,10984,10985,10987,10988,3596,10990,3580],{},[3118,10979,4204],{}," Лише Pod, які ",[3118,10982,10983],{},"пройшли readiness probe",", додаються до ",[3140,10986,10714],{},". Pod, які не готові, потрапляють до ",[3140,10989,10720],{},[3118,10991,10992],{},"не отримують трафік",[3122,10994,10996],{"id":10995},"endpointslices-масштабована-альтернатива","EndpointSlices — масштабована альтернатива",[3114,10998,10999,11002],{},[3118,11000,11001],{},"Проблема Endpoints:"," Якщо у Service 1000 Pod, об'єкт Endpoints містить 1000 IP-адрес. При кожній зміні (додавання/видалення Pod) весь об'єкт оновлюється, що створює навантаження на API Server та etcd.",[3114,11004,11005,4793,11008,11011],{},[3118,11006,11007],{},"Рішення:",[3118,11009,11010],{},"EndpointSlices"," (Kubernetes 1.21+) — розбиває Endpoints на менші частини (slices).",[3130,11013,11014],{},[3133,11015,11017],{"className":3135,"code":11016,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ncomponent \"Service\\napi-service\" as svc #e3f2fd\n\npackage \"EndpointSlices\" {\n    component \"EndpointSlice 1\" as es1 #fff3e0 {\n        [10.244.1.10:8080]\n        [10.244.1.11:8080]\n        [...]\n        [10.244.1.99:8080]\n    }\n    \n    component \"EndpointSlice 2\" as es2 #fff3e0 {\n        [10.244.1.100:8080]\n        [10.244.1.101:8080]\n        [...]\n        [10.244.1.199:8080]\n    }\n    \n    component \"EndpointSlice N\" as esn #fff3e0 {\n        [10.244.1.900:8080]\n        [10.244.1.901:8080]\n        [...]\n        [10.244.1.999:8080]\n    }\n}\n\nsvc --> es1\nsvc --> es2\nsvc --> esn\n\nnote right of es1\n    Кожен EndpointSlice\n    містить до 100 endpoints\n    (за замовчуванням)\n    \n    При зміні Pod оновлюється\n    лише один slice, а не всі\nend note\n\n@enduml\n",[3140,11018,11019,11023,11027,11031,11035,11040,11044,11049,11054,11058,11062,11067,11072,11076,11080,11085,11090,11095,11099,11104,11108,11112,11117,11122,11127,11131,11136,11140,11144,11148,11153,11158,11163,11167,11172,11177,11182,11187,11191,11196,11201,11205,11209],{"__ignoreMap":3138},[3143,11020,11021],{"class":3145,"line":3146},[3143,11022,3149],{},[3143,11024,11025],{"class":3145,"line":3152},[3143,11026,3155],{},[3143,11028,11029],{"class":3145,"line":3158},[3143,11030,3161],{},[3143,11032,11033],{"class":3145,"line":3164},[3143,11034,3168],{"emptyLinePlaceholder":3167},[3143,11036,11037],{"class":3145,"line":3171},[3143,11038,11039],{},"component \"Service\\napi-service\" as svc #e3f2fd\n",[3143,11041,11042],{"class":3145,"line":3177},[3143,11043,3168],{"emptyLinePlaceholder":3167},[3143,11045,11046],{"class":3145,"line":3183},[3143,11047,11048],{},"package \"EndpointSlices\" {\n",[3143,11050,11051],{"class":3145,"line":3189},[3143,11052,11053],{},"    component \"EndpointSlice 1\" as es1 #fff3e0 {\n",[3143,11055,11056],{"class":3145,"line":3195},[3143,11057,3772],{},[3143,11059,11060],{"class":3145,"line":3201},[3143,11061,3777],{},[3143,11063,11064],{"class":3145,"line":3207},[3143,11065,11066],{},"        [...]\n",[3143,11068,11069],{"class":3145,"line":3213},[3143,11070,11071],{},"        [10.244.1.99:8080]\n",[3143,11073,11074],{"class":3145,"line":3219},[3143,11075,3198],{},[3143,11077,11078],{"class":3145,"line":3225},[3143,11079,3204],{},[3143,11081,11082],{"class":3145,"line":3231},[3143,11083,11084],{},"    component \"EndpointSlice 2\" as es2 #fff3e0 {\n",[3143,11086,11087],{"class":3145,"line":3236},[3143,11088,11089],{},"        [10.244.1.100:8080]\n",[3143,11091,11092],{"class":3145,"line":3242},[3143,11093,11094],{},"        [10.244.1.101:8080]\n",[3143,11096,11097],{"class":3145,"line":3247},[3143,11098,11066],{},[3143,11100,11101],{"class":3145,"line":3253},[3143,11102,11103],{},"        [10.244.1.199:8080]\n",[3143,11105,11106],{"class":3145,"line":3259},[3143,11107,3198],{},[3143,11109,11110],{"class":3145,"line":3265},[3143,11111,3204],{},[3143,11113,11114],{"class":3145,"line":3270},[3143,11115,11116],{},"    component \"EndpointSlice N\" as esn #fff3e0 {\n",[3143,11118,11119],{"class":3145,"line":3276},[3143,11120,11121],{},"        [10.244.1.900:8080]\n",[3143,11123,11124],{"class":3145,"line":3282},[3143,11125,11126],{},"        [10.244.1.901:8080]\n",[3143,11128,11129],{"class":3145,"line":3288},[3143,11130,11066],{},[3143,11132,11133],{"class":3145,"line":3293},[3143,11134,11135],{},"        [10.244.1.999:8080]\n",[3143,11137,11138],{"class":3145,"line":3299},[3143,11139,3198],{},[3143,11141,11142],{"class":3145,"line":3305},[3143,11143,3239],{},[3143,11145,11146],{"class":3145,"line":3311},[3143,11147,3168],{"emptyLinePlaceholder":3167},[3143,11149,11150],{"class":3145,"line":3317},[3143,11151,11152],{},"svc --> es1\n",[3143,11154,11155],{"class":3145,"line":3323},[3143,11156,11157],{},"svc --> es2\n",[3143,11159,11160],{"class":3145,"line":3328},[3143,11161,11162],{},"svc --> esn\n",[3143,11164,11165],{"class":3145,"line":3334},[3143,11166,3168],{"emptyLinePlaceholder":3167},[3143,11168,11169],{"class":3145,"line":3340},[3143,11170,11171],{},"note right of es1\n",[3143,11173,11174],{"class":3145,"line":3346},[3143,11175,11176],{},"    Кожен EndpointSlice\n",[3143,11178,11179],{"class":3145,"line":3352},[3143,11180,11181],{},"    містить до 100 endpoints\n",[3143,11183,11184],{"class":3145,"line":3357},[3143,11185,11186],{},"    (за замовчуванням)\n",[3143,11188,11189],{"class":3145,"line":3362},[3143,11190,3204],{},[3143,11192,11193],{"class":3145,"line":3869},[3143,11194,11195],{},"    При зміні Pod оновлюється\n",[3143,11197,11198],{"class":3145,"line":3875},[3143,11199,11200],{},"    лише один slice, а не всі\n",[3143,11202,11203],{"class":3145,"line":3881},[3143,11204,3320],{},[3143,11206,11207],{"class":3145,"line":3887},[3143,11208,3168],{"emptyLinePlaceholder":3167},[3143,11210,11211],{"class":3145,"line":3893},[3143,11212,3365],{},[3114,11214,11215],{},[3118,11216,11217],{},"Переваги EndpointSlices:",[3387,11219,11220,11226,11232],{},[3390,11221,11222,11225],{},[3118,11223,11224],{},"Масштабованість"," — менше навантаження на API Server при великій кількості Pod",[3390,11227,11228,11231],{},[3118,11229,11230],{},"Ефективність"," — оновлюється лише один slice, а не весь список",[3390,11233,11234,11237],{},[3118,11235,11236],{},"Додаткові метадані"," — topology hints, zone information",[3114,11239,11240],{},[3118,11241,11242],{},"Перегляд EndpointSlices:",[6191,11244,11246,11255,11259],{"title":11245},"kubectl get endpointslices",[6195,11247,11249,4793,11252],{"className":11248},[3145],[3143,11250,6209],{"className":11251},[6201],[3118,11253,11254],{},"kubectl get endpointslices -l kubernetes.io/service-name=api-service",[6195,11256,11258],{"className":11257},[3145],"NAME                  ADDRESSTYPE   PORTS   ENDPOINTS                                         AGE",[6195,11260,11262],{"className":11261},[3145],"api-service-abc123    IPv4          8080    10.244.1.10,10.244.1.11,10.244.1.12              5m",[3602,11264,11265,11270,11282,11285],{},[3114,11266,11267],{},[3118,11268,11269],{},"Endpoints vs EndpointSlices:",[3387,11271,11272,11277],{},[3390,11273,11274,11276],{},[3118,11275,4013],{}," — legacy, один об'єкт для всіх Pod",[3390,11278,11279,11281],{},[3118,11280,11010],{}," — сучасний підхід, розбиття на частини",[3114,11283,11284],{},"Kubernetes автоматично створює обидва для зворотної сумісності. kube-proxy підтримує обидва формати.",[3114,11286,11287,11290],{},[3118,11288,11289],{},"Рекомендація:"," Використовуйте EndpointSlices для нових кластерів (Kubernetes 1.21+). Endpoints залишається для сумісності зі старими версіями.",[3582,11292],{},[3109,11294,11296],{"id":11295},"service-без-selector-ручне-управління-endpoints","Service без selector — ручне управління Endpoints",[3114,11298,11299,11300,11302],{},"Іноді потрібен Service, який ",[3118,11301,3612],{}," автоматично вибирає Pod за селектором. Наприклад:",[3387,11304,11305,11308,11311],{},[3390,11306,11307],{},"Доступ до зовнішньої бази даних (не у Kubernetes)",[3390,11309,11310],{},"Міграція з зовнішнього сервісу у Kubernetes",[3390,11312,11313],{},"Проксування до legacy системи",[3114,11315,11316,11318,11319,11322],{},[3118,11317,11007],{}," Створити Service ",[3118,11320,11321],{},"без selector"," та вручну створити Endpoints.",[3122,11324,11326],{"id":11325},"приклад-зовнішня-база-даних","Приклад: Зовнішня база даних",[3114,11328,11329],{},[3118,11330,11331],{},"Service без selector:",[3133,11333,11335],{"className":3443,"code":11334,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: external-postgres\nspec:\n  # Немає selector!\n  ports:\n    - port: 5432\n      targetPort: 5432\n",[3140,11336,11337,11345,11353,11359,11368,11374,11379,11385,11395],{"__ignoreMap":3138},[3143,11338,11339,11341,11343],{"class":3145,"line":3146},[3143,11340,4039],{"class":3452},[3143,11342,3516],{"class":3456},[3143,11344,4044],{"class":3479},[3143,11346,11347,11349,11351],{"class":3145,"line":3152},[3143,11348,4049],{"class":3452},[3143,11350,3516],{"class":3456},[3143,11352,4054],{"class":3479},[3143,11354,11355,11357],{"class":3145,"line":3158},[3143,11356,4059],{"class":3452},[3143,11358,3457],{"class":3456},[3143,11360,11361,11363,11365],{"class":3145,"line":3164},[3143,11362,4066],{"class":3452},[3143,11364,3516],{"class":3456},[3143,11366,11367],{"class":3479},"external-postgres\n",[3143,11369,11370,11372],{"class":3145,"line":3171},[3143,11371,4086],{"class":3452},[3143,11373,3457],{"class":3456},[3143,11375,11376],{"class":3145,"line":3177},[3143,11377,11378],{"class":4245},"  # Немає selector!\n",[3143,11380,11381,11383],{"class":3145,"line":3183},[3143,11382,4110],{"class":3452},[3143,11384,3457],{"class":3456},[3143,11386,11387,11389,11391,11393],{"class":3145,"line":3189},[3143,11388,4117],{"class":3456},[3143,11390,4338],{"class":3452},[3143,11392,3516],{"class":3456},[3143,11394,9678],{"class":3673},[3143,11396,11397,11399,11401],{"class":3145,"line":3195},[3143,11398,4149],{"class":3452},[3143,11400,3516],{"class":3456},[3143,11402,9678],{"class":3673},[3114,11404,11405],{},[3118,11406,11407],{},"Endpoints (створюємо вручну):",[3133,11409,11411],{"className":3443,"code":11410,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Endpoints\nmetadata:\n  name: external-postgres  # Має збігатись з іменем Service\nsubsets:\n  - addresses:\n      - ip: 192.168.1.100  # IP зовнішньої БД\n    ports:\n      - port: 5432\n",[3140,11412,11413,11421,11430,11436,11448,11455,11464,11479,11485],{"__ignoreMap":3138},[3143,11414,11415,11417,11419],{"class":3145,"line":3146},[3143,11416,4039],{"class":3452},[3143,11418,3516],{"class":3456},[3143,11420,4044],{"class":3479},[3143,11422,11423,11425,11427],{"class":3145,"line":3152},[3143,11424,4049],{"class":3452},[3143,11426,3516],{"class":3456},[3143,11428,11429],{"class":3479},"Endpoints\n",[3143,11431,11432,11434],{"class":3145,"line":3158},[3143,11433,4059],{"class":3452},[3143,11435,3457],{"class":3456},[3143,11437,11438,11440,11442,11445],{"class":3145,"line":3164},[3143,11439,4066],{"class":3452},[3143,11441,3516],{"class":3456},[3143,11443,11444],{"class":3479},"external-postgres",[3143,11446,11447],{"class":4245},"  # Має збігатись з іменем Service\n",[3143,11449,11450,11453],{"class":3145,"line":3171},[3143,11451,11452],{"class":3452},"subsets",[3143,11454,3457],{"class":3456},[3143,11456,11457,11459,11462],{"class":3145,"line":3177},[3143,11458,3510],{"class":3456},[3143,11460,11461],{"class":3452},"addresses",[3143,11463,3457],{"class":3456},[3143,11465,11466,11468,11471,11473,11476],{"class":3145,"line":3183},[3143,11467,3476],{"class":3456},[3143,11469,11470],{"class":3452},"ip",[3143,11472,3516],{"class":3456},[3143,11474,11475],{"class":3673},"192.168.1.100",[3143,11477,11478],{"class":4245},"  # IP зовнішньої БД\n",[3143,11480,11481,11483],{"class":3145,"line":3189},[3143,11482,4767],{"class":3452},[3143,11484,3457],{"class":3456},[3143,11486,11487,11489,11491,11493],{"class":3145,"line":3195},[3143,11488,3476],{"class":3456},[3143,11490,4338],{"class":3452},[3143,11492,3516],{"class":3456},[3143,11494,9678],{"class":3673},[3114,11496,11497],{},[3118,11498,5186],{},[3542,11500,11501,11507,11515],{},[3390,11502,11503,11504,4002],{},"Service створюється з ClusterIP (наприклад, ",[3140,11505,11506],{},"10.96.0.50",[3390,11508,11509,11510,5201,11513],{},"DNS-запис створюється: ",[3140,11511,11512],{},"external-postgres.default.svc.cluster.local",[3140,11514,11506],{},[3390,11516,5917,11517,4404,11520],{},[3140,11518,11519],{},"10.96.0.50:5432",[3140,11521,11522],{},"192.168.1.100:5432",[3114,11524,11525],{},[3118,11526,5211],{},[3130,11528,11529],{},[3133,11530,11532],{"className":3135,"code":11531,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Kubernetes Cluster\" {\n    component \"Pod\" as pod #e3f2fd\n    \n    component \"Service\\nexternal-postgres\" as svc #fff3e0 {\n        [ClusterIP: 10.96.0.50]\n        [NO selector]\n    }\n    \n    component \"Endpoints\\nexternal-postgres\" as ep #e8f5e9 {\n        [192.168.1.100:5432]\n    }\n}\n\ncloud \"Зовнішня мережа\" {\n    component \"PostgreSQL\\n192.168.1.100\" as db\n}\n\npod --> svc : psql -h external-postgres\nsvc --> ep : Lookup endpoints\nep --> db : Connect to 192.168.1.100:5432\n\nnote right of svc\n    Service без selector\n    не шукає Pod автоматично\n    \n    Використовує вручну\n    створені Endpoints\nend note\n\n@enduml\n",[3140,11533,11534,11538,11542,11546,11550,11554,11559,11563,11568,11573,11578,11582,11586,11591,11596,11600,11604,11608,11613,11618,11622,11626,11631,11636,11641,11645,11649,11654,11659,11663,11668,11673,11677,11681],{"__ignoreMap":3138},[3143,11535,11536],{"class":3145,"line":3146},[3143,11537,3149],{},[3143,11539,11540],{"class":3145,"line":3152},[3143,11541,3155],{},[3143,11543,11544],{"class":3145,"line":3158},[3143,11545,3161],{},[3143,11547,11548],{"class":3145,"line":3164},[3143,11549,3168],{"emptyLinePlaceholder":3167},[3143,11551,11552],{"class":3145,"line":3171},[3143,11553,3174],{},[3143,11555,11556],{"class":3145,"line":3177},[3143,11557,11558],{},"    component \"Pod\" as pod #e3f2fd\n",[3143,11560,11561],{"class":3145,"line":3183},[3143,11562,3204],{},[3143,11564,11565],{"class":3145,"line":3189},[3143,11566,11567],{},"    component \"Service\\nexternal-postgres\" as svc #fff3e0 {\n",[3143,11569,11570],{"class":3145,"line":3195},[3143,11571,11572],{},"        [ClusterIP: 10.96.0.50]\n",[3143,11574,11575],{"class":3145,"line":3201},[3143,11576,11577],{},"        [NO selector]\n",[3143,11579,11580],{"class":3145,"line":3207},[3143,11581,3198],{},[3143,11583,11584],{"class":3145,"line":3213},[3143,11585,3204],{},[3143,11587,11588],{"class":3145,"line":3219},[3143,11589,11590],{},"    component \"Endpoints\\nexternal-postgres\" as ep #e8f5e9 {\n",[3143,11592,11593],{"class":3145,"line":3225},[3143,11594,11595],{},"        [192.168.1.100:5432]\n",[3143,11597,11598],{"class":3145,"line":3231},[3143,11599,3198],{},[3143,11601,11602],{"class":3145,"line":3236},[3143,11603,3239],{},[3143,11605,11606],{"class":3145,"line":3242},[3143,11607,3168],{"emptyLinePlaceholder":3167},[3143,11609,11610],{"class":3145,"line":3247},[3143,11611,11612],{},"cloud \"Зовнішня мережа\" {\n",[3143,11614,11615],{"class":3145,"line":3253},[3143,11616,11617],{},"    component \"PostgreSQL\\n192.168.1.100\" as db\n",[3143,11619,11620],{"class":3145,"line":3259},[3143,11621,3239],{},[3143,11623,11624],{"class":3145,"line":3265},[3143,11625,3168],{"emptyLinePlaceholder":3167},[3143,11627,11628],{"class":3145,"line":3270},[3143,11629,11630],{},"pod --> svc : psql -h external-postgres\n",[3143,11632,11633],{"class":3145,"line":3276},[3143,11634,11635],{},"svc --> ep : Lookup endpoints\n",[3143,11637,11638],{"class":3145,"line":3282},[3143,11639,11640],{},"ep --> db : Connect to 192.168.1.100:5432\n",[3143,11642,11643],{"class":3145,"line":3288},[3143,11644,3168],{"emptyLinePlaceholder":3167},[3143,11646,11647],{"class":3145,"line":3293},[3143,11648,3872],{},[3143,11650,11651],{"class":3145,"line":3299},[3143,11652,11653],{},"    Service без selector\n",[3143,11655,11656],{"class":3145,"line":3305},[3143,11657,11658],{},"    не шукає Pod автоматично\n",[3143,11660,11661],{"class":3145,"line":3311},[3143,11662,3204],{},[3143,11664,11665],{"class":3145,"line":3317},[3143,11666,11667],{},"    Використовує вручну\n",[3143,11669,11670],{"class":3145,"line":3323},[3143,11671,11672],{},"    створені Endpoints\n",[3143,11674,11675],{"class":3145,"line":3328},[3143,11676,3320],{},[3143,11678,11679],{"class":3145,"line":3334},[3143,11680,3168],{"emptyLinePlaceholder":3167},[3143,11682,11683],{"class":3145,"line":3340},[3143,11684,3365],{},[3114,11686,11687],{},[3118,11688,5401],{},[3387,11690,11691,11694,11697],{},[3390,11692,11693],{},"Зовнішня база даних (AWS RDS, Azure Database)",[3390,11695,11696],{},"Legacy системи поза Kubernetes",[3390,11698,11699],{},"Поступова міграція у Kubernetes",[3114,11701,11702],{},[3118,11703,5038],{},[3387,11705,11706,11709,11712],{},[3390,11707,11708],{},"Код не змінюється — використовує той самий DNS-ім'я",[3390,11710,11711],{},"Легко мігрувати: спочатку зовнішня БД, потім Pod у Kubernetes",[3390,11713,11714],{},"Централізована конфігурація через Service",[3582,11716],{},[3109,11718,11720],{"id":11719},"практичний-приклад-todoapi-з-різними-типами-service","Практичний приклад: TodoApi з різними типами Service",[3114,11722,11723],{},"Тепер створимо повний приклад з TodoApi та різними типами Service.",[3122,11725,11727],{"id":11726},"архітектура-застосунку","Архітектура застосунку",[3130,11729,11730],{},[3133,11731,11733],{"className":3135,"code":11732,"language":3137,"meta":3138,"style":3138},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Зовнішній користувач\" as user\n\ncloud \"LoadBalancer\" {\n    component \"Load Balancer\\n34.123.45.67\" as lb #e3f2fd\n}\n\npackage \"Kubernetes Cluster\" {\n    component \"Service\\nfrontend-lb\\nType: LoadBalancer\" as fe_svc #fff3e0\n    \n    package \"Frontend Pods\" {\n        component \"Frontend Pod 1\" as fe1 #e8f5e9\n        component \"Frontend Pod 2\" as fe2 #e8f5e9\n    }\n    \n    component \"Service\\napi-service\\nType: ClusterIP\" as api_svc #fff3e0\n    \n    package \"API Pods\" {\n        component \"API Pod 1\" as api1 #e8f5e9\n        component \"API Pod 2\" as api2 #e8f5e9\n        component \"API Pod 3\" as api3 #e8f5e9\n    }\n    \n    component \"Service\\npostgres-service\\nType: ClusterIP\" as db_svc #fff3e0\n    \n    component \"PostgreSQL Pod\" as db #e8f5e9\n}\n\nuser --> lb : HTTP\nlb --> fe_svc\nfe_svc --> fe1\nfe_svc --> fe2\n\nfe1 --> api_svc : http://api-service\nfe2 --> api_svc : http://api-service\n\napi_svc --> api1\napi_svc --> api2\napi_svc --> api3\n\napi1 --> db_svc : postgres-service:5432\napi2 --> db_svc : postgres-service:5432\napi3 --> db_svc : postgres-service:5432\n\ndb_svc --> db\n\n@enduml\n",[3140,11734,11735,11739,11743,11747,11751,11755,11759,11764,11768,11772,11776,11780,11785,11789,11794,11799,11804,11808,11812,11817,11821,11825,11830,11835,11840,11844,11848,11853,11857,11862,11866,11870,11875,11880,11885,11890,11894,11899,11904,11908,11913,11918,11923,11927,11932,11937,11942,11946,11951,11955],{"__ignoreMap":3138},[3143,11736,11737],{"class":3145,"line":3146},[3143,11738,3149],{},[3143,11740,11741],{"class":3145,"line":3152},[3143,11742,3155],{},[3143,11744,11745],{"class":3145,"line":3158},[3143,11746,3161],{},[3143,11748,11749],{"class":3145,"line":3164},[3143,11750,3168],{"emptyLinePlaceholder":3167},[3143,11752,11753],{"class":3145,"line":3171},[3143,11754,5953],{},[3143,11756,11757],{"class":3145,"line":3177},[3143,11758,3168],{"emptyLinePlaceholder":3167},[3143,11760,11761],{"class":3145,"line":3183},[3143,11762,11763],{},"cloud \"LoadBalancer\" {\n",[3143,11765,11766],{"class":3145,"line":3189},[3143,11767,6515],{},[3143,11769,11770],{"class":3145,"line":3195},[3143,11771,3239],{},[3143,11773,11774],{"class":3145,"line":3201},[3143,11775,3168],{"emptyLinePlaceholder":3167},[3143,11777,11778],{"class":3145,"line":3207},[3143,11779,3174],{},[3143,11781,11782],{"class":3145,"line":3213},[3143,11783,11784],{},"    component \"Service\\nfrontend-lb\\nType: LoadBalancer\" as fe_svc #fff3e0\n",[3143,11786,11787],{"class":3145,"line":3219},[3143,11788,3204],{},[3143,11790,11791],{"class":3145,"line":3225},[3143,11792,11793],{},"    package \"Frontend Pods\" {\n",[3143,11795,11796],{"class":3145,"line":3231},[3143,11797,11798],{},"        component \"Frontend Pod 1\" as fe1 #e8f5e9\n",[3143,11800,11801],{"class":3145,"line":3236},[3143,11802,11803],{},"        component \"Frontend Pod 2\" as fe2 #e8f5e9\n",[3143,11805,11806],{"class":3145,"line":3242},[3143,11807,3198],{},[3143,11809,11810],{"class":3145,"line":3247},[3143,11811,3204],{},[3143,11813,11814],{"class":3145,"line":3253},[3143,11815,11816],{},"    component \"Service\\napi-service\\nType: ClusterIP\" as api_svc #fff3e0\n",[3143,11818,11819],{"class":3145,"line":3259},[3143,11820,3204],{},[3143,11822,11823],{"class":3145,"line":3265},[3143,11824,6589],{},[3143,11826,11827],{"class":3145,"line":3270},[3143,11828,11829],{},"        component \"API Pod 1\" as api1 #e8f5e9\n",[3143,11831,11832],{"class":3145,"line":3276},[3143,11833,11834],{},"        component \"API Pod 2\" as api2 #e8f5e9\n",[3143,11836,11837],{"class":3145,"line":3282},[3143,11838,11839],{},"        component \"API Pod 3\" as api3 #e8f5e9\n",[3143,11841,11842],{"class":3145,"line":3288},[3143,11843,3198],{},[3143,11845,11846],{"class":3145,"line":3293},[3143,11847,3204],{},[3143,11849,11850],{"class":3145,"line":3299},[3143,11851,11852],{},"    component \"Service\\npostgres-service\\nType: ClusterIP\" as db_svc #fff3e0\n",[3143,11854,11855],{"class":3145,"line":3305},[3143,11856,3204],{},[3143,11858,11859],{"class":3145,"line":3311},[3143,11860,11861],{},"    component \"PostgreSQL Pod\" as db #e8f5e9\n",[3143,11863,11864],{"class":3145,"line":3317},[3143,11865,3239],{},[3143,11867,11868],{"class":3145,"line":3323},[3143,11869,3168],{"emptyLinePlaceholder":3167},[3143,11871,11872],{"class":3145,"line":3328},[3143,11873,11874],{},"user --> lb : HTTP\n",[3143,11876,11877],{"class":3145,"line":3334},[3143,11878,11879],{},"lb --> fe_svc\n",[3143,11881,11882],{"class":3145,"line":3340},[3143,11883,11884],{},"fe_svc --> fe1\n",[3143,11886,11887],{"class":3145,"line":3346},[3143,11888,11889],{},"fe_svc --> fe2\n",[3143,11891,11892],{"class":3145,"line":3352},[3143,11893,3168],{"emptyLinePlaceholder":3167},[3143,11895,11896],{"class":3145,"line":3357},[3143,11897,11898],{},"fe1 --> api_svc : http://api-service\n",[3143,11900,11901],{"class":3145,"line":3362},[3143,11902,11903],{},"fe2 --> api_svc : http://api-service\n",[3143,11905,11906],{"class":3145,"line":3869},[3143,11907,3168],{"emptyLinePlaceholder":3167},[3143,11909,11910],{"class":3145,"line":3875},[3143,11911,11912],{},"api_svc --> api1\n",[3143,11914,11915],{"class":3145,"line":3881},[3143,11916,11917],{},"api_svc --> api2\n",[3143,11919,11920],{"class":3145,"line":3887},[3143,11921,11922],{},"api_svc --> api3\n",[3143,11924,11925],{"class":3145,"line":3893},[3143,11926,3168],{"emptyLinePlaceholder":3167},[3143,11928,11929],{"class":3145,"line":3899},[3143,11930,11931],{},"api1 --> db_svc : postgres-service:5432\n",[3143,11933,11934],{"class":3145,"line":3904},[3143,11935,11936],{},"api2 --> db_svc : postgres-service:5432\n",[3143,11938,11939],{"class":3145,"line":3909},[3143,11940,11941],{},"api3 --> db_svc : postgres-service:5432\n",[3143,11943,11944],{"class":3145,"line":3915},[3143,11945,3168],{"emptyLinePlaceholder":3167},[3143,11947,11948],{"class":3145,"line":3921},[3143,11949,11950],{},"db_svc --> db\n",[3143,11952,11953],{"class":3145,"line":3927},[3143,11954,3168],{"emptyLinePlaceholder":3167},[3143,11956,11957],{"class":3145,"line":3933},[3143,11958,3365],{},[3122,11960,11962],{"id":11961},"крок-1-postgresql-з-clusterip-service","Крок 1: PostgreSQL з ClusterIP Service",[3114,11964,11965],{},[3118,11966,11967],{},"postgres-deployment.yaml:",[3133,11969,11971],{"className":3443,"code":11970,"language":3445,"meta":3138,"style":3138},"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: postgres\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: postgres\n  template:\n    metadata:\n      labels:\n        app: postgres\n    spec:\n      containers:\n        - name: postgres\n          image: postgres:16\n          ports:\n            - containerPort: 5432\n          env:\n            - name: POSTGRES_DB\n              value: tododb\n            - name: POSTGRES_USER\n              value: todouser\n            - name: POSTGRES_PASSWORD\n              value: todopass\n          volumeMounts:\n            - name: postgres-storage\n              mountPath: /var/lib/postgresql/data\n      volumes:\n        - name: postgres-storage\n          emptyDir: {}\n",[3140,11972,11973,11982,11991,11997,12005,12011,12021,12027,12034,12042,12048,12055,12062,12071,12077,12083,12093,12103,12109,12119,12126,12137,12147,12158,12167,12178,12187,12194,12205,12215,12222,12232],{"__ignoreMap":3138},[3143,11974,11975,11977,11979],{"class":3145,"line":3146},[3143,11976,4039],{"class":3452},[3143,11978,3516],{"class":3456},[3143,11980,11981],{"class":3479},"apps/v1\n",[3143,11983,11984,11986,11988],{"class":3145,"line":3152},[3143,11985,4049],{"class":3452},[3143,11987,3516],{"class":3456},[3143,11989,11990],{"class":3479},"Deployment\n",[3143,11992,11993,11995],{"class":3145,"line":3158},[3143,11994,4059],{"class":3452},[3143,11996,3457],{"class":3456},[3143,11998,11999,12001,12003],{"class":3145,"line":3164},[3143,12000,4066],{"class":3452},[3143,12002,3516],{"class":3456},[3143,12004,9661],{"class":3479},[3143,12006,12007,12009],{"class":3145,"line":3171},[3143,12008,4086],{"class":3452},[3143,12010,3457],{"class":3456},[3143,12012,12013,12016,12018],{"class":3145,"line":3177},[3143,12014,12015],{"class":3452},"  replicas",[3143,12017,3516],{"class":3456},[3143,12019,12020],{"class":3673},"1\n",[3143,12022,12023,12025],{"class":3145,"line":3183},[3143,12024,4093],{"class":3452},[3143,12026,3457],{"class":3456},[3143,12028,12029,12032],{"class":3145,"line":3189},[3143,12030,12031],{"class":3452},"    matchLabels",[3143,12033,3457],{"class":3456},[3143,12035,12036,12038,12040],{"class":3145,"line":3195},[3143,12037,4296],{"class":3452},[3143,12039,3516],{"class":3456},[3143,12041,9661],{"class":3479},[3143,12043,12044,12046],{"class":3145,"line":3201},[3143,12045,4862],{"class":3452},[3143,12047,3457],{"class":3456},[3143,12049,12050,12053],{"class":3145,"line":3207},[3143,12051,12052],{"class":3452},"    metadata",[3143,12054,3457],{"class":3456},[3143,12056,12057,12060],{"class":3145,"line":3213},[3143,12058,12059],{"class":3452},"      labels",[3143,12061,3457],{"class":3456},[3143,12063,12064,12067,12069],{"class":3145,"line":3219},[3143,12065,12066],{"class":3452},"        app",[3143,12068,3516],{"class":3456},[3143,12070,9661],{"class":3479},[3143,12072,12073,12075],{"class":3145,"line":3225},[3143,12074,4869],{"class":3452},[3143,12076,3457],{"class":3456},[3143,12078,12079,12081],{"class":3145,"line":3231},[3143,12080,4876],{"class":3452},[3143,12082,3457],{"class":3456},[3143,12084,12085,12087,12089,12091],{"class":3145,"line":3236},[3143,12086,4883],{"class":3456},[3143,12088,3513],{"class":3452},[3143,12090,3516],{"class":3456},[3143,12092,9661],{"class":3479},[3143,12094,12095,12098,12100],{"class":3145,"line":3242},[3143,12096,12097],{"class":3452},"          image",[3143,12099,3516],{"class":3456},[3143,12101,12102],{"class":3479},"postgres:16\n",[3143,12104,12105,12107],{"class":3145,"line":3247},[3143,12106,4894],{"class":3452},[3143,12108,3457],{"class":3456},[3143,12110,12111,12113,12115,12117],{"class":3145,"line":3253},[3143,12112,4901],{"class":3456},[3143,12114,4691],{"class":3452},[3143,12116,3516],{"class":3456},[3143,12118,9678],{"class":3673},[3143,12120,12121,12124],{"class":3145,"line":3259},[3143,12122,12123],{"class":3452},"          env",[3143,12125,3457],{"class":3456},[3143,12127,12128,12130,12132,12134],{"class":3145,"line":3265},[3143,12129,4901],{"class":3456},[3143,12131,3513],{"class":3452},[3143,12133,3516],{"class":3456},[3143,12135,12136],{"class":3479},"POSTGRES_DB\n",[3143,12138,12139,12142,12144],{"class":3145,"line":3270},[3143,12140,12141],{"class":3452},"              value",[3143,12143,3516],{"class":3456},[3143,12145,12146],{"class":3479},"tododb\n",[3143,12148,12149,12151,12153,12155],{"class":3145,"line":3276},[3143,12150,4901],{"class":3456},[3143,12152,3513],{"class":3452},[3143,12154,3516],{"class":3456},[3143,12156,12157],{"class":3479},"POSTGRES_USER\n",[3143,12159,12160,12162,12164],{"class":3145,"line":3282},[3143,12161,12141],{"class":3452},[3143,12163,3516],{"class":3456},[3143,12165,12166],{"class":3479},"todouser\n",[3143,12168,12169,12171,12173,12175],{"class":3145,"line":3288},[3143,12170,4901],{"class":3456},[3143,12172,3513],{"class":3452},[3143,12174,3516],{"class":3456},[3143,12176,12177],{"class":3479},"POSTGRES_PASSWORD\n",[3143,12179,12180,12182,12184],{"class":3145,"line":3293},[3143,12181,12141],{"class":3452},[3143,12183,3516],{"class":3456},[3143,12185,12186],{"class":3479},"todopass\n",[3143,12188,12189,12192],{"class":3145,"line":3299},[3143,12190,12191],{"class":3452},"          volumeMounts",[3143,12193,3457],{"class":3456},[3143,12195,12196,12198,12200,12202],{"class":3145,"line":3305},[3143,12197,4901],{"class":3456},[3143,12199,3513],{"class":3452},[3143,12201,3516],{"class":3456},[3143,12203,12204],{"class":3479},"postgres-storage\n",[3143,12206,12207,12210,12212],{"class":3145,"line":3311},[3143,12208,12209],{"class":3452},"              mountPath",[3143,12211,3516],{"class":3456},[3143,12213,12214],{"class":3479},"/var/lib/postgresql/data\n",[3143,12216,12217,12220],{"class":3145,"line":3317},[3143,12218,12219],{"class":3452},"      volumes",[3143,12221,3457],{"class":3456},[3143,12223,12224,12226,12228,12230],{"class":3145,"line":3323},[3143,12225,4883],{"class":3456},[3143,12227,3513],{"class":3452},[3143,12229,3516],{"class":3456},[3143,12231,12204],{"class":3479},[3143,12233,12234,12237],{"class":3145,"line":3328},[3143,12235,12236],{"class":3452},"          emptyDir",[3143,12238,12239],{"class":3456},": {}\n",[3114,12241,12242],{},[3118,12243,12244],{},"postgres-service.yaml:",[3133,12246,12248],{"className":3443,"code":12247,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: postgres-service\nspec:\n  type: ClusterIP  # За замовчуванням, можна не вказувати\n  selector:\n    app: postgres\n  ports:\n    - port: 5432\n      targetPort: 5432\n",[3140,12249,12250,12258,12266,12272,12280,12286,12296,12302,12310,12316,12326],{"__ignoreMap":3138},[3143,12251,12252,12254,12256],{"class":3145,"line":3146},[3143,12253,4039],{"class":3452},[3143,12255,3516],{"class":3456},[3143,12257,4044],{"class":3479},[3143,12259,12260,12262,12264],{"class":3145,"line":3152},[3143,12261,4049],{"class":3452},[3143,12263,3516],{"class":3456},[3143,12265,4054],{"class":3479},[3143,12267,12268,12270],{"class":3145,"line":3158},[3143,12269,4059],{"class":3452},[3143,12271,3457],{"class":3456},[3143,12273,12274,12276,12278],{"class":3145,"line":3164},[3143,12275,4066],{"class":3452},[3143,12277,3516],{"class":3456},[3143,12279,7320],{"class":3479},[3143,12281,12282,12284],{"class":3145,"line":3171},[3143,12283,4086],{"class":3452},[3143,12285,3457],{"class":3456},[3143,12287,12288,12290,12292,12294],{"class":3145,"line":3177},[3143,12289,4159],{"class":3452},[3143,12291,3516],{"class":3456},[3143,12293,3991],{"class":3479},[3143,12295,5143],{"class":4245},[3143,12297,12298,12300],{"class":3145,"line":3183},[3143,12299,4093],{"class":3452},[3143,12301,3457],{"class":3456},[3143,12303,12304,12306,12308],{"class":3145,"line":3189},[3143,12305,4100],{"class":3452},[3143,12307,3516],{"class":3456},[3143,12309,9661],{"class":3479},[3143,12311,12312,12314],{"class":3145,"line":3195},[3143,12313,4110],{"class":3452},[3143,12315,3457],{"class":3456},[3143,12317,12318,12320,12322,12324],{"class":3145,"line":3201},[3143,12319,4117],{"class":3456},[3143,12321,4338],{"class":3452},[3143,12323,3516],{"class":3456},[3143,12325,9678],{"class":3673},[3143,12327,12328,12330,12332],{"class":3145,"line":3207},[3143,12329,4149],{"class":3452},[3143,12331,3516],{"class":3456},[3143,12333,9678],{"class":3673},[3122,12335,12337],{"id":12336},"крок-2-todoapi-з-clusterip-service","Крок 2: TodoApi з ClusterIP Service",[3114,12339,12340],{},[3118,12341,12342],{},"api-deployment.yaml:",[3133,12344,12346],{"className":3443,"code":12345,"language":3445,"meta":3138,"style":3138},"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: todoapi\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: todoapi\n  template:\n    metadata:\n      labels:\n        app: todoapi\n    spec:\n      containers:\n        - name: todoapi\n          image: todoapi:1.0.0\n          ports:\n            - containerPort: 8080\n          env:\n            - name: ASPNETCORE_ENVIRONMENT\n              value: \"Production\"\n            - name: ASPNETCORE_URLS\n              value: \"http://+:8080\"\n            - name: ConnectionStrings__DefaultConnection\n              value: \"Host=postgres-service;Database=tododb;Username=todouser;Password=todopass\"\n          resources:\n            requests:\n              memory: \"128Mi\"\n              cpu: \"100m\"\n            limits:\n              memory: \"256Mi\"\n              cpu: \"500m\"\n",[3140,12347,12348,12356,12364,12370,12379,12385,12393,12399,12405,12413,12419,12425,12431,12439,12445,12451,12461,12470,12476,12486,12492,12503,12512,12523,12532,12543,12552,12559,12566,12576,12586,12593,12602],{"__ignoreMap":3138},[3143,12349,12350,12352,12354],{"class":3145,"line":3146},[3143,12351,4039],{"class":3452},[3143,12353,3516],{"class":3456},[3143,12355,11981],{"class":3479},[3143,12357,12358,12360,12362],{"class":3145,"line":3152},[3143,12359,4049],{"class":3452},[3143,12361,3516],{"class":3456},[3143,12363,11990],{"class":3479},[3143,12365,12366,12368],{"class":3145,"line":3158},[3143,12367,4059],{"class":3452},[3143,12369,3457],{"class":3456},[3143,12371,12372,12374,12376],{"class":3145,"line":3164},[3143,12373,4066],{"class":3452},[3143,12375,3516],{"class":3456},[3143,12377,12378],{"class":3479},"todoapi\n",[3143,12380,12381,12383],{"class":3145,"line":3171},[3143,12382,4086],{"class":3452},[3143,12384,3457],{"class":3456},[3143,12386,12387,12389,12391],{"class":3145,"line":3177},[3143,12388,12015],{"class":3452},[3143,12390,3516],{"class":3456},[3143,12392,3674],{"class":3673},[3143,12394,12395,12397],{"class":3145,"line":3183},[3143,12396,4093],{"class":3452},[3143,12398,3457],{"class":3456},[3143,12400,12401,12403],{"class":3145,"line":3189},[3143,12402,12031],{"class":3452},[3143,12404,3457],{"class":3456},[3143,12406,12407,12409,12411],{"class":3145,"line":3195},[3143,12408,4296],{"class":3452},[3143,12410,3516],{"class":3456},[3143,12412,12378],{"class":3479},[3143,12414,12415,12417],{"class":3145,"line":3201},[3143,12416,4862],{"class":3452},[3143,12418,3457],{"class":3456},[3143,12420,12421,12423],{"class":3145,"line":3207},[3143,12422,12052],{"class":3452},[3143,12424,3457],{"class":3456},[3143,12426,12427,12429],{"class":3145,"line":3213},[3143,12428,12059],{"class":3452},[3143,12430,3457],{"class":3456},[3143,12432,12433,12435,12437],{"class":3145,"line":3219},[3143,12434,12066],{"class":3452},[3143,12436,3516],{"class":3456},[3143,12438,12378],{"class":3479},[3143,12440,12441,12443],{"class":3145,"line":3225},[3143,12442,4869],{"class":3452},[3143,12444,3457],{"class":3456},[3143,12446,12447,12449],{"class":3145,"line":3231},[3143,12448,4876],{"class":3452},[3143,12450,3457],{"class":3456},[3143,12452,12453,12455,12457,12459],{"class":3145,"line":3236},[3143,12454,4883],{"class":3456},[3143,12456,3513],{"class":3452},[3143,12458,3516],{"class":3456},[3143,12460,12378],{"class":3479},[3143,12462,12463,12465,12467],{"class":3145,"line":3242},[3143,12464,12097],{"class":3452},[3143,12466,3516],{"class":3456},[3143,12468,12469],{"class":3479},"todoapi:1.0.0\n",[3143,12471,12472,12474],{"class":3145,"line":3247},[3143,12473,4894],{"class":3452},[3143,12475,3457],{"class":3456},[3143,12477,12478,12480,12482,12484],{"class":3145,"line":3253},[3143,12479,4901],{"class":3456},[3143,12481,4691],{"class":3452},[3143,12483,3516],{"class":3456},[3143,12485,4154],{"class":3673},[3143,12487,12488,12490],{"class":3145,"line":3259},[3143,12489,12123],{"class":3452},[3143,12491,3457],{"class":3456},[3143,12493,12494,12496,12498,12500],{"class":3145,"line":3265},[3143,12495,4901],{"class":3456},[3143,12497,3513],{"class":3452},[3143,12499,3516],{"class":3456},[3143,12501,12502],{"class":3479},"ASPNETCORE_ENVIRONMENT\n",[3143,12504,12505,12507,12509],{"class":3145,"line":3270},[3143,12506,12141],{"class":3452},[3143,12508,3516],{"class":3456},[3143,12510,12511],{"class":3529},"\"Production\"\n",[3143,12513,12514,12516,12518,12520],{"class":3145,"line":3276},[3143,12515,4901],{"class":3456},[3143,12517,3513],{"class":3452},[3143,12519,3516],{"class":3456},[3143,12521,12522],{"class":3479},"ASPNETCORE_URLS\n",[3143,12524,12525,12527,12529],{"class":3145,"line":3282},[3143,12526,12141],{"class":3452},[3143,12528,3516],{"class":3456},[3143,12530,12531],{"class":3529},"\"http://+:8080\"\n",[3143,12533,12534,12536,12538,12540],{"class":3145,"line":3288},[3143,12535,4901],{"class":3456},[3143,12537,3513],{"class":3452},[3143,12539,3516],{"class":3456},[3143,12541,12542],{"class":3479},"ConnectionStrings__DefaultConnection\n",[3143,12544,12545,12547,12549],{"class":3145,"line":3293},[3143,12546,12141],{"class":3452},[3143,12548,3516],{"class":3456},[3143,12550,12551],{"class":3529},"\"Host=postgres-service;Database=tododb;Username=todouser;Password=todopass\"\n",[3143,12553,12554,12557],{"class":3145,"line":3299},[3143,12555,12556],{"class":3452},"          resources",[3143,12558,3457],{"class":3456},[3143,12560,12561,12564],{"class":3145,"line":3305},[3143,12562,12563],{"class":3452},"            requests",[3143,12565,3457],{"class":3456},[3143,12567,12568,12571,12573],{"class":3145,"line":3311},[3143,12569,12570],{"class":3452},"              memory",[3143,12572,3516],{"class":3456},[3143,12574,12575],{"class":3529},"\"128Mi\"\n",[3143,12577,12578,12581,12583],{"class":3145,"line":3317},[3143,12579,12580],{"class":3452},"              cpu",[3143,12582,3516],{"class":3456},[3143,12584,12585],{"class":3529},"\"100m\"\n",[3143,12587,12588,12591],{"class":3145,"line":3323},[3143,12589,12590],{"class":3452},"            limits",[3143,12592,3457],{"class":3456},[3143,12594,12595,12597,12599],{"class":3145,"line":3328},[3143,12596,12570],{"class":3452},[3143,12598,3516],{"class":3456},[3143,12600,12601],{"class":3529},"\"256Mi\"\n",[3143,12603,12604,12606,12608],{"class":3145,"line":3334},[3143,12605,12580],{"class":3452},[3143,12607,3516],{"class":3456},[3143,12609,12610],{"class":3529},"\"500m\"\n",[3114,12612,12613],{},[3118,12614,12615],{},"api-service.yaml:",[3133,12617,12619],{"className":3443,"code":12618,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: api-service\nspec:\n  type: ClusterIP\n  selector:\n    app: todoapi\n  ports:\n    - name: http\n      port: 80\n      targetPort: 8080\n",[3140,12620,12621,12629,12637,12643,12651,12657,12665,12671,12679,12685,12695,12703],{"__ignoreMap":3138},[3143,12622,12623,12625,12627],{"class":3145,"line":3146},[3143,12624,4039],{"class":3452},[3143,12626,3516],{"class":3456},[3143,12628,4044],{"class":3479},[3143,12630,12631,12633,12635],{"class":3145,"line":3152},[3143,12632,4049],{"class":3452},[3143,12634,3516],{"class":3456},[3143,12636,4054],{"class":3479},[3143,12638,12639,12641],{"class":3145,"line":3158},[3143,12640,4059],{"class":3452},[3143,12642,3457],{"class":3456},[3143,12644,12645,12647,12649],{"class":3145,"line":3164},[3143,12646,4066],{"class":3452},[3143,12648,3516],{"class":3456},[3143,12650,4071],{"class":3479},[3143,12652,12653,12655],{"class":3145,"line":3171},[3143,12654,4086],{"class":3452},[3143,12656,3457],{"class":3456},[3143,12658,12659,12661,12663],{"class":3145,"line":3177},[3143,12660,4159],{"class":3452},[3143,12662,3516],{"class":3456},[3143,12664,4164],{"class":3479},[3143,12666,12667,12669],{"class":3145,"line":3183},[3143,12668,4093],{"class":3452},[3143,12670,3457],{"class":3456},[3143,12672,12673,12675,12677],{"class":3145,"line":3189},[3143,12674,4100],{"class":3452},[3143,12676,3516],{"class":3456},[3143,12678,12378],{"class":3479},[3143,12680,12681,12683],{"class":3145,"line":3195},[3143,12682,4110],{"class":3452},[3143,12684,3457],{"class":3456},[3143,12686,12687,12689,12691,12693],{"class":3145,"line":3201},[3143,12688,4117],{"class":3456},[3143,12690,3513],{"class":3452},[3143,12692,3516],{"class":3456},[3143,12694,4124],{"class":3479},[3143,12696,12697,12699,12701],{"class":3145,"line":3207},[3143,12698,4139],{"class":3452},[3143,12700,3516],{"class":3456},[3143,12702,4144],{"class":3673},[3143,12704,12705,12707,12709],{"class":3145,"line":3213},[3143,12706,4149],{"class":3452},[3143,12708,3516],{"class":3456},[3143,12710,4154],{"class":3673},[3122,12712,12714],{"id":12713},"крок-3-frontend-з-loadbalancer-service-або-nodeport-для-minikube","Крок 3: Frontend з LoadBalancer Service (або NodePort для Minikube)",[3114,12716,12717],{},[3118,12718,12719],{},"frontend-deployment.yaml:",[3133,12721,12723],{"className":3443,"code":12722,"language":3445,"meta":3138,"style":3138},"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: frontend\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: frontend\n  template:\n    metadata:\n      labels:\n        app: frontend\n    spec:\n      containers:\n        - name: nginx\n          image: nginx:1.27\n          ports:\n            - containerPort: 80\n          volumeMounts:\n            - name: nginx-config\n              mountPath: /etc/nginx/conf.d\n      volumes:\n        - name: nginx-config\n          configMap:\n            name: nginx-config\n",[3140,12724,12725,12733,12741,12747,12756,12762,12771,12777,12783,12791,12797,12803,12809,12817,12823,12829,12840,12849,12855,12865,12871,12882,12891,12897,12907,12914],{"__ignoreMap":3138},[3143,12726,12727,12729,12731],{"class":3145,"line":3146},[3143,12728,4039],{"class":3452},[3143,12730,3516],{"class":3456},[3143,12732,11981],{"class":3479},[3143,12734,12735,12737,12739],{"class":3145,"line":3152},[3143,12736,4049],{"class":3452},[3143,12738,3516],{"class":3456},[3143,12740,11990],{"class":3479},[3143,12742,12743,12745],{"class":3145,"line":3158},[3143,12744,4059],{"class":3452},[3143,12746,3457],{"class":3456},[3143,12748,12749,12751,12753],{"class":3145,"line":3164},[3143,12750,4066],{"class":3452},[3143,12752,3516],{"class":3456},[3143,12754,12755],{"class":3479},"frontend\n",[3143,12757,12758,12760],{"class":3145,"line":3171},[3143,12759,4086],{"class":3452},[3143,12761,3457],{"class":3456},[3143,12763,12764,12766,12768],{"class":3145,"line":3177},[3143,12765,12015],{"class":3452},[3143,12767,3516],{"class":3456},[3143,12769,12770],{"class":3673},"2\n",[3143,12772,12773,12775],{"class":3145,"line":3183},[3143,12774,4093],{"class":3452},[3143,12776,3457],{"class":3456},[3143,12778,12779,12781],{"class":3145,"line":3189},[3143,12780,12031],{"class":3452},[3143,12782,3457],{"class":3456},[3143,12784,12785,12787,12789],{"class":3145,"line":3195},[3143,12786,4296],{"class":3452},[3143,12788,3516],{"class":3456},[3143,12790,12755],{"class":3479},[3143,12792,12793,12795],{"class":3145,"line":3201},[3143,12794,4862],{"class":3452},[3143,12796,3457],{"class":3456},[3143,12798,12799,12801],{"class":3145,"line":3207},[3143,12800,12052],{"class":3452},[3143,12802,3457],{"class":3456},[3143,12804,12805,12807],{"class":3145,"line":3213},[3143,12806,12059],{"class":3452},[3143,12808,3457],{"class":3456},[3143,12810,12811,12813,12815],{"class":3145,"line":3219},[3143,12812,12066],{"class":3452},[3143,12814,3516],{"class":3456},[3143,12816,12755],{"class":3479},[3143,12818,12819,12821],{"class":3145,"line":3225},[3143,12820,4869],{"class":3452},[3143,12822,3457],{"class":3456},[3143,12824,12825,12827],{"class":3145,"line":3231},[3143,12826,4876],{"class":3452},[3143,12828,3457],{"class":3456},[3143,12830,12831,12833,12835,12837],{"class":3145,"line":3236},[3143,12832,4883],{"class":3456},[3143,12834,3513],{"class":3452},[3143,12836,3516],{"class":3456},[3143,12838,12839],{"class":3479},"nginx\n",[3143,12841,12842,12844,12846],{"class":3145,"line":3242},[3143,12843,12097],{"class":3452},[3143,12845,3516],{"class":3456},[3143,12847,12848],{"class":3479},"nginx:1.27\n",[3143,12850,12851,12853],{"class":3145,"line":3247},[3143,12852,4894],{"class":3452},[3143,12854,3457],{"class":3456},[3143,12856,12857,12859,12861,12863],{"class":3145,"line":3253},[3143,12858,4901],{"class":3456},[3143,12860,4691],{"class":3452},[3143,12862,3516],{"class":3456},[3143,12864,4144],{"class":3673},[3143,12866,12867,12869],{"class":3145,"line":3259},[3143,12868,12191],{"class":3452},[3143,12870,3457],{"class":3456},[3143,12872,12873,12875,12877,12879],{"class":3145,"line":3265},[3143,12874,4901],{"class":3456},[3143,12876,3513],{"class":3452},[3143,12878,3516],{"class":3456},[3143,12880,12881],{"class":3479},"nginx-config\n",[3143,12883,12884,12886,12888],{"class":3145,"line":3270},[3143,12885,12209],{"class":3452},[3143,12887,3516],{"class":3456},[3143,12889,12890],{"class":3479},"/etc/nginx/conf.d\n",[3143,12892,12893,12895],{"class":3145,"line":3276},[3143,12894,12219],{"class":3452},[3143,12896,3457],{"class":3456},[3143,12898,12899,12901,12903,12905],{"class":3145,"line":3282},[3143,12900,4883],{"class":3456},[3143,12902,3513],{"class":3452},[3143,12904,3516],{"class":3456},[3143,12906,12881],{"class":3479},[3143,12908,12909,12912],{"class":3145,"line":3288},[3143,12910,12911],{"class":3452},"          configMap",[3143,12913,3457],{"class":3456},[3143,12915,12916,12919,12921],{"class":3145,"line":3293},[3143,12917,12918],{"class":3452},"            name",[3143,12920,3516],{"class":3456},[3143,12922,12881],{"class":3479},[3114,12924,12925],{},[3118,12926,12927],{},"nginx-configmap.yaml:",[3133,12929,12931],{"className":3443,"code":12930,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nginx-config\ndata:\n  default.conf: |\n    upstream api {\n        server api-service:80;\n    }\n    \n    server {\n        listen 80;\n        \n        location /api/ {\n            proxy_pass http://api/;\n            proxy_set_header Host $host;\n            proxy_set_header X-Real-IP $remote_addr;\n        }\n        \n        location / {\n            root /usr/share/nginx/html;\n            index index.html;\n            try_files $uri $uri/ /index.html;\n        }\n    }\n",[3140,12932,12933,12941,12949,12955,12963,12969,12978,12983,12988,12992,12996,13001,13006,13011,13016,13021,13026,13031,13036,13040,13045,13050,13055,13060,13064],{"__ignoreMap":3138},[3143,12934,12935,12937,12939],{"class":3145,"line":3146},[3143,12936,4039],{"class":3452},[3143,12938,3516],{"class":3456},[3143,12940,4044],{"class":3479},[3143,12942,12943,12945,12947],{"class":3145,"line":3152},[3143,12944,4049],{"class":3452},[3143,12946,3516],{"class":3456},[3143,12948,5717],{"class":3479},[3143,12950,12951,12953],{"class":3145,"line":3158},[3143,12952,4059],{"class":3452},[3143,12954,3457],{"class":3456},[3143,12956,12957,12959,12961],{"class":3145,"line":3164},[3143,12958,4066],{"class":3452},[3143,12960,3516],{"class":3456},[3143,12962,12881],{"class":3479},[3143,12964,12965,12967],{"class":3145,"line":3171},[3143,12966,5737],{"class":3452},[3143,12968,3457],{"class":3456},[3143,12970,12971,12974,12976],{"class":3145,"line":3177},[3143,12972,12973],{"class":3452},"  default.conf",[3143,12975,3516],{"class":3456},[3143,12977,8195],{"class":8194},[3143,12979,12980],{"class":3145,"line":3183},[3143,12981,12982],{"class":3479},"    upstream api {\n",[3143,12984,12985],{"class":3145,"line":3189},[3143,12986,12987],{"class":3479},"        server api-service:80;\n",[3143,12989,12990],{"class":3145,"line":3195},[3143,12991,3198],{"class":3479},[3143,12993,12994],{"class":3145,"line":3201},[3143,12995,3204],{"class":3479},[3143,12997,12998],{"class":3145,"line":3207},[3143,12999,13000],{"class":3479},"    server {\n",[3143,13002,13003],{"class":3145,"line":3213},[3143,13004,13005],{"class":3479},"        listen 80;\n",[3143,13007,13008],{"class":3145,"line":3219},[3143,13009,13010],{"class":3479},"        \n",[3143,13012,13013],{"class":3145,"line":3225},[3143,13014,13015],{"class":3479},"        location /api/ {\n",[3143,13017,13018],{"class":3145,"line":3231},[3143,13019,13020],{"class":3479},"            proxy_pass http://api/;\n",[3143,13022,13023],{"class":3145,"line":3236},[3143,13024,13025],{"class":3479},"            proxy_set_header Host $host;\n",[3143,13027,13028],{"class":3145,"line":3242},[3143,13029,13030],{"class":3479},"            proxy_set_header X-Real-IP $remote_addr;\n",[3143,13032,13033],{"class":3145,"line":3247},[3143,13034,13035],{"class":3479},"        }\n",[3143,13037,13038],{"class":3145,"line":3253},[3143,13039,13010],{"class":3479},[3143,13041,13042],{"class":3145,"line":3259},[3143,13043,13044],{"class":3479},"        location / {\n",[3143,13046,13047],{"class":3145,"line":3265},[3143,13048,13049],{"class":3479},"            root /usr/share/nginx/html;\n",[3143,13051,13052],{"class":3145,"line":3270},[3143,13053,13054],{"class":3479},"            index index.html;\n",[3143,13056,13057],{"class":3145,"line":3276},[3143,13058,13059],{"class":3479},"            try_files $uri $uri/ /index.html;\n",[3143,13061,13062],{"class":3145,"line":3282},[3143,13063,13035],{"class":3479},[3143,13065,13066],{"class":3145,"line":3288},[3143,13067,3198],{"class":3479},[3114,13069,13070],{},[3118,13071,13072],{},"frontend-service.yaml (для production з LoadBalancer):",[3133,13074,13076],{"className":3443,"code":13075,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: frontend-service\nspec:\n  type: LoadBalancer\n  selector:\n    app: frontend\n  ports:\n    - port: 80\n      targetPort: 80\n",[3140,13077,13078,13086,13094,13100,13109,13115,13123,13129,13137,13143,13153],{"__ignoreMap":3138},[3143,13079,13080,13082,13084],{"class":3145,"line":3146},[3143,13081,4039],{"class":3452},[3143,13083,3516],{"class":3456},[3143,13085,4044],{"class":3479},[3143,13087,13088,13090,13092],{"class":3145,"line":3152},[3143,13089,4049],{"class":3452},[3143,13091,3516],{"class":3456},[3143,13093,4054],{"class":3479},[3143,13095,13096,13098],{"class":3145,"line":3158},[3143,13097,4059],{"class":3452},[3143,13099,3457],{"class":3456},[3143,13101,13102,13104,13106],{"class":3145,"line":3164},[3143,13103,4066],{"class":3452},[3143,13105,3516],{"class":3456},[3143,13107,13108],{"class":3479},"frontend-service\n",[3143,13110,13111,13113],{"class":3145,"line":3171},[3143,13112,4086],{"class":3452},[3143,13114,3457],{"class":3456},[3143,13116,13117,13119,13121],{"class":3145,"line":3177},[3143,13118,4159],{"class":3452},[3143,13120,3516],{"class":3456},[3143,13122,6414],{"class":3479},[3143,13124,13125,13127],{"class":3145,"line":3183},[3143,13126,4093],{"class":3452},[3143,13128,3457],{"class":3456},[3143,13130,13131,13133,13135],{"class":3145,"line":3189},[3143,13132,4100],{"class":3452},[3143,13134,3516],{"class":3456},[3143,13136,12755],{"class":3479},[3143,13138,13139,13141],{"class":3145,"line":3195},[3143,13140,4110],{"class":3452},[3143,13142,3457],{"class":3456},[3143,13144,13145,13147,13149,13151],{"class":3145,"line":3201},[3143,13146,4117],{"class":3456},[3143,13148,4338],{"class":3452},[3143,13150,3516],{"class":3456},[3143,13152,4144],{"class":3673},[3143,13154,13155,13157,13159],{"class":3145,"line":3207},[3143,13156,4149],{"class":3452},[3143,13158,3516],{"class":3456},[3143,13160,4144],{"class":3673},[3114,13162,13163],{},[3118,13164,13165],{},"frontend-service-nodeport.yaml (для Minikube):",[3133,13167,13169],{"className":3443,"code":13168,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: frontend-service\nspec:\n  type: NodePort\n  selector:\n    app: frontend\n  ports:\n    - port: 80\n      targetPort: 80\n      nodePort: 30080  # Доступ через http://\u003Cminikube-ip>:30080\n",[3140,13170,13171,13179,13187,13193,13201,13207,13215,13221,13229,13235,13245,13253],{"__ignoreMap":3138},[3143,13172,13173,13175,13177],{"class":3145,"line":3146},[3143,13174,4039],{"class":3452},[3143,13176,3516],{"class":3456},[3143,13178,4044],{"class":3479},[3143,13180,13181,13183,13185],{"class":3145,"line":3152},[3143,13182,4049],{"class":3452},[3143,13184,3516],{"class":3456},[3143,13186,4054],{"class":3479},[3143,13188,13189,13191],{"class":3145,"line":3158},[3143,13190,4059],{"class":3452},[3143,13192,3457],{"class":3456},[3143,13194,13195,13197,13199],{"class":3145,"line":3164},[3143,13196,4066],{"class":3452},[3143,13198,3516],{"class":3456},[3143,13200,13108],{"class":3479},[3143,13202,13203,13205],{"class":3145,"line":3171},[3143,13204,4086],{"class":3452},[3143,13206,3457],{"class":3456},[3143,13208,13209,13211,13213],{"class":3145,"line":3177},[3143,13210,4159],{"class":3452},[3143,13212,3516],{"class":3456},[3143,13214,5845],{"class":3479},[3143,13216,13217,13219],{"class":3145,"line":3183},[3143,13218,4093],{"class":3452},[3143,13220,3457],{"class":3456},[3143,13222,13223,13225,13227],{"class":3145,"line":3189},[3143,13224,4100],{"class":3452},[3143,13226,3516],{"class":3456},[3143,13228,12755],{"class":3479},[3143,13230,13231,13233],{"class":3145,"line":3195},[3143,13232,4110],{"class":3452},[3143,13234,3457],{"class":3456},[3143,13236,13237,13239,13241,13243],{"class":3145,"line":3201},[3143,13238,4117],{"class":3456},[3143,13240,4338],{"class":3452},[3143,13242,3516],{"class":3456},[3143,13244,4144],{"class":3673},[3143,13246,13247,13249,13251],{"class":3145,"line":3207},[3143,13248,4149],{"class":3452},[3143,13250,3516],{"class":3456},[3143,13252,4144],{"class":3673},[3143,13254,13255,13257,13259,13261],{"class":3145,"line":3213},[3143,13256,5888],{"class":3452},[3143,13258,3516],{"class":3456},[3143,13260,5893],{"class":3673},[3143,13262,13263],{"class":4245},"  # Доступ через http://\u003Cminikube-ip>:30080\n",[3122,13265,13267],{"id":13266},"розгортання","Розгортання",[6191,13269,13271,13278,13287,13296,13299,13306,13315,13324,13327,13334,13343,13352,13361,13364,13371,13380,13384,13388,13392,13396,13400,13404,13408,13411,13415,13419,13423],{"title":13270},"Розгортання застосунку",[6195,13272,13274],{"className":13273},[3145],[3143,13275,13277],{"className":13276},[6201],"# PostgreSQL",[6195,13279,13281,4793,13284],{"className":13280},[3145],[3143,13282,6209],{"className":13283},[6201],[3118,13285,13286],{},"kubectl apply -f postgres-deployment.yaml",[6195,13288,13290,4793,13293],{"className":13289},[3145],[3143,13291,6209],{"className":13292},[6201],[3118,13294,13295],{},"kubectl apply -f postgres-service.yaml",[6195,13297],{"className":13298},[3145],[6195,13300,13302],{"className":13301},[3145],[3143,13303,13305],{"className":13304},[6201],"# TodoApi",[6195,13307,13309,4793,13312],{"className":13308},[3145],[3143,13310,6209],{"className":13311},[6201],[3118,13313,13314],{},"kubectl apply -f api-deployment.yaml",[6195,13316,13318,4793,13321],{"className":13317},[3145],[3143,13319,6209],{"className":13320},[6201],[3118,13322,13323],{},"kubectl apply -f api-service.yaml",[6195,13325],{"className":13326},[3145],[6195,13328,13330],{"className":13329},[3145],[3143,13331,13333],{"className":13332},[6201],"# Frontend",[6195,13335,13337,4793,13340],{"className":13336},[3145],[3143,13338,6209],{"className":13339},[6201],[3118,13341,13342],{},"kubectl apply -f nginx-configmap.yaml",[6195,13344,13346,4793,13349],{"className":13345},[3145],[3143,13347,6209],{"className":13348},[6201],[3118,13350,13351],{},"kubectl apply -f frontend-deployment.yaml",[6195,13353,13355,4793,13358],{"className":13354},[3145],[3143,13356,6209],{"className":13357},[6201],[3118,13359,13360],{},"kubectl apply -f frontend-service-nodeport.yaml",[6195,13362],{"className":13363},[3145],[6195,13365,13367],{"className":13366},[3145],[3143,13368,13370],{"className":13369},[6201],"# Перевірка",[6195,13372,13374,4793,13377],{"className":13373},[3145],[3143,13375,6209],{"className":13376},[6201],[3118,13378,13379],{},"kubectl get all",[6195,13381,13383],{"className":13382},[3145],"NAME                            READY   STATUS    RESTARTS   AGE",[6195,13385,13387],{"className":13386},[3145],"pod/postgres-xxx                1/1     Running   0          2m",[6195,13389,13391],{"className":13390},[3145],"pod/todoapi-xxx                 1/1     Running   0          1m",[6195,13393,13395],{"className":13394},[3145],"pod/todoapi-yyy                 1/1     Running   0          1m",[6195,13397,13399],{"className":13398},[3145],"pod/todoapi-zzz                 1/1     Running   0          1m",[6195,13401,13403],{"className":13402},[3145],"pod/frontend-xxx                1/1     Running   0          30s",[6195,13405,13407],{"className":13406},[3145],"pod/frontend-yyy                1/1     Running   0          30s",[6195,13409],{"className":13410},[3145],[6195,13412,13414],{"className":13413},[3145],"NAME                       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)",[6195,13416,13418],{"className":13417},[3145],"service/postgres-service   ClusterIP   10.96.0.10     \u003Cnone>        5432/TCP",[6195,13420,13422],{"className":13421},[3145],"service/api-service        ClusterIP   10.96.0.20     \u003Cnone>        80/TCP",[6195,13424,13426],{"className":13425},[3145],"service/frontend-service   NodePort    10.96.0.30     \u003Cnone>        80:30080/TCP",[3122,13428,968],{"id":13429},"тестування",[6191,13431,13433,13440,13448,13451,13454,13461,13470,13474,13477,13484,13493],{"title":13432},"Тестування застосунку",[6195,13434,13436],{"className":13435},[3145],[3143,13437,13439],{"className":13438},[6201],"# Отримання IP Minikube",[6195,13441,13443,4793,13446],{"className":13442},[3145],[3143,13444,6209],{"className":13445},[6201],[3118,13447,6266],{},[6195,13449,6270],{"className":13450},[3145],[6195,13452],{"className":13453},[3145],[6195,13455,13457],{"className":13456},[3145],[3143,13458,13460],{"className":13459},[6201],"# Доступ до frontend",[6195,13462,13464,4793,13467],{"className":13463},[3145],[3143,13465,6209],{"className":13466},[6201],[3118,13468,13469],{},"curl http://192.168.49.2:30080",[6195,13471,13473],{"className":13472},[3145],"\u003Chtml>...\u003C/html>",[6195,13475],{"className":13476},[3145],[6195,13478,13480],{"className":13479},[3145],[3143,13481,13483],{"className":13482},[6201],"# Доступ до API через frontend",[6195,13485,13487,4793,13490],{"className":13486},[3145],[3143,13488,6209],{"className":13489},[6201],[3118,13491,13492],{},"curl http://192.168.49.2:30080/api/todos",[6195,13494,6293],{"className":13495},[3145],[3582,13497],{},[3109,13499,13501],{"id":13500},"практичні-завдання","Практичні завдання",[3114,13503,13504],{},"Тепер виконайте завдання для закріплення знань про Service та мережі у Kubernetes.",[3122,13506,13508],{"id":13507},"завдання-1-експерименти-з-типами-service","Завдання 1: Експерименти з типами Service",[3114,13510,13511,13514],{},[3118,13512,13513],{},"Мета:"," Зрозуміти різницю між ClusterIP, NodePort та LoadBalancer.",[3114,13516,13517],{},[3118,13518,13519],{},"Завдання:",[3542,13521,13522,13525,13538,13552],{},[3390,13523,13524],{},"Створіть Deployment з nginx (3 репліки)",[3390,13526,13527,13528],{},"Створіть три Service для того самого Deployment:",[3387,13529,13530,13532,13535],{},[3390,13531,9230],{},[3390,13533,13534],{},"NodePort Service",[3390,13536,13537],{},"LoadBalancer Service (або емулюйте через minikube tunnel)",[3390,13539,13540,13541],{},"Протестуйте доступ до кожного Service:",[3387,13542,13543,13546,13549],{},[3390,13544,13545],{},"ClusterIP — з іншого Pod",[3390,13547,13548],{},"NodePort — з локальної машини",[3390,13550,13551],{},"LoadBalancer — через EXTERNAL-IP",[3390,13553,13554],{},"Порівняйте результати",[3114,13556,13557,13560],{},[3118,13558,13559],{},"Очікуваний результат:"," Ви зрозумієте, коли використовувати кожен тип Service.",[13562,13563,13565,13570,13712,13717,13805,13810,13907,13912,14000,14005],"collapsible",{"title":13564},"Показати рішення",[3114,13566,13567],{},[3118,13568,13569],{},"nginx-deployment.yaml:",[3133,13571,13573],{"className":3443,"code":13572,"language":3445,"meta":3138,"style":3138},"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-test\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n        - name: nginx\n          image: nginx:1.27\n          ports:\n            - containerPort: 80\n",[3140,13574,13575,13583,13591,13597,13606,13612,13620,13626,13632,13640,13646,13652,13658,13666,13672,13678,13688,13696,13702],{"__ignoreMap":3138},[3143,13576,13577,13579,13581],{"class":3145,"line":3146},[3143,13578,4039],{"class":3452},[3143,13580,3516],{"class":3456},[3143,13582,11981],{"class":3479},[3143,13584,13585,13587,13589],{"class":3145,"line":3152},[3143,13586,4049],{"class":3452},[3143,13588,3516],{"class":3456},[3143,13590,11990],{"class":3479},[3143,13592,13593,13595],{"class":3145,"line":3158},[3143,13594,4059],{"class":3452},[3143,13596,3457],{"class":3456},[3143,13598,13599,13601,13603],{"class":3145,"line":3164},[3143,13600,4066],{"class":3452},[3143,13602,3516],{"class":3456},[3143,13604,13605],{"class":3479},"nginx-test\n",[3143,13607,13608,13610],{"class":3145,"line":3171},[3143,13609,4086],{"class":3452},[3143,13611,3457],{"class":3456},[3143,13613,13614,13616,13618],{"class":3145,"line":3177},[3143,13615,12015],{"class":3452},[3143,13617,3516],{"class":3456},[3143,13619,3674],{"class":3673},[3143,13621,13622,13624],{"class":3145,"line":3183},[3143,13623,4093],{"class":3452},[3143,13625,3457],{"class":3456},[3143,13627,13628,13630],{"class":3145,"line":3189},[3143,13629,12031],{"class":3452},[3143,13631,3457],{"class":3456},[3143,13633,13634,13636,13638],{"class":3145,"line":3195},[3143,13635,4296],{"class":3452},[3143,13637,3516],{"class":3456},[3143,13639,12839],{"class":3479},[3143,13641,13642,13644],{"class":3145,"line":3201},[3143,13643,4862],{"class":3452},[3143,13645,3457],{"class":3456},[3143,13647,13648,13650],{"class":3145,"line":3207},[3143,13649,12052],{"class":3452},[3143,13651,3457],{"class":3456},[3143,13653,13654,13656],{"class":3145,"line":3213},[3143,13655,12059],{"class":3452},[3143,13657,3457],{"class":3456},[3143,13659,13660,13662,13664],{"class":3145,"line":3219},[3143,13661,12066],{"class":3452},[3143,13663,3516],{"class":3456},[3143,13665,12839],{"class":3479},[3143,13667,13668,13670],{"class":3145,"line":3225},[3143,13669,4869],{"class":3452},[3143,13671,3457],{"class":3456},[3143,13673,13674,13676],{"class":3145,"line":3231},[3143,13675,4876],{"class":3452},[3143,13677,3457],{"class":3456},[3143,13679,13680,13682,13684,13686],{"class":3145,"line":3236},[3143,13681,4883],{"class":3456},[3143,13683,3513],{"class":3452},[3143,13685,3516],{"class":3456},[3143,13687,12839],{"class":3479},[3143,13689,13690,13692,13694],{"class":3145,"line":3242},[3143,13691,12097],{"class":3452},[3143,13693,3516],{"class":3456},[3143,13695,12848],{"class":3479},[3143,13697,13698,13700],{"class":3145,"line":3247},[3143,13699,4894],{"class":3452},[3143,13701,3457],{"class":3456},[3143,13703,13704,13706,13708,13710],{"class":3145,"line":3253},[3143,13705,4901],{"class":3456},[3143,13707,4691],{"class":3452},[3143,13709,3516],{"class":3456},[3143,13711,4144],{"class":3673},[3114,13713,13714],{},[3118,13715,13716],{},"clusterip-service.yaml:",[3133,13718,13720],{"className":3443,"code":13719,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-clusterip\nspec:\n  type: ClusterIP\n  selector:\n    app: nginx\n  ports:\n    - port: 80\n      targetPort: 80\n",[3140,13721,13722,13730,13738,13744,13753,13759,13767,13773,13781,13787,13797],{"__ignoreMap":3138},[3143,13723,13724,13726,13728],{"class":3145,"line":3146},[3143,13725,4039],{"class":3452},[3143,13727,3516],{"class":3456},[3143,13729,4044],{"class":3479},[3143,13731,13732,13734,13736],{"class":3145,"line":3152},[3143,13733,4049],{"class":3452},[3143,13735,3516],{"class":3456},[3143,13737,4054],{"class":3479},[3143,13739,13740,13742],{"class":3145,"line":3158},[3143,13741,4059],{"class":3452},[3143,13743,3457],{"class":3456},[3143,13745,13746,13748,13750],{"class":3145,"line":3164},[3143,13747,4066],{"class":3452},[3143,13749,3516],{"class":3456},[3143,13751,13752],{"class":3479},"nginx-clusterip\n",[3143,13754,13755,13757],{"class":3145,"line":3171},[3143,13756,4086],{"class":3452},[3143,13758,3457],{"class":3456},[3143,13760,13761,13763,13765],{"class":3145,"line":3177},[3143,13762,4159],{"class":3452},[3143,13764,3516],{"class":3456},[3143,13766,4164],{"class":3479},[3143,13768,13769,13771],{"class":3145,"line":3183},[3143,13770,4093],{"class":3452},[3143,13772,3457],{"class":3456},[3143,13774,13775,13777,13779],{"class":3145,"line":3189},[3143,13776,4100],{"class":3452},[3143,13778,3516],{"class":3456},[3143,13780,12839],{"class":3479},[3143,13782,13783,13785],{"class":3145,"line":3195},[3143,13784,4110],{"class":3452},[3143,13786,3457],{"class":3456},[3143,13788,13789,13791,13793,13795],{"class":3145,"line":3201},[3143,13790,4117],{"class":3456},[3143,13792,4338],{"class":3452},[3143,13794,3516],{"class":3456},[3143,13796,4144],{"class":3673},[3143,13798,13799,13801,13803],{"class":3145,"line":3207},[3143,13800,4149],{"class":3452},[3143,13802,3516],{"class":3456},[3143,13804,4144],{"class":3673},[3114,13806,13807],{},[3118,13808,13809],{},"nodeport-service.yaml:",[3133,13811,13813],{"className":3443,"code":13812,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-nodeport\nspec:\n  type: NodePort\n  selector:\n    app: nginx\n  ports:\n    - port: 80\n      targetPort: 80\n      nodePort: 30080\n",[3140,13814,13815,13823,13831,13837,13846,13852,13860,13866,13874,13880,13890,13898],{"__ignoreMap":3138},[3143,13816,13817,13819,13821],{"class":3145,"line":3146},[3143,13818,4039],{"class":3452},[3143,13820,3516],{"class":3456},[3143,13822,4044],{"class":3479},[3143,13824,13825,13827,13829],{"class":3145,"line":3152},[3143,13826,4049],{"class":3452},[3143,13828,3516],{"class":3456},[3143,13830,4054],{"class":3479},[3143,13832,13833,13835],{"class":3145,"line":3158},[3143,13834,4059],{"class":3452},[3143,13836,3457],{"class":3456},[3143,13838,13839,13841,13843],{"class":3145,"line":3164},[3143,13840,4066],{"class":3452},[3143,13842,3516],{"class":3456},[3143,13844,13845],{"class":3479},"nginx-nodeport\n",[3143,13847,13848,13850],{"class":3145,"line":3171},[3143,13849,4086],{"class":3452},[3143,13851,3457],{"class":3456},[3143,13853,13854,13856,13858],{"class":3145,"line":3177},[3143,13855,4159],{"class":3452},[3143,13857,3516],{"class":3456},[3143,13859,5845],{"class":3479},[3143,13861,13862,13864],{"class":3145,"line":3183},[3143,13863,4093],{"class":3452},[3143,13865,3457],{"class":3456},[3143,13867,13868,13870,13872],{"class":3145,"line":3189},[3143,13869,4100],{"class":3452},[3143,13871,3516],{"class":3456},[3143,13873,12839],{"class":3479},[3143,13875,13876,13878],{"class":3145,"line":3195},[3143,13877,4110],{"class":3452},[3143,13879,3457],{"class":3456},[3143,13881,13882,13884,13886,13888],{"class":3145,"line":3201},[3143,13883,4117],{"class":3456},[3143,13885,4338],{"class":3452},[3143,13887,3516],{"class":3456},[3143,13889,4144],{"class":3673},[3143,13891,13892,13894,13896],{"class":3145,"line":3207},[3143,13893,4149],{"class":3452},[3143,13895,3516],{"class":3456},[3143,13897,4144],{"class":3673},[3143,13899,13900,13902,13904],{"class":3145,"line":3213},[3143,13901,5888],{"class":3452},[3143,13903,3516],{"class":3456},[3143,13905,13906],{"class":3673},"30080\n",[3114,13908,13909],{},[3118,13910,13911],{},"loadbalancer-service.yaml:",[3133,13913,13915],{"className":3443,"code":13914,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-loadbalancer\nspec:\n  type: LoadBalancer\n  selector:\n    app: nginx\n  ports:\n    - port: 80\n      targetPort: 80\n",[3140,13916,13917,13925,13933,13939,13948,13954,13962,13968,13976,13982,13992],{"__ignoreMap":3138},[3143,13918,13919,13921,13923],{"class":3145,"line":3146},[3143,13920,4039],{"class":3452},[3143,13922,3516],{"class":3456},[3143,13924,4044],{"class":3479},[3143,13926,13927,13929,13931],{"class":3145,"line":3152},[3143,13928,4049],{"class":3452},[3143,13930,3516],{"class":3456},[3143,13932,4054],{"class":3479},[3143,13934,13935,13937],{"class":3145,"line":3158},[3143,13936,4059],{"class":3452},[3143,13938,3457],{"class":3456},[3143,13940,13941,13943,13945],{"class":3145,"line":3164},[3143,13942,4066],{"class":3452},[3143,13944,3516],{"class":3456},[3143,13946,13947],{"class":3479},"nginx-loadbalancer\n",[3143,13949,13950,13952],{"class":3145,"line":3171},[3143,13951,4086],{"class":3452},[3143,13953,3457],{"class":3456},[3143,13955,13956,13958,13960],{"class":3145,"line":3177},[3143,13957,4159],{"class":3452},[3143,13959,3516],{"class":3456},[3143,13961,6414],{"class":3479},[3143,13963,13964,13966],{"class":3145,"line":3183},[3143,13965,4093],{"class":3452},[3143,13967,3457],{"class":3456},[3143,13969,13970,13972,13974],{"class":3145,"line":3189},[3143,13971,4100],{"class":3452},[3143,13973,3516],{"class":3456},[3143,13975,12839],{"class":3479},[3143,13977,13978,13980],{"class":3145,"line":3195},[3143,13979,4110],{"class":3452},[3143,13981,3457],{"class":3456},[3143,13983,13984,13986,13988,13990],{"class":3145,"line":3201},[3143,13985,4117],{"class":3456},[3143,13987,4338],{"class":3452},[3143,13989,3516],{"class":3456},[3143,13991,4144],{"class":3673},[3143,13993,13994,13996,13998],{"class":3145,"line":3207},[3143,13995,4149],{"class":3452},[3143,13997,3516],{"class":3456},[3143,13999,4144],{"class":3673},[3114,14001,14002],{},[3118,14003,14004],{},"Команди:",[3133,14006,14008],{"className":6307,"code":14007,"language":6309,"meta":3138,"style":3138},"# Створення\nkubectl apply -f nginx-deployment.yaml\nkubectl apply -f clusterip-service.yaml\nkubectl apply -f nodeport-service.yaml\nkubectl apply -f loadbalancer-service.yaml\n\n# Перегляд Service\nkubectl get services\n# NAME                  TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)\n# nginx-clusterip       ClusterIP      10.96.0.10     \u003Cnone>        80/TCP\n# nginx-nodeport        NodePort       10.96.0.20     \u003Cnone>        80:30080/TCP\n# nginx-loadbalancer    LoadBalancer   10.96.0.30     \u003Cpending>     80/TCP\n\n# Тест 1: ClusterIP (з іншого Pod)\nkubectl run test-pod --image=curlimages/curl --rm -it --restart=Never -- \\\n  curl http://nginx-clusterip\n# Працює ✅\n\n# Тест 2: NodePort (з локальної машини)\ncurl http://$(minikube ip):30080\n# Працює ✅\n\n# Тест 3: LoadBalancer (для Minikube потрібен tunnel)\nminikube tunnel  # У окремому терміналі\nkubectl get service nginx-loadbalancer\n# EXTERNAL-IP тепер має значення (наприклад, 127.0.0.1)\ncurl http://127.0.0.1\n# Працює ✅\n\n# Очищення\nkubectl delete deployment nginx-test\nkubectl delete service nginx-clusterip nginx-nodeport nginx-loadbalancer\n",[3140,14009,14010,14015,14029,14040,14051,14062,14066,14071,14081,14086,14091,14096,14101,14105,14110,14139,14147,14152,14156,14161,14182,14186,14190,14195,14205,14216,14221,14228,14232,14236,14241,14254],{"__ignoreMap":3138},[3143,14011,14012],{"class":3145,"line":3146},[3143,14013,14014],{"class":4245},"# Створення\n",[3143,14016,14017,14020,14023,14026],{"class":3145,"line":3152},[3143,14018,14019],{"class":5536},"kubectl",[3143,14021,14022],{"class":3529}," apply",[3143,14024,14025],{"class":5520}," -f",[3143,14027,14028],{"class":3529}," nginx-deployment.yaml\n",[3143,14030,14031,14033,14035,14037],{"class":3145,"line":3158},[3143,14032,14019],{"class":5536},[3143,14034,14022],{"class":3529},[3143,14036,14025],{"class":5520},[3143,14038,14039],{"class":3529}," clusterip-service.yaml\n",[3143,14041,14042,14044,14046,14048],{"class":3145,"line":3164},[3143,14043,14019],{"class":5536},[3143,14045,14022],{"class":3529},[3143,14047,14025],{"class":5520},[3143,14049,14050],{"class":3529}," nodeport-service.yaml\n",[3143,14052,14053,14055,14057,14059],{"class":3145,"line":3171},[3143,14054,14019],{"class":5536},[3143,14056,14022],{"class":3529},[3143,14058,14025],{"class":5520},[3143,14060,14061],{"class":3529}," loadbalancer-service.yaml\n",[3143,14063,14064],{"class":3145,"line":3177},[3143,14065,3168],{"emptyLinePlaceholder":3167},[3143,14067,14068],{"class":3145,"line":3183},[3143,14069,14070],{"class":4245},"# Перегляд Service\n",[3143,14072,14073,14075,14078],{"class":3145,"line":3189},[3143,14074,14019],{"class":5536},[3143,14076,14077],{"class":3529}," get",[3143,14079,14080],{"class":3529}," services\n",[3143,14082,14083],{"class":3145,"line":3195},[3143,14084,14085],{"class":4245},"# NAME                  TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)\n",[3143,14087,14088],{"class":3145,"line":3201},[3143,14089,14090],{"class":4245},"# nginx-clusterip       ClusterIP      10.96.0.10     \u003Cnone>        80/TCP\n",[3143,14092,14093],{"class":3145,"line":3207},[3143,14094,14095],{"class":4245},"# nginx-nodeport        NodePort       10.96.0.20     \u003Cnone>        80:30080/TCP\n",[3143,14097,14098],{"class":3145,"line":3213},[3143,14099,14100],{"class":4245},"# nginx-loadbalancer    LoadBalancer   10.96.0.30     \u003Cpending>     80/TCP\n",[3143,14102,14103],{"class":3145,"line":3219},[3143,14104,3168],{"emptyLinePlaceholder":3167},[3143,14106,14107],{"class":3145,"line":3225},[3143,14108,14109],{"class":4245},"# Тест 1: ClusterIP (з іншого Pod)\n",[3143,14111,14112,14114,14117,14120,14123,14126,14129,14132,14135],{"class":3145,"line":3231},[3143,14113,14019],{"class":5536},[3143,14115,14116],{"class":3529}," run",[3143,14118,14119],{"class":3529}," test-pod",[3143,14121,14122],{"class":5520}," --image=curlimages/curl",[3143,14124,14125],{"class":5520}," --rm",[3143,14127,14128],{"class":5520}," -it",[3143,14130,14131],{"class":5520}," --restart=Never",[3143,14133,14134],{"class":5520}," --",[3143,14136,14138],{"class":14137},"sjcCO"," \\\n",[3143,14140,14141,14144],{"class":3145,"line":3236},[3143,14142,14143],{"class":3529},"  curl",[3143,14145,14146],{"class":3529}," http://nginx-clusterip\n",[3143,14148,14149],{"class":3145,"line":3242},[3143,14150,14151],{"class":4245},"# Працює ✅\n",[3143,14153,14154],{"class":3145,"line":3247},[3143,14155,3168],{"emptyLinePlaceholder":3167},[3143,14157,14158],{"class":3145,"line":3253},[3143,14159,14160],{"class":4245},"# Тест 2: NodePort (з локальної машини)\n",[3143,14162,14163,14166,14169,14172,14174,14177,14179],{"class":3145,"line":3259},[3143,14164,14165],{"class":5536},"curl",[3143,14167,14168],{"class":3529}," http://",[3143,14170,14171],{"class":3456},"$(",[3143,14173,6316],{"class":5536},[3143,14175,14176],{"class":3529}," ip",[3143,14178,4002],{"class":3456},[3143,14180,14181],{"class":3529},":30080\n",[3143,14183,14184],{"class":3145,"line":3265},[3143,14185,14151],{"class":4245},[3143,14187,14188],{"class":3145,"line":3270},[3143,14189,3168],{"emptyLinePlaceholder":3167},[3143,14191,14192],{"class":3145,"line":3276},[3143,14193,14194],{"class":4245},"# Тест 3: LoadBalancer (для Minikube потрібен tunnel)\n",[3143,14196,14197,14199,14202],{"class":3145,"line":3282},[3143,14198,6316],{"class":5536},[3143,14200,14201],{"class":3529}," tunnel",[3143,14203,14204],{"class":4245},"  # У окремому терміналі\n",[3143,14206,14207,14209,14211,14213],{"class":3145,"line":3288},[3143,14208,14019],{"class":5536},[3143,14210,14077],{"class":3529},[3143,14212,6319],{"class":3529},[3143,14214,14215],{"class":3529}," nginx-loadbalancer\n",[3143,14217,14218],{"class":3145,"line":3293},[3143,14219,14220],{"class":4245},"# EXTERNAL-IP тепер має значення (наприклад, 127.0.0.1)\n",[3143,14222,14223,14225],{"class":3145,"line":3299},[3143,14224,14165],{"class":5536},[3143,14226,14227],{"class":3529}," http://127.0.0.1\n",[3143,14229,14230],{"class":3145,"line":3305},[3143,14231,14151],{"class":4245},[3143,14233,14234],{"class":3145,"line":3311},[3143,14235,3168],{"emptyLinePlaceholder":3167},[3143,14237,14238],{"class":3145,"line":3317},[3143,14239,14240],{"class":4245},"# Очищення\n",[3143,14242,14243,14245,14248,14251],{"class":3145,"line":3323},[3143,14244,14019],{"class":5536},[3143,14246,14247],{"class":3529}," delete",[3143,14249,14250],{"class":3529}," deployment",[3143,14252,14253],{"class":3529}," nginx-test\n",[3143,14255,14256,14258,14260,14262,14265,14268],{"class":3145,"line":3328},[3143,14257,14019],{"class":5536},[3143,14259,14247],{"class":3529},[3143,14261,6319],{"class":3529},[3143,14263,14264],{"class":3529}," nginx-clusterip",[3143,14266,14267],{"class":3529}," nginx-nodeport",[3143,14269,14215],{"class":3529},[3582,14271],{},[3122,14273,14275],{"id":14274},"завдання-2-service-discovery-через-dns","Завдання 2: Service Discovery через DNS",[3114,14277,14278,14280],{},[3118,14279,13513],{}," Навчитись використовувати DNS для service discovery.",[3114,14282,14283],{},[3118,14284,13519],{},[3542,14286,14287,14307,14310,14330],{},[3390,14288,14289,14290],{},"Створіть два Deployment у різних namespace:",[3387,14291,14292,14300],{},[3390,14293,14294,14296,14297],{},[3140,14295,3485],{}," у namespace ",[3140,14298,14299],{},"backend",[3390,14301,14302,14296,14305],{},[3140,14303,14304],{},"frontend",[3140,14306,14304],{},[3390,14308,14309],{},"Створіть ClusterIP Service для кожного",[3390,14311,14312,14313],{},"З Pod frontend зробіть DNS-запит до API Service:",[3387,14314,14315,14318,14324],{},[3390,14316,14317],{},"Коротка форма (не працює — різні namespace)",[3390,14319,14320,14321,4002],{},"З namespace (",[3140,14322,14323],{},"api.backend",[3390,14325,14326,14327,4002],{},"Повна форма (",[3140,14328,14329],{},"api.backend.svc.cluster.local",[3390,14331,14332],{},"Перевірте HTTP-запит через DNS-ім'я",[3114,14334,14335,14337],{},[3118,14336,13559],{}," Ви зрозумієте, як працює DNS resolution між namespace.",[13562,14339,14340,14344],{"title":13564},[3114,14341,14342],{},[3118,14343,14004],{},[3133,14345,14347],{"className":6307,"code":14346,"language":6309,"meta":3138,"style":3138},"# Створення namespace\nkubectl create namespace backend\nkubectl create namespace frontend\n\n# API у namespace backend\nkubectl create deployment api --image=nginx:1.27 --replicas=2 -n backend\nkubectl expose deployment api --port=80 --target-port=80 -n backend\n\n# Frontend у namespace frontend\nkubectl create deployment frontend --image=nginx:1.27 --replicas=2 -n frontend\n\n# Тестування DNS з frontend Pod\nkubectl run test-dns -n frontend --image=curlimages/curl --rm -it --restart=Never -- sh\n\n# Тест 1: Коротка форма (не працює)\n$ nslookup api\n# Server:    10.96.0.10\n# ** server can't find api: NXDOMAIN\n# ❌ Не працює — різні namespace\n\n# Тест 2: З namespace\n$ nslookup api.backend\n# Name:      api.backend.svc.cluster.local\n# Address:   10.96.0.50\n# ✅ Працює\n\n# Тест 3: Повна форма\n$ nslookup api.backend.svc.cluster.local\n# Name:      api.backend.svc.cluster.local\n# Address:   10.96.0.50\n# ✅ Працює\n\n# Тест 4: HTTP-запит\n$ curl http://api.backend\n# \u003C!DOCTYPE html>...\n# ✅ Працює\n\n# Очищення\nkubectl delete namespace backend frontend\n",[3140,14348,14349,14354,14367,14378,14382,14387,14409,14430,14434,14439,14458,14462,14467,14493,14497,14502,14512,14517,14522,14527,14531,14536,14545,14550,14555,14560,14564,14569,14578,14582,14586,14590,14594,14599,14609,14614,14618,14622,14626],{"__ignoreMap":3138},[3143,14350,14351],{"class":3145,"line":3146},[3143,14352,14353],{"class":4245},"# Створення namespace\n",[3143,14355,14356,14358,14361,14364],{"class":3145,"line":3152},[3143,14357,14019],{"class":5536},[3143,14359,14360],{"class":3529}," create",[3143,14362,14363],{"class":3529}," namespace",[3143,14365,14366],{"class":3529}," backend\n",[3143,14368,14369,14371,14373,14375],{"class":3145,"line":3158},[3143,14370,14019],{"class":5536},[3143,14372,14360],{"class":3529},[3143,14374,14363],{"class":3529},[3143,14376,14377],{"class":3529}," frontend\n",[3143,14379,14380],{"class":3145,"line":3164},[3143,14381,3168],{"emptyLinePlaceholder":3167},[3143,14383,14384],{"class":3145,"line":3171},[3143,14385,14386],{"class":4245},"# API у namespace backend\n",[3143,14388,14389,14391,14393,14395,14398,14401,14404,14407],{"class":3145,"line":3177},[3143,14390,14019],{"class":5536},[3143,14392,14360],{"class":3529},[3143,14394,14250],{"class":3529},[3143,14396,14397],{"class":3529}," api",[3143,14399,14400],{"class":5520}," --image=nginx:1.27",[3143,14402,14403],{"class":5520}," --replicas=2",[3143,14405,14406],{"class":5520}," -n",[3143,14408,14366],{"class":3529},[3143,14410,14411,14413,14416,14418,14420,14423,14426,14428],{"class":3145,"line":3183},[3143,14412,14019],{"class":5536},[3143,14414,14415],{"class":3529}," expose",[3143,14417,14250],{"class":3529},[3143,14419,14397],{"class":3529},[3143,14421,14422],{"class":5520}," --port=80",[3143,14424,14425],{"class":5520}," --target-port=80",[3143,14427,14406],{"class":5520},[3143,14429,14366],{"class":3529},[3143,14431,14432],{"class":3145,"line":3189},[3143,14433,3168],{"emptyLinePlaceholder":3167},[3143,14435,14436],{"class":3145,"line":3195},[3143,14437,14438],{"class":4245},"# Frontend у namespace frontend\n",[3143,14440,14441,14443,14445,14447,14450,14452,14454,14456],{"class":3145,"line":3201},[3143,14442,14019],{"class":5536},[3143,14444,14360],{"class":3529},[3143,14446,14250],{"class":3529},[3143,14448,14449],{"class":3529}," frontend",[3143,14451,14400],{"class":5520},[3143,14453,14403],{"class":5520},[3143,14455,14406],{"class":5520},[3143,14457,14377],{"class":3529},[3143,14459,14460],{"class":3145,"line":3207},[3143,14461,3168],{"emptyLinePlaceholder":3167},[3143,14463,14464],{"class":3145,"line":3213},[3143,14465,14466],{"class":4245},"# Тестування DNS з frontend Pod\n",[3143,14468,14469,14471,14473,14476,14478,14480,14482,14484,14486,14488,14490],{"class":3145,"line":3219},[3143,14470,14019],{"class":5536},[3143,14472,14116],{"class":3529},[3143,14474,14475],{"class":3529}," test-dns",[3143,14477,14406],{"class":5520},[3143,14479,14449],{"class":3529},[3143,14481,14122],{"class":5520},[3143,14483,14125],{"class":5520},[3143,14485,14128],{"class":5520},[3143,14487,14131],{"class":5520},[3143,14489,14134],{"class":5520},[3143,14491,14492],{"class":3529}," sh\n",[3143,14494,14495],{"class":3145,"line":3225},[3143,14496,3168],{"emptyLinePlaceholder":3167},[3143,14498,14499],{"class":3145,"line":3231},[3143,14500,14501],{"class":4245},"# Тест 1: Коротка форма (не працює)\n",[3143,14503,14504,14506,14509],{"class":3145,"line":3236},[3143,14505,6209],{"class":5536},[3143,14507,14508],{"class":3529}," nslookup",[3143,14510,14511],{"class":3529}," api\n",[3143,14513,14514],{"class":3145,"line":3242},[3143,14515,14516],{"class":4245},"# Server:    10.96.0.10\n",[3143,14518,14519],{"class":3145,"line":3247},[3143,14520,14521],{"class":4245},"# ** server can't find api: NXDOMAIN\n",[3143,14523,14524],{"class":3145,"line":3253},[3143,14525,14526],{"class":4245},"# ❌ Не працює — різні namespace\n",[3143,14528,14529],{"class":3145,"line":3259},[3143,14530,3168],{"emptyLinePlaceholder":3167},[3143,14532,14533],{"class":3145,"line":3265},[3143,14534,14535],{"class":4245},"# Тест 2: З namespace\n",[3143,14537,14538,14540,14542],{"class":3145,"line":3270},[3143,14539,6209],{"class":5536},[3143,14541,14508],{"class":3529},[3143,14543,14544],{"class":3529}," api.backend\n",[3143,14546,14547],{"class":3145,"line":3276},[3143,14548,14549],{"class":4245},"# Name:      api.backend.svc.cluster.local\n",[3143,14551,14552],{"class":3145,"line":3282},[3143,14553,14554],{"class":4245},"# Address:   10.96.0.50\n",[3143,14556,14557],{"class":3145,"line":3288},[3143,14558,14559],{"class":4245},"# ✅ Працює\n",[3143,14561,14562],{"class":3145,"line":3293},[3143,14563,3168],{"emptyLinePlaceholder":3167},[3143,14565,14566],{"class":3145,"line":3299},[3143,14567,14568],{"class":4245},"# Тест 3: Повна форма\n",[3143,14570,14571,14573,14575],{"class":3145,"line":3305},[3143,14572,6209],{"class":5536},[3143,14574,14508],{"class":3529},[3143,14576,14577],{"class":3529}," api.backend.svc.cluster.local\n",[3143,14579,14580],{"class":3145,"line":3311},[3143,14581,14549],{"class":4245},[3143,14583,14584],{"class":3145,"line":3317},[3143,14585,14554],{"class":4245},[3143,14587,14588],{"class":3145,"line":3323},[3143,14589,14559],{"class":4245},[3143,14591,14592],{"class":3145,"line":3328},[3143,14593,3168],{"emptyLinePlaceholder":3167},[3143,14595,14596],{"class":3145,"line":3334},[3143,14597,14598],{"class":4245},"# Тест 4: HTTP-запит\n",[3143,14600,14601,14603,14606],{"class":3145,"line":3340},[3143,14602,6209],{"class":5536},[3143,14604,14605],{"class":3529}," curl",[3143,14607,14608],{"class":3529}," http://api.backend\n",[3143,14610,14611],{"class":3145,"line":3346},[3143,14612,14613],{"class":4245},"# \u003C!DOCTYPE html>...\n",[3143,14615,14616],{"class":3145,"line":3352},[3143,14617,14559],{"class":4245},[3143,14619,14620],{"class":3145,"line":3357},[3143,14621,3168],{"emptyLinePlaceholder":3167},[3143,14623,14624],{"class":3145,"line":3362},[3143,14625,14240],{"class":4245},[3143,14627,14628,14630,14632,14634,14637],{"class":3145,"line":3869},[3143,14629,14019],{"class":5536},[3143,14631,14247],{"class":3529},[3143,14633,14363],{"class":3529},[3143,14635,14636],{"class":3529}," backend",[3143,14638,14377],{"class":3529},[3582,14640],{},[3122,14642,14644],{"id":14643},"завдання-3-headless-service-для-statefulset","Завдання 3: Headless Service для StatefulSet",[3114,14646,14647,14649],{},[3118,14648,13513],{}," Навчитись використовувати Headless Service для доступу до конкретних Pod.",[3114,14651,14652],{},[3118,14653,13519],{},[3542,14655,14656,14659,14664,14675],{},[3390,14657,14658],{},"Створіть StatefulSet з 3 репліками nginx",[3390,14660,14661,14662,4002],{},"Створіть Headless Service (",[3140,14663,9539],{},[3390,14665,14666,14667],{},"Перевірте DNS-записи:",[3387,14668,14669,14672],{},[3390,14670,14671],{},"Service DNS (повертає всі Pod)",[3390,14673,14674],{},"Pod DNS (повертає конкретний Pod)",[3390,14676,14677],{},"Зробіть HTTP-запит до конкретного Pod через DNS",[3114,14679,14680,14682],{},[3118,14681,13559],{}," Ви зрозумієте, як Headless Service надає стабільні DNS-імена для Pod.",[13562,14684,14685,14690,14842,14847,14937,14941],{"title":13564},[3114,14686,14687],{},[3118,14688,14689],{},"nginx-statefulset.yaml:",[3133,14691,14693],{"className":3443,"code":14692,"language":3445,"meta":3138,"style":3138},"apiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: nginx\nspec:\n  serviceName: nginx-headless\n  replicas: 3\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n        - name: nginx\n          image: nginx:1.27\n          ports:\n            - containerPort: 80\n",[3140,14694,14695,14703,14712,14718,14726,14732,14742,14750,14756,14762,14770,14776,14782,14788,14796,14802,14808,14818,14826,14832],{"__ignoreMap":3138},[3143,14696,14697,14699,14701],{"class":3145,"line":3146},[3143,14698,4039],{"class":3452},[3143,14700,3516],{"class":3456},[3143,14702,11981],{"class":3479},[3143,14704,14705,14707,14709],{"class":3145,"line":3152},[3143,14706,4049],{"class":3452},[3143,14708,3516],{"class":3456},[3143,14710,14711],{"class":3479},"StatefulSet\n",[3143,14713,14714,14716],{"class":3145,"line":3158},[3143,14715,4059],{"class":3452},[3143,14717,3457],{"class":3456},[3143,14719,14720,14722,14724],{"class":3145,"line":3164},[3143,14721,4066],{"class":3452},[3143,14723,3516],{"class":3456},[3143,14725,12839],{"class":3479},[3143,14727,14728,14730],{"class":3145,"line":3171},[3143,14729,4086],{"class":3452},[3143,14731,3457],{"class":3456},[3143,14733,14734,14737,14739],{"class":3145,"line":3177},[3143,14735,14736],{"class":3452},"  serviceName",[3143,14738,3516],{"class":3456},[3143,14740,14741],{"class":3479},"nginx-headless\n",[3143,14743,14744,14746,14748],{"class":3145,"line":3183},[3143,14745,12015],{"class":3452},[3143,14747,3516],{"class":3456},[3143,14749,3674],{"class":3673},[3143,14751,14752,14754],{"class":3145,"line":3189},[3143,14753,4093],{"class":3452},[3143,14755,3457],{"class":3456},[3143,14757,14758,14760],{"class":3145,"line":3195},[3143,14759,12031],{"class":3452},[3143,14761,3457],{"class":3456},[3143,14763,14764,14766,14768],{"class":3145,"line":3201},[3143,14765,4296],{"class":3452},[3143,14767,3516],{"class":3456},[3143,14769,12839],{"class":3479},[3143,14771,14772,14774],{"class":3145,"line":3207},[3143,14773,4862],{"class":3452},[3143,14775,3457],{"class":3456},[3143,14777,14778,14780],{"class":3145,"line":3213},[3143,14779,12052],{"class":3452},[3143,14781,3457],{"class":3456},[3143,14783,14784,14786],{"class":3145,"line":3219},[3143,14785,12059],{"class":3452},[3143,14787,3457],{"class":3456},[3143,14789,14790,14792,14794],{"class":3145,"line":3225},[3143,14791,12066],{"class":3452},[3143,14793,3516],{"class":3456},[3143,14795,12839],{"class":3479},[3143,14797,14798,14800],{"class":3145,"line":3231},[3143,14799,4869],{"class":3452},[3143,14801,3457],{"class":3456},[3143,14803,14804,14806],{"class":3145,"line":3236},[3143,14805,4876],{"class":3452},[3143,14807,3457],{"class":3456},[3143,14809,14810,14812,14814,14816],{"class":3145,"line":3242},[3143,14811,4883],{"class":3456},[3143,14813,3513],{"class":3452},[3143,14815,3516],{"class":3456},[3143,14817,12839],{"class":3479},[3143,14819,14820,14822,14824],{"class":3145,"line":3247},[3143,14821,12097],{"class":3452},[3143,14823,3516],{"class":3456},[3143,14825,12848],{"class":3479},[3143,14827,14828,14830],{"class":3145,"line":3253},[3143,14829,4894],{"class":3452},[3143,14831,3457],{"class":3456},[3143,14833,14834,14836,14838,14840],{"class":3145,"line":3259},[3143,14835,4901],{"class":3456},[3143,14837,4691],{"class":3452},[3143,14839,3516],{"class":3456},[3143,14841,4144],{"class":3673},[3114,14843,14844],{},[3118,14845,14846],{},"nginx-headless-service.yaml:",[3133,14848,14850],{"className":3443,"code":14849,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-headless\nspec:\n  clusterIP: None  # Headless Service\n  selector:\n    app: nginx\n  ports:\n    - port: 80\n      targetPort: 80\n",[3140,14851,14852,14860,14868,14874,14882,14888,14899,14905,14913,14919,14929],{"__ignoreMap":3138},[3143,14853,14854,14856,14858],{"class":3145,"line":3146},[3143,14855,4039],{"class":3452},[3143,14857,3516],{"class":3456},[3143,14859,4044],{"class":3479},[3143,14861,14862,14864,14866],{"class":3145,"line":3152},[3143,14863,4049],{"class":3452},[3143,14865,3516],{"class":3456},[3143,14867,4054],{"class":3479},[3143,14869,14870,14872],{"class":3145,"line":3158},[3143,14871,4059],{"class":3452},[3143,14873,3457],{"class":3456},[3143,14875,14876,14878,14880],{"class":3145,"line":3164},[3143,14877,4066],{"class":3452},[3143,14879,3516],{"class":3456},[3143,14881,14741],{"class":3479},[3143,14883,14884,14886],{"class":3145,"line":3171},[3143,14885,4086],{"class":3452},[3143,14887,3457],{"class":3456},[3143,14889,14890,14892,14894,14896],{"class":3145,"line":3177},[3143,14891,9638],{"class":3452},[3143,14893,3516],{"class":3456},[3143,14895,9643],{"class":3479},[3143,14897,14898],{"class":4245},"  # Headless Service\n",[3143,14900,14901,14903],{"class":3145,"line":3183},[3143,14902,4093],{"class":3452},[3143,14904,3457],{"class":3456},[3143,14906,14907,14909,14911],{"class":3145,"line":3189},[3143,14908,4100],{"class":3452},[3143,14910,3516],{"class":3456},[3143,14912,12839],{"class":3479},[3143,14914,14915,14917],{"class":3145,"line":3195},[3143,14916,4110],{"class":3452},[3143,14918,3457],{"class":3456},[3143,14920,14921,14923,14925,14927],{"class":3145,"line":3201},[3143,14922,4117],{"class":3456},[3143,14924,4338],{"class":3452},[3143,14926,3516],{"class":3456},[3143,14928,4144],{"class":3673},[3143,14930,14931,14933,14935],{"class":3145,"line":3207},[3143,14932,4149],{"class":3452},[3143,14934,3516],{"class":3456},[3143,14936,4144],{"class":3673},[3114,14938,14939],{},[3118,14940,14004],{},[3133,14942,14944],{"className":6307,"code":14943,"language":6309,"meta":3138,"style":3138},"# Створення\nkubectl apply -f nginx-headless-service.yaml\nkubectl apply -f nginx-statefulset.yaml\n\n# Очікування готовності\nkubectl wait --for=condition=ready pod -l app=nginx --timeout=60s\n\n# Перегляд Pod\nkubectl get pods -l app=nginx\n# NAME      READY   STATUS    RESTARTS   AGE\n# nginx-0   1/1     Running   0          30s\n# nginx-1   1/1     Running   0          25s\n# nginx-2   1/1     Running   0          20s\n\n# Тестування DNS\nkubectl run test-dns --image=curlimages/curl --rm -it --restart=Never -- sh\n\n# Тест 1: Service DNS (повертає всі Pod)\n$ nslookup nginx-headless.default.svc.cluster.local\n# Name:      nginx-headless.default.svc.cluster.local\n# Address:   10.244.1.10  (nginx-0)\n# Address:   10.244.1.11  (nginx-1)\n# Address:   10.244.1.12  (nginx-2)\n\n# Тест 2: Pod DNS (конкретний Pod)\n$ nslookup nginx-0.nginx-headless.default.svc.cluster.local\n# Name:      nginx-0.nginx-headless.default.svc.cluster.local\n# Address:   10.244.1.10\n\n$ nslookup nginx-1.nginx-headless.default.svc.cluster.local\n# Name:      nginx-1.nginx-headless.default.svc.cluster.local\n# Address:   10.244.1.11\n\n# Тест 3: HTTP-запит до конкретного Pod\n$ curl http://nginx-0.nginx-headless\n# \u003C!DOCTYPE html>...\n# ✅ Працює\n\n$ curl http://nginx-1.nginx-headless\n# \u003C!DOCTYPE html>...\n# ✅ Працює\n\n# Очищення\nkubectl delete statefulset nginx\nkubectl delete service nginx-headless\n",[3140,14945,14946,14950,14961,14972,14976,14981,15003,15007,15012,15026,15031,15036,15041,15046,15050,15055,15075,15079,15084,15093,15098,15103,15108,15113,15117,15122,15131,15136,15141,15145,15154,15159,15164,15168,15173,15182,15186,15190,15194,15203,15207,15211,15215,15219,15231],{"__ignoreMap":3138},[3143,14947,14948],{"class":3145,"line":3146},[3143,14949,14014],{"class":4245},[3143,14951,14952,14954,14956,14958],{"class":3145,"line":3152},[3143,14953,14019],{"class":5536},[3143,14955,14022],{"class":3529},[3143,14957,14025],{"class":5520},[3143,14959,14960],{"class":3529}," nginx-headless-service.yaml\n",[3143,14962,14963,14965,14967,14969],{"class":3145,"line":3158},[3143,14964,14019],{"class":5536},[3143,14966,14022],{"class":3529},[3143,14968,14025],{"class":5520},[3143,14970,14971],{"class":3529}," nginx-statefulset.yaml\n",[3143,14973,14974],{"class":3145,"line":3164},[3143,14975,3168],{"emptyLinePlaceholder":3167},[3143,14977,14978],{"class":3145,"line":3171},[3143,14979,14980],{"class":4245},"# Очікування готовності\n",[3143,14982,14983,14985,14988,14991,14994,14997,15000],{"class":3145,"line":3177},[3143,14984,14019],{"class":5536},[3143,14986,14987],{"class":3529}," wait",[3143,14989,14990],{"class":5520}," --for=condition=ready",[3143,14992,14993],{"class":3529}," pod",[3143,14995,14996],{"class":5520}," -l",[3143,14998,14999],{"class":3529}," app=nginx",[3143,15001,15002],{"class":5520}," --timeout=60s\n",[3143,15004,15005],{"class":3145,"line":3183},[3143,15006,3168],{"emptyLinePlaceholder":3167},[3143,15008,15009],{"class":3145,"line":3189},[3143,15010,15011],{"class":4245},"# Перегляд Pod\n",[3143,15013,15014,15016,15018,15021,15023],{"class":3145,"line":3195},[3143,15015,14019],{"class":5536},[3143,15017,14077],{"class":3529},[3143,15019,15020],{"class":3529}," pods",[3143,15022,14996],{"class":5520},[3143,15024,15025],{"class":3529}," app=nginx\n",[3143,15027,15028],{"class":3145,"line":3201},[3143,15029,15030],{"class":4245},"# NAME      READY   STATUS    RESTARTS   AGE\n",[3143,15032,15033],{"class":3145,"line":3207},[3143,15034,15035],{"class":4245},"# nginx-0   1/1     Running   0          30s\n",[3143,15037,15038],{"class":3145,"line":3213},[3143,15039,15040],{"class":4245},"# nginx-1   1/1     Running   0          25s\n",[3143,15042,15043],{"class":3145,"line":3219},[3143,15044,15045],{"class":4245},"# nginx-2   1/1     Running   0          20s\n",[3143,15047,15048],{"class":3145,"line":3225},[3143,15049,3168],{"emptyLinePlaceholder":3167},[3143,15051,15052],{"class":3145,"line":3231},[3143,15053,15054],{"class":4245},"# Тестування DNS\n",[3143,15056,15057,15059,15061,15063,15065,15067,15069,15071,15073],{"class":3145,"line":3236},[3143,15058,14019],{"class":5536},[3143,15060,14116],{"class":3529},[3143,15062,14475],{"class":3529},[3143,15064,14122],{"class":5520},[3143,15066,14125],{"class":5520},[3143,15068,14128],{"class":5520},[3143,15070,14131],{"class":5520},[3143,15072,14134],{"class":5520},[3143,15074,14492],{"class":3529},[3143,15076,15077],{"class":3145,"line":3242},[3143,15078,3168],{"emptyLinePlaceholder":3167},[3143,15080,15081],{"class":3145,"line":3247},[3143,15082,15083],{"class":4245},"# Тест 1: Service DNS (повертає всі Pod)\n",[3143,15085,15086,15088,15090],{"class":3145,"line":3253},[3143,15087,6209],{"class":5536},[3143,15089,14508],{"class":3529},[3143,15091,15092],{"class":3529}," nginx-headless.default.svc.cluster.local\n",[3143,15094,15095],{"class":3145,"line":3259},[3143,15096,15097],{"class":4245},"# Name:      nginx-headless.default.svc.cluster.local\n",[3143,15099,15100],{"class":3145,"line":3265},[3143,15101,15102],{"class":4245},"# Address:   10.244.1.10  (nginx-0)\n",[3143,15104,15105],{"class":3145,"line":3270},[3143,15106,15107],{"class":4245},"# Address:   10.244.1.11  (nginx-1)\n",[3143,15109,15110],{"class":3145,"line":3276},[3143,15111,15112],{"class":4245},"# Address:   10.244.1.12  (nginx-2)\n",[3143,15114,15115],{"class":3145,"line":3282},[3143,15116,3168],{"emptyLinePlaceholder":3167},[3143,15118,15119],{"class":3145,"line":3288},[3143,15120,15121],{"class":4245},"# Тест 2: Pod DNS (конкретний Pod)\n",[3143,15123,15124,15126,15128],{"class":3145,"line":3293},[3143,15125,6209],{"class":5536},[3143,15127,14508],{"class":3529},[3143,15129,15130],{"class":3529}," nginx-0.nginx-headless.default.svc.cluster.local\n",[3143,15132,15133],{"class":3145,"line":3299},[3143,15134,15135],{"class":4245},"# Name:      nginx-0.nginx-headless.default.svc.cluster.local\n",[3143,15137,15138],{"class":3145,"line":3305},[3143,15139,15140],{"class":4245},"# Address:   10.244.1.10\n",[3143,15142,15143],{"class":3145,"line":3311},[3143,15144,3168],{"emptyLinePlaceholder":3167},[3143,15146,15147,15149,15151],{"class":3145,"line":3317},[3143,15148,6209],{"class":5536},[3143,15150,14508],{"class":3529},[3143,15152,15153],{"class":3529}," nginx-1.nginx-headless.default.svc.cluster.local\n",[3143,15155,15156],{"class":3145,"line":3323},[3143,15157,15158],{"class":4245},"# Name:      nginx-1.nginx-headless.default.svc.cluster.local\n",[3143,15160,15161],{"class":3145,"line":3328},[3143,15162,15163],{"class":4245},"# Address:   10.244.1.11\n",[3143,15165,15166],{"class":3145,"line":3334},[3143,15167,3168],{"emptyLinePlaceholder":3167},[3143,15169,15170],{"class":3145,"line":3340},[3143,15171,15172],{"class":4245},"# Тест 3: HTTP-запит до конкретного Pod\n",[3143,15174,15175,15177,15179],{"class":3145,"line":3346},[3143,15176,6209],{"class":5536},[3143,15178,14605],{"class":3529},[3143,15180,15181],{"class":3529}," http://nginx-0.nginx-headless\n",[3143,15183,15184],{"class":3145,"line":3352},[3143,15185,14613],{"class":4245},[3143,15187,15188],{"class":3145,"line":3357},[3143,15189,14559],{"class":4245},[3143,15191,15192],{"class":3145,"line":3362},[3143,15193,3168],{"emptyLinePlaceholder":3167},[3143,15195,15196,15198,15200],{"class":3145,"line":3869},[3143,15197,6209],{"class":5536},[3143,15199,14605],{"class":3529},[3143,15201,15202],{"class":3529}," http://nginx-1.nginx-headless\n",[3143,15204,15205],{"class":3145,"line":3875},[3143,15206,14613],{"class":4245},[3143,15208,15209],{"class":3145,"line":3881},[3143,15210,14559],{"class":4245},[3143,15212,15213],{"class":3145,"line":3887},[3143,15214,3168],{"emptyLinePlaceholder":3167},[3143,15216,15217],{"class":3145,"line":3893},[3143,15218,14240],{"class":4245},[3143,15220,15221,15223,15225,15228],{"class":3145,"line":3899},[3143,15222,14019],{"class":5536},[3143,15224,14247],{"class":3529},[3143,15226,15227],{"class":3529}," statefulset",[3143,15229,15230],{"class":3529}," nginx\n",[3143,15232,15233,15235,15237,15239],{"class":3145,"line":3904},[3143,15234,14019],{"class":5536},[3143,15236,14247],{"class":3529},[3143,15238,6319],{"class":3529},[3143,15240,15241],{"class":3529}," nginx-headless\n",[3582,15243],{},[3122,15245,15247],{"id":15246},"завдання-4-service-без-selector-для-зовнішньої-бд","Завдання 4: Service без selector для зовнішньої БД",[3114,15249,15250,15252],{},[3118,15251,13513],{}," Навчитись створювати Service для зовнішніх ресурсів.",[3114,15254,15255],{},[3118,15256,13519],{},[3542,15258,15259,15262,15269,15272],{},[3390,15260,15261],{},"Створіть Service без selector",[3390,15263,15264,15265,15268],{},"Вручну створіть Endpoints з IP-адресою зовнішнього сервісу (наприклад, ",[3140,15266,15267],{},"8.8.8.8"," — Google DNS для тесту)",[3390,15270,15271],{},"Перевірте DNS resolution",[3390,15273,15274],{},"Зробіть запит до Service (має перенаправити на зовнішній сервіс)",[3114,15276,15277,15279],{},[3118,15278,13559],{}," Ви навчитесь інтегрувати зовнішні сервіси у Kubernetes через Service.",[13562,15281,15282,15287,15367,15372,15462,15466,15687,15692,15698,15776,15782],{"title":13564},[3114,15283,15284],{},[3118,15285,15286],{},"external-service.yaml:",[3133,15288,15290],{"className":3443,"code":15289,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Service\nmetadata:\n  name: external-dns\nspec:\n  # Немає selector!\n  ports:\n    - port: 53\n      targetPort: 53\n      protocol: UDP\n",[3140,15291,15292,15300,15308,15314,15323,15329,15333,15339,15350,15358],{"__ignoreMap":3138},[3143,15293,15294,15296,15298],{"class":3145,"line":3146},[3143,15295,4039],{"class":3452},[3143,15297,3516],{"class":3456},[3143,15299,4044],{"class":3479},[3143,15301,15302,15304,15306],{"class":3145,"line":3152},[3143,15303,4049],{"class":3452},[3143,15305,3516],{"class":3456},[3143,15307,4054],{"class":3479},[3143,15309,15310,15312],{"class":3145,"line":3158},[3143,15311,4059],{"class":3452},[3143,15313,3457],{"class":3456},[3143,15315,15316,15318,15320],{"class":3145,"line":3164},[3143,15317,4066],{"class":3452},[3143,15319,3516],{"class":3456},[3143,15321,15322],{"class":3479},"external-dns\n",[3143,15324,15325,15327],{"class":3145,"line":3171},[3143,15326,4086],{"class":3452},[3143,15328,3457],{"class":3456},[3143,15330,15331],{"class":3145,"line":3177},[3143,15332,11378],{"class":4245},[3143,15334,15335,15337],{"class":3145,"line":3183},[3143,15336,4110],{"class":3452},[3143,15338,3457],{"class":3456},[3143,15340,15341,15343,15345,15347],{"class":3145,"line":3189},[3143,15342,4117],{"class":3456},[3143,15344,4338],{"class":3452},[3143,15346,3516],{"class":3456},[3143,15348,15349],{"class":3673},"53\n",[3143,15351,15352,15354,15356],{"class":3145,"line":3195},[3143,15353,4149],{"class":3452},[3143,15355,3516],{"class":3456},[3143,15357,15349],{"class":3673},[3143,15359,15360,15362,15364],{"class":3145,"line":3201},[3143,15361,4129],{"class":3452},[3143,15363,3516],{"class":3456},[3143,15365,15366],{"class":3479},"UDP\n",[3114,15368,15369],{},[3118,15370,15371],{},"external-endpoints.yaml:",[3133,15373,15375],{"className":3443,"code":15374,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Endpoints\nmetadata:\n  name: external-dns  # Має збігатись з іменем Service\nsubsets:\n  - addresses:\n      - ip: 8.8.8.8  # Google DNS\n    ports:\n      - port: 53\n        protocol: UDP\n",[3140,15376,15377,15385,15393,15399,15410,15416,15424,15437,15443,15453],{"__ignoreMap":3138},[3143,15378,15379,15381,15383],{"class":3145,"line":3146},[3143,15380,4039],{"class":3452},[3143,15382,3516],{"class":3456},[3143,15384,4044],{"class":3479},[3143,15386,15387,15389,15391],{"class":3145,"line":3152},[3143,15388,4049],{"class":3452},[3143,15390,3516],{"class":3456},[3143,15392,11429],{"class":3479},[3143,15394,15395,15397],{"class":3145,"line":3158},[3143,15396,4059],{"class":3452},[3143,15398,3457],{"class":3456},[3143,15400,15401,15403,15405,15408],{"class":3145,"line":3164},[3143,15402,4066],{"class":3452},[3143,15404,3516],{"class":3456},[3143,15406,15407],{"class":3479},"external-dns",[3143,15409,11447],{"class":4245},[3143,15411,15412,15414],{"class":3145,"line":3171},[3143,15413,11452],{"class":3452},[3143,15415,3457],{"class":3456},[3143,15417,15418,15420,15422],{"class":3145,"line":3177},[3143,15419,3510],{"class":3456},[3143,15421,11461],{"class":3452},[3143,15423,3457],{"class":3456},[3143,15425,15426,15428,15430,15432,15434],{"class":3145,"line":3183},[3143,15427,3476],{"class":3456},[3143,15429,11470],{"class":3452},[3143,15431,3516],{"class":3456},[3143,15433,15267],{"class":3673},[3143,15435,15436],{"class":4245},"  # Google DNS\n",[3143,15438,15439,15441],{"class":3145,"line":3189},[3143,15440,4767],{"class":3452},[3143,15442,3457],{"class":3456},[3143,15444,15445,15447,15449,15451],{"class":3145,"line":3195},[3143,15446,3476],{"class":3456},[3143,15448,4338],{"class":3452},[3143,15450,3516],{"class":3456},[3143,15452,15349],{"class":3673},[3143,15454,15455,15458,15460],{"class":3145,"line":3201},[3143,15456,15457],{"class":3452},"        protocol",[3143,15459,3516],{"class":3456},[3143,15461,15366],{"class":3479},[3114,15463,15464],{},[3118,15465,14004],{},[3133,15467,15469],{"className":6307,"code":15468,"language":6309,"meta":3138,"style":3138},"# Створення\nkubectl apply -f external-service.yaml\nkubectl apply -f external-endpoints.yaml\n\n# Перегляд Service та Endpoints\nkubectl get service external-dns\n# NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)\n# external-dns   ClusterIP   10.96.0.100   \u003Cnone>        53/UDP\n\nkubectl get endpoints external-dns\n# NAME           ENDPOINTS         AGE\n# external-dns   8.8.8.8:53        10s\n\n# Тестування\nkubectl run test-dns --image=curlimages/curl --rm -it --restart=Never -- sh\n\n# DNS resolution\n$ nslookup external-dns.default.svc.cluster.local\n# Name:      external-dns.default.svc.cluster.local\n# Address:   10.96.0.100\n\n# Тест DNS-запиту через Service (перенаправляється на 8.8.8.8)\n$ nslookup google.com external-dns.default.svc.cluster.local\n# Server:    external-dns.default.svc.cluster.local\n# Address:   10.96.0.100:53\n#\n# Name:      google.com\n# Address:   142.250.185.46\n# ✅ Працює — запит пішов на 8.8.8.8 через Service\n\n# Очищення\nkubectl delete service external-dns\nkubectl delete endpoints external-dns\n",[3140,15470,15471,15475,15486,15497,15501,15506,15517,15522,15527,15531,15542,15547,15552,15556,15561,15581,15585,15590,15599,15604,15609,15613,15618,15629,15634,15639,15644,15649,15654,15659,15663,15667,15677],{"__ignoreMap":3138},[3143,15472,15473],{"class":3145,"line":3146},[3143,15474,14014],{"class":4245},[3143,15476,15477,15479,15481,15483],{"class":3145,"line":3152},[3143,15478,14019],{"class":5536},[3143,15480,14022],{"class":3529},[3143,15482,14025],{"class":5520},[3143,15484,15485],{"class":3529}," external-service.yaml\n",[3143,15487,15488,15490,15492,15494],{"class":3145,"line":3158},[3143,15489,14019],{"class":5536},[3143,15491,14022],{"class":3529},[3143,15493,14025],{"class":5520},[3143,15495,15496],{"class":3529}," external-endpoints.yaml\n",[3143,15498,15499],{"class":3145,"line":3164},[3143,15500,3168],{"emptyLinePlaceholder":3167},[3143,15502,15503],{"class":3145,"line":3171},[3143,15504,15505],{"class":4245},"# Перегляд Service та Endpoints\n",[3143,15507,15508,15510,15512,15514],{"class":3145,"line":3177},[3143,15509,14019],{"class":5536},[3143,15511,14077],{"class":3529},[3143,15513,6319],{"class":3529},[3143,15515,15516],{"class":3529}," external-dns\n",[3143,15518,15519],{"class":3145,"line":3183},[3143,15520,15521],{"class":4245},"# NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)\n",[3143,15523,15524],{"class":3145,"line":3189},[3143,15525,15526],{"class":4245},"# external-dns   ClusterIP   10.96.0.100   \u003Cnone>        53/UDP\n",[3143,15528,15529],{"class":3145,"line":3195},[3143,15530,3168],{"emptyLinePlaceholder":3167},[3143,15532,15533,15535,15537,15540],{"class":3145,"line":3201},[3143,15534,14019],{"class":5536},[3143,15536,14077],{"class":3529},[3143,15538,15539],{"class":3529}," endpoints",[3143,15541,15516],{"class":3529},[3143,15543,15544],{"class":3145,"line":3207},[3143,15545,15546],{"class":4245},"# NAME           ENDPOINTS         AGE\n",[3143,15548,15549],{"class":3145,"line":3213},[3143,15550,15551],{"class":4245},"# external-dns   8.8.8.8:53        10s\n",[3143,15553,15554],{"class":3145,"line":3219},[3143,15555,3168],{"emptyLinePlaceholder":3167},[3143,15557,15558],{"class":3145,"line":3225},[3143,15559,15560],{"class":4245},"# Тестування\n",[3143,15562,15563,15565,15567,15569,15571,15573,15575,15577,15579],{"class":3145,"line":3231},[3143,15564,14019],{"class":5536},[3143,15566,14116],{"class":3529},[3143,15568,14475],{"class":3529},[3143,15570,14122],{"class":5520},[3143,15572,14125],{"class":5520},[3143,15574,14128],{"class":5520},[3143,15576,14131],{"class":5520},[3143,15578,14134],{"class":5520},[3143,15580,14492],{"class":3529},[3143,15582,15583],{"class":3145,"line":3236},[3143,15584,3168],{"emptyLinePlaceholder":3167},[3143,15586,15587],{"class":3145,"line":3242},[3143,15588,15589],{"class":4245},"# DNS resolution\n",[3143,15591,15592,15594,15596],{"class":3145,"line":3247},[3143,15593,6209],{"class":5536},[3143,15595,14508],{"class":3529},[3143,15597,15598],{"class":3529}," external-dns.default.svc.cluster.local\n",[3143,15600,15601],{"class":3145,"line":3253},[3143,15602,15603],{"class":4245},"# Name:      external-dns.default.svc.cluster.local\n",[3143,15605,15606],{"class":3145,"line":3259},[3143,15607,15608],{"class":4245},"# Address:   10.96.0.100\n",[3143,15610,15611],{"class":3145,"line":3265},[3143,15612,3168],{"emptyLinePlaceholder":3167},[3143,15614,15615],{"class":3145,"line":3270},[3143,15616,15617],{"class":4245},"# Тест DNS-запиту через Service (перенаправляється на 8.8.8.8)\n",[3143,15619,15620,15622,15624,15627],{"class":3145,"line":3276},[3143,15621,6209],{"class":5536},[3143,15623,14508],{"class":3529},[3143,15625,15626],{"class":3529}," google.com",[3143,15628,15598],{"class":3529},[3143,15630,15631],{"class":3145,"line":3282},[3143,15632,15633],{"class":4245},"# Server:    external-dns.default.svc.cluster.local\n",[3143,15635,15636],{"class":3145,"line":3288},[3143,15637,15638],{"class":4245},"# Address:   10.96.0.100:53\n",[3143,15640,15641],{"class":3145,"line":3293},[3143,15642,15643],{"class":4245},"#\n",[3143,15645,15646],{"class":3145,"line":3299},[3143,15647,15648],{"class":4245},"# Name:      google.com\n",[3143,15650,15651],{"class":3145,"line":3305},[3143,15652,15653],{"class":4245},"# Address:   142.250.185.46\n",[3143,15655,15656],{"class":3145,"line":3311},[3143,15657,15658],{"class":4245},"# ✅ Працює — запит пішов на 8.8.8.8 через Service\n",[3143,15660,15661],{"class":3145,"line":3317},[3143,15662,3168],{"emptyLinePlaceholder":3167},[3143,15664,15665],{"class":3145,"line":3323},[3143,15666,14240],{"class":4245},[3143,15668,15669,15671,15673,15675],{"class":3145,"line":3328},[3143,15670,14019],{"class":5536},[3143,15672,14247],{"class":3529},[3143,15674,6319],{"class":3529},[3143,15676,15516],{"class":3529},[3143,15678,15679,15681,15683,15685],{"class":3145,"line":3334},[3143,15680,14019],{"class":5536},[3143,15682,14247],{"class":3529},[3143,15684,15539],{"class":3529},[3143,15686,15516],{"class":3529},[3114,15688,15689],{},[3118,15690,15691],{},"Практичне застосування:",[3114,15693,15694,15695,15697],{},"Замість ",[3140,15696,15267],{}," використовуйте IP вашої зовнішньої бази даних:",[3133,15699,15701],{"className":3443,"code":15700,"language":3445,"meta":3138,"style":3138},"apiVersion: v1\nkind: Endpoints\nmetadata:\n  name: external-postgres\nsubsets:\n  - addresses:\n      - ip: 192.168.1.100  # IP вашої БД\n    ports:\n      - port: 5432\n",[3140,15702,15703,15711,15719,15725,15733,15739,15747,15760,15766],{"__ignoreMap":3138},[3143,15704,15705,15707,15709],{"class":3145,"line":3146},[3143,15706,4039],{"class":3452},[3143,15708,3516],{"class":3456},[3143,15710,4044],{"class":3479},[3143,15712,15713,15715,15717],{"class":3145,"line":3152},[3143,15714,4049],{"class":3452},[3143,15716,3516],{"class":3456},[3143,15718,11429],{"class":3479},[3143,15720,15721,15723],{"class":3145,"line":3158},[3143,15722,4059],{"class":3452},[3143,15724,3457],{"class":3456},[3143,15726,15727,15729,15731],{"class":3145,"line":3164},[3143,15728,4066],{"class":3452},[3143,15730,3516],{"class":3456},[3143,15732,11367],{"class":3479},[3143,15734,15735,15737],{"class":3145,"line":3171},[3143,15736,11452],{"class":3452},[3143,15738,3457],{"class":3456},[3143,15740,15741,15743,15745],{"class":3145,"line":3177},[3143,15742,3510],{"class":3456},[3143,15744,11461],{"class":3452},[3143,15746,3457],{"class":3456},[3143,15748,15749,15751,15753,15755,15757],{"class":3145,"line":3183},[3143,15750,3476],{"class":3456},[3143,15752,11470],{"class":3452},[3143,15754,3516],{"class":3456},[3143,15756,11475],{"class":3673},[3143,15758,15759],{"class":4245},"  # IP вашої БД\n",[3143,15761,15762,15764],{"class":3145,"line":3189},[3143,15763,4767],{"class":3452},[3143,15765,3457],{"class":3456},[3143,15767,15768,15770,15772,15774],{"class":3145,"line":3195},[3143,15769,3476],{"class":3456},[3143,15771,4338],{"class":3452},[3143,15773,3516],{"class":3456},[3143,15775,9678],{"class":3673},[3114,15777,15778,15779,15781],{},"Тепер код може використовувати ",[3140,15780,11444],{}," як звичайний Service:",[3133,15783,15785],{"className":5511,"code":15784,"language":5513,"meta":3138,"style":3138},"var connectionString = \"Host=external-postgres;Database=mydb;Username=user;Password=pass\";\n",[3140,15786,15787],{"__ignoreMap":3138},[3143,15788,15789,15791,15793,15795,15798],{"class":3145,"line":3146},[3143,15790,5521],{"class":5520},[3143,15792,7389],{"class":5524},[3143,15794,5528],{"class":3456},[3143,15796,15797],{"class":3529},"\"Host=external-postgres;Database=mydb;Username=user;Password=pass\"",[3143,15799,5587],{"class":3456},[3582,15801],{},[3109,15803,15805],{"id":15804},"резюме","Резюме",[3114,15807,15808,15809,15811],{},"У цій статті ми детально вивчили ",[3118,15810,3579],{}," — мережеву абстракцію для Pod у Kubernetes. Ось що ми розглянули:",[3372,15813,15814,15819,15823,15828,15832,15835,15838,15842,15845,15850],{},[3375,15815,15818],{"icon":15816,"title":15817},"i-heroicons-exclamation-triangle","Проблема ефемерних IP-адрес","Чому прямий доступ до Pod за IP неможливий у production: IP змінюються при перезапуску, немає балансування навантаження, відсутній service discovery.",[3375,15820,15822],{"icon":7535,"title":15821},"Що таке Service","Абстракція, яка надає стабільну мережеву точку доступу (IP та DNS) для групи ефемерних Pod. Service — це проксі перед Pod.",[3375,15824,15827],{"icon":15825,"title":15826},"i-heroicons-squares-2x2","Типи Service","ClusterIP (внутрішній), NodePort (доступ через вузли), LoadBalancer (зовнішній load balancer), ExternalName (DNS alias). Кожен для різних сценаріїв.",[3375,15829,15831],{"icon":3489,"title":15830},"kube-proxy та iptables","Як Kubernetes перенаправляє трафік від Service до Pod через iptables/IPVS. DNAT, SNAT, балансування навантаження на рівні ядра.",[3375,15833,15834],{"icon":3436,"title":8653},"Автоматичне створення DNS-записів для Service. Формат DNS-імен, скорочені форми, міжнамespace комунікація.",[3375,15836,15837],{"icon":9272,"title":9531},"Service без ClusterIP для прямого доступу до Pod. DNS повертає IP всіх Pod. Використовується для StatefulSet та peer discovery.",[3375,15839,15841],{"icon":15840,"title":10395},"i-heroicons-list-bullet","Список IP:Port всіх Pod, які відповідають селектору. Автоматичне оновлення при зміні Pod. EndpointSlices для масштабованості.",[3375,15843,15844],{"icon":7625,"title":7520},"Ручне управління Endpoints для інтеграції зовнішніх сервісів. Міграція з зовнішніх систем у Kubernetes.",[3375,15846,15849],{"icon":15847,"title":15848},"i-heroicons-code-bracket","Практичний приклад","Повний застосунок з Frontend, API та PostgreSQL. Різні типи Service для різних компонентів. Nginx як reverse proxy.",[3375,15851,15853],{"icon":15852,"title":13501},"i-heroicons-academic-cap","4 завдання для закріплення знань: типи Service, DNS resolution, Headless Service, Service без selector.",[3122,15855,15857],{"id":15856},"ключові-висновки","Ключові висновки",[3542,15859,15860,15866,15872,15878,15884,15890,15896],{},[3390,15861,15862,15865],{},[3118,15863,15864],{},"Service — це не Pod"," — це мережевий об'єкт, який діє як стабільний проксі перед групою Pod.",[3390,15867,15868,15871],{},[3118,15869,15870],{},"ClusterIP для більшості випадків"," — внутрішня комунікація між сервісами. NodePort та LoadBalancer лише для зовнішнього доступу.",[3390,15873,15874,15877],{},[3118,15875,15876],{},"DNS — основа service discovery"," — використовуйте DNS-імена замість IP-адрес. Короткі форми для того самого namespace, повні для міжнамespace.",[3390,15879,15880,15883],{},[3118,15881,15882],{},"kube-proxy не проксує трафік"," — він налаштовує iptables/IPVS. Трафік йде напряму від клієнта до Pod через kernel.",[3390,15885,15886,15889],{},[3118,15887,15888],{},"Readiness probe критично важливий"," — лише готові Pod додаються до Endpoints. Без readiness probe Service надсилає трафік на неготові Pod.",[3390,15891,15892,15895],{},[3118,15893,15894],{},"Headless Service для stateful застосунків"," — коли потрібен доступ до конкретного Pod за стабільним DNS-іменем.",[3390,15897,15898,15901],{},[3118,15899,15900],{},"Service без selector для зовнішніх ресурсів"," — інтеграція зовнішніх баз даних, API, legacy систем у Kubernetes.",[3122,15903,15905],{"id":15904},"що-далі","Що далі?",[3114,15907,15908],{},"Ви вивчили основи Service та мережі у Kubernetes. Наступні теми для поглибленого вивчення:",[3387,15910,15911,15916,15922,15928,15934],{},[3390,15912,15913,15915],{},[3118,15914,6936],{}," — HTTP-маршрутизація та TLS termination для багатьох Service",[3390,15917,15918,15921],{},[3118,15919,15920],{},"NetworkPolicy"," — ізоляція трафіку між Pod та namespace",[3390,15923,15924,15927],{},[3118,15925,15926],{},"Service Mesh"," — розширені можливості мережі (mTLS, traffic management, observability)",[3390,15929,15930,15933],{},[3118,15931,15932],{},"ConfigMap та Secret"," — управління конфігурацією та секретами",[3390,15935,15936,15939],{},[3118,15937,15938],{},"Volumes та PersistentVolume"," — зберігання даних",[3582,15941],{},[3109,15943,15945],{"id":15944},"корисні-команди","Корисні команди",[3114,15947,15948],{},"Для швидкого доступу — всі команди для роботи з Service:",[15950,15951,15952,16088,16164,16295],"code-group",{},[3133,15953,15956],{"className":6307,"code":15954,"filename":15955,"language":6309,"meta":3138,"style":3138},"# Створення Service з YAML\nkubectl apply -f service.yaml\n\n# Створення Service з kubectl expose\nkubectl expose deployment \u003Cname> --port=80 --target-port=8080\n\n# Перегляд Service\nkubectl get services\nkubectl get svc  # скорочена форма\n\n# Детальна інформація\nkubectl describe service \u003Cname>\n\n# Перегляд у форматі YAML\nkubectl get service \u003Cname> -o yaml\n","Створення та перегляд",[3140,15957,15958,15963,15974,15978,15983,16006,16010,16014,16022,16034,16038,16043,16059,16063,16068],{"__ignoreMap":3138},[3143,15959,15960],{"class":3145,"line":3146},[3143,15961,15962],{"class":4245},"# Створення Service з YAML\n",[3143,15964,15965,15967,15969,15971],{"class":3145,"line":3152},[3143,15966,14019],{"class":5536},[3143,15968,14022],{"class":3529},[3143,15970,14025],{"class":5520},[3143,15972,15973],{"class":3529}," service.yaml\n",[3143,15975,15976],{"class":3145,"line":3158},[3143,15977,3168],{"emptyLinePlaceholder":3167},[3143,15979,15980],{"class":3145,"line":3164},[3143,15981,15982],{"class":4245},"# Створення Service з kubectl expose\n",[3143,15984,15985,15987,15989,15991,15994,15997,16000,16003],{"class":3145,"line":3171},[3143,15986,14019],{"class":5536},[3143,15988,14415],{"class":3529},[3143,15990,14250],{"class":3529},[3143,15992,15993],{"class":3456}," \u003C",[3143,15995,15996],{"class":3529},"nam",[3143,15998,15999],{"class":3456},"e> ",[3143,16001,16002],{"class":5520},"--port=80",[3143,16004,16005],{"class":5520}," --target-port=8080\n",[3143,16007,16008],{"class":3145,"line":3177},[3143,16009,3168],{"emptyLinePlaceholder":3167},[3143,16011,16012],{"class":3145,"line":3183},[3143,16013,14070],{"class":4245},[3143,16015,16016,16018,16020],{"class":3145,"line":3189},[3143,16017,14019],{"class":5536},[3143,16019,14077],{"class":3529},[3143,16021,14080],{"class":3529},[3143,16023,16024,16026,16028,16031],{"class":3145,"line":3195},[3143,16025,14019],{"class":5536},[3143,16027,14077],{"class":3529},[3143,16029,16030],{"class":3529}," svc",[3143,16032,16033],{"class":4245},"  # скорочена форма\n",[3143,16035,16036],{"class":3145,"line":3201},[3143,16037,3168],{"emptyLinePlaceholder":3167},[3143,16039,16040],{"class":3145,"line":3207},[3143,16041,16042],{"class":4245},"# Детальна інформація\n",[3143,16044,16045,16047,16050,16052,16054,16056],{"class":3145,"line":3213},[3143,16046,14019],{"class":5536},[3143,16048,16049],{"class":3529}," describe",[3143,16051,6319],{"class":3529},[3143,16053,15993],{"class":3456},[3143,16055,15996],{"class":3529},[3143,16057,16058],{"class":3456},"e>\n",[3143,16060,16061],{"class":3145,"line":3219},[3143,16062,3168],{"emptyLinePlaceholder":3167},[3143,16064,16065],{"class":3145,"line":3225},[3143,16066,16067],{"class":4245},"# Перегляд у форматі YAML\n",[3143,16069,16070,16072,16074,16076,16078,16080,16082,16085],{"class":3145,"line":3231},[3143,16071,14019],{"class":5536},[3143,16073,14077],{"class":3529},[3143,16075,6319],{"class":3529},[3143,16077,15993],{"class":3456},[3143,16079,15996],{"class":3529},[3143,16081,15999],{"class":3456},[3143,16083,16084],{"class":5520},"-o",[3143,16086,16087],{"class":3529}," yaml\n",[3133,16089,16091],{"className":6307,"code":16090,"filename":4013,"language":6309,"meta":3138,"style":3138},"# Перегляд Endpoints\nkubectl get endpoints \u003Cservice-name>\n\n# Детальна інформація\nkubectl describe endpoints \u003Cservice-name>\n\n# Перегляд EndpointSlices\nkubectl get endpointslices -l kubernetes.io/service-name=\u003Cname>\n",[3140,16092,16093,16098,16113,16117,16121,16135,16139,16144],{"__ignoreMap":3138},[3143,16094,16095],{"class":3145,"line":3146},[3143,16096,16097],{"class":4245},"# Перегляд Endpoints\n",[3143,16099,16100,16102,16104,16106,16108,16111],{"class":3145,"line":3152},[3143,16101,14019],{"class":5536},[3143,16103,14077],{"class":3529},[3143,16105,15539],{"class":3529},[3143,16107,15993],{"class":3456},[3143,16109,16110],{"class":3529},"service-nam",[3143,16112,16058],{"class":3456},[3143,16114,16115],{"class":3145,"line":3158},[3143,16116,3168],{"emptyLinePlaceholder":3167},[3143,16118,16119],{"class":3145,"line":3164},[3143,16120,16042],{"class":4245},[3143,16122,16123,16125,16127,16129,16131,16133],{"class":3145,"line":3171},[3143,16124,14019],{"class":5536},[3143,16126,16049],{"class":3529},[3143,16128,15539],{"class":3529},[3143,16130,15993],{"class":3456},[3143,16132,16110],{"class":3529},[3143,16134,16058],{"class":3456},[3143,16136,16137],{"class":3145,"line":3177},[3143,16138,3168],{"emptyLinePlaceholder":3167},[3143,16140,16141],{"class":3145,"line":3183},[3143,16142,16143],{"class":4245},"# Перегляд EndpointSlices\n",[3143,16145,16146,16148,16150,16153,16155,16158,16160,16162],{"class":3145,"line":3189},[3143,16147,14019],{"class":5536},[3143,16149,14077],{"class":3529},[3143,16151,16152],{"class":3529}," endpointslices",[3143,16154,14996],{"class":5520},[3143,16156,16157],{"class":3529}," kubernetes.io/service-name=",[3143,16159,7434],{"class":3456},[3143,16161,15996],{"class":3529},[3143,16163,16058],{"class":3456},[3133,16165,16168],{"className":6307,"code":16166,"filename":16167,"language":6309,"meta":3138,"style":3138},"# Запуск тестового Pod з curl та nslookup\nkubectl run test-dns --image=curlimages/curl --rm -it --restart=Never -- sh\n\n# DNS resolution\nnslookup \u003Cservice-name>\nnslookup \u003Cservice-name>.\u003Cnamespace>\nnslookup \u003Cservice-name>.\u003Cnamespace>.svc.cluster.local\n\n# HTTP-запит через DNS\ncurl http://\u003Cservice-name>\ncurl http://\u003Cservice-name>.\u003Cnamespace>\n","DNS тестування",[3140,16169,16170,16175,16195,16199,16203,16213,16233,16254,16258,16263,16275],{"__ignoreMap":3138},[3143,16171,16172],{"class":3145,"line":3146},[3143,16173,16174],{"class":4245},"# Запуск тестового Pod з curl та nslookup\n",[3143,16176,16177,16179,16181,16183,16185,16187,16189,16191,16193],{"class":3145,"line":3152},[3143,16178,14019],{"class":5536},[3143,16180,14116],{"class":3529},[3143,16182,14475],{"class":3529},[3143,16184,14122],{"class":5520},[3143,16186,14125],{"class":5520},[3143,16188,14128],{"class":5520},[3143,16190,14131],{"class":5520},[3143,16192,14134],{"class":5520},[3143,16194,14492],{"class":3529},[3143,16196,16197],{"class":3145,"line":3158},[3143,16198,3168],{"emptyLinePlaceholder":3167},[3143,16200,16201],{"class":3145,"line":3164},[3143,16202,15589],{"class":4245},[3143,16204,16205,16207,16209,16211],{"class":3145,"line":3171},[3143,16206,9250],{"class":5536},[3143,16208,15993],{"class":3456},[3143,16210,16110],{"class":3529},[3143,16212,16058],{"class":3456},[3143,16214,16215,16217,16219,16221,16224,16226,16228,16231],{"class":3145,"line":3177},[3143,16216,9250],{"class":5536},[3143,16218,15993],{"class":3456},[3143,16220,16110],{"class":3529},[3143,16222,16223],{"class":3456},"e>",[3143,16225,3580],{"class":3529},[3143,16227,7434],{"class":3456},[3143,16229,16230],{"class":3529},"namespac",[3143,16232,16058],{"class":3456},[3143,16234,16235,16237,16239,16241,16243,16245,16247,16249,16251],{"class":3145,"line":3183},[3143,16236,9250],{"class":5536},[3143,16238,15993],{"class":3456},[3143,16240,16110],{"class":3529},[3143,16242,16223],{"class":3456},[3143,16244,3580],{"class":3529},[3143,16246,7434],{"class":3456},[3143,16248,16230],{"class":3529},[3143,16250,16223],{"class":3456},[3143,16252,16253],{"class":3529},".svc.cluster.local\n",[3143,16255,16256],{"class":3145,"line":3189},[3143,16257,3168],{"emptyLinePlaceholder":3167},[3143,16259,16260],{"class":3145,"line":3195},[3143,16261,16262],{"class":4245},"# HTTP-запит через DNS\n",[3143,16264,16265,16267,16269,16271,16273],{"class":3145,"line":3201},[3143,16266,14165],{"class":5536},[3143,16268,14168],{"class":3529},[3143,16270,7434],{"class":3456},[3143,16272,16110],{"class":3529},[3143,16274,16058],{"class":3456},[3143,16276,16277,16279,16281,16283,16285,16287,16289,16291,16293],{"class":3145,"line":3207},[3143,16278,14165],{"class":5536},[3143,16280,14168],{"class":3529},[3143,16282,7434],{"class":3456},[3143,16284,16110],{"class":3529},[3143,16286,16223],{"class":3456},[3143,16288,3580],{"class":3529},[3143,16290,7434],{"class":3456},[3143,16292,16230],{"class":3529},[3143,16294,16058],{"class":3456},[3133,16296,16299],{"className":6307,"code":16297,"filename":16298,"language":6309,"meta":3138,"style":3138},"# Перегляд логів CoreDNS\nkubectl logs -n kube-system -l k8s-app=kube-dns\n\n# Перегляд конфігурації kube-proxy\nkubectl get configmap kube-proxy -n kube-system -o yaml\n\n# Перегляд iptables правил (на вузлі)\nsudo iptables -t nat -L KUBE-SERVICES\n\n# Port-forward до Service\nkubectl port-forward service/\u003Cname> 8080:80\n","Debugging",[3140,16300,16301,16306,16323,16327,16332,16353,16357,16362,16382,16386,16391],{"__ignoreMap":3138},[3143,16302,16303],{"class":3145,"line":3146},[3143,16304,16305],{"class":4245},"# Перегляд логів CoreDNS\n",[3143,16307,16308,16310,16313,16315,16318,16320],{"class":3145,"line":3152},[3143,16309,14019],{"class":5536},[3143,16311,16312],{"class":3529}," logs",[3143,16314,14406],{"class":5520},[3143,16316,16317],{"class":3529}," kube-system",[3143,16319,14996],{"class":5520},[3143,16321,16322],{"class":3529}," k8s-app=kube-dns\n",[3143,16324,16325],{"class":3145,"line":3158},[3143,16326,3168],{"emptyLinePlaceholder":3167},[3143,16328,16329],{"class":3145,"line":3164},[3143,16330,16331],{"class":4245},"# Перегляд конфігурації kube-proxy\n",[3143,16333,16334,16336,16338,16341,16344,16346,16348,16351],{"class":3145,"line":3171},[3143,16335,14019],{"class":5536},[3143,16337,14077],{"class":3529},[3143,16339,16340],{"class":3529}," configmap",[3143,16342,16343],{"class":3529}," kube-proxy",[3143,16345,14406],{"class":5520},[3143,16347,16317],{"class":3529},[3143,16349,16350],{"class":5520}," -o",[3143,16352,16087],{"class":3529},[3143,16354,16355],{"class":3145,"line":3177},[3143,16356,3168],{"emptyLinePlaceholder":3167},[3143,16358,16359],{"class":3145,"line":3183},[3143,16360,16361],{"class":4245},"# Перегляд iptables правил (на вузлі)\n",[3143,16363,16364,16367,16370,16373,16376,16379],{"class":3145,"line":3189},[3143,16365,16366],{"class":5536},"sudo",[3143,16368,16369],{"class":3529}," iptables",[3143,16371,16372],{"class":5520}," -t",[3143,16374,16375],{"class":3529}," nat",[3143,16377,16378],{"class":5520}," -L",[3143,16380,16381],{"class":3529}," KUBE-SERVICES\n",[3143,16383,16384],{"class":3145,"line":3195},[3143,16385,3168],{"emptyLinePlaceholder":3167},[3143,16387,16388],{"class":3145,"line":3201},[3143,16389,16390],{"class":4245},"# Port-forward до Service\n",[3143,16392,16393,16395,16398,16401,16403,16405,16407],{"class":3145,"line":3207},[3143,16394,14019],{"class":5536},[3143,16396,16397],{"class":3529}," port-forward",[3143,16399,16400],{"class":3529}," service/",[3143,16402,7434],{"class":3456},[3143,16404,15996],{"class":3529},[3143,16406,15999],{"class":3456},[3143,16408,16409],{"class":3529},"8080:80\n",[3582,16411],{},[3109,16413,16415],{"id":16414},"додаткові-ресурси","Додаткові ресурси",[3372,16417,16418,16425,16430,16436],{},[3375,16419,16424],{"icon":16420,"title":16421,"target":16422,"to":16423},"i-heroicons-book-open","Офіційна документація: Service","_blank","https://kubernetes.io/docs/concepts/services-networking/service/","Повна документація про Service з усіма полями та прикладами.",[3375,16426,16429],{"icon":3436,"title":16427,"target":16422,"to":16428},"DNS for Services and Pods","https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/","Детальний опис DNS resolution у Kubernetes.",[3375,16431,16435],{"icon":16432,"title":16433,"target":16422,"to":16434},"i-heroicons-link","Connecting Applications with Services","https://kubernetes.io/docs/tutorials/services/connect-applications-service/","Офіційний туторіал з підключення застосунків через Service.",[3375,16437,16440],{"icon":15847,"title":16438,"target":16422,"to":16439},"Service API Reference","https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/","Детальна специфікація API для Service v1.",[3582,16442],{},[3114,16444,16445,4793,16448],{},[3118,16446,16447],{},"Попередня стаття:",[16449,16450,2767],"a",{"href":2768},[3114,16452,16453,16456],{},[3118,16454,16455],{},"Наступна стаття:"," ConfigMap та Secret — управління конфігурацією",[16458,16459,16460],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .su9tN, html code.shiki .su9tN{--shiki-light:#0000FF;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .sCDza, html code.shiki .sCDza{--shiki-light:#AF00DB;--shiki-default:#CE92A4;--shiki-dark:#CE92A4}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"title":3138,"searchDepth":3152,"depth":3152,"links":16462},[16463,16467,16470,16474,16481,16482,16488,16496,16503,16509,16512,16520,16526,16530,16531],{"id":3111,"depth":3152,"text":3112,"children":16464},[16465,16466],{"id":3124,"depth":3158,"text":3125},{"id":3536,"depth":3158,"text":3537},{"id":3586,"depth":3152,"text":3587,"children":16468},[16469],{"id":3682,"depth":3158,"text":3683},{"id":4025,"depth":3152,"text":4026,"children":16471},[16472,16473],{"id":4444,"depth":3158,"text":4445},{"id":4913,"depth":3158,"text":4914},{"id":5051,"depth":3152,"text":5052,"children":16475},[16476,16477,16478,16479,16480],{"id":5058,"depth":3158,"text":5059},{"id":5415,"depth":3158,"text":5416},{"id":5756,"depth":3158,"text":5757},{"id":6333,"depth":3158,"text":6334},{"id":6942,"depth":3158,"text":6943},{"id":7529,"depth":3152,"text":7530},{"id":7780,"depth":3152,"text":7781,"children":16483},[16484,16485,16486,16487],{"id":7794,"depth":3158,"text":7795},{"id":8019,"depth":3158,"text":8020},{"id":8246,"depth":3158,"text":8247},{"id":8398,"depth":3158,"text":8399},{"id":8652,"depth":3152,"text":8653,"children":16489},[16490,16491,16492,16493,16494,16495],{"id":8665,"depth":3158,"text":8666},{"id":8864,"depth":3158,"text":8865},{"id":8970,"depth":3158,"text":8971},{"id":9131,"depth":3158,"text":9132},{"id":9224,"depth":3158,"text":9225},{"id":9366,"depth":3158,"text":9367},{"id":9525,"depth":3152,"text":9526,"children":16497},[16498,16499,16500,16501,16502],{"id":9543,"depth":3158,"text":9544},{"id":9590,"depth":3158,"text":9591},{"id":9704,"depth":3158,"text":9705},{"id":9903,"depth":3158,"text":9904},{"id":9997,"depth":3158,"text":9998},{"id":10394,"depth":3152,"text":10395,"children":16504},[16505,16506,16507,16508],{"id":10403,"depth":3158,"text":10404},{"id":10615,"depth":3158,"text":10616},{"id":10730,"depth":3158,"text":10731},{"id":10995,"depth":3158,"text":10996},{"id":11295,"depth":3152,"text":11296,"children":16510},[16511],{"id":11325,"depth":3158,"text":11326},{"id":11719,"depth":3152,"text":11720,"children":16513},[16514,16515,16516,16517,16518,16519],{"id":11726,"depth":3158,"text":11727},{"id":11961,"depth":3158,"text":11962},{"id":12336,"depth":3158,"text":12337},{"id":12713,"depth":3158,"text":12714},{"id":13266,"depth":3158,"text":13267},{"id":13429,"depth":3158,"text":968},{"id":13500,"depth":3152,"text":13501,"children":16521},[16522,16523,16524,16525],{"id":13507,"depth":3158,"text":13508},{"id":14274,"depth":3158,"text":14275},{"id":14643,"depth":3158,"text":14644},{"id":15246,"depth":3158,"text":15247},{"id":15804,"depth":3152,"text":15805,"children":16527},[16528,16529],{"id":15856,"depth":3158,"text":15857},{"id":15904,"depth":3158,"text":15905},{"id":15944,"depth":3152,"text":15945},{"id":16414,"depth":3152,"text":16415},"Від ефемерних IP-адрес Pod до стабільних Service endpoints — service discovery, балансування навантаження та мережева архітектура Kubernetes","md",null,{},{"title":2771,"description":16532},"RVYboqW7hBjD_4uuT2Mbv3hNdSJ2_7gILOkJyVLULvA",[16539,16541],{"title":2767,"path":2768,"stem":2769,"description":16540,"children":-1},"Оновлення застосунків без downtime — від теорії до практики з детальною візуалізацією, математичними розрахунками та реальними прикладами",{"title":2781,"path":2782,"stem":2783,"description":16542,"children":-1},"В 1986 році Фред Брукс, автор книги «Міфічний людино-місяць», опублікував статтю під назвою \"No Silver Bullet — Essence and Accident in Software Engineering\".",1778489424465]