539 lines
14 KiB
Bash
Executable File
539 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
||
set -e
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||
CONFIG_FILE="$PROJECT_DIR/config/cluster-vars.yml"
|
||
|
||
echo "=== 推送Nginx测试应用到Gitea ==="
|
||
|
||
# 读取配置
|
||
GITEA_USER=$(yq eval '.gitea_user_name' "$CONFIG_FILE")
|
||
GITEA_PASSWORD=$(yq eval '.gitea_user_password' "$CONFIG_FILE")
|
||
GITEA_ORG=$(yq eval '.gitea_org_name' "$CONFIG_FILE")
|
||
NGINX_REPO=$(yq eval '.nginx_app_repo_name' "$CONFIG_FILE")
|
||
NGINX_DOMAIN=$(yq eval '.nginx_app_domain' "$CONFIG_FILE")
|
||
|
||
# 获取Gitea NodePort
|
||
GITEA_NODEPORT=$(kubectl get svc gitea-http -n gitea -o jsonpath='{.spec.ports[0].nodePort}')
|
||
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
|
||
|
||
GITEA_URL="http://$NODE_IP:$GITEA_NODEPORT"
|
||
REPO_URL="$GITEA_URL/$GITEA_ORG/$NGINX_REPO.git"
|
||
|
||
# 创建临时目录
|
||
TEMP_DIR=$(mktemp -d)
|
||
cd "$TEMP_DIR"
|
||
|
||
echo "📝 创建Nginx应用清单..."
|
||
|
||
# 创建manifests目录
|
||
mkdir -p manifests
|
||
|
||
# 创建Nginx Deployment
|
||
cat > manifests/deployment.yaml <<EOF
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: nginx-test
|
||
namespace: default
|
||
labels:
|
||
app: nginx-test
|
||
spec:
|
||
replicas: 2
|
||
selector:
|
||
matchLabels:
|
||
app: nginx-test
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: nginx-test
|
||
spec:
|
||
containers:
|
||
- name: nginx
|
||
image: nginx:1.25-alpine
|
||
ports:
|
||
- containerPort: 80
|
||
name: http
|
||
volumeMounts:
|
||
- name: nginx-config
|
||
mountPath: /etc/nginx/conf.d/default.conf
|
||
subPath: default.conf
|
||
- name: html
|
||
mountPath: /usr/share/nginx/html
|
||
resources:
|
||
requests:
|
||
memory: "64Mi"
|
||
cpu: "100m"
|
||
limits:
|
||
memory: "128Mi"
|
||
cpu: "200m"
|
||
livenessProbe:
|
||
httpGet:
|
||
path: /
|
||
port: 80
|
||
initialDelaySeconds: 10
|
||
periodSeconds: 10
|
||
readinessProbe:
|
||
httpGet:
|
||
path: /
|
||
port: 80
|
||
initialDelaySeconds: 5
|
||
periodSeconds: 5
|
||
volumes:
|
||
- name: nginx-config
|
||
configMap:
|
||
name: nginx-config
|
||
- name: html
|
||
configMap:
|
||
name: nginx-html
|
||
EOF
|
||
|
||
# 创建Nginx ConfigMap
|
||
cat > manifests/configmap.yaml <<EOF
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: nginx-config
|
||
namespace: default
|
||
data:
|
||
default.conf: |
|
||
server {
|
||
listen 80;
|
||
server_name ${NGINX_DOMAIN};
|
||
|
||
location / {
|
||
root /usr/share/nginx/html;
|
||
index index.html;
|
||
}
|
||
|
||
location /health {
|
||
access_log off;
|
||
return 200 "healthy\n";
|
||
add_header Content-Type text/plain;
|
||
}
|
||
}
|
||
---
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: nginx-html
|
||
namespace: default
|
||
data:
|
||
index.html: |
|
||
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Nginx Test - GitOps Demo</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
min-height: 100vh;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 20px;
|
||
}
|
||
.container {
|
||
background: white;
|
||
border-radius: 20px;
|
||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||
padding: 60px;
|
||
max-width: 800px;
|
||
text-align: center;
|
||
}
|
||
h1 {
|
||
color: #667eea;
|
||
font-size: 3em;
|
||
margin-bottom: 20px;
|
||
text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
|
||
}
|
||
.version {
|
||
display: inline-block;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 10px 30px;
|
||
border-radius: 50px;
|
||
font-size: 1.2em;
|
||
font-weight: bold;
|
||
margin: 20px 0;
|
||
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
|
||
}
|
||
.info {
|
||
background: #f8f9fa;
|
||
border-radius: 10px;
|
||
padding: 30px;
|
||
margin: 30px 0;
|
||
text-align: left;
|
||
}
|
||
.info-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
padding: 15px 0;
|
||
border-bottom: 1px solid #e9ecef;
|
||
}
|
||
.info-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.info-label {
|
||
font-weight: bold;
|
||
color: #495057;
|
||
}
|
||
.info-value {
|
||
color: #667eea;
|
||
font-family: 'Courier New', monospace;
|
||
}
|
||
.badge {
|
||
display: inline-block;
|
||
background: #28a745;
|
||
color: white;
|
||
padding: 5px 15px;
|
||
border-radius: 20px;
|
||
font-size: 0.9em;
|
||
margin: 10px 5px;
|
||
}
|
||
.footer {
|
||
margin-top: 30px;
|
||
color: #6c757d;
|
||
font-size: 0.9em;
|
||
}
|
||
.emoji {
|
||
font-size: 3em;
|
||
margin-bottom: 20px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="emoji">🚀</div>
|
||
<h1>Nginx Test Application</h1>
|
||
<div class="version">Version: v1.0</div>
|
||
|
||
<div class="info">
|
||
<div class="info-item">
|
||
<span class="info-label">域名:</span>
|
||
<span class="info-value">${NGINX_DOMAIN}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">应用名称:</span>
|
||
<span class="info-value">nginx-test</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">镜像:</span>
|
||
<span class="info-value">nginx:1.25-alpine</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">副本数:</span>
|
||
<span class="info-value">2</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">部署方式:</span>
|
||
<span class="info-value">GitOps (ArgoCD)</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<span class="badge">✓ Kubernetes</span>
|
||
<span class="badge">✓ GitOps</span>
|
||
<span class="badge">✓ ArgoCD</span>
|
||
<span class="badge">✓ Nginx</span>
|
||
</div>
|
||
|
||
<div class="footer">
|
||
<p>🎯 这是一个通过GitOps自动部署的Nginx测试应用</p>
|
||
<p>修改Git仓库中的配置,ArgoCD会自动同步部署</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
EOF
|
||
|
||
# 创建Service
|
||
cat > manifests/service.yaml <<EOF
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: nginx-test
|
||
namespace: default
|
||
labels:
|
||
app: nginx-test
|
||
spec:
|
||
type: ClusterIP
|
||
selector:
|
||
app: nginx-test
|
||
ports:
|
||
- port: 80
|
||
targetPort: 80
|
||
protocol: TCP
|
||
name: http
|
||
EOF
|
||
|
||
# 创建Ingress
|
||
cat > manifests/ingress.yaml <<EOF
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: Ingress
|
||
metadata:
|
||
name: nginx-test
|
||
namespace: default
|
||
annotations:
|
||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||
spec:
|
||
ingressClassName: nginx
|
||
tls:
|
||
- hosts:
|
||
- ${NGINX_DOMAIN}
|
||
secretName: nginx-test-tls
|
||
rules:
|
||
- host: ${NGINX_DOMAIN}
|
||
http:
|
||
paths:
|
||
- path: /
|
||
pathType: Prefix
|
||
backend:
|
||
service:
|
||
name: nginx-test
|
||
port:
|
||
number: 80
|
||
EOF
|
||
|
||
# 创建README
|
||
cat > README.md <<EOF
|
||
# Nginx Test Application
|
||
|
||
这是一个由ArgoCD管理的Nginx测试应用,用于演示GitOps自动化部署。
|
||
|
||
## 应用信息
|
||
|
||
- **应用名称**: nginx-test
|
||
- **镜像**: nginx:1.25-alpine
|
||
- **副本数**: 2
|
||
- **域名**: ${NGINX_DOMAIN}
|
||
- **命名空间**: default
|
||
|
||
## 架构说明
|
||
|
||
\`\`\`
|
||
Git仓库 (Gitea) → ArgoCD监控 → 自动同步 → K3s集群部署
|
||
\`\`\`
|
||
|
||
## 访问方式
|
||
|
||
### 通过域名访问(推荐)
|
||
\`\`\`bash
|
||
curl https://${NGINX_DOMAIN}
|
||
\`\`\`
|
||
|
||
### 通过NodePort访问
|
||
\`\`\`bash
|
||
# 获取Service信息
|
||
kubectl get svc nginx-test -n default
|
||
|
||
# 访问应用
|
||
curl http://<NODE_IP>:<NODE_PORT>
|
||
\`\`\`
|
||
|
||
## 更新应用
|
||
|
||
### 方式1: 修改版本号
|
||
编辑 \`manifests/configmap.yaml\` 中的 HTML 内容,修改版本号:
|
||
\`\`\`html
|
||
<div class="version">Version: v2.0</div>
|
||
\`\`\`
|
||
|
||
### 方式2: 修改副本数
|
||
编辑 \`manifests/deployment.yaml\`:
|
||
\`\`\`yaml
|
||
spec:
|
||
replicas: 3 # 修改副本数
|
||
\`\`\`
|
||
|
||
### 方式3: 更新Nginx配置
|
||
编辑 \`manifests/configmap.yaml\` 中的 nginx 配置。
|
||
|
||
提交更改后,ArgoCD会在3分钟内自动检测并部署新版本。
|
||
|
||
## 监控部署状态
|
||
|
||
\`\`\`bash
|
||
# 查看ArgoCD Application状态
|
||
kubectl get application nginx-app -n argocd
|
||
|
||
# 查看Pod状态
|
||
kubectl get pods -l app=nginx-test -n default
|
||
|
||
# 查看Ingress状态
|
||
kubectl get ingress nginx-test -n default
|
||
|
||
# 查看应用日志
|
||
kubectl logs -l app=nginx-test -n default --tail=50
|
||
\`\`\`
|
||
|
||
## 健康检查
|
||
|
||
应用提供了健康检查端点:
|
||
\`\`\`bash
|
||
curl https://${NGINX_DOMAIN}/health
|
||
\`\`\`
|
||
|
||
## 故障排查
|
||
|
||
### 检查Pod状态
|
||
\`\`\`bash
|
||
kubectl describe pod -l app=nginx-test -n default
|
||
\`\`\`
|
||
|
||
### 检查Ingress
|
||
\`\`\`bash
|
||
kubectl describe ingress nginx-test -n default
|
||
\`\`\`
|
||
|
||
### 检查ArgoCD同步状态
|
||
\`\`\`bash
|
||
kubectl describe application nginx-app -n argocd
|
||
\`\`\`
|
||
|
||
## GitOps工作流
|
||
|
||
1. 开发者修改 \`manifests/\` 目录下的配置文件
|
||
2. 提交并推送到Git仓库
|
||
3. ArgoCD自动检测到变化(每3分钟轮询一次)
|
||
4. ArgoCD自动同步并部署到K3s集群
|
||
5. 应用自动更新,无需手动执行kubectl命令
|
||
|
||
## 回滚操作
|
||
|
||
如果需要回滚到之前的版本:
|
||
\`\`\`bash
|
||
# 查看Git历史
|
||
git log --oneline
|
||
|
||
# 回滚到指定commit
|
||
git revert <commit-hash>
|
||
git push
|
||
|
||
# 或者通过ArgoCD UI进行回滚
|
||
\`\`\`
|
||
|
||
## 技术栈
|
||
|
||
- **容器编排**: Kubernetes (K3s)
|
||
- **Web服务器**: Nginx 1.25
|
||
- **GitOps工具**: ArgoCD
|
||
- **Git仓库**: Gitea
|
||
- **Ingress控制器**: Nginx Ingress Controller
|
||
- **证书管理**: cert-manager (Let's Encrypt)
|
||
|
||
## 注意事项
|
||
|
||
1. 确保DNS已正确配置,${NGINX_DOMAIN} 指向K3s集群节点IP
|
||
2. 首次访问HTTPS可能需要等待证书签发(约1-2分钟)
|
||
3. ArgoCD默认每3分钟检查一次Git仓库更新
|
||
4. 可以通过ArgoCD UI手动触发同步以立即部署更改
|
||
|
||
## 相关链接
|
||
|
||
- ArgoCD Dashboard: https://argocd.jpc.net3w.com
|
||
- Gitea Repository: http://<NODE_IP>:<GITEA_PORT>/k3s-apps/nginx-app
|
||
- Application URL: https://${NGINX_DOMAIN}
|
||
EOF
|
||
|
||
# 创建更新脚本
|
||
cat > update-app.sh <<'SCRIPT_EOF'
|
||
#!/bin/bash
|
||
set -e
|
||
|
||
VERSION=${1:-v2.0}
|
||
|
||
echo "🔄 更新Nginx应用到版本 $VERSION"
|
||
|
||
# 修改版本号
|
||
sed -i "s/Version: v[0-9.]*/Version: $VERSION/" manifests/configmap.yaml
|
||
|
||
# 根据版本修改背景色
|
||
case $VERSION in
|
||
v1.0)
|
||
COLOR="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
||
;;
|
||
v2.0)
|
||
COLOR="linear-gradient(135deg, #f093fb 0%, #f5576c 100%)"
|
||
;;
|
||
v3.0)
|
||
COLOR="linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)"
|
||
;;
|
||
*)
|
||
COLOR="linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)"
|
||
;;
|
||
esac
|
||
|
||
sed -i "s|background: linear-gradient([^)]*)|background: $COLOR|" manifests/configmap.yaml
|
||
|
||
# 提交更改
|
||
git add manifests/configmap.yaml
|
||
git commit -m "Update nginx-app to $VERSION
|
||
|
||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||
git push
|
||
|
||
echo "✅ 更新完成!"
|
||
echo "⏳ 等待ArgoCD同步(约3分钟)..."
|
||
echo "🌐 访问 https://ng.jpc.net3w.com 查看更新"
|
||
SCRIPT_EOF
|
||
|
||
chmod +x update-app.sh
|
||
|
||
# 初始化Git仓库
|
||
echo "🔧 初始化Git仓库..."
|
||
git init -b main
|
||
git config user.name "$GITEA_USER"
|
||
git config user.email "$GITEA_USER@example.com"
|
||
git add .
|
||
git commit -m "Initial commit: Add nginx test application
|
||
|
||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||
|
||
# 推送到Gitea
|
||
echo "📤 推送到Gitea..."
|
||
git remote add origin "$REPO_URL"
|
||
|
||
# URL encode the password to handle special characters
|
||
ENCODED_PASSWORD=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$GITEA_PASSWORD'))")
|
||
git push -u origin main || {
|
||
echo "⚠️ 首次推送失败,尝试使用凭证..."
|
||
git remote set-url origin "http://$GITEA_USER:$ENCODED_PASSWORD@$NODE_IP:$GITEA_NODEPORT/$GITEA_ORG/$NGINX_REPO.git"
|
||
git push -u origin main
|
||
}
|
||
|
||
# 清理
|
||
cd "$PROJECT_DIR"
|
||
rm -rf "$TEMP_DIR"
|
||
|
||
echo ""
|
||
echo "✅ Nginx测试应用推送成功!"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo "📊 仓库信息:"
|
||
echo " - 仓库地址: $REPO_URL"
|
||
echo " - Gitea访问: $GITEA_URL/$GITEA_ORG/$NGINX_REPO"
|
||
echo ""
|
||
echo "🌐 应用信息:"
|
||
echo " - 域名: https://${NGINX_DOMAIN}"
|
||
echo " - 应用名称: nginx-test"
|
||
echo " - 命名空间: default"
|
||
echo ""
|
||
echo "📝 下一步:"
|
||
echo " 1. 运行: ./scripts/create-nginx-argocd-app.sh"
|
||
echo " 2. 等待ArgoCD同步(约3分钟)"
|
||
echo " 3. 访问: https://${NGINX_DOMAIN}"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|