Files
K3S/docker/entrypoint.sh
Sergey Antropoff 437d0cce34 refactor: перемещение плейбуков в playbooks/, ротация сертификатов, сохранение ключей локально
Организация плейбуков:
- все .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
2026-04-24 07:00:18 +03:00

390 lines
16 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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