|
Docker
Docker - команды
Установкаsudo apt install docker.io sudo chmod 666 /var/run/docker.sock
список образов (классов):
docker images
список активных контейнеров (объектов)
docker ps -a-a - историй запусков
запуск образа:
docker run py_app:v0.1Ключи
-d (--detach) - запускает в фоновом режиме контейнер и выводит в консоль ID-контейнера
-p (--publish) - открывает порт(-ы) для докер-контейнера на хосте
-p 8080:8080 - диапазон портов для которых открывают работать приложение на хосте по тегу, что создавали ранее
-rm - выполнить образ и удалить (удобно для скачиваемых)
-it - интерактивный запуск (перенаправление stdin/out из контейнера в родительскую ОС)
docker run --rm --name stepik-task -it ubuntu:14.04
подключение командной строкой к уже работающему приложению
docker exec -it container-name bash
удаление:
rmi - удалить образ (класс)
rm - удалить контейнер (объект)
Задание тэга для образа:
docker tag go:v0.2 pihel/lesson1:v0.2* загрузка в докехаб:
docker push pihel/lesson1:v0.2* загрузка в yandex registry
yc container registry create --name pihel-registry #create and gets ID 123 yc container registry configure-docker docker tag fastapi cr.yandex/123/fastapi:v0.0.1 docker push cr.yandex/123/fastapi:v0.0.1
Создание образа (класса) из контейнера (объекта)
docker commit название_старое новое(сохранятся команды изменения, но не точка входа)
слои образа (изменения которые вносились)
docker historyидеалогия copy on write - изменения создают новый слой, оригинальные данные остаются в предыдущем слое (страдает производительность при чтении)
примонтировать папку из родительского хоста:
--mount type=bind,source=/tmp,target=/usr -v /tmp:/tmp
хранение данных докера в файле на хосте (место определяем докер)
docker volume create my-volмонтирование -v tratata:/tratata
проброс портов:
-p <port_on_host_machine>:<port_inside_container>
docker run -rm -p 80:80 parseq/stepik-ports-docker
взаимодействие контейнеров через сеть bridge
все контейнеры попадают в 1 сеть bridge и могут взаимодействовать через ип адреса в этой сети
Создание Dockerfile
собираем образ автоматически:docker build . -t py_app:v0.1в образ попадают все файлы рядом с Dockerfile
Делаем dockerfile вручную:
vim Dockerfile FROM python:3.6-alpine3.8 # Скачиваем легковесный образ python-alpine COPY 1.py /app/ # Копируем 1.py с компьютера в дирректорию /app образа (делается 1 раз при сборка) WORKDIR /app # Делаем /app рабочей дирректорией для след. команды ENTRYPOINT ["python3", "/app/1.py"] # Говорим "Питон3, запусти приложение /app/1.py"
операции RUN, COPY, ADD - создает новый слой
по этому несколько однотипных комманд объединяем через &&
изменение слоя вначале приводит к пересборке всех нижних, по этому самое редко используемое должно быть вначале
Копирование образа builder в собираемый:
COPY --from=builder ./app . # Копируем собранное приложение из образа biulder
Kuber
Установка minikube
minikube - для тестовых локальных запусковminikube start --vm-driver=none sudo apt-get install -y conntrack sudo apt-get install -y goДополнительная инструкция по установке minukube
Создание pod из файла
pod - минимальная абстракция для управления куберомЧаще всего в одном Поде находится один Контейнер
Контейнеры в одном Поде могут обмениваться файлами через общий том (volume).
Контейнеры в одном Поде только на одной Ноде
минимальное описание пода:
#pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
namespace: lesson14
labels:
app: goweb #помечает под для перенаправления трафика на него (у нескольких подов может быть 1 label)
spec:
containers:
- name: web #имя контейнера в поде
image: pihel/lesson1:v0.2 #образ для контейнера
ports:
- name: web
containerPort: 8080
protocol: TCP
Команды kubectl
- Запуск minikube:minikube start --vm-driver=docker minikube status- установка утилиты kubectl и привязка ее к аккаунту яндекса
yc managed-kubernetes cluster get-credentials --id *** --external curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"- установка yaml:
kubectl apply -f pod.yaml- список куберов
kubectl config get-contexts- текущий кубер
kubectl config current-context- Namespace - логическое разделение ресурсов (аналог - папка) - создание namespace
#ns.yaml
apiVersion: v1
kind: Namespace
metadata:
name: examples-dev
- список namespaces
kubectl get ns- список подов в NS
kubectl -n NS get pods- проброс порта на лольную машину для портов <1000 нужно sudo -E
sudo -E kubectl port-forward -n fastapi fastapi 80:80- получить информацию на какой ноде находится под:
kubectl get pod -n lesson14 -o wide- подробное описание пода
kubectl describe pod -n lesson14- логи пода:
kubectl logs -f -n kube-system etcd-minikube- заход в командную строку пода:
kubectl exec -it -n fastapi fastapi -- /bin/bash- информация о загрузке подов:
kubectl top pods -n fastapi #NAME CPU(cores) MEMORY(bytes) #fastapi 2m 54Mi- удалить под
kubectl delete -n fastapi pod fastapi --now
Стратегии автоматизации работы
- Deployment - поддержание подов в нужном состоянии- 3 реплики приложения:
apiVersion: apps/v1
kind: Deployment
metadata:
name: goapp-deployment
namespace: web-app-stage
labels:
app: goapp
spec:
replicas: 3 #описание реплик
selector:
matchLabels:
app: goapp
template: #описание подов
metadata:
labels:
app: goapp
spec:
containers:
- name: web
image: ksxack/lesson1:v0.2 ## Используйте свой Образ
ports:
- containerPort: 8080
- плавное обновление
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # Не более одного недоступного Пода во время обновления
maxSurge: 1 # Одновременно можно создавать один новый Под
- DaemonSet - установка пода на отдельную ноду- CronJob - запуск пода по расписанию
- StatefulSet - гарантия постоянного сетевого адреса, хранилища и порядка деплоя (для баз / файловых хранилищ и т.д.)
- Job - одноразовая задача: создаст и убъет за собой поду
apiVersion: batch/v1
kind: Job
metadata:
name: pi-job
spec:
template:
spec:
containers:
- name: pi
image: python:3.9
command: ["python", "-c", "from math import pi; print(f'{pi:.20f}')"]
restartPolicy: Never
backoffLimit: 4
- список деплойментов
kubectl -n fastapi get deployment- описание
kubectl -n fastapi describe deployment goapp-deployment- изменение числа реплик
kubectl -n fastapi scale deployment goapp-deployment --replicas 5
Статичные адреса
- проброс портов между подами:
apiVersion: v1
kind: Service
metadata:
namespace: fastapi
name: fastapi-svc
spec:
selector:
app: fastapi
ports:
- protocol: TCP
port: 80 ## порт, который слушает Сервис
targetPort: 80 ## порт Пода, на который Сервис направляет запросы
с помощью service у облачных провайдеров можно сделать статичный ип (отдельный на каждое приложение) и через него организовать балансер- ingress - маршрутизатор внешних запросов на сервисы Kuber.
В ЯО нужно предварительно поставить Ingress Nginx через Marketplace
Будет один общий ip/dns для всех сервисов.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: fastapi
spec:
ingressClassName: nginx
rules:
- host: fastapi.example
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: fastapi-svc
port:
number: 80
в ЯО неявно создаст load balancer
- просмотр параметров
kubectl -n fastapi get ingress # NAME CLASS HOSTS ADDRESS PORTS AGE # example-ingress nginx fastapi.example 51.250.43.78 80 8m2s
Скалирование от нагрузки
горизонтальное скалирование от загрузки цпу и ограничение ресурсов:requests - минимально доступное число ресурсов
limits - максимум ресурсов
apiVersion: apps/v1
kind: Deployment
metadata:
name: goapp-deployment
namespace: demo-ingress
labels:
app: goapp
spec:
replicas: 1
selector:
matchLabels:
app: goapp
template:
metadata:
labels:
app: goapp
spec:
containers:
- name: web
image: ksxack/lesson1:v0.2
ports:
- containerPort: 8080
resources:
requests: #минимально доступное число ресурсов
memory: "100Mi"
cpu: "200m"
limits: #максимум
memory: "150Mi"
cpu: "300m"
классы подов в зависимости от ограничеий:- Guaranteed - requests = limits
- Burstable - requests < limits - можно расширять
- Best Effort - requests / limits не указаны, будет работать, если есть ресурсы (низкий приоритет)
Пробы
- livenessProbe - Health чеки, что приложение живо
apiVersion: v1
kind: Pod
metadata:
labels:
test: my-pod
name: my-pod-http
spec:
containers:
- name: containername
image: k8s.gcr.io/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3 #секунд между стартом и 1 пробой
periodSeconds: 2 #периодичность проверки
failureThreshold: количество повторных Проверок перед рестартом. По умолчанию 3timeoutSeconds: Количество секунд ожидания ответа на Проверке. По умолчанию 1 секунда.
successThreshold: Минимальное количество последовательных проверок, чтобы проба считалась успешной после неудачной. По умолчанию 1.
- проверка загруженности пода, если проверка не проходит, то запрос отправится на другую поду
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
- проба, что приложение стартовало, если initialDelaySeconds недостаточно
startupProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 30
periodSeconds: 10
Передача переменных в pod
- конфигурацииapiVersion: v1 kind: ConfigMap metadata: name: env-config namespace: demo-cm data: LOG_LEVEL: "debug" DATABASE_URL: "postgresql://user:password@db:5432/mydatabase"
- создание переменных окружения из конфиг маппы
spec:
containers:
- name: app
image: busybox
command: ["/bin/sh", "-c", "echo \"Log Level: $LOG_LEVEL, Database URL: $DATABASE_URL\" && sleep 3600"]
envFrom:
- configMapRef:
name: env-config
Helm
- шаблонизация kuber манифестов
env:
- name: {{ .Values.secret.name }}
valueFrom:
secretKeyRef:
name: {{ .Values.secret.name }}
key: password
Задание значени в values.yaml
secret: name: load-secret password: loadqwertyПрименение значений
helm install my-helm-release test-chart -n tst-namespace -f test-chart/values.yaml
Rest API
Раздел будет дополняться.Практический пример
Сухая теория плохо запоминается, по этому попробуем создать питон приложение и развернуть его в kuberКод приложения
Простейшее FastApi приложение
#main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get('/calculate')
async def calculate(num1: int, num2: int):
return {f'sum of numbers {num1} and {num2} is ': f'{num1+num2}'}
Docker образ программы
Dockerfile с питоном и нашим приложением. Точка входа - запуск приложения.FROM python:3.12-slim RUN pip install fastapi[all] WORKDIR /app COPY ./main.py /app/ EXPOSE 8000 CMD ["fastapi", "run", "/app/main.py", "--port", "80"]Собираем Image
docker build -t fastapi .Можем сразу его запустить, пробросить порты и проверить, что при обращении к localhost возвращается {"message": "Hello World"}
docker run -d --name fastapi -p 80:80 fastapi
Загрузка Docker образа в Яндекс
Создаем Docker registry, загружаем туда образ и проверяем работу#создаем registry yc container registry create --name pihel-registry yc container registry configure-docker #задаем тег docker tag fastapi cr.yandex/***/fastapi:v0.0.1 #загружаем в registry docker push cr.yandex/***/fastapi:v0.0.1 #проверяем, что образ запускается из удаленного registry docker run --rm -p 80:80 cr.yandex/***/fastapi:v0.0.1
Установка Kuber
- Ставим managed kuber в ЯО, все параметры можно оставить поумолчанию.- Kuber создастся без узлов, по этому заходим в "Управление узлами" и создаем группу из 3 минимальных узлов.
- Ставим и привязываем kubectl
yc managed-kubernetes cluster get-credentials --id *** --external curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
Создание pod
- Сначала создадим namespace#ns.yaml apiVersion: v1 kind: Namespace metadata: name: fastapi kubectl apply -f ns.yaml- Эмулируем некоторые настроечные параметры, которые будут использоваться в env
#conf.yaml apiVersion: v1 kind: ConfigMap metadata: name: env-config-test namespace: fastapi data: TEST_PARAM: "test_value" kubectl apply -f conf.yaml- Pod с нашим приложением в 2 экземплярах
#depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: fastapi-deployment
namespace: fastapi
labels:
app: fastapi
spec:
replicas: 2 #2 реплики для отказоустойсивости
selector:
matchLabels:
app: fastapi
template:
metadata:
labels:
app: fastapi
spec:
containers:
- name: fastapi
image: cr.yandex/***/fastapi:v0.0.1 #наш образ с приложением
ports:
- containerPort: 80 #открыт 80 порт
resources: #ограничения на ресурсы
requests:
memory: "100Mi"
cpu: "200m"
limits:
memory: "150Mi"
cpu: "300m"
envFrom: #переменные окружения из конфига
- configMapRef:
name: env-config-test
- проверяем что все запустилось
#деплоим kubectl apply -f depl.yaml #работающие Поды kubectl -n fastapi get pods #NAME READY STATUS RESTARTS AGE #fastapi-deployment-***-2p7s2 1/1 Running 0 11m #fastapi-deployment-***-ppfgw 1/1 Running 0 11m- пробросим порты и проверим работу в браузере:
#для портов <1000 нужно sudo -E
sudo -E kubectl port-forward -n fastapi fastapi-deployment-*** 80:80
curl 127.0.0.1
#{"message":"Hello World"}
- проверим, что конфигурационные параметры видны в ENV
kubectl exec -it -n fastapi fastapi-deployment-*** -- sh -c 'echo $TEST_PARAM' # test_value
Настройка Ingress
Настроим Ingress, чтобы иметь едную точку входа для всех приложений и чтобы была балансировка нагрзуки между 2 подами запущенных приложений.В ЯО нужно предварительно поставить Ingress Nginx через Marketplace
- Ставим service для проброса портов
apiVersion: v1
kind: Service
metadata:
namespace: fastapi
name: fastapi-svc
spec:
selector:
app: fastapi
ports:
- protocol: TCP
port: 80 ## порт, который слушает Сервис
targetPort: 80 ## порт Пода, на который Сервис направляет запросы
- деплоим настройки ingress, чтобы он смотрел на наш сервис по префиксу /
#ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: fastapi
spec:
ingressClassName: nginx
rules:
- host: fastapi.example
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: fastapi-svc
port:
number: 80
с деплоем неявно создастся балансировщик на 2 наши поды.- информация о ingress endpoint:
kubectl -n fastapi get ingress #NAME CLASS HOSTS ADDRESS PORTS AGE #example-ingress nginx fastapi.example 51.250.43.78 80 8m2s- Добавляем ip эндпойнта в hosts и проверяем, что обращение к хосту по днс работает
cat /etc/hosts | grep fastapi
# 51.250.43.78 fastapi.example
curl fastapi.example
# {"message":"Hello World"}
Комментариев нет:
Отправить комментарий