diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8cae4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +.env +talos-k8s/config/* diff --git a/talos-k8s/generate.sh b/talos-k8s/generate.sh index e6a200d..903c55f 100755 --- a/talos-k8s/generate.sh +++ b/talos-k8s/generate.sh @@ -47,23 +47,85 @@ echo -e "${GREEN}--- Интерактивный конфигуратор Talos K # --- Вопросы пользователю --- +# Список вопросов для прогресса +QUESTIONS=( + "Введите имя кластера [talos-demo]: " + "Введите версию Kubernetes [${DEFAULT_K8S_VERSION}]: " + "Введите имя сетевого адаптера (например, ens18 или eth0) [ens18]: " + "Введите количество control plane (нечетное, макс 7) [1]: " + "Введите количество worker-нод (макс 15, мин 0) [3]: " + "Введите общий gateway (например, 192.168.23.1): " + "Введите маску сети (например, 24) [24]: " + "Введите первый DNS сервер: (например, 8.8.8.8) [8.8.8.8]: " + "Введите второй DNS сервер: (например, 8.8.4.4) [8.8.4.4]: " + "Введите первый NTP сервер [1.ru.pool.ntp.org]: " + "Введите второй NTP сервер [2.ru.pool.ntp.org]: " + "Введите третий NTP сервер [3.ru.pool.ntp.org]: " + "Нужен ли VIP адрес? (y/n) [y]: " + "Введите VIP адрес (например, 192.168.23.20): " + "Нужен ли внешний балансировщик? (y/n) [n]: " + "Введите IP адрес внешнего балансировщика: " + "Введите диск для установки базовой ос [/dev/sda]: " + "Нужна ли поддержка drbd? (y/n) [y]: " + "Нужна ли поддержка zfs? (y/n) [n]: " + "Нужна ли поддержка spl? (y/n) [n]: " + "Нужна ли поддержка vfio_pci? (y/n) [n]: " + "Нужна ли поддержка vfio_iommu_type1? (y/n) [n]: " + "Нужна ли поддержка openvswitch? (y/n) [n]: " + "Хотите ли вы использовать зеркала timeweb.cloud и gcr.io для docker.io? (y/n) [y]: " + "Нужно ли установить maxPods: 512? (110 подов на ноду по умолчанию) (y/n) [n]: " +) +QUESTION_IDX=0 +QUESTION_TOTAL=${#QUESTIONS[@]} + +# Функция для вывода вопроса с прогрессом +ask_with_progress() { + local prompt="$1" + ((QUESTION_IDX++)) + read -p "[$QUESTION_IDX из $QUESTION_TOTAL] $prompt" "$2" +} + +ask_yes_no_progress() { + local prompt="$1" + local default="$2" + local varname="$3" + ((QUESTION_IDX++)) + local answer + while true; do + read -p "[$QUESTION_IDX из $QUESTION_TOTAL] $prompt" answer + answer=${answer:-$default} + answer=$(echo "$answer" | tr '[:upper:]' '[:lower:]') + case "$answer" in + y|yes) + eval "$varname=\"y\"" + return 0 + ;; + n|no) + eval "$varname=\"n\"" + return 0 + ;; + *) + echo -e "${YELLOW}Некорректный ввод. Введите 'y'/'yes' или 'n'/'no'.${NC}" + ;; + esac + done +} + # Имя кластера -read -p "Введите имя кластера [talos-demo]: " CLUSTER_NAME +ask_with_progress "Введите имя кластера [talos-demo]: " CLUSTER_NAME CLUSTER_NAME=${CLUSTER_NAME:-talos-demo} # Версия Kubernetes -read -p "Введите версию Kubernetes [${DEFAULT_K8S_VERSION}]: " K8S_VERSION +ask_with_progress "Введите версию 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 +ask_with_progress "Введите имя сетевого адаптера (например, ens18 или eth0) [ens18]: " INTERFACE_NAME INTERFACE_NAME=${INTERFACE_NAME:-ens18} # Количество control plane while true; do - read -p "Введите количество control plane (нечетное, макс 7) [1]: " CP_COUNT + ask_with_progress "Введите количество control plane (нечетное, макс 7) [1]: " CP_COUNT CP_COUNT=${CP_COUNT:-1} if (( CP_COUNT % 2 != 0 && CP_COUNT > 0 && CP_COUNT <= 7 )); then break @@ -74,8 +136,8 @@ done # Количество worker-нод while true; do - read -p "Введите количество worker-нод (макс 15, мин 0) [2]: " WORKER_COUNT - WORKER_COUNT=${WORKER_COUNT:-2} + ask_with_progress "Введите количество worker-нод (макс 15, мин 0) [3]: " WORKER_COUNT + WORKER_COUNT=${WORKER_COUNT:-3} if (( WORKER_COUNT >= 0 && WORKER_COUNT <= 15 )); then break else @@ -85,7 +147,7 @@ done # Общий шлюз while true; do - read -p "Введите общий gateway (например, 192.168.23.1): " GATEWAY + ask_with_progress "Введите общий gateway (например, 192.168.23.1): " GATEWAY if [[ -n "$GATEWAY" ]]; then USED_IPS+=("$GATEWAY") break @@ -96,7 +158,7 @@ done # Маска сети while true; do - read -p "Введите маску сети (например, 24) [24]: " NETMASK + ask_with_progress "Введите маску сети (например, 24) [24]: " NETMASK NETMASK=${NETMASK:-24} if [[ -n "$NETMASK" ]]; then break @@ -107,7 +169,7 @@ done # DNS-серверы while true; do - read -p "Введите первый DNS сервер: (например, 8.8.8.8) [8.8.8.8]: " DNS1 + ask_with_progress "Введите первый DNS сервер: (например, 8.8.8.8) [8.8.8.8]: " DNS1 DNS1=${DNS1:-8.8.8.8} if [[ -n "$DNS1" ]]; then break @@ -116,7 +178,7 @@ while true; do fi done while true; do - read -p "Введите второй DNS сервер: (например, 8.8.4.4) [8.8.4.4]: " DNS2 + ask_with_progress "Введите второй DNS сервер: (например, 8.8.4.4) [8.8.4.4]: " DNS2 DNS2=${DNS2:-8.8.4.4} if [[ -n "$DNS2" ]]; then break @@ -126,26 +188,25 @@ while true; do done # NTP-серверы -read -p "Введите первый NTP сервер [1.ru.pool.ntp.org]: " NTP1 +ask_with_progress "Введите первый NTP сервер [1.ru.pool.ntp.org]: " NTP1 NTP1=${NTP1:-1.ru.pool.ntp.org} -read -p "Введите второй NTP сервер [2.ru.pool.ntp.org]: " NTP2 +ask_with_progress "Введите второй NTP сервер [2.ru.pool.ntp.org]: " NTP2 NTP2=${NTP2:-2.ru.pool.ntp.org} -read -p "Введите третий NTP сервер [3.ru.pool.ntp.org]: " NTP3 +ask_with_progress "Введите третий 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") + ask_yes_no_progress "Нужен ли VIP адрес? (y/n) [y]: " "y" USE_VIP if [[ "$USE_VIP" == "y" ]]; then while true; do - read -p "Введите VIP адрес (например, 192.168.23.20): " VIP_IP + ask_with_progress "Введите 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 @@ -158,15 +219,14 @@ fi # Внешний балансировщик EXT_BALANCER_IP="" -USE_EXT_BALANCER=$(ask_yes_no "Нужен ли внешний балансировщик? (y/n) [n]: " "n") +ask_yes_no_progress "Нужен ли внешний балансировщик? (y/n) [n]: " "n" USE_EXT_BALANCER if [[ "$USE_EXT_BALANCER" == "y" ]]; then while true; do - read -p "Введите IP адрес внешнего балансировщика: " EXT_BALANCER_IP_INPUT + ask_with_progress "Введите 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 @@ -178,11 +238,22 @@ if [[ "$USE_EXT_BALANCER" == "y" ]]; then fi # Диск -read -p "Введите диск для worker-нод (например, /dev/sda) [/dev/sda]: " DISK +ask_with_progress "Введите диск для установки базовой ос [/dev/sda]: " DISK DISK=${DISK:-/dev/sda} -# Поддержка drbd -USE_DRBD=$(ask_yes_no "Нужна ли поддержка drbd? (y/n) [y]: " "y") +# Вопросы по модулям ядра +ask_yes_no_progress "Нужна ли поддержка drbd? (y/n) [y]: " "y" USE_DRBD +ask_yes_no_progress "Нужна ли поддержка zfs? (y/n) [n]: " "n" USE_ZFS +ask_yes_no_progress "Нужна ли поддержка spl? (y/n) [n]: " "n" USE_SPL +ask_yes_no_progress "Нужна ли поддержка vfio_pci? (y/n) [n]: " "n" USE_VFIO_PCI +ask_yes_no_progress "Нужна ли поддержка vfio_iommu_type1? (y/n) [n]: " "n" USE_VFIO_IOMMU_TYPE1 +ask_yes_no_progress "Нужна ли поддержка openvswitch? (y/n) [n]: " "n" USE_OPENVSWITCH + +# Использовать зеркало mirror.gcr.io? +ask_yes_no_progress "Хотите ли вы использовать зеркала timeweb.cloud и gcr.io для docker.io? (y/n) [y]: " "y" USE_MIRROR_GCR + +# Вопрос: нужен ли maxPods: 512 для kubelet? +ask_yes_no_progress "Нужно ли установить maxPods: 512? (110 подов на ноду по умолчанию) (y/n) [n]: " "n" USE_KUBELET_MAXPODS # --- Генерация конфигурационных файлов --- @@ -190,7 +261,6 @@ mkdir -p "$CONFIG_DIR" PATCH_FILE="$CONFIG_DIR/patch.yaml" # --- Создание patch.yaml --- -# Этот подход не использует sed и работает одинаково на macOS и Linux. # Записываем первую часть файла cat > "$PATCH_FILE" << EOF @@ -207,13 +277,38 @@ fi # Добавляем блок kernel для drbd, если нужно if [[ "$USE_DRBD" == "y" ]] && (( WORKER_COUNT == 0 )); then - cat >> "$PATCH_FILE" << 'EOF' + cat >> "$PATCH_FILE" << EOF kernel: modules: - name: drbd parameters: - usermode_helper=disabled EOF + if [[ "$USE_ZFS" == "y" ]]; then + cat >> "$PATCH_FILE" << EOF + - name: zfs +EOF + fi + if [[ "$USE_SPL" == "y" ]]; then + cat >> "$PATCH_FILE" << EOF + - name: spl +EOF + fi + if [[ "$USE_VFIO_PCI" == "y" ]]; then + cat >> "$PATCH_FILE" << EOF + - name: vfio_pci +EOF + fi + if [[ "$USE_VFIO_IOMMU_TYPE1" == "y" ]]; then + cat >> "$PATCH_FILE" << EOF + - name: vfio_iommu_type1 +EOF + fi + if [[ "$USE_OPENVSWITCH" == "y" ]]; then + cat >> "$PATCH_FILE" << EOF + - name: openvswitch +EOF + fi fi # Добавляем основную часть machine и начало cluster @@ -225,6 +320,20 @@ cat >> "$PATCH_FILE" << EOF install: disk: ${DISK} image: ${IMAGE} +EOF + +if [[ "$USE_MIRROR_GCR" == "y" ]]; then + cat >> "$PATCH_FILE" << EOF + registries: + mirrors: + docker.io: + endpoints: + - https://dockerhub.timeweb.cloud + - https://mirror.gcr.io +EOF +fi + +cat >> "$PATCH_FILE" << EOF time: servers: - ${NTP1} @@ -281,6 +390,17 @@ for i in $(seq 1 $CP_COUNT); do # Создание базового патча cat > "$FILENAME" << EOF machine: +EOF + + if [[ "$USE_KUBELET_MAXPODS" == "y" ]]; then + cat >> "$FILENAME" << EOF + kubelet: + extraConfig: + maxPods: 512 +EOF + fi + + cat >> "$FILENAME" << EOF network: hostname: $HOSTNAME interfaces: