Задание:

a.    Любым способом разверните недостающие виртуальные машины в облаке в соответствие с топологией (см. Топология Project_03).

  1. Характеристики виртуальных машин:
    1. master01: 1vCPU, 1 ГБ ОЗУ, 10 ГБ размер диска.
    2. worker01: 1vCPU, 1 ГБ ОЗУ, 10 ГБ размер диска.
    3. worker02: 1vCPU, 1 ГБ ОЗУ, 10 ГБ размер
  2. Образ операционной системы: alt-p11-cloud-x86_64.qcow2.

b.    На развёрнутых виртуальных машинах реализуйте следующий функционал:

  1. Сформируйте кластер Docker Swarm.
    1. Используйте ВМ master01 в качестве менеджера кластера, worker01 и worker02 - в качестве исполнителей.
    2. Запускать контейнеры на менеджере запрещено.
  2. Разместите в кластере Docker Swarm service для организации собственного хранилища образов контейнеров:
    1. В качестве образа используйте registry:3
    2. Локальное хранилище образов должно быть доступно со всех узлов кластера на порту 5000
  3. Разместите в кластере Docker Swarm stack для организации работы приложения (см. Приложение Project_03)
    1. В качестве имени для stack используйте school-site-project
    2. Приложение должно быть доступно с Cloud-ADM по http://school-site.au.team и https://school-site.au.team
    3. В случае достапу по https, проблем с сертификатом возникать недолжно.
  4. На данный момент это просто статический сайт, но стоит предусмотреть возможность развёртывания таких сервисов в стеке как:
    1. redis - для решения задач, требующих быстрой обработки данных
    2. СУБД: PostgreSQL – для хранения данных
    3. Веб-приложение пока не умеет работать с данными сервисами, но сервисы должны быть развёрнуты в рамках стека school-site-project для будущей разработки

Вариант реализации:

Cloud-ADM:

Развёртывание недостающих виртуальных машин

  • Допустимы любые способы, в том числе и ручное создание ВМ
  • Модернизирует ранее написанные файлы для Terraform чтобы ускорить процесс создания ВМ
cd ~/Projects/
mkdir -p Project_03/terraform
cd Project_03/terraform
  • За основу возьмём файлы из Project02:
cp ~/Projects/Project_02/terraform/provider.tf ./
cp ~/Projects/Project_02/terraform/cloud-init.yml ./
cp ~/Projects/Project_02/terraform/network.tf ./
cp ~/Projects/Project_02/terraform/vm.tf ./
  • Инициализируем текущий каталог для работы с Terraform:
terraform init
  • Модернизируем файл network.tf в текущей директории для Project03:
resource "openstack_networking_port_v2" "port_vm_master01" {
    name           = "port_master01"
    network_id     = "61845892-f9cc-4fde-962c-34b59425a74d"
    admin_state_up = true

    fixed_ip {
        subnet_id   = "13592ca4-8782-410b-9bcc-90810ccab6fe"
        ip_address  = "192.168.1.107"
    }
}

resource "openstack_networking_port_v2" "port_vm_worker01" {
    name           = "port_worker01"
    network_id     = "61845892-f9cc-4fde-962c-34b59425a74d"
    admin_state_up = true

    fixed_ip {
        subnet_id   = "13592ca4-8782-410b-9bcc-90810ccab6fe"
        ip_address  = "192.168.1.108"
    }
}

resource "openstack_networking_port_v2" "port_vm_worker02" {
    name           = "port_worker02"
    network_id     = "61845892-f9cc-4fde-962c-34b59425a74d"
    admin_state_up = true

    fixed_ip {
        subnet_id   = "13592ca4-8782-410b-9bcc-90810ccab6fe"
        ip_address  = "192.168.1.109"
    }
}
  • Модернизируем файл vm.tf в текущей директории для Project03:
resource "openstack_compute_instance_v2" "master01" {
  name      = "master01"
  flavor_id = "03bf1b85-2f5f-4ada-a07b-8b994b6dcb57"
  user_data = file("cloud-init.yml")

  block_device {
    uuid                  = "827e08fa-fd3c-41cd-92ca-845bb5018478"
    source_type           = "image"
    volume_size           = "10"
    boot_index            = 0
    destination_type      = "volume"
    delete_on_termination = true
  }

  network {
    port = openstack_networking_port_v2.port_vm_master01.id
  }
}

resource "openstack_compute_instance_v2" "worker01" {
  name      = "worker01"
  flavor_id = "03bf1b85-2f5f-4ada-a07b-8b994b6dcb57"
  user_data = file("cloud-init.yml")

  block_device {
    uuid                  = "827e08fa-fd3c-41cd-92ca-845bb5018478"
    source_type           = "image"
    volume_size           = "10"
    boot_index            = 0
    destination_type      = "volume"
    delete_on_termination = true
  }

  network {
    port = openstack_networking_port_v2.port_vm_worker01.id
  }
}

resource "openstack_compute_instance_v2" "worker02" {
  name      = "worker02"
  flavor_id = "03bf1b85-2f5f-4ada-a07b-8b994b6dcb57"
  user_data = file("cloud-init.yml")

  block_device {
    uuid                  = "827e08fa-fd3c-41cd-92ca-845bb5018478"
    source_type           = "image"
    volume_size           = "10"
    boot_index            = 0
    destination_type      = "volume"
    delete_on_termination = true
  }

  network {
    port = openstack_networking_port_v2.port_vm_worker02.id
  }
}
  • Запускаем автоматическое развёртывания ВМ для Project03 через Terraform:
terraform apply
  • Результат:

  • Результат в веб-интерфейсе облака:

  • Для удобства приводим конфигурационный файл /etc/hosts к следующему виду:

  • Проверяем доступ до созданных ВМ:

 

master01, worker01 и worker02:

  • Установим пакет docker-engine:
apt-get update && apt-get install -y docker-engine
  • Включить и добавить в автозагрузку службу docker:
systemctl enable --now docker
  • Внести изменения в конфигурационный файл /etc/docker/daemon.json:
    • привести параметр live-restore к следующему виду:

  • Перезагрузить службу docker для применения изменений:
systemctl restart docker

 

master01:

  • Создаём кластер Docker Swarm:
docker swarm init
  • Результат:
    • команда генерирует два случайных токена, рабочий токен и токен менеджера
    • когда добавляется новый узел к swarm, узел присоединяется как рабочий или управляющий узел на основе токена

 

worker01 и worker02:

  • Добавляем узлы в кластер Docker Swarm:
    • worker01:

    • worker02:

 

master01:

  • Проверить наличие нод в кластере:
docker node ls
  • Результат:

  • Запускаем сервис для локального хранилища на базе образа registry:3:
docker service create \
    --name registry \
    --publish published=5000,target=5000 \
    --constraint node.role==worker \
    registry:3
  • Проверьте статус запущенного сервиса можно с помощью docker service ls:

  • Проверить что задача развернулась именно на ноде с ролью worker можно с помощью команды docker service ps registry:

 

Cloud-ADM:

  • Любым возможным способом скачиваем файлы приложения Project03 и передаём их на master01:
scp Project03.zip master01:~/

 

master01:

  • Устанавливаем пакет unzip и docker-compose-v2:
    • Docker Compose будет использоваться для тестирования сборки и запуска прилодения с последующим добавлением его в ранее развёрнутое локальное хранилище
apt-get install -y unzip docker-compose-v2
  • Расспаковываем архив с приложением и переходим в директорию:
unzip /home/altlinux/Project03.zip -d ./
cd School-site-project-main/
  • Создаём максимально минимальный Dockerfile для сборки образа приложения:
FROM nginx:1.29.3-alpine
COPY . /usr/share/nginx/html
  • Создадим файл compose.yaml и укажем в нём следующее содержимое:
    • для сборки образа и тестирования приложения
    • образ называем именно так, чтобы в дальнейшем можно было его добавить в ранее развёрнутое локальное хранилище обращов
    • можно использовать 127.0.0.1, всё остальное за вас сделает маршрутизация в рамках кластера Docker Swarm
services:
  app:
    image: 127.0.0.1:5000/app
    build: .
    ports:
      - "80:80"
  • Выполним сборку и запуск контейнера для проверки работоспособности:
docker compose up -d
  • Проверить сборку образа можно с помощью команды docker image ls:

  • Проверить запущенный контейнер можно с помощью команды docker compose ps:

  • Проверить работоспособность веб-приложения с Cloud-ADM в браузере:
    • обращаясь в веб-браузере на IP-адрес любой из нод:

  • Удаляем всё что было использовано для тестового запуска:
docker compose down --volumes
docker image rm 127.0.0.1:5000/app

 

Cloud-ADM:

  • Сгенерируем необходимые файлы сертификатов, через ранее развёрнутый ЦА:
    • создаём ключ:
openssl genrsa -out site.key 2048
    • создаём запрос:
openssl req -key site.key -new -out site.csr
  • Результат:

  • Файл с расширениями для сертификата site.ext:
cat <<EOF > site.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
subjectAltName=@alt_names
[alt_names]
DNS.1=school-site.au.team
IP.1=192.168.1.107
EOF
  • Выпускаем сертификат:
openssl x509 -req -CA Projects/Project_01/ansible/files/ca.crt -CAkey Projects/Project_01/ansible/files/ca.key -in site.csr -out site.crt -days 365 -CAcreateserial -extfile site.ext
  • Передаём ключ и сертификат на master01:
scp site.key master01:~/
scp site.crt master01:~/

 

master01:

  • Копируем ключ и сертификат в директорию с файлами приложения:
cp /home/altlinux/site.crt ./
cp /home/altlinux/site.key ./
  • Создаём свой конфигурационный файл для веб-сервера nginx, например custom.conf:
server {
    listen       80;
    server_name  school-site.au.team;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

server {
    listen       443 ssl;
    server_name  school-site.au.team;

    ssl_certificate /etc/nginx/site.crt;
    ssl_certificate_key  /etc/nginx/site.key;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
  • Модернизируем ранее написанный Dockerfile для сборки образа с приложением:
FROM nginx:1.29.3-alpine
COPY site.crt site.key /etc/nginx/
COPY custom.conf /etc/nginx/conf.d/default.conf
COPY . /usr/share/nginx/html
  • Модернизируем ранее написанный compose.yaml:
services:
  app:
    image: 127.0.0.1:5000/app
    build: .
    ports:
      - "80:80"
      - "443:443"
  • Выполним сборку и запуск контейнера для проверки работоспособности:
docker compose up -d
  • Проверить доступ к приложению с Cloud-ADM как по http так и по https
  • Удаляем всё что было использовано для тестового запуска:
docker compose down --volumes
  • Отправляем средствами Docker Compose образ нашего приложения в ранее развёрнутое хранилище образов:
docker compose push
  • Результат:

  • Удаляем образ собранный локально:
docker image rm 127.0.0.1:5000/app
  • Модернизируем ранее написанный compose.yaml:
services:
  app:
    image: 127.0.0.1:5000/app
    ports:
      - "80:80"
      - "443:443"
    deploy:
      placement:
        constraints:
          - "node.role==worker"

  redis:
    image: redis:8.4.0-alpine
    deploy:
      placement:
        constraints:
          - "node.role==worker"

  db:
    image: postgres:18.1-alpine3.22
    environment:
      POSTGRES_PASSWORD: "P@ssw0rd"
    deploy:
      placement:
        constraints:
          - "node.role==worker"
  • Запускаем развёртывание стека с именем school-site-project:
docker stack deploy --compose-file compose.yaml school-site-project
  • Проверить созданные стек в кластере можно с помощью команды docker stack ls:

  • Проверить созданные сервисы в рамках стека можно с помощью команды docker stack services school-site-project:

  • Проверить на каких нодах запустились задачи сервивов в рамках стека можно с помощью команды docker stack ps school-site-project:

 

Cloud-ADM:

  • Добавляем в файл /etc/hosts следующую запись:

Последнее изменение: среда, 26 ноября 2025, 10:53