#!/bin/bash # ============================================================================= # Aula 12 - Victoria Metrics (Observabilidade via GitOps) # ============================================================================= # # Este script instala Victoria Metrics stack usando ArgoCD (GitOps): # 1. Cria projeto 'factory/monitoring' no GitLab # 2. Push dos manifests GitOps # 3. Cria ArgoCD Application # 4. Victoria Metrics + Grafana são sincronizados automaticamente # # Pré-requisitos: # - Cluster Kubernetes (aula-08) # - ArgoCD instalado (aula-11) # - GitLab com grupo 'factory' (aula-10/11) # # ============================================================================= set -e # Cores para output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Funções de log log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[OK]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # Diretório do script SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE="${SCRIPT_DIR}/.env" GITOPS_DIR="${SCRIPT_DIR}/gitops" # ============================================================================= # VERIFICAR PRÉ-REQUISITOS # ============================================================================= log_info "Verificando pré-requisitos..." # Verificar kubectl if ! command -v kubectl &> /dev/null; then log_error "kubectl não encontrado. Instale com: brew install kubectl" exit 1 fi # Verificar helm if ! command -v helm &> /dev/null; then log_error "helm não encontrado. Instale com: brew install helm" exit 1 fi # Verificar git if ! command -v git &> /dev/null; then log_error "git não encontrado. Instale com: brew install git" exit 1 fi # Verificar conexão com cluster if ! kubectl cluster-info &> /dev/null; then log_error "Não foi possível conectar ao cluster Kubernetes" log_info "Verifique se KUBECONFIG está configurado corretamente" exit 1 fi # Verificar se ArgoCD está instalado if ! kubectl get namespace argocd &> /dev/null; then log_error "Namespace 'argocd' não encontrado" log_info "Execute primeiro a aula-11 para instalar o ArgoCD" exit 1 fi # Verificar se ArgoCD está rodando if ! kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server --no-headers 2>/dev/null | grep -q Running; then log_error "ArgoCD server não está rodando" log_info "Verifique: kubectl get pods -n argocd" exit 1 fi log_success "Pré-requisitos verificados" # ============================================================================= # CARREGAR CONFIGURAÇÃO # ============================================================================= # Carregar configuração local (se existir) if [[ -f "$ENV_FILE" ]]; then log_info "Carregando configuração local..." source "$ENV_FILE" fi # Herdar configuração da aula-11 AULA11_ENV="${SCRIPT_DIR}/../aula-11/.env" if [[ -f "$AULA11_ENV" ]]; then log_info "Herdando configuração da aula-11..." source "$AULA11_ENV" fi # Herdar configuração da aula-10 AULA10_ENV="${SCRIPT_DIR}/../aula-10/.env" if [[ -f "$AULA10_ENV" ]]; then log_info "Herdando configuração da aula-10..." source "$AULA10_ENV" fi # ============================================================================= # COLETAR CONFIGURAÇÃO # ============================================================================= echo "" echo "==========================================" echo " Configuração Victoria Metrics (GitOps)" echo "==========================================" echo "" # GitLab Host if [[ -z "$GITLAB_HOST" ]]; then read -p "Hostname do GitLab (ex: git.kube.quest): " GITLAB_HOST fi log_info "GitLab: https://${GITLAB_HOST}" # Extrair domínio base if [[ -z "$DOMAIN" ]]; then DOMAIN=$(echo "$GITLAB_HOST" | sed 's/^[^.]*\.//') fi # Grafana Host if [[ -z "$GRAFANA_HOST" ]]; then DEFAULT_GRAFANA="grafana.${DOMAIN}" read -p "Hostname do Grafana [${DEFAULT_GRAFANA}]: " GRAFANA_HOST GRAFANA_HOST="${GRAFANA_HOST:-$DEFAULT_GRAFANA}" fi log_info "Grafana: https://${GRAFANA_HOST}" # GitLab Token (para criar projeto via API) if [[ -z "$GITLAB_TOKEN" ]]; then echo "" echo "Token de acesso GitLab (para criar projeto via API):" echo " 1. Acesse https://${GITLAB_HOST}/-/user_settings/personal_access_tokens" echo " 2. Crie um token com scope 'api'" echo "" read -p "GitLab Token: " GITLAB_TOKEN fi # TLS (herdar da aula-11) if [[ -z "$USE_CLOUDFLARE" && -z "$USE_LETSENCRYPT" ]]; then echo "" echo "Configuração de TLS:" echo " 1) CloudFlare (proxy ativo - TLS na borda)" echo " 2) Let's Encrypt (cert-manager)" echo " 3) HTTP apenas (desenvolvimento)" read -p "Escolha [1-3]: " TLS_CHOICE case $TLS_CHOICE in 1) USE_CLOUDFLARE=true; USE_LETSENCRYPT=false ;; 2) USE_CLOUDFLARE=false; USE_LETSENCRYPT=true ;; *) USE_CLOUDFLARE=false; USE_LETSENCRYPT=false ;; esac fi # Salvar configuração cat > "$ENV_FILE" << EOF # Configuração gerada pelo setup.sh # $(date) GITLAB_HOST=${GITLAB_HOST} GRAFANA_HOST=${GRAFANA_HOST} DOMAIN=${DOMAIN} USE_CLOUDFLARE=${USE_CLOUDFLARE} USE_LETSENCRYPT=${USE_LETSENCRYPT} GITLAB_TOKEN=${GITLAB_TOKEN} EOF log_success "Configuração salva em ${ENV_FILE}" # ============================================================================= # CRIAR PROJETO NO GITLAB (VIA API) # ============================================================================= echo "" log_info "=== Criando Projeto no GitLab ===" # Verificar se grupo factory existe log_info "Verificando grupo 'factory'..." GROUP_RESPONSE=$(curl -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ "https://${GITLAB_HOST}/api/v4/groups?search=factory") GROUP_ID=$(echo "$GROUP_RESPONSE" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2) if [[ -z "$GROUP_ID" ]]; then log_info "Criando grupo 'factory'..." GROUP_CREATE=$(curl -s --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --header "Content-Type: application/json" \ --data '{"name": "factory", "path": "factory", "visibility": "internal"}' \ "https://${GITLAB_HOST}/api/v4/groups") GROUP_ID=$(echo "$GROUP_CREATE" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2) if [[ -z "$GROUP_ID" ]]; then log_error "Falha ao criar grupo 'factory'" log_info "Crie manualmente em https://${GITLAB_HOST}/admin/groups/new" exit 1 fi log_success "Grupo 'factory' criado (ID: ${GROUP_ID})" else log_success "Grupo 'factory' já existe (ID: ${GROUP_ID})" fi # Verificar se projeto monitoring existe log_info "Verificando projeto 'monitoring'..." PROJECT_RESPONSE=$(curl -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ "https://${GITLAB_HOST}/api/v4/projects?search=monitoring") PROJECT_EXISTS=$(echo "$PROJECT_RESPONSE" | grep -o '"path_with_namespace":"factory/monitoring"' || true) if [[ -z "$PROJECT_EXISTS" ]]; then log_info "Criando projeto 'monitoring'..." PROJECT_CREATE=$(curl -s --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --header "Content-Type: application/json" \ --data "{\"name\": \"monitoring\", \"namespace_id\": ${GROUP_ID}, \"visibility\": \"internal\", \"initialize_with_readme\": false}" \ "https://${GITLAB_HOST}/api/v4/projects") PROJECT_ID=$(echo "$PROJECT_CREATE" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2) if [[ -z "$PROJECT_ID" ]]; then log_error "Falha ao criar projeto 'monitoring'" echo "$PROJECT_CREATE" exit 1 fi log_success "Projeto 'monitoring' criado (ID: ${PROJECT_ID})" else log_success "Projeto 'monitoring' já existe" fi # ============================================================================= # PUSH DOS MANIFESTS GITOPS # ============================================================================= echo "" log_info "=== Push dos Manifests GitOps ===" # Criar diretório temporário para clone TEMP_DIR=$(mktemp -d) trap "rm -rf ${TEMP_DIR}" EXIT cd "${TEMP_DIR}" # Configurar git git config --global user.email "argocd@${DOMAIN}" 2>/dev/null || true git config --global user.name "ArgoCD Setup" 2>/dev/null || true # Clone do repositório (usando token) log_info "Clonando repositório..." GIT_URL="https://oauth2:${GITLAB_TOKEN}@${GITLAB_HOST}/factory/monitoring.git" if ! git clone "${GIT_URL}" monitoring 2>/dev/null; then # Repositório vazio, inicializar mkdir monitoring cd monitoring git init git remote add origin "${GIT_URL}" else cd monitoring fi # Copiar arquivos GitOps log_info "Copiando manifests GitOps..." cp -r "${GITOPS_DIR}/apps" . # Configurar values.yaml com hostname do Grafana log_info "Configurando Grafana hostname..." if [[ -f "apps/victoria-metrics/values.yaml" ]]; then sed -i.bak "s/GRAFANA_HOST_PLACEHOLDER/${GRAFANA_HOST}/g" apps/victoria-metrics/values.yaml rm -f apps/victoria-metrics/values.yaml.bak fi # Commit e push git add -A if git diff --cached --quiet; then log_info "Nenhuma mudança para commit" else git commit -m "feat: Victoria Metrics stack configuration" log_info "Pushing para GitLab..." git push -u origin main 2>/dev/null || git push -u origin master 2>/dev/null || { # Primeiro push em repo vazio git push --set-upstream origin main 2>/dev/null || git push --set-upstream origin master } log_success "Manifests enviados para GitLab" fi cd "${SCRIPT_DIR}" # ============================================================================= # CRIAR NAMESPACE MONITORING # ============================================================================= echo "" log_info "=== Criando Namespace ===" kubectl create namespace monitoring 2>/dev/null || log_info "Namespace 'monitoring' já existe" log_success "Namespace 'monitoring' pronto" # ============================================================================= # CONFIGURAR REPOSITÓRIO NO ARGOCD # ============================================================================= echo "" log_info "=== Configurando Repositório no ArgoCD ===" # Criar secret para o repositório log_info "Criando secret de acesso ao repositório..." kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: factory-monitoring-repo namespace: argocd labels: argocd.argoproj.io/secret-type: repository stringData: type: git url: https://${GITLAB_HOST}/factory/monitoring.git username: oauth2 password: ${GITLAB_TOKEN} EOF log_success "Repositório configurado no ArgoCD" # ============================================================================= # CRIAR ARGOCD APPLICATION # ============================================================================= echo "" log_info "=== Criando ArgoCD Application ===" # Construir anotações de Ingress INGRESS_ANNOTATIONS="" if [[ "$USE_LETSENCRYPT" == "true" ]]; then INGRESS_ANNOTATIONS='cert-manager.io/cluster-issuer: letsencrypt-prod' fi # Aplicar ArgoCD Application kubectl apply -f - << EOF apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: monitoring namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.io spec: project: default source: repoURL: https://${GITLAB_HOST}/factory/monitoring.git targetRevision: HEAD path: apps/victoria-metrics helm: valueFiles: - values.yaml destination: server: https://kubernetes.default.svc namespace: monitoring syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true - ServerSideApply=true EOF log_success "ArgoCD Application criada" # ============================================================================= # AGUARDAR SINCRONIZAÇÃO # ============================================================================= echo "" log_info "=== Aguardando Sincronização ===" log_info "ArgoCD está sincronizando Victoria Metrics stack..." log_info "Isso pode levar alguns minutos na primeira vez..." # Aguardar até 5 minutos for i in {1..60}; do STATUS=$(kubectl get application monitoring -n argocd -o jsonpath='{.status.sync.status}' 2>/dev/null || echo "Unknown") HEALTH=$(kubectl get application monitoring -n argocd -o jsonpath='{.status.health.status}' 2>/dev/null || echo "Unknown") echo -ne "\r Status: ${STATUS} | Health: ${HEALTH} " if [[ "$STATUS" == "Synced" && "$HEALTH" == "Healthy" ]]; then echo "" log_success "Victoria Metrics stack sincronizado e saudável!" break fi if [[ $i -eq 60 ]]; then echo "" log_warn "Timeout aguardando sincronização" log_info "Verifique o status no ArgoCD UI" fi sleep 5 done # ============================================================================= # OBTER SENHA DO GRAFANA # ============================================================================= echo "" log_info "=== Credenciais do Grafana ===" # Aguardar secret ser criado for i in {1..30}; do if kubectl get secret vm-grafana -n monitoring &> /dev/null; then break fi sleep 2 done GRAFANA_PASSWORD=$(kubectl get secret vm-grafana -n monitoring -o jsonpath='{.data.admin-password}' 2>/dev/null | base64 -d 2>/dev/null || echo "") if [[ -z "$GRAFANA_PASSWORD" ]]; then # Tentar nome alternativo do secret GRAFANA_PASSWORD=$(kubectl get secret -n monitoring -l app.kubernetes.io/name=grafana -o jsonpath='{.items[0].data.admin-password}' 2>/dev/null | base64 -d 2>/dev/null || echo "admin") fi # ============================================================================= # INSTRUÇÕES FINAIS # ============================================================================= echo "" echo "==========================================" echo " Instalação Concluída!" echo "==========================================" echo "" echo "Victoria Metrics Stack instalado via GitOps" echo "" echo "Grafana:" if [[ "$USE_CLOUDFLARE" == "true" || "$USE_LETSENCRYPT" == "true" ]]; then echo " URL: https://${GRAFANA_HOST}" else echo " URL: http://${GRAFANA_HOST}" fi echo " Username: admin" echo " Password: ${GRAFANA_PASSWORD:-'(ver secret vm-grafana)'}" echo "" echo "Acesso via port-forward:" echo " kubectl port-forward -n monitoring svc/vm-grafana 3000:80" echo " open http://localhost:3000" echo "" echo "ArgoCD Application:" echo " kubectl get application monitoring -n argocd" echo "" echo "Pods:" echo " kubectl get pods -n monitoring" echo "" echo "GitOps Repository:" echo " https://${GITLAB_HOST}/factory/monitoring" echo "" echo "Verificar métricas:" echo " kubectl port-forward -n monitoring svc/vmsingle-vm 8429:8429" echo " curl http://localhost:8429/api/v1/query?query=up" echo "" echo "=========================================="