439 lines
13 KiB
Bash
Executable File
439 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
### Дефолты ###
|
||
IMAGE=factory.talos.dev/metal-installer/956b9107edd250304169d2e7a765cdd4e0c31f9097036e2e113b042e6c01bb98:v1.10.4
|
||
DEFAULT_K8S_VERSION=1.33.2
|
||
CONFIG_DIR="config"
|
||
|
||
# Цвета для вывода
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Helper function for checking uniqueness in an array
|
||
contains_element () {
|
||
local e match="$1"
|
||
shift
|
||
for e; do [[ "$e" == "$match" ]] && return 0; done
|
||
return 1
|
||
}
|
||
|
||
# Function for asking yes/no questions
|
||
ask_yes_no() {
|
||
local prompt="$1"
|
||
local default="$2"
|
||
local answer
|
||
while true; do
|
||
read -p "$prompt" answer
|
||
answer=${answer:-$default}
|
||
answer=$(echo "$answer" | tr '[:upper:]' '[:lower:]') # convert to lowercase
|
||
case "$answer" in
|
||
y|yes)
|
||
echo "y"
|
||
return 0
|
||
;;
|
||
n|no)
|
||
echo "n"
|
||
return 0
|
||
;;
|
||
*)
|
||
echo -e "${YELLOW}Некорректный ввод. Введите 'y'/'yes' или 'n'/'no'.${NC}"
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
echo -e "${GREEN}--- Интерактивный конфигуратор Talos K8s ---${NC}"
|
||
|
||
# --- Вопросы пользователю ---
|
||
|
||
# Имя кластера
|
||
read -p "Введите имя кластера [talos-demo]: " CLUSTER_NAME
|
||
CLUSTER_NAME=${CLUSTER_NAME:-talos-demo}
|
||
|
||
# Версия Kubernetes
|
||
read -p "Введите версию Kubernetes [${DEFAULT_K8S_VERSION}]: " K8S_VERSION
|
||
K8S_VERSION=${K8S_VERSION:-${DEFAULT_K8S_VERSION}}
|
||
|
||
echo "K8S_VERSION: ${K8S_VERSION}"
|
||
|
||
# Имя сетевого адаптера
|
||
read -p "Введите имя сетевого адаптера (например, ens18 или eth0) [ens18]: " INTERFACE_NAME
|
||
INTERFACE_NAME=${INTERFACE_NAME:-ens18}
|
||
|
||
# Количество control plane
|
||
while true; do
|
||
read -p "Введите количество control plane (нечетное, макс 7) [1]: " CP_COUNT
|
||
CP_COUNT=${CP_COUNT:-1}
|
||
if (( CP_COUNT % 2 != 0 && CP_COUNT > 0 && CP_COUNT <= 7 )); then
|
||
break
|
||
else
|
||
echo -e "${YELLOW}Некорректное значение. Введите нечетное число от 1 до 7.${NC}"
|
||
fi
|
||
done
|
||
|
||
# Количество worker-нод
|
||
while true; do
|
||
read -p "Введите количество worker-нод (макс 15, мин 0) [2]: " WORKER_COUNT
|
||
WORKER_COUNT=${WORKER_COUNT:-2}
|
||
if (( WORKER_COUNT >= 0 && WORKER_COUNT <= 15 )); then
|
||
break
|
||
else
|
||
echo -e "${YELLOW}Некорректное значение. Введите число от 0 до 15.${NC}"
|
||
fi
|
||
done
|
||
|
||
# Общий шлюз
|
||
while true; do
|
||
read -p "Введите общий gateway (например, 192.168.23.1): " GATEWAY
|
||
if [[ -n "$GATEWAY" ]]; then
|
||
USED_IPS+=("$GATEWAY")
|
||
break
|
||
else
|
||
echo -e "${YELLOW}Gateway не может быть пустым.${NC}"
|
||
fi
|
||
done
|
||
|
||
# Маска сети
|
||
while true; do
|
||
read -p "Введите маску сети (например, 24) [24]: " NETMASK
|
||
NETMASK=${NETMASK:-24}
|
||
if [[ -n "$NETMASK" ]]; then
|
||
break
|
||
else
|
||
echo -e "${YELLOW}Маска сети не может быть пустой.${NC}"
|
||
fi
|
||
done
|
||
|
||
# DNS-серверы
|
||
while true; do
|
||
read -p "Введите первый DNS сервер: (например, 8.8.8.8) [8.8.8.8]: " DNS1
|
||
DNS1=${DNS1:-8.8.8.8}
|
||
if [[ -n "$DNS1" ]]; then
|
||
break
|
||
else
|
||
echo -e "${YELLOW}DNS сервер не может быть пустым.${NC}"
|
||
fi
|
||
done
|
||
while true; do
|
||
read -p "Введите второй DNS сервер: (например, 8.8.4.4) [8.8.4.4]: " DNS2
|
||
DNS2=${DNS2:-8.8.4.4}
|
||
if [[ -n "$DNS2" ]]; then
|
||
break
|
||
else
|
||
echo -e "${YELLOW}DNS сервер не может быть пустым.${NC}"
|
||
fi
|
||
done
|
||
|
||
# NTP-серверы
|
||
read -p "Введите первый NTP сервер [1.ru.pool.ntp.org]: " NTP1
|
||
NTP1=${NTP1:-1.ru.pool.ntp.org}
|
||
read -p "Введите второй NTP сервер [2.ru.pool.ntp.org]: " NTP2
|
||
NTP2=${NTP2:-2.ru.pool.ntp.org}
|
||
read -p "Введите третий NTP сервер [3.ru.pool.ntp.org]: " NTP3
|
||
NTP3=${NTP3:-3.ru.pool.ntp.org}
|
||
|
||
# VIP адрес
|
||
VIP_IP=""
|
||
USE_VIP="n"
|
||
if (( CP_COUNT > 1 )); then
|
||
USE_VIP=$(ask_yes_no "Нужен ли VIP адрес? (y/n) [y]: " "y")
|
||
if [[ "$USE_VIP" == "y" ]]; then
|
||
while true; do
|
||
read -p "Введите VIP адрес (например, 192.168.23.20): " VIP_IP
|
||
if [[ -z "$VIP_IP" ]]; then
|
||
echo -e "${YELLOW}VIP адрес не может быть пустым.${NC}"
|
||
continue
|
||
fi
|
||
|
||
if contains_element "$VIP_IP" "${USED_IPS[@]}"; then
|
||
echo -e "${YELLOW}Этот IP адрес уже используется. Введите уникальный адрес.${NC}"
|
||
else
|
||
USED_IPS+=("$VIP_IP")
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
fi
|
||
|
||
# Внешний балансировщик
|
||
EXT_BALANCER_IP=""
|
||
USE_EXT_BALANCER=$(ask_yes_no "Нужен ли внешний балансировщик? (y/n) [n]: " "n")
|
||
if [[ "$USE_EXT_BALANCER" == "y" ]]; then
|
||
while true; do
|
||
read -p "Введите IP адрес внешнего балансировщика: " EXT_BALANCER_IP_INPUT
|
||
if [[ -z "$EXT_BALANCER_IP_INPUT" ]]; then
|
||
echo -e "${YELLOW}IP адрес не может быть пустым.${NC}"
|
||
continue
|
||
fi
|
||
|
||
if contains_element "$EXT_BALANCER_IP_INPUT" "${USED_IPS[@]}"; then
|
||
echo -e "${YELLOW}Этот IP адрес уже используется. Введите уникальный адрес.${NC}"
|
||
else
|
||
EXT_BALANCER_IP=$EXT_BALANCER_IP_INPUT
|
||
USED_IPS+=("$EXT_BALANCER_IP")
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# Диск
|
||
read -p "Введите диск для worker-нод (например, /dev/sda) [/dev/sda]: " DISK
|
||
DISK=${DISK:-/dev/sda}
|
||
|
||
# Поддержка drbd
|
||
USE_DRBD=$(ask_yes_no "Нужна ли поддержка drbd? (y/n) [y]: " "y")
|
||
|
||
# --- Генерация конфигурационных файлов ---
|
||
|
||
mkdir -p "$CONFIG_DIR"
|
||
PATCH_FILE="$CONFIG_DIR/patch.yaml"
|
||
|
||
# --- Создание patch.yaml ---
|
||
# Этот подход не использует sed и работает одинаково на macOS и Linux.
|
||
|
||
# Записываем первую часть файла
|
||
cat > "$PATCH_FILE" << EOF
|
||
machine:
|
||
EOF
|
||
|
||
# Добавляем certSANs если есть внешний балансировщик
|
||
if [[ -n "$EXT_BALANCER_IP" ]]; then
|
||
cat >> "$PATCH_FILE" << EOF
|
||
certSANs:
|
||
- ${EXT_BALANCER_IP}
|
||
EOF
|
||
fi
|
||
|
||
# Добавляем блок kernel для drbd, если нужно
|
||
if [[ "$USE_DRBD" == "y" ]] && (( WORKER_COUNT == 0 )); then
|
||
cat >> "$PATCH_FILE" << 'EOF'
|
||
kernel:
|
||
modules:
|
||
- name: drbd
|
||
parameters:
|
||
- usermode_helper=disabled
|
||
EOF
|
||
fi
|
||
|
||
# Добавляем основную часть machine и начало cluster
|
||
cat >> "$PATCH_FILE" << EOF
|
||
network:
|
||
nameservers:
|
||
- ${DNS1}
|
||
- ${DNS2}
|
||
install:
|
||
disk: ${DISK}
|
||
image: ${IMAGE}
|
||
time:
|
||
servers:
|
||
- ${NTP1}
|
||
- ${NTP2}
|
||
- ${NTP3}
|
||
cluster:
|
||
EOF
|
||
|
||
# Добавляем allowSchedulingOnControlPlanes и финальную часть
|
||
if (( WORKER_COUNT == 0 )); then
|
||
echo -e "\n${YELLOW}Воркеры отсутствуют. Разрешение на запуск подов на control plane...${NC}"
|
||
cat >> "$PATCH_FILE" << EOF
|
||
allowSchedulingOnControlPlanes: true
|
||
network:
|
||
cni:
|
||
name: none
|
||
proxy:
|
||
disabled: true
|
||
EOF
|
||
else
|
||
cat >> "$PATCH_FILE" << EOF
|
||
network:
|
||
cni:
|
||
name: none
|
||
proxy:
|
||
disabled: true
|
||
EOF
|
||
fi
|
||
|
||
CP_IPS=()
|
||
|
||
# Генерация патчей для control plane
|
||
echo -e "\n${GREEN}--- Настройка Control Plane нод ---${NC}"
|
||
for i in $(seq 1 $CP_COUNT); do
|
||
while true; do
|
||
read -p "Введите IP адрес для control plane $i (например, 192.168.23.5${i}): " CP_IP
|
||
if [[ -z "$CP_IP" ]]; then
|
||
echo -e "${YELLOW}IP адрес не может быть пустым.${NC}"
|
||
continue
|
||
fi
|
||
|
||
if contains_element "$CP_IP" "${USED_IPS[@]}"; then
|
||
echo -e "${YELLOW}Этот IP адрес уже используется. Введите уникальный адрес.${NC}"
|
||
else
|
||
CP_IPS+=("$CP_IP")
|
||
USED_IPS+=("$CP_IP")
|
||
break
|
||
fi
|
||
done
|
||
|
||
HOSTNAME="cp-$i"
|
||
FILENAME="$CONFIG_DIR/cp$i.patch"
|
||
|
||
# Создание базового патча
|
||
cat > "$FILENAME" << EOF
|
||
machine:
|
||
network:
|
||
hostname: $HOSTNAME
|
||
interfaces:
|
||
- interface: $INTERFACE_NAME
|
||
dhcp: false
|
||
addresses:
|
||
- $CP_IP/$NETMASK
|
||
EOF
|
||
|
||
# Добавление VIP, если он используется
|
||
if [[ "$USE_VIP" == "y" && -n "$VIP_IP" ]]; then
|
||
cat >> "$FILENAME" << EOF
|
||
vip:
|
||
ip: $VIP_IP
|
||
EOF
|
||
fi
|
||
|
||
# Добавление маршрутов
|
||
cat >> "$FILENAME" << EOF
|
||
routes:
|
||
- network: 0.0.0.0/0
|
||
gateway: $GATEWAY
|
||
EOF
|
||
echo "Создан файл: $FILENAME"
|
||
done
|
||
|
||
# Генерация патчей для worker-нод
|
||
if (( WORKER_COUNT > 0 )); then
|
||
echo -e "\n${GREEN}--- Настройка Worker нод ---${NC}"
|
||
for i in $(seq 1 $WORKER_COUNT); do
|
||
while true; do
|
||
read -p "Введите IP адрес для worker $i (например, 192.168.23.10${i}): " WORKER_IP
|
||
if [[ -z "$WORKER_IP" ]]; then
|
||
echo -e "${YELLOW}IP адрес не может быть пустым.${NC}"
|
||
continue
|
||
fi
|
||
|
||
if contains_element "$WORKER_IP" "${USED_IPS[@]}"; then
|
||
echo -e "${YELLOW}Этот IP адрес уже используется. Введите уникальный адрес.${NC}"
|
||
else
|
||
USED_IPS+=("$WORKER_IP")
|
||
break
|
||
fi
|
||
done
|
||
|
||
HOSTNAME="worker-$i"
|
||
FILENAME="$CONFIG_DIR/worker$i.patch"
|
||
|
||
cat > "$FILENAME" << EOF
|
||
machine:
|
||
network:
|
||
hostname: $HOSTNAME
|
||
interfaces:
|
||
- deviceSelector:
|
||
physical: true
|
||
dhcp: false
|
||
addresses:
|
||
- $WORKER_IP/$NETMASK
|
||
routes:
|
||
- network: 0.0.0.0/0
|
||
gateway: $GATEWAY
|
||
EOF
|
||
# Добавляем drbd если выбрано
|
||
if [[ "$USE_DRBD" == "y" ]]; then
|
||
cat >> "$FILENAME" << EOF
|
||
kernel:
|
||
modules:
|
||
- name: drbd
|
||
parameters:
|
||
- usermode_helper=disabled
|
||
EOF
|
||
fi
|
||
echo "Создан файл: $FILENAME"
|
||
done
|
||
fi
|
||
|
||
# --- Вывод команд для выполнения ---
|
||
|
||
echo -e "\n${YELLOW}--------------------------------------------------${NC}"
|
||
echo -e "${GREEN}Конфигурация завершена. Собираю файлы в кучу:${NC}"
|
||
echo -e "${YELLOW}--------------------------------------------------${NC}"
|
||
|
||
# Генерация секретов
|
||
talosctl gen secrets -o $CONFIG_DIR/secrets.yaml
|
||
|
||
# Определение эндпоинта
|
||
ENDPOINT_IP=""
|
||
if [[ "$USE_VIP" == "y" && -n "$VIP_IP" ]]; then
|
||
ENDPOINT_IP=$VIP_IP
|
||
else
|
||
FIRST_CP_FULL_IP=${CP_IPS[0]}
|
||
ENDPOINT_IP=$(echo "$FIRST_CP_FULL_IP" | cut -d'/' -f1)
|
||
fi
|
||
|
||
# Генерация основной конфигурации
|
||
cd $CONFIG_DIR
|
||
echo "talosctl gen config --kubernetes-version $K8S_VERSION --with-secrets secrets.yaml $CLUSTER_NAME https://${ENDPOINT_IP}:6443 --config-patch @patch.yaml"
|
||
talosctl gen config --kubernetes-version $K8S_VERSION --with-secrets secrets.yaml $CLUSTER_NAME https://${ENDPOINT_IP}:6443 --config-patch @patch.yaml
|
||
|
||
# Применение патчей к control plane
|
||
for i in $(seq 1 $CP_COUNT); do
|
||
talosctl machineconfig patch controlplane.yaml --patch @cp$i.patch --output cp$i.yaml
|
||
echo "Создан файл: $CONFIG_DIR/cp$i.yaml"
|
||
done
|
||
|
||
# Применение патчей к worker-нодам
|
||
if (( WORKER_COUNT > 0 )); then
|
||
for i in $(seq 1 $WORKER_COUNT); do
|
||
talosctl machineconfig patch worker.yaml --patch @worker$i.patch --output worker$i.yaml
|
||
echo "Создан файл: $CONFIG_DIR/worker$i.yaml"
|
||
done
|
||
fi
|
||
|
||
# Обновление talosconfig с endpoints
|
||
echo -e "\n${GREEN}--- Обновление talosconfig ---${NC}"
|
||
|
||
# Создаем массив endpoints
|
||
ENDPOINTS=()
|
||
|
||
# Добавляем все control plane IPs
|
||
for cp_ip in "${CP_IPS[@]}"; do
|
||
ENDPOINTS+=("$cp_ip")
|
||
done
|
||
|
||
# Добавляем VIP если есть
|
||
if [[ "$USE_VIP" == "y" && -n "$VIP_IP" ]]; then
|
||
ENDPOINTS+=("$VIP_IP")
|
||
fi
|
||
|
||
# Добавляем внешний балансировщик если есть
|
||
if [[ "$USE_EXT_BALANCER" == "y" && -n "$EXT_BALANCER_IP" ]]; then
|
||
ENDPOINTS+=("$EXT_BALANCER_IP")
|
||
fi
|
||
|
||
# Объединяем endpoints через запятую с пробелом
|
||
ENDPOINTS_STRING=$(IFS="," ; echo "${ENDPOINTS[*]}")
|
||
|
||
# Обновляем talosconfig
|
||
if [[ -f "talosconfig" ]]; then
|
||
TMP_CONFIG=$(mktemp)
|
||
while IFS= read -r line; do
|
||
if [[ "$line" == *"endpoints: []"* ]]; then
|
||
echo "${line/endpoints: []/endpoints: [$ENDPOINTS_STRING]}" >> "$TMP_CONFIG"
|
||
else
|
||
echo "$line" >> "$TMP_CONFIG"
|
||
fi
|
||
done < "talosconfig"
|
||
mv "$TMP_CONFIG" "talosconfig"
|
||
echo -e "${GREEN}Обновлен talosconfig с endpoints: [$ENDPOINTS_STRING]${NC}"
|
||
else
|
||
echo -e "${YELLOW}Файл talosconfig не найден${NC}"
|
||
fi
|
||
|
||
cd ..
|
||
echo "Работа скрипта завершена"
|