日常更新
This commit is contained in:
@@ -3,3 +3,5 @@
|
||||
host_key_checking = False
|
||||
# 使用 inventory 同目录
|
||||
inventory = inventory.ini
|
||||
# 允许 include_role 解析仓库内角色(例如 verify_common)
|
||||
roles_path = roles
|
||||
|
||||
56
ansible/bin/deploy-lab.sh
Executable file
56
ansible/bin/deploy-lab.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT}/ansible/lib/lib-ansible-lab.sh"
|
||||
ansible_lab_export_config
|
||||
|
||||
load_env() {
|
||||
if [[ -f "${ROOT}/ansible/env/.env.verify" ]]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT}/ansible/env/.env.verify"
|
||||
set +a
|
||||
echo "[OK] 已加载 ansible/env/.env.verify"
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法:ansible/bin/deploy-lab.sh <子命令>
|
||||
子命令:k3s | longhorn | nginx-matrix | nginx-matrix-tls
|
||||
EOF
|
||||
}
|
||||
|
||||
ansible_wrap() {
|
||||
local inv="${ANSIBLE_INVENTORY:-${ROOT}/ansible/inventory.ini}"
|
||||
[[ -f "$inv" ]] || { echo "[ERR] inventory 不存在:$inv" >&2; exit 1; }
|
||||
command -v ansible-playbook >/dev/null 2>&1 || { echo "[ERR] 未找到 ansible-playbook" >&2; exit 1; }
|
||||
ansible_lab_check_inventory_keys "$inv" || exit 1
|
||||
local td="${DEPLOY_VERIFY_TEARDOWN:-0}"
|
||||
echo "[RUN] ansible-playbook -i $inv -e VERIFY_TEARDOWN=$td $*"
|
||||
ansible-playbook -i "$inv" -e "VERIFY_TEARDOWN=$td" "$@"
|
||||
}
|
||||
|
||||
cmd_k3s() {
|
||||
if [[ "${K3S_PREPARE_STORAGE:-false}" == "true" ]]; then
|
||||
ansible_wrap "${ROOT}/ansible/playbooks/verify/01-05.yml" -e 'k3s_do_prepare_storage=true' -e 'k3s_prepare_storage=true'
|
||||
fi
|
||||
ansible_wrap "${ROOT}/ansible/playbooks/verify/01-05.yml" -e 'k3s_do_install=true'
|
||||
}
|
||||
|
||||
main() {
|
||||
load_env
|
||||
local sub="${1:-}"
|
||||
case "$sub" in
|
||||
""|-h|--help) usage ;;
|
||||
k3s) cmd_k3s ;;
|
||||
longhorn) ansible_wrap "${ROOT}/ansible/playbooks/verify/03-07.yml" ;;
|
||||
nginx-matrix) ansible_wrap "${ROOT}/ansible/playbooks/verify/02-05.yml" ;;
|
||||
nginx-matrix-tls) ansible_wrap "${ROOT}/ansible/playbooks/verify/03-02.yml" -e 'nginx_matrix_tls_enable=true' ;;
|
||||
*) echo "[ERR] 未知子命令:$sub" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
6
ansible/bin/scaffold-doc-id.sh
Executable file
6
ansible/bin/scaffold-doc-id.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# 生成执行域 doc_id 最小骨架(docs + ansible/files + verify playbook)。参见 ansible/tools/scaffold_doc_id.py
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
exec python3 "$ROOT/ansible/tools/scaffold_doc_id.py" "$@"
|
||||
304
ansible/bin/verify.sh
Executable file
304
ansible/bin/verify.sh
Executable file
@@ -0,0 +1,304 @@
|
||||
#!/usr/bin/env bash
|
||||
# 验证入口(以 ansible/playbooks/verify/<doc_id>.yml 为唯一执行真源):
|
||||
# - run <XX-YY>:执行单篇验证 playbook
|
||||
# - run-all:按 verify 目录中存在的 <doc_id>.yml 顺序执行(仅执行域:XX>0 && YY>0)
|
||||
# - full:preflight + run-all
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT}/ansible/lib/lib-ansible-lab.sh"
|
||||
ansible_lab_export_config
|
||||
|
||||
export VERIFY_TEARDOWN="${VERIFY_TEARDOWN:-1}"
|
||||
STATUS_DIR="${ROOT}/.status"
|
||||
TEARDOWN_STATE_JSON="${STATUS_DIR}/verify-teardown-state.json"
|
||||
|
||||
load_env() {
|
||||
export ANSIBLE_CONFIG="${ANSIBLE_CONFIG:-${ROOT}/ansible/ansible.cfg}"
|
||||
local td_override="${VERIFY_TEARDOWN-__unset__}"
|
||||
if [[ -f "${ROOT}/ansible/env/.env.verify" ]]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT}/ansible/env/.env.verify"
|
||||
set +a
|
||||
echo "[OK] 已加载 ansible/env/.env.verify"
|
||||
else
|
||||
echo "[TIP] 未发现 ansible/env/.env.verify,按默认变量继续"
|
||||
fi
|
||||
if [[ "${td_override}" != "__unset__" ]]; then
|
||||
export VERIFY_TEARDOWN="${td_override}"
|
||||
else
|
||||
export VERIFY_TEARDOWN="${VERIFY_TEARDOWN:-1}"
|
||||
fi
|
||||
echo "[INFO] ANSIBLE_CONFIG=${ANSIBLE_CONFIG}"
|
||||
}
|
||||
|
||||
record_teardown_state() {
|
||||
mkdir -p "${STATUS_DIR}"
|
||||
local td="${VERIFY_TEARDOWN:-1}"
|
||||
local ts
|
||||
ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
cat > "${TEARDOWN_STATE_JSON}" <<EOF
|
||||
{"updated_at":"${ts}","verify_teardown":${td}}
|
||||
EOF
|
||||
}
|
||||
|
||||
warn_teardown_mode() {
|
||||
local td="${VERIFY_TEARDOWN:-1}"
|
||||
if [[ "${td}" == "0" ]]; then
|
||||
echo "[WARN] VERIFY_TEARDOWN=0:保留现场模式已启用(可能污染后续 full/run-all)" >&2
|
||||
echo "[TIP] 恢复建议:切回 VERIFY_TEARDOWN=1 并复跑主线;必要时手工清理残留命名空间/资源" >&2
|
||||
echo "[OC] doc_id=preflight result=verified phase=preflight assertion=teardown_mode verify_teardown=0"
|
||||
fi
|
||||
|
||||
if [[ -f "${TEARDOWN_STATE_JSON}" && "${td}" == "1" ]]; then
|
||||
local last_td=""
|
||||
last_td="$(TEARDOWN_STATE_JSON="${TEARDOWN_STATE_JSON}" python3 - <<'PY' 2>/dev/null || true
|
||||
import json, os, pathlib
|
||||
p = pathlib.Path(os.environ["TEARDOWN_STATE_JSON"])
|
||||
try:
|
||||
d = json.loads(p.read_text(encoding="utf-8"))
|
||||
print(d.get("verify_teardown", ""))
|
||||
except Exception:
|
||||
pass
|
||||
PY
|
||||
)"
|
||||
if [[ "${last_td}" == "0" ]]; then
|
||||
echo "[WARN] 检测到上次验证使用 VERIFY_TEARDOWN=0:当前虽为 1,但可能存在残留污染" >&2
|
||||
echo "[TIP] 建议:VERIFY_TEARDOWN=1 ./ansible/bin/verify.sh full(或 run-all)以清理并回归" >&2
|
||||
echo "[OC] doc_id=preflight result=verified phase=preflight assertion=teardown_state last_verify_teardown=0 current_verify_teardown=1"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
DOC_ID_EXEC_RE='^(0[1-9]|[1-9][0-9])-(0[1-9]|[1-9][0-9])$'
|
||||
|
||||
is_exec_doc_id() {
|
||||
local doc_id="$1"
|
||||
[[ "$doc_id" =~ $DOC_ID_EXEC_RE ]]
|
||||
}
|
||||
|
||||
list_doc_ids_from_verify_dir() {
|
||||
local series="${1:-}"
|
||||
local id_regex="${2:-}"
|
||||
local exclude_noop="${3:-0}"
|
||||
local require_teardown="${4:-0}"
|
||||
ROOT="${ROOT}" SERIES="${series}" ID_REGEX="${id_regex}" EXCLUDE_NOOP="${exclude_noop}" REQUIRE_TEARDOWN="${require_teardown}" python3 - <<'PY'
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
root = Path(os.environ["ROOT"])
|
||||
verify_dir = root / "ansible" / "playbooks" / "verify"
|
||||
series = os.environ.get("SERIES", "").strip()
|
||||
id_regex = os.environ.get("ID_REGEX", "").strip()
|
||||
exclude_noop = os.environ.get("EXCLUDE_NOOP", "0") == "1"
|
||||
require_teardown = os.environ.get("REQUIRE_TEARDOWN", "0") == "1"
|
||||
|
||||
pat = re.compile(r"^(?P<id>(0[1-9]|[1-9][0-9])-(0[1-9]|[1-9][0-9]))\.yml$")
|
||||
id_pat = re.compile(id_regex) if id_regex else None
|
||||
|
||||
ids = []
|
||||
for p in verify_dir.iterdir():
|
||||
m = pat.match(p.name)
|
||||
if not m:
|
||||
continue
|
||||
doc_id = m.group("id")
|
||||
if series and not doc_id.startswith(f"{series}-"):
|
||||
continue
|
||||
if id_pat and not id_pat.search(doc_id):
|
||||
continue
|
||||
if exclude_noop or require_teardown:
|
||||
content = p.read_text(encoding="utf-8", errors="ignore")
|
||||
if exclude_noop and "noop verify" in content:
|
||||
continue
|
||||
if require_teardown and ("VERIFY_TEARDOWN" not in content and "verify_teardown" not in content):
|
||||
continue
|
||||
ids.append(doc_id)
|
||||
|
||||
for x in sorted(set(ids)):
|
||||
print(x)
|
||||
PY
|
||||
}
|
||||
|
||||
run_preflight() {
|
||||
local inv="${ANSIBLE_INVENTORY:-${ROOT}/ansible/inventory.ini}"
|
||||
oc_failed() {
|
||||
# OC-like preflight line for humans/tools (minimal; stdout is source of truth).
|
||||
local assertion="$1"
|
||||
shift || true
|
||||
echo "[OC] doc_id=preflight result=failed phase=preflight assertion=${assertion} $*"
|
||||
}
|
||||
oc_gated() {
|
||||
local missing="$1"
|
||||
local scope="$2"
|
||||
echo "[OC] doc_id=preflight result=gated phase=preflight assertion=dependency_check missing_dependency=${missing} skip_scope=\"${scope}\""
|
||||
}
|
||||
need_cmd_or_fail() {
|
||||
local cmd="$1"
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "[ERR] 未找到命令:$cmd" >&2
|
||||
oc_failed "missing_cmd" "missing_cmd=${cmd}"
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
need_cmd_or_fail ansible-playbook
|
||||
need_cmd_or_fail ansible
|
||||
|
||||
warn_teardown_mode
|
||||
record_teardown_state
|
||||
|
||||
[[ -f "$inv" ]] || { echo "[ERR] inventory 不存在:$inv" >&2; oc_failed "missing_inventory" "inventory=${inv}"; exit 2; }
|
||||
ansible_lab_check_inventory_keys "$inv" || { oc_failed "inventory_keys" "inventory=${inv}"; exit 2; }
|
||||
|
||||
echo "[INFO] 变量边界:inventory=$inv | group_vars=ansible/group_vars/all.yml | env=ansible/env/.env.verify"
|
||||
echo "[INFO] 关键变量:VERIFY_TEARDOWN=${VERIFY_TEARDOWN:-1} nginx_entry_base=${nginx_entry_base:-<unset>} nodejs_entry_base=${nodejs_entry_base:-<unset>}"
|
||||
|
||||
echo "[RUN] ansible k3s_server -m ping"
|
||||
if ! ansible k3s_server -i "$inv" -m ping; then
|
||||
echo "[ERR] ansible ping 失败:k3s_server 不可达" >&2
|
||||
oc_failed "ansible_ping" "target_group=k3s_server"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Optional cluster-side check (may still fail-fast: control-side hard failure).
|
||||
if [[ "${VERIFY_PREFLIGHT_CLUSTER:-0}" == "1" ]]; then
|
||||
if ! ansible k3s_server -i "$inv" -b -m ansible.builtin.shell -a \
|
||||
'KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get nodes'; then
|
||||
echo "[ERR] kubectl 集群检查失败(VERIFY_PREFLIGHT_CLUSTER=1)" >&2
|
||||
oc_failed "kubectl_get_nodes"
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
# External dependencies: missing deps should not fail preflight (EC2) but must be explicit gated.
|
||||
# We gate only the dependent scopes; runtime verify can still proceed for non-dependent doc_ids.
|
||||
local gated=0
|
||||
local missing_list=()
|
||||
local scope_list=()
|
||||
|
||||
if [[ -z "${ACME_EMAIL:-}" ]]; then
|
||||
gated=1; missing_list+=("acme"); scope_list+=("acme/tls issuance")
|
||||
fi
|
||||
# Epic 4:Traefik ACME DNS-01 仅需 CF_API_TOKEN(见 03-02 ensure secret);ZONE_* 不由 preflight 强门禁。
|
||||
if [[ -z "${CF_API_TOKEN:-}" ]]; then
|
||||
gated=1; missing_list+=("cloudflare"); scope_list+=("cloudflare api token / acme dns01")
|
||||
fi
|
||||
if [[ -z "${NFS_SERVER_IP:-}" || -z "${NFS_EXPORT_PATH:-}" ]]; then
|
||||
gated=1; missing_list+=("nfs"); scope_list+=("nfs pv/pvc")
|
||||
fi
|
||||
if [[ -z "${WORKSTATION_SSH:-}" ]]; then
|
||||
gated=1; missing_list+=("third_party_probe"); scope_list+=("third-party probe (WORKSTATION_SSH e.g. jack@ylc65)")
|
||||
fi
|
||||
|
||||
if [[ "$gated" == "1" ]]; then
|
||||
# Join arrays into readable strings.
|
||||
local missing joined_scope
|
||||
missing="$(IFS=,; echo "${missing_list[*]}")"
|
||||
joined_scope="$(IFS='; '; echo "${scope_list[*]}")"
|
||||
echo "[GATE] preflight external deps missing: ${missing} (scopes: ${joined_scope})"
|
||||
oc_gated "${missing}" "${joined_scope}"
|
||||
echo "[OK] preflight 通过(带门控:gated)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "[OC] doc_id=preflight result=verified phase=preflight assertion=connectivity"
|
||||
echo "[OK] preflight 通过"
|
||||
}
|
||||
|
||||
run_all_verify() {
|
||||
local series="${1:-}"
|
||||
local id_regex="${2:-}"
|
||||
local exclude_noop="${3:-0}"
|
||||
local require_teardown="${4:-0}"
|
||||
local id
|
||||
while IFS= read -r id; do
|
||||
echo ""
|
||||
echo "########################################## $id"
|
||||
ansible_verify "$id"
|
||||
done < <(list_doc_ids_from_verify_dir "$series" "$id_regex" "$exclude_noop" "$require_teardown")
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法:ansible/bin/verify.sh <命令> [...]
|
||||
命令:flow | preflight | full | list | run <XX-YY> | run-all
|
||||
筛选参数:--series <XX> | --id-regex <regex> | --exclude-noop | --require-teardown
|
||||
EOF
|
||||
}
|
||||
|
||||
print_flow() {
|
||||
cat <<EOF
|
||||
1 接入目标环境 inventory + 仓库同步;可选 source ansible/env/.env.verify
|
||||
2 环境与前置清理 轻量:各 verify playbook 的 teardown
|
||||
3 部署 ./ansible/bin/deploy-lab.sh k3s|longhorn|nginx-matrix*
|
||||
4 断言 ./ansible/bin/verify.sh run <XX-YY> / run-all
|
||||
EOF
|
||||
}
|
||||
|
||||
ansible_verify() {
|
||||
local doc_id="$1"
|
||||
if ! is_exec_doc_id "$doc_id"; then
|
||||
echo "[ERR] 非执行域 doc_id:$doc_id(仅允许 XX>0 且 YY>0)" >&2
|
||||
echo "[OC] doc_id=${doc_id} result=failed phase=verify assertion=invalid_doc_id"
|
||||
exit 1
|
||||
fi
|
||||
local inv="${ANSIBLE_INVENTORY:-${ROOT}/ansible/inventory.ini}"
|
||||
local pb_single="${ROOT}/ansible/playbooks/verify/${doc_id}.yml"
|
||||
[[ -f "$pb_single" ]] || { echo "[ERR] verify playbook 不存在:$pb_single" >&2; echo "[OC] doc_id=${doc_id} result=failed phase=verify assertion=missing_playbook"; exit 1; }
|
||||
[[ -f "$inv" ]] || { echo "[ERR] inventory 不存在:$inv" >&2; echo "[OC] doc_id=${doc_id} result=failed phase=verify assertion=missing_inventory"; exit 1; }
|
||||
local td="${VERIFY_TEARDOWN:-1}"
|
||||
local run_log
|
||||
run_log="$(mktemp)"
|
||||
echo "[RUN] ansible-playbook -i $inv -e VERIFY_TEARDOWN=$td $pb_single"
|
||||
if ansible-playbook -i "$inv" -e "VERIFY_TEARDOWN=$td" "$pb_single" 2>&1 | tee "$run_log"; then
|
||||
if grep -q '\[GATE\]' "$run_log"; then
|
||||
echo "[OC] doc_id=${doc_id} result=gated phase=verify assertion=playbook_gated"
|
||||
else
|
||||
# OC1: stable parse fields. OC3 evidence points to playbook output sections.
|
||||
echo "[OC] doc_id=${doc_id} result=verified phase=verify assertion=playbook_success"
|
||||
echo "[OC-EVIDENCE] doc_id=${doc_id} kind=cluster summary=\"see kubectl/assert output in playbook logs\""
|
||||
echo "[OC-EVIDENCE] doc_id=${doc_id} kind=entry summary=\"see http/tls/assert output in playbook logs\""
|
||||
fi
|
||||
else
|
||||
echo "[OC] doc_id=${doc_id} result=failed phase=verify assertion=playbook_failed"
|
||||
rm -f "$run_log"
|
||||
return 1
|
||||
fi
|
||||
rm -f "$run_log"
|
||||
}
|
||||
|
||||
main() {
|
||||
load_env
|
||||
local cmd="${1:-}"
|
||||
shift || true
|
||||
local series=""
|
||||
local id_regex=""
|
||||
local exclude_noop=0
|
||||
local require_teardown=0
|
||||
parse_filter_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--series) series="${2:-}"; shift 2 ;;
|
||||
--id-regex) id_regex="${2:-}"; shift 2 ;;
|
||||
--exclude-noop) exclude_noop=1; shift ;;
|
||||
--require-teardown) require_teardown=1; shift ;;
|
||||
*) echo "[ERR] 未知参数:$1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
case "$cmd" in
|
||||
""|-h|--help) usage ;;
|
||||
flow) print_flow ;;
|
||||
preflight) run_preflight ;;
|
||||
full) parse_filter_args "$@"; run_preflight; run_all_verify "$series" "$id_regex" "$exclude_noop" "$require_teardown" ;;
|
||||
list) parse_filter_args "$@"; list_doc_ids_from_verify_dir "$series" "$id_regex" "$exclude_noop" "$require_teardown" ;;
|
||||
run) local doc_id="${1:?need doc_id like 02-05}"; ansible_verify "$doc_id" ;;
|
||||
run-all) parse_filter_args "$@"; run_all_verify "$series" "$id_regex" "$exclude_noop" "$require_teardown" ;;
|
||||
*) echo "[ERR] unknown cmd: $cmd" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
128
ansible/env/.env.verify.example
vendored
Normal file
128
ansible/env/.env.verify.example
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
# 验证矩阵 / 编排脚本用环境变量模板(example)
|
||||
# ---------------------------------------------------------------------------
|
||||
# 约定:本文件只写“值”(KEY=VALUE),不写默认展开/命令替换等执行逻辑。
|
||||
#
|
||||
# 使用(必须在仓库根目录执行):
|
||||
# cp ansible/env/.env.verify.example ansible/env/.env.verify
|
||||
# set -a && source ansible/env/.env.verify && set +a
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# =========================
|
||||
# 1) 你只需要改这一段(值)
|
||||
# =========================
|
||||
|
||||
# --- SSH ---
|
||||
# K3S_SSH_KEY_DIR:存放 ssh key 的目录
|
||||
K3S_SSH_KEY_DIR=$HOME/.ssh
|
||||
# K3S_SSH_KEY_PREFIX:key 前缀(脚本会按此前缀拼接具体节点 key)
|
||||
K3S_SSH_KEY_PREFIX=id_ed25519_k3s_
|
||||
# SSH_USER:ssh 登录用户名
|
||||
SSH_USER=jack
|
||||
# TIMEOUT_SEC:常用探测/连接超时时间(秒)
|
||||
TIMEOUT_SEC=5
|
||||
|
||||
# --- Ansible(控制端)---
|
||||
# ANSIBLE_INVENTORY:inventory 路径(相对仓库根);一般无需改
|
||||
ANSIBLE_INVENTORY=ansible/inventory.ini
|
||||
# ANSIBLE_LOCAL_TMP:可选;控制端无法写 ~/.ansible 时设为仓库内路径,如 $PWD/.ansible-tmp(见 docs/00-03)
|
||||
|
||||
# --- 01-01 / 01-02:集群、kubectl 与 data-dir(k3s,共用)---
|
||||
# docs/01-01(控制面)与 docs/01-02(工作节点加入)共用此二项:K3S_SERVER_HOSTNAME = 控制面短主机名(inventory 中 k3s_server,01-02 手工 K3S_URL 指向该节点 6443);K3S_DATA_DIR = 各节点一致的 k3s --data-dir(与 group_vars k3s_data_dir 一致)。verify/01-01 以节点 kubeconfig 为准,playbook 不强制从 env 读此二项。
|
||||
K3S_SERVER_HOSTNAME=ylc61
|
||||
K3S_DATA_DIR=/storage
|
||||
|
||||
# --- 01-03 / 01-04 armv7(docs/01-03、01-04;docs/00-03 §10.E)---
|
||||
# (可选)SKIP_ARMV7:默认 1 时 verify/01-03、01-04 仅矩阵基线;0 时须配 ARMV7_SSH 等并由 playbook lookup
|
||||
SKIP_ARMV7=1
|
||||
# 01-03:SKIP_ARMV7=0 时需 ARMV7_SSH;verify 调用 ansible/tools/armv7-docker-verify-install.sh(先 docker info,失败再 get.docker.com)。
|
||||
# 01-04:SKIP_ARMV7=0 时需 ARMV7_NFS_SSH(或同机);ARMV7_NFS_EXPORT_PATH、ARMV7_NFS_CLIENT_SUBNET 见 verify/01-04.yml
|
||||
ARMV7_SSH=YOUR_ARMV7_SSH
|
||||
ARMV7_NFS_SSH=YOUR_ARMV7_NFS_SSH
|
||||
ARMV7_NFS_EXPORT_PATH=/sdcard
|
||||
ARMV7_NFS_CLIENT_SUBNET=192.168.2.0/24
|
||||
|
||||
# --- 01-05(docs/01-05:节点初始化与 k3s 安装)---
|
||||
# K3S_PREPARE_STORAGE:deploy-lab.sh k3s 是否在首段跑「准备数据盘」(ansible/bin/deploy-lab.sh 读此变量)
|
||||
# K3S_DO_PREPARE_STORAGE / K3S_DO_INSTALL:verify/01-05.yml 从环境读取(与 ansible-playbook -e 等价)。真正分区还须 group_vars k3s_prepare_storage: true 且 k3s_data_disk_device=/dev/xxx
|
||||
K3S_PREPARE_STORAGE=false
|
||||
K3S_DO_PREPARE_STORAGE=false
|
||||
K3S_DO_INSTALL=false
|
||||
# k3s 安装脚本镜像/超时:在 ansible/group_vars/all.yml 设 k3s_install_mirror: cn、k3s_install_curl_max_time 等(非本 env 变量);或 ansible-playbook … -e k3s_install_mirror=cn
|
||||
|
||||
# --- deploy-lab.sh(铺栈,docs/00-03 / project-context)---
|
||||
# DEPLOY_VERIFY_TEARDOWN:deploy-lab 传入 playbook 的 VERIFY_TEARDOWN,默认 0(保留已部署资源)
|
||||
DEPLOY_VERIFY_TEARDOWN=0
|
||||
|
||||
# --- 01-06 集群外探测 SSH(docs/01-06、00-03)---
|
||||
# WORKSTATION_SSH:在 **Linux 工作机**上执行集群外 curl 等的一行 ssh(示例 ylc65,见 docs/00-02);可改为 user@<你的工作机主机名>。含空格必须加引号。(旧名 ONECLOUD_SSH 已弃用)
|
||||
WORKSTATION_SSH="ssh -o BatchMode=yes jack@ylc65"
|
||||
|
||||
# --- 验证入口与 preflight(02-xx / 04-xx 共用)---
|
||||
# nginx_entry_base、nodejs_entry_base:HTTP 验证入口基址(按 ingress/负载均衡填写)。nginx 矩阵(02-01~02-04)为集群内临时 Pod 直连 nginx-mX.default.svc。
|
||||
# VERIFY_TEARDOWN:verify.sh 默认 1(清理现场);调试可设 0(保留现场,可能污染后续用例)
|
||||
VERIFY_TEARDOWN=1
|
||||
# VERIFY_PREFLIGHT_CLUSTER:默认 0(离线/轻量 preflight);设 1 时 preflight 在控制节点执行 kubectl get nodes(见 docs/00-03)
|
||||
VERIFY_PREFLIGHT_CLUSTER=0
|
||||
nginx_entry_base=http://192.168.2.61
|
||||
nodejs_entry_base=http://192.168.2.61
|
||||
|
||||
# --- 03-08 k3s HA(可选·预留)---
|
||||
# (可选)SKIP_HA:当前 verify playbook 未 lookup;仅与 docs/03-08 及 HA 类备忘对齐
|
||||
SKIP_HA=1
|
||||
|
||||
# --- 03-09 GitOps(可选·预留)---
|
||||
# (可选)SKIP_GITOPS:当前 verify playbook 未 lookup;仅与 docs/03-09 备忘对齐
|
||||
SKIP_GITOPS=1
|
||||
|
||||
# --- Cloudflare(CF API / Zone)---
|
||||
# 03-02 / 03-03:ACME DNS-01 需 CF_API_TOKEN;ZONE_* 为手工/Token 校验辅助,preflight 不强门禁(verify.sh 注释)
|
||||
# CF_API_TOKEN:Cloudflare API Token(敏感信息)
|
||||
CF_API_TOKEN=YOUR_CF_API_TOKEN
|
||||
# ZONE_NAME / ZONE_ID:Cloudflare Zone 信息(可选;预留,playbook 未 lookup)
|
||||
ZONE_NAME=jackadam.top
|
||||
ZONE_ID=YOUR_ZONE_ID
|
||||
|
||||
# --- 03-02 / 03-03 ACME 与 Traefik ---
|
||||
# 03-02 / 03-03:ACME_EMAIL 为 Let's Encrypt 注册邮箱(verify 必填)。ACME_CA_STAGING=1 使用 staging CA。
|
||||
# TRAEFIK_NAMESPACE:预留(playbook 中 Traefik 固定 kube-system,未读此 env)
|
||||
ACME_EMAIL=you@example.com
|
||||
ACME_CA_STAGING=0
|
||||
TRAEFIK_NAMESPACE=kube-system
|
||||
# TRAEFIK_DASHBOARD_VERIFY_URL:03-03 验收 Dashboard HTTP 探针完整 URL(可选;未设则按 k3s_server_ip/dashboard/)
|
||||
# TRAEFIK_DASHBOARD_VERIFY_URL=http://192.168.2.61/dashboard/
|
||||
|
||||
# --- TLS 域名(预留)---
|
||||
# VERIFY_TLS_HOSTS:手工 openssl/curl 对照用;03-02 TLS 矩阵域名为清单内嵌,playbook 未读此变量
|
||||
VERIFY_TLS_HOSTS=test01.jackadam.top,test02.jackadam.top,test03.jackadam.top,test04.jackadam.top
|
||||
|
||||
# --- 03-02(nginx 矩阵 TLS 可选)---
|
||||
# 03-02:NGINX_MATRIX_TLS_ENABLE=true 时部署 TLS+HTTP nginx 矩阵(改 default;与 deploy-lab.sh nginx-matrix-tls 一致)。
|
||||
NGINX_MATRIX_TLS_ENABLE=false
|
||||
|
||||
# --- 03-04 Cloudflare Tunnel(docs/03-04)---
|
||||
# HTTPS 探针需 CF_TUNNEL_TEST_URL 或 CF_TUNNEL_TEST_HOST(二选一;皆缺则 [GATE])。TUNNEL_TOKEN 与集群 kube-system Secret cloudflared-credentials 二选一。
|
||||
TUNNEL_TOKEN=YOUR_TUNNEL_TOKEN
|
||||
# CF_TUNNEL_TEST_URL=https://your-tunnel-host.example.com/
|
||||
CF_TUNNEL_TEST_HOST=traefik.jackadam.top
|
||||
# CF_TUNNEL_CURL_INSECURE=1 — 03-04 探针 curl 使用 -k(排障用)
|
||||
|
||||
# --- 03-05 ---
|
||||
# 03-05:LOCAL_PATH_APPLY_LAB_CONFIG=true 时注入 local-path lab ConfigMap 并 rollout restart provisioner。
|
||||
LOCAL_PATH_APPLY_LAB_CONFIG=false
|
||||
|
||||
# --- NFS(docs/03-06)---
|
||||
# verify/03-06.yml:NFS_SERVER_IP + NFS_EXPORT_PATH 均非空才跑 PV/PVC + Job;任一为空则 [GATE]。NFS_SERVER_HOST 仅与文档/运维备注对齐,playbook 不读取。
|
||||
NFS_SERVER_HOST=onecloud
|
||||
NFS_SERVER_IP=onecloud
|
||||
NFS_EXPORT_PATH=/export/k3s
|
||||
|
||||
# --- Longhorn(预留)---
|
||||
# LONGHORN_NAMESPACE:与 docs/03-07 叙述对齐;命名空间以 playbook/group_vars 为准,当前 verify 未 lookup 此键
|
||||
LONGHORN_NAMESPACE=longhorn-system
|
||||
|
||||
# --- 04-07 / 04-12 NodeJS TLS(docs/04-12、00-03)---
|
||||
# 04-12:NODEJS_TLS_ENTRY_BASE + NODEJS_TLS_HOST 时跑 tls-openssl-sni + HTTPS 断言;无 Secret 时可 CREATE_NODEJS_DEMO_TLS_SECRET=1 自签。
|
||||
# NODEJS_TLS_ENTRY_BASE=https://192.168.2.61:443
|
||||
# NODEJS_TLS_HOST=app.example.local
|
||||
# CREATE_NODEJS_DEMO_TLS_SECRET=1
|
||||
# NODEJS_TLS_CURL_INSECURE=1
|
||||
9
ansible/files/01-01/README.md
Normal file
9
ansible/files/01-01/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 01-01(单控制节点安装)
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `k3s-server-install.example.sh` | 默认或 `--data-dir=/storage` 安装片段备忘 |
|
||||
|
||||
- **手动**:在控制节点按 [docs/01-01-k3s-控制节点含traefik.md](../../../docs/01-01-k3s-控制节点含traefik.md) 执行;可与本目录示例对照。
|
||||
- **自动**:`./ansible/bin/verify.sh run 01-01`(专用 playbook:`kubectl` 断言;与本目录 shell 示例共用真源路径)。
|
||||
- 本篇**无** Kubernetes 应用清单;扩展名 `.sh` 不会进入 `kubectl apply --dry-run` 列表。
|
||||
11
ansible/files/01-01/k3s-server-install.example.sh
Normal file
11
ansible/files/01-01/k3s-server-install.example.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
# 控制节点安装 k3s server(示例)— 真源目录 ansible/files/01-01/
|
||||
# 详见:docs/01-01-k3s-控制节点含traefik.md
|
||||
|
||||
# 方案一:默认数据目录
|
||||
# curl -sfL https://get.k3s.io | sh -
|
||||
|
||||
# 方案二:数据盘
|
||||
# curl -sfL https://get.k3s.io | sh -s - server --data-dir=/storage
|
||||
|
||||
echo "[INFO] 取消注释其一并在节点上执行;token 路径随方案在文档中说明。"
|
||||
8
ansible/files/01-02/README.md
Normal file
8
ansible/files/01-02/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# 01-02(工作节点加入 + Traefik 基线)
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `k3s-agent-join.example.sh` | worker 使用环境变量或 `agent --data-dir` 加入集群的片段 |
|
||||
|
||||
- **手动**:按 [docs/01-02-k3s-工作节点.md](../../../docs/01-02-k3s-工作节点.md) 在 worker 执行;替换 `K3S_URL`、`TOKEN` 与 IP。
|
||||
- **自动**:`./ansible/bin/verify.sh run 01-02`(与手工步骤共用本目录作为命令真源备忘)。
|
||||
17
ansible/files/01-02/k3s-agent-join.example.sh
Normal file
17
ansible/files/01-02/k3s-agent-join.example.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
# 工作节点加入 k3s(示例)— ansible/files/01-02/
|
||||
# 详见:docs/01-02-k3s-工作节点.md
|
||||
|
||||
# 方案一:默认数据目录
|
||||
# curl -sfL https://get.k3s.io | \
|
||||
# K3S_URL=https://192.168.2.61:6443 \
|
||||
# K3S_TOKEN=<TOKEN> \
|
||||
# sh -
|
||||
|
||||
# 方案二:数据盘
|
||||
# curl -sfL https://get.k3s.io | sh -s - agent \
|
||||
# --data-dir=/storage \
|
||||
# --server https://192.168.2.61:6443 \
|
||||
# --token <TOKEN>
|
||||
|
||||
echo "[INFO] 将占位符替换为控制面地址与 token 后执行。"
|
||||
6
ansible/files/01-03/README.md
Normal file
6
ansible/files/01-03/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 01-03(armv7 独立 Docker)
|
||||
|
||||
- **手动**:在 armv7 主机按 [docs/01-03-armv7-standalone-docker.md](../../../docs/01-03-armv7-standalone-docker.md)(**get.docker.com** 官方脚本 + 先 `docker info` 再决定是否安装)。
|
||||
- **远程脚本**:仓库根执行 [ansible/tools/armv7-docker-verify-install.sh](../../tools/armv7-docker-verify-install.sh)(与文档流程一致;`ARMV7_SSH='ssh …' ./ansible/tools/...`)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 01-03`(`SKIP_ARMV7=0` 时调用上述脚本)。
|
||||
- 本篇无通用 K8s 清单;若后续补充 compose 或单元脚本,请用 `.example.` 命名或放在非 `.yml`/`.yaml` 扩展名以避免误 dry-run。
|
||||
0
ansible/files/01-04/.gitkeep
Normal file
0
ansible/files/01-04/.gitkeep
Normal file
6
ansible/files/01-05/README.md
Normal file
6
ansible/files/01-05/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 01-05(Ansible 一键装集群)
|
||||
|
||||
- **真源 playbook**:`ansible/playbooks/verify/01-05.yml`(与 `deploy-lab.sh` 调用一致)。
|
||||
- **文档**:[docs/01-05-节点初始化-ansible-实践.md](../../../docs/01-05-节点初始化-ansible-实践.md)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 01-05` 或 `./ansible/bin/deploy-lab.sh k3s`。
|
||||
- 本目录用于与 `doc_id` 三元契约对齐;集群对象由 playbook / 其它 `ansible/files` 篇生成,此处可不放置额外 YAML。
|
||||
12
ansible/files/01-06/README.md
Normal file
12
ansible/files/01-06/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 01-06(OpenWrt HAProxy)
|
||||
|
||||
- **说明与选用**:[`docs/01-06-openwrt-haproxy.md`](../../../docs/01-06-openwrt-haproxy.md)(文首有各 `*.cfg` 对照表)。
|
||||
- **本目录**:HAProxy 示例配置(非 K8s YAML);复制到 OpenWrt 后改 IP/端口并 `haproxy -c -f …` 校验。
|
||||
|
||||
| 文件 | 用途摘要 |
|
||||
|------|----------|
|
||||
| `haproxy-no-check.cfg` | 最简,无 check |
|
||||
| `haproxy-http.cfg` | 80 明文 httpchk |
|
||||
| `haproxy-tls.cfg` | 443 TCP + ssl-hello-chk |
|
||||
| `haproxy-https.cfg` | 443 应用层 HTTPS 检查(HAProxy 终结 TLS) |
|
||||
| `haproxy-proxy-http-tls.cfg` | 检查 + PROXY v2 |
|
||||
@@ -1,6 +1,6 @@
|
||||
# 01-07 HAProxy - 3.2 HTTP 健康检查(80 明文)
|
||||
# 01-06 HAProxy - 3.2 HTTP 健康检查(80 明文)
|
||||
# backend k3s_http 增加 option httpchk GET /
|
||||
# 文档:docs/01-07-openwrt-haproxy.md 第 3.2 节
|
||||
# 文档:docs/01-06-openwrt-haproxy.md 第 3.2 节
|
||||
global
|
||||
log /dev/log local0
|
||||
maxconn 4096
|
||||
@@ -1,8 +1,8 @@
|
||||
# 01-07 HAProxy - 3.4 HTTPS 健康检查(443 应用层,HAProxy 终结 TLS,由 HAProxy 提供证书)
|
||||
# 01-06 HAProxy - 3.4 HTTPS 健康检查(443 应用层,HAProxy 终结 TLS,由 HAProxy 提供证书)
|
||||
# frontend 需 bind *:443 ssl,backend mode http 连 K3s:443 做 HTTP over TLS 检查
|
||||
# 将 your-ingress.example.com 改为实际 Host;将 /etc/ssl/haproxy.pem 改为实际证书路径
|
||||
# 自签/内网 CA 用 verify none,生产建议 ca-file
|
||||
# 文档:docs/01-07-openwrt-haproxy.md 第 3.4 节
|
||||
# 文档:docs/01-06-openwrt-haproxy.md 第 3.4 节
|
||||
global
|
||||
log /dev/log local0
|
||||
maxconn 4096
|
||||
@@ -1,5 +1,5 @@
|
||||
# 01-07 OpenWrt HAProxy 负载均衡 - 原生最简(无健康检查)
|
||||
# 文档:docs/01-07-openwrt-haproxy.md 第 2 节
|
||||
# 01-06 OpenWrt HAProxy 负载均衡 - 原生最简(无健康检查)
|
||||
# 文档:docs/01-06-openwrt-haproxy.md 第 2 节
|
||||
# 将 192.168.2.61~64 按实际 K3s 节点 IP 修改
|
||||
# 如需健康检查,见第 3 节对应 cfg
|
||||
global
|
||||
@@ -1,6 +1,6 @@
|
||||
# 01-07 HAProxy - 健康检查升级(HTTP+TLS)+ PROXY Protocol
|
||||
# 01-06 HAProxy - 健康检查升级(HTTP+TLS)+ PROXY Protocol
|
||||
# 组合:k3s_http 用 option httpchk,k3s_https 用 ssl-hello-chk,均带 send-proxy-v2
|
||||
# 文档:docs/01-07-openwrt-haproxy.md 第 5 节「健康检查与 PROXY 组合」
|
||||
# 文档:docs/01-06-openwrt-haproxy.md 第 5 节「健康检查与 PROXY 组合」
|
||||
global
|
||||
log /dev/log local0
|
||||
maxconn 4096
|
||||
@@ -1,6 +1,6 @@
|
||||
# 01-07 HAProxy - 3.3 TLS 健康检查(443 握手,mode tcp)
|
||||
# 01-06 HAProxy - 3.3 TLS 健康检查(443 握手,mode tcp)
|
||||
# backend k3s_https 增加 option ssl-hello-chk
|
||||
# 文档:docs/01-07-openwrt-haproxy.md 第 3.3 节
|
||||
# 文档:docs/01-06-openwrt-haproxy.md 第 3.3 节
|
||||
global
|
||||
log /dev/log local0
|
||||
maxconn 4096
|
||||
9
ansible/files/01-07/README.md
Normal file
9
ansible/files/01-07/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 01-07 双控制节点 HA(手工演练为主)
|
||||
|
||||
本目录用于满足 `doc_id=01-07` 的真源目录一致性约束。
|
||||
|
||||
当前 `01-07` 主要是手工 runbook(切换/演练类),自动验证入口为:
|
||||
|
||||
- `ansible/playbooks/verify/01-07.yml`(文档存在性与说明提示)
|
||||
|
||||
如后续将 01-07 演练步骤自动化,可在本目录新增对应清单与配置文件。
|
||||
101
ansible/files/02-01/01-control-ingress.yaml
Normal file
101
ansible/files/02-01/01-control-ingress.yaml
Normal file
@@ -0,0 +1,101 @@
|
||||
# 02-05: Nginx + 控制节点 + Ingress(M1)
|
||||
# 路径 /demo-m1,随机一台控制节点(nodeSelector + toleration,控制节点常有 NoSchedule 污点)
|
||||
# ConfigMap:首页 + default.conf(单文件 subPath 挂载,与 M2~M4 一致,便于 nginx 后续扩展)
|
||||
---
|
||||
apiVersion: v1 # ConfigMap 使用的 API 版本
|
||||
kind: ConfigMap # 配置资源类型:ConfigMap
|
||||
metadata: # 对该 ConfigMap 的标识信息
|
||||
name: nginx-m1-html # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # ConfigMap 数据键值区
|
||||
index.html: | # HTML 内容:会挂载到 nginx 的网页目录
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="utf-8"><title>M1</title></head>
|
||||
<body><h1>M1</h1><p>控制节点 + Ingress</p><p><strong>Backend: M1</strong></p></body></html>
|
||||
default.conf: | # nginx 配置:通过 subPath 单文件挂载到 conf.d/default.conf
|
||||
server { listen 80 default_server; server_name _; root /usr/share/nginx/html; index index.html; location / { add_header X-Backend "M1"; try_files $uri $uri/ /index.html; } }
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment 使用的 API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 标识信息
|
||||
name: nginx-m1 # Deployment 名称
|
||||
namespace: default # 部署命名空间
|
||||
labels: # 额外标签(用于检索/筛选)
|
||||
app: nginx-m1 # 应用标签
|
||||
matrix: "02-05-m1" # 矩阵编号标签(用于你后续调试/统计)
|
||||
spec: # Deployment 期望状态
|
||||
replicas: 1 # 副本数:本例为 1(便于对应路径验证)
|
||||
selector: # Deployment 用于选择 Pod 的条件
|
||||
matchLabels: # 标签匹配集合(用于选中模板 Pod)
|
||||
app: nginx-m1 # 必须与 template.metadata.labels 对上
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 的元信息
|
||||
labels: # Pod 标签
|
||||
app: nginx-m1 # Pod 标签
|
||||
spec: # Pod 规范
|
||||
nodeSelector: # 节点选择:固定跑在 control-plane 上
|
||||
node-role.kubernetes.io/control-plane: "" # 选择带 control-plane 角色标签的节点
|
||||
tolerations: # 容忍污点:让 Pod 能调度到 control-plane
|
||||
- key: node-role.kubernetes.io/control-plane # 污点 key
|
||||
operator: Exists # 存在即匹配
|
||||
effect: NoSchedule # 匹配 NoSchedule 污点效果
|
||||
volumes: # Pod 内卷定义
|
||||
- name: html # 卷名:给 volumeMounts 引用
|
||||
configMap: # 卷来源:ConfigMap
|
||||
name: nginx-m1-html # 引用的 ConfigMap 名称
|
||||
containers: # 容器列表
|
||||
- name: nginx # 容器名
|
||||
image: nginx:alpine # nginx 镜像
|
||||
ports: # 容器端口列表
|
||||
- containerPort: 80 # nginx HTTP 端口
|
||||
volumeMounts: # 容器内挂载点列表
|
||||
- name: html # 对应 volumes[].name
|
||||
mountPath: /usr/share/nginx/html/index.html # 挂载到网页文件路径
|
||||
subPath: index.html # 从 ConfigMap 里选取单个 key
|
||||
readOnly: true # 只读挂载(配置文件更安全)
|
||||
- name: html # 第二处也使用同一个卷
|
||||
mountPath: /etc/nginx/conf.d/default.conf # nginx 配置文件路径
|
||||
subPath: default.conf # 从 ConfigMap 里选取对应 key
|
||||
readOnly: true # 只读挂载
|
||||
---
|
||||
apiVersion: v1 # Service 使用的 API 版本
|
||||
kind: Service # 网络抽象:把 Pod 暴露成稳定访问入口
|
||||
metadata: # Service 标识
|
||||
name: nginx-m1 # Service 名称
|
||||
namespace: default # Service 所在命名空间
|
||||
spec: # Service 期望状态
|
||||
selector: # Service 按标签选择后端 Pod
|
||||
app: nginx-m1 # 选择 nginx-m1 Pod
|
||||
ports: # Service 端口映射
|
||||
- port: 80 # Service 端口
|
||||
targetPort: 80 # 转发到 Pod 的端口
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1 # Traefik Middleware 使用的 API 版本
|
||||
kind: Middleware # 路由中间件:stripPrefix
|
||||
metadata: # Middleware 标识
|
||||
name: stripprefix-m1 # Middleware 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Middleware 配置
|
||||
stripPrefix: # 去掉前缀
|
||||
prefixes: # 要剔除的前缀列表
|
||||
- /demo-m1 # 本矩阵的路径前缀
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress 使用的 API 版本
|
||||
kind: Ingress # 入口资源:把路径转发到 Service
|
||||
metadata: # Ingress 标识
|
||||
name: nginx-m1 # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Ingress 注解:Traefik 用来绑定中间件
|
||||
traefik.ingress.kubernetes.io/router.middlewares: default-stripprefix-m1@kubernetescrd # 绑定 stripprefix-m1
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 规则
|
||||
paths: # 路径匹配列表
|
||||
- path: /demo-m1 # 匹配路径
|
||||
pathType: Prefix # 前缀匹配类型
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nginx-m1 # Service 名
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/02-01/README.md
Normal file
6
ansible/files/02-01/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 02-01(nginx 分课)
|
||||
|
||||
本目录 YAML 与 `ansible/files/02-05/` 中对应课节清单为**同构副本**,专供本 `doc_id` 解耦学习与手工复制。
|
||||
|
||||
- **手动**:将清单拷到目标机路径,按文档改字段后执行 `kubectl` / bash(不必使用 verify)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 02-01`。
|
||||
95
ansible/files/02-02/02-control-ingressroute.yaml
Normal file
95
ansible/files/02-02/02-control-ingressroute.yaml
Normal file
@@ -0,0 +1,95 @@
|
||||
# 03-02: Nginx + 控制节点 + IngressRoute(M2)
|
||||
# 路径 /demo-m2,指定一台控制节点(按实际 FQDN 修改 kubernetes.io/hostname)
|
||||
# ConfigMap:首页 + default.conf,X-Backend: M2 便于区分
|
||||
---
|
||||
apiVersion: v1 # ConfigMap 使用的 API 版本
|
||||
kind: ConfigMap # 配置资源类型:ConfigMap
|
||||
metadata: # ConfigMap 标识信息
|
||||
name: nginx-m2-html # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # ConfigMap 数据区
|
||||
index.html: | # HTML 内容:会挂载到 nginx 的网页目录
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="utf-8"><title>M2</title></head>
|
||||
<body><h1>M2</h1><p>控制节点 + IngressRoute</p></body></html>
|
||||
default.conf: | # nginx 配置:通过 subPath 单文件挂载到 conf.d/default.conf
|
||||
server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; location / { add_header X-Backend "M2"; try_files $uri $uri/ /index.html; } }
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment 使用的 API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 标识信息
|
||||
name: nginx-m2 # Deployment 名称
|
||||
namespace: default # 部署命名空间
|
||||
labels: # 标签集合
|
||||
app: nginx-m2 # 应用标签
|
||||
matrix: "02-05-m2" # 矩阵编号标签
|
||||
spec: # Deployment 期望状态
|
||||
replicas: 1 # 副本数:单副本便于验证
|
||||
selector: # Deployment 选择 Pod
|
||||
matchLabels: # 标签匹配集合(用于选中模板 Pod)
|
||||
app: nginx-m2 # 必须与 template.metadata.labels 对上
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nginx-m2 # Pod 标签
|
||||
spec: # Pod 规范
|
||||
nodeSelector: # 固定调度节点(按实际修改)
|
||||
kubernetes.io/hostname: ylc61 # 目标节点主机名
|
||||
volumes: # 卷定义
|
||||
- name: html # 卷名
|
||||
configMap: # 卷来源为 ConfigMap
|
||||
name: nginx-m2-html # 引用的 ConfigMap 名称
|
||||
containers: # 容器列表
|
||||
- name: nginx # 容器名
|
||||
image: nginx:alpine # nginx 镜像
|
||||
ports: # 容器端口声明
|
||||
- containerPort: 80 # nginx 监听端口
|
||||
volumeMounts: # 容器内挂载点
|
||||
- name: html # 对应 volumes[].name
|
||||
mountPath: /usr/share/nginx/html/index.html # 挂到网页文件
|
||||
subPath: index.html # 使用 ConfigMap 的 index.html key
|
||||
readOnly: true # 配置只读挂载
|
||||
- name: html # 第二处配置仍复用该卷
|
||||
mountPath: /etc/nginx/conf.d/default.conf # 挂到 nginx 配置文件
|
||||
subPath: default.conf # 使用 ConfigMap 的 default.conf key
|
||||
readOnly: true # 只读挂载
|
||||
---
|
||||
apiVersion: v1 # Service 使用的 API 版本
|
||||
kind: Service # 网络抽象:为 Pod 提供稳定访问地址
|
||||
metadata: # Service 标识
|
||||
name: nginx-m2 # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 期望状态
|
||||
selector: # 通过标签选择后端 Pod
|
||||
app: nginx-m2 # 选择 app 标签为 nginx-m2 的 Pod
|
||||
ports: # Service 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 80 # 转发到 Pod 容器端口
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1 # Traefik Middleware 使用的 API 版本
|
||||
kind: Middleware # 中间件类型:stripPrefix
|
||||
metadata: # Middleware 标识
|
||||
name: stripprefix-m2 # Middleware 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # 中间件配置
|
||||
stripPrefix: # 去掉路径前缀
|
||||
prefixes: # 需要剔除的前缀列表
|
||||
- /demo-m2 # 本矩阵的路径前缀
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1 # IngressRoute 的 API 版本
|
||||
kind: IngressRoute # 路由资源类型
|
||||
metadata: # IngressRoute 标识
|
||||
name: nginx-m2 # 路由名称
|
||||
namespace: default # 命名空间
|
||||
spec: # 路由规则
|
||||
entryPoints: # Traefik 入口点列表
|
||||
- web # 使用 web entrypoint
|
||||
routes: # 路由列表
|
||||
- match: PathPrefix(`/demo-m2`) # 匹配 /demo-m2 前缀
|
||||
kind: Rule # 规则类型:Rule
|
||||
middlewares: # 绑定中间件(去前缀)
|
||||
- name: stripprefix-m2 # 使用 stripprefix-m2
|
||||
services: # 匹配后转发的服务
|
||||
- name: nginx-m2 # 后端 Service 名称
|
||||
port: 80 # 后端 Service 端口
|
||||
|
||||
6
ansible/files/02-02/README.md
Normal file
6
ansible/files/02-02/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 02-02(nginx 分课)
|
||||
|
||||
本目录 YAML 与 `ansible/files/02-05/` 中对应课节清单为**同构副本**,专供本 `doc_id` 解耦学习与手工复制。
|
||||
|
||||
- **手动**:将清单拷到目标机路径,按文档改字段后执行 `kubectl` / bash(不必使用 verify)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 02-02`。
|
||||
97
ansible/files/02-03/03-worker-ingress.yaml
Normal file
97
ansible/files/02-03/03-worker-ingress.yaml
Normal file
@@ -0,0 +1,97 @@
|
||||
# 03-03: Nginx + 工作节点 + Ingress(M3)
|
||||
# 路径 /demo-m3,随机一台工作节点(nodeSelector: node-role.kubernetes.io/worker)
|
||||
# ConfigMap:首页 + default.conf,X-Backend: M3 便于区分
|
||||
---
|
||||
apiVersion: v1 # ConfigMap 使用的 API 版本
|
||||
kind: ConfigMap # 配置资源类型:ConfigMap
|
||||
metadata: # 对该 ConfigMap 的标识信息
|
||||
name: nginx-m3-html # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # ConfigMap 数据键值区
|
||||
index.html: | # HTML 内容:会挂载到 nginx 网页目录(内部内容行不改动)
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="utf-8"><title>M3</title></head>
|
||||
<body><h1>M3</h1><p>工作节点 + Ingress</p></body></html>
|
||||
default.conf: | # nginx 配置:通过 subPath 单文件挂载到 conf.d/default.conf(内部内容行不改动)
|
||||
server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; location / { add_header X-Backend "M3"; try_files $uri $uri/ /index.html; } }
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment 使用的 API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 标识信息
|
||||
name: nginx-m3 # Deployment 名称
|
||||
namespace: default # 部署命名空间
|
||||
labels: # 额外标签(用于筛选/统计)
|
||||
app: nginx-m3 # 应用标签
|
||||
matrix: "02-05-m3" # 矩阵编号标签
|
||||
spec: # Deployment 期望状态
|
||||
replicas: 1 # 副本数:这里为 1
|
||||
selector: # Deployment 用于选择 Pod 的条件
|
||||
matchLabels: # 标签匹配集合(用于选中模板 Pod)
|
||||
app: nginx-m3 # 必须与 template.metadata.labels 对上
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nginx-m3 # Pod 标签
|
||||
spec: # Pod 规范
|
||||
nodeSelector: # 固定跑到 worker 节点
|
||||
node-role.kubernetes.io/worker: "" # worker 节点 selector
|
||||
volumes: # 卷定义
|
||||
- name: html # 卷名(供 volumeMounts 引用)
|
||||
configMap: # 卷来源:ConfigMap
|
||||
name: nginx-m3-html # 引用的 ConfigMap 名称
|
||||
containers: # 容器列表
|
||||
- name: nginx # 容器名
|
||||
image: nginx:alpine # nginx 镜像
|
||||
ports: # 容器端口声明
|
||||
- containerPort: 80 # nginx HTTP 端口
|
||||
volumeMounts: # 容器内挂载点
|
||||
- name: html # 对应 volumes[].name
|
||||
mountPath: /usr/share/nginx/html/index.html # 挂到网页首页
|
||||
subPath: index.html # 从 ConfigMap 取该 key
|
||||
readOnly: true # 配置只读
|
||||
- name: html # 第二处仍引用同一个卷
|
||||
mountPath: /etc/nginx/conf.d/default.conf # 挂到 nginx 配置文件路径
|
||||
subPath: default.conf # 从 ConfigMap 取该 key
|
||||
readOnly: true # 配置只读
|
||||
---
|
||||
apiVersion: v1 # Service 使用的 API 版本
|
||||
kind: Service # 网络抽象:把 Pod 暴露成稳定访问入口
|
||||
metadata: # Service 标识
|
||||
name: nginx-m3 # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 期望状态
|
||||
selector: # Service 通过标签选中后端 Pod
|
||||
app: nginx-m3 # 选择 app 标签
|
||||
ports: # Service 端口映射列表
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 80 # 转发到 Pod 的容器端口
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1 # Traefik Middleware API 版本
|
||||
kind: Middleware # 中间件类型:stripPrefix
|
||||
metadata: # Middleware 标识
|
||||
name: stripprefix-m3 # 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # 中间件配置
|
||||
stripPrefix: # 去掉指定路径前缀
|
||||
prefixes: # 前缀列表
|
||||
- /demo-m3 # 本矩阵路径前缀
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress 使用的 API 版本
|
||||
kind: Ingress # 入口资源:把路径转发到 Service
|
||||
metadata: # Ingress 标识
|
||||
name: nginx-m3 # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解:绑定中间件
|
||||
traefik.ingress.kubernetes.io/router.middlewares: default-stripprefix-m3@kubernetescrd # 绑定 stripprefix-m3 中间件
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 规则
|
||||
paths: # 路径匹配列表
|
||||
- path: /demo-m3 # 匹配路径
|
||||
pathType: Prefix # 前缀匹配类型
|
||||
backend: # 后端目标
|
||||
service: # 后端是 Service
|
||||
name: nginx-m3 # Service 名称
|
||||
port: # 后端端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/02-03/README.md
Normal file
6
ansible/files/02-03/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 02-03(nginx 分课)
|
||||
|
||||
本目录 YAML 与 `ansible/files/02-05/` 中对应课节清单为**同构副本**,专供本 `doc_id` 解耦学习与手工复制。
|
||||
|
||||
- **手动**:将清单拷到目标机路径,按文档改字段后执行 `kubectl` / bash(不必使用 verify)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 02-03`。
|
||||
95
ansible/files/02-04/04-worker-ingressroute.yaml
Normal file
95
ansible/files/02-04/04-worker-ingressroute.yaml
Normal file
@@ -0,0 +1,95 @@
|
||||
# 03-04: Nginx + 工作节点 + IngressRoute(M4)
|
||||
# 路径 /demo-m4,指定一台工作节点(按实际 FQDN 修改 kubernetes.io/hostname)
|
||||
# ConfigMap:首页 + default.conf,X-Backend: M4 便于区分
|
||||
---
|
||||
apiVersion: v1 # ConfigMap 使用的 API 版本
|
||||
kind: ConfigMap # 配置资源类型:ConfigMap
|
||||
metadata: # ConfigMap 标识信息
|
||||
name: nginx-m4-html # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # ConfigMap 数据区
|
||||
index.html: | # HTML 内容:挂载到 nginx 网页目录(内部内容行不改动)
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="utf-8"><title>M4</title></head>
|
||||
<body><h1>M4</h1><p>工作节点 + IngressRoute</p></body></html>
|
||||
default.conf: | # nginx 配置:通过 subPath 挂载到 conf.d/default.conf(内部内容行不改动)
|
||||
server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; location / { add_header X-Backend "M4"; try_files $uri $uri/ /index.html; } }
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment 使用的 API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 标识信息
|
||||
name: nginx-m4 # Deployment 名称
|
||||
namespace: default # 部署命名空间
|
||||
labels: # 应用标签/矩阵标签
|
||||
app: nginx-m4 # 应用标签
|
||||
matrix: "02-05-m4" # 矩阵编号
|
||||
spec: # Deployment 期望状态
|
||||
replicas: 1 # 副本数
|
||||
selector: # Deployment 选择器
|
||||
matchLabels: # 标签匹配集合(用于选中模板 Pod)
|
||||
app: nginx-m4 # 必须与 template.metadata.labels 对上
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nginx-m4 # Pod 标签
|
||||
spec: # Pod 规范
|
||||
nodeSelector: # 固定运行的工作节点
|
||||
kubernetes.io/hostname: ylc64 # worker 节点主机名
|
||||
volumes: # 卷定义
|
||||
- name: html # 卷名
|
||||
configMap: # 卷来源
|
||||
name: nginx-m4-html # 引用的 ConfigMap 名称
|
||||
containers: # 容器列表
|
||||
- name: nginx # 容器名
|
||||
image: nginx:alpine # nginx 镜像
|
||||
ports: # 容器端口
|
||||
- containerPort: 80 # HTTP 端口
|
||||
volumeMounts: # 容器内挂载
|
||||
- name: html # 引用 volumes[].name
|
||||
mountPath: /usr/share/nginx/html/index.html # 挂到首页文件
|
||||
subPath: index.html # 取 ConfigMap 的 index.html key
|
||||
readOnly: true # 只读
|
||||
- name: html # 仍复用同一个卷
|
||||
mountPath: /etc/nginx/conf.d/default.conf # 挂到 nginx 配置文件
|
||||
subPath: default.conf # 取 ConfigMap 的 default.conf key
|
||||
readOnly: true # 只读
|
||||
---
|
||||
apiVersion: v1 # Service 使用的 API 版本
|
||||
kind: Service # 网络抽象:把 Pod 暴露为稳定入口
|
||||
metadata: # Service 标识
|
||||
name: nginx-m4 # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 期望状态
|
||||
selector: # Service 选择器
|
||||
app: nginx-m4 # 选中后端 Pod
|
||||
ports: # 端口映射列表
|
||||
- port: 80 # Service 端口
|
||||
targetPort: 80 # 转发到 Pod 容器端口
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1 # Traefik Middleware API 版本
|
||||
kind: Middleware # 中间件:stripPrefix
|
||||
metadata: # Middleware 标识
|
||||
name: stripprefix-m4 # 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # 中间件配置
|
||||
stripPrefix: # 去除路径前缀
|
||||
prefixes: # 前缀列表
|
||||
- /demo-m4 # 本矩阵路径前缀
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1 # IngressRoute API 版本
|
||||
kind: IngressRoute # Traefik 路由 CRD
|
||||
metadata: # IngressRoute 标识
|
||||
name: nginx-m4 # 路由名称
|
||||
namespace: default # 命名空间
|
||||
spec: # IngressRoute 规则
|
||||
entryPoints: # 入口点列表
|
||||
- web # web(HTTP)
|
||||
routes: # 路由列表
|
||||
- match: PathPrefix(`/demo-m4`) # 匹配 /demo-m4 前缀
|
||||
kind: Rule # 规则类型
|
||||
middlewares: # 绑定中间件
|
||||
- name: stripprefix-m4 # 需要去前缀
|
||||
services: # 后端服务列表
|
||||
- name: nginx-m4 # Service 名称
|
||||
port: 80 # Service 端口
|
||||
|
||||
6
ansible/files/02-04/README.md
Normal file
6
ansible/files/02-04/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 02-04(nginx 分课)
|
||||
|
||||
本目录 YAML 与 `ansible/files/02-05/` 中对应课节清单为**同构副本**,专供本 `doc_id` 解耦学习与手工复制。
|
||||
|
||||
- **手动**:将清单拷到目标机路径,按文档改字段后执行 `kubectl` / bash(不必使用 verify)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 02-04`。
|
||||
@@ -39,3 +39,8 @@ spec: # chart 注入配置的具体内容
|
||||
nodeSelector: # 把 Traefik Pod 固定到指定节点(配合 RWO 本地存储更安全)
|
||||
kubernetes.io/hostname: ylc61 # 固定节点主机名(按你的实际节点修改)
|
||||
|
||||
# ping 绑定 websecure 时,chart 默认对 8080 做 HTTP /ping;须与 03-03 一致改为 HTTPS:8443
|
||||
deployment:
|
||||
healthchecksPort: 8443
|
||||
healthchecksScheme: HTTPS
|
||||
|
||||
|
||||
@@ -9,13 +9,17 @@ metadata:
|
||||
namespace: kube-system
|
||||
spec:
|
||||
valuesContent: |-
|
||||
# chart 39.x:expose 须为表,布尔会与默认 values 合并冲突并导致 helm upgrade 模板失败
|
||||
ports:
|
||||
web:
|
||||
expose: true
|
||||
expose:
|
||||
default: true
|
||||
websecure:
|
||||
expose: true
|
||||
expose:
|
||||
default: true
|
||||
traefik:
|
||||
expose: true
|
||||
expose:
|
||||
default: true
|
||||
|
||||
additionalArguments:
|
||||
# Dashboard
|
||||
@@ -48,13 +52,20 @@ spec:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: ylc61
|
||||
|
||||
# persistence:将 /data 持久化(local-path PVC),保证 acme.json 落盘
|
||||
# ping 绑定 websecure 时,chart 默认仍对 traefik(8080) 做 HTTP /ping → 404;与 chart 39 对齐探针
|
||||
deployment:
|
||||
healthchecksPort: 8443
|
||||
healthchecksScheme: HTTPS
|
||||
|
||||
# persistence:将 /data 持久化,保证 acme.json 落盘
|
||||
# 显式 local-path:避免集群默认 StorageClass 为 longhorn 等未就绪时 Pod 长期 Pending
|
||||
persistence:
|
||||
enabled: true
|
||||
name: data
|
||||
accessMode: ReadWriteOnce
|
||||
size: 128Mi
|
||||
path: /data
|
||||
storageClass: local-path
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
|
||||
@@ -1,38 +1,31 @@
|
||||
# docs/03-04-k3s-cloudflare-tunnel-配置接入.md — 替换 TUNNEL_TOKEN 后应用
|
||||
apiVersion: v1 # Secret 使用的 Kubernetes API 版本
|
||||
kind: Secret # 资源类型:Secret(用于保存 Cloudflare Tunnel token)
|
||||
metadata: # 元信息(名称/命名空间等)
|
||||
name: cloudflared-credentials # Secret 名称(Deployment 中会引用)
|
||||
namespace: kube-system # Secret 所在命名空间
|
||||
type: Opaque # Secret 类型(普通自定义键值)
|
||||
stringData: # 以字符串方式提供 Secret 数据(便于直接写明文)
|
||||
TUNNEL_TOKEN: "<YOUR_TUNNEL_TOKEN>" # Cloudflare Tunnel Token(用你真实的 token 替换)
|
||||
# docs/03-04-k3s-cloudflare-tunnel-配置接入.md
|
||||
# Secret `cloudflared-credentials`(key=TUNNEL_TOKEN)由 verify playbook / 手工 kubectl create secret 创建,勿与此 Deployment 同 apply,避免覆盖 token。
|
||||
# 参考:ansible/playbooks/verify/03-04.yml → ensure-cloudflared-tunnel-secret
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment 使用的 API 版本
|
||||
kind: Deployment # 工作负载:Deployment(管理 Pod 副本)
|
||||
metadata: # Deployment 元信息
|
||||
name: cloudflared # Deployment 名称
|
||||
namespace: kube-system # 部署到的命名空间
|
||||
spec: # Deployment 期望状态
|
||||
replicas: 1 # 副本数(Tunnel 通常只跑一个副本即可)
|
||||
selector: # Deployment 选择器:匹配 template 的 Pod
|
||||
matchLabels: # 必须与 template.metadata.labels 对齐
|
||||
app: cloudflared # 应用标签
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: cloudflared # 与 selector.matchLabels 相同
|
||||
spec: # Pod 规范
|
||||
containers: # 容器列表
|
||||
- name: cloudflared # 容器名
|
||||
image: cloudflare/cloudflared:latest # cloudflared 镜像
|
||||
args: # 容器启动参数
|
||||
- tunnel # 命令子参数:tunnel
|
||||
- run # 命令子参数:run
|
||||
env: # 环境变量
|
||||
- name: TUNNEL_TOKEN # 容器内使用的环境变量名
|
||||
valueFrom: # 从某个来源取值
|
||||
secretKeyRef: # 从 Secret 的 key 取值
|
||||
name: cloudflared-credentials # Secret 名称
|
||||
key: TUNNEL_TOKEN # Secret 中的 key
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cloudflared
|
||||
namespace: kube-system
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: cloudflared
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cloudflared
|
||||
spec:
|
||||
containers:
|
||||
- name: cloudflared
|
||||
image: cloudflare/cloudflared:latest
|
||||
args:
|
||||
- tunnel
|
||||
- run
|
||||
env:
|
||||
- name: TUNNEL_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: cloudflared-credentials
|
||||
key: TUNNEL_TOKEN
|
||||
|
||||
@@ -4,6 +4,7 @@ kind: PersistentVolume # 资源类型:持久卷(集群级)
|
||||
metadata: # PV 元信息
|
||||
name: nfs-pv-demo # PV 名称
|
||||
spec: # PV 规格
|
||||
storageClassName: "" # 显式禁用默认 StorageClass,供静态绑定 PVC 使用
|
||||
capacity: # 容量声明
|
||||
storage: 20Gi # PV 总容量
|
||||
accessModes: # 访问模式列表
|
||||
@@ -19,6 +20,7 @@ metadata: # PVC 元信息
|
||||
name: nfs-pvc-demo # PVC 名称
|
||||
namespace: default # PVC 所在命名空间
|
||||
spec: # PVC 规格
|
||||
storageClassName: "" # 与 PV 对齐,避免被默认 longhorn class 注入导致绑定失败
|
||||
accessModes: # 访问模式要求
|
||||
- ReadWriteMany # 申请 RWX 访问模式
|
||||
resources: # 资源请求
|
||||
|
||||
27
ansible/files/03-06/nfs-pvc-verify-job.yaml
Normal file
27
ansible/files/03-06/nfs-pvc-verify-job.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
# docs/03-06-k3s-使用nfs存储.md — 自动化验收用:挂载 nfs-pvc-demo 并写文件(OC3 证据)
|
||||
# 与 nfs-pv-pvc-demo.yaml 配合;手动学习 PV/PVC 时可不应用本文件。
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: nfs-pvc-verify-demo
|
||||
namespace: default
|
||||
spec:
|
||||
backoffLimit: 3
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: verify-write
|
||||
image: busybox:1.36
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- echo "ok-$(date +%s)" > /data/.verify-nfs && sync && test -f /data/.verify-nfs
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
readOnly: false
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: nfs-pvc-demo
|
||||
9
ansible/files/03-08/README.md
Normal file
9
ansible/files/03-08/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 03-08(K3s HA 配置与切换)
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `k3s-server-ha-env.example.sh` | 外部 datastore、`tls-san`、第二节点 `K3S_URL`/`TOKEN` 等环境变量示例(**非** Kubernetes 清单) |
|
||||
|
||||
- **手动**:将示例中的连接串、LB IP、token 替换为真实值;与 systemd/k3s 安装参数对照 [docs/03-08-k3s-ha-集群配置与切换.md](../../../docs/03-08-k3s-ha-集群配置与切换.md)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 03-08`(noop + 基线;HA 步骤仍以文档与手工为准)。
|
||||
- 本篇**不提供**可 `kubectl apply` 的 HA 安装真源(控制平面由 k3s 与 datastore 决定)。
|
||||
17
ansible/files/03-08/k3s-server-ha-env.example.sh
Normal file
17
ansible/files/03-08/k3s-server-ha-env.example.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
# k3s 多 server + 外部 datastore 参数备忘(示例,勿直接 source 到生产)
|
||||
# 完整步骤见:docs/03-08-k3s-ha-集群配置与切换.md
|
||||
# 真源目录:ansible/files/03-08/
|
||||
|
||||
# --- 首个 server(示例 IP 请替换)---
|
||||
# export K3S_DATASTORE_ENDPOINT='postgres://k3s:CHANGE_ME@192.168.2.50:5432/k3s?sslmode=disable'
|
||||
# sudo k3s server --datastore-endpoint="$K3S_DATASTORE_ENDPOINT" --tls-san 192.168.2.60
|
||||
|
||||
# --- 第二个 server(经 LB 加入,token 与控制端一致)---
|
||||
# export K3S_URL='https://192.168.2.60:6443'
|
||||
# export K3S_TOKEN='<SAME_TOKEN_AS_SERVER1>'
|
||||
# export K3S_DATASTORE_ENDPOINT='postgres://k3s:CHANGE_ME@192.168.2.50:5432/k3s?sslmode=disable'
|
||||
# sudo k3s server --server "$K3S_URL" --token "$K3S_TOKEN" \
|
||||
# --datastore-endpoint="$K3S_DATASTORE_ENDPOINT" --tls-san 192.168.2.60
|
||||
|
||||
echo "[INFO] 编辑本文件中的占位符后,将命令复制到节点上执行;或写入 systemd ExecStart。"
|
||||
9
ansible/files/03-09/README.md
Normal file
9
ansible/files/03-09/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 03-09(GitOps 框架)
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `argocd-namespace.example.yaml` | 仅创建 `argocd` 命名空间的极简示例(正式安装请用官方 `install.yaml` 或 Helm) |
|
||||
|
||||
- **手动**:集群声明性配置的**主真源**建议在独立 GitOps 仓库(见 [docs/03-09-k3s-gitops-集群配置管理.md](../../../docs/03-09-k3s-gitops-集群配置管理.md));本目录只放与本仓库文档对齐的**示意**文件。
|
||||
- **自动**:`./ansible/bin/verify.sh run 03-09`(noop + 基线)。
|
||||
- 同一套 YAML 路径既可供你 `kubectl apply -f` 试跑,也与自动化验收引用同一目录,避免文档与仓库脱节。
|
||||
8
ansible/files/03-09/argocd-namespace.example.yaml
Normal file
8
ansible/files/03-09/argocd-namespace.example.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
# 极简示例:为后续 Argo CD 安装预留命名空间
|
||||
# 生产请改用官方清单: https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: argocd
|
||||
labels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
59
ansible/files/04-02/04-02-nodejs-demo.yaml
Normal file
59
ansible/files/04-02/04-02-nodejs-demo.yaml
Normal file
@@ -0,0 +1,59 @@
|
||||
# 对应文档:docs/04-02-nodejs-镜像与运行命令.md
|
||||
# 累积:04-01 + 固定镜像 tag、imagePullPolicy、command/args
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Deployment 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # 固定 tag 的 Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略:本地有则不重复拉取
|
||||
command: ["node"] # 主命令
|
||||
args: # 命令参数
|
||||
- "-e" # 执行内联脚本
|
||||
- "require('http').createServer((req,res)=>res.end('Hello from pinned image')).listen(3000)" # Node.js 内联服务逻辑
|
||||
ports: # 容器端口
|
||||
- containerPort: 3000 # 应用监听端口
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 3000 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /node # 匹配路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-02/README.md
Normal file
6
ansible/files/04-02/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-02(nodejs 分课)
|
||||
|
||||
本目录 `04-02-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-02/04-02-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-02`。
|
||||
76
ansible/files/04-03/04-03-nodejs-demo.yaml
Normal file
76
ansible/files/04-03/04-03-nodejs-demo.yaml
Normal file
@@ -0,0 +1,76 @@
|
||||
# 对应文档:docs/04-03-nodejs-环境变量与配置注入.md
|
||||
# 累积:04-02 + ConfigMap + 通过 env 注入 APP_MSG(镜像仍用 18.20-alpine 与 04-02 一致)
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源:ConfigMap
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 注入给应用的消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Deployment 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
env: # 环境变量注入
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从资源引用取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 运行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内部内容不改动)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(3000);
|
||||
ports: # 容器端口
|
||||
- containerPort: 3000 # 应用监听端口
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 3000 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /node # 匹配路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-03/README.md
Normal file
6
ansible/files/04-03/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-03(nodejs 分课)
|
||||
|
||||
本目录 `04-03-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-03/04-03-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-03`。
|
||||
76
ansible/files/04-04/04-04-nodejs-demo.yaml
Normal file
76
ansible/files/04-04/04-04-nodejs-demo.yaml
Normal file
@@ -0,0 +1,76 @@
|
||||
# 对应文档:docs/04-04-nodejs-端口与Service.md
|
||||
# 累积:04-03 + 容器与进程改监听 8080,Service targetPort 对齐
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源:ConfigMap
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 注入给应用的消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Deployment 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
env: # 环境变量注入
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从资源引用取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 运行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内部内容不改动)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 应用监听端口
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /node # 匹配路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-04/README.md
Normal file
6
ansible/files/04-04/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-04(nodejs 分课)
|
||||
|
||||
本目录 `04-04-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-04/04-04-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-04`。
|
||||
83
ansible/files/04-05/04-05-nodejs-demo.yaml
Normal file
83
ansible/files/04-05/04-05-nodejs-demo.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
# 对应文档:docs/04-05-nodejs-资源请求与限制.md
|
||||
# 累积:04-04 + resources.requests/limits
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源:ConfigMap
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 注入给应用的消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Deployment 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
env: # 环境变量注入
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从资源引用取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 运行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内部内容不改动)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 应用监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /node # 匹配路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-05/README.md
Normal file
6
ansible/files/04-05/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-05(nodejs 分课)
|
||||
|
||||
本目录 `04-05-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-05/04-05-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-05`。
|
||||
95
ansible/files/04-06/04-06-nodejs-demo.yaml
Normal file
95
ansible/files/04-06/04-06-nodejs-demo.yaml
Normal file
@@ -0,0 +1,95 @@
|
||||
# 对应文档:docs/04-06-nodejs-探针与健康检查.md
|
||||
# 累积:04-05 + livenessProbe/readinessProbe(端口 8080,路径 /)
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源:ConfigMap
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 注入给应用的消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Deployment 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
env: # 环境变量注入
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从资源引用取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 运行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内部内容不改动)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 应用监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
livenessProbe: # 存活探针(判断容器是否需要重启)
|
||||
httpGet: # 通过 HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 3 # 启动后首次探测延迟
|
||||
periodSeconds: 10 # 探测周期
|
||||
readinessProbe: # 就绪探针(判断是否接收流量)
|
||||
httpGet: # 通过 HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 2 # 启动后首次探测延迟
|
||||
periodSeconds: 5 # 探测周期
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /node # 匹配路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-06/README.md
Normal file
6
ansible/files/04-06/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-06(nodejs 分课)
|
||||
|
||||
本目录 `04-06-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-06/04-06-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-06`。
|
||||
97
ansible/files/04-07/04-07-nodejs-demo.yaml
Normal file
97
ansible/files/04-07/04-07-nodejs-demo.yaml
Normal file
@@ -0,0 +1,97 @@
|
||||
# 对应文档:docs/04-07-nodejs-调度与亲和.md
|
||||
# 累积:04-06 + nodeSelector(默认 ylc62,请改为本集群节点短主机名)
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源:ConfigMap
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 注入给应用的消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Deployment 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
nodeSelector: # 调度到指定节点
|
||||
kubernetes.io/hostname: ylc62 # 节点主机名(按实际修改)
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
env: # 环境变量注入
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从资源引用取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 运行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内部内容不改动)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 应用监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
livenessProbe: # 存活探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 3 # 启动后首次探测延迟
|
||||
periodSeconds: 10 # 探测周期
|
||||
readinessProbe: # 就绪探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 2 # 启动后首次探测延迟
|
||||
periodSeconds: 5 # 探测周期
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /node # 匹配路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-07/README.md
Normal file
6
ansible/files/04-07/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-07(nodejs 分课)
|
||||
|
||||
本目录 `04-07-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-07/04-07-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-07`。
|
||||
110
ansible/files/04-08/04-08-nodejs-demo.yaml
Normal file
110
ansible/files/04-08/04-08-nodejs-demo.yaml
Normal file
@@ -0,0 +1,110 @@
|
||||
# 对应文档:docs/04-08-nodejs-安全上下文.md
|
||||
# 累积:04-07 + pod securityContext.fsGroup、容器 securityContext、只读根、/tmp emptyDir
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源:ConfigMap
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 注入给应用的消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Deployment 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
nodeSelector: # 调度到指定节点
|
||||
kubernetes.io/hostname: ylc62 # 节点主机名(按实际修改)
|
||||
securityContext: # Pod 级安全上下文
|
||||
fsGroup: 1000 # 挂载卷文件组 ID
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
securityContext: # 容器级安全上下文
|
||||
allowPrivilegeEscalation: false # 禁止提权
|
||||
runAsNonRoot: true # 强制非 root 运行
|
||||
runAsUser: 1000 # 运行用户 UID
|
||||
readOnlyRootFilesystem: true # 根文件系统只读
|
||||
env: # 环境变量注入
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从资源引用取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 运行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内部内容不改动)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 应用监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
livenessProbe: # 存活探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 3 # 启动后首次探测延迟
|
||||
periodSeconds: 10 # 探测周期
|
||||
readinessProbe: # 就绪探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 2 # 启动后首次探测延迟
|
||||
periodSeconds: 5 # 探测周期
|
||||
volumeMounts: # 卷挂载
|
||||
- name: tmp # 引用临时卷
|
||||
mountPath: /tmp # 容器内临时目录
|
||||
volumes: # 卷定义
|
||||
- name: tmp # 临时卷名称
|
||||
emptyDir: {} # 空目录卷(Pod 生命周期内)
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /node # 匹配路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-08/README.md
Normal file
6
ansible/files/04-08/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-08(nodejs 分课)
|
||||
|
||||
本目录 `04-08-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-08/04-08-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-08`。
|
||||
128
ansible/files/04-09/04-09-nodejs-demo.yaml
Normal file
128
ansible/files/04-09/04-09-nodejs-demo.yaml
Normal file
@@ -0,0 +1,128 @@
|
||||
# 对应文档:docs/04-09-nodejs-存储与卷.md
|
||||
# 累积:04-08 + PVC nodejs-demo-data(默认 storageClassName: local-path,可按集群改为 longhorn 等)+ 挂载 /data
|
||||
apiVersion: v1 # PVC API 版本
|
||||
kind: PersistentVolumeClaim # 持久卷声明
|
||||
metadata: # PVC 元信息
|
||||
name: nodejs-demo-data # PVC 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # PVC 规格
|
||||
accessModes: # 访问模式
|
||||
- ReadWriteOnce # RWO:同一时间仅单节点挂载读写
|
||||
storageClassName: local-path # 存储类(按集群可改)
|
||||
resources: # 资源请求
|
||||
requests: # 配额请求
|
||||
storage: 1Gi # 申请容量
|
||||
---
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 示例消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Pod 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
nodeSelector: # 节点选择
|
||||
kubernetes.io/hostname: ylc62 # 固定到指定节点(按实际修改)
|
||||
securityContext: # Pod 级安全上下文
|
||||
fsGroup: 1000 # 挂载卷文件组 ID
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
securityContext: # 容器级安全上下文
|
||||
allowPrivilegeEscalation: false # 禁止提权
|
||||
runAsNonRoot: true # 非 root 运行
|
||||
runAsUser: 1000 # 运行用户 UID
|
||||
readOnlyRootFilesystem: true # 根文件系统只读
|
||||
env: # 环境变量
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从引用源取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 执行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内容保持原样)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
livenessProbe: # 存活探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 3 # 初始延迟
|
||||
periodSeconds: 10 # 探测周期
|
||||
readinessProbe: # 就绪探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 2 # 初始延迟
|
||||
periodSeconds: 5 # 探测周期
|
||||
volumeMounts: # 卷挂载
|
||||
- name: tmp # 临时卷名称
|
||||
mountPath: /tmp # 容器内临时目录
|
||||
- name: data # 数据卷名称
|
||||
mountPath: /data # 容器内数据目录
|
||||
volumes: # 卷定义
|
||||
- name: tmp # 临时卷
|
||||
emptyDir: {} # 空目录卷
|
||||
- name: data # 数据卷
|
||||
persistentVolumeClaim: # 卷来源为 PVC
|
||||
claimName: nodejs-demo-data # 绑定 PVC 名称
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /node # 路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-09/README.md
Normal file
6
ansible/files/04-09/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-09(nodejs 分课)
|
||||
|
||||
本目录 `04-09-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-09/04-09-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-09`。
|
||||
129
ansible/files/04-10/04-10-nodejs-demo.yaml
Normal file
129
ansible/files/04-10/04-10-nodejs-demo.yaml
Normal file
@@ -0,0 +1,129 @@
|
||||
# 对应文档:docs/04-10-nodejs-Ingress与Traefik.md
|
||||
# 累积:04-09 + Ingress 增加 host、path 改为 /api(访问需 Host: app.example.local)
|
||||
apiVersion: v1 # PVC API 版本
|
||||
kind: PersistentVolumeClaim # 持久卷声明
|
||||
metadata: # PVC 元信息
|
||||
name: nodejs-demo-data # PVC 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # PVC 规格
|
||||
accessModes: # 访问模式
|
||||
- ReadWriteOnce # RWO:同一时间仅单节点挂载读写
|
||||
storageClassName: local-path # 存储类
|
||||
resources: # 资源请求
|
||||
requests: # 配额请求
|
||||
storage: 1Gi # 申请容量
|
||||
---
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 示例消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 1 # 副本数
|
||||
selector: # Pod 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
nodeSelector: # 节点选择
|
||||
kubernetes.io/hostname: ylc62 # 固定到指定节点(按实际修改)
|
||||
securityContext: # Pod 级安全上下文
|
||||
fsGroup: 1000 # 挂载卷文件组 ID
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
securityContext: # 容器级安全上下文
|
||||
allowPrivilegeEscalation: false # 禁止提权
|
||||
runAsNonRoot: true # 非 root 运行
|
||||
runAsUser: 1000 # 运行用户 UID
|
||||
readOnlyRootFilesystem: true # 根文件系统只读
|
||||
env: # 环境变量
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从引用源取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 执行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内容保持原样)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
livenessProbe: # 存活探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 3 # 初始延迟
|
||||
periodSeconds: 10 # 探测周期
|
||||
readinessProbe: # 就绪探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 2 # 初始延迟
|
||||
periodSeconds: 5 # 探测周期
|
||||
volumeMounts: # 卷挂载
|
||||
- name: tmp # 临时卷名称
|
||||
mountPath: /tmp # 容器内临时目录
|
||||
- name: data # 数据卷名称
|
||||
mountPath: /data # 容器内数据目录
|
||||
volumes: # 卷定义
|
||||
- name: tmp # 临时卷
|
||||
emptyDir: {} # 空目录卷
|
||||
- name: data # 数据卷
|
||||
persistentVolumeClaim: # 卷来源为 PVC
|
||||
claimName: nodejs-demo-data # 绑定 PVC 名称
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- host: app.example.local # 主机名匹配
|
||||
http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /api # 匹配 API 路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-10/README.md
Normal file
6
ansible/files/04-10/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-10(nodejs 分课)
|
||||
|
||||
本目录 `04-10-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-10/04-10-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-10`。
|
||||
134
ansible/files/04-11/04-11-nodejs-demo.yaml
Normal file
134
ansible/files/04-11/04-11-nodejs-demo.yaml
Normal file
@@ -0,0 +1,134 @@
|
||||
# 对应文档:docs/04-11-nodejs-副本与滚动发布.md
|
||||
# 累积:04-10 + replicas: 3 + RollingUpdate(maxSurge:1 maxUnavailable:0)
|
||||
apiVersion: v1 # PVC API 版本
|
||||
kind: PersistentVolumeClaim # 持久卷声明
|
||||
metadata: # PVC 元信息
|
||||
name: nodejs-demo-data # PVC 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # PVC 规格
|
||||
accessModes: # 访问模式
|
||||
- ReadWriteOnce # RWO:同一时间仅单节点挂载读写
|
||||
storageClassName: local-path # 存储类
|
||||
resources: # 资源请求
|
||||
requests: # 配额请求
|
||||
storage: 1Gi # 申请容量
|
||||
---
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 示例消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 3 # 副本数(高可用)
|
||||
strategy: # 更新策略
|
||||
type: RollingUpdate # 滚动更新
|
||||
rollingUpdate: # 滚动更新参数
|
||||
maxSurge: 1 # 更新时最多额外增加 1 个 Pod
|
||||
maxUnavailable: 0 # 更新时不可用 Pod 数为 0
|
||||
selector: # Pod 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
nodeSelector: # 节点选择
|
||||
kubernetes.io/hostname: ylc62 # 固定到指定节点(按实际修改)
|
||||
securityContext: # Pod 级安全上下文
|
||||
fsGroup: 1000 # 挂载卷文件组 ID
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
securityContext: # 容器级安全上下文
|
||||
allowPrivilegeEscalation: false # 禁止提权
|
||||
runAsNonRoot: true # 非 root 运行
|
||||
runAsUser: 1000 # 运行用户 UID
|
||||
readOnlyRootFilesystem: true # 根文件系统只读
|
||||
env: # 环境变量
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从引用源取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 执行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内容保持原样)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
livenessProbe: # 存活探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 3 # 初始延迟
|
||||
periodSeconds: 10 # 探测周期
|
||||
readinessProbe: # 就绪探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 2 # 初始延迟
|
||||
periodSeconds: 5 # 探测周期
|
||||
volumeMounts: # 卷挂载
|
||||
- name: tmp # 临时卷名称
|
||||
mountPath: /tmp # 容器内临时目录
|
||||
- name: data # 数据卷名称
|
||||
mountPath: /data # 容器内数据目录
|
||||
volumes: # 卷定义
|
||||
- name: tmp # 临时卷
|
||||
emptyDir: {} # 空目录卷
|
||||
- name: data # 数据卷
|
||||
persistentVolumeClaim: # 卷来源为 PVC
|
||||
claimName: nodejs-demo-data # 绑定 PVC 名称
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||||
spec: # Ingress 规则
|
||||
rules: # 规则列表
|
||||
- host: app.example.local # 主机名匹配
|
||||
http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /api # 匹配 API 路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-11/README.md
Normal file
6
ansible/files/04-11/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-11(nodejs 分课)
|
||||
|
||||
本目录 `04-11-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-11/04-11-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-11`。
|
||||
141
ansible/files/04-12/04-12-nodejs-demo.yaml
Normal file
141
ansible/files/04-12/04-12-nodejs-demo.yaml
Normal file
@@ -0,0 +1,141 @@
|
||||
# 对应文档:docs/04-12-nodejs-TLS与证书.md
|
||||
# 累积:04-11 + Ingress TLS(websecure、secretName: nodejs-demo-tls)
|
||||
# 应用前请先创建 TLS Secret,例如:
|
||||
# kubectl create secret tls nodejs-demo-tls --cert=fullchain.pem --key=privkey.pem -n default
|
||||
# 证书 SAN 须覆盖 app.example.local(与 rules.host / tls.hosts 一致)
|
||||
apiVersion: v1 # PVC API 版本
|
||||
kind: PersistentVolumeClaim # 持久卷声明
|
||||
metadata: # PVC 元信息
|
||||
name: nodejs-demo-data # PVC 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # PVC 规格
|
||||
accessModes: # 访问模式
|
||||
- ReadWriteOnce # RWO:同一时间仅单节点挂载读写
|
||||
storageClassName: local-path # 存储类
|
||||
resources: # 资源请求
|
||||
requests: # 配额请求
|
||||
storage: 1Gi # 申请容量
|
||||
---
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 示例消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 3 # 副本数
|
||||
strategy: # 更新策略
|
||||
type: RollingUpdate # 滚动更新
|
||||
rollingUpdate: # 滚动更新参数
|
||||
maxSurge: 1 # 更新时最多额外增加 1 个 Pod
|
||||
maxUnavailable: 0 # 更新时不可用 Pod 数为 0
|
||||
selector: # Pod 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
nodeSelector: # 节点选择
|
||||
kubernetes.io/hostname: ylc62 # 固定到指定节点(按实际修改)
|
||||
securityContext: # Pod 级安全上下文
|
||||
fsGroup: 1000 # 挂载卷文件组 ID
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
securityContext: # 容器级安全上下文
|
||||
allowPrivilegeEscalation: false # 禁止提权
|
||||
runAsNonRoot: true # 非 root 运行
|
||||
runAsUser: 1000 # 运行用户 UID
|
||||
readOnlyRootFilesystem: true # 根文件系统只读
|
||||
env: # 环境变量
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从引用源取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 执行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内容保持原样)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
livenessProbe: # 存活探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 3 # 初始延迟
|
||||
periodSeconds: 10 # 探测周期
|
||||
readinessProbe: # 就绪探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 2 # 初始延迟
|
||||
periodSeconds: 5 # 探测周期
|
||||
volumeMounts: # 卷挂载
|
||||
- name: tmp # 临时卷名称
|
||||
mountPath: /tmp # 容器内临时目录
|
||||
- name: data # 数据卷名称
|
||||
mountPath: /data # 容器内数据目录
|
||||
volumes: # 卷定义
|
||||
- name: tmp # 临时卷
|
||||
emptyDir: {} # 空目录卷
|
||||
- name: data # 数据卷
|
||||
persistentVolumeClaim: # 卷来源为 PVC
|
||||
claimName: nodejs-demo-data # 绑定 PVC 名称
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure # 使用 websecure(HTTPS) 入口
|
||||
spec: # Ingress 规则
|
||||
tls: # TLS 配置
|
||||
- hosts: # 证书覆盖域名
|
||||
- app.example.local # 域名
|
||||
secretName: nodejs-demo-tls # 引用的 TLS Secret 名称
|
||||
rules: # 路由规则列表
|
||||
- host: app.example.local # 主机名匹配
|
||||
http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /api # 匹配 API 路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
|
||||
6
ansible/files/04-12/README.md
Normal file
6
ansible/files/04-12/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-12(nodejs 分课)
|
||||
|
||||
本目录 `04-12-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-12/04-12-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-12`。
|
||||
158
ansible/files/04-13/04-13-nodejs-demo.yaml
Normal file
158
ansible/files/04-13/04-13-nodejs-demo.yaml
Normal file
@@ -0,0 +1,158 @@
|
||||
# 对应文档:docs/04-13-nodejs-HPA.md
|
||||
# 累积:04-12 + HorizontalPodAutoscaler(CPU 50%,min 1 max 5)
|
||||
apiVersion: v1 # PVC API 版本
|
||||
kind: PersistentVolumeClaim # 持久卷声明
|
||||
metadata: # PVC 元信息
|
||||
name: nodejs-demo-data # PVC 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # PVC 规格
|
||||
accessModes: # 访问模式
|
||||
- ReadWriteOnce # RWO:同一时间仅单节点挂载读写
|
||||
storageClassName: local-path # 存储类
|
||||
resources: # 资源请求
|
||||
requests: # 配额请求
|
||||
storage: 1Gi # 申请容量
|
||||
---
|
||||
apiVersion: v1 # ConfigMap API 版本
|
||||
kind: ConfigMap # 配置资源
|
||||
metadata: # ConfigMap 元信息
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
namespace: default # 命名空间
|
||||
data: # 配置键值
|
||||
APP_MSG: "Hello from ConfigMap" # 示例消息内容
|
||||
---
|
||||
apiVersion: apps/v1 # Deployment API 版本
|
||||
kind: Deployment # 工作负载:Deployment
|
||||
metadata: # Deployment 元信息
|
||||
name: nodejs-demo # Deployment 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Deployment 规格
|
||||
replicas: 3 # 副本数
|
||||
strategy: # 更新策略
|
||||
type: RollingUpdate # 滚动更新
|
||||
rollingUpdate: # 滚动更新参数
|
||||
maxSurge: 1 # 更新时最多额外增加 1 个 Pod
|
||||
maxUnavailable: 0 # 更新时不可用 Pod 数为 0
|
||||
selector: # Pod 选择器
|
||||
matchLabels: # 标签匹配集合
|
||||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||||
template: # Pod 模板
|
||||
metadata: # Pod 元信息
|
||||
labels: # Pod 标签
|
||||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||||
spec: # Pod 规格
|
||||
nodeSelector: # 节点选择
|
||||
kubernetes.io/hostname: ylc62 # 固定到指定节点(按实际修改)
|
||||
securityContext: # Pod 级安全上下文
|
||||
fsGroup: 1000 # 挂载卷文件组 ID
|
||||
containers: # 容器列表
|
||||
- name: nodejs-demo # 容器名
|
||||
image: node:18.20-alpine # Node.js 镜像
|
||||
imagePullPolicy: IfNotPresent # 拉取策略
|
||||
securityContext: # 容器级安全上下文
|
||||
allowPrivilegeEscalation: false # 禁止提权
|
||||
runAsNonRoot: true # 非 root 运行
|
||||
runAsUser: 1000 # 运行用户 UID
|
||||
readOnlyRootFilesystem: true # 根文件系统只读
|
||||
env: # 环境变量
|
||||
- name: APP_MSG # 环境变量名
|
||||
valueFrom: # 从引用源取值
|
||||
configMapKeyRef: # 从 ConfigMap key 读取
|
||||
name: nodejs-demo-config # ConfigMap 名称
|
||||
key: APP_MSG # ConfigMap 键名
|
||||
command: # 启动命令
|
||||
- node # 执行 node
|
||||
- "-e" # 执行内联脚本
|
||||
- | # 多行 JS 脚本(内容保持原样)
|
||||
const http=require('http');
|
||||
const msg=process.env.APP_MSG||'no env';
|
||||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||||
ports: # 容器端口
|
||||
- containerPort: 8080 # 监听端口
|
||||
resources: # 资源请求与限制
|
||||
requests: # 最小资源请求
|
||||
cpu: "50m" # 请求 CPU
|
||||
memory: "64Mi" # 请求内存
|
||||
limits: # 资源上限
|
||||
cpu: "500m" # CPU 限制
|
||||
memory: "256Mi" # 内存限制
|
||||
livenessProbe: # 存活探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 3 # 初始延迟
|
||||
periodSeconds: 10 # 探测周期
|
||||
readinessProbe: # 就绪探针
|
||||
httpGet: # HTTP 探测
|
||||
path: / # 探测路径
|
||||
port: 8080 # 探测端口
|
||||
initialDelaySeconds: 2 # 初始延迟
|
||||
periodSeconds: 5 # 探测周期
|
||||
volumeMounts: # 卷挂载
|
||||
- name: tmp # 临时卷名称
|
||||
mountPath: /tmp # 容器内临时目录
|
||||
- name: data # 数据卷名称
|
||||
mountPath: /data # 容器内数据目录
|
||||
volumes: # 卷定义
|
||||
- name: tmp # 临时卷
|
||||
emptyDir: {} # 空目录卷
|
||||
- name: data # 数据卷
|
||||
persistentVolumeClaim: # 卷来源为 PVC
|
||||
claimName: nodejs-demo-data # 绑定 PVC 名称
|
||||
---
|
||||
apiVersion: v1 # Service API 版本
|
||||
kind: Service # Service 资源
|
||||
metadata: # Service 元信息
|
||||
name: nodejs-demo # Service 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # Service 规格
|
||||
selector: # 选择后端 Pod
|
||||
app: nodejs-demo # 选中 app=nodejs-demo
|
||||
ports: # 端口映射
|
||||
- port: 80 # Service 暴露端口
|
||||
targetPort: 8080 # 转发到容器端口
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||||
kind: Ingress # Ingress 资源
|
||||
metadata: # Ingress 元信息
|
||||
name: nodejs-demo # Ingress 名称
|
||||
namespace: default # 命名空间
|
||||
annotations: # Traefik 注解
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure # 使用 websecure(HTTPS) 入口
|
||||
spec: # Ingress 规则
|
||||
tls: # TLS 配置
|
||||
- hosts: # 证书覆盖域名
|
||||
- app.example.local # 域名
|
||||
secretName: nodejs-demo-tls # 引用的 TLS Secret 名称
|
||||
rules: # 路由规则列表
|
||||
- host: app.example.local # 主机名匹配
|
||||
http: # HTTP 路由
|
||||
paths: # 路径列表
|
||||
- path: /api # 匹配 API 路径前缀
|
||||
pathType: Prefix # 前缀匹配
|
||||
backend: # 后端目标
|
||||
service: # 后端 Service
|
||||
name: nodejs-demo # Service 名称
|
||||
port: # Service 端口
|
||||
number: 80 # 端口号
|
||||
---
|
||||
apiVersion: autoscaling/v2 # HPA API 版本
|
||||
kind: HorizontalPodAutoscaler # 水平自动扩缩容资源
|
||||
metadata: # HPA 元信息
|
||||
name: nodejs-demo # HPA 名称
|
||||
namespace: default # 命名空间
|
||||
spec: # HPA 规格
|
||||
scaleTargetRef: # 伸缩目标引用
|
||||
apiVersion: apps/v1 # 目标 API 版本
|
||||
kind: Deployment # 目标资源类型
|
||||
name: nodejs-demo # 目标 Deployment 名称
|
||||
minReplicas: 1 # 最小副本数
|
||||
maxReplicas: 5 # 最大副本数
|
||||
metrics: # 伸缩指标
|
||||
- type: Resource # 资源指标类型
|
||||
resource: # 资源指标配置
|
||||
name: cpu # 指标资源:CPU
|
||||
target: # 目标值
|
||||
type: Utilization # 目标类型:利用率
|
||||
averageUtilization: 50 # 目标平均 CPU 利用率(%)
|
||||
|
||||
6
ansible/files/04-13/README.md
Normal file
6
ansible/files/04-13/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 04-13(nodejs 分课)
|
||||
|
||||
本目录 `04-13-nodejs-demo.yaml` 由 `ansible/files/04-01/` 同名文件复制,与总集目录内文件**同构**,专供本课独立阅读;改本课清单时以本目录为准即可最小化影响其他篇。
|
||||
|
||||
- **手动**:`kubectl apply -f ansible/files/04-13/04-13-nodejs-demo.yaml`(按需改字段)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 04-13`。
|
||||
5
ansible/files/04-14/README.md
Normal file
5
ansible/files/04-14/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 04-14 truth source placeholder
|
||||
|
||||
`04-14` 当前以流程说明(GitOps/CI 流水线)为主,暂无独立可直接 `kubectl apply` 的单一清单。
|
||||
|
||||
本目录用于满足 `doc_id -> ansible/files/<doc_id>/` 一致性约束。
|
||||
69
ansible/files/05-03/values-gitlab.example.yaml
Normal file
69
ansible/files/05-03/values-gitlab.example.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
# GitLab Helm Chart 示例 values(实验室用)
|
||||
#
|
||||
# 使用方式:
|
||||
# cp ansible/files/05-03/values-gitlab.example.yaml values-gitlab.yaml
|
||||
# 按需修改域名、资源、Ingress;完整键名以当前 Chart 为准:
|
||||
# helm show values gitlab/gitlab
|
||||
#
|
||||
# Chart 文档:https://docs.gitlab.com/charts/
|
||||
|
||||
global:
|
||||
# 实验室:固定调度到指定节点,PVC(local-path)与 Pod 同节点 → 数据落在该节点本地盘
|
||||
# 本仓库 inventory 中 192.168.2.63 对应节点名 ylc63;若你的集群节点名不同,请 kubectl get nodes 后改写
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: ylc63
|
||||
hosts:
|
||||
# 根域占位;请改为你的域名(内网实验可配合 hosts / split-horizon DNS)
|
||||
domain: example.com
|
||||
# GitLab Web 主机名片段:最终为 <name>.<domain>,例如 git.example.com
|
||||
gitlab:
|
||||
name: git
|
||||
registry:
|
||||
name: registry
|
||||
ingress:
|
||||
# 集群已用 Traefik 或在外层终止 TLS 时,通常不启用 Chart 内置 cert-manager
|
||||
configureCertmanager: false
|
||||
tls:
|
||||
enabled: true
|
||||
# 若使用已有 Secret(例如 Traefik / 手工证书),取消注释并填写:
|
||||
# secretName: gitlab-wildcard-tls
|
||||
|
||||
# 实验室缩小副本(可选;生产请按官方 sizing 与监控数据调整)
|
||||
gitlab:
|
||||
webservice:
|
||||
minReplicas: 1
|
||||
sidekiq:
|
||||
minReplicas: 1
|
||||
# Gitaly 仓库数据盘:与 global.nodeSelector 同节点时,local-path 卷落在该节点本地
|
||||
gitaly:
|
||||
persistence:
|
||||
storageClass: local-path
|
||||
size: 50Gi
|
||||
|
||||
# Bitnami PostgreSQL / Redis、MinIO 子 chart **不**继承 global.nodeSelector 时需单独写(见 GitLab Chart 文档 Node Selector 节)
|
||||
postgresql:
|
||||
primary:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: ylc63
|
||||
persistence:
|
||||
storageClass: local-path
|
||||
size: 8Gi
|
||||
|
||||
redis:
|
||||
master:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: ylc63
|
||||
persistence:
|
||||
storageClass: local-path
|
||||
size: 5Gi
|
||||
|
||||
minio:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: ylc63
|
||||
persistence:
|
||||
storageClass: local-path
|
||||
size: 10Gi
|
||||
|
||||
# 资源紧张时可考虑关闭捆绑 Prometheus(按需取消注释)
|
||||
# prometheus:
|
||||
# install: false
|
||||
9
ansible/files/05-05/README.md
Normal file
9
ansible/files/05-05/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 05-05(Prometheus + Grafana)
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `kube-prometheus-stack-values.example.yaml` | Helm `kube-prometheus-stack` 的实验室向 values 示例(**非** `kubectl apply` 对象) |
|
||||
|
||||
- **手动**:按 [docs/05-05-prometheus与grafana.md](../../../docs/05-05-prometheus与grafana.md) 执行 `helm repo add` / `helm upgrade --install`,可附加 `-f ansible/files/05-05/kube-prometheus-stack-values.example.yaml`。
|
||||
- **自动**:`./ansible/bin/verify.sh run 05-05`(noop + 集群基线;与本目录示例共用真源,便于对照文档改 values)。
|
||||
- 文件名含 `example.`,`verify_common` 不会对其实施 `kubectl apply --dry-run`。
|
||||
@@ -0,0 +1,22 @@
|
||||
# Helm values for prometheus-community/kube-prometheus-stack
|
||||
# 用法(仓库根):
|
||||
# helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
|
||||
# helm repo update
|
||||
# kubectl create namespace monitoring --dry-run=client -o yaml | kubectl apply -f -
|
||||
# helm upgrade --install monitoring prometheus-community/kube-prometheus-stack -n monitoring \
|
||||
# -f ansible/files/05-05/kube-prometheus-stack-values.example.yaml
|
||||
#
|
||||
# 注意:本文件是 Helm values,不要用 kubectl apply。
|
||||
|
||||
prometheus:
|
||||
prometheusSpec:
|
||||
retention: 7d
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
|
||||
grafana:
|
||||
enabled: true
|
||||
persistence:
|
||||
enabled: false
|
||||
10
ansible/files/06-01/README.md
Normal file
10
ansible/files/06-01/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# 06-01(NetworkPolicy 与连通性排障)
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `networkpolicy-traefik-egress.example.yaml` | Traefik 出站示例:后端命名空间、Service CIDR、DNS |
|
||||
| `networkpolicy-backend-ingress.example.yaml` | 后端仅允许来自 `kube-system`(Traefik)的入站示例 |
|
||||
|
||||
- **手动**:复制为正式名后 `kubectl apply -f ...`,并按集群实际 **namespace / 标签 / CIDR** 修改(见 [docs/06-01-k3s-networkpolicy-故障排查.md](../../../docs/06-01-k3s-networkpolicy-故障排查.md))。
|
||||
- **自动**:`./ansible/bin/verify.sh run 06-01`(noop + 基线;策略真源以本目录为准,与手工 `kubectl` 一致)。
|
||||
- 示例文件名含 `example.`,默认验证流程跳过对其的 `kubectl dry-run`。
|
||||
@@ -0,0 +1,21 @@
|
||||
# 示例:后端 Namespace 仅允许来自 kube-system(Traefik)的入站
|
||||
# 将 namespace、podSelector、端口改为你的应用标签与 Service 端口。
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: backend-from-traefik-example
|
||||
namespace: default
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
@@ -0,0 +1,32 @@
|
||||
# 示例:为 Traefik 放行出站(按实际 namespace 与标签调整)
|
||||
# 适用场景:后端在其它命名空间、需访问集群 DNS 与 Service VIP。
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: traefik-egress-lab-example
|
||||
namespace: kube-system
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: traefik
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
# 访问任意命名空间内 Pod(可按需收窄为 namespaceSelector + podSelector)
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
- protocol: TCP
|
||||
port: 8000
|
||||
# Service CIDR(k3s 默认常为 10.43.0.0/16,请与集群一致)
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 10.43.0.0/16
|
||||
# 集群 DNS
|
||||
- ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
5
ansible/files/06-02/README.md
Normal file
5
ansible/files/06-02/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 06-02(运维小结)
|
||||
|
||||
- **文档**:[docs/06-02-运维小结.md](../../../docs/06-02-运维小结.md)(检查项、命令速查、变更记录建议)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 06-02`(noop + 集群基线)。
|
||||
- 本篇无独立 Kubernetes 清单;运维动作以 `kubectl`/脚本为主。
|
||||
5
ansible/files/07-01/README.md
Normal file
5
ansible/files/07-01/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 07-01(Calico 双栈实验)
|
||||
|
||||
- **文档**:[docs/07-01-k3s-calico-dualstack.md](../../../docs/07-01-k3s-calico-dualstack.md)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 07-01`(实验环境与主线 Flannel 可能冲突,仅在隔离环境操作)。
|
||||
- 清单与安装步骤以文档为准;本目录占位满足契约,避免与生产集群误用。
|
||||
5
ansible/files/07-02/README.md
Normal file
5
ansible/files/07-02/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 07-02(Cilium 双栈 / eBPF 实验)
|
||||
|
||||
- **文档**:[docs/07-02-k3s-cilium-dualstack-ebpf.md](../../../docs/07-02-k3s-cilium-dualstack-ebpf.md)。
|
||||
- **自动**:`./ansible/bin/verify.sh run 07-02`。
|
||||
- 实验性 CNI 切换风险高;YAML 真源随文档演进时再纳入本目录。
|
||||
@@ -1,4 +1,8 @@
|
||||
---
|
||||
# 变量边界约定:
|
||||
# - inventory.ini:主机拓扑/SSH
|
||||
# - group_vars/all.yml:长期基线参数
|
||||
# - ansible/env/.env.verify:运行时上下文与外部依赖(ACME/NFS/Cloudflare 等)
|
||||
# 使用 root SSH 连接(setup-k3s-workers-ssh.sh 已将同一公钥写入各节点 root)
|
||||
ansible_user: root
|
||||
|
||||
@@ -8,11 +12,17 @@ timezone: "Asia/Shanghai"
|
||||
k3s_version: "" # 为空表示用 get.k3s.io 默认最新
|
||||
k3s_data_dir: "/storage"
|
||||
k3s_server_ip: "192.168.2.61"
|
||||
# 安装脚本网络:GitHub 慢/不可达时设 cn(等价于安装脚本环境变量 INSTALL_K3S_MIRROR);也可用 ansible-playbook -e k3s_install_mirror=cn
|
||||
k3s_install_mirror: ""
|
||||
# curl 连接/整体超时(秒),避免 get.k3s.io 卡住时 Ansible 长时间无反馈;-e k3s_install_curl_max_time=900 可调大
|
||||
k3s_install_curl_max_time: 600
|
||||
# 安装 shell 在控制面上的硬超时(秒),应略大于 k3s_install_curl_max_time
|
||||
k3s_install_task_timeout: 720
|
||||
|
||||
# 安装 k3s 前校验:/storage 为挂载点且与 / 不同设备(实验室 10G+32G 建议 true;「目录式假 /storage」旧环境可 false)
|
||||
k3s_verify_storage_mount: true
|
||||
|
||||
# 可选:由 playbooks/verify/01-06.yml(-e k3s_do_prepare_storage=true)对第二块整盘分区、格式化并挂载到 k3s_data_dir(会清空该盘,见 01-06)
|
||||
# 可选:由 playbooks/verify/01-05.yml(-e k3s_do_prepare_storage=true)对第二块整盘分区、格式化并挂载到 k3s_data_dir(会清空该盘,见 01-05)
|
||||
k3s_prepare_storage: false
|
||||
# k3s_data_disk_device: "/dev/vdb"
|
||||
# NVMe 整盘一般为 /dev/nvme0n1,首分区为 /dev/nvme0n1p1,playbook 会按设备名自动加 1 或 p1
|
||||
|
||||
37
ansible/lib/lib-ansible-lab.sh
Normal file
37
ansible/lib/lib-ansible-lab.sh
Normal file
@@ -0,0 +1,37 @@
|
||||
# shellcheck shell=bash
|
||||
# 仓库根 Ansible:从任意 cwd 调用时仍使用 ansible/ansible.cfg(如 host_key_checking=False)。
|
||||
ansible_lab_export_config() {
|
||||
export ANSIBLE_CONFIG="${ROOT}/ansible/ansible.cfg"
|
||||
}
|
||||
|
||||
# 若 inventory 为各主机声明了 ansible_ssh_private_key_file,则在本机检查文件存在(避免 ssh 报 no such identity)。
|
||||
ansible_lab_check_inventory_keys() {
|
||||
local inv="$1"
|
||||
local line path exp
|
||||
[[ -f "$inv" ]] || return 0
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
||||
[[ "$line" =~ ansible_ssh_private_key_file=([^[:space:]]+) ]] || continue
|
||||
path="${BASH_REMATCH[1]}"
|
||||
exp="${path/#\~/$HOME}"
|
||||
if [[ ! -f "$exp" ]]; then
|
||||
echo "[ERR] SSH 私钥不存在:$exp(inventory 中为 $path)" >&2
|
||||
echo " 将密钥放到该路径并 chmod 600,或改 ansible/inventory.ini 中的 ansible_ssh_private_key_file。" >&2
|
||||
echo " 生成/分发可参考:scripts/ssh/setup-k3s-workers-ssh.sh、docs/01-05-节点初始化-ansible-实践.md" >&2
|
||||
return 1
|
||||
fi
|
||||
# OpenSSH 拒绝 group/other 可读的私钥(常见误为 0644),须 600 或 400
|
||||
local mode
|
||||
mode=$(stat -c '%a' "$exp" 2>/dev/null) || mode=""
|
||||
case "$mode" in
|
||||
600|400) ;;
|
||||
*)
|
||||
echo "[ERR] SSH 私钥权限过宽(当前 ${mode:-?},须仅所有者可读):$exp" >&2
|
||||
echo " 执行:chmod 600 $exp" >&2
|
||||
echo " 若需一次修正本仓库 inventory 中各节点密钥:chmod 600 ~/.ssh/id_ed25519_k3s_192.168.2.61 ~/.ssh/id_ed25519_k3s_192.168.2.62 ~/.ssh/id_ed25519_k3s_192.168.2.63 ~/.ssh/id_ed25519_k3s_192.168.2.64" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done < "$inv"
|
||||
return 0
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
# SKIP_ARMV7=1(默认):仅 noop(文档 + ansible/files)。
|
||||
# SKIP_ARMV7=0 且设置 ARMV7_SSH:经 SSH 在 armv7/arm32 主机上 dnf 安装 docker 并校验(Fedora/RHEL 系,见 docs/01-03)。
|
||||
# SKIP_ARMV7=0 且设置 ARMV7_SSH:经 SSH 调用 ansible/tools/armv7-docker-verify-install.sh(先 docker info,失败再 get.docker.com,见 docs/01-03)。
|
||||
- name: 01-03 armv7 Docker(矩阵 + 可选远程安装)
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
@@ -102,7 +102,7 @@
|
||||
|
||||
- name: Fail when SKIP_ARMV7=0 but ARMV7_SSH empty
|
||||
ansible.builtin.fail:
|
||||
msg: "SKIP_ARMV7=0 但未设置 ARMV7_SSH(见 scripts/.env.verify.example)"
|
||||
msg: "SKIP_ARMV7=0 但未设置 ARMV7_SSH(见 ansible/env/.env.verify.example)"
|
||||
when: skip_armv7 == '0' and armv7_ssh | length == 0
|
||||
|
||||
- name: Note skipping remote arm install
|
||||
@@ -110,19 +110,14 @@
|
||||
msg: "SKIP_ARMV7={{ skip_armv7 }}:跳过 arm 远程安装。若需安装:SKIP_ARMV7=0 且 export ARMV7_SSH='ssh -o BatchMode=yes user@arm-host'"
|
||||
when: skip_armv7 != '0' or armv7_ssh | length == 0
|
||||
|
||||
- name: Remote Docker install (dnf on arm)
|
||||
- name: Remote Docker verify-or-install (get.docker.com)
|
||||
when: skip_armv7 == '0' and armv7_ssh | length > 0
|
||||
block:
|
||||
- name: Check docker on armv7 host
|
||||
ansible.builtin.shell: "{{ armv7_ssh }} docker version"
|
||||
register: armv7_docker_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Install Docker and enable service (dnf)
|
||||
ansible.builtin.shell: "{{ armv7_ssh }} 'sudo dnf install -y docker && sudo systemctl enable --now docker'"
|
||||
when: armv7_docker_check.rc != 0
|
||||
|
||||
- name: Verify docker version and ps
|
||||
ansible.builtin.shell: "{{ armv7_ssh }} docker version && {{ armv7_ssh }} docker ps -a"
|
||||
changed_when: false
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
exec bash "{{ repo_root }}/ansible/tools/armv7-docker-verify-install.sh"
|
||||
environment:
|
||||
ARMV7_SSH: "{{ armv7_ssh }}"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: armv7_docker_verify_install
|
||||
changed_when: "'skip_install=0' in (armv7_docker_verify_install.stdout | default(''))"
|
||||
|
||||
145
ansible/playbooks/verify/01-04.yml
Normal file
145
ansible/playbooks/verify/01-04.yml
Normal file
@@ -0,0 +1,145 @@
|
||||
# SKIP_ARMV7=1(默认):仅 noop。
|
||||
# SKIP_ARMV7=0 且 ARMV7_NFS_SSH 或 ARMV7_SSH:经 SSH 在 arm 上 dnf 装 nfs-utils、写 /etc/exports、exportfs(见 docs/01-04)。
|
||||
# 导出路径/网段:ARMV7_NFS_EXPORT_PATH(默认 /sdcard)、ARMV7_NFS_CLIENT_SUBNET(默认 192.168.2.0/24)
|
||||
- name: 01-04 armv7 NFS(矩阵 + 可选远程安装)
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
repo_root: "{{ playbook_dir }}/../../.."
|
||||
doc_id: "01-04"
|
||||
doc_filename: "01-04-armv7-nfs服务安装.md"
|
||||
skip_armv7: "{{ lookup('env', 'SKIP_ARMV7') | default('1', true) | trim }}"
|
||||
armv7_ssh: "{{ lookup('env', 'ARMV7_SSH') | default('', true) | trim }}"
|
||||
armv7_nfs_export_path: "{{ lookup('env', 'ARMV7_NFS_EXPORT_PATH') | default('/sdcard', true) | trim }}"
|
||||
armv7_nfs_client_subnet: "{{ lookup('env', 'ARMV7_NFS_CLIENT_SUBNET') | default('192.168.2.0/24', true) | trim }}"
|
||||
tasks:
|
||||
- name: Resolve ARMV7_NFS_SSH from env
|
||||
ansible.builtin.set_fact:
|
||||
armv7_nfs_ssh: >-
|
||||
{% set n = lookup('env', 'ARMV7_NFS_SSH') | default('', true) | trim %}
|
||||
{% set b = lookup('env', 'ARMV7_SSH') | default('', true) | trim %}
|
||||
{{ n if n | length > 0 else b }}
|
||||
|
||||
- name: Baseline docs/files checks
|
||||
block:
|
||||
- name: Assert docs file exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ repo_root }}/docs/{{ doc_filename }}"
|
||||
register: _doc_stat
|
||||
|
||||
- name: Fail when docs file missing
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _doc_stat.stat.exists
|
||||
fail_msg: "docs file missing: docs/{{ doc_filename }}"
|
||||
|
||||
- name: Find matching ansible/files doc_id directory
|
||||
ansible.builtin.find:
|
||||
paths: "{{ repo_root }}/ansible/files"
|
||||
file_type: directory
|
||||
patterns: "{{ doc_id }}"
|
||||
use_regex: false
|
||||
register: _files_dirs
|
||||
|
||||
- name: Fail when ansible/files doc_id directory missing
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _files_dirs.matched | int >= 1
|
||||
fail_msg: "ansible/files missing doc_id directory: ansible/files/{{ doc_id }}"
|
||||
|
||||
- name: Show noop verification summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "doc_id={{ doc_id }}"
|
||||
- "doc={{ doc_filename }}"
|
||||
- "files_dirs={{ _files_dirs.files | map(attribute='path') | list }}"
|
||||
|
||||
- name: Verify cluster reachable (kubectl get nodes) [runbook baseline]
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig | default('/etc/rancher/k3s/k3s.yaml') }} kubectl get nodes
|
||||
args:
|
||||
executable: /bin/bash
|
||||
delegate_to: "{{ groups['k3s_server'][0] }}"
|
||||
become: true
|
||||
run_once: true
|
||||
changed_when: false
|
||||
|
||||
- name: Verify core namespace exists (kube-system) [runbook baseline]
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig | default('/etc/rancher/k3s/k3s.yaml') }} kubectl get ns kube-system
|
||||
args:
|
||||
executable: /bin/bash
|
||||
delegate_to: "{{ groups['k3s_server'][0] }}"
|
||||
become: true
|
||||
run_once: true
|
||||
changed_when: false
|
||||
|
||||
- name: Find YAML manifests under ansible/files doc_id dirs
|
||||
ansible.builtin.find:
|
||||
paths: "{{ _files_dirs.files | map(attribute='path') | list }}"
|
||||
file_type: file
|
||||
patterns:
|
||||
- "*.yml"
|
||||
- "*.yaml"
|
||||
recurse: true
|
||||
use_regex: false
|
||||
register: _files_manifests
|
||||
|
||||
- name: Show manifest count summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "doc_id={{ doc_id }}"
|
||||
- "manifest_files={{ _files_manifests.matched | default(0) }}"
|
||||
- "manifest_paths={{ (_files_manifests.files | map(attribute='path') | list)[:12] }}"
|
||||
|
||||
- name: Server-side dry-run apply (kubectl apply --dry-run=server) [doc assertion]
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig | default('/etc/rancher/k3s/k3s.yaml') }} \
|
||||
kubectl apply --dry-run=server -f "{{ item.path }}"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
loop: "{{ _files_manifests.files }}"
|
||||
loop_control:
|
||||
label: "{{ item.path }}"
|
||||
delegate_to: "{{ groups['k3s_server'][0] }}"
|
||||
become: true
|
||||
run_once: true
|
||||
changed_when: false
|
||||
when: (_files_manifests.matched | default(0) | int) > 0
|
||||
|
||||
- name: Fail when SKIP_ARMV7=0 but no ARMV7_SSH / ARMV7_NFS_SSH
|
||||
ansible.builtin.fail:
|
||||
msg: "SKIP_ARMV7=0 但未设置 ARMV7_SSH(或 ARMV7_NFS_SSH 指向 NFS 所在 arm 主机)"
|
||||
when: skip_armv7 == '0' and armv7_nfs_ssh | length == 0
|
||||
|
||||
- name: Note skipping remote NFS setup
|
||||
ansible.builtin.debug:
|
||||
msg: "SKIP_ARMV7={{ skip_armv7 }}:跳过 arm NFS 远程配置。"
|
||||
when: skip_armv7 != '0' or armv7_nfs_ssh | length == 0
|
||||
|
||||
- name: Remote NFS install (dnf on arm)
|
||||
when: skip_armv7 == '0' and armv7_nfs_ssh | length > 0
|
||||
block:
|
||||
- name: Install nfs-utils and enable nfs-server
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} 'sudo dnf install -y nfs-utils && sudo systemctl enable --now nfs-server'"
|
||||
|
||||
- name: Check if export path already in /etc/exports
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} sudo grep -qF {{ armv7_nfs_export_path | quote }} /etc/exports"
|
||||
register: armv7_exports_grep
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Append NFS export line
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} bash -c 'echo \"{{ armv7_nfs_export_path }} {{ armv7_nfs_client_subnet }}(rw,sync,no_subtree_check,no_root_squash)\" | sudo tee -a /etc/exports'"
|
||||
when: armv7_exports_grep.rc != 0
|
||||
|
||||
- name: Apply exportfs
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} sudo exportfs -rav"
|
||||
changed_when: true
|
||||
|
||||
- name: Verify showmount
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} showmount -e localhost"
|
||||
changed_when: false
|
||||
@@ -1,145 +1,347 @@
|
||||
# SKIP_ARMV7=1(默认):仅 noop。
|
||||
# SKIP_ARMV7=0 且 ARMV7_NFS_SSH 或 ARMV7_SSH:经 SSH 在 arm 上 dnf 装 nfs-utils、写 /etc/exports、exportfs(见 docs/01-05)。
|
||||
# 导出路径/网段:ARMV7_NFS_EXPORT_PATH(默认 /sdcard)、ARMV7_NFS_CLIENT_SUBNET(默认 192.168.2.0/24)
|
||||
- name: 01-05 armv7 NFS(矩阵 + 可选远程安装)
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
---
|
||||
# 单文件化说明:
|
||||
# - 01-05.yml 默认仍做“最小 verify”(kube-system pods)
|
||||
# - 如需“准备数据盘/安装 K3s”,必须显式开启开关:
|
||||
# -e k3s_do_prepare_storage=true # 内联原 01-05-prepare-storage.yml
|
||||
# -e k3s_do_install=true # 内联原 01-05-install.yml
|
||||
# 或 source ansible/env/.env.verify 后由环境变量 K3S_DO_PREPARE_STORAGE / K3S_DO_INSTALL(true/false)开启
|
||||
|
||||
- name: Prepare data disk and mount to k3s_data_dir (opt-in)
|
||||
hosts: k3s_nodes
|
||||
become: true
|
||||
vars:
|
||||
repo_root: "{{ playbook_dir }}/../../.."
|
||||
doc_id: "01-05"
|
||||
doc_filename: "01-05-armv7-nfs服务安装.md"
|
||||
skip_armv7: "{{ lookup('env', 'SKIP_ARMV7') | default('1', true) | trim }}"
|
||||
armv7_ssh: "{{ lookup('env', 'ARMV7_SSH') | default('', true) | trim }}"
|
||||
armv7_nfs_export_path: "{{ lookup('env', 'ARMV7_NFS_EXPORT_PATH') | default('/sdcard', true) | trim }}"
|
||||
armv7_nfs_client_subnet: "{{ lookup('env', 'ARMV7_NFS_CLIENT_SUBNET') | default('192.168.2.0/24', true) | trim }}"
|
||||
_k3s_do_prepare_storage: "{{ k3s_do_prepare_storage | default((lookup('env', 'K3S_DO_PREPARE_STORAGE') | default('', true) | trim | lower in ['true', '1', 'yes']) | bool) }}"
|
||||
k3s_do_prepare_storage_enabled: "{{ _k3s_do_prepare_storage | bool }}"
|
||||
pre_tasks:
|
||||
- name: Gate - skip prepare storage when k3s_do_prepare_storage=false
|
||||
when: not k3s_do_prepare_storage_enabled
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[SKIP] optional doc_id=01-05 action=prepare-storage var=k3s_do_prepare_storage"
|
||||
- meta: end_play
|
||||
tasks:
|
||||
- name: Resolve ARMV7_NFS_SSH from env
|
||||
ansible.builtin.set_fact:
|
||||
armv7_nfs_ssh: >-
|
||||
{% set n = lookup('env', 'ARMV7_NFS_SSH') | default('', true) | trim %}
|
||||
{% set b = lookup('env', 'ARMV7_SSH') | default('', true) | trim %}
|
||||
{{ n if n | length > 0 else b }}
|
||||
|
||||
- name: Baseline docs/files checks
|
||||
block:
|
||||
- name: Assert docs file exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ repo_root }}/docs/{{ doc_filename }}"
|
||||
register: _doc_stat
|
||||
|
||||
- name: Fail when docs file missing
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _doc_stat.stat.exists
|
||||
fail_msg: "docs file missing: docs/{{ doc_filename }}"
|
||||
|
||||
- name: Find matching ansible/files doc_id directory
|
||||
ansible.builtin.find:
|
||||
paths: "{{ repo_root }}/ansible/files"
|
||||
file_type: directory
|
||||
patterns: "{{ doc_id }}"
|
||||
use_regex: false
|
||||
register: _files_dirs
|
||||
|
||||
- name: Fail when ansible/files doc_id directory missing
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _files_dirs.matched | int >= 1
|
||||
fail_msg: "ansible/files missing doc_id directory: ansible/files/{{ doc_id }}"
|
||||
|
||||
- name: Show noop verification summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "doc_id={{ doc_id }}"
|
||||
- "doc={{ doc_filename }}"
|
||||
- "files_dirs={{ _files_dirs.files | map(attribute='path') | list }}"
|
||||
|
||||
- name: Verify cluster reachable (kubectl get nodes) [runbook baseline]
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig | default('/etc/rancher/k3s/k3s.yaml') }} kubectl get nodes
|
||||
args:
|
||||
executable: /bin/bash
|
||||
delegate_to: "{{ groups['k3s_server'][0] }}"
|
||||
become: true
|
||||
run_once: true
|
||||
changed_when: false
|
||||
|
||||
- name: Verify core namespace exists (kube-system) [runbook baseline]
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig | default('/etc/rancher/k3s/k3s.yaml') }} kubectl get ns kube-system
|
||||
args:
|
||||
executable: /bin/bash
|
||||
delegate_to: "{{ groups['k3s_server'][0] }}"
|
||||
become: true
|
||||
run_once: true
|
||||
changed_when: false
|
||||
|
||||
- name: Find YAML manifests under ansible/files doc_id dirs
|
||||
ansible.builtin.find:
|
||||
paths: "{{ _files_dirs.files | map(attribute='path') | list }}"
|
||||
file_type: file
|
||||
patterns:
|
||||
- "*.yml"
|
||||
- "*.yaml"
|
||||
recurse: true
|
||||
use_regex: false
|
||||
register: _files_manifests
|
||||
|
||||
- name: Show manifest count summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "doc_id={{ doc_id }}"
|
||||
- "manifest_files={{ _files_manifests.matched | default(0) }}"
|
||||
- "manifest_paths={{ (_files_manifests.files | map(attribute='path') | list)[:12] }}"
|
||||
|
||||
- name: Server-side dry-run apply (kubectl apply --dry-run=server) [doc assertion]
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig | default('/etc/rancher/k3s/k3s.yaml') }} \
|
||||
kubectl apply --dry-run=server -f "{{ item.path }}"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
loop: "{{ _files_manifests.files }}"
|
||||
loop_control:
|
||||
label: "{{ item.path }}"
|
||||
delegate_to: "{{ groups['k3s_server'][0] }}"
|
||||
become: true
|
||||
run_once: true
|
||||
changed_when: false
|
||||
when: (_files_manifests.matched | default(0) | int) > 0
|
||||
|
||||
- name: Fail when SKIP_ARMV7=0 but no ARMV7_SSH / ARMV7_NFS_SSH
|
||||
ansible.builtin.fail:
|
||||
msg: "SKIP_ARMV7=0 但未设置 ARMV7_SSH(或 ARMV7_NFS_SSH 指向 NFS 所在 arm 主机)"
|
||||
when: skip_armv7 == '0' and armv7_nfs_ssh | length == 0
|
||||
|
||||
- name: Note skipping remote NFS setup
|
||||
- name: Skip notice when storage prep disabled
|
||||
ansible.builtin.debug:
|
||||
msg: "SKIP_ARMV7={{ skip_armv7 }}:跳过 arm NFS 远程配置。"
|
||||
when: skip_armv7 != '0' or armv7_nfs_ssh | length == 0
|
||||
msg: "k3s_prepare_storage is false — skipping (see group_vars/all.yml)"
|
||||
when: not (k3s_prepare_storage | default(false) | bool)
|
||||
|
||||
- name: Remote NFS install (dnf on arm)
|
||||
when: skip_armv7 == '0' and armv7_nfs_ssh | length > 0
|
||||
- name: Prepare block storage for k3s_data_dir
|
||||
when: k3s_prepare_storage | default(false) | bool
|
||||
block:
|
||||
- name: Install nfs-utils and enable nfs-server
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} 'sudo dnf install -y nfs-utils && sudo systemctl enable --now nfs-server'"
|
||||
|
||||
- name: Check if export path already in /etc/exports
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} sudo grep -qF {{ armv7_nfs_export_path | quote }} /etc/exports"
|
||||
register: armv7_exports_grep
|
||||
# 先判挂载:已挂载则不再要求 k3s_data_disk_device(避免「目录已就绪仍 assert 磁盘」)
|
||||
- name: Check whether k3s_data_dir is already a mountpoint
|
||||
ansible.builtin.command: mountpoint -q {{ k3s_data_dir }}
|
||||
register: mp_k3s
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Skip when k3s_data_dir already mounted
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ k3s_data_dir }} already mounted — skipping partitioning on {{ inventory_hostname }}"
|
||||
when: mp_k3s.rc == 0
|
||||
|
||||
- name: Require k3s_data_disk_device only when partition work is needed
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- k3s_data_disk_device is defined
|
||||
- (k3s_data_disk_device | string | length) > 0
|
||||
fail_msg: "Set k3s_data_disk_device (e.g. /dev/vdb) in group_vars or host_vars"
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Verify k3s_data_disk_device is a block device
|
||||
ansible.builtin.command: test -b {{ k3s_data_disk_device }}
|
||||
changed_when: false
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Append NFS export line
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} bash -c 'echo \"{{ armv7_nfs_export_path }} {{ armv7_nfs_client_subnet }}(rw,sync,no_subtree_check,no_root_squash)\" | sudo tee -a /etc/exports'"
|
||||
when: armv7_exports_grep.rc != 0
|
||||
- name: Install partitioning and filesystem tools
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- parted
|
||||
- e2fsprogs
|
||||
state: present
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Apply exportfs
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} sudo exportfs -rav"
|
||||
- name: Compute first partition path (nvme*n* -> p1, else 1)
|
||||
ansible.builtin.set_fact:
|
||||
k3s_data_partition: >-
|
||||
{{ k3s_data_disk_device }}{{ 'p1' if (k3s_data_disk_device | regex_search('nvme[0-9]+n[0-9]+$')) else '1' }}
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Create GPT and single ext4 partition
|
||||
ansible.builtin.command: >-
|
||||
parted -s {{ k3s_data_disk_device }} mklabel gpt mkpart primary ext4 0% 100%
|
||||
args:
|
||||
creates: "{{ k3s_data_partition }}"
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Wait for partition node in /dev
|
||||
ansible.builtin.wait_for:
|
||||
path: "{{ k3s_data_partition }}"
|
||||
state: present
|
||||
timeout: 60
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Detect existing filesystem on partition
|
||||
ansible.builtin.command: blkid -s TYPE -o value {{ k3s_data_partition }}
|
||||
register: fs_type
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Create ext4 on partition
|
||||
ansible.builtin.command: mkfs.ext4 -F {{ k3s_data_partition }}
|
||||
when:
|
||||
- mp_k3s.rc != 0
|
||||
- (fs_type.stdout | default('') | trim | length) == 0
|
||||
|
||||
- name: Read UUID of partition
|
||||
ansible.builtin.command: blkid -s UUID -o value {{ k3s_data_partition }}
|
||||
register: blk_uuid
|
||||
changed_when: false
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Ensure mount directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ k3s_data_dir }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Add fstab entry for k3s_data_dir
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/fstab
|
||||
regexp: "^UUID={{ blk_uuid.stdout | trim }}\\s"
|
||||
line: "UUID={{ blk_uuid.stdout | trim }} {{ k3s_data_dir }} ext4 defaults,nofail 0 2"
|
||||
create: true
|
||||
mode: "0644"
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Mount all from fstab
|
||||
ansible.builtin.command: mount -a
|
||||
changed_when: true
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Verify showmount
|
||||
ansible.builtin.shell: "{{ armv7_nfs_ssh }} showmount -e localhost"
|
||||
- name: Install K3s (opt-in)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
_k3s_do_install: "{{ k3s_do_install | default((lookup('env', 'K3S_DO_INSTALL') | default('', true) | trim | lower in ['true', '1', 'yes']) | bool) }}"
|
||||
k3s_do_install_enabled: "{{ _k3s_do_install | bool }}"
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
k3s_verify_storage_mount_enabled: "{{ k3s_verify_storage_mount | default(true) | bool }}"
|
||||
pre_tasks:
|
||||
- name: Gate - skip install when k3s_do_install=false
|
||||
when: not k3s_do_install_enabled
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[SKIP] optional doc_id=01-05 action=install var=k3s_do_install"
|
||||
- meta: end_play
|
||||
tasks:
|
||||
- name: Require k3s_server_ip
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- k3s_server_ip is defined
|
||||
- (k3s_server_ip | string | length) > 0
|
||||
fail_msg: "k3s_server_ip 未配置,请在 ansible/group_vars/all.yml 设置"
|
||||
|
||||
- name: Verify /storage mountpoint when enabled
|
||||
when: k3s_verify_storage_mount_enabled
|
||||
block:
|
||||
- name: Ensure k3s_data_dir is mountpoint
|
||||
ansible.builtin.command: mountpoint -q {{ k3s_data_dir }}
|
||||
changed_when: false
|
||||
|
||||
- name: Read root and k3s_data_dir mount sources
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
root_src=$(findmnt -n -o SOURCE /)
|
||||
data_src=$(findmnt -n -o SOURCE {{ k3s_data_dir }})
|
||||
echo "root=${root_src}"
|
||||
echo "data=${data_src}"
|
||||
test "${root_src}" != "${data_src}"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Install required packages for k3s install
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- curl
|
||||
- tar
|
||||
- iproute
|
||||
state: present
|
||||
|
||||
- name: Check k3s binary
|
||||
ansible.builtin.stat:
|
||||
path: /usr/local/bin/k3s
|
||||
register: _k3s_bin
|
||||
|
||||
- name: Note k3s server install network expectations
|
||||
when: not _k3s_bin.stat.exists
|
||||
ansible.builtin.debug:
|
||||
msg: "正在下载安装 k3s server(get.k3s.io,最长约 {{ k3s_install_curl_max_time | default(600) }}s);久无输出多为网络问题,可在 group_vars 设 k3s_install_mirror: cn 或调大 k3s_install_curl_max_time"
|
||||
|
||||
- name: Install k3s server when binary absent
|
||||
when: not _k3s_bin.stat.exists
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
curl --connect-timeout 30 --max-time {{ k3s_install_curl_max_time | default(600) | int }} -sfL https://get.k3s.io | \
|
||||
{{ ('INSTALL_K3S_MIRROR=' ~ (k3s_install_mirror | default('') | trim) ~ ' ') if (k3s_install_mirror | default('') | trim | length > 0) else '' }}{{ ('INSTALL_K3S_VERSION=' ~ k3s_version ~ ' ') if (k3s_version | default('') | trim | length > 0) else '' }}INSTALL_K3S_EXEC="server --data-dir {{ k3s_data_dir }} --write-kubeconfig-mode 644" sh -
|
||||
args:
|
||||
executable: /bin/bash
|
||||
timeout: "{{ k3s_install_task_timeout | default(720) | int }}"
|
||||
|
||||
- name: Ensure k3s service enabled and started
|
||||
ansible.builtin.service:
|
||||
name: k3s
|
||||
enabled: true
|
||||
state: started
|
||||
|
||||
- name: Wait k3s kubeconfig ready
|
||||
ansible.builtin.wait_for:
|
||||
path: "{{ k3s_kubeconfig }}"
|
||||
state: present
|
||||
timeout: 300
|
||||
|
||||
- name: Wait server node Ready
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl get node "{{ inventory_hostname }}" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: _server_ready
|
||||
changed_when: false
|
||||
until: _server_ready.stdout | trim == "True"
|
||||
retries: 60
|
||||
delay: 5
|
||||
|
||||
- name: Read k3s server token
|
||||
ansible.builtin.slurp:
|
||||
path: "{{ k3s_data_dir }}/server/token"
|
||||
register: _server_token_raw
|
||||
|
||||
- name: Save k3s token for workers
|
||||
ansible.builtin.set_fact:
|
||||
k3s_server_token: "{{ _server_token_raw.content | b64decode | trim }}"
|
||||
|
||||
- name: Install K3s workers (opt-in)
|
||||
hosts: k3s_worker
|
||||
become: true
|
||||
serial: 1
|
||||
vars:
|
||||
_k3s_do_install: "{{ k3s_do_install | default((lookup('env', 'K3S_DO_INSTALL') | default('', true) | trim | lower in ['true', '1', 'yes']) | bool) }}"
|
||||
k3s_do_install_enabled: "{{ _k3s_do_install | bool }}"
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
k3s_verify_storage_mount_enabled: "{{ k3s_verify_storage_mount | default(true) | bool }}"
|
||||
k3s_server_host: "{{ groups['k3s_server'][0] }}"
|
||||
k3s_join_token: "{{ hostvars[k3s_server_host].k3s_server_token | default('') }}"
|
||||
pre_tasks:
|
||||
- name: Gate - skip worker install when k3s_do_install=false
|
||||
when: not k3s_do_install_enabled
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[SKIP] optional doc_id=01-05 action=worker-install var=k3s_do_install"
|
||||
- meta: end_play
|
||||
tasks:
|
||||
- name: Require k3s join token
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- (k3s_join_token | trim | length) > 0
|
||||
fail_msg: "k3s join token 为空,请先确保 server 安装成功"
|
||||
|
||||
- name: Verify /storage mountpoint on worker when enabled
|
||||
when: k3s_verify_storage_mount_enabled
|
||||
block:
|
||||
- name: Ensure k3s_data_dir is mountpoint
|
||||
ansible.builtin.command: mountpoint -q {{ k3s_data_dir }}
|
||||
changed_when: false
|
||||
|
||||
- name: Read root and k3s_data_dir mount sources
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
root_src=$(findmnt -n -o SOURCE /)
|
||||
data_src=$(findmnt -n -o SOURCE {{ k3s_data_dir }})
|
||||
test "${root_src}" != "${data_src}"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Install required packages for worker install
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- curl
|
||||
- tar
|
||||
- iproute
|
||||
state: present
|
||||
|
||||
- name: Check k3s-agent binary
|
||||
ansible.builtin.stat:
|
||||
path: /usr/local/bin/k3s-agent
|
||||
register: _k3s_agent_bin
|
||||
|
||||
- name: Note k3s agent install network expectations
|
||||
when: not _k3s_agent_bin.stat.exists
|
||||
ansible.builtin.debug:
|
||||
msg: "正在本节点下载安装 k3s-agent(get.k3s.io → GitHub,最长约 {{ k3s_install_curl_max_time | default(600) }}s);卡住时请检查 worker 出网或设 k3s_install_mirror: cn"
|
||||
|
||||
- name: Install k3s worker when binary absent
|
||||
when: not _k3s_agent_bin.stat.exists
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
curl --connect-timeout 30 --max-time {{ k3s_install_curl_max_time | default(600) | int }} -sfL https://get.k3s.io | \
|
||||
{{ ('INSTALL_K3S_MIRROR=' ~ (k3s_install_mirror | default('') | trim) ~ ' ') if (k3s_install_mirror | default('') | trim | length > 0) else '' }}{{ ('INSTALL_K3S_VERSION=' ~ k3s_version ~ ' ') if (k3s_version | default('') | trim | length > 0) else '' }}K3S_URL="https://{{ k3s_server_ip }}:6443" K3S_TOKEN={{ k3s_join_token | quote }} INSTALL_K3S_EXEC="agent --data-dir {{ k3s_data_dir }}" sh -
|
||||
args:
|
||||
executable: /bin/bash
|
||||
timeout: "{{ k3s_install_task_timeout | default(720) | int }}"
|
||||
|
||||
- name: Ensure k3s-agent service enabled and started
|
||||
ansible.builtin.service:
|
||||
name: k3s-agent
|
||||
enabled: true
|
||||
state: started
|
||||
|
||||
# 不在 worker 上 delegate_to server:部分环境下会从 worker 上下文连控制机 SSH 失败(如 192.168.2.61:22 timeout)。
|
||||
# 改为独立 play,仅由控制端 SSH → k3s_server 执行 kubectl,与「Install K3s server」连接路径一致。
|
||||
- name: Wait k3s workers Ready from server (post-install)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
_k3s_do_install: "{{ k3s_do_install | default((lookup('env', 'K3S_DO_INSTALL') | default('', true) | trim | lower in ['true', '1', 'yes']) | bool) }}"
|
||||
k3s_do_install_enabled: "{{ _k3s_do_install | bool }}"
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
pre_tasks:
|
||||
- name: Gate - skip when k3s_do_install=false
|
||||
when: not k3s_do_install_enabled
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[SKIP] optional doc_id=01-05 action=wait-workers-ready var=k3s_do_install"
|
||||
- meta: end_play
|
||||
tasks:
|
||||
- name: Wait each worker node Ready
|
||||
when: (groups['k3s_worker'] | default([])) | length > 0
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
export KUBECONFIG={{ k3s_kubeconfig | quote }}
|
||||
kubectl wait --for=condition=Ready "node/{{ item }}" --timeout=320s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
loop: "{{ groups['k3s_worker'] }}"
|
||||
changed_when: false
|
||||
|
||||
- name: "01-05 k3s baseline verify (kube-system pods)"
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
tasks:
|
||||
- name: kubectl get nodes
|
||||
ansible.builtin.shell: KUBECONFIG={{ k3s_kubeconfig }} kubectl get nodes -o wide
|
||||
changed_when: false
|
||||
|
||||
- name: kube-system pods summary
|
||||
ansible.builtin.shell: KUBECONFIG={{ k3s_kubeconfig }} kubectl get pods -n kube-system -o wide
|
||||
changed_when: false
|
||||
|
||||
|
||||
@@ -1,146 +1,12 @@
|
||||
---
|
||||
# 单文件化说明:
|
||||
# - 01-06.yml 默认仍做“最小 verify”(kube-system pods)
|
||||
# - 如需“准备数据盘/安装 K3s”,必须显式开启开关:
|
||||
# -e k3s_do_prepare_storage=true # 内联原 01-06-prepare-storage.yml
|
||||
# -e k3s_do_install=true # 内联原 01-06-install.yml
|
||||
|
||||
- name: Prepare data disk and mount to k3s_data_dir (opt-in)
|
||||
hosts: k3s_nodes
|
||||
become: true
|
||||
- name: "01-06 noop verify"
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
k3s_do_prepare_storage: "{{ k3s_do_prepare_storage | default(false) | bool }}"
|
||||
pre_tasks:
|
||||
- name: Gate - skip prepare storage when k3s_do_prepare_storage=false
|
||||
when: not k3s_do_prepare_storage
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[GATE] skipped doc_id=01-06 action=prepare-storage var=k3s_do_prepare_storage"
|
||||
- meta: end_play
|
||||
repo_root: "{{ playbook_dir }}/../../.."
|
||||
doc_id: "01-06"
|
||||
doc_filename: "01-06-openwrt-haproxy.md"
|
||||
tasks:
|
||||
- name: Skip notice when storage prep disabled
|
||||
ansible.builtin.debug:
|
||||
msg: "k3s_prepare_storage is false — skipping (see group_vars/all.yml)"
|
||||
when: not (k3s_prepare_storage | default(false) | bool)
|
||||
|
||||
- name: Prepare block storage for k3s_data_dir
|
||||
when: k3s_prepare_storage | default(false) | bool
|
||||
block:
|
||||
- name: Require k3s_data_disk_device when k3s_prepare_storage is true
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- k3s_data_disk_device is defined
|
||||
- (k3s_data_disk_device | string | length) > 0
|
||||
fail_msg: "Set k3s_data_disk_device (e.g. /dev/vdb) in group_vars or host_vars"
|
||||
|
||||
- name: Verify k3s_data_disk_device is a block device
|
||||
ansible.builtin.command: test -b {{ k3s_data_disk_device }}
|
||||
changed_when: false
|
||||
|
||||
- name: Check whether k3s_data_dir is already a mountpoint
|
||||
ansible.builtin.command: mountpoint -q {{ k3s_data_dir }}
|
||||
register: mp_k3s
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Skip when k3s_data_dir already mounted
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ k3s_data_dir }} already mounted — skipping partitioning on {{ inventory_hostname }}"
|
||||
when: mp_k3s.rc == 0
|
||||
|
||||
- name: Install partitioning and filesystem tools
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- parted
|
||||
- e2fsprogs
|
||||
state: present
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Compute first partition path (nvme*n* -> p1, else 1)
|
||||
ansible.builtin.set_fact:
|
||||
k3s_data_partition: >-
|
||||
{{ k3s_data_disk_device }}{{ 'p1' if (k3s_data_disk_device | regex_search('nvme[0-9]+n[0-9]+$')) else '1' }}
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Create GPT and single ext4 partition
|
||||
ansible.builtin.command: >-
|
||||
parted -s {{ k3s_data_disk_device }} mklabel gpt mkpart primary ext4 0% 100%
|
||||
args:
|
||||
creates: "{{ k3s_data_partition }}"
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Wait for partition node in /dev
|
||||
ansible.builtin.wait_for:
|
||||
path: "{{ k3s_data_partition }}"
|
||||
state: present
|
||||
timeout: 60
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Detect existing filesystem on partition
|
||||
ansible.builtin.command: blkid -s TYPE -o value {{ k3s_data_partition }}
|
||||
register: fs_type
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Create ext4 on partition
|
||||
ansible.builtin.command: mkfs.ext4 -F {{ k3s_data_partition }}
|
||||
when:
|
||||
- mp_k3s.rc != 0
|
||||
- (fs_type.stdout | default('') | trim | length) == 0
|
||||
|
||||
- name: Read UUID of partition
|
||||
ansible.builtin.command: blkid -s UUID -o value {{ k3s_data_partition }}
|
||||
register: blk_uuid
|
||||
changed_when: false
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Ensure mount directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ k3s_data_dir }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Add fstab entry for k3s_data_dir
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/fstab
|
||||
regexp: "^UUID={{ blk_uuid.stdout | trim }}\\s"
|
||||
line: "UUID={{ blk_uuid.stdout | trim }} {{ k3s_data_dir }} ext4 defaults,nofail 0 2"
|
||||
create: true
|
||||
mode: "0644"
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Mount all from fstab
|
||||
ansible.builtin.command: mount -a
|
||||
changed_when: true
|
||||
when: mp_k3s.rc != 0
|
||||
|
||||
- name: Install K3s (opt-in)
|
||||
hosts: k3s_nodes
|
||||
become: true
|
||||
vars:
|
||||
k3s_do_install: "{{ k3s_do_install | default(false) | bool }}"
|
||||
pre_tasks:
|
||||
- name: Gate - skip install when k3s_do_install=false
|
||||
when: not k3s_do_install
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[GATE] skipped doc_id=01-06 action=install var=k3s_do_install"
|
||||
- meta: end_play
|
||||
tasks:
|
||||
- name: Placeholder (install content inlined in following plays)
|
||||
ansible.builtin.debug:
|
||||
msg: "[RUN] doc_id=01-06 action=install-start"
|
||||
|
||||
- name: "01-06 k3s baseline verify (kube-system pods)"
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
tasks:
|
||||
- name: kube-system pods summary
|
||||
ansible.builtin.shell: KUBECONFIG={{ k3s_kubeconfig }} kubectl get pods -n kube-system -o wide
|
||||
changed_when: false
|
||||
|
||||
- name: Include noop doc verify role tasks
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: noop-doc-verify.yml
|
||||
|
||||
@@ -4,7 +4,23 @@
|
||||
vars:
|
||||
repo_root: "{{ playbook_dir }}/../../.."
|
||||
doc_id: "01-07"
|
||||
doc_filename: "01-07-openwrt-haproxy.md"
|
||||
doc_filename: "01-07-双控制节点ha.md"
|
||||
tasks:
|
||||
- name: Include noop doc verify tasks
|
||||
ansible.builtin.include_tasks: tasks/noop-doc-verify.yml
|
||||
- name: Assert docs file exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ repo_root }}/docs/{{ doc_filename }}"
|
||||
register: _doc
|
||||
|
||||
- name: Fail when docs file missing
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _doc.stat.exists
|
||||
fail_msg: "docs missing: docs/{{ doc_filename }}"
|
||||
|
||||
- name: Summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "doc_id={{ doc_id }} (manual runbook / HA exercise)"
|
||||
- "This verify case only asserts docs file exists."
|
||||
- "HA join/switch must be exercised manually per docs/{{ doc_filename }}."
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
- name: "01-08 noop verify"
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
repo_root: "{{ playbook_dir }}/../../.."
|
||||
doc_id: "01-08"
|
||||
doc_filename: "01-08-双控制节点ha.md"
|
||||
tasks:
|
||||
- name: Assert docs file exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ repo_root }}/docs/{{ doc_filename }}"
|
||||
register: _doc
|
||||
|
||||
- name: Fail when docs file missing
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _doc.stat.exists
|
||||
fail_msg: "docs missing: docs/{{ doc_filename }}"
|
||||
|
||||
- name: Summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "doc_id={{ doc_id }} (manual runbook / HA exercise)"
|
||||
- "This verify case only asserts docs file exists."
|
||||
- "HA join/switch must be exercised manually per docs/{{ doc_filename }}."
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
manifest_src: "{{ playbook_dir }}/../../files/02-05/01-control-ingress.yaml"
|
||||
manifest_src: "{{ playbook_dir }}/../../files/02-01/01-control-ingress.yaml"
|
||||
manifest_dest: /tmp/nginx-m1.yaml
|
||||
tasks:
|
||||
- name: Copy manifest
|
||||
@@ -27,35 +27,24 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_entry_base: "{{ nginx_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
tasks:
|
||||
- name: Rollout status nginx-m1
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nginx-m1 -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/nginx-m1
|
||||
|
||||
- name: HTTP check /demo-m1 (retry 503 for convergence)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
base="{{ verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
url="$base/demo-m1/"
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
echo "try $i: $url -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
backend=$(curl -sS -D - -o /dev/null --connect-timeout 3 --max-time 8 "$url" 2>/dev/null | awk -F': ' '/^X-Backend:/{print $2; exit}' | tr -d '\r')
|
||||
echo "X-Backend=$backend"
|
||||
test "$backend" = "M1"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
- name: HTTP check /demo-m1 (in-cluster via Service ClusterIP)
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: http-curl-traefik-incluster.yml
|
||||
vars:
|
||||
verify_traefik_kubeconfig: "{{ k3s_kubeconfig }}"
|
||||
verify_incluster_http_url: "http://nginx-m1.default.svc.cluster.local/"
|
||||
verify_traefik_assertion: nginx_matrix_m1_entry_http
|
||||
verify_traefik_header_name: X-Backend
|
||||
verify_traefik_header_value: M1
|
||||
|
||||
- name: Teardown 02-01 nginx control + Ingress (M1)
|
||||
hosts: k3s_server
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
manifest_src: "{{ playbook_dir }}/../../files/02-05/02-control-ingressroute.yaml"
|
||||
manifest_src: "{{ playbook_dir }}/../../files/02-02/02-control-ingressroute.yaml"
|
||||
manifest_dest: /tmp/nginx-m2.yaml
|
||||
tasks:
|
||||
- name: Copy manifest
|
||||
@@ -31,35 +31,24 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_entry_base: "{{ nginx_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
tasks:
|
||||
- name: Rollout status nginx-m2
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nginx-m2 -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/nginx-m2
|
||||
|
||||
- name: HTTP check /demo-m2 (retry 503 for convergence)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
base="{{ verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
url="$base/demo-m2/"
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
echo "try $i: $url -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
backend=$(curl -sS -D - -o /dev/null --connect-timeout 3 --max-time 8 "$url" 2>/dev/null | awk -F': ' '/^X-Backend:/{print $2; exit}' | tr -d '\r')
|
||||
echo "X-Backend=$backend"
|
||||
test "$backend" = "M2"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
- name: HTTP check /demo-m2 (in-cluster via Service ClusterIP)
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: http-curl-traefik-incluster.yml
|
||||
vars:
|
||||
verify_traefik_kubeconfig: "{{ k3s_kubeconfig }}"
|
||||
verify_incluster_http_url: "http://nginx-m2.default.svc.cluster.local/"
|
||||
verify_traefik_assertion: nginx_matrix_m2_entry_http
|
||||
verify_traefik_header_name: X-Backend
|
||||
verify_traefik_header_value: M2
|
||||
|
||||
- name: Teardown 02-02 nginx control + IngressRoute (M2)
|
||||
hosts: k3s_server
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
manifest_src: "{{ playbook_dir }}/../../files/02-05/03-worker-ingress.yaml"
|
||||
manifest_src: "{{ playbook_dir }}/../../files/02-03/03-worker-ingress.yaml"
|
||||
manifest_dest: /tmp/nginx-m3.yaml
|
||||
tasks:
|
||||
- name: Copy manifest
|
||||
@@ -27,35 +27,24 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_entry_base: "{{ nginx_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
tasks:
|
||||
- name: Rollout status nginx-m3
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nginx-m3 -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/nginx-m3
|
||||
|
||||
- name: HTTP check /demo-m3 (retry 503 for convergence)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
base="{{ verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
url="$base/demo-m3/"
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
echo "try $i: $url -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
backend=$(curl -sS -D - -o /dev/null --connect-timeout 3 --max-time 8 "$url" 2>/dev/null | awk -F': ' '/^X-Backend:/{print $2; exit}' | tr -d '\r')
|
||||
echo "X-Backend=$backend"
|
||||
test "$backend" = "M3"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
- name: HTTP check /demo-m3 (in-cluster via Service ClusterIP)
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: http-curl-traefik-incluster.yml
|
||||
vars:
|
||||
verify_traefik_kubeconfig: "{{ k3s_kubeconfig }}"
|
||||
verify_incluster_http_url: "http://nginx-m3.default.svc.cluster.local/"
|
||||
verify_traefik_assertion: nginx_matrix_m3_entry_http
|
||||
verify_traefik_header_name: X-Backend
|
||||
verify_traefik_header_value: M3
|
||||
|
||||
- name: Teardown 02-03 nginx worker + Ingress (M3)
|
||||
hosts: k3s_server
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
manifest_src: "{{ playbook_dir }}/../../files/02-05/04-worker-ingressroute.yaml"
|
||||
manifest_src: "{{ playbook_dir }}/../../files/02-04/04-worker-ingressroute.yaml"
|
||||
manifest_dest: /tmp/nginx-m4.yaml
|
||||
tasks:
|
||||
- name: Copy manifest
|
||||
@@ -27,35 +27,24 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_entry_base: "{{ nginx_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
tasks:
|
||||
- name: Rollout status nginx-m4
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nginx-m4 -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/nginx-m4
|
||||
|
||||
- name: HTTP check /demo-m4 (retry 503 for convergence)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
base="{{ verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
url="$base/demo-m4/"
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
echo "try $i: $url -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
backend=$(curl -sS -D - -o /dev/null --connect-timeout 3 --max-time 8 "$url" 2>/dev/null | awk -F': ' '/^X-Backend:/{print $2; exit}' | tr -d '\r')
|
||||
echo "X-Backend=$backend"
|
||||
test "$backend" = "M4"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
- name: HTTP check /demo-m4 (in-cluster via Service ClusterIP)
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: http-curl-traefik-incluster.yml
|
||||
vars:
|
||||
verify_traefik_kubeconfig: "{{ k3s_kubeconfig }}"
|
||||
verify_incluster_http_url: "http://nginx-m4.default.svc.cluster.local/"
|
||||
verify_traefik_assertion: nginx_matrix_m4_entry_http
|
||||
verify_traefik_header_name: X-Backend
|
||||
verify_traefik_header_value: M4
|
||||
|
||||
- name: Teardown 02-04 nginx worker + IngressRoute (M4)
|
||||
hosts: k3s_server
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
# 合并说明:
|
||||
# - 原 02-05.yml 仅 import 02-05-deploy.yml + 02-01..02-04
|
||||
# - 现已把 02-05-deploy.yml 内联到本文件,保持 scripts/verify.sh run 02-05 的语义不变
|
||||
# - 现已把 02-05-deploy.yml 内联到本文件,保持 ansible/bin/verify.sh run 02-05 的语义不变
|
||||
|
||||
- name: Deploy nginx matrix (M1~M4)
|
||||
hosts: k3s_server
|
||||
@@ -56,17 +56,22 @@
|
||||
register: restart_out
|
||||
changed_when: true
|
||||
|
||||
- name: Wait for nginx pods to be ready
|
||||
# rollout restart 后 Pod 名频繁更替,kubectl wait pod -l 可能竞态 NotFound;改用 rollout status
|
||||
- name: Wait for nginx rollouts stable after ConfigMap restart
|
||||
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
|
||||
set -euo pipefail
|
||||
KCFG={{ k3s_kubeconfig | quote }}
|
||||
export KUBECONFIG="$KCFG"
|
||||
for dep in nginx-m1 nginx-m2; do
|
||||
echo "[OC-ASSERT] assertion=nginx_matrix_rollout deployment=${dep} timeout=60s"
|
||||
kubectl rollout status "deployment/$dep" -n default --timeout=60s
|
||||
done
|
||||
for dep in nginx-m3 nginx-m4; do
|
||||
echo "[OC-ASSERT] assertion=nginx_matrix_rollout deployment=${dep} timeout=120s"
|
||||
kubectl rollout status "deployment/$dep" -n default --timeout=120s
|
||||
done
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Verify nginx matrix
|
||||
|
||||
@@ -30,12 +30,13 @@
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
tasks:
|
||||
- name: Rollout status traefik (kube-system)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/traefik -n kube-system --timeout=240s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/traefik
|
||||
verify_rollout_namespace: kube-system
|
||||
verify_rollout_timeout_s: 240
|
||||
|
||||
- name: Assert HelmChartConfig exists
|
||||
ansible.builtin.shell: |
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
manifest_src: "{{ playbook_dir }}/../../files/03-02/traefik-acme.yaml"
|
||||
manifest_dest: /tmp/traefik-acme.yaml
|
||||
acme_email: "{{ lookup('env', 'ACME_EMAIL') | default('', true) }}"
|
||||
cf_api_token: "{{ lookup('env', 'CF_API_TOKEN') | default('', true) }}"
|
||||
tasks:
|
||||
- name: "Gate - skip apply when ACME_EMAIL missing"
|
||||
when: acme_email | trim == ""
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[GATE] skipped doc_id=03-02 reason=missing_env missing=ACME_EMAIL"
|
||||
- meta: end_play
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-02 reason=missing_env missing=ACME_EMAIL"
|
||||
|
||||
- name: Copy manifest
|
||||
ansible.builtin.copy:
|
||||
@@ -28,6 +30,21 @@
|
||||
regexp: "<YOUR_REAL_EMAIL>"
|
||||
replace: "{{ acme_email | trim }}"
|
||||
|
||||
- name: Enable ACME staging CA when ACME_CA_STAGING=1
|
||||
when: (lookup('env', 'ACME_CA_STAGING') | default('0', true) | trim) == "1"
|
||||
ansible.builtin.replace:
|
||||
path: "{{ manifest_dest }}"
|
||||
regexp: '^\s*# - "--certificatesresolvers\.cloudflare\.acme\.caserver=https://acme-staging-v02\.api\.letsencrypt\.org/directory".*$'
|
||||
replace: ' - "--certificatesresolvers.cloudflare.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"'
|
||||
|
||||
- name: Ensure Cloudflare API token Secret before Traefik ACME apply
|
||||
when: (cf_api_token | trim | length) > 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: ensure-cloudflare-api-token-secret.yml
|
||||
vars:
|
||||
verify_cf_api_token: "{{ cf_api_token | trim }}"
|
||||
|
||||
- name: Apply manifest
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
@@ -42,7 +59,8 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
nginx_matrix_tls_enable: "{{ nginx_matrix_tls_enable | default(false) | bool }}"
|
||||
_nginx_matrix_tls_enable: "{{ nginx_matrix_tls_enable | default((lookup('env', 'NGINX_MATRIX_TLS_ENABLE') | default('', true) | trim | lower in ['true', '1', 'yes']) | bool) }}"
|
||||
nginx_matrix_tls_enabled: "{{ _nginx_matrix_tls_enable | bool }}"
|
||||
manifests_path: "{{ playbook_dir }}/../../files/03-02"
|
||||
tls_domains:
|
||||
- test01.jackadam.top
|
||||
@@ -51,24 +69,30 @@
|
||||
- test04.jackadam.top
|
||||
pre_tasks:
|
||||
- name: Gate - skip nginx matrix TLS when nginx_matrix_tls_enable=false
|
||||
when: not nginx_matrix_tls_enable
|
||||
when: not nginx_matrix_tls_enabled
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[GATE] skipped doc_id=03-02 action=nginx-matrix-tls var=nginx_matrix_tls_enable"
|
||||
msg: "[SKIP] optional doc_id=03-02 action=nginx-matrix-tls var=nginx_matrix_tls_enable"
|
||||
- meta: end_play
|
||||
tasks:
|
||||
- name: Deploy nginx matrix TLS (mode=deploy)
|
||||
when: (mode | default('deploy')) == 'deploy'
|
||||
block:
|
||||
- name: Ensure manifests path exists
|
||||
- name: Ensure manifests path exists (controller repo path)
|
||||
ansible.builtin.stat:
|
||||
path: "{{ manifests_path }}"
|
||||
register: manifests_stat
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
run_once: true
|
||||
|
||||
- name: Fail if manifests not found
|
||||
ansible.builtin.fail:
|
||||
msg: "manifests 未找到: {{ manifests_path }},请从仓库根目录或 ansible 同级执行"
|
||||
when: not manifests_stat.stat.exists
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
run_once: true
|
||||
|
||||
- name: Ensure control-plane label on k3s_server nodes (for M1)
|
||||
ansible.builtin.shell: |
|
||||
@@ -105,12 +129,21 @@
|
||||
ansible.builtin.shell: KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout restart deployment nginx-m1 nginx-m2 nginx-m3 nginx-m4 -n default
|
||||
changed_when: true
|
||||
|
||||
- name: Wait for nginx pods to be ready
|
||||
- name: Wait for nginx rollouts stable after ConfigMap restart
|
||||
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
|
||||
set -euo pipefail
|
||||
KCFG={{ k3s_kubeconfig | quote }}
|
||||
export KUBECONFIG="$KCFG"
|
||||
for dep in nginx-m1 nginx-m2; do
|
||||
echo "[OC-ASSERT] assertion=nginx_matrix_tls_rollout deployment=${dep} timeout=60s"
|
||||
kubectl rollout status "deployment/$dep" -n default --timeout=60s
|
||||
done
|
||||
for dep in nginx-m3 nginx-m4; do
|
||||
echo "[OC-ASSERT] assertion=nginx_matrix_tls_rollout deployment=${dep} timeout=120s"
|
||||
kubectl rollout status "deployment/$dep" -n default --timeout=120s
|
||||
done
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Verify nginx matrix TLS resources
|
||||
@@ -187,29 +220,85 @@
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
acme_email: "{{ lookup('env', 'ACME_EMAIL') | default('', true) }}"
|
||||
cf_api_token: "{{ lookup('env', 'CF_API_TOKEN') | default('', true) }}"
|
||||
tasks:
|
||||
- name: "Gate - skip verify when ACME_EMAIL missing"
|
||||
when: acme_email | trim == ""
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[GATE] skipped doc_id=03-02 reason=missing_env missing=ACME_EMAIL"
|
||||
- meta: end_play
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-02 reason=missing_env missing=ACME_EMAIL"
|
||||
|
||||
- name: Assert Cloudflare token secret exists
|
||||
- name: Ensure Cloudflare token Secret from CF_API_TOKEN (real-pass)
|
||||
when: (cf_api_token | trim | length) > 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: ensure-cloudflare-api-token-secret.yml
|
||||
vars:
|
||||
verify_cf_api_token: "{{ cf_api_token | trim }}"
|
||||
|
||||
- name: Check cloudflare-api-token secret exists
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl -n kube-system get secret cloudflare-api-token
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
register: cloudflare_secret_check
|
||||
failed_when: false
|
||||
|
||||
- name: Rollout status traefik (kube-system)
|
||||
- name: Gate - no CF_API_TOKEN and secret missing
|
||||
when: cloudflare_secret_check.rc != 0 and (cf_api_token | trim | length) == 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-02 reason=missing_dependency missing=cloudflare-api-token skip_scope=traefik-acme"
|
||||
|
||||
- name: Fail when secret missing but CF_API_TOKEN was set
|
||||
when: cloudflare_secret_check.rc != 0 and (cf_api_token | trim | length) > 0
|
||||
ansible.builtin.fail:
|
||||
msg: "已设置 CF_API_TOKEN 但 cloudflare-api-token Secret 仍不可用,请检查 apiserver 权限与命名空间 kube-system"
|
||||
|
||||
# Helm/ACME 换新 RS 时,旧 Pod 可能长期「pending termination」,rollout status 永久卡住。
|
||||
# 实验室验收:scale 0 → 清 Pod → scale 1(入口短暂不可用,可接受)。
|
||||
- name: Unstick Traefik deployment via scale down/up (kube-system)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/traefik -n kube-system --timeout=300s
|
||||
set -euo pipefail
|
||||
export KUBECONFIG={{ k3s_kubeconfig }}
|
||||
echo "[OC-ASSERT] assertion=traefik_rollout_unblock phase=scale_reset"
|
||||
kubectl scale deployment traefik -n kube-system --replicas=0
|
||||
for i in $(seq 1 90); do
|
||||
rep=$(kubectl get deployment traefik -n kube-system -o jsonpath='{.status.replicas}' 2>/dev/null || echo 1)
|
||||
[ "${rep:-1}" = "0" ] && break
|
||||
sleep 2
|
||||
done
|
||||
for sel in "app.kubernetes.io/name=traefik" "app.kubernetes.io/instance=traefik"; do
|
||||
kubectl get pods -n kube-system -l "$sel" -o name 2>/dev/null | while read -r p; do
|
||||
[ -z "$p" ] && continue
|
||||
kubectl delete "$p" -n kube-system --grace-period=0 --force --ignore-not-found=true || true
|
||||
done
|
||||
done
|
||||
{ kubectl get pods -n kube-system --no-headers -o custom-columns=:metadata.name 2>/dev/null | grep -E '^traefik-[0-9a-f]+-' || true; } | while read -r n; do
|
||||
[ -z "$n" ] && continue
|
||||
kubectl delete pod "$n" -n kube-system --grace-period=0 --force --ignore-not-found=true || true
|
||||
done
|
||||
kubectl scale deployment traefik -n kube-system --replicas=1
|
||||
sleep 3
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
changed_when: true
|
||||
failed_when: false
|
||||
|
||||
- name: Rollout status traefik (kube-system)
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/traefik
|
||||
verify_rollout_namespace: kube-system
|
||||
verify_rollout_timeout_s: 600
|
||||
|
||||
- name: Teardown 03-02 Traefik ACME (optional)
|
||||
hosts: k3s_server
|
||||
|
||||
@@ -1,10 +1,231 @@
|
||||
- name: "03-03 noop verify"
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
---
|
||||
# 03-03 Traefik Dashboard + ACME(HelmChartConfig 合并版)
|
||||
# 与 03-02 共用同一 Traefik HelmChartConfig 资源名(traefik);勿在无协调下交替 full 验证二者——后 apply 者覆盖前者。
|
||||
#
|
||||
- name: Deploy 03-03 Traefik Dashboard + ACME (HelmChartConfig)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
repo_root: "{{ playbook_dir }}/../../.."
|
||||
doc_id: "03-03"
|
||||
doc_filename: "03-03-k3s-traefik-dashboard-acme.md"
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
manifest_src: "{{ playbook_dir }}/../../files/03-03/traefik-dashboard-acme.yaml"
|
||||
manifest_dest: /tmp/traefik-dashboard-acme.yaml
|
||||
acme_email: "{{ lookup('env', 'ACME_EMAIL') | default('', true) }}"
|
||||
cf_api_token: "{{ lookup('env', 'CF_API_TOKEN') | default('', true) }}"
|
||||
tasks:
|
||||
- name: Include noop doc verify tasks
|
||||
ansible.builtin.include_tasks: tasks/noop-doc-verify.yml
|
||||
- name: "Gate - skip apply when ACME_EMAIL missing"
|
||||
when: acme_email | trim == ""
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-03 reason=missing_env missing=ACME_EMAIL"
|
||||
|
||||
- name: Copy manifest
|
||||
ansible.builtin.copy:
|
||||
src: "{{ manifest_src }}"
|
||||
dest: "{{ manifest_dest }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Replace ACME email placeholder
|
||||
ansible.builtin.replace:
|
||||
path: "{{ manifest_dest }}"
|
||||
regexp: "<YOUR_REAL_EMAIL>"
|
||||
replace: "{{ acme_email | trim }}"
|
||||
|
||||
- name: Enable ACME staging CA when ACME_CA_STAGING=1
|
||||
when: (lookup('env', 'ACME_CA_STAGING') | default('0', true) | trim) == "1"
|
||||
ansible.builtin.replace:
|
||||
path: "{{ manifest_dest }}"
|
||||
regexp: '^\s*# - "--certificatesresolvers\.cloudflare\.acme\.caserver=https://acme-staging-v02\.api\.letsencrypt\.org/directory".*$'
|
||||
replace: ' - "--certificatesresolvers.cloudflare.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"'
|
||||
|
||||
- name: Ensure Cloudflare API token Secret before Traefik ACME apply
|
||||
when: (cf_api_token | trim | length) > 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: ensure-cloudflare-api-token-secret.yml
|
||||
vars:
|
||||
verify_cf_api_token: "{{ cf_api_token | trim }}"
|
||||
|
||||
- name: Apply manifest
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ manifest_dest }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Verify 03-03 Traefik Dashboard + ACME (rollout + dashboard http)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
acme_email: "{{ lookup('env', 'ACME_EMAIL') | default('', true) }}"
|
||||
cf_api_token: "{{ lookup('env', 'CF_API_TOKEN') | default('', true) }}"
|
||||
_traefik_dash_url_env: "{{ lookup('env', 'TRAEFIK_DASHBOARD_VERIFY_URL') | default('', true) | trim }}"
|
||||
traefik_dashboard_probe_url: "{{ _traefik_dash_url_env if (_traefik_dash_url_env | length > 0) else ('http://' ~ k3s_server_ip ~ '/dashboard/') }}"
|
||||
tasks:
|
||||
- name: "Gate - skip verify when ACME_EMAIL missing"
|
||||
when: acme_email | trim == ""
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-03 reason=missing_env missing=ACME_EMAIL"
|
||||
|
||||
- name: Ensure Cloudflare token Secret from CF_API_TOKEN (real-pass)
|
||||
when: (cf_api_token | trim | length) > 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: ensure-cloudflare-api-token-secret.yml
|
||||
vars:
|
||||
verify_cf_api_token: "{{ cf_api_token | trim }}"
|
||||
|
||||
- name: Check cloudflare-api-token secret exists
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl -n kube-system get secret cloudflare-api-token
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
register: cloudflare_secret_check
|
||||
failed_when: false
|
||||
|
||||
- name: Gate - no CF_API_TOKEN and secret missing
|
||||
when: cloudflare_secret_check.rc != 0 and (cf_api_token | trim | length) == 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-03 reason=missing_dependency missing=cloudflare-api-token skip_scope=traefik-dashboard-acme"
|
||||
|
||||
- name: Fail when secret missing but CF_API_TOKEN was set
|
||||
when: cloudflare_secret_check.rc != 0 and (cf_api_token | trim | length) > 0
|
||||
ansible.builtin.fail:
|
||||
msg: "已设置 CF_API_TOKEN 但 cloudflare-api-token Secret 仍不可用,请检查 apiserver 权限与命名空间 kube-system"
|
||||
|
||||
# 与 03-02 Verify 一致:旧 RS pending termination 时 rollout 可能永久卡住;scale 重置会短暂影响入口。
|
||||
- name: Unstick Traefik deployment via scale down/up (kube-system)
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
export KUBECONFIG={{ k3s_kubeconfig }}
|
||||
echo "[OC-ASSERT] assertion=traefik_rollout_unblock phase=scale_reset doc_id=03-03"
|
||||
kubectl scale deployment traefik -n kube-system --replicas=0
|
||||
for i in $(seq 1 90); do
|
||||
rep=$(kubectl get deployment traefik -n kube-system -o jsonpath='{.status.replicas}' 2>/dev/null || echo 1)
|
||||
[ "${rep:-1}" = "0" ] && break
|
||||
sleep 2
|
||||
done
|
||||
for sel in "app.kubernetes.io/name=traefik" "app.kubernetes.io/instance=traefik"; do
|
||||
kubectl get pods -n kube-system -l "$sel" -o name 2>/dev/null | while read -r p; do
|
||||
[ -z "$p" ] && continue
|
||||
kubectl delete "$p" -n kube-system --grace-period=0 --force --ignore-not-found=true || true
|
||||
done
|
||||
done
|
||||
{ kubectl get pods -n kube-system --no-headers -o custom-columns=:metadata.name 2>/dev/null | grep -E '^traefik-[0-9a-f]+-' || true; } | while read -r n; do
|
||||
[ -z "$n" ] && continue
|
||||
kubectl delete pod "$n" -n kube-system --grace-period=0 --force --ignore-not-found=true || true
|
||||
done
|
||||
kubectl scale deployment traefik -n kube-system --replicas=1
|
||||
sleep 3
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
failed_when: false
|
||||
|
||||
- name: Rollout status traefik (kube-system)
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/traefik
|
||||
verify_rollout_namespace: kube-system
|
||||
verify_rollout_timeout_s: 600
|
||||
|
||||
# deployment spec.replicas=0 时 kubectl rollout status 也会“成功”,需显式等到 Pod Ready
|
||||
- name: Wait for traefik Pod Ready (kube-system)
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
export KUBECONFIG={{ k3s_kubeconfig }}
|
||||
kubectl wait --for=condition=ready pod \
|
||||
-l app.kubernetes.io/name=traefik,app.kubernetes.io/instance=traefik-kube-system \
|
||||
-n kube-system --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: HTTP probe Traefik Dashboard via TRAEFIK_DASHBOARD_VERIFY_URL (control 机)
|
||||
when: _traefik_dash_url_env | length > 0
|
||||
ansible.builtin.uri:
|
||||
url: "{{ traefik_dashboard_probe_url }}"
|
||||
method: GET
|
||||
follow_redirects: all
|
||||
status_code: [200]
|
||||
timeout: 15
|
||||
register: traefik_03_03_dashboard_http
|
||||
changed_when: false
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: OC3 summary for Traefik Dashboard HTTP (external URL)
|
||||
when: _traefik_dash_url_env | length > 0
|
||||
ansible.builtin.debug:
|
||||
msg: "[OC-ASSERT] assertion=traefik_03_03_dashboard_http phase=http probe=uri status={{ traefik_03_03_dashboard_http.status | default('') }} url={{ traefik_dashboard_probe_url }}"
|
||||
|
||||
- name: HTTP probe Traefik Dashboard (port-forward traefik Pod,试 web 容器端口 8000/8080)
|
||||
when: _traefik_dash_url_env | length == 0
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
export KUBECONFIG={{ k3s_kubeconfig }}
|
||||
POD=$(kubectl get pods -n kube-system \
|
||||
-l 'app.kubernetes.io/name=traefik,app.kubernetes.io/instance=traefik-kube-system' \
|
||||
-o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
|
||||
test -n "$POD"
|
||||
local_port=$(shuf -i 32000-32767 -n 1)
|
||||
ok=0
|
||||
for cport in 8000 8080 80; do
|
||||
kubectl port-forward -n kube-system "pod/$POD" "${local_port}:${cport}" >/tmp/traefik-03-03-pf.log 2>&1 &
|
||||
PF_PID=$!
|
||||
trap 'kill $PF_PID 2>/dev/null || true' EXIT
|
||||
for i in $(seq 1 20); do
|
||||
grep -q "Forwarding from" /tmp/traefik-03-03-pf.log 2>/dev/null && break
|
||||
sleep 1
|
||||
done
|
||||
if curl -sfL --connect-timeout 3 --max-time 12 -o /dev/null "http://127.0.0.1:${local_port}/dashboard/" 2>/dev/null; then
|
||||
ok=1
|
||||
echo "[OC-ASSERT] assertion=traefik_03_03_dashboard_http phase=http probe=port_forward status=200 pod_port=${cport} local_port=${local_port}"
|
||||
break
|
||||
fi
|
||||
kill $PF_PID 2>/dev/null || true
|
||||
trap - EXIT
|
||||
wait $PF_PID 2>/dev/null || true
|
||||
done
|
||||
test "$ok" = "1"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Teardown 03-03 Traefik Dashboard + ACME (optional)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_teardown: "{{ (VERIFY_TEARDOWN | default('1')) | string }}"
|
||||
acme_email: "{{ lookup('env', 'ACME_EMAIL') | default('', true) }}"
|
||||
manifest_dest: /tmp/traefik-dashboard-acme.yaml
|
||||
tasks:
|
||||
- name: Skip teardown when gated
|
||||
when: acme_email | trim == ""
|
||||
meta: end_play
|
||||
|
||||
- name: Delete resources when VERIFY_TEARDOWN=1
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl delete -f {{ manifest_dest }} --ignore-not-found=true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
@@ -1,10 +1,166 @@
|
||||
- name: "03-04 noop verify"
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
---
|
||||
# 探针 URL:CF_TUNNEL_TEST_URL(完整 HTTPS)与 CF_TUNNEL_TEST_HOST(仅主机名 → https://HOST/)二选一
|
||||
- name: Deploy 03-04 Cloudflare Tunnel (cloudflared)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
repo_root: "{{ playbook_dir }}/../../.."
|
||||
doc_id: "03-04"
|
||||
doc_filename: "03-04-k3s-cloudflare-tunnel-配置接入.md"
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
manifest_src: "{{ playbook_dir }}/../../files/03-04/cloudflared.yaml"
|
||||
manifest_dest: /tmp/cloudflared-deploy.yaml
|
||||
tunnel_token: "{{ lookup('env', 'TUNNEL_TOKEN') | default('', true) }}"
|
||||
_cf_tunnel_url_raw: "{{ lookup('env', 'CF_TUNNEL_TEST_URL') | default('', true) | trim }}"
|
||||
_cf_tunnel_host_raw: "{{ lookup('env', 'CF_TUNNEL_TEST_HOST') | default('', true) | trim }}"
|
||||
cf_tunnel_probe_url: >-
|
||||
{{ (_cf_tunnel_url_raw | length > 0) | ternary(_cf_tunnel_url_raw,
|
||||
((_cf_tunnel_host_raw | length > 0) | ternary('https://' ~ (_cf_tunnel_host_raw | regex_replace('^https?://', '') | regex_replace('/.*$', '') | regex_replace('/+$', '')) ~ '/', ''))) }}
|
||||
tasks:
|
||||
- name: Include noop doc verify tasks
|
||||
ansible.builtin.include_tasks: tasks/noop-doc-verify.yml
|
||||
- name: "Gate - tunnel probe URL required (CF_TUNNEL_TEST_URL or CF_TUNNEL_TEST_HOST)"
|
||||
when: cf_tunnel_probe_url | trim == ""
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-04 reason=missing_env missing=CF_TUNNEL_TEST_URL_or_CF_TUNNEL_TEST_HOST skip_scope=03-04 tunnel http probe"
|
||||
|
||||
- name: Check cloudflared-credentials secret exists
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl -n kube-system get secret cloudflared-credentials
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: cloudflared_secret_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: "Gate - no TUNNEL_TOKEN and secret missing"
|
||||
when: cloudflared_secret_check.rc != 0 and (tunnel_token | trim | length) == 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-04 reason=missing_dependency missing=cloudflared-credentials/TUNNEL_TOKEN skip_scope=03-04 cloudflared deploy"
|
||||
|
||||
- name: Ensure cloudflared tunnel Secret from TUNNEL_TOKEN
|
||||
when: (tunnel_token | trim | length) > 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: ensure-cloudflared-tunnel-secret.yml
|
||||
vars:
|
||||
verify_tunnel_token: "{{ tunnel_token | trim }}"
|
||||
|
||||
- name: Copy cloudflared Deployment manifest
|
||||
ansible.builtin.copy:
|
||||
src: "{{ manifest_src }}"
|
||||
dest: "{{ manifest_dest }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Apply cloudflared Deployment
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ manifest_dest }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Verify 03-04 Cloudflare Tunnel (rollout + HTTPS probe)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
tunnel_token: "{{ lookup('env', 'TUNNEL_TOKEN') | default('', true) }}"
|
||||
_cf_tunnel_url_raw: "{{ lookup('env', 'CF_TUNNEL_TEST_URL') | default('', true) | trim }}"
|
||||
_cf_tunnel_host_raw: "{{ lookup('env', 'CF_TUNNEL_TEST_HOST') | default('', true) | trim }}"
|
||||
cf_tunnel_probe_url: >-
|
||||
{{ (_cf_tunnel_url_raw | length > 0) | ternary(_cf_tunnel_url_raw,
|
||||
((_cf_tunnel_host_raw | length > 0) | ternary('https://' ~ (_cf_tunnel_host_raw | regex_replace('^https?://', '') | regex_replace('/.*$', '') | regex_replace('/+$', '')) ~ '/', ''))) }}
|
||||
tasks:
|
||||
- name: "Gate - skip verify when tunnel probe URL missing"
|
||||
when: cf_tunnel_probe_url | trim == ""
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-04 reason=missing_env missing=CF_TUNNEL_TEST_URL_or_CF_TUNNEL_TEST_HOST skip_scope=03-04 tunnel http probe"
|
||||
|
||||
- name: Ensure cloudflared tunnel Secret from TUNNEL_TOKEN (idempotent)
|
||||
when: (tunnel_token | trim | length) > 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: ensure-cloudflared-tunnel-secret.yml
|
||||
vars:
|
||||
verify_tunnel_token: "{{ tunnel_token | trim }}"
|
||||
|
||||
- name: Check cloudflared-credentials secret exists
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl -n kube-system get secret cloudflared-credentials
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: cloudflared_secret_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: "Gate - no TUNNEL_TOKEN and secret missing"
|
||||
when: cloudflared_secret_check.rc != 0 and (tunnel_token | trim | length) == 0
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-04 reason=missing_dependency missing=cloudflared-credentials/TUNNEL_TOKEN skip_scope=03-04 cloudflared verify"
|
||||
|
||||
- name: Fail when secret missing but TUNNEL_TOKEN was set
|
||||
when: cloudflared_secret_check.rc != 0 and (tunnel_token | trim | length) > 0
|
||||
ansible.builtin.fail:
|
||||
msg: "已设置 TUNNEL_TOKEN 但 cloudflared-credentials Secret 仍不可用,请检查 apiserver 与 kube-system 权限"
|
||||
|
||||
- name: Rollout status cloudflared (kube-system)
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/cloudflared
|
||||
verify_rollout_namespace: kube-system
|
||||
verify_rollout_timeout_s: 240
|
||||
|
||||
- name: HTTPS probe via Tunnel (CF_TUNNEL_TEST_URL / CF_TUNNEL_TEST_HOST)
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: http-curl-expect.yml
|
||||
vars:
|
||||
verify_http_url: "{{ cf_tunnel_probe_url | trim }}"
|
||||
verify_http_expected_code: 200
|
||||
verify_http_connect_timeout: 5
|
||||
verify_http_max_time: 15
|
||||
verify_http_retries: 12
|
||||
verify_http_retry_sleep: 3
|
||||
verify_http_assertion_label: cf_tunnel_03_04_https
|
||||
verify_http_tls_insecure: "{{ (lookup('env', 'CF_TUNNEL_CURL_INSECURE') | default('0', true) | trim) == '1' }}"
|
||||
|
||||
- name: Teardown 03-04 Cloudflare Tunnel (optional)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_teardown: "{{ (VERIFY_TEARDOWN | default('1')) | string }}"
|
||||
_cf_tunnel_url_raw: "{{ lookup('env', 'CF_TUNNEL_TEST_URL') | default('', true) | trim }}"
|
||||
_cf_tunnel_host_raw: "{{ lookup('env', 'CF_TUNNEL_TEST_HOST') | default('', true) | trim }}"
|
||||
cf_tunnel_probe_url: >-
|
||||
{{ (_cf_tunnel_url_raw | length > 0) | ternary(_cf_tunnel_url_raw,
|
||||
((_cf_tunnel_host_raw | length > 0) | ternary('https://' ~ (_cf_tunnel_host_raw | regex_replace('^https?://', '') | regex_replace('/.*$', '') | regex_replace('/+$', '')) ~ '/', ''))) }}
|
||||
tasks:
|
||||
- name: Skip teardown when 03-04 verify path not engaged
|
||||
when: cf_tunnel_probe_url | trim == ""
|
||||
meta: end_play
|
||||
|
||||
- name: Delete cloudflared Deployment and credentials when VERIFY_TEARDOWN=1
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl delete deployment cloudflared -n kube-system --ignore-not-found=true
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl delete secret cloudflared-credentials -n kube-system --ignore-not-found=true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
run_once: true
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
local_path_apply_lab_config_enabled: "{{ local_path_apply_lab_config | default(false) | bool }}"
|
||||
_local_path_apply_lab_cfg: "{{ local_path_apply_lab_config | default((lookup('env', 'LOCAL_PATH_APPLY_LAB_CONFIG') | default('', true) | trim | lower in ['true', '1', 'yes']) | bool) }}"
|
||||
local_path_apply_lab_config_enabled: "{{ _local_path_apply_lab_cfg | bool }}"
|
||||
local_path_json_src: "{{ playbook_dir }}/../../files/03-05/local-path-config-lab.json"
|
||||
local_path_json_dest: /root/local-path-config-lab.json
|
||||
pre_tasks:
|
||||
@@ -13,7 +14,7 @@
|
||||
when: not local_path_apply_lab_config_enabled
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[GATE] skipped doc_id=03-05 action=apply-local-path-config var=local_path_apply_lab_config"
|
||||
msg: "[SKIP] optional doc_id=03-05 action=apply-local-path-config var=local_path_apply_lab_config"
|
||||
- meta: end_play
|
||||
tasks:
|
||||
- name: Copy local-path lab json
|
||||
@@ -84,12 +85,12 @@
|
||||
delay: 2
|
||||
|
||||
- name: Rollout status nginx-local-pvc-demo
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nginx-local-pvc-demo -n default --timeout=240s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/nginx-local-pvc-demo
|
||||
verify_rollout_timeout_s: 240
|
||||
|
||||
- name: Teardown 03-05 local-path pvc demo (optional)
|
||||
hosts: k3s_server
|
||||
|
||||
@@ -7,15 +7,18 @@
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
manifest_src: "{{ playbook_dir }}/../../files/03-06/nfs-pv-pvc-demo.yaml"
|
||||
manifest_dest: /tmp/nfs-pv-pvc-demo.yaml
|
||||
nfs_job_manifest_src: "{{ playbook_dir }}/../../files/03-06/nfs-pvc-verify-job.yaml"
|
||||
nfs_job_manifest_dest: /tmp/nfs-pvc-verify-job.yaml
|
||||
nfs_server_ip: "{{ lookup('env', 'NFS_SERVER_IP') | default('', true) }}"
|
||||
nfs_export_path: "{{ lookup('env', 'NFS_EXPORT_PATH') | default('', true) }}"
|
||||
tasks:
|
||||
- name: "Gate - skip apply when NFS vars missing"
|
||||
when: (nfs_server_ip | trim == "") or (nfs_export_path | trim == "")
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[GATE] skipped doc_id=03-06 reason=missing_env missing=NFS_SERVER_IP,NFS_EXPORT_PATH"
|
||||
- meta: end_play
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-06 reason=missing_env missing=NFS_SERVER_IP,NFS_EXPORT_PATH"
|
||||
|
||||
- name: Copy manifest
|
||||
ansible.builtin.copy:
|
||||
@@ -35,7 +38,33 @@
|
||||
regexp: "<NFS_EXPORT_PATH>"
|
||||
replace: "{{ nfs_export_path | trim }}"
|
||||
|
||||
- name: Apply manifest
|
||||
- name: Reset stale nfs demo resources before apply (handle immutable PVC fields)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
export KUBECONFIG={{ k3s_kubeconfig }}
|
||||
kubectl -n default delete job nfs-pvc-verify-demo --ignore-not-found=true || true
|
||||
for i in $(seq 1 60); do
|
||||
n=$(kubectl -n default get pods -l job-name=nfs-pvc-verify-demo --no-headers 2>/dev/null | wc -l | tr -d ' ')
|
||||
[ "${n:-99}" -eq 0 ] && break
|
||||
sleep 1
|
||||
done || true
|
||||
kubectl -n default delete pvc nfs-pvc-demo --ignore-not-found=true || true
|
||||
kubectl delete pv nfs-pv-demo --ignore-not-found=true || true
|
||||
for i in $(seq 1 40); do
|
||||
pvc_gone=0
|
||||
pv_gone=0
|
||||
kubectl -n default get pvc nfs-pvc-demo >/dev/null 2>&1 || pvc_gone=1
|
||||
kubectl get pv nfs-pv-demo >/dev/null 2>&1 || pv_gone=1
|
||||
if [ "$pvc_gone" -eq 1 ] && [ "$pv_gone" -eq 1 ]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Apply PV/PVC manifest
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ manifest_dest }}
|
||||
@@ -43,7 +72,33 @@
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Verify 03-06 nfs pvc demo (Bound)
|
||||
- name: Wait pvc Bound before Job
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl get pvc nfs-pvc-demo -n default -o jsonpath='{.status.phase}'
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: pvc_phase_deploy
|
||||
changed_when: false
|
||||
until: pvc_phase_deploy.stdout | trim == "Bound"
|
||||
retries: 40
|
||||
delay: 3
|
||||
|
||||
- name: Copy nfs verify Job manifest
|
||||
ansible.builtin.copy:
|
||||
src: "{{ nfs_job_manifest_src }}"
|
||||
dest: "{{ nfs_job_manifest_dest }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Apply nfs verify Job
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ nfs_job_manifest_dest }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Verify 03-06 nfs pvc demo (Bound + Job RW)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
run_once: true
|
||||
@@ -54,10 +109,11 @@
|
||||
tasks:
|
||||
- name: "Gate - skip verify when NFS vars missing"
|
||||
when: (nfs_server_ip | trim == "") or (nfs_export_path | trim == "")
|
||||
block:
|
||||
- ansible.builtin.debug:
|
||||
msg: "[GATE] skipped doc_id=03-06 reason=missing_env missing=NFS_SERVER_IP,NFS_EXPORT_PATH"
|
||||
- meta: end_play
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: gate-debug-end-play.yml
|
||||
vars:
|
||||
verify_gate_message: "[GATE] skipped doc_id=03-06 reason=missing_env missing=NFS_SERVER_IP,NFS_EXPORT_PATH"
|
||||
|
||||
- name: Wait pvc Bound
|
||||
ansible.builtin.shell: |
|
||||
@@ -71,6 +127,25 @@
|
||||
retries: 40
|
||||
delay: 3
|
||||
|
||||
- name: Wait nfs verify Job complete
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl wait --for=condition=complete job/nfs-pvc-verify-demo -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: OC3 evidence — nfs verify Job logs
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
export KUBECONFIG={{ k3s_kubeconfig }}
|
||||
echo "[OC-ASSERT] assertion=nfs_pvc_rw phase=cluster probe=job_logs job=nfs-pvc-verify-demo"
|
||||
kubectl -n default logs job/nfs-pvc-verify-demo --tail=30
|
||||
echo "[OC-ASSERT] assertion=nfs_pvc_rw phase=verify probe=job_complete result=ok job=nfs-pvc-verify-demo"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Teardown 03-06 nfs pv+pvc demo (optional)
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
@@ -86,7 +161,17 @@
|
||||
when: (nfs_server_ip | trim == "") or (nfs_export_path | trim == "")
|
||||
meta: end_play
|
||||
|
||||
- name: Delete resources when VERIFY_TEARDOWN=1
|
||||
- name: Delete Job before PVC/PV (teardown order)
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
export KUBECONFIG={{ k3s_kubeconfig }}
|
||||
kubectl delete job nfs-pvc-verify-demo -n default --ignore-not-found=true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Delete PV/PVC manifest when VERIFY_TEARDOWN=1
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
@@ -94,4 +179,3 @@
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
|
||||
@@ -93,18 +93,45 @@
|
||||
dest: "{{ longhorn_values_dest }}"
|
||||
mode: "0600"
|
||||
|
||||
- name: Ensure longhorn-system namespace is not stuck Terminating (force finalize if needed)
|
||||
- name: Recover longhorn-system namespace from Terminating and recreate cleanly
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
export KUBECONFIG={{ k3s_kubeconfig }}
|
||||
ns="longhorn-system"
|
||||
phase="$(kubectl get ns "$ns" -o jsonpath='{.status.phase}' 2>/dev/null || true)"
|
||||
if [ "$phase" = "Terminating" ]; then
|
||||
echo "[WARN] namespace $ns is Terminating; force finalize to unblock install"
|
||||
echo "[WARN] namespace $ns is Terminating; force finalize and wait deletion"
|
||||
kubectl get ns "$ns" -o json > /tmp/ns.json
|
||||
python3 -c "import json; obj=json.load(open('/tmp/ns.json')); obj.setdefault('spec',{}); obj['spec']['finalizers']=[]; json.dump(obj, open('/tmp/ns-finalize.json','w'))"
|
||||
kubectl replace --raw \"/api/v1/namespaces/$ns/finalize\" -f /tmp/ns-finalize.json >/dev/null
|
||||
kubectl replace --raw \"/api/v1/namespaces/$ns/finalize\" -f /tmp/ns-finalize.json >/dev/null || true
|
||||
kubectl delete ns "$ns" --ignore-not-found=true --wait=false || true
|
||||
for i in $(seq 1 60); do
|
||||
if ! kubectl get ns "$ns" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
|
||||
# 保证 Helm 能写 release secret:命名空间必须处于 Active 且可创建资源
|
||||
if ! kubectl get ns "$ns" >/dev/null 2>&1; then
|
||||
kubectl create ns "$ns"
|
||||
fi
|
||||
phase_now="$(kubectl get ns "$ns" -o jsonpath='{.status.phase}' 2>/dev/null || true)"
|
||||
deleting_now="$(kubectl get ns "$ns" -o jsonpath='{.metadata.deletionTimestamp}' 2>/dev/null || true)"
|
||||
if [ "$phase_now" = "Terminating" ]; then
|
||||
echo "[ERR] namespace $ns still Terminating after recovery; abort helm install"
|
||||
kubectl get ns "$ns" -o yaml || true
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$deleting_now" ]; then
|
||||
echo "[ERR] namespace $ns has deletionTimestamp=$deleting_now; abort helm install"
|
||||
kubectl get ns "$ns" -o yaml || true
|
||||
exit 1
|
||||
fi
|
||||
# 探针:确认命名空间可写,避免 Helm 创建 release secret 时才失败
|
||||
kubectl -n "$ns" create configmap longhorn-write-probe --from-literal=ok=1 >/dev/null
|
||||
kubectl -n "$ns" delete configmap longhorn-write-probe --ignore-not-found=true >/dev/null
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
@@ -199,7 +226,51 @@
|
||||
- name: Helm upgrade/install Longhorn(失败兜底:install --replace)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
helm upgrade --install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace -f {{ longhorn_values_dest }} --version {{ longhorn_chart_version }} --wait --timeout 15m || helm install --replace longhorn longhorn/longhorn --namespace longhorn-system --create-namespace -f {{ longhorn_values_dest }} --version {{ longhorn_chart_version }} --wait --timeout 15m
|
||||
ns="longhorn-system"
|
||||
recover_ns() {
|
||||
phase="$(kubectl get ns "$ns" -o jsonpath='{.status.phase}' 2>/dev/null || true)"
|
||||
deleting="$(kubectl get ns "$ns" -o jsonpath='{.metadata.deletionTimestamp}' 2>/dev/null || true)"
|
||||
if [ "$phase" = "Terminating" ] || [ -n "$deleting" ]; then
|
||||
kubectl get ns "$ns" -o json > /tmp/ns.json || true
|
||||
python3 -c "import json; obj=json.load(open('/tmp/ns.json')); obj.setdefault('spec',{}); obj['spec']['finalizers']=[]; json.dump(obj, open('/tmp/ns-finalize.json','w'))" || true
|
||||
kubectl replace --raw "/api/v1/namespaces/$ns/finalize" -f /tmp/ns-finalize.json >/dev/null || true
|
||||
kubectl delete ns "$ns" --ignore-not-found=true --wait=false || true
|
||||
for i in $(seq 1 90); do
|
||||
if ! kubectl get ns "$ns" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
kubectl get ns "$ns" >/dev/null 2>&1 || kubectl create ns "$ns"
|
||||
}
|
||||
|
||||
for i in 1 2 3 4 5; do
|
||||
set +e
|
||||
out="$(helm upgrade --install longhorn longhorn/longhorn --namespace "$ns" --create-namespace -f {{ longhorn_values_dest }} --version {{ longhorn_chart_version }} --wait --timeout 15m 2>&1)"
|
||||
rc=$?
|
||||
set -e
|
||||
if [ $rc -eq 0 ]; then
|
||||
echo "$out"
|
||||
exit 0
|
||||
fi
|
||||
echo "$out"
|
||||
if echo "$out" | grep -q "is being terminated"; then
|
||||
echo "[WARN] namespace $ns is being terminated, recover and retry ($i/5)"
|
||||
recover_ns
|
||||
sleep $((i * 3))
|
||||
continue
|
||||
fi
|
||||
if echo "$out" | grep -q "engineimages.longhorn.io\" not found"; then
|
||||
echo "[WARN] longhorn CRD propagation not ready, retry ($i/5)"
|
||||
sleep $((i * 5))
|
||||
continue
|
||||
fi
|
||||
# 非命名空间终止类错误,直接失败
|
||||
exit $rc
|
||||
done
|
||||
# 兜底:仍失败则返回非 0
|
||||
exit 1
|
||||
environment:
|
||||
KUBECONFIG: "{{ k3s_kubeconfig }}"
|
||||
args:
|
||||
|
||||
@@ -6,5 +6,7 @@
|
||||
doc_id: "03-08"
|
||||
doc_filename: "03-08-k3s-ha-集群配置与切换.md"
|
||||
tasks:
|
||||
- name: Include noop doc verify tasks
|
||||
ansible.builtin.include_tasks: tasks/noop-doc-verify.yml
|
||||
- name: Include noop doc verify role tasks
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: noop-doc-verify.yml
|
||||
|
||||
@@ -6,5 +6,7 @@
|
||||
doc_id: "03-09"
|
||||
doc_filename: "03-09-k3s-gitops-集群配置管理.md"
|
||||
tasks:
|
||||
- name: Include noop doc verify tasks
|
||||
ansible.builtin.include_tasks: tasks/noop-doc-verify.yml
|
||||
- name: Include noop doc verify role tasks
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: noop-doc-verify.yml
|
||||
|
||||
@@ -6,5 +6,7 @@
|
||||
doc_id: "03-10"
|
||||
doc_filename: "03-10-k3s-traefik-custom-ports.md"
|
||||
tasks:
|
||||
- name: Include noop doc verify tasks
|
||||
ansible.builtin.include_tasks: tasks/noop-doc-verify.yml
|
||||
- name: Include noop doc verify role tasks
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: noop-doc-verify.yml
|
||||
|
||||
@@ -48,23 +48,22 @@
|
||||
verify_entry_base: "{{ nodejs_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
tasks:
|
||||
- name: Rollout status nodejs-demo
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nodejs-demo -n default --timeout=240s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: kubectl-rollout-status.yml
|
||||
vars:
|
||||
verify_rollout_ref: deployment/nodejs-demo
|
||||
verify_rollout_timeout_s: 240
|
||||
|
||||
- name: HTTP check /node
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
base="{{ verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
url="$base/node"
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 10 "$url" 2>/dev/null || echo "000")
|
||||
echo "$url -> $code"
|
||||
test "$code" = "200"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: http-curl-expect.yml
|
||||
vars:
|
||||
verify_http_entry_base: "{{ verify_entry_base }}"
|
||||
verify_http_path: "/node"
|
||||
verify_http_connect_timeout: 3
|
||||
verify_http_max_time: 10
|
||||
verify_http_assertion_label: nodejs_base_04_01_entry_http
|
||||
|
||||
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_teardown: "{{ (VERIFY_TEARDOWN | default('1')) | string }}"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-01/04-02-nodejs-demo.yaml"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-02/04-02-nodejs-demo.yaml"
|
||||
nodejs_manifest_dest: /tmp/nodejs-demo-04-02.yaml
|
||||
nodejs_verify_entry_base: "{{ nodejs_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
nodejs_verify_path: "/node"
|
||||
nodejs_expected_target_port: 3000
|
||||
nodejs_http_assertion_label: nodejs_04_02_entry_http
|
||||
tasks:
|
||||
- name: Include nodejs deploy+verify template
|
||||
ansible.builtin.include_tasks: tasks/nodejs-demo-deploy-verify.yml
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: nodejs-demo-deploy-verify.yml
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Deploy+Verify 04-03 nodejs image + command/args
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
@@ -5,87 +6,14 @@
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_teardown: "{{ (VERIFY_TEARDOWN | default('1')) | string }}"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-01/04-03-nodejs-demo.yaml"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-03/04-03-nodejs-demo.yaml"
|
||||
nodejs_manifest_dest: /tmp/nodejs-demo-04-03.yaml
|
||||
nodejs_verify_entry_base: "{{ nodejs_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
nodejs_verify_path: "/node"
|
||||
nodejs_expected_target_port: 8080
|
||||
nodejs_expected_target_port: 3000
|
||||
nodejs_http_assertion_label: nodejs_04_03_entry_http
|
||||
tasks:
|
||||
- name: Copy nodejs demo manifest
|
||||
ansible.builtin.copy:
|
||||
src: "{{ nodejs_manifest_src }}"
|
||||
dest: "{{ nodejs_manifest_dest }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Apply nodejs demo manifest
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ nodejs_manifest_dest }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Rollout status nodejs-demo
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nodejs-demo -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Service targetPort matches expected (optional)
|
||||
when: nodejs_expected_target_port is defined and (nodejs_expected_target_port | int) > 0
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
exp="{{ nodejs_expected_target_port | int }}"
|
||||
got=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get svc nodejs-demo -n default -o jsonpath='{.spec.ports[0].targetPort}')
|
||||
echo "svc/nodejs-demo targetPort=$got expected=$exp"
|
||||
test "$got" = "$exp"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Endpoints exist
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
eps=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get endpoints nodejs-demo -n default -o jsonpath='{.subsets[0].addresses[0].ip}' 2>/dev/null || true)
|
||||
echo "endpoints.ip=$eps"
|
||||
test -n "$eps"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: HTTP check nodejs demo (path/host optional)
|
||||
when: nodejs_http_check_enabled | default(true)
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
base="{{ nodejs_verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
path="{{ nodejs_verify_path | default('/node') }}"
|
||||
url="$base${path}"
|
||||
host="{{ nodejs_verify_host | default('') | trim }}"
|
||||
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
if [ -n "$host" ]; then
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: ${host}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
else
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
fi
|
||||
echo "try $i: $url host=${host:-<none>} -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Teardown when VERIFY_TEARDOWN=1
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl delete -f {{ nodejs_manifest_dest }} --ignore-not-found=true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Include nodejs deploy+verify template
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: nodejs-demo-deploy-verify.yml
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Deploy+Verify 04-04 nodejs env + config injection
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
@@ -5,87 +6,14 @@
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_teardown: "{{ (VERIFY_TEARDOWN | default('1')) | string }}"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-01/04-04-nodejs-demo.yaml"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-04/04-04-nodejs-demo.yaml"
|
||||
nodejs_manifest_dest: /tmp/nodejs-demo-04-04.yaml
|
||||
nodejs_verify_entry_base: "{{ nodejs_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
nodejs_verify_path: "/node"
|
||||
nodejs_expected_target_port: 8080
|
||||
nodejs_http_assertion_label: nodejs_04_04_entry_http
|
||||
tasks:
|
||||
- name: Copy nodejs demo manifest
|
||||
ansible.builtin.copy:
|
||||
src: "{{ nodejs_manifest_src }}"
|
||||
dest: "{{ nodejs_manifest_dest }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Apply nodejs demo manifest
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ nodejs_manifest_dest }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Rollout status nodejs-demo
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nodejs-demo -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Service targetPort matches expected (optional)
|
||||
when: nodejs_expected_target_port is defined and (nodejs_expected_target_port | int) > 0
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
exp="{{ nodejs_expected_target_port | int }}"
|
||||
got=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get svc nodejs-demo -n default -o jsonpath='{.spec.ports[0].targetPort}')
|
||||
echo "svc/nodejs-demo targetPort=$got expected=$exp"
|
||||
test "$got" = "$exp"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Endpoints exist
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
eps=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get endpoints nodejs-demo -n default -o jsonpath='{.subsets[0].addresses[0].ip}' 2>/dev/null || true)
|
||||
echo "endpoints.ip=$eps"
|
||||
test -n "$eps"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: HTTP check nodejs demo (path/host optional)
|
||||
when: nodejs_http_check_enabled | default(true)
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
base="{{ nodejs_verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
path="{{ nodejs_verify_path | default('/node') }}"
|
||||
url="$base${path}"
|
||||
host="{{ nodejs_verify_host | default('') | trim }}"
|
||||
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
if [ -n "$host" ]; then
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: ${host}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
else
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
fi
|
||||
echo "try $i: $url host=${host:-<none>} -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Teardown when VERIFY_TEARDOWN=1
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl delete -f {{ nodejs_manifest_dest }} --ignore-not-found=true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Include nodejs deploy+verify template
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: nodejs-demo-deploy-verify.yml
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Deploy+Verify 04-05 nodejs probes
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
@@ -5,87 +6,14 @@
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_teardown: "{{ (VERIFY_TEARDOWN | default('1')) | string }}"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-01/04-05-nodejs-demo.yaml"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-05/04-05-nodejs-demo.yaml"
|
||||
nodejs_manifest_dest: /tmp/nodejs-demo-04-05.yaml
|
||||
nodejs_verify_entry_base: "{{ nodejs_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
nodejs_verify_path: "/node"
|
||||
nodejs_expected_target_port: 8080
|
||||
nodejs_http_assertion_label: nodejs_04_05_entry_http
|
||||
tasks:
|
||||
- name: Copy nodejs demo manifest
|
||||
ansible.builtin.copy:
|
||||
src: "{{ nodejs_manifest_src }}"
|
||||
dest: "{{ nodejs_manifest_dest }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Apply nodejs demo manifest
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ nodejs_manifest_dest }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Rollout status nodejs-demo
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nodejs-demo -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Service targetPort matches expected (optional)
|
||||
when: nodejs_expected_target_port is defined and (nodejs_expected_target_port | int) > 0
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
exp="{{ nodejs_expected_target_port | int }}"
|
||||
got=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get svc nodejs-demo -n default -o jsonpath='{.spec.ports[0].targetPort}')
|
||||
echo "svc/nodejs-demo targetPort=$got expected=$exp"
|
||||
test "$got" = "$exp"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Endpoints exist
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
eps=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get endpoints nodejs-demo -n default -o jsonpath='{.subsets[0].addresses[0].ip}' 2>/dev/null || true)
|
||||
echo "endpoints.ip=$eps"
|
||||
test -n "$eps"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: HTTP check nodejs demo (path/host optional)
|
||||
when: nodejs_http_check_enabled | default(true)
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
base="{{ nodejs_verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
path="{{ nodejs_verify_path | default('/node') }}"
|
||||
url="$base${path}"
|
||||
host="{{ nodejs_verify_host | default('') | trim }}"
|
||||
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
if [ -n "$host" ]; then
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: ${host}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
else
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
fi
|
||||
echo "try $i: $url host=${host:-<none>} -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Teardown when VERIFY_TEARDOWN=1
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl delete -f {{ nodejs_manifest_dest }} --ignore-not-found=true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Include nodejs deploy+verify template
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: nodejs-demo-deploy-verify.yml
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Deploy+Verify 04-06 nodejs replicas + rolling update
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
@@ -5,87 +6,14 @@
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_teardown: "{{ (VERIFY_TEARDOWN | default('1')) | string }}"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-01/04-06-nodejs-demo.yaml"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-06/04-06-nodejs-demo.yaml"
|
||||
nodejs_manifest_dest: /tmp/nodejs-demo-04-06.yaml
|
||||
nodejs_verify_entry_base: "{{ nodejs_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
nodejs_verify_path: "/node"
|
||||
nodejs_expected_target_port: 8080
|
||||
nodejs_http_assertion_label: nodejs_04_06_entry_http
|
||||
tasks:
|
||||
- name: Copy nodejs demo manifest
|
||||
ansible.builtin.copy:
|
||||
src: "{{ nodejs_manifest_src }}"
|
||||
dest: "{{ nodejs_manifest_dest }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Apply nodejs demo manifest
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ nodejs_manifest_dest }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Rollout status nodejs-demo
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nodejs-demo -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Service targetPort matches expected (optional)
|
||||
when: nodejs_expected_target_port is defined and (nodejs_expected_target_port | int) > 0
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
exp="{{ nodejs_expected_target_port | int }}"
|
||||
got=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get svc nodejs-demo -n default -o jsonpath='{.spec.ports[0].targetPort}')
|
||||
echo "svc/nodejs-demo targetPort=$got expected=$exp"
|
||||
test "$got" = "$exp"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Endpoints exist
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
eps=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get endpoints nodejs-demo -n default -o jsonpath='{.subsets[0].addresses[0].ip}' 2>/dev/null || true)
|
||||
echo "endpoints.ip=$eps"
|
||||
test -n "$eps"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: HTTP check nodejs demo (path/host optional)
|
||||
when: nodejs_http_check_enabled | default(true)
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
base="{{ nodejs_verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
path="{{ nodejs_verify_path | default('/node') }}"
|
||||
url="$base${path}"
|
||||
host="{{ nodejs_verify_host | default('') | trim }}"
|
||||
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
if [ -n "$host" ]; then
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: ${host}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
else
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
fi
|
||||
echo "try $i: $url host=${host:-<none>} -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Teardown when VERIFY_TEARDOWN=1
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl delete -f {{ nodejs_manifest_dest }} --ignore-not-found=true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Include nodejs deploy+verify template
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: nodejs-demo-deploy-verify.yml
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Deploy+Verify 04-07 nodejs Ingress + Traefik
|
||||
hosts: k3s_server
|
||||
become: true
|
||||
@@ -5,87 +6,25 @@
|
||||
vars:
|
||||
k3s_kubeconfig: /etc/rancher/k3s/k3s.yaml
|
||||
verify_teardown: "{{ (VERIFY_TEARDOWN | default('1')) | string }}"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-01/04-07-nodejs-demo.yaml"
|
||||
nodejs_manifest_src: "{{ playbook_dir }}/../../files/04-07/04-07-nodejs-demo.yaml"
|
||||
nodejs_manifest_dest: /tmp/nodejs-demo-04-07.yaml
|
||||
nodejs_verify_entry_base: "{{ nodejs_entry_base | default('http://' ~ k3s_server_ip) }}"
|
||||
nodejs_verify_path: "/api/"
|
||||
nodejs_verify_host: "{{ nodejs_verify_host | default('app.example.local') }}"
|
||||
nodejs_verify_path: "/node"
|
||||
nodejs_verify_host: ""
|
||||
_nodejs_tls_entry_base: "{{ NODEJS_TLS_ENTRY_BASE | default(lookup('env', 'NODEJS_TLS_ENTRY_BASE') | default('', true), true) | trim }}"
|
||||
_nodejs_tls_host: "{{ NODEJS_TLS_HOST | default(lookup('env', 'NODEJS_TLS_HOST') | default('', true), true) | trim }}"
|
||||
nodejs_tls_probe_enabled: "{{ (_nodejs_tls_entry_base | length > 0) and (_nodejs_tls_host | length > 0) and (_nodejs_tls_entry_base is match('^https?://')) }}"
|
||||
_nodejs_tls_authority: "{{ _nodejs_tls_entry_base | regex_replace('^https?://', '') | regex_replace('/.*$', '') }}"
|
||||
nodejs_tls_connect_host: "{{ _nodejs_tls_authority | regex_replace(':([0-9]+)$', '') }}"
|
||||
nodejs_tls_connect_port: "{{ (_nodejs_tls_authority | regex_replace('^[^:]*:', '') | int) if (':' in _nodejs_tls_authority) else 443 }}"
|
||||
nodejs_tls_sni_probe_enabled: "{{ nodejs_tls_probe_enabled | bool }}"
|
||||
nodejs_tls_sni_connect_host: "{{ nodejs_tls_connect_host }}"
|
||||
nodejs_tls_sni_port: "{{ nodejs_tls_connect_port }}"
|
||||
nodejs_tls_sni_servername: "{{ _nodejs_tls_host }}"
|
||||
nodejs_tls_sni_assertion_label: nodejs_04_07_tls_sni_handshake
|
||||
nodejs_http_assertion_label: nodejs_04_07_entry_http
|
||||
tasks:
|
||||
- name: Copy nodejs demo manifest
|
||||
ansible.builtin.copy:
|
||||
src: "{{ nodejs_manifest_src }}"
|
||||
dest: "{{ nodejs_manifest_dest }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Apply nodejs demo manifest
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl apply -f {{ nodejs_manifest_dest }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Rollout status nodejs-demo
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl rollout status deployment/nodejs-demo -n default --timeout=180s
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Service targetPort matches expected (optional)
|
||||
when: nodejs_expected_target_port is defined and (nodejs_expected_target_port | int) > 0
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
exp="{{ nodejs_expected_target_port | int }}"
|
||||
got=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get svc nodejs-demo -n default -o jsonpath='{.spec.ports[0].targetPort}')
|
||||
echo "svc/nodejs-demo targetPort=$got expected=$exp"
|
||||
test "$got" = "$exp"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Assert Endpoints exist
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
eps=$(KUBECONFIG={{ k3s_kubeconfig }} kubectl get endpoints nodejs-demo -n default -o jsonpath='{.subsets[0].addresses[0].ip}' 2>/dev/null || true)
|
||||
echo "endpoints.ip=$eps"
|
||||
test -n "$eps"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: HTTP check nodejs demo (path/host optional)
|
||||
when: nodejs_http_check_enabled | default(true)
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
base="{{ nodejs_verify_entry_base | trim | regex_replace('/+$','') }}"
|
||||
path="{{ nodejs_verify_path | default('/node') }}"
|
||||
url="$base${path}"
|
||||
host="{{ nodejs_verify_host | default('') | trim }}"
|
||||
|
||||
ok=0
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
if [ -n "$host" ]; then
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: ${host}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
else
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 8 "$url" 2>/dev/null || echo "000")
|
||||
fi
|
||||
echo "try $i: $url host=${host:-<none>} -> $code"
|
||||
if [ "$code" = "200" ]; then ok=1; break; fi
|
||||
sleep 2
|
||||
done
|
||||
test "$ok" = "1"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
|
||||
- name: Teardown when VERIFY_TEARDOWN=1
|
||||
when: verify_teardown == "1"
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
KUBECONFIG={{ k3s_kubeconfig }} kubectl delete -f {{ nodejs_manifest_dest }} --ignore-not-found=true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: true
|
||||
|
||||
- name: Include nodejs deploy+verify template
|
||||
ansible.builtin.include_role:
|
||||
name: verify_common
|
||||
tasks_from: nodejs-demo-deploy-verify.yml
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user