Организация плейбуков: - все .yml плейбуки перенесены из корня в playbooks/ - Makefile и entrypoint.sh обновлены — все пути с playbooks/ префиксом - k8s-user.yml переработан: include_tasks → include_role (корректная работа из подкаталога) Сохранение ключей и kubeconfig локально: - k8s-user.yml: новый play сохраняет k8s SSH ключи в ./keys/ на машине запуска - переменная k8s_local_keys_dir: "./keys" (настраивается в group_vars) - .gitignore: keys/k8s_id_rsa исключён (публичный ключ можно коммитить) - kubeconfig уже сохранялся роль k3s (k3s_kubeconfig_local_path: "./kubeconfig") Автоматическая ротация сертификатов K3S (роль k3s-certs): - K3S выпускает сертификаты на 1 год (hardcoded), таймер обеспечивает их обновление - скрипт k3s-cert-check.sh: проверяет срок через openssl, ротирует при k3s_cert_rotate_before_days - systemd service + timer: запуск по расписанию k3s_cert_check_schedule (по умолчанию monthly) - RandomizedDelaySec: снижает нагрузку при одновременном запуске на нескольких нодах - переменные: k3s_cert_validity_years: 5, k3s_cert_rotate_before_days: 90 - добавлен в site.yml (тег certs) и отдельный плейбук playbooks/k3s-certs.yml - make k3s-certs и команда k3s-certs в entrypoint.sh
390 lines
16 KiB
Bash
390 lines
16 KiB
Bash
#!/usr/bin/env bash
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# Entrypoint для Ansible Runner контейнера
|
||
# Выполняет: настройку SSH, vault-пароля, и запуск ansible-playbook
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
set -euo pipefail
|
||
|
||
# Цвета для вывода
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
CYAN='\033[0;36m'
|
||
BOLD='\033[1m'
|
||
NC='\033[0m' # No Color
|
||
|
||
log() { echo -e "${BLUE}[runner]${NC} $*"; }
|
||
ok() { echo -e "${GREEN}[runner]${NC} ✓ $*"; }
|
||
warn() { echo -e "${YELLOW}[runner]${NC} ⚠ $*"; }
|
||
err() { echo -e "${RED}[runner]${NC} ✗ $*" >&2; }
|
||
|
||
# ── Баннер ────────────────────────────────────────────────────────────────────
|
||
print_banner() {
|
||
echo -e "${CYAN}"
|
||
echo "╔══════════════════════════════════════════════════════╗"
|
||
echo "║ K3S Ansible Runner 🚀 ║"
|
||
echo "║ Ansible $(ansible --version | head -1 | awk '{print $3}') • Helm $(helm version --short) • kubectl $(kubectl version --client -o json 2>/dev/null | jq -r .clientVersion.gitVersion 2>/dev/null || echo 'n/a') ║"
|
||
echo "╚══════════════════════════════════════════════════════╝"
|
||
echo -e "${NC}"
|
||
}
|
||
|
||
# ── Справка ───────────────────────────────────────────────────────────────────
|
||
print_help() {
|
||
echo -e "${BOLD}Использование:${NC}"
|
||
echo ""
|
||
echo " Через Makefile (рекомендуется):"
|
||
echo " make install — полный стек"
|
||
echo " make install-k3s — только K3S"
|
||
echo " make install-kubevip — только kube-vip"
|
||
echo " make install-nfs — NFS сервер + CSI"
|
||
echo " make install-ingress — ingress-nginx"
|
||
echo " make health — диагностика"
|
||
echo " make upgrade VERSION=v1.30.0+k3s1"
|
||
echo ""
|
||
echo " Напрямую через docker run:"
|
||
echo " docker run --rm -it \\"
|
||
echo " -v \$(pwd):/ansible \\"
|
||
echo " -v ~/.ssh:/root/.ssh:ro \\"
|
||
echo " -e VAULT_PASSWORD=мой-пароль \\"
|
||
echo " k3s-ansible install"
|
||
echo ""
|
||
echo -e "${BOLD}Переменные окружения:${NC}"
|
||
echo " VAULT_PASSWORD — пароль Ansible Vault"
|
||
echo " VAULT_PASSWORD_FILE — путь к файлу с паролем (альтернатива)"
|
||
echo " ANSIBLE_TAGS — запустить только указанные теги"
|
||
echo " ANSIBLE_SKIP_TAGS — пропустить указанные теги"
|
||
echo " EXTRA_VARS — дополнительные переменные (-e)"
|
||
echo " ANSIBLE_VERBOSITY — уровень verbose (0-4, default: 0)"
|
||
echo ""
|
||
echo -e "${BOLD}Доступные команды:${NC}"
|
||
echo " bootstrap — создать пользователя + задеплоить SSH ключ"
|
||
echo " k8s-user — создать k8s пользователя + разложить SSH ключи"
|
||
echo " mdadm — найти RAID массив и смонтировать в /storage"
|
||
echo " k3s-certs — установить systemd таймер ротации сертификатов"
|
||
echo " install — полный стек (site.yml)"
|
||
echo " install-k3s — только K3S"
|
||
echo " install-kubevip — только kube-vip"
|
||
echo " install-nfs — NFS + CSI"
|
||
echo " install-ingress — ingress-nginx"
|
||
echo " install-cert-manager — cert-manager + ClusterIssuer"
|
||
echo " add-node <node> — добавить ноду (мастер или воркер)"
|
||
echo " remove-node <node> — безопасно удалить ноду"
|
||
echo " etcd-backup — создать снимок etcd"
|
||
echo " etcd-restore <snap> — восстановить etcd"
|
||
echo " etcd-list — список снимков etcd"
|
||
echo " upgrade — обновить K3S (нужен VERSION=)"
|
||
echo " uninstall — удалить весь стек"
|
||
echo " health — диагностика"
|
||
echo " verify — проверка стека"
|
||
echo " ping — проверить SSH до всех нод"
|
||
echo " shell — интерактивный bash"
|
||
echo " ansible-playbook — прямой вызов ansible-playbook"
|
||
echo " ansible — прямой вызов ansible"
|
||
}
|
||
|
||
# ── Настройка SSH ─────────────────────────────────────────────────────────────
|
||
setup_ssh() {
|
||
log "Настройка SSH..."
|
||
|
||
# Создаём директорию если не существует
|
||
mkdir -p /root/.ssh
|
||
chmod 700 /root/.ssh
|
||
|
||
# Конфигурация SSH клиента
|
||
cat > /root/.ssh/config << 'SSHEOF'
|
||
Host *
|
||
StrictHostKeyChecking no
|
||
UserKnownHostsFile /dev/null
|
||
ControlMaster auto
|
||
ControlPath /tmp/ssh-%r@%h:%p
|
||
ControlPersist 60s
|
||
ServerAliveInterval 30
|
||
ServerAliveCountMax 3
|
||
ConnectTimeout 30
|
||
SSHEOF
|
||
chmod 600 /root/.ssh/config
|
||
|
||
# Исправляем права на ключи если они примонтированы
|
||
if ls /root/.ssh/*.pem 2>/dev/null || ls /root/.ssh/id_* 2>/dev/null; then
|
||
chmod 600 /root/.ssh/id_* 2>/dev/null || true
|
||
chmod 600 /root/.ssh/*.pem 2>/dev/null || true
|
||
ok "SSH ключи найдены"
|
||
else
|
||
warn "SSH ключи не найдены в /root/.ssh — убедись что они примонтированы"
|
||
fi
|
||
}
|
||
|
||
# ── Настройка Vault пароля ────────────────────────────────────────────────────
|
||
setup_vault() {
|
||
local vault_file="/tmp/.vault_pass"
|
||
|
||
if [[ -n "${VAULT_PASSWORD:-}" ]]; then
|
||
echo "${VAULT_PASSWORD}" > "${vault_file}"
|
||
chmod 600 "${vault_file}"
|
||
export ANSIBLE_VAULT_PASSWORD_FILE="${vault_file}"
|
||
ok "Vault пароль установлен из переменной VAULT_PASSWORD"
|
||
|
||
elif [[ -n "${VAULT_PASSWORD_FILE:-}" ]] && [[ -f "${VAULT_PASSWORD_FILE}" ]]; then
|
||
export ANSIBLE_VAULT_PASSWORD_FILE="${VAULT_PASSWORD_FILE}"
|
||
ok "Vault пароль загружен из файла: ${VAULT_PASSWORD_FILE}"
|
||
|
||
elif [[ -f "/ansible/.vault_pass" ]]; then
|
||
export ANSIBLE_VAULT_PASSWORD_FILE="/ansible/.vault_pass"
|
||
ok "Vault пароль найден в /ansible/.vault_pass"
|
||
|
||
else
|
||
warn "Vault пароль не задан. Используй переменную VAULT_PASSWORD или файл .vault_pass"
|
||
warn "Если vault не используется — это нормально"
|
||
fi
|
||
}
|
||
|
||
# ── Сборка аргументов ansible-playbook ───────────────────────────────────────
|
||
build_ansible_args() {
|
||
local args=()
|
||
|
||
# Файл vault-пароля
|
||
if [[ -n "${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then
|
||
args+=("--vault-password-file" "${ANSIBLE_VAULT_PASSWORD_FILE}")
|
||
fi
|
||
|
||
# Уровень verbose
|
||
local verbosity="${ANSIBLE_VERBOSITY:-0}"
|
||
if [[ "${verbosity}" -gt 0 ]]; then
|
||
args+=("-$(printf 'v%.0s' $(seq 1 "${verbosity}"))")
|
||
fi
|
||
|
||
# Теги
|
||
if [[ -n "${ANSIBLE_TAGS:-}" ]]; then
|
||
args+=("--tags" "${ANSIBLE_TAGS}")
|
||
fi
|
||
|
||
# Пропустить теги
|
||
if [[ -n "${ANSIBLE_SKIP_TAGS:-}" ]]; then
|
||
args+=("--skip-tags" "${ANSIBLE_SKIP_TAGS}")
|
||
fi
|
||
|
||
# Дополнительные переменные
|
||
if [[ -n "${EXTRA_VARS:-}" ]]; then
|
||
args+=("-e" "${EXTRA_VARS}")
|
||
fi
|
||
|
||
echo "${args[@]:-}"
|
||
}
|
||
|
||
# ── Запуск playbook ───────────────────────────────────────────────────────────
|
||
run_playbook() {
|
||
local playbook="$1"
|
||
shift
|
||
local extra_args=("$@")
|
||
|
||
# shellcheck disable=SC2207
|
||
local ansible_args=($(build_ansible_args))
|
||
|
||
log "Запуск: ansible-playbook ${playbook} ${ansible_args[*]} ${extra_args[*]}"
|
||
echo ""
|
||
|
||
exec ansible-playbook "${playbook}" \
|
||
"${ansible_args[@]}" \
|
||
"${extra_args[@]}"
|
||
}
|
||
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# MAIN
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
print_banner
|
||
setup_ssh
|
||
setup_vault
|
||
|
||
COMMAND="${1:-help}"
|
||
shift || true
|
||
|
||
case "${COMMAND}" in
|
||
|
||
# ── Bootstrap ─────────────────────────────────────────────────────────────
|
||
bootstrap)
|
||
log "Bootstrap нод: создание пользователя + деплой SSH ключа..."
|
||
exec ansible-playbook playbooks/bootstrap.yml "$@"
|
||
;;
|
||
|
||
# ── k8s-user ──────────────────────────────────────────────────────────────
|
||
k8s-user)
|
||
log "Создание k8s пользователя и деплой SSH ключей..."
|
||
run_playbook playbooks/k8s-user.yml "$@"
|
||
;;
|
||
|
||
# ── mdadm ─────────────────────────────────────────────────────────────────
|
||
mdadm)
|
||
log "Настройка mdadm RAID и монтирование /storage..."
|
||
run_playbook playbooks/mdadm.yml "$@"
|
||
;;
|
||
|
||
# ── k3s-certs ─────────────────────────────────────────────────────────────
|
||
k3s-certs)
|
||
log "Установка systemd таймера ротации сертификатов K3S..."
|
||
run_playbook playbooks/k3s-certs.yml "$@"
|
||
;;
|
||
|
||
# ── Основные команды ───────────────────────────────────────────────────────
|
||
install)
|
||
log "Разворачиваю полный K3S стек..."
|
||
run_playbook playbooks/site.yml "$@"
|
||
;;
|
||
|
||
install-k3s)
|
||
log "Устанавливаю K3S cluster..."
|
||
run_playbook playbooks/site.yml --tags k3s "$@"
|
||
;;
|
||
|
||
install-kubevip)
|
||
log "Устанавливаю kube-vip..."
|
||
run_playbook playbooks/site.yml --tags kube_vip "$@"
|
||
;;
|
||
|
||
install-nfs)
|
||
log "Устанавливаю NFS Server + CSI Driver..."
|
||
run_playbook playbooks/site.yml --tags nfs,csi_nfs "$@"
|
||
;;
|
||
|
||
install-ingress)
|
||
log "Устанавливаю ingress-nginx..."
|
||
run_playbook playbooks/site.yml --tags ingress_nginx "$@"
|
||
;;
|
||
|
||
install-cert-manager)
|
||
log "Устанавливаю cert-manager..."
|
||
run_playbook playbooks/site.yml --tags cert_manager -e cert_manager_enabled=true "$@"
|
||
;;
|
||
|
||
add-node)
|
||
if [[ -z "${2:-}" ]]; then
|
||
err "Укажи ноду: add-node <nodename>"
|
||
exit 1
|
||
fi
|
||
log "Добавляю ноду ${2} в кластер..."
|
||
exec ansible-playbook playbooks/add-node.yml -e "node_to_add=${2}" "${@:3}"
|
||
;;
|
||
|
||
remove-node)
|
||
if [[ -z "${2:-}" ]]; then
|
||
err "Укажи ноду: remove-node <nodename>"
|
||
exit 1
|
||
fi
|
||
log "Удаляю ноду ${2} из кластера..."
|
||
exec ansible-playbook playbooks/remove-node.yml -e "node_to_remove=${2}" "${@:3}"
|
||
;;
|
||
|
||
etcd-backup)
|
||
log "Создаю снимок etcd..."
|
||
exec ansible-playbook playbooks/etcd-backup.yml "$@"
|
||
;;
|
||
|
||
etcd-restore)
|
||
if [[ -z "${2:-}" ]]; then
|
||
err "Укажи снимок: etcd-restore <snapshot.db>"
|
||
exit 1
|
||
fi
|
||
log "Восстанавливаю etcd из ${2}..."
|
||
exec ansible-playbook playbooks/etcd-restore.yml -e "etcd_restore_snapshot=${2}" "${@:3}"
|
||
;;
|
||
|
||
etcd-list)
|
||
log "Список снимков etcd..."
|
||
exec ansible-playbook playbooks/etcd-restore.yml --tags list "$@"
|
||
;;
|
||
|
||
upgrade)
|
||
if [[ -z "${VERSION:-}" ]]; then
|
||
err "Нужна переменная VERSION. Пример: make upgrade VERSION=v1.30.0+k3s1"
|
||
exit 1
|
||
fi
|
||
log "Обновляю K3S до ${VERSION}..."
|
||
run_playbook playbooks/upgrade.yml -e "k3s_version=${VERSION}" "$@"
|
||
;;
|
||
|
||
uninstall)
|
||
warn "Удаление всего стека! Данные будут потеряны."
|
||
run_playbook playbooks/uninstall.yml -e "confirm_uninstall=yes" "$@"
|
||
;;
|
||
|
||
health)
|
||
log "Диагностика кластера..."
|
||
run_playbook playbooks/healthcheck.yml "$@"
|
||
;;
|
||
|
||
verify)
|
||
log "Проверка полного стека..."
|
||
run_playbook playbooks/site.yml --tags verify "$@"
|
||
;;
|
||
|
||
ping)
|
||
log "Проверяю SSH доступность всех нод..."
|
||
# shellcheck disable=SC2207
|
||
local ansible_args=($(build_ansible_args))
|
||
exec ansible all -m ping "${ansible_args[@]}" "$@"
|
||
;;
|
||
|
||
# ── Molecule тестирование ролей ───────────────────────────────────────────
|
||
molecule)
|
||
ROLE="${2:-}"
|
||
shift 2 || true
|
||
if [[ -z "${ROLE}" ]]; then
|
||
err "Укажи роль: molecule k3s | molecule prometheus-stack | molecule istio"
|
||
echo ""
|
||
echo " Пример: make molecule-k3s"
|
||
exit 1
|
||
fi
|
||
if [[ ! -d "/ansible/roles/${ROLE}" ]]; then
|
||
err "Роль не найдена: /ansible/roles/${ROLE}"
|
||
exit 1
|
||
fi
|
||
log "Тестирую роль: ${ROLE}"
|
||
cd "/ansible/roles/${ROLE}"
|
||
exec molecule "${@:-test}"
|
||
;;
|
||
|
||
molecule-lint)
|
||
log "Запуск линтинга (yamllint + ansible-lint)..."
|
||
cd /ansible
|
||
yamllint .
|
||
ansible-lint
|
||
ok "Линтинг прошёл"
|
||
;;
|
||
|
||
# ── Прямые вызовы ─────────────────────────────────────────────────────────
|
||
ansible-playbook)
|
||
exec ansible-playbook "$@"
|
||
;;
|
||
|
||
ansible)
|
||
exec ansible "$@"
|
||
;;
|
||
|
||
helm)
|
||
exec helm "$@"
|
||
;;
|
||
|
||
kubectl)
|
||
exec kubectl "$@"
|
||
;;
|
||
|
||
# ── Shell ─────────────────────────────────────────────────────────────────
|
||
shell|bash|sh)
|
||
log "Запуск интерактивного shell..."
|
||
exec /bin/bash "$@"
|
||
;;
|
||
|
||
# ── Помощь ────────────────────────────────────────────────────────────────
|
||
help|--help|-h)
|
||
print_help
|
||
;;
|
||
|
||
*)
|
||
err "Неизвестная команда: ${COMMAND}"
|
||
echo ""
|
||
print_help
|
||
exit 1
|
||
;;
|
||
|
||
esac
|