From 75fcea1371c5ae9b2ff69881d566b3167d3b0547 Mon Sep 17 00:00:00 2001 From: Dmitry Ignatiev Date: Sun, 19 Nov 2023 18:49:13 +0300 Subject: [PATCH 1/9] m2/10/tasks --- .../todo_app/.gitignore | 1 + .../TodoApi/Helpers/TodoHealthCheck.cs | 12 +++ .../todo_app/TodoApi/Program.cs | 13 +++ .../todo_app/TodoApi/TodoApi.csproj | 3 + .../todo_app/TodoApi/appsettings.json | 5 +- module2/10_monitoring_basics/lection.md | 10 ++ module2/10_monitoring_basics/tasks.md | 91 +++++++++++++++++++ 7 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 module2/08_docker_containerization_advanced/todo_app/TodoApi/Helpers/TodoHealthCheck.cs diff --git a/module2/08_docker_containerization_advanced/todo_app/.gitignore b/module2/08_docker_containerization_advanced/todo_app/.gitignore index 8c9f516..9076963 100644 --- a/module2/08_docker_containerization_advanced/todo_app/.gitignore +++ b/module2/08_docker_containerization_advanced/todo_app/.gitignore @@ -1,3 +1,4 @@ Dockerfile docker-compose.yml nginx.conf +prometheus.yml diff --git a/module2/08_docker_containerization_advanced/todo_app/TodoApi/Helpers/TodoHealthCheck.cs b/module2/08_docker_containerization_advanced/todo_app/TodoApi/Helpers/TodoHealthCheck.cs new file mode 100644 index 0000000..53f88b6 --- /dev/null +++ b/module2/08_docker_containerization_advanced/todo_app/TodoApi/Helpers/TodoHealthCheck.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace TodoApi.Helpers +{ + public class TodoHealthCheck : IHealthCheck + { + public Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) + { + return Task.FromResult(new HealthCheckResult(HealthStatus.Healthy)); + } + } +} diff --git a/module2/08_docker_containerization_advanced/todo_app/TodoApi/Program.cs b/module2/08_docker_containerization_advanced/todo_app/TodoApi/Program.cs index a7991cb..d69a8be 100644 --- a/module2/08_docker_containerization_advanced/todo_app/TodoApi/Program.cs +++ b/module2/08_docker_containerization_advanced/todo_app/TodoApi/Program.cs @@ -1,6 +1,8 @@ using Microsoft.EntityFrameworkCore; using System.Text.Json; using System.Text.Json.Serialization; +using Prometheus; +using TodoApi.Helpers; using TodoApi.Model; var builder = WebApplication.CreateBuilder(args); @@ -27,6 +29,15 @@ builder.Services.AddControllers() o.JsonSerializerOptions.Converters.Add(enumConverter); }); +builder.Services.AddMetricServer(options => +{ + options.Port = config.GetRequiredSection("Metrics").GetValue("Port", 9123); +}); + +builder.Services.AddHealthChecks() + .AddCheck(nameof(TodoHealthCheck)) + .ForwardToPrometheus(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -35,6 +46,8 @@ app.UseStaticFiles(); app.MapControllers(); +app.UseHttpMetrics(); + app.MapFallbackToFile("index.html"); app.Run(); diff --git a/module2/08_docker_containerization_advanced/todo_app/TodoApi/TodoApi.csproj b/module2/08_docker_containerization_advanced/todo_app/TodoApi/TodoApi.csproj index dab021e..57dcb33 100644 --- a/module2/08_docker_containerization_advanced/todo_app/TodoApi/TodoApi.csproj +++ b/module2/08_docker_containerization_advanced/todo_app/TodoApi/TodoApi.csproj @@ -8,6 +8,9 @@ + + + diff --git a/module2/08_docker_containerization_advanced/todo_app/TodoApi/appsettings.json b/module2/08_docker_containerization_advanced/todo_app/TodoApi/appsettings.json index 70f88e6..36ee201 100644 --- a/module2/08_docker_containerization_advanced/todo_app/TodoApi/appsettings.json +++ b/module2/08_docker_containerization_advanced/todo_app/TodoApi/appsettings.json @@ -8,5 +8,8 @@ "ConnectionStrings": { "PostgreSQL": "Host=localhost;Port=5432;Database=todo;Username=todo;Password=todo" }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "Metrics": { + "Port": 9123 + } } diff --git a/module2/10_monitoring_basics/lection.md b/module2/10_monitoring_basics/lection.md index e69de29..0a1f269 100644 --- a/module2/10_monitoring_basics/lection.md +++ b/module2/10_monitoring_basics/lection.md @@ -0,0 +1,10 @@ + +## Ссылки + +- https://prometheus.io/docs/prometheus/latest/getting_started/ +- https://povilasv.me/prometheus-tracking-request-duration/ +- https://www.innoq.com/en/blog/2020/04/scraping-docker-swarm-service-instances-with-prometheus/ +- https://github.com/prometheus/node_exporter +- https://prometheus.io/docs/practices/histograms/ +- https://grafana.com/docs/ +- https://grafana.com/blog/2020/06/23/how-to-visualize-prometheus-histograms-in-grafana/ diff --git a/module2/10_monitoring_basics/tasks.md b/module2/10_monitoring_basics/tasks.md index e69de29..604f169 100644 --- a/module2/10_monitoring_basics/tasks.md +++ b/module2/10_monitoring_basics/tasks.md @@ -0,0 +1,91 @@ +# Задания + +## Prometheus + +1. Вы должны были получить обновленное приложение `todo_app`. + + API-сервис приложения теперь отдает метрики Prometheus на порту `9123`(можно поменять через переменную среды `Metrics__Port`) и по url `/metrics`. + + Таким образом, полное URL для получения метрик, выглядит, например, как `http://todo_api:9123/metrics`. + + Дополните Compose-файл для `todo_app` так, чтобы в сети `todo` запускался контейнер из образа `prom/prometheus`, при этом: + - Напишите для него конфигурацию, то есть файл `prometheus.yml` \ + (который должен в итоге находится в контейнере на месте `/etc/prometheus/prometheus.yml`), \ + таким образом чтобы Prometheus собирал метрики из `todo_api` каждые 5 секунд. + - Прокиньте порт `9090`, на котором находится веб-интерфейс Prometheus по умолчанию, на хост машины с Docker. + - Создайте том данных `todo_prometheus_data`, который бы хранил данные внутренней БД Prometheus, и который бы\ + монтировался на директорию `/prometheus` внутри его контейнера. + + Убедитесь, что веб-интерфейс Prometheus не был доступен извне. Для доступа к нему, сделайте SSH-туннель на вашу локальную машину. + +2. Запустите систему в Compose-режиме, то есть не в режиме кластера, и без дополнительных реплик. + +3. На веб-интерфейсе Prometheus, проверьте, что он собирает метрики из `todo_api`(на вкладке `Targets`) + +4. На веб-интерфейсе Prometheus, выведите значение метрики `dotnet_total_memory_bytes` - общее число байт, находящихся в управляемой(т.е. подотчетной сборщику мусора .NET) памяти API-сервиса. + +5. Выведите максимальное значение этой метрики за последние 15 минут. + +6. Дополните compose-файл так, чтобы в сети `todo` запустить контейнер из образа `bitnami/postgres-exporter`, при этом: + - Установите для этого контейнера переменную среды `DATA_SOURCE_NAME`\ + в значение `postgresql://todo:todo@todo_postgres:5432/todo?sslmode=disable`(при необходимости поменяйте здесь порт, хост, итд.) + - Отредактируйте конфигурацию `prometheus.yml` так, чтобы теперь также собирать метрики из `postgres-exporter`. \ + Postgres Exporter по умолчанию отдает метрики на порту `9187`, и по URL `/metrics` + +7. Проверьте на веб-интерфейсе Prometheus метрику `pg_stat_user_tables_size_bytes` (она показывает количество памяти, занимаемой пользовательскими таблицами в PostgreSQL) + +8. Дополните compose-файл так, чтобы также запускать контейнер из образа `prom/node-exporter`.\ + Учтите, что так как этот exporter используется для мониторинга хост-машин, ему не нужна такая изоляция, как обычным приложениям, и даже наоборот: + - Для этого контейнера необходимо примонтировать корневую директорию хост-машины в read-only режиме, \ + чтобы она была доступна например как директория `/host` внутри контейнера. + - При старте этого контейнера, передайте ему аргумент `--path.rootfs=/host` + - Также, установите значение `--pid` в `host` (`pid: host` в compose-файле) + - Желательно также установить режим сети в `host` (`network_mode: host` в compose-файле) (N.B.: Работает только на Linux, и не работает на Docker Desktop на macOS и Windows) + + node-exporter по умолчанию отдает метрики на порту `9100` и по URL `/metrics`. \ + Доступ к `host`-машине Docker изнутри контейнера Prometheus можно получить по адресу (`host.docker.internal`) + + Дополните конфигурацию `prometheus.yml` так чтобы собирать метрики и из `node-exporter` + +9. Проверьте на веб-интерфейсе Prometheus метрику `node_memory_MemFree_bytes` - она показывает количество свободной оперативной памяти хост-машины(и берет ее из `/proc/meminfo`). + +## Grafana + +1. Дополните compose-файл так, чтобы в сети `todo` запустить контейнер из образа `grafana/grafana`. \ + - Интерфейс grafana по умолчанию доступен на порту 3000, пробростье этот порт на хост машину. + - Также, создайте том данных `todo_grafana_data`, примонтированный в контейнер по пути `/var/lib/grafana` + - Установите для контейнера переменную окружения `GF_USERS_ALLOW_SIGN_UP` в значение `false`, чтобы отключить возможность регистрации пользователей. + +2. Перезапустите систему. Убедитесь что `grafana` доступна извне. Для этого настройте конфигурацию `nginx` на хост-системе, если вы используете его в качестве внешнего прокси. + +3. Зайдите на веб-интерфейс grafana. Логин и пароль по умолчанию - `admin` `admin`(пароль можно поменять установив переменную окружения `GF_SECURITY_ADMIN_PASSWORD`). \ + Поменяйте пароль на свой, если вы не установили его как переменную среды. + +4. Добавьте пользователя с именем `viewer`, и разрешением на просмотр визуализаций(роль `Viewer`). + +5. Добавьте источник данных `Prometheus`, при этом установите его URL в `http://todo_prometheus:9090` (поменяйте хост на имя контейнера, в котором запускается Prometheus) + +6. Создайте новый Dashboard, и добавьте на него новую визуализацию метрики `dotnet_total_memory_bytes`. + - Выберите тип графика как `Time Series` + - Назовите график с визуализацией `.NET Total Memory Bytes` + - Поставьте единицу измерения `bytes(SI)` + - Установите display name для выводимого поля, например в `.NET memory` + - Сделайте так, чтобы на график выводилось значение за последние 5 минут. + - Добавьте вывод порогового значения(`threshold`) в 10 мегабайт, так чтобы график выше этого значения был закрашен желтым. + +7. Сохраните Dashboard под именем `My Dashboard`. Установите график обновления в 5 секунд. + +8. Добавьте визуализацию свободной памяти на хост-машине. Сделайте так чтобы визуализация показывала минимальное за последние 5 минут значение, \ + а сам график выводил показывал отрезок времени в последний час. Сохраните визуализацию и Dashboard. + +9. API-сервис отдает метрику `http_request_duration_seconds`. Она собирает время обработки HTTP-запроса API-сервисом в секундах. \ + `http_request_duration_seconds_bucket` - значения метрики в виде гистограммы. \ + `http_request_duration_seconds_sum` и `http_request_duration_seconds_count` - части этой метрики, отдающие, соответственно сумму времени всех запросов, и общее количество запросов. + + Добавьте визуализацию среднего времени обработки HTTP-запросов API-сервером за последние 5 минут. Сохраните Dashboard. + +10. Перезапустите всю систему, но уже не в Docker Compose, а в Docker Swarm. Сделайте так, чтобы API-сервис работал на трех репликах. + + Убедитесь, что Prometheus правильно собирает метрики со всех трех реплик одновременно(в Targets на интерфейсе Prometheus должны присутствовать все три). + + Отредактируйте визуализации, связанные с API-сервисом так, чтобы они показывали средние значения по всем трем репликам. From 96c8b1be85c4966a3298f143e9be499384c8d669 Mon Sep 17 00:00:00 2001 From: Dmitry Ignatiev Date: Sun, 19 Nov 2023 18:56:06 +0300 Subject: [PATCH 2/9] m2/08/solutions --- .../solutions.md | 578 ++++++++++++++++++ 1 file changed, 578 insertions(+) diff --git a/module2/08_docker_containerization_advanced/solutions.md b/module2/08_docker_containerization_advanced/solutions.md index e69de29..b519463 100644 --- a/module2/08_docker_containerization_advanced/solutions.md +++ b/module2/08_docker_containerization_advanced/solutions.md @@ -0,0 +1,578 @@ +### 1. Многоступенчатая сборка образов + +#### 1.1.1 + +````Dockerfile +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS api_build + +WORKDIR /src + +COPY ./TodoApi /src + +RUN dotnet restore TodoApi.csproj + +RUN dotnet build TodoApi.csproj -c Release -o /app/build + +FROM api_build AS publish + +RUN dotnet publish TodoApi.csproj -c Release -o /app/publish + +FROM node:21 AS ui_build + +WORKDIR /src + +COPY ./todo_ui /src + +RUN npm install + +RUN npm run build + +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base + +WORKDIR /app + +COPY --from=publish /app/publish . + +COPY --from=ui_build /src/wwwroot ./wwwroot + +ENTRYPOINT ["./TodoApi"] +```` + +В директории todo_app: + +````bash +docker build -t todo-bundle . +```` + +#### 1.1.2 + +Создание сети: +````bash +docker network create todo +```` +Создание тома для PostgerSQL: +````bash +docker volume create todo_pgdata +```` +Запуск PostgreSQL: +````bash +docker run -d --name=todo_postgres --network=todo -e POSTGRES_DB=todo -e POSTGRES_USER=todo -e POSTGRES_PASSWORD=todo --mount type=bind,source=./initdb,target=/docker-entrypoint-initdb.d --mount type=volume,source=todo_pgdata,target=/var/lib/postgresql/data postgres:16 +```` + +#### 1.1.3 + +````bash +docker run --rm -p 8080:80 --name todo_bundle -e 'ConnectionStrings__PostgreSQL=Host=todo_postgres;Port=5432;Database=todo;Username=todo;Password=todo' --name=todo_bundle --network=todo -t todo-bundle +```` + +#### 1.2.1 + +````bash +docker container rm -f todo_bundle && docker image rm -f todo-bundle +```` + +Докер-файл для API-сервиса +````Dockerfile +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build + +WORKDIR /src + +COPY . /src + +RUN dotnet restore TodoApi.csproj + +RUN dotnet build TodoApi.csproj -c Release -o /app/build + +FROM build AS publish + +RUN dotnet publish TodoApi.csproj -c Release -o /app/publish + +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base + +WORKDIR /app + +COPY --from=publish /app/publish . + +ENTRYPOINT ["./TodoApi"] +```` + +Сборка образа API-сервиса: +(из директории `TodoApi`) +````bash +docker build -t todo-api . +```` + +Конфигурация Nginx: +````nginx +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + #gzip on; + + keepalive_timeout 65; + + server { + listen 80; + + location / { + root /var/www/todo; + index index.html; + try_files $uri $uri/ /index.html =404; + } + + location /api { + proxy_set_header X-Forwarded-Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffers 8 64k; + proxy_busy_buffers_size 128k; + proxy_buffer_size 64k; + + client_max_body_size 10m; + + proxy_http_version 1.1; + proxy_pass http://todo_api; + } + } +} +```` + +Докер-файл для JS-приложения: +````Dockerfile +FROM node:21 AS ui_build + +WORKDIR /build + +COPY . /build + +RUN npm install + +RUN npm run build + +FROM nginx AS base + +WORKDIR /var/www/todo + +COPY --from=ui_build /build/nginx.conf /etc/nginx/nginx.conf + +COPY --from=ui_build /build/wwwroot ./ +```` + +Сборка образа UI: +(из директории `todo_ui`) +````bash +docker build -t todo-ui . +```` + +#### 1.2.2 + +Запуск API-сервиса: + +````bash +docker run -d --name=todo_api --network=todo -e 'ConnectionStrings__PostgreSQL=Host=todo_postgres;Port=5432;Database=todo;Username=todo;Password=todo' todo-api +```` + +Запуск UI: + +````bash +docker run -d -p 8080:80 --name=todo_ui --network=todo todo-ui +```` + +#### 1.2.3 + +````Dockerfile +FROM mcr.microsoft.com/dotnet/sdk:7.0-bullseye-slim AS build + +WORKDIR /src + +COPY . /src + +RUN dotnet restore TodoApi.csproj + +RUN dotnet build TodoApi.csproj -c Release -o /app/build + +FROM build AS publish + +RUN dotnet publish TodoApi.csproj --self-contained -r linux-x64 -c Release -o /app/publish + +FROM debian:bullseye-slim AS base + +WORKDIR /app + +RUN apt-get update && apt-get install libicu67 + +COPY --from=publish /app/publish . + +ENTRYPOINT ["./TodoApi"] +```` +В директории `TodoApi`: +````bash +docker build -t todo-api . +```` +Запуск, как и выше: +````bash +docker run -d --name=todo_api --network=todo -e 'ConnectionStrings__PostgreSQL=Host=todo_postgres;Port=5432;Database=todo;Username=todo;Password=todo' todo-api +```` + +### 2. Политики перезапуска + +#### 1. + +Добавить в `docker run` опцию `--restart=unless-stopped` + +#### 2. + +````bash +docker run -d --name=todo_postgres --network=todo -e POSTGRES_DB=todo -e POSTGRES_USER=todo -e POSTGRES_PASSWORD=todo --mount type=bind,source=./initdb,target=/docker-entrypoint-initdb.d --mount type=volume,source=todo_pgdata,target=/var/lib/postgresql/data --health-cmd='pg_isready -U todo -d todo' --health-interval=10s --health-retries=5 --health-timeout=5s --health-start-period=10s --restart=unless-stopped postgres:16 +```` + +### 3. Ограничения ресурсов + +#### 1. + +Добавить опцию `--memory` в `docker run` + +#### 2. + +Добавить опцию `--cpus` в `docker run` + +### 4. Docker compose + +#### 1. + +`docker compose version` + +https://docs.docker.com/compose/install/linux/ + +#### 1. + +````yaml +version: '3.9' + +services: + hello: + image: busybox + entrypoint: /bin/echo 'Hello, World!' +```` + +Запуск, здесь и далее: `docker compose up` + +#### 2. + +из директории `cats_app` из прошлой лабы: + +Dockerfile взять из solutions.md оттуда + +````yaml +version: '3.9' + +services: + cats_app: + container_name: cats_app + image: cats-app + build: + context: ../ + dockerfile: ./cats_app/Dockerfile + networks: + - cats + nginx: + image: nginx + container_name: nginx + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + depends_on: + - cats_app + ports: + - 5000:80 + networks: + - cats + +networks: + cats: + driver: bridge +```` + +#### 3. + +см. ниже + +#### 4. +````yaml +version: '3.9' + +services: + todo_api: + image: todo-api:latest + container_name: todo_api + depends_on: + - todo_postgres + build: ./TodoApi + environment: + ConnectionStrings__PostgreSQL: "Host=todo_postgres;Port=5432;Database=todo;Username=todo;Password=todo" + ASPNETCORE_URLS: 'http://*:80' + restart: unless-stopped + deploy: + resources: + limits: + cpus: '1' + memory: 500M + networks: + - todo + todo_ui: + image: todo-ui:latest + container_name: todo_ui + depends_on: + - todo_api + build: ./todo_ui + restart: unless-stopped + deploy: + resources: + limits: + cpus: '1' + memory: 300M + ports: + - 8080:80 + networks: + - todo + todo_postgres: + image: postgres:16 + container_name: todo_postgres + environment: + POSTGRES_DB: "todo" + POSTGRES_USER: "todo" + POSTGRES_PASSWORD: "todo" + PGDATA: "/var/lib/postgresql/data" + volumes: + - ./initdb:/docker-entrypoint-initdb.d + - todo_pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U todo -d todo"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + restart: unless-stopped + deploy: + resources: + limits: + cpus: '2' + memory: 800M + networks: + - todo + todo_pgadmin: + container_name: todo_pgadmin + image: dpage/pgadmin4:7 + depends_on: + - todo_postgres + environment: + PGADMIN_DEFAULT_EMAIL: "todo@example.com" + PGADMIN_DEFAULT_PASSWORD: "todo" + PGADMIN_CONFIG_SERVER_MODE: "False" + volumes: + - todo_admin_data:/var/lib/pgadmin + ports: + - "5050:80" + restart: unless-stopped + networks: + - todo + +volumes: + todo_pgdata: + todo_admin_data: + +networks: + todo: + driver: bridge +```` + +### 5. Docker Swarm + +#### 1. + +````bash +docker swarm init +```` +Потом необходимо запомнить токен + +#### 2. +````bash +docker node ls +```` +#### 3. + +````bash +docker swarm join-token worker +```` + +#### 4. + +````bash +docker network create -d overlay todo_swarm +```` + +#### 5. + +````bash +docker volume create todo_swarm_pgdata --sharing onewriter +```` + +#### 6. + +````bash +docker service create --name=todo_postgres --replicas 1 --network=todo_swarm -e POSTGRES_DB=todo -e POSTGRES_USER=todo -e POSTGRES_PASSWORD=todo --mount type=bind,source=./initdb,target=/docker-entrypoint-initdb.d --mount type=volume,source=todo_swarm_pgdata,target=/var/lib/postgresql/data --health-cmd='pg_isready -U todo -d todo' --health-interval=10s --health-retries=5 --health-timeout=5s --health-start-period=10s postgres:16 +```` + +#### 7. + +````bash +docker service create --name=todo_api --replicas 1 --network=todo_swarm -e 'ConnectionStrings__PostgreSQL=Host=todo_postgres;Port=5432;Database=todo;Username=todo;Password=todo' -e 'ASPNETCORE_URLS=http://*:80' todo-api +```` + +#### 8. + +````bash +docker service create -p 8080:80 --name=todo_ui --replicas 1 --network=todo_swarm todo-ui +```` + +#### 9. + +Открыть localhost:8080 в браузере + +#### 10. + +````bash +docker service scale todo_ui=3 todo_api=3 +```` + +#### 11. + +````bash +docker service ps todo_ui +```` + +````bash +docker service ps todo_api +```` + +#### 12. + +````bash +docker service logs todo_api +```` + +#### 13. + +````bash +docker service rm todo_api && docker service rm todo_ui && docker service rm todo_postgreq +```` + +#### 14 + +````yaml +version: '3.9' + +services: + todo_api: + image: todo-api:latest + depends_on: + - todo_postgres + environment: + ConnectionStrings__PostgreSQL: "Host=todo_postgres;Port=5432;Database=todo;Username=todo;Password=todo" + ASPNETCORE_URLS: 'http://*:80' + deploy: + mode: replicated + replicas: 3 + resources: + limits: + cpus: '1' + memory: 500M + networks: + - todo + todo_ui: + image: todo-ui:latest + depends_on: + - todo_api + deploy: + mode: replicated + replicas: 3 + resources: + limits: + cpus: '1' + memory: 300M + ports: + - 8080:80 + networks: + - todo + todo_postgres: + image: postgres:16 + environment: + POSTGRES_DB: "todo" + POSTGRES_USER: "todo" + POSTGRES_PASSWORD: "todo" + PGDATA: "/var/lib/postgresql/data" + volumes: + - ./initdb:/docker-entrypoint-initdb.d + - todo_pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U todo -d todo"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + deploy: + resources: + limits: + cpus: '2' + memory: 800M + networks: + - todo + todo_pgadmin: + image: dpage/pgadmin4:7 + depends_on: + - todo_postgres + environment: + PGADMIN_DEFAULT_EMAIL: "todo@example.com" + PGADMIN_DEFAULT_PASSWORD: "todo" + PGADMIN_CONFIG_SERVER_MODE: "False" + volumes: + - todo_admin_data:/var/lib/pgadmin + ports: + - "5050:80" + networks: + - todo + +volumes: + todo_pgdata: + todo_admin_data: + +networks: + todo: + driver: overlay +```` + +#### 15. + +````bash +docker stack deploy --compose-file docker-compose.yml +```` From 2d6cfcbbefd295bdb9891522f019db4da3e42190 Mon Sep 17 00:00:00 2001 From: Dmitry Ignatiev Date: Sun, 19 Nov 2023 22:44:33 +0300 Subject: [PATCH 3/9] m2/monitoring - questions & lection --- module2/10_monitoring_basics/lection.md | 37 ++++++++++++++++++++++- module2/10_monitoring_basics/questions.md | 11 +++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/module2/10_monitoring_basics/lection.md b/module2/10_monitoring_basics/lection.md index 0a1f269..1d9714c 100644 --- a/module2/10_monitoring_basics/lection.md +++ b/module2/10_monitoring_basics/lection.md @@ -1,10 +1,45 @@ +## Основы мониторинга -## Ссылки +Одна из главных задач системного администратора или DevOps-инженера это мониторинг состояния и работоспособности подотчетных ему систем. + +Инструментов и средств для мониторинга существует огромное множество, и в простейших случаях они могут быть даже самописными. Вы уже сталкивались с такими в приложениях `cats_app` и при использовании healthcheck в Docker. В реальном мире для мониторинга используются внешние сторонние инструменты, такие, как Google Analytics, Zabbix, Elastic Search(и вообще стек ELK), Sentry, и другие, однако на этом занятии мы рассмотрим один из наиболее распространенных стеков программного обеспечения, применяемых для этих задач - Prometheus + Grafana. + +## Prometheus + +Prometheus - это серверное ПО, собирающее метрики из каких-либо других систем, и хранящее их в своей специализированной базе данных, приспособленной для обработки временных рядов(time series). + +Отличие метрик от логов в том, что метрики дают более общую картину о каком-либо процессе, тогда как логи обычно показывают какое-либо событие или же их последовательность. + +Prometheus может собирать метрики сам, делая запросы по HTTP(если какая либо платформа и система имеет возможность их таким образом показывать), либо же, получать их через сторонние средства, называемые экспортерами(exporters). Один из наиболее примечательных экспортеров называется `node-exporter`, который собирает информацию об операционной системе, на которой запущен. + +После того как метрики были собраны в базу, к ней можно делать запросы на специализированном языке PromQL, специально предназначенном для обработки временных рядов и статистики, точно так же как SQL предназначен для обработки реляционных данных. + +Prometheus поддерживает 4 вида метрик "из коробки": +- `Counter` - метрика этого типа используется чтобы замерять какое-либо неубывающее значение, как пример - общее количество HTTP-запросов к серверу. +- `Gauge` - данный вид метрик используется для отображения значений, которые могут как увеличиваться, так и уменьшаться. Пример - количество памяти, занимаемой процессом. +- `Histogram` - такие метрики показывают набор семплированных значений определенного рода. Используются, например, для отслеживания времени обработки HTTP-запросов. +- `Summary` - подобно `Histogram`, но семлирует значение временных рядов в определенный промежуток времени. + +К каждой метрике Prometheus могут быть прикрепленые разные метки(label), которые позволяют, например, идентифицировать источник информации. + +После того, как метрики были собраны в TSDB - внутреннюю базу данных Prometheus, их могут собирать и обрабатывать сторонние системы, такие как Grafana(для их визуализации), или, например, Alertmanager(для, к примеру, оповещения о превышении каких-либо значений путем email, slack и т.п.; его использование выходит за рамки данного занятия). + +## Grafana + +Grafana это система для визуализации данных с открытым исходным кодом. Очень часто используется в связке вместе с Prometheus. + +Хотя веб-интерфейс самого Prometheus позволяет создавать базовые визуализации, Grafana добавляет множество удобств - возможность группировки визуализаций в Dashboard, помощь в составлении выражений PromQL, огромное количество видов визуализаций, плагины, и так далее. + +По Grafana существует больше количество подробной документации и примеров, как на официальном сайте, так и в других местах интернета. + +## Полезные ссылки - https://prometheus.io/docs/prometheus/latest/getting_started/ +- https://habr.com/ru/companies/tochka/articles/683608/ - https://povilasv.me/prometheus-tracking-request-duration/ - https://www.innoq.com/en/blog/2020/04/scraping-docker-swarm-service-instances-with-prometheus/ - https://github.com/prometheus/node_exporter - https://prometheus.io/docs/practices/histograms/ +- https://prometheus.io/docs/visualization/grafana/ - https://grafana.com/docs/ - https://grafana.com/blog/2020/06/23/how-to-visualize-prometheus-histograms-in-grafana/ diff --git a/module2/10_monitoring_basics/questions.md b/module2/10_monitoring_basics/questions.md index e69de29..8046c1e 100644 --- a/module2/10_monitoring_basics/questions.md +++ b/module2/10_monitoring_basics/questions.md @@ -0,0 +1,11 @@ +1. Чем метрики отличаются от логов? +2. Как называется файл конфигурации Prometheus? +3. Какие виды метрик поддерживает Prometheus? +4. Зачем нужны экспортеры(exporters)? +5. Что делает node_exporter, для чего он нужен? +6. Какие типы данных поддерживает PromQL? +7. Что делает функция `rate()` из PromQL и зачем она нужна? +8. Как в PromQL вывести среднее значение какой-либо метрики(напр. типа Gauge, и с названием my_metric), за последние 5 минут? +9. Как сконфигурировать Prometheus в кластере Docker Swarm так, чтобы он собирал метрики из всех репликаций какого-либо сервиса Swarm, доступных по одному доменному имени? +10. Как установить пароль администратора в Grafana? +11. Как экспортировать Dashboard в Grafana и потом импортировать назад? From 7ae079f7f5edca86605b9a7d2c658ca95663b685 Mon Sep 17 00:00:00 2001 From: Dmitry Ignatiev Date: Sun, 19 Nov 2023 23:12:08 +0300 Subject: [PATCH 4/9] changed histogram & summary description a bit --- module2/10_monitoring_basics/lection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module2/10_monitoring_basics/lection.md b/module2/10_monitoring_basics/lection.md index 1d9714c..5df315e 100644 --- a/module2/10_monitoring_basics/lection.md +++ b/module2/10_monitoring_basics/lection.md @@ -17,8 +17,8 @@ Prometheus может собирать метрики сам, делая зап Prometheus поддерживает 4 вида метрик "из коробки": - `Counter` - метрика этого типа используется чтобы замерять какое-либо неубывающее значение, как пример - общее количество HTTP-запросов к серверу. - `Gauge` - данный вид метрик используется для отображения значений, которые могут как увеличиваться, так и уменьшаться. Пример - количество памяти, занимаемой процессом. -- `Histogram` - такие метрики показывают набор семплированных значений определенного рода. Используются, например, для отслеживания времени обработки HTTP-запросов. -- `Summary` - подобно `Histogram`, но семлирует значение временных рядов в определенный промежуток времени. +- `Histogram` - такие метрики представляют собой набор значений определенного рода, сгруппированный по некоторому распределению. Используются, например, для отслеживания времени обработки HTTP-запросов. +- `Summary` - похожи на `Histogram`, но квантили распределения сразу задаются поставщиком метрики. К каждой метрике Prometheus могут быть прикрепленые разные метки(label), которые позволяют, например, идентифицировать источник информации. From c28f6190ac43d21e70ff6befd6ddf581b30ed8fc Mon Sep 17 00:00:00 2001 From: Dmitry Ignatiev Date: Mon, 20 Nov 2023 01:09:39 +0300 Subject: [PATCH 5/9] Add notes and another link to monitoring --- module2/10_monitoring_basics/lection.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module2/10_monitoring_basics/lection.md b/module2/10_monitoring_basics/lection.md index 5df315e..6880405 100644 --- a/module2/10_monitoring_basics/lection.md +++ b/module2/10_monitoring_basics/lection.md @@ -17,8 +17,8 @@ Prometheus может собирать метрики сам, делая зап Prometheus поддерживает 4 вида метрик "из коробки": - `Counter` - метрика этого типа используется чтобы замерять какое-либо неубывающее значение, как пример - общее количество HTTP-запросов к серверу. - `Gauge` - данный вид метрик используется для отображения значений, которые могут как увеличиваться, так и уменьшаться. Пример - количество памяти, занимаемой процессом. -- `Histogram` - такие метрики представляют собой набор значений определенного рода, сгруппированный по некоторому распределению. Используются, например, для отслеживания времени обработки HTTP-запросов. -- `Summary` - похожи на `Histogram`, но квантили распределения сразу задаются поставщиком метрики. +- `Histogram` - такие метрики представляют собой счетчики событий для нескольких заданных диапазонов. Используются, например, для отслеживания времени обработки HTTP-запросов. +- `Summary` - похожи на `Histogram`, но представляют собой препросчитанное разбиение значений по квантилям. К каждой метрике Prometheus могут быть прикрепленые разные метки(label), которые позволяют, например, идентифицировать источник информации. @@ -43,3 +43,4 @@ Grafana это система для визуализации данных с о - https://prometheus.io/docs/visualization/grafana/ - https://grafana.com/docs/ - https://grafana.com/blog/2020/06/23/how-to-visualize-prometheus-histograms-in-grafana/ +- https://www.timescale.com/blog/four-types-prometheus-metrics-to-collect/ From 27c8ba7c791a7601bcdfb86e8ee7fb92b99e49c6 Mon Sep 17 00:00:00 2001 From: Dmitry Ignatiev Date: Mon, 20 Nov 2023 01:37:38 +0300 Subject: [PATCH 6/9] Small note about summary metrics --- module2/10_monitoring_basics/lection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module2/10_monitoring_basics/lection.md b/module2/10_monitoring_basics/lection.md index 6880405..740d160 100644 --- a/module2/10_monitoring_basics/lection.md +++ b/module2/10_monitoring_basics/lection.md @@ -18,7 +18,7 @@ Prometheus поддерживает 4 вида метрик "из коробки - `Counter` - метрика этого типа используется чтобы замерять какое-либо неубывающее значение, как пример - общее количество HTTP-запросов к серверу. - `Gauge` - данный вид метрик используется для отображения значений, которые могут как увеличиваться, так и уменьшаться. Пример - количество памяти, занимаемой процессом. - `Histogram` - такие метрики представляют собой счетчики событий для нескольких заданных диапазонов. Используются, например, для отслеживания времени обработки HTTP-запросов. -- `Summary` - похожи на `Histogram`, но представляют собой препросчитанное разбиение значений по квантилям. +- `Summary` - похожи на `Histogram`, но представляют собой препросчитанное разбиение значений по квантилям. Этот тип метрик не поддерживает агрегацию, что делает его слабо приспособленным для распределенных приложений в кластере. К каждой метрике Prometheus могут быть прикрепленые разные метки(label), которые позволяют, например, идентифицировать источник информации. From 158184e0a6f169e121663cda4163e23c78cd2871 Mon Sep 17 00:00:00 2001 From: Dmitry Ignatiev Date: Mon, 20 Nov 2023 13:53:29 +0300 Subject: [PATCH 7/9] Mention git pull --- module2/10_monitoring_basics/tasks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module2/10_monitoring_basics/tasks.md b/module2/10_monitoring_basics/tasks.md index 604f169..cc2bd1d 100644 --- a/module2/10_monitoring_basics/tasks.md +++ b/module2/10_monitoring_basics/tasks.md @@ -2,7 +2,7 @@ ## Prometheus -1. Вы должны были получить обновленное приложение `todo_app`. +1. Обновите приложение `todo_app` из задания 08 сделав `git pull` ветки `main`. API-сервис приложения теперь отдает метрики Prometheus на порту `9123`(можно поменять через переменную среды `Metrics__Port`) и по url `/metrics`. From 20e07ea0325b62766127d826559930bcdb626fe8 Mon Sep 17 00:00:00 2001 From: Dmitry Ignatiev Date: Mon, 20 Nov 2023 15:24:18 +0300 Subject: [PATCH 8/9] Handle errors on JS side in todo_app --- .../todo_app/todo_ui/README.md | 2 - .../todo_ui/src/components/ErrorToast.vue | 38 +++++++++++ .../todo_ui/src/components/TodoList.vue | 64 ++++++++++++++++--- 3 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 module2/08_docker_containerization_advanced/todo_app/todo_ui/src/components/ErrorToast.vue diff --git a/module2/08_docker_containerization_advanced/todo_app/todo_ui/README.md b/module2/08_docker_containerization_advanced/todo_app/todo_ui/README.md index ff9e1a4..d8d71a5 100644 --- a/module2/08_docker_containerization_advanced/todo_app/todo_ui/README.md +++ b/module2/08_docker_containerization_advanced/todo_app/todo_ui/README.md @@ -1,7 +1,5 @@ # todo-ui -This template should help get you started developing with Vue 3 in Vite. - ## Recommended IDE Setup [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). diff --git a/module2/08_docker_containerization_advanced/todo_app/todo_ui/src/components/ErrorToast.vue b/module2/08_docker_containerization_advanced/todo_app/todo_ui/src/components/ErrorToast.vue new file mode 100644 index 0000000..05ff5ce --- /dev/null +++ b/module2/08_docker_containerization_advanced/todo_app/todo_ui/src/components/ErrorToast.vue @@ -0,0 +1,38 @@ + + + diff --git a/module2/08_docker_containerization_advanced/todo_app/todo_ui/src/components/TodoList.vue b/module2/08_docker_containerization_advanced/todo_app/todo_ui/src/components/TodoList.vue index 8ab8b76..29381d7 100644 --- a/module2/08_docker_containerization_advanced/todo_app/todo_ui/src/components/TodoList.vue +++ b/module2/08_docker_containerization_advanced/todo_app/todo_ui/src/components/TodoList.vue @@ -78,18 +78,24 @@ +
+ +