#!/bin/bash # ============================================================================= # Aula 11 - ArgoCD + GitLab Runner (GitOps) # ============================================================================= # # Este script instala: # 1. GitLab Runner (executor kubernetes) para CI # 2. ArgoCD para CD declarativo (GitOps) # 3. Integração com GitLab self-hosted (aula-10) # # Pré-requisitos: # - Cluster Kubernetes (aula-08) # - GitLab instalado (aula-10) # - NGINX Ingress Controller # - kubectl e helm instalados # # ============================================================================= 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" # ============================================================================= # 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 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" log_info "Exemplo: export KUBECONFIG=\$(pwd)/../aula-08/kubeconfig" exit 1 fi # Verificar se GitLab está instalado if ! kubectl get namespace gitlab &> /dev/null; then log_error "Namespace 'gitlab' não encontrado" log_info "Execute primeiro a aula-10 para instalar o GitLab" exit 1 fi # Verificar NGINX Ingress if ! kubectl get ingressclass nginx &> /dev/null; then log_error "NGINX Ingress Controller não encontrado" log_info "Execute o script de instalação do NGINX Ingress na aula-08" exit 1 fi log_success "Pré-requisitos verificados" # ============================================================================= # CONFIGURAR POD SECURITY PARA DOCKER-IN-DOCKER # ============================================================================= # # Docker-in-Docker requer pods privilegiados. Kubernetes 1.25+ aplica # Pod Security Admission por padrão, bloqueando containers privilegiados # no modo "baseline". Precisamos configurar o namespace gitlab para # permitir pods privilegiados. # log_info "Configurando PodSecurity para Docker-in-Docker..." kubectl label namespace gitlab \ pod-security.kubernetes.io/enforce=privileged \ pod-security.kubernetes.io/warn=privileged \ pod-security.kubernetes.io/audit=privileged \ --overwrite log_success "PodSecurity configurado para permitir Docker-in-Docker" # ============================================================================= # CARREGAR CONFIGURAÇÃO EXISTENTE # ============================================================================= # Carregar configuração local PRIMEIRO (se existir) if [[ -f "$ENV_FILE" ]]; then log_info "Carregando configuração local..." source "$ENV_FILE" fi # Se não tiver configuração local, tentar herdar da aula-10 if [[ -z "$GITLAB_HOST" ]]; then AULA10_ENV="${SCRIPT_DIR}/../aula-10/.env" if [[ -f "$AULA10_ENV" ]]; then log_info "Herdando configuração da aula-10..." source "$AULA10_ENV" GITLAB_HOST="${GITLAB_HOST:-}" DOMAIN="${DOMAIN:-}" USE_CLOUDFLARE="${USE_CLOUDFLARE:-false}" USE_LETSENCRYPT="${USE_LETSENCRYPT:-false}" LETSENCRYPT_EMAIL="${LETSENCRYPT_EMAIL:-}" fi fi # ============================================================================= # COLETAR CONFIGURAÇÃO # ============================================================================= echo "" echo "==========================================" echo " Configuração do ArgoCD + GitLab CI" 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 # ArgoCD Host if [[ -z "$ARGOCD_HOST" ]]; then DEFAULT_ARGOCD="argocd.${DOMAIN}" read -p "Hostname do ArgoCD [${DEFAULT_ARGOCD}]: " ARGOCD_HOST ARGOCD_HOST="${ARGOCD_HOST:-$DEFAULT_ARGOCD}" fi log_info "ArgoCD: https://${ARGOCD_HOST}" # TLS (herdar da aula-10 ou perguntar) if [[ "$USE_CLOUDFLARE" != "true" && "$USE_LETSENCRYPT" != "true" ]]; 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 if [[ -z "$LETSENCRYPT_EMAIL" ]]; then read -p "Email para Let's Encrypt: " LETSENCRYPT_EMAIL fi ;; *) 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} ARGOCD_HOST=${ARGOCD_HOST} DOMAIN=${DOMAIN} USE_CLOUDFLARE=${USE_CLOUDFLARE} USE_LETSENCRYPT=${USE_LETSENCRYPT} LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL} EOF log_success "Configuração salva em ${ENV_FILE}" # ============================================================================= # INSTALAR GITLAB RUNNER # ============================================================================= echo "" log_info "=== Instalando GitLab Runner ===" # Adicionar repositório Helm helm repo add gitlab https://charts.gitlab.io 2>/dev/null || true helm repo update # Verificar se já está instalado if helm status gitlab-runner -n gitlab &> /dev/null; then log_warn "GitLab Runner já instalado, fazendo upgrade..." HELM_CMD="upgrade" else HELM_CMD="install" fi # Obter runner registration token log_info "Obtendo token de registro do GitLab Runner..." # Tentar obter o token do secret RUNNER_TOKEN="" if kubectl get secret gitlab-gitlab-runner-secret -n gitlab &> /dev/null; then RUNNER_TOKEN=$(kubectl get secret gitlab-gitlab-runner-secret -n gitlab -o jsonpath='{.data.runner-registration-token}' 2>/dev/null | base64 -d 2>/dev/null || echo "") fi if [[ -z "$RUNNER_TOKEN" ]]; then log_warn "Token de registro não encontrado automaticamente" echo "" echo "Para obter o token:" echo " 1. Acesse https://${GITLAB_HOST}/admin/runners" echo " 2. Clique em 'New instance runner'" echo " 3. Copie o registration token" echo "" read -p "Cole o registration token: " RUNNER_TOKEN fi if [[ -z "$RUNNER_TOKEN" ]]; then log_error "Token de registro é obrigatório" exit 1 fi # Instalar GitLab Runner log_info "Instalando GitLab Runner via Helm..." helm ${HELM_CMD} gitlab-runner gitlab/gitlab-runner \ --namespace gitlab \ -f "${SCRIPT_DIR}/gitlab-runner-values.yaml" \ --set gitlabUrl="https://${GITLAB_HOST}" \ --set runnerRegistrationToken="${RUNNER_TOKEN}" \ --wait --timeout 5m log_success "GitLab Runner instalado" # Verificar pods log_info "Verificando pods do GitLab Runner..." kubectl get pods -n gitlab -l app=gitlab-runner # ============================================================================= # INSTALAR CERT-MANAGER (se Let's Encrypt) # ============================================================================= if [[ "$USE_LETSENCRYPT" == "true" ]]; then echo "" log_info "=== Verificando cert-manager ===" if ! kubectl get namespace cert-manager &> /dev/null; then log_info "Instalando cert-manager..." helm repo add jetstack https://charts.jetstack.io 2>/dev/null || true helm repo update helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --set crds.enabled=true \ --wait --timeout 5m log_success "cert-manager instalado" else log_success "cert-manager já instalado" fi # Criar ClusterIssuer se não existir if ! kubectl get clusterissuer letsencrypt-prod &> /dev/null; then log_info "Criando ClusterIssuer letsencrypt-prod..." kubectl apply -f - << EOF apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: ${LETSENCRYPT_EMAIL} privateKeySecretRef: name: letsencrypt-prod solvers: - http01: ingress: class: nginx EOF log_success "ClusterIssuer criado" fi fi # ============================================================================= # INSTALAR ARGOCD # ============================================================================= echo "" log_info "=== Instalando ArgoCD ===" # Adicionar repositório Helm helm repo add argo https://argoproj.github.io/argo-helm 2>/dev/null || true helm repo update # Criar namespace kubectl create namespace argocd 2>/dev/null || true # Verificar se já está instalado if helm status argocd -n argocd &> /dev/null; then log_warn "ArgoCD já instalado, fazendo upgrade..." HELM_CMD="upgrade" else HELM_CMD="install" fi # Construir argumentos Helm HELM_ARGS="" HELM_ARGS="$HELM_ARGS --set global.domain=${ARGOCD_HOST}" HELM_ARGS="$HELM_ARGS --set server.ingress.hosts[0]=${ARGOCD_HOST}" if [[ "$USE_LETSENCRYPT" == "true" ]]; then HELM_ARGS="$HELM_ARGS --set server.ingress.tls[0].secretName=argocd-server-tls" HELM_ARGS="$HELM_ARGS --set server.ingress.tls[0].hosts[0]=${ARGOCD_HOST}" HELM_ARGS="$HELM_ARGS --set 'server.ingress.annotations.cert-manager\.io/cluster-issuer=letsencrypt-prod'" elif [[ "$USE_CLOUDFLARE" == "true" ]]; then # CloudFlare faz TLS na borda HELM_ARGS="$HELM_ARGS --set server.ingress.tls=" fi # Instalar ArgoCD log_info "Instalando ArgoCD via Helm..." eval helm ${HELM_CMD} argocd argo/argo-cd \ --namespace argocd \ -f "${SCRIPT_DIR}/argocd-values.yaml" \ ${HELM_ARGS} \ --wait --timeout 10m log_success "ArgoCD instalado" # ============================================================================= # OBTER SENHA DO ADMIN # ============================================================================= echo "" log_info "=== Credenciais do ArgoCD ===" # Aguardar secret ser criado log_info "Aguardando secret de credenciais..." for i in {1..30}; do if kubectl get secret argocd-initial-admin-secret -n argocd &> /dev/null; then break fi sleep 2 done ARGOCD_PASSWORD=$(kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath='{.data.password}' 2>/dev/null | base64 -d 2>/dev/null || echo "") if [[ -z "$ARGOCD_PASSWORD" ]]; then log_warn "Não foi possível obter a senha inicial" log_info "Tente: kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath='{.data.password}' | base64 -d" else echo "" echo "==========================================" echo " ArgoCD Credenciais" echo "==========================================" echo " URL: https://${ARGOCD_HOST}" echo " Username: admin" echo " Password: ${ARGOCD_PASSWORD}" echo "==========================================" fi # ============================================================================= # CONFIGURAR INTEGRAÇÃO GITLAB # ============================================================================= echo "" log_info "=== Configurando Integração GitLab ===" # Obter host key do GitLab log_info "Obtendo SSH host key do GitLab..." SSH_HOST_KEY=$(ssh-keyscan -t ed25519 ${GITLAB_HOST} 2>/dev/null || ssh-keyscan ${GITLAB_HOST} 2>/dev/null || echo "") if [[ -n "$SSH_HOST_KEY" ]]; then # Criar ConfigMap com known hosts kubectl create configmap argocd-ssh-known-hosts-cm \ --from-literal=ssh_known_hosts="${SSH_HOST_KEY}" \ -n argocd \ --dry-run=client -o yaml | kubectl apply -f - log_success "SSH host key configurado" else log_warn "Não foi possível obter SSH host key" log_info "Configure manualmente: argocd cert add-ssh --batch < known_hosts" fi # ============================================================================= # INSTRUÇÕES FINAIS # ============================================================================= echo "" echo "==========================================" echo " Instalação Concluída!" echo "==========================================" echo "" echo "ArgoCD:" echo " URL: https://${ARGOCD_HOST}" echo " Username: admin" if [[ -n "$ARGOCD_PASSWORD" ]]; then echo " Password: ${ARGOCD_PASSWORD}" else echo " Password: kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath='{.data.password}' | base64 -d" fi echo "" echo "GitLab Runner:" echo " Namespace: gitlab" echo " Verificar: kubectl get pods -n gitlab -l app=gitlab-runner" echo " Status no GitLab: https://${GITLAB_HOST}/admin/runners" echo "" echo "Próximos passos:" echo "" echo "1. Configure DNS:" echo " Adicione registro A para ${ARGOCD_HOST} apontando para o LoadBalancer" echo "" echo "2. Crie um repositório GitOps no GitLab:" echo " - Nome: gitops-demo" echo " - Estrutura: apps/node-bugado/{deployment,service,configmap}.yaml" echo "" echo "3. Configure repositório no ArgoCD:" echo " a) Gere uma deploy key:" echo " ssh-keygen -t ed25519 -f argocd-deploy-key -N ''" echo "" echo " b) Adicione a chave pública no GitLab:" echo " Settings → Repository → Deploy Keys" echo "" echo " c) Conecte o repositório no ArgoCD:" echo " - Acesse https://${ARGOCD_HOST}" echo " - Settings → Repositories → Connect Repo" echo " - Method: SSH" echo " - URL: git@${GITLAB_HOST}:/gitops-demo.git" echo " - SSH private key: (conteúdo de argocd-deploy-key)" echo "" echo "4. Crie uma Application no ArgoCD:" echo " kubectl apply -f - << 'EOF'" echo " apiVersion: argoproj.io/v1alpha1" echo " kind: Application" echo " metadata:" echo " name: node-bugado" echo " namespace: argocd" echo " spec:" echo " project: default" echo " source:" echo " repoURL: git@${GITLAB_HOST}:/gitops-demo.git" echo " targetRevision: HEAD" echo " path: apps/node-bugado" echo " destination:" echo " server: https://kubernetes.default.svc" echo " namespace: demo" echo " syncPolicy:" echo " automated:" echo " prune: true" echo " selfHeal: true" echo " syncOptions:" echo " - CreateNamespace=true" echo " EOF" echo "" echo "Comandos úteis:" echo " kubectl get pods -n argocd" echo " kubectl get applications -n argocd" echo " kubectl logs -n gitlab -l app=gitlab-runner -f" echo ""