2.4 Kubernetes для начинающих #
📚 Градация сложности изучения Kubernetes:
- 🟢 Новичок (0-6 месяцев): Pod, Service, основные команды kubectl
- 🟡 Базовый (6-12 месяцев): Deployment, ConfigMap, Secrets, Ingress
- 🟠 Средний (1-2 года): Helm, operators, networking, storage
- 🔴 Продвинутый (2+ года): Custom resources, cluster administration, security
🟢 Что такое Kubernetes (простыми словами) #
Kubernetes — это как “умный управляющий” для контейнеров. Представьте, что у вас есть 100 контейнеров с приложениями, и вам нужно:
- Следить, чтобы они все работали
- Перезапускать упавшие
- Распределять нагрузку между ними
- Обновлять их без остановки сервиса
Kubernetes делает всё это автоматически!
Аналогия с дирижером оркестра:
- Docker — это музыканты (контейнеры)
- Kubernetes — это дирижер, который координирует их работу
🎯 Зачем нужен Kubernetes #
Проблемы без оркестрации #
Проблемы ручного управления контейнерами:
Обычный подход без Kubernetes:
- Отдельный запуск каждого контейнера app1, app2, app3 в фоновом режиме
- Отсутствие автоматического управления
Критические вопросы без оркестрации:
- Отказоустойчивость: Кто перезапустит упавший контейнер?
- Масштабирование: Как распределить нагрузку между контейнерами?
- Миграция: Как перенести контейнеры на другой сервер при сбое?
- Обновления: Как обновить приложение без прерывания сервиса?
Решение с Kubernetes #
Декларативное описание желаемого состояния приложения:
Конфигурация Deployment:
- API версия: apps/v1 (стандарт для приложений)
- Тип ресурса: Deployment (управление Pod’ами)
- Имя: “myapp” (уникальный идентификатор)
Параметры развертывания:
- Количество реплик: 3 экземпляра (высокая доступность)
- Селектор: метка “app: myapp” для связи с Pod’ами
- Образ контейнера: myapp:v1.0
- Порт: 8080 (внутренний порт контейнера)
Автоматические возможности Kubernetes:
- ✅ Автоматический запуск 3 экземпляров приложения
- ✅ Мгновенный перезапуск сломанных контейнеров
- ✅ Интеллектуальное распределение по серверам кластера
- ✅ Встроенная балансировка нагрузки между экземплярами
🏗️ Архитектура Kubernetes #
Control Plane (Управляющий слой) #
Компоненты управляющего узла (Master Node):
- API Server: Центральная точка входа для всех операций с кластером
- etcd: Распределенная база данных для хранения всего состояния кластера
- Controller: Множество контроллеров для управления различными ресурсами
- Scheduler: Планировщик, определяющий на каком узле запустить Pod
- Cloud Controller: Интеграция с облачными провайдерами (AWS, GCP, Azure)
Worker Nodes (Рабочие узлы) #
Компоненты рабочих узлов кластера:
- kubelet: Основной агент узла, отвечающий за запуск и мониторинг Pod’ов
- kube-proxy: Сетевой прокси для маршрутизации трафика к Service’ам
- Container Runtime: Движок контейнеров (Docker, containerd, CRI-O)
- Pods: Фактически запущенные приложения в контейнерах
Полная схема #
Схема взаимодействия компонентов Kubernetes кластера:
Архитектура кластера:
Мастер-узел (управляющий):
- API Server: центральная точка входа
- etcd: распределенное хранилище данных
- Controller: контроллеры ресурсов
Рабочие узлы (выполняющие):
- kubelet: агент для связи с мастером
- kube-proxy: сетевой маршрутизатор
- Container Runtime: движок контейнеров
- Pods: работающие приложения
Принцип работы: API Server на мастер-узле обменивается командами с kubelet’ами на рабочих узлах, координируя работу всего кластера
📦 Основные объекты Kubernetes #
1. Pod - минимальная единица развертывания #
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: nginx:latest
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
2. Deployment - управляет Pod’ами #
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v1.0
ports:
- containerPort: 8080
livenessProbe: # Проверка жизнеспособности
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe: # Проверка готовности
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
3. Service - сетевой доступ к Pod’ам #
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP # ClusterIP, NodePort, LoadBalancer, ExternalName
4. Ingress - внешний доступ HTTP/HTTPS #
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 80
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
🛠️ Установка и настройка #
Локальная разработка - Minikube #
# Установка minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Запуск локального кластера
minikube start --driver=docker --memory=4096 --cpus=2
# Проверка статуса
minikube status
# Доступ к dashboard
minikube dashboard
Установка kubectl (обновлено для 2025) #
# Метод 1: Через официальный репозиторий (рекомендуется)
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubectl
# Метод 2: Прямая загрузка актуальной версии
curl -LO "https://dl.k8s.io/release/v1.30.0/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# Метод 3: Через snap (Ubuntu)
sudo snap install kubectl --classic
# Проверить установку
kubectl version --client
# Включить автодополнение для bash
echo 'source <(kubectl completion bash)' >>~/.bashrc
source ~/.bashrc
Kind (Kubernetes in Docker) #
# Установка kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.17.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# Создание кластера
kind create cluster --name my-cluster
# Использование кластера
kubectl cluster-info --context kind-my-cluster
📋 Основные команды kubectl #
Информация о кластере #
# Информация о кластере
kubectl cluster-info
kubectl get nodes
kubectl describe node node-name
# Все ресурсы в кластере
kubectl get all --all-namespaces
# Версии API
kubectl api-versions
kubectl api-resources
Работа с Pod’ами #
# Просмотр pods
kubectl get pods # в текущем namespace
kubectl get pods -n kube-system # в конкретном namespace
kubectl get pods -o wide # с дополнительной информацией
kubectl get pods --watch # отслеживать изменения
# Детальная информация
kubectl describe pod pod-name
kubectl logs pod-name # логи
kubectl logs -f pod-name # следить за логами
kubectl logs pod-name -c container-name # логи конкретного контейнера
# Выполнение команд
kubectl exec -it pod-name -- bash # подключиться к pod
kubectl exec pod-name -- ls /app # выполнить команду
Применение конфигураций #
# Создание ресурсов
kubectl apply -f deployment.yaml # из файла
kubectl apply -f ./configs/ # из директории
kubectl apply -k ./kustomize/ # с Kustomize
# Удаление ресурсов
kubectl delete -f deployment.yaml
kubectl delete pod pod-name
kubectl delete deployment deployment-name
# Обновление ресурсов
kubectl replace -f deployment.yaml
kubectl patch deployment myapp -p '{"spec":{"replicas":5}}'
Масштабирование и обновления #
# Масштабирование
kubectl scale deployment myapp --replicas=5
# Rolling updates
kubectl set image deployment/myapp myapp=myapp:v2.0
kubectl rollout status deployment/myapp
kubectl rollout history deployment/myapp
kubectl rollout undo deployment/myapp
# Restart deployment
kubectl rollout restart deployment/myapp
🎯 Практический пример: Веб-приложение #
Структура проекта #
k8s-webapp/
├── app/
│ ├── Dockerfile
│ ├── app.py
│ └── requirements.txt
└── k8s/
├── namespace.yaml
├── deployment.yaml
├── service.yaml
└── ingress.yaml
app.py #
from flask import Flask, jsonify
import os
import socket
app = Flask(__name__)
@app.route('/')
def hello():
return jsonify({
'message': 'Hello from Kubernetes!',
'hostname': socket.gethostname(),
'version': os.getenv('APP_VERSION', 'v1.0')
})
@app.route('/health')
def health():
return jsonify({'status': 'healthy'})
@app.route('/ready')
def ready():
return jsonify({'status': 'ready'})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
k8s/namespace.yaml #
apiVersion: v1
kind: Namespace
metadata:
name: webapp
labels:
name: webapp
k8s/deployment.yaml #
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-deployment
namespace: webapp
labels:
app: webapp
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: webapp:v1.0
ports:
- containerPort: 8080
env:
- name: APP_VERSION
value: "v1.0"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
k8s/service.yaml #
apiVersion: v1
kind: Service
metadata:
name: webapp-service
namespace: webapp
spec:
selector:
app: webapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
k8s/ingress.yaml #
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
namespace: webapp
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- webapp.example.com
secretName: webapp-tls
rules:
- host: webapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-service
port:
number: 80
Развертывание #
# 1. Собрать Docker образ
cd app/
docker build -t webapp:v1.0 .
# 2. Для minikube загрузить в локальный registry
minikube image load webapp:v1.0
# 3. Применить конфигурации
kubectl apply -f k8s/
# 4. Проверить развертывание
kubectl get all -n webapp
# 5. Проверить доступность (для minikube)
minikube service webapp-service -n webapp
🔧 ConfigMaps и Secrets #
ConfigMap для конфигурации #
apiVersion: v1
kind: ConfigMap
metadata:
name: webapp-config
namespace: webapp
data:
database_url: "postgresql://localhost:5432/mydb"
log_level: "info"
feature_flag: "true"
config.properties: |
server.port=8080
server.host=0.0.0.0
database.connection.timeout=30s
Secret для чувствительных данных #
apiVersion: v1
kind: Secret
metadata:
name: webapp-secrets
namespace: webapp
type: Opaque
data:
database_password: cGFzc3dvcmQxMjM= # base64 encoded
api_key: YWJjZGVmZ2hpams= # base64 encoded
Использование в Deployment #
spec:
containers:
- name: webapp
image: webapp:v1.0
env:
# Из ConfigMap
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: webapp-config
key: database_url
# Из Secret
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: webapp-secrets
key: database_password
# Монтирование как файлы
volumeMounts:
- name: config-volume
mountPath: /etc/config
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: config-volume
configMap:
name: webapp-config
- name: secret-volume
secret:
secretName: webapp-secrets
📊 Мониторинг и логирование #
Prometheus + Grafana #
# prometheus-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml: |
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
Fluent Bit для логов #
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
spec:
selector:
matchLabels:
name: fluent-bit
template:
metadata:
labels:
name: fluent-bit
spec:
containers:
- name: fluent-bit
image: fluent/fluent-bit:latest
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: fluent-bit-config
mountPath: /fluent-bit/etc/
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: fluent-bit-config
configMap:
name: fluent-bit-config
🔒 Безопасность Kubernetes #
RBAC (Role-Based Access Control) #
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: webapp-sa
namespace: webapp
---
# Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: webapp-role
namespace: webapp
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: webapp-binding
namespace: webapp
subjects:
- kind: ServiceAccount
name: webapp-sa
namespace: webapp
roleRef:
kind: Role
name: webapp-role
apiGroup: rbac.authorization.k8s.io
Network Policies #
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: webapp-netpol
namespace: webapp
spec:
podSelector:
matchLabels:
app: webapp
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector:
matchLabels:
name: database
ports:
- protocol: TCP
port: 5432
Pod Security Standards #
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
🎯 Практические задания #
Задание 1: Настройка локального кластера Kubernetes (30 минут) #
# 1. Установка и настройка minikube
echo "🚀 Установка minikube..."
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
rm minikube-linux-amd64
# 2. Установка kubectl
echo "⚙️ Установка kubectl..."
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
rm kubectl
# 3. Запуск локального кластера
echo "🔄 Запуск кластера Kubernetes..."
minikube start --driver=docker --memory=4096 --cpus=2 --disk-size=20g
# 4. Проверка статуса
echo "✅ Проверка статуса кластера:"
minikube status
kubectl cluster-info
kubectl get nodes
# 5. Включение необходимых дополнений
echo "🔧 Включение дополнений..."
minikube addons enable dashboard
minikube addons enable metrics-server
minikube addons enable ingress
# 6. Настройка автодополнения kubectl
echo "📝 Настройка автодополнения..."
echo 'source <(kubectl completion bash)' >> ~/.bashrc
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -F __start_kubectl k' >> ~/.bashrc
# 7. Создание первого Pod
echo "🐳 Создание первого Pod..."
kubectl run test-pod --image=nginx:alpine --port=80
# 8. Проверка Pod
echo "🔍 Проверка Pod:"
kubectl get pods
kubectl describe pod test-pod
# 9. Создание Service для доступа к Pod
kubectl expose pod test-pod --type=NodePort --port=80
# 10. Получение URL для доступа
echo "🌐 URL для доступа к приложению:"
minikube service test-pod --url
# 11. Тестирование доступности
TEST_URL=$(minikube service test-pod --url)
curl -s $TEST_URL | head -n 5
# 12. Очистка ресурсов
echo "🧹 Очистка тестовых ресурсов..."
kubectl delete pod test-pod
kubectl delete service test-pod
echo "✅ Локальный кластер Kubernetes готов к использованию!"
Проверка: Кластер должен быть запущен, kubectl должен подключаться к кластеру, и тестовый Pod должен быть доступен.
Задание 2: Создание полноценного веб-приложения (45 минут) #
# 1. Создайте проект для Kubernetes приложения
mkdir ~/k8s-webapp && cd ~/k8s-webapp
# 2. Создайте простое веб-приложение
mkdir app
cat > app/app.py << 'EOF'
from flask import Flask, jsonify, request
import os
import socket
import datetime
import time
import random
app = Flask(__name__)
start_time = time.time()
@app.route('/')
def home():
return jsonify({
'message': 'Hello from Kubernetes!',
'hostname': socket.gethostname(),
'version': os.getenv('APP_VERSION', 'v1.0'),
'environment': os.getenv('ENVIRONMENT', 'development'),
'uptime_seconds': int(time.time() - start_time),
'timestamp': datetime.datetime.now().isoformat()
})
@app.route('/health')
def health():
# Симуляция проблем со здоровьем (5% вероятность)
if random.random() < 0.05:
return jsonify({'status': 'unhealthy', 'error': 'Random failure'}), 500
return jsonify({'status': 'healthy', 'uptime': int(time.time() - start_time)})
@app.route('/ready')
def ready():
# Симуляция времени готовности (10 секунд после запуска)
if time.time() - start_time < 10:
return jsonify({'status': 'not ready', 'message': 'Still starting up'}), 503
return jsonify({'status': 'ready'})
@app.route('/info')
def info():
return jsonify({
'hostname': socket.gethostname(),
'version': os.getenv('APP_VERSION', 'v1.0'),
'environment': os.getenv('ENVIRONMENT', 'development'),
'config': {
'database_url': os.getenv('DATABASE_URL', 'not configured'),
'cache_enabled': os.getenv('CACHE_ENABLED', 'false'),
'log_level': os.getenv('LOG_LEVEL', 'info')
},
'uptime_seconds': int(time.time() - start_time),
'start_time': datetime.datetime.fromtimestamp(start_time).isoformat()
})
@app.route('/load')
def load():
# Эндпоинт для создания нагрузки
duration = int(request.args.get('duration', 1))
cpu_load = float(request.args.get('cpu', 0.5))
start = time.time()
while time.time() - start < duration:
# Создаем CPU нагрузку
if random.random() < cpu_load:
sum(i*i for i in range(10000))
return jsonify({
'message': f'Generated load for {duration} seconds',
'cpu_load': cpu_load,
'hostname': socket.gethostname()
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=False)
EOF
# 3. Создайте requirements.txt
cat > app/requirements.txt << 'EOF'
Flask==2.3.3
gunicorn==21.2.0
EOF
# 4. Создайте Dockerfile
cat > app/Dockerfile << 'EOF'
FROM python:3.11-alpine
# Создание пользователя для безопасности
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
WORKDIR /app
# Установка зависимостей
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копирование приложения
COPY --chown=appuser:appgroup app.py .
USER appuser
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "--timeout", "30", "app:app"]
EOF
# 5. Создайте директорию для Kubernetes манифестов
mkdir k8s
# 6. Создайте Namespace
cat > k8s/01-namespace.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: webapp
labels:
name: webapp
environment: development
EOF
# 7. Создайте ConfigMap
cat > k8s/02-configmap.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: webapp-config
namespace: webapp
data:
DATABASE_URL: "postgresql://db:5432/webapp"
CACHE_ENABLED: "true"
LOG_LEVEL: "info"
ENVIRONMENT: "kubernetes"
# Файл конфигурации
app.properties: |
server.port=8080
server.host=0.0.0.0
database.connection.pool.size=10
cache.ttl=300
logging.level=info
EOF
# 8. Создайте Secret
cat > k8s/03-secret.yaml << 'EOF'
apiVersion: v1
kind: Secret
metadata:
name: webapp-secrets
namespace: webapp
type: Opaque
data:
# Пароли и ключи в base64
database_password: c2VjcmV0UGFzc3dvcmQ= # secretPassword
api_key: YWJjZGVmZ2hpams= # abcdefghijk
jwt_secret: bXlTdXBlclNlY3JldEtleQ== # mySuperSecretKey
EOF
# 9. Создайте Deployment
cat > k8s/04-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-deployment
namespace: webapp
labels:
app: webapp
version: v1.0
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
version: v1.0
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
spec:
containers:
- name: webapp
image: webapp:v1.0
imagePullPolicy: Never # Для локальных образов
ports:
- containerPort: 8080
name: http
env:
- name: APP_VERSION
value: "v1.0"
# Переменные из ConfigMap
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: webapp-config
key: DATABASE_URL
- name: CACHE_ENABLED
valueFrom:
configMapKeyRef:
name: webapp-config
key: CACHE_ENABLED
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: webapp-config
key: LOG_LEVEL
- name: ENVIRONMENT
valueFrom:
configMapKeyRef:
name: webapp-config
key: ENVIRONMENT
# Секреты
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: webapp-secrets
key: database_password
- name: API_KEY
valueFrom:
secretKeyRef:
name: webapp-secrets
key: api_key
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "300m"
# Проверки здоровья
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
# Монтирование конфигурационных файлов
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: config-volume
configMap:
name: webapp-config
items:
- key: app.properties
path: app.properties
- name: secret-volume
secret:
secretName: webapp-secrets
defaultMode: 0400
# Настройки безопасности
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
EOF
# 10. Создайте Service
cat > k8s/05-service.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: webapp-service
namespace: webapp
labels:
app: webapp
spec:
selector:
app: webapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
sessionAffinity: None
---
# NodePort Service для внешнего доступа
apiVersion: v1
kind: Service
metadata:
name: webapp-nodeport
namespace: webapp
labels:
app: webapp
spec:
selector:
app: webapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080
nodePort: 30080
type: NodePort
EOF
# 11. Создайте HorizontalPodAutoscaler
cat > k8s/06-hpa.yaml << 'EOF'
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: webapp-hpa
namespace: webapp
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: webapp-deployment
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
EOF
# 12. Создайте Ingress
cat > k8s/07-ingress.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
namespace: webapp
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: webapp.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-service
port:
number: 80
EOF
# 13. Соберите Docker образ
echo "🐳 Сборка Docker образа..."
cd app
docker build -t webapp:v1.0 .
cd ..
# 14. Загрузите образ в minikube
echo "⬆️ Загрузка образа в minikube..."
minikube image load webapp:v1.0
# 15. Примените все манифесты
echo "🚀 Развертывание приложения..."
kubectl apply -f k8s/
# 16. Ожидайте готовности
echo "⏳ Ожидание готовности всех Pod..."
kubectl wait --for=condition=ready pod -l app=webapp -n webapp --timeout=300s
# 17. Проверьте статус развертывания
echo "📊 Статус развертывания:"
kubectl get all -n webapp
echo ""
kubectl get configmap,secret -n webapp
echo ""
kubectl get hpa -n webapp
# 18. Тестирование приложения
echo "🧪 Тестирование приложения:"
# Получение URL через NodePort
NODE_PORT_URL="http://$(minikube ip):30080"
echo "NodePort URL: $NODE_PORT_URL"
# Тестирование различных эндпоинтов
echo "Тестирование главной страницы:"
curl -s $NODE_PORT_URL | python3 -m json.tool
echo -e "\nТестирование health check:"
curl -s $NODE_PORT_URL/health | python3 -m json.tool
echo -e "\nТестирование готовности:"
curl -s $NODE_PORT_URL/ready | python3 -m json.tool
echo -e "\nТестирование информации о приложении:"
curl -s $NODE_PORT_URL/info | python3 -m json.tool
# 19. Демонстрация балансировки нагрузки
echo -e "\n🔄 Демонстрация балансировки нагрузки:"
for i in {1..5}; do
echo "Запрос $i:"
curl -s $NODE_PORT_URL | jq -r '.hostname'
done
# 20. Создайте скрипт для мониторинга
cat > monitor-app.sh << 'EOF'
#!/bin/bash
echo "🔍 Мониторинг Kubernetes приложения"
echo "=================================="
while true; do
echo "$(date): Pods status:"
kubectl get pods -n webapp -o wide
echo -e "\nHPA status:"
kubectl get hpa -n webapp
echo -e "\nСобытия (последние 5):"
kubectl get events -n webapp --sort-by='.lastTimestamp' | tail -5
echo -e "\n" && sleep 30
done
EOF
chmod +x monitor-app.sh
echo "✅ Веб-приложение успешно развернуто!"
echo "🌐 Доступ к приложению: $NODE_PORT_URL"
echo "📊 Для мониторинга запустите: ./monitor-app.sh"
echo "🎯 Для создания нагрузки: curl '$NODE_PORT_URL/load?duration=5&cpu=0.8'"
Проверка: Все Pod должны быть в статусе Running, приложение должно отвечать на всех эндпоинтах, HPA должен быть настроен.
Задание 3: Управление конфигурацией и секретами (25 минут) #
# 1. Создайте проект для демонстрации конфигураций
mkdir ~/k8s-config-demo && cd ~/k8s-config-demo
# 2. Создайте ConfigMap с различными типами данных
cat > configmap-demo.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: multi-config
namespace: default
data:
# Простые переменные
database_host: "postgres.example.com"
database_port: "5432"
cache_size: "100"
debug_mode: "false"
# JSON конфигурация
app_config.json: |
{
"server": {
"port": 8080,
"host": "0.0.0.0",
"timeout": 30
},
"database": {
"max_connections": 100,
"connection_timeout": 30,
"retry_attempts": 3
},
"features": {
"authentication": true,
"caching": true,
"metrics": true
}
}
# YAML конфигурация
app_config.yaml: |
server:
port: 8080
host: 0.0.0.0
timeout: 30
database:
max_connections: 100
connection_timeout: 30
retry_attempts: 3
features:
authentication: true
caching: true
metrics: true
# Properties файл
app.properties: |
server.port=8080
server.host=0.0.0.0
database.url=jdbc:postgresql://postgres:5432/mydb
cache.enabled=true
cache.ttl=3600
logging.level=INFO
# Nginx конфигурация
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /health {
access_log off;
return 200 "healthy\n";
}
}
EOF
# 3. Создайте Secret с различными типами секретов
cat > secret-demo.yaml << 'EOF'
apiVersion: v1
kind: Secret
metadata:
name: multi-secret
namespace: default
type: Opaque
data:
# Пароли (base64 encoded)
database_password: cG9zdGdyZXNfcGFzc3dvcmQ= # postgres_password
redis_password: cmVkaXNfcGFzc3dvcmQ= # redis_password
admin_password: YWRtaW5fcGFzc3dvcmQ= # admin_password
# API ключи
github_token: Z2hwX2FiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MTIzNDU= # ghp_abcdefghijklmnopqrstuvwxyz12345
aws_access_key: QUtJQUlPU0ZPRE5ON0VYQU1QTEU= # AKIAIOSFODNN7EXAMPLE
aws_secret_key: d0phbHJYVXRuRkVNSS9LN01ERU5HL2JQWEZ1Q1lFWEFNUExFa2V5 # wJalrXUtnFEMI/K7MDENG/bPwFzuCYEXAMPLEkey
# TLS сертификаты (примеры)
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t # -----BEGIN CERTIFICATE-----
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0t # -----BEGIN PRIVATE KEY-----
---
# Docker registry secret
apiVersion: v1
kind: Secret
metadata:
name: docker-registry-secret
namespace: default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: eyJhdXRocyI6eyJyZWdpc3RyeS5leGFtcGxlLmNvbSI6eyJ1c2VybmFtZSI6InVzZXIiLCJwYXNzd29yZCI6InBhc3N3b3JkIiwiYXV0aCI6ImRYTmxjanB3WVhOemQyOXlaQT09In19fQ==
---
# TLS secret
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
namespace: default
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0t
EOF
# 4. Создайте Pod для демонстрации использования конфигураций
cat > config-consumer-pod.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: config-consumer
namespace: default
spec:
containers:
- name: app
image: busybox:latest
command: ['sh', '-c', 'while true; do sleep 30; done']
# Переменные окружения из ConfigMap
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: multi-config
key: database_host
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: multi-config
key: database_port
- name: CACHE_SIZE
valueFrom:
configMapKeyRef:
name: multi-config
key: cache_size
# Переменные из Secret
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: multi-secret
key: database_password
- name: GITHUB_TOKEN
valueFrom:
secretKeyRef:
name: multi-secret
key: github_token
# Монтирование файлов конфигурации
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
- name: nginx-config
mountPath: /etc/nginx
readOnly: true
volumes:
# Полный ConfigMap как том
- name: config-volume
configMap:
name: multi-config
# Secret как том с ограниченными правами
- name: secret-volume
secret:
secretName: multi-secret
defaultMode: 0400
# Отдельные файлы из ConfigMap
- name: nginx-config
configMap:
name: multi-config
items:
- key: nginx.conf
path: nginx.conf
mode: 0644
restartPolicy: Never
EOF
# 5. Примените все конфигурации
echo "📦 Создание ConfigMap и Secret..."
kubectl apply -f configmap-demo.yaml
kubectl apply -f secret-demo.yaml
echo "🚀 Запуск Pod для демонстрации..."
kubectl apply -f config-consumer-pod.yaml
# 6. Дождитесь запуска Pod
kubectl wait --for=condition=ready pod config-consumer --timeout=60s
# 7. Демонстрация переменных окружения
echo "🔍 Переменные окружения в Pod:"
kubectl exec config-consumer -- env | grep -E "(DATABASE|CACHE|GITHUB)" | sort
# 8. Демонстрация монтированных файлов
echo -e "\n📁 Конфигурационные файлы в /etc/config:"
kubectl exec config-consumer -- ls -la /etc/config/
echo -e "\n📄 Содержимое app_config.json:"
kubectl exec config-consumer -- cat /etc/config/app_config.json
echo -e "\n📄 Содержимое nginx.conf:"
kubectl exec config-consumer -- cat /etc/nginx/nginx.conf
echo -e "\n🔒 Секретные файлы в /etc/secrets:"
kubectl exec config-consumer -- ls -la /etc/secrets/
# Примечание: не показываем содержимое секретов в продакшене!
echo -e "\n⚠️ Содержимое секретов (только для демо):"
kubectl exec config-consumer -- sh -c 'echo "Database password: $(cat /etc/secrets/database_password)"'
# 9. Создайте Deployment с обновлением конфигурации
cat > config-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: config-demo-app
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: config-demo
template:
metadata:
labels:
app: config-demo
# Аннотация для автоматического перезапуска при изменении ConfigMap
annotations:
configmap/hash: "" # Будет обновляться автоматически
spec:
containers:
- name: app
image: nginx:alpine
ports:
- containerPort: 80
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: multi-config
key: database_host
- name: DEBUG_MODE
valueFrom:
configMapKeyRef:
name: multi-config
key: debug_mode
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/default.conf
subPath: nginx.conf
- name: app-config
mountPath: /etc/app/config.json
subPath: app_config.json
volumes:
- name: nginx-config
configMap:
name: multi-config
items:
- key: nginx.conf
path: nginx.conf
- name: app-config
configMap:
name: multi-config
items:
- key: app_config.json
path: app_config.json
EOF
echo -e "\n🚀 Создание Deployment с конфигурацией..."
kubectl apply -f config-deployment.yaml
# 10. Обновление ConfigMap и демонстрация rolling update
echo -e "\n🔄 Обновление конфигурации..."
kubectl patch configmap multi-config --patch '{"data":{"debug_mode":"true","cache_size":"200"}}'
# 11. Принудительный restart Deployment для применения изменений
kubectl rollout restart deployment config-demo-app
echo -e "\n⏳ Ожидание завершения rolling update..."
kubectl rollout status deployment config-demo-app
# 12. Проверка обновленной конфигурации
echo -e "\n✅ Проверка обновленных переменных:"
POD_NAME=$(kubectl get pods -l app=config-demo -o jsonpath='{.items[0].metadata.name}')
kubectl exec $POD_NAME -- env | grep -E "(DEBUG_MODE|CACHE_SIZE)"
# 13. Создайте скрипт для демонстрации управления секретами
cat > manage-secrets.sh << 'EOF'
#!/bin/bash
echo "🔐 Демонстрация управления секретами в Kubernetes"
echo "================================================"
# Создание секрета из командной строки
echo "1. Создание секрета из командной строки:"
kubectl create secret generic cli-secret \
--from-literal=username=admin \
--from-literal=password=secret123 \
--dry-run=client -o yaml
echo -e "\n2. Создание секрета из файлов:"
echo "secret-value-1" > /tmp/secret1.txt
echo "secret-value-2" > /tmp/secret2.txt
kubectl create secret generic file-secret \
--from-file=/tmp/secret1.txt \
--from-file=/tmp/secret2.txt \
--dry-run=client -o yaml
echo -e "\n3. Создание Docker registry секрета:"
kubectl create secret docker-registry my-registry-secret \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=myemail@example.com \
--dry-run=client -o yaml
echo -e "\n4. Создание TLS секрета:"
# В реальности вы бы использовали настоящие сертификаты
kubectl create secret tls my-tls-secret \
--cert=/path/to/cert/file \
--key=/path/to/key/file \
--dry-run=client -o yaml || echo "Нужны реальные сертификаты"
echo -e "\n5. Просмотр секретов (без значений):"
kubectl get secrets
kubectl describe secret multi-secret
echo -e "\n6. Декодирование секрета (только для демонстрации!):"
kubectl get secret multi-secret -o jsonpath='{.data.database_password}' | base64 -d
echo ""
# Очистка временных файлов
rm -f /tmp/secret*.txt
EOF
chmod +x manage-secrets.sh
echo -e "\n📚 Демонстрация управления конфигурацией завершена!"
echo "🔧 Для изучения управления секретами запустите: ./manage-secrets.sh"
echo "🧹 Для очистки ресурсов:"
echo " kubectl delete pod config-consumer"
echo " kubectl delete deployment config-demo-app"
echo " kubectl delete configmap multi-config"
echo " kubectl delete secret multi-secret docker-registry-secret tls-secret"
Проверка: Pod должен получать переменные из ConfigMap и Secret, файлы должны быть правильно смонтированы, обновление конфигурации должно приводить к rolling update.
Задание 4: Автомасштабирование и нагрузочное тестирование (35 минут) #
# 1. Создайте проект для демонстрации автомасштабирования
mkdir ~/k8s-scaling-demo && cd ~/k8s-scaling-demo
# 2. Создайте приложение с возможностью создания нагрузки
cat > stress-app.py << 'EOF'
from flask import Flask, jsonify, request
import multiprocessing
import time
import os
import threading
app = Flask(__name__)
# Глобальная переменная для отслеживания нагрузки
current_load = 0
load_lock = threading.Lock()
@app.route('/')
def home():
return jsonify({
'message': 'Stress Test Application',
'hostname': os.uname().nodename,
'current_load': current_load,
'cpu_count': multiprocessing.cpu_count()
})
@app.route('/health')
def health():
return jsonify({'status': 'healthy'})
@app.route('/stress')
def stress():
global current_load
# Параметры нагрузки
duration = int(request.args.get('duration', 10))
intensity = float(request.args.get('intensity', 0.5))
def cpu_stress():
global current_load
with load_lock:
current_load += 1
start_time = time.time()
while time.time() - start_time < duration:
# Создаем CPU нагрузку
if time.time() % 1 < intensity:
sum(i * i for i in range(10000))
with load_lock:
current_load -= 1
# Запускаем нагрузку в отдельном потоке
thread = threading.Thread(target=cpu_stress)
thread.start()
return jsonify({
'message': f'Started stress test for {duration} seconds',
'intensity': intensity,
'hostname': os.uname().nodename,
'active_stress_threads': current_load
})
@app.route('/memory-stress')
def memory_stress():
"""Создает нагрузку на память"""
size_mb = int(request.args.get('size', 50))
duration = int(request.args.get('duration', 10))
def memory_load():
# Выделяем память
data = []
for i in range(size_mb):
# Создаем массив размером ~1MB
chunk = bytearray(1024 * 1024)
data.append(chunk)
# Держим память занятой
time.sleep(duration)
# Освобождаем память
del data
thread = threading.Thread(target=memory_load)
thread.start()
return jsonify({
'message': f'Started memory stress test: {size_mb}MB for {duration} seconds',
'hostname': os.uname().nodename
})
@app.route('/metrics')
def metrics():
"""Простые метрики для мониторинга"""
import psutil
return jsonify({
'cpu_percent': psutil.cpu_percent(),
'memory_percent': psutil.virtual_memory().percent,
'hostname': os.uname().nodename,
'active_stress_threads': current_load
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=False)
EOF
# 3. Создайте requirements.txt
cat > requirements.txt << 'EOF'
Flask==2.3.3
psutil==5.9.5
gunicorn==21.2.0
EOF
# 4. Создайте Dockerfile
cat > Dockerfile << 'EOF'
FROM python:3.11-slim
# Установка системных утилит
RUN apt-get update && apt-get install -y \
stress-ng \
htop \
&& rm -rf /var/lib/apt/lists/*
# Создание пользователя
RUN addgroup --gid 1001 appgroup && \
adduser --uid 1001 --gid 1001 --disabled-password --gecos "" appuser
WORKDIR /app
# Установка Python зависимостей
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копирование приложения
COPY --chown=appuser:appgroup stress-app.py .
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "--timeout", "60", "stress-app:app"]
EOF
# 5. Создайте Deployment с ресурсными ограничениями
cat > stress-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: stress-app
namespace: default
labels:
app: stress-app
spec:
replicas: 2
selector:
matchLabels:
app: stress-app
template:
metadata:
labels:
app: stress-app
spec:
containers:
- name: stress-app
image: stress-app:latest
imagePullPolicy: Never
ports:
- containerPort: 8080
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "400m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: stress-app-service
labels:
app: stress-app
spec:
selector:
app: stress-app
ports:
- name: http
port: 80
targetPort: 8080
type: ClusterIP
---
# NodePort для внешнего доступа
apiVersion: v1
kind: Service
metadata:
name: stress-app-nodeport
labels:
app: stress-app
spec:
selector:
app: stress-app
ports:
- name: http
port: 80
targetPort: 8080
nodePort: 30090
type: NodePort
EOF
# 6. Создайте HorizontalPodAutoscaler
cat > hpa.yaml << 'EOF'
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: stress-app-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: stress-app
minReplicas: 2
maxReplicas: 8
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 180
policies:
- type: Percent
value: 50
periodSeconds: 60
EOF
# 7. Создайте VPA (Vertical Pod Autoscaler) для демонстрации
cat > vpa.yaml << 'EOF'
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: stress-app-vpa
namespace: default
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: stress-app
updatePolicy:
updateMode: "Off" # Только рекомендации, без автоматического обновления
resourcePolicy:
containerPolicies:
- containerName: stress-app
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 500m
memory: 512Mi
controlledResources: ["cpu", "memory"]
EOF
# 8. Соберите и разверните приложение
echo "🐳 Сборка Docker образа..."
docker build -t stress-app:latest .
echo "⬆️ Загрузка образа в minikube..."
minikube image load stress-app:latest
echo "🚀 Развертывание приложения..."
kubectl apply -f stress-deployment.yaml
echo "⏳ Ожидание готовности Pod..."
kubectl wait --for=condition=ready pod -l app=stress-app --timeout=120s
echo "📊 Применение HPA..."
kubectl apply -f hpa.yaml
# Применение VPA только если установлен VPA controller
kubectl apply -f vpa.yaml 2>/dev/null || echo "VPA не установлен, пропускаем"
# 9. Создайте скрипт для мониторинга автомасштабирования
cat > monitor-scaling.sh << 'EOF'
#!/bin/bash
echo "📊 Мониторинг автомасштабирования Kubernetes"
echo "============================================"
while true; do
clear
echo "$(date)"
echo "============================================"
echo "🏃 HPA Status:"
kubectl get hpa stress-app-hpa
echo -e "\n📦 Pod Status:"
kubectl get pods -l app=stress-app -o wide
echo -e "\n📈 Resource Usage:"
kubectl top pods -l app=stress-app 2>/dev/null || echo "Metrics server недоступен"
echo -e "\n🎯 Node Resources:"
kubectl top nodes 2>/dev/null || echo "Metrics server недоступен"
echo -e "\n📋 Recent Events:"
kubectl get events --field-selector involvedObject.name=stress-app-hpa --sort-by='.lastTimestamp' | tail -3
echo -e "\nPress Ctrl+C to stop monitoring"
sleep 10
done
EOF
chmod +x monitor-scaling.sh
# 10. Создайте скрипт для генерации нагрузки
cat > generate-load.sh << 'EOF'
#!/bin/bash
NODEPORT_URL="http://$(minikube ip):30090"
echo "🔥 Генератор нагрузки для тестирования автомасштабирования"
echo "URL приложения: $NODEPORT_URL"
echo "========================================================="
echo "1. Проверка доступности приложения:"
curl -s $NODEPORT_URL | python3 -m json.tool
echo -e "\n2. Создание базовой нагрузки (10 параллельных запросов):"
for i in {1..10}; do
curl -s "$NODEPORT_URL/stress?duration=30&intensity=0.3" &
done
wait
echo -e "\n3. Создание высокой CPU нагрузки:"
for i in {1..5}; do
curl -s "$NODEPORT_URL/stress?duration=60&intensity=0.8" &
done
echo -e "\n4. Создание нагрузки на память:"
for i in {1..3}; do
curl -s "$NODEPORT_URL/memory-stress?size=100&duration=60" &
done
echo -e "\n5. Непрерывная нагрузка (для демонстрации масштабирования):"
while true; do
curl -s "$NODEPORT_URL/stress?duration=20&intensity=0.7" > /dev/null &
curl -s "$NODEPORT_URL/memory-stress?size=80&duration=20" > /dev/null &
sleep 5
done
EOF
chmod +x generate-load.sh
# 11. Создайте скрипт для тестирования различных сценариев
cat > test-scenarios.sh << 'EOF'
#!/bin/bash
NODEPORT_URL="http://$(minikube ip):30090"
echo "🧪 Сценарии тестирования автомасштабирования"
echo "============================================"
function wait_for_scaling() {
echo "⏳ Ожидание масштабирования (60 секунд)..."
sleep 60
kubectl get hpa stress-app-hpa
kubectl get pods -l app=stress-app
}
echo "Сценарий 1: Постепенное увеличение нагрузки"
echo "-------------------------------------------"
for intensity in 0.2 0.4 0.6 0.8; do
echo "Интенсивность: $intensity"
for i in {1..5}; do
curl -s "$NODEPORT_URL/stress?duration=30&intensity=$intensity" > /dev/null &
done
wait_for_scaling
done
echo -e "\nСценарий 2: Пиковая нагрузка"
echo "----------------------------"
for i in {1..20}; do
curl -s "$NODEPORT_URL/stress?duration=90&intensity=0.9" > /dev/null &
done
wait_for_scaling
echo -e "\nСценарий 3: Смешанная нагрузка (CPU + Memory)"
echo "---------------------------------------------"
for i in {1..10}; do
curl -s "$NODEPORT_URL/stress?duration=60&intensity=0.6" > /dev/null &
curl -s "$NODEPORT_URL/memory-stress?size=120&duration=60" > /dev/null &
done
wait_for_scaling
echo -e "\nСценарий 4: Снижение нагрузки (scale down)"
echo "------------------------------------------"
echo "Прекращение генерации нагрузки..."
pkill -f curl
echo "Ожидание уменьшения количества Pod (3 минуты)..."
sleep 180
kubectl get hpa stress-app-hpa
kubectl get pods -l app=stress-app
echo -e "\n✅ Тестирование завершено!"
EOF
chmod +x test-scenarios.sh
# 12. Запустите мониторинг и начальное тестирование
echo "📊 Текущий статус HPA:"
kubectl get hpa
echo -e "\n📦 Текущие Pod:"
kubectl get pods -l app=stress-app
echo -e "\n🌐 URL приложения: http://$(minikube ip):30090"
echo -e "\n📚 Доступные скрипты:"
echo " ./monitor-scaling.sh - Мониторинг автомасштабирования"
echo " ./generate-load.sh - Генерация нагрузки"
echo " ./test-scenarios.sh - Тестирование различных сценариев"
echo -e "\n🧪 Базовое тестирование:"
NODEPORT_URL="http://$(minikube ip):30090"
echo "Проверка приложения:"
curl -s $NODEPORT_URL | python3 -m json.tool
echo -e "\nСоздание легкой нагрузки для демонстрации:"
curl -s "$NODEPORT_URL/stress?duration=30&intensity=0.5" | python3 -m json.tool
echo -e "\n⚡ Для наблюдения за автомасштабированием запустите в отдельных терминалах:"
echo " Terminal 1: ./monitor-scaling.sh"
echo " Terminal 2: ./generate-load.sh"
Проверка: HPA должен корректно масштабировать Pod при увеличении нагрузки, метрики должны отображаться, и количество Pod должно увеличиваться/уменьшаться в зависимости от нагрузки.
Задание 5: Производственный деплой с мониторингом (40 минут) #
# 1. Создайте проект для производственного деплоя
mkdir ~/k8s-production && cd ~/k8s-production
# 2. Создайте namespace для production
cat > 01-namespace.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
name: production
environment: production
tier: production
---
# Resource quota для production namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
services: "10"
persistentvolumeclaims: "5"
---
# Limit range для Pod
apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
namespace: production
spec:
limits:
- default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
type: Container
EOF
# 3. Создайте RBAC конфигурацию
cat > 02-rbac.yaml << 'EOF'
# Service Account для production приложений
apiVersion: v1
kind: ServiceAccount
metadata:
name: production-app-sa
namespace: production
---
# Role для production приложений
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: production-app-role
namespace: production
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: production-app-binding
namespace: production
subjects:
- kind: ServiceAccount
name: production-app-sa
namespace: production
roleRef:
kind: Role
name: production-app-role
apiGroup: rbac.authorization.k8s.io
EOF
# 4. Создайте Network Policy
cat > 03-network-policy.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: production-netpol
namespace: production
spec:
podSelector:
matchLabels:
app: production-app
policyTypes:
- Ingress
- Egress
ingress:
# Разрешить трафик от ingress controller
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
# Разрешить трафик для мониторинга
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 8080
egress:
# Разрешить DNS
- to: []
ports:
- protocol: UDP
port: 53
# Разрешить HTTPS (для внешних API)
- to: []
ports:
- protocol: TCP
port: 443
# Разрешить доступ к базе данных
- to:
- namespaceSelector:
matchLabels:
name: database
ports:
- protocol: TCP
port: 5432
EOF
# 5. Создайте Pod Security Policy
cat > 04-pod-security.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: security-example
namespace: production
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:alpine
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
volumeMounts:
- name: tmp
mountPath: /tmp
- name: var-cache
mountPath: /var/cache/nginx
- name: var-run
mountPath: /var/run
volumes:
- name: tmp
emptyDir: {}
- name: var-cache
emptyDir: {}
- name: var-run
emptyDir: {}
restartPolicy: Never
EOF
# 6. Создайте приложение с мониторингом
cat > production-app.py << 'EOF'
from flask import Flask, jsonify, request, Response
import os
import socket
import time
import psutil
import json
import logging
from datetime import datetime
from prometheus_client import Counter, Histogram, Gauge, generate_latest, CONTENT_TYPE_LATEST
# Настройка логирования
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(),
logging.FileHandler('/tmp/app.log')
]
)
logger = logging.getLogger(__name__)
app = Flask(__name__)
# Prometheus метрики
REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint', 'status'])
REQUEST_DURATION = Histogram('http_request_duration_seconds', 'HTTP request duration')
ACTIVE_CONNECTIONS = Gauge('active_connections', 'Number of active connections')
APP_INFO = Gauge('app_info', 'Application info', ['version', 'hostname'])
# Инициализация метрик
APP_INFO.labels(version=os.getenv('APP_VERSION', 'unknown'), hostname=socket.gethostname()).set(1)
@app.before_request
def before_request():
request.start_time = time.time()
ACTIVE_CONNECTIONS.inc()
@app.after_request
def after_request(response):
REQUEST_COUNT.labels(
method=request.method,
endpoint=request.endpoint or 'unknown',
status=response.status_code
).inc()
REQUEST_DURATION.observe(time.time() - request.start_time)
ACTIVE_CONNECTIONS.dec()
return response
@app.route('/')
def home():
logger.info("Home endpoint accessed")
return jsonify({
'message': 'Production Application',
'hostname': socket.gethostname(),
'version': os.getenv('APP_VERSION', 'v1.0'),
'environment': os.getenv('ENVIRONMENT', 'production'),
'timestamp': datetime.now().isoformat(),
'status': 'healthy'
})
@app.route('/health')
def health():
"""Health check endpoint"""
try:
# Проверки здоровья приложения
cpu_percent = psutil.cpu_percent()
memory_percent = psutil.virtual_memory().percent
disk_percent = psutil.disk_usage('/').percent
# Определение статуса
if cpu_percent > 90 or memory_percent > 90 or disk_percent > 90:
status = 'degraded'
else:
status = 'healthy'
return jsonify({
'status': status,
'checks': {
'cpu_percent': cpu_percent,
'memory_percent': memory_percent,
'disk_percent': disk_percent
},
'hostname': socket.gethostname(),
'timestamp': datetime.now().isoformat()
})
except Exception as e:
logger.error(f"Health check failed: {e}")
return jsonify({
'status': 'unhealthy',
'error': str(e),
'hostname': socket.gethostname()
}), 500
@app.route('/ready')
def ready():
"""Readiness check endpoint"""
# Проверка готовности (например, подключение к БД)
return jsonify({
'status': 'ready',
'hostname': socket.gethostname(),
'timestamp': datetime.now().isoformat()
})
@app.route('/metrics')
def metrics():
"""Prometheus metrics endpoint"""
return Response(generate_latest(), mimetype=CONTENT_TYPE_LATEST)
@app.route('/info')
def info():
"""Detailed application information"""
return jsonify({
'application': {
'name': 'production-app',
'version': os.getenv('APP_VERSION', 'v1.0'),
'environment': os.getenv('ENVIRONMENT', 'production'),
'hostname': socket.gethostname()
},
'system': {
'cpu_count': psutil.cpu_count(),
'memory_total_gb': round(psutil.virtual_memory().total / (1024**3), 2),
'disk_total_gb': round(psutil.disk_usage('/').total / (1024**3), 2)
},
'configuration': {
'database_url': os.getenv('DATABASE_URL', 'not configured'),
'cache_enabled': os.getenv('CACHE_ENABLED', 'false'),
'log_level': os.getenv('LOG_LEVEL', 'info'),
'max_connections': os.getenv('MAX_CONNECTIONS', '100')
},
'runtime': {
'start_time': datetime.fromtimestamp(psutil.Process().create_time()).isoformat(),
'uptime_seconds': int(time.time() - psutil.Process().create_time()),
'python_version': os.sys.version
}
})
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': 'Not found', 'hostname': socket.gethostname()}), 404
@app.errorhandler(500)
def internal_error(error):
logger.error(f"Internal server error: {error}")
return jsonify({'error': 'Internal server error', 'hostname': socket.gethostname()}), 500
if __name__ == '__main__':
logger.info("Starting production application")
app.run(host='0.0.0.0', port=8080, debug=False)
EOF
# 7. Создайте requirements.txt
cat > requirements.txt << 'EOF'
Flask==2.3.3
gunicorn==21.2.0
psutil==5.9.5
prometheus-client==0.17.1
EOF
# 8. Создайте production Dockerfile
cat > Dockerfile << 'EOF'
FROM python:3.11-slim
# Метаданные
LABEL maintainer="devops@company.com"
LABEL version="2.0.0"
LABEL description="Production Flask Application with Monitoring"
# Установка системных зависимостей
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
procps \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# Создание пользователя
RUN groupadd -r -g 1000 appgroup && \
useradd -r -u 1000 -g appgroup -m -s /bin/false appuser
# Создание директорий
RUN mkdir -p /app /tmp/app-logs && \
chown -R appuser:appgroup /app /tmp/app-logs
WORKDIR /app
# Установка Python зависимостей
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
# Копирование приложения
COPY --chown=appuser:appgroup production-app.py .
# Переключение на непривилегированного пользователя
USER appuser
# Переменные окружения
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV FLASK_ENV=production
ENV APP_VERSION=v2.0.0
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=15s --start-period=30s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# Запуск с Gunicorn
CMD ["gunicorn", \
"--bind", "0.0.0.0:8080", \
"--workers", "3", \
"--timeout", "60", \
"--max-requests", "1000", \
"--max-requests-jitter", "100", \
"--preload", \
"--access-logfile", "-", \
"--error-logfile", "-", \
"production-app:app"]
EOF
# 9. Создайте ConfigMap для production
cat > 05-configmap.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: production-config
namespace: production
data:
ENVIRONMENT: "production"
DATABASE_URL: "postgresql://prod-db:5432/production"
CACHE_ENABLED: "true"
LOG_LEVEL: "info"
MAX_CONNECTIONS: "200"
# Конфигурационные файлы
gunicorn.conf.py: |
import multiprocessing
bind = "0.0.0.0:8080"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
worker_connections = 1000
max_requests = 1000
max_requests_jitter = 100
preload_app = True
timeout = 60
keepalive = 5
# Logging
accesslog = "-"
errorlog = "-"
loglevel = "info"
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
def when_ready(server):
server.log.info("Server is ready. Spawning workers")
def worker_int(worker):
worker.log.info("worker received INT or QUIT signal")
def on_exit(server):
server.log.info("Server is shutting down")
EOF
# 10. Создайте Secret для production
cat > 06-secret.yaml << 'EOF'
apiVersion: v1
kind: Secret
metadata:
name: production-secrets
namespace: production
type: Opaque
data:
# Production пароли (base64 encoded)
database_password: cHJvZHVjdGlvbl9wYXNzd29yZA== # production_password
api_key: cHJvZF9hcGlfa2V5XzEyMzQ1Ng== # prod_api_key_123456
jwt_secret: cHJvZF9qd3Rfc2VjcmV0X2tleQ== # prod_jwt_secret_key
redis_password: cHJvZF9yZWRpc19wYXNzd29yZA== # prod_redis_password
EOF
# 11. Создайте production Deployment
cat > 07-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: production-app
namespace: production
labels:
app: production-app
version: v2.0.0
tier: backend
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # Zero downtime deployment
selector:
matchLabels:
app: production-app
template:
metadata:
labels:
app: production-app
version: v2.0.0
tier: backend
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
config.hash: "{{ checksum }}" # Для автоматического обновления при изменении конфигурации
spec:
serviceAccountName: production-app-sa
# Настройки безопасности
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: production-app
image: production-app:v2.0.0
imagePullPolicy: Never
ports:
- containerPort: 8080
name: http
protocol: TCP
# Переменные окружения из ConfigMap
envFrom:
- configMapRef:
name: production-config
env:
- name: APP_VERSION
value: "v2.0.0"
# Секреты
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: production-secrets
key: database_password
- name: API_KEY
valueFrom:
secretKeyRef:
name: production-secrets
key: api_key
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: production-secrets
key: jwt_secret
# Ресурсы для production
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
# Production health checks
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
successThreshold: 1
readinessProbe:
httpGet:
path: /ready
port: 8080
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
# Startup probe для медленно стартующих приложений
startupProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 10
# Security context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
# Volume mounts
volumeMounts:
- name: tmp
mountPath: /tmp
- name: app-logs
mountPath: /tmp/app-logs
- name: config-volume
mountPath: /etc/app-config
readOnly: true
volumes:
- name: tmp
emptyDir: {}
- name: app-logs
emptyDir: {}
- name: config-volume
configMap:
name: production-config
items:
- key: gunicorn.conf.py
path: gunicorn.conf.py
# Распределение Pod по узлам
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- production-app
topologyKey: kubernetes.io/hostname
# Tolerations для production nodes
tolerations:
- key: "production"
operator: "Equal"
value: "true"
effect: "NoSchedule"
# Graceful shutdown
terminationGracePeriodSeconds: 60
EOF
# 12. Создайте Services
cat > 08-service.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: production-app-service
namespace: production
labels:
app: production-app
spec:
selector:
app: production-app
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
sessionAffinity: None
---
# Headless service для direct Pod access
apiVersion: v1
kind: Service
metadata:
name: production-app-headless
namespace: production
labels:
app: production-app
spec:
selector:
app: production-app
ports:
- name: http
port: 8080
targetPort: 8080
clusterIP: None
---
# NodePort для внешнего доступа
apiVersion: v1
kind: Service
metadata:
name: production-app-nodeport
namespace: production
labels:
app: production-app
spec:
selector:
app: production-app
ports:
- name: http
port: 80
targetPort: 8080
nodePort: 30100
type: NodePort
EOF
# 13. Создайте HPA для production
cat > 09-hpa.yaml << 'EOF'
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: production-app-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: production-app
minReplicas: 3
maxReplicas: 15
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 50
periodSeconds: 60
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 25
periodSeconds: 60
EOF
# 14. Создайте PodDisruptionBudget
cat > 10-pdb.yaml << 'EOF'
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: production-app-pdb
namespace: production
spec:
selector:
matchLabels:
app: production-app
minAvailable: 2 # Минимум 2 Pod должны быть доступны во время обновлений
EOF
# 15. Соберите и разверните приложение
echo "🐳 Сборка production Docker образа..."
docker build -t production-app:v2.0.0 .
echo "⬆️ Загрузка образа в minikube..."
minikube image load production-app:v2.0.0
echo "🚀 Развертывание production приложения..."
kubectl apply -f 01-namespace.yaml
kubectl apply -f 02-rbac.yaml
kubectl apply -f 03-network-policy.yaml
kubectl apply -f 05-configmap.yaml
kubectl apply -f 06-secret.yaml
kubectl apply -f 07-deployment.yaml
kubectl apply -f 08-service.yaml
kubectl apply -f 09-hpa.yaml
kubectl apply -f 10-pdb.yaml
echo "⏳ Ожидание готовности всех Pod..."
kubectl wait --for=condition=ready pod -l app=production-app -n production --timeout=300s
# 16. Создайте скрипт для мониторинга production
cat > production-monitor.sh << 'EOF'
#!/bin/bash
echo "📊 Production Kubernetes Application Monitor"
echo "==========================================="
while true; do
clear
echo "$(date)"
echo "==========================================="
echo "🏗️ Deployment Status:"
kubectl get deployment -n production
echo -e "\n📦 Pod Status:"
kubectl get pods -n production -o wide
echo -e "\n🔄 HPA Status:"
kubectl get hpa -n production
echo -e "\n📊 Resource Usage:"
kubectl top pods -n production 2>/dev/null || echo "Metrics server unavailable"
echo -e "\n🚦 Service Status:"
kubectl get services -n production
echo -e "\n📋 Recent Events:"
kubectl get events -n production --sort-by='.lastTimestamp' | tail -5
echo -e "\n🔒 Security Status:"
kubectl get pdb,networkpolicy -n production
echo -e "\nPress Ctrl+C to stop monitoring"
sleep 15
done
EOF
chmod +x production-monitor.sh
# 17. Создайте скрипт для health checks
cat > health-checks.sh << 'EOF'
#!/bin/bash
NODEPORT_URL="http://$(minikube ip):30100"
echo "🏥 Production Application Health Checks"
echo "======================================"
echo "Application URL: $NODEPORT_URL"
echo ""
function check_endpoint() {
local endpoint=$1
local expected_status=$2
echo -n "Checking $endpoint... "
response=$(curl -s -w "%{http_code}" $NODEPORT_URL$endpoint)
status_code="${response: -3}"
body="${response%???}"
if [ "$status_code" -eq "$expected_status" ]; then
echo "✅ OK ($status_code)"
if [ "$endpoint" != "/metrics" ]; then
echo "$body" | python3 -m json.tool 2>/dev/null || echo "$body"
fi
else
echo "❌ FAILED (expected $expected_status, got $status_code)"
echo "Response: $body"
fi
echo ""
}
echo "1. Health Checks:"
check_endpoint "/" 200
check_endpoint "/health" 200
check_endpoint "/ready" 200
check_endpoint "/info" 200
echo "2. Metrics Check:"
check_endpoint "/metrics" 200
echo "3. Error Handling:"
check_endpoint "/non-existent" 404
echo "4. Load Balancing Test:"
echo "Testing load balancing across pods..."
for i in {1..5}; do
hostname=$(curl -s $NODEPORT_URL | python3 -c "import sys, json; print(json.load(sys.stdin)['hostname'])" 2>/dev/null)
echo "Request $i: Pod $hostname"
done
echo -e "\n5. Resource Monitoring:"
echo "Pod resource usage:"
kubectl top pods -n production 2>/dev/null || echo "Metrics server unavailable"
echo -e "\n6. Application Logs (last 10 lines):"
kubectl logs -n production -l app=production-app --tail=10 --prefix=true
echo -e "\n✅ Health checks completed!"
EOF
chmod +x health-checks.sh
# 18. Выполните итоговые проверки
echo "📊 Production deployment status:"
kubectl get all -n production
echo -e "\n🌐 Application URL: http://$(minikube ip):30100"
echo -e "\n🧪 Running initial health checks..."
sleep 10
./health-checks.sh
echo -e "\n📚 Available monitoring scripts:"
echo " ./production-monitor.sh - Continuous monitoring"
echo " ./health-checks.sh - Health and functionality checks"
echo -e "\n✅ Production deployment completed!"
echo "🎯 Key features implemented:"
echo " - Resource quotas and limits"
echo " - RBAC security"
echo " - Network policies"
echo " - Pod security contexts"
echo " - Health checks and monitoring"
echo " - Horizontal autoscaling"
echo " - Pod disruption budgets"
echo " - Zero-downtime deployments"
Проверка: Production приложение должно быть развернуто с полной конфигурацией безопасности, все health checks должны проходить, мониторинг должен показывать корректные метрики, и автомасштабирование должно работать.
📊 Проверочный тест Kubernetes #
- Какая команда показывает все Pod во всех namespace?
- Как масштабировать Deployment до 5 реплик?
- Какой тип Service обеспечивает внешний доступ через LoadBalancer?
- Как посмотреть логи всех Pod с лейблом app=myapp?
- Какая команда применяет все YAML файлы из директории?
Ответы:
kubectl get pods --all-namespaces
kubectl scale deployment myapp --replicas=5
LoadBalancer
kubectl logs -l app=myapp
kubectl apply -f ./directory/
🛠️ Полезные инструменты #
k9s - TUI для Kubernetes #
# Установка
curl -sS https://webinstall.dev/k9s | bash
# Использование
k9s
Helm - пакетный менеджер #
# Установка Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Добавить репозиторий
helm repo add stable https://charts.helm.sh/stable
helm repo update
# Установить приложение
helm install my-release stable/mysql
# Список установленных релизов
helm list
Kustomize - управление конфигурациями #
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
namePrefix: prod-
namespace: production
images:
- name: myapp
newTag: v2.0
replicas:
- name: webapp-deployment
count: 5
🎯 Заключение #
Kubernetes — это мощная платформа оркестрации, но и сложная. Ключевые принципы:
✅ Изучайте постепенно - начните с Pod, Service, Deployment
✅ Практикуйтесь локально - используйте minikube или kind
✅ Понимайте архитектуру - как компоненты взаимодействуют
✅ Используйте декларативный подход - YAML манифесты
✅ Мониторьте и логируйте - observability критически важна
✅ Думайте о безопасности - RBAC, Network Policies, Pod Security
Помните: Kubernetes - это марафон, а не спринт. Не пытайтесь изучить всё сразу. Начните с основ и постепенно углубляйтесь в детали.
Следующий раздел: 2.5 Облачные платформы