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: количество повторных Проверок перед рестартом. По умолчанию 3
timeoutSeconds: Количество секунд ожидания ответа на Проверке. По умолчанию 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"}
Комментариев нет:
Отправить комментарий