Как развернуть приложение?

Навроцкий Артем

Как развернуть приложение?

Навроцкий Артем

Контейнеры и виртуальные машины

Сервисы и физическое железо

Обычно физический сервер слишком большой для одного экземпляра сервиса.

Есть потребность запускать несколько разных сервисов на одном физичесом сервере.

Сервер xFusion 1288H V7 8SFF (1U)

Итого: 64 ядра (128 потоков исполнения) и 768GB RAM

Несколько сервисов на одном сервере

Технически можно установить несколько сервисов на одном сервере.

Какие пути решения?

Виртуализация

Внутри гипервизора запускаем несколько виртуальных хостов.

Каждый виртуальный хост притворяется физическим хостом.

Контейнеризация

Внутри операционной системы приложения изолируются в отдельных контейнерах.

Каждый процесс контейнера является обычным процессом операционной системы.

Виртуализация

Важно

Плюсы

Минусы

Контейнеризация

Важно

Плюсы

Минусы

Docker

Контейнеры существуют очень давно, но до Docker-а не было простой инфраструктуры для работы с контейнерами.

Docker предоставил законченное решение для:

Docker-контейнеры поддерживают операционные системы:

Docker-образ

git clone https://github.com/docker/docker-gs-ping .
docker build --tag docker-gs-ping .

Dockerfile

# syntax=docker/dockerfile:1
FROM golang:1.19
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping
EXPOSE 8080
CMD [ "/docker-gs-ping" ]

Docker-образ (multistage)

git clone https://github.com/docker/docker-gs-ping .
docker build --tag docker-gs-ping -f Dockerfile.multistage .

Dockerfile.multistage

# syntax=docker/dockerfile:1
FROM golang:1.19 AS build-stage
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping

FROM gcr.io/distroless/base-debian11 AS build-release-stage
WORKDIR /
COPY --from=build-stage /docker-gs-ping /docker-gs-ping
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/docker-gs-ping"]

Кэширование сборки docker-образов

Не правильно

RUN apt update
RUN apt install -y golang

Что внутри образа?

Подведём итоги

Шпаргалки по Docker

https://docker.how/

https://docs.docker.com/get-started/docker_cheatsheet.pdf

Kubernetes

Kubernetes (K8S) — среда для контейнеров

Как запустить контейнер в Kubernetes?

Описание Pod-а pods/simple-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

Создание Pod-а

kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml

Как запустить контейнер в Kubernetes?

kubectl get pods
kubectl describe pod nginx
kubectl logs nginx
kubectl delete pod nginx

Открытые вопросы

Ресурсы в Kubernetes

Запуск приложения

Pod
Минимальный объект в Kubernetes.
ReplicaSet
Управляет количеством однотипных Pod-ов.
Deployment, StatefulSet, DaemonSet
Объекты, которые управляют жизненным циклом контейнерных приложений.

Ресурсы в Kubernetes

Конфигурация приложения

Переменные окружения
У Pod-а можно переопределить переменные окружения. Так же через них можно прокинуть часть данных о Pod-е в контейнер (https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/).
Параметры командной строки
Можно переопределить параметры командной строки для Pod-а.
Secret, ConfigMap
Специальные ресурсы, которые можно отобразить на файловую систему Pod-а.

Ресурсы в Kubernetes

Ресурсы для доступа к Pod-у

Service
Объект, который позволяет адресовать группу Pod-ов.
Ingress
Объект, который позволяет достучаться к Pod-у снаружи Kubernetes-кластера.

Запуск Pod-ов через Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

Указываем, какие ресурсы нужны Pod-ам

TODO: Добавить пример информацию о ресурсах

Контроль жизненного цикла

Для определения состояния Pod-а есть следующие "пробы":

readinessProbe
Готов ли Pod принимать пользовательскую нагрузку?
livenessProbe
Жив ли Pod?
Если Pod не живой, то его удалит автоматика
startupProbe
До завершения старта сервиса к нему не применяются readinessProbe и livenessProbe

Долго стартующие приложения причиняют боль страдание.

Контроль жизненного цикла

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80
    readinessProbe:
      httpGet:
        path: /
        port: 80
      periodSeconds: 3

Конфигурация внутри Pod-а

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    command: ["nginx", "-g", "daemon off;"]
    env:
    - name: FOO
      value: "bar"
    - name: MY_POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    ports:
    - containerPort: 80

Конфигурация снаружи Pod-а

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx
data:
  index.html: |
    <html><body><h1>Hello, world!!!</h1></body></html>
  ping.html: |
    <html><body><h1>Pong</h1></body></html>
TODO: Добавить пример конфигурации через ConfigMap

Доступ к Pod-у снаружи Kubernetes-кластера

TODO: Добавить пример Service и Ingress

Подведём итоги

Что осталось за кадром?

Шпаргалки по Kubernetes

TODO: Добавить шпаргалки по Kubernetes

Deploy

Откуда берутся ресурсы для Kubernetes?

При раскатки приложения ресурсы для Kubernetes обычно генерируются каким-либо образом.

Применение ресурсов через kubectl apply имеет существенный недостаток: никто не удаляет более ненужные ресурсы.

Стандартом де-факто для создания "приложений" в Kubernetes является Helm

Helm

Helm — менеджер пакетов для Kubernetes, который упрощает установку, обновление и управление приложениями в кластере. Особенность — использование чартов (Helm Charts) — стандартизированных пакетов, в которых содержатся все необходимые ресурсы и конфигурации.

Шаблонизатор Helm

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"

Внутри Helm использует шаблонизатор Go Template с набором дополнительных функций (в том числе go-spew).

Одна из проблем такого подхода: шаблонизатор работает с Yaml на уровне текста.

Как всё выкатить?

TODO: Ссылка на готовый пример с приложениями на Go и Python

Настройка выкатки в Yandex Cloud

Подготовка Docker Registry

TODO: Добавить инструкцию по созданию Docker Registry

Подготовка Kubernetes-кластера

TODO: Добавить инструкцию по созданию managed Kubernetes-кластера

Настройка CI

TODO: Добавление воркера для сборки из Github Actions

Настройка CI

TODO: Добавление секретов для доступа к Docker Registry и Kubernetes-кластеру на CI

Сбор метрик с Pod-ов

TODO: Добавление сбора метрик с Pod-ов в Yandex Cloud

Спасибо за внимание!