部署Web应用 #

一、应用架构 #

本案例部署一个典型的三层Web应用。

text
应用架构
    │
    ├── 前端层
    │   └── Nginx静态页面
    │
    ├── 后端层
    │   └── API服务
    │
    └── 数据层
        └── MySQL数据库

二、命名空间创建 #

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: webapp
  labels:
    app: webapp
bash
kubectl apply -f namespace.yaml

三、部署数据库 #

3.1 创建Secret #

yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: webapp
type: Opaque
stringData:
  mysql-root-password: rootpassword
  mysql-user: webapp
  mysql-password: webapppassword

3.2 创建PVC #

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: webapp
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

3.3 部署MySQL #

yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: webapp
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-root-password
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-user
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-password
        - name: MYSQL_DATABASE
          value: webapp
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
        livenessProbe:
          exec:
            command:
            - mysqladmin
            - ping
            - -h
            - localhost
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command:
            - mysql
            - -h
            - 127.0.0.1
            - -e
            - SELECT 1
          initialDelaySeconds: 5
          periodSeconds: 2
        resources:
          requests:
            cpu: 100m
            memory: 256Mi
          limits:
            cpu: 500m
            memory: 512Mi
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: mysql-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: webapp
spec:
  selector:
    app: mysql
  ports:
  - port: 3306
    targetPort: 3306

四、部署后端API #

4.1 创建ConfigMap #

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: api-config
  namespace: webapp
data:
  DB_HOST: mysql
  DB_PORT: "3306"
  DB_NAME: webapp

4.2 部署API服务 #

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: webapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: node:18-alpine
        command: ["node", "server.js"]
        workingDir: /app
        env:
        - name: DB_HOST
          valueFrom:
            configMapKeyRef:
              name: api-config
              key: DB_HOST
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-user
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-password
        ports:
        - containerPort: 3000
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 200m
            memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
  name: api
  namespace: webapp
spec:
  selector:
    app: api
  ports:
  - port: 3000
    targetPort: 3000

五、部署前端 #

5.1 创建Nginx配置 #

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: webapp
data:
  nginx.conf: |
    events {
      worker_connections 1024;
    }
    http {
      server {
        listen 80;
        location / {
          root /usr/share/nginx/html;
          index index.html;
          try_files $uri $uri/ /index.html;
        }
        location /api {
          proxy_pass http://api:3000;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
        }
      }
    }

5.2 部署前端 #

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: webapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            cpu: 50m
            memory: 64Mi
          limits:
            cpu: 100m
            memory: 128Mi
      volumes:
      - name: config
        configMap:
          name: nginx-config
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
  namespace: webapp
spec:
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 80

六、配置Ingress #

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp-ingress
  namespace: webapp
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: webapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend
            port:
              number: 80

七、完整部署脚本 #

bash
#!/bin/bash
# deploy.sh

echo "Creating namespace..."
kubectl apply -f namespace.yaml

echo "Deploying database..."
kubectl apply -f mysql-secret.yaml
kubectl apply -f mysql-pvc.yaml
kubectl apply -f mysql-statefulset.yaml

echo "Waiting for MySQL to be ready..."
kubectl wait --for=condition=ready pod -l app=mysql -n webapp --timeout=300s

echo "Deploying API..."
kubectl apply -f api-config.yaml
kubectl apply -f api-deployment.yaml

echo "Waiting for API to be ready..."
kubectl wait --for=condition=ready pod -l app=api -n webapp --timeout=300s

echo "Deploying frontend..."
kubectl apply -f nginx-config.yaml
kubectl apply -f frontend-deployment.yaml

echo "Configuring Ingress..."
kubectl apply -f ingress.yaml

echo "Deployment completed!"
kubectl get all -n webapp

八、验证部署 #

8.1 检查状态 #

bash
# 查看所有资源
kubectl get all -n webapp

# 查看Pod状态
kubectl get pods -n webapp

# 查看服务状态
kubectl get svc -n webapp

# 查看Ingress
kubectl get ingress -n webapp

8.2 测试访问 #

bash
# 获取Ingress地址
kubectl get ingress -n webapp

# 测试前端
curl -H "Host: webapp.example.com" http://<ingress-ip>

# 测试API
curl -H "Host: webapp.example.com" http://<ingress-ip>/api/health

九、扩缩容 #

9.1 手动扩容 #

bash
# 扩容API
kubectl scale deployment api --replicas=5 -n webapp

# 扩容前端
kubectl scale deployment frontend --replicas=3 -n webapp

9.2 自动扩容 #

yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
  namespace: webapp
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

十、清理资源 #

bash
# 删除所有资源
kubectl delete namespace webapp

# 或逐个删除
kubectl delete -f ingress.yaml
kubectl delete -f frontend-deployment.yaml
kubectl delete -f api-deployment.yaml
kubectl delete -f mysql-statefulset.yaml
kubectl delete -f mysql-pvc.yaml
kubectl delete -f mysql-secret.yaml
kubectl delete -f namespace.yaml

十一、总结 #

本案例展示了完整的Web应用部署流程:

组件 资源类型 说明
数据库 StatefulSet 有状态应用
API Deployment 无状态应用
前端 Deployment 无状态应用
Ingress Ingress 外部访问入口

下一步 #

让我们学习 部署数据库,深入了解有状态应用的部署方法。

最后更新:2026-03-28