K8S部署LNMP架构 ECShop

K8s 中部署 LNMP 架构 ECShop 电商

项目需求

在 K8s 中部署 LNMP 架构 ECShop 电商。

  1. 部署 NFS 服务器,提供共享目录 /ecshop

  2. 部署 NFS 动态卷制备,存储类型 ecshop

  3. 电商相关资源部署在 ecshop 命名空间

  4. 为 ecshop 命名空间设置 Quota:

    • cpu: "4"
    • memory: 8G
    • requests.cpu: "4"
    • requests.memory: 8G
    • requests.storage: 500G
  5. 为 ecshop 命名空间设置 LimitRange:

    • requests.cpu:默认:200m,最小:100m
    • requests.memory:默认:256Mi,最小:256Mi
    • cpu:默认:500m,最大:1
    • memory:默认:512Mi,最大:2048Mi
  6. 部署 mysql 应用:

    • 使用 StatefullSets 部署,基于 mysql:5.7 镜像,副本数1个
    • 存储由 NFS 动态卷制备提供
    • 使用 secret 存储mysql 用户 root 密码,ecshop应用用户名ecshop、密码shizhan@123、数据库ecshop
    • 配置合适的Probe,进行健康监测
    • 额外配置一个 svc,用于暴漏 mysql 应用
  7. 部署 php 应用:

    • 使用 deployment 部署,基于 php:7.2-fpm-ecshop 镜像,副本数1个
    • 配置合适的Probe,进行健康监测
    • 使用 service-clusterIP 暴露
  8. 部署 nginx 应用:

    • 使用 deployment 部署,基于 nginx:1.24 镜像,副本数1个
    • 存储由 NFS 动态卷制备提供
    • 使用 cm 存储 nginx 配置文件,
    • 配置合适的Probe,进行健康监测
    • 配置一个 svc,用于暴漏 ecshop 应用
  9. 部署网络组件:

    • 部署 metallab
    • 部署 ingress,为ingress-nginx控制器提供自谦名证书和私钥,用于后续的应用的https通信
  10. 配置 ingress 规则,通过 https://shop.shizhan.cloud 访问商城。

  11. 部署 Metric Server,针对 php 和 nginx 应用,配置 HPA 规则,最小2个pod,最大5个pod。

  12. 部署 Kubernetes Dashboard 用于监视和管理 Kubernetes 集群,配置 ingress 规则,通过 https://dashboard.shizhan.cloud 访问 Kubernetes Dashboard。

站点架构

Dashboard_GROUP
Nginx_GROUP
PHP_GROUP
MySQL_GROUP
right
NFS服务器

10.1.8.30 /ecshop
PV 动态卷制备
PVC-mysql
ConfigMap: nginx-config
PVC-ecshop
Secret: mysql账号密码
Secret: nginx-tls

通用TLS证书
Statefulset: mysql
Service: mysql HeadLess
Service: mysql ClusterIP
Deployment: php
Service: php ClusterIP
Deployment: nginx
Service: nginx ClusterIP
Deployment: kubernetes-dashboard
Service: kubernetes-dashboard ClusterIP
MetalLB 负载均衡

分配外部LB VIP
Ingress-Nginx Controller

集群入口网关
Ingress规则: shop.shizhan.cloud
Ingress规则: dashboard.shizhan.cloud

步骤 1:部署存储

1.1 部署 NFS 服务

NFS 服务器操作

bash 复制代码
# 安装 NFS 服务
[root@master30 ~]# apt install -y nfs-kernel-server

# 创建共享目录
[root@master30 ~]# mkdir -p -m 777 /ecshop

# 配置 NFS 共享(地址已改为10.1.8.30,允许所有节点访问)
[root@master30 ~]# echo "/ecshop *(rw,sync,no_root_squash,no_all_squash)" >> /etc/exports

# 启动服务
[root@master30 ~]# systemctl restart nfs-server

NFS 客户端操作

bash 复制代码
## 安装 NFS 客户端
[root@worker31-32 ~]# apt install -y nfs-common

## 验证共享
[root@worker31-32 ~]# showmount -e master30
Export list for master30:
/ecshop  *

1.2 部署 NFS provisioner

NFS没有内置制备器,这里我们自定义外部分配器。

bash 复制代码
# 部署 NFS provisioner到命名空间:kube-storage
[root@master30 ~]# kubectl create ns kube-storage

创建 nfs-rbac.yaml 文件,赋予 Provisioner 操作 PV/PVC 的权限。

yaml 复制代码
[root@master30 ~]# cat > nfs-rbac.yaml <<'EOF'
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: kube-storage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: kube-storage
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f nfs-rbac.yaml

部署 NFS Provisioner 应用

yaml 复制代码
[root@master30 ~]# cat > nfs-provisioner.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: kube-storage
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      volumes:
      - name: nfs-client-root
        nfs:
          server: 10.1.8.30  # 同上 NFS 服务器 IP
          path: /ecshop  # 核心:同步改为 /ecshop
      containers:
      - name: nfs-client-provisioner
        image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
        volumeMounts:
        - name: nfs-client-root
          mountPath: /persistentvolumes
        env:
        - name: PROVISIONER_NAME
          value: fuseim.pri/ifs
        - name: NFS_SERVER
          value: 10.1.8.30  # 替换为你的 NFS 服务器 IP
        - name: NFS_PATH
          value: /ecshop  # 核心:共享路径改为 /ecshop
EOF
bash 复制代码
#  部署 NFS Provisioner 应用
[root@master30 ~]# kubectl apply -f nfs-provisioner.yaml

# 查看 NFS Provisioner 应用
[root@master30 ~]# kubectl get deployments.apps -n kube-storage 
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
nfs-client-provisioner   1/1     1            1           1m

创建 NFS StorageClass

yaml 复制代码
[root@master30 ~]# cat > ecshop-StorageClass.yaml <<'EOF'
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ecshop
  namespace: kube-storage
provisioner: fuseim.pri/ifs  # 必须和 Provisioner 名称一致
parameters:
  onDelete: retain  # 删除 PVC 保留 NFS 数据
  archiveOnDelete: "false"
# 按需设置回收策略
#reclaimPolicy: Retain
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: Immediate
EOF
bash 复制代码
# 创建 StorageClass
[root@master30 ~]# kubectl apply -f ecshop-StorageClass.yaml
[root@master30 ~]# kubectl get sc ecshop
NAME        PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
ecshop   fuseim.pri/ifs   Delete          Immediate           true                   11s

步骤 2:配置命名空间

2.1 创建 Namespace

bash 复制代码
[root@master30 ~]# kubectl create ns ecshop
[root@master30 ~]# kubectl config set-context --current --namespace ecshop

2.2 配置 Quota

bash 复制代码
[root@master30 ~]# kubectl create quota ecshop \
--hard=cpu=4,memory=8G,requests.cpu=4,requests.memory=8G,requests.storage=500G
[root@master30 ~]# kubectl describe quota ecshop 
Name:             ecshop
Namespace:        ecshop
Resource          Used  Hard
--------          ----  ----
cpu               0     4
memory            0     8G
requests.cpu      0     4
requests.memory   0     8G
requests.storage  0     500G

2.3 配置 LimitRange

yaml 复制代码
[root@master30 ~]# cat > ecshop-LimitRange.yaml <<'EOF'
apiVersion: v1
kind: LimitRange
metadata:
  name: ecshop
  namespace: ecshop
spec:
  limits:
    - type: Container
      max:
        memory: 2048Mi
        cpu: 1
      min:
        memory: 256Mi
        cpu: 100m
      default:
        memory: 512Mi
        cpu: 500m
      defaultRequest:
        memory: 256Mi
        cpu: 200m
EOF
yaml 复制代码
[root@master30 ~]# kubectl apply -f ecshop-LimitRange.yaml
[root@master30 ~]# kubectl describe limitranges ecshop 
Name:       ecshop
Namespace:  ecshop
Type        Resource  Min    Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---    ---  ---------------  -------------  -----------------------
Container   cpu       100m   1    200m             500m           -
Container   memory    256Mi  2Gi  256Mi            512Mi          -

步骤 3:部署 MySQL

3.1 创建 Secret

创建 Secret 存储 MySQL root 密码、ECShop 专用用户及密码、数据库,替代明文配置,提升安全性。

这里定义:

  • MySQL root 密码:Root@123(可按需修改)
  • ECShop 专用数据库用户:ecshop
  • ECShop 专用用户密码:ECShop@123(可按需修改)
  • ECShop 专用数据库:ecshop

执行命令创建 Secret:

bash 复制代码
# 创建 Secret 存储数据库敏感信息
[root@master30 ~]# kubectl create secret generic mysql \
  --namespace ecshop \
  --from-literal=mysql-root-password=Root@123 \
  --from-literal=ecshop-db-user=ecshop \
  --from-literal=ecshop-db-password=ECShop@123

# 验证 Secret
[root@master30 ~]# kubectl get secrets 
NAME    TYPE     DATA   AGE
mysql   Opaque   3      10s

3.2 创建 Service

创建 mysql-service.yaml

  • mysql-headless,为后续 StatefulSet 管理的 Pod 提供固定名称
  • mysql,为后续 StatefulSet 管理的 Pod 提供负载均衡
yaml 复制代码
[root@master30 ~]# cat > mysql-service.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
  namespace: ecshop
spec:
  type: ClusterIP
  selector:
    app: mysql  ## 匹配 StatefulSet 管理的 Pod 标签
  clusterIP: None  ## 无头服务,ClusterIP 设为 None
  ports:
  - port: 3306
    targetPort: 3306
    name: mysql-port  ## 端口名称,便于识别
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: ecshop
spec:
  type: ClusterIP
  selector:
    app: mysql  ## 匹配 StatefulSet 管理的 Pod 标签
  ports:
  - port: 3306
    targetPort: 3306
    name: mysql-port  ## 端口名称,便于识别
EOF

# 创建服务
[root@master30 ~]# kubectl apply -f mysql-service.yaml

# 没有 CLUSTER-IP 
[root@master30 ~]# kubectl get svc
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
mysql            ClusterIP   10.100.246.245   <none>        3306/TCP   6s
mysql-headless   ClusterIP   None             <none>        3306/TCP   6s

3.3 部署 MySQL

bash 复制代码
# worker节点提前准备好镜像,并导入
[root@worker31 ~]# nerdctl load -i docker.io_library_mysql_5.7.tar
[root@worker31 ~]# nerdctl load -i docker.io_library_nginx-1.24.tar
[root@worker31 ~]# nerdctl load -i php-7.2-fpm-ecshop.tar

[root@worker32 ~]# nerdctl load -i docker.io_library_mysql_5.7.tar
[root@worker32 ~]# nerdctl load -i docker.io_library_nginx-1.24.tar
[root@worker32 ~]# nerdctl load -i php-7.2-fpm-ecshop.tar

创建 mysql-statefulset.yaml,副本数保持1个,Service为ClusterIP,无其他修改:

yaml 复制代码
[root@master30 ~]# cat > mysql-statefulset.yaml <<'EOF'
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: ecshop
spec:
  serviceName: mysql-headless
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        ports:
        - containerPort: 3306
          name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql
              key: mysql-root-password
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: mysql
              key: ecshop-db-user
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql
              key: ecshop-db-password
        - name: MYSQL_DATABASE
          value: "ecshop"
        volumeMounts:
        - name: mysql-data  ## 挂载存储卷,名称与 volumeClaimTemplates 一致
          mountPath: /var/lib/mysql  ## MySQL 数据存储路径
        # 1. 启动探针:等待MySQL完全启动(适配初始化耗时)
        startupProbe:
          exec:
            command: 
            - sh
            - -c
            - "mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e 'SELECT 1;'"
          initialDelaySeconds: 10  # 启动后10秒开始检测
          periodSeconds: 5         # 每5秒检测一次
          failureThreshold: 30     # 最多重试30次(总超时150秒)
          timeoutSeconds: 3        # 单次检测超时3秒
        # 2. 存活探针:检测MySQL是否存活,异常则重启
        livenessProbe:
          exec:
            command:
            - sh
            - -c
            - "mysqladmin ping -uroot -p${MYSQL_ROOT_PASSWORD}"
          initialDelaySeconds: 30  # 启动后30秒开始检测(避开初始化)
          periodSeconds: 10        # 每10秒检测一次
          timeoutSeconds: 5        # 单次检测超时5秒
          failureThreshold: 3      # 失败3次则判定异常
        # 3. 就绪探针:检测MySQL是否可接收请求
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - "mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e 'SHOW DATABASES;'"
          initialDelaySeconds: 20  # 比存活探针早启动
          periodSeconds: 5         # 每5秒检测一次
          timeoutSeconds: 2        # 单次检测超时2秒
          successThreshold: 1      # 成功1次则判定就绪
          failureThreshold: 2      # 失败2次则移除服务端点
  volumeClaimTemplates:  ## PVC 模板,为每个 Pod 自动创建 PVC
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "ecshop"  ## 与 PV 的 storageClassName 一致
      resources:
        requests:
          storage: 10Gi
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f mysql-statefulset.yaml
[root@master30 ~]# kubectl get statefulsets.apps 
NAME    READY   AGE
mysql   1/1     52s

[root@master30 ~]# kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
mysql-0   1/1     Running   0          78s

[root@master30 ~]# kubectl get pvc
NAME                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
mysql-data-mysql-0   Bound    pvc-c40fcf08-0f68-481f-b266-29b03eca925b   10Gi       RWO            ecshop      <unset>                 3m2s

验证数据库

bash 复制代码
[root@master30 ~]# apt install -y mysql-client
[root@master30 ~]# mysql -uecshop -pECShop@123 -h 10.100.246.245 -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| information_schema |
| ecshop             |
+--------------------+

步骤 4:部署 PHP

4.1 创建 PVC

PHP 和 Nginx 使用相同存储存储,创建 ecshop-pvc.yaml

yaml 复制代码
[root@master30 ~]# cat > ecshop-pvc.yaml <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ecshop
  namespace: ecshop
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  storageClassName: ecshop
EOF

执行创建:

bash 复制代码
[root@master30 ~]# kubectl apply -f ecshop-pvc.yaml
[root@master30 ~]# kubectl get pvc ecshop 
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
ecshop   Bound    pvc-54472f60-0c65-4f41-bc38-e54a775f9c61   10Gi       RWX            ecshop      <unset>                 4s

4.2 部署 PHP

创建 php-deploy.yaml

yaml 复制代码
[root@master30 ~]# cat > php-deploy.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: php
  namespace: ecshop
spec:
  replicas: 1
  selector:
    matchLabels:
      app: php
  template:
    metadata:
      labels:
        app: php
    spec:
      containers:
      - name: php
        image: php:7.2-fpm-ecshop
        ports:
        - containerPort: 9000
        # 1. 存活探针:验证 FPM 进程存活(核心)
        livenessProbe:
          tcpSocket:
            port: 9000
          initialDelaySeconds: 10  # 启动后10秒开始检测(避开初始化)
          periodSeconds: 10        # 每10秒检测一次
          timeoutSeconds: 5        # 单次检测超时5秒
          failureThreshold: 3      # 失败3次重启容器
        # 2. 就绪探针:验证 FPM 可接收请求(推荐用状态页)
        readinessProbe:
          tcpSocket:
            port: 9000
          initialDelaySeconds: 5   # 比存活探针早启动
          periodSeconds: 5         # 每5秒检测一次
          timeoutSeconds: 3        # 单次检测超时3秒
          successThreshold: 1      # 成功1次即就绪
          failureThreshold: 2      # 失败2次移除服务端点
        volumeMounts:
        ## PHP 网站根目录
        - name: ecshop-data
          mountPath: /usr/share/nginx/html  
      volumes:
      ## PHP 网站根目录
      - name: ecshop-data
        persistentVolumeClaim:
          claimName: ecshop
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f php-deploy.yaml
[root@master30 ~]# kubectl get deploy php
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
php    1/1     1            1           6s

4.3 创建 Service

创建 php-service.yaml

bash 复制代码
[root@master30 ~]# cat > php-service.yaml <<'EOF'
---
apiVersion: v1
kind: Service
metadata:
  name: php
  namespace: ecshop
spec:
  type: ClusterIP
  selector:
    app: php
  ports:
  - port: 9000
    targetPort: 9000
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f php-service.yaml
[root@master30 ~]#  kubectl get svc php
NAME   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
php    ClusterIP   10.111.26.134   <none>        9000/TCP   5s

步骤 5:部署 Nginx

5.1 部署 ECShop 代码

bash 复制代码
## 进入 NFS 服务器(IP:10.1.8.30),配置 ECShop 源码
[root@master30 ~]# unzip ECShop_V4.1.20_UTF8.zip

# 查看代码物理位置名称
[root@master30 ~]# kubectl get pvc ecshop
NAME                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
ecshop            Bound    pvc-54472f60-0c65-4f41-bc38-e54a775f9c61   10Gi       RWX            ecshop      <unset>                 10m

[root@master30 ~]# cp -a ECShop_V4.1.20_UTF8_release20250416/source/ecshop/* /ecshop/ecshop-ecshop-pvc-54472f60-0c65-4f41-bc38-e54a775f9c61/
[root@master30 ~]# chmod 777 -R /ecshop/ecshop-ecshop-pvc-54472f60-0c65-4f41-bc38-e54a775f9c61/

# 存储服务器准备测试页面
[root@master30 ~]# echo Hello World From Nginx > /ecshop/ecshop-ecshop-pvc-54472f60-0c65-4f41-bc38-e54a775f9c61/index.html
[root@master30 ~]# echo "<?php phpinfo(); ?>" > /ecshop/ecshop-ecshop-pvc-54472f60-0c65-4f41-bc38-e54a775f9c61/phpinfo.php
[root@master30 ~]# cat > /ecshop/ecshop-ecshop-pvc-54472f60-0c65-4f41-bc38-e54a775f9c61/php-mysql.php <<'EOF'
<?php
  $link=mysqli_connect('mysql','ecshop','ECShop@123');
  if($link)
    echo "Connect Mysql Success !\n";
  else
    echo "Connect Mysql Failed !\n";
  $link->close();
?>
EOF

5.2 创建 Nginx 配置

bash 复制代码
[root@master30 ~]# cat > nginx-configmap.yaml <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx
  namespace: ecshop
data:
  nginx.conf: |
    worker_processes auto;
    events {
        worker_connections 1024;
    }
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;

        # ECShop 站点配置
        server {
            listen 80;
            server_name shop.shizhan.cloud;  

            # 网站根目录
            root /usr/share/nginx/html;
            index index.php index.html;

            # PHP 转发配置(指向ecshop命名空间的PHP Service)
            location ~ \.php$ {
                fastcgi_pass php.ecshop.svc.cluster.local:9000;  # 跨命名空间访问,格式:服务名.命名空间.svc.cluster.local
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
                fastcgi_param HTTPS on;
            }

            # 静态资源缓存
            location ~* \.(jpg|jpeg|png|gif|css|js)$ {
                expires 30d;
                add_header Cache-Control "public, max-age=2592000";
            }
        }
    }
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f nginx-configmap.yaml
[root@master30 ~]# kubectl get cm nginx
NAME    DATA   AGE
nginx   1      27s

5.4 部署 Nginx

创建 nginx-deploy.yaml

bash 复制代码
[root@master30 ~]# cat > nginx-deploy.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: ecshop
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.24
        ports:
        - containerPort: 80
        - containerPort: 443
        # 1. 启动探针(可选):适配首次启动耗时
        startupProbe:
          tcpSocket:
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 2
          failureThreshold: 10     # 总超时20秒,确保启动完成
        # 2. 存活探针:验证 Nginx 核心服务存活
        livenessProbe:
          exec:
            # 访问 Nginx 内置状态页(需提前配置),返回 200 则正常
            command:
            - sh
            - -c
            - "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/index.html | grep '200'"
          initialDelaySeconds: 10  # 启动后10秒开始检测
          periodSeconds: 10        # 每10秒检测一次
          timeoutSeconds: 5        # 单次检测超时5秒
          failureThreshold: 3      # 失败3次重启容器
        # 3. 就绪探针:验证 Nginx 可接收外部请求
        readinessProbe:
          httpGet:
            path: /          # 业务根路径(可替换为你的实际业务路径)
            port: 80
            scheme: HTTP
          initialDelaySeconds: 5   # 比存活探针早启动
          periodSeconds: 5         # 每5秒检测一次
          timeoutSeconds: 2        # 单次检测超时2秒
          successThreshold: 1      # 成功1次即就绪
          failureThreshold: 2      # 失败2次移除服务端点
        volumeMounts:
        - name: nginx
          mountPath: /etc/nginx/nginx.conf  ## 挂载 Nginx 配置
          subPath: nginx.conf
        - name: ecshop-data
          mountPath: /usr/share/nginx/html  ## 挂载 ECShop 代码目录
      volumes:
      - name: nginx
        configMap:
          name: nginx
      - name: ecshop-data
        persistentVolumeClaim:
          claimName: ecshop
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f nginx-deploy.yaml
[root@master30 ~]# kubectl get deploy nginx
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           21s

5.5 创建 Service

创建 ecshop-service.yaml

bash 复制代码
[root@master30 ~]# cat > nginx-service.yaml <<'EOF'
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: ecshop
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    name: http
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f nginx-service.yaml
[root@master30 ~]# kubectl get svc nginx 
NAME    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
nginx   ClusterIP   10.109.217.173   <none>        80/TCP    5s

5.6 测试 Nginx

bash 复制代码
[root@master30 ~]# kubectl get svc nginx 
NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
nginx   ClusterIP   10.98.1.27   <none>        80/TCP,443/TCP   50s

# 欢迎页面
[root@master30 ~]# curl http://10.109.217.173/index.html
Hello World From Nginx

# php页面
[root@master30 ~]# curl http://10.109.217.173/phpinfo.php -s|grep -o 'PHP Version 7.2'
PHP Version 7.2

# mysql连接
[root@master30 ~]# curl http://10.109.217.173/php-mysql.php
Connect Mysql Success !

步骤 6:部署 LoadBalancer

bash 复制代码
[root@master30 ~]# tar -xf metallb-0.14.8.tar.gz
# 查看metallb使用了哪些镜像
[root@master30 ~]# grep image: metallb-0.14.8/config/manifests/metallb-native.yaml
        image: quay.io/metallb/controller:v0.14.8
        image: quay.io/metallb/speaker:v0.14.8

# 导入metallb镜像 metallb-images-v0.14.8.zip包中的controller:v0.14.8 speaker:v0.14.8
[root@worker31 ~]# unzip metallb-images-v0.14.8.zip
[root@worker31 ~]# cd metallb-images-v0.14.8/
[root@worker31 metallb-images-v0.14.8]# nerdctl load -i metallb-controller-v0.14.8.tar
[root@worker31 metallb-images-v0.14.8]# nerdctl load -i metallb-speaker-v0.14.8.tar

[root@worker32 metallb-images-v0.14.8]# nerdctl load -i metallb-controller-v0.14.8.tar
[root@worker32 metallb-images-v0.14.8]# nerdctl load -i metallb-speaker-v0.14.8.tar

[root@master30 metallb-images-v0.14.8]# nerdctl load -i metallb-speaker-v0.14.8.tar

# 部署metallb
[root@master30 ~]# kubectl apply -f metallb-0.14.8/config/manifests/metallb-native.yaml

# 等待着所有pod正常运行再进行下一步
[root@master30 ~]# kubectl get pods -n metallb-system 
NAME                              READY   STATUS    RESTARTS   AGE
pod/controller-786f9df989-98bjh   1/1     Running   0          85s
pod/speaker-gthhx                 1/1     Running   0          85s
pod/speaker-jwj25                 1/1     Running   0          85s
pod/speaker-s5zvq                 1/1     Running   0          85s

# 配置地址池
[root@master30 ~]# cat << 'EOF' > ippool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 10.1.8.50-10.1.8.80
EOF
[root@master30 ~]# kubectl apply -f ippool.yaml

# 配置 lay2
[root@master30 ~]# cat << 'EOF' > L2.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system
EOF
[root@master30 ~]# kubectl apply -f L2.yaml

步骤 7:部署 Ingress

bash 复制代码
# worker节点导入镜像controller:v1.11.2 kube-webhook-certgen:v1.4.3
[root@worker31 ~]# nerdctl load -i ingress-nginx-controller-v1.11.2.tar
[root@worker31 ~]# nerdctl load -i ingress-nginx-kube-webhook-certgen-v1.4.3.tar

[root@worker32 ~]# nerdctl load -i ingress-nginx-controller-v1.11.2.tar
[root@worker32 ~]# nerdctl load -i ingress-nginx-kube-webhook-certgen-v1.4.3.tar

[root@master30 ~]# tar -xf ingress-nginx-controller-v1.11.2.tar.gz
[root@master30 ~]# kubectl apply -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
[root@master30 ~]# kubectl get svc -n ingress-nginx 
NAME                                 TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.108.53.60   10.1.8.50     80:31003/TCP,443:31797/TCP   5s
ingress-nginx-controller-admission   ClusterIP      10.100.8.74    <none>        443/TCP                      5s

准备证书

bash 复制代码
## 生成自签名证书
[root@master30 ~]# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout tls.key -out tls.crt \
  -subj "/CN=*.shizhan.cloud"
  
## 创建 Secret 存储证书
[root@master30 ~]# kubectl create secret tls ingress-nginx-tls \
--namespace ecshop \
--cert=tls.crt \
--key=tls.key

[root@master30 ~]# kubectl get secrets ingress-nginx-tls 
NAME                TYPE                DATA   AGE
ingress-nginx-tls   kubernetes.io/tls   2      28s

步骤 8:初始化站点

8.1 配置 ingress 规则

bash 复制代码
[root@master30 ~]# cat > shop-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress-shop
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - shop.shizhan.cloud
    secretName: ingress-nginx-tls
  rules:
  - host: shop.shizhan.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx
            port: 
              number: 80
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f shop-ingress.yaml
[root@master30 ~]#  kubectl describe ingress tls-ingress-shop
Name:             tls-ingress-shop
Labels:           <none>
Namespace:        ecshop
Address:          10.1.8.50
Ingress Class:    nginx
Default backend:  <default>
TLS:
  ingress-nginx-tls terminates shop.shizhan.cloud
Rules:
  Host                Path  Backends
  ----                ----  --------
  shop.shizhan.cloud  
                      /   nginx:80 (10.224.103.70:80)
Annotations:          nginx.ingress.kubernetes.io/force-ssl-redirect: true
                      nginx.ingress.kubernetes.io/ssl-redirect: true
Events:               <none>

8.2 访问站点

windows 访问,需提前配置域名解析。

C:\Windows\System32\drivers\etc\hosts

10.1.8.50 shop.shizhan.cloud

访问 https://shop.shizhan.cloud,点击高级继续。

点击继续前往shop.shizhan.cloud(不安全)继续。

8.3 初始化站点

进入 ECShop 商城站点欢迎页面,勾选我已仔细阅读,并同意上述条款中的所有内容,点击下一步:配置安装环境继续。

点击下一步:配置系统继续。

根据提示填写相关内容,然后点击立即安装继续。

安装完成后访问主页https://shop.shizhan.cloud/。

访问后台 https://shop.shizhan.cloud/admin,使用ECShop账号登录。

输入用户名和密码,点击登录

登录成功。

步骤 9:部署 Metric Server

bash 复制代码
# 下载 Metrics-Server 资源定义
[root@master30 ~]# wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.1/components.yaml

# 修改Metrics-Server配置,不校验tls
[root@master30 ~]# vim components.yaml
yaml 复制代码
......
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: metrics-server
  strategy:
    rollingUpdate:
      maxUnavailable: 0
  template:
    metadata:
      labels:
        k8s-app: metrics-server
    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=10250
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
        - --kubelet-use-node-status-port
        - --metric-resolution=15s
        
        # 添加--kubelet-insecure-tls参数
        - --kubelet-insecure-tls
......
bash 复制代码
[root@master30 ~]# kubectl apply -f components.yaml
[root@master30 ~]# kubectl top nodes
NAME                   CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
master30.shizhan.cloud   70m          3%     1709Mi          45%       
worker31.shizhan.cloud   22m          1%     1166Mi          30%       
worker32.shizhan.cloud   24m          1%     1069Mi          28

步骤 10:配置 HPA

bash 复制代码
# 扩容
[root@master30 ~]# kubectl autoscale deployment php --min=2 --max=5 --cpu-percent=80
[root@master30 ~]# kubectl get deployments.apps php
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
php     2/2     2            2           3h33m

[root@master30 ~]# kubectl autoscale deployment nginx --min=2 --max=5 --cpu-percent=80
[root@master30 ~]# kubectl get deployments.apps nginx
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/2     2            2           3h27m

[root@master30 ~]# kubectl describe quota ecshop 
Name:             ecshop
Namespace:        ecshop
Resource          Used         Hard
--------          ----         ----
cpu               1            4
memory            1342177280   8G
requests.cpu      1            4
requests.memory   1342177280   8G
requests.storage  21474836480  500G

步骤 11:部署 Dashboard

11.1 部署 Dashboard

bash 复制代码
# 下载资源yaml文件
[root@master30 ~]# wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.6.1/aio/deploy/recommended.yaml

# 查看images
[root@master30 ~]# grep image: recommended.yaml 
          image: kubernetesui/dashboard:v2.6.1
          image: kubernetesui/metrics-scraper:v1.0.8
          
# 导入镜像kubernetesui_dashboard_v2.6.1.tar、kubernetesui_metrics-scraper_v1.0.8.tar
[root@worker31 ~]# nerdctl load -i kubernetesui_dashboard_v2.6.1.tar
[root@worker31 ~]# nerdctl load -i kubernetesui_metrics-scraper_v1.0.8.tar
[root@worker32 ~]# nerdctl load -i kubernetesui_dashboard_v2.6.1.tar
[root@worker32 ~]# nerdctl load -i kubernetesui_metrics-scraper_v1.0.8.tar

# 执行部署
[root@master30 ~]# kubectl apply -f recommended.yaml

11.2 配置 ingress 规则

bash 复制代码
[root@master30 ~]# cat > dashborad-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress-dashborad
  namespace: kubernetes-dashboard
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - dashboard.shizhan.cloud
    secretName: ingress-nginx-tls
  rules:
  - host: dashboard.shizhan.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: kubernetes-dashboard
            port: 
              number: 443
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f dashborad-ingress.yaml
[root@master30 ~]# kubectl describe ingress -n kubernetes-dashboard tls-ingress-dashborad 
Name:             tls-ingress-dashborad
Labels:           <none>
Namespace:        kubernetes-dashboard
Address:          10.1.8.50
Ingress Class:    nginx
Default backend:  <default>
TLS:
  ingress-nginx-tls terminates dashboard.shizhan.cloud
Rules:
  Host                     Path  Backends
  ----                     ----  --------
  dashboard.shizhan.cloud  
                           /   kubernetes-dashboard:443 (10.224.88.201:8443)
Annotations:               nginx.ingress.kubernetes.io/backend-protocol: HTTPS
                           nginx.ingress.kubernetes.io/force-ssl-redirect: true
                           nginx.ingress.kubernetes.io/ssl-redirect: true
Events:                    <none>

  
[root@master30 ~]# kubectl get service  -n kubernetes-dashboard
NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
dashboard-metrics-scraper   ClusterIP   10.111.171.224   <none>        8000/TCP   7m48s
kubernetes-dashboard        ClusterIP   10.107.0.186     <none>        443/TCP    7m48s

# 修改 service/kubernetes-dashboard 类型为 NodePort,从外部访问。
[root@master30 ~]# kubectl edit svc kubernetes-dashboard
spec:
......
  type: NodePort
  
[root@master30 ~]# kubectl get svc kubernetes-dashboard  -n kubernetes-dashboard
NAME                   TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE
kubernetes-dashboard   NodePort   10.107.0.186   <none>        443:32065/TCP   12m
 
# 配置hosts
C:\Windows\System32\drivers\etc\hosts
10.1.8.50 dashboard.shizhan.cloud

11.3 访问 dashboard

访问 https://dashboard.shizhan.cloud

要访问 https://dashboard.shizhan.cloud/,需要创建一个名为 admin-user 的 ServiceAccount,再创建一个 ClusterRolebinding,将其绑定到 Kubernetes 集群中默认初始化的 cluster-admin 这个 ClusterRole。

bash 复制代码
[root@master30 ~]# cat > kubernetes-dashboard-admin-user.yaml <<'EOF'
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard
EOF
bash 复制代码
[root@master30 ~]# kubectl apply -f kubernetes-dashboard-admin-user.yaml

# 创建 Bearer Token
[root@master30 ~]# kubectl -n kubernetes-dashboard create token admin-user
eyJhbGciOiJSUzI1NiIsImtpZCI6IkszbHV2VVhzZGptc2VqREJ5aUhWRUdNRWwzVFUtQkxOM0VYTzdfckYxWEEifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzc4MjMzNzU3LCJpYXQiOjE3NzgyMzAxNTcsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiZWM2NzZjZGEtYTgxYy00YWE1LWI3OTYtMTA4ODY2ODNjMGJkIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJhZG1pbi11c2VyIiwidWlkIjoiNmIzZDIwNjAtZDMzZC00ZTIyLWFmMzctZTg4MmEyMDliYjY2In19LCJuYmYiOjE3NzgyMzAxNTcsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDphZG1pbi11c2VyIn0.RrS_S0PYN2JPuK7PsCJWT4RhltuM3eVOwTJFKAisCwXFaGQdHJ47ZI6CuhLN3WdI1bccnVo2Sk5xTkWRVXXUQferkOtrtVrYpuSq6mEf4Xz1uIbsKdbfrnuvjSf6b-jDLrvIb2LwYG46ENuyETN6vaWY-AfRkGxNvWWeIlai6l_JNuD7K_tNFPxI-uQIWg38plmvq44gg-HrKPLpBHMqnL82HHoY4qGdrUj24rLYlJG2D08OtW_lDJnqpMnJYBw0nPye3uNdMxtOSyXHc9l-NaNGLoejoi9VmdCPW97wXzEreoYzwWVDswavQT5c1Q8m53enahDhtlO7Yve89KIgRA

提示:Token默认有效期1小时,过期后自动删除。下一次登录需要生成新的Token。

pod/kubernetes-dashboard 以 sa/kubernetes-dashboard身份运行,权限有限。

赋予sa/kubernetes-dashboard最高权限clusterrole/cluster-admin。

bash 复制代码
[root@master30 ~]# kubectl create clusterrolebinding kubernetes-dashboard-cluster-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:kubernetes-dashboard

再次刷新页面查看:

相关推荐
A-刘晨阳1 天前
K8s之负载均衡
linux·运维·容器·kubernetes·负载均衡
米高梅狮子1 天前
11.Quota and Limits、健康检查和认证与授权
云原生·容器·架构·kubernetes·自动化
米高梅狮子1 天前
13.ETCD 存储系统、生产环境 Kubernetes 集群部署和Kubernetes 集群升级
数据库·云原生·容器·架构·kubernetes·自动化·etcd
梵得儿SHI2 天前
(第三篇)Spring AI 架构设计与优化:容器化与云原生部署,基于 K8s 的 AI 应用全生命周期管理
java·ci/cd·docker·云原生·kubernetes·容器化·spring ai
m0_737539372 天前
基于LNMP的综合实验
容器·kubernetes
胡小禾4 天前
K8S常识-如何指定只更新一个deployment中的某一个实例
云原生·容器·kubernetes
红球yyds4 天前
Kubernetes 简介及部署方法
云原生·容器·kubernetes
.柒宇.5 天前
AI掘金头条项目-K8s部署实战教程
python·云原生·容器·kubernetes·fastapi
PH = 75 天前
K8S集群的搭建
云原生·容器·kubernetes