Урок 08 · CI / K8s

GitLab CI и мост к Kubernetes

Прочитайте CI job как набор containers, перенесите Docker-модель на Pod/Service и проведите итоговый triage неисправного запуска.

Время: 25 минутРезультат: CI-модельИнтервью: mock round

Прочитайте job до объяснения

Какие containers появятся, как test runner найдёт frontend и где останется trace после падения?

e2e:
  image: mcr.microsoft.com/playwright:v1.61.0-noble
  services:
    - name: registry.example/wms/frontend:$CI_COMMIT_SHA
      alias: frontend
    - name: postgres:17-alpine
      alias: db
  variables:
    POSTGRES_DB: wms
    POSTGRES_USER: wms
    POSTGRES_PASSWORD: local-ci-only
    BASE_URL: http://frontend:8080
  script:
    - npm ci
    - npx playwright test
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/

Docker-модель внутри GitLab CI

КонструкцияРоль
imageExecution environment job: здесь выполняются before_script, script и after_script.
servicesСоседние service containers, доступные job по alias/DNS согласно executor.
variablesRuntime configuration. Чувствительные значения должны приходить из protected/masked CI variables.
artifacts: when: alwaysСобирает диагностику из job workspace даже при failed tests.

Job не обязан запускать Docker CLI. Если runner уже создаёт job и service containers, тесты могут обращаться к dependencies напрямую. Docker daemon/DinD нужен только для операций вроде build/run внутри job и добавляет отдельную security и caching модель.

Версии PlaywrightJob image и @playwright/test должны совпадать, как в локальном Dockerfile. CI не отменяет этот контракт.

Что меняется в Kubernetes

Docker даёт переносимый image и базовую container-модель. Kubernetes управляет размещением, рестартами, rollout и сетевой доступностью containerized workloads.

Знакомое понятиеБлижайшая Kubernetes-модель
Image в registryТот же image указан в Pod template; tag/digest определяет версию.
ContainerContainer запускается внутри Pod; containers одного Pod делят network namespace.
Compose serviceЧасто раскладывается на Deployment/StatefulSet и Kubernetes Service, но соответствие не один-к-одному.
HealthcheckReadiness решает, получает ли Pod traffic; liveness — нужен ли restart; startup защищает медленный старт.
Named volumePersistentVolumeClaim запрашивает storage с lifecycle, заданным кластером.
Service DNSKubernetes Service даёт стабильное имя и маршрутизацию к ready Pods.
Не говорите «Kubernetes запускает Docker containers»Kubernetes работает через CRI-compatible container runtime и использует OCI images. Docker Engine не является обязательным runtime кластера.

Итоговый incident

Дано: frontend и DB отмечены healthy, Playwright job сразу получает ECONNREFUSED 127.0.0.1:8080, screenshots не появились. Назовите две независимые проблемы до раскрытия.

Показать разбор
  1. В job container 127.0.0.1 указывает на сам job. Target service нужно открывать по alias и container port, например http://frontend:8080.
  2. Screenshots/trace сохранятся как artifacts, только если reporter пишет в объявленные paths внутри job workspace и artifacts.when позволяет сбор при failure.
  3. Health frontend не доказывает корректность URL test runner: readiness target и network address клиента — разные контракты.

Mock interview: восемь вопросов

1. Чем image отличается от container?

Image — неизменяемый слоёный пакет; container — runtime-экземпляр с конфигурацией, network и writable layer. Один image создаёт много containers.

2. Почему container завершился сразу?

Его основной process завершился. Проверяю ps -a, exit code/OOM через inspect и stdout/stderr через logs.

3. Как ускорить npm build?

Сначала копировать lock/manifests и выполнять npm ci, затем копировать часто меняющийся source; уменьшить context через .dockerignore.

4. Почему Playwright падает только в Docker?

Сверяю package/image versions, shared memory и limits, PID 1/init, network namespace, user/permissions и mounted artifacts.

5. Почему localhost не видит frontend?

Loopback принадлежит текущему container. Для соседнего service использую его DNS alias и внутренний port.

6. Volume или bind mount?

Volume для Docker-managed persistent service data; bind для host-owned source/workspace/artifacts; tmpfs для временных данных в памяти.

7. Почему depends_on недостаточно?

Порядок start не означает readiness. Нужен meaningful healthcheck и condition service_healthy либо ожидание в orchestration/CI.

8. Как Docker связан с Kubernetes?

Мы собираем OCI image и определяем container runtime contract. Kubernetes оркестрирует Pods, rollout, service discovery, probes и persistent storage через CRI runtime.

Проверка понимания

1. Что задаёт GitLab CI image?

2. Что делает readiness probe?

3. Зачем artifacts: when: always?

Финальный ответ

«В AQA я использую Docker как воспроизводимый runtime contract: pin-ю image, отделяю build от start, поднимаю dependencies в изолированной сети, проверяю readiness, а test runner запускаю одноразово и сохраняю artifacts вне container. При сбое иду от status/exit/logs к фактическим network, mounts и config. В GitLab CI job image и services реализуют ту же модель; Kubernetes расширяет её orchestration, probes и service discovery».

Произнесите ответ без текста и попросите преподавателя провести устный follow-up по двум самым слабым пунктам.

Первичные источники