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 +```` 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/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 @@ +
+ +