#!/bin/bash # Envoy 快速部署脚本 # 用途:自动化部署 Envoy Gateway 到 Kubernetes set -e # 配置 NAMESPACE="${NAMESPACE:-juwan}" RELEASE_NAME="${RELEASE_NAME:-envoy-gateway}" TIMEOUT="${TIMEOUT:-300s}" CONTEXT="${CONTEXT:-}" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 日志函数 log_info() { echo -e "${BLUE}ℹ${NC} $1" } log_success() { echo -e "${GREEN}✓${NC} $1" } log_warn() { echo -e "${YELLOW}⚠${NC} $1" } log_error() { echo -e "${RED}✗${NC} $1" } # 检查依赖 check_dependencies() { log_info "检查依赖..." local missing_deps=() if ! command -v kubectl &> /dev/null; then missing_deps+=("kubectl") fi if ! command -v openssl &> /dev/null; then missing_deps+=("openssl") fi if [ ${#missing_deps[@]} -gt 0 ]; then log_error "缺少以下依赖: ${missing_deps[*]}" return 1 fi log_success "所有依赖已安装" return 0 } # 生成 TLS 证书 generate_tls_cert() { log_info "生成 TLS 证书..." local cert_dir="certs" local key_file="$cert_dir/tls.key" local cert_file="$cert_dir/tls.crt" # 创建 certs 目录 mkdir -p "$cert_dir" # 检查是否已存在证书 if [ -f "$cert_file" ] && [ -f "$key_file" ]; then log_warn "证书已存在: $cert_file, $key_file" read -p "是否要重新生成? (y/n) " -t 10 -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_success "使用现有证书" return 0 fi fi # 生成自签名证书(仅用于测试) openssl req -x509 -newkey rsa:4096 \ -keyout "$key_file" \ -out "$cert_file" \ -days 365 -nodes \ -subj "/CN=api.juwan.local" \ -addext "subjectAltName=DNS:api.juwan.local,DNS:*.juwan.local" \ > /dev/null 2>&1 log_success "TLS 证书已生成" log_warn "警告: 这是自签名证书,仅用于测试环境" log_warn "生产环境应使用正式的 CA 签发证书" return 0 } # 创建命名空间 create_namespace() { log_info "创建 Kubernetes 命名空间..." if kubectl get namespace "$NAMESPACE" &> /dev/null; then log_warn "命名空间已存在: $NAMESPACE" return 0 fi kubectl create namespace "$NAMESPACE" log_success "命名空间已创建: $NAMESPACE" return 0 } # 创建 TLS Secret create_tls_secret() { log_info "创建 TLS Secret..." local cert_dir="certs" local key_file="$cert_dir/tls.key" local cert_file="$cert_dir/tls.crt" # 检查证书文件 if [ ! -f "$cert_file" ] || [ ! -f "$key_file" ]; then log_error "证书文件不存在" return 1 fi # 检查 Secret 是否已存在 if kubectl get secret envoy-tls -n "$NAMESPACE" &> /dev/null; then log_warn "Secret 已存在,删除后重建" kubectl delete secret envoy-tls -n "$NAMESPACE" fi # 创建 Secret kubectl create secret tls envoy-tls \ -n "$NAMESPACE" \ --cert="$cert_file" \ --key="$key_file" log_success "TLS Secret 已创建: envoy-tls" return 0 } # 部署 Envoy Gateway deploy_envoy() { log_info "部署 Envoy Gateway..." local manifest_file="deploy/k8s/envoy-gateway.yaml" if [ ! -f "$manifest_file" ]; then log_error "找不到部署清单: $manifest_file" return 1 fi # 应用部署 if [ -n "$CONTEXT" ]; then kubectl apply -f "$manifest_file" --context="$CONTEXT" else kubectl apply -f "$manifest_file" fi log_success "Envoy Gateway 部署清单已应用" return 0 } # 等待部署完成 wait_deployment() { log_info "等待部署完成(超时: $TIMEOUT)..." kubectl rollout status deployment/envoy-gateway \ -n "$NAMESPACE" \ --timeout="$TIMEOUT" || { log_error "部署超时" return 1 } log_success "部署已完成" return 0 } # 验证部署 verify_deployment() { log_info "验证部署..." # 检查 Pod local pod_count=$(kubectl get pods -n "$NAMESPACE" \ -l app=envoy-gateway \ -o jsonpath='{.items | length}') if [ "$pod_count" -eq 0 ]; then log_error "未找到 Envoy 容器" return 1 fi log_success "找到 $pod_count 个 Envoy 容器" # 检查 Service local svc_status=$(kubectl get svc -n "$NAMESPACE" | grep envoy-gateway || echo "") if [ -z "$svc_status" ]; then log_error "未找到 Service" return 1 fi log_success "Service 已创建" # 显示 LoadBalancer IP log_info "等待 LoadBalancer IP..." local lb_ip="" for i in {1..30}; do lb_ip=$(kubectl get svc envoy-gateway -n "$NAMESPACE" \ -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || echo "") if [ -n "$lb_ip" ] && [ "$lb_ip" != "null" ]; then log_success "LoadBalancer IP: $lb_ip" break fi if [ $i -eq 30 ]; then log_warn "未获得 LoadBalancer IP(可能在内网环境或使用 NodePort)" kubectl get svc -n "$NAMESPACE" envoy-gateway break fi sleep 2 done return 0 } # 显示部署信息 show_summary() { log_info "部署摘要" echo "" echo " Namespace: $NAMESPACE" echo " Release: $RELEASE_NAME" echo "" echo " Pods:" kubectl get pods -n "$NAMESPACE" -l app=envoy-gateway \ -o custom-columns=NAME:.metadata.name,STATUS:.status.phase,IP:.status.podIP \ | sed 's/^/ /' echo "" echo " Service:" kubectl get svc -n "$NAMESPACE" envoy-gateway \ -o custom-columns=NAME:.metadata.name,TYPE:.spec.type,IP:.spec.clusterIP,EXTERNAL_IP:.status.loadBalancer.ingress[0].ip \ | sed 's/^/ /' echo "" echo " 后续步骤:" echo " 1. 在 User RPC 中暴露 JWKS 端点 (/.well-known/jwks.json)" echo " 2. 配置 JWT_SECRET_KEY 环境变量" echo " 3. 测试 JWT 验证: curl -k https:///api/v1/users/login" echo "" echo " 文档:" echo " - 配置指南: deploy/envoy/ENVOY_CONFIG_GUIDE.md" echo " - 快速参考: deploy/envoy/QUICK_REFERENCE.md" echo "" } # 清理部署 cleanup() { log_warn "清理 Envoy Gateway..." kubectl delete -f deploy/k8s/envoy-gateway.yaml -n "$NAMESPACE" || true kubectl delete secret envoy-tls -n "$NAMESPACE" || true log_success "清理完成" } # 主函数 main() { echo "" echo -e "${BLUE}╔════════════════════════════════════════╗${NC}" echo -e "${BLUE}║ Envoy Gateway 快速部署脚本 ║${NC}" echo -e "${BLUE}╚════════════════════════════════════════╝${NC}" echo "" # 解析命令行参数 local cmd="${1:-deploy}" case "$cmd" in deploy) check_dependencies || exit 1 generate_tls_cert || exit 1 create_namespace || exit 1 create_tls_secret || exit 1 deploy_envoy || exit 1 wait_deployment || exit 1 verify_deployment || exit 1 show_summary log_success "Envoy Gateway 已成功部署!" ;; cleanup) cleanup ;; status) log_info "部署状态" kubectl get all -n "$NAMESPACE" -l app=envoy-gateway ;; logs) log_info "Envoy 日志" kubectl logs -n "$NAMESPACE" -l app=envoy-gateway -f ;; *) echo "用法: $0 <命令>" echo "" echo "命令:" echo " deploy 部署 Envoy Gateway(默认)" echo " cleanup 移除部署" echo " status 查看部署状态" echo " logs 查看 Envoy 日志" echo "" echo "环境变量:" echo " NAMESPACE K8s 命名空间(默认: juwan)" echo " RELEASE_NAME 发布名称(默认: envoy-gateway)" echo " TIMEOUT 部署超时(默认: 300s)" echo " CONTEXT K8s 上下文(可选)" echo "" exit 1 ;; esac echo "" } main "$@"