feat: add lab 3

This commit is contained in:
Black_Raven committed 2026-06-18 21:52:59 +03:00
1 parent b2713667e6
commit cc1e9c2320
12 files changed
+1512

No files matched your search

@@ -0,0 +1,421 @@
terraform {
required_providers {
vkcs = {
source = "vk-cs/vkcs"
version = "~> 0.1"
}
}
}
# Настройка провайдера (использует переменные окружения из RC-файла)
provider "vkcs" {}
data "vkcs_networking_network" "extnet" {
name = var.external_network_name
}
data "vkcs_networking_secgroup" "ssh" {
name = "ssh"
}
data "vkcs_networking_router" "router" {
id = var.router_id
}
data "vkcs_images_image" "ubuntu" {
name = var.image_name
}
data "vkcs_compute_flavor" "web" {
name = var.flavor_web
}
data "vkcs_compute_flavor" "bastion" {
name = var.flavor_bastion
}
resource "vkcs_networking_network" "main" {
name = "${var.project_name}-network"
sdn = "sprut"
}
resource "vkcs_networking_subnet" "public" {
name = "${var.project_name}-public-subnet"
network_id = vkcs_networking_network.main.id
cidr = var.public_subnet_cidr
dns_nameservers = ["8.8.8.8", "1.1.1.1"]
}
resource "vkcs_networking_subnet" "private" {
name = "${var.project_name}-private-subnet"
network_id = vkcs_networking_network.main.id
cidr = var.private_subnet_cidr
dns_nameservers = ["8.8.8.8", "1.1.1.1"]
}
resource "vkcs_networking_router_interface" "public" {
router_id = data.vkcs_networking_router.router.id
subnet_id = vkcs_networking_subnet.public.id
}
resource "vkcs_networking_router_interface" "private" {
router_id = data.vkcs_networking_router.router.id
subnet_id = vkcs_networking_subnet.private.id
}
resource "vkcs_networking_secgroup" "main" {
name = "${var.project_name}-secgroup"
description = "Security group for monitoring lab"
}
resource "vkcs_networking_secgroup_rule" "ssh" {
security_group_id = vkcs_networking_secgroup.main.id
direction = "ingress"
protocol = "tcp"
port_range_min = 22
port_range_max = 22
remote_ip_prefix = "${var.my_ip}/32"
}
resource "vkcs_networking_secgroup_rule" "http" {
security_group_id = vkcs_networking_secgroup.main.id
direction = "ingress"
protocol = "tcp"
port_range_min = 80
port_range_max = 80
remote_ip_prefix = "0.0.0.0/0"
}
resource "vkcs_networking_secgroup_rule" "prometheus" {
security_group_id = vkcs_networking_secgroup.main.id
direction = "ingress"
protocol = "tcp"
port_range_min = 9090
port_range_max = 9090
remote_ip_prefix = "0.0.0.0/0"
}
resource "vkcs_networking_secgroup_rule" "grafana" {
security_group_id = vkcs_networking_secgroup.main.id
direction = "ingress"
protocol = "tcp"
port_range_min = 3000
port_range_max = 3000
remote_ip_prefix = "0.0.0.0/0"
}
resource "vkcs_networking_secgroup_rule" "node_exporter_public" {
security_group_id = vkcs_networking_secgroup.main.id
direction = "ingress"
protocol = "tcp"
port_range_min = 9100
port_range_max = 9100
remote_ip_prefix = var.public_subnet_cidr
}
resource "vkcs_networking_secgroup_rule" "node_exporter_private" {
security_group_id = vkcs_networking_secgroup.main.id
direction = "ingress"
protocol = "tcp"
port_range_min = 9100
port_range_max = 9100
remote_ip_prefix = var.private_subnet_cidr
}
resource "vkcs_networking_secgroup_rule" "egress" {
security_group_id = vkcs_networking_secgroup.main.id
direction = "egress"
remote_ip_prefix = "0.0.0.0/0"
}
resource "vkcs_compute_keypair" "my_key" {
name = "${var.project_name}-key"
public_key = file(var.ssh_public_key)
}
resource "vkcs_compute_instance" "web" {
count = 2
name = "${var.project_name}-web-${count.index + 1}"
flavor_id = data.vkcs_compute_flavor.web.id
key_pair = vkcs_compute_keypair.my_key.name
security_group_ids = [vkcs_networking_secgroup.main.id, data.vkcs_networking_secgroup.ssh.id]
availability_zone = "MS1"
block_device {
uuid = data.vkcs_images_image.ubuntu.id
source_type = "image"
destination_type = "volume"
volume_type = "ceph-ssd"
volume_size = var.volume_size_web
boot_index = 0
delete_on_termination = true
}
network {
uuid = vkcs_networking_network.main.id
fixed_ip_v4 = cidrhost(var.private_subnet_cidr, count.index + 10)
}
user_data = <<-EOF
#!/bin/bash
set -e
apt update
apt install -y nginx
cat <<HTML > /var/www/html/index.html
<!DOCTYPE html>
<html>
<head><title>Web Server $(hostname)</title></head>
<body>
<h1>Welcome to $(hostname)</h1>
<p>Server IP: $(hostname -I | awk '{print $1}')</p>
</body>
</html>
HTML
systemctl enable nginx
systemctl start nginx
# Node Exporter
cd /tmp
wget -q https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xf node_exporter-1.7.0.linux-amd64.tar.gz
sudo mv node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/
rm -rf node_exporter-1.7.0.linux-amd64*
cat <<SERVICE > /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
After=network.target
[Service]
Type=simple
User=nobody
Group=nogroup
ExecStart=/usr/local/bin/node_exporter
Restart=always
[Install]
WantedBy=multi-user.target
SERVICE
systemctl daemon-reload
systemctl enable node_exporter
systemctl start node_exporter
EOF
}
locals {
web_private_ips = vkcs_compute_instance.web[*].network[0].fixed_ip_v4
}
resource "vkcs_lb_loadbalancer" "main" {
name = "${var.project_name}-lb"
vip_subnet_id = vkcs_networking_subnet.public.id
}
resource "vkcs_lb_listener" "http" {
name = "${var.project_name}-listener"
loadbalancer_id = vkcs_lb_loadbalancer.main.id
protocol = "HTTP"
protocol_port = 80
}
resource "vkcs_lb_pool" "web" {
name = "${var.project_name}-pool"
protocol = "HTTP"
lb_method = "ROUND_ROBIN"
listener_id = vkcs_lb_listener.http.id
}
resource "vkcs_lb_monitor" "web" {
pool_id = vkcs_lb_pool.web.id
type = "HTTP"
url_path = "/"
delay = 10
timeout = 5
max_retries = 3
}
resource "vkcs_lb_member" "web" {
count = 2
pool_id = vkcs_lb_pool.web.id
address = local.web_private_ips[count.index]
protocol_port = 80
subnet_id = vkcs_networking_subnet.private.id
}
resource "vkcs_networking_floatingip" "lb" {
pool = data.vkcs_networking_network.extnet.name
}
resource "vkcs_networking_floatingip_associate" "lb" {
floating_ip = vkcs_networking_floatingip.lb.address
port_id = vkcs_lb_loadbalancer.main.vip_port_id
}
resource "vkcs_compute_instance" "bastion" {
name = "${var.project_name}-bastion-monitoring"
flavor_id = data.vkcs_compute_flavor.bastion.id
key_pair = vkcs_compute_keypair.my_key.name
security_group_ids = [vkcs_networking_secgroup.main.id, data.vkcs_networking_secgroup.ssh.id]
availability_zone = "MS1"
block_device {
uuid = data.vkcs_images_image.ubuntu.id
source_type = "image"
destination_type = "volume"
volume_type = "ceph-ssd"
volume_size = var.volume_size_bastion
boot_index = 0
delete_on_termination = true
}
network {
uuid = vkcs_networking_network.main.id
fixed_ip_v4 = cidrhost(var.public_subnet_cidr, 10)
}
user_data = <<-EOF
#!/bin/bash
set -e
# ---- Prometheus ----
cd /tmp
wget -q https://github.com/prometheus/prometheus/releases/download/v2.48.0/prometheus-2.48.0.linux-amd64.tar.gz
tar xf prometheus-2.48.0.linux-amd64.tar.gz
sudo mv prometheus-2.48.0.linux-amd64 /opt/prometheus
sudo mkdir -p /opt/prometheus/data
sudo chown -R nobody:nogroup /opt/prometheus/data
cat <<PROM > /opt/prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "rules/*.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets:
- 'localhost:9100'
${join("\n", [for ip in local.web_private_ips : " - '${ip}:9100'"])}
PROM
cat <<SERVICE > /etc/systemd/system/prometheus.service
[Unit]
Description=Prometheus
After=network.target
[Service]
Type=simple
User=nobody
Group=nogroup
ExecStart=/opt/prometheus/prometheus --config.file=/opt/prometheus/prometheus.yml --storage.tsdb.path=/opt/prometheus/data
Restart=always
[Install]
WantedBy=multi-user.target
SERVICE
systemctl daemon-reload
systemctl enable prometheus
systemctl start prometheus
# ---- Grafana (прямая установка) ----
cd /tmp
wget -q https://dl.grafana.com/oss/release/grafana_10.4.0_amd64.deb
sudo apt-get update
sudo apt-get install -y musl libfontconfig1 fontconfig-config fonts-dejavu-core
sudo dpkg -i grafana_10.4.0_amd64.deb || sudo apt-get install -f -y
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
# ---- Node Exporter для самой ВМ ----
cd /tmp
wget -q https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xf node_exporter-1.7.0.linux-amd64.tar.gz
sudo mv node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/
rm -rf node_exporter-1.7.0.linux-amd64*
cat <<NEX > /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
After=network.target
[Service]
Type=simple
User=nobody
Group=nogroup
ExecStart=/usr/local/bin/node_exporter
Restart=always
[Install]
WantedBy=multi-user.target
NEX
systemctl daemon-reload
systemctl enable node_exporter
systemctl start node_exporter
# ---- Alertmanager ----
cd /tmp
wget -q https://github.com/prometheus/alertmanager/releases/download/v0.26.0/alertmanager-0.26.0.linux-amd64.tar.gz
tar xf alertmanager-0.26.0.linux-amd64.tar.gz
sudo mv alertmanager-0.26.0.linux-amd64 /opt/alertmanager
cat <<AM > /opt/alertmanager/alertmanager.yml
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 1h
receiver: 'null'
receivers:
- name: 'null'
AM
cat <<AMS > /etc/systemd/system/alertmanager.service
[Unit]
Description=Alertmanager
After=network.target
[Service]
Type=simple
User=nobody
Group=nogroup
ExecStart=/opt/alertmanager/alertmanager --config.file=/opt/alertmanager/alertmanager.yml
Restart=always
[Install]
WantedBy=multi-user.target
AMS
systemctl daemon-reload
systemctl enable alertmanager
systemctl start alertmanager
# ---- Правила алертов ----
sudo mkdir -p /opt/prometheus/rules
cat <<RULES > /opt/prometheus/rules/alerts.yml
groups:
- name: instance_alerts
rules:
- alert: InstanceDown
expr: up{job="node"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Instance {{ \$labels.instance }} is down"
description: "{{ \$labels.instance }} has been down for more than 5 minutes."
RULES
systemctl restart prometheus
EOF
}
resource "vkcs_networking_floatingip" "bastion" {
pool = data.vkcs_networking_network.extnet.name
}
resource "vkcs_networking_floatingip_associate" "bastion" {
floating_ip = vkcs_networking_floatingip.bastion.address
port_id = vkcs_compute_instance.bastion.network[0].port
}
@@ -0,0 +1,29 @@
output "load_balancer_ip" {
value = vkcs_networking_floatingip.lb.address
description = "Публичный IP балансировщика"
}
output "bastion_floating_ip" {
value = vkcs_networking_floatingip.bastion.address
description = "Публичный IP ВМ бастиона + мониторинга"
}
output "web_private_ips" {
value = local.web_private_ips
description = "Приватные IP веб-серверов"
}
output "grafana_url" {
value = "http://${vkcs_networking_floatingip.bastion.address}:3000"
description = "URL Grafana"
}
output "prometheus_url" {
value = "http://${vkcs_networking_floatingip.bastion.address}:9090"
description = "URL Prometheus"
}
output "ssh_to_bastion" {
value = "ssh -i ~/.ssh/id_rsa ubuntu@${vkcs_networking_floatingip.bastion.address}"
description = "Команда для подключения к бастиону"
}
@@ -0,0 +1,71 @@
variable "my_ip" {
description = "Ваш публичный IP для SSH (узнать через curl ifconfig.me)"
type = string
sensitive = true
}
variable "project_name" {
description = "Префикс для имен ресурсов"
type = string
default = "lab3"
}
variable "router_id" {
description = "ID существующего роутера"
type = string
default = "913bdd47-9155-45b2-b404-5c10d0086132"
}
variable "external_network_name" {
description = "Имя внешней сети для Floating IP"
type = string
default = "internet"
}
variable "ssh_public_key" {
description = "Путь к публичному SSH-ключу"
type = string
default = "~/.ssh/id_rsa.pub"
}
variable "image_name" {
description = "Имя образа Ubuntu 20.04"
type = string
default = "ubuntu-20-202602051631.gite7a38aaf"
}
variable "flavor_web" {
description = "Flavor для веб-серверов (используется только как ID, т.к. загрузка с тома)"
type = string
default = "Basic-1-1-10"
}
variable "flavor_bastion" {
description = "Flavor для ВМ бастиона"
type = string
default = "Basic-1-1-10"
}
variable "public_subnet_cidr" {
description = "CIDR публичной подсети"
type = string
default = "192.168.1.0/24"
}
variable "private_subnet_cidr" {
description = "CIDR приватной подсети"
type = string
default = "192.168.2.0/24"
}
variable "volume_size_web" {
description = "Размер диска для веб-серверов (ГБ)"
type = number
default = 10
}
variable "volume_size_bastion" {
description = "Размер диска для бастиона (ГБ)"
type = number
default = 20
}