273 lines
8.0 KiB
Bash
273 lines
8.0 KiB
Bash
#!/bin/bash
|
||
|
||
# Kubernetes 自动部署脚本
|
||
# 用于从私有 Harbor 仓库拉取 NGINX 镜像并部署到 K8s 集群
|
||
|
||
set -e
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 打印带颜色的信息
|
||
print_info() {
|
||
echo -e "${BLUE}[INFO]${NC} $1"
|
||
}
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
}
|
||
|
||
# 检查必要的环境变量
|
||
check_env_vars() {
|
||
print_info "检查环境变量..."
|
||
|
||
required_vars=("HARBOR_REGISTRY" "HARBOR_USERNAME" "HARBOR_PASSWORD" "NGINX_IMAGE_TAG")
|
||
missing_vars=()
|
||
|
||
for var in "${required_vars[@]}"; do
|
||
if [[ -z "${!var}" ]]; then
|
||
missing_vars+=("$var")
|
||
fi
|
||
done
|
||
|
||
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
||
print_error "缺少必要的环境变量:"
|
||
for var in "${missing_vars[@]}"; do
|
||
echo " - $var"
|
||
done
|
||
print_info "请设置以下环境变量:"
|
||
echo " export HARBOR_REGISTRY=<你的Harbor仓库地址>"
|
||
echo " export HARBOR_USERNAME=<Harbor用户名>"
|
||
echo " export HARBOR_PASSWORD=<Harbor密码>"
|
||
echo " export NGINX_IMAGE_TAG=<镜像标签,如: \${GITHUB_SHA} 或 latest>"
|
||
exit 1
|
||
fi
|
||
|
||
print_success "环境变量检查通过"
|
||
}
|
||
|
||
# 检查 kubectl 连接
|
||
check_kubectl() {
|
||
print_info "检查 kubectl 连接..."
|
||
|
||
if ! command -v kubectl &> /dev/null; then
|
||
print_error "kubectl 未安装或不在 PATH 中"
|
||
exit 1
|
||
fi
|
||
|
||
if ! kubectl cluster-info &> /dev/null; then
|
||
print_error "无法连接到 Kubernetes 集群"
|
||
print_info "请确保:"
|
||
echo " 1. kubectl 已正确配置"
|
||
echo " 2. 能够访问 Kubernetes 集群"
|
||
echo " 3. 当前用户有适当的权限"
|
||
exit 1
|
||
fi
|
||
|
||
print_success "kubectl 连接正常"
|
||
kubectl cluster-info
|
||
}
|
||
|
||
# 创建命名空间(如果不存在)
|
||
create_namespace() {
|
||
local namespace=${1:-default}
|
||
print_info "检查命名空间: $namespace"
|
||
|
||
if kubectl get namespace "$namespace" &> /dev/null; then
|
||
print_success "命名空间 '$namespace' 已存在"
|
||
else
|
||
print_info "创建命名空间: $namespace"
|
||
kubectl create namespace "$namespace"
|
||
print_success "命名空间 '$namespace' 创建成功"
|
||
fi
|
||
}
|
||
|
||
# 创建或更新 Harbor 仓库访问凭据
|
||
create_harbor_secret() {
|
||
local namespace=${1:-default}
|
||
print_info "创建/更新 Harbor 仓库访问凭据..."
|
||
|
||
# 删除已存在的 secret(如果存在)
|
||
kubectl delete secret harbor-registry-secret -n "$namespace" --ignore-not-found=true
|
||
|
||
# 创建新的 secret
|
||
kubectl create secret docker-registry harbor-registry-secret \
|
||
--docker-server="$HARBOR_REGISTRY" \
|
||
--docker-username="$HARBOR_USERNAME" \
|
||
--docker-password="$HARBOR_PASSWORD" \
|
||
--namespace="$namespace"
|
||
|
||
print_success "Harbor 仓库访问凭据创建成功"
|
||
}
|
||
|
||
# 更新部署文件中的镜像标签
|
||
update_deployment_image() {
|
||
local deployment_file="$1"
|
||
local image_tag="$2"
|
||
|
||
print_info "更新部署文件中的镜像标签: $image_tag"
|
||
|
||
# 使用镜像完整路径
|
||
local full_image="${HARBOR_REGISTRY}/test/nginx:${image_tag}"
|
||
print_info "使用镜像: $full_image"
|
||
|
||
# 备份原文件
|
||
cp "$deployment_file" "${deployment_file}.bak"
|
||
|
||
# 使用 sed 替换环境变量,替换 $HARBOR_REGISTRY 和 $NGINX_IMAGE_TAG
|
||
sed -i.tmp "s|\$HARBOR_REGISTRY|${HARBOR_REGISTRY}|g" "$deployment_file"
|
||
sed -i.tmp "s|\$NGINX_IMAGE_TAG|${image_tag}|g" "$deployment_file"
|
||
|
||
# 如果有其他环境变量需要替换,可以继续添加类似的 sed 命令
|
||
# 例如:sed -i.tmp "s|\$NAMESPACE|${NAMESPACE}|g" "$deployment_file"
|
||
|
||
# 清理临时文件
|
||
rm -f "${deployment_file}.tmp"
|
||
|
||
print_success "镜像标签和环境变量替换完成,使用镜像: $full_image"
|
||
}
|
||
|
||
# 应用 Kubernetes 配置
|
||
apply_k8s_config() {
|
||
local deployment_file="$1"
|
||
print_info "应用 Kubernetes 配置..."
|
||
|
||
if [[ ! -f "$deployment_file" ]]; then
|
||
print_error "部署文件不存在: $deployment_file"
|
||
exit 1
|
||
fi
|
||
|
||
kubectl apply -f "$deployment_file"
|
||
print_success "Kubernetes 配置应用成功"
|
||
}
|
||
|
||
# 等待部署就绪
|
||
wait_for_deployment() {
|
||
local deployment_name="nginx-deployment"
|
||
local namespace=${1:-default}
|
||
local timeout=${2:-300}
|
||
|
||
print_info "等待部署就绪..."
|
||
|
||
if kubectl wait --for=condition=available deployment/"$deployment_name" \
|
||
--namespace="$namespace" --timeout="${timeout}s"; then
|
||
print_success "部署已就绪"
|
||
else
|
||
print_error "部署超时,请检查部署状态"
|
||
kubectl describe deployment "$deployment_name" -n "$namespace"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 显示部署状态
|
||
show_deployment_status() {
|
||
local namespace=${1:-default}
|
||
print_info "部署状态:"
|
||
|
||
echo
|
||
echo "=== Pods ==="
|
||
kubectl get pods -l app=nginx -n "$namespace" -o wide
|
||
|
||
echo
|
||
echo "=== Services ==="
|
||
kubectl get services -l app=nginx -n "$namespace"
|
||
|
||
echo
|
||
echo "=== Deployments ==="
|
||
kubectl get deployments -l app=nginx -n "$namespace"
|
||
|
||
echo
|
||
echo "=== HPA ==="
|
||
kubectl get hpa -l app=nginx -n "$namespace" 2>/dev/null || echo "HPA 未启用"
|
||
|
||
echo
|
||
echo "=== Events ==="
|
||
kubectl get events --sort-by=.metadata.creationTimestamp -n "$namespace" | tail -10
|
||
}
|
||
|
||
# 获取访问信息
|
||
get_access_info() {
|
||
local namespace=${1:-default}
|
||
print_info "获取访问信息..."
|
||
|
||
local service_type=$(kubectl get service nginx-service -n "$namespace" -o jsonpath='{.spec.type}')
|
||
|
||
case "$service_type" in
|
||
"NodePort")
|
||
local node_port=$(kubectl get service nginx-service -n "$namespace" -o jsonpath='{.spec.ports[0].nodePort}')
|
||
local node_ip=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="ExternalIP")].address}')
|
||
if [[ -z "$node_ip" ]]; then
|
||
node_ip=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
|
||
fi
|
||
print_success "NodePort 访问地址: http://${node_ip}:${node_port}"
|
||
;;
|
||
"LoadBalancer")
|
||
print_info "等待 LoadBalancer 外部 IP..."
|
||
local external_ip=$(kubectl get service nginx-service -n "$namespace" -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||
if [[ -n "$external_ip" ]]; then
|
||
print_success "LoadBalancer 访问地址: http://${external_ip}"
|
||
else
|
||
print_warning "LoadBalancer 外部 IP 仍在分配中"
|
||
fi
|
||
;;
|
||
"ClusterIP")
|
||
local cluster_ip=$(kubectl get service nginx-service -n "$namespace" -o jsonpath='{.spec.clusterIP}')
|
||
print_success "ClusterIP 访问地址: http://${cluster_ip}"
|
||
print_info "注意: ClusterIP 只能在集群内部访问"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
print_info "开始 NGINX Kubernetes 自动部署..."
|
||
|
||
# 设置默认值
|
||
local namespace=${NAMESPACE:-default}
|
||
local deployment_file=${DEPLOYMENT_FILE:-./nginx-deployment.yaml}
|
||
local image_tag=${NGINX_IMAGE_TAG:-latest}
|
||
|
||
# 执行部署步骤
|
||
check_env_vars
|
||
check_kubectl
|
||
create_namespace "$namespace"
|
||
create_harbor_secret "$namespace"
|
||
|
||
update_deployment_image "$deployment_file" "$image_tag"
|
||
apply_k8s_config "$deployment_file"
|
||
wait_for_deployment "$namespace"
|
||
show_deployment_status "$namespace"
|
||
get_access_info "$namespace"
|
||
|
||
print_success "🎉 NGINX 部署完成!"
|
||
}
|
||
|
||
# 清理函数
|
||
cleanup() {
|
||
print_info "执行清理操作..."
|
||
# 恢复备份文件
|
||
if [[ -f "./nginx-deployment.yaml.bak" ]]; then
|
||
mv "./nginx-deployment.yaml.bak" "./nginx-deployment.yaml"
|
||
fi
|
||
}
|
||
|
||
# 设置清理陷阱
|
||
trap cleanup EXIT
|
||
|
||
# 如果直接运行此脚本
|
||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||
main "$@"
|
||
fi
|