- Extrair função ask_hostname para simplificar coleta de inputs - Remover variável DOMAIN do .env (usar hosts individuais) - Herdar domínio da aula-10 como default para hostnames - Adicionar label PodSecurity privileged no namespace istio-system - Usar ClusterIP no istio-ingressgateway e timeout de 10m no Helm - Permitir edição do email Let's Encrypt quando já configurado
620 lines
26 KiB
Bash
Executable File
620 lines
26 KiB
Bash
Executable File
#!/bin/bash
|
|
# ============================================================================
|
|
# Aula 14 - Istio Traffic Splitting
|
|
# ============================================================================
|
|
# Instala Istio com Kiali e Jaeger para demonstrar canary deployment
|
|
# usando traffic splitting entre duas versões da aplicação.
|
|
#
|
|
# Componentes:
|
|
# - Istio (istio-base + istiod)
|
|
# - Kiali (visualização do service mesh)
|
|
# - Jaeger (tracing distribuído)
|
|
# - Aplicação app-backend v1 e v2
|
|
#
|
|
# Observabilidade:
|
|
# - Usa Victoria Metrics da aula-12 para métricas
|
|
# - Jaeger para tracing distribuído
|
|
#
|
|
# Pré-requisitos:
|
|
# - Cluster Kubernetes da aula-08
|
|
# - Victoria Metrics da aula-12
|
|
# - Gitea com Registry da aula-10
|
|
# - kubectl, helm e docker instalados
|
|
# ============================================================================
|
|
|
|
set -e
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
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}[ERRO]${NC} $1"; }
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ENV_FILE="${SCRIPT_DIR}/.env"
|
|
AULA10_ENV="${SCRIPT_DIR}/../aula-10/.env"
|
|
|
|
# ============================================================================
|
|
# Gerenciamento de Configuração
|
|
# ============================================================================
|
|
|
|
load_config() {
|
|
if [[ -f "$ENV_FILE" ]]; then
|
|
source "$ENV_FILE"
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
save_config() {
|
|
cat > "$ENV_FILE" << EOF
|
|
# Configuração da Aula 14 - Istio Traffic Splitting
|
|
# Gerado em: $(date)
|
|
|
|
REGISTRY_HOST=${REGISTRY_HOST}
|
|
REGISTRY_PROJECT=${REGISTRY_PROJECT}
|
|
APP_HOST=${APP_HOST}
|
|
KIALI_HOST=${KIALI_HOST}
|
|
JAEGER_HOST=${JAEGER_HOST}
|
|
USE_LETSENCRYPT=${USE_LETSENCRYPT}
|
|
LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
|
|
BASIC_AUTH_USER=${BASIC_AUTH_USER}
|
|
BASIC_AUTH_PASS=${BASIC_AUTH_PASS}
|
|
EOF
|
|
log_success "Configuração salva em .env"
|
|
}
|
|
|
|
ask_hostname() {
|
|
local label="$1" current="$2" default="$3"
|
|
local value="${current:-$default}"
|
|
|
|
if [[ -n "$value" ]]; then
|
|
echo -e "${label}: ${GREEN}${value}${NC}" >&2
|
|
read -p "Enter para confirmar ou digite novo valor: " new_value
|
|
[[ -n "$new_value" ]] && value="$new_value"
|
|
else
|
|
read -p "${label}: " value
|
|
fi
|
|
echo "$value"
|
|
}
|
|
|
|
collect_user_input() {
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Configuração do Istio Traffic Splitting${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
|
|
if load_config; then
|
|
echo -e "Configuração existente encontrada:"
|
|
echo -e " Registry: ${GREEN}${REGISTRY_HOST}${NC}"
|
|
echo -e " App: ${GREEN}${APP_HOST}${NC}"
|
|
echo -e " Kiali: ${GREEN}${KIALI_HOST}${NC}"
|
|
echo -e " Jaeger: ${GREEN}${JAEGER_HOST}${NC}"
|
|
echo ""
|
|
echo -e "[1] Usar configuração existente"
|
|
echo -e "[2] Inserir nova configuração"
|
|
read -p "Escolha [1/2]: " choice
|
|
if [[ "$choice" == "1" ]]; then
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# Herdar defaults da aula-10
|
|
local INHERITED_DOMAIN=""
|
|
if [[ -f "$AULA10_ENV" ]]; then
|
|
source "$AULA10_ENV"
|
|
INHERITED_DOMAIN="${DOMAIN}"
|
|
log_info "Configuração herdada da aula-10"
|
|
fi
|
|
|
|
echo ""
|
|
REGISTRY_HOST=$(ask_hostname "Registry" "$REGISTRY_HOST" "reg.${INHERITED_DOMAIN}")
|
|
echo ""
|
|
APP_HOST=$(ask_hostname "App" "$APP_HOST" "app.${INHERITED_DOMAIN}")
|
|
KIALI_HOST=$(ask_hostname "Kiali" "$KIALI_HOST" "kiali.${INHERITED_DOMAIN}")
|
|
JAEGER_HOST=$(ask_hostname "Jaeger" "$JAEGER_HOST" "jaeger.${INHERITED_DOMAIN}")
|
|
|
|
# Owner/repo no Gitea para o registry (ex: root, demo, factory)
|
|
if [[ -z "$REGISTRY_PROJECT" ]]; then
|
|
REGISTRY_PROJECT="root"
|
|
fi
|
|
echo ""
|
|
echo -e "Owner/repo no Gitea: ${GREEN}${REGISTRY_PROJECT}${NC}"
|
|
echo -e " Imagens: ${CYAN}${REGISTRY_HOST}/${REGISTRY_PROJECT}/app-backend:v1${NC}"
|
|
echo -e " ${CYAN}${REGISTRY_HOST}/${REGISTRY_PROJECT}/app-backend:v2${NC}"
|
|
read -p "Grupo/projeto [${REGISTRY_PROJECT}]: " new_project
|
|
[[ -n "$new_project" ]] && REGISTRY_PROJECT="$new_project"
|
|
|
|
echo ""
|
|
echo -e "[1] Usar Let's Encrypt (HTTPS)"
|
|
echo -e "[2] Sem TLS (HTTP)"
|
|
read -p "Escolha [1/2]: " tls_choice
|
|
if [[ "$tls_choice" == "1" ]]; then
|
|
USE_LETSENCRYPT=true
|
|
if [[ -n "$LETSENCRYPT_EMAIL" ]]; then
|
|
echo -e "Email Let's Encrypt: ${GREEN}${LETSENCRYPT_EMAIL}${NC}"
|
|
read -p "Enter para confirmar ou digite novo valor: " new_email
|
|
[[ -n "$new_email" ]] && LETSENCRYPT_EMAIL="$new_email"
|
|
else
|
|
read -p "Email para Let's Encrypt: " LETSENCRYPT_EMAIL
|
|
fi
|
|
else
|
|
USE_LETSENCRYPT=false
|
|
fi
|
|
|
|
# Basic Auth para Kiali e Jaeger
|
|
echo ""
|
|
echo -e "${CYAN}Autenticação para Kiali e Jaeger:${NC}"
|
|
if [[ -z "$BASIC_AUTH_USER" ]]; then
|
|
BASIC_AUTH_USER="admin"
|
|
fi
|
|
echo -e "Usuário: ${GREEN}${BASIC_AUTH_USER}${NC}"
|
|
read -p "Enter para confirmar ou digite novo valor: " new_user
|
|
[[ -n "$new_user" ]] && BASIC_AUTH_USER="$new_user"
|
|
|
|
if [[ -z "$BASIC_AUTH_PASS" ]]; then
|
|
BASIC_AUTH_PASS=$(openssl rand -base64 12 | tr -d '/+=' | head -c 16)
|
|
echo -e "Senha gerada: ${GREEN}${BASIC_AUTH_PASS}${NC}"
|
|
else
|
|
echo -e "Senha: ${GREEN}${BASIC_AUTH_PASS}${NC}"
|
|
fi
|
|
read -p "Enter para confirmar ou digite nova senha: " new_pass
|
|
[[ -n "$new_pass" ]] && BASIC_AUTH_PASS="$new_pass"
|
|
|
|
save_config
|
|
}
|
|
|
|
# ============================================================================
|
|
# Verificação de Pré-requisitos
|
|
# ============================================================================
|
|
|
|
check_prerequisites() {
|
|
echo ""
|
|
log_info "Verificando pré-requisitos..."
|
|
|
|
if ! command -v kubectl &> /dev/null; then
|
|
log_error "kubectl não encontrado"
|
|
exit 1
|
|
fi
|
|
log_success "kubectl encontrado"
|
|
|
|
if ! command -v helm &> /dev/null; then
|
|
log_error "helm não encontrado"
|
|
exit 1
|
|
fi
|
|
log_success "helm encontrado"
|
|
|
|
if ! command -v docker &> /dev/null; then
|
|
log_error "docker não encontrado"
|
|
exit 1
|
|
fi
|
|
log_success "docker encontrado"
|
|
|
|
if ! kubectl cluster-info &> /dev/null; then
|
|
log_error "Cluster Kubernetes não acessível"
|
|
exit 1
|
|
fi
|
|
log_success "Cluster Kubernetes acessível"
|
|
|
|
# Verificar Victoria Metrics (aula-12)
|
|
if kubectl get svc -n monitoring vmsingle-victoria-metrics-k8s-stack &> /dev/null; then
|
|
log_success "Victoria Metrics encontrado (aula-12)"
|
|
VICTORIA_METRICS_URL="http://vmsingle-victoria-metrics-k8s-stack.monitoring:8429"
|
|
else
|
|
log_warn "Victoria Metrics não encontrado. Instale a aula-12 primeiro."
|
|
log_warn "Kiali funcionará sem métricas até Victoria Metrics estar disponível."
|
|
VICTORIA_METRICS_URL=""
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# Instalação do Istio
|
|
# ============================================================================
|
|
|
|
install_istio() {
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Instalando Istio${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
helm repo add istio https://istio-release.storage.googleapis.com/charts 2>/dev/null || true
|
|
helm repo update istio
|
|
|
|
kubectl create namespace istio-system 2>/dev/null || true
|
|
kubectl label namespace istio-system \
|
|
pod-security.kubernetes.io/enforce=privileged \
|
|
pod-security.kubernetes.io/warn=privileged \
|
|
--overwrite 2>/dev/null || true
|
|
|
|
log_info "Instalando istio-base..."
|
|
if helm status istio-base -n istio-system &> /dev/null; then
|
|
helm upgrade istio-base istio/base -n istio-system --wait
|
|
else
|
|
helm install istio-base istio/base -n istio-system --wait
|
|
fi
|
|
log_success "istio-base instalado"
|
|
|
|
log_info "Instalando istiod..."
|
|
if helm status istiod -n istio-system &> /dev/null; then
|
|
helm upgrade istiod istio/istiod -n istio-system --wait --timeout=10m
|
|
else
|
|
helm install istiod istio/istiod -n istio-system --wait --timeout=10m
|
|
fi
|
|
log_success "istiod instalado"
|
|
|
|
log_info "Aguardando istiod..."
|
|
kubectl wait --for=condition=available deployment/istiod -n istio-system --timeout=300s
|
|
log_success "istiod pronto"
|
|
|
|
log_info "Instalando istio-ingressgateway..."
|
|
local GW_ARGS="--set service.type=ClusterIP"
|
|
if helm status istio-ingressgateway -n istio-system &> /dev/null; then
|
|
helm upgrade istio-ingressgateway istio/gateway -n istio-system $GW_ARGS --wait --timeout=10m
|
|
else
|
|
helm install istio-ingressgateway istio/gateway -n istio-system $GW_ARGS --wait --timeout=10m
|
|
fi
|
|
log_success "istio-ingressgateway instalado"
|
|
|
|
log_info "Aguardando ingressgateway..."
|
|
kubectl wait --for=condition=available deployment/istio-ingressgateway -n istio-system --timeout=300s
|
|
log_success "ingressgateway pronto"
|
|
}
|
|
|
|
# ============================================================================
|
|
# Instalação de Observabilidade
|
|
# ============================================================================
|
|
|
|
install_observability() {
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Instalando Kiali e Jaeger${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
log_info "Instalando Jaeger..."
|
|
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/addons/jaeger.yaml 2>/dev/null || true
|
|
log_success "Jaeger instalado"
|
|
|
|
# Instalar Kiali com configuração para Victoria Metrics
|
|
log_info "Instalando Kiali..."
|
|
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/addons/kiali.yaml 2>/dev/null || true
|
|
|
|
# Configurar Kiali para usar Victoria Metrics
|
|
if [[ -n "$VICTORIA_METRICS_URL" ]]; then
|
|
log_info "Configurando Kiali para usar Victoria Metrics..."
|
|
kubectl patch configmap kiali -n istio-system --type merge -p "{
|
|
\"data\": {
|
|
\"config.yaml\": \"external_services:\\n prometheus:\\n url: ${VICTORIA_METRICS_URL}\\n tracing:\\n enabled: true\\n in_cluster_url: http://tracing.istio-system:16685/jaeger\\n use_grpc: true\\n\"
|
|
}
|
|
}" 2>/dev/null || true
|
|
# Reiniciar Kiali para aplicar configuração
|
|
kubectl rollout restart deployment/kiali -n istio-system 2>/dev/null || true
|
|
fi
|
|
log_success "Kiali instalado"
|
|
|
|
log_info "Aguardando pods de observabilidade..."
|
|
kubectl wait --for=condition=available deployment/kiali -n istio-system --timeout=300s 2>/dev/null || true
|
|
kubectl wait --for=condition=available deployment/jaeger -n istio-system --timeout=300s 2>/dev/null || true
|
|
log_success "Observabilidade pronta"
|
|
}
|
|
|
|
# ============================================================================
|
|
# Configuração de Basic Auth
|
|
# ============================================================================
|
|
|
|
setup_basic_auth() {
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Configurando Basic Auth para Kiali e Jaeger${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
log_info "Criando secret basic-auth..."
|
|
|
|
# Verificar se htpasswd está disponível
|
|
if ! command -v htpasswd &> /dev/null; then
|
|
log_info "htpasswd não encontrado, usando openssl..."
|
|
# Gerar hash com openssl (compatível com Apache htpasswd)
|
|
local HASH=$(openssl passwd -apr1 "${BASIC_AUTH_PASS}")
|
|
echo "${BASIC_AUTH_USER}:${HASH}" > /tmp/auth
|
|
else
|
|
htpasswd -cb /tmp/auth "${BASIC_AUTH_USER}" "${BASIC_AUTH_PASS}"
|
|
fi
|
|
|
|
kubectl delete secret basic-auth -n istio-system 2>/dev/null || true
|
|
kubectl create secret generic basic-auth -n istio-system --from-file=auth=/tmp/auth
|
|
rm -f /tmp/auth
|
|
|
|
log_success "Secret basic-auth criado"
|
|
}
|
|
|
|
# ============================================================================
|
|
# Configuração de Ingress
|
|
# ============================================================================
|
|
|
|
setup_ingress() {
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Configurando Ingress para Kiali e Jaeger${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
local TLS_ANNOTATION=""
|
|
local TLS_CONFIG=""
|
|
|
|
if [[ "$USE_LETSENCRYPT" == "true" ]]; then
|
|
TLS_ANNOTATION="cert-manager.io/cluster-issuer: letsencrypt-prod"
|
|
fi
|
|
|
|
log_info "Criando Ingress para Kiali..."
|
|
if [[ "$USE_LETSENCRYPT" == "true" ]]; then
|
|
TLS_CONFIG="tls:
|
|
- hosts:
|
|
- ${KIALI_HOST}
|
|
secretName: kiali-tls"
|
|
fi
|
|
export KIALI_HOST TLS_ANNOTATION TLS_CONFIG
|
|
envsubst '${KIALI_HOST} ${TLS_ANNOTATION} ${TLS_CONFIG}' < "${SCRIPT_DIR}/k8s/ingress-kiali.yaml" | kubectl apply -f -
|
|
log_success "Ingress do Kiali criado"
|
|
|
|
log_info "Criando Ingress para Jaeger..."
|
|
if [[ "$USE_LETSENCRYPT" == "true" ]]; then
|
|
TLS_CONFIG="tls:
|
|
- hosts:
|
|
- ${JAEGER_HOST}
|
|
secretName: jaeger-tls"
|
|
else
|
|
TLS_CONFIG=""
|
|
fi
|
|
export JAEGER_HOST TLS_ANNOTATION TLS_CONFIG
|
|
envsubst '${JAEGER_HOST} ${TLS_ANNOTATION} ${TLS_CONFIG}' < "${SCRIPT_DIR}/k8s/ingress-jaeger.yaml" | kubectl apply -f -
|
|
log_success "Ingress do Jaeger criado"
|
|
}
|
|
|
|
setup_app_ingress() {
|
|
echo ""
|
|
log_info "Criando Ingress para App..."
|
|
|
|
local TLS_ANNOTATION=""
|
|
local TLS_CONFIG=""
|
|
|
|
if [[ "$USE_LETSENCRYPT" == "true" ]]; then
|
|
TLS_ANNOTATION="cert-manager.io/cluster-issuer: letsencrypt-prod"
|
|
TLS_CONFIG="tls:
|
|
- hosts:
|
|
- ${APP_HOST}
|
|
secretName: app-tls"
|
|
fi
|
|
|
|
export APP_HOST TLS_ANNOTATION TLS_CONFIG
|
|
envsubst '${APP_HOST} ${TLS_ANNOTATION} ${TLS_CONFIG}' < "${SCRIPT_DIR}/k8s/ingress-app.yaml" | kubectl apply -f -
|
|
log_success "Ingress do App criado"
|
|
}
|
|
|
|
# ============================================================================
|
|
# Build e Push das Imagens
|
|
# ============================================================================
|
|
|
|
build_and_push_images() {
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Build e Push das Imagens (ARM64)${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
local IMAGE_BASE="${REGISTRY_HOST}/${REGISTRY_PROJECT}/app-backend"
|
|
|
|
log_info "Build app-backend:v1 (linux/arm64)..."
|
|
docker buildx build --platform linux/arm64 -t "${IMAGE_BASE}:v1" --push "${SCRIPT_DIR}/app-backend/v1"
|
|
log_success "app-backend:v1 construída e enviada"
|
|
|
|
log_info "Build app-backend:v2 (linux/arm64)..."
|
|
docker buildx build --platform linux/arm64 -t "${IMAGE_BASE}:v2" --push "${SCRIPT_DIR}/app-backend/v2"
|
|
log_success "app-backend:v2 construída e enviada"
|
|
}
|
|
|
|
# ============================================================================
|
|
# Deploy da Aplicação
|
|
# ============================================================================
|
|
|
|
create_registry_secret() {
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Criando Secret do Registry${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
log_info "Criando namespace istio..."
|
|
kubectl apply -f "${SCRIPT_DIR}/k8s/namespace.yaml"
|
|
log_success "Namespace criado"
|
|
|
|
log_info "Obtendo credenciais do registry..."
|
|
local CREDS
|
|
if command -v docker-credential-osxkeychain &> /dev/null; then
|
|
CREDS=$(docker-credential-osxkeychain get <<< "${REGISTRY_HOST}" 2>/dev/null || true)
|
|
elif command -v docker-credential-secretservice &> /dev/null; then
|
|
CREDS=$(docker-credential-secretservice get <<< "${REGISTRY_HOST}" 2>/dev/null || true)
|
|
fi
|
|
|
|
if [[ -n "$CREDS" ]]; then
|
|
local USERNAME=$(echo "$CREDS" | jq -r '.Username')
|
|
local PASSWORD=$(echo "$CREDS" | jq -r '.Secret')
|
|
|
|
kubectl delete secret regcred -n istio 2>/dev/null || true
|
|
kubectl create secret docker-registry regcred -n istio \
|
|
--docker-server="${REGISTRY_HOST}" \
|
|
--docker-username="${USERNAME}" \
|
|
--docker-password="${PASSWORD}"
|
|
log_success "Secret regcred criado"
|
|
else
|
|
log_warn "Credenciais não encontradas no credential helper"
|
|
log_info "Tentando criar secret a partir do Docker config..."
|
|
kubectl delete secret regcred -n istio 2>/dev/null || true
|
|
kubectl create secret generic regcred -n istio \
|
|
--from-file=.dockerconfigjson="${HOME}/.docker/config.json" \
|
|
--type=kubernetes.io/dockerconfigjson 2>/dev/null || \
|
|
log_warn "Falha ao criar secret. Faça login no registry: docker login ${REGISTRY_HOST}"
|
|
fi
|
|
}
|
|
|
|
deploy_application() {
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Deploy da Aplicação${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
|
|
log_info "Deploy app-backend v1..."
|
|
export REGISTRY_HOST REGISTRY_PROJECT
|
|
envsubst < "${SCRIPT_DIR}/k8s/deployment-v1.yaml" | kubectl apply -f -
|
|
log_success "v1 implantada"
|
|
|
|
log_info "Deploy app-backend v2..."
|
|
envsubst < "${SCRIPT_DIR}/k8s/deployment-v2.yaml" | kubectl apply -f -
|
|
log_success "v2 implantada"
|
|
|
|
log_info "Criando Service..."
|
|
kubectl apply -f "${SCRIPT_DIR}/k8s/service.yaml"
|
|
log_success "Service criado"
|
|
|
|
log_info "Aplicando DestinationRule..."
|
|
kubectl apply -f "${SCRIPT_DIR}/k8s/destination-rule.yaml"
|
|
log_success "DestinationRule aplicada"
|
|
|
|
log_info "Aplicando Gateway..."
|
|
export APP_HOST
|
|
envsubst < "${SCRIPT_DIR}/k8s/gateway.yaml" | kubectl apply -f -
|
|
log_success "Gateway aplicado"
|
|
|
|
log_info "Aplicando VirtualService (90% v1, 10% v2)..."
|
|
envsubst < "${SCRIPT_DIR}/k8s/virtual-service.yaml" | kubectl apply -f -
|
|
log_success "VirtualService aplicado"
|
|
|
|
log_info "Aguardando pods..."
|
|
kubectl wait --for=condition=available deployment/app-backend-v1 -n istio --timeout=120s
|
|
kubectl wait --for=condition=available deployment/app-backend-v2 -n istio --timeout=120s
|
|
log_success "Pods prontos"
|
|
}
|
|
|
|
create_test_pod() {
|
|
log_info "Criando pod de teste..."
|
|
kubectl run curl-test -n istio --image=curlimages/curl:latest \
|
|
--restart=Never --command -- sleep infinity 2>/dev/null || true
|
|
kubectl wait --for=condition=ready pod/curl-test -n istio --timeout=60s 2>/dev/null || true
|
|
log_success "Pod de teste disponível"
|
|
}
|
|
|
|
# ============================================================================
|
|
# Resumo
|
|
# ============================================================================
|
|
|
|
show_summary() {
|
|
local protocol="http"
|
|
[[ "$USE_LETSENCRYPT" == "true" ]] && protocol="https"
|
|
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Instalação Concluída${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Componentes instalados:${NC}"
|
|
echo " - Istio (istiod + base)"
|
|
echo " - Kiali (dashboard do service mesh)"
|
|
echo " - Jaeger (tracing distribuído)"
|
|
echo " - app-backend v1 e v2"
|
|
echo ""
|
|
if [[ -n "$VICTORIA_METRICS_URL" ]]; then
|
|
echo -e "${GREEN}Métricas:${NC} Victoria Metrics (aula-12)"
|
|
else
|
|
echo -e "${YELLOW}Métricas:${NC} Victoria Metrics não disponível. Instale aula-12."
|
|
fi
|
|
echo ""
|
|
echo -e "${GREEN}URLs:${NC}"
|
|
echo -e " App: ${CYAN}${protocol}://${APP_HOST}${NC}"
|
|
echo -e " Kiali: ${CYAN}${protocol}://${KIALI_HOST}${NC}"
|
|
echo -e " Jaeger: ${CYAN}${protocol}://${JAEGER_HOST}${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Credenciais (Basic Auth para Kiali/Jaeger):${NC}"
|
|
echo -e " Usuário: ${CYAN}${BASIC_AUTH_USER}${NC}"
|
|
echo -e " Senha: ${CYAN}${BASIC_AUTH_PASS}${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Fluxo de Uso:${NC}"
|
|
echo ""
|
|
echo " # 1. Setup"
|
|
echo " ./setup.sh # Deploy com 90% v1, 10% v2"
|
|
echo ""
|
|
echo " # 2. Testar distribuição"
|
|
echo " ./teste-stress.sh # Veja ~90 v1, ~10 v2"
|
|
echo ""
|
|
echo " # 3. Mudar para 50/50 e re-testar"
|
|
echo " kubectl patch virtualservice app-backend -n istio --type='json' \\"
|
|
echo " -p='[{\"op\":\"replace\",\"path\":\"/spec/http/0/route/0/weight\",\"value\":50},"
|
|
echo " {\"op\":\"replace\",\"path\":\"/spec/http/0/route/1/weight\",\"value\":50}]'"
|
|
echo " ./teste-stress.sh"
|
|
echo ""
|
|
echo " # 4. Rollout completo para v2"
|
|
echo " kubectl patch virtualservice app-backend -n istio --type='json' \\"
|
|
echo " -p='[{\"op\":\"replace\",\"path\":\"/spec/http/0/route/0/weight\",\"value\":0},"
|
|
echo " {\"op\":\"replace\",\"path\":\"/spec/http/0/route/1/weight\",\"value\":100}]'"
|
|
echo " ./teste-stress.sh"
|
|
echo ""
|
|
echo -e "${YELLOW}Configure DNS para:${NC}"
|
|
echo " ${APP_HOST} -> IP do Ingress"
|
|
echo " ${KIALI_HOST} -> IP do Ingress"
|
|
echo " ${JAEGER_HOST} -> IP do Ingress"
|
|
echo ""
|
|
}
|
|
|
|
# ============================================================================
|
|
# Execução
|
|
# ============================================================================
|
|
|
|
main() {
|
|
echo ""
|
|
echo -e "${CYAN}╔═══════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${CYAN}║ Aula 14 - Istio Traffic Splitting ║${NC}"
|
|
echo -e "${CYAN}╚═══════════════════════════════════════════════════════════╝${NC}"
|
|
|
|
check_prerequisites
|
|
collect_user_input
|
|
install_istio
|
|
install_observability
|
|
setup_basic_auth
|
|
|
|
# Pausa para configuração de DNS
|
|
local LB_IP
|
|
LB_IP=$(kubectl get svc -n ingress-nginx ingress-nginx-controller \
|
|
-o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || echo "<pendente>")
|
|
|
|
echo ""
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Configure o DNS${NC}"
|
|
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
echo "No seu provedor DNS, crie registros A apontando para ${GREEN}${LB_IP}${NC}:"
|
|
echo ""
|
|
echo -e " ${YELLOW}${APP_HOST}${NC}"
|
|
echo -e " ${YELLOW}${KIALI_HOST}${NC}"
|
|
echo -e " ${YELLOW}${JAEGER_HOST}${NC}"
|
|
echo ""
|
|
if [[ "$USE_LETSENCRYPT" == "true" ]]; then
|
|
echo -e "${YELLOW}⚠ O Let's Encrypt precisa do DNS configurado para emitir o certificado.${NC}"
|
|
else
|
|
echo -e "${YELLOW}⚠ Configure o DNS agora antes de continuar.${NC}"
|
|
fi
|
|
echo ""
|
|
echo -n "Pressione ENTER quando o DNS estiver configurado..."
|
|
read -r
|
|
|
|
setup_ingress
|
|
build_and_push_images
|
|
create_registry_secret
|
|
deploy_application
|
|
setup_app_ingress
|
|
create_test_pod
|
|
show_summary
|
|
}
|
|
|
|
main "$@"
|