[{"data":1,"prerenderedAt":16580},["ShallowReactive",2],{"navigation_docs":3,"-aws-docker-ecs":3338,"-aws-docker-ecs-surround":16575},[4,1707,1904,2358,2539,2608,2815,2937,2987,3044,3078,3204,3281,3334],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.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},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.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 до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.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 та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.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},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.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},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.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","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.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: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.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","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"План навчання: Курс C++ — Продовження (Статті 29–60+)","\u002Fcpp\u002Fcurriculum-plan","02.cpp\u002Fcurriculum-plan",{"title":1905,"icon":1906,"path":1907,"stem":1908,"children":1909,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[1910,1936,1990,2012,2316,2354],{"title":1911,"icon":1912,"path":1913,"stem":1914,"children":1915,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[1916,1920,1924,1928,1932],{"title":1917,"path":1918,"stem":1919},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":1921,"path":1922,"stem":1923},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":1925,"path":1926,"stem":1927},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":1929,"path":1930,"stem":1931},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":1933,"path":1934,"stem":1935},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":1937,"icon":1938,"path":1939,"stem":1940,"children":1941,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[1942,1946,1950,1954,1958,1962,1966,1970,1974,1978,1982,1986],{"title":1943,"path":1944,"stem":1945},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":1947,"path":1948,"stem":1949},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":1951,"path":1952,"stem":1953},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":1955,"path":1956,"stem":1957},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":1959,"path":1960,"stem":1961},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":1963,"path":1964,"stem":1965},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":1967,"path":1968,"stem":1969},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":1971,"path":1972,"stem":1973},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":1975,"path":1976,"stem":1977},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":1979,"path":1980,"stem":1981},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":1983,"path":1984,"stem":1985},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":1987,"path":1988,"stem":1989},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":1991,"icon":1992,"path":1993,"stem":1994,"children":1995,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[1996,2000,2004,2008],{"title":1997,"path":1998,"stem":1999},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2001,"path":2002,"stem":2003},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2005,"path":2006,"stem":2007},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2009,"path":2010,"stem":2011},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2013,"icon":2014,"path":2015,"stem":2016,"children":2017},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2018,2019,2023,2027,2031,2035,2098,2133,2285],{"title":2013,"path":2015,"stem":2016},{"title":2020,"path":2021,"stem":2022},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2024,"path":2025,"stem":2026},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2028,"path":2029,"stem":2030},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2032,"path":2033,"stem":2034},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2036,"icon":132,"path":2037,"stem":2038,"children":2039},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2040,2042,2046,2050,2054,2058,2062,2066,2070,2074,2078,2082,2086,2090,2094],{"title":2041,"path":2037,"stem":2038},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2043,"path":2044,"stem":2045},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2047,"path":2048,"stem":2049},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2051,"path":2052,"stem":2053},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2055,"path":2056,"stem":2057},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2059,"path":2060,"stem":2061},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2063,"path":2064,"stem":2065},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2067,"path":2068,"stem":2069},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2071,"path":2072,"stem":2073},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2075,"path":2076,"stem":2077},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2079,"path":2080,"stem":2081},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2083,"path":2084,"stem":2085},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2087,"path":2088,"stem":2089},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2091,"path":2092,"stem":2093},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2095,"path":2096,"stem":2097},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2099,"icon":2014,"path":2100,"stem":2101,"children":2102},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2103,2105,2109,2113,2117,2121,2125,2129],{"title":2104,"path":2100,"stem":2101},"React Router: Навігаційна система сучасного вебу",{"title":2106,"path":2107,"stem":2108},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2110,"path":2111,"stem":2112},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2114,"path":2115,"stem":2116},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2118,"path":2119,"stem":2120},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2122,"path":2123,"stem":2124},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2126,"path":2127,"stem":2128},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2130,"path":2131,"stem":2132},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2134,"icon":132,"path":2135,"stem":2136,"children":2137},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2138,2140,2156,2185,2194,2215,2231,2260],{"title":2139,"path":2135,"stem":2136},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2141,"stem":2142,"children":2143,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2144,2148,2152],{"title":2145,"path":2146,"stem":2147},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2149,"path":2150,"stem":2151},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2153,"path":2154,"stem":2155},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2157,"icon":132,"path":2158,"stem":2159,"children":2160,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2161,2165,2169,2173,2177,2181],{"title":2162,"path":2163,"stem":2164},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2166,"path":2167,"stem":2168},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2170,"path":2171,"stem":2172},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2174,"path":2175,"stem":2176},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2178,"path":2179,"stem":2180},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2182,"path":2183,"stem":2184},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2186,"icon":132,"path":2187,"stem":2188,"children":2189,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2190],{"title":2191,"path":2192,"stem":2193},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2195,"icon":132,"path":2196,"stem":2197,"children":2198,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2199,2203,2207,2211],{"title":2200,"path":2201,"stem":2202},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2204,"path":2205,"stem":2206},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2208,"path":2209,"stem":2210},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2212,"path":2213,"stem":2214},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2216,"icon":92,"path":2217,"stem":2218,"children":2219,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2220,2224,2228],{"title":2221,"path":2222,"stem":2223},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2225,"path":2226,"stem":2227},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2075,"path":2229,"stem":2230},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2232,"icon":132,"path":2233,"stem":2234,"children":2235,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2236,2240,2244,2248,2252,2256],{"title":2237,"path":2238,"stem":2239},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2241,"path":2242,"stem":2243},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2245,"path":2246,"stem":2247},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2249,"path":2250,"stem":2251},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2253,"path":2254,"stem":2255},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2257,"path":2258,"stem":2259},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2261,"icon":132,"path":2262,"stem":2263,"children":2264,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2265,2269,2273,2277,2281],{"title":2266,"path":2267,"stem":2268},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2270,"path":2271,"stem":2272},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2274,"path":2275,"stem":2276},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2278,"path":2279,"stem":2280},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2282,"path":2283,"stem":2284},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2286,"icon":132,"path":2287,"stem":2288,"children":2289},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2290,2292,2296,2300,2304,2308,2312],{"title":2291,"path":2287,"stem":2288},"UI Бібліотеки в React",{"title":2293,"path":2294,"stem":2295},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2297,"path":2298,"stem":2299},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2301,"path":2302,"stem":2303},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2305,"path":2306,"stem":2307},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2309,"path":2310,"stem":2311},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2313,"path":2314,"stem":2315},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2317,"icon":2318,"path":2319,"stem":2320,"children":2321,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2322,2326,2330,2334,2338,2342,2346,2350],{"title":2323,"path":2324,"stem":2325},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2327,"path":2328,"stem":2329},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2331,"path":2332,"stem":2333},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2335,"path":2336,"stem":2337},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2339,"path":2340,"stem":2341},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2343,"path":2344,"stem":2345},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2347,"path":2348,"stem":2349},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2351,"path":2352,"stem":2353},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2355,"path":2356,"stem":2357},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2359,"icon":2360,"path":2361,"stem":2362,"children":2363,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2364,2367,2370,2374,2378,2382,2386],{"title":162,"path":2365,"stem":2366},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2368,"stem":2369},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2371,"path":2372,"stem":2373},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2375,"path":2376,"stem":2377},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2379,"path":2380,"stem":2381},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2383,"path":2384,"stem":2385},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2387,"path":2388,"stem":2389,"children":2390,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2391,2395,2399,2403,2407,2411,2415,2419,2423,2427,2431,2435,2439,2443,2447,2451,2455,2459,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511,2515,2519,2523,2527,2531,2535],{"title":2392,"path":2393,"stem":2394},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2396,"path":2397,"stem":2398},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2400,"path":2401,"stem":2402},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2404,"path":2405,"stem":2406},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2408,"path":2409,"stem":2410},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2412,"path":2413,"stem":2414},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2416,"path":2417,"stem":2418},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2420,"path":2421,"stem":2422},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2424,"path":2425,"stem":2426},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2428,"path":2429,"stem":2430},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2432,"path":2433,"stem":2434},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2436,"path":2437,"stem":2438},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2440,"path":2441,"stem":2442},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2444,"path":2445,"stem":2446},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2448,"path":2449,"stem":2450},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2452,"path":2453,"stem":2454},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2456,"path":2457,"stem":2458},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2460,"path":2461,"stem":2462},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2464,"path":2465,"stem":2466},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2468,"path":2469,"stem":2470},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2472,"path":2473,"stem":2474},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2476,"path":2477,"stem":2478},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2480,"path":2481,"stem":2482},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2484,"path":2485,"stem":2486},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2488,"path":2489,"stem":2490},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2492,"path":2493,"stem":2494},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2496,"path":2497,"stem":2498},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2500,"path":2501,"stem":2502},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2504,"path":2505,"stem":2506},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2508,"path":2509,"stem":2510},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2512,"path":2513,"stem":2514},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2516,"path":2517,"stem":2518},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2520,"path":2521,"stem":2522},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2524,"path":2525,"stem":2526},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2528,"path":2529,"stem":2530},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2532,"path":2533,"stem":2534},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2536,"path":2537,"stem":2538},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2540,"icon":2541,"path":2542,"stem":2543,"children":2544,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2545,2549,2552,2556,2560,2564,2568,2572,2576,2580,2584,2588,2592,2596,2600,2604],{"title":2546,"path":2547,"stem":2548},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2550,"stem":2551},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2553,"path":2554,"stem":2555},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2557,"path":2558,"stem":2559},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2561,"path":2562,"stem":2563},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2565,"path":2566,"stem":2567},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2569,"path":2570,"stem":2571},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2573,"path":2574,"stem":2575},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2577,"path":2578,"stem":2579},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2581,"path":2582,"stem":2583},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2585,"path":2586,"stem":2587},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2589,"path":2590,"stem":2591},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2593,"path":2594,"stem":2595},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2597,"path":2598,"stem":2599},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2601,"path":2602,"stem":2603},"📦 Повний посібник з модулів, пакетів та віртуальних середовищ у Python","\u002Fpython\u002Flesson_9","05.python\u002Flesson_9",{"title":2605,"path":2606,"stem":2607},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2609,"icon":2610,"path":2611,"stem":2612,"children":2613,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2614,2644,2667,2704,2733,2751,2785,2797,2806],{"title":2615,"icon":2616,"path":2617,"stem":2618,"children":2619,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2620,2624,2628,2632,2636,2640],{"title":2621,"path":2622,"stem":2623},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2625,"path":2626,"stem":2627},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2629,"path":2630,"stem":2631},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2633,"path":2634,"stem":2635},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2637,"path":2638,"stem":2639},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2641,"path":2642,"stem":2643},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2645,"icon":2610,"path":2646,"stem":2647,"children":2648,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2649,2653,2659,2663],{"title":2650,"path":2651,"stem":2652},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2654,"path":2655,"stem":2656,"children":2657},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2658],{"title":2654,"path":2655,"stem":2656},{"title":2660,"path":2661,"stem":2662},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2664,"path":2665,"stem":2666},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2668,"icon":2610,"path":2669,"stem":2670,"children":2671,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2672,2676,2680,2684,2688,2692,2696,2700],{"title":2673,"path":2674,"stem":2675},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2677,"path":2678,"stem":2679},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2681,"path":2682,"stem":2683},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2685,"path":2686,"stem":2687},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2689,"path":2690,"stem":2691},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2693,"path":2694,"stem":2695},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2697,"path":2698,"stem":2699},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2701,"path":2702,"stem":2703},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2705,"icon":2610,"path":2706,"stem":2707,"children":2708,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2709,2713,2717,2721,2725,2729],{"title":2710,"path":2711,"stem":2712},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2714,"path":2715,"stem":2716},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2718,"path":2719,"stem":2720},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2722,"path":2723,"stem":2724},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2726,"path":2727,"stem":2728},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2730,"path":2731,"stem":2732},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2734,"icon":2735,"path":2736,"stem":2737,"children":2738,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2739,2743,2747],{"title":2740,"path":2741,"stem":2742},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2744,"path":2745,"stem":2746},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":2748,"path":2749,"stem":2750},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":2752,"icon":2753,"path":2754,"stem":2755,"children":2756,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[2757,2761,2765,2769,2773,2777,2781],{"title":2758,"path":2759,"stem":2760},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":2762,"path":2763,"stem":2764},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":2766,"path":2767,"stem":2768},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":2770,"path":2771,"stem":2772},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":2774,"path":2775,"stem":2776},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":2778,"path":2779,"stem":2780},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":2782,"path":2783,"stem":2784},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":2782,"icon":793,"path":2786,"stem":2787,"children":2788,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[2789,2793],{"title":2790,"path":2791,"stem":2792},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":2794,"path":2795,"stem":2796},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":2798,"icon":2799,"path":2800,"stem":2801,"children":2802,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[2803],{"title":2798,"path":2804,"stem":2805},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":2807,"icon":2808,"path":2809,"stem":2810,"children":2811,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[2812],{"title":2807,"path":2813,"stem":2814},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":2816,"icon":2817,"path":2818,"stem":2819,"children":2820,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[2821,2897],{"title":2822,"icon":2823,"path":2824,"stem":2825,"children":2826},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[2827,2829,2833,2837,2841,2845,2849,2853,2857,2861,2865,2869,2873,2877,2881,2885,2889,2893],{"title":2828,"path":2824,"stem":2825},"Docker: від нуля до production",{"title":2830,"path":2831,"stem":2832},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":2834,"path":2835,"stem":2836},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":2838,"path":2839,"stem":2840},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":2842,"path":2843,"stem":2844},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":2846,"path":2847,"stem":2848},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":2850,"path":2851,"stem":2852},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":2854,"path":2855,"stem":2856},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":2858,"path":2859,"stem":2860},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":2862,"path":2863,"stem":2864},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":2866,"path":2867,"stem":2868},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":2870,"path":2871,"stem":2872},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":2874,"path":2875,"stem":2876},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":2878,"path":2879,"stem":2880},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":2882,"path":2883,"stem":2884},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":2886,"path":2887,"stem":2888},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":2890,"path":2891,"stem":2892},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":2894,"path":2895,"stem":2896},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":2898,"icon":2899,"path":2900,"stem":2901,"children":2902},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[2903,2905,2909,2913,2917,2921,2925,2929,2933],{"title":2904,"path":2900,"stem":2901},"Kubernetes: від розробки до production",{"title":2906,"path":2907,"stem":2908},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":2910,"path":2911,"stem":2912},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":2914,"path":2915,"stem":2916},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":2918,"path":2919,"stem":2920},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":2922,"path":2923,"stem":2924},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":2926,"path":2927,"stem":2928},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":2930,"path":2931,"stem":2932},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":2934,"path":2935,"stem":2936},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":2938,"icon":2939,"path":2940,"stem":2941,"children":2942,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[2943,2947,2951,2955,2959,2963,2967,2971,2975,2979,2983],{"title":2944,"path":2945,"stem":2946},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":2948,"path":2949,"stem":2950},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":2952,"path":2953,"stem":2954},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":2956,"path":2957,"stem":2958},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":2960,"path":2961,"stem":2962},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":2964,"path":2965,"stem":2966},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":2968,"path":2969,"stem":2970},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":2972,"path":2973,"stem":2974},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":2976,"path":2977,"stem":2978},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":2980,"path":2981,"stem":2982},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":2984,"path":2985,"stem":2986},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":2988,"icon":943,"path":2989,"stem":2990,"children":2991,"page":59},"DDD","\u002Fddd","10.ddd",[2992,2996,3000,3004,3008,3012,3016,3020,3024,3028,3032,3036,3040],{"title":2993,"path":2994,"stem":2995},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":2997,"path":2998,"stem":2999},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3001,"path":3002,"stem":3003},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3005,"path":3006,"stem":3007},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3009,"path":3010,"stem":3011},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3013,"path":3014,"stem":3015},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3017,"path":3018,"stem":3019},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3021,"path":3022,"stem":3023},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3025,"path":3026,"stem":3027},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3029,"path":3030,"stem":3031},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3033,"path":3034,"stem":3035},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3037,"path":3038,"stem":3039},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3041,"path":3042,"stem":3043},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3045,"icon":3046,"path":3047,"stem":3048,"children":3049,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3050,3054,3058,3062,3066,3070,3074],{"title":3051,"path":3052,"stem":3053},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3055,"path":3056,"stem":3057},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3059,"path":3060,"stem":3061},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3063,"path":3064,"stem":3065},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3067,"path":3068,"stem":3069},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3071,"path":3072,"stem":3073},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3075,"path":3076,"stem":3077},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3079,"icon":3080,"path":3081,"stem":3082,"children":3083,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3084,3088,3092,3096,3100,3104,3108,3112,3116,3120,3124,3128,3132,3136,3140,3144,3148,3152,3156,3160,3164,3168,3172,3176,3180,3184,3188,3192,3196,3200],{"title":3085,"path":3086,"stem":3087},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3089,"path":3090,"stem":3091},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3093,"path":3094,"stem":3095},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3097,"path":3098,"stem":3099},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3101,"path":3102,"stem":3103},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3105,"path":3106,"stem":3107},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3109,"path":3110,"stem":3111},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3113,"path":3114,"stem":3115},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3117,"path":3118,"stem":3119},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3121,"path":3122,"stem":3123},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3125,"path":3126,"stem":3127},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3129,"path":3130,"stem":3131},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3133,"path":3134,"stem":3135},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3137,"path":3138,"stem":3139},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3141,"path":3142,"stem":3143},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3145,"path":3146,"stem":3147},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3149,"path":3150,"stem":3151},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3153,"path":3154,"stem":3155},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3157,"path":3158,"stem":3159},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3161,"path":3162,"stem":3163},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3165,"path":3166,"stem":3167},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3169,"path":3170,"stem":3171},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3173,"path":3174,"stem":3175},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3177,"path":3178,"stem":3179},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3181,"path":3182,"stem":3183},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3185,"path":3186,"stem":3187},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3189,"path":3190,"stem":3191},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3193,"path":3194,"stem":3195},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3197,"path":3198,"stem":3199},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3201,"path":3202,"stem":3203},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3205,"path":3206,"stem":3207,"children":3208,"page":59},"AWS","\u002Faws","13.aws",[3209,3213,3217,3221,3225,3229,3233,3237,3241,3245,3249,3253,3257,3261,3265,3269,3273,3277],{"title":3210,"path":3211,"stem":3212},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3214,"path":3215,"stem":3216},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3218,"path":3219,"stem":3220},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3222,"path":3223,"stem":3224},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3226,"path":3227,"stem":3228},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3230,"path":3231,"stem":3232},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3234,"path":3235,"stem":3236},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3238,"path":3239,"stem":3240},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3242,"path":3243,"stem":3244},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3246,"path":3247,"stem":3248},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3250,"path":3251,"stem":3252},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3254,"path":3255,"stem":3256},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3258,"path":3259,"stem":3260},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3262,"path":3263,"stem":3264},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3266,"path":3267,"stem":3268},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3270,"path":3271,"stem":3272},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3274,"path":3275,"stem":3276},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3278,"path":3279,"stem":3280},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3282,"path":3283,"stem":3284,"children":3285,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[3286,3290,3294,3298,3302,3306,3310,3314,3318,3322,3326,3330],{"title":3287,"path":3288,"stem":3289},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":3291,"path":3292,"stem":3293},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":3295,"path":3296,"stem":3297},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":3299,"path":3300,"stem":3301},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":3303,"path":3304,"stem":3305},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":3307,"path":3308,"stem":3309},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":3311,"path":3312,"stem":3313},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":3315,"path":3316,"stem":3317},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":3319,"path":3320,"stem":3321},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":3323,"path":3324,"stem":3325},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":3327,"path":3328,"stem":3329},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":3331,"path":3332,"stem":3333},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":3335,"path":3336,"stem":3337},"Тестування компонентів діаграм","\u002Ftest-components","98.test-components",{"id":3339,"title":3226,"body":3340,"description":16569,"extension":16570,"links":16571,"meta":16572,"navigation":3618,"path":3227,"seo":16573,"stem":3228,"__hash__":16574},"docs\u002F13.aws\u002F03.docker-ecs.md",{"type":3341,"value":3342,"toc":16482},"minimark",[3343,3348,3353,3357,3438,3441,3485,3517,3520,3524,3533,3536,3544,3553,3564,3572,3577,3584,3587,3773,3779,3789,3792,3794,3798,3805,3812,3816,3822,3828,3834,3840,3844,3851,3859,3862,3868,3872,3875,3880,3922,3927,3933,3942,4337,4342,4382,4401,4404,4406,4410,4417,4423,4426,4695,4698,4721,4725,4736,4849,4851,4855,4862,4865,4879,4916,4922,4992,4999,5004,5043,5073,5078,5113,5120,5122,5126,5133,5139,5145,5162,5166,5169,5175,5181,5187,5193,5197,5204,5296,5308,5328,5505,5509,5516,5519,5965,5968,5983,5994,6006,6014,6018,6029,6138,6154,6189,6191,6195,6202,6209,6213,6224,6229,6240,6246,6250,6260,6270,6275,6289,6294,6340,6342,6346,6353,6364,6368,6374,6385,6399,6405,6409,6412,6426,6436,6580,6584,6590,6593,6613,6617,6626,6632,6635,6655,6659,6670,6676,6687,6691,6694,6700,6709,6713,6719,6722,6724,6728,6735,6749,6753,6760,6828,6831,6840,6849,6854,7054,7068,7072,7078,7084,7222,7224,7228,7235,7241,7245,7256,7261,7267,7270,7274,7695,7705,7707,7711,7718,7728,7733,7750,7768,7774,7783,7785,7792,7796,7802,7937,7944,7948,7955,7999,8004,8021,8028,8032,8172,8174,8181,8185,8189,8196,8212,8225,8285,8288,8335,8339,8342,8353,8435,8445,8518,8523,8584,8586,8590,8597,8709,8713,8719,8725,8732,8737,8964,8969,9011,9032,9044,9046,9053,9057,9064,9069,9079,9085,9090,9209,9214,9252,9254,9261,9265,9271,9295,9303,9348,9350,9357,9361,9368,9479,9524,9526,9533,9537,9540,9600,9602,9606,9613,9712,9716,9730,9736,9741,9838,9845,9850,10025,10065,10076,10078,10085,10181,10185,10191,10197,10203,10287,10303,10310,10312,10319,10412,10416,10422,10442,10447,10556,10566,10568,10575,10674,10678,10689,10694,11106,11108,11115,11218,11222,11228,11242,11247,11315,11321,11323,11330,11437,11441,11447,11452,11492,11505,11515,11517,11524,11528,11531,11535,11538,11568,11574,11803,11806,11845,11849,11859,12056,12077,12081,12122,12125,12220,12224,12476,12480,12651,12657,12702,12733,12736,12752,12756,12863,12915,12919,12922,13109,13113,13125,13531,13535,13538,13919,13997,14001,14264,14269,14303,14307,14310,14549,14552,14586,14590,14593,14601,14631,14634,14717,14720,15062,15065,15091,15099,15106,15110,15184,15252,15267,15271,15277,15280,15584,15586,15593,15597,15607,15612,15618,15629,15634,15689,15693,15709,15713,15722,15781,15804,15807,15846,15850,15853,15867,15997,16003,16281,16288,16290,16297,16301,16353,16355,16362,16366,16370,16376,16382,16398,16402,16418,16434,16440,16444,16468,16478],[3344,3345,3347],"h1",{"id":3346},"docker-та-контейнеризація-в-aws","Docker та контейнеризація в AWS",[3349,3350,3352],"h2",{"id":3351},"передумови","Передумови",[3354,3355,3356],"p",{},"Для виконання практичних завдань у цьому розділі необхідне таке програмне забезпечення та конфігурація:",[3358,3359,3360,3376],"table",{},[3361,3362,3363],"thead",{},[3364,3365,3366,3370,3373],"tr",{},[3367,3368,3369],"th",{},"Інструмент",[3367,3371,3372],{},"Версія",[3367,3374,3375],{},"Призначення",[3377,3378,3379,3397,3412,3427],"tbody",{},[3364,3380,3381,3391,3394],{},[3382,3383,3384],"td",{},[3385,3386,3390],"a",{"href":3387,"rel":3388},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fcli\u002Flatest\u002Fuserguide\u002Finstall-cliv2.html",[3389],"nofollow","AWS CLI v2",[3382,3392,3393],{},"2.x",[3382,3395,3396],{},"Керування ресурсами AWS з терміналу",[3364,3398,3399,3406,3409],{},[3382,3400,3401],{},[3385,3402,3405],{"href":3403,"rel":3404},"https:\u002F\u002Fwww.docker.com\u002Fproducts\u002Fdocker-desktop\u002F",[3389],"Docker Desktop",[3382,3407,3408],{},"4.x+",[3382,3410,3411],{},"Збірка та локальний запуск контейнерів",[3364,3413,3414,3421,3424],{},[3382,3415,3416],{},[3385,3417,3420],{"href":3418,"rel":3419},"https:\u002F\u002Fdotnet.microsoft.com\u002Fdownload\u002Fdotnet\u002F8.0",[3389],".NET SDK 8",[3382,3422,3423],{},"8.0+",[3382,3425,3426],{},"Компіляція ASP.NET Core проєктів",[3364,3428,3429,3432,3435],{},[3382,3430,3431],{},"AWS-акаунт",[3382,3433,3434],{},"—",[3382,3436,3437],{},"Доступ до ECR, ECS, IAM, CloudWatch",[3354,3439,3440],{},"Перевірте налаштування AWS CLI перед початком:",[3442,3443,3448],"pre",{"className":3444,"code":3445,"language":3446,"meta":3447,"style":3447},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","aws configure list      # переглянути поточний профіль\naws sts get-caller-identity   # перевірити підключення до акаунту\n","bash","",[3449,3450,3451,3471],"code",{"__ignoreMap":3447},[3452,3453,3456,3460,3464,3467],"span",{"class":3454,"line":3455},"line",1,[3452,3457,3459],{"class":3458},"s8Opu","aws",[3452,3461,3463],{"class":3462},"sbdoH"," configure",[3452,3465,3466],{"class":3462}," list",[3452,3468,3470],{"class":3469},"spJ8K","      # переглянути поточний профіль\n",[3452,3472,3474,3476,3479,3482],{"class":3454,"line":3473},2,[3452,3475,3459],{"class":3458},[3452,3477,3478],{"class":3462}," sts",[3452,3480,3481],{"class":3462}," get-caller-identity",[3452,3483,3484],{"class":3469},"   # перевірити підключення до акаунту\n",[3354,3486,3487,3488,3491,3492,3491,3495,3491,3498,3491,3501,3491,3504,3491,3507,3491,3510,3491,3513,3516],{},"Користувач або роль, від імені якої ви працюєте, повинна мати права на: ",[3449,3489,3490],{},"ecr:*",", ",[3449,3493,3494],{},"ecs:*",[3449,3496,3497],{},"iam:CreateRole",[3449,3499,3500],{},"iam:AttachRolePolicy",[3449,3502,3503],{},"ec2:DescribeVpcs",[3449,3505,3506],{},"ec2:DescribeSubnets",[3449,3508,3509],{},"ec2:CreateSecurityGroup",[3449,3511,3512],{},"elasticloadbalancing:*",[3449,3514,3515],{},"logs:CreateLogGroup",".",[3518,3519],"hr",{},[3349,3521,3523],{"id":3522},"проблема-яку-вирішують-контейнери","Проблема, яку вирішують контейнери",[3354,3525,3526],{},[3527,3528],"img",{"alt":3529,"className":3530,"src":3532},"Docker container solves works on my machine problem with standardized environment",[3531],"diagram-img","\u002Fimages\u002Faws\u002Fdocker-ecs\u002F01.png",[3354,3534,3535],{},"Уявіть класичну ситуацію: ваш .NET Web API ідеально працює на вашому MacBook. Ви передаєте код колезі — і він не запускається, бо у нього інша версія .NET Runtime. Ви деплоїте на сервер з Ubuntu — і знову проблеми, бо там встановлені інші версії бібліотек. DevOps-інженер каже: «У мене все працює» — але ж середовища різні!",[3354,3537,3538,3539,3543],{},"Це фундаментальна проблема розробки програмного забезпечення, відома як ",[3540,3541,3542],"strong",{},"«works on my machine»"," — «у мене на машині працює». Десятиліттями це вирішувалось через детальну документацію налаштування середовища, складні інструкції для DevOps, або просто через «ну, запустіть ще раз».",[3354,3545,3546,3548,3549,3552],{},[3540,3547,2822],{}," вирішує цю проблему радикально: замість того, щоб передавати код і сподіватись, що середовище збігається — ви передаєте ",[3540,3550,3551],{},"весь застосунок разом із середовищем",". Код, .NET Runtime, бібліотеки, системні залежності — все упаковане в один незмінний артефакт, який однаково запускається на будь-якій машині.",[3354,3554,3555,3556,3559,3560,3563],{},"Цей артефакт називається ",[3540,3557,3558],{},"Docker-образом"," (image), а запущений екземпляр образу — ",[3540,3561,3562],{},"контейнером"," (container).",[3565,3566,3567,3568,3571],"note",{},"Docker та контейнеризація — окрема велика тема, яку ви, можливо, вже вивчали або будете вивчати детально. У цьому модулі ми зосередимось на тому, ",[3540,3569,3570],{},"як використовувати контейнери в AWS",": де зберігати образи, як запускати їх у хмарі, як масштабувати та оновлювати без простоїв.",[3573,3574,3576],"h3",{"id":3575},"контейнер-vs-віртуальна-машина","Контейнер vs Віртуальна машина",[3354,3578,3579],{},[3527,3580],{"alt":3581,"className":3582,"src":3583},"Container versus virtual machine architecture comparison sharing host OS kernel",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F02.png",[3354,3585,3586],{},"Важливо відразу розуміти різницю між контейнером і віртуальною машиною (VM), яку ми вивчали у попередньому модулі (EC2).",[3588,3589,3590],"plant-uml",{},[3442,3591,3595],{"className":3592,"code":3593,"language":3594,"meta":3447,"style":3447},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Віртуальна машина (VM)\" #fef3c7 {\n    node \"EC2 Instance\" {\n        rectangle \"Guest OS (Linux\u002FWindows)\" as GuestOS1 #e5e7eb\n        rectangle \"App + Runtime\" as App1 #d1fae5\n        GuestOS1 -down-> App1\n    }\n    rectangle \"Hypervisor (Xen\u002FKVM)\" as HV #f3f4f6\n    rectangle \"Host OS\" as HostOS1 #e5e7eb\n    rectangle \"Фізичне залізо\" as HW1 #d1d5db\n    HV -down-> HostOS1\n    HostOS1 -down-> HW1\n}\n\npackage \"Контейнер (Docker)\" #d1fae5 {\n    node \"Docker Host\" {\n        rectangle \"Container A\\n(App + Runtime)\" as CA #bbf7d0\n        rectangle \"Container B\\n(App + Runtime)\" as CB #bbf7d0\n        rectangle \"Container C\\n(App + Runtime)\" as CC #bbf7d0\n    }\n    rectangle \"Docker Engine\" as DE #f3f4f6\n    rectangle \"Host OS (Linux)\" as HostOS2 #e5e7eb\n    rectangle \"Фізичне залізо\" as HW2 #d1d5db\n    DE -down-> HostOS2\n    HostOS2 -down-> HW2\n}\n@enduml\n","plantuml",[3449,3596,3597,3602,3607,3613,3620,3626,3632,3638,3644,3650,3656,3662,3668,3674,3680,3686,3692,3697,3703,3709,3715,3721,3727,3732,3738,3744,3750,3756,3762,3767],{"__ignoreMap":3447},[3452,3598,3599],{"class":3454,"line":3455},[3452,3600,3601],{},"@startuml\n",[3452,3603,3604],{"class":3454,"line":3473},[3452,3605,3606],{},"skinparam style plain\n",[3452,3608,3610],{"class":3454,"line":3609},3,[3452,3611,3612],{},"skinparam backgroundColor #ffffff\n",[3452,3614,3616],{"class":3454,"line":3615},4,[3452,3617,3619],{"emptyLinePlaceholder":3618},true,"\n",[3452,3621,3623],{"class":3454,"line":3622},5,[3452,3624,3625],{},"package \"Віртуальна машина (VM)\" #fef3c7 {\n",[3452,3627,3629],{"class":3454,"line":3628},6,[3452,3630,3631],{},"    node \"EC2 Instance\" {\n",[3452,3633,3635],{"class":3454,"line":3634},7,[3452,3636,3637],{},"        rectangle \"Guest OS (Linux\u002FWindows)\" as GuestOS1 #e5e7eb\n",[3452,3639,3641],{"class":3454,"line":3640},8,[3452,3642,3643],{},"        rectangle \"App + Runtime\" as App1 #d1fae5\n",[3452,3645,3647],{"class":3454,"line":3646},9,[3452,3648,3649],{},"        GuestOS1 -down-> App1\n",[3452,3651,3653],{"class":3454,"line":3652},10,[3452,3654,3655],{},"    }\n",[3452,3657,3659],{"class":3454,"line":3658},11,[3452,3660,3661],{},"    rectangle \"Hypervisor (Xen\u002FKVM)\" as HV #f3f4f6\n",[3452,3663,3665],{"class":3454,"line":3664},12,[3452,3666,3667],{},"    rectangle \"Host OS\" as HostOS1 #e5e7eb\n",[3452,3669,3671],{"class":3454,"line":3670},13,[3452,3672,3673],{},"    rectangle \"Фізичне залізо\" as HW1 #d1d5db\n",[3452,3675,3677],{"class":3454,"line":3676},14,[3452,3678,3679],{},"    HV -down-> HostOS1\n",[3452,3681,3683],{"class":3454,"line":3682},15,[3452,3684,3685],{},"    HostOS1 -down-> HW1\n",[3452,3687,3689],{"class":3454,"line":3688},16,[3452,3690,3691],{},"}\n",[3452,3693,3695],{"class":3454,"line":3694},17,[3452,3696,3619],{"emptyLinePlaceholder":3618},[3452,3698,3700],{"class":3454,"line":3699},18,[3452,3701,3702],{},"package \"Контейнер (Docker)\" #d1fae5 {\n",[3452,3704,3706],{"class":3454,"line":3705},19,[3452,3707,3708],{},"    node \"Docker Host\" {\n",[3452,3710,3712],{"class":3454,"line":3711},20,[3452,3713,3714],{},"        rectangle \"Container A\\n(App + Runtime)\" as CA #bbf7d0\n",[3452,3716,3718],{"class":3454,"line":3717},21,[3452,3719,3720],{},"        rectangle \"Container B\\n(App + Runtime)\" as CB #bbf7d0\n",[3452,3722,3724],{"class":3454,"line":3723},22,[3452,3725,3726],{},"        rectangle \"Container C\\n(App + Runtime)\" as CC #bbf7d0\n",[3452,3728,3730],{"class":3454,"line":3729},23,[3452,3731,3655],{},[3452,3733,3735],{"class":3454,"line":3734},24,[3452,3736,3737],{},"    rectangle \"Docker Engine\" as DE #f3f4f6\n",[3452,3739,3741],{"class":3454,"line":3740},25,[3452,3742,3743],{},"    rectangle \"Host OS (Linux)\" as HostOS2 #e5e7eb\n",[3452,3745,3747],{"class":3454,"line":3746},26,[3452,3748,3749],{},"    rectangle \"Фізичне залізо\" as HW2 #d1d5db\n",[3452,3751,3753],{"class":3454,"line":3752},27,[3452,3754,3755],{},"    DE -down-> HostOS2\n",[3452,3757,3759],{"class":3454,"line":3758},28,[3452,3760,3761],{},"    HostOS2 -down-> HW2\n",[3452,3763,3765],{"class":3454,"line":3764},29,[3452,3766,3691],{},[3452,3768,3770],{"class":3454,"line":3769},30,[3452,3771,3772],{},"@enduml\n",[3354,3774,3775,3778],{},[3540,3776,3777],{},"VM"," — повна ізоляція через апаратну віртуалізацію. Кожна VM містить власну гостьову ОС (~1–20 GB). Запуск займає хвилини.",[3354,3780,3781,3784,3785,3788],{},[3540,3782,3783],{},"Контейнер"," — ізоляція на рівні ОС через namespaces та cgroups Linux. Контейнер ",[3540,3786,3787],{},"ділить ядро"," з хост-ОС. Розмір образу — десятки–сотні MB. Запуск займає секунди або мілісекунди.",[3354,3790,3791],{},"Для AWS це означає: на одному EC2 інстансі можна запустити десятки контейнерів, де могло б бути лише кілька VM.",[3518,3793],{},[3349,3795,3797],{"id":3796},"amazon-ecr-elastic-container-registry","Amazon ECR — Elastic Container Registry",[3354,3799,3800],{},[3527,3801],{"alt":3802,"className":3803,"src":3804},"Amazon ECR Elastic Container Registry repository with Docker images",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F03.png",[3354,3806,3807,3808,3811],{},"Перш ніж запустити контейнер в AWS, образ потрібно десь зберегти. ",[3540,3809,3810],{},"Amazon Elastic Container Registry (ECR)"," — це керований сервіс для зберігання, версіонування та поширення Docker-образів, аналогічний Docker Hub, але повністю інтегрований з AWS IAM та іншими сервісами AWS.",[3573,3813,3815],{"id":3814},"чому-ecr-а-не-docker-hub","Чому ECR, а не Docker Hub?",[3354,3817,3818,3821],{},[3540,3819,3820],{},"Приватність та безпека:"," ECR-репозиторії за замовчуванням приватні і захищені IAM-правами. Жоден зовнішній користувач не зможе завантажити ваші образи без явного дозволу.",[3354,3823,3824,3827],{},[3540,3825,3826],{},"Інтеграція з AWS:"," ECS, EKS та Lambda автоматично аутентифікуються в ECR через IAM Role — без додаткових секретів і паролів. Порівняйте з Docker Hub, де потрібно зберігати credentials у Secrets Manager.",[3354,3829,3830,3833],{},[3540,3831,3832],{},"Швидкість:"," ECR розміщений в тому ж регіоні, що і ваші ECS\u002FEKS кластери. Завантаження образу відбувається через внутрішню мережу AWS — без витрат на transfer та з максимальною швидкістю.",[3354,3835,3836,3839],{},[3540,3837,3838],{},"Lifecycle Policies:"," ECR автоматично видаляє старі версії образів за правилами, які ви визначаєте (наприклад, зберігати лише 10 останніх версій). Це суттєво знижує вартість зберігання.",[3573,3841,3843],{"id":3842},"структура-ecr","Структура ECR",[3354,3845,3846,3847,3850],{},"ECR організований через ",[3540,3848,3849],{},"репозиторії"," (repositories). Один репозиторій — один Docker-образ у різних версіях (тегах).",[3442,3852,3857],{"className":3853,"code":3855,"language":3856},[3854],"language-text","123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002F\n├── my-api\u002F\n│   ├── :latest\n│   ├── :v1.2.3\n│   └── :sha256-abc123...\n├── my-worker\u002F\n│   ├── :latest\n│   └── :v2.0.0\n└── my-frontend\u002F\n    └── :latest\n","text",[3449,3858,3855],{"__ignoreMap":3447},[3354,3860,3861],{},"Адреса ECR-репозиторію завжди має формат:",[3442,3863,3866],{"className":3864,"code":3865,"language":3856},[3854],"{account-id}.dkr.ecr.{region}.amazonaws.com\u002F{repository-name}:{tag}\n",[3449,3867,3865],{"__ignoreMap":3447},[3573,3869,3871],{"id":3870},"практика-створення-aspnet-minimal-api-проєкту","Практика: Створення ASP.NET Minimal API проєкту",[3354,3873,3874],{},"Перш ніж писати Dockerfile, підготуємо сам застосунок. Пройдемо по кроках — від порожнього каталогу до готового проєкту, який потім контейнеризуємо та задеплоїмо в AWS.",[3354,3876,3877],{},[3540,3878,3879],{},"Крок 1 — Створення проєкту:",[3881,3882,3884,3897,3904,3910,3918],"terminal-preview",{"title":3883},"dotnet new webapi — ініціалізація",[3885,3886,3888,3893,3894],"div",{"className":3887},[3454],[3452,3889,3892],{"className":3890},[3891],"opacity-40","$"," ",[3540,3895,3896],{},"dotnet new webapi \\",[3885,3898,3900,3901],{"className":3899},[3454],"        ",[3540,3902,3903],{},"--name MyApi \\",[3885,3905,3900,3907],{"className":3906},[3454],[3540,3908,3909],{},"--output .\u002FMyApi",[3885,3911,3913],{"className":3912},[3454],[3452,3914,3917],{"className":3915},[3916],"text-green-400","The template \"ASP.NET Core Web API\" was created successfully.",[3885,3919,3921],{"className":3920},[3454],"Restore succeeded.",[3354,3923,3924],{},[3540,3925,3926],{},"Крок 2 — Структура проєкту:",[3442,3928,3931],{"className":3929,"code":3930,"language":3856},[3854],"MyApi\u002F\n├── MyApi.csproj\n├── Program.cs\n├── appsettings.json\n└── appsettings.Development.json\n",[3449,3932,3930],{"__ignoreMap":3447},[3354,3934,3935,3941],{},[3540,3936,3937,3938],{},"Крок 3 — Замініть вміст ",[3449,3939,3940],{},"Program.cs"," на мінімальний API з health check endpoint:",[3442,3943,3947],{"className":3944,"code":3945,"language":3946,"meta":3447,"style":3447},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","var builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddHealthChecks();\n\nvar app = builder.Build();\n\napp.MapGet(\"\u002F\", () => new { status = \"ok\", version = \"1.0.0\" });\n\napp.MapGet(\"\u002Fweatherforecast\", () =>\n{\n    var summaries = new[] { \"Freezing\", \"Cool\", \"Warm\", \"Hot\" };\n    return Enumerable.Range(1, 5).Select(i => new\n    {\n        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(i)),\n        TemperatureC = Random.Shared.Next(-20, 55),\n        Summary = summaries[Random.Shared.Next(summaries.Length)]\n    });\n});\n\n\u002F\u002F Health check endpoint — потрібен для ECS health check\napp.MapHealthChecks(\"\u002Fhealth\");\n\napp.Run();\n","csharp",[3449,3948,3949,3980,3984,4002,4006,4024,4028,4073,4077,4093,4098,4134,4176,4181,4218,4252,4287,4292,4297,4301,4306,4322,4326],{"__ignoreMap":3447},[3452,3950,3951,3955,3959,3963,3966,3968,3971,3974,3977],{"class":3454,"line":3455},[3452,3952,3954],{"class":3953},"su1O8","var",[3452,3956,3958],{"class":3957},"siwwj"," builder",[3452,3960,3962],{"class":3961},"sHH4Y"," = ",[3452,3964,3965],{"class":3957},"WebApplication",[3452,3967,3516],{"class":3961},[3452,3969,3970],{"class":3458},"CreateBuilder",[3452,3972,3973],{"class":3961},"(",[3452,3975,3976],{"class":3957},"args",[3452,3978,3979],{"class":3961},");\n",[3452,3981,3982],{"class":3454,"line":3473},[3452,3983,3619],{"emptyLinePlaceholder":3618},[3452,3985,3986,3989,3991,3994,3996,3999],{"class":3454,"line":3609},[3452,3987,3988],{"class":3957},"builder",[3452,3990,3516],{"class":3961},[3452,3992,3993],{"class":3957},"Services",[3452,3995,3516],{"class":3961},[3452,3997,3998],{"class":3458},"AddHealthChecks",[3452,4000,4001],{"class":3961},"();\n",[3452,4003,4004],{"class":3454,"line":3615},[3452,4005,3619],{"emptyLinePlaceholder":3618},[3452,4007,4008,4010,4013,4015,4017,4019,4022],{"class":3454,"line":3622},[3452,4009,3954],{"class":3953},[3452,4011,4012],{"class":3957}," app",[3452,4014,3962],{"class":3961},[3452,4016,3988],{"class":3957},[3452,4018,3516],{"class":3961},[3452,4020,4021],{"class":3458},"Build",[3452,4023,4001],{"class":3961},[3452,4025,4026],{"class":3454,"line":3628},[3452,4027,3619],{"emptyLinePlaceholder":3618},[3452,4029,4030,4033,4035,4038,4040,4043,4046,4049,4052,4055,4057,4060,4062,4065,4067,4070],{"class":3454,"line":3634},[3452,4031,4032],{"class":3957},"app",[3452,4034,3516],{"class":3961},[3452,4036,4037],{"class":3458},"MapGet",[3452,4039,3973],{"class":3961},[3452,4041,4042],{"class":3462},"\"\u002F\"",[3452,4044,4045],{"class":3961},", () => ",[3452,4047,4048],{"class":3953},"new",[3452,4050,4051],{"class":3961}," { ",[3452,4053,4054],{"class":3957},"status",[3452,4056,3962],{"class":3961},[3452,4058,4059],{"class":3462},"\"ok\"",[3452,4061,3491],{"class":3961},[3452,4063,4064],{"class":3957},"version",[3452,4066,3962],{"class":3961},[3452,4068,4069],{"class":3462},"\"1.0.0\"",[3452,4071,4072],{"class":3961}," });\n",[3452,4074,4075],{"class":3454,"line":3640},[3452,4076,3619],{"emptyLinePlaceholder":3618},[3452,4078,4079,4081,4083,4085,4087,4090],{"class":3454,"line":3646},[3452,4080,4032],{"class":3957},[3452,4082,3516],{"class":3961},[3452,4084,4037],{"class":3458},[3452,4086,3973],{"class":3961},[3452,4088,4089],{"class":3462},"\"\u002Fweatherforecast\"",[3452,4091,4092],{"class":3961},", () =>\n",[3452,4094,4095],{"class":3454,"line":3652},[3452,4096,4097],{"class":3961},"{\n",[3452,4099,4100,4103,4106,4108,4110,4113,4116,4118,4121,4123,4126,4128,4131],{"class":3454,"line":3658},[3452,4101,4102],{"class":3953},"    var",[3452,4104,4105],{"class":3957}," summaries",[3452,4107,3962],{"class":3961},[3452,4109,4048],{"class":3953},[3452,4111,4112],{"class":3961},"[] { ",[3452,4114,4115],{"class":3462},"\"Freezing\"",[3452,4117,3491],{"class":3961},[3452,4119,4120],{"class":3462},"\"Cool\"",[3452,4122,3491],{"class":3961},[3452,4124,4125],{"class":3462},"\"Warm\"",[3452,4127,3491],{"class":3961},[3452,4129,4130],{"class":3462},"\"Hot\"",[3452,4132,4133],{"class":3961}," };\n",[3452,4135,4136,4140,4143,4145,4148,4150,4154,4156,4159,4162,4165,4167,4170,4173],{"class":3454,"line":3664},[3452,4137,4139],{"class":4138},"s8xlr","    return",[3452,4141,4142],{"class":3957}," Enumerable",[3452,4144,3516],{"class":3961},[3452,4146,4147],{"class":3458},"Range",[3452,4149,3973],{"class":3961},[3452,4151,4153],{"class":4152},"sJj4R","1",[3452,4155,3491],{"class":3961},[3452,4157,4158],{"class":4152},"5",[3452,4160,4161],{"class":3961},").",[3452,4163,4164],{"class":3458},"Select",[3452,4166,3973],{"class":3961},[3452,4168,4169],{"class":3957},"i",[3452,4171,4172],{"class":3961}," => ",[3452,4174,4175],{"class":3953},"new\n",[3452,4177,4178],{"class":3454,"line":3670},[3452,4179,4180],{"class":3961},"    {\n",[3452,4182,4183,4186,4188,4191,4193,4196,4198,4201,4203,4206,4208,4211,4213,4215],{"class":3454,"line":3676},[3452,4184,4185],{"class":3957},"        Date",[3452,4187,3962],{"class":3961},[3452,4189,4190],{"class":3957},"DateOnly",[3452,4192,3516],{"class":3961},[3452,4194,4195],{"class":3458},"FromDateTime",[3452,4197,3973],{"class":3961},[3452,4199,4200],{"class":3957},"DateTime",[3452,4202,3516],{"class":3961},[3452,4204,4205],{"class":3957},"Now",[3452,4207,3516],{"class":3961},[3452,4209,4210],{"class":3458},"AddDays",[3452,4212,3973],{"class":3961},[3452,4214,4169],{"class":3957},[3452,4216,4217],{"class":3961},")),\n",[3452,4219,4220,4223,4225,4228,4230,4233,4235,4238,4241,4244,4246,4249],{"class":3454,"line":3682},[3452,4221,4222],{"class":3957},"        TemperatureC",[3452,4224,3962],{"class":3961},[3452,4226,4227],{"class":3957},"Random",[3452,4229,3516],{"class":3961},[3452,4231,4232],{"class":3957},"Shared",[3452,4234,3516],{"class":3961},[3452,4236,4237],{"class":3458},"Next",[3452,4239,4240],{"class":3961},"(-",[3452,4242,4243],{"class":4152},"20",[3452,4245,3491],{"class":3961},[3452,4247,4248],{"class":4152},"55",[3452,4250,4251],{"class":3961},"),\n",[3452,4253,4254,4257,4259,4262,4265,4267,4269,4271,4273,4275,4277,4279,4281,4284],{"class":3454,"line":3688},[3452,4255,4256],{"class":3957},"        Summary",[3452,4258,3962],{"class":3961},[3452,4260,4261],{"class":3957},"summaries",[3452,4263,4264],{"class":3961},"[",[3452,4266,4227],{"class":3957},[3452,4268,3516],{"class":3961},[3452,4270,4232],{"class":3957},[3452,4272,3516],{"class":3961},[3452,4274,4237],{"class":3458},[3452,4276,3973],{"class":3961},[3452,4278,4261],{"class":3957},[3452,4280,3516],{"class":3961},[3452,4282,4283],{"class":3957},"Length",[3452,4285,4286],{"class":3961},")]\n",[3452,4288,4289],{"class":3454,"line":3694},[3452,4290,4291],{"class":3961},"    });\n",[3452,4293,4294],{"class":3454,"line":3699},[3452,4295,4296],{"class":3961},"});\n",[3452,4298,4299],{"class":3454,"line":3705},[3452,4300,3619],{"emptyLinePlaceholder":3618},[3452,4302,4303],{"class":3454,"line":3711},[3452,4304,4305],{"class":3469},"\u002F\u002F Health check endpoint — потрібен для ECS health check\n",[3452,4307,4308,4310,4312,4315,4317,4320],{"class":3454,"line":3717},[3452,4309,4032],{"class":3957},[3452,4311,3516],{"class":3961},[3452,4313,4314],{"class":3458},"MapHealthChecks",[3452,4316,3973],{"class":3961},[3452,4318,4319],{"class":3462},"\"\u002Fhealth\"",[3452,4321,3979],{"class":3961},[3452,4323,4324],{"class":3454,"line":3723},[3452,4325,3619],{"emptyLinePlaceholder":3618},[3452,4327,4328,4330,4332,4335],{"class":3454,"line":3729},[3452,4329,4032],{"class":3957},[3452,4331,3516],{"class":3961},[3452,4333,4334],{"class":3458},"Run",[3452,4336,4001],{"class":3961},[3354,4338,4339],{},[3540,4340,4341],{},"Крок 4 — Локальний запуск і перевірка:",[3881,4343,4345,4354,4362,4371,4378],{"title":4344},"dotnet run — локальна перевірка",[3885,4346,4348,3893,4351],{"className":4347},[3454],[3452,4349,3892],{"className":4350},[3891],[3540,4352,4353],{},"cd MyApi && dotnet run",[3885,4355,4357,4361],{"className":4356},[3454],[3452,4358,4360],{"className":4359},[3891],"info:"," Microsoft.Hosting.Lifetime[14]",[3885,4363,4365,4366],{"className":4364},[3454],"    Now listening on: ",[3452,4367,4370],{"className":4368},[4369],"text-blue-400","http:\u002F\u002Flocalhost:5000",[3885,4372,4374,4377],{"className":4373},[3454],[3452,4375,4360],{"className":4376},[3891]," Microsoft.Hosting.Lifetime[0]",[3885,4379,4381],{"className":4380},[3454],"    Application started. Press Ctrl+C to shut down.",[3881,4383,4385,4394],{"title":4384},"curl — перевірка health endpoint",[3885,4386,4388,3893,4391],{"className":4387},[3454],[3452,4389,3892],{"className":4390},[3891],[3540,4392,4393],{},"curl http:\u002F\u002Flocalhost:5000\u002Fhealth",[3885,4395,4397],{"className":4396},[3454],[3452,4398,4400],{"className":4399},[3916],"Healthy",[3354,4402,4403],{},"Проєкт готовий до контейнеризації. Далі — пишемо Dockerfile.",[3518,4405],{},[3573,4407,4409],{"id":4408},"dockerfile-для-net-8-multi-stage-build","Dockerfile для .NET 8 — multi-stage build",[3354,4411,4412],{},[3527,4413],{"alt":4414,"className":4415,"src":4416},"Multi-stage Dockerfile build process SDK stage to runtime stage diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F04.png",[3354,4418,4419,4422],{},[3540,4420,4421],{},"Multi-stage build"," — це техніка написання Dockerfile, яка дозволяє значно зменшити розмір фінального образу. Ідея: використовуємо один образ для збірки (з усіма інструментами розробника) і окремий — мінімальний — для запуску в production.",[3354,4424,4425],{},"Розглянемо детально кожен рядок оптимального Dockerfile для ASP.NET Core 8:",[3442,4427,4431],{"className":4428,"code":4429,"language":4430,"meta":3447,"style":3447},"language-dockerfile shiki shiki-themes light-plus dark-plus dark-plus","# ─── STAGE 1: BUILD ────────────────────────────────────────────────────────────\n# Базовий образ із SDK для збірки (~800 MB)\nFROM mcr.microsoft.com\u002Fdotnet\u002Fsdk:8.0 AS build\n\n# Встановлюємо робочу директорію всередині контейнера\nWORKDIR \u002Fsrc\n\n# Спочатку копіюємо ЛИШЕ .csproj файли і відновлюємо залежності.\n# Це використовує Docker layer caching: якщо .csproj не змінились —\n# команда restore береться з кешу, і збірка прискорюється суттєво.\nCOPY [\"MyApi\u002FMyApi.csproj\", \"MyApi\u002F\"]\nRUN dotnet restore \"MyApi\u002FMyApi.csproj\"\n\n# Тепер копіюємо весь вихідний код\nCOPY . .\n\n# Перейдіть у директорію проєкту\nWORKDIR \"\u002Fsrc\u002FMyApi\"\n\n# Публікуємо Release-версію у директорію \u002Fapp\u002Fpublish\n# -c Release      — конфігурація Release\n# -o \u002Fapp\u002Fpublish — директорія виводу\n# --no-restore    — restore вже виконали вище\nRUN dotnet publish \"MyApi.csproj\" -c Release -o \u002Fapp\u002Fpublish --no-restore\n\n# ─── STAGE 2: RUNTIME ──────────────────────────────────────────────────────────\n# Мінімальний runtime-образ (~200 MB) — набагато менший за SDK\nFROM mcr.microsoft.com\u002Fdotnet\u002Faspnet:8.0 AS final\n\n# Задаємо робочу директорію\nWORKDIR \u002Fapp\n\n# Копіюємо ЛИШЕ опублікований артефакт зі stage build\n# Весь SDK, вихідний код, проміжні файли — залишаються в stage build\n# і НЕ потрапляють у фінальний образ\nCOPY --from=build \u002Fapp\u002Fpublish .\n\n# Вказуємо точку входу\nENTRYPOINT [\"dotnet\", \"MyApi.dll\"]\n","dockerfile",[3449,4432,4433,4438,4443,4457,4461,4466,4474,4478,4483,4488,4493,4512,4523,4527,4532,4539,4543,4548,4555,4559,4564,4569,4574,4579,4592,4596,4601,4606,4618,4622,4627,4635,4640,4646,4652,4658,4666,4671,4677],{"__ignoreMap":3447},[3452,4434,4435],{"class":3454,"line":3455},[3452,4436,4437],{"class":3469},"# ─── STAGE 1: BUILD ────────────────────────────────────────────────────────────\n",[3452,4439,4440],{"class":3454,"line":3473},[3452,4441,4442],{"class":3469},"# Базовий образ із SDK для збірки (~800 MB)\n",[3452,4444,4445,4448,4451,4454],{"class":3454,"line":3609},[3452,4446,4447],{"class":3953},"FROM",[3452,4449,4450],{"class":3961}," mcr.microsoft.com\u002Fdotnet\u002Fsdk:8.0 ",[3452,4452,4453],{"class":3953},"AS",[3452,4455,4456],{"class":3961}," build\n",[3452,4458,4459],{"class":3454,"line":3615},[3452,4460,3619],{"emptyLinePlaceholder":3618},[3452,4462,4463],{"class":3454,"line":3622},[3452,4464,4465],{"class":3469},"# Встановлюємо робочу директорію всередині контейнера\n",[3452,4467,4468,4471],{"class":3454,"line":3628},[3452,4469,4470],{"class":3953},"WORKDIR",[3452,4472,4473],{"class":3961}," \u002Fsrc\n",[3452,4475,4476],{"class":3454,"line":3634},[3452,4477,3619],{"emptyLinePlaceholder":3618},[3452,4479,4480],{"class":3454,"line":3640},[3452,4481,4482],{"class":3469},"# Спочатку копіюємо ЛИШЕ .csproj файли і відновлюємо залежності.\n",[3452,4484,4485],{"class":3454,"line":3646},[3452,4486,4487],{"class":3469},"# Це використовує Docker layer caching: якщо .csproj не змінились —\n",[3452,4489,4490],{"class":3454,"line":3652},[3452,4491,4492],{"class":3469},"# команда restore береться з кешу, і збірка прискорюється суттєво.\n",[3452,4494,4495,4498,4501,4504,4506,4509],{"class":3454,"line":3658},[3452,4496,4497],{"class":3953},"COPY",[3452,4499,4500],{"class":3961}," [",[3452,4502,4503],{"class":3462},"\"MyApi\u002FMyApi.csproj\"",[3452,4505,3491],{"class":3961},[3452,4507,4508],{"class":3462},"\"MyApi\u002F\"",[3452,4510,4511],{"class":3961},"]\n",[3452,4513,4514,4517,4520],{"class":3454,"line":3664},[3452,4515,4516],{"class":3953},"RUN",[3452,4518,4519],{"class":3961}," dotnet restore ",[3452,4521,4522],{"class":3462},"\"MyApi\u002FMyApi.csproj\"\n",[3452,4524,4525],{"class":3454,"line":3670},[3452,4526,3619],{"emptyLinePlaceholder":3618},[3452,4528,4529],{"class":3454,"line":3676},[3452,4530,4531],{"class":3469},"# Тепер копіюємо весь вихідний код\n",[3452,4533,4534,4536],{"class":3454,"line":3682},[3452,4535,4497],{"class":3953},[3452,4537,4538],{"class":3961}," . .\n",[3452,4540,4541],{"class":3454,"line":3688},[3452,4542,3619],{"emptyLinePlaceholder":3618},[3452,4544,4545],{"class":3454,"line":3694},[3452,4546,4547],{"class":3469},"# Перейдіть у директорію проєкту\n",[3452,4549,4550,4552],{"class":3454,"line":3699},[3452,4551,4470],{"class":3953},[3452,4553,4554],{"class":3462}," \"\u002Fsrc\u002FMyApi\"\n",[3452,4556,4557],{"class":3454,"line":3705},[3452,4558,3619],{"emptyLinePlaceholder":3618},[3452,4560,4561],{"class":3454,"line":3711},[3452,4562,4563],{"class":3469},"# Публікуємо Release-версію у директорію \u002Fapp\u002Fpublish\n",[3452,4565,4566],{"class":3454,"line":3717},[3452,4567,4568],{"class":3469},"# -c Release      — конфігурація Release\n",[3452,4570,4571],{"class":3454,"line":3723},[3452,4572,4573],{"class":3469},"# -o \u002Fapp\u002Fpublish — директорія виводу\n",[3452,4575,4576],{"class":3454,"line":3729},[3452,4577,4578],{"class":3469},"# --no-restore    — restore вже виконали вище\n",[3452,4580,4581,4583,4586,4589],{"class":3454,"line":3734},[3452,4582,4516],{"class":3953},[3452,4584,4585],{"class":3961}," dotnet publish ",[3452,4587,4588],{"class":3462},"\"MyApi.csproj\"",[3452,4590,4591],{"class":3961}," -c Release -o \u002Fapp\u002Fpublish --no-restore\n",[3452,4593,4594],{"class":3454,"line":3740},[3452,4595,3619],{"emptyLinePlaceholder":3618},[3452,4597,4598],{"class":3454,"line":3746},[3452,4599,4600],{"class":3469},"# ─── STAGE 2: RUNTIME ──────────────────────────────────────────────────────────\n",[3452,4602,4603],{"class":3454,"line":3752},[3452,4604,4605],{"class":3469},"# Мінімальний runtime-образ (~200 MB) — набагато менший за SDK\n",[3452,4607,4608,4610,4613,4615],{"class":3454,"line":3758},[3452,4609,4447],{"class":3953},[3452,4611,4612],{"class":3961}," mcr.microsoft.com\u002Fdotnet\u002Faspnet:8.0 ",[3452,4614,4453],{"class":3953},[3452,4616,4617],{"class":3961}," final\n",[3452,4619,4620],{"class":3454,"line":3764},[3452,4621,3619],{"emptyLinePlaceholder":3618},[3452,4623,4624],{"class":3454,"line":3769},[3452,4625,4626],{"class":3469},"# Задаємо робочу директорію\n",[3452,4628,4630,4632],{"class":3454,"line":4629},31,[3452,4631,4470],{"class":3953},[3452,4633,4634],{"class":3961}," \u002Fapp\n",[3452,4636,4638],{"class":3454,"line":4637},32,[3452,4639,3619],{"emptyLinePlaceholder":3618},[3452,4641,4643],{"class":3454,"line":4642},33,[3452,4644,4645],{"class":3469},"# Копіюємо ЛИШЕ опублікований артефакт зі stage build\n",[3452,4647,4649],{"class":3454,"line":4648},34,[3452,4650,4651],{"class":3469},"# Весь SDK, вихідний код, проміжні файли — залишаються в stage build\n",[3452,4653,4655],{"class":3454,"line":4654},35,[3452,4656,4657],{"class":3469},"# і НЕ потрапляють у фінальний образ\n",[3452,4659,4661,4663],{"class":3454,"line":4660},36,[3452,4662,4497],{"class":3953},[3452,4664,4665],{"class":3961}," --from=build \u002Fapp\u002Fpublish .\n",[3452,4667,4669],{"class":3454,"line":4668},37,[3452,4670,3619],{"emptyLinePlaceholder":3618},[3452,4672,4674],{"class":3454,"line":4673},38,[3452,4675,4676],{"class":3469},"# Вказуємо точку входу\n",[3452,4678,4680,4683,4685,4688,4690,4693],{"class":3454,"line":4679},39,[3452,4681,4682],{"class":3953},"ENTRYPOINT",[3452,4684,4500],{"class":3961},[3452,4686,4687],{"class":3462},"\"dotnet\"",[3452,4689,3491],{"class":3961},[3452,4691,4692],{"class":3462},"\"MyApi.dll\"",[3452,4694,4511],{"class":3961},[3354,4696,4697],{},"Завдяки multi-stage build:",[4699,4700,4701,4708,4714],"ul",{},[4702,4703,4704,4707],"li",{},[3540,4705,4706],{},"Build image:"," ~800 MB (SDK + вихідний код)",[4702,4709,4710,4713],{},[3540,4711,4712],{},"Final image:"," ~200 MB (лише Runtime + скомпільований застосунок)",[4702,4715,4716,4717,4720],{},"Вихідний код ",[3540,4718,4719],{},"не потрапляє"," у production образ — важливо для безпеки",[3573,4722,4724],{"id":4723},"dockerignore-що-не-копіювати-в-образ",".dockerignore — що не копіювати в образ",[3354,4726,4727,4728,4731,4732,4735],{},"Файл ",[3449,4729,4730],{},".dockerignore"," (аналог ",[3449,4733,4734],{},".gitignore",") вказує Docker, які файли ігнорувати при копіюванні:",[3442,4737,4741],{"className":4738,"code":4739,"language":4740,"meta":3447,"style":3447},"language-dockerignore shiki shiki-themes light-plus dark-plus dark-plus","# Директорії збірки — вони будуть перезбудовані всередині контейнера\n**\u002Fbin\u002F\n**\u002Fobj\u002F\n\n# Git-директорія та файли\n.git\n.gitignore\n\n# Налаштування IDE\n.vs\u002F\n.rider\u002F\n*.user\n\n# Docker-файли самі по собі\nDockerfile\n.dockerignore\n\n# Локальні секрети та конфігурації\n**\u002Fappsettings.Development.json\n**\u002Fappsettings.Local.json\n**\u002F*.pfx\n**\u002F.env\n","dockerignore",[3449,4742,4743,4748,4753,4758,4762,4767,4772,4777,4781,4786,4791,4796,4801,4805,4810,4815,4820,4824,4829,4834,4839,4844],{"__ignoreMap":3447},[3452,4744,4745],{"class":3454,"line":3455},[3452,4746,4747],{},"# Директорії збірки — вони будуть перезбудовані всередині контейнера\n",[3452,4749,4750],{"class":3454,"line":3473},[3452,4751,4752],{},"**\u002Fbin\u002F\n",[3452,4754,4755],{"class":3454,"line":3609},[3452,4756,4757],{},"**\u002Fobj\u002F\n",[3452,4759,4760],{"class":3454,"line":3615},[3452,4761,3619],{"emptyLinePlaceholder":3618},[3452,4763,4764],{"class":3454,"line":3622},[3452,4765,4766],{},"# Git-директорія та файли\n",[3452,4768,4769],{"class":3454,"line":3628},[3452,4770,4771],{},".git\n",[3452,4773,4774],{"class":3454,"line":3634},[3452,4775,4776],{},".gitignore\n",[3452,4778,4779],{"class":3454,"line":3640},[3452,4780,3619],{"emptyLinePlaceholder":3618},[3452,4782,4783],{"class":3454,"line":3646},[3452,4784,4785],{},"# Налаштування IDE\n",[3452,4787,4788],{"class":3454,"line":3652},[3452,4789,4790],{},".vs\u002F\n",[3452,4792,4793],{"class":3454,"line":3658},[3452,4794,4795],{},".rider\u002F\n",[3452,4797,4798],{"class":3454,"line":3664},[3452,4799,4800],{},"*.user\n",[3452,4802,4803],{"class":3454,"line":3670},[3452,4804,3619],{"emptyLinePlaceholder":3618},[3452,4806,4807],{"class":3454,"line":3676},[3452,4808,4809],{},"# Docker-файли самі по собі\n",[3452,4811,4812],{"class":3454,"line":3682},[3452,4813,4814],{},"Dockerfile\n",[3452,4816,4817],{"class":3454,"line":3688},[3452,4818,4819],{},".dockerignore\n",[3452,4821,4822],{"class":3454,"line":3694},[3452,4823,3619],{"emptyLinePlaceholder":3618},[3452,4825,4826],{"class":3454,"line":3699},[3452,4827,4828],{},"# Локальні секрети та конфігурації\n",[3452,4830,4831],{"class":3454,"line":3705},[3452,4832,4833],{},"**\u002Fappsettings.Development.json\n",[3452,4835,4836],{"class":3454,"line":3711},[3452,4837,4838],{},"**\u002Fappsettings.Local.json\n",[3452,4840,4841],{"class":3454,"line":3717},[3452,4842,4843],{},"**\u002F*.pfx\n",[3452,4845,4846],{"class":3454,"line":3723},[3452,4847,4848],{},"**\u002F.env\n",[3518,4850],{},[3573,4852,4854],{"id":4853},"практика-push-образу-в-amazon-ecr","Практика: Push образу в Amazon ECR",[3354,4856,4857],{},[3527,4858],{"alt":4859,"className":4860,"src":4861},"Docker push workflow from local to ECR repository authentication and upload",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F05.png",[3354,4863,4864],{},"Після написання Dockerfile — виконуємо п'ять послідовних операцій для відправки образу в ECR.",[3354,4866,4867,4870,4871,4874,4875,4878],{},[3540,4868,4869],{},"Крок 1 — Аутентифікація у ECR."," AWS ECR не зберігає постійних паролів Docker Hub. Натомість використовуються тимчасові токени, дійсні 12 годин. Команда ",[3449,4872,4873],{},"get-login-password"," отримує токен і через pipe передає його стандартному ",[3449,4876,4877],{},"docker login",":",[3881,4880,4882,4891,4897,4903,4909],{"title":4881},"aws ecr get-login-password — аутентифікація",[3885,4883,4885,3893,4888],{"className":4884},[3454],[3452,4886,3892],{"className":4887},[3891],[3540,4889,4890],{},"aws ecr get-login-password \\",[3885,4892,3900,4894],{"className":4893},[3454],[3540,4895,4896],{},"--region eu-central-1 \\",[3885,4898,3900,4900],{"className":4899},[3454],[3540,4901,4902],{},"| docker login --username AWS \\",[3885,4904,3900,4906],{"className":4905},[3454],[3540,4907,4908],{},"--password-stdin 123456789012.dkr.ecr.eu-central-1.amazonaws.com",[3885,4910,4912],{"className":4911},[3454],[3452,4913,4915],{"className":4914},[3916],"Login Succeeded",[3354,4917,4918,4921],{},[3540,4919,4920],{},"Крок 2 — Створення репозиторію у ECR"," (виконується один раз; якщо репозиторій вже існує — пропустіть):",[3881,4923,4925,4934,4940,4945,4951,4955,4959,4963,4967,4971,4980,4984,4988],{"title":4924},"aws ecr create-repository — відповідь",[3885,4926,4928,3893,4931],{"className":4927},[3454],[3452,4929,3892],{"className":4930},[3891],[3540,4932,4933],{},"aws ecr create-repository \\",[3885,4935,3900,4937],{"className":4936},[3454],[3540,4938,4939],{},"--repository-name my-api \\",[3885,4941,3900,4943],{"className":4942},[3454],[3540,4944,4896],{},[3885,4946,3900,4948],{"className":4947},[3454],[3540,4949,4950],{},"--image-scanning-configuration scanOnPush=true",[3885,4952,4954],{"className":4953},[3454],"{",[3885,4956,4958],{"className":4957},[3454],"  \"repository\": {",[3885,4960,4962],{"className":4961},[3454],"    \"repositoryArn\": \"arn:aws:ecr:eu-central-1:123456789012:repository\u002Fmy-api\",",[3885,4964,4966],{"className":4965},[3454],"    \"registryId\": \"123456789012\",",[3885,4968,4970],{"className":4969},[3454],"    \"repositoryName\": \"my-api\",",[3885,4972,4974,4975,4979],{"className":4973},[3454],"    ",[3452,4976,4978],{"className":4977},[3916],"\"repositoryUri\": \"123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fmy-api\"",",",[3885,4981,4983],{"className":4982},[3454],"    \"imageScanningConfiguration\": { \"scanOnPush\": true }",[3885,4985,4987],{"className":4986},[3454],"  }",[3885,4989,4991],{"className":4990},[3454],"}",[3354,4993,4994,4995,4998],{},"Значення ",[3449,4996,4997],{},"repositoryUri"," — адреса вашого репозиторію в ECR. Саме цей URI використовується у наступних двох кроках.",[3354,5000,5001],{},[3540,5002,5003],{},"Крок 3 — Збірка та теґування образу:",[3881,5005,5007,5016,5020,5028,5036],{"title":5006},"docker build",[3885,5008,5010,3893,5013],{"className":5009},[3454],[3452,5011,3892],{"className":5012},[3891],[3540,5014,5015],{},"docker build -t my-api:latest .",[3885,5017,5019],{"className":5018},[3454],"[+] Building 38.5s (12\u002F12) FINISHED",[3885,5021,5023,5024],{"className":5022},[3454]," => [build 3\u002F5] RUN dotnet restore \"MyApi.csproj\"          ",[3452,5025,5027],{"className":5026},[3891],"10.2s",[3885,5029,5031,5032],{"className":5030},[3454]," => [build 5\u002F5] RUN dotnet publish \"MyApi.csproj\" -c Release -o \u002Fapp\u002Fpublish  ",[3452,5033,5035],{"className":5034},[3891],"18.1s",[3885,5037,5039],{"className":5038},[3454],[3452,5040,5042],{"className":5041},[3916]," => => writing image sha256:a1b2c3d4e5f6...  0.1s",[3442,5044,5046],{"className":3444,"code":5045,"language":3446,"meta":3447,"style":3447},"# Теґуємо образ адресою ECR репозиторію\ndocker tag my-api:latest \\\n    123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fmy-api:latest\n",[3449,5047,5048,5053,5068],{"__ignoreMap":3447},[3452,5049,5050],{"class":3454,"line":3455},[3452,5051,5052],{"class":3469},"# Теґуємо образ адресою ECR репозиторію\n",[3452,5054,5055,5058,5061,5064],{"class":3454,"line":3473},[3452,5056,5057],{"class":3458},"docker",[3452,5059,5060],{"class":3462}," tag",[3452,5062,5063],{"class":3462}," my-api:latest",[3452,5065,5067],{"class":5066},"sjcCO"," \\\n",[3452,5069,5070],{"class":3454,"line":3609},[3452,5071,5072],{"class":3462},"    123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fmy-api:latest\n",[3354,5074,5075],{},[3540,5076,5077],{},"Крок 4 — Завантаження образу в ECR:",[3881,5079,5081,5090,5094,5098,5102,5106],{"title":5080},"docker push — завантаження в ECR",[3885,5082,5084,3893,5087],{"className":5083},[3454],[3452,5085,3892],{"className":5086},[3891],[3540,5088,5089],{},"docker push 123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fmy-api:latest",[3885,5091,5093],{"className":5092},[3454],"The push refers to repository [123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fmy-api]",[3885,5095,5097],{"className":5096},[3454],"8c2d1e5f9a3b: Pushing  45.23 MB\u002F120.5 MB",[3885,5099,5101],{"className":5100},[3454],"3f4a8b9c1d2e: Pushed",[3885,5103,5105],{"className":5104},[3454],"1a4f7e2c8b6d: Pushed",[3885,5107,5109],{"className":5108},[3454],[3452,5110,5112],{"className":5111},[3916],"latest: digest: sha256:abc123def456... size: 1847",[5114,5115,5116,5117,5119],"tip",{},"Зверніть увагу на ",[3449,5118,4950],{},". ECR автоматично сканує кожен завантажений образ на відомі CVE (Common Vulnerabilities and Exposures) за допомогою Amazon Inspector. Це безкоштовна перша лінія захисту від вразливостей у ваших залежностях.",[3518,5121],{},[3349,5123,5125],{"id":5124},"amazon-ecs-elastic-container-service","Amazon ECS — Elastic Container Service",[3354,5127,5128],{},[3527,5129],{"alt":5130,"className":5131,"src":5132},"Amazon ECS Elastic Container Service orchestration with tasks services and clusters",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F06.jpg",[3354,5134,5135,5138],{},[3540,5136,5137],{},"Amazon Elastic Container Service (ECS)"," — це повністю керований оркестратор контейнерів від AWS. Якщо ECR — це «склад» для образів, то ECS — це «виробничий цех», де ці образи запускаються, масштабуються та оновлюються.",[3354,5140,5141,5144],{},[3540,5142,5143],{},"Оркестратор контейнерів"," — це система, яка відповідає за:",[4699,5146,5147,5150,5153,5156,5159],{},[4702,5148,5149],{},"Запуск контейнерів на доступних серверах",[4702,5151,5152],{},"Перезапуск контейнерів у разі збою",[4702,5154,5155],{},"Масштабування (запуск більше копій при зростанні навантаження)",[4702,5157,5158],{},"Rolling updates — оновлення без зупинки сервісу",[4702,5160,5161],{},"Балансування трафіку між копіями контейнера",[3573,5163,5165],{"id":5164},"три-ключові-сутності-ecs","Три ключові сутності ECS",[3354,5167,5168],{},"ECS оперує трьома основними концепціями. Розберемо їх через аналогію з рестораном.",[3354,5170,5171,5174],{},[3540,5172,5173],{},"Task Definition"," — це рецепт страви. Він описує: який образ використовувати, скільки CPU і RAM виділити, які змінні середовища передати, де зберігати логи, які порти відкрити. Task Definition є незмінним шаблоном — кожна зміна створює нову версію (revision).",[3354,5176,5177,5180],{},[3540,5178,5179],{},"Task"," — це конкретна приготована страва. Один запущений екземпляр Task Definition. Контейнер, що реально виконується прямо зараз.",[3354,5182,5183,5186],{},[3540,5184,5185],{},"Service"," — це менеджер, який гарантує, що завжди є рівно N порцій страви готових до подачі. Якщо одна «страва» зіпсувалась (контейнер впав) — Service автоматично замовить нову. Він також керує rolling updates і підключає Tasks до Load Balancer.",[3354,5188,5189,5192],{},[3540,5190,5191],{},"Cluster"," — це сам ресторан: фізичне місце, де все це відбувається. Логічна група, яка об'єднує всі Tasks і Services.",[3573,5194,5196],{"id":5195},"lifecycle-task-від-запиту-до-зупинки","Lifecycle Task: від запиту до зупинки",[3354,5198,5199,5200,5203],{},"Розуміння ",[3540,5201,5202],{},"станів Task"," є практично важливим: якщо Task «застряг» у певному стані, правильна діагностика можлива лише тоді, коли ви розумієте, що в ньому відбувається.",[3358,5205,5206,5216],{},[3361,5207,5208],{},[3364,5209,5210,5213],{},[3367,5211,5212],{},"Стан",[3367,5214,5215],{},"Що відбувається",[3377,5217,5218,5228,5238,5250,5260,5273,5283],{},[3364,5219,5220,5225],{},[3382,5221,5222],{},[3449,5223,5224],{},"PROVISIONING",[3382,5226,5227],{},"Fargate виділяє ізольоване обчислювальне середовище, ENI",[3364,5229,5230,5235],{},[3382,5231,5232],{},[3449,5233,5234],{},"PENDING",[3382,5236,5237],{},"Завантажується Docker-образ з ECR у виділене середовище",[3364,5239,5240,5245],{},[3382,5241,5242],{},[3449,5243,5244],{},"ACTIVATING",[3382,5246,5247,5248],{},"Запускаються контейнери, виконується ",[3449,5249,4682],{},[3364,5251,5252,5257],{},[3382,5253,5254],{},[3449,5255,5256],{},"RUNNING",[3382,5258,5259],{},"Контейнер працює; ECS виконує health check-и",[3364,5261,5262,5267],{},[3382,5263,5264],{},[3449,5265,5266],{},"DEACTIVATING",[3382,5268,5269,5270],{},"Починається graceful shutdown: Task отримує сигнал ",[3449,5271,5272],{},"SIGTERM",[3364,5274,5275,5280],{},[3382,5276,5277],{},[3449,5278,5279],{},"STOPPING",[3382,5281,5282],{},"Очікування завершення застосунку (до 30 сек за замовчуванням)",[3364,5284,5285,5290],{},[3382,5286,5287],{},[3449,5288,5289],{},"STOPPED",[3382,5291,5292,5293],{},"Task завершено; причина зупинки зафіксована в ",[3449,5294,5295],{},"stoppedReason",[3354,5297,5298,5303,5304,5307],{},[3540,5299,5300,5301,4878],{},"Типові причини застрягання в ",[3449,5302,5234],{}," образ не знайдено в ECR (невірний URI або тег), Task Execution Role не має прав на ",[3449,5305,5306],{},"ecr:GetDownloadUrlForLayer",", Task у приватній підмережі без NAT Gateway.",[3354,5309,5310,5313,5314,5317,5318,3491,5321,3491,5324,5327],{},[3540,5311,5312],{},"Ревізії Task Definition."," Кожна зміна Task Definition (навіть однієї змінної середовища) створює нову ",[3540,5315,5316],{},"revision"," — наприклад, ",[3449,5319,5320],{},"my-api:1",[3449,5322,5323],{},"my-api:2",[3449,5325,5326],{},"my-api:3",". Попередні ревізії зберігаються назавжди і не видаляються автоматично. ECS Service завжди посилається на конкретну ревізію, що гарантує точну відтворюваність середовища при кожному запуску Task.",[3588,5329,5330],{},[3442,5331,5333],{"className":3592,"code":5332,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"ECS Cluster: production\" #e9ecef {\n\n    rectangle \"Task Definition: my-api:v3\" as TD #dbeafe\n\n    note right of TD\n      Image: 123456789012.dkr.ecr...\u002Fmy-api:v1.2.3\n      CPU: 256 (.25 vCPU)\n      Memory: 512 MB\n      Port: 8080\n      Env: ASPNETCORE_ENVIRONMENT=Production\n    end note\n\n    package \"ECS Service: my-api-service\" as Service #d1fae5 {\n\n        rectangle \"Task 1\" as T1 #bbf7d0\n        rectangle \"Task 2\" as T2 #bbf7d0\n        rectangle \"Task 3\" as T3 #bbf7d0\n    }\n\n    note top of Service\n      Desired count: 3 Tasks\n      Rolling update: max 200%, min 50%\n      ALB target group\n    end note\n\n    TD -down-> Service : \"запускає Tasks за шаблоном\"\n}\n\nrectangle \"Application Load Balancer\" as ALB #fef3c7\nALB -right-> T1\nALB -right-> T2\nALB -right-> T3\n@enduml\n",[3449,5334,5335,5339,5343,5347,5351,5356,5360,5365,5369,5374,5379,5384,5389,5394,5399,5404,5408,5413,5417,5422,5427,5432,5436,5440,5445,5450,5455,5460,5464,5468,5473,5477,5481,5486,5491,5496,5501],{"__ignoreMap":3447},[3452,5336,5337],{"class":3454,"line":3455},[3452,5338,3601],{},[3452,5340,5341],{"class":3454,"line":3473},[3452,5342,3606],{},[3452,5344,5345],{"class":3454,"line":3609},[3452,5346,3612],{},[3452,5348,5349],{"class":3454,"line":3615},[3452,5350,3619],{"emptyLinePlaceholder":3618},[3452,5352,5353],{"class":3454,"line":3622},[3452,5354,5355],{},"package \"ECS Cluster: production\" #e9ecef {\n",[3452,5357,5358],{"class":3454,"line":3628},[3452,5359,3619],{"emptyLinePlaceholder":3618},[3452,5361,5362],{"class":3454,"line":3634},[3452,5363,5364],{},"    rectangle \"Task Definition: my-api:v3\" as TD #dbeafe\n",[3452,5366,5367],{"class":3454,"line":3640},[3452,5368,3619],{"emptyLinePlaceholder":3618},[3452,5370,5371],{"class":3454,"line":3646},[3452,5372,5373],{},"    note right of TD\n",[3452,5375,5376],{"class":3454,"line":3652},[3452,5377,5378],{},"      Image: 123456789012.dkr.ecr...\u002Fmy-api:v1.2.3\n",[3452,5380,5381],{"class":3454,"line":3658},[3452,5382,5383],{},"      CPU: 256 (.25 vCPU)\n",[3452,5385,5386],{"class":3454,"line":3664},[3452,5387,5388],{},"      Memory: 512 MB\n",[3452,5390,5391],{"class":3454,"line":3670},[3452,5392,5393],{},"      Port: 8080\n",[3452,5395,5396],{"class":3454,"line":3676},[3452,5397,5398],{},"      Env: ASPNETCORE_ENVIRONMENT=Production\n",[3452,5400,5401],{"class":3454,"line":3682},[3452,5402,5403],{},"    end note\n",[3452,5405,5406],{"class":3454,"line":3688},[3452,5407,3619],{"emptyLinePlaceholder":3618},[3452,5409,5410],{"class":3454,"line":3694},[3452,5411,5412],{},"    package \"ECS Service: my-api-service\" as Service #d1fae5 {\n",[3452,5414,5415],{"class":3454,"line":3699},[3452,5416,3619],{"emptyLinePlaceholder":3618},[3452,5418,5419],{"class":3454,"line":3705},[3452,5420,5421],{},"        rectangle \"Task 1\" as T1 #bbf7d0\n",[3452,5423,5424],{"class":3454,"line":3711},[3452,5425,5426],{},"        rectangle \"Task 2\" as T2 #bbf7d0\n",[3452,5428,5429],{"class":3454,"line":3717},[3452,5430,5431],{},"        rectangle \"Task 3\" as T3 #bbf7d0\n",[3452,5433,5434],{"class":3454,"line":3723},[3452,5435,3655],{},[3452,5437,5438],{"class":3454,"line":3729},[3452,5439,3619],{"emptyLinePlaceholder":3618},[3452,5441,5442],{"class":3454,"line":3734},[3452,5443,5444],{},"    note top of Service\n",[3452,5446,5447],{"class":3454,"line":3740},[3452,5448,5449],{},"      Desired count: 3 Tasks\n",[3452,5451,5452],{"class":3454,"line":3746},[3452,5453,5454],{},"      Rolling update: max 200%, min 50%\n",[3452,5456,5457],{"class":3454,"line":3752},[3452,5458,5459],{},"      ALB target group\n",[3452,5461,5462],{"class":3454,"line":3758},[3452,5463,5403],{},[3452,5465,5466],{"class":3454,"line":3764},[3452,5467,3619],{"emptyLinePlaceholder":3618},[3452,5469,5470],{"class":3454,"line":3769},[3452,5471,5472],{},"    TD -down-> Service : \"запускає Tasks за шаблоном\"\n",[3452,5474,5475],{"class":3454,"line":4629},[3452,5476,3691],{},[3452,5478,5479],{"class":3454,"line":4637},[3452,5480,3619],{"emptyLinePlaceholder":3618},[3452,5482,5483],{"class":3454,"line":4642},[3452,5484,5485],{},"rectangle \"Application Load Balancer\" as ALB #fef3c7\n",[3452,5487,5488],{"class":3454,"line":4648},[3452,5489,5490],{},"ALB -right-> T1\n",[3452,5492,5493],{"class":3454,"line":4654},[3452,5494,5495],{},"ALB -right-> T2\n",[3452,5497,5498],{"class":3454,"line":4660},[3452,5499,5500],{},"ALB -right-> T3\n",[3452,5502,5503],{"class":3454,"line":4668},[3452,5504,3772],{},[3573,5506,5508],{"id":5507},"task-definition-детальна-конфігурація","Task Definition: детальна конфігурація",[3354,5510,5511],{},[3527,5512],{"alt":5513,"className":5514,"src":5515},"ECS Task Definition JSON configuration fields explained diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F07.png",[3354,5517,5518],{},"Task Definition — це JSON-документ, але AWS Console надає зручний конструктор. Розберемо ключові поля:",[3442,5520,5524],{"className":5521,"code":5522,"language":5523,"meta":3447,"style":3447},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\n    \"family\": \"my-api\",\n    \"networkMode\": \"awsvpc\",\n    \"requiresCompatibilities\": [\"FARGATE\"],\n    \"cpu\": \"256\",\n    \"memory\": \"512\",\n    \"executionRoleArn\": \"arn:aws:iam::123456789012:role\u002FecsTaskExecutionRole\",\n    \"taskRoleArn\": \"arn:aws:iam::123456789012:role\u002Fmy-api-task-role\",\n    \"containerDefinitions\": [\n        {\n            \"name\": \"my-api\",\n            \"image\": \"123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fmy-api:v1.2.3\",\n            \"portMappings\": [\n                {\n                    \"containerPort\": 8080,\n                    \"protocol\": \"tcp\"\n                }\n            ],\n            \"environment\": [\n                { \"name\": \"ASPNETCORE_ENVIRONMENT\", \"value\": \"Production\" },\n                { \"name\": \"ASPNETCORE_URLS\", \"value\": \"http:\u002F\u002F+:8080\" }\n            ],\n            \"secrets\": [\n                {\n                    \"name\": \"ConnectionStrings__DefaultConnection\",\n                    \"valueFrom\": \"arn:aws:secretsmanager:eu-central-1:123456789012:secret:prod\u002Fdb-connection\"\n                }\n            ],\n            \"logConfiguration\": {\n                \"logDriver\": \"awslogs\",\n                \"options\": {\n                    \"awslogs-group\": \"\u002Fecs\u002Fmy-api\",\n                    \"awslogs-region\": \"eu-central-1\",\n                    \"awslogs-stream-prefix\": \"ecs\"\n                }\n            },\n            \"healthCheck\": {\n                \"command\": [\"CMD-SHELL\", \"curl -f http:\u002F\u002Flocalhost:8080\u002Fhealth || exit 1\"],\n                \"interval\": 30,\n                \"timeout\": 5,\n                \"retries\": 3,\n                \"startPeriod\": 60\n            }\n        }\n    ]\n}\n","json",[3449,5525,5526,5530,5545,5557,5571,5583,5595,5607,5619,5627,5632,5643,5655,5662,5667,5679,5689,5694,5699,5706,5732,5755,5759,5766,5770,5782,5792,5796,5800,5808,5820,5827,5839,5851,5861,5865,5870,5877,5894,5906,5918,5931,5942,5948,5954,5960],{"__ignoreMap":3447},[3452,5527,5528],{"class":3454,"line":3455},[3452,5529,4097],{"class":3961},[3452,5531,5532,5536,5539,5542],{"class":3454,"line":3473},[3452,5533,5535],{"class":5534},"sLwNe","    \"family\"",[3452,5537,5538],{"class":3961},": ",[3452,5540,5541],{"class":3462},"\"my-api\"",[3452,5543,5544],{"class":3961},",\n",[3452,5546,5547,5550,5552,5555],{"class":3454,"line":3609},[3452,5548,5549],{"class":5534},"    \"networkMode\"",[3452,5551,5538],{"class":3961},[3452,5553,5554],{"class":3462},"\"awsvpc\"",[3452,5556,5544],{"class":3961},[3452,5558,5559,5562,5565,5568],{"class":3454,"line":3615},[3452,5560,5561],{"class":5534},"    \"requiresCompatibilities\"",[3452,5563,5564],{"class":3961},": [",[3452,5566,5567],{"class":3462},"\"FARGATE\"",[3452,5569,5570],{"class":3961},"],\n",[3452,5572,5573,5576,5578,5581],{"class":3454,"line":3622},[3452,5574,5575],{"class":5534},"    \"cpu\"",[3452,5577,5538],{"class":3961},[3452,5579,5580],{"class":3462},"\"256\"",[3452,5582,5544],{"class":3961},[3452,5584,5585,5588,5590,5593],{"class":3454,"line":3628},[3452,5586,5587],{"class":5534},"    \"memory\"",[3452,5589,5538],{"class":3961},[3452,5591,5592],{"class":3462},"\"512\"",[3452,5594,5544],{"class":3961},[3452,5596,5597,5600,5602,5605],{"class":3454,"line":3634},[3452,5598,5599],{"class":5534},"    \"executionRoleArn\"",[3452,5601,5538],{"class":3961},[3452,5603,5604],{"class":3462},"\"arn:aws:iam::123456789012:role\u002FecsTaskExecutionRole\"",[3452,5606,5544],{"class":3961},[3452,5608,5609,5612,5614,5617],{"class":3454,"line":3640},[3452,5610,5611],{"class":5534},"    \"taskRoleArn\"",[3452,5613,5538],{"class":3961},[3452,5615,5616],{"class":3462},"\"arn:aws:iam::123456789012:role\u002Fmy-api-task-role\"",[3452,5618,5544],{"class":3961},[3452,5620,5621,5624],{"class":3454,"line":3646},[3452,5622,5623],{"class":5534},"    \"containerDefinitions\"",[3452,5625,5626],{"class":3961},": [\n",[3452,5628,5629],{"class":3454,"line":3652},[3452,5630,5631],{"class":3961},"        {\n",[3452,5633,5634,5637,5639,5641],{"class":3454,"line":3658},[3452,5635,5636],{"class":5534},"            \"name\"",[3452,5638,5538],{"class":3961},[3452,5640,5541],{"class":3462},[3452,5642,5544],{"class":3961},[3452,5644,5645,5648,5650,5653],{"class":3454,"line":3664},[3452,5646,5647],{"class":5534},"            \"image\"",[3452,5649,5538],{"class":3961},[3452,5651,5652],{"class":3462},"\"123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fmy-api:v1.2.3\"",[3452,5654,5544],{"class":3961},[3452,5656,5657,5660],{"class":3454,"line":3670},[3452,5658,5659],{"class":5534},"            \"portMappings\"",[3452,5661,5626],{"class":3961},[3452,5663,5664],{"class":3454,"line":3676},[3452,5665,5666],{"class":3961},"                {\n",[3452,5668,5669,5672,5674,5677],{"class":3454,"line":3682},[3452,5670,5671],{"class":5534},"                    \"containerPort\"",[3452,5673,5538],{"class":3961},[3452,5675,5676],{"class":4152},"8080",[3452,5678,5544],{"class":3961},[3452,5680,5681,5684,5686],{"class":3454,"line":3688},[3452,5682,5683],{"class":5534},"                    \"protocol\"",[3452,5685,5538],{"class":3961},[3452,5687,5688],{"class":3462},"\"tcp\"\n",[3452,5690,5691],{"class":3454,"line":3694},[3452,5692,5693],{"class":3961},"                }\n",[3452,5695,5696],{"class":3454,"line":3699},[3452,5697,5698],{"class":3961},"            ],\n",[3452,5700,5701,5704],{"class":3454,"line":3705},[3452,5702,5703],{"class":5534},"            \"environment\"",[3452,5705,5626],{"class":3961},[3452,5707,5708,5711,5714,5716,5719,5721,5724,5726,5729],{"class":3454,"line":3711},[3452,5709,5710],{"class":3961},"                { ",[3452,5712,5713],{"class":5534},"\"name\"",[3452,5715,5538],{"class":3961},[3452,5717,5718],{"class":3462},"\"ASPNETCORE_ENVIRONMENT\"",[3452,5720,3491],{"class":3961},[3452,5722,5723],{"class":5534},"\"value\"",[3452,5725,5538],{"class":3961},[3452,5727,5728],{"class":3462},"\"Production\"",[3452,5730,5731],{"class":3961}," },\n",[3452,5733,5734,5736,5738,5740,5743,5745,5747,5749,5752],{"class":3454,"line":3717},[3452,5735,5710],{"class":3961},[3452,5737,5713],{"class":5534},[3452,5739,5538],{"class":3961},[3452,5741,5742],{"class":3462},"\"ASPNETCORE_URLS\"",[3452,5744,3491],{"class":3961},[3452,5746,5723],{"class":5534},[3452,5748,5538],{"class":3961},[3452,5750,5751],{"class":3462},"\"http:\u002F\u002F+:8080\"",[3452,5753,5754],{"class":3961}," }\n",[3452,5756,5757],{"class":3454,"line":3723},[3452,5758,5698],{"class":3961},[3452,5760,5761,5764],{"class":3454,"line":3729},[3452,5762,5763],{"class":5534},"            \"secrets\"",[3452,5765,5626],{"class":3961},[3452,5767,5768],{"class":3454,"line":3734},[3452,5769,5666],{"class":3961},[3452,5771,5772,5775,5777,5780],{"class":3454,"line":3740},[3452,5773,5774],{"class":5534},"                    \"name\"",[3452,5776,5538],{"class":3961},[3452,5778,5779],{"class":3462},"\"ConnectionStrings__DefaultConnection\"",[3452,5781,5544],{"class":3961},[3452,5783,5784,5787,5789],{"class":3454,"line":3746},[3452,5785,5786],{"class":5534},"                    \"valueFrom\"",[3452,5788,5538],{"class":3961},[3452,5790,5791],{"class":3462},"\"arn:aws:secretsmanager:eu-central-1:123456789012:secret:prod\u002Fdb-connection\"\n",[3452,5793,5794],{"class":3454,"line":3752},[3452,5795,5693],{"class":3961},[3452,5797,5798],{"class":3454,"line":3758},[3452,5799,5698],{"class":3961},[3452,5801,5802,5805],{"class":3454,"line":3764},[3452,5803,5804],{"class":5534},"            \"logConfiguration\"",[3452,5806,5807],{"class":3961},": {\n",[3452,5809,5810,5813,5815,5818],{"class":3454,"line":3769},[3452,5811,5812],{"class":5534},"                \"logDriver\"",[3452,5814,5538],{"class":3961},[3452,5816,5817],{"class":3462},"\"awslogs\"",[3452,5819,5544],{"class":3961},[3452,5821,5822,5825],{"class":3454,"line":4629},[3452,5823,5824],{"class":5534},"                \"options\"",[3452,5826,5807],{"class":3961},[3452,5828,5829,5832,5834,5837],{"class":3454,"line":4637},[3452,5830,5831],{"class":5534},"                    \"awslogs-group\"",[3452,5833,5538],{"class":3961},[3452,5835,5836],{"class":3462},"\"\u002Fecs\u002Fmy-api\"",[3452,5838,5544],{"class":3961},[3452,5840,5841,5844,5846,5849],{"class":3454,"line":4642},[3452,5842,5843],{"class":5534},"                    \"awslogs-region\"",[3452,5845,5538],{"class":3961},[3452,5847,5848],{"class":3462},"\"eu-central-1\"",[3452,5850,5544],{"class":3961},[3452,5852,5853,5856,5858],{"class":3454,"line":4648},[3452,5854,5855],{"class":5534},"                    \"awslogs-stream-prefix\"",[3452,5857,5538],{"class":3961},[3452,5859,5860],{"class":3462},"\"ecs\"\n",[3452,5862,5863],{"class":3454,"line":4654},[3452,5864,5693],{"class":3961},[3452,5866,5867],{"class":3454,"line":4660},[3452,5868,5869],{"class":3961},"            },\n",[3452,5871,5872,5875],{"class":3454,"line":4668},[3452,5873,5874],{"class":5534},"            \"healthCheck\"",[3452,5876,5807],{"class":3961},[3452,5878,5879,5882,5884,5887,5889,5892],{"class":3454,"line":4673},[3452,5880,5881],{"class":5534},"                \"command\"",[3452,5883,5564],{"class":3961},[3452,5885,5886],{"class":3462},"\"CMD-SHELL\"",[3452,5888,3491],{"class":3961},[3452,5890,5891],{"class":3462},"\"curl -f http:\u002F\u002Flocalhost:8080\u002Fhealth || exit 1\"",[3452,5893,5570],{"class":3961},[3452,5895,5896,5899,5901,5904],{"class":3454,"line":4679},[3452,5897,5898],{"class":5534},"                \"interval\"",[3452,5900,5538],{"class":3961},[3452,5902,5903],{"class":4152},"30",[3452,5905,5544],{"class":3961},[3452,5907,5909,5912,5914,5916],{"class":3454,"line":5908},40,[3452,5910,5911],{"class":5534},"                \"timeout\"",[3452,5913,5538],{"class":3961},[3452,5915,4158],{"class":4152},[3452,5917,5544],{"class":3961},[3452,5919,5921,5924,5926,5929],{"class":3454,"line":5920},41,[3452,5922,5923],{"class":5534},"                \"retries\"",[3452,5925,5538],{"class":3961},[3452,5927,5928],{"class":4152},"3",[3452,5930,5544],{"class":3961},[3452,5932,5934,5937,5939],{"class":3454,"line":5933},42,[3452,5935,5936],{"class":5534},"                \"startPeriod\"",[3452,5938,5538],{"class":3961},[3452,5940,5941],{"class":4152},"60\n",[3452,5943,5945],{"class":3454,"line":5944},43,[3452,5946,5947],{"class":3961},"            }\n",[3452,5949,5951],{"class":3454,"line":5950},44,[3452,5952,5953],{"class":3961},"        }\n",[3452,5955,5957],{"class":3454,"line":5956},45,[3452,5958,5959],{"class":3961},"    ]\n",[3452,5961,5963],{"class":3454,"line":5962},46,[3452,5964,3691],{"class":3961},[3354,5966,5967],{},"Розберемо важливі поля:",[3354,5969,5970,5975,5976,5979,5980,3516],{},[3540,5971,5972],{},[3449,5973,5974],{},"executionRoleArn"," — IAM Role для ",[3540,5977,5978],{},"ECS агента"," (не вашого застосунку). Потрібна для завантаження образу з ECR та запису логів у CloudWatch. Стандартна роль: ",[3449,5981,5982],{},"AmazonECSTaskExecutionRolePolicy",[3354,5984,5985,5975,5990,5993],{},[3540,5986,5987],{},[3449,5988,5989],{},"taskRoleArn",[3540,5991,5992],{},"вашого застосунку всередині контейнера",". Якщо API потребує доступу до S3 або DynamoDB — саме сюди додаються ці права.",[3354,5995,5996,6001,6002,6005],{},[3540,5997,5998],{},[3449,5999,6000],{},"secrets"," — замість передачі паролів через ",[3449,6003,6004],{},"environment"," (небезпечно!) — отримання секретів із AWS Secrets Manager або SSM Parameter Store. ECS агент завантажує секрет і підставляє як змінну середовища під час запуску контейнера.",[3354,6007,6008,6013],{},[3540,6009,6010],{},[3449,6011,6012],{},"healthCheck"," — ECS регулярно перевіряє стан контейнера. Якщо health check провалюється тричі — Task вважається нездоровим і Service замінює його новим.",[3573,6015,6017],{"id":6016},"допустимі-комбінації-cpu-та-памяті-для-fargate","Допустимі комбінації CPU та пам'яті для Fargate",[3354,6019,6020,6021,6024,6025,6028],{},"Параметри ",[3449,6022,6023],{},"cpu"," і ",[3449,6026,6027],{},"memory"," у Task Definition — це рядки (не числа). Fargate не приймає довільні значення — допустимі лише певні комбінації, перелік яких наведено нижче. Спроба вказати неіснуючу комбінацію призведе до помилки валідації Task Definition.",[3358,6030,6031,6047],{},[3361,6032,6033],{},[3364,6034,6035,6038,6041],{},[3367,6036,6037],{},"CPU (JSON рядок)",[3367,6039,6040],{},"Реальне значення",[3367,6042,6043,6044,6046],{},"Допустима пам'ять (",[3449,6045,6027],{},", MB)",[3377,6048,6049,6061,6073,6086,6099,6112,6125],{},[3364,6050,6051,6055,6058],{},[3382,6052,6053],{},[3449,6054,5580],{},[3382,6056,6057],{},"0.25 vCPU",[3382,6059,6060],{},"512, 1024, 2048",[3364,6062,6063,6067,6070],{},[3382,6064,6065],{},[3449,6066,5592],{},[3382,6068,6069],{},"0.5 vCPU",[3382,6071,6072],{},"1024, 2048, 3072, 4096",[3364,6074,6075,6080,6083],{},[3382,6076,6077],{},[3449,6078,6079],{},"\"1024\"",[3382,6081,6082],{},"1 vCPU",[3382,6084,6085],{},"2048–8192 (крок 1024)",[3364,6087,6088,6093,6096],{},[3382,6089,6090],{},[3449,6091,6092],{},"\"2048\"",[3382,6094,6095],{},"2 vCPU",[3382,6097,6098],{},"4096–16384 (крок 1024)",[3364,6100,6101,6106,6109],{},[3382,6102,6103],{},[3449,6104,6105],{},"\"4096\"",[3382,6107,6108],{},"4 vCPU",[3382,6110,6111],{},"8192–30720 (крок 1024)",[3364,6113,6114,6119,6122],{},[3382,6115,6116],{},[3449,6117,6118],{},"\"8192\"",[3382,6120,6121],{},"8 vCPU",[3382,6123,6124],{},"16384–61440 (крок 4096)",[3364,6126,6127,6132,6135],{},[3382,6128,6129],{},[3449,6130,6131],{},"\"16384\"",[3382,6133,6134],{},"16 vCPU",[3382,6136,6137],{},"32768–122880 (крок 8192)",[3354,6139,6140,6141,6143,6144,6146,6147,6149,6150,6153],{},"Для більшості .NET Web API-сервісів достатньо ",[3449,6142,5580],{}," (0.25 vCPU) і ",[3449,6145,5592],{}," MB RAM — це найменш вартісна конфігурація Fargate. При високому RPS або інтенсивних обчисленнях рекомендовано стартувати з ",[3449,6148,5592],{}," \u002F ",[3449,6151,6152],{},"1024 MB"," і коригувати на основі метрик CloudWatch.",[6155,6156,6157,6163,6182],"caution",{},[3354,6158,6159,6162],{},[3540,6160,6161],{},"Health checks у .NET"," потребують окремого endpoint. Додайте у Program.cs:",[3442,6164,6166],{"className":3944,"code":6165,"language":3946,"meta":3447,"style":3447},"app.MapHealthChecks(\"\u002Fhealth\");\n",[3449,6167,6168],{"__ignoreMap":3447},[3452,6169,6170,6172,6174,6176,6178,6180],{"class":3454,"line":3455},[3452,6171,4032],{"class":3957},[3452,6173,3516],{"class":3961},[3452,6175,4314],{"class":3458},[3452,6177,3973],{"class":3961},[3452,6179,4319],{"class":3462},[3452,6181,3979],{"class":3961},[3354,6183,6184,6185,6188],{},"І переконайтесь, що endpoint доступний ",[3540,6186,6187],{},"до"," підключення до бази даних. ECS починає перевірку одразу після старту контейнера, а DB може ще не бути доступна.",[3518,6190],{},[3349,6192,6194],{"id":6193},"aws-fargate-vs-ec2-launch-types","AWS Fargate vs EC2 Launch Types",[3354,6196,6197],{},[3527,6198],{"alt":6199,"className":6200,"src":6201},"AWS Fargate serverless versus EC2 launch type comparison architecture",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F08.png",[3354,6203,6204,6205,6208],{},"Один із ключових вибір при налаштуванні ECS: ",[3540,6206,6207],{},"як запускати Tasks?"," ECS підтримує два «launch types» — режими запуску, які принципово відрізняються підходом до управління інфраструктурою.",[3573,6210,6212],{"id":6211},"ec2-launch-type","EC2 Launch Type",[3354,6214,6215,6216,6219,6220,6223],{},"При використанні EC2 launch type ви ",[3540,6217,6218],{},"самостійно управляєте EC2 інстансами",", на яких запускаються контейнери. ECS розміщує Tasks на ваших інстансах, але ",[3540,6221,6222],{},"відповідальність за самі інстанси — на вас",": встановлення ECS Agent, оновлення ОС, вибір типу і розміру інстансу, масштабування парку машин.",[3354,6225,6226],{},[3540,6227,6228],{},"Переваги EC2 launch type:",[4699,6230,6231,6234,6237],{},[4702,6232,6233],{},"Нижча вартість при стабільному, передбачуваному навантаженні (Reserved Instances, Savings Plans)",[4702,6235,6236],{},"Більш детальний контроль: GPU інстанси для ML, специфічні типи інстансів, Spot Instances для batch-задач",[4702,6238,6239],{},"Можливість запускати privileged контейнери та монтувати локальні томи",[3354,6241,6242,6245],{},[3540,6243,6244],{},"Недоліки:"," Ви платите за інстанс, навіть якщо він простоює. Потрібно управляти capacity, оновленнями ОС, патчами безпеки.",[3573,6247,6249],{"id":6248},"aws-fargate-serverless-containers","AWS Fargate — Serverless Containers",[3354,6251,6252,6255,6256,6259],{},[3540,6253,6254],{},"AWS Fargate"," — це serverless платформа для запуску контейнерів. При використанні Fargate launch type ",[3540,6257,6258],{},"AWS повністю бере на себе управління інфраструктурою",": ви не вибираєте, не запускаєте і не обслуговуєте жодного EC2 інстансу. Ви просто описуєте Task Definition (образ, CPU, RAM) — і Fargate запускає контейнер.",[3354,6261,6262,6265,6266,6269],{},[3540,6263,6264],{},"Принцип роботи Fargate:"," для кожного Task AWS виділяє ізольоване мікро-середовище з запитаними ресурсами. Task не знає про інші Tasks. Після зупинки Task — ресурси звільняються. ",[3540,6267,6268],{},"Ви платите лише за час виконання Task"," (vCPU-годину та GB-годину RAM).",[3354,6271,6272],{},[3540,6273,6274],{},"Переваги Fargate:",[4699,6276,6277,6280,6283,6286],{},[4702,6278,6279],{},"Нуль операційного overhead: немає кластеру EC2 для управління",[4702,6281,6282],{},"Ізоляція на рівні завдання — кожен Task у власному мікро-VM",[4702,6284,6285],{},"Автоматичне масштабування від 0 до тисяч Tasks без попереднього планування capacity",[4702,6287,6288],{},"Ідеально для нерівномірного навантаження, мікросервісів та стартапів",[3354,6290,6291,6293],{},[3540,6292,6244],{}," Дорожче за EC2 для стабільного, постійного навантаження. Немає GPU-підтримки. Холодний старт повільніший (кілька секунд для підняття ізольованого середовища).",[6295,6296,6297,6319],"card-group",{},[6298,6299,6302],"card",{"icon":6300,"title":6301},"i-heroicons-bolt","Fargate — коли обирати",[4699,6303,6304,6307,6310,6313,6316],{},[4702,6305,6306],{},"Мікросервісна архітектура",[4702,6308,6309],{},"Нерівномірне навантаження (пікові навантаження вдень, майже нуль вночі)",[4702,6311,6312],{},"Команда без DevOps-досвіду або маленька команда",[4702,6314,6315],{},"Batch-задачі, фонові воркери",[4702,6317,6318],{},"Стартапи та MVP",[6298,6320,6323],{"icon":6321,"title":6322},"i-heroicons-server-stack","EC2 Launch Type — коли обирати",[4699,6324,6325,6328,6331,6334,6337],{},[4702,6326,6327],{},"Стабільне, передбачуване навантаження 24\u002F7",[4702,6329,6330],{},"Потреба у GPU (ML моделі)",[4702,6332,6333],{},"Специфічні вимоги до типу інстансу",[4702,6335,6336],{},"Spot Instances для batch-обробки даних",[4702,6338,6339],{},"Велика компанія з виділеним DevOps-відділом",[3518,6341],{},[3349,6343,6345],{"id":6344},"ecs-task-networking-awsvpc-режим","ECS Task Networking: awsvpc режим",[3354,6347,6348],{},[3527,6349],{"alt":6350,"className":6351,"src":6352},"ECS awsvpc network mode each task gets own ENI and private IP diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F09.png",[3354,6354,6355,6356,6359,6360,6363],{},"Перш ніж розглядати мережевий режим ",[3449,6357,6358],{},"awsvpc",", необхідно сформувати чітке розуміння фундаментальної концепції AWS-інфраструктури — ",[3540,6361,6362],{},"Amazon VPC",", — без якої неможливо пояснити, яким чином ECS Tasks отримують мережеву ідентичність і як вони стають доступними ззовні.",[3573,6365,6367],{"id":6366},"що-таке-amazon-vpc","Що таке Amazon VPC",[3354,6369,6370,6373],{},[3540,6371,6372],{},"Amazon Virtual Private Cloud (VPC)"," — це логічно ізольована віртуальна мережа всередині AWS, яку користувач визначає і якою повністю керує. Концептуально VPC відтворює традиційну корпоративну мережу, розміщену у власному дата-центрі: ви самостійно обираєте діапазон IP-адрес, розбиваєте мережу на сегменти, встановлюєте правила фільтрації трафіку — проте замість фізичного обладнання весь цей контроль здійснюється програмно.",[3354,6375,6376,6377,6380,6381,6384],{},"Кожен AWS-акаунт при створенні отримує ",[3540,6378,6379],{},"Default VPC"," у кожному регіоні — попередньо налаштовану мережу з адресним простором ",[3449,6382,6383],{},"172.31.0.0\u002F16",", готову до використання без жодних додаткових налаштувань. Саме цей Default VPC застосовуватиметься у практичному прикладі далі в розділі.",[3354,6386,6387,6388,6391,6392,6395,6396,3516],{},"VPC охоплює весь регіон AWS (наприклад, ",[3449,6389,6390],{},"eu-central-1","), однак ресурси всередині VPC фізично розміщуються у конкретних ",[3540,6393,6394],{},"Availability Zones"," (зонах доступності) — незалежних дата-центрах у межах регіону. Для розподілу ресурсів між зонами VPC ділиться на ",[3540,6397,6398],{},"підмережі (Subnets)",[3442,6400,6403],{"className":6401,"code":6402,"language":3856},[3854],"AWS Region: eu-central-1 (Frankfurt)\n└── VPC: 10.0.0.0\u002F16  ← адресний простір: 65 536 IP-адрес\n    ├── Subnet: 10.0.1.0\u002F24  → Availability Zone eu-central-1a  (256 адрес)\n    ├── Subnet: 10.0.2.0\u002F24  → Availability Zone eu-central-1b  (256 адрес)\n    └── Subnet: 10.0.3.0\u002F24  → Availability Zone eu-central-1c  (256 адрес)\n",[3449,6404,6402],{"__ignoreMap":3447},[3573,6406,6408],{"id":6407},"публічні-та-приватні-підмережі","Публічні та приватні підмережі",[3354,6410,6411],{},"Підмережі поділяються на два принципово різних типи залежно від наявності маршруту до Інтернету.",[3354,6413,6414,6417,6418,6421,6422,6425],{},[3540,6415,6416],{},"Публічна підмережа (Public Subnet)"," — підмережа, маршрутна таблиця якої містить запис, що направляє зовнішній трафік (",[3449,6419,6420],{},"0.0.0.0\u002F0",") до ",[3540,6423,6424],{},"Internet Gateway (IGW)",". Internet Gateway — керований AWS компонент, що забезпечує двосторонній зв'язок між ресурсами VPC та публічним Інтернетом. Ресурс, розміщений у публічній підмережі і наділений публічною IP-адресою, є досяжним з Інтернету і сам здатний ініціювати вихідні з'єднання назовні.",[3354,6427,6428,6431,6432,6435],{},[3540,6429,6430],{},"Приватна підмережа (Private Subnet)"," — підмережа, маршрутна таблиця якої не містить маршруту до Internet Gateway. Ресурси у ній недоступні з Інтернету за будь-яких умов. Для вихідного трафіку (наприклад, завантаження Docker-образу з Amazon ECR або звернення до зовнішнього API) використовується ",[3540,6433,6434],{},"NAT Gateway"," — керований AWS-сервіс, розміщений у публічній підмережі. NAT Gateway транслює приватну IP-адресу вихідного пакета у власну публічну Elastic IP, пропускаючи трафік назовні, проте залишаючи ресурси закритими для будь-яких вхідних з'єднань ззовні.",[3588,6437,6438],{},[3442,6439,6441],{"className":3592,"code":6440,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"Internet\" as NET #e5e7eb\n\npackage \"VPC: 10.0.0.0\u002F16\" #f0f4ff {\n\n    rectangle \"Internet Gateway (IGW)\" as IGW #fef3c7\n\n    package \"Public Subnet: 10.0.1.0\u002F24\\n(AZ: eu-central-1a)\" #d1fae5 {\n        rectangle \"ECS Task\\nPublic IP: 3.64.x.x\\nPrivate IP: 10.0.1.15\" as TASK_PUB #bbf7d0\n        rectangle \"NAT Gateway\\n(Elastic IP)\" as NAT #fde68a\n    }\n\n    package \"Private Subnet: 10.0.2.0\u002F24\\n(AZ: eu-central-1b)\" #dbeafe {\n        rectangle \"ECS Task\\nPrivate IP: 10.0.2.8\\n(без публічного IP)\" as TASK_PRV #bfdbfe\n        rectangle \"RDS Database\\nPrivate IP: 10.0.2.50\" as RDS #e0e7ff\n    }\n}\n\nNET \u003C--> IGW\nIGW \u003C--> TASK_PUB : вхідний та вихідний трафік\nTASK_PRV -down-> NAT : вихідний трафік (наприклад, pull образу з ECR)\nNAT --> IGW : передає назовні з Elastic IP\nnote right of TASK_PRV\n  Недоступний з Інтернету напряму.\n  Вихідний трафік — через NAT Gateway.\nend note\n@enduml\n",[3449,6442,6443,6447,6451,6455,6459,6464,6468,6473,6477,6482,6486,6491,6496,6501,6505,6509,6514,6519,6524,6528,6532,6536,6541,6546,6551,6556,6561,6566,6571,6576],{"__ignoreMap":3447},[3452,6444,6445],{"class":3454,"line":3455},[3452,6446,3601],{},[3452,6448,6449],{"class":3454,"line":3473},[3452,6450,3606],{},[3452,6452,6453],{"class":3454,"line":3609},[3452,6454,3612],{},[3452,6456,6457],{"class":3454,"line":3615},[3452,6458,3619],{"emptyLinePlaceholder":3618},[3452,6460,6461],{"class":3454,"line":3622},[3452,6462,6463],{},"rectangle \"Internet\" as NET #e5e7eb\n",[3452,6465,6466],{"class":3454,"line":3628},[3452,6467,3619],{"emptyLinePlaceholder":3618},[3452,6469,6470],{"class":3454,"line":3634},[3452,6471,6472],{},"package \"VPC: 10.0.0.0\u002F16\" #f0f4ff {\n",[3452,6474,6475],{"class":3454,"line":3640},[3452,6476,3619],{"emptyLinePlaceholder":3618},[3452,6478,6479],{"class":3454,"line":3646},[3452,6480,6481],{},"    rectangle \"Internet Gateway (IGW)\" as IGW #fef3c7\n",[3452,6483,6484],{"class":3454,"line":3652},[3452,6485,3619],{"emptyLinePlaceholder":3618},[3452,6487,6488],{"class":3454,"line":3658},[3452,6489,6490],{},"    package \"Public Subnet: 10.0.1.0\u002F24\\n(AZ: eu-central-1a)\" #d1fae5 {\n",[3452,6492,6493],{"class":3454,"line":3664},[3452,6494,6495],{},"        rectangle \"ECS Task\\nPublic IP: 3.64.x.x\\nPrivate IP: 10.0.1.15\" as TASK_PUB #bbf7d0\n",[3452,6497,6498],{"class":3454,"line":3670},[3452,6499,6500],{},"        rectangle \"NAT Gateway\\n(Elastic IP)\" as NAT #fde68a\n",[3452,6502,6503],{"class":3454,"line":3676},[3452,6504,3655],{},[3452,6506,6507],{"class":3454,"line":3682},[3452,6508,3619],{"emptyLinePlaceholder":3618},[3452,6510,6511],{"class":3454,"line":3688},[3452,6512,6513],{},"    package \"Private Subnet: 10.0.2.0\u002F24\\n(AZ: eu-central-1b)\" #dbeafe {\n",[3452,6515,6516],{"class":3454,"line":3694},[3452,6517,6518],{},"        rectangle \"ECS Task\\nPrivate IP: 10.0.2.8\\n(без публічного IP)\" as TASK_PRV #bfdbfe\n",[3452,6520,6521],{"class":3454,"line":3699},[3452,6522,6523],{},"        rectangle \"RDS Database\\nPrivate IP: 10.0.2.50\" as RDS #e0e7ff\n",[3452,6525,6526],{"class":3454,"line":3705},[3452,6527,3655],{},[3452,6529,6530],{"class":3454,"line":3711},[3452,6531,3691],{},[3452,6533,6534],{"class":3454,"line":3717},[3452,6535,3619],{"emptyLinePlaceholder":3618},[3452,6537,6538],{"class":3454,"line":3723},[3452,6539,6540],{},"NET \u003C--> IGW\n",[3452,6542,6543],{"class":3454,"line":3729},[3452,6544,6545],{},"IGW \u003C--> TASK_PUB : вхідний та вихідний трафік\n",[3452,6547,6548],{"class":3454,"line":3734},[3452,6549,6550],{},"TASK_PRV -down-> NAT : вихідний трафік (наприклад, pull образу з ECR)\n",[3452,6552,6553],{"class":3454,"line":3740},[3452,6554,6555],{},"NAT --> IGW : передає назовні з Elastic IP\n",[3452,6557,6558],{"class":3454,"line":3746},[3452,6559,6560],{},"note right of TASK_PRV\n",[3452,6562,6563],{"class":3454,"line":3752},[3452,6564,6565],{},"  Недоступний з Інтернету напряму.\n",[3452,6567,6568],{"class":3454,"line":3758},[3452,6569,6570],{},"  Вихідний трафік — через NAT Gateway.\n",[3452,6572,6573],{"class":3454,"line":3764},[3452,6574,6575],{},"end note\n",[3452,6577,6578],{"class":3454,"line":3769},[3452,6579,3772],{},[3573,6581,6583],{"id":6582},"eni-elastic-network-interface","ENI — Elastic Network Interface",[3354,6585,6586,6589],{},[3540,6587,6588],{},"Elastic Network Interface (ENI)"," — це віртуальний мережевий адаптер у VPC. Фізичною аналогією слугує мережева карта (NIC) комп'ютера: ENI є тим інтерфейсом, через який ресурс AWS підключається до мережі, отримує приватну IP-адресу, і через який проходить увесь його мережевий трафік.",[3354,6591,6592],{},"Кожен ENI характеризується такими атрибутами:",[4699,6594,6595,6601,6607],{},[4702,6596,6597,6600],{},[3540,6598,6599],{},"Приватна IP-адреса"," — постійна адреса всередині VPC, що призначається з діапазону підмережі",[4702,6602,6603,6606],{},[3540,6604,6605],{},"Публічна IP-адреса"," — необов'язкова; призначається лише для ресурсів у публічних підмережах при явному запиті",[4702,6608,6609,6612],{},[3540,6610,6611],{},"Security Groups"," — набори правил фільтрації трафіку, прикріплені безпосередньо до ENI",[3573,6614,6616],{"id":6615},"режим-awsvpc-та-його-значення-для-ecs","Режим awsvpc та його значення для ECS",[3354,6618,6619,6621,6622,6625],{},[3540,6620,6358],{}," — це мережевий режим Task Definition, при якому ",[3540,6623,6624],{},"кожен запущений Task отримує власний виділений ENI"," і, відповідно, власну приватну IP-адресу всередині VPC. Цей режим є обов'язковим для Fargate і рекомендованим для EC2 launch type.",[3354,6627,6628,6629,6631],{},"Дана модель принципово відрізняється від традиційного підходу, де всі контейнери на одному хості розділяють мережевий простір хостової машини і відрізняються лише номерами портів. У режимі ",[3449,6630,6358],{}," Task є повноправним мережевим ресурсом VPC — таким самим, як EC2-інстанс або RDS-база даних.",[3354,6633,6634],{},"Практичні наслідки цього рішення:",[4699,6636,6637,6643,6649],{},[4702,6638,6639,6642],{},[3540,6640,6641],{},"Власна IP-адреса кожного Task."," ALB реєструє IP кожного Task як окремий target і направляє трафік безпосередньо, без додаткових рівнів трансляції.",[4702,6644,6645,6648],{},[3540,6646,6647],{},"Security Groups на рівні Task."," Правила фільтрації трафіку застосовуються окремо до кожного Task, що забезпечує точний контроль: наприклад, дозволити трафік на порт 8080 лише з конкретного ALB.",[4702,6650,6651,6654],{},[3540,6652,6653],{},"Підтримка VPC Flow Logs."," Весь мережевий трафік Tasks можна логувати та аналізувати на рівні мережі.",[3573,6656,6658],{"id":6657},"публічний-доступ-до-fargate-task-assignpublicip","Публічний доступ до Fargate Task: assignPublicIp",[3354,6660,6661,6662,6665,6666,6669],{},"Найпростіший спосіб надати Task доступ з Інтернету — розмістити його у ",[3540,6663,6664],{},"публічній підмережі"," та встановити параметр ",[3449,6667,6668],{},"assignPublicIp: ENABLED"," при запуску Service або окремого Task. У такому випадку AWS автоматично призначає ENI Task тимчасову публічну IP-адресу.",[3442,6671,6674],{"className":6672,"code":6673,"language":3856},[3854],"Internet\n    ↓\nPublic IP: 3.64.x.x  (тимчасова, змінюється при рестарті Task)\n    ↓\nENI Task (awsvpc)\n    ↓\n.NET контейнер: порт 8080\n",[3449,6675,6673],{"__ignoreMap":3447},[3565,6677,6678,6679,6682,6683,6686],{},"Тимчасова публічна IP-адреса є прийнятною для навчальних цілей і прямого тестування без балансувальника. У production-середовищі Tasks розміщуються у ",[3540,6680,6681],{},"приватних підмережах",", а єдиною точкою входу ззовні слугує ",[3540,6684,6685],{},"Application Load Balancer"," — ресурс зі статичним DNS-name, розміщений у публічних підмережах. Такий підхід забезпечує стабільну адресацію і виключає пряме звернення до Tasks з Інтернету.",[3573,6688,6690],{"id":6689},"приватне-розміщення-tasks-і-роль-nat-gateway","Приватне розміщення Tasks і роль NAT Gateway",[3354,6692,6693],{},"Якщо ECS Task розташований у приватній підмережі (рекомендована production-конфігурація), він не має публічного IP і залишається ізольованим від зовнішнього трафіку. Проте для коректного запуску Task вихідне з'єднання усе одно необхідне — щонайменше для завантаження Docker-образу з Amazon ECR в момент старту контейнера.",[3354,6695,6696,6697,6699],{},"Для забезпечення вихідного трафіку з приватної підмережі в цій же VPC розміщується ",[3540,6698,6434],{}," — у публічній підмережі, де він має доступ до Internet Gateway. NAT Gateway транслює адресу Task у власну Elastic IP при проходженні трафіку назовні, не відкриваючи Task для вхідних з'єднань ззовні.",[6155,6701,6702,6703,6705,6706,6708],{},"NAT Gateway є платним сервісом: ~$0.045\u002Fгод за роботу плюс ~$0.045\u002FGB переданих даних. У навчальній лабораторній роботі далі Tasks розміщуватимуться у ",[3540,6704,6664],{}," з ",[3449,6707,6668],{}," — в такому разі NAT Gateway не потрібен, а трафік іде напряму через Internet Gateway. Врахуйте цей факт при проектуванні production-архітектури.",[3573,6710,6712],{"id":6711},"підсумкова-схема-адресації-tasks","Підсумкова схема адресації Tasks",[3442,6714,6717],{"className":6715,"code":6716,"language":3856},[3854],"VPC: 10.0.0.0\u002F16\n│\n├── Public Subnet: 10.0.1.0\u002F24  (AZ: eu-central-1a)\n│   ├── Task 1  ENI → Private: 10.0.1.15 │ Public: 3.64.12.5   (my-api)\n│   ├── Task 2  ENI → Private: 10.0.1.23 │ Public: 3.64.18.7   (my-api)\n│   └── NAT Gateway (Elastic IP: 52.29.x.x)\n│\n└── Private Subnet: 10.0.2.0\u002F24  (AZ: eu-central-1b)\n    ├── Task 3  ENI → Private: 10.0.2.8  │ Public: —           (my-api)\n    └── RDS     ENI → Private: 10.0.2.50 │ Public: —           (postgres)\n",[3449,6718,6716],{"__ignoreMap":3447},[3354,6720,6721],{},"Tasks у публічній підмережі доступні з Інтернету безпосередньо за публічним IP (прийнятно для тестування). Tasks у приватній підмережі досяжні лише через ALB або інші ресурси всередині VPC — що є стандартною production-моделлю.",[3518,6723],{},[3349,6725,6727],{"id":6726},"ecs-service-auto-scaling","ECS Service Auto Scaling",[3354,6729,6730],{},[3527,6731],{"alt":6732,"className":6733,"src":6734},"ECS Service Auto Scaling target tracking CPU metric diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F10.png",[3354,6736,6737,6740,6741,6744,6745,6748],{},[3540,6738,6739],{},"Auto Scaling"," — це автоматична зміна кількості запущених Tasks у відповідь на зміну навантаження. ECS Service Auto Scaling інтегрований з ",[3540,6742,6743],{},"Amazon CloudWatch"," та ",[3540,6746,6747],{},"Application Auto Scaling"," і підтримує три стратегії масштабування:",[3573,6750,6752],{"id":6751},"target-tracking-scaling","Target Tracking Scaling",[3354,6754,6755,6756,6759],{},"Найпростіший і найрекомендованіший підхід для початку. Ви вказуєте ",[3540,6757,6758],{},"цільове значення метрики"," — і AWS автоматично додає або видаляє Tasks для підтримання цього значення.",[3442,6761,6763],{"className":5521,"code":6762,"language":5523,"meta":3447,"style":3447},"{\n    \"TargetValue\": 70.0,\n    \"PredefinedMetricSpecification\": {\n        \"PredefinedMetricType\": \"ECSServiceAverageCPUUtilization\"\n    },\n    \"ScaleInCooldown\": 300,\n    \"ScaleOutCooldown\": 60\n}\n",[3449,6764,6765,6769,6781,6788,6798,6803,6815,6824],{"__ignoreMap":3447},[3452,6766,6767],{"class":3454,"line":3455},[3452,6768,4097],{"class":3961},[3452,6770,6771,6774,6776,6779],{"class":3454,"line":3473},[3452,6772,6773],{"class":5534},"    \"TargetValue\"",[3452,6775,5538],{"class":3961},[3452,6777,6778],{"class":4152},"70.0",[3452,6780,5544],{"class":3961},[3452,6782,6783,6786],{"class":3454,"line":3609},[3452,6784,6785],{"class":5534},"    \"PredefinedMetricSpecification\"",[3452,6787,5807],{"class":3961},[3452,6789,6790,6793,6795],{"class":3454,"line":3615},[3452,6791,6792],{"class":5534},"        \"PredefinedMetricType\"",[3452,6794,5538],{"class":3961},[3452,6796,6797],{"class":3462},"\"ECSServiceAverageCPUUtilization\"\n",[3452,6799,6800],{"class":3454,"line":3622},[3452,6801,6802],{"class":3961},"    },\n",[3452,6804,6805,6808,6810,6813],{"class":3454,"line":3628},[3452,6806,6807],{"class":5534},"    \"ScaleInCooldown\"",[3452,6809,5538],{"class":3961},[3452,6811,6812],{"class":4152},"300",[3452,6814,5544],{"class":3961},[3452,6816,6817,6820,6822],{"class":3454,"line":3634},[3452,6818,6819],{"class":5534},"    \"ScaleOutCooldown\"",[3452,6821,5538],{"class":3961},[3452,6823,5941],{"class":4152},[3452,6825,6826],{"class":3454,"line":3640},[3452,6827,3691],{"class":3961},[3354,6829,6830],{},"Ця конфігурація каже: «Підтримуй середнє CPU-завантаження на рівні 70%. Якщо CPU зростає вище — додай Tasks (cooldown 60 сек). Якщо CPU падає нижче — видали Tasks (cooldown 300 сек)».",[3354,6832,6833,6839],{},[3540,6834,6835,6838],{},[3449,6836,6837],{},"ScaleOutCooldown"," (60 сек)"," — пауза після масштабування вгору. Невеликий, бо при зростанні навантаження важливо швидко реагувати.",[3354,6841,6842,6848],{},[3540,6843,6844,6847],{},[3449,6845,6846],{},"ScaleInCooldown"," (300 сек)"," — пауза після маштабування вниз. Більший, бо передчасне видалення Tasks при тимчасовому зниженні навантаження є контрпродуктивним.",[3354,6850,6851],{},[3540,6852,6853],{},"Налаштування Target Tracking через AWS CLI:",[3442,6855,6857],{"className":3444,"code":6856,"language":3446,"meta":3447,"style":3447},"# Крок 1: Зареєструйте ECS Service як scalable target.\n# resource-id має формат: service\u002F\u003Ccluster-name>\u002F\u003Cservice-name>\naws application-autoscaling register-scalable-target \\\n    --service-namespace ecs \\\n    --scalable-dimension ecs:service:DesiredCount \\\n    --resource-id service\u002Fproduction\u002Fmy-api \\\n    --min-capacity 2 \\\n    --max-capacity 20 \\\n    --region eu-central-1\n\n# Крок 2: Додайте Target Tracking Policy\naws application-autoscaling put-scaling-policy \\\n    --service-namespace ecs \\\n    --scalable-dimension ecs:service:DesiredCount \\\n    --resource-id service\u002Fproduction\u002Fmy-api \\\n    --policy-name cpu-target-70 \\\n    --policy-type TargetTrackingScaling \\\n    --target-tracking-scaling-policy-configuration '{\n        \"TargetValue\": 70.0,\n        \"PredefinedMetricSpecification\": {\n            \"PredefinedMetricType\": \"ECSServiceAverageCPUUtilization\"\n        },\n        \"ScaleInCooldown\": 300,\n        \"ScaleOutCooldown\": 60\n    }' \\\n    --region eu-central-1\n",[3449,6858,6859,6864,6869,6881,6891,6901,6911,6921,6931,6939,6943,6948,6959,6967,6975,6983,6993,7003,7011,7016,7021,7026,7031,7036,7041,7048],{"__ignoreMap":3447},[3452,6860,6861],{"class":3454,"line":3455},[3452,6862,6863],{"class":3469},"# Крок 1: Зареєструйте ECS Service як scalable target.\n",[3452,6865,6866],{"class":3454,"line":3473},[3452,6867,6868],{"class":3469},"# resource-id має формат: service\u002F\u003Ccluster-name>\u002F\u003Cservice-name>\n",[3452,6870,6871,6873,6876,6879],{"class":3454,"line":3609},[3452,6872,3459],{"class":3458},[3452,6874,6875],{"class":3462}," application-autoscaling",[3452,6877,6878],{"class":3462}," register-scalable-target",[3452,6880,5067],{"class":5066},[3452,6882,6883,6886,6889],{"class":3454,"line":3615},[3452,6884,6885],{"class":3953},"    --service-namespace",[3452,6887,6888],{"class":3462}," ecs",[3452,6890,5067],{"class":5066},[3452,6892,6893,6896,6899],{"class":3454,"line":3622},[3452,6894,6895],{"class":3953},"    --scalable-dimension",[3452,6897,6898],{"class":3462}," ecs:service:DesiredCount",[3452,6900,5067],{"class":5066},[3452,6902,6903,6906,6909],{"class":3454,"line":3628},[3452,6904,6905],{"class":3953},"    --resource-id",[3452,6907,6908],{"class":3462}," service\u002Fproduction\u002Fmy-api",[3452,6910,5067],{"class":5066},[3452,6912,6913,6916,6919],{"class":3454,"line":3634},[3452,6914,6915],{"class":3953},"    --min-capacity",[3452,6917,6918],{"class":4152}," 2",[3452,6920,5067],{"class":5066},[3452,6922,6923,6926,6929],{"class":3454,"line":3640},[3452,6924,6925],{"class":3953},"    --max-capacity",[3452,6927,6928],{"class":4152}," 20",[3452,6930,5067],{"class":5066},[3452,6932,6933,6936],{"class":3454,"line":3646},[3452,6934,6935],{"class":3953},"    --region",[3452,6937,6938],{"class":3462}," eu-central-1\n",[3452,6940,6941],{"class":3454,"line":3652},[3452,6942,3619],{"emptyLinePlaceholder":3618},[3452,6944,6945],{"class":3454,"line":3658},[3452,6946,6947],{"class":3469},"# Крок 2: Додайте Target Tracking Policy\n",[3452,6949,6950,6952,6954,6957],{"class":3454,"line":3664},[3452,6951,3459],{"class":3458},[3452,6953,6875],{"class":3462},[3452,6955,6956],{"class":3462}," put-scaling-policy",[3452,6958,5067],{"class":5066},[3452,6960,6961,6963,6965],{"class":3454,"line":3670},[3452,6962,6885],{"class":3953},[3452,6964,6888],{"class":3462},[3452,6966,5067],{"class":5066},[3452,6968,6969,6971,6973],{"class":3454,"line":3676},[3452,6970,6895],{"class":3953},[3452,6972,6898],{"class":3462},[3452,6974,5067],{"class":5066},[3452,6976,6977,6979,6981],{"class":3454,"line":3682},[3452,6978,6905],{"class":3953},[3452,6980,6908],{"class":3462},[3452,6982,5067],{"class":5066},[3452,6984,6985,6988,6991],{"class":3454,"line":3688},[3452,6986,6987],{"class":3953},"    --policy-name",[3452,6989,6990],{"class":3462}," cpu-target-70",[3452,6992,5067],{"class":5066},[3452,6994,6995,6998,7001],{"class":3454,"line":3694},[3452,6996,6997],{"class":3953},"    --policy-type",[3452,6999,7000],{"class":3462}," TargetTrackingScaling",[3452,7002,5067],{"class":5066},[3452,7004,7005,7008],{"class":3454,"line":3699},[3452,7006,7007],{"class":3953},"    --target-tracking-scaling-policy-configuration",[3452,7009,7010],{"class":3462}," '{\n",[3452,7012,7013],{"class":3454,"line":3705},[3452,7014,7015],{"class":3462},"        \"TargetValue\": 70.0,\n",[3452,7017,7018],{"class":3454,"line":3711},[3452,7019,7020],{"class":3462},"        \"PredefinedMetricSpecification\": {\n",[3452,7022,7023],{"class":3454,"line":3717},[3452,7024,7025],{"class":3462},"            \"PredefinedMetricType\": \"ECSServiceAverageCPUUtilization\"\n",[3452,7027,7028],{"class":3454,"line":3723},[3452,7029,7030],{"class":3462},"        },\n",[3452,7032,7033],{"class":3454,"line":3729},[3452,7034,7035],{"class":3462},"        \"ScaleInCooldown\": 300,\n",[3452,7037,7038],{"class":3454,"line":3734},[3452,7039,7040],{"class":3462},"        \"ScaleOutCooldown\": 60\n",[3452,7042,7043,7046],{"class":3454,"line":3740},[3452,7044,7045],{"class":3462},"    }'",[3452,7047,5067],{"class":5066},[3452,7049,7050,7052],{"class":3454,"line":3746},[3452,7051,6935],{"class":3953},[3452,7053,6938],{"class":3462},[5114,7055,7056,7061,7062,7067],{},[3540,7057,7058],{},[3449,7059,7060],{},"--min-capacity 2"," — для production-сервісу рекомендовано завжди підтримувати щонайменше 2 Tasks: це захищає від повного простою при падінні одного Task або під час rolling update. ",[3540,7063,7064],{},[3449,7065,7066],{},"--max-capacity 20"," — верхня межа захищає від неочікуваних витрат (наприклад, хиба у логіці політики, що змушує CPU зростати безмежно).",[3573,7069,7071],{"id":7070},"step-scaling-та-scheduled-scaling","Step Scaling та Scheduled Scaling",[3354,7073,7074,7077],{},[3540,7075,7076],{},"Step Scaling"," дозволяє задати різні кроки масштабування залежно від величини відхилення. Наприклад: CPU 70–80% → +1 Task, CPU 80–90% → +2 Tasks, CPU >90% → +4 Tasks.",[3354,7079,7080,7083],{},[3540,7081,7082],{},"Scheduled Scaling"," дозволяє масштабувати за розкладом — корисно, якщо навантаження передбачуване (наприклад, кожен день о 8:00 збільшувати мінімум до 5 Tasks).",[3588,7085,7086],{},[3442,7087,7089],{"className":3592,"code":7088,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"User Traffic\" as User\nrectangle \"Application Load Balancer\" as ALB #fef3c7\npackage \"ECS Service (Auto Scaling)\" #d1fae5 {\n    rectangle \"Task 1\" as T1 #bbf7d0\n    rectangle \"Task 2\" as T2 #bbf7d0\n    rectangle \"Task N...\" as TN #bbf7d0 {\n        note right\n          Додається автоматично\n          при CPU > 70%\n        end note\n    }\n}\nrectangle \"CloudWatch\u003Cbr\u002F>Metrics\" as CW #e0e7ff\nrectangle \"Auto Scaling\u003Cbr\u002F>Policy\" as ASP #fce7f3\n\nUser -down-> ALB\nALB -down-> T1\nALB -down-> T2\nALB -down-> TN\nT1 -right-> CW : CPU, Memory metrics\nT2 -right-> CW\nCW -down-> ASP : Alarm triggers\nASP -right-> \"ECS Service (Auto Scaling)\" : Scale Out\u002FIn\n@enduml\n",[3449,7090,7091,7095,7099,7103,7107,7112,7116,7121,7126,7131,7136,7141,7146,7151,7156,7160,7164,7169,7174,7178,7183,7188,7193,7198,7203,7208,7213,7218],{"__ignoreMap":3447},[3452,7092,7093],{"class":3454,"line":3455},[3452,7094,3601],{},[3452,7096,7097],{"class":3454,"line":3473},[3452,7098,3606],{},[3452,7100,7101],{"class":3454,"line":3609},[3452,7102,3612],{},[3452,7104,7105],{"class":3454,"line":3615},[3452,7106,3619],{"emptyLinePlaceholder":3618},[3452,7108,7109],{"class":3454,"line":3622},[3452,7110,7111],{},"actor \"User Traffic\" as User\n",[3452,7113,7114],{"class":3454,"line":3628},[3452,7115,5485],{},[3452,7117,7118],{"class":3454,"line":3634},[3452,7119,7120],{},"package \"ECS Service (Auto Scaling)\" #d1fae5 {\n",[3452,7122,7123],{"class":3454,"line":3640},[3452,7124,7125],{},"    rectangle \"Task 1\" as T1 #bbf7d0\n",[3452,7127,7128],{"class":3454,"line":3646},[3452,7129,7130],{},"    rectangle \"Task 2\" as T2 #bbf7d0\n",[3452,7132,7133],{"class":3454,"line":3652},[3452,7134,7135],{},"    rectangle \"Task N...\" as TN #bbf7d0 {\n",[3452,7137,7138],{"class":3454,"line":3658},[3452,7139,7140],{},"        note right\n",[3452,7142,7143],{"class":3454,"line":3664},[3452,7144,7145],{},"          Додається автоматично\n",[3452,7147,7148],{"class":3454,"line":3670},[3452,7149,7150],{},"          при CPU > 70%\n",[3452,7152,7153],{"class":3454,"line":3676},[3452,7154,7155],{},"        end note\n",[3452,7157,7158],{"class":3454,"line":3682},[3452,7159,3655],{},[3452,7161,7162],{"class":3454,"line":3688},[3452,7163,3691],{},[3452,7165,7166],{"class":3454,"line":3694},[3452,7167,7168],{},"rectangle \"CloudWatch\u003Cbr\u002F>Metrics\" as CW #e0e7ff\n",[3452,7170,7171],{"class":3454,"line":3699},[3452,7172,7173],{},"rectangle \"Auto Scaling\u003Cbr\u002F>Policy\" as ASP #fce7f3\n",[3452,7175,7176],{"class":3454,"line":3705},[3452,7177,3619],{"emptyLinePlaceholder":3618},[3452,7179,7180],{"class":3454,"line":3711},[3452,7181,7182],{},"User -down-> ALB\n",[3452,7184,7185],{"class":3454,"line":3717},[3452,7186,7187],{},"ALB -down-> T1\n",[3452,7189,7190],{"class":3454,"line":3723},[3452,7191,7192],{},"ALB -down-> T2\n",[3452,7194,7195],{"class":3454,"line":3729},[3452,7196,7197],{},"ALB -down-> TN\n",[3452,7199,7200],{"class":3454,"line":3734},[3452,7201,7202],{},"T1 -right-> CW : CPU, Memory metrics\n",[3452,7204,7205],{"class":3454,"line":3740},[3452,7206,7207],{},"T2 -right-> CW\n",[3452,7209,7210],{"class":3454,"line":3746},[3452,7211,7212],{},"CW -down-> ASP : Alarm triggers\n",[3452,7214,7215],{"class":3454,"line":3752},[3452,7216,7217],{},"ASP -right-> \"ECS Service (Auto Scaling)\" : Scale Out\u002FIn\n",[3452,7219,7220],{"class":3454,"line":3758},[3452,7221,3772],{},[3518,7223],{},[3349,7225,7227],{"id":7226},"application-load-balancer-для-ecs","Application Load Balancer для ECS",[3354,7229,7230],{},[3527,7231],{"alt":7232,"className":7233,"src":7234},"Application Load Balancer routing traffic to ECS Fargate tasks diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F11.png",[3354,7236,7237,7240],{},[3540,7238,7239],{},"Application Load Balancer (ALB)"," — це Layer 7 (HTTP\u002FHTTPS) балансувальник навантаження, який розподіляє вхідні запити між Tasks у ECS Service. Без ALB ваш застосунок буде доступний лише за приватною IP-адресою Task — що змінюється при кожному рестарті.",[3573,7242,7244],{"id":7243},"як-alb-інтегрується-з-ecs","Як ALB інтегрується з ECS",[3354,7246,7247,7248,7251,7252,7255],{},"Коли ECS Service запускає новий Task — він автоматично ",[3540,7249,7250],{},"реєструє"," IP Task у ",[3540,7253,7254],{},"Target Group"," ALB. Коли Task зупиняється — видаляє його. ALB завжди знає актуальний список здорових Tasks і направляє на них трафік.",[3354,7257,7258],{},[3540,7259,7260],{},"Ланцюжок запиту:",[3442,7262,7265],{"className":7263,"code":7264,"language":3856},[3854],"Internet → Route 53 (DNS) → ALB (HTTPS:443) → Target Group → Tasks (HTTP:8080)\n",[3449,7266,7264],{"__ignoreMap":3447},[3354,7268,7269],{},"ALB виконує SSL termination: приймає HTTPS від клієнта, розшифровує і передає у Tasks по звичайному HTTP — Tasks не потрібно конфігурувати SSL.",[3573,7271,7273],{"id":7272},"налаштування-alb-для-ecs-через-aws-cli","Налаштування ALB для ECS через AWS CLI",[3442,7275,7277],{"className":3444,"code":7276,"language":3446,"meta":3447,"style":3447},"# 0. Створіть сам ALB (публічний, розміщується в публічних підмережах)\nALB_ARN=$(aws elbv2 create-load-balancer \\\n    --name my-api-alb \\\n    --subnets subnet-aaa subnet-bbb \\\n    --security-groups sg-alb-id \\\n    --scheme internet-facing \\\n    --type application \\\n    --query \"LoadBalancers[0].LoadBalancerArn\" --output text \\\n    --region eu-central-1)\necho \"ALB ARN: $ALB_ARN\"\n\n# 1. Створіть Target Group (куди ALB направлятиме запити)\nTG_ARN=$(aws elbv2 create-target-group \\\n    --name my-api-tg \\\n    --protocol HTTP \\\n    --port 8080 \\\n    --vpc-id vpc-0a1b2c3d4e5f \\\n    --target-type ip \\\n    --health-check-path \u002Fhealth \\\n    --health-check-interval-seconds 30 \\\n    --healthy-threshold-count 2 \\\n    --unhealthy-threshold-count 3 \\\n    --query \"TargetGroups[0].TargetGroupArn\" --output text \\\n    --region eu-central-1)\necho \"Target Group ARN: $TG_ARN\"\n\n# 1b. Додайте HTTP Listener до ALB (порт 80 → Target Group)\naws elbv2 create-listener \\\n    --load-balancer-arn $ALB_ARN \\\n    --protocol HTTP --port 80 \\\n    --default-actions Type=forward,TargetGroupArn=$TG_ARN \\\n    --region eu-central-1\n\n# 2. Під час створення ECS Service — прив'яжіть Target Group\naws ecs create-service \\\n    --cluster production \\\n    --service-name my-api \\\n    --task-definition my-api:3 \\\n    --desired-count 3 \\\n    --launch-type FARGATE \\\n    --load-balancers \"targetGroupArn=$TG_ARN,containerName=my-api,containerPort=8080\" \\\n    --network-configuration \"awsvpcConfiguration={subnets=[subnet-xxx,subnet-yyy],securityGroups=[sg-zzz],assignPublicIp=DISABLED}\"\n",[3449,7278,7279,7284,7302,7312,7325,7335,7345,7355,7371,7381,7395,7399,7404,7420,7429,7439,7449,7459,7469,7479,7489,7498,7508,7521,7529,7541,7545,7550,7561,7571,7585,7597,7603,7607,7612,7623,7633,7643,7653,7662,7672,7687],{"__ignoreMap":3447},[3452,7280,7281],{"class":3454,"line":3455},[3452,7282,7283],{"class":3469},"# 0. Створіть сам ALB (публічний, розміщується в публічних підмережах)\n",[3452,7285,7286,7289,7292,7294,7297,7300],{"class":3454,"line":3473},[3452,7287,7288],{"class":3957},"ALB_ARN",[3452,7290,7291],{"class":3961},"=$(",[3452,7293,3459],{"class":3458},[3452,7295,7296],{"class":3462}," elbv2",[3452,7298,7299],{"class":3462}," create-load-balancer",[3452,7301,5067],{"class":5066},[3452,7303,7304,7307,7310],{"class":3454,"line":3609},[3452,7305,7306],{"class":3953},"    --name",[3452,7308,7309],{"class":3462}," my-api-alb",[3452,7311,5067],{"class":5066},[3452,7313,7314,7317,7320,7323],{"class":3454,"line":3615},[3452,7315,7316],{"class":3953},"    --subnets",[3452,7318,7319],{"class":3462}," subnet-aaa",[3452,7321,7322],{"class":3462}," subnet-bbb",[3452,7324,5067],{"class":5066},[3452,7326,7327,7330,7333],{"class":3454,"line":3622},[3452,7328,7329],{"class":3953},"    --security-groups",[3452,7331,7332],{"class":3462}," sg-alb-id",[3452,7334,5067],{"class":5066},[3452,7336,7337,7340,7343],{"class":3454,"line":3628},[3452,7338,7339],{"class":3953},"    --scheme",[3452,7341,7342],{"class":3462}," internet-facing",[3452,7344,5067],{"class":5066},[3452,7346,7347,7350,7353],{"class":3454,"line":3634},[3452,7348,7349],{"class":3953},"    --type",[3452,7351,7352],{"class":3462}," application",[3452,7354,5067],{"class":5066},[3452,7356,7357,7360,7363,7366,7369],{"class":3454,"line":3640},[3452,7358,7359],{"class":3953},"    --query",[3452,7361,7362],{"class":3462}," \"LoadBalancers[0].LoadBalancerArn\"",[3452,7364,7365],{"class":3953}," --output",[3452,7367,7368],{"class":3462}," text",[3452,7370,5067],{"class":5066},[3452,7372,7373,7375,7378],{"class":3454,"line":3646},[3452,7374,6935],{"class":3953},[3452,7376,7377],{"class":3462}," eu-central-1",[3452,7379,7380],{"class":3961},")\n",[3452,7382,7383,7386,7389,7392],{"class":3454,"line":3652},[3452,7384,7385],{"class":3458},"echo",[3452,7387,7388],{"class":3462}," \"ALB ARN: ",[3452,7390,7391],{"class":3957},"$ALB_ARN",[3452,7393,7394],{"class":3462},"\"\n",[3452,7396,7397],{"class":3454,"line":3658},[3452,7398,3619],{"emptyLinePlaceholder":3618},[3452,7400,7401],{"class":3454,"line":3664},[3452,7402,7403],{"class":3469},"# 1. Створіть Target Group (куди ALB направлятиме запити)\n",[3452,7405,7406,7409,7411,7413,7415,7418],{"class":3454,"line":3670},[3452,7407,7408],{"class":3957},"TG_ARN",[3452,7410,7291],{"class":3961},[3452,7412,3459],{"class":3458},[3452,7414,7296],{"class":3462},[3452,7416,7417],{"class":3462}," create-target-group",[3452,7419,5067],{"class":5066},[3452,7421,7422,7424,7427],{"class":3454,"line":3676},[3452,7423,7306],{"class":3953},[3452,7425,7426],{"class":3462}," my-api-tg",[3452,7428,5067],{"class":5066},[3452,7430,7431,7434,7437],{"class":3454,"line":3682},[3452,7432,7433],{"class":3953},"    --protocol",[3452,7435,7436],{"class":3462}," HTTP",[3452,7438,5067],{"class":5066},[3452,7440,7441,7444,7447],{"class":3454,"line":3688},[3452,7442,7443],{"class":3953},"    --port",[3452,7445,7446],{"class":4152}," 8080",[3452,7448,5067],{"class":5066},[3452,7450,7451,7454,7457],{"class":3454,"line":3694},[3452,7452,7453],{"class":3953},"    --vpc-id",[3452,7455,7456],{"class":3462}," vpc-0a1b2c3d4e5f",[3452,7458,5067],{"class":5066},[3452,7460,7461,7464,7467],{"class":3454,"line":3699},[3452,7462,7463],{"class":3953},"    --target-type",[3452,7465,7466],{"class":3462}," ip",[3452,7468,5067],{"class":5066},[3452,7470,7471,7474,7477],{"class":3454,"line":3705},[3452,7472,7473],{"class":3953},"    --health-check-path",[3452,7475,7476],{"class":3462}," \u002Fhealth",[3452,7478,5067],{"class":5066},[3452,7480,7481,7484,7487],{"class":3454,"line":3711},[3452,7482,7483],{"class":3953},"    --health-check-interval-seconds",[3452,7485,7486],{"class":4152}," 30",[3452,7488,5067],{"class":5066},[3452,7490,7491,7494,7496],{"class":3454,"line":3717},[3452,7492,7493],{"class":3953},"    --healthy-threshold-count",[3452,7495,6918],{"class":4152},[3452,7497,5067],{"class":5066},[3452,7499,7500,7503,7506],{"class":3454,"line":3723},[3452,7501,7502],{"class":3953},"    --unhealthy-threshold-count",[3452,7504,7505],{"class":4152}," 3",[3452,7507,5067],{"class":5066},[3452,7509,7510,7512,7515,7517,7519],{"class":3454,"line":3729},[3452,7511,7359],{"class":3953},[3452,7513,7514],{"class":3462}," \"TargetGroups[0].TargetGroupArn\"",[3452,7516,7365],{"class":3953},[3452,7518,7368],{"class":3462},[3452,7520,5067],{"class":5066},[3452,7522,7523,7525,7527],{"class":3454,"line":3734},[3452,7524,6935],{"class":3953},[3452,7526,7377],{"class":3462},[3452,7528,7380],{"class":3961},[3452,7530,7531,7533,7536,7539],{"class":3454,"line":3740},[3452,7532,7385],{"class":3458},[3452,7534,7535],{"class":3462}," \"Target Group ARN: ",[3452,7537,7538],{"class":3957},"$TG_ARN",[3452,7540,7394],{"class":3462},[3452,7542,7543],{"class":3454,"line":3746},[3452,7544,3619],{"emptyLinePlaceholder":3618},[3452,7546,7547],{"class":3454,"line":3752},[3452,7548,7549],{"class":3469},"# 1b. Додайте HTTP Listener до ALB (порт 80 → Target Group)\n",[3452,7551,7552,7554,7556,7559],{"class":3454,"line":3758},[3452,7553,3459],{"class":3458},[3452,7555,7296],{"class":3462},[3452,7557,7558],{"class":3462}," create-listener",[3452,7560,5067],{"class":5066},[3452,7562,7563,7566,7569],{"class":3454,"line":3764},[3452,7564,7565],{"class":3953},"    --load-balancer-arn",[3452,7567,7568],{"class":3957}," $ALB_ARN",[3452,7570,5067],{"class":5066},[3452,7572,7573,7575,7577,7580,7583],{"class":3454,"line":3769},[3452,7574,7433],{"class":3953},[3452,7576,7436],{"class":3462},[3452,7578,7579],{"class":3953}," --port",[3452,7581,7582],{"class":4152}," 80",[3452,7584,5067],{"class":5066},[3452,7586,7587,7590,7593,7595],{"class":3454,"line":4629},[3452,7588,7589],{"class":3953},"    --default-actions",[3452,7591,7592],{"class":3462}," Type=forward,TargetGroupArn=",[3452,7594,7538],{"class":3957},[3452,7596,5067],{"class":5066},[3452,7598,7599,7601],{"class":3454,"line":4637},[3452,7600,6935],{"class":3953},[3452,7602,6938],{"class":3462},[3452,7604,7605],{"class":3454,"line":4642},[3452,7606,3619],{"emptyLinePlaceholder":3618},[3452,7608,7609],{"class":3454,"line":4648},[3452,7610,7611],{"class":3469},"# 2. Під час створення ECS Service — прив'яжіть Target Group\n",[3452,7613,7614,7616,7618,7621],{"class":3454,"line":4654},[3452,7615,3459],{"class":3458},[3452,7617,6888],{"class":3462},[3452,7619,7620],{"class":3462}," create-service",[3452,7622,5067],{"class":5066},[3452,7624,7625,7628,7631],{"class":3454,"line":4660},[3452,7626,7627],{"class":3953},"    --cluster",[3452,7629,7630],{"class":3462}," production",[3452,7632,5067],{"class":5066},[3452,7634,7635,7638,7641],{"class":3454,"line":4668},[3452,7636,7637],{"class":3953},"    --service-name",[3452,7639,7640],{"class":3462}," my-api",[3452,7642,5067],{"class":5066},[3452,7644,7645,7648,7651],{"class":3454,"line":4673},[3452,7646,7647],{"class":3953},"    --task-definition",[3452,7649,7650],{"class":3462}," my-api:3",[3452,7652,5067],{"class":5066},[3452,7654,7655,7658,7660],{"class":3454,"line":4679},[3452,7656,7657],{"class":3953},"    --desired-count",[3452,7659,7505],{"class":4152},[3452,7661,5067],{"class":5066},[3452,7663,7664,7667,7670],{"class":3454,"line":5908},[3452,7665,7666],{"class":3953},"    --launch-type",[3452,7668,7669],{"class":3462}," FARGATE",[3452,7671,5067],{"class":5066},[3452,7673,7674,7677,7680,7682,7685],{"class":3454,"line":5920},[3452,7675,7676],{"class":3953},"    --load-balancers",[3452,7678,7679],{"class":3462}," \"targetGroupArn=",[3452,7681,7538],{"class":3957},[3452,7683,7684],{"class":3462},",containerName=my-api,containerPort=8080\"",[3452,7686,5067],{"class":5066},[3452,7688,7689,7692],{"class":3454,"line":5933},[3452,7690,7691],{"class":3953},"    --network-configuration",[3452,7693,7694],{"class":3462}," \"awsvpcConfiguration={subnets=[subnet-xxx,subnet-yyy],securityGroups=[sg-zzz],assignPublicIp=DISABLED}\"\n",[3354,7696,7697,7698,7701,7702,7704],{},"Зверніть увагу: ",[3449,7699,7700],{},"--target-type ip"," — це специфічно для Fargate та awsvpc режиму, де кожен Task має власний IP. ALB звертається до Task безпосередньо по IP, а не через порт на хості. Security Group ALB повинна дозволяти вхід на порт 80\u002F443 з ",[3449,7703,6420],{},", а Security Group Tasks — вхід на порт 8080 лише з Security Group ALB.",[3518,7706],{},[3349,7708,7710],{"id":7709},"rolling-updates-оновлення-без-зупинки-сервісу","Rolling Updates — оновлення без зупинки сервісу",[3354,7712,7713],{},[3527,7714],{"alt":7715,"className":7716,"src":7717},"ECS Rolling update strategy zero downtime deployment old and new tasks",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F12.png",[3354,7719,7720,7723,7724,7727],{},[3540,7721,7722],{},"Rolling update"," — це стратегія оновлення, яка дозволяє замінити стару версію застосунку новою ",[3540,7725,7726],{},"без жодного часу простою (downtime)",". ECS Service виконує rolling update автоматично щоразу, коли ви змінюєте Task Definition.",[3354,7729,7730],{},[3540,7731,7732],{},"Як це працює покроково:",[3354,7734,7735,7736,7739,7740,7743,7744,3491,7747,3516],{},"Припустимо, у вас 4 Tasks з версією ",[3449,7737,7738],{},"v1.2.3",", і ви хочете оновитись до ",[3449,7741,7742],{},"v1.3.0",". Конфігурація: ",[3449,7745,7746],{},"minimumHealthyPercent=50",[3449,7748,7749],{},"maximumPercent=200",[7751,7752,7753,7756,7759,7762,7765],"ol",{},[4702,7754,7755],{},"ALB продовжує направляти трафік на всі 4 Tasks (v1.2.3)",[4702,7757,7758],{},"ECS запускає 4 нових Tasks (v1.3.0) — тепер запущено 8 Tasks (200% від бажаних 4)",[4702,7760,7761],{},"ECS чекає, поки нові Tasks пройдуть health check і зареєструються в ALB",[4702,7763,7764],{},"ECS зупиняє 4 старих Tasks (v1.2.3) — залишається 4 Tasks (v1.3.0), 100%",[4702,7766,7767],{},"Оновлення завершено, ALB направляє трафік на v1.3.0",[3354,7769,7770,7771,7773],{},"У будь-який момент процесу ",[3449,7772,7746],{}," гарантує, що щонайменше 2 Tasks (50% від 4) залишаються здоровими.",[5114,7775,7776,7779,7780,3516],{},[3540,7777,7778],{},"Нова версія образу в ECR не запускається автоматично."," ECS запам'ятовує конкретний digest образу в Task Definition. Щоб запустити оновлений образ — оновіть Task Definition (вкажіть новий тег або sha256 digest) та оновіть Service. Це захищає від ненавмисних оновлень через зміну тегу ",[3449,7781,7782],{},":latest",[3518,7784],{},[3354,7786,7787],{},[3527,7788],{"alt":7789,"className":7790,"src":7791},"Amazon EKS Kubernetes managed service architecture control plane and worker nodes",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F13.jpg",[3349,7793,7795],{"id":7794},"amazon-eks-огляд-kubernetes-на-aws","Amazon EKS — огляд Kubernetes на AWS",[3354,7797,7798,7801],{},[3540,7799,7800],{},"Amazon Elastic Kubernetes Service (EKS)"," — це керований сервіс Kubernetes від AWS.",[3588,7803,7804],{},[3442,7805,7807],{"className":3592,"code":7806,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"Amazon EKS Cluster\" #e9ecef {\n    rectangle \"Control Plane\" as CP #dbeafe {\n        rectangle \"API Server\" as API #bfdbfe\n        rectangle \"etcd\" as ETCD #bfdbfe\n        rectangle \"Scheduler\" as SCH #bfdbfe\n        rectangle \"Controller\\nManager\" as CM #bfdbfe\n    }\n\n    rectangle \"Worker Nodes (EC2)\" as WN #d1fae5 {\n        rectangle \"Pod: UserService\" as P1 #bbf7d0\n        rectangle \"Pod: OrderService\" as P2 #bbf7d0\n        rectangle \"Pod: Notification\" as P3 #bbf7d0\n    }\n\n    rectangle \"Fargate Profile\" as FP #fef3c7 {\n        rectangle \"Pod on Fargate\" as P4 #fde68a\n    }\n}\n\nrectangle \"AWS Managed\" as AWS #f3f4f6\nCP -down--> WN : manages\nCP -down--> FP : manages\nAWS --> CP : manages control plane\n@enduml\n",[3449,7808,7809,7813,7817,7821,7825,7830,7835,7840,7845,7850,7855,7859,7863,7868,7873,7878,7883,7887,7891,7896,7901,7905,7909,7913,7918,7923,7928,7933],{"__ignoreMap":3447},[3452,7810,7811],{"class":3454,"line":3455},[3452,7812,3601],{},[3452,7814,7815],{"class":3454,"line":3473},[3452,7816,3606],{},[3452,7818,7819],{"class":3454,"line":3609},[3452,7820,3612],{},[3452,7822,7823],{"class":3454,"line":3615},[3452,7824,3619],{"emptyLinePlaceholder":3618},[3452,7826,7827],{"class":3454,"line":3622},[3452,7828,7829],{},"package \"Amazon EKS Cluster\" #e9ecef {\n",[3452,7831,7832],{"class":3454,"line":3628},[3452,7833,7834],{},"    rectangle \"Control Plane\" as CP #dbeafe {\n",[3452,7836,7837],{"class":3454,"line":3634},[3452,7838,7839],{},"        rectangle \"API Server\" as API #bfdbfe\n",[3452,7841,7842],{"class":3454,"line":3640},[3452,7843,7844],{},"        rectangle \"etcd\" as ETCD #bfdbfe\n",[3452,7846,7847],{"class":3454,"line":3646},[3452,7848,7849],{},"        rectangle \"Scheduler\" as SCH #bfdbfe\n",[3452,7851,7852],{"class":3454,"line":3652},[3452,7853,7854],{},"        rectangle \"Controller\\nManager\" as CM #bfdbfe\n",[3452,7856,7857],{"class":3454,"line":3658},[3452,7858,3655],{},[3452,7860,7861],{"class":3454,"line":3664},[3452,7862,3619],{"emptyLinePlaceholder":3618},[3452,7864,7865],{"class":3454,"line":3670},[3452,7866,7867],{},"    rectangle \"Worker Nodes (EC2)\" as WN #d1fae5 {\n",[3452,7869,7870],{"class":3454,"line":3676},[3452,7871,7872],{},"        rectangle \"Pod: UserService\" as P1 #bbf7d0\n",[3452,7874,7875],{"class":3454,"line":3682},[3452,7876,7877],{},"        rectangle \"Pod: OrderService\" as P2 #bbf7d0\n",[3452,7879,7880],{"class":3454,"line":3688},[3452,7881,7882],{},"        rectangle \"Pod: Notification\" as P3 #bbf7d0\n",[3452,7884,7885],{"class":3454,"line":3694},[3452,7886,3655],{},[3452,7888,7889],{"class":3454,"line":3699},[3452,7890,3619],{"emptyLinePlaceholder":3618},[3452,7892,7893],{"class":3454,"line":3705},[3452,7894,7895],{},"    rectangle \"Fargate Profile\" as FP #fef3c7 {\n",[3452,7897,7898],{"class":3454,"line":3711},[3452,7899,7900],{},"        rectangle \"Pod on Fargate\" as P4 #fde68a\n",[3452,7902,7903],{"class":3454,"line":3717},[3452,7904,3655],{},[3452,7906,7907],{"class":3454,"line":3723},[3452,7908,3691],{},[3452,7910,7911],{"class":3454,"line":3729},[3452,7912,3619],{"emptyLinePlaceholder":3618},[3452,7914,7915],{"class":3454,"line":3734},[3452,7916,7917],{},"rectangle \"AWS Managed\" as AWS #f3f4f6\n",[3452,7919,7920],{"class":3454,"line":3740},[3452,7921,7922],{},"CP -down--> WN : manages\n",[3452,7924,7925],{"class":3454,"line":3746},[3452,7926,7927],{},"CP -down--> FP : manages\n",[3452,7929,7930],{"class":3454,"line":3752},[3452,7931,7932],{},"AWS --> CP : manages control plane\n",[3452,7934,7935],{"class":3454,"line":3758},[3452,7936,3772],{},[3354,7938,7939,7940,7943],{},"Він надає повноцінний Kubernetes кластер, де AWS бере на себе управління ",[3540,7941,7942],{},"control plane"," (API Server, etcd, Controller Manager, Scheduler) — найскладнішою і найкритичнішою частиною Kubernetes.",[3573,7945,7947],{"id":7946},"kubernetes-і-ecs-в-чому-різниця","Kubernetes і ECS — в чому різниця?",[3354,7949,7950,7951,7954],{},"Якщо ECS — це «AWS-рідний» оркестратор, розроблений Amazon, то Kubernetes — це ",[3540,7952,7953],{},"відкритий галузевий стандарт"," оркестрації контейнерів, розроблений Google і переданий у CNCF (Cloud Native Computing Foundation).",[6295,7956,7957,7978],{},[6298,7958,7961],{"icon":7959,"title":7960},"i-simple-icons-amazonaws","Amazon ECS",[4699,7962,7963,7966,7969,7972,7975],{},[4702,7964,7965],{},"Розроблений Amazon, нативно інтегрований з AWS",[4702,7967,7968],{},"Значно простіший в налаштуванні та управлінні",[4702,7970,7971],{},"Менше концепцій для вивчення",[4702,7973,7974],{},"Менша гнучкість і екосистема",[4702,7976,7977],{},"Ідеальний вибір, якщо ви не плануєте мігрувати між провайдерами",[6298,7979,7982],{"icon":7980,"title":7981},"i-simple-icons-kubernetes","Amazon EKS (Kubernetes)",[4699,7983,7984,7987,7990,7993,7996],{},[4702,7985,7986],{},"Відкритий стандарт, мультихмарний (AWS, Azure, GCP, on-premises)",[4702,7988,7989],{},"Значно потужніша екосистема (Helm, Istio, ArgoCD, Prometheus)",[4702,7991,7992],{},"Складніший: потрібно розуміти Pods, Deployments, Services, Ingress, RBAC тощо",[4702,7994,7995],{},"Вища гнучкість та контроль",[4702,7997,7998],{},"Краще для великих команд із K8s-досвідом",[3354,8000,8001],{},[3540,8002,8003],{},"Коли обирати EKS?",[4699,8005,8006,8009,8012,8015,8018],{},[4702,8007,8008],{},"Команда вже має Kubernetes-досвід",[4702,8010,8011],{},"Потреба у мультихмарній або гібридній архітектурі",[4702,8013,8014],{},"Складні networking вимоги (service mesh, mutual TLS)",[4702,8016,8017],{},"Розширена екосистема: Helm charts, GitOps (ArgoCD\u002FFlux), observability стек (Prometheus + Grafana)",[4702,8019,8020],{},"Потреба у більшому контролі над scheduling (node affinity, tolerations, pod disruption budgets)",[3565,8022,8023,8024,8027],{},"У цьому курсі ми зосереджуємось на ",[3540,8025,8026],{},"ECS Fargate"," як оптимальному варіанті для .NET розробників без глибокого DevOps-досвіду. Kubernetes і EKS є окремою великою темою, яка заслуговує власного курсу. Базовий огляд K8s ви вже маєте з розділу про інструменти DevOps.",[3573,8029,8031],{"id":8030},"ecs-vs-eks-vs-fargate-підсумкова-таблиця","ECS vs EKS vs Fargate: підсумкова таблиця",[3358,8033,8034,8053],{},[3361,8035,8036],{},[3364,8037,8038,8041,8044,8047,8050],{},[3367,8039,8040],{},"Характеристика",[3367,8042,8043],{},"ECS + EC2",[3367,8045,8046],{},"ECS + Fargate",[3367,8048,8049],{},"EKS + EC2",[3367,8051,8052],{},"EKS + Fargate",[3377,8054,8055,8071,8086,8104,8119,8136,8153],{},[3364,8056,8057,8062,8065,8067,8069],{},[3382,8058,8059],{},[3540,8060,8061],{},"Управління серверами",[3382,8063,8064],{},"Ви",[3382,8066,3205],{},[3382,8068,8064],{},[3382,8070,3205],{},[3364,8072,8073,8078,8080,8082,8084],{},[3382,8074,8075],{},[3540,8076,8077],{},"Управління K8s control plane",[3382,8079,3434],{},[3382,8081,3434],{},[3382,8083,3205],{},[3382,8085,3205],{},[3364,8087,8088,8093,8096,8099,8102],{},[3382,8089,8090],{},[3540,8091,8092],{},"Складність налаштування",[3382,8094,8095],{},"Середня",[3382,8097,8098],{},"Низька",[3382,8100,8101],{},"Висока",[3382,8103,8101],{},[3364,8105,8106,8111,8113,8115,8117],{},[3382,8107,8108],{},[3540,8109,8110],{},"Гнучкість",[3382,8112,8095],{},[3382,8114,8098],{},[3382,8116,8101],{},[3382,8118,8095],{},[3364,8120,8121,8126,8129,8132,8134],{},[3382,8122,8123],{},[3540,8124,8125],{},"Вартість",[3382,8127,8128],{},"Нижча",[3382,8130,8131],{},"Вища",[3382,8133,8128],{},[3382,8135,8131],{},[3364,8137,8138,8143,8146,8148,8151],{},[3382,8139,8140],{},[3540,8141,8142],{},"Мультихмарність",[3382,8144,8145],{},"❌",[3382,8147,8145],{},[3382,8149,8150],{},"✅",[3382,8152,8150],{},[3364,8154,8155,8160,8163,8166,8169],{},[3382,8156,8157],{},[3540,8158,8159],{},"Рекомендовано для",[3382,8161,8162],{},"Досвідчені DevOps",[3382,8164,8165],{},"Малі команди, MVP",[3382,8167,8168],{},"Великі команди з K8s",[3382,8170,8171],{},"Складні K8s, без серверів",[3518,8173],{},[3354,8175,8176],{},[3527,8177],{"alt":8178,"className":8179,"src":8180},"ECS environment variables and secrets configuration from Task Definition to .NET IConfiguration",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F14.png",[3349,8182,8184],{"id":8183},"environment-variables-у-ecs-task-definitions-специфіка-net","Environment Variables у ECS Task Definitions — специфіка .NET",[3573,8186,8188],{"id":8187},"проблема-конфігурація-у-контейнерному-середовищі","Проблема: конфігурація у контейнерному середовищі",[3354,8190,8191,8192,8195],{},".NET традиційно зберігає конфігурацію в ",[3449,8193,8194],{},"appsettings.json",". У Docker-контейнері це проблема: конфіг «запечений» у образ і не може відрізнятись між dev та production без перезбірки образу.",[3354,8197,8198,8201,8202,8207,8208,8211],{},[3540,8199,8200],{},"Правильний підхід:"," дотримання принципу ",[3385,8203,8206],{"href":8204,"rel":8205},"https:\u002F\u002F12factor.net\u002F",[3389],"12-Factor App"," — конфігурація зберігається у ",[3540,8209,8210],{},"змінних середовища"," (environment variables), які передаються контейнеру при запуску.",[3354,8213,8214,8215,8218,8219,8221,8222,4878],{},"ASP.NET Core автоматично читає змінні середовища через ",[3449,8216,8217],{},"IConfiguration"," — жодних додаткових налаштувань не потрібно. Ієрархічні ключі з ",[3449,8220,8194],{}," відповідають змінним з подвійним підкресленням ",[3449,8223,8224],{},"__",[3442,8226,8228],{"className":5521,"code":8227,"language":5523,"meta":3447,"style":3447},"\u002F\u002F appsettings.json\n{\n    \"ConnectionStrings\": {\n        \"DefaultConnection\": \"будь-яке значення\"\n    },\n    \"Feature\": {\n        \"MaxItems\": 100\n    }\n}\n",[3449,8229,8230,8235,8239,8246,8256,8260,8267,8277,8281],{"__ignoreMap":3447},[3452,8231,8232],{"class":3454,"line":3455},[3452,8233,8234],{"class":3469},"\u002F\u002F appsettings.json\n",[3452,8236,8237],{"class":3454,"line":3473},[3452,8238,4097],{"class":3961},[3452,8240,8241,8244],{"class":3454,"line":3609},[3452,8242,8243],{"class":5534},"    \"ConnectionStrings\"",[3452,8245,5807],{"class":3961},[3452,8247,8248,8251,8253],{"class":3454,"line":3615},[3452,8249,8250],{"class":5534},"        \"DefaultConnection\"",[3452,8252,5538],{"class":3961},[3452,8254,8255],{"class":3462},"\"будь-яке значення\"\n",[3452,8257,8258],{"class":3454,"line":3622},[3452,8259,6802],{"class":3961},[3452,8261,8262,8265],{"class":3454,"line":3628},[3452,8263,8264],{"class":5534},"    \"Feature\"",[3452,8266,5807],{"class":3961},[3452,8268,8269,8272,8274],{"class":3454,"line":3634},[3452,8270,8271],{"class":5534},"        \"MaxItems\"",[3452,8273,5538],{"class":3961},[3452,8275,8276],{"class":4152},"100\n",[3452,8278,8279],{"class":3454,"line":3640},[3452,8280,3655],{"class":3961},[3452,8282,8283],{"class":3454,"line":3646},[3452,8284,3691],{"class":3961},[3354,8286,8287],{},"Відповідні змінні середовища:",[3442,8289,8291],{"className":3444,"code":8290,"language":3446,"meta":3447,"style":3447},"ConnectionStrings__DefaultConnection=Host=prod-db;Database=mydb;...\nFeature__MaxItems=50\n",[3449,8292,8293,8325],{"__ignoreMap":3447},[3452,8294,8295,8298,8301,8304,8306,8309,8312,8315,8317,8320,8322],{"class":3454,"line":3455},[3452,8296,8297],{"class":3957},"ConnectionStrings__DefaultConnection",[3452,8299,8300],{"class":3961},"=",[3452,8302,8303],{"class":3957},"Host",[3452,8305,8300],{"class":3961},[3452,8307,8308],{"class":3462},"prod-db",[3452,8310,8311],{"class":3961},";",[3452,8313,8314],{"class":3957},"Database",[3452,8316,8300],{"class":3961},[3452,8318,8319],{"class":3462},"mydb",[3452,8321,8311],{"class":3961},[3452,8323,8324],{"class":3458},"...\n",[3452,8326,8327,8330,8332],{"class":3454,"line":3473},[3452,8328,8329],{"class":3957},"Feature__MaxItems",[3452,8331,8300],{"class":3961},[3452,8333,8334],{"class":3462},"50\n",[3573,8336,8338],{"id":8337},"де-зберігати-секрети-в-ecs","Де зберігати секрети в ECS",[3354,8340,8341],{},"У Task Definition є два способи передачі конфігурації:",[3354,8343,8344,8348,8349,8352],{},[3540,8345,8346],{},[3449,8347,6004],{}," — для ",[3540,8350,8351],{},"незасекреченої"," конфігурації:",[3442,8354,8356],{"className":5521,"code":8355,"language":5523,"meta":3447,"style":3447},"\"environment\": [\n    {\"name\": \"ASPNETCORE_ENVIRONMENT\", \"value\": \"Production\"},\n    {\"name\": \"Feature__MaxItems\", \"value\": \"100\"},\n    {\"name\": \"Logging__LogLevel__Default\", \"value\": \"Warning\"}\n]\n",[3449,8357,8358,8365,8387,8409,8431],{"__ignoreMap":3447},[3452,8359,8360,8363],{"class":3454,"line":3455},[3452,8361,8362],{"class":3462},"\"environment\"",[3452,8364,5626],{"class":3961},[3452,8366,8367,8370,8372,8374,8376,8378,8380,8382,8384],{"class":3454,"line":3473},[3452,8368,8369],{"class":3961},"    {",[3452,8371,5713],{"class":5534},[3452,8373,5538],{"class":3961},[3452,8375,5718],{"class":3462},[3452,8377,3491],{"class":3961},[3452,8379,5723],{"class":5534},[3452,8381,5538],{"class":3961},[3452,8383,5728],{"class":3462},[3452,8385,8386],{"class":3961},"},\n",[3452,8388,8389,8391,8393,8395,8398,8400,8402,8404,8407],{"class":3454,"line":3609},[3452,8390,8369],{"class":3961},[3452,8392,5713],{"class":5534},[3452,8394,5538],{"class":3961},[3452,8396,8397],{"class":3462},"\"Feature__MaxItems\"",[3452,8399,3491],{"class":3961},[3452,8401,5723],{"class":5534},[3452,8403,5538],{"class":3961},[3452,8405,8406],{"class":3462},"\"100\"",[3452,8408,8386],{"class":3961},[3452,8410,8411,8413,8415,8417,8420,8422,8424,8426,8429],{"class":3454,"line":3615},[3452,8412,8369],{"class":3961},[3452,8414,5713],{"class":5534},[3452,8416,5538],{"class":3961},[3452,8418,8419],{"class":3462},"\"Logging__LogLevel__Default\"",[3452,8421,3491],{"class":3961},[3452,8423,5723],{"class":5534},[3452,8425,5538],{"class":3961},[3452,8427,8428],{"class":3462},"\"Warning\"",[3452,8430,3691],{"class":3961},[3452,8432,8433],{"class":3454,"line":3622},[3452,8434,4511],{"class":3961},[3354,8436,8437,8348,8441,8444],{},[3540,8438,8439],{},[3449,8440,6000],{},[3540,8442,8443],{},"секретів"," (паролі, API ключі, connection strings). Значення не зберігається у Task Definition у відкритому вигляді — ECS агент завантажує секрет з AWS Secrets Manager або SSM Parameter Store під час запуску:",[3442,8446,8448],{"className":5521,"code":8447,"language":5523,"meta":3447,"style":3447},"\"secrets\": [\n    {\n        \"name\": \"ConnectionStrings__DefaultConnection\",\n        \"valueFrom\": \"arn:aws:secretsmanager:eu-central-1:123456789012:secret:prod\u002Fdb-conn\"\n    },\n    {\n        \"name\": \"ExternalApi__ApiKey\",\n        \"valueFrom\": \"\u002Fprod\u002Fexternal-api\u002Fkey\"\n    }\n]\n",[3449,8449,8450,8457,8461,8472,8482,8486,8490,8501,8510,8514],{"__ignoreMap":3447},[3452,8451,8452,8455],{"class":3454,"line":3455},[3452,8453,8454],{"class":3462},"\"secrets\"",[3452,8456,5626],{"class":3961},[3452,8458,8459],{"class":3454,"line":3473},[3452,8460,4180],{"class":3961},[3452,8462,8463,8466,8468,8470],{"class":3454,"line":3609},[3452,8464,8465],{"class":5534},"        \"name\"",[3452,8467,5538],{"class":3961},[3452,8469,5779],{"class":3462},[3452,8471,5544],{"class":3961},[3452,8473,8474,8477,8479],{"class":3454,"line":3615},[3452,8475,8476],{"class":5534},"        \"valueFrom\"",[3452,8478,5538],{"class":3961},[3452,8480,8481],{"class":3462},"\"arn:aws:secretsmanager:eu-central-1:123456789012:secret:prod\u002Fdb-conn\"\n",[3452,8483,8484],{"class":3454,"line":3622},[3452,8485,6802],{"class":3961},[3452,8487,8488],{"class":3454,"line":3628},[3452,8489,4180],{"class":3961},[3452,8491,8492,8494,8496,8499],{"class":3454,"line":3634},[3452,8493,8465],{"class":5534},[3452,8495,5538],{"class":3961},[3452,8497,8498],{"class":3462},"\"ExternalApi__ApiKey\"",[3452,8500,5544],{"class":3961},[3452,8502,8503,8505,8507],{"class":3454,"line":3640},[3452,8504,8476],{"class":5534},[3452,8506,5538],{"class":3961},[3452,8508,8509],{"class":3462},"\"\u002Fprod\u002Fexternal-api\u002Fkey\"\n",[3452,8511,8512],{"class":3454,"line":3646},[3452,8513,3655],{"class":3961},[3452,8515,8516],{"class":3454,"line":3652},[3452,8517,4511],{"class":3961},[3354,8519,8520,8521,4878],{},"У .NET-коді все виглядає однаково через ",[3449,8522,8217],{},[3442,8524,8526],{"className":3944,"code":8525,"language":3946,"meta":3447,"style":3447},"\u002F\u002F Program.cs — нічого особливого, стандартна конфігурація\nvar connectionString = builder.Configuration.GetConnectionString(\"DefaultConnection\");\nvar apiKey = builder.Configuration[\"ExternalApi:ApiKey\"];\n",[3449,8527,8528,8533,8561],{"__ignoreMap":3447},[3452,8529,8530],{"class":3454,"line":3455},[3452,8531,8532],{"class":3469},"\u002F\u002F Program.cs — нічого особливого, стандартна конфігурація\n",[3452,8534,8535,8537,8540,8542,8544,8546,8549,8551,8554,8556,8559],{"class":3454,"line":3473},[3452,8536,3954],{"class":3953},[3452,8538,8539],{"class":3957}," connectionString",[3452,8541,3962],{"class":3961},[3452,8543,3988],{"class":3957},[3452,8545,3516],{"class":3961},[3452,8547,8548],{"class":3957},"Configuration",[3452,8550,3516],{"class":3961},[3452,8552,8553],{"class":3458},"GetConnectionString",[3452,8555,3973],{"class":3961},[3452,8557,8558],{"class":3462},"\"DefaultConnection\"",[3452,8560,3979],{"class":3961},[3452,8562,8563,8565,8568,8570,8572,8574,8576,8578,8581],{"class":3454,"line":3609},[3452,8564,3954],{"class":3953},[3452,8566,8567],{"class":3957}," apiKey",[3452,8569,3962],{"class":3961},[3452,8571,3988],{"class":3957},[3452,8573,3516],{"class":3961},[3452,8575,8548],{"class":3957},[3452,8577,4264],{"class":3961},[3452,8579,8580],{"class":3462},"\"ExternalApi:ApiKey\"",[3452,8582,8583],{"class":3961},"];\n",[3518,8585],{},[3349,8587,8589],{"id":8588},"довідник-amazon-ecr-повна-документація-функцій","Довідник: Amazon ECR — повна документація функцій",[3354,8591,8592],{},[3527,8593],{"alt":8594,"className":8595,"src":8596},"ECR lifecycle policy rules automatic image expiration and cleanup diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F15.png",[3588,8598,8599],{},[3442,8600,8602],{"className":3592,"code":8601,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"ECR Repository: my-api\" as REPO #dbeafe\nrectangle \"Images (25 versions)\" as IMGS #e5e7eb\n\nrectangle \"Lifecycle Policy Rules\" as RULES #fef3c7 {\n    rectangle \"Rule 1: Untagged > 1 day\" as R1 #fde68a\n    rectangle \"Rule 2: Keep last 10 tagged\" as R2 #fde68a\n}\n\nrectangle \"AWS EventBridge\\n(daily trigger)\" as EB #e0e7ff\nrectangle \"Expired Images\" as EXP #fecaca\n\nIMGS --> RULES : evaluated\nEB -down-> RULES : triggers daily\nRULES -right-> EXP : deletes\nnote right of EXP\n  Images #11-25 deleted,\n  images #1-10 preserved\nend note\n@enduml\n",[3449,8603,8604,8608,8612,8616,8620,8625,8630,8634,8639,8644,8649,8653,8657,8662,8667,8671,8676,8681,8686,8691,8696,8701,8705],{"__ignoreMap":3447},[3452,8605,8606],{"class":3454,"line":3455},[3452,8607,3601],{},[3452,8609,8610],{"class":3454,"line":3473},[3452,8611,3606],{},[3452,8613,8614],{"class":3454,"line":3609},[3452,8615,3612],{},[3452,8617,8618],{"class":3454,"line":3615},[3452,8619,3619],{"emptyLinePlaceholder":3618},[3452,8621,8622],{"class":3454,"line":3622},[3452,8623,8624],{},"rectangle \"ECR Repository: my-api\" as REPO #dbeafe\n",[3452,8626,8627],{"class":3454,"line":3628},[3452,8628,8629],{},"rectangle \"Images (25 versions)\" as IMGS #e5e7eb\n",[3452,8631,8632],{"class":3454,"line":3634},[3452,8633,3619],{"emptyLinePlaceholder":3618},[3452,8635,8636],{"class":3454,"line":3640},[3452,8637,8638],{},"rectangle \"Lifecycle Policy Rules\" as RULES #fef3c7 {\n",[3452,8640,8641],{"class":3454,"line":3646},[3452,8642,8643],{},"    rectangle \"Rule 1: Untagged > 1 day\" as R1 #fde68a\n",[3452,8645,8646],{"class":3454,"line":3652},[3452,8647,8648],{},"    rectangle \"Rule 2: Keep last 10 tagged\" as R2 #fde68a\n",[3452,8650,8651],{"class":3454,"line":3658},[3452,8652,3691],{},[3452,8654,8655],{"class":3454,"line":3664},[3452,8656,3619],{"emptyLinePlaceholder":3618},[3452,8658,8659],{"class":3454,"line":3670},[3452,8660,8661],{},"rectangle \"AWS EventBridge\\n(daily trigger)\" as EB #e0e7ff\n",[3452,8663,8664],{"class":3454,"line":3676},[3452,8665,8666],{},"rectangle \"Expired Images\" as EXP #fecaca\n",[3452,8668,8669],{"class":3454,"line":3682},[3452,8670,3619],{"emptyLinePlaceholder":3618},[3452,8672,8673],{"class":3454,"line":3688},[3452,8674,8675],{},"IMGS --> RULES : evaluated\n",[3452,8677,8678],{"class":3454,"line":3694},[3452,8679,8680],{},"EB -down-> RULES : triggers daily\n",[3452,8682,8683],{"class":3454,"line":3699},[3452,8684,8685],{},"RULES -right-> EXP : deletes\n",[3452,8687,8688],{"class":3454,"line":3705},[3452,8689,8690],{},"note right of EXP\n",[3452,8692,8693],{"class":3454,"line":3711},[3452,8694,8695],{},"  Images #11-25 deleted,\n",[3452,8697,8698],{"class":3454,"line":3717},[3452,8699,8700],{},"  images #1-10 preserved\n",[3452,8702,8703],{"class":3454,"line":3723},[3452,8704,6575],{},[3452,8706,8707],{"class":3454,"line":3729},[3452,8708,3772],{},[3573,8710,8712],{"id":8711},"lifecycle-policies-автоматичне-управління-версіями-образів","Lifecycle Policies — автоматичне управління версіями образів",[3354,8714,8715,8718],{},[3540,8716,8717],{},"Lifecycle Policy"," — це правило, яке ECR виконує автоматично для видалення старих або непотрібних образів. Без lifecycle policy репозиторій безмежно росте, і ви платите за зберігання тисяч застарілих образів.",[3354,8720,8721,8724],{},[3540,8722,8723],{},"Навіщо потрібні:"," кожен CI\u002FCD pipeline при кожному commit'і завантажує новий образ. За місяць це 30+ образів на репозиторій. Lifecycle policy забезпечує автоматичне очищення.",[3354,8726,8727,8728,8731],{},"Lifecycle policy складається з ",[3540,8729,8730],{},"правил"," (rules) з пріоритетами. Кожне правило описує: які образи шукати (за тегом або без тегу) та що з ними робити (видалити після N днів або зберегти лише N останніх).",[3354,8733,8734],{},[3540,8735,8736],{},"Типовий сценарій: зберігати лише 10 tagged версій і видаляти untagged після 1 дня:",[3442,8738,8740],{"className":5521,"code":8739,"language":5523,"meta":3447,"style":3447},"{\n    \"rules\": [\n        {\n            \"rulePriority\": 1,\n            \"description\": \"Видаляти untagged образи через 1 день\",\n            \"selection\": {\n                \"tagStatus\": \"untagged\",\n                \"countType\": \"sinceImagePushed\",\n                \"countUnit\": \"days\",\n                \"countNumber\": 1\n            },\n            \"action\": { \"type\": \"expire\" }\n        },\n        {\n            \"rulePriority\": 2,\n            \"description\": \"Зберігати лише 10 останніх tagged образів\",\n            \"selection\": {\n                \"tagStatus\": \"tagged\",\n                \"tagPrefixList\": [\"v\"],\n                \"countType\": \"imageCountMoreThan\",\n                \"countNumber\": 10\n            },\n            \"action\": { \"type\": \"expire\" }\n        }\n    ]\n}\n",[3449,8741,8742,8746,8753,8757,8768,8780,8787,8799,8811,8823,8833,8837,8855,8859,8863,8874,8885,8891,8902,8914,8925,8934,8938,8952,8956,8960],{"__ignoreMap":3447},[3452,8743,8744],{"class":3454,"line":3455},[3452,8745,4097],{"class":3961},[3452,8747,8748,8751],{"class":3454,"line":3473},[3452,8749,8750],{"class":5534},"    \"rules\"",[3452,8752,5626],{"class":3961},[3452,8754,8755],{"class":3454,"line":3609},[3452,8756,5631],{"class":3961},[3452,8758,8759,8762,8764,8766],{"class":3454,"line":3615},[3452,8760,8761],{"class":5534},"            \"rulePriority\"",[3452,8763,5538],{"class":3961},[3452,8765,4153],{"class":4152},[3452,8767,5544],{"class":3961},[3452,8769,8770,8773,8775,8778],{"class":3454,"line":3622},[3452,8771,8772],{"class":5534},"            \"description\"",[3452,8774,5538],{"class":3961},[3452,8776,8777],{"class":3462},"\"Видаляти untagged образи через 1 день\"",[3452,8779,5544],{"class":3961},[3452,8781,8782,8785],{"class":3454,"line":3628},[3452,8783,8784],{"class":5534},"            \"selection\"",[3452,8786,5807],{"class":3961},[3452,8788,8789,8792,8794,8797],{"class":3454,"line":3634},[3452,8790,8791],{"class":5534},"                \"tagStatus\"",[3452,8793,5538],{"class":3961},[3452,8795,8796],{"class":3462},"\"untagged\"",[3452,8798,5544],{"class":3961},[3452,8800,8801,8804,8806,8809],{"class":3454,"line":3640},[3452,8802,8803],{"class":5534},"                \"countType\"",[3452,8805,5538],{"class":3961},[3452,8807,8808],{"class":3462},"\"sinceImagePushed\"",[3452,8810,5544],{"class":3961},[3452,8812,8813,8816,8818,8821],{"class":3454,"line":3646},[3452,8814,8815],{"class":5534},"                \"countUnit\"",[3452,8817,5538],{"class":3961},[3452,8819,8820],{"class":3462},"\"days\"",[3452,8822,5544],{"class":3961},[3452,8824,8825,8828,8830],{"class":3454,"line":3652},[3452,8826,8827],{"class":5534},"                \"countNumber\"",[3452,8829,5538],{"class":3961},[3452,8831,8832],{"class":4152},"1\n",[3452,8834,8835],{"class":3454,"line":3658},[3452,8836,5869],{"class":3961},[3452,8838,8839,8842,8845,8848,8850,8853],{"class":3454,"line":3664},[3452,8840,8841],{"class":5534},"            \"action\"",[3452,8843,8844],{"class":3961},": { ",[3452,8846,8847],{"class":5534},"\"type\"",[3452,8849,5538],{"class":3961},[3452,8851,8852],{"class":3462},"\"expire\"",[3452,8854,5754],{"class":3961},[3452,8856,8857],{"class":3454,"line":3670},[3452,8858,7030],{"class":3961},[3452,8860,8861],{"class":3454,"line":3676},[3452,8862,5631],{"class":3961},[3452,8864,8865,8867,8869,8872],{"class":3454,"line":3682},[3452,8866,8761],{"class":5534},[3452,8868,5538],{"class":3961},[3452,8870,8871],{"class":4152},"2",[3452,8873,5544],{"class":3961},[3452,8875,8876,8878,8880,8883],{"class":3454,"line":3688},[3452,8877,8772],{"class":5534},[3452,8879,5538],{"class":3961},[3452,8881,8882],{"class":3462},"\"Зберігати лише 10 останніх tagged образів\"",[3452,8884,5544],{"class":3961},[3452,8886,8887,8889],{"class":3454,"line":3694},[3452,8888,8784],{"class":5534},[3452,8890,5807],{"class":3961},[3452,8892,8893,8895,8897,8900],{"class":3454,"line":3699},[3452,8894,8791],{"class":5534},[3452,8896,5538],{"class":3961},[3452,8898,8899],{"class":3462},"\"tagged\"",[3452,8901,5544],{"class":3961},[3452,8903,8904,8907,8909,8912],{"class":3454,"line":3705},[3452,8905,8906],{"class":5534},"                \"tagPrefixList\"",[3452,8908,5564],{"class":3961},[3452,8910,8911],{"class":3462},"\"v\"",[3452,8913,5570],{"class":3961},[3452,8915,8916,8918,8920,8923],{"class":3454,"line":3711},[3452,8917,8803],{"class":5534},[3452,8919,5538],{"class":3961},[3452,8921,8922],{"class":3462},"\"imageCountMoreThan\"",[3452,8924,5544],{"class":3961},[3452,8926,8927,8929,8931],{"class":3454,"line":3717},[3452,8928,8827],{"class":5534},[3452,8930,5538],{"class":3961},[3452,8932,8933],{"class":4152},"10\n",[3452,8935,8936],{"class":3454,"line":3723},[3452,8937,5869],{"class":3961},[3452,8939,8940,8942,8944,8946,8948,8950],{"class":3454,"line":3729},[3452,8941,8841],{"class":5534},[3452,8943,8844],{"class":3961},[3452,8945,8847],{"class":5534},[3452,8947,5538],{"class":3961},[3452,8949,8852],{"class":3462},[3452,8951,5754],{"class":3961},[3452,8953,8954],{"class":3454,"line":3734},[3452,8955,5953],{"class":3961},[3452,8957,8958],{"class":3454,"line":3740},[3452,8959,5959],{"class":3961},[3452,8961,8962],{"class":3454,"line":3746},[3452,8963,3691],{"class":3961},[3354,8965,8966],{},[3540,8967,8968],{},"Застосування через AWS CLI:",[3442,8970,8972],{"className":3444,"code":8971,"language":3446,"meta":3447,"style":3447},"aws ecr put-lifecycle-policy \\\n    --repository-name my-api \\\n    --lifecycle-policy-text file:\u002F\u002Flifecycle-policy.json \\\n    --region eu-central-1\n",[3449,8973,8974,8986,8995,9005],{"__ignoreMap":3447},[3452,8975,8976,8978,8981,8984],{"class":3454,"line":3455},[3452,8977,3459],{"class":3458},[3452,8979,8980],{"class":3462}," ecr",[3452,8982,8983],{"class":3462}," put-lifecycle-policy",[3452,8985,5067],{"class":5066},[3452,8987,8988,8991,8993],{"class":3454,"line":3473},[3452,8989,8990],{"class":3953},"    --repository-name",[3452,8992,7640],{"class":3462},[3452,8994,5067],{"class":5066},[3452,8996,8997,9000,9003],{"class":3454,"line":3609},[3452,8998,8999],{"class":3953},"    --lifecycle-policy-text",[3452,9001,9002],{"class":3462}," file:\u002F\u002Flifecycle-policy.json",[3452,9004,5067],{"class":5066},[3452,9006,9007,9009],{"class":3454,"line":3615},[3452,9008,6935],{"class":3953},[3452,9010,6938],{"class":3462},[3354,9012,9013,9016,9017,9020,9021,9024,9025,9028,9029,3516],{},[3540,9014,9015],{},"Через AWS Console:"," ECR → Repositories → ",[3449,9018,9019],{},"my-api"," → вкладка ",[3540,9022,9023],{},"«Lifecycle policy»"," → ",[3540,9026,9027],{},"Create rule"," → задайте умови у формі → ",[3540,9030,9031],{},"Save",[5114,9033,9034,9035,9024,9037,9024,9040,9043],{},"Перед застосуванням lifecycle policy перевірте, які образи будуть видалені: ECR → Repositories → ",[3449,9036,9019],{},[3540,9038,9039],{},"Lifecycle policy",[3540,9041,9042],{},"Test rules"," → ECR покаже список образів, які підпадають під правила, без реального видалення.",[3518,9045],{},[3354,9047,9048],{},[3527,9049],{"alt":9050,"className":9051,"src":9052},"ECR image scanning with Amazon Inspector CVE vulnerability detection",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F16.png",[3573,9054,9056],{"id":9055},"image-scanning-автоматичний-аудит-безпеки","Image Scanning — автоматичний аудит безпеки",[3354,9058,9059,9060,9063],{},"ECR інтегрований з ",[3540,9061,9062],{},"Amazon Inspector"," і може автоматично сканувати кожен завантажений образ на відомі CVE (Common Vulnerabilities and Exposures) — бази відомих вразливостей у ПЗ.",[3354,9065,9066],{},[3540,9067,9068],{},"Два режими сканування:",[3354,9070,9071,9074,9075,9078],{},[3540,9072,9073],{},"Basic Scanning"," — безкоштовне сканування на основі відкритої бази даних CVE. Виконується один раз при push (якщо ",[3449,9076,9077],{},"scanOnPush=true",") або вручну.",[3354,9080,9081,9084],{},[3540,9082,9083],{},"Enhanced Scanning"," (Amazon Inspector) — платне безперервне сканування. Повторно аналізує образи при появі нових CVE у базі — навіть якщо образ давно завантажений.",[3354,9086,9087],{},[3540,9088,9089],{},"Перегляд результатів через CLI:",[3442,9091,9093],{"className":3444,"code":9092,"language":3446,"meta":3447,"style":3447},"# Переглянути результати останнього сканування\naws ecr describe-image-scan-findings \\\n    --repository-name my-api \\\n    --image-id imageTag=v1.2.3 \\\n    --region eu-central-1\n\n# Приклад відповіді:\n# {\n#   \"imageScanFindings\": {\n#     \"findings\": [\n#       {\n#         \"name\": \"CVE-2023-12345\",\n#         \"severity\": \"HIGH\",\n#         \"description\": \"Buffer overflow in libssl...\",\n#         \"uri\": \"https:\u002F\u002Fnvd.nist.gov\u002Fvuln\u002Fdetail\u002FCVE-2023-12345\"\n#       }\n#     ],\n#     \"findingSeverityCounts\": {\"HIGH\": 1, \"MEDIUM\": 3, \"LOW\": 12}\n#   }\n# }\n",[3449,9094,9095,9100,9111,9119,9129,9135,9139,9144,9149,9154,9159,9164,9169,9174,9179,9184,9189,9194,9199,9204],{"__ignoreMap":3447},[3452,9096,9097],{"class":3454,"line":3455},[3452,9098,9099],{"class":3469},"# Переглянути результати останнього сканування\n",[3452,9101,9102,9104,9106,9109],{"class":3454,"line":3473},[3452,9103,3459],{"class":3458},[3452,9105,8980],{"class":3462},[3452,9107,9108],{"class":3462}," describe-image-scan-findings",[3452,9110,5067],{"class":5066},[3452,9112,9113,9115,9117],{"class":3454,"line":3609},[3452,9114,8990],{"class":3953},[3452,9116,7640],{"class":3462},[3452,9118,5067],{"class":5066},[3452,9120,9121,9124,9127],{"class":3454,"line":3615},[3452,9122,9123],{"class":3953},"    --image-id",[3452,9125,9126],{"class":3462}," imageTag=v1.2.3",[3452,9128,5067],{"class":5066},[3452,9130,9131,9133],{"class":3454,"line":3622},[3452,9132,6935],{"class":3953},[3452,9134,6938],{"class":3462},[3452,9136,9137],{"class":3454,"line":3628},[3452,9138,3619],{"emptyLinePlaceholder":3618},[3452,9140,9141],{"class":3454,"line":3634},[3452,9142,9143],{"class":3469},"# Приклад відповіді:\n",[3452,9145,9146],{"class":3454,"line":3640},[3452,9147,9148],{"class":3469},"# {\n",[3452,9150,9151],{"class":3454,"line":3646},[3452,9152,9153],{"class":3469},"#   \"imageScanFindings\": {\n",[3452,9155,9156],{"class":3454,"line":3652},[3452,9157,9158],{"class":3469},"#     \"findings\": [\n",[3452,9160,9161],{"class":3454,"line":3658},[3452,9162,9163],{"class":3469},"#       {\n",[3452,9165,9166],{"class":3454,"line":3664},[3452,9167,9168],{"class":3469},"#         \"name\": \"CVE-2023-12345\",\n",[3452,9170,9171],{"class":3454,"line":3670},[3452,9172,9173],{"class":3469},"#         \"severity\": \"HIGH\",\n",[3452,9175,9176],{"class":3454,"line":3676},[3452,9177,9178],{"class":3469},"#         \"description\": \"Buffer overflow in libssl...\",\n",[3452,9180,9181],{"class":3454,"line":3682},[3452,9182,9183],{"class":3469},"#         \"uri\": \"https:\u002F\u002Fnvd.nist.gov\u002Fvuln\u002Fdetail\u002FCVE-2023-12345\"\n",[3452,9185,9186],{"class":3454,"line":3688},[3452,9187,9188],{"class":3469},"#       }\n",[3452,9190,9191],{"class":3454,"line":3694},[3452,9192,9193],{"class":3469},"#     ],\n",[3452,9195,9196],{"class":3454,"line":3699},[3452,9197,9198],{"class":3469},"#     \"findingSeverityCounts\": {\"HIGH\": 1, \"MEDIUM\": 3, \"LOW\": 12}\n",[3452,9200,9201],{"class":3454,"line":3705},[3452,9202,9203],{"class":3469},"#   }\n",[3452,9205,9206],{"class":3454,"line":3711},[3452,9207,9208],{"class":3469},"# }\n",[3354,9210,9211],{},[3540,9212,9213],{},"Запустити сканування вручну:",[3442,9215,9217],{"className":3444,"code":9216,"language":3446,"meta":3447,"style":3447},"aws ecr start-image-scan \\\n    --repository-name my-api \\\n    --image-id imageTag=v1.2.3 \\\n    --region eu-central-1\n",[3449,9218,9219,9230,9238,9246],{"__ignoreMap":3447},[3452,9220,9221,9223,9225,9228],{"class":3454,"line":3455},[3452,9222,3459],{"class":3458},[3452,9224,8980],{"class":3462},[3452,9226,9227],{"class":3462}," start-image-scan",[3452,9229,5067],{"class":5066},[3452,9231,9232,9234,9236],{"class":3454,"line":3473},[3452,9233,8990],{"class":3953},[3452,9235,7640],{"class":3462},[3452,9237,5067],{"class":5066},[3452,9239,9240,9242,9244],{"class":3454,"line":3609},[3452,9241,9123],{"class":3953},[3452,9243,9126],{"class":3462},[3452,9245,5067],{"class":5066},[3452,9247,9248,9250],{"class":3454,"line":3615},[3452,9249,6935],{"class":3953},[3452,9251,6938],{"class":3462},[3518,9253],{},[3354,9255,9256],{},[3527,9257],{"alt":9258,"className":9259,"src":9260},"ECR image tag mutability immutable vs mutable tag protection",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F17.jpeg",[3573,9262,9264],{"id":9263},"image-tag-mutability-захист-від-перезапису-тегів","Image Tag Mutability — захист від перезапису тегів",[3354,9266,9267,9270],{},[3540,9268,9269],{},"Tag Mutability"," визначає, чи можна перезаписати тег образу, який вже існує.",[4699,9272,9273,9286],{},[4702,9274,9275,9278,9279,9281,9282,9285],{},[3540,9276,9277],{},"MUTABLE"," (за замовчуванням) — тег ",[3449,9280,7782],{}," або ",[3449,9283,9284],{},":v1.0.0"," можна перезаписати новим образом. Зручно, але небезпечно: CI\u002FCD міг завантажити інший образ під тим самим тегом.",[4702,9287,9288,9291,9292,9294],{},[3540,9289,9290],{},"IMMUTABLE"," — після першого завантаження тег не можна перезаписати. Забезпечує повну відтворюваність: образ ",[3449,9293,9284],{}," завжди залишається тим самим.",[3354,9296,9297,9300,9301,3516],{},[3540,9298,9299],{},"Рекомендація:"," використовуйте IMMUTABLE для production репозиторіїв. Для тегування використовуйте git commit SHA або семантичне версіонування, а не ",[3449,9302,7782],{},[3442,9304,9306],{"className":3444,"code":9305,"language":3446,"meta":3447,"style":3447},"# Змінити mutability для існуючого репозиторію\naws ecr put-image-tag-mutability \\\n    --repository-name my-api \\\n    --image-tag-mutability IMMUTABLE \\\n    --region eu-central-1\n",[3449,9307,9308,9313,9324,9332,9342],{"__ignoreMap":3447},[3452,9309,9310],{"class":3454,"line":3455},[3452,9311,9312],{"class":3469},"# Змінити mutability для існуючого репозиторію\n",[3452,9314,9315,9317,9319,9322],{"class":3454,"line":3473},[3452,9316,3459],{"class":3458},[3452,9318,8980],{"class":3462},[3452,9320,9321],{"class":3462}," put-image-tag-mutability",[3452,9323,5067],{"class":5066},[3452,9325,9326,9328,9330],{"class":3454,"line":3609},[3452,9327,8990],{"class":3953},[3452,9329,7640],{"class":3462},[3452,9331,5067],{"class":5066},[3452,9333,9334,9337,9340],{"class":3454,"line":3615},[3452,9335,9336],{"class":3953},"    --image-tag-mutability",[3452,9338,9339],{"class":3462}," IMMUTABLE",[3452,9341,5067],{"class":5066},[3452,9343,9344,9346],{"class":3454,"line":3622},[3452,9345,6935],{"class":3953},[3452,9347,6938],{"class":3462},[3518,9349],{},[3354,9351,9352],{},[3527,9353],{"alt":9354,"className":9355,"src":9356},"ECR cross-account access repository policy multi-account architecture",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F18.png",[3573,9358,9360],{"id":9359},"cross-account-access-доступ-між-aws-акаунтами","Cross-Account Access — доступ між AWS акаунтами",[3354,9362,9363,9364,9367],{},"У multi-account архітектурі (окремі акаунти для dev\u002Fstaging\u002Fproduction) ECR може бути в одному акаунті, а ECS кластери — в інших. Для цього налаштовується ",[3540,9365,9366],{},"Repository Policy"," — IAM Policy на рівні репозиторію, яка дозволяє зовнішнім акаунтам завантажувати образи.",[3442,9369,9371],{"className":5521,"code":9370,"language":5523,"meta":3447,"style":3447},"{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"AllowPullFromProductionAccount\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\n                \"AWS\": \"arn:aws:iam::PRODUCTION_ACCOUNT_ID:root\"\n            },\n            \"Action\": [\"ecr:GetDownloadUrlForLayer\", \"ecr:BatchGetImage\", \"ecr:BatchCheckLayerAvailability\"]\n        }\n    ]\n}\n",[3449,9372,9373,9377,9389,9396,9400,9412,9424,9431,9441,9445,9467,9471,9475],{"__ignoreMap":3447},[3452,9374,9375],{"class":3454,"line":3455},[3452,9376,4097],{"class":3961},[3452,9378,9379,9382,9384,9387],{"class":3454,"line":3473},[3452,9380,9381],{"class":5534},"    \"Version\"",[3452,9383,5538],{"class":3961},[3452,9385,9386],{"class":3462},"\"2012-10-17\"",[3452,9388,5544],{"class":3961},[3452,9390,9391,9394],{"class":3454,"line":3609},[3452,9392,9393],{"class":5534},"    \"Statement\"",[3452,9395,5626],{"class":3961},[3452,9397,9398],{"class":3454,"line":3615},[3452,9399,5631],{"class":3961},[3452,9401,9402,9405,9407,9410],{"class":3454,"line":3622},[3452,9403,9404],{"class":5534},"            \"Sid\"",[3452,9406,5538],{"class":3961},[3452,9408,9409],{"class":3462},"\"AllowPullFromProductionAccount\"",[3452,9411,5544],{"class":3961},[3452,9413,9414,9417,9419,9422],{"class":3454,"line":3628},[3452,9415,9416],{"class":5534},"            \"Effect\"",[3452,9418,5538],{"class":3961},[3452,9420,9421],{"class":3462},"\"Allow\"",[3452,9423,5544],{"class":3961},[3452,9425,9426,9429],{"class":3454,"line":3634},[3452,9427,9428],{"class":5534},"            \"Principal\"",[3452,9430,5807],{"class":3961},[3452,9432,9433,9436,9438],{"class":3454,"line":3640},[3452,9434,9435],{"class":5534},"                \"AWS\"",[3452,9437,5538],{"class":3961},[3452,9439,9440],{"class":3462},"\"arn:aws:iam::PRODUCTION_ACCOUNT_ID:root\"\n",[3452,9442,9443],{"class":3454,"line":3646},[3452,9444,5869],{"class":3961},[3452,9446,9447,9450,9452,9455,9457,9460,9462,9465],{"class":3454,"line":3652},[3452,9448,9449],{"class":5534},"            \"Action\"",[3452,9451,5564],{"class":3961},[3452,9453,9454],{"class":3462},"\"ecr:GetDownloadUrlForLayer\"",[3452,9456,3491],{"class":3961},[3452,9458,9459],{"class":3462},"\"ecr:BatchGetImage\"",[3452,9461,3491],{"class":3961},[3452,9463,9464],{"class":3462},"\"ecr:BatchCheckLayerAvailability\"",[3452,9466,4511],{"class":3961},[3452,9468,9469],{"class":3454,"line":3658},[3452,9470,5953],{"class":3961},[3452,9472,9473],{"class":3454,"line":3664},[3452,9474,5959],{"class":3961},[3452,9476,9477],{"class":3454,"line":3670},[3452,9478,3691],{"class":3961},[3442,9480,9482],{"className":3444,"code":9481,"language":3446,"meta":3447,"style":3447},"# Застосувати Repository Policy\naws ecr set-repository-policy \\\n    --repository-name my-api \\\n    --policy-text file:\u002F\u002Frepo-policy.json \\\n    --region eu-central-1\n",[3449,9483,9484,9489,9500,9508,9518],{"__ignoreMap":3447},[3452,9485,9486],{"class":3454,"line":3455},[3452,9487,9488],{"class":3469},"# Застосувати Repository Policy\n",[3452,9490,9491,9493,9495,9498],{"class":3454,"line":3473},[3452,9492,3459],{"class":3458},[3452,9494,8980],{"class":3462},[3452,9496,9497],{"class":3462}," set-repository-policy",[3452,9499,5067],{"class":5066},[3452,9501,9502,9504,9506],{"class":3454,"line":3609},[3452,9503,8990],{"class":3953},[3452,9505,7640],{"class":3462},[3452,9507,5067],{"class":5066},[3452,9509,9510,9513,9516],{"class":3454,"line":3615},[3452,9511,9512],{"class":3953},"    --policy-text",[3452,9514,9515],{"class":3462}," file:\u002F\u002Frepo-policy.json",[3452,9517,5067],{"class":5066},[3452,9519,9520,9522],{"class":3454,"line":3622},[3452,9521,6935],{"class":3953},[3452,9523,6938],{"class":3462},[3518,9525],{},[3354,9527,9528],{},[3527,9529],{"alt":9530,"className":9531,"src":9532},"ECR cross-region replication between AWS regions for disaster recovery",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F19.png",[3573,9534,9536],{"id":9535},"ecr-replication-реплікація-між-регіонами","ECR Replication — реплікація між регіонами",[3354,9538,9539],{},"Якщо ваші ECS кластери розташовані у кількох регіонах (наприклад, EU та US), образи варто реплікувати в кожен регіон — для швидкого завантаження без cross-region трафіку.",[3442,9541,9543],{"className":3444,"code":9542,"language":3446,"meta":3447,"style":3447},"# Налаштувати реплікацію образів у інший регіон\naws ecr put-replication-configuration \\\n    --replication-configuration '{\n        \"rules\": [{\n            \"destinations\": [{\"region\": \"us-east-1\", \"registryId\": \"ACCOUNT_ID\"}],\n            \"repositoryFilters\": [{\"filter\": \"my-api\", \"filterType\": \"PREFIX_MATCH\"}]\n        }]\n    }' \\\n    --region eu-central-1\n",[3449,9544,9545,9550,9561,9568,9573,9578,9583,9588,9594],{"__ignoreMap":3447},[3452,9546,9547],{"class":3454,"line":3455},[3452,9548,9549],{"class":3469},"# Налаштувати реплікацію образів у інший регіон\n",[3452,9551,9552,9554,9556,9559],{"class":3454,"line":3473},[3452,9553,3459],{"class":3458},[3452,9555,8980],{"class":3462},[3452,9557,9558],{"class":3462}," put-replication-configuration",[3452,9560,5067],{"class":5066},[3452,9562,9563,9566],{"class":3454,"line":3609},[3452,9564,9565],{"class":3953},"    --replication-configuration",[3452,9567,7010],{"class":3462},[3452,9569,9570],{"class":3454,"line":3615},[3452,9571,9572],{"class":3462},"        \"rules\": [{\n",[3452,9574,9575],{"class":3454,"line":3622},[3452,9576,9577],{"class":3462},"            \"destinations\": [{\"region\": \"us-east-1\", \"registryId\": \"ACCOUNT_ID\"}],\n",[3452,9579,9580],{"class":3454,"line":3628},[3452,9581,9582],{"class":3462},"            \"repositoryFilters\": [{\"filter\": \"my-api\", \"filterType\": \"PREFIX_MATCH\"}]\n",[3452,9584,9585],{"class":3454,"line":3634},[3452,9586,9587],{"class":3462},"        }]\n",[3452,9589,9590,9592],{"class":3454,"line":3640},[3452,9591,7045],{"class":3462},[3452,9593,5067],{"class":5066},[3452,9595,9596,9598],{"class":3454,"line":3646},[3452,9597,6935],{"class":3953},[3452,9599,6938],{"class":3462},[3518,9601],{},[3349,9603,9605],{"id":9604},"довідник-amazon-ecs-повна-документація-функцій","Довідник: Amazon ECS — повна документація функцій",[3354,9607,9608],{},[3527,9609],{"alt":9610,"className":9611,"src":9612},"ECS Exec interactive shell session to running container debugging diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F20.png",[3588,9614,9615],{},[3442,9616,9618],{"className":3592,"code":9617,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Developer\" as Dev\nrectangle \"AWS CLI\\naws ecs execute-command\" as CLI #e0e7ff\nrectangle \"AWS Systems Manager\\nSession Manager\" as SSM #fef3c7\nrectangle \"ECS Task\\n(Container)\" as Task #bbf7d0 {\n    rectangle \".NET API\" as API #d1fae5\n    rectangle \"\u002Fbin\u002Fbash\" as BASH #f3f4f6\n}\n\nDev -right-> CLI : runs command\nCLI -right-> SSM : creates session\nSSM -right-> Task : opens channel\nnote right of Task\n  Interactive bash session\n  inside running container\nend note\n@enduml\n",[3449,9619,9620,9624,9628,9632,9636,9641,9646,9651,9656,9661,9666,9670,9674,9679,9684,9689,9694,9699,9704,9708],{"__ignoreMap":3447},[3452,9621,9622],{"class":3454,"line":3455},[3452,9623,3601],{},[3452,9625,9626],{"class":3454,"line":3473},[3452,9627,3606],{},[3452,9629,9630],{"class":3454,"line":3609},[3452,9631,3612],{},[3452,9633,9634],{"class":3454,"line":3615},[3452,9635,3619],{"emptyLinePlaceholder":3618},[3452,9637,9638],{"class":3454,"line":3622},[3452,9639,9640],{},"actor \"Developer\" as Dev\n",[3452,9642,9643],{"class":3454,"line":3628},[3452,9644,9645],{},"rectangle \"AWS CLI\\naws ecs execute-command\" as CLI #e0e7ff\n",[3452,9647,9648],{"class":3454,"line":3634},[3452,9649,9650],{},"rectangle \"AWS Systems Manager\\nSession Manager\" as SSM #fef3c7\n",[3452,9652,9653],{"class":3454,"line":3640},[3452,9654,9655],{},"rectangle \"ECS Task\\n(Container)\" as Task #bbf7d0 {\n",[3452,9657,9658],{"class":3454,"line":3646},[3452,9659,9660],{},"    rectangle \".NET API\" as API #d1fae5\n",[3452,9662,9663],{"class":3454,"line":3652},[3452,9664,9665],{},"    rectangle \"\u002Fbin\u002Fbash\" as BASH #f3f4f6\n",[3452,9667,9668],{"class":3454,"line":3658},[3452,9669,3691],{},[3452,9671,9672],{"class":3454,"line":3664},[3452,9673,3619],{"emptyLinePlaceholder":3618},[3452,9675,9676],{"class":3454,"line":3670},[3452,9677,9678],{},"Dev -right-> CLI : runs command\n",[3452,9680,9681],{"class":3454,"line":3676},[3452,9682,9683],{},"CLI -right-> SSM : creates session\n",[3452,9685,9686],{"class":3454,"line":3682},[3452,9687,9688],{},"SSM -right-> Task : opens channel\n",[3452,9690,9691],{"class":3454,"line":3688},[3452,9692,9693],{},"note right of Task\n",[3452,9695,9696],{"class":3454,"line":3694},[3452,9697,9698],{},"  Interactive bash session\n",[3452,9700,9701],{"class":3454,"line":3699},[3452,9702,9703],{},"  inside running container\n",[3452,9705,9706],{"class":3454,"line":3705},[3452,9707,6575],{},[3452,9709,9710],{"class":3454,"line":3711},[3452,9711,3772],{},[3573,9713,9715],{"id":9714},"ecs-exec-підключення-до-контейнера-для-дебагінгу","ECS Exec — підключення до контейнера для дебагінгу",[3354,9717,9718,9721,9722,9725,9726,9729],{},[3540,9719,9720],{},"ECS Exec"," — це функція, яка дозволяє запустити інтерактивну сесію (bash або будь-яку команду) всередині запущеного Task. Аналог ",[3449,9723,9724],{},"kubectl exec"," у Kubernetes або ",[3449,9727,9728],{},"docker exec"," для локальних контейнерів.",[3354,9731,9732,9735],{},[3540,9733,9734],{},"Навіщо потрібно:"," коли контейнер поводиться дивно у production — перевірити змінні середовища, пінгувати БД зсередини контейнера, переглянути файли.",[3354,9737,9738],{},[3540,9739,9740],{},"Підготовка — IAM права для ECS Exec:",[3442,9742,9744],{"className":5521,"code":9743,"language":5523,"meta":3447,"style":3447},"{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"ssmmessages:CreateControlChannel\",\n                \"ssmmessages:CreateDataChannel\",\n                \"ssmmessages:OpenControlChannel\",\n                \"ssmmessages:OpenDataChannel\"\n            ],\n            \"Resource\": \"*\"\n        }\n    ]\n}\n",[3449,9745,9746,9750,9760,9766,9770,9780,9786,9793,9800,9807,9812,9816,9826,9830,9834],{"__ignoreMap":3447},[3452,9747,9748],{"class":3454,"line":3455},[3452,9749,4097],{"class":3961},[3452,9751,9752,9754,9756,9758],{"class":3454,"line":3473},[3452,9753,9381],{"class":5534},[3452,9755,5538],{"class":3961},[3452,9757,9386],{"class":3462},[3452,9759,5544],{"class":3961},[3452,9761,9762,9764],{"class":3454,"line":3609},[3452,9763,9393],{"class":5534},[3452,9765,5626],{"class":3961},[3452,9767,9768],{"class":3454,"line":3615},[3452,9769,5631],{"class":3961},[3452,9771,9772,9774,9776,9778],{"class":3454,"line":3622},[3452,9773,9416],{"class":5534},[3452,9775,5538],{"class":3961},[3452,9777,9421],{"class":3462},[3452,9779,5544],{"class":3961},[3452,9781,9782,9784],{"class":3454,"line":3628},[3452,9783,9449],{"class":5534},[3452,9785,5626],{"class":3961},[3452,9787,9788,9791],{"class":3454,"line":3634},[3452,9789,9790],{"class":3462},"                \"ssmmessages:CreateControlChannel\"",[3452,9792,5544],{"class":3961},[3452,9794,9795,9798],{"class":3454,"line":3640},[3452,9796,9797],{"class":3462},"                \"ssmmessages:CreateDataChannel\"",[3452,9799,5544],{"class":3961},[3452,9801,9802,9805],{"class":3454,"line":3646},[3452,9803,9804],{"class":3462},"                \"ssmmessages:OpenControlChannel\"",[3452,9806,5544],{"class":3961},[3452,9808,9809],{"class":3454,"line":3652},[3452,9810,9811],{"class":3462},"                \"ssmmessages:OpenDataChannel\"\n",[3452,9813,9814],{"class":3454,"line":3658},[3452,9815,5698],{"class":3961},[3452,9817,9818,9821,9823],{"class":3454,"line":3664},[3452,9819,9820],{"class":5534},"            \"Resource\"",[3452,9822,5538],{"class":3961},[3452,9824,9825],{"class":3462},"\"*\"\n",[3452,9827,9828],{"class":3454,"line":3670},[3452,9829,5953],{"class":3961},[3452,9831,9832],{"class":3454,"line":3676},[3452,9833,5959],{"class":3961},[3452,9835,9836],{"class":3454,"line":3682},[3452,9837,3691],{"class":3961},[3354,9839,9840,9841,9844],{},"Додайте цю Policy до ",[3540,9842,9843],{},"Task Role"," (не Execution Role).",[3354,9846,9847],{},[3540,9848,9849],{},"Увімкнення ECS Exec для Service:",[9851,9852,9853,9994],"tabs",{},[9854,9855,9857],"tabs-item",{"label":9856},"AWS CLI",[3442,9858,9860],{"className":3444,"code":9859,"language":3446,"meta":3447,"style":3447},"# Увімкнути execute-command при оновленні сервісу\naws ecs update-service \\\n    --cluster my-cluster \\\n    --service my-api-service \\\n    --enable-execute-command \\\n    --region eu-central-1\n\n# Підключитися до контейнера у запущеному Task\nTASK_ARN=\"arn:aws:ecs:eu-central-1:123456789012:task\u002Fmy-cluster\u002Fabc123\"\n\naws ecs execute-command \\\n    --cluster my-cluster \\\n    --task $TASK_ARN \\\n    --container my-api \\\n    --interactive \\\n    --command \"\u002Fbin\u002Fbash\" \\\n    --region eu-central-1\n",[3449,9861,9862,9867,9878,9887,9897,9904,9910,9914,9919,9929,9933,9944,9952,9962,9971,9978,9988],{"__ignoreMap":3447},[3452,9863,9864],{"class":3454,"line":3455},[3452,9865,9866],{"class":3469},"# Увімкнути execute-command при оновленні сервісу\n",[3452,9868,9869,9871,9873,9876],{"class":3454,"line":3473},[3452,9870,3459],{"class":3458},[3452,9872,6888],{"class":3462},[3452,9874,9875],{"class":3462}," update-service",[3452,9877,5067],{"class":5066},[3452,9879,9880,9882,9885],{"class":3454,"line":3609},[3452,9881,7627],{"class":3953},[3452,9883,9884],{"class":3462}," my-cluster",[3452,9886,5067],{"class":5066},[3452,9888,9889,9892,9895],{"class":3454,"line":3615},[3452,9890,9891],{"class":3953},"    --service",[3452,9893,9894],{"class":3462}," my-api-service",[3452,9896,5067],{"class":5066},[3452,9898,9899,9902],{"class":3454,"line":3622},[3452,9900,9901],{"class":3953},"    --enable-execute-command",[3452,9903,5067],{"class":5066},[3452,9905,9906,9908],{"class":3454,"line":3628},[3452,9907,6935],{"class":3953},[3452,9909,6938],{"class":3462},[3452,9911,9912],{"class":3454,"line":3634},[3452,9913,3619],{"emptyLinePlaceholder":3618},[3452,9915,9916],{"class":3454,"line":3640},[3452,9917,9918],{"class":3469},"# Підключитися до контейнера у запущеному Task\n",[3452,9920,9921,9924,9926],{"class":3454,"line":3646},[3452,9922,9923],{"class":3957},"TASK_ARN",[3452,9925,8300],{"class":3961},[3452,9927,9928],{"class":3462},"\"arn:aws:ecs:eu-central-1:123456789012:task\u002Fmy-cluster\u002Fabc123\"\n",[3452,9930,9931],{"class":3454,"line":3652},[3452,9932,3619],{"emptyLinePlaceholder":3618},[3452,9934,9935,9937,9939,9942],{"class":3454,"line":3658},[3452,9936,3459],{"class":3458},[3452,9938,6888],{"class":3462},[3452,9940,9941],{"class":3462}," execute-command",[3452,9943,5067],{"class":5066},[3452,9945,9946,9948,9950],{"class":3454,"line":3664},[3452,9947,7627],{"class":3953},[3452,9949,9884],{"class":3462},[3452,9951,5067],{"class":5066},[3452,9953,9954,9957,9960],{"class":3454,"line":3670},[3452,9955,9956],{"class":3953},"    --task",[3452,9958,9959],{"class":3957}," $TASK_ARN",[3452,9961,5067],{"class":5066},[3452,9963,9964,9967,9969],{"class":3454,"line":3676},[3452,9965,9966],{"class":3953},"    --container",[3452,9968,7640],{"class":3462},[3452,9970,5067],{"class":5066},[3452,9972,9973,9976],{"class":3454,"line":3682},[3452,9974,9975],{"class":3953},"    --interactive",[3452,9977,5067],{"class":5066},[3452,9979,9980,9983,9986],{"class":3454,"line":3688},[3452,9981,9982],{"class":3953},"    --command",[3452,9984,9985],{"class":3462}," \"\u002Fbin\u002Fbash\"",[3452,9987,5067],{"class":5066},[3452,9989,9990,9992],{"class":3454,"line":3694},[3452,9991,6935],{"class":3953},[3452,9993,6938],{"class":3462},[9854,9995,9997],{"label":9996},"AWS Console",[7751,9998,9999,10006,10012,10022],{},[4702,10000,10001,10002,10005],{},"ECS → Clusters → ",[3449,10003,10004],{},"my-cluster"," → Tasks",[4702,10007,10008,10009],{},"Оберіть потрібний Task → натисніть ",[3540,10010,10011],{},"«Execute command»",[4702,10013,10014,10015,10018,10019],{},"Оберіть контейнер → введіть команду (наприклад ",[3449,10016,10017],{},"\u002Fbin\u002Fbash",") → ",[3540,10020,10021],{},"Execute",[4702,10023,10024],{},"Відкриється термінальна сесія прямо в браузері через AWS CloudShell",[3881,10026,10028,10032,10035,10039,10047,10051,10055,10062],{"title":10027},"ECS Exec session",[3885,10029,10031],{"className":10030},[3454],"The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.",[3885,10033],{"className":10034},[3454],[3885,10036,10038],{"className":10037},[3454],"Starting session with SessionId: ecs-execute-command-abc123",[3885,10040,10042,10046],{"className":10041},[3454],[3452,10043,10045],{"className":10044},[3916],"root@3f4a8b9c1d2e:\u002Fapp#"," env | grep ASPNETCORE",[3885,10048,10050],{"className":10049},[3454],"ASPNETCORE_ENVIRONMENT=Production",[3885,10052,10054],{"className":10053},[3454],"ASPNETCORE_URLS=http:\u002F\u002F+:8080",[3885,10056,10058,10061],{"className":10057},[3454],[3452,10059,10045],{"className":10060},[3916]," curl localhost:8080\u002Fhealth",[3885,10063,4400],{"className":10064},[3454],[6155,10066,10067,10068,10071,10072,10075],{},"ECS Exec використовує AWS Systems Manager Session Manager під капотом. Для роботи потрібно: встановлений AWS CLI Session Manager plugin локально (",[3449,10069,10070],{},"session-manager-plugin","), Task Role з SSM правами (вище), ",[3449,10073,10074],{},"enableExecuteCommand: true"," у Service.",[3518,10077],{},[3354,10079,10080],{},[3527,10081],{"alt":10082,"className":10083,"src":10084},"ECS deployment circuit breaker automatic rollback on failed deployment",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F21.png",[3588,10086,10087],{},[3442,10088,10090],{"className":3592,"code":10089,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"Service Update (v1→v2)\" as UPDATE #dbeafe\nrectangle \"New Tasks starting...\" as NEW #bbf7d0\nrectangle \"Health Check Failed ❌\" as FAIL #fecaca\nrectangle \"Count: 10 failures\" as COUNT #fde68a\nrectangle \"Circuit Breaker 🔴\" as CB #fca5a5\nrectangle \"Rollback to v1 ✅\" as ROLLBACK #bbf7d0\nrectangle \"Service stable\" as OK #d1fae5\n\nUPDATE -down-> NEW\nNEW -down-> FAIL : health check fails\nFAIL -down-> COUNT : increment counter\nCOUNT -down-> CB : threshold reached\nCB -down-> ROLLBACK : automatic\nROLLBACK -down-> OK\n@enduml\n",[3449,10091,10092,10096,10100,10104,10108,10113,10118,10123,10128,10133,10138,10143,10147,10152,10157,10162,10167,10172,10177],{"__ignoreMap":3447},[3452,10093,10094],{"class":3454,"line":3455},[3452,10095,3601],{},[3452,10097,10098],{"class":3454,"line":3473},[3452,10099,3606],{},[3452,10101,10102],{"class":3454,"line":3609},[3452,10103,3612],{},[3452,10105,10106],{"class":3454,"line":3615},[3452,10107,3619],{"emptyLinePlaceholder":3618},[3452,10109,10110],{"class":3454,"line":3622},[3452,10111,10112],{},"rectangle \"Service Update (v1→v2)\" as UPDATE #dbeafe\n",[3452,10114,10115],{"class":3454,"line":3628},[3452,10116,10117],{},"rectangle \"New Tasks starting...\" as NEW #bbf7d0\n",[3452,10119,10120],{"class":3454,"line":3634},[3452,10121,10122],{},"rectangle \"Health Check Failed ❌\" as FAIL #fecaca\n",[3452,10124,10125],{"class":3454,"line":3640},[3452,10126,10127],{},"rectangle \"Count: 10 failures\" as COUNT #fde68a\n",[3452,10129,10130],{"class":3454,"line":3646},[3452,10131,10132],{},"rectangle \"Circuit Breaker 🔴\" as CB #fca5a5\n",[3452,10134,10135],{"class":3454,"line":3652},[3452,10136,10137],{},"rectangle \"Rollback to v1 ✅\" as ROLLBACK #bbf7d0\n",[3452,10139,10140],{"class":3454,"line":3658},[3452,10141,10142],{},"rectangle \"Service stable\" as OK #d1fae5\n",[3452,10144,10145],{"class":3454,"line":3664},[3452,10146,3619],{"emptyLinePlaceholder":3618},[3452,10148,10149],{"class":3454,"line":3670},[3452,10150,10151],{},"UPDATE -down-> NEW\n",[3452,10153,10154],{"class":3454,"line":3676},[3452,10155,10156],{},"NEW -down-> FAIL : health check fails\n",[3452,10158,10159],{"class":3454,"line":3682},[3452,10160,10161],{},"FAIL -down-> COUNT : increment counter\n",[3452,10163,10164],{"class":3454,"line":3688},[3452,10165,10166],{},"COUNT -down-> CB : threshold reached\n",[3452,10168,10169],{"class":3454,"line":3694},[3452,10170,10171],{},"CB -down-> ROLLBACK : automatic\n",[3452,10173,10174],{"class":3454,"line":3699},[3452,10175,10176],{},"ROLLBACK -down-> OK\n",[3452,10178,10179],{"class":3454,"line":3705},[3452,10180,3772],{},[3573,10182,10184],{"id":10183},"deployment-circuit-breaker-автоматичний-відкат-при-збоях","Deployment Circuit Breaker — автоматичний відкат при збоях",[3354,10186,10187,10190],{},[3540,10188,10189],{},"Circuit Breaker"," — це механізм, який автоматично зупиняє rolling deployment і відкочується до попередньої версії, якщо нові Tasks не проходять health check.",[3354,10192,10193,10196],{},[3540,10194,10195],{},"Без Circuit Breaker:"," якщо новий образ має баг і Tasks не запускаються — ECS нескінченно намагається їх запустити. Deployment «зависає», стара версія поступово видаляється — сервіс деградує.",[3354,10198,10199,10202],{},[3540,10200,10201],{},"З Circuit Breaker:"," ECS підраховує, скільки Tasks підряд не вдалося запустити. Якщо досягнуто порогу (за замовчуванням 10 провальних Tasks) — deployment зупиняється і автоматично відкочується до попередньої Task Definition revision.",[3442,10204,10206],{"className":3444,"code":10205,"language":3446,"meta":3447,"style":3447},"# Увімкнути Circuit Breaker при оновленні Service\naws ecs update-service \\\n    --cluster my-cluster \\\n    --service my-api-service \\\n    --deployment-configuration '{\n        \"deploymentCircuitBreaker\": {\n            \"enable\": true,\n            \"rollback\": true\n        },\n        \"maximumPercent\": 200,\n        \"minimumHealthyPercent\": 50\n    }' \\\n    --region eu-central-1\n",[3449,10207,10208,10213,10223,10231,10239,10246,10251,10256,10261,10265,10270,10275,10281],{"__ignoreMap":3447},[3452,10209,10210],{"class":3454,"line":3455},[3452,10211,10212],{"class":3469},"# Увімкнути Circuit Breaker при оновленні Service\n",[3452,10214,10215,10217,10219,10221],{"class":3454,"line":3473},[3452,10216,3459],{"class":3458},[3452,10218,6888],{"class":3462},[3452,10220,9875],{"class":3462},[3452,10222,5067],{"class":5066},[3452,10224,10225,10227,10229],{"class":3454,"line":3609},[3452,10226,7627],{"class":3953},[3452,10228,9884],{"class":3462},[3452,10230,5067],{"class":5066},[3452,10232,10233,10235,10237],{"class":3454,"line":3615},[3452,10234,9891],{"class":3953},[3452,10236,9894],{"class":3462},[3452,10238,5067],{"class":5066},[3452,10240,10241,10244],{"class":3454,"line":3622},[3452,10242,10243],{"class":3953},"    --deployment-configuration",[3452,10245,7010],{"class":3462},[3452,10247,10248],{"class":3454,"line":3628},[3452,10249,10250],{"class":3462},"        \"deploymentCircuitBreaker\": {\n",[3452,10252,10253],{"class":3454,"line":3634},[3452,10254,10255],{"class":3462},"            \"enable\": true,\n",[3452,10257,10258],{"class":3454,"line":3640},[3452,10259,10260],{"class":3462},"            \"rollback\": true\n",[3452,10262,10263],{"class":3454,"line":3646},[3452,10264,7030],{"class":3462},[3452,10266,10267],{"class":3454,"line":3652},[3452,10268,10269],{"class":3462},"        \"maximumPercent\": 200,\n",[3452,10271,10272],{"class":3454,"line":3658},[3452,10273,10274],{"class":3462},"        \"minimumHealthyPercent\": 50\n",[3452,10276,10277,10279],{"class":3454,"line":3664},[3452,10278,7045],{"class":3462},[3452,10280,5067],{"class":5066},[3452,10282,10283,10285],{"class":3454,"line":3670},[3452,10284,6935],{"class":3953},[3452,10286,6938],{"class":3462},[3354,10288,10289,10292,10293,10296,10297,10296,10300,3516],{},[3540,10290,10291],{},"Через Console:"," ECS → Services → Update → розділ ",[3540,10294,10295],{},"«Deployment options»"," → ✅ ",[3540,10298,10299],{},"Circuit breaker",[3540,10301,10302],{},"Rollback on failure",[5114,10304,10305,10306,10309],{},"Завжди вмикайте Circuit Breaker з ",[3449,10307,10308],{},"rollback: true"," у production. Це забезпечує автоматичний захист від деплою зламаного коду.",[3518,10311],{},[3354,10313,10314],{},[3527,10315],{"alt":10316,"className":10317,"src":10318},"ECS Service Connect internal service discovery and mesh communication",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F22.jpg",[3588,10320,10321],{},[3442,10322,10324],{"className":3592,"code":10323,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\npackage \"ECS Cluster\" #e9ecef {\n    package \"Service Connect Namespace: my-app\" #dbeafe {\n        rectangle \"OrderService\\n(order-service:8080)\" as OS #bbf7d0\n        rectangle \"UserService\\n(user-service:8080)\" as US #bbf7d0\n        rectangle \"NotificationService\\n(notify-service:8080)\" as NS #bbf7d0\n    }\n}\n\nOS -down-> US : http:\u002F\u002Fuser-service:8080\u002Fapi\u002Fusers\nOS -down-> NS : http:\u002F\u002Fnotify-service:8080\u002Fsend\nnote right of OS\n  Service Connect proxy (Envoy)\n  automatically routes traffic\nend note\n@enduml\n",[3449,10325,10326,10330,10334,10338,10342,10347,10352,10357,10362,10367,10371,10375,10379,10384,10389,10394,10399,10404,10408],{"__ignoreMap":3447},[3452,10327,10328],{"class":3454,"line":3455},[3452,10329,3601],{},[3452,10331,10332],{"class":3454,"line":3473},[3452,10333,3606],{},[3452,10335,10336],{"class":3454,"line":3609},[3452,10337,3612],{},[3452,10339,10340],{"class":3454,"line":3615},[3452,10341,3619],{"emptyLinePlaceholder":3618},[3452,10343,10344],{"class":3454,"line":3622},[3452,10345,10346],{},"package \"ECS Cluster\" #e9ecef {\n",[3452,10348,10349],{"class":3454,"line":3628},[3452,10350,10351],{},"    package \"Service Connect Namespace: my-app\" #dbeafe {\n",[3452,10353,10354],{"class":3454,"line":3634},[3452,10355,10356],{},"        rectangle \"OrderService\\n(order-service:8080)\" as OS #bbf7d0\n",[3452,10358,10359],{"class":3454,"line":3640},[3452,10360,10361],{},"        rectangle \"UserService\\n(user-service:8080)\" as US #bbf7d0\n",[3452,10363,10364],{"class":3454,"line":3646},[3452,10365,10366],{},"        rectangle \"NotificationService\\n(notify-service:8080)\" as NS #bbf7d0\n",[3452,10368,10369],{"class":3454,"line":3652},[3452,10370,3655],{},[3452,10372,10373],{"class":3454,"line":3658},[3452,10374,3691],{},[3452,10376,10377],{"class":3454,"line":3664},[3452,10378,3619],{"emptyLinePlaceholder":3618},[3452,10380,10381],{"class":3454,"line":3670},[3452,10382,10383],{},"OS -down-> US : http:\u002F\u002Fuser-service:8080\u002Fapi\u002Fusers\n",[3452,10385,10386],{"class":3454,"line":3676},[3452,10387,10388],{},"OS -down-> NS : http:\u002F\u002Fnotify-service:8080\u002Fsend\n",[3452,10390,10391],{"class":3454,"line":3682},[3452,10392,10393],{},"note right of OS\n",[3452,10395,10396],{"class":3454,"line":3688},[3452,10397,10398],{},"  Service Connect proxy (Envoy)\n",[3452,10400,10401],{"class":3454,"line":3694},[3452,10402,10403],{},"  automatically routes traffic\n",[3452,10405,10406],{"class":3454,"line":3699},[3452,10407,6575],{},[3452,10409,10410],{"class":3454,"line":3705},[3452,10411,3772],{},[3573,10413,10415],{"id":10414},"service-connect-внутрішній-service-discovery","Service Connect — внутрішній service discovery",[3354,10417,10418,10421],{},[3540,10419,10420],{},"ECS Service Connect"," — це вбудований механізм service discovery та load balancing для комунікації між мікросервісами всередині одного кластера. Замість того, щоб налаштовувати AWS Cloud Map або ALB для internal трафіку, Service Connect робить це автоматично.",[3354,10423,10424,3893,10427,10430,10431,10434,10435,10437,10438,10441],{},[3540,10425,10426],{},"Сценарій:",[3449,10428,10429],{},"OrderService"," потребує звертатись до ",[3449,10432,10433],{},"UserService",". З Service Connect — ",[3449,10436,10433],{}," доступний просто за назвою ",[3449,10439,10440],{},"user-service:8080"," без жодного DNS-налаштування.",[3354,10443,10444],{},[3540,10445,10446],{},"Налаштування Service Connect у Task Definition:",[3442,10448,10450],{"className":5521,"code":10449,"language":5523,"meta":3447,"style":3447},"\"serviceConnectConfiguration\": {\n    \"enabled\": true,\n    \"namespace\": \"my-app\",\n    \"services\": [{\n        \"portName\": \"http\",\n        \"discoveryName\": \"user-service\",\n        \"clientAliases\": [{\n            \"port\": 8080,\n            \"dnsName\": \"user-service\"\n        }]\n    }]\n}\n",[3449,10451,10452,10459,10471,10483,10491,10503,10515,10522,10533,10543,10547,10552],{"__ignoreMap":3447},[3452,10453,10454,10457],{"class":3454,"line":3455},[3452,10455,10456],{"class":3462},"\"serviceConnectConfiguration\"",[3452,10458,5807],{"class":3961},[3452,10460,10461,10464,10466,10469],{"class":3454,"line":3473},[3452,10462,10463],{"class":5534},"    \"enabled\"",[3452,10465,5538],{"class":3961},[3452,10467,10468],{"class":3953},"true",[3452,10470,5544],{"class":3961},[3452,10472,10473,10476,10478,10481],{"class":3454,"line":3609},[3452,10474,10475],{"class":5534},"    \"namespace\"",[3452,10477,5538],{"class":3961},[3452,10479,10480],{"class":3462},"\"my-app\"",[3452,10482,5544],{"class":3961},[3452,10484,10485,10488],{"class":3454,"line":3615},[3452,10486,10487],{"class":5534},"    \"services\"",[3452,10489,10490],{"class":3961},": [{\n",[3452,10492,10493,10496,10498,10501],{"class":3454,"line":3622},[3452,10494,10495],{"class":5534},"        \"portName\"",[3452,10497,5538],{"class":3961},[3452,10499,10500],{"class":3462},"\"http\"",[3452,10502,5544],{"class":3961},[3452,10504,10505,10508,10510,10513],{"class":3454,"line":3628},[3452,10506,10507],{"class":5534},"        \"discoveryName\"",[3452,10509,5538],{"class":3961},[3452,10511,10512],{"class":3462},"\"user-service\"",[3452,10514,5544],{"class":3961},[3452,10516,10517,10520],{"class":3454,"line":3634},[3452,10518,10519],{"class":5534},"        \"clientAliases\"",[3452,10521,10490],{"class":3961},[3452,10523,10524,10527,10529,10531],{"class":3454,"line":3640},[3452,10525,10526],{"class":5534},"            \"port\"",[3452,10528,5538],{"class":3961},[3452,10530,5676],{"class":4152},[3452,10532,5544],{"class":3961},[3452,10534,10535,10538,10540],{"class":3454,"line":3646},[3452,10536,10537],{"class":5534},"            \"dnsName\"",[3452,10539,5538],{"class":3961},[3452,10541,10542],{"class":3462},"\"user-service\"\n",[3452,10544,10545],{"class":3454,"line":3652},[3452,10546,9587],{"class":3961},[3452,10548,10549],{"class":3454,"line":3658},[3452,10550,10551],{"class":3961},"    }]\n",[3452,10553,10554],{"class":3454,"line":3664},[3452,10555,3691],{"class":3961},[3354,10557,10558,10559,10561,10562,10565],{},"Після цього ",[3449,10560,10429],{}," може звертатись до ",[3449,10563,10564],{},"http:\u002F\u002Fuser-service:8080\u002Fapi\u002Fusers"," — ECS автоматично проксіює запит на відповідний Task через Envoy proxy, вбудований у кожен Task.",[3518,10567],{},[3354,10569,10570],{},[3527,10571],{"alt":10572,"className":10573,"src":10574},"ECS scheduled tasks with Amazon EventBridge Scheduler cron job diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F23.png",[3588,10576,10577],{},[3442,10578,10580],{"className":3592,"code":10579,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"EventBridge Scheduler\\ncron(0 2 * * ? *)\" as EB #e0e7ff\nrectangle \"IAM Role\" as IAM #fef3c7\nrectangle \"ECS Cluster\" as ECS #dbeafe {\n    rectangle \"Daily Cleanup Task\\n(Fargate)\" as TASK #bbf7d0\n}\nrectangle \"CloudWatch Logs\" as LOGS #d1fae5\n\nEB -right-> IAM : assumes role\nIAM -right-> ECS : ecs:RunTask\nECS -right-> TASK : runs container\nTASK -right-> LOGS : writes logs\nnote right of EB\n  Trigger: every day at 02:00 UTC\n  One-time RunTask (not Service)\nend note\n@enduml\n",[3449,10581,10582,10586,10590,10594,10598,10603,10608,10613,10618,10622,10627,10631,10636,10641,10646,10651,10656,10661,10666,10670],{"__ignoreMap":3447},[3452,10583,10584],{"class":3454,"line":3455},[3452,10585,3601],{},[3452,10587,10588],{"class":3454,"line":3473},[3452,10589,3606],{},[3452,10591,10592],{"class":3454,"line":3609},[3452,10593,3612],{},[3452,10595,10596],{"class":3454,"line":3615},[3452,10597,3619],{"emptyLinePlaceholder":3618},[3452,10599,10600],{"class":3454,"line":3622},[3452,10601,10602],{},"rectangle \"EventBridge Scheduler\\ncron(0 2 * * ? *)\" as EB #e0e7ff\n",[3452,10604,10605],{"class":3454,"line":3628},[3452,10606,10607],{},"rectangle \"IAM Role\" as IAM #fef3c7\n",[3452,10609,10610],{"class":3454,"line":3634},[3452,10611,10612],{},"rectangle \"ECS Cluster\" as ECS #dbeafe {\n",[3452,10614,10615],{"class":3454,"line":3640},[3452,10616,10617],{},"    rectangle \"Daily Cleanup Task\\n(Fargate)\" as TASK #bbf7d0\n",[3452,10619,10620],{"class":3454,"line":3646},[3452,10621,3691],{},[3452,10623,10624],{"class":3454,"line":3652},[3452,10625,10626],{},"rectangle \"CloudWatch Logs\" as LOGS #d1fae5\n",[3452,10628,10629],{"class":3454,"line":3658},[3452,10630,3619],{"emptyLinePlaceholder":3618},[3452,10632,10633],{"class":3454,"line":3664},[3452,10634,10635],{},"EB -right-> IAM : assumes role\n",[3452,10637,10638],{"class":3454,"line":3670},[3452,10639,10640],{},"IAM -right-> ECS : ecs:RunTask\n",[3452,10642,10643],{"class":3454,"line":3676},[3452,10644,10645],{},"ECS -right-> TASK : runs container\n",[3452,10647,10648],{"class":3454,"line":3682},[3452,10649,10650],{},"TASK -right-> LOGS : writes logs\n",[3452,10652,10653],{"class":3454,"line":3688},[3452,10654,10655],{},"note right of EB\n",[3452,10657,10658],{"class":3454,"line":3694},[3452,10659,10660],{},"  Trigger: every day at 02:00 UTC\n",[3452,10662,10663],{"class":3454,"line":3699},[3452,10664,10665],{},"  One-time RunTask (not Service)\n",[3452,10667,10668],{"class":3454,"line":3705},[3452,10669,6575],{},[3452,10671,10672],{"class":3454,"line":3711},[3452,10673,3772],{},[3573,10675,10677],{"id":10676},"scheduled-tasks-запуск-контейнерів-за-розкладом","Scheduled Tasks — запуск контейнерів за розкладом",[3354,10679,10680,10681,10684,10685,10688],{},"ECS підтримує запуск ",[3540,10682,10683],{},"одноразових Tasks"," за розкладом через інтеграцію з ",[3540,10686,10687],{},"Amazon EventBridge Scheduler",". Це ідеально для batch-задач, щоденних звітів, очищення даних.",[3354,10690,10691],{},[3540,10692,10693],{},"Приклад: запускати контейнер щодня о 02:00 UTC:",[9851,10695,10696,11059],{},[9854,10697,10698],{"label":9856},[3442,10699,10701],{"className":3444,"code":10700,"language":3446,"meta":3447,"style":3447},"# Крок 1: Створіть Trust Policy файл для IAM Role\ncat > \u002Ftmp\u002Feb-ecs-trust.json \u003C\u003C 'EOF'\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [{\n        \"Effect\": \"Allow\",\n        \"Principal\": { \"Service\": \"scheduler.amazonaws.com\" },\n        \"Action\": \"sts:AssumeRole\"\n    }]\n}\nEOF\n\n# Крок 2: Створіть IAM Role\naws iam create-role \\\n    --role-name EventBridgeECSRole \\\n    --assume-role-policy-document file:\u002F\u002F\u002Ftmp\u002Feb-ecs-trust.json\n\n# Крок 3: Додайте інлайн-політику з правами ecs:RunTask та iam:PassRole\naws iam put-role-policy \\\n    --role-name EventBridgeECSRole \\\n    --policy-name ECSRunTaskPolicy \\\n    --policy-document '{\n        \"Version\": \"2012-10-17\",\n        \"Statement\": [\n            {\n                \"Effect\": \"Allow\",\n                \"Action\": \"ecs:RunTask\",\n                \"Resource\": \"arn:aws:ecs:eu-central-1:123456789012:task-definition\u002Fcleanup-task:*\"\n            },\n            {\n                \"Effect\": \"Allow\",\n                \"Action\": \"iam:PassRole\",\n                \"Resource\": \"arn:aws:iam::123456789012:role\u002FecsTaskExecutionRole\"\n            }\n        ]\n    }'\n\n# Крок 4: Створіть scheduled task\naws scheduler create-schedule \\\n    --name \"daily-cleanup\" \\\n    --schedule-expression \"cron(0 2 * * ? *)\" \\\n    --flexible-time-window '{\"Mode\": \"OFF\"}' \\\n    --target '{\n        \"Arn\": \"arn:aws:ecs:eu-central-1:123456789012:cluster\u002Fmy-cluster\",\n        \"RoleArn\": \"arn:aws:iam::123456789012:role\u002FEventBridgeECSRole\",\n        \"EcsParameters\": {\n            \"TaskDefinitionArn\": \"arn:aws:ecs:eu-central-1:123456789012:task-definition\u002Fcleanup-task:1\",\n            \"LaunchType\": \"FARGATE\",\n            \"NetworkConfiguration\": {\n                \"AwsvpcConfiguration\": {\n                    \"Subnets\": [\"subnet-xxx\"],\n                    \"SecurityGroups\": [\"sg-xxx\"],\n                    \"AssignPublicIp\": \"DISABLED\"\n                }\n            }\n        }\n    }' \\\n    --region eu-central-1\n",[3449,10702,10703,10708,10725,10729,10734,10739,10744,10749,10754,10758,10762,10767,10771,10776,10788,10798,10806,10810,10815,10826,10834,10843,10850,10855,10860,10865,10870,10875,10880,10884,10888,10892,10897,10902,10906,10911,10916,10920,10925,10937,10946,10956,10966,10973,10978,10983,10988,10994,11000,11006,11012,11018,11024,11030,11035,11040,11045,11052],{"__ignoreMap":3447},[3452,10704,10705],{"class":3454,"line":3455},[3452,10706,10707],{"class":3469},"# Крок 1: Створіть Trust Policy файл для IAM Role\n",[3452,10709,10710,10713,10716,10719,10722],{"class":3454,"line":3473},[3452,10711,10712],{"class":3458},"cat",[3452,10714,10715],{"class":3961}," > ",[3452,10717,10718],{"class":3462},"\u002Ftmp\u002Feb-ecs-trust.json",[3452,10720,10721],{"class":3961}," \u003C\u003C ",[3452,10723,10724],{"class":3961},"'EOF'\n",[3452,10726,10727],{"class":3454,"line":3609},[3452,10728,4097],{"class":3462},[3452,10730,10731],{"class":3454,"line":3615},[3452,10732,10733],{"class":3462},"    \"Version\": \"2012-10-17\",\n",[3452,10735,10736],{"class":3454,"line":3622},[3452,10737,10738],{"class":3462},"    \"Statement\": [{\n",[3452,10740,10741],{"class":3454,"line":3628},[3452,10742,10743],{"class":3462},"        \"Effect\": \"Allow\",\n",[3452,10745,10746],{"class":3454,"line":3634},[3452,10747,10748],{"class":3462},"        \"Principal\": { \"Service\": \"scheduler.amazonaws.com\" },\n",[3452,10750,10751],{"class":3454,"line":3640},[3452,10752,10753],{"class":3462},"        \"Action\": \"sts:AssumeRole\"\n",[3452,10755,10756],{"class":3454,"line":3646},[3452,10757,10551],{"class":3462},[3452,10759,10760],{"class":3454,"line":3652},[3452,10761,3691],{"class":3462},[3452,10763,10764],{"class":3454,"line":3658},[3452,10765,10766],{"class":3961},"EOF\n",[3452,10768,10769],{"class":3454,"line":3664},[3452,10770,3619],{"emptyLinePlaceholder":3618},[3452,10772,10773],{"class":3454,"line":3670},[3452,10774,10775],{"class":3469},"# Крок 2: Створіть IAM Role\n",[3452,10777,10778,10780,10783,10786],{"class":3454,"line":3676},[3452,10779,3459],{"class":3458},[3452,10781,10782],{"class":3462}," iam",[3452,10784,10785],{"class":3462}," create-role",[3452,10787,5067],{"class":5066},[3452,10789,10790,10793,10796],{"class":3454,"line":3682},[3452,10791,10792],{"class":3953},"    --role-name",[3452,10794,10795],{"class":3462}," EventBridgeECSRole",[3452,10797,5067],{"class":5066},[3452,10799,10800,10803],{"class":3454,"line":3688},[3452,10801,10802],{"class":3953},"    --assume-role-policy-document",[3452,10804,10805],{"class":3462}," file:\u002F\u002F\u002Ftmp\u002Feb-ecs-trust.json\n",[3452,10807,10808],{"class":3454,"line":3694},[3452,10809,3619],{"emptyLinePlaceholder":3618},[3452,10811,10812],{"class":3454,"line":3699},[3452,10813,10814],{"class":3469},"# Крок 3: Додайте інлайн-політику з правами ecs:RunTask та iam:PassRole\n",[3452,10816,10817,10819,10821,10824],{"class":3454,"line":3705},[3452,10818,3459],{"class":3458},[3452,10820,10782],{"class":3462},[3452,10822,10823],{"class":3462}," put-role-policy",[3452,10825,5067],{"class":5066},[3452,10827,10828,10830,10832],{"class":3454,"line":3711},[3452,10829,10792],{"class":3953},[3452,10831,10795],{"class":3462},[3452,10833,5067],{"class":5066},[3452,10835,10836,10838,10841],{"class":3454,"line":3717},[3452,10837,6987],{"class":3953},[3452,10839,10840],{"class":3462}," ECSRunTaskPolicy",[3452,10842,5067],{"class":5066},[3452,10844,10845,10848],{"class":3454,"line":3723},[3452,10846,10847],{"class":3953},"    --policy-document",[3452,10849,7010],{"class":3462},[3452,10851,10852],{"class":3454,"line":3729},[3452,10853,10854],{"class":3462},"        \"Version\": \"2012-10-17\",\n",[3452,10856,10857],{"class":3454,"line":3734},[3452,10858,10859],{"class":3462},"        \"Statement\": [\n",[3452,10861,10862],{"class":3454,"line":3740},[3452,10863,10864],{"class":3462},"            {\n",[3452,10866,10867],{"class":3454,"line":3746},[3452,10868,10869],{"class":3462},"                \"Effect\": \"Allow\",\n",[3452,10871,10872],{"class":3454,"line":3752},[3452,10873,10874],{"class":3462},"                \"Action\": \"ecs:RunTask\",\n",[3452,10876,10877],{"class":3454,"line":3758},[3452,10878,10879],{"class":3462},"                \"Resource\": \"arn:aws:ecs:eu-central-1:123456789012:task-definition\u002Fcleanup-task:*\"\n",[3452,10881,10882],{"class":3454,"line":3764},[3452,10883,5869],{"class":3462},[3452,10885,10886],{"class":3454,"line":3769},[3452,10887,10864],{"class":3462},[3452,10889,10890],{"class":3454,"line":4629},[3452,10891,10869],{"class":3462},[3452,10893,10894],{"class":3454,"line":4637},[3452,10895,10896],{"class":3462},"                \"Action\": \"iam:PassRole\",\n",[3452,10898,10899],{"class":3454,"line":4642},[3452,10900,10901],{"class":3462},"                \"Resource\": \"arn:aws:iam::123456789012:role\u002FecsTaskExecutionRole\"\n",[3452,10903,10904],{"class":3454,"line":4648},[3452,10905,5947],{"class":3462},[3452,10907,10908],{"class":3454,"line":4654},[3452,10909,10910],{"class":3462},"        ]\n",[3452,10912,10913],{"class":3454,"line":4660},[3452,10914,10915],{"class":3462},"    }'\n",[3452,10917,10918],{"class":3454,"line":4668},[3452,10919,3619],{"emptyLinePlaceholder":3618},[3452,10921,10922],{"class":3454,"line":4673},[3452,10923,10924],{"class":3469},"# Крок 4: Створіть scheduled task\n",[3452,10926,10927,10929,10932,10935],{"class":3454,"line":4679},[3452,10928,3459],{"class":3458},[3452,10930,10931],{"class":3462}," scheduler",[3452,10933,10934],{"class":3462}," create-schedule",[3452,10936,5067],{"class":5066},[3452,10938,10939,10941,10944],{"class":3454,"line":5908},[3452,10940,7306],{"class":3953},[3452,10942,10943],{"class":3462}," \"daily-cleanup\"",[3452,10945,5067],{"class":5066},[3452,10947,10948,10951,10954],{"class":3454,"line":5920},[3452,10949,10950],{"class":3953},"    --schedule-expression",[3452,10952,10953],{"class":3462}," \"cron(0 2 * * ? *)\"",[3452,10955,5067],{"class":5066},[3452,10957,10958,10961,10964],{"class":3454,"line":5933},[3452,10959,10960],{"class":3953},"    --flexible-time-window",[3452,10962,10963],{"class":3462}," '{\"Mode\": \"OFF\"}'",[3452,10965,5067],{"class":5066},[3452,10967,10968,10971],{"class":3454,"line":5944},[3452,10969,10970],{"class":3953},"    --target",[3452,10972,7010],{"class":3462},[3452,10974,10975],{"class":3454,"line":5950},[3452,10976,10977],{"class":3462},"        \"Arn\": \"arn:aws:ecs:eu-central-1:123456789012:cluster\u002Fmy-cluster\",\n",[3452,10979,10980],{"class":3454,"line":5956},[3452,10981,10982],{"class":3462},"        \"RoleArn\": \"arn:aws:iam::123456789012:role\u002FEventBridgeECSRole\",\n",[3452,10984,10985],{"class":3454,"line":5962},[3452,10986,10987],{"class":3462},"        \"EcsParameters\": {\n",[3452,10989,10991],{"class":3454,"line":10990},47,[3452,10992,10993],{"class":3462},"            \"TaskDefinitionArn\": \"arn:aws:ecs:eu-central-1:123456789012:task-definition\u002Fcleanup-task:1\",\n",[3452,10995,10997],{"class":3454,"line":10996},48,[3452,10998,10999],{"class":3462},"            \"LaunchType\": \"FARGATE\",\n",[3452,11001,11003],{"class":3454,"line":11002},49,[3452,11004,11005],{"class":3462},"            \"NetworkConfiguration\": {\n",[3452,11007,11009],{"class":3454,"line":11008},50,[3452,11010,11011],{"class":3462},"                \"AwsvpcConfiguration\": {\n",[3452,11013,11015],{"class":3454,"line":11014},51,[3452,11016,11017],{"class":3462},"                    \"Subnets\": [\"subnet-xxx\"],\n",[3452,11019,11021],{"class":3454,"line":11020},52,[3452,11022,11023],{"class":3462},"                    \"SecurityGroups\": [\"sg-xxx\"],\n",[3452,11025,11027],{"class":3454,"line":11026},53,[3452,11028,11029],{"class":3462},"                    \"AssignPublicIp\": \"DISABLED\"\n",[3452,11031,11033],{"class":3454,"line":11032},54,[3452,11034,5693],{"class":3462},[3452,11036,11038],{"class":3454,"line":11037},55,[3452,11039,5947],{"class":3462},[3452,11041,11043],{"class":3454,"line":11042},56,[3452,11044,5953],{"class":3462},[3452,11046,11048,11050],{"class":3454,"line":11047},57,[3452,11049,7045],{"class":3462},[3452,11051,5067],{"class":5066},[3452,11053,11055,11057],{"class":3454,"line":11054},58,[3452,11056,6935],{"class":3953},[3452,11058,6938],{"class":3462},[9854,11060,11061],{"label":9996},[7751,11062,11063,11075,11081,11087,11097,11100],{},[4702,11064,11065,11066,9024,11069,9024,11072],{},"Відкрийте ",[3540,11067,11068],{},"Amazon EventBridge",[3540,11070,11071],{},"Schedules",[3540,11073,11074],{},"Create schedule",[4702,11076,11077,11078],{},"Name: ",[3449,11079,11080],{},"daily-cleanup",[4702,11082,11083,11084],{},"Schedule pattern: Recurring → Cron: ",[3449,11085,11086],{},"0 2 * * ? *",[4702,11088,11089,11090,11093,11094],{},"Target: ",[3540,11091,11092],{},"AWS API"," → ECS → ",[3540,11095,11096],{},"RunTask",[4702,11098,11099],{},"Оберіть кластер, Task Definition, підмережі, Security Group",[4702,11101,11102,11103],{},"Натисніть ",[3540,11104,11105],{},"«Create schedule»",[3518,11107],{},[3354,11109,11110],{},[3527,11111],{"alt":11112,"className":11113,"src":11114},"ECS capacity providers FARGATE and FARGATE_SPOT strategy diagram",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F24.jpg",[3588,11116,11117],{},[3442,11118,11120],{"className":3592,"code":11119,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"ECS Cluster\" as CLUSTER #e9ecef {\n    rectangle \"Capacity Provider Strategy\" as STRAT #dbeafe {\n        rectangle \"FARGATE (25%)\\nbase=1, weight=1\" as FG #bbf7d0\n        rectangle \"FARGATE_SPOT (75%)\\nweight=3\" as SPOT #fef3c7\n    }\n    rectangle \"Task 1 (base)\" as T1 #bbf7d0\n    rectangle \"Task 2 (Spot)\" as T2 #fde68a\n    rectangle \"Task 3 (Spot)\" as T3 #fde68a\n    rectangle \"Task 4 (Spot)\" as T4 #fde68a\n}\n\nnote right of SPOT\n  ~50-60% cost savings\n  Tasks can be interrupted\n  with 2-min warning\nend note\n@enduml\n",[3449,11121,11122,11126,11130,11134,11138,11143,11148,11153,11158,11162,11167,11172,11177,11182,11186,11190,11195,11200,11205,11210,11214],{"__ignoreMap":3447},[3452,11123,11124],{"class":3454,"line":3455},[3452,11125,3601],{},[3452,11127,11128],{"class":3454,"line":3473},[3452,11129,3606],{},[3452,11131,11132],{"class":3454,"line":3609},[3452,11133,3612],{},[3452,11135,11136],{"class":3454,"line":3615},[3452,11137,3619],{"emptyLinePlaceholder":3618},[3452,11139,11140],{"class":3454,"line":3622},[3452,11141,11142],{},"rectangle \"ECS Cluster\" as CLUSTER #e9ecef {\n",[3452,11144,11145],{"class":3454,"line":3628},[3452,11146,11147],{},"    rectangle \"Capacity Provider Strategy\" as STRAT #dbeafe {\n",[3452,11149,11150],{"class":3454,"line":3634},[3452,11151,11152],{},"        rectangle \"FARGATE (25%)\\nbase=1, weight=1\" as FG #bbf7d0\n",[3452,11154,11155],{"class":3454,"line":3640},[3452,11156,11157],{},"        rectangle \"FARGATE_SPOT (75%)\\nweight=3\" as SPOT #fef3c7\n",[3452,11159,11160],{"class":3454,"line":3646},[3452,11161,3655],{},[3452,11163,11164],{"class":3454,"line":3652},[3452,11165,11166],{},"    rectangle \"Task 1 (base)\" as T1 #bbf7d0\n",[3452,11168,11169],{"class":3454,"line":3658},[3452,11170,11171],{},"    rectangle \"Task 2 (Spot)\" as T2 #fde68a\n",[3452,11173,11174],{"class":3454,"line":3664},[3452,11175,11176],{},"    rectangle \"Task 3 (Spot)\" as T3 #fde68a\n",[3452,11178,11179],{"class":3454,"line":3670},[3452,11180,11181],{},"    rectangle \"Task 4 (Spot)\" as T4 #fde68a\n",[3452,11183,11184],{"class":3454,"line":3676},[3452,11185,3691],{},[3452,11187,11188],{"class":3454,"line":3682},[3452,11189,3619],{"emptyLinePlaceholder":3618},[3452,11191,11192],{"class":3454,"line":3688},[3452,11193,11194],{},"note right of SPOT\n",[3452,11196,11197],{"class":3454,"line":3694},[3452,11198,11199],{},"  ~50-60% cost savings\n",[3452,11201,11202],{"class":3454,"line":3699},[3452,11203,11204],{},"  Tasks can be interrupted\n",[3452,11206,11207],{"class":3454,"line":3705},[3452,11208,11209],{},"  with 2-min warning\n",[3452,11211,11212],{"class":3454,"line":3711},[3452,11213,6575],{},[3452,11215,11216],{"class":3454,"line":3717},[3452,11217,3772],{},[3573,11219,11221],{"id":11220},"capacity-providers-управління-ресурсами-кластера","Capacity Providers — управління ресурсами кластера",[3354,11223,11224,11227],{},[3540,11225,11226],{},"Capacity Provider"," визначає, де і як ECS виділяє ресурси для запуску Tasks. Для Fargate доступні два built-in провайдери:",[4699,11229,11230,11236],{},[4702,11231,11232,11235],{},[3540,11233,11234],{},"FARGATE"," — стандартний Fargate. Підходить для більшості задач.",[4702,11237,11238,11241],{},[3540,11239,11240],{},"FARGATE_SPOT"," — Tasks запускаються на AWS Spot Capacity. Знижка до 70%, але Tasks можуть бути примусово зупинені з 2-хвилинним попередженням. Ідеально для batch-задач і stateless воркерів.",[3354,11243,11244],{},[3540,11245,11246],{},"Налаштування Capacity Provider Strategy:",[3442,11248,11250],{"className":3444,"code":11249,"language":3446,"meta":3447,"style":3447},"# Налаштувати кластер на використання Fargate Spot\naws ecs put-cluster-capacity-providers \\\n    --cluster my-cluster \\\n    --capacity-providers FARGATE FARGATE_SPOT \\\n    --default-capacity-provider-strategy \\\n        \"capacityProvider=FARGATE_SPOT,weight=3,base=0\" \\\n        \"capacityProvider=FARGATE,weight=1,base=1\" \\\n    --region eu-central-1\n",[3449,11251,11252,11257,11268,11276,11288,11295,11302,11309],{"__ignoreMap":3447},[3452,11253,11254],{"class":3454,"line":3455},[3452,11255,11256],{"class":3469},"# Налаштувати кластер на використання Fargate Spot\n",[3452,11258,11259,11261,11263,11266],{"class":3454,"line":3473},[3452,11260,3459],{"class":3458},[3452,11262,6888],{"class":3462},[3452,11264,11265],{"class":3462}," put-cluster-capacity-providers",[3452,11267,5067],{"class":5066},[3452,11269,11270,11272,11274],{"class":3454,"line":3609},[3452,11271,7627],{"class":3953},[3452,11273,9884],{"class":3462},[3452,11275,5067],{"class":5066},[3452,11277,11278,11281,11283,11286],{"class":3454,"line":3615},[3452,11279,11280],{"class":3953},"    --capacity-providers",[3452,11282,7669],{"class":3462},[3452,11284,11285],{"class":3462}," FARGATE_SPOT",[3452,11287,5067],{"class":5066},[3452,11289,11290,11293],{"class":3454,"line":3622},[3452,11291,11292],{"class":3953},"    --default-capacity-provider-strategy",[3452,11294,5067],{"class":5066},[3452,11296,11297,11300],{"class":3454,"line":3628},[3452,11298,11299],{"class":3462},"        \"capacityProvider=FARGATE_SPOT,weight=3,base=0\"",[3452,11301,5067],{"class":5066},[3452,11303,11304,11307],{"class":3454,"line":3634},[3452,11305,11306],{"class":3462},"        \"capacityProvider=FARGATE,weight=1,base=1\"",[3452,11308,5067],{"class":5066},[3452,11310,11311,11313],{"class":3454,"line":3640},[3452,11312,6935],{"class":3953},[3452,11314,6938],{"class":3462},[3354,11316,11317,11318],{},"Ця конфігурація: 1 Task завжди на FARGATE (base=1), потім 75% нових Tasks — FARGATE_SPOT, 25% — FARGATE. ",[3540,11319,11320],{},"Економія 50–60% при прийнятному рівні надійності.",[3518,11322],{},[3354,11324,11325],{},[3527,11326],{"alt":11327,"className":11328,"src":11329},"CloudWatch Container Insights dashboard for ECS metrics CPU memory monitoring",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F25.png",[3588,11331,11332],{},[3442,11333,11335],{"className":3592,"code":11334,"language":3594,"meta":3447,"style":3447},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nrectangle \"ECS Cluster\" as CLUSTER #e9ecef {\n    rectangle \"Service: my-api\\nTask 1\" as T1 #bbf7d0\n    rectangle \"Service: my-api\\nTask 2\" as T2 #bbf7d0\n}\n\nrectangle \"CloudWatch\" as CW #dbeafe {\n    rectangle \"Container Insights\" as CI #bfdbfe\n    rectangle \"Metrics: CPU, Memory\\nNetwork, Storage\" as MET #e0e7ff\n    rectangle \"Logs: \u002Fecs\u002Fmy-api\" as LOGS #d1fae5\n    rectangle \"Dashboard\" as DASH #fef3c7\n}\n\nCLUSTER -right-> CW : emits metrics & logs\nCW --> CI : aggregates\nCI --> MET : collects\nCI --> LOGS : streams\nLOGS --> DASH : visualizes\n@enduml\n",[3449,11336,11337,11341,11345,11349,11353,11357,11362,11367,11371,11375,11380,11385,11390,11395,11400,11404,11408,11413,11418,11423,11428,11433],{"__ignoreMap":3447},[3452,11338,11339],{"class":3454,"line":3455},[3452,11340,3601],{},[3452,11342,11343],{"class":3454,"line":3473},[3452,11344,3606],{},[3452,11346,11347],{"class":3454,"line":3609},[3452,11348,3612],{},[3452,11350,11351],{"class":3454,"line":3615},[3452,11352,3619],{"emptyLinePlaceholder":3618},[3452,11354,11355],{"class":3454,"line":3622},[3452,11356,11142],{},[3452,11358,11359],{"class":3454,"line":3628},[3452,11360,11361],{},"    rectangle \"Service: my-api\\nTask 1\" as T1 #bbf7d0\n",[3452,11363,11364],{"class":3454,"line":3634},[3452,11365,11366],{},"    rectangle \"Service: my-api\\nTask 2\" as T2 #bbf7d0\n",[3452,11368,11369],{"class":3454,"line":3640},[3452,11370,3691],{},[3452,11372,11373],{"class":3454,"line":3646},[3452,11374,3619],{"emptyLinePlaceholder":3618},[3452,11376,11377],{"class":3454,"line":3652},[3452,11378,11379],{},"rectangle \"CloudWatch\" as CW #dbeafe {\n",[3452,11381,11382],{"class":3454,"line":3658},[3452,11383,11384],{},"    rectangle \"Container Insights\" as CI #bfdbfe\n",[3452,11386,11387],{"class":3454,"line":3664},[3452,11388,11389],{},"    rectangle \"Metrics: CPU, Memory\\nNetwork, Storage\" as MET #e0e7ff\n",[3452,11391,11392],{"class":3454,"line":3670},[3452,11393,11394],{},"    rectangle \"Logs: \u002Fecs\u002Fmy-api\" as LOGS #d1fae5\n",[3452,11396,11397],{"class":3454,"line":3676},[3452,11398,11399],{},"    rectangle \"Dashboard\" as DASH #fef3c7\n",[3452,11401,11402],{"class":3454,"line":3682},[3452,11403,3691],{},[3452,11405,11406],{"class":3454,"line":3688},[3452,11407,3619],{"emptyLinePlaceholder":3618},[3452,11409,11410],{"class":3454,"line":3694},[3452,11411,11412],{},"CLUSTER -right-> CW : emits metrics & logs\n",[3452,11414,11415],{"class":3454,"line":3699},[3452,11416,11417],{},"CW --> CI : aggregates\n",[3452,11419,11420],{"class":3454,"line":3705},[3452,11421,11422],{},"CI --> MET : collects\n",[3452,11424,11425],{"class":3454,"line":3711},[3452,11426,11427],{},"CI --> LOGS : streams\n",[3452,11429,11430],{"class":3454,"line":3717},[3452,11431,11432],{},"LOGS --> DASH : visualizes\n",[3452,11434,11435],{"class":3454,"line":3723},[3452,11436,3772],{},[3573,11438,11440],{"id":11439},"container-insights-розширений-моніторинг","Container Insights — розширений моніторинг",[3354,11442,11443,11446],{},[3540,11444,11445],{},"CloudWatch Container Insights"," — це dashboard з деталізованими метриками для ECS: CPU та Memory по кожному Task, Service та Cluster; кількість Task failures; network I\u002FO; storage I\u002FO.",[3354,11448,11449],{},[3540,11450,11451],{},"Увімкнення для кластера:",[3442,11453,11455],{"className":3444,"code":11454,"language":3446,"meta":3447,"style":3447},"aws ecs update-cluster-settings \\\n    --cluster my-cluster \\\n    --settings name=containerInsights,value=enabled \\\n    --region eu-central-1\n",[3449,11456,11457,11468,11476,11486],{"__ignoreMap":3447},[3452,11458,11459,11461,11463,11466],{"class":3454,"line":3455},[3452,11460,3459],{"class":3458},[3452,11462,6888],{"class":3462},[3452,11464,11465],{"class":3462}," update-cluster-settings",[3452,11467,5067],{"class":5066},[3452,11469,11470,11472,11474],{"class":3454,"line":3473},[3452,11471,7627],{"class":3953},[3452,11473,9884],{"class":3462},[3452,11475,5067],{"class":5066},[3452,11477,11478,11481,11484],{"class":3454,"line":3609},[3452,11479,11480],{"class":3953},"    --settings",[3452,11482,11483],{"class":3462}," name=containerInsights,value=enabled",[3452,11485,5067],{"class":5066},[3452,11487,11488,11490],{"class":3454,"line":3615},[3452,11489,6935],{"class":3953},[3452,11491,6938],{"class":3462},[3354,11493,11494,11496,11497,9024,11499,10296,11502,3516],{},[3540,11495,10291],{}," ECS → Clusters → ",[3449,11498,10004],{},[3540,11500,11501],{},"Update cluster",[3540,11503,11504],{},"Use Container Insights",[3354,11506,11507,11508,9024,11511,11514],{},"Після увімкнення: ",[3540,11509,11510],{},"CloudWatch",[3540,11512,11513],{},"Container Insights"," → оберіть ECS Clusters — ви побачите автоматично згенеровані дашборди з графіками CPU, Memory, Task count по кожному сервісу.",[3518,11516],{},[3354,11518,11519],{},[3527,11520],{"alt":11521,"className":11522,"src":11523},".NET Web API on ECS Fargate full deployment pipeline architecture",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F26.png",[3349,11525,11527],{"id":11526},"практичний-приклад-net-web-api-на-ecs-fargate-від-а-до-я","Практичний приклад: .NET Web API на ECS Fargate від А до Я",[3354,11529,11530],{},"Тепер застосуємо всю теорію та пройдемо повний шлях: від порожньої папки до працюючого API у хмарі.",[3573,11532,11534],{"id":11533},"крок-1-створення-net-проєкту","Крок 1: Створення .NET проєкту",[3354,11536,11537],{},"Відкрийте термінал і створіть новий проєкт:",[3881,11539,11541,11550,11556,11559],{"title":11540},"dotnet new webapi",[3885,11542,11544,3893,11547],{"className":11543},[3454],[3452,11545,3892],{"className":11546},[3891],[3540,11548,11549],{},"dotnet new webapi -n EcsLabApi --no-openapi",[3885,11551,11553],{"className":11552},[3454],[3452,11554,3917],{"className":11555},[3916],[3885,11557],{"className":11558},[3454],[3885,11560,11562,3893,11565],{"className":11561},[3454],[3452,11563,3892],{"className":11564},[3891],[3540,11566,11567],{},"cd EcsLabApi",[3354,11569,11570,11571,11573],{},"Відредагуйте ",[3449,11572,3940],{}," — повний вміст файлу:",[3442,11575,11577],{"className":3944,"code":11576,"language":3946,"meta":3447,"style":3447},"var builder = WebApplication.CreateBuilder(args);\n\n\u002F\u002F Реєструємо Health Check сервіс\nbuilder.Services.AddHealthChecks();\n\nvar app = builder.Build();\n\n\u002F\u002F Головний ендпоінт — версія відповіді береться зі змінної середовища\nvar version = Environment.GetEnvironmentVariable(\"APP_VERSION\") ?? \"1.0.0\";\n\napp.MapGet(\"\u002F\", () => new\n{\n    message = \"Hello from ECS Fargate!\",\n    version = version,\n    environment = app.Environment.EnvironmentName,\n    timestamp = DateTime.UtcNow\n});\n\n\u002F\u002F Health check ендпоінт — ECS використовує його для перевірки стану\napp.MapHealthChecks(\"\u002Fhealth\");\n\napp.Run();\n",[3449,11578,11579,11599,11603,11608,11622,11626,11642,11646,11651,11681,11685,11701,11705,11717,11728,11748,11762,11766,11770,11775,11789,11793],{"__ignoreMap":3447},[3452,11580,11581,11583,11585,11587,11589,11591,11593,11595,11597],{"class":3454,"line":3455},[3452,11582,3954],{"class":3953},[3452,11584,3958],{"class":3957},[3452,11586,3962],{"class":3961},[3452,11588,3965],{"class":3957},[3452,11590,3516],{"class":3961},[3452,11592,3970],{"class":3458},[3452,11594,3973],{"class":3961},[3452,11596,3976],{"class":3957},[3452,11598,3979],{"class":3961},[3452,11600,11601],{"class":3454,"line":3473},[3452,11602,3619],{"emptyLinePlaceholder":3618},[3452,11604,11605],{"class":3454,"line":3609},[3452,11606,11607],{"class":3469},"\u002F\u002F Реєструємо Health Check сервіс\n",[3452,11609,11610,11612,11614,11616,11618,11620],{"class":3454,"line":3615},[3452,11611,3988],{"class":3957},[3452,11613,3516],{"class":3961},[3452,11615,3993],{"class":3957},[3452,11617,3516],{"class":3961},[3452,11619,3998],{"class":3458},[3452,11621,4001],{"class":3961},[3452,11623,11624],{"class":3454,"line":3622},[3452,11625,3619],{"emptyLinePlaceholder":3618},[3452,11627,11628,11630,11632,11634,11636,11638,11640],{"class":3454,"line":3628},[3452,11629,3954],{"class":3953},[3452,11631,4012],{"class":3957},[3452,11633,3962],{"class":3961},[3452,11635,3988],{"class":3957},[3452,11637,3516],{"class":3961},[3452,11639,4021],{"class":3458},[3452,11641,4001],{"class":3961},[3452,11643,11644],{"class":3454,"line":3634},[3452,11645,3619],{"emptyLinePlaceholder":3618},[3452,11647,11648],{"class":3454,"line":3640},[3452,11649,11650],{"class":3469},"\u002F\u002F Головний ендпоінт — версія відповіді береться зі змінної середовища\n",[3452,11652,11653,11655,11658,11660,11663,11665,11668,11670,11673,11676,11678],{"class":3454,"line":3646},[3452,11654,3954],{"class":3953},[3452,11656,11657],{"class":3957}," version",[3452,11659,3962],{"class":3961},[3452,11661,11662],{"class":3957},"Environment",[3452,11664,3516],{"class":3961},[3452,11666,11667],{"class":3458},"GetEnvironmentVariable",[3452,11669,3973],{"class":3961},[3452,11671,11672],{"class":3462},"\"APP_VERSION\"",[3452,11674,11675],{"class":3961},") ?? ",[3452,11677,4069],{"class":3462},[3452,11679,11680],{"class":3961},";\n",[3452,11682,11683],{"class":3454,"line":3652},[3452,11684,3619],{"emptyLinePlaceholder":3618},[3452,11686,11687,11689,11691,11693,11695,11697,11699],{"class":3454,"line":3658},[3452,11688,4032],{"class":3957},[3452,11690,3516],{"class":3961},[3452,11692,4037],{"class":3458},[3452,11694,3973],{"class":3961},[3452,11696,4042],{"class":3462},[3452,11698,4045],{"class":3961},[3452,11700,4175],{"class":3953},[3452,11702,11703],{"class":3454,"line":3664},[3452,11704,4097],{"class":3961},[3452,11706,11707,11710,11712,11715],{"class":3454,"line":3670},[3452,11708,11709],{"class":3957},"    message",[3452,11711,3962],{"class":3961},[3452,11713,11714],{"class":3462},"\"Hello from ECS Fargate!\"",[3452,11716,5544],{"class":3961},[3452,11718,11719,11722,11724,11726],{"class":3454,"line":3676},[3452,11720,11721],{"class":3957},"    version",[3452,11723,3962],{"class":3961},[3452,11725,4064],{"class":3957},[3452,11727,5544],{"class":3961},[3452,11729,11730,11733,11735,11737,11739,11741,11743,11746],{"class":3454,"line":3682},[3452,11731,11732],{"class":3957},"    environment",[3452,11734,3962],{"class":3961},[3452,11736,4032],{"class":3957},[3452,11738,3516],{"class":3961},[3452,11740,11662],{"class":3957},[3452,11742,3516],{"class":3961},[3452,11744,11745],{"class":3957},"EnvironmentName",[3452,11747,5544],{"class":3961},[3452,11749,11750,11753,11755,11757,11759],{"class":3454,"line":3688},[3452,11751,11752],{"class":3957},"    timestamp",[3452,11754,3962],{"class":3961},[3452,11756,4200],{"class":3957},[3452,11758,3516],{"class":3961},[3452,11760,11761],{"class":3957},"UtcNow\n",[3452,11763,11764],{"class":3454,"line":3694},[3452,11765,4296],{"class":3961},[3452,11767,11768],{"class":3454,"line":3699},[3452,11769,3619],{"emptyLinePlaceholder":3618},[3452,11771,11772],{"class":3454,"line":3705},[3452,11773,11774],{"class":3469},"\u002F\u002F Health check ендпоінт — ECS використовує його для перевірки стану\n",[3452,11776,11777,11779,11781,11783,11785,11787],{"class":3454,"line":3711},[3452,11778,4032],{"class":3957},[3452,11780,3516],{"class":3961},[3452,11782,4314],{"class":3458},[3452,11784,3973],{"class":3961},[3452,11786,4319],{"class":3462},[3452,11788,3979],{"class":3961},[3452,11790,11791],{"class":3454,"line":3717},[3452,11792,3619],{"emptyLinePlaceholder":3618},[3452,11794,11795,11797,11799,11801],{"class":3454,"line":3723},[3452,11796,4032],{"class":3957},[3452,11798,3516],{"class":3961},[3452,11800,4334],{"class":3458},[3452,11802,4001],{"class":3961},[3354,11804,11805],{},"Перевірте, що проєкт збирається локально:",[3881,11807,11809,11817,11824,11828,11831,11839],{"title":11808},"dotnet run",[3885,11810,11812,3893,11815],{"className":11811},[3454],[3452,11813,3892],{"className":11814},[3891],[3540,11816,11808],{},[3885,11818,11820],{"className":11819},[3454],[3452,11821,11823],{"className":11822},[4369],"info: Microsoft.Hosting.Lifetime[14]",[3885,11825,11827],{"className":11826},[3454],"     Now listening on: http:\u002F\u002Flocalhost:5000",[3885,11829],{"className":11830},[3454],[3885,11832,11834,3893,11837],{"className":11833},[3454],[3452,11835,3892],{"className":11836},[3891],[3540,11838,4393],{},[3885,11840,11842],{"className":11841},[3454],[3452,11843,4400],{"className":11844},[3916],[3573,11846,11848],{"id":11847},"крок-2-dockerfile-та-dockerignore","Крок 2: Dockerfile та .dockerignore",[3354,11850,11851,11852,11855,11856,4878],{},"Створіть файл ",[3449,11853,11854],{},"Dockerfile"," у корені проєкту ",[3449,11857,11858],{},"EcsLabApi\u002F",[3442,11860,11862],{"className":4428,"code":11861,"language":4430,"meta":3447,"style":3447},"# ─── STAGE 1: BUILD ───────────────────────────────────────────\nFROM mcr.microsoft.com\u002Fdotnet\u002Fsdk:8.0 AS build\nWORKDIR \u002Fsrc\n\n# Копіюємо .csproj і відновлюємо залежності (layer cache!)\nCOPY [\"EcsLabApi.csproj\", \".\"]\nRUN dotnet restore \"EcsLabApi.csproj\"\n\n# Копіюємо решту коду і публікуємо Release-версію\nCOPY . .\nRUN dotnet publish \"EcsLabApi.csproj\" -c Release -o \u002Fapp\u002Fpublish --no-restore\n\n# ─── STAGE 2: RUNTIME ─────────────────────────────────────────\nFROM mcr.microsoft.com\u002Fdotnet\u002Faspnet:8.0 AS final\nWORKDIR \u002Fapp\n\n# ASP.NET Core слухає на порту 8080 (не 5000!)\nENV ASPNETCORE_URLS=http:\u002F\u002F+:8080\n\n# Встановлюємо curl — він потрібен для health check команди в ECS Task Definition.\n# Базовий aspnet-образ мінімальний і curl не містить за замовчуванням.\n# Без цього рядка ECS health check завжди повертає \"unhealthy\".\nRUN apt-get update \\\n    && apt-get install -y --no-install-recommends curl \\\n    && rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n\n# Копіюємо лише опублікований артефакт — SDK і вихідний код не потрапляють у образ\nCOPY --from=build \u002Fapp\u002Fpublish .\n\nENTRYPOINT [\"dotnet\", \"EcsLabApi.dll\"]\n",[3449,11863,11864,11869,11879,11885,11889,11894,11910,11919,11923,11928,11934,11944,11948,11953,11963,11969,11973,11978,11986,11990,11995,12000,12005,12012,12017,12022,12026,12031,12037,12041],{"__ignoreMap":3447},[3452,11865,11866],{"class":3454,"line":3455},[3452,11867,11868],{"class":3469},"# ─── STAGE 1: BUILD ───────────────────────────────────────────\n",[3452,11870,11871,11873,11875,11877],{"class":3454,"line":3473},[3452,11872,4447],{"class":3953},[3452,11874,4450],{"class":3961},[3452,11876,4453],{"class":3953},[3452,11878,4456],{"class":3961},[3452,11880,11881,11883],{"class":3454,"line":3609},[3452,11882,4470],{"class":3953},[3452,11884,4473],{"class":3961},[3452,11886,11887],{"class":3454,"line":3615},[3452,11888,3619],{"emptyLinePlaceholder":3618},[3452,11890,11891],{"class":3454,"line":3622},[3452,11892,11893],{"class":3469},"# Копіюємо .csproj і відновлюємо залежності (layer cache!)\n",[3452,11895,11896,11898,11900,11903,11905,11908],{"class":3454,"line":3628},[3452,11897,4497],{"class":3953},[3452,11899,4500],{"class":3961},[3452,11901,11902],{"class":3462},"\"EcsLabApi.csproj\"",[3452,11904,3491],{"class":3961},[3452,11906,11907],{"class":3462},"\".\"",[3452,11909,4511],{"class":3961},[3452,11911,11912,11914,11916],{"class":3454,"line":3634},[3452,11913,4516],{"class":3953},[3452,11915,4519],{"class":3961},[3452,11917,11918],{"class":3462},"\"EcsLabApi.csproj\"\n",[3452,11920,11921],{"class":3454,"line":3640},[3452,11922,3619],{"emptyLinePlaceholder":3618},[3452,11924,11925],{"class":3454,"line":3646},[3452,11926,11927],{"class":3469},"# Копіюємо решту коду і публікуємо Release-версію\n",[3452,11929,11930,11932],{"class":3454,"line":3652},[3452,11931,4497],{"class":3953},[3452,11933,4538],{"class":3961},[3452,11935,11936,11938,11940,11942],{"class":3454,"line":3658},[3452,11937,4516],{"class":3953},[3452,11939,4585],{"class":3961},[3452,11941,11902],{"class":3462},[3452,11943,4591],{"class":3961},[3452,11945,11946],{"class":3454,"line":3664},[3452,11947,3619],{"emptyLinePlaceholder":3618},[3452,11949,11950],{"class":3454,"line":3670},[3452,11951,11952],{"class":3469},"# ─── STAGE 2: RUNTIME ─────────────────────────────────────────\n",[3452,11954,11955,11957,11959,11961],{"class":3454,"line":3676},[3452,11956,4447],{"class":3953},[3452,11958,4612],{"class":3961},[3452,11960,4453],{"class":3953},[3452,11962,4617],{"class":3961},[3452,11964,11965,11967],{"class":3454,"line":3682},[3452,11966,4470],{"class":3953},[3452,11968,4634],{"class":3961},[3452,11970,11971],{"class":3454,"line":3688},[3452,11972,3619],{"emptyLinePlaceholder":3618},[3452,11974,11975],{"class":3454,"line":3694},[3452,11976,11977],{"class":3469},"# ASP.NET Core слухає на порту 8080 (не 5000!)\n",[3452,11979,11980,11983],{"class":3454,"line":3699},[3452,11981,11982],{"class":3953},"ENV",[3452,11984,11985],{"class":3961}," ASPNETCORE_URLS=http:\u002F\u002F+:8080\n",[3452,11987,11988],{"class":3454,"line":3705},[3452,11989,3619],{"emptyLinePlaceholder":3618},[3452,11991,11992],{"class":3454,"line":3711},[3452,11993,11994],{"class":3469},"# Встановлюємо curl — він потрібен для health check команди в ECS Task Definition.\n",[3452,11996,11997],{"class":3454,"line":3717},[3452,11998,11999],{"class":3469},"# Базовий aspnet-образ мінімальний і curl не містить за замовчуванням.\n",[3452,12001,12002],{"class":3454,"line":3723},[3452,12003,12004],{"class":3469},"# Без цього рядка ECS health check завжди повертає \"unhealthy\".\n",[3452,12006,12007,12009],{"class":3454,"line":3729},[3452,12008,4516],{"class":3953},[3452,12010,12011],{"class":3961}," apt-get update \\\n",[3452,12013,12014],{"class":3454,"line":3734},[3452,12015,12016],{"class":3961},"    && apt-get install -y --no-install-recommends curl \\\n",[3452,12018,12019],{"class":3454,"line":3740},[3452,12020,12021],{"class":3961},"    && rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n",[3452,12023,12024],{"class":3454,"line":3746},[3452,12025,3619],{"emptyLinePlaceholder":3618},[3452,12027,12028],{"class":3454,"line":3752},[3452,12029,12030],{"class":3469},"# Копіюємо лише опублікований артефакт — SDK і вихідний код не потрапляють у образ\n",[3452,12032,12033,12035],{"class":3454,"line":3758},[3452,12034,4497],{"class":3953},[3452,12036,4665],{"class":3961},[3452,12038,12039],{"class":3454,"line":3764},[3452,12040,3619],{"emptyLinePlaceholder":3618},[3452,12042,12043,12045,12047,12049,12051,12054],{"class":3454,"line":3769},[3452,12044,4682],{"class":3953},[3452,12046,4500],{"class":3961},[3452,12048,4687],{"class":3462},[3452,12050,3491],{"class":3961},[3452,12052,12053],{"class":3462},"\"EcsLabApi.dll\"",[3452,12055,4511],{"class":3961},[6155,12057,12058,12068,12069,12072,12073,12076],{},[3540,12059,12060,12063,12064,12067],{},[3449,12061,12062],{},"curl"," відсутній у базовому ",[3449,12065,12066],{},"aspnet"," образі."," Якщо не встановити його явно — ECS health check (",[3449,12070,12071],{},"curl -f http:\u002F\u002Flocalhost:8080\u002Fhealth || exit 1",") завжди завершуватиметься з кодом 127 («command not found»), і Task буде позначений як ",[3449,12074,12075],{},"UNHEALTHY"," та циклічно перезапускатиметься.",[3354,12078,11851,12079,4878],{},[3449,12080,4730],{},[3442,12082,12084],{"className":4738,"code":12083,"language":4740,"meta":3447,"style":3447},"**\u002Fbin\u002F\n**\u002Fobj\u002F\n.git\n.gitignore\n.vs\u002F\n.rider\u002F\nDockerfile\n.dockerignore\n**\u002Fappsettings.Development.json\n",[3449,12085,12086,12090,12094,12098,12102,12106,12110,12114,12118],{"__ignoreMap":3447},[3452,12087,12088],{"class":3454,"line":3455},[3452,12089,4752],{},[3452,12091,12092],{"class":3454,"line":3473},[3452,12093,4757],{},[3452,12095,12096],{"class":3454,"line":3609},[3452,12097,4771],{},[3452,12099,12100],{"class":3454,"line":3615},[3452,12101,4776],{},[3452,12103,12104],{"class":3454,"line":3622},[3452,12105,4790],{},[3452,12107,12108],{"class":3454,"line":3628},[3452,12109,4795],{},[3452,12111,12112],{"class":3454,"line":3634},[3452,12113,4814],{},[3452,12115,12116],{"class":3454,"line":3640},[3452,12117,4819],{},[3452,12119,12120],{"class":3454,"line":3646},[3452,12121,4833],{},[3354,12123,12124],{},"Зберіть образ і перевірте локально:",[3881,12126,12128,12137,12141,12145,12149,12153,12157,12164,12167,12176,12182,12186,12189,12198,12204,12207,12216],{"title":12127},"docker build & run",[3885,12129,12131,3893,12134],{"className":12130},[3454],[3452,12132,3892],{"className":12133},[3891],[3540,12135,12136],{},"docker build -t ecs-lab-api:v1.0.0 .",[3885,12138,12140],{"className":12139},[3454],"[+] Building 42.3s (12\u002F12) FINISHED",[3885,12142,12144],{"className":12143},[3454]," => [build 1\u002F5] FROM mcr.microsoft.com\u002Fdotnet\u002Fsdk:8.0",[3885,12146,12148],{"className":12147},[3454]," => [build 4\u002F5] RUN dotnet restore \"EcsLabApi.csproj\"",[3885,12150,12152],{"className":12151},[3454]," => [build 5\u002F5] RUN dotnet publish \"EcsLabApi.csproj\" -c Release -o \u002Fapp\u002Fpublish",[3885,12154,12156],{"className":12155},[3454]," => [final 2\u002F2] COPY --from=build \u002Fapp\u002Fpublish .",[3885,12158,12160],{"className":12159},[3454],[3452,12161,12163],{"className":12162},[3916]," => => writing image sha256:a1b2c3d4...",[3885,12165],{"className":12166},[3454],[3885,12168,12170,3893,12173],{"className":12169},[3454],[3452,12171,3892],{"className":12172},[3891],[3540,12174,12175],{},"docker run -p 8080:8080 ecs-lab-api:v1.0.0",[3885,12177,12179],{"className":12178},[3454],[3452,12180,11823],{"className":12181},[4369],[3885,12183,12185],{"className":12184},[3454],"     Now listening on: http:\u002F\u002F[::]:8080",[3885,12187],{"className":12188},[3454],[3885,12190,12192,3893,12195],{"className":12191},[3454],[3452,12193,3892],{"className":12194},[3891],[3540,12196,12197],{},"curl http:\u002F\u002Flocalhost:8080\u002Fhealth",[3885,12199,12201],{"className":12200},[3454],[3452,12202,4400],{"className":12203},[3916],[3885,12205],{"className":12206},[3454],[3885,12208,12210,3893,12213],{"className":12209},[3454],[3452,12211,3892],{"className":12212},[3891],[3540,12214,12215],{},"curl http:\u002F\u002Flocalhost:8080\u002F",[3885,12217,12219],{"className":12218},[3454],"{\"message\":\"Hello from ECS Fargate!\",\"version\":\"1.0.0\",\"environment\":\"Production\",...}",[3573,12221,12223],{"id":12222},"крок-3-створення-ecr-репозиторію","Крок 3: Створення ECR репозиторію",[9851,12225,12226,12398],{},[9854,12227,12228,12262,12316,12319,12389],{"label":9856},[3442,12229,12231],{"className":3444,"code":12230,"language":3446,"meta":3447,"style":3447},"# Спочатку дізнайтесь ваш Account ID — він знадобиться в наступних кроках\naws sts get-caller-identity --query Account --output text\n# Виведе: 123456789012  ← запам'ятайте це число, це ВАШ реальний AWS Account ID\n",[3449,12232,12233,12238,12257],{"__ignoreMap":3447},[3452,12234,12235],{"class":3454,"line":3455},[3452,12236,12237],{"class":3469},"# Спочатку дізнайтесь ваш Account ID — він знадобиться в наступних кроках\n",[3452,12239,12240,12242,12244,12246,12249,12252,12254],{"class":3454,"line":3473},[3452,12241,3459],{"class":3458},[3452,12243,3478],{"class":3462},[3452,12245,3481],{"class":3462},[3452,12247,12248],{"class":3953}," --query",[3452,12250,12251],{"class":3462}," Account",[3452,12253,7365],{"class":3953},[3452,12255,12256],{"class":3462}," text\n",[3452,12258,12259],{"class":3454,"line":3609},[3452,12260,12261],{"class":3469},"# Виведе: 123456789012  ← запам'ятайте це число, це ВАШ реальний AWS Account ID\n",[3442,12263,12265],{"className":3444,"code":12264,"language":3446,"meta":3447,"style":3447},"# Створіть репозиторій у ECR\n# eu-central-1 — змініть на ваш регіон, якщо потрібно\naws ecr create-repository \\\n    --repository-name ecs-lab-api \\\n    --region eu-central-1 \\\n    --image-scanning-configuration scanOnPush=true\n",[3449,12266,12267,12272,12277,12288,12297,12305],{"__ignoreMap":3447},[3452,12268,12269],{"class":3454,"line":3455},[3452,12270,12271],{"class":3469},"# Створіть репозиторій у ECR\n",[3452,12273,12274],{"class":3454,"line":3473},[3452,12275,12276],{"class":3469},"# eu-central-1 — змініть на ваш регіон, якщо потрібно\n",[3452,12278,12279,12281,12283,12286],{"class":3454,"line":3609},[3452,12280,3459],{"class":3458},[3452,12282,8980],{"class":3462},[3452,12284,12285],{"class":3462}," create-repository",[3452,12287,5067],{"class":5066},[3452,12289,12290,12292,12295],{"class":3454,"line":3615},[3452,12291,8990],{"class":3953},[3452,12293,12294],{"class":3462}," ecs-lab-api",[3452,12296,5067],{"class":5066},[3452,12298,12299,12301,12303],{"class":3454,"line":3622},[3452,12300,6935],{"class":3953},[3452,12302,7377],{"class":3462},[3452,12304,5067],{"class":5066},[3452,12306,12307,12310,12313],{"class":3454,"line":3628},[3452,12308,12309],{"class":3953},"    --image-scanning-configuration",[3452,12311,12312],{"class":3462}," scanOnPush=",[3452,12314,12315],{"class":3953},"true\n",[3354,12317,12318],{},"Успішна відповідь матиме вигляд:",[3442,12320,12322],{"className":5521,"code":12321,"language":5523,"meta":3447,"style":3447},"{\n    \"repository\": {\n        \"repositoryArn\": \"arn:aws:ecr:eu-central-1:123456789012:repository\u002Fecs-lab-api\",\n        \"registryId\": \"123456789012\",\n        \"repositoryName\": \"ecs-lab-api\",\n        \"repositoryUri\": \"123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fecs-lab-api\"\n    }\n}\n",[3449,12323,12324,12328,12335,12347,12359,12371,12381,12385],{"__ignoreMap":3447},[3452,12325,12326],{"class":3454,"line":3455},[3452,12327,4097],{"class":3961},[3452,12329,12330,12333],{"class":3454,"line":3473},[3452,12331,12332],{"class":5534},"    \"repository\"",[3452,12334,5807],{"class":3961},[3452,12336,12337,12340,12342,12345],{"class":3454,"line":3609},[3452,12338,12339],{"class":5534},"        \"repositoryArn\"",[3452,12341,5538],{"class":3961},[3452,12343,12344],{"class":3462},"\"arn:aws:ecr:eu-central-1:123456789012:repository\u002Fecs-lab-api\"",[3452,12346,5544],{"class":3961},[3452,12348,12349,12352,12354,12357],{"class":3454,"line":3615},[3452,12350,12351],{"class":5534},"        \"registryId\"",[3452,12353,5538],{"class":3961},[3452,12355,12356],{"class":3462},"\"123456789012\"",[3452,12358,5544],{"class":3961},[3452,12360,12361,12364,12366,12369],{"class":3454,"line":3622},[3452,12362,12363],{"class":5534},"        \"repositoryName\"",[3452,12365,5538],{"class":3961},[3452,12367,12368],{"class":3462},"\"ecs-lab-api\"",[3452,12370,5544],{"class":3961},[3452,12372,12373,12376,12378],{"class":3454,"line":3628},[3452,12374,12375],{"class":5534},"        \"repositoryUri\"",[3452,12377,5538],{"class":3961},[3452,12379,12380],{"class":3462},"\"123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fecs-lab-api\"\n",[3452,12382,12383],{"class":3454,"line":3634},[3452,12384,3655],{"class":3961},[3452,12386,12387],{"class":3454,"line":3640},[3452,12388,3691],{"class":3961},[3354,12390,4994,12391,12393,12394,12397],{},[3449,12392,4997],{}," — це адреса вашого репозиторію. ",[3540,12395,12396],{},"Скопіюйте її",", вона знадобиться у наступному кроці.",[9854,12399,12400],{"label":9996},[7751,12401,12402,12416,12422,12427,12458,12462],{},[4702,12403,11065,12404,12408,12409,12412,12413],{},[3385,12405,9996],{"href":12406,"rel":12407},"https:\u002F\u002Fconsole.aws.amazon.com",[3389]," → у рядку пошуку введіть ",[3540,12410,12411],{},"ECR"," → оберіть ",[3540,12414,12415],{},"Elastic Container Registry",[4702,12417,12418,12419],{},"Переконайтесь, що у верхньому правому куті обрано регіон ",[3540,12420,12421],{},"eu-central-1 (Frankfurt)",[4702,12423,11102,12424],{},[3540,12425,12426],{},"«Create repository»",[4702,12428,12429,12430],{},"Заповніть форму:\n",[4699,12431,12432,12438,12446,12452],{},[4702,12433,12434,12437],{},[3540,12435,12436],{},"Visibility:"," Private (за замовчуванням)",[4702,12439,12440,3893,12443],{},[3540,12441,12442],{},"Repository name:",[3449,12444,12445],{},"ecs-lab-api",[4702,12447,12448,12451],{},[3540,12449,12450],{},"Image tag mutability:"," Mutable",[4702,12453,12454,12457],{},[3540,12455,12456],{},"Image scan settings:"," ✅ Scan on push",[4702,12459,11102,12460],{},[3540,12461,12426],{},[4702,12463,12464,12465,12467,12468,12471,12472,12475],{},"У списку репозиторіїв знайдіть ",[3449,12466,12445],{}," — скопіюйте значення в колонці ",[3540,12469,12470],{},"URI"," (виглядає як ",[3449,12473,12474],{},"123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fecs-lab-api",")",[3573,12477,12479],{"id":12478},"крок-4-push-образу-в-ecr","Крок 4: Push образу в ECR",[9851,12481,12482,12625],{},[9854,12483,12484,12495,12565],{"label":9856},[3354,12485,12486,12487,12494],{},"Виконайте команди послідовно. ",[3540,12488,12489,12490,12493],{},"Замініть ",[3449,12491,12492],{},"123456789012"," на ваш реальний Account ID"," (отриманий на попередньому кроці):",[3442,12496,12498],{"className":3444,"code":12497,"language":3446,"meta":3447,"style":3447},"# Змінні — підставте ваші реальні значення\nACCOUNT_ID=\"123456789012\"   # ← ЗАМІНІТЬ на ваш Account ID\nREGION=\"eu-central-1\"        # ← змініть на ваш регіон\nREPO_URI=\"${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com\u002Fecs-lab-api\"\n\necho \"Буде використано репозиторій: $REPO_URI\"\n",[3449,12499,12500,12505,12517,12529,12549,12553],{"__ignoreMap":3447},[3452,12501,12502],{"class":3454,"line":3455},[3452,12503,12504],{"class":3469},"# Змінні — підставте ваші реальні значення\n",[3452,12506,12507,12510,12512,12514],{"class":3454,"line":3473},[3452,12508,12509],{"class":3957},"ACCOUNT_ID",[3452,12511,8300],{"class":3961},[3452,12513,12356],{"class":3462},[3452,12515,12516],{"class":3469},"   # ← ЗАМІНІТЬ на ваш Account ID\n",[3452,12518,12519,12522,12524,12526],{"class":3454,"line":3609},[3452,12520,12521],{"class":3957},"REGION",[3452,12523,8300],{"class":3961},[3452,12525,5848],{"class":3462},[3452,12527,12528],{"class":3469},"        # ← змініть на ваш регіон\n",[3452,12530,12531,12534,12536,12539,12541,12544,12546],{"class":3454,"line":3615},[3452,12532,12533],{"class":3957},"REPO_URI",[3452,12535,8300],{"class":3961},[3452,12537,12538],{"class":3462},"\"${",[3452,12540,12509],{"class":3957},[3452,12542,12543],{"class":3462},"}.dkr.ecr.${",[3452,12545,12521],{"class":3957},[3452,12547,12548],{"class":3462},"}.amazonaws.com\u002Fecs-lab-api\"\n",[3452,12550,12551],{"class":3454,"line":3622},[3452,12552,3619],{"emptyLinePlaceholder":3618},[3452,12554,12555,12557,12560,12563],{"class":3454,"line":3628},[3452,12556,7385],{"class":3458},[3452,12558,12559],{"class":3462}," \"Буде використано репозиторій: ",[3452,12561,12562],{"class":3957},"$REPO_URI",[3452,12564,7394],{"class":3462},[3442,12566,12568],{"className":3444,"code":12567,"language":3446,"meta":3447,"style":3447},"# Аутентифікуємось у ECR — отримуємо тимчасовий токен і передаємо docker login\naws ecr get-login-password --region $REGION | \\\n    docker login --username AWS --password-stdin \"${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com\"\n",[3449,12569,12570,12575,12596],{"__ignoreMap":3447},[3452,12571,12572],{"class":3454,"line":3455},[3452,12573,12574],{"class":3469},"# Аутентифікуємось у ECR — отримуємо тимчасовий токен і передаємо docker login\n",[3452,12576,12577,12579,12581,12584,12587,12590,12593],{"class":3454,"line":3473},[3452,12578,3459],{"class":3458},[3452,12580,8980],{"class":3462},[3452,12582,12583],{"class":3462}," get-login-password",[3452,12585,12586],{"class":3953}," --region",[3452,12588,12589],{"class":3957}," $REGION",[3452,12591,12592],{"class":3961}," | ",[3452,12594,12595],{"class":5066},"\\\n",[3452,12597,12598,12601,12604,12607,12610,12613,12616,12618,12620,12622],{"class":3454,"line":3609},[3452,12599,12600],{"class":3458},"    docker",[3452,12602,12603],{"class":3462}," login",[3452,12605,12606],{"class":3953}," --username",[3452,12608,12609],{"class":3462}," AWS",[3452,12611,12612],{"class":3953}," --password-stdin",[3452,12614,12615],{"class":3462}," \"${",[3452,12617,12509],{"class":3957},[3452,12619,12543],{"class":3462},[3452,12621,12521],{"class":3957},[3452,12623,12624],{"class":3462},"}.amazonaws.com\"\n",[9854,12626,12627,12630],{"label":9996},[3354,12628,12629],{},"Для push через консоль скористайтесь вбудованими інструкціями ECR:",[7751,12631,12632,12637,12644],{},[4702,12633,12634,12635],{},"ECR → Repositories → ",[3449,12636,12445],{},[4702,12638,12639,12640,12643],{},"Натисніть кнопку ",[3540,12641,12642],{},"«View push commands»"," у правому верхньому куті",[4702,12645,12646,12647,12650],{},"У вікні, що відкрилось, ви побачите ",[3540,12648,12649],{},"чотири готові команди"," з вашим реальним Account ID та регіоном — просто скопіюйте і виконайте їх послідовно у терміналі",[3881,12652,12654],{"title":12653},"docker login output",[3885,12655,4915],{"className":12656},[3454],[3442,12658,12660],{"className":3444,"code":12659,"language":3446,"meta":3447,"style":3447},"# Тегуємо локальний образ адресою ECR репозиторію\ndocker tag ecs-lab-api:v1.0.0 $REPO_URI:v1.0.0\n\n# Завантажуємо образ у ECR\ndocker push $REPO_URI:v1.0.0\n",[3449,12661,12662,12667,12682,12686,12691],{"__ignoreMap":3447},[3452,12663,12664],{"class":3454,"line":3455},[3452,12665,12666],{"class":3469},"# Тегуємо локальний образ адресою ECR репозиторію\n",[3452,12668,12669,12671,12673,12676,12679],{"class":3454,"line":3473},[3452,12670,5057],{"class":3458},[3452,12672,5060],{"class":3462},[3452,12674,12675],{"class":3462}," ecs-lab-api:v1.0.0",[3452,12677,12678],{"class":3957}," $REPO_URI",[3452,12680,12681],{"class":3462},":v1.0.0\n",[3452,12683,12684],{"class":3454,"line":3609},[3452,12685,3619],{"emptyLinePlaceholder":3618},[3452,12687,12688],{"class":3454,"line":3615},[3452,12689,12690],{"class":3469},"# Завантажуємо образ у ECR\n",[3452,12692,12693,12695,12698,12700],{"class":3454,"line":3622},[3452,12694,5057],{"class":3458},[3452,12696,12697],{"class":3462}," push",[3452,12699,12678],{"class":3957},[3452,12701,12681],{"class":3462},[3881,12703,12705,12714,12718,12722,12726],{"title":12704},"docker push output",[3885,12706,12708,3893,12711],{"className":12707},[3454],[3452,12709,3892],{"className":12710},[3891],[3540,12712,12713],{},"docker push 123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fecs-lab-api:v1.0.0",[3885,12715,12717],{"className":12716},[3454],"The push refers to repository [123456789012.dkr.ecr.eu-central-1.amazonaws.com\u002Fecs-lab-api]",[3885,12719,12721],{"className":12720},[3454],"a1b2c3d4e5f6: Pushed",[3885,12723,12725],{"className":12724},[3454],"b2c3d4e5f6a7: Pushed",[3885,12727,12729],{"className":12728},[3454],[3452,12730,12732],{"className":12731},[3916],"v1.0.0: digest: sha256:abc123... size: 1234",[3354,12734,12735],{},"Перевірте результат — образ має з'явитись у консолі:",[7751,12737,12738,12745],{},[4702,12739,12634,12740,9020,12742],{},[3449,12741,12445],{},[3540,12743,12744],{},"«Images»",[4702,12746,12747,12748,12751],{},"Ви побачите образ з тегом ",[3449,12749,12750],{},"v1.0.0"," та статус сканування",[3573,12753,12755],{"id":12754},"крок-5-створення-ecs-cluster","Крок 5: Створення ECS Cluster",[9851,12757,12758,12808],{},[9854,12759,12760],{"label":9996},[7751,12761,12762,12768,12777,12802],{},[4702,12763,11065,12764,12767],{},[3540,12765,12766],{},"ECS"," (Elastic Container Service) у AWS Console",[4702,12769,12770,12771,9024,12774],{},"У лівому меню → ",[3540,12772,12773],{},"Clusters",[3540,12775,12776],{},"Create cluster",[4702,12778,12779,12780],{},"Заповніть:\n",[4699,12781,12782,12790,12799],{},[4702,12783,12784,3893,12787],{},[3540,12785,12786],{},"Cluster name:",[3449,12788,12789],{},"ecs-lab-cluster",[4702,12791,12792,12795,12796,12798],{},[3540,12793,12794],{},"Infrastructure:"," ✅ ",[3540,12797,6254],{}," (зніміть галочку з Amazon EC2 instances)",[4702,12800,12801],{},"Моніторинг: ✅ Use Container Insights (рекомендовано — дасть метрики CPU\u002FMemory)",[4702,12803,11102,12804,12807],{},[3540,12805,12806],{},"«Create»"," — кластер створюється за ~30 секунд",[9854,12809,12810],{"label":9856},[3442,12811,12813],{"className":3444,"code":12812,"language":3446,"meta":3447,"style":3447},"# Створіть кластер із підтримкою Fargate та вмікненими Container Insights\naws ecs create-cluster \\\n    --cluster-name ecs-lab-cluster \\\n    --capacity-providers FARGATE \\\n    --settings name=containerInsights,value=enabled \\\n    --region eu-central-1\n",[3449,12814,12815,12820,12831,12841,12849,12857],{"__ignoreMap":3447},[3452,12816,12817],{"class":3454,"line":3455},[3452,12818,12819],{"class":3469},"# Створіть кластер із підтримкою Fargate та вмікненими Container Insights\n",[3452,12821,12822,12824,12826,12829],{"class":3454,"line":3473},[3452,12823,3459],{"class":3458},[3452,12825,6888],{"class":3462},[3452,12827,12828],{"class":3462}," create-cluster",[3452,12830,5067],{"class":5066},[3452,12832,12833,12836,12839],{"class":3454,"line":3609},[3452,12834,12835],{"class":3953},"    --cluster-name",[3452,12837,12838],{"class":3462}," ecs-lab-cluster",[3452,12840,5067],{"class":5066},[3452,12842,12843,12845,12847],{"class":3454,"line":3615},[3452,12844,11280],{"class":3953},[3452,12846,7669],{"class":3462},[3452,12848,5067],{"class":5066},[3452,12850,12851,12853,12855],{"class":3454,"line":3622},[3452,12852,11480],{"class":3953},[3452,12854,11483],{"class":3462},[3452,12856,5067],{"class":5066},[3452,12858,12859,12861],{"class":3454,"line":3628},[3452,12860,6935],{"class":3953},[3452,12862,6938],{"class":3462},[3881,12864,12866,12875,12878,12882,12886,12893,12897,12901,12905,12909,12912],{"title":12865},"aws ecs create-cluster — відповідь",[3885,12867,12869,3893,12872],{"className":12868},[3454],[3452,12870,3892],{"className":12871},[3891],[3540,12873,12874],{},"aws ecs create-cluster --cluster-name ecs-lab-cluster --capacity-providers FARGATE --settings name=containerInsights,value=enabled --region eu-central-1",[3885,12876,4954],{"className":12877},[3454],[3885,12879,12881],{"className":12880},[3454],"  \"cluster\": {",[3885,12883,12885],{"className":12884},[3454],"    \"clusterArn\": \"arn:aws:ecs:eu-central-1:123456789012:cluster\u002Fecs-lab-cluster\",",[3885,12887,4974,12889,4979],{"className":12888},[3454],[3452,12890,12892],{"className":12891},[3916],"\"clusterName\": \"ecs-lab-cluster\"",[3885,12894,12896],{"className":12895},[3454],"    \"status\": \"ACTIVE\",",[3885,12898,12900],{"className":12899},[3454],"    \"registeredContainerInstancesCount\": 0,",[3885,12902,12904],{"className":12903},[3454],"    \"settings\": [{ \"name\": \"containerInsights\", \"value\": \"enabled\" }],",[3885,12906,12908],{"className":12907},[3454],"    \"capacityProviders\": [\"FARGATE\"]",[3885,12910,4987],{"className":12911},[3454],[3885,12913,4991],{"className":12914},[3454],[3573,12916,12918],{"id":12917},"крок-6-створення-iam-role-для-ecs-task-execution","Крок 6: Створення IAM Role для ECS Task Execution",[3354,12920,12921],{},"ECS потребує IAM Role, щоб завантажити образ з ECR та записувати логи. Це стандартна роль — її потрібно створити один раз.",[9851,12923,12924,12976],{},[9854,12925,12926],{"label":9996},[7751,12927,12928,12939,12945,12954,12958,12964],{},[4702,12929,11065,12930,9024,12933,9024,12936],{},[3540,12931,12932],{},"IAM",[3540,12934,12935],{},"Roles",[3540,12937,12938],{},"Create role",[4702,12940,12941,12944],{},[3540,12942,12943],{},"Trusted entity type:"," AWS service",[4702,12946,12947,12950,12951],{},[3540,12948,12949],{},"Use case:"," знайдіть і оберіть ",[3540,12952,12953],{},"Elastic Container Service Task",[4702,12955,11102,12956],{},[3540,12957,4237],{},[4702,12959,12960,12961,12963],{},"У пошуку политик введіть ",[3449,12962,5982],{}," → поставте ✅",[4702,12965,11102,12966,9024,12968,3893,12971,9024,12974],{},[3540,12967,4237],{},[3540,12969,12970],{},"Role name:",[3449,12972,12973],{},"ecsTaskExecutionRole",[3540,12975,12938],{},[9854,12977,12978],{"label":9856},[3442,12979,12981],{"className":3444,"code":12980,"language":3446,"meta":3447,"style":3447},"# Крок 6a: Створіть Trust Policy файл\ncat > \u002Ftmp\u002Fecs-trust-policy.json \u003C\u003C 'EOF'\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [{\n        \"Effect\": \"Allow\",\n        \"Principal\": {\"Service\": \"ecs-tasks.amazonaws.com\"},\n        \"Action\": \"sts:AssumeRole\"\n    }]\n}\nEOF\n\n# Крок 6b: Створіть роль\naws iam create-role \\\n    --role-name ecsTaskExecutionRole \\\n    --assume-role-policy-document file:\u002F\u002F\u002Ftmp\u002Fecs-trust-policy.json\n\n# Крок 6c: Прикріпіть стандартну policy\naws iam attach-role-policy \\\n    --role-name ecsTaskExecutionRole \\\n    --policy-arn arn:aws:iam::aws:policy\u002Fservice-role\u002FAmazonECSTaskExecutionRolePolicy\n",[3449,12982,12983,12988,13001,13005,13009,13013,13017,13022,13026,13030,13034,13038,13042,13047,13057,13066,13073,13077,13082,13093,13101],{"__ignoreMap":3447},[3452,12984,12985],{"class":3454,"line":3455},[3452,12986,12987],{"class":3469},"# Крок 6a: Створіть Trust Policy файл\n",[3452,12989,12990,12992,12994,12997,12999],{"class":3454,"line":3473},[3452,12991,10712],{"class":3458},[3452,12993,10715],{"class":3961},[3452,12995,12996],{"class":3462},"\u002Ftmp\u002Fecs-trust-policy.json",[3452,12998,10721],{"class":3961},[3452,13000,10724],{"class":3961},[3452,13002,13003],{"class":3454,"line":3609},[3452,13004,4097],{"class":3462},[3452,13006,13007],{"class":3454,"line":3615},[3452,13008,10733],{"class":3462},[3452,13010,13011],{"class":3454,"line":3622},[3452,13012,10738],{"class":3462},[3452,13014,13015],{"class":3454,"line":3628},[3452,13016,10743],{"class":3462},[3452,13018,13019],{"class":3454,"line":3634},[3452,13020,13021],{"class":3462},"        \"Principal\": {\"Service\": \"ecs-tasks.amazonaws.com\"},\n",[3452,13023,13024],{"class":3454,"line":3640},[3452,13025,10753],{"class":3462},[3452,13027,13028],{"class":3454,"line":3646},[3452,13029,10551],{"class":3462},[3452,13031,13032],{"class":3454,"line":3652},[3452,13033,3691],{"class":3462},[3452,13035,13036],{"class":3454,"line":3658},[3452,13037,10766],{"class":3961},[3452,13039,13040],{"class":3454,"line":3664},[3452,13041,3619],{"emptyLinePlaceholder":3618},[3452,13043,13044],{"class":3454,"line":3670},[3452,13045,13046],{"class":3469},"# Крок 6b: Створіть роль\n",[3452,13048,13049,13051,13053,13055],{"class":3454,"line":3676},[3452,13050,3459],{"class":3458},[3452,13052,10782],{"class":3462},[3452,13054,10785],{"class":3462},[3452,13056,5067],{"class":5066},[3452,13058,13059,13061,13064],{"class":3454,"line":3682},[3452,13060,10792],{"class":3953},[3452,13062,13063],{"class":3462}," ecsTaskExecutionRole",[3452,13065,5067],{"class":5066},[3452,13067,13068,13070],{"class":3454,"line":3688},[3452,13069,10802],{"class":3953},[3452,13071,13072],{"class":3462}," file:\u002F\u002F\u002Ftmp\u002Fecs-trust-policy.json\n",[3452,13074,13075],{"class":3454,"line":3694},[3452,13076,3619],{"emptyLinePlaceholder":3618},[3452,13078,13079],{"class":3454,"line":3699},[3452,13080,13081],{"class":3469},"# Крок 6c: Прикріпіть стандартну policy\n",[3452,13083,13084,13086,13088,13091],{"class":3454,"line":3705},[3452,13085,3459],{"class":3458},[3452,13087,10782],{"class":3462},[3452,13089,13090],{"class":3462}," attach-role-policy",[3452,13092,5067],{"class":5066},[3452,13094,13095,13097,13099],{"class":3454,"line":3711},[3452,13096,10792],{"class":3953},[3452,13098,13063],{"class":3462},[3452,13100,5067],{"class":5066},[3452,13102,13103,13106],{"class":3454,"line":3717},[3452,13104,13105],{"class":3953},"    --policy-arn",[3452,13107,13108],{"class":3462}," arn:aws:iam::aws:policy\u002Fservice-role\u002FAmazonECSTaskExecutionRolePolicy\n",[3573,13110,13112],{"id":13111},"крок-7-створення-task-definition","Крок 7: Створення Task Definition",[3354,13114,13115,13118,13119,6744,13122,13124],{},[3540,13116,13117],{},"Важливо:"," у полі ",[3449,13120,13121],{},"image",[3449,13123,5974],{}," підставте ваші реальні значення.",[9851,13126,13127,13278],{},[9854,13128,13129],{"label":9996},[7751,13130,13131,13140,13147,13175,13195,13261,13274],{},[4702,13132,13133,13134,9024,13137],{},"ECS → ",[3540,13135,13136],{},"Task definitions",[3540,13138,13139],{},"Create new task definition",[4702,13141,13142,3893,13145],{},[3540,13143,13144],{},"Task definition family:",[3449,13146,12445],{},[4702,13148,13149,13152],{},[3540,13150,13151],{},"Infrastructure requirements:",[4699,13153,13154,13159,13162,13168],{},[4702,13155,13156,13157],{},"Launch type: ✅ ",[3540,13158,6254],{},[4702,13160,13161],{},"OS\u002FArchitecture: Linux\u002FX86_64",[4702,13163,13164,13165,13167],{},"CPU: ",[3540,13166,6057],{}," (.25)",[4702,13169,13170,13171,13174],{},"Memory: ",[3540,13172,13173],{},"0.5 GB"," (512 MB)",[4702,13176,13177,13180],{},[3540,13178,13179],{},"Task roles:",[4699,13181,13182,13190],{},[4702,13183,13184,13185,13189],{},"Task role: ",[13186,13187,13188],"em",{},"залиште пустим"," (наш API не звертається до інших AWS сервісів)",[4702,13191,13192,13193],{},"Task execution role: ",[3449,13194,12973],{},[4702,13196,13197,13200],{},[3540,13198,13199],{},"Container — 1:",[4699,13201,13202,13206,13215,13221,13247,13255],{},[4702,13203,11077,13204],{},[3449,13205,12445],{},[4702,13207,13208,13209,13212],{},"Image URI: ",[3449,13210,13211],{},"ВАШ_ACCOUNT_ID.dkr.ecr.eu-central-1.amazonaws.com\u002Fecs-lab-api:v1.0.0",[13186,13213,13214],{},"(скопіюйте URI з ECR → Repositories → ecs-lab-api → Images → тег v1.0.0)",[4702,13216,13217,13218,13220],{},"Container port: ",[3449,13219,5676],{},", Protocol: TCP",[4702,13222,13223,13226,13227],{},[3540,13224,13225],{},"Environment variables"," → Add:\n",[4699,13228,13229,13239],{},[4702,13230,13231,13232,13235,13236],{},"Key: ",[3449,13233,13234],{},"ASPNETCORE_ENVIRONMENT",", Value: ",[3449,13237,13238],{},"Production",[4702,13240,13231,13241,13235,13244],{},[3449,13242,13243],{},"APP_VERSION",[3449,13245,13246],{},"1.0.0",[4702,13248,13249,3893,13252],{},[3540,13250,13251],{},"Health check command:",[3449,13253,13254],{},"CMD-SHELL, curl -f http:\u002F\u002Flocalhost:8080\u002Fhealth || exit 1",[4702,13256,13257,13260],{},[3540,13258,13259],{},"Health check intervals:"," Interval: 30s, Timeout: 5s, Start period: 10s, Retries: 3",[4702,13262,13263,13266,13267,13270,13271],{},[3540,13264,13265],{},"Logging:"," ✅ Use log collection → ",[3540,13268,13269],{},"awslogs",", log group ",[3449,13272,13273],{},"\u002Fecs\u002Fecs-lab-api",[4702,13275,11102,13276],{},[3540,13277,12806],{},[9854,13279,13280],{"label":9856},[3442,13281,13283],{"className":3444,"code":13282,"language":3446,"meta":3447,"style":3447},"# Підставте ВАШ РЕАЛЬНИЙ ACCOUNT_ID\nACCOUNT_ID=\"123456789012\"   # ← ЗАМІНІТЬ!\nREGION=\"eu-central-1\"\n\n# Збережіть Task Definition у файл\ncat > \u002Ftmp\u002Ftask-def.json \u003C\u003C EOF\n{\n    \"family\": \"ecs-lab-api\",\n    \"networkMode\": \"awsvpc\",\n    \"requiresCompatibilities\": [\"FARGATE\"],\n    \"cpu\": \"256\",\n    \"memory\": \"512\",\n    \"executionRoleArn\": \"arn:aws:iam::${ACCOUNT_ID}:role\u002FecsTaskExecutionRole\",\n    \"containerDefinitions\": [{\n        \"name\": \"ecs-lab-api\",\n        \"image\": \"${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com\u002Fecs-lab-api:v1.0.0\",\n        \"portMappings\": [{\"containerPort\": 8080, \"protocol\": \"tcp\"}],\n        \"environment\": [\n            {\"name\": \"ASPNETCORE_ENVIRONMENT\", \"value\": \"Production\"},\n            {\"name\": \"APP_VERSION\", \"value\": \"1.0.0\"}\n        ],\n        \"healthCheck\": {\n            \"command\": [\"CMD-SHELL\", \"curl -f http:\u002F\u002Flocalhost:8080\u002Fhealth || exit 1\"],\n            \"interval\": 30, \"timeout\": 5, \"retries\": 3, \"startPeriod\": 10\n        },\n        \"logConfiguration\": {\n            \"logDriver\": \"awslogs\",\n            \"options\": {\n                \"awslogs-group\": \"\u002Fecs\u002Fecs-lab-api\",\n                \"awslogs-region\": \"${REGION}\",\n                \"awslogs-stream-prefix\": \"ecs\",\n                \"awslogs-create-group\": \"true\"\n            }\n        }\n    }]\n}\nEOF\n\naws ecs register-task-definition \\\n    --cli-input-json file:\u002F\u002F\u002Ftmp\u002Ftask-def.json \\\n    --region $REGION\n",[3449,13284,13285,13290,13301,13310,13314,13319,13332,13336,13341,13346,13351,13356,13361,13371,13376,13381,13395,13400,13405,13410,13415,13420,13425,13430,13435,13439,13444,13449,13454,13459,13469,13474,13479,13483,13487,13491,13495,13499,13503,13514,13524],{"__ignoreMap":3447},[3452,13286,13287],{"class":3454,"line":3455},[3452,13288,13289],{"class":3469},"# Підставте ВАШ РЕАЛЬНИЙ ACCOUNT_ID\n",[3452,13291,13292,13294,13296,13298],{"class":3454,"line":3473},[3452,13293,12509],{"class":3957},[3452,13295,8300],{"class":3961},[3452,13297,12356],{"class":3462},[3452,13299,13300],{"class":3469},"   # ← ЗАМІНІТЬ!\n",[3452,13302,13303,13305,13307],{"class":3454,"line":3609},[3452,13304,12521],{"class":3957},[3452,13306,8300],{"class":3961},[3452,13308,13309],{"class":3462},"\"eu-central-1\"\n",[3452,13311,13312],{"class":3454,"line":3615},[3452,13313,3619],{"emptyLinePlaceholder":3618},[3452,13315,13316],{"class":3454,"line":3622},[3452,13317,13318],{"class":3469},"# Збережіть Task Definition у файл\n",[3452,13320,13321,13323,13325,13328,13330],{"class":3454,"line":3628},[3452,13322,10712],{"class":3458},[3452,13324,10715],{"class":3961},[3452,13326,13327],{"class":3462},"\u002Ftmp\u002Ftask-def.json",[3452,13329,10721],{"class":3961},[3452,13331,10766],{"class":3961},[3452,13333,13334],{"class":3454,"line":3634},[3452,13335,4097],{"class":3462},[3452,13337,13338],{"class":3454,"line":3640},[3452,13339,13340],{"class":3462},"    \"family\": \"ecs-lab-api\",\n",[3452,13342,13343],{"class":3454,"line":3646},[3452,13344,13345],{"class":3462},"    \"networkMode\": \"awsvpc\",\n",[3452,13347,13348],{"class":3454,"line":3652},[3452,13349,13350],{"class":3462},"    \"requiresCompatibilities\": [\"FARGATE\"],\n",[3452,13352,13353],{"class":3454,"line":3658},[3452,13354,13355],{"class":3462},"    \"cpu\": \"256\",\n",[3452,13357,13358],{"class":3454,"line":3664},[3452,13359,13360],{"class":3462},"    \"memory\": \"512\",\n",[3452,13362,13363,13366,13368],{"class":3454,"line":3670},[3452,13364,13365],{"class":3462},"    \"executionRoleArn\": \"arn:aws:iam::${",[3452,13367,12509],{"class":3957},[3452,13369,13370],{"class":3462},"}:role\u002FecsTaskExecutionRole\",\n",[3452,13372,13373],{"class":3454,"line":3676},[3452,13374,13375],{"class":3462},"    \"containerDefinitions\": [{\n",[3452,13377,13378],{"class":3454,"line":3682},[3452,13379,13380],{"class":3462},"        \"name\": \"ecs-lab-api\",\n",[3452,13382,13383,13386,13388,13390,13392],{"class":3454,"line":3688},[3452,13384,13385],{"class":3462},"        \"image\": \"${",[3452,13387,12509],{"class":3957},[3452,13389,12543],{"class":3462},[3452,13391,12521],{"class":3957},[3452,13393,13394],{"class":3462},"}.amazonaws.com\u002Fecs-lab-api:v1.0.0\",\n",[3452,13396,13397],{"class":3454,"line":3694},[3452,13398,13399],{"class":3462},"        \"portMappings\": [{\"containerPort\": 8080, \"protocol\": \"tcp\"}],\n",[3452,13401,13402],{"class":3454,"line":3699},[3452,13403,13404],{"class":3462},"        \"environment\": [\n",[3452,13406,13407],{"class":3454,"line":3705},[3452,13408,13409],{"class":3462},"            {\"name\": \"ASPNETCORE_ENVIRONMENT\", \"value\": \"Production\"},\n",[3452,13411,13412],{"class":3454,"line":3711},[3452,13413,13414],{"class":3462},"            {\"name\": \"APP_VERSION\", \"value\": \"1.0.0\"}\n",[3452,13416,13417],{"class":3454,"line":3717},[3452,13418,13419],{"class":3462},"        ],\n",[3452,13421,13422],{"class":3454,"line":3723},[3452,13423,13424],{"class":3462},"        \"healthCheck\": {\n",[3452,13426,13427],{"class":3454,"line":3729},[3452,13428,13429],{"class":3462},"            \"command\": [\"CMD-SHELL\", \"curl -f http:\u002F\u002Flocalhost:8080\u002Fhealth || exit 1\"],\n",[3452,13431,13432],{"class":3454,"line":3734},[3452,13433,13434],{"class":3462},"            \"interval\": 30, \"timeout\": 5, \"retries\": 3, \"startPeriod\": 10\n",[3452,13436,13437],{"class":3454,"line":3740},[3452,13438,7030],{"class":3462},[3452,13440,13441],{"class":3454,"line":3746},[3452,13442,13443],{"class":3462},"        \"logConfiguration\": {\n",[3452,13445,13446],{"class":3454,"line":3752},[3452,13447,13448],{"class":3462},"            \"logDriver\": \"awslogs\",\n",[3452,13450,13451],{"class":3454,"line":3758},[3452,13452,13453],{"class":3462},"            \"options\": {\n",[3452,13455,13456],{"class":3454,"line":3764},[3452,13457,13458],{"class":3462},"                \"awslogs-group\": \"\u002Fecs\u002Fecs-lab-api\",\n",[3452,13460,13461,13464,13466],{"class":3454,"line":3769},[3452,13462,13463],{"class":3462},"                \"awslogs-region\": \"${",[3452,13465,12521],{"class":3957},[3452,13467,13468],{"class":3462},"}\",\n",[3452,13470,13471],{"class":3454,"line":4629},[3452,13472,13473],{"class":3462},"                \"awslogs-stream-prefix\": \"ecs\",\n",[3452,13475,13476],{"class":3454,"line":4637},[3452,13477,13478],{"class":3462},"                \"awslogs-create-group\": \"true\"\n",[3452,13480,13481],{"class":3454,"line":4642},[3452,13482,5947],{"class":3462},[3452,13484,13485],{"class":3454,"line":4648},[3452,13486,5953],{"class":3462},[3452,13488,13489],{"class":3454,"line":4654},[3452,13490,10551],{"class":3462},[3452,13492,13493],{"class":3454,"line":4660},[3452,13494,3691],{"class":3462},[3452,13496,13497],{"class":3454,"line":4668},[3452,13498,10766],{"class":3961},[3452,13500,13501],{"class":3454,"line":4673},[3452,13502,3619],{"emptyLinePlaceholder":3618},[3452,13504,13505,13507,13509,13512],{"class":3454,"line":4679},[3452,13506,3459],{"class":3458},[3452,13508,6888],{"class":3462},[3452,13510,13511],{"class":3462}," register-task-definition",[3452,13513,5067],{"class":5066},[3452,13515,13516,13519,13522],{"class":3454,"line":5908},[3452,13517,13518],{"class":3953},"    --cli-input-json",[3452,13520,13521],{"class":3462}," file:\u002F\u002F\u002Ftmp\u002Ftask-def.json",[3452,13523,5067],{"class":5066},[3452,13525,13526,13528],{"class":3454,"line":5920},[3452,13527,6935],{"class":3953},[3452,13529,13530],{"class":3957}," $REGION\n",[3573,13532,13534],{"id":13533},"крок-8-визначення-security-group-та-підмережі","Крок 8: Визначення Security Group та підмережі",[3354,13536,13537],{},"Перед запуском Service потрібно знати ID вашої VPC та підмереж. Fargate Tasks будуть запускатись у них.",[9851,13539,13540,13847],{},[9854,13541,13542,13668,13671],{"label":9856},[3442,13543,13545],{"className":3444,"code":13544,"language":3446,"meta":3447,"style":3447},"# Знайдіть ID вашого default VPC\naws ec2 describe-vpcs \\\n    --filters \"Name=isDefault,Values=true\" \\\n    --query \"Vpcs[0].VpcId\" \\\n    --output text --region eu-central-1\n# Виведе щось на кшталт: vpc-0a1b2c3d4e5f67890\n# ← ЗАПИШІТЬ це значення, знадобиться далі\n\n# Знайдіть підмережі у цьому VPC (потрібні мінімум 2 у різних AZ)\naws ec2 describe-subnets \\\n    --filters \"Name=defaultForAz,Values=true\" \\\n    --query \"Subnets[*].{ID:SubnetId,AZ:AvailabilityZone}\" \\\n    --output table --region eu-central-1\n# Виведе таблицю підмереж — запишіть 2 ID, наприклад:\n# subnet-0a1b2c3d  eu-central-1a\n# subnet-1b2c3d4e  eu-central-1b\n",[3449,13546,13547,13552,13564,13574,13583,13594,13599,13604,13608,13613,13624,13633,13642,13653,13658,13663],{"__ignoreMap":3447},[3452,13548,13549],{"class":3454,"line":3455},[3452,13550,13551],{"class":3469},"# Знайдіть ID вашого default VPC\n",[3452,13553,13554,13556,13559,13562],{"class":3454,"line":3473},[3452,13555,3459],{"class":3458},[3452,13557,13558],{"class":3462}," ec2",[3452,13560,13561],{"class":3462}," describe-vpcs",[3452,13563,5067],{"class":5066},[3452,13565,13566,13569,13572],{"class":3454,"line":3609},[3452,13567,13568],{"class":3953},"    --filters",[3452,13570,13571],{"class":3462}," \"Name=isDefault,Values=true\"",[3452,13573,5067],{"class":5066},[3452,13575,13576,13578,13581],{"class":3454,"line":3615},[3452,13577,7359],{"class":3953},[3452,13579,13580],{"class":3462}," \"Vpcs[0].VpcId\"",[3452,13582,5067],{"class":5066},[3452,13584,13585,13588,13590,13592],{"class":3454,"line":3622},[3452,13586,13587],{"class":3953},"    --output",[3452,13589,7368],{"class":3462},[3452,13591,12586],{"class":3953},[3452,13593,6938],{"class":3462},[3452,13595,13596],{"class":3454,"line":3628},[3452,13597,13598],{"class":3469},"# Виведе щось на кшталт: vpc-0a1b2c3d4e5f67890\n",[3452,13600,13601],{"class":3454,"line":3634},[3452,13602,13603],{"class":3469},"# ← ЗАПИШІТЬ це значення, знадобиться далі\n",[3452,13605,13606],{"class":3454,"line":3640},[3452,13607,3619],{"emptyLinePlaceholder":3618},[3452,13609,13610],{"class":3454,"line":3646},[3452,13611,13612],{"class":3469},"# Знайдіть підмережі у цьому VPC (потрібні мінімум 2 у різних AZ)\n",[3452,13614,13615,13617,13619,13622],{"class":3454,"line":3652},[3452,13616,3459],{"class":3458},[3452,13618,13558],{"class":3462},[3452,13620,13621],{"class":3462}," describe-subnets",[3452,13623,5067],{"class":5066},[3452,13625,13626,13628,13631],{"class":3454,"line":3658},[3452,13627,13568],{"class":3953},[3452,13629,13630],{"class":3462}," \"Name=defaultForAz,Values=true\"",[3452,13632,5067],{"class":5066},[3452,13634,13635,13637,13640],{"class":3454,"line":3664},[3452,13636,7359],{"class":3953},[3452,13638,13639],{"class":3462}," \"Subnets[*].{ID:SubnetId,AZ:AvailabilityZone}\"",[3452,13641,5067],{"class":5066},[3452,13643,13644,13646,13649,13651],{"class":3454,"line":3670},[3452,13645,13587],{"class":3953},[3452,13647,13648],{"class":3462}," table",[3452,13650,12586],{"class":3953},[3452,13652,6938],{"class":3462},[3452,13654,13655],{"class":3454,"line":3676},[3452,13656,13657],{"class":3469},"# Виведе таблицю підмереж — запишіть 2 ID, наприклад:\n",[3452,13659,13660],{"class":3454,"line":3682},[3452,13661,13662],{"class":3469},"# subnet-0a1b2c3d  eu-central-1a\n",[3452,13664,13665],{"class":3454,"line":3688},[3452,13666,13667],{"class":3469},"# subnet-1b2c3d4e  eu-central-1b\n",[3354,13669,13670],{},"Створіть Security Group для Tasks:",[3442,13672,13674],{"className":3444,"code":13673,"language":3446,"meta":3447,"style":3447},"VPC_ID=\"vpc-0a1b2c3d4e5f67890\"   # ← ЗАМІНІТЬ на ваш реальний VPC ID\n\n# Створіть Security Group\nSG_ID=$(aws ec2 create-security-group \\\n    --group-name \"ecs-lab-sg\" \\\n    --description \"Security group for ECS lab tasks\" \\\n    --vpc-id $VPC_ID \\\n    --region eu-central-1 \\\n    --query GroupId --output text)\n\necho \"Security Group ID: $SG_ID\"   # ← ЗАПИШІТЬ цей ID\n\n# Дозвольте вхідний трафік на порт 8080\naws ec2 authorize-security-group-ingress \\\n    --group-id $SG_ID \\\n    --protocol tcp \\\n    --port 8080 \\\n    --cidr 0.0.0.0\u002F0 \\\n    --region eu-central-1\n",[3449,13675,13676,13689,13693,13698,13714,13724,13734,13743,13751,13764,13768,13784,13788,13793,13804,13814,13823,13831,13841],{"__ignoreMap":3447},[3452,13677,13678,13681,13683,13686],{"class":3454,"line":3455},[3452,13679,13680],{"class":3957},"VPC_ID",[3452,13682,8300],{"class":3961},[3452,13684,13685],{"class":3462},"\"vpc-0a1b2c3d4e5f67890\"",[3452,13687,13688],{"class":3469},"   # ← ЗАМІНІТЬ на ваш реальний VPC ID\n",[3452,13690,13691],{"class":3454,"line":3473},[3452,13692,3619],{"emptyLinePlaceholder":3618},[3452,13694,13695],{"class":3454,"line":3609},[3452,13696,13697],{"class":3469},"# Створіть Security Group\n",[3452,13699,13700,13703,13705,13707,13709,13712],{"class":3454,"line":3615},[3452,13701,13702],{"class":3957},"SG_ID",[3452,13704,7291],{"class":3961},[3452,13706,3459],{"class":3458},[3452,13708,13558],{"class":3462},[3452,13710,13711],{"class":3462}," create-security-group",[3452,13713,5067],{"class":5066},[3452,13715,13716,13719,13722],{"class":3454,"line":3622},[3452,13717,13718],{"class":3953},"    --group-name",[3452,13720,13721],{"class":3462}," \"ecs-lab-sg\"",[3452,13723,5067],{"class":5066},[3452,13725,13726,13729,13732],{"class":3454,"line":3628},[3452,13727,13728],{"class":3953},"    --description",[3452,13730,13731],{"class":3462}," \"Security group for ECS lab tasks\"",[3452,13733,5067],{"class":5066},[3452,13735,13736,13738,13741],{"class":3454,"line":3634},[3452,13737,7453],{"class":3953},[3452,13739,13740],{"class":3957}," $VPC_ID",[3452,13742,5067],{"class":5066},[3452,13744,13745,13747,13749],{"class":3454,"line":3640},[3452,13746,6935],{"class":3953},[3452,13748,7377],{"class":3462},[3452,13750,5067],{"class":5066},[3452,13752,13753,13755,13758,13760,13762],{"class":3454,"line":3646},[3452,13754,7359],{"class":3953},[3452,13756,13757],{"class":3462}," GroupId",[3452,13759,7365],{"class":3953},[3452,13761,7368],{"class":3462},[3452,13763,7380],{"class":3961},[3452,13765,13766],{"class":3454,"line":3652},[3452,13767,3619],{"emptyLinePlaceholder":3618},[3452,13769,13770,13772,13775,13778,13781],{"class":3454,"line":3658},[3452,13771,7385],{"class":3458},[3452,13773,13774],{"class":3462}," \"Security Group ID: ",[3452,13776,13777],{"class":3957},"$SG_ID",[3452,13779,13780],{"class":3462},"\"",[3452,13782,13783],{"class":3469},"   # ← ЗАПИШІТЬ цей ID\n",[3452,13785,13786],{"class":3454,"line":3664},[3452,13787,3619],{"emptyLinePlaceholder":3618},[3452,13789,13790],{"class":3454,"line":3670},[3452,13791,13792],{"class":3469},"# Дозвольте вхідний трафік на порт 8080\n",[3452,13794,13795,13797,13799,13802],{"class":3454,"line":3676},[3452,13796,3459],{"class":3458},[3452,13798,13558],{"class":3462},[3452,13800,13801],{"class":3462}," authorize-security-group-ingress",[3452,13803,5067],{"class":5066},[3452,13805,13806,13809,13812],{"class":3454,"line":3682},[3452,13807,13808],{"class":3953},"    --group-id",[3452,13810,13811],{"class":3957}," $SG_ID",[3452,13813,5067],{"class":5066},[3452,13815,13816,13818,13821],{"class":3454,"line":3688},[3452,13817,7433],{"class":3953},[3452,13819,13820],{"class":3462}," tcp",[3452,13822,5067],{"class":5066},[3452,13824,13825,13827,13829],{"class":3454,"line":3694},[3452,13826,7443],{"class":3953},[3452,13828,7446],{"class":4152},[3452,13830,5067],{"class":5066},[3452,13832,13833,13836,13839],{"class":3454,"line":3699},[3452,13834,13835],{"class":3953},"    --cidr",[3452,13837,13838],{"class":3462}," 0.0.0.0\u002F0",[3452,13840,5067],{"class":5066},[3452,13842,13843,13845],{"class":3454,"line":3705},[3452,13844,6935],{"class":3953},[3452,13846,6938],{"class":3462},[9854,13848,13849,13854,13877,13882],{"label":9996},[3354,13850,13851],{},[3540,13852,13853],{},"Знайдіть VPC та підмережі:",[7751,13855,13856,13862,13871],{},[4702,13857,11065,13858,13861],{},[3540,13859,13860],{},"VPC"," (через пошук у консолі)",[4702,13863,13864,13867,13868],{},[3540,13865,13866],{},"Your VPCs"," → знайдіть рядок з колонкою \"Default VPC: Yes\" → скопіюйте ",[3540,13869,13870],{},"VPC ID",[4702,13872,13873,13876],{},[3540,13874,13875],{},"Subnets"," → відфільтруйте за вашим VPC ID → запишіть ID двох підмереж у різних AZ",[3354,13878,13879],{},[3540,13880,13881],{},"Створіть Security Group:",[7751,13883,13884,13893,13899,13910],{},[4702,13885,13886,13887,9024,13890],{},"VPC → ",[3540,13888,13889],{},"Security groups",[3540,13891,13892],{},"Create security group",[4702,13894,11077,13895,13898],{},[3449,13896,13897],{},"ecs-lab-sg",", VPC: оберіть ваш default VPC",[4702,13900,13901,13904,13905],{},[3540,13902,13903],{},"Inbound rules"," → Add rule:\n",[4699,13906,13907],{},[4702,13908,13909],{},"Type: Custom TCP, Port: 8080, Source: Anywhere-IPv4 (0.0.0.0\u002F0)",[4702,13911,11102,13912,13915,13916],{},[3540,13913,13914],{},"Create"," → скопіюйте ",[3540,13917,13918],{},"Security group ID",[6155,13920,13921,13931],{},[3354,13922,13923,13924,13926,13927,13930],{},"Правило ",[3449,13925,6420],{}," (доступ з усього Інтернету) прийнятне лише для цьої навчальної лабораторної роботи, де Tasks мають публічний IP і немає ALB. У production-середовищі Security Group Tasks повинна дозволяти вхідний трафік на порт 8080 ",[3540,13928,13929],{},"виключно з Security Group вашого ALB",", а не з усього Інтернету:",[3442,13932,13934],{"className":3444,"code":13933,"language":3446,"meta":3447,"style":3447},"# Правильне production-правило для Security Group Tasks:\n# Source: sg-alb-id  (а не 0.0.0.0\u002F0)\naws ec2 authorize-security-group-ingress \\\n    --group-id $TASKS_SG_ID \\\n    --protocol tcp \\\n    --port 8080 \\\n    --source-group $ALB_SG_ID \\\n    --region eu-central-1\n",[3449,13935,13936,13941,13946,13956,13965,13973,13981,13991],{"__ignoreMap":3447},[3452,13937,13938],{"class":3454,"line":3455},[3452,13939,13940],{"class":3469},"# Правильне production-правило для Security Group Tasks:\n",[3452,13942,13943],{"class":3454,"line":3473},[3452,13944,13945],{"class":3469},"# Source: sg-alb-id  (а не 0.0.0.0\u002F0)\n",[3452,13947,13948,13950,13952,13954],{"class":3454,"line":3609},[3452,13949,3459],{"class":3458},[3452,13951,13558],{"class":3462},[3452,13953,13801],{"class":3462},[3452,13955,5067],{"class":5066},[3452,13957,13958,13960,13963],{"class":3454,"line":3615},[3452,13959,13808],{"class":3953},[3452,13961,13962],{"class":3957}," $TASKS_SG_ID",[3452,13964,5067],{"class":5066},[3452,13966,13967,13969,13971],{"class":3454,"line":3622},[3452,13968,7433],{"class":3953},[3452,13970,13820],{"class":3462},[3452,13972,5067],{"class":5066},[3452,13974,13975,13977,13979],{"class":3454,"line":3628},[3452,13976,7443],{"class":3953},[3452,13978,7446],{"class":4152},[3452,13980,5067],{"class":5066},[3452,13982,13983,13986,13989],{"class":3454,"line":3634},[3452,13984,13985],{"class":3953},"    --source-group",[3452,13987,13988],{"class":3957}," $ALB_SG_ID",[3452,13990,5067],{"class":5066},[3452,13992,13993,13995],{"class":3454,"line":3640},[3452,13994,6935],{"class":3953},[3452,13996,6938],{"class":3462},[3573,13998,14000],{"id":13999},"крок-9-запуск-ecs-service","Крок 9: Запуск ECS Service",[9851,14002,14003,14091],{},[9854,14004,14005],{"label":9996},[7751,14006,14007,14017,14032,14061,14087],{},[4702,14008,13133,14009,9024,14011,9020,14013,9024,14015],{},[3540,14010,12773],{},[3449,14012,12789],{},[3540,14014,3993],{},[3540,14016,13914],{},[4702,14018,14019,14022],{},[3540,14020,14021],{},"Environment:",[4699,14023,14024,14029],{},[4702,14025,14026,14027],{},"Compute options: Launch type → ",[3540,14028,11234],{},[4702,14030,14031],{},"Platform version: LATEST",[4702,14033,14034,14037],{},[3540,14035,14036],{},"Deployment configuration:",[4699,14038,14039,14044,14050,14056],{},[4702,14040,14041,14042],{},"Application type: ",[3540,14043,5185],{},[4702,14045,14046,14047,14049],{},"Task definition Family: ",[3449,14048,12445],{},", Revision: LATEST",[4702,14051,14052,14053],{},"Service name: ",[3449,14054,14055],{},"ecs-lab-service",[4702,14057,14058,14059],{},"Desired tasks: ",[3540,14060,8871],{},[4702,14062,14063,14066],{},[3540,14064,14065],{},"Networking:",[4699,14067,14068,14071,14074,14080],{},[4702,14069,14070],{},"VPC: ваш default VPC",[4702,14072,14073],{},"Subnets: оберіть 2 підмережі у різних AZ",[4702,14075,14076,14077,14079],{},"Security group: ",[3449,14078,13897],{}," (створений вище)",[4702,14081,14082,14083,14086],{},"Public IP: ",[3540,14084,14085],{},"Turn on"," (для цієї лабораторної роботи)",[4702,14088,11102,14089],{},[3540,14090,12806],{},[9854,14092,14093],{"label":9856},[3442,14094,14096],{"className":3444,"code":14095,"language":3446,"meta":3447,"style":3447},"# ЗАМІНІТЬ усі значення на реальні з попередніх кроків!\nACCOUNT_ID=\"123456789012\"      # ← ваш Account ID\nREGION=\"eu-central-1\"\nSUBNET_1=\"subnet-0a1b2c3d\"    # ← ваш Subnet ID 1\nSUBNET_2=\"subnet-1b2c3d4e\"    # ← ваш Subnet ID 2\nSG_ID=\"sg-0a1b2c3d4e5f67890\"  # ← ваш Security Group ID\n\naws ecs create-service \\\n    --cluster ecs-lab-cluster \\\n    --service-name ecs-lab-service \\\n    --task-definition ecs-lab-api \\\n    --desired-count 2 \\\n    --launch-type FARGATE \\\n    --network-configuration \"awsvpcConfiguration={\n        subnets=[$SUBNET_1,$SUBNET_2],\n        securityGroups=[$SG_ID],\n        assignPublicIp=ENABLED\n    }\" \\\n    --region $REGION\n",[3449,14097,14098,14103,14114,14122,14135,14148,14160,14164,14174,14182,14191,14199,14207,14215,14222,14237,14246,14251,14258],{"__ignoreMap":3447},[3452,14099,14100],{"class":3454,"line":3455},[3452,14101,14102],{"class":3469},"# ЗАМІНІТЬ усі значення на реальні з попередніх кроків!\n",[3452,14104,14105,14107,14109,14111],{"class":3454,"line":3473},[3452,14106,12509],{"class":3957},[3452,14108,8300],{"class":3961},[3452,14110,12356],{"class":3462},[3452,14112,14113],{"class":3469},"      # ← ваш Account ID\n",[3452,14115,14116,14118,14120],{"class":3454,"line":3609},[3452,14117,12521],{"class":3957},[3452,14119,8300],{"class":3961},[3452,14121,13309],{"class":3462},[3452,14123,14124,14127,14129,14132],{"class":3454,"line":3615},[3452,14125,14126],{"class":3957},"SUBNET_1",[3452,14128,8300],{"class":3961},[3452,14130,14131],{"class":3462},"\"subnet-0a1b2c3d\"",[3452,14133,14134],{"class":3469},"    # ← ваш Subnet ID 1\n",[3452,14136,14137,14140,14142,14145],{"class":3454,"line":3622},[3452,14138,14139],{"class":3957},"SUBNET_2",[3452,14141,8300],{"class":3961},[3452,14143,14144],{"class":3462},"\"subnet-1b2c3d4e\"",[3452,14146,14147],{"class":3469},"    # ← ваш Subnet ID 2\n",[3452,14149,14150,14152,14154,14157],{"class":3454,"line":3628},[3452,14151,13702],{"class":3957},[3452,14153,8300],{"class":3961},[3452,14155,14156],{"class":3462},"\"sg-0a1b2c3d4e5f67890\"",[3452,14158,14159],{"class":3469},"  # ← ваш Security Group ID\n",[3452,14161,14162],{"class":3454,"line":3634},[3452,14163,3619],{"emptyLinePlaceholder":3618},[3452,14165,14166,14168,14170,14172],{"class":3454,"line":3640},[3452,14167,3459],{"class":3458},[3452,14169,6888],{"class":3462},[3452,14171,7620],{"class":3462},[3452,14173,5067],{"class":5066},[3452,14175,14176,14178,14180],{"class":3454,"line":3646},[3452,14177,7627],{"class":3953},[3452,14179,12838],{"class":3462},[3452,14181,5067],{"class":5066},[3452,14183,14184,14186,14189],{"class":3454,"line":3652},[3452,14185,7637],{"class":3953},[3452,14187,14188],{"class":3462}," ecs-lab-service",[3452,14190,5067],{"class":5066},[3452,14192,14193,14195,14197],{"class":3454,"line":3658},[3452,14194,7647],{"class":3953},[3452,14196,12294],{"class":3462},[3452,14198,5067],{"class":5066},[3452,14200,14201,14203,14205],{"class":3454,"line":3664},[3452,14202,7657],{"class":3953},[3452,14204,6918],{"class":4152},[3452,14206,5067],{"class":5066},[3452,14208,14209,14211,14213],{"class":3454,"line":3670},[3452,14210,7666],{"class":3953},[3452,14212,7669],{"class":3462},[3452,14214,5067],{"class":5066},[3452,14216,14217,14219],{"class":3454,"line":3676},[3452,14218,7691],{"class":3953},[3452,14220,14221],{"class":3462}," \"awsvpcConfiguration={\n",[3452,14223,14224,14227,14230,14232,14235],{"class":3454,"line":3682},[3452,14225,14226],{"class":3462},"        subnets=[",[3452,14228,14229],{"class":3957},"$SUBNET_1",[3452,14231,4979],{"class":3462},[3452,14233,14234],{"class":3957},"$SUBNET_2",[3452,14236,5570],{"class":3462},[3452,14238,14239,14242,14244],{"class":3454,"line":3688},[3452,14240,14241],{"class":3462},"        securityGroups=[",[3452,14243,13777],{"class":3957},[3452,14245,5570],{"class":3462},[3452,14247,14248],{"class":3454,"line":3694},[3452,14249,14250],{"class":3462},"        assignPublicIp=ENABLED\n",[3452,14252,14253,14256],{"class":3454,"line":3699},[3452,14254,14255],{"class":3462},"    }\"",[3452,14257,5067],{"class":5066},[3452,14259,14260,14262],{"class":3454,"line":3705},[3452,14261,6935],{"class":3953},[3452,14263,13530],{"class":3957},[3354,14265,14266,14267,3516],{},"Після запуску зачекайте 1–2 хвилини поки Tasks перейдуть у стан ",[3449,14268,5256],{},[3881,14270,14272,14281,14284,14288,14292,14296,14300],{"title":14271},"aws ecs list-tasks",[3885,14273,14275,3893,14278],{"className":14274},[3454],[3452,14276,3892],{"className":14277},[3891],[3540,14279,14280],{},"aws ecs list-tasks --cluster ecs-lab-cluster --region eu-central-1",[3885,14282,4954],{"className":14283},[3454],[3885,14285,14287],{"className":14286},[3454],"  \"taskArns\": [",[3885,14289,14291],{"className":14290},[3454],"    \"arn:aws:ecs:eu-central-1:123456789012:task\u002Fecs-lab-cluster\u002Fabc123\",",[3885,14293,14295],{"className":14294},[3454],"    \"arn:aws:ecs:eu-central-1:123456789012:task\u002Fecs-lab-cluster\u002Fdef456\"",[3885,14297,14299],{"className":14298},[3454],"  ]",[3885,14301,4991],{"className":14302},[3454],[3573,14304,14306],{"id":14305},"крок-10-перевірка-роботи-застосунку","Крок 10: Перевірка роботи застосунку",[3354,14308,14309],{},"Знайдіть публічну IP-адресу одного з Tasks:",[9851,14311,14312,14339],{},[9854,14313,14314],{"label":9996},[7751,14315,14316,14323,14328,14336],{},[4702,14317,10001,14318,9020,14320],{},[3449,14319,12789],{},[3540,14321,14322],{},"Tasks",[4702,14324,14325,14326],{},"Натисніть на будь-який Task у стані ",[3449,14327,5256],{},[4702,14329,14330,14331,13915,14333],{},"У розділі ",[3540,14332,1937],{},[3540,14334,14335],{},"Public IP",[4702,14337,14338],{},"Відкрийте у браузері або через curl",[9854,14340,14341],{"label":9856},[3442,14342,14344],{"className":3444,"code":14343,"language":3446,"meta":3447,"style":3447},"# Отримайте список Tasks\nTASK_ARN=$(aws ecs list-tasks \\\n    --cluster ecs-lab-cluster \\\n    --region eu-central-1 \\\n    --query \"taskArns[0]\" --output text)\n\n# Знайдіть ENI прикріплений до Task\nENI_ID=$(aws ecs describe-tasks \\\n    --cluster ecs-lab-cluster \\\n    --tasks $TASK_ARN \\\n    --region eu-central-1 \\\n    --query \"tasks[0].attachments[0].details[?name==\\`networkInterfaceId\\`].value\" \\\n    --output text)\n\n# Отримайте публічний IP\nPUBLIC_IP=$(aws ec2 describe-network-interfaces \\\n    --network-interface-ids $ENI_ID \\\n    --region eu-central-1 \\\n    --query \"NetworkInterfaces[0].Association.PublicIp\" \\\n    --output text)\n\necho \"Public IP: $PUBLIC_IP\"\n",[3449,14345,14346,14351,14366,14374,14382,14395,14399,14404,14420,14428,14437,14445,14465,14473,14477,14482,14498,14508,14516,14525,14533,14537],{"__ignoreMap":3447},[3452,14347,14348],{"class":3454,"line":3455},[3452,14349,14350],{"class":3469},"# Отримайте список Tasks\n",[3452,14352,14353,14355,14357,14359,14361,14364],{"class":3454,"line":3473},[3452,14354,9923],{"class":3957},[3452,14356,7291],{"class":3961},[3452,14358,3459],{"class":3458},[3452,14360,6888],{"class":3462},[3452,14362,14363],{"class":3462}," list-tasks",[3452,14365,5067],{"class":5066},[3452,14367,14368,14370,14372],{"class":3454,"line":3609},[3452,14369,7627],{"class":3953},[3452,14371,12838],{"class":3462},[3452,14373,5067],{"class":5066},[3452,14375,14376,14378,14380],{"class":3454,"line":3615},[3452,14377,6935],{"class":3953},[3452,14379,7377],{"class":3462},[3452,14381,5067],{"class":5066},[3452,14383,14384,14386,14389,14391,14393],{"class":3454,"line":3622},[3452,14385,7359],{"class":3953},[3452,14387,14388],{"class":3462}," \"taskArns[0]\"",[3452,14390,7365],{"class":3953},[3452,14392,7368],{"class":3462},[3452,14394,7380],{"class":3961},[3452,14396,14397],{"class":3454,"line":3628},[3452,14398,3619],{"emptyLinePlaceholder":3618},[3452,14400,14401],{"class":3454,"line":3634},[3452,14402,14403],{"class":3469},"# Знайдіть ENI прикріплений до Task\n",[3452,14405,14406,14409,14411,14413,14415,14418],{"class":3454,"line":3640},[3452,14407,14408],{"class":3957},"ENI_ID",[3452,14410,7291],{"class":3961},[3452,14412,3459],{"class":3458},[3452,14414,6888],{"class":3462},[3452,14416,14417],{"class":3462}," describe-tasks",[3452,14419,5067],{"class":5066},[3452,14421,14422,14424,14426],{"class":3454,"line":3646},[3452,14423,7627],{"class":3953},[3452,14425,12838],{"class":3462},[3452,14427,5067],{"class":5066},[3452,14429,14430,14433,14435],{"class":3454,"line":3652},[3452,14431,14432],{"class":3953},"    --tasks",[3452,14434,9959],{"class":3957},[3452,14436,5067],{"class":5066},[3452,14438,14439,14441,14443],{"class":3454,"line":3658},[3452,14440,6935],{"class":3953},[3452,14442,7377],{"class":3462},[3452,14444,5067],{"class":5066},[3452,14446,14447,14449,14452,14455,14458,14460,14463],{"class":3454,"line":3664},[3452,14448,7359],{"class":3953},[3452,14450,14451],{"class":3462}," \"tasks[0].attachments[0].details[?name==",[3452,14453,14454],{"class":5066},"\\`",[3452,14456,14457],{"class":3462},"networkInterfaceId",[3452,14459,14454],{"class":5066},[3452,14461,14462],{"class":3462},"].value\"",[3452,14464,5067],{"class":5066},[3452,14466,14467,14469,14471],{"class":3454,"line":3670},[3452,14468,13587],{"class":3953},[3452,14470,7368],{"class":3462},[3452,14472,7380],{"class":3961},[3452,14474,14475],{"class":3454,"line":3676},[3452,14476,3619],{"emptyLinePlaceholder":3618},[3452,14478,14479],{"class":3454,"line":3682},[3452,14480,14481],{"class":3469},"# Отримайте публічний IP\n",[3452,14483,14484,14487,14489,14491,14493,14496],{"class":3454,"line":3688},[3452,14485,14486],{"class":3957},"PUBLIC_IP",[3452,14488,7291],{"class":3961},[3452,14490,3459],{"class":3458},[3452,14492,13558],{"class":3462},[3452,14494,14495],{"class":3462}," describe-network-interfaces",[3452,14497,5067],{"class":5066},[3452,14499,14500,14503,14506],{"class":3454,"line":3694},[3452,14501,14502],{"class":3953},"    --network-interface-ids",[3452,14504,14505],{"class":3957}," $ENI_ID",[3452,14507,5067],{"class":5066},[3452,14509,14510,14512,14514],{"class":3454,"line":3699},[3452,14511,6935],{"class":3953},[3452,14513,7377],{"class":3462},[3452,14515,5067],{"class":5066},[3452,14517,14518,14520,14523],{"class":3454,"line":3705},[3452,14519,7359],{"class":3953},[3452,14521,14522],{"class":3462}," \"NetworkInterfaces[0].Association.PublicIp\"",[3452,14524,5067],{"class":5066},[3452,14526,14527,14529,14531],{"class":3454,"line":3711},[3452,14528,13587],{"class":3953},[3452,14530,7368],{"class":3462},[3452,14532,7380],{"class":3961},[3452,14534,14535],{"class":3454,"line":3717},[3452,14536,3619],{"emptyLinePlaceholder":3618},[3452,14538,14539,14541,14544,14547],{"class":3454,"line":3723},[3452,14540,7385],{"class":3458},[3452,14542,14543],{"class":3462}," \"Public IP: ",[3452,14545,14546],{"class":3957},"$PUBLIC_IP",[3452,14548,7394],{"class":3462},[3354,14550,14551],{},"Перевірте, що API відповідає:",[3881,14553,14555,14564,14570,14573,14582],{"title":14554},"curl перевірка",[3885,14556,14558,3893,14561],{"className":14557},[3454],[3452,14559,3892],{"className":14560},[3891],[3540,14562,14563],{},"curl http:\u002F\u002F\u003CPUBLIC_IP>:8080\u002Fhealth",[3885,14565,14567],{"className":14566},[3454],[3452,14568,4400],{"className":14569},[3916],[3885,14571],{"className":14572},[3454],[3885,14574,14576,3893,14579],{"className":14575},[3454],[3452,14577,3892],{"className":14578},[3891],[3540,14580,14581],{},"curl http:\u002F\u002F\u003CPUBLIC_IP>:8080\u002F",[3885,14583,14585],{"className":14584},[3454],"{\"message\":\"Hello from ECS Fargate!\",\"version\":\"1.0.0\",\"environment\":\"Production\",\"timestamp\":\"2024-...\"}",[3573,14587,14589],{"id":14588},"крок-11-rolling-update-деплой-нової-версії","Крок 11: Rolling Update — деплой нової версії",[3354,14591,14592],{},"Змінимо версію API і задеплоїмо оновлення без зупинки сервісу.",[3354,14594,14595,3893,14598,14600],{},[3540,14596,14597],{},"Оновіть",[3449,14599,3940],{}," — змініть значення за замовчуванням:",[3442,14602,14604],{"className":3944,"code":14603,"language":3946,"meta":3447,"style":3447},"var version = Environment.GetEnvironmentVariable(\"APP_VERSION\") ?? \"1.1.0\";\n",[3449,14605,14606],{"__ignoreMap":3447},[3452,14607,14608,14610,14612,14614,14616,14618,14620,14622,14624,14626,14629],{"class":3454,"line":3455},[3452,14609,3954],{"class":3953},[3452,14611,11657],{"class":3957},[3452,14613,3962],{"class":3961},[3452,14615,11662],{"class":3957},[3452,14617,3516],{"class":3961},[3452,14619,11667],{"class":3458},[3452,14621,3973],{"class":3961},[3452,14623,11672],{"class":3462},[3452,14625,11675],{"class":3961},[3452,14627,14628],{"class":3462},"\"1.1.0\"",[3452,14630,11680],{"class":3961},[3354,14632,14633],{},"Зберіть і завантажте новий образ:",[3442,14635,14637],{"className":3444,"code":14636,"language":3446,"meta":3447,"style":3447},"ACCOUNT_ID=\"123456789012\"   # ← ваш Account ID\nREGION=\"eu-central-1\"\nREPO_URI=\"${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com\u002Fecs-lab-api\"\n\ndocker build -t ecs-lab-api:v1.1.0 .\ndocker tag ecs-lab-api:v1.1.0 $REPO_URI:v1.1.0\ndocker push $REPO_URI:v1.1.0\n",[3449,14638,14639,14650,14658,14674,14678,14694,14707],{"__ignoreMap":3447},[3452,14640,14641,14643,14645,14647],{"class":3454,"line":3455},[3452,14642,12509],{"class":3957},[3452,14644,8300],{"class":3961},[3452,14646,12356],{"class":3462},[3452,14648,14649],{"class":3469},"   # ← ваш Account ID\n",[3452,14651,14652,14654,14656],{"class":3454,"line":3473},[3452,14653,12521],{"class":3957},[3452,14655,8300],{"class":3961},[3452,14657,13309],{"class":3462},[3452,14659,14660,14662,14664,14666,14668,14670,14672],{"class":3454,"line":3609},[3452,14661,12533],{"class":3957},[3452,14663,8300],{"class":3961},[3452,14665,12538],{"class":3462},[3452,14667,12509],{"class":3957},[3452,14669,12543],{"class":3462},[3452,14671,12521],{"class":3957},[3452,14673,12548],{"class":3462},[3452,14675,14676],{"class":3454,"line":3615},[3452,14677,3619],{"emptyLinePlaceholder":3618},[3452,14679,14680,14682,14685,14688,14691],{"class":3454,"line":3622},[3452,14681,5057],{"class":3458},[3452,14683,14684],{"class":3462}," build",[3452,14686,14687],{"class":3953}," -t",[3452,14689,14690],{"class":3462}," ecs-lab-api:v1.1.0",[3452,14692,14693],{"class":3462}," .\n",[3452,14695,14696,14698,14700,14702,14704],{"class":3454,"line":3628},[3452,14697,5057],{"class":3458},[3452,14699,5060],{"class":3462},[3452,14701,14690],{"class":3462},[3452,14703,12678],{"class":3957},[3452,14705,14706],{"class":3462},":v1.1.0\n",[3452,14708,14709,14711,14713,14715],{"class":3454,"line":3634},[3452,14710,5057],{"class":3458},[3452,14712,12697],{"class":3462},[3452,14714,12678],{"class":3957},[3452,14716,14706],{"class":3462},[3354,14718,14719],{},"Оновіть Task Definition та запустіть Rolling Update:",[9851,14721,14722,14790],{},[9854,14723,14724],{"label":9996},[7751,14725,14726,14735,14748,14756,14761,14771,14778,14783],{},[4702,14727,13133,14728,9024,14730,9024,14732],{},[3540,14729,13136],{},[3449,14731,12445],{},[3540,14733,14734],{},"Create new revision",[4702,14736,14737,14738,14741,14742,14744,14745],{},"Знайдіть поле ",[3540,14739,14740],{},"Image URI"," у розділі Container → змініть тег ",[3449,14743,9284],{}," на ",[3449,14746,14747],{},":v1.1.0",[4702,14749,14750,14751,14744,14753],{},"Також змініть Environment variable ",[3449,14752,13243],{},[3449,14754,14755],{},"1.1.0",[4702,14757,11102,14758,14760],{},[3540,14759,12806],{}," → з'явиться revision 2",[4702,14762,10001,14763,14765,14766,9024,14768],{},[3449,14764,12789],{}," → Services → ",[3449,14767,14055],{},[3540,14769,14770],{},"Update",[4702,14772,14773,14774,14777],{},"Task definition: оберіть ",[3449,14775,14776],{},"ecs-lab-api:2"," (нова revision)",[4702,14779,11102,14780],{},[3540,14781,14782],{},"«Update»",[4702,14784,14785,14786,14789],{},"Перейдіть на вкладку ",[3540,14787,14788],{},"Deployments"," — спостерігайте як нові Tasks запускаються (Running: 2→4→2)",[9854,14791,14792],{"label":9856},[3442,14793,14795],{"className":3444,"code":14794,"language":3446,"meta":3447,"style":3447},"ACCOUNT_ID=\"123456789012\"   # ← ваш Account ID\nREGION=\"eu-central-1\"\n\n# Зареєструйте нову Task Definition з оновленим образом\naws ecs register-task-definition \\\n    --family ecs-lab-api \\\n    --network-mode awsvpc \\\n    --requires-compatibilities FARGATE \\\n    --cpu 256 --memory 512 \\\n    --execution-role-arn \"arn:aws:iam::${ACCOUNT_ID}:role\u002FecsTaskExecutionRole\" \\\n    --container-definitions '[{\n        \"name\": \"ecs-lab-api\",\n        \"image\": \"'\"${ACCOUNT_ID}\"'.dkr.ecr.'\"${REGION}\"'.amazonaws.com\u002Fecs-lab-api:v1.1.0\",\n        \"portMappings\": [{\"containerPort\": 8080}],\n        \"environment\": [\n            {\"name\": \"ASPNETCORE_ENVIRONMENT\", \"value\": \"Production\"},\n            {\"name\": \"APP_VERSION\", \"value\": \"1.1.0\"}\n        ],\n        \"healthCheck\": {\n            \"command\": [\"CMD-SHELL\", \"curl -f http:\u002F\u002Flocalhost:8080\u002Fhealth || exit 1\"],\n            \"interval\": 30, \"timeout\": 5, \"retries\": 3, \"startPeriod\": 10\n        },\n        \"logConfiguration\": {\n            \"logDriver\": \"awslogs\",\n            \"options\": {\n                \"awslogs-group\": \"\u002Fecs\u002Fecs-lab-api\",\n                \"awslogs-region\": \"'\"${REGION}\"'\",\n                \"awslogs-stream-prefix\": \"ecs\",\n                \"awslogs-create-group\": \"true\"\n            }\n        }\n    }]' \\\n    --region $REGION\n\n# Оновіть Service — він автоматично визначить latest revision\naws ecs update-service \\\n    --cluster ecs-lab-cluster \\\n    --service ecs-lab-service \\\n    --task-definition ecs-lab-api \\\n    --region $REGION\n",[3449,14796,14797,14807,14815,14819,14824,14834,14843,14853,14862,14878,14893,14901,14905,14920,14925,14929,14933,14938,14942,14946,14950,14954,14958,14962,14966,14970,14974,14984,14988,14992,14996,15000,15007,15013,15017,15022,15032,15040,15048,15056],{"__ignoreMap":3447},[3452,14798,14799,14801,14803,14805],{"class":3454,"line":3455},[3452,14800,12509],{"class":3957},[3452,14802,8300],{"class":3961},[3452,14804,12356],{"class":3462},[3452,14806,14649],{"class":3469},[3452,14808,14809,14811,14813],{"class":3454,"line":3473},[3452,14810,12521],{"class":3957},[3452,14812,8300],{"class":3961},[3452,14814,13309],{"class":3462},[3452,14816,14817],{"class":3454,"line":3609},[3452,14818,3619],{"emptyLinePlaceholder":3618},[3452,14820,14821],{"class":3454,"line":3615},[3452,14822,14823],{"class":3469},"# Зареєструйте нову Task Definition з оновленим образом\n",[3452,14825,14826,14828,14830,14832],{"class":3454,"line":3622},[3452,14827,3459],{"class":3458},[3452,14829,6888],{"class":3462},[3452,14831,13511],{"class":3462},[3452,14833,5067],{"class":5066},[3452,14835,14836,14839,14841],{"class":3454,"line":3628},[3452,14837,14838],{"class":3953},"    --family",[3452,14840,12294],{"class":3462},[3452,14842,5067],{"class":5066},[3452,14844,14845,14848,14851],{"class":3454,"line":3634},[3452,14846,14847],{"class":3953},"    --network-mode",[3452,14849,14850],{"class":3462}," awsvpc",[3452,14852,5067],{"class":5066},[3452,14854,14855,14858,14860],{"class":3454,"line":3640},[3452,14856,14857],{"class":3953},"    --requires-compatibilities",[3452,14859,7669],{"class":3462},[3452,14861,5067],{"class":5066},[3452,14863,14864,14867,14870,14873,14876],{"class":3454,"line":3646},[3452,14865,14866],{"class":3953},"    --cpu",[3452,14868,14869],{"class":4152}," 256",[3452,14871,14872],{"class":3953}," --memory",[3452,14874,14875],{"class":4152}," 512",[3452,14877,5067],{"class":5066},[3452,14879,14880,14883,14886,14888,14891],{"class":3454,"line":3652},[3452,14881,14882],{"class":3953},"    --execution-role-arn",[3452,14884,14885],{"class":3462}," \"arn:aws:iam::${",[3452,14887,12509],{"class":3957},[3452,14889,14890],{"class":3462},"}:role\u002FecsTaskExecutionRole\"",[3452,14892,5067],{"class":5066},[3452,14894,14895,14898],{"class":3454,"line":3658},[3452,14896,14897],{"class":3953},"    --container-definitions",[3452,14899,14900],{"class":3462}," '[{\n",[3452,14902,14903],{"class":3454,"line":3664},[3452,14904,13380],{"class":3462},[3452,14906,14907,14910,14912,14915,14917],{"class":3454,"line":3670},[3452,14908,14909],{"class":3462},"        \"image\": \"'\"${",[3452,14911,12509],{"class":3957},[3452,14913,14914],{"class":3462},"}\"'.dkr.ecr.'\"${",[3452,14916,12521],{"class":3957},[3452,14918,14919],{"class":3462},"}\"'.amazonaws.com\u002Fecs-lab-api:v1.1.0\",\n",[3452,14921,14922],{"class":3454,"line":3676},[3452,14923,14924],{"class":3462},"        \"portMappings\": [{\"containerPort\": 8080}],\n",[3452,14926,14927],{"class":3454,"line":3682},[3452,14928,13404],{"class":3462},[3452,14930,14931],{"class":3454,"line":3688},[3452,14932,13409],{"class":3462},[3452,14934,14935],{"class":3454,"line":3694},[3452,14936,14937],{"class":3462},"            {\"name\": \"APP_VERSION\", \"value\": \"1.1.0\"}\n",[3452,14939,14940],{"class":3454,"line":3699},[3452,14941,13419],{"class":3462},[3452,14943,14944],{"class":3454,"line":3705},[3452,14945,13424],{"class":3462},[3452,14947,14948],{"class":3454,"line":3711},[3452,14949,13429],{"class":3462},[3452,14951,14952],{"class":3454,"line":3717},[3452,14953,13434],{"class":3462},[3452,14955,14956],{"class":3454,"line":3723},[3452,14957,7030],{"class":3462},[3452,14959,14960],{"class":3454,"line":3729},[3452,14961,13443],{"class":3462},[3452,14963,14964],{"class":3454,"line":3734},[3452,14965,13448],{"class":3462},[3452,14967,14968],{"class":3454,"line":3740},[3452,14969,13453],{"class":3462},[3452,14971,14972],{"class":3454,"line":3746},[3452,14973,13458],{"class":3462},[3452,14975,14976,14979,14981],{"class":3454,"line":3752},[3452,14977,14978],{"class":3462},"                \"awslogs-region\": \"'\"${",[3452,14980,12521],{"class":3957},[3452,14982,14983],{"class":3462},"}\"'\",\n",[3452,14985,14986],{"class":3454,"line":3758},[3452,14987,13473],{"class":3462},[3452,14989,14990],{"class":3454,"line":3764},[3452,14991,13478],{"class":3462},[3452,14993,14994],{"class":3454,"line":3769},[3452,14995,5947],{"class":3462},[3452,14997,14998],{"class":3454,"line":4629},[3452,14999,5953],{"class":3462},[3452,15001,15002,15005],{"class":3454,"line":4637},[3452,15003,15004],{"class":3462},"    }]'",[3452,15006,5067],{"class":5066},[3452,15008,15009,15011],{"class":3454,"line":4642},[3452,15010,6935],{"class":3953},[3452,15012,13530],{"class":3957},[3452,15014,15015],{"class":3454,"line":4648},[3452,15016,3619],{"emptyLinePlaceholder":3618},[3452,15018,15019],{"class":3454,"line":4654},[3452,15020,15021],{"class":3469},"# Оновіть Service — він автоматично визначить latest revision\n",[3452,15023,15024,15026,15028,15030],{"class":3454,"line":4660},[3452,15025,3459],{"class":3458},[3452,15027,6888],{"class":3462},[3452,15029,9875],{"class":3462},[3452,15031,5067],{"class":5066},[3452,15033,15034,15036,15038],{"class":3454,"line":4668},[3452,15035,7627],{"class":3953},[3452,15037,12838],{"class":3462},[3452,15039,5067],{"class":5066},[3452,15041,15042,15044,15046],{"class":3454,"line":4673},[3452,15043,9891],{"class":3953},[3452,15045,14188],{"class":3462},[3452,15047,5067],{"class":5066},[3452,15049,15050,15052,15054],{"class":3454,"line":4679},[3452,15051,7647],{"class":3953},[3452,15053,12294],{"class":3462},[3452,15055,5067],{"class":5066},[3452,15057,15058,15060],{"class":3454,"line":5908},[3452,15059,6935],{"class":3953},[3452,15061,13530],{"class":3957},[3354,15063,15064],{},"Поки йде оновлення, виконуйте запити до API — жодного збою не буде:",[3881,15066,15068,15077,15081,15084,15088],{"title":15067},"Перевірка під час Rolling Update",[3885,15069,15071,3893,15074],{"className":15070},[3454],[3452,15072,3892],{"className":15073},[3891],[3540,15075,15076],{},"while true; do curl -s http:\u002F\u002F\u003CPUBLIC_IP>:8080\u002F | grep version; sleep 2; done",[3885,15078,15080],{"className":15079},[3454],"\"version\":\"1.0.0\"",[3885,15082,15080],{"className":15083},[3454],[3885,15085,15087],{"className":15086},[3454],"\"version\":\"1.1.0\"",[3885,15089,15087],{"className":15090},[3454],[3354,15092,15093,15094,14744,15096,15098],{},"Ви побачите, як відповіді поступово переходять з ",[3449,15095,13246],{},[3449,15097,14755],{}," — без жодної помилки.",[3354,15100,15101],{},[3527,15102],{"alt":15103,"className":15104,"src":15105},"CloudWatch Logs for ECS container log streaming and monitoring",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F27.png",[3573,15107,15109],{"id":15108},"крок-12-перегляд-логів-у-cloudwatch","Крок 12: Перегляд логів у CloudWatch",[9851,15111,15112,15134],{},[9854,15113,15114],{"label":9996},[7751,15115,15116,15125,15128],{},[4702,15117,11065,15118,9024,15120,9024,15123],{},[3540,15119,11510],{},[3540,15121,15122],{},"Log groups",[3449,15124,13273],{},[4702,15126,15127],{},"Оберіть один із Log Streams — ви побачите логи запитів у реальному часі",[4702,15129,11102,15130,15133],{},[3540,15131,15132],{},"«Start tailing»"," для live-режиму",[9854,15135,15136],{"label":9856},[3442,15137,15139],{"className":3444,"code":15138,"language":3446,"meta":3447,"style":3447},"# Переглянути останні логи у режимі постійного оновлення\naws logs tail \u002Fecs\u002Fecs-lab-api \\\n    --follow \\\n    --format short \\\n    --region eu-central-1\n",[3449,15140,15141,15146,15161,15168,15178],{"__ignoreMap":3447},[3452,15142,15143],{"class":3454,"line":3455},[3452,15144,15145],{"class":3469},"# Переглянути останні логи у режимі постійного оновлення\n",[3452,15147,15148,15150,15153,15156,15159],{"class":3454,"line":3473},[3452,15149,3459],{"class":3458},[3452,15151,15152],{"class":3462}," logs",[3452,15154,15155],{"class":3462}," tail",[3452,15157,15158],{"class":3462}," \u002Fecs\u002Fecs-lab-api",[3452,15160,5067],{"class":5066},[3452,15162,15163,15166],{"class":3454,"line":3609},[3452,15164,15165],{"class":3953},"    --follow",[3452,15167,5067],{"class":5066},[3452,15169,15170,15173,15176],{"class":3454,"line":3615},[3452,15171,15172],{"class":3953},"    --format",[3452,15174,15175],{"class":3462}," short",[3452,15177,5067],{"class":5066},[3452,15179,15180,15182],{"class":3454,"line":3622},[3452,15181,6935],{"class":3953},[3452,15183,6938],{"class":3462},[3881,15185,15187,15196,15204,15211,15223,15231,15238,15245],{"title":15186},"aws logs tail — логи .NET API з CloudWatch",[3885,15188,15190,3893,15193],{"className":15189},[3454],[3452,15191,3892],{"className":15192},[3891],[3540,15194,15195],{},"aws logs tail \u002Fecs\u002Fecs-lab-api --follow --format short --region eu-central-1",[3885,15197,15199,15203],{"className":15198},[3454],[3452,15200,15202],{"className":15201},[3891],"2024-01-15T10:23:45"," ecs\u002Fecs-lab-api\u002Fabc123  info: Microsoft.Hosting.Lifetime[14]",[3885,15205,15207,15210],{"className":15206},[3454],[3452,15208,15202],{"className":15209},[3891]," ecs\u002Fecs-lab-api\u002Fabc123      Now listening on: http:\u002F\u002F[::]:8080",[3885,15212,15214,15218,15219],{"className":15213},[3454],[3452,15215,15217],{"className":15216},[3891],"2024-01-15T10:23:46"," ecs\u002Fecs-lab-api\u002Fabc123  ",[3452,15220,15222],{"className":15221},[3916],"info: Microsoft.Hosting.Lifetime[0] Application started.",[3885,15224,15226,15230],{"className":15225},[3454],[3452,15227,15229],{"className":15228},[3891],"2024-01-15T10:24:01"," ecs\u002Fecs-lab-api\u002Fabc123  info: Microsoft.AspNetCore.Hosting.Diagnostics[1]",[3885,15232,15234,15237],{"className":15233},[3454],[3452,15235,15229],{"className":15236},[3891]," ecs\u002Fecs-lab-api\u002Fabc123      Request starting HTTP\u002F1.1 GET http:\u002F\u002F10.0.1.47:8080\u002Fhealth - - -",[3885,15239,15241,15244],{"className":15240},[3454],[3452,15242,15229],{"className":15243},[3891]," ecs\u002Fecs-lab-api\u002Fabc123  info: Microsoft.AspNetCore.Hosting.Diagnostics[2]",[3885,15246,15248,15251],{"className":15247},[3454],[3452,15249,15229],{"className":15250},[3891]," ecs\u002Fecs-lab-api\u002Fabc123      Request finished HTTP\u002F1.1 GET \u002Fhealth - 200 - text\u002Fplain 1.2ms",[5114,15253,15254,15255,15258,15259,15262,15263,15266],{},"Адреса ",[3449,15256,15257],{},"10.0.1.47"," у логах — це IP ALB, який виконує health check. Кожен Task пише логи у окремий ",[3540,15260,15261],{},"Log Stream"," (ім'я стріму — це ",[3449,15264,15265],{},"ecs\u002F\u003Cродина>\u002F\u003Ctask-id>","). При рестарті Task створюється новий стрім, тому історія логів попередньої інстанції завжди доступна в CloudWatch.",[3573,15268,15270],{"id":15269},"крок-13-обовязково-очищення-ресурсів","Крок 13: ОБОВ'ЯЗКОВО — Очищення ресурсів",[6155,15272,15273,15276],{},[3540,15274,15275],{},"Не пропускайте цей крок!"," Fargate Tasks тарифікуються за кожну хвилину роботи. ECS Service з 2 Tasks на Fargate коштує ~$0.015\u002Fгод — це ~$11\u002Fмісяць. Видаліть усе після завершення лабораторної роботи.",[3354,15278,15279],{},"Порядок видалення важливий — ресурси мають залежності між собою:",[9851,15281,15282,15364],{},[9854,15283,15284],{"label":9996},[7751,15285,15286,15306,15316,15333,15344,15354],{},[4702,15287,15288,15290,15291,14765,15293,9024,15295,15298],{},[3540,15289,12766],{}," → Clusters → ",[3449,15292,12789],{},[3449,15294,14055],{},[3540,15296,15297],{},"Delete service",[4699,15299,15300],{},[4702,15301,15302,15303],{},"✅ Force delete service → ",[3540,15304,15305],{},"Delete",[4702,15307,15308,15290,15310,9024,15312,15315],{},[3540,15309,12766],{},[3449,15311,12789],{},[3540,15313,15314],{},"Delete cluster"," → підтвердіть",[4702,15317,15318,15320,15321,9024,15323,15326],{},[3540,15319,12411],{}," → Repositories → ",[3449,15322,12445],{},[3540,15324,15325],{},"Delete repository",[4699,15327,15328],{},[4702,15329,15330,15331],{},"✅ Delete all images in this repository → підтвердіть назву → ",[3540,15332,15305],{},[4702,15334,15335,15337,15338,9024,15340,15343],{},[3540,15336,11510],{}," → Log groups → ",[3449,15339,13273],{},[3540,15341,15342],{},"Actions"," → Delete log group(s)",[4702,15345,15346,15348,15349,9024,15351,15353],{},[3540,15347,13860],{}," → Security groups → ",[3449,15350,13897],{},[3540,15352,15342],{}," → Delete security group",[4702,15355,15356,15358,15359,9024,15361,15363],{},[3540,15357,12932],{}," → Roles → ",[3449,15360,12973],{},[3540,15362,15305],{}," (лише якщо ви більше не будете використовувати ECS)",[9854,15365,15366],{"label":9856},[3442,15367,15369],{"className":3444,"code":15368,"language":3446,"meta":3447,"style":3447},"REGION=\"eu-central-1\"\nSG_ID=\"sg-0a1b2c3d4e5f67890\"   # ← ваш Security Group ID\n\n# 1. Зупиніть Service (desired count → 0, потім видаліть)\naws ecs update-service --cluster ecs-lab-cluster --service ecs-lab-service --desired-count 0 --region $REGION\naws ecs delete-service --cluster ecs-lab-cluster --service ecs-lab-service --force --region $REGION\n\n# 2. Видаліть кластер\naws ecs delete-cluster --cluster ecs-lab-cluster --region $REGION\n\n# 3. Видаліть образи в ECR та репозиторій\naws ecr batch-delete-image --repository-name ecs-lab-api --image-ids imageTag=v1.0.0 imageTag=v1.1.0 --region $REGION\naws ecr delete-repository --repository-name ecs-lab-api --region $REGION\n\n# 4. Видаліть log group\naws logs delete-log-group --log-group-name \u002Fecs\u002Fecs-lab-api --region $REGION\n\n# 5. Видаліть Security Group\naws ec2 delete-security-group --group-id $SG_ID --region $REGION\n",[3449,15370,15371,15379,15390,15394,15399,15427,15451,15455,15460,15477,15481,15486,15513,15530,15534,15539,15557,15561,15566],{"__ignoreMap":3447},[3452,15372,15373,15375,15377],{"class":3454,"line":3455},[3452,15374,12521],{"class":3957},[3452,15376,8300],{"class":3961},[3452,15378,13309],{"class":3462},[3452,15380,15381,15383,15385,15387],{"class":3454,"line":3473},[3452,15382,13702],{"class":3957},[3452,15384,8300],{"class":3961},[3452,15386,14156],{"class":3462},[3452,15388,15389],{"class":3469},"   # ← ваш Security Group ID\n",[3452,15391,15392],{"class":3454,"line":3609},[3452,15393,3619],{"emptyLinePlaceholder":3618},[3452,15395,15396],{"class":3454,"line":3615},[3452,15397,15398],{"class":3469},"# 1. Зупиніть Service (desired count → 0, потім видаліть)\n",[3452,15400,15401,15403,15405,15407,15410,15412,15415,15417,15420,15423,15425],{"class":3454,"line":3622},[3452,15402,3459],{"class":3458},[3452,15404,6888],{"class":3462},[3452,15406,9875],{"class":3462},[3452,15408,15409],{"class":3953}," --cluster",[3452,15411,12838],{"class":3462},[3452,15413,15414],{"class":3953}," --service",[3452,15416,14188],{"class":3462},[3452,15418,15419],{"class":3953}," --desired-count",[3452,15421,15422],{"class":4152}," 0",[3452,15424,12586],{"class":3953},[3452,15426,13530],{"class":3957},[3452,15428,15429,15431,15433,15436,15438,15440,15442,15444,15447,15449],{"class":3454,"line":3628},[3452,15430,3459],{"class":3458},[3452,15432,6888],{"class":3462},[3452,15434,15435],{"class":3462}," delete-service",[3452,15437,15409],{"class":3953},[3452,15439,12838],{"class":3462},[3452,15441,15414],{"class":3953},[3452,15443,14188],{"class":3462},[3452,15445,15446],{"class":3953}," --force",[3452,15448,12586],{"class":3953},[3452,15450,13530],{"class":3957},[3452,15452,15453],{"class":3454,"line":3634},[3452,15454,3619],{"emptyLinePlaceholder":3618},[3452,15456,15457],{"class":3454,"line":3640},[3452,15458,15459],{"class":3469},"# 2. Видаліть кластер\n",[3452,15461,15462,15464,15466,15469,15471,15473,15475],{"class":3454,"line":3646},[3452,15463,3459],{"class":3458},[3452,15465,6888],{"class":3462},[3452,15467,15468],{"class":3462}," delete-cluster",[3452,15470,15409],{"class":3953},[3452,15472,12838],{"class":3462},[3452,15474,12586],{"class":3953},[3452,15476,13530],{"class":3957},[3452,15478,15479],{"class":3454,"line":3652},[3452,15480,3619],{"emptyLinePlaceholder":3618},[3452,15482,15483],{"class":3454,"line":3658},[3452,15484,15485],{"class":3469},"# 3. Видаліть образи в ECR та репозиторій\n",[3452,15487,15488,15490,15492,15495,15498,15500,15503,15506,15509,15511],{"class":3454,"line":3664},[3452,15489,3459],{"class":3458},[3452,15491,8980],{"class":3462},[3452,15493,15494],{"class":3462}," batch-delete-image",[3452,15496,15497],{"class":3953}," --repository-name",[3452,15499,12294],{"class":3462},[3452,15501,15502],{"class":3953}," --image-ids",[3452,15504,15505],{"class":3462}," imageTag=v1.0.0",[3452,15507,15508],{"class":3462}," imageTag=v1.1.0",[3452,15510,12586],{"class":3953},[3452,15512,13530],{"class":3957},[3452,15514,15515,15517,15519,15522,15524,15526,15528],{"class":3454,"line":3670},[3452,15516,3459],{"class":3458},[3452,15518,8980],{"class":3462},[3452,15520,15521],{"class":3462}," delete-repository",[3452,15523,15497],{"class":3953},[3452,15525,12294],{"class":3462},[3452,15527,12586],{"class":3953},[3452,15529,13530],{"class":3957},[3452,15531,15532],{"class":3454,"line":3676},[3452,15533,3619],{"emptyLinePlaceholder":3618},[3452,15535,15536],{"class":3454,"line":3682},[3452,15537,15538],{"class":3469},"# 4. Видаліть log group\n",[3452,15540,15541,15543,15545,15548,15551,15553,15555],{"class":3454,"line":3688},[3452,15542,3459],{"class":3458},[3452,15544,15152],{"class":3462},[3452,15546,15547],{"class":3462}," delete-log-group",[3452,15549,15550],{"class":3953}," --log-group-name",[3452,15552,15158],{"class":3462},[3452,15554,12586],{"class":3953},[3452,15556,13530],{"class":3957},[3452,15558,15559],{"class":3454,"line":3694},[3452,15560,3619],{"emptyLinePlaceholder":3618},[3452,15562,15563],{"class":3454,"line":3699},[3452,15564,15565],{"class":3469},"# 5. Видаліть Security Group\n",[3452,15567,15568,15570,15572,15575,15578,15580,15582],{"class":3454,"line":3705},[3452,15569,3459],{"class":3458},[3452,15571,13558],{"class":3462},[3452,15573,15574],{"class":3462}," delete-security-group",[3452,15576,15577],{"class":3953}," --group-id",[3452,15579,13811],{"class":3957},[3452,15581,12586],{"class":3953},[3452,15583,13530],{"class":3957},[3518,15585],{},[3354,15587,15588],{},[3527,15589],{"alt":15590,"className":15591,"src":15592},"Custom domain pp.ua connected to ALB with CNAME record DNS architecture",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F28.png",[3573,15594,15596],{"id":15595},"крок-14-бонус-підключення-безкоштовного-домену-ppua-до-alb","Крок 14 (бонус): Підключення безкоштовного домену pp.ua до ALB",[3354,15598,15599,15600,15603,15604,3516],{},"Ваш ECS Service доступний через ALB DNS name — щось схоже на ",[3449,15601,15602],{},"ecs-lab-alb-123456789.eu-central-1.elb.amazonaws.com",". Підключимо читабельний домен ",[3449,15605,15606],{},"pp.ua",[3354,15608,15609],{},[3540,15610,15611],{},"Загальна схема:",[3442,15613,15616],{"className":15614,"code":15615,"language":3856},[3854],"myecs.pp.ua\n    ↓ CNAME record (DNS)\necs-lab-alb-123456789.eu-central-1.elb.amazonaws.com\n    ↓ ALB (порт 80\u002F443)\nECS Fargate Task → .NET API (порт 8080)\n",[3449,15617,15615],{"__ignoreMap":3447},[3565,15619,15620,15621,15624,15625,15628],{},"На відміну від EC2 де ми використовували ",[3540,15622,15623],{},"A record"," (IP-адресу), тут ALB не має сталої IP — він використовує DNS name. Тому для ALB завжди використовують ",[3540,15626,15627],{},"CNAME record"," (псевдонім), що вказує на DNS name ALB.",[15630,15631,15633],"h4",{"id":15632},"крок-14a-отримання-dns-name-вашого-alb","Крок 14a: Отримання DNS name вашого ALB",[3442,15635,15637],{"className":3444,"code":15636,"language":3446,"meta":3447,"style":3447},"# Знайдіть DNS name ALB (якщо не записали раніше)\naws elbv2 describe-load-balancers \\\n    --names ecs-lab-alb \\\n    --query \"LoadBalancers[0].DNSName\" \\\n    --output text --region eu-central-1\n# Виведе: ecs-lab-alb-123456789.eu-central-1.elb.amazonaws.com\n",[3449,15638,15639,15644,15655,15665,15674,15684],{"__ignoreMap":3447},[3452,15640,15641],{"class":3454,"line":3455},[3452,15642,15643],{"class":3469},"# Знайдіть DNS name ALB (якщо не записали раніше)\n",[3452,15645,15646,15648,15650,15653],{"class":3454,"line":3473},[3452,15647,3459],{"class":3458},[3452,15649,7296],{"class":3462},[3452,15651,15652],{"class":3462}," describe-load-balancers",[3452,15654,5067],{"class":5066},[3452,15656,15657,15660,15663],{"class":3454,"line":3609},[3452,15658,15659],{"class":3953},"    --names",[3452,15661,15662],{"class":3462}," ecs-lab-alb",[3452,15664,5067],{"class":5066},[3452,15666,15667,15669,15672],{"class":3454,"line":3615},[3452,15668,7359],{"class":3953},[3452,15670,15671],{"class":3462}," \"LoadBalancers[0].DNSName\"",[3452,15673,5067],{"class":5066},[3452,15675,15676,15678,15680,15682],{"class":3454,"line":3622},[3452,15677,13587],{"class":3953},[3452,15679,7368],{"class":3462},[3452,15681,12586],{"class":3953},[3452,15683,6938],{"class":3462},[3452,15685,15686],{"class":3454,"line":3628},[3452,15687,15688],{"class":3469},"# Виведе: ecs-lab-alb-123456789.eu-central-1.elb.amazonaws.com\n",[15630,15690,15692],{"id":15691},"крок-14b-реєстрація-субдомену-на-ppua","Крок 14b: Реєстрація субдомену на pp.ua",[7751,15694,15695,15706],{},[4702,15696,15697,15698,15702,15703,12475],{},"Перейдіть на ",[3385,15699,15700],{"href":15700,"rel":15701},"https:\u002F\u002Fpp.ua",[3389]," та зареєструйте субдомен (наприклад ",[3449,15704,15705],{},"myecs.pp.ua",[4702,15707,15708],{},"Підтвердіть email і увійдіть у панель управління",[15630,15710,15712],{"id":15711},"крок-14c-додавання-cname-record-у-ppua","Крок 14c: Додавання CNAME record у pp.ua",[3354,15714,15715,15716,9024,15719,4878],{},"Панель pp.ua → ",[3540,15717,15718],{},"DNS Management",[3540,15720,15721],{},"Add Record",[3358,15723,15724,15734],{},[3361,15725,15726],{},[3364,15727,15728,15731],{},[3367,15729,15730],{},"Поле",[3367,15732,15733],{},"Значення",[3377,15735,15736,15746,15758,15772],{},[3364,15737,15738,15743],{},[3382,15739,15740],{},[3540,15741,15742],{},"Type",[3382,15744,15745],{},"CNAME",[3364,15747,15748,15753],{},[3382,15749,15750],{},[3540,15751,15752],{},"Name\u002FHost",[3382,15754,15755],{},[3449,15756,15757],{},"myecs",[3364,15759,15760,15765],{},[3382,15761,15762],{},[3540,15763,15764],{},"Value\u002FTarget",[3382,15766,15767,3893,15769],{},[3449,15768,15602],{},[13186,15770,15771],{},"(ваш ALB DNS)",[3364,15773,15774,15779],{},[3382,15775,15776],{},[3540,15777,15778],{},"TTL",[3382,15780,6812],{},[3354,15782,15783,3893,15786,15789,15790,15793,15794,15796,15797,15800,15801,15803],{},[3540,15784,15785],{},"Різниця A vs CNAME:",[3449,15787,15788],{},"A"," record вказує на IP-адресу (",[3449,15791,15792],{},"3.64.185.42","). ",[3449,15795,15745],{}," record вказує на інший DNS name (",[3449,15798,15799],{},"ecs-lab-alb-xxx.amazonaws.com",") — браузер потім сам вирішує IP цього name. CNAME не можна використовувати для кореневого домену (",[3449,15802,15606],{},"), лише для субдоменів.",[3354,15805,15806],{},"Зачекайте 1–10 хвилин і перевірте:",[3881,15808,15810,15819,15823,15830,15833,15842],{"title":15809},"Перевірка CNAME та HTTP запиту",[3885,15811,15813,3893,15816],{"className":15812},[3454],[3452,15814,3892],{"className":15815},[3891],[3540,15817,15818],{},"nslookup -type=CNAME myecs.pp.ua",[3885,15820,15822],{"className":15821},[3454],"Non-authoritative answer:",[3885,15824,15826],{"className":15825},[3454],[3452,15827,15829],{"className":15828},[3916],"myecs.pp.ua  canonical name = ecs-lab-alb-123456789.eu-central-1.elb.amazonaws.com.",[3885,15831],{"className":15832},[3454],[3885,15834,15836,3893,15839],{"className":15835},[3454],[3452,15837,3892],{"className":15838},[3891],[3540,15840,15841],{},"curl http:\u002F\u002Fmyecs.pp.ua\u002F",[3885,15843,15845],{"className":15844},[3454],"{\"message\":\"Hello from ECS Fargate!\",\"container\":\"abc123def456\",...}",[15630,15847,15849],{"id":15848},"крок-14d-https-через-acm-alb-опціонально","Крок 14d: HTTPS через ACM + ALB (опціонально)",[3354,15851,15852],{},"ALB підтримує ACM сертифікати — на відміну від EC2, де потрібен Certbot. Сертифікат ACM безкоштовний.",[6155,15854,15855,15856,15859,15860,15862,15863,15866],{},"ACM сертифікат для ALB (на відміну від CloudFront) створюється ",[3540,15857,15858],{},"у тому ж регіоні що й ALB"," — наприклад ",[3449,15861,6390],{},". Не ",[3449,15864,15865],{},"us-east-1","!",[3442,15868,15870],{"className":3444,"code":15869,"language":3446,"meta":3447,"style":3447},"# 1. Запросити сертифікат (eu-central-1, той самий регіон що ALB)\nCERT_ARN=$(aws acm request-certificate \\\n    --domain-name \"myecs.pp.ua\" \\\n    --validation-method DNS \\\n    --region eu-central-1 \\\n    --query CertificateArn --output text)\necho \"Certificate ARN: $CERT_ARN\"\n\n# 2. Отримати CNAME для DNS валідації\naws acm describe-certificate \\\n    --certificate-arn $CERT_ARN \\\n    --region eu-central-1 \\\n    --query \"Certificate.DomainValidationOptions[0].ResourceRecord\"\n# Виведе Name і Value для CNAME — додайте у pp.ua (Type: CNAME)\n",[3449,15871,15872,15877,15894,15904,15914,15922,15935,15947,15951,15956,15967,15977,15985,15992],{"__ignoreMap":3447},[3452,15873,15874],{"class":3454,"line":3455},[3452,15875,15876],{"class":3469},"# 1. Запросити сертифікат (eu-central-1, той самий регіон що ALB)\n",[3452,15878,15879,15882,15884,15886,15889,15892],{"class":3454,"line":3473},[3452,15880,15881],{"class":3957},"CERT_ARN",[3452,15883,7291],{"class":3961},[3452,15885,3459],{"class":3458},[3452,15887,15888],{"class":3462}," acm",[3452,15890,15891],{"class":3462}," request-certificate",[3452,15893,5067],{"class":5066},[3452,15895,15896,15899,15902],{"class":3454,"line":3609},[3452,15897,15898],{"class":3953},"    --domain-name",[3452,15900,15901],{"class":3462}," \"myecs.pp.ua\"",[3452,15903,5067],{"class":5066},[3452,15905,15906,15909,15912],{"class":3454,"line":3615},[3452,15907,15908],{"class":3953},"    --validation-method",[3452,15910,15911],{"class":3462}," DNS",[3452,15913,5067],{"class":5066},[3452,15915,15916,15918,15920],{"class":3454,"line":3622},[3452,15917,6935],{"class":3953},[3452,15919,7377],{"class":3462},[3452,15921,5067],{"class":5066},[3452,15923,15924,15926,15929,15931,15933],{"class":3454,"line":3628},[3452,15925,7359],{"class":3953},[3452,15927,15928],{"class":3462}," CertificateArn",[3452,15930,7365],{"class":3953},[3452,15932,7368],{"class":3462},[3452,15934,7380],{"class":3961},[3452,15936,15937,15939,15942,15945],{"class":3454,"line":3634},[3452,15938,7385],{"class":3458},[3452,15940,15941],{"class":3462}," \"Certificate ARN: ",[3452,15943,15944],{"class":3957},"$CERT_ARN",[3452,15946,7394],{"class":3462},[3452,15948,15949],{"class":3454,"line":3640},[3452,15950,3619],{"emptyLinePlaceholder":3618},[3452,15952,15953],{"class":3454,"line":3646},[3452,15954,15955],{"class":3469},"# 2. Отримати CNAME для DNS валідації\n",[3452,15957,15958,15960,15962,15965],{"class":3454,"line":3652},[3452,15959,3459],{"class":3458},[3452,15961,15888],{"class":3462},[3452,15963,15964],{"class":3462}," describe-certificate",[3452,15966,5067],{"class":5066},[3452,15968,15969,15972,15975],{"class":3454,"line":3658},[3452,15970,15971],{"class":3953},"    --certificate-arn",[3452,15973,15974],{"class":3957}," $CERT_ARN",[3452,15976,5067],{"class":5066},[3452,15978,15979,15981,15983],{"class":3454,"line":3664},[3452,15980,6935],{"class":3953},[3452,15982,7377],{"class":3462},[3452,15984,5067],{"class":5066},[3452,15986,15987,15989],{"class":3454,"line":3670},[3452,15988,7359],{"class":3953},[3452,15990,15991],{"class":3462}," \"Certificate.DomainValidationOptions[0].ResourceRecord\"\n",[3452,15993,15994],{"class":3454,"line":3676},[3452,15995,15996],{"class":3469},"# Виведе Name і Value для CNAME — додайте у pp.ua (Type: CNAME)\n",[3354,15998,15999,16000,3516],{},"Додайте у pp.ua другий CNAME для валідації ACM (Name і Value з попередньої команди). Дочекайтесь статусу ",[3449,16001,16002],{},"Issued",[3442,16004,16006],{"className":3444,"code":16005,"language":3446,"meta":3447,"style":3447},"# 3. Знайдіть ARN вашого ALB\nALB_ARN=$(aws elbv2 describe-load-balancers \\\n    --names ecs-lab-alb \\\n    --query \"LoadBalancers[0].LoadBalancerArn\" \\\n    --output text --region eu-central-1)\n\n# 3b. Знайдіть ARN Target Group (створеної при налаштуванні Service)\nTG_ARN=$(aws elbv2 describe-target-groups \\\n    --names ecs-lab-tg \\\n    --query \"TargetGroups[0].TargetGroupArn\" \\\n    --output text --region eu-central-1)\n\n# 4. Додати HTTPS Listener на ALB\naws elbv2 create-listener \\\n    --load-balancer-arn $ALB_ARN \\\n    --protocol HTTPS --port 443 \\\n    --certificates CertificateArn=$CERT_ARN \\\n    --default-actions Type=forward,TargetGroupArn=$TG_ARN \\\n    --region eu-central-1\n\n# 5. HTTP → HTTPS redirect (змінити HTTP listener)\nHTTP_LISTENER=$(aws elbv2 describe-listeners \\\n    --load-balancer-arn $ALB_ARN \\\n    --query \"Listeners[?Port==\\`80\\`].ListenerArn\" \\\n    --output text --region eu-central-1)\n\naws elbv2 modify-listener \\\n    --listener-arn $HTTP_LISTENER \\\n    --default-actions 'Type=redirect,RedirectConfig={Protocol=HTTPS,Port=443,StatusCode=HTTP_301}' \\\n    --region eu-central-1\n",[3449,16007,16008,16013,16027,16035,16043,16055,16059,16064,16079,16088,16096,16108,16112,16117,16127,16135,16149,16161,16171,16177,16181,16186,16202,16210,16229,16241,16245,16256,16266,16275],{"__ignoreMap":3447},[3452,16009,16010],{"class":3454,"line":3455},[3452,16011,16012],{"class":3469},"# 3. Знайдіть ARN вашого ALB\n",[3452,16014,16015,16017,16019,16021,16023,16025],{"class":3454,"line":3473},[3452,16016,7288],{"class":3957},[3452,16018,7291],{"class":3961},[3452,16020,3459],{"class":3458},[3452,16022,7296],{"class":3462},[3452,16024,15652],{"class":3462},[3452,16026,5067],{"class":5066},[3452,16028,16029,16031,16033],{"class":3454,"line":3609},[3452,16030,15659],{"class":3953},[3452,16032,15662],{"class":3462},[3452,16034,5067],{"class":5066},[3452,16036,16037,16039,16041],{"class":3454,"line":3615},[3452,16038,7359],{"class":3953},[3452,16040,7362],{"class":3462},[3452,16042,5067],{"class":5066},[3452,16044,16045,16047,16049,16051,16053],{"class":3454,"line":3622},[3452,16046,13587],{"class":3953},[3452,16048,7368],{"class":3462},[3452,16050,12586],{"class":3953},[3452,16052,7377],{"class":3462},[3452,16054,7380],{"class":3961},[3452,16056,16057],{"class":3454,"line":3628},[3452,16058,3619],{"emptyLinePlaceholder":3618},[3452,16060,16061],{"class":3454,"line":3634},[3452,16062,16063],{"class":3469},"# 3b. Знайдіть ARN Target Group (створеної при налаштуванні Service)\n",[3452,16065,16066,16068,16070,16072,16074,16077],{"class":3454,"line":3640},[3452,16067,7408],{"class":3957},[3452,16069,7291],{"class":3961},[3452,16071,3459],{"class":3458},[3452,16073,7296],{"class":3462},[3452,16075,16076],{"class":3462}," describe-target-groups",[3452,16078,5067],{"class":5066},[3452,16080,16081,16083,16086],{"class":3454,"line":3646},[3452,16082,15659],{"class":3953},[3452,16084,16085],{"class":3462}," ecs-lab-tg",[3452,16087,5067],{"class":5066},[3452,16089,16090,16092,16094],{"class":3454,"line":3652},[3452,16091,7359],{"class":3953},[3452,16093,7514],{"class":3462},[3452,16095,5067],{"class":5066},[3452,16097,16098,16100,16102,16104,16106],{"class":3454,"line":3658},[3452,16099,13587],{"class":3953},[3452,16101,7368],{"class":3462},[3452,16103,12586],{"class":3953},[3452,16105,7377],{"class":3462},[3452,16107,7380],{"class":3961},[3452,16109,16110],{"class":3454,"line":3664},[3452,16111,3619],{"emptyLinePlaceholder":3618},[3452,16113,16114],{"class":3454,"line":3670},[3452,16115,16116],{"class":3469},"# 4. Додати HTTPS Listener на ALB\n",[3452,16118,16119,16121,16123,16125],{"class":3454,"line":3676},[3452,16120,3459],{"class":3458},[3452,16122,7296],{"class":3462},[3452,16124,7558],{"class":3462},[3452,16126,5067],{"class":5066},[3452,16128,16129,16131,16133],{"class":3454,"line":3682},[3452,16130,7565],{"class":3953},[3452,16132,7568],{"class":3957},[3452,16134,5067],{"class":5066},[3452,16136,16137,16139,16142,16144,16147],{"class":3454,"line":3688},[3452,16138,7433],{"class":3953},[3452,16140,16141],{"class":3462}," HTTPS",[3452,16143,7579],{"class":3953},[3452,16145,16146],{"class":4152}," 443",[3452,16148,5067],{"class":5066},[3452,16150,16151,16154,16157,16159],{"class":3454,"line":3694},[3452,16152,16153],{"class":3953},"    --certificates",[3452,16155,16156],{"class":3462}," CertificateArn=",[3452,16158,15944],{"class":3957},[3452,16160,5067],{"class":5066},[3452,16162,16163,16165,16167,16169],{"class":3454,"line":3699},[3452,16164,7589],{"class":3953},[3452,16166,7592],{"class":3462},[3452,16168,7538],{"class":3957},[3452,16170,5067],{"class":5066},[3452,16172,16173,16175],{"class":3454,"line":3705},[3452,16174,6935],{"class":3953},[3452,16176,6938],{"class":3462},[3452,16178,16179],{"class":3454,"line":3711},[3452,16180,3619],{"emptyLinePlaceholder":3618},[3452,16182,16183],{"class":3454,"line":3717},[3452,16184,16185],{"class":3469},"# 5. HTTP → HTTPS redirect (змінити HTTP listener)\n",[3452,16187,16188,16191,16193,16195,16197,16200],{"class":3454,"line":3723},[3452,16189,16190],{"class":3957},"HTTP_LISTENER",[3452,16192,7291],{"class":3961},[3452,16194,3459],{"class":3458},[3452,16196,7296],{"class":3462},[3452,16198,16199],{"class":3462}," describe-listeners",[3452,16201,5067],{"class":5066},[3452,16203,16204,16206,16208],{"class":3454,"line":3729},[3452,16205,7565],{"class":3953},[3452,16207,7568],{"class":3957},[3452,16209,5067],{"class":5066},[3452,16211,16212,16214,16217,16219,16222,16224,16227],{"class":3454,"line":3734},[3452,16213,7359],{"class":3953},[3452,16215,16216],{"class":3462}," \"Listeners[?Port==",[3452,16218,14454],{"class":5066},[3452,16220,16221],{"class":3462},"80",[3452,16223,14454],{"class":5066},[3452,16225,16226],{"class":3462},"].ListenerArn\"",[3452,16228,5067],{"class":5066},[3452,16230,16231,16233,16235,16237,16239],{"class":3454,"line":3740},[3452,16232,13587],{"class":3953},[3452,16234,7368],{"class":3462},[3452,16236,12586],{"class":3953},[3452,16238,7377],{"class":3462},[3452,16240,7380],{"class":3961},[3452,16242,16243],{"class":3454,"line":3746},[3452,16244,3619],{"emptyLinePlaceholder":3618},[3452,16246,16247,16249,16251,16254],{"class":3454,"line":3752},[3452,16248,3459],{"class":3458},[3452,16250,7296],{"class":3462},[3452,16252,16253],{"class":3462}," modify-listener",[3452,16255,5067],{"class":5066},[3452,16257,16258,16261,16264],{"class":3454,"line":3758},[3452,16259,16260],{"class":3953},"    --listener-arn",[3452,16262,16263],{"class":3957}," $HTTP_LISTENER",[3452,16265,5067],{"class":5066},[3452,16267,16268,16270,16273],{"class":3454,"line":3764},[3452,16269,7589],{"class":3953},[3452,16271,16272],{"class":3462}," 'Type=redirect,RedirectConfig={Protocol=HTTPS,Port=443,StatusCode=HTTP_301}'",[3452,16274,5067],{"class":5066},[3452,16276,16277,16279],{"class":3454,"line":3769},[3452,16278,6935],{"class":3953},[3452,16280,6938],{"class":3462},[3354,16282,16283,16284,16287],{},"Тепер ",[3449,16285,16286],{},"https:\u002F\u002Fmyecs.pp.ua"," — ваш ECS Fargate .NET API з офіційним SSL сертифікатом!",[3518,16289],{},[3354,16291,16292],{},[3527,16293],{"alt":16294,"className":16295,"src":16296},"Docker and ECS on AWS summary mindmap key concepts",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F29.jpeg",[3349,16298,16300],{"id":16299},"резюме","Резюме",[4699,16302,16303,16308,16314,16320,16325,16331,16336,16342],{},[4702,16304,16305,16307],{},[3540,16306,2822],{}," вирішує проблему «works on my machine»: застосунок пакується разом із середовищем у незмінний образ.",[4702,16309,16310,16313],{},[3540,16311,16312],{},"Multi-stage Dockerfile",": build stage (~800 MB SDK) → runtime stage (~200 MB). Вихідний код не потрапляє у фінальний образ.",[4702,16315,16316,16319],{},[3540,16317,16318],{},"Amazon ECR"," — приватний реєстр образів, інтегрований з IAM. Автоматичне сканування вразливостей при push.",[4702,16321,16322,16324],{},[3540,16323,12766],{},": Task Definition (шаблон) → Task (запущений контейнер) → Service (підтримує N Tasks, rolling updates).",[4702,16326,16327,16330],{},[3540,16328,16329],{},"Fargate"," — serverless запуск контейнерів без управління EC2. Оплата за vCPU\u002FRAM × час роботи Task.",[4702,16332,16333,16335],{},[3540,16334,6358],{}," — кожен Task отримує власний ENI та IP. Security Groups на рівні Task.",[4702,16337,16338,16341],{},[3540,16339,16340],{},"Rolling updates"," — нові Tasks запускаються паралельно зі старими, трафік переключається поступово.",[4702,16343,16344,16346,16347,16349,16350,16352],{},[3540,16345,13225],{}," у Task Definition: ",[3449,16348,6004],{}," для конфігурації, ",[3449,16351,6000],{}," для паролів зі Secrets Manager.",[3518,16354],{},[3354,16356,16357],{},[3527,16358],{"alt":16359,"className":16360,"src":16361},"ECS Fargate practical tasks and lab exercises for .NET developers",[3531],"\u002Fimages\u002Faws\u002Fdocker-ecs\u002F30.png",[3349,16363,16365],{"id":16364},"практичні-завдання","Практичні завдання",[3573,16367,16369],{"id":16368},"рівень-1-базовий","Рівень 1 (Базовий)",[3354,16371,16372,16375],{},[3540,16373,16374],{},"Завдання 1."," Поясніть різницю між Docker image та Docker container. Що таке multi-stage Dockerfile і яку проблему він вирішує для .NET?",[3354,16377,16378,16381],{},[3540,16379,16380],{},"Завдання 2."," У чому принципова відмінність між Fargate та EC2 launch type? Для якого сценарію ви б обрали кожен?",[3354,16383,16384,16387,16388,3491,16390,3491,16392,16394,16395,16397],{},[3540,16385,16386],{},"Завдання 3."," Поясніть, що відбувається під час кожного з станів Task: ",[3449,16389,5224],{},[3449,16391,5234],{},[3449,16393,5244],{},". Чому Task може застрягти у стані ",[3449,16396,5234],{}," і як це діагностувати?",[3573,16399,16401],{"id":16400},"рівень-2-практичний","Рівень 2 (Практичний)",[3354,16403,16404,16407,16408,16410,16411,16414,16415,16417],{},[3540,16405,16406],{},"Завдання 4."," Напишіть ",[3449,16409,11854],{}," для ASP.NET Core 8, який використовує multi-stage build, запускається як non-root user (",[3449,16412,16413],{},"USER app"," перед ",[3449,16416,4682],{},") і налаштований для production (Release конфігурація).",[3354,16419,16420,16423,16424,16426,16427,16430,16431,3516],{},[3540,16421,16422],{},"Завдання 5."," Напишіть повний Task Definition JSON для ECS Fargate де: .NET API слухає порт 8080, ",[3449,16425,10050],{},", connection string PostgreSQL отримується з Secrets Manager, логи пишуться у CloudWatch ",[3449,16428,16429],{},"\u002Fecs\u002Fmy-api",", health check кожні 30 секунд за ",[3449,16432,16433],{},"\u002Fhealth",[3354,16435,16436,16439],{},[3540,16437,16438],{},"Завдання 6."," Сервіс отримує всплески після ролінгу оновлення до нової версії. Що змінити в Service, щоб деплой завжди зупинявся при 10+ послідовних помилкових health check? Які два параметри деплою відповідають за мінімальну кількість здорових Tasks під час оновлення?",[3573,16441,16443],{"id":16442},"рівень-3-архітектура","Рівень 3 (Архітектура)",[3354,16445,16446,16449,16450,16452,16453,16452,16455,16458,16459,16461,16462,16464,16465,16467],{},[3540,16447,16448],{},"Завдання 7."," Спроектуйте ECS-архітектуру для трьох мікросервісів: ",[3449,16451,10433],{}," (.NET), ",[3449,16454,10429],{},[3449,16456,16457],{},"NotificationService"," (background worker). Вимоги: усі у приватних підмережах, зовнішній трафік лише через ALB, ",[3449,16460,10433],{},"\u002F",[3449,16463,10429],{}," масштабуються за CPU (60%), ",[3449,16466,16457],{}," — за кількістю повідомлень у SQS. Паролі в Secrets Manager. Намалюйте PlantUML схему.",[3354,16469,16470,16473,16474,16477],{},[3540,16471,16472],{},"Завдання 8."," Ваш ",[3449,16475,16476],{},".NET"," API пише цитабельні дані безпосередньо у файл (appsettings.Production.json), який потрапляє в Docker image. Опишіть послідовність дій для перенесення секретів у Secrets Manager (які AWS пермішення потрібні, які зміни в Task Definition, які зміни в коді .NET для зчитування з перемінних середовища).",[16479,16480,16481],"style",{},"html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}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 .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 .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}html pre.shiki code .sLwNe, html code.shiki .sLwNe{--shiki-light:#0451A5;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}",{"title":3447,"searchDepth":3473,"depth":3473,"links":16483},[16484,16485,16488,16496,16502,16506,16515,16519,16523,16524,16528,16532,16539,16547,16563,16564],{"id":3351,"depth":3473,"text":3352},{"id":3522,"depth":3473,"text":3523,"children":16486},[16487],{"id":3575,"depth":3609,"text":3576},{"id":3796,"depth":3473,"text":3797,"children":16489},[16490,16491,16492,16493,16494,16495],{"id":3814,"depth":3609,"text":3815},{"id":3842,"depth":3609,"text":3843},{"id":3870,"depth":3609,"text":3871},{"id":4408,"depth":3609,"text":4409},{"id":4723,"depth":3609,"text":4724},{"id":4853,"depth":3609,"text":4854},{"id":5124,"depth":3473,"text":5125,"children":16497},[16498,16499,16500,16501],{"id":5164,"depth":3609,"text":5165},{"id":5195,"depth":3609,"text":5196},{"id":5507,"depth":3609,"text":5508},{"id":6016,"depth":3609,"text":6017},{"id":6193,"depth":3473,"text":6194,"children":16503},[16504,16505],{"id":6211,"depth":3609,"text":6212},{"id":6248,"depth":3609,"text":6249},{"id":6344,"depth":3473,"text":6345,"children":16507},[16508,16509,16510,16511,16512,16513,16514],{"id":6366,"depth":3609,"text":6367},{"id":6407,"depth":3609,"text":6408},{"id":6582,"depth":3609,"text":6583},{"id":6615,"depth":3609,"text":6616},{"id":6657,"depth":3609,"text":6658},{"id":6689,"depth":3609,"text":6690},{"id":6711,"depth":3609,"text":6712},{"id":6726,"depth":3473,"text":6727,"children":16516},[16517,16518],{"id":6751,"depth":3609,"text":6752},{"id":7070,"depth":3609,"text":7071},{"id":7226,"depth":3473,"text":7227,"children":16520},[16521,16522],{"id":7243,"depth":3609,"text":7244},{"id":7272,"depth":3609,"text":7273},{"id":7709,"depth":3473,"text":7710},{"id":7794,"depth":3473,"text":7795,"children":16525},[16526,16527],{"id":7946,"depth":3609,"text":7947},{"id":8030,"depth":3609,"text":8031},{"id":8183,"depth":3473,"text":8184,"children":16529},[16530,16531],{"id":8187,"depth":3609,"text":8188},{"id":8337,"depth":3609,"text":8338},{"id":8588,"depth":3473,"text":8589,"children":16533},[16534,16535,16536,16537,16538],{"id":8711,"depth":3609,"text":8712},{"id":9055,"depth":3609,"text":9056},{"id":9263,"depth":3609,"text":9264},{"id":9359,"depth":3609,"text":9360},{"id":9535,"depth":3609,"text":9536},{"id":9604,"depth":3473,"text":9605,"children":16540},[16541,16542,16543,16544,16545,16546],{"id":9714,"depth":3609,"text":9715},{"id":10183,"depth":3609,"text":10184},{"id":10414,"depth":3609,"text":10415},{"id":10676,"depth":3609,"text":10677},{"id":11220,"depth":3609,"text":11221},{"id":11439,"depth":3609,"text":11440},{"id":11526,"depth":3473,"text":11527,"children":16548},[16549,16550,16551,16552,16553,16554,16555,16556,16557,16558,16559,16560,16561,16562],{"id":11533,"depth":3609,"text":11534},{"id":11847,"depth":3609,"text":11848},{"id":12222,"depth":3609,"text":12223},{"id":12478,"depth":3609,"text":12479},{"id":12754,"depth":3609,"text":12755},{"id":12917,"depth":3609,"text":12918},{"id":13111,"depth":3609,"text":13112},{"id":13533,"depth":3609,"text":13534},{"id":13999,"depth":3609,"text":14000},{"id":14305,"depth":3609,"text":14306},{"id":14588,"depth":3609,"text":14589},{"id":15108,"depth":3609,"text":15109},{"id":15269,"depth":3609,"text":15270},{"id":15595,"depth":3609,"text":15596},{"id":16299,"depth":3473,"text":16300},{"id":16364,"depth":3473,"text":16365,"children":16565},[16566,16567,16568],{"id":16368,"depth":3609,"text":16369},{"id":16400,"depth":3609,"text":16401},{"id":16442,"depth":3609,"text":16443},"Від локального Dockerfile до повноцінного задеплоєного .NET Web API на AWS ECS Fargate. Розбираємо ECR, ECS Task Definitions, Clusters, Services, Auto Scaling та порівнюємо ECS, Fargate і EKS.","md",null,{},{"title":3226,"description":16569},"1J5o6nwdfM3PPHys2svTo5tXf5m4iMLVlTWtixWPy0Q",[16576,16578],{"title":3222,"path":3223,"stem":3224,"description":16577,"children":-1},"Повний довідник AWS CLI команд для IAM — Users, Groups, Roles, Policies, MFA, STS. Усі важливі команди з прикладами та очікуваним виводом.",{"title":3230,"path":3231,"stem":3232,"description":16579,"children":-1},"Повний довідник AWS CLI команд для ECR та ECS — аутентифікація, репозиторії, кластери, сервіси, мережа, балансувальник, автомасштабування, логи. Усі важливі команди з прикладами та очікуваним виводом.",1782371303754]