DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

JumpToTech Kubernetes Core YAML Lab

Namespace: jumptotech
│
├── ConfigMap ───────────────┐
│                            │
├── Secret ──────────────────┤
│                            ↓
│                       Deployment
│                            ↓
│                       ReplicaSet
│                            ↓
│               ┌────────────┼────────────┐
│               ↓            ↓            ↓
│             Pod 1        Pod 2        Pod 3
│               │            │            │
│               └────────────┼────────────┘
│                            ↑
│                         Service
│                            ↑
│                         Ingress
│
├── ServiceAccount ─────→ Pods
│
└── PDB ────────────────→ protects availability
Enter fullscreen mode Exit fullscreen mode

1. Создайте папку

mkdir k8s-core-lab
cd k8s-core-lab
Enter fullscreen mode Exit fullscreen mode

В конце у вас будет:

k8s-core-lab/
├── namespace.yaml
├── configmap.yaml
├── secret.yaml
├── serviceaccount.yaml
├── deployment.yaml
├── service.yaml
├── pdb.yaml
└── ingress.yaml
Enter fullscreen mode Exit fullscreen mode

2. Namespace

Создайте namespace.yaml:

apiVersion: v1
kind: Namespace
metadata:
  name: jumptotech
Enter fullscreen mode Exit fullscreen mode

Применяем:

kubectl apply -f namespace.yaml
kubectl get namespaces
Enter fullscreen mode Exit fullscreen mode

Объяснение:

Namespace — логическое разделение ресурсов внутри одного Kubernetes cluster.

Теперь почти всё приложение будем создавать внутри:

jumptotech
Enter fullscreen mode Exit fullscreen mode

3. ConfigMap

configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: web-config
  namespace: jumptotech
data:
  APP_NAME: "JumpToTech"
  APP_ENV: "production"
  APP_MESSAGE: "Welcome to Kubernetes"
Enter fullscreen mode Exit fullscreen mode

Применяем:

kubectl apply -f configmap.yaml
kubectl get configmap -n jumptotech
kubectl describe configmap web-config -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Объясните:

ConfigMap хранит несекретную конфигурацию отдельно от Docker image.

Например:

APP_ENV
APP_NAME
LOG_LEVEL
API_URL
Enter fullscreen mode Exit fullscreen mode

Не надо rebuild image только потому, что:

APP_ENV=dev
Enter fullscreen mode Exit fullscreen mode

нужно поменять на:

APP_ENV=production
Enter fullscreen mode Exit fullscreen mode

4. Secret

secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: web-secret
  namespace: jumptotech
type: Opaque
stringData:
  DB_USERNAME: "admin"
  DB_PASSWORD: "jumptotech123"
Enter fullscreen mode Exit fullscreen mode

Для учебного lab это удобно, но объясните студентам:

В production реальные passwords нельзя коммитить в Git в таком YAML. Обычно используют внешний secret-management solution и соответствующую интеграцию.

Применяем:

kubectl apply -f secret.yaml
kubectl get secrets -n jumptotech
kubectl describe secret web-secret -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Обратите внимание: describe не должен просто печатать secret value.


5. ServiceAccount

Создаём serviceaccount.yaml:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: web-service-account
  namespace: jumptotech
Enter fullscreen mode Exit fullscreen mode

Применяем:

kubectl apply -f serviceaccount.yaml
kubectl get serviceaccounts -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Объяснение:

ServiceAccount — identity для workload/Pod внутри Kubernetes.

Очень важно:

Human
  ↓
User identity

Pod
  ↓
ServiceAccount
Enter fullscreen mode Exit fullscreen mode

Сам по себе ServiceAccount не означает, что Pod автоматически получил доступ ко всему. Permissions определяются отдельно, например RBAC; в AWS также могут использоваться workload identity mechanisms.


6. Deployment + Requests + Limits

Теперь основной файл — deployment.yaml.

Замените YOUR_ECR_IMAGE своим настоящим ECR URI.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
  namespace: jumptotech

spec:
  replicas: 3

  selector:
    matchLabels:
      app: web

  template:
    metadata:
      labels:
        app: web

    spec:
      serviceAccountName: web-service-account

      containers:
        - name: web-container
          image: YOUR_ECR_IMAGE
          ports:
            - containerPort: 80

          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "256Mi"

          env:
            - name: APP_NAME
              valueFrom:
                configMapKeyRef:
                  name: web-config
                  key: APP_NAME

            - name: APP_ENV
              valueFrom:
                configMapKeyRef:
                  name: web-config
                  key: APP_ENV

            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: web-secret
                  key: DB_USERNAME

            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: web-secret
                  key: DB_PASSWORD
Enter fullscreen mode Exit fullscreen mode

Здесь остановитесь надолго.

Студенты должны понимать:

Deployment
    ↓
replicas: 3
    ↓
ReplicaSet
    ↓
3 Pods
Enter fullscreen mode Exit fullscreen mode

И:

resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
Enter fullscreen mode Exit fullscreen mode

означает:

Scheduler учитывает эти requests при выборе Node.

А:

limits:
  cpu: "500m"
  memory: "256Mi"
Enter fullscreen mode Exit fullscreen mode

устанавливает верхние ограничения для контейнера.

Ключевая разница:

REQUEST
   ↓
Scheduler / placement

LIMIT
   ↓
Runtime resource ceiling
Enter fullscreen mode Exit fullscreen mode

CPU:

1000m = 1 CPU
500m  = 0.5 CPU
100m  = 0.1 CPU
Enter fullscreen mode Exit fullscreen mode

7. Apply Deployment

kubectl apply -f deployment.yaml
Enter fullscreen mode Exit fullscreen mode

Проверяем:

kubectl get deployments -n jumptotech
kubectl get rs -n jumptotech
kubectl get pods -n jumptotech
kubectl get pods -n jumptotech -o wide
Enter fullscreen mode Exit fullscreen mode

Должно быть:

Deployment
    ↓
ReplicaSet
    ↓
3 Pods
Enter fullscreen mode Exit fullscreen mode

8. Проверяем Resources

Выберите Pod:

kubectl describe pod POD_NAME -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Найдите:

Limits:
  cpu:     500m
  memory:  256Mi

Requests:
  cpu:     100m
  memory:  128Mi
Enter fullscreen mode Exit fullscreen mode

Спросите:

Что использует Scheduler при выборе Node?

Requests.

Что будет, если приложение пытается использовать CPU больше CPU limit?

CPU может throttled.

Что может произойти при превышении memory limit?

Контейнер может быть убит из-за OOM (OOMKilled).


9. Проверяем ConfigMap и Secret внутри Pod

Сначала ConfigMap:

kubectl exec -n jumptotech POD_NAME -- printenv APP_NAME
Enter fullscreen mode Exit fullscreen mode

Должно показать:

JumpToTech
Enter fullscreen mode Exit fullscreen mode

Потом:

kubectl exec -n jumptotech POD_NAME -- printenv APP_ENV
Enter fullscreen mode Exit fullscreen mode

Получим:

production
Enter fullscreen mode Exit fullscreen mode

Для учебной демонстрации можно проверить username:

kubectl exec -n jumptotech POD_NAME -- printenv DB_USERNAME
Enter fullscreen mode Exit fullscreen mode

Главная идея:

ConfigMap ──────┐
                ↓
              Pod
                ↑
Secret ─────────┘
Enter fullscreen mode Exit fullscreen mode

10. Проверяем ServiceAccount

kubectl get pod POD_NAME \
-n jumptotech \
-o jsonpath='{.spec.serviceAccountName}'
Enter fullscreen mode Exit fullscreen mode

Получим:

web-service-account
Enter fullscreen mode Exit fullscreen mode

Связь:

Deployment Pod Template
       ↓
serviceAccountName
       ↓
web-service-account
       ↓
Pod identity
Enter fullscreen mode Exit fullscreen mode

11. Service

Создаём service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: web-service
  namespace: jumptotech

spec:
  type: ClusterIP

  selector:
    app: web

  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
Enter fullscreen mode Exit fullscreen mode

Применяем:

kubectl apply -f service.yaml
kubectl get svc -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Главная связь:

Service
selector: app=web
       ↓
     MATCH
       ↓
Pod labels
app=web
Enter fullscreen mode Exit fullscreen mode

12. EndpointSlice

Сначала:

kubectl get pods -n jumptotech -o wide
Enter fullscreen mode Exit fullscreen mode

Посмотрите Pod IP.

Потом:

kubectl get endpointslice \
-n jumptotech \
-l kubernetes.io/service-name=web-service
Enter fullscreen mode Exit fullscreen mode

Для дополнительной учебной проверки можно также использовать старую команду:

kubectl get endpoints web-service -n jumptotech
Enter fullscreen mode Exit fullscreen mode

но в вашем кластере вы уже видели предупреждение о deprecated Endpoints API, поэтому EndpointSlice — современный объект, который студентам лучше знать.

Логика:

Service selector
      ↓
Pod labels
      ↓
matching backend Pods
      ↓
EndpointSlice maintains backend addresses
Enter fullscreen mode Exit fullscreen mode

13. Проверяем Service

Пока ALB не нужен.

kubectl port-forward \
service/web-service \
8080:80 \
-n jumptotech
Enter fullscreen mode Exit fullscreen mode

Открываем:

http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Если приложение открывается:

Deployment ✅
Pods       ✅
Service    ✅
Enter fullscreen mode Exit fullscreen mode

14. PodDisruptionBudget — PDB

Теперь очень хороший production object.

Создаём pdb.yaml:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
  namespace: jumptotech

spec:
  minAvailable: 2

  selector:
    matchLabels:
      app: web
Enter fullscreen mode Exit fullscreen mode

Применяем:

kubectl apply -f pdb.yaml
kubectl get pdb -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Объясните:

У нас:

replicas = 3
Enter fullscreen mode Exit fullscreen mode

PDB:

minAvailable = 2
Enter fullscreen mode Exit fullscreen mode

То есть при voluntary disruptions, например некоторых операциях drain/maintenance, Kubernetes должен учитывать требование:

3 Pods

Pod 1   Pod 2   Pod 3
  ✓       ✓       ✓

PDB:
минимум 2 должны оставаться available
Enter fullscreen mode Exit fullscreen mode

Очень важное уточнение:

PDB не гарантирует, что Pod никогда не упадёт.

Если Node внезапно умер или приложение crash — PDB не является магической защитой от этого.

PDB в первую очередь ограничивает voluntary disruptions.


15. Readiness и Liveness Probes

Я бы обязательно добавила их в этот же Deployment lab.

В deployment.yaml под container добавьте:

livenessProbe:
  httpGet:
    path: /
    port: 80
  initialDelaySeconds: 10
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /
    port: 80
  initialDelaySeconds: 5
  periodSeconds: 5
Enter fullscreen mode Exit fullscreen mode

Получится:

containers:
  - name: web-container
    image: YOUR_ECR_IMAGE

    ports:
      - containerPort: 80

    resources:
      requests:
        cpu: "100m"
        memory: "128Mi"
      limits:
        cpu: "500m"
        memory: "256Mi"

    livenessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 10

    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5
Enter fullscreen mode Exit fullscreen mode

Объясните:

LIVENESS
"Приложение живое?"
      ↓
если постоянно fail
      ↓
kubelet может restart container


READINESS
"Приложение готово получать traffic?"
      ↓
NO
      ↓
Pod не должен использоваться
как ready backend
Enter fullscreen mode Exit fullscreen mode

Применяем:

kubectl apply -f deployment.yaml
kubectl get pods -n jumptotech
Enter fullscreen mode Exit fullscreen mode

16. Ingress

Если AWS Load Balancer Controller уже установлен, создаём ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  namespace: jumptotech

  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip

spec:
  ingressClassName: alb

  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-service
                port:
                  number: 80
Enter fullscreen mode Exit fullscreen mode

Перед применением:

kubectl get deployment \
-n kube-system \
aws-load-balancer-controller
Enter fullscreen mode Exit fullscreen mode

Если controller существует:

kubectl apply -f ingress.yaml
Enter fullscreen mode Exit fullscreen mode

Проверяем:

kubectl get ingress -n jumptotech
kubectl describe ingress web-ingress -n jumptotech
Enter fullscreen mode Exit fullscreen mode

17. Теперь вся архитектура

На доске нарисуйте:

                     INTERNET
                         ↓
                       ALB
                         ↓
                      Ingress
                         ↓
                    web-service
                  selector: app=web
                         ↓
             ┌───────────┼───────────┐
             ↓           ↓           ↓
           Pod 1       Pod 2       Pod 3
           app=web     app=web     app=web
             │           │           │
             └───────────┼───────────┘
                         ↑
                 Deployment
                         ↑
                    ReplicaSet


ConfigMap ───────────────→ Pods
Secret ─────────────────→ Pods
ServiceAccount ─────────→ Pods
Resources ──────────────→ Containers
PDB ────────────────────→ availability during
                           voluntary disruption

EVERYTHING:
Namespace = jumptotech
Enter fullscreen mode Exit fullscreen mode

18. Очень важный troubleshooting lab

Теперь специально ломаем.

Поменяйте Service:

selector:
  app: WRONG
Enter fullscreen mode Exit fullscreen mode

Примените:

kubectl apply -f service.yaml
Enter fullscreen mode Exit fullscreen mode

Проверьте:

kubectl get svc -n jumptotech
kubectl get pods -n jumptotech
kubectl get endpointslice \
-n jumptotech \
-l kubernetes.io/service-name=web-service
Enter fullscreen mode Exit fullscreen mode

Pods:

Running
Running
Running
Enter fullscreen mode Exit fullscreen mode

Service:

Exists
Enter fullscreen mode Exit fullscreen mode

Но backend endpoints не соответствуют нужным Pods.

Почему?

Service selector
app=WRONG
      X
Pod labels
app=web
Enter fullscreen mode Exit fullscreen mode

Исправляем:

selector:
  app: web
Enter fullscreen mode Exit fullscreen mode

И:

kubectl apply -f service.yaml
Enter fullscreen mode Exit fullscreen mode

19. Resources troubleshooting

Теперь специально создайте слишком большой request:

resources:
  requests:
    cpu: "100"
    memory: "100Gi"
Enter fullscreen mode Exit fullscreen mode

Это означает 100 CPU cores, а не 100m.

Примените:

kubectl apply -f deployment.yaml
Enter fullscreen mode Exit fullscreen mode

Новые Pods могут зависнуть:

Pending
Enter fullscreen mode Exit fullscreen mode

Тогда:

kubectl describe pod POD_NAME -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Ищите scheduling events вроде:

Insufficient cpu
Insufficient memory
Enter fullscreen mode Exit fullscreen mode

Объяснение:

Pod
requests 100 CPU
       ↓
Scheduler
       ↓
Node 1 ❌
Node 2 ❌
       ↓
No suitable Node
       ↓
Pending
Enter fullscreen mode Exit fullscreen mode

После демонстрации обязательно верните:

requests:
  cpu: "100m"
  memory: "128Mi"
Enter fullscreen mode Exit fullscreen mode

20. Проверяем self-healing

kubectl get pods -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Удалите один Pod:

kubectl delete pod POD_NAME -n jumptotech
Enter fullscreen mode Exit fullscreen mode

Смотрите:

kubectl get pods -n jumptotech -w
Enter fullscreen mode Exit fullscreen mode

Объясняем:

Deployment desired replicas = 3
            ↓
ReplicaSet
            ↓
Pod deleted
            ↓
осталось 2
            ↓
replacement Pod
            ↓
снова 3
Enter fullscreen mode Exit fullscreen mode

После появления replacement Pod сравните:

kubectl get pods -n jumptotech -o wide
Enter fullscreen mode Exit fullscreen mode

с:

kubectl get endpointslice \
-n jumptotech \
-l kubernetes.io/service-name=web-service
Enter fullscreen mode Exit fullscreen mode

Новый Pod может иметь новый IP, но поскольку:

label = app=web
Enter fullscreen mode Exit fullscreen mode

Service продолжает выбирать его.


Что студент обязан знать после этого Lab

Я бы дала им именно эти объекты как Kubernetes Core Pack:

Namespace
   ↓
где логически находятся ресурсы

ConfigMap
   ↓
non-sensitive configuration

Secret
   ↓
sensitive configuration

ServiceAccount
   ↓
workload identity

Deployment
   ↓
desired application state

ReplicaSet
   ↓
maintains replica count

Pod
   ↓
smallest deployable workload unit

Container
   ↓
running application

Requests
   ↓
scheduler capacity decision

Limits
   ↓
resource ceiling

Liveness Probe
   ↓
"жив ли container/application?"

Readiness Probe
   ↓
"готов ли Pod получать traffic?"

Service
   ↓
stable service abstraction + selector

EndpointSlice
   ↓
backend addresses for Service

PDB
   ↓
protects availability during
voluntary disruptions

Ingress
   ↓
HTTP/HTTPS routing configuration

Ingress Controller
   ↓
implements/reconciles that configuration
Enter fullscreen mode Exit fullscreen mode

И главное: студенты должны не просто запомнить YAML, а уметь рассказать цепочку:

Image in ECR
      ↓
Deployment
      ↓
ReplicaSet
      ↓
Pod
      ↓
Container

Scheduler → chooses Node using requests
Kubelet   → manages assigned Pod/containers

ConfigMap + Secret → configuration
ServiceAccount     → workload identity

Service selector
      ↓
Pod labels
      ↓
EndpointSlice
      ↓
backend Pods

Ingress
      ↓
AWS Load Balancer Controller
      ↓
ALB
      ↓
Service/backend
Enter fullscreen mode Exit fullscreen mode

Top comments (0)