Скрипт развертывания приложения в Kubernetes: структура и рабочий пример | AdminWiki

Скрипт развертывания приложения в Kubernetes: структура и рабочий пример

06 сентября 2026 18 мин. чтения
Содержание статьи

Скрипт развертывания приложения в Kubernetes должен принимать параметры среды, собирать Docker-образ, присваивать ему неизменяемый тег, отправлять образ в Container Registry, подготавливать манифесты и выполнять kubectl apply. После этого сценарий обязан дождаться kubectl rollout status и проверить готовность Pod, Service и Ingress, если приложение опубликовано наружу.

Рабочая схема выглядит так: коммит проходит тесты, CI job собирает образ, registry хранит конкретную версию, deploy job выбирает namespace и IMAGE_TAG, Kubernetes создает или обновляет Deployment, ReplicaSet и Pod, а Service направляет трафик по labels. Стратегия RollingUpdate постепенно заменяет Pod, readiness probe не отправляет запросы в неготовый контейнер, liveness probe перезапускает зависший экземпляр.

Сборку запускайте на рабочей машине или CI-сервере. Production-сервер должен получать готовый образ из registry и применять манифесты. Такой подход превращает ручной набор команд в повторяемый процесс с журналом действий, контролем результата и понятным откатом.

Коротко: как работает деплой приложения в Kubernetes

Цепочка операций: от коммита до готового Pod

Сценарий деплоя связывает четыре компонента: Docker создает артефакт, Container Registry хранит его версию, Kubernetes запускает контейнеры, а CI/CD pipeline управляет последовательностью шагов.

  1. Проверка изменений. Pipeline запускает тесты, линтеры и проверки Dockerfile до публикации образа.
  2. Сборка. Команда docker build создает образ приложения из текущей версии исходного кода.
  3. Тегирование. Образу присваивается тег релиза или SHA коммита, например v2026.09.06 или git-a13f9c2.
  4. Публикация. Команда docker push отправляет образ в registry, доступный узлам Kubernetes.
  5. Выбор среды. Скрипт получает NAMESPACE, IMAGE_TAG, домен и конфигурацию приложения.
  6. Применение ресурсов. kubectl apply -f создает или обновляет Deployment, Service, ConfigMap и Ingress.
  7. Ожидание обновления. kubectl rollout status ждет, пока Deployment запустит нужное число готовых Pod.
  8. Smoke-проверка. Проверяются состояние Pod, endpoints Service и доступность HTTP-маршрута через Service или Ingress.

Код возврата kubectl apply подтверждает принятие манифеста API-сервером. Он не подтверждает, что приложение скачало образ, запустилось и отвечает на запросы. Поэтому ожидание rollout и проверка доступности входят в обязательную часть сценария.

Когда скрипта достаточно, а когда нужен CI/CD pipeline

Отдельный Bash-скрипт подходит для локального стенда, K3s, тестового namespace и повторяемых административных операций. Его удобно запускать вручную после сборки образа или использовать как единую команду для небольшой команды.

Для командной разработки и production скрипт лучше запускать внутри CI/CD pipeline. Pipeline добавляет автоматические тесты, журнал выполнения, защищенные секреты, разграничение прав, ручное подтверждение production-релиза и сохранение диагностических данных при ошибке.

Подходы к автоматизации отличаются требованиями к масштабу, контролю изменений и сопровождению. Практическое сравнение shell-скриптов, CI/CD, Docker и Kubernetes приведено в статье о системах развертывания приложений.

Что подготовить перед запуском скрипта

Параметры кластера и целевого окружения

Перед первым запуском зафиксируйте характеристики среды. Одна и та же команда может вести себя по-разному в полноразмерном Kubernetes, K3s, Minikube и managed-кластере.

  • Дистрибутив и версию Kubernetes или K3s.
  • Операционную систему узлов.
  • Архитектуру процессора, например amd64 или arm64.
  • Сетевую схему, firewall, доступные порты и правила DNS.
  • Ingress-контроллер, например Traefik в типичной установке K3s.
  • Внутренний порт приложения, например 8080.
  • Namespace, в котором будут создаваться ресурсы.
  • StorageClass, если приложению нужны PersistentVolume и PersistentVolumeClaim.
  • Состав системных компонентов, включая CoreDNS, CNI и Ingress-контроллер.

В учебном сценарии удобно использовать K3s с Traefik. Для внешнего HTTP-доступа понадобятся DNS-запись на адрес кластера и доступные порты 80 или 443. Локальное хранилище K3s имеет ограничения, поэтому stateful-приложения требуют отдельной проверки StorageClass и политики резервного копирования.

Если кластер нужен в облачной инфраструктуре с VDS, хранилищем и Kubernetes, можно рассмотреть Timeweb Cloud. Перед запуском проверьте поддерживаемые версии Kubernetes, сетевые правила, типы дисков и способ выдачи учетных данных.

Проверка kubectl context и прав доступа

Самая опасная ошибка перед деплоем, применение манифестов не в тот кластер. Скрипт должен явно проверять текущий context или получать ожидаемое значение через переменную.

kubectl config current-context
kubectl cluster-info
kubectl get namespace staging
kubectl auth can-i get pods --namespace staging
kubectl auth can-i create deployments --namespace staging

Для production проверяйте сразу три значения: context, namespace и образ. Полезно вывести их в лог до команды kubectl apply. Если context отличается от ожидаемого, сценарий должен завершиться с ошибкой без изменения ресурсов.

Учетная запись deploy job должна иметь минимальные права. Для одного приложения обычно нужны операции с Deployment, Pod, Service, ConfigMap, Ingress и просмотр событий в целевом namespace. Доступ администратора к кластеру для автоматического деплоя повышает риск ошибки.

Доступ к Container Registry

Сначала авторизуйте Docker на машине сборки:

docker login registry.local

В команде используется имя образа с registry и репозиторием, например registry.local/team/catalog. Тег должен однозначно указывать на содержимое образа.

Если registry закрытый, узлы Kubernetes должны получить право скачать образ. Для этого создают Secret типа kubernetes.io/dockerconfigjson и подключают его к Pod через imagePullSecrets. Логины, токены и содержимое kubeconfig нельзя хранить в Bash-файле, YAML или открытом Git-репозитории.

Структура Kubernetes-манифестов для приложения

Минимальный набор ресурсов состоит из Deployment и Service. ConfigMap добавляет конфигурацию приложения, Secret хранит чувствительные значения, а Ingress публикует HTTP или HTTPS-маршруты наружу.

k8s/
  app.yaml.tmpl
  configmap.yaml
  secret.example.yaml

Namespace можно создать заранее отдельной командой или описать отдельным манифестом. Для production чаще используют заранее подготовленный namespace с ограничениями ресурсов, политиками доступа и сетевыми правилами.

Синтаксис apiVersion, kind, metadata и spec разобран с примерами в практическом материале о структуре Kubernetes-манифестов.

Deployment: образ, реплики, ресурсы и стратегия обновления

Deployment описывает желаемое состояние приложения и поддерживает нужное число реплик. При изменении поля spec.template, например образа или переменной окружения, Kubernetes создает новую ревизию ReplicaSet.

ПолеНазначениеПрактический ориентир
replicasКоличество экземпляров приложения2 для базового отказоустойчивого сценария
imageПолное имя Docker-образа и его тегregistry.local/team/app:v2026.09.06
selectorСвязь Deployment с Pod по labelsЗначение совпадает с labels шаблона Pod
containerPortПорт процесса внутри контейнера8080
resources.requestsРесурсы для планирования PodCPU 100m, память 128Mi
resources.limitsВерхнее ограничение потребленияCPU 500m, память 512Mi
strategyПорядок замены PodRollingUpdate

В примере используется RollingUpdate с одной дополнительной репликой и нулевым количеством недоступных Pod. Такая схема снижает риск простоя, если приложение корректно обрабатывает параллельный запуск версий.

Полное руководство по Deployment, probes, requests, limits, rollout и откату доступно в статье об управлении приложениями через Kubernetes Deployment.

Readiness и liveness probes

readinessProbe отвечает на вопрос, может ли Pod принимать трафик. Пока проверка не проходит, Service не направляет запросы в этот Pod.

livenessProbe контролирует жизнеспособность процесса. После нескольких неудачных проверок kubelet перезапускает контейнер.

Для HTTP-приложения можно использовать два endpoint: /ready для готовности и /health для проверки процесса. Пути должны существовать в приложении, а порт probe должен совпадать с портом контейнера или именем порта.

readinessProbe:
  httpGet:
    path: /ready
    port: http
  initialDelaySeconds: 5
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 6
livenessProbe:
  httpGet:
    path: /health
    port: http
  initialDelaySeconds: 15
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3

Неверный путь, порт или слишком короткая задержка блокируют rollout. Если приложение запускается 40 секунд, значение initialDelaySeconds для liveness должно учитывать это время.

Service и Ingress

Service предоставляет стабильное имя и виртуальный адрес внутри кластера. Он выбирает Pod по selector, поэтому labels Deployment и selector Service должны совпадать.

Ingress нужен при внешнем HTTP или HTTPS-доступе. В K3s запрос принимает Traefik, выбирает правило по домену и передает трафик в Service. Для внутреннего API без публичного адреса достаточно Service.

apiVersion: v1
kind: Service
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
  labels:
    app: ${APP_NAME}
spec:
  selector:
    app: ${APP_NAME}
  ports:
    - name: http
      port: 80
      targetPort: http
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
  labels:
    app: ${APP_NAME}
spec:
  ingressClassName: traefik
  rules:
    - host: ${DOMAIN}
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: ${APP_NAME}
                port:
                  number: 80

Для такого Ingress DNS-имя должно указывать на адрес, где Traefik принимает запросы. Если DNS или firewall не настроены, исправный Pod все равно не будет доступен извне.

Рабочий скрипт развертывания приложения в Kubernetes

Входные переменные и предварительная валидация

Скрипт получает параметры через переменные окружения. Режим set -Eeuo pipefail останавливает выполнение при ошибке команды, обращении к незаданной переменной или сбое в конвейере.

Ниже приведен пример, который собирает образ, проверяет context, публикует образ, подставляет переменные в шаблон и ждет завершения rollout.

#!/usr/bin/env bash
set -Eeuo pipefail

: "${NAMESPACE:?NAMESPACE is required}"
: "${IMAGE_TAG:?IMAGE_TAG is required}"
: "${IMAGE_REPOSITORY:?IMAGE_REPOSITORY is required}"
: "${APP_NAME:?APP_NAME is required}"
: "${CONTAINER_PORT:=8080}"
: "${DOMAIN:=app.example.internal}"
: "${EXPECTED_CONTEXT:?EXPECTED_CONTEXT is required}"

command -v docker >/dev/null
command -v kubectl >/dev/null

CURRENT_CONTEXT=$(kubectl config current-context)
if [ "$CURRENT_CONTEXT" != "$EXPECTED_CONTEXT" ]; then
  echo "Unexpected Kubernetes context: $CURRENT_CONTEXT" >&2
  exit 1
fi

kubectl get namespace "$NAMESPACE" >/dev/null
kubectl auth can-i create deployments --namespace "$NAMESPACE" >/dev/null
kubectl auth can-i get pods --namespace "$NAMESPACE" >/dev/null

if [ "$NAMESPACE" = production ]; then
  if [ "$IMAGE_TAG" = latest ]; then
    echo "latest is forbidden in production" >&2
    exit 1
  fi
  echo "Production deploy: context=$CURRENT_CONTEXT namespace=$NAMESPACE image=$IMAGE_REPOSITORY:$IMAGE_TAG"
  read -r -p "Type production to continue: " CONFIRM
  if [ "$CONFIRM" != production ]; then
    echo "Deployment cancelled"
    exit 1
  fi
fi

IMAGE="$IMAGE_REPOSITORY:$IMAGE_TAG"
MANIFEST_FILE=$(mktemp)
trap 'rm -f "$MANIFEST_FILE"' EXIT

echo "Building $IMAGE"
docker build --pull --tag "$IMAGE" .
echo "Pushing $IMAGE"
docker push "$IMAGE"

export NAMESPACE APP_NAME IMAGE CONTAINER_PORT DOMAIN
envsubst '${NAMESPACE} ${APP_NAME} ${IMAGE} ${CONTAINER_PORT} ${DOMAIN}' < k8s/app.yaml.tmpl > "$MANIFEST_FILE"

echo "Applying Kubernetes manifests"
kubectl apply --filename "$MANIFEST_FILE"

echo "Waiting for rollout"
kubectl rollout status "deployment/$APP_NAME" --namespace "$NAMESPACE" --timeout=180s

echo "Checking resources"
kubectl get deployment "$APP_NAME" --namespace "$NAMESPACE"
kubectl get pods --namespace "$NAMESPACE" --selector "app=$APP_NAME" -o wide
kubectl get service "$APP_NAME" --namespace "$NAMESPACE"
if kubectl get ingress "$APP_NAME" --namespace "$NAMESPACE"; then
  true
fi

Проверка существования namespace защищает от случайного создания ресурсов в новом пространстве имен из-за опечатки. Если namespace нужно создавать автоматически, добавьте отдельный разрешенный шаг с проверкой допустимого списка значений.

Сборка и публикация Docker-образа

Переменная IMAGE_REPOSITORY хранит имя registry и репозитория без тега:

IMAGE_REPOSITORY=registry.local/team/catalog
IMAGE_TAG=git-a13f9c2

Скрипт собирает итоговый образ с именем registry.local/team/catalog:git-a13f9c2 и отправляет его через docker push. Тег на основе SHA коммита связывает образ с исходным кодом. Релизный тег вроде v2026.09.06 удобен для ручного поиска и журналов.

Повторная сборка на production-сервере нарушает разделение build и deploy. В таком сценарии результат может зависеть от локального Docker-кэша, версии инструментов и состояния исходного каталога. Production получает готовый артефакт из registry.

Подстановка параметров и применение манифестов

Шаблон можно обработать через envsubst. Файлы не приходится копировать для staging и production, меняются только переменные окружения и значения конфигурации.

Файл k8s/app.yaml.tmpl может содержать такие ресурсы:

apiVersion: v1
kind: ConfigMap
metadata:
  name: ${APP_NAME}-config
  namespace: ${NAMESPACE}
data:
  LOG_LEVEL: info
  FEATURE_MODE: standard
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
  labels:
    app: ${APP_NAME}
spec:
  replicas: 2
  revisionHistoryLimit: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: ${APP_NAME}
  template:
    metadata:
      labels:
        app: ${APP_NAME}
    spec:
      containers:
        - name: ${APP_NAME}
          image: ${IMAGE}
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: ${CONTAINER_PORT}
          envFrom:
            - configMapRef:
                name: ${APP_NAME}-config
          readinessProbe:
            httpGet:
              path: /ready
              port: http
            initialDelaySeconds: 5
            periodSeconds: 5
            timeoutSeconds: 2
            failureThreshold: 6
          livenessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 15
            periodSeconds: 10
            timeoutSeconds: 2
            failureThreshold: 3
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
  labels:
    app: ${APP_NAME}
spec:
  selector:
    app: ${APP_NAME}
  ports:
    - name: http
      port: 80
      targetPort: http
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ${APP_NAME}
  namespace: ${NAMESPACE}
spec:
  ingressClassName: traefik
  rules:
    - host: ${DOMAIN}
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: ${APP_NAME}
                port:
                  number: 80

Перед применением проверьте получившийся YAML:

envsubst '${NAMESPACE} ${APP_NAME} ${IMAGE} ${CONTAINER_PORT} ${DOMAIN}' < k8s/app.yaml.tmpl > /tmp/app.yaml
kubectl apply --dry-run=server --filename /tmp/app.yaml
kubectl apply --filename /tmp/app.yaml

Проверка --dry-run=server отправляет манифест API-серверу без изменения ресурсов. Она помогает обнаружить неверный apiVersion, запрещенное поле или ошибку схемы до настоящего применения.

Ожидание rollout и базовая smoke-проверка

После kubectl apply дождитесь завершения обновления с ограничением времени:

kubectl rollout status deployment/catalog --namespace staging --timeout=180s
kubectl get pods --namespace staging --selector app=catalog
kubectl get service catalog --namespace staging
kubectl get ingress catalog --namespace staging

Успешный rollout означает, что Deployment получил готовые Pod согласно заданной стратегии. Для проверки функции приложения выполните HTTP-запрос из временного Pod внутри кластера или отправьте запрос через внешний Ingress.

kubectl run smoke-client --rm --stdin --tty --restart=Never --image=curlimages/curl -- curl --fail --silent http://catalog/ready

Команда использует внутреннее имя Service. Если запрос завершается ошибкой, сравните состояние Pod, endpoints Service и логи приложения. Для внешнего теста проверьте домен, правила Traefik и доступность порта.

Параметризация скрипта для staging и production

Namespace и тег образа как обязательные параметры

Namespace отделяет ресурсы разных сред и снижает вероятность смешения конфигураций. Один и тот же сценарий можно запустить с разными значениями:

NAMESPACE=staging \
IMAGE_TAG=git-a13f9c2 \
IMAGE_REPOSITORY=registry.local/team/catalog \
APP_NAME=catalog \
CONTAINER_PORT=8080 \
DOMAIN=catalog.staging.example.internal \
EXPECTED_CONTEXT=cluster-staging \
./deploy.sh
NAMESPACE=production \
IMAGE_TAG=v2026.09.06 \
IMAGE_REPOSITORY=registry.local/team/catalog \
APP_NAME=catalog \
CONTAINER_PORT=8080 \
DOMAIN=catalog.example.internal \
EXPECTED_CONTEXT=cluster-production \
./deploy.sh

Для production используйте явный релизный тег или SHA коммита. Тег latest оставьте для локальных экспериментов, где воспроизводимость релиза не требуется.

Конфигурация приложения через ConfigMap и Secret

Параметры, не содержащие секретов, передаются через ConfigMap. В примере это уровень логирования и режим функций:

apiVersion: v1
kind: ConfigMap
metadata:
  name: catalog-config
  namespace: staging
data:
  LOG_LEVEL: info
  FEATURE_MODE: standard

Пароли, токены, ключи и строки подключения передаются через Secret или внешний менеджер секретов. Значения можно хранить в защищенных переменных CI/CD и создавать Secret во время deploy job. Поле data использует base64-кодирование, которое не шифрует содержимое, поэтому открытый Secret в Git не защищает учетные данные.

envFrom:
  - configMapRef:
      name: catalog-config
  - secretRef:
      name: catalog-secrets

Обычные настройки можно менять без пересборки образа. После изменения ConfigMap или Secret проверьте, требуется ли приложению перезапуск Pod для чтения новых значений.

Защита production от случайного запуска

Скрипт должен выводить перед запуском итоговые значения context, namespace, image repository и image tag. Для production добавьте подтверждение, запрет latest и проверку допустимого списка кластеров.

  • Разделите учетные данные staging и production.
  • Ограничьте production deploy отдельной CI/CD job.
  • Добавьте ручное подтверждение или правило защищенной ветки.
  • Запретите пустой, изменяемый или неизвестный тег.
  • Проверяйте, что context соответствует целевому окружению.
  • Используйте разные домены, лимиты ресурсов и ConfigMap для сред.

Один скрипт отвечает за последовательность команд. Значения среды хранятся отдельно, поэтому исправление логики деплоя не требует синхронного редактирования нескольких копий файла.

Как встроить деплой в CI/CD pipeline

Разделение pipeline на build и deploy

Pipeline удобно разделить на последовательные jobs:

  1. Test. Проверка кода, зависимостей, Dockerfile и Kubernetes-шаблонов.
  2. Build. Сборка образа с тегом SHA коммита или версии релиза.
  3. Push. Публикация образа в Container Registry.
  4. Deploy staging. Запуск единого скрипта с namespace staging.
  5. Smoke. Проверка rollout, Pod и HTTP-ответа.
  6. Approve. Ручное или защищенное разрешение на production.
  7. Deploy production. Развертывание того же тега в production.
  8. Verify. Проверка состояния, доступности и событий Kubernetes.

Build job создает артефакт. Deploy job использует его, но не пересобирает приложение. Это сохраняет связь между образом, тестами и production-релизом.

Минимальный вызов deploy job выглядит так:

export NAMESPACE=staging
export IMAGE_TAG="$CI_COMMIT_SHA"
export IMAGE_REPOSITORY=registry.local/team/catalog
export APP_NAME=catalog
export EXPECTED_CONTEXT=cluster-staging
./deploy.sh

Переменные и секреты CI/CD

В защищенном хранилище CI/CD размещают токены registry, kubeconfig или краткоживущие учетные данные, а также значения конфигурации конкретной среды. Секреты не должны попадать в вывод команд, артефакты job и Git-репозиторий.

  • REGISTRY_USER и REGISTRY_TOKEN нужны build job.
  • KUBECONFIG или временный токен нужен deploy job.
  • EXPECTED_CONTEXT защищает от обращения к чужому кластеру.
  • PRODUCTION_DOMAIN, лимиты ресурсов и имена Secret хранятся отдельно для каждой среды.

Разрешения deploy job ограничьте целевым namespace. Отдельный service account для staging не должен автоматически получать права на production.

Проверка результата как обязательный этап pipeline

Job должна завершаться ошибкой, если rollout не закончился за заданное время, Pod не перешел в Ready или smoke-запрос вернул ошибку.

kubectl rollout status deployment/catalog --namespace staging --timeout=180s
kubectl wait --for=condition=available deployment/catalog --namespace staging --timeout=60s
kubectl get pods --namespace staging --selector app=catalog
kubectl get events --namespace staging --sort-by=.lastTimestamp

При ошибке pipeline сохраняет вывод kubectl describe, логи контейнеров и события. Эти данные сокращают время поиска причины и позволяют отличить проблему образа от ошибки приложения или сети.

Проверка rollout и диагностика проблем

Проверка Deployment и Pod

Проверку выполняйте по цепочке Deployment, Pod, Service, Ingress. Сначала убедитесь, что Deployment получил нужное число доступных реплик.

kubectl get deployment catalog --namespace production
kubectl rollout status deployment/catalog --namespace production --timeout=180s
kubectl get pods --namespace production --selector app=catalog -o wide
kubectl get pods --namespace production --selector app=catalog -o custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[0].ready,STATUS:.status.phase,RESTARTS:.status.containerStatuses[0].restartCount,IMAGE:.spec.containers[0].image

В нормальном результате Pod имеют статус Running, состояние контейнера Ready равно true, а счетчик RESTARTS не растет. Образ в выводе должен содержать ожидаемый IMAGE_TAG.

Анализ логов и событий Kubernetes

Если rollout остановился, получите описание Pod, логи контейнера и последние события:

kubectl describe pod catalog-xxxxx --namespace production
kubectl logs deployment/catalog --namespace production --all-containers=true --tail=200
kubectl get events --namespace production --sort-by=.lastTimestamp
ПризнакВероятная причинаПроверка
ImagePullBackOffОшибка имени образа, тега или доступа к registryПроверить image, registry credentials и imagePullSecrets
CrashLoopBackOffПроцесс приложения завершается после запускаПосмотреть kubectl logs и переменные окружения
Pod Running, Ready falseНе проходит readiness probeПроверить endpoint, порт и время запуска
Недостаточно ресурсовНа узле нет свободных CPU или памятиИзучить события и значения requests
Рост рестартовПадает процесс или срабатывает liveness probeСравнить логи, лимиты и параметры liveness

События показывают причину, которую не всегда видно в логах приложения: отказ планировщика, нехватку памяти, ошибку монтирования тома или проблему загрузки образа.

Проверка Service и Ingress

Если Pod готов, но запрос не проходит, проверьте Service и его endpoints:

kubectl get service catalog --namespace production
kubectl get endpointslice --namespace production -l kubernetes.io/service-name=catalog
kubectl describe service catalog --namespace production
kubectl describe ingress catalog --namespace production

Пустой EndpointSlice обычно означает, что selector Service не совпадает с labels Pod или Pod не прошел readiness probe. Сравните эти значения:

kubectl get pods --namespace production --show-labels
kubectl get service catalog --namespace production -o yaml

Для K3s проверьте класс Ingress traefik, домен, DNS-запись и доступность портов 80 или 443. Внутренний тест через Service помогает отделить сетевую проблему Ingress от ошибки приложения.

Откат релиза и защита от неудачного деплоя

Когда нужно выполнять rollback

Остановите обновление и подготовьте откат, если rollout не завершился за заданный тайм-аут, Pod не проходят readiness probe, новая версия возвращает ошибки в smoke-тесте или контейнер не может скачать образ.

Откат нужен и после формально успешного rollout, если приложение отвечает с ошибками, теряет соединение с базой данных или нарушает критическую бизнес-функцию. Проверка статуса Deployment не заменяет функциональный тест.

Команды для возврата к предыдущей версии

Сначала посмотрите историю ревизий:

kubectl rollout history deployment/catalog --namespace production
kubectl rollout history deployment/catalog --namespace production --revision=3

Затем верните предыдущую ревизию и дождитесь ее готовности:

kubectl rollout undo deployment/catalog --namespace production
kubectl rollout status deployment/catalog --namespace production --timeout=180s
kubectl get pods --namespace production --selector app=catalog
kubectl get service catalog --namespace production
kubectl get ingress catalog --namespace production

После отката сохраните логи и события неудачной версии. Откат восстанавливает рабочее состояние, но не объясняет причину сбоя.

Идемпотентность и повторный запуск

Используйте kubectl apply, фиксированные имена ресурсов и одинаковые шаблоны. Повторный запуск должен приводить кластер к тому же состоянию, если параметры образа и конфигурации не изменились.

  • Не удаляйте Deployment перед каждым обновлением.
  • Не создавайте новые имена Pod вручную, ими управляет Deployment.
  • Проверяйте существование namespace до применения манифестов.
  • Обрабатывайте ситуацию, когда предыдущий rollout еще не завершился.
  • Не переиспользуйте изменяемый тег для разных содержимых образа.
  • Задавайте тайм-аут rollout и понятный код ошибки.

Типичные ошибки в скрипте развертывания приложения в Kubernetes

Деплой считается успешным после kubectl apply

kubectl apply сообщает о принятии объектов Kubernetes. Контейнер после этого может не запуститься, не скачать образ или не пройти probe.

Исправление: ждать kubectl rollout status, проверять Ready-состояние Pod и выполнять smoke-запрос. При тайм-ауте нужно вывести логи, описание ресурсов и события.

Плавающие теги и повторяемая сборка

Тег latest скрывает содержимое релиза. Один и тот же манифест может запустить разные образы в разные моменты, а rollback не даст надежной гарантии возврата к прежнему содержимому.

Используйте уникальные теги релиза или SHA коммита, храните связь между исходным кодом и образом в registry. Не собирайте приложение на production-сервере, сборка должна проходить в build job или на подготовленной рабочей машине.

Секреты и параметры окружения находятся в репозитории

Пароли и токены в Git попадают в историю коммитов и могут остаться доступными после удаления строки из последней версии файла.

Исправление: хранить чувствительные значения в Secret, защищенных переменных CI/CD или внешнем менеджере секретов. ConfigMap используйте для обычных параметров и разделяйте значения staging и production.

  • Неверный namespace. Перед применением проверяйте разрешенный список namespace и текущий context.
  • Несовпадение labels и selector. Используйте одинаковое значение app в Deployment, Pod и Service.
  • Отсутствие probes. Добавьте readiness и liveness с реальными endpoint приложения.
  • Неограниченное ожидание rollout. Используйте тайм-аут, например 180 секунд, и завершайте job с ошибкой.
  • Нет плана отката. Проверьте историю Deployment и заранее подготовьте команду kubectl rollout undo.

Чек-лист готового сценария деплоя

Минимальный набор проверок перед production

Перед рабочим запуском сначала выполните деплой в staging на том же наборе манифестов. После smoke-проверки используйте для production тот же IMAGE_TAG, который прошел тестирование.

  • Образ собирается на CI-сервере или рабочей машине, production не выполняет сборку.
  • Используется уникальный IMAGE_TAG, тег latest запрещен.
  • Container Registry доступен build job и узлам Kubernetes.
  • Namespace задан явно и проверяется до запуска.
  • Kubernetes context совпадает с ожидаемым кластером.
  • Права kubectl ограничены целевым namespace.
  • Манифесты параметризованы через namespace, образ, тег и конфигурацию среды.
  • Deployment содержит replicas, requests, limits и стратегию RollingUpdate.
  • Readiness probe проверяет реальный endpoint готовности.
  • Liveness probe контролирует процесс и учитывает время запуска.
  • Service выбирает Pod по совпадающим labels и selector.
  • Ingress настроен только при необходимости внешнего HTTP или HTTPS-доступа.
  • Rollout ожидается с ограничением времени.
  • Проверяются состояние Pod, логи, события, Service и Ingress.
  • Секреты не хранятся в открытом виде в Git и логах pipeline.
  • Для неудачного релиза подготовлена команда kubectl rollout undo.
  • Результат staging и production сохраняется в журнале CI/CD.

Готовый сценарий должен завершаться только после подтверждения состояния приложения. Применение манифестов, успешный rollout и рабочий HTTP-ответ проверяют разные уровни деплоя, поэтому каждый из них нужен в автоматической цепочке.

Поделиться:
Сохранить гайд? В закладки браузера