Compare commits
5 Commits
bb4dc311c1
...
87883a6175
| Author | SHA1 | Date | |
|---|---|---|---|
| 87883a6175 | |||
|
|
abc7a61de0 | ||
|
|
e5598685f4 | ||
|
|
326572de4d | ||
|
|
40694927c8 |
13
.codeassistant/mcp.json
Normal file
13
.codeassistant/mcp.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"sourcecraft": {
|
||||||
|
"type": "streamable-http",
|
||||||
|
"url": "https://api.sourcecraft.tech/mcp",
|
||||||
|
"disabled": false,
|
||||||
|
"headers": {},
|
||||||
|
"disabledTools": [],
|
||||||
|
"timeout": 60,
|
||||||
|
"alwaysAllow": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
ansible/ansible.cfg
Normal file
6
ansible/ansible.cfg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = ./inventory.ini
|
||||||
|
remote_user = iurii
|
||||||
|
private_key_file = ~/.ssh/id_rsa
|
||||||
|
host_key_checking = false
|
||||||
|
interpreter_python = auto_silent
|
||||||
2
ansible/inventory.ini
Normal file
2
ansible/inventory.ini
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[docker]
|
||||||
|
lab1 ansible_host=192.168.20.11
|
||||||
45
ansible/playbook.yml
Normal file
45
ansible/playbook.yml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
- name: Install Docker on Rocky Linux 9
|
||||||
|
hosts: docker
|
||||||
|
become: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
docker_packages:
|
||||||
|
- docker-ce
|
||||||
|
- docker-ce-cli
|
||||||
|
- containerd.io
|
||||||
|
- docker-buildx-plugin
|
||||||
|
- docker-compose-plugin
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Install dnf plugins
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
name: dnf-plugins-core
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Add Docker CE repository
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://download.docker.com/linux/rhel/docker-ce.repo
|
||||||
|
dest: /etc/yum.repos.d/docker-ce.repo
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Install Docker packages
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
name: "{{ docker_packages }}"
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Enable and start Docker
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: docker
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Verify Docker service
|
||||||
|
ansible.builtin.command: systemctl is-active docker
|
||||||
|
register: docker_status
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Show Docker status
|
||||||
|
ansible.builtin.debug:
|
||||||
|
var: docker_status.stdout
|
||||||
21
cluster/cloud-config/rocky.yml
Normal file
21
cluster/cloud-config/rocky.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#cloud-config
|
||||||
|
timezone: Europe/Moscow
|
||||||
|
|
||||||
|
users:
|
||||||
|
- name: iurii
|
||||||
|
groups: [wheel]
|
||||||
|
shell: /bin/bash
|
||||||
|
lock_passwd: false
|
||||||
|
passwd: "$6$Zc8nwvtw0Kns5.sD$FpQ4aBSeGogefqjM4we4U5QQd4YBtC98tuG3rR4j9ZmbtC1kyFf2sY/IodYW3wG.U81aEntlZrtOTOqw3ZcOc0"
|
||||||
|
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ${ssh_key}
|
||||||
|
|
||||||
|
package_update: true
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- qemu-guest-agent
|
||||||
|
|
||||||
|
runcmd:
|
||||||
|
- systemctl enable --now qemu-guest-agent
|
||||||
|
- hostnamectl set-hostname ${hostname}
|
||||||
@@ -99,7 +99,8 @@
|
|||||||
locals {
|
locals {
|
||||||
nodes = {
|
nodes = {
|
||||||
k8s-master-1 = {
|
k8s-master-1 = {
|
||||||
cloudinit = "master.yml"
|
cloudinit = "rocky.yml"
|
||||||
|
image_file = "import/rocky9.qcow2"
|
||||||
index = 1
|
index = 1
|
||||||
cpu = var.worker_cpu
|
cpu = var.worker_cpu
|
||||||
memory = 4092
|
memory = 4092
|
||||||
@@ -115,45 +116,45 @@ locals {
|
|||||||
gateway = "192.168.20.1"
|
gateway = "192.168.20.1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
k8s-worker-1 = {
|
# k8s-worker-1 = {
|
||||||
cloudinit = "worker.yml"
|
# cloudinit = "worker.yml"
|
||||||
index = 2
|
# index = 2
|
||||||
cpu = var.worker_cpu
|
# cpu = var.worker_cpu
|
||||||
memory = 8192
|
# memory = 8192
|
||||||
disk = var.worker_disk
|
# disk = var.worker_disk
|
||||||
datastore = var.worker_datastore
|
# datastore = var.worker_datastore
|
||||||
|
|
||||||
network_devices = [
|
# network_devices = [
|
||||||
{
|
# {
|
||||||
bridge = var.node_bridge
|
# bridge = var.node_bridge
|
||||||
vlan_id = 20
|
# vlan_id = 20
|
||||||
ip = "192.168.20.22"
|
# ip = "192.168.20.22"
|
||||||
cidr = 24
|
# cidr = 24
|
||||||
gateway = "192.168.20.1"
|
# gateway = "192.168.20.1"
|
||||||
}
|
# }
|
||||||
]
|
# ]
|
||||||
},
|
# },
|
||||||
k8s-worker-2 = {
|
# k8s-worker-2 = {
|
||||||
cloudinit = "worker.yml"
|
# cloudinit = "worker.yml"
|
||||||
index = 3
|
# index = 3
|
||||||
cpu = var.worker_cpu
|
# cpu = var.worker_cpu
|
||||||
memory = 8192
|
# memory = 8192
|
||||||
disk = var.worker_disk
|
# disk = var.worker_disk
|
||||||
datastore = var.worker_datastore
|
# datastore = var.worker_datastore
|
||||||
|
|
||||||
network_devices = [
|
# network_devices = [
|
||||||
{
|
# {
|
||||||
bridge = var.node_bridge
|
# bridge = var.node_bridge
|
||||||
vlan_id = 20
|
# vlan_id = 20
|
||||||
ip = "192.168.20.23"
|
# ip = "192.168.20.23"
|
||||||
cidr = 24
|
# cidr = 24
|
||||||
gateway = "192.168.20.1"
|
# gateway = "192.168.20.1"
|
||||||
},
|
# },
|
||||||
{
|
# {
|
||||||
bridge = "vmbr0"
|
# bridge = "vmbr0"
|
||||||
}
|
# }
|
||||||
]
|
# ]
|
||||||
}
|
# }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
124
example_locals.tf
Normal file
124
example_locals.tf
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
locals {
|
||||||
|
nodes = {
|
||||||
|
k8s-worker-1 = {
|
||||||
|
index = 1
|
||||||
|
cpu = 2
|
||||||
|
memory = 2048
|
||||||
|
|
||||||
|
disks = [
|
||||||
|
{
|
||||||
|
datastore = "ssd2"
|
||||||
|
interface = "scsi0"
|
||||||
|
size = 20
|
||||||
|
import_from = "local:import/ubuntu-24.qcow2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
network_devices = [
|
||||||
|
{
|
||||||
|
bridge = "vmbr0"
|
||||||
|
vlan_id = 20
|
||||||
|
ip = "192.168.20.10"
|
||||||
|
cidr = 24
|
||||||
|
gateway = "192.168.20.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
k8s-worker-2 = {
|
||||||
|
index = 2
|
||||||
|
cpu = 2
|
||||||
|
memory = 2048
|
||||||
|
|
||||||
|
disks = [
|
||||||
|
{
|
||||||
|
datastore = "ssd2"
|
||||||
|
interface = "scsi0"
|
||||||
|
size = 20
|
||||||
|
import_from = "local:import/ubuntu-24.qcow2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
network_devices = [
|
||||||
|
{
|
||||||
|
bridge = "vmbr0"
|
||||||
|
vlan_id = 20
|
||||||
|
ip = "192.168.20.11"
|
||||||
|
cidr = 24
|
||||||
|
gateway = "192.168.20.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
k8s-worker-3 = {
|
||||||
|
index = 3
|
||||||
|
cpu = 2
|
||||||
|
memory = 2048
|
||||||
|
|
||||||
|
disks = [
|
||||||
|
{
|
||||||
|
datastore = "ssd2"
|
||||||
|
interface = "scsi0"
|
||||||
|
size = 20
|
||||||
|
import_from = "local:import/ubuntu-24.qcow2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
network_devices = [
|
||||||
|
{
|
||||||
|
bridge = "vmbr0"
|
||||||
|
vlan_id = 20
|
||||||
|
ip = "192.168.20.12"
|
||||||
|
cidr = 24
|
||||||
|
gateway = "192.168.20.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
k8s-worker-4 = {
|
||||||
|
index = 4
|
||||||
|
cpu = 2
|
||||||
|
memory = 2048
|
||||||
|
|
||||||
|
disks = [
|
||||||
|
{
|
||||||
|
datastore = "ssd2"
|
||||||
|
interface = "scsi0"
|
||||||
|
size = 20
|
||||||
|
import_from = "local:import/ubuntu-24.qcow2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
network_devices = [
|
||||||
|
{
|
||||||
|
bridge = "vmbr0"
|
||||||
|
vlan_id = 20
|
||||||
|
ip = "192.168.20.13"
|
||||||
|
cidr = 24
|
||||||
|
gateway = "192.168.20.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
k8s-worker-5 = {
|
||||||
|
index = 5
|
||||||
|
cpu = 2
|
||||||
|
memory = 2048
|
||||||
|
|
||||||
|
disks = [
|
||||||
|
{
|
||||||
|
datastore = "ssd2"
|
||||||
|
interface = "scsi0"
|
||||||
|
size = 20
|
||||||
|
import_from = "local:import/ubuntu-24.qcow2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
network_devices = [
|
||||||
|
{
|
||||||
|
bridge = "vmbr0"
|
||||||
|
vlan_id = 20
|
||||||
|
ip = "192.168.20.14"
|
||||||
|
cidr = 24
|
||||||
|
gateway = "192.168.20.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
generate.py
Normal file
54
generate.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
BASE_IP = "192.168.20"
|
||||||
|
START = 10
|
||||||
|
COUNT = 5
|
||||||
|
|
||||||
|
CPU = 2
|
||||||
|
MEMORY = 2048
|
||||||
|
GATEWAY = "192.168.20.1"
|
||||||
|
|
||||||
|
def generate():
|
||||||
|
print("locals {")
|
||||||
|
print(" nodes = {")
|
||||||
|
|
||||||
|
for i in range(COUNT):
|
||||||
|
idx = i + 1
|
||||||
|
last_octet = START + i
|
||||||
|
|
||||||
|
if last_octet > 254:
|
||||||
|
raise ValueError("IP overflow")
|
||||||
|
|
||||||
|
ip = f"{BASE_IP}.{last_octet}"
|
||||||
|
comma = "," if i < COUNT - 1 else ""
|
||||||
|
|
||||||
|
print(f""" k8s-worker-{idx} = {{
|
||||||
|
index = {idx}
|
||||||
|
cpu = {CPU}
|
||||||
|
memory = {MEMORY}
|
||||||
|
|
||||||
|
disks = [
|
||||||
|
{{
|
||||||
|
datastore = "ssd2"
|
||||||
|
interface = "scsi0"
|
||||||
|
size = 20
|
||||||
|
import_from = "local:import/ubuntu-24.qcow2"
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
|
||||||
|
network_devices = [
|
||||||
|
{{
|
||||||
|
bridge = "vmbr0"
|
||||||
|
vlan_id = 20
|
||||||
|
ip = "{ip}"
|
||||||
|
cidr = 24
|
||||||
|
gateway = "{GATEWAY}"
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}}{comma}""")
|
||||||
|
|
||||||
|
print(" }")
|
||||||
|
print("}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#cloud-config
|
#cloud-config
|
||||||
# vpn
|
# Создать passwd hash: openssl passwd -6
|
||||||
|
|
||||||
timezone: Europe/Moscow
|
timezone: Europe/Moscow
|
||||||
|
|
||||||
21
infra/cloud-config/rocky.yml
Normal file
21
infra/cloud-config/rocky.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#cloud-config
|
||||||
|
timezone: Europe/Moscow
|
||||||
|
|
||||||
|
users:
|
||||||
|
- name: iurii
|
||||||
|
groups: [wheel]
|
||||||
|
shell: /bin/bash
|
||||||
|
lock_passwd: false
|
||||||
|
passwd: "$6$Zc8nwvtw0Kns5.sD$FpQ4aBSeGogefqjM4we4U5QQd4YBtC98tuG3rR4j9ZmbtC1kyFf2sY/IodYW3wG.U81aEntlZrtOTOqw3ZcOc0"
|
||||||
|
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ${ssh_key}
|
||||||
|
|
||||||
|
package_update: true
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- qemu-guest-agent
|
||||||
|
|
||||||
|
runcmd:
|
||||||
|
- systemctl enable --now qemu-guest-agent
|
||||||
|
- hostnamectl set-hostname ${hostname}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#cloud-config
|
#cloud-config
|
||||||
# vpn
|
# Создать passwd hash: openssl passwd -6
|
||||||
|
|
||||||
timezone: Europe/Moscow
|
timezone: Europe/Moscow
|
||||||
|
|
||||||
179
infra/locals.tf
179
infra/locals.tf
@@ -1,43 +1,160 @@
|
|||||||
# nodes — описание виртуальных машин
|
# nodes — описание виртуальных машин
|
||||||
#
|
#
|
||||||
|
# Общая идея:
|
||||||
|
# - каждая VM может иметь несколько сетевых интерфейсов (network_devices)
|
||||||
|
# - каждый интерфейс полностью описывает свою сеть (bridge, VLAN, IP, gateway)
|
||||||
|
# - порядок элементов в network_devices важен:
|
||||||
|
# [0] → eth0 (основной интерфейс, обычно с default gateway)
|
||||||
|
# [1] → eth1
|
||||||
|
# [2] → eth2
|
||||||
|
#
|
||||||
|
# network_devices:
|
||||||
|
# - список сетевых интерфейсов VM
|
||||||
|
#
|
||||||
|
# поля:
|
||||||
|
#
|
||||||
|
# bridge:
|
||||||
|
# - имя Proxmox bridge (например vmbr0, vmbr1)
|
||||||
|
# - ОБЯЗАТЕЛЬНО
|
||||||
|
#
|
||||||
# vlan_id:
|
# vlan_id:
|
||||||
# - опциональный параметр
|
# - опционально
|
||||||
# - если НЕ указан → VM будет в обычной сети (untagged, vmbr0)
|
# - если НЕ указан → интерфейс untagged
|
||||||
# - если указан → VM попадет в соответствующий VLAN (например 20 → 192.168.20.0/24)
|
# - если указан → интерфейс будет в VLAN (например 20 → зависит от настройки Proxmox bridge)
|
||||||
|
#
|
||||||
|
# ip:
|
||||||
|
# - IPv4 адрес без CIDR (например "192.168.20.11")
|
||||||
|
# - если не указан → будет использован DHCP (если доступен в сети)
|
||||||
|
#
|
||||||
|
# cidr:
|
||||||
|
# - маска сети (например 24)
|
||||||
|
# - используется вместе с ip → итог: ip/cidr
|
||||||
|
#
|
||||||
|
# gateway:
|
||||||
|
# - опционально
|
||||||
|
# - указывать ТОЛЬКО для одного интерфейса (обычно первого)
|
||||||
|
# - задаёт default route внутри VM
|
||||||
|
#
|
||||||
|
# ВАЖНО:
|
||||||
|
# - gateway должен быть только у одного интерфейса
|
||||||
|
# - порядок network_devices критичен (eth0, eth1 и т.д.)
|
||||||
|
# - неправильный порядок → потеря доступа к VM
|
||||||
|
#
|
||||||
|
#
|
||||||
# cloudinit:
|
# cloudinit:
|
||||||
# - опциональный параметр
|
# - опциональный параметр
|
||||||
# - указывает имя cloud-init файла для конкретной VM
|
# - имя cloud-init файла
|
||||||
# - файл должен находиться в root: cloud-config/<имя>.yml
|
# - ищется в:
|
||||||
# - если НЕ указан → используется "default.yml"
|
# cloud-config/<имя>.yml (root)
|
||||||
# - если файл НЕ найден в root → используется fallback из модуля (modules/node/cloud-config/default.yml)
|
# - если не найден → fallback:
|
||||||
|
# modules/node/cloud-config/default.yml
|
||||||
#
|
#
|
||||||
# пример:
|
# пример:
|
||||||
# - cloudinit = "worker.yml" → будет использован cloud-config/worker.yml
|
# - cloudinit = "worker.yml" → cloud-config/worker.yml
|
||||||
# - cloudinit не задан → будет использован default.yml
|
# - не указан → default.yml
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# пример одной сети (single NIC):
|
||||||
|
#
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = "vmbr0"
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.11"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# пример двух сетей:
|
||||||
|
#
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = "vmbr0"
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.23"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# bridge = "vmbr1"
|
||||||
|
# ip = "192.168.22.26"
|
||||||
|
# cidr = 24
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# РЕКОМЕНДАЦИИ:
|
||||||
|
# - первый интерфейс (eth0) → management сеть
|
||||||
|
# - второй интерфейс → storage / overlay / secondary
|
||||||
|
# - не задавать gateway на вторичных интерфейсах
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ПОВЕДЕНИЕ:
|
||||||
|
# - ip_config генерируется автоматически из network_devices
|
||||||
|
# - соответствие: порядок массива = порядок интерфейсов
|
||||||
|
#
|
||||||
|
|
||||||
locals {
|
locals {
|
||||||
nodes = {
|
nodes = {
|
||||||
# sing-box-tun= {
|
k8s-master-1 = {
|
||||||
# cloudinit = "vm.yml"
|
cloudinit = "rocky.yml"
|
||||||
# index = 2
|
image_file = "import/rocky9.qcow2"
|
||||||
# cpu = 1
|
index = 1
|
||||||
# memory = 2048
|
cpu = var.worker_cpu
|
||||||
# disk = 7
|
memory = 4092
|
||||||
# datastore = "local-lvm"
|
disk = var.worker_disk
|
||||||
# ip_offset = 0
|
datastore = var.worker_datastore
|
||||||
# ip = "192.168.22.50"
|
|
||||||
# }
|
|
||||||
|
|
||||||
lesson= {
|
|
||||||
cloudinit = "vm.yml"
|
|
||||||
index = 2
|
|
||||||
cpu = 2
|
|
||||||
memory = 2048
|
|
||||||
disk = 7
|
|
||||||
datastore = "local-lvm"
|
|
||||||
ip_offset = 0
|
|
||||||
ip = "192.168.22.52"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
network_devices = [
|
||||||
|
{
|
||||||
|
bridge = var.node_bridge
|
||||||
|
vlan_id = 20
|
||||||
|
ip = "192.168.20.11"
|
||||||
|
cidr = 24
|
||||||
|
gateway = "192.168.20.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
# k8s-worker-1 = {
|
||||||
|
# cloudinit = "worker.yml"
|
||||||
|
# index = 2
|
||||||
|
# cpu = var.worker_cpu
|
||||||
|
# memory = 8192
|
||||||
|
# disk = var.worker_disk
|
||||||
|
# datastore = var.worker_datastore
|
||||||
|
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = var.node_bridge
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.22"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# k8s-worker-2 = {
|
||||||
|
# cloudinit = "worker.yml"
|
||||||
|
# index = 3
|
||||||
|
# cpu = var.worker_cpu
|
||||||
|
# memory = 8192
|
||||||
|
# disk = var.worker_disk
|
||||||
|
# datastore = var.worker_datastore
|
||||||
|
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = var.node_bridge
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.23"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# bridge = "vmbr0"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,6 @@ module "cluster" {
|
|||||||
nodes = local.nodes
|
nodes = local.nodes
|
||||||
ssh_key = trimspace(data.local_file.ssh_key.content)
|
ssh_key = trimspace(data.local_file.ssh_key.content)
|
||||||
|
|
||||||
cluster_ip_start = var.cluster_ip_start
|
|
||||||
worker_vmid_start = var.worker_vmid_start
|
worker_vmid_start = var.worker_vmid_start
|
||||||
|
|
||||||
cloudinit_datastore = var.cloudinit_datastore
|
cloudinit_datastore = var.cloudinit_datastore
|
||||||
@@ -19,9 +18,5 @@ module "cluster" {
|
|||||||
image_file = var.image_file
|
image_file = var.image_file
|
||||||
disk_interface = var.disk_interface
|
disk_interface = var.disk_interface
|
||||||
|
|
||||||
network_base = var.network_base
|
|
||||||
network_cidr = var.network_cidr
|
|
||||||
cluster_gateway = var.cluster_gateway
|
|
||||||
|
|
||||||
data_datastore = var.data_datastore
|
data_datastore = var.data_datastore
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,23 +41,6 @@ variable "worker_disk" {
|
|||||||
default = 20
|
default = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "network_base" {
|
|
||||||
default = "192.168.22"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "network_cidr" {
|
|
||||||
default = "24"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "cluster_gateway" {
|
|
||||||
default = "192.168.22.1"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "cluster_ip_start" {
|
|
||||||
default = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
variable "worker_ip_offset" {
|
variable "worker_ip_offset" {
|
||||||
default = 5
|
default = 5
|
||||||
}
|
}
|
||||||
@@ -66,6 +49,7 @@ variable "node_bridge" {
|
|||||||
default = "vmbr0"
|
default = "vmbr0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
variable "worker_datastore" {
|
variable "worker_datastore" {
|
||||||
type = string
|
type = string
|
||||||
default = "local-lvm"
|
default = "local-lvm"
|
||||||
|
|||||||
34
lab/cloud-config/master.yml
Normal file
34
lab/cloud-config/master.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#cloud-config
|
||||||
|
# Создать passwd hash: openssl passwd -6
|
||||||
|
|
||||||
|
timezone: Europe/Moscow
|
||||||
|
|
||||||
|
users:
|
||||||
|
- name: iurii
|
||||||
|
groups: [sudo]
|
||||||
|
shell: /bin/bash
|
||||||
|
lock_passwd: false
|
||||||
|
passwd: "$6$Zc8nwvtw0Kns5.sD$FpQ4aBSeGogefqjM4we4U5QQd4YBtC98tuG3rR4j9ZmbtC1kyFf2sY/IodYW3wG.U81aEntlZrtOTOqw3ZcOc0"
|
||||||
|
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ${ssh_key}
|
||||||
|
|
||||||
|
package_update: true
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- qemu-guest-agent
|
||||||
|
|
||||||
|
runcmd:
|
||||||
|
- systemctl enable --now qemu-guest-agent
|
||||||
|
- hostnamectl set-hostname ${hostname}
|
||||||
|
- systemctl disable --now packagekit
|
||||||
|
- systemctl disable --now ModemManager
|
||||||
|
- systemctl disable --now multipathd
|
||||||
|
|
||||||
|
write_files:
|
||||||
|
- path: /etc/motd
|
||||||
|
content: |
|
||||||
|
Managed by OpenTofu
|
||||||
|
|
||||||
|
|
||||||
|
final_message: "cloud-init finished"
|
||||||
21
lab/cloud-config/rocky.yml
Normal file
21
lab/cloud-config/rocky.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#cloud-config
|
||||||
|
timezone: Europe/Moscow
|
||||||
|
|
||||||
|
users:
|
||||||
|
- name: iurii
|
||||||
|
groups: [wheel]
|
||||||
|
shell: /bin/bash
|
||||||
|
lock_passwd: false
|
||||||
|
passwd: "$6$Zc8nwvtw0Kns5.sD$FpQ4aBSeGogefqjM4we4U5QQd4YBtC98tuG3rR4j9ZmbtC1kyFf2sY/IodYW3wG.U81aEntlZrtOTOqw3ZcOc0"
|
||||||
|
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ${ssh_key}
|
||||||
|
|
||||||
|
package_update: true
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- qemu-guest-agent
|
||||||
|
|
||||||
|
runcmd:
|
||||||
|
- systemctl enable --now qemu-guest-agent
|
||||||
|
- hostnamectl set-hostname ${hostname}
|
||||||
34
lab/cloud-config/worker.yml
Normal file
34
lab/cloud-config/worker.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#cloud-config
|
||||||
|
# Создать passwd hash: openssl passwd -6
|
||||||
|
|
||||||
|
timezone: Europe/Moscow
|
||||||
|
|
||||||
|
users:
|
||||||
|
- name: iurii
|
||||||
|
groups: [sudo]
|
||||||
|
shell: /bin/bash
|
||||||
|
lock_passwd: false
|
||||||
|
passwd: "$6$Zc8nwvtw0Kns5.sD$FpQ4aBSeGogefqjM4we4U5QQd4YBtC98tuG3rR4j9ZmbtC1kyFf2sY/IodYW3wG.U81aEntlZrtOTOqw3ZcOc0"
|
||||||
|
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ${ssh_key}
|
||||||
|
|
||||||
|
package_update: true
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- qemu-guest-agent
|
||||||
|
|
||||||
|
runcmd:
|
||||||
|
- systemctl enable --now qemu-guest-agent
|
||||||
|
- hostnamectl set-hostname ${hostname}
|
||||||
|
- systemctl disable --now packagekit
|
||||||
|
- systemctl disable --now ModemManager
|
||||||
|
- systemctl disable --now multipathd
|
||||||
|
|
||||||
|
write_files:
|
||||||
|
- path: /etc/motd
|
||||||
|
content: |
|
||||||
|
Managed by OpenTofu
|
||||||
|
|
||||||
|
|
||||||
|
final_message: "cloud-init finished"
|
||||||
184
lab/locals.tf
184
lab/locals.tf
@@ -1,31 +1,179 @@
|
|||||||
# nodes — описание виртуальных машин
|
# nodes — описание виртуальных машин
|
||||||
#
|
#
|
||||||
|
# Общая идея:
|
||||||
|
# - каждая VM может иметь несколько сетевых интерфейсов (network_devices)
|
||||||
|
# - каждый интерфейс полностью описывает свою сеть (bridge, VLAN, IP, gateway)
|
||||||
|
# - порядок элементов в network_devices важен:
|
||||||
|
# [0] → eth0 (основной интерфейс, обычно с default gateway)
|
||||||
|
# [1] → eth1
|
||||||
|
# [2] → eth2
|
||||||
|
#
|
||||||
|
# network_devices:
|
||||||
|
# - список сетевых интерфейсов VM
|
||||||
|
#
|
||||||
|
# поля:
|
||||||
|
#
|
||||||
|
# bridge:
|
||||||
|
# - имя Proxmox bridge (например vmbr0, vmbr1)
|
||||||
|
# - ОБЯЗАТЕЛЬНО
|
||||||
|
#
|
||||||
# vlan_id:
|
# vlan_id:
|
||||||
# - опциональный параметр
|
# - опционально
|
||||||
# - если НЕ указан → VM будет в обычной сети (untagged, vmbr0)
|
# - если НЕ указан → интерфейс untagged
|
||||||
# - если указан → VM попадет в соответствующий VLAN (например 20 → 192.168.20.0/24)
|
# - если указан → интерфейс будет в VLAN (например 20 → зависит от настройки Proxmox bridge)
|
||||||
|
#
|
||||||
|
# ip:
|
||||||
|
# - IPv4 адрес без CIDR (например "192.168.20.11")
|
||||||
|
# - если не указан → будет использован DHCP (если доступен в сети)
|
||||||
|
#
|
||||||
|
# cidr:
|
||||||
|
# - маска сети (например 24)
|
||||||
|
# - используется вместе с ip → итог: ip/cidr
|
||||||
|
#
|
||||||
|
# gateway:
|
||||||
|
# - опционально
|
||||||
|
# - указывать ТОЛЬКО для одного интерфейса (обычно первого)
|
||||||
|
# - задаёт default route внутри VM
|
||||||
|
#
|
||||||
|
# ВАЖНО:
|
||||||
|
# - gateway должен быть только у одного интерфейса
|
||||||
|
# - порядок network_devices критичен (eth0, eth1 и т.д.)
|
||||||
|
# - неправильный порядок → потеря доступа к VM
|
||||||
|
#
|
||||||
|
#
|
||||||
# cloudinit:
|
# cloudinit:
|
||||||
# - опциональный параметр
|
# - опциональный параметр
|
||||||
# - указывает имя cloud-init файла для конкретной VM
|
# - имя cloud-init файла
|
||||||
# - файл должен находиться в root: cloud-config/<имя>.yml
|
# - ищется в:
|
||||||
# - если НЕ указан → используется "default.yml"
|
# cloud-config/<имя>.yml (root)
|
||||||
# - если файл НЕ найден в root → используется fallback из модуля (modules/node/cloud-config/default.yml)
|
# - если не найден → fallback:
|
||||||
|
# modules/node/cloud-config/default.yml
|
||||||
#
|
#
|
||||||
# пример:
|
# пример:
|
||||||
# - cloudinit = "worker.yml" → будет использован cloud-config/worker.yml
|
# - cloudinit = "worker.yml" → cloud-config/worker.yml
|
||||||
# - cloudinit не задан → будет использован default.yml
|
# - не указан → default.yml
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# пример одной сети (single NIC):
|
||||||
|
#
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = "vmbr0"
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.11"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# пример двух сетей:
|
||||||
|
#
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = "vmbr0"
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.23"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# bridge = "vmbr1"
|
||||||
|
# ip = "192.168.22.26"
|
||||||
|
# cidr = 24
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# РЕКОМЕНДАЦИИ:
|
||||||
|
# - первый интерфейс (eth0) → management сеть
|
||||||
|
# - второй интерфейс → storage / overlay / secondary
|
||||||
|
# - не задавать gateway на вторичных интерфейсах
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ПОВЕДЕНИЕ:
|
||||||
|
# - ip_config генерируется автоматически из network_devices
|
||||||
|
# - соответствие: порядок массива = порядок интерфейсов
|
||||||
|
#
|
||||||
|
|
||||||
locals {
|
locals {
|
||||||
nodes = {
|
nodes = {
|
||||||
vm1 = {
|
lab-1 = {
|
||||||
cloudinit = "vm.yml"
|
cloudinit = "rocky.yml"
|
||||||
|
image_file = "import/rocky9.qcow2"
|
||||||
index = 1
|
index = 1
|
||||||
cpu = 1
|
cpu = var.worker_cpu
|
||||||
memory = 1024
|
memory = 4092
|
||||||
disk = var.worker_disk
|
disk = var.worker_disk
|
||||||
datastore = var.worker_datastore
|
datastore = var.worker_datastore
|
||||||
ip_offset = 0
|
|
||||||
vlan_id = 20
|
network_devices = [
|
||||||
}
|
{
|
||||||
}
|
bridge = var.node_bridge
|
||||||
}
|
vlan_id = 20
|
||||||
|
ip = "192.168.20.11"
|
||||||
|
cidr = 24
|
||||||
|
gateway = "192.168.20.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
# lab-2 = {
|
||||||
|
# cloudinit = "rocky.yml"
|
||||||
|
# image_file = "import/rocky9.qcow2"
|
||||||
|
# index = 2
|
||||||
|
# cpu = var.worker_cpu
|
||||||
|
# memory = 2048
|
||||||
|
# disk = var.worker_disk
|
||||||
|
# datastore = var.worker_datastore
|
||||||
|
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = var.node_bridge
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.12"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
# k8s-worker-1 = {
|
||||||
|
# cloudinit = "worker.yml"
|
||||||
|
# index = 2
|
||||||
|
# cpu = var.worker_cpu
|
||||||
|
# memory = 8192
|
||||||
|
# disk = var.worker_disk
|
||||||
|
# datastore = var.worker_datastore
|
||||||
|
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = var.node_bridge
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.22"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# k8s-worker-2 = {
|
||||||
|
# cloudinit = "worker.yml"
|
||||||
|
# index = 3
|
||||||
|
# cpu = var.worker_cpu
|
||||||
|
# memory = 8192
|
||||||
|
# disk = var.worker_disk
|
||||||
|
# datastore = var.worker_datastore
|
||||||
|
|
||||||
|
# network_devices = [
|
||||||
|
# {
|
||||||
|
# bridge = var.node_bridge
|
||||||
|
# vlan_id = 20
|
||||||
|
# ip = "192.168.20.23"
|
||||||
|
# cidr = 24
|
||||||
|
# gateway = "192.168.20.1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# bridge = "vmbr0"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,6 @@ module "cluster" {
|
|||||||
nodes = local.nodes
|
nodes = local.nodes
|
||||||
ssh_key = trimspace(data.local_file.ssh_key.content)
|
ssh_key = trimspace(data.local_file.ssh_key.content)
|
||||||
|
|
||||||
cluster_ip_start = var.cluster_ip_start
|
|
||||||
worker_vmid_start = var.worker_vmid_start
|
worker_vmid_start = var.worker_vmid_start
|
||||||
|
|
||||||
cloudinit_datastore = var.cloudinit_datastore
|
cloudinit_datastore = var.cloudinit_datastore
|
||||||
@@ -19,9 +18,5 @@ module "cluster" {
|
|||||||
image_file = var.image_file
|
image_file = var.image_file
|
||||||
disk_interface = var.disk_interface
|
disk_interface = var.disk_interface
|
||||||
|
|
||||||
network_base = var.network_base
|
|
||||||
network_cidr = var.network_cidr
|
|
||||||
cluster_gateway = var.cluster_gateway
|
|
||||||
|
|
||||||
data_datastore = var.data_datastore
|
data_datastore = var.data_datastore
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,23 +41,6 @@ variable "worker_disk" {
|
|||||||
default = 20
|
default = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "network_base" {
|
|
||||||
default = "192.168.22"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "network_cidr" {
|
|
||||||
default = "24"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "cluster_gateway" {
|
|
||||||
default = "192.168.22.1"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "cluster_ip_start" {
|
|
||||||
default = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
variable "worker_ip_offset" {
|
variable "worker_ip_offset" {
|
||||||
default = 5
|
default = 5
|
||||||
}
|
}
|
||||||
@@ -66,6 +49,7 @@ variable "node_bridge" {
|
|||||||
default = "vmbr0"
|
default = "vmbr0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
variable "worker_datastore" {
|
variable "worker_datastore" {
|
||||||
type = string
|
type = string
|
||||||
default = "local-lvm"
|
default = "local-lvm"
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ resource "proxmox_virtual_environment_file" "cloudinit" {
|
|||||||
|
|
||||||
resource "proxmox_virtual_environment_vm" "nodes" {
|
resource "proxmox_virtual_environment_vm" "nodes" {
|
||||||
for_each = local.nodes
|
for_each = local.nodes
|
||||||
|
tags = ["tofu"]
|
||||||
|
|
||||||
name = local.hostname_map[each.key]
|
name = local.hostname_map[each.key]
|
||||||
node_name = var.proxmox_node
|
node_name = var.proxmox_node
|
||||||
@@ -48,6 +49,8 @@ resource "proxmox_virtual_environment_vm" "nodes" {
|
|||||||
|
|
||||||
cpu {
|
cpu {
|
||||||
cores = each.value.cpu
|
cores = each.value.cpu
|
||||||
|
type = "host"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memory {
|
memory {
|
||||||
@@ -63,12 +66,24 @@ resource "proxmox_virtual_environment_vm" "nodes" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
disk {
|
dynamic "clone" {
|
||||||
|
for_each = try(each.value.template_id, null) == null ? [] : [each.value.template_id]
|
||||||
|
|
||||||
|
content {
|
||||||
|
vm_id = clone.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic "disk" {
|
||||||
|
for_each = try(each.value.template_id, null) == null ? [1] : []
|
||||||
|
|
||||||
|
content {
|
||||||
datastore_id = each.value.datastore
|
datastore_id = each.value.datastore
|
||||||
import_from = "${var.image_datastore}:${var.image_file}"
|
import_from = "${var.image_datastore}:${var.image_file}"
|
||||||
interface = var.disk_interface
|
interface = var.disk_interface
|
||||||
size = each.value.disk
|
size = each.value.disk
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dynamic "disk" {
|
dynamic "disk" {
|
||||||
for_each = try([each.value.data_disk], [])
|
for_each = try([each.value.data_disk], [])
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ variable "nodes" {
|
|||||||
vmid = optional(number)
|
vmid = optional(number)
|
||||||
data_disk = optional(number)
|
data_disk = optional(number)
|
||||||
cloudinit = optional(string)
|
cloudinit = optional(string)
|
||||||
|
template_id = optional(number)
|
||||||
|
|
||||||
network_devices = list(object({
|
network_devices = list(object({
|
||||||
bridge = string
|
bridge = string
|
||||||
|
|||||||
48
setup_disk.sh
Normal file
48
setup_disk.sh
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DISK="/dev/sdb"
|
||||||
|
PART="${DISK}1"
|
||||||
|
MOUNT_POINT="/u01"
|
||||||
|
|
||||||
|
echo "[1] Проверка диска"
|
||||||
|
lsblk "$DISK"
|
||||||
|
|
||||||
|
echo "[2] Создание GPT и раздела"
|
||||||
|
sudo parted "$DISK" --script mklabel gpt
|
||||||
|
sudo parted "$DISK" --script mkpart primary ext4 0% 100%
|
||||||
|
|
||||||
|
echo "[3] Ожидание появления раздела"
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
echo "[4] Форматирование"
|
||||||
|
sudo mkfs.ext4 -F "$PART"
|
||||||
|
|
||||||
|
echo "[5] Создание точки монтирования"
|
||||||
|
sudo mkdir -p "$MOUNT_POINT"
|
||||||
|
|
||||||
|
echo "[6] Получение UUID"
|
||||||
|
UUID=$(blkid -s UUID -o value "$PART")
|
||||||
|
|
||||||
|
if [[ -z "$UUID" ]]; then
|
||||||
|
echo "ERROR: UUID not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[7] Добавление в fstab"
|
||||||
|
if ! grep -q "$UUID" /etc/fstab; then
|
||||||
|
echo "UUID=$UUID $MOUNT_POINT ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[8] Применение"
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo mount -a
|
||||||
|
|
||||||
|
echo "[9] Проверка"
|
||||||
|
df -h | grep "$MOUNT_POINT"
|
||||||
|
|
||||||
|
echo "[10] Подготовка под OpenSearch"
|
||||||
|
sudo mkdir -p /u01/opensearch
|
||||||
|
sudo chown -R 1000:1000 /u01/opensearch
|
||||||
|
|
||||||
|
echo "DONE"
|
||||||
Reference in New Issue
Block a user