Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Поясніть концепцію immutable infrastructure з Docker.». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Immutable infrastructure** = як сервер (або container) deployed, він **ніколи не модифікується**. Зміни відбуваються через **заміну** усього instance на нову версію, не patching existing. З Docker це default-модель: - **Image** одиниця deploy. - Нова версія значить **новий image-tag** + redeploy. Container'и зупиняються і заміщуються, не patching. - Без SSH-in для fix config; без `apt-get upgrade` на running-container. - State (DB, file) живе **поза** container у volume або external-сервісах. ```bash # Старий спосіб (mutable): SSH і tweak ssh prod "sudo systemctl restart api && vi /etc/api/config.yaml" # Новий спосіб (immutable): build новий image, redeploy docker build -t myorg/api:1.1 . docker push myorg/api:1.1 kubectl set image deployment/api api=myorg/api:1.1 # або compose pull && up -d ``` **Виграші:** reproducibility, легкий rollback (deploy старий tag), без config-drift. **Ціна:** state має бути external.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Immutable infrastructure** це deployment-філософія: як runtime-instance deployed, він **ніколи не модифікується in place**. Update, patch і config-зміни відбуваються через **build нового artifact** (новий image, нова VM, новий container) і заміну старого. Docker enforce'ить це natural'но, бо image read-only, а container'и дешеві для recreate. Результат: reproducible, predictable-infrastructure. ## Теорія ### TL;DR - **Mutable:** patch running-server in place (SSH, `apt upgrade`, edit-config). State кожного сервера розходиться з часом. «Snowflake-server». - **Immutable:** build новий artifact (image), deploy, retire старий. Кожен instance identical. «Phoenix-server». - Docker робить immutable легким: image = artifact, container = instance, redeploy = stop+start. - **State має бути external**: DB на managed-сервісі або persistent-volume, file у object-storage, session у Redis. Сам container disposable. - Rollback це просто «deploy попередній tag». - Натурально комбінується з **blue-green**, **canary**, **rolling-update**. ### Mental shift **Mutable mindset:** - «Сервер `prod-1` крутиться 3 роки. Ми застосували 47 patch». - Config живе на disk; всі мають SSH-access; з часом, ні два сервера не identical. - Нова версія = SSH-in, run installer, restart service. - Drift між staging і production constant fight. **Immutable mindset:** - «Цей release це image-tag `1.7.3`. Кожен running-container з того самого digest». - Config приходять з env-var або mounted-файлів на start-time. - Нова версія = новий image, новий container, той самий image крутиться в dev/staging/prod. - Drift impossible, бо нічого не модифікує running-instance. ### Що йде поза container Щоб immutable працював, все, що потребує **change at runtime** має жити поза: | Concern | Де живе | |---|---| | Application-binary, lib, runtime | Всередині image (immutable). | | Static-config, що варіюються by env | Env-var або mounted-file. | | Secrets | Mounted з secret-manager (Vault, AWS Secrets Manager, Docker Secrets). | | User-data, DB-state | External DB / managed-service / persistent-volume. | | Uploaded-file | Object-storage (S3) або shared-volume. | | Logі | Streaming у log-aggregator (Loki, ELK, CloudWatch). | | Session | Redis, JWT або signed-cookie, ніколи in-memory, прив'язаний до single-container. | Якщо щось з цього на writable-layer container, immutable зламано: заміна container втрачає дані. ### Чому immutable виграє 1. **Reproducibility.** Даний image-tag, run де завгодно, behave однаково. Dev = staging = prod. 2. **Легкий rollback.** «Deploy `1.7.2` знову». Одна команда. Без restoration system-state. 3. **Без config-drift.** Кожен container того ж tag bit-identical. 4. **Auditability.** Що крутиться? `docker inspect` показує image-digest. Trace до git-SHA через build-label. 5. **Forces good hygiene.** Не можеш SSH і «just fix it», pushing назад у image-build-process виробляє permanent-fix. 6. **Pair з deployment-патернами.** Blue-green, canary, rolling, всі припускають identical-replica, які можна swap. ### Trade-off - **Ціна externalization-state.** Setup Postgres, Redis, S3 тощо більше upfront-work, ніж slap data на local-disk. - **Build-pipeline має бути solid.** Якщо твій CI flaky, кожна зміна коштує. - **Image-size.** 2 GB-image OK у mutable-land, але сповільнює immutable-redeploy. Оптимізуй image-size агресивно. - **Cold-start-ціна.** Новий container starts cold; warm-cache gone. Мітигуй через startup-warmup або readiness-probe. ## Приклади ### Mutable vs Immutable: та сама зміна Фікс: підняти max-body-size API з 1 MB до 5 MB. **Mutable workflow:** ```bash ssh prod-1 "sudo vi /etc/api/config.yaml" # (edit max_body_size: 5MB) ssh prod-1 "sudo systemctl restart api" # Повторити на prod-2, prod-3... # Забув prod-4. Тепер prod-4 має 1 MB-limit. Drift. ``` **Immutable workflow:** ```bash # Edit config у repo git checkout -b bump-body-size vi config/api.yaml # max_body_size: 5MB git commit -am "Bump body size" && git push # CI build'ить image myorg/api:1.7.4 # Deploy: kubectl set image deployment/api api=myorg/api:1.7.4 # Або: docker compose pull && docker compose up -d # Кожен container підбирає новий image. Drift impossible. ``` ### Externalization state Добре: ```yaml # docker-compose.yaml services: app: image: myorg/app:1.0 environment: DATABASE_URL: ${DATABASE_URL} REDIS_URL: ${REDIS_URL} S3_BUCKET: my-uploads # Нота: без «db»-сервісу. DB це RDS/Cloud SQL/тощо. ``` Погано (state всередині container): ```yaml services: app: image: myorg/app:1.0 # Якщо втратимо цей container, втратимо дані! ``` ### Immutable + blue-green ```bash # Image v1 крутиться docker run -d --name app-blue myorg/app:1.0 # Build і push v2 docker build -t myorg/app:2.0 . docker push myorg/app:2.0 # Підняти green з нового image docker run -d --name app-green myorg/app:2.0 # Traffic flip через load-balancer # Підтверди, що v2 healthy # Прибери blue docker stop app-blue && docker rm app-blue ``` Blue і green обидва immutable: blue крутить `1.0`, green крутить `2.0`, ні один не мутується mid-flight. ### Immutable + canary ```bash # 9 копій v1, 1 копія v2, load-balancer шле 10% на v2 # Дивись метрики. Якщо хороше, поступово заміни більше v1 на v2. ``` Кожна копія immutable; rollout це серія замін, не in-place upgrade. ### Immutable + rolling-update (Swarm) ```bash docker service update --image myorg/app:2.0 myapp # Swarm заміняє task one at a time, кожен task свіжий container з нового image. ``` ### Pinning by digest для true immutability ```yaml image: myorg/app@sha256:abc123def456... ``` Tag типу `myorg/app:1.0` може бути re-pushed (хтось міг overwrite). Digest не може. Для максимальної reproducibility (і security), pin by digest у production. ```bash # Знайди digest після push docker inspect myorg/app:1.0 --format='{{.Id}}' # sha256:abc... ``` Build-system може lock digest у deploy-manifest: ```yaml image: myorg/app:1.0@sha256:abc123... ``` ## Реальне застосування - **Microservice на Kubernetes**: кожен Pod це container з конкретного image; без kubectl exec для fix bug у prod. - **Serverless / containers-as-a-service** (Cloud Run, Fargate): platform enforce'ить immutability, не можеш SSH-in. - **Compose-managed dev-environment**: redeploy на кожну зміну; container throwaway. - **CI build-agent**: кожен job крутиться у fresh-container. - **Hardened production-environment**: container-image підписані і scanned, deployed через GitOps (Argo CD, Flux). Уся pipeline immutable end-to-end. ### Anti-patterns to avoid **SSH-in у running-container, щоб fix щось** ```bash docker exec -it api bash # vi /etc/api/config.yaml ← ПОГАНО ``` Fix живе до restart container, потім gone. Гірше, відрізняється від твого image. Push fix у repo, rebuild, redeploy. **Зберігати дані у writable-layer container** Коли container заміщений, ці дані gone. Завжди бери volume або external-сервіси. **Re-use того ж tag для нових build** ```bash docker build -t myorg/app:latest . docker push myorg/app:latest # Тепер що це «:latest»? Вчорашній? Сьогоднішній? ``` Бери meaningful-tag (semver, git-SHA, timestamp). Резервуй `latest` для dev-зручності; ніколи не deploy з `latest` у prod. **Treating host як immutable, а container як mutable** Якщо `docker exec` у container, щоб patch'ити, ти небагато виграв. Весь стек має слідувати дисципліні. ### Типові помилки **Забувати, що volume ламає модель** Volume *це* mutable-state. Це OK, це externalized-data. Але розумій: коли redeploy, новий container reuse той самий volume. Якщо deploy-migration corrupt'ить дані, наступний deploy inherit corruption. Treat volume (і DB-schema) обережно. **Config запечений у image** ```dockerfile COPY config/prod.yaml /etc/api/config.yaml ``` Тепер той самий image не portable через environment. Mount або env-inject config на run-time. **Long-lived container з hot-reload** Якщо твій dev-workflow це `docker exec api npm run reload`, ти зробив container mutable. Для dev це OK. Для prod, ніколи. ### Питання для поглиблення **Q:** Чи immutable infrastructure досяжна лише з container? **A:** Ні. AMI, Packer-built-image, terraform-recreated-сервери всі enable. Container'и роблять дешевше, бо rebuild + redeploy швидкий. **Q:** Що з secret, що змінюються без redeploy? **A:** Mount їх з secret-manager (Vault, AWS, GCP). Container читає на startup або refresh периодично. Сам image без secret. **Q:** Чи immutable значить, що я не можу restart container? **A:** Restart OK, не модифікує image, лише re-run. «Immutable» referring до image і on-disk filesystem running-container, не його lifecycle. **Q:** (Senior) Як reason'ити про довгий in-memory-state (cache-warmup, leader-election) під immutable? **A:** Дві стратегії. (1) Make state externally-durable: leader-election через shared-сервіс (etcd, ZooKeeper); cache backed Redis. (2) Embrace cold-start: кожен новий container warmup from cold. Combine з rolling-deploy, щоб traffic shift поступово, без thundering-herd. Реальні системи беруть обидва: warm-cache коли важливо, externalize коли correctness залежить. **Q:** (Senior) Як immutable infrastructure взаємодіє з regulated-environment (PCI, HIPAA)? **A:** Прекрасно. Аудитори обожнюють. Кожна running-version мапиться назад до signed-image (cosign/Notary), який мапиться до CI-build, який мапиться до git-commit. Provenance end-to-end. Patching це code-change з PR, review і CI-artifact, не хтось SSH-in у prod і edit config. Більшість compliance-framework тепер явно favor immutable + GitOps як сильніший control-surface за mutable patch-management.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.