--- # Ansible 一键部署 nginx 矩阵(M1~M4) # 对应文档:docs/02-05-nginx-验证矩阵-一键部署.md(02-01~02-04 分篇已整合) # # 说明:复制 manifests → kubectl apply → 等待 Pod 就绪 → 验证 Pod 节点分布 → curl 16 目标 # manifests:ansible/files/02-05-nginx-matrix/,M1 control-plane / M2 ylc61 / M3 worker / M4 ylc64,按实际修改 02/04 hostname # # 执行(在 ansible/ 目录下): # ansible-playbook -i inventory.ini playbooks/nginx-matrix-deploy.yml # 或在仓库根目录: # ansible-playbook -i ansible/inventory.ini ansible/playbooks/nginx-matrix-deploy.yml - name: Deploy nginx matrix (M1~M4) hosts: k3s_server become: true run_once: true vars: k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml # manifests 在 ansible/files/02-05-nginx-matrix/,与 playbook 同项目 manifests_path: "{{ playbook_dir }}/../files/02-05-nginx-matrix" tasks: - name: Ensure manifests path exists ansible.builtin.stat: path: "{{ manifests_path }}" register: manifests_stat - name: Fail if manifests not found ansible.builtin.fail: msg: "manifests 未找到: {{ manifests_path }},请从仓库根目录或 ansible 同级执行" when: not manifests_stat.stat.exists # 部署前确保 control-plane/worker 标签存在(M1/M3 需此才能调度),节点名为短主机名(ylc61~ylc64) - name: Ensure control-plane label on k3s_server nodes (for M1) ansible.builtin.shell: | KUBECONFIG={{ k3s_kubeconfig }} kubectl label node {{ item }} node-role.kubernetes.io/control-plane= --overwrite loop: "{{ groups['k3s_server'] | default([]) }}" - name: Ensure worker label on k3s_worker nodes (for M3) ansible.builtin.shell: | KUBECONFIG={{ k3s_kubeconfig }} kubectl label node {{ item }} node-role.kubernetes.io/worker= --overwrite loop: "{{ groups['k3s_worker'] | default([]) }}" - name: Copy nginx matrix manifests to server ansible.builtin.copy: src: "{{ manifests_path }}/" dest: /tmp/nginx-matrix/ mode: '0644' # 先删全部 nginx 矩阵 Deployment 再 apply,避免旧 ReplicaSet 导致任一 Mx 仍显示默认页 - name: Delete all nginx matrix deployments before apply ansible.builtin.shell: KUBECONFIG={{ k3s_kubeconfig }} kubectl delete deployment nginx-m1 nginx-m2 nginx-m3 nginx-m4 -n default --ignore-not-found=true register: del_nginx changed_when: "'deleted' in del_nginx.stdout" - name: kubectl apply nginx matrix ansible.builtin.shell: KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f /tmp/nginx-matrix/ -R register: k8s_apply changed_when: "'configured' in k8s_apply.stdout or 'created' in k8s_apply.stdout" - name: Restart nginx deployments so pods pick up ConfigMap (M1~M4 标识) ansible.builtin.shell: KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout restart deployment nginx-m1 nginx-m2 nginx-m3 nginx-m4 -n default register: restart_out changed_when: true - name: Wait for nginx pods to be ready ansible.builtin.shell: | KUBECONFIG={{ k3s_kubeconfig }} kubectl wait --for=condition=ready pod \ -l app=nginx-m1 --timeout=60s KUBECONFIG={{ k3s_kubeconfig }} kubectl wait --for=condition=ready pod \ -l app=nginx-m2 --timeout=60s KUBECONFIG={{ k3s_kubeconfig }} kubectl wait --for=condition=ready pod \ -l app=nginx-m3 --timeout=120s KUBECONFIG={{ k3s_kubeconfig }} kubectl wait --for=condition=ready pod \ -l app=nginx-m4 --timeout=120s register: wait_result changed_when: false - name: Verify nginx matrix ansible.builtin.shell: KUBECONFIG={{ k3s_kubeconfig }} kubectl get pod,svc,ing,ingressroute -n default -o wide register: verify changed_when: false - name: ">>> nginx matrix 资源" ansible.builtin.debug: msg: "{{ item }}" loop: "{{ verify.stdout_lines }}" - name: 验证 Pod 节点分布(M1/M2 应在控制节点,M3/M4 应在工作节点) ansible.builtin.shell: | KUBECONFIG={{ k3s_kubeconfig }} kubectl get pod -n default -o custom-columns='NAME:.metadata.name,APP:.metadata.labels.app,NODE:.spec.nodeName' | grep -E '^(NAME|nginx-m)' register: pod_placement changed_when: false - name: ">>> Pod 节点分布" ansible.builtin.debug: msg: "{{ item }}" loop: "{{ pod_placement.stdout_lines }}" - name: M1 容器内诊断(排查为何仍为 nginx 欢迎页) ansible.builtin.shell: | echo "========== 1. M1 容器内 /usr/share/nginx/html/ 目录 ==========" KUBECONFIG={{ k3s_kubeconfig }} kubectl exec -n default deployment/nginx-m1 -- ls -la /usr/share/nginx/html/ 2>/dev/null || echo "(exec 失败)" echo "" echo "========== 2. M1 容器内 index.html 内容(前 5 行)==========" KUBECONFIG={{ k3s_kubeconfig }} kubectl exec -n default deployment/nginx-m1 -- cat /usr/share/nginx/html/index.html 2>/dev/null | head -5 || echo "(exec 失败)" echo "" echo "========== 3. M1 容器内 /etc/nginx/conf.d/ 目录 ==========" KUBECONFIG={{ k3s_kubeconfig }} kubectl exec -n default deployment/nginx-m1 -- ls -la /etc/nginx/conf.d/ 2>/dev/null || echo "(exec 失败)" echo "" echo "========== 4. M1 容器内 default.conf 内容 ==========" KUBECONFIG={{ k3s_kubeconfig }} kubectl exec -n default deployment/nginx-m1 -- cat /etc/nginx/conf.d/default.conf 2>/dev/null || echo "(exec 失败)" echo "" echo "========== 5. M1 容器内 nginx 生效配置中的 server 块(前 40 行)==========" KUBECONFIG={{ k3s_kubeconfig }} kubectl exec -n default deployment/nginx-m1 -- nginx -T 2>/dev/null | grep -A 200 "server {" | head -40 || echo "(exec 失败)" register: m1_diag changed_when: false failed_when: false - name: ">>> M1 容器内诊断结果(若 M1 仍为欢迎页,请根据此处输出排查)" ansible.builtin.debug: msg: "{{ item }}" loop: "{{ m1_diag.stdout_lines }}" - name: 验证 M1~M4 标识(Pod 内 index.html 含 Mx、响应头 X-Backend) ansible.builtin.shell: | base="{{ groups['k3s_nodes'] | map('extract', hostvars) | map(attribute='ansible_host') | first }}" for id in 1 2 3 4; do echo "=== M$id Pod 内 index.html 前 2 行 ===" KUBECONFIG={{ k3s_kubeconfig }} kubectl exec -n default deployment/nginx-m$id -- cat /usr/share/nginx/html/index.html 2>/dev/null | head -2 || echo "(exec 失败)" echo "=== M$id 响应头 X-Backend ===" curl -sI "http://$base/demo-m$id/" 2>/dev/null | grep -i x-backend || echo "(未看到 X-Backend)" echo "" done register: m_check changed_when: false failed_when: false - name: ">>> M1~M4 验证" ansible.builtin.debug: msg: "{{ item }}" loop: "{{ m_check.stdout_lines }}" - name: curl 验证(16 个目标:4 节点 × 4 路径) ansible.builtin.shell: | bases="{{ groups['k3s_nodes'] | map('extract', hostvars) | map(attribute='ansible_host') | join(' ') }}" paths="/demo-m1 /demo-m2 /demo-m3 /demo-m4" count=0 ok=0 echo "=== 16 个目标 (4 节点 × 4 路径) ===" echo "节点 M1(控制+Ingress) M2(控制+IR) M3(工作+Ingress) M4(工作+IR)" for base in $bases; do m1=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 http://$base/demo-m1 2>/dev/null) || m1="fail" m2=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 http://$base/demo-m2 2>/dev/null) || m2="fail" m3=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 http://$base/demo-m3 2>/dev/null) || m3="fail" m4=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 http://$base/demo-m4 2>/dev/null) || m4="fail" printf "%-12s %-16s %-11s %-16s %s\n" "$base" "$m1" "$m2" "$m3" "$m4" for c in $m1 $m2 $m3 $m4; do count=$((count+1)); [ "$c" = "200" ] && ok=$((ok+1)); done done echo "---" echo "共验证 $count 个目标,$ok 个返回 200" register: curl_result changed_when: false - name: ">>> curl 矩阵" ansible.builtin.debug: msg: "{{ item }}" loop: "{{ curl_result.stdout_lines }}"