Деплой реального приложения

Соберём всё изученное в один реальный стек: фронтенд, бэкенд и база данных в одном кластере.

Типичное приложение в Kubernetes — это несколько Deployment-ов и Service-ов, связанных по именам через DNS, плюс ConfigMap/Secret для настроек.

Развернём трёхзвенное приложение: frontend (отдаёт UI), backend (API), db (Postgres). Каждый компонент — свой Deployment и свой Service. Связи: frontend зовёт backend по имени, backend зовёт db по имени.

База данных: Secret + Deployment + Service

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:                 # stringData — без ручного base64
  POSTGRES_PASSWORD: s3cr3t
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db
spec:
  replicas: 1
  selector:
    matchLabels: { app: db }
  template:
    metadata:
      labels: { app: db }
    spec:
      containers:
        - name: postgres
          image: postgres:16
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef: { name: db-secret, key: POSTGRES_PASSWORD }
          ports:
            - containerPort: 5432
---
apiVersion: v1
kind: Service
metadata:
  name: db
spec:
  selector: { app: db }
  ports:
    - port: 5432
      targetPort: 5432

Несколько объектов в одном файле разделяют строкой ---. Service назван db — backend будет ходить по этому имени.

Бэкенд: Deployment + Service

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 2
  selector:
    matchLabels: { app: backend }
  template:
    metadata:
      labels: { app: backend }
    spec:
      containers:
        - name: api
          image: my-backend:1.0
          env:
            - name: DB_HOST
              value: db          # имя сервиса БД
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: backend
spec:
  selector: { app: backend }
  ports:
    - port: 8080
      targetPort: 8080

Бэкенд знает базу как db — DNS превратит это имя в адрес сервиса БД.

Фронтенд: Deployment + Service

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 2
  selector:
    matchLabels: { app: frontend }
  template:
    metadata:
      labels: { app: frontend }
    spec:
      containers:
        - name: web
          image: my-frontend:1.0
          env:
            - name: API_URL
              value: http://backend:8080
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  type: NodePort
  selector: { app: frontend }
  ports:
    - port: 80
      targetPort: 80

Применяем всё

kubectl apply -f db.yaml
kubectl apply -f backend.yaml
kubectl apply -f frontend.yaml
kubectl get pods,services

Вывод:

pod/db-...        1/1   Running
pod/backend-...   1/1   Running
pod/backend-...   1/1   Running
pod/frontend-...  1/1   Running
pod/frontend-...  1/1   Running

Готово: фронтенд через backend ходит в API, тот через db — в базу. Всё связано именами, без единого жёсткого IP.

Итог

  • Каждый компонент — отдельный Deployment + Service.
  • Компоненты находят друг друга по именам сервисов через DNS.
  • Секреты БД хранятся в Secret, объекты в файле разделяются ---.
Проверьте себя
1. Как backend в этом примере находит базу данных?
AПо жёстко прописанному IP пода
BПо имени сервиса db через DNS
CЧерез port-forward
DЧерез переменную из Ingress
2. Что разделяет несколько объектов в одном YAML-файле?
AЗапятая
BСтрока ---
CПустая строка
DТег <break>
3. Почему каждый компонент получает свой Service?
AЧтобы хранить логи
BЧтобы дать стабильное имя и балансировку для обращения других компонентов
CЭто обязательное требование для Deployment
DЧтобы зашифровать данные
Поддержать проект