diff --git a/docs/kubernetes/install-kubectl-nodes.sh b/docs/kubernetes/install-kubectl-nodes.sh new file mode 100644 index 0000000000..a9df305951 --- /dev/null +++ b/docs/kubernetes/install-kubectl-nodes.sh @@ -0,0 +1,98 @@ +#!/bin/bash +set -e + +# 为 node1 和 node2 安装 kubectl 脚本 +# 功能: 从 master 传输 kubectl 二进制文件到其他节点 + +echo "==== 为 node1 和 node2 安装 kubectl ====" + +# 定义节点列表 +NODES=("172.17.0.15:master" "172.17.0.43:node1" "172.17.0.34:node2") + +# 本机 IP 与 SSH 选项 +LOCAL_IP=$(ip route get 1 | awk '{print $7; exit}') +SSH_OPTS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes' +# SSH 私钥(可用环境变量 SSH_KEY 覆盖),存在则自动携带 +SSH_KEY_PATH=${SSH_KEY:-$HOME/.ssh/id_rsa} +[ -f "$SSH_KEY_PATH" ] && SSH_ID="-i $SSH_KEY_PATH" || SSH_ID="" + +# 函数:在指定节点执行命令 +execute_on_node() { + local ip="$1" + local hostname="$2" + local command="$3" + local description="$4" + + echo "==== $description on $hostname ($ip) ====" + if [ "$ip" = "$LOCAL_IP" ] || [ "$hostname" = "master" ]; then + bash -lc "$command" + else + ssh $SSH_OPTS $SSH_ID ubuntu@$ip "$command" + fi + echo "" +} + +# 函数:传输文件到指定节点 +copy_to_node() { + local ip="$1" + local hostname="$2" + local file="$3" + echo "传输 $file 到 $hostname ($ip)" + if [ "$ip" = "$LOCAL_IP" ] || [ "$hostname" = "master" ]; then + cp -f "$file" ~/ + else + scp $SSH_OPTS $SSH_ID "$file" ubuntu@$ip:~/ + fi +} + +# 创建 kubectl 安装脚本 +cat > kubectl-install.sh << 'EOF_INSTALL' +#!/bin/bash +set -e + +echo "==== 安装 kubectl ====" + +# 1. 检查是否已安装 +if command -v kubectl &> /dev/null; then + echo "kubectl 已安装,版本: $(kubectl version --client 2>/dev/null | grep 'Client Version' || echo 'unknown')" + echo "跳过安装" + exit 0 +fi + +# 2. 安装 kubectl +echo "安装 kubectl..." +sudo apt update +sudo apt install -y apt-transport-https ca-certificates curl + +# 添加 Kubernetes 官方 GPG key +curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg + +# 添加 Kubernetes apt 仓库 +echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list + +# 更新包列表并安装 kubectl +sudo apt update +sudo apt install -y kubectl + +# 3. 验证安装 +echo "验证 kubectl 安装..." +kubectl version --client + +echo "==== kubectl 安装完成 ====" +EOF_INSTALL + +chmod +x kubectl-install.sh + +# 为 node1 和 node2 安装 kubectl +for node in "${NODES[@]}"; do + IFS=':' read -r ip hostname <<< "$node" + if [ "$hostname" != "master" ]; then + copy_to_node "$ip" "$hostname" "kubectl-install.sh" + execute_on_node "$ip" "$hostname" "./kubectl-install.sh" "安装 kubectl" + fi +done + +# 清理临时文件 +rm -f kubectl-install.sh + +echo "==== 所有节点 kubectl 安装完成 ====" diff --git a/docs/kubernetes/k8s-image-pull-and-import.sh b/docs/kubernetes/k8s-image-pull-and-import.sh new file mode 100644 index 0000000000..b758b788cc --- /dev/null +++ b/docs/kubernetes/k8s-image-pull-and-import.sh @@ -0,0 +1,122 @@ +#!/bin/bash +set -euo pipefail + +# 说明: +# 在 master、node1、node2 三台节点上分别拉取指定镜像, 并导入到 containerd (k8s.io 命名空间) +# 不通过主机分发镜像归档, 而是每台节点各自拉取/导入。 +# +# 使用示例: +# chmod +x k8s-image-pull-and-import.sh +# ./k8s-image-pull-and-import.sh beppeb/devstar-controller-manager:3.0.0.without_istio +# +# 可选环境变量: +# SSH_KEY 指定私钥路径 (默认: ~/.ssh/id_rsa, 若存在自动携带) + +echo "==== K8s 镜像拉取并导入 containerd ====" + +if [ $# -lt 1 ]; then + echo "用法: $0 " + echo "示例: $0 beppeb/devstar-controller-manager:3.0.0.without_istio" + exit 1 +fi + +IMAGE_INPUT="$1" + +# 规范化镜像名, 若无 registry 前缀则补全 docker.io/ +normalize_image() { + local img="$1" + if [[ "$img" != */*/* ]]; then + # 只有一个斜杠(如 library/nginx 或 beppeb/devstar-...): 仍可能缺少 registry + # Docker 的默认 registry 是 docker.io + echo "docker.io/${img}" + else + echo "$img" + fi +} + +CANONICAL_IMAGE=$(normalize_image "$IMAGE_INPUT") +echo "目标镜像: ${CANONICAL_IMAGE}" + +# 节点列表: 与 k8s-step1-prepare-env.sh 风格一致 +NODES=("172.17.0.15:master" "172.17.0.43:node1" "172.17.0.34:node2") + +# 本机 IP 与 SSH 选项 +LOCAL_IP=$(ip route get 1 | awk '{print $7; exit}') +SSH_OPTS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes' +SSH_KEY_PATH=${SSH_KEY:-$HOME/.ssh/id_rsa} +[ -f "$SSH_KEY_PATH" ] && SSH_ID="-i $SSH_KEY_PATH" || SSH_ID="" + +run_remote() { + local ip="$1"; shift + local cmd="$*" + if [ "$ip" = "$LOCAL_IP" ]; then + bash -lc "$cmd" + else + ssh $SSH_OPTS $SSH_ID ubuntu@"$ip" "$cmd" + fi +} + +# 在远端节点执行: 使用 docker 或 containerd 拉取镜像, 并确保导入到 containerd k8s.io +remote_pull_and_import_cmd() { + local image="$1" + # 注意: 使用单引号包裹, 传到远端后再展开变量 + cat <<'EOF_REMOTE' +set -euo pipefail + +IMAGE_REMOTE="$IMAGE_PLACEHOLDER" + +has_cmd() { command -v "$1" >/dev/null 2>&1; } + +echo "[\"$(hostname)\"] 处理镜像: ${IMAGE_REMOTE}" + +# 优先尝试 docker 拉取, 成功后直接导入 containerd (无需落盘) +if has_cmd docker; then + echo "[\"$(hostname)\"] 使用 docker pull" + sudo docker pull "${IMAGE_REMOTE}" + echo "[\"$(hostname)\"] 导入到 containerd (k8s.io)" + sudo docker save "${IMAGE_REMOTE}" | sudo ctr -n k8s.io images import - >/dev/null +else + echo "[\"$(hostname)\"] 未检测到 docker, 尝试使用 containerd 拉取" + # containerd 直接拉取到 k8s.io 命名空间 + sudo ctr -n k8s.io images pull --all-platforms "${IMAGE_REMOTE}" +fi + +# 规范化 tag: 若镜像缺少 docker.io 前缀, 在 containerd 内补齐一份别名 +NEED_PREFIX=0 +if [[ "${IMAGE_REMOTE}" != docker.io/* ]]; then + NEED_PREFIX=1 +fi + +if [ "$NEED_PREFIX" -eq 1 ]; then + # 仅当不存在 docker.io/ 前缀时, 补一个 docker.io/ 的 tag, 方便与清单匹配 + # 计算补齐后的名字 + if [[ "${IMAGE_REMOTE}" == */*/* ]]; then + # 已有显式 registry, 不重复打 tag + : + else + FIXED="docker.io/${IMAGE_REMOTE}" + echo "[\"$(hostname)\"] 为 containerd 打标签: ${FIXED}" + sudo ctr -n k8s.io images tag "${IMAGE_REMOTE}" "${FIXED}" || true + fi +fi + +echo "[\"$(hostname)\"] 验证镜像是否存在于 containerd:" +sudo ctr -n k8s.io images ls | grep -E "$(printf '%s' "${IMAGE_REMOTE}" | sed 's/[\/.\-]/\\&/g')" || true +EOF_REMOTE +} + +# 遍历节点执行 +for node in "${NODES[@]}"; do + IFS=':' read -r ip hostname <<< "$node" + echo "==== 在 ${hostname} (${ip}) 执行镜像拉取与导入 ====" + # 将占位符替换为实际镜像并远程执行 + remote_script=$(remote_pull_and_import_cmd "$CANONICAL_IMAGE") + # 安全替换占位符为镜像名 + remote_script=${remote_script//\$IMAGE_PLACEHOLDER/$CANONICAL_IMAGE} + run_remote "$ip" "$remote_script" + echo "" +done + +echo "==== 完成 ====" + + diff --git a/docs/kubernetes/k8s-install-all.sh b/docs/kubernetes/k8s-install-all.sh new file mode 100644 index 0000000000..7c9b9dd437 --- /dev/null +++ b/docs/kubernetes/k8s-install-all.sh @@ -0,0 +1,69 @@ +#!/bin/bash +set -e + +# Kubernetes 集群一键安装脚本 +# 功能: 按顺序执行所有安装步骤 + +echo "==== Kubernetes 集群一键安装 ====" +echo "集群信息:" +echo "- Master: 172.17.0.15" +echo "- Node1: 172.17.0.43" +echo "- Node2: 172.17.0.34" +echo "- Kubernetes 版本: v1.32.3" +echo "- 网络插件: Flannel" +echo "- 容器运行时: containerd" +echo "" + +# 检查脚本文件是否存在 +SCRIPTS=( + "k8s-step1-prepare-env.sh" + "k8s-step2-install-containerd.sh" + "k8s-step3-install-components.sh" + "k8s-step4-init-cluster.sh" + "k8s-step5-install-flannel.sh" + "k8s-step6-join-nodes.sh" +) + +for script in "${SCRIPTS[@]}"; do + if [ ! -f "$script" ]; then + echo "错误: 找不到脚本文件 $script" + exit 1 + fi +done + +echo "所有脚本文件检查完成,开始安装..." +echo "" + +# 执行安装步骤 +echo "==== 步骤 1: 环境准备 ====" +./k8s-step1-prepare-env.sh +echo "" + +echo "==== 步骤 2: 安装 containerd ====" +./k8s-step2-install-containerd.sh +echo "" + +echo "==== 步骤 3: 安装 Kubernetes 组件 ====" +./k8s-step3-install-components.sh +echo "" + +echo "==== 步骤 4: 初始化集群 ====" +./k8s-step4-init-cluster.sh +echo "" + +echo "==== 步骤 5: 安装 Flannel 网络插件 ====" +./k8s-step5-install-flannel.sh +echo "" + +echo "==== 步骤 6: 节点加入集群 ====" +./k8s-step6-join-nodes.sh +echo "" + +echo "==== 安装完成 ====" +echo "集群状态:" +kubectl get nodes +echo "" +kubectl get pods -A +echo "" +echo "集群已就绪,可以开始部署应用!" + diff --git a/docs/kubernetes/k8s-prepare-env.sh b/docs/kubernetes/k8s-prepare-env.sh new file mode 100644 index 0000000000..1c032c0f1e --- /dev/null +++ b/docs/kubernetes/k8s-prepare-env.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -e + +echo "==== Kubernetes 环境准备 ====" + +# 1. 更新系统包 +echo "更新系统包..." +sudo apt update && sudo apt upgrade -y + +# 2. 安装必要的工具 +echo "安装必要工具..." +sudo apt install -y curl wget gnupg lsb-release ca-certificates apt-transport-https software-properties-common + +# 3. 禁用 swap +echo "禁用 swap..." +sudo swapoff -a +sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab + +# 4. 配置内核参数 +echo "配置内核参数..." +cat < k8s-prepare-env.sh << 'EOF_OUTER' +#!/bin/bash +set -e + +echo "==== Kubernetes 环境准备 ====" + +# 1. 更新系统包 +echo "更新系统包..." +sudo apt update && sudo apt upgrade -y + +# 2. 安装必要的工具 +echo "安装必要工具..." +sudo apt install -y curl wget gnupg lsb-release ca-certificates apt-transport-https software-properties-common + +# 3. 禁用 swap +echo "禁用 swap..." +sudo swapoff -a +sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab + +# 4. 配置内核参数 +echo "配置内核参数..." +cat < k8s-install-containerd.sh << 'EOF_OUTER' +#!/bin/bash +set -e + +echo "==== 安装容器运行时 (containerd) ====" + +# 1. 安装 containerd +echo "安装 containerd..." +sudo apt update +sudo apt install -y containerd + +# 2. 配置 containerd +echo "配置 containerd..." +# ① 停止 containerd +sudo systemctl stop containerd + +# ② 生成默认配置 +sudo containerd config default | sudo tee /etc/containerd/config.toml > /dev/null + +# ③ 注入镜像加速配置(docker.io/quay.io:腾讯云,其它:高校镜像优先) +sudo sed -i '/\[plugins."io.containerd.grpc.v1.cri".registry.mirrors\]/a\ + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]\n endpoint = ["https://mirror.ccs.tencentyun.com"]\n [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]\n endpoint = ["https://quay.tencentcloudcr.com"]\n [plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]\n endpoint = ["https://ghcr.nju.edu.cn"]\n [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]\n endpoint = ["https://gcr.nju.edu.cn"]\n [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]\n endpoint = ["https://registry-k8s-io.mirrors.sjtug.sjtu.edu.cn"]\n [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]\n endpoint = ["https://gcr.nju.edu.cn"]' /etc/containerd/config.toml + +# ④ 重新加载并启动 containerd +sudo systemctl daemon-reexec +sudo systemctl daemon-reload +sudo systemctl restart containerd + +## 4. 在 master 预下载 CNI 压缩包并分发到各节点 +echo "准备 CNI 工件并分发..." +if [ "$LOCAL_IP" = "172.17.0.15" ]; then + mkdir -p "$ARTIFACTS_DIR" + if [ ! -f "$ARTIFACTS_DIR/$CNI_TGZ" ]; then + echo "在 master 下载 $CNI_TGZ ..." + curl -L --fail --retry 3 --connect-timeout 10 \ + -o "$ARTIFACTS_DIR/$CNI_TGZ" \ + "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/$CNI_TGZ" + else + echo "已存在 $ARTIFACTS_DIR/$CNI_TGZ,跳过下载" + fi + # 分发到所有节点 home 目录 + copy_to_all_nodes "$ARTIFACTS_DIR/$CNI_TGZ" +fi + +# 5. 安装 CNI 插件(优先使用已分发的本地文件) +echo "安装 CNI 插件..." +sudo mkdir -p /opt/cni/bin +if [ -f "$CNI_TGZ" ]; then + echo "使用已分发的 $CNI_TGZ 进行安装" + sudo tar -xzf "$CNI_TGZ" -C /opt/cni/bin/ + rm -f "$CNI_TGZ" +else + echo "未找到本地 $CNI_TGZ,尝试在线下载(网络慢时可能用时较长)..." + curl -L --fail --retry 3 --connect-timeout 10 \ + -o "$CNI_TGZ" \ + "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/$CNI_TGZ" + sudo tar -xzf "$CNI_TGZ" -C /opt/cni/bin/ + rm -f "$CNI_TGZ" +fi + +# 6. 验证安装 +echo "==== 验证 containerd 安装 ====" +sudo systemctl status containerd --no-pager -l +sudo ctr version + +echo "==== containerd 安装完成 ====" +EOF_OUTER + +chmod +x k8s-install-containerd.sh +copy_to_all_nodes k8s-install-containerd.sh +execute_on_all_nodes "./k8s-install-containerd.sh" "安装容器运行时" + +echo "==== 容器运行时安装完成 ====" + diff --git a/docs/kubernetes/k8s-step3-install-components.sh b/docs/kubernetes/k8s-step3-install-components.sh new file mode 100644 index 0000000000..7ffe0928d2 --- /dev/null +++ b/docs/kubernetes/k8s-step3-install-components.sh @@ -0,0 +1,149 @@ +#!/bin/bash +set -e + +# Kubernetes 组件安装脚本 +# 功能: 在所有节点安装 kubelet, kubeadm, kubectl + +echo "==== 安装 Kubernetes 组件 ====" + +# 定义节点列表 +NODES=("172.17.0.15:master" "172.17.0.43:node1" "172.17.0.34:node2") + +# 本机 IP 与 SSH 选项 +LOCAL_IP=$(ip route get 1 | awk '{print $7; exit}') +SSH_OPTS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes' +# SSH 私钥(可用环境变量 SSH_KEY 覆盖),存在则自动携带 +SSH_KEY_PATH=${SSH_KEY:-$HOME/.ssh/id_rsa} +[ -f "$SSH_KEY_PATH" ] && SSH_ID="-i $SSH_KEY_PATH" || SSH_ID="" + +# 函数:在所有节点执行命令 +execute_on_all_nodes() { + local command="$1" + local description="$2" + + echo "==== $description ====" + for node in "${NODES[@]}"; do + IFS=':' read -r ip hostname <<< "$node" + echo "在 $hostname ($ip) 执行: $command" + if [ "$ip" = "$LOCAL_IP" ] || [ "$hostname" = "master" ]; then + bash -lc "$command" + else + ssh $SSH_OPTS $SSH_ID ubuntu@$ip "$command" + fi + done + echo "" +} + +# 函数:传输文件到所有节点 +copy_to_all_nodes() { + local file="$1" + echo "==== 传输文件 $file 到所有节点 ====" + for node in "${NODES[@]}"; do + IFS=':' read -r ip hostname <<< "$node" + echo "传输到 $hostname ($ip)" + if [ "$ip" = "$LOCAL_IP" ] || [ "$hostname" = "master" ]; then + cp -f "$file" ~/ + else + scp $SSH_OPTS $SSH_ID "$file" ubuntu@$ip:~/ + fi + done + echo "" +} + +# 创建 Kubernetes 组件安装脚本 +cat > k8s-install-components.sh << 'EOF_OUTER' +#!/bin/bash +set -e + +echo "==== 安装 Kubernetes 组件 ====" + +# 1. 添加 Kubernetes 仓库 +echo "添加 Kubernetes 仓库 (pkgs.k8s.io v1.32)..." +# 确保 keyrings 目录存在并可读 +sudo install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg +sudo chmod a+r /etc/apt/keyrings/kubernetes-apt-keyring.gpg +echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list >/dev/null + +# 2. 更新包列表 +echo "更新包列表..." +sudo apt update + +# 3. 安装 Kubernetes 组件(使用 v1.32 通道的最新补丁版本) +echo "安装 Kubernetes 组件..." +sudo apt install -y kubelet kubeadm kubectl + +# 4. 锁定版本防止自动更新 +echo "锁定 Kubernetes 版本..." +sudo apt-mark hold kubelet kubeadm kubectl + +# 5. 配置 kubelet +echo "配置 kubelet..." +sudo mkdir -p /var/lib/kubelet +cat < node-join-command.txt + +# 4. 验证集群状态 +echo "==== 验证集群状态 ====" +kubectl get nodes +kubectl get pods -n kube-system + +echo "==== 集群初始化完成 ====" +echo "请保存节点加入命令,稍后用于将 node1 和 node2 加入集群" diff --git a/docs/kubernetes/k8s-step5-install-flannel.sh b/docs/kubernetes/k8s-step5-install-flannel.sh new file mode 100644 index 0000000000..5ee7ed9967 --- /dev/null +++ b/docs/kubernetes/k8s-step5-install-flannel.sh @@ -0,0 +1,77 @@ +#!/bin/bash +set -e + +# Kubernetes 网络插件安装脚本 +# 功能: 在 Master 节点安装 Flannel 网络插件 + +echo "==== 安装 Flannel 网络插件 ====" + +# 1. 下载 Flannel 配置文件 +echo "下载 Flannel 配置文件..." +FLANNEL_VER="v0.27.4" +curl -fsSL https://raw.githubusercontent.com/flannel-io/flannel/${FLANNEL_VER}/Documentation/kube-flannel.yml -O + +# 2. 修改 Flannel 配置 +echo "修改 Flannel 配置..." +sed -i 's|"Network": "10.244.0.0/16"|"Network": "10.244.0.0/16"|g' kube-flannel.yml + +echo "预拉取 Flannel 相关镜像(优先国内镜像域名,拉取后回标官方名)..." +DOCKER_MIRROR="docker.m.daocloud.io" +REGISTRY_K8S_MIRROR="registry-k8s-io.mirrors.sjtug.sjtu.edu.cn" +GHCR_MIRROR="ghcr.tencentcloudcr.com" + +IMAGES=( + "registry.k8s.io/pause:3.8" + "ghcr.io/flannel-io/flannel:${FLANNEL_VER}" +) + +pull_and_tag() { + local origin_ref="$1" # e.g. registry.k8s.io/pause:3.8 + local mirror_ref="$2" # e.g. registry-k8s-io.mirrors.sjtug.sjtu.edu.cn/pause:3.8 + echo "尝试从镜像 ${mirror_ref} 预拉取..." + for i in $(seq 1 5); do + if sudo ctr -n k8s.io images pull "${mirror_ref}"; then + echo "打官方标签: ${origin_ref} <- ${mirror_ref}" + sudo ctr -n k8s.io images tag "${mirror_ref}" "${origin_ref}" || true + return 0 + fi + echo "pull 失败,重试 ${i}/5..."; sleep 2 + done + return 1 +} + +# 预拉取 pause 镜像 +echo "预拉取: registry.k8s.io/pause:3.8" +if pull_and_tag "registry.k8s.io/pause:3.8" "${REGISTRY_K8S_MIRROR}/pause:3.8"; then + echo "pause 镜像拉取成功" +else + echo "WARN: pause 镜像拉取失败,将由 kubelet 重试" +fi + +# 预拉取 flannel 镜像 +echo "预拉取: ghcr.io/flannel-io/flannel:${FLANNEL_VER}" +if pull_and_tag "ghcr.io/flannel-io/flannel:${FLANNEL_VER}" "${GHCR_MIRROR}/flannel-io/flannel:${FLANNEL_VER}"; then + echo "flannel 镜像拉取成功" +else + echo "WARN: flannel 镜像拉取失败,将由 kubelet 重试" +fi + +# 3. 安装 Flannel +echo "安装 Flannel..." +kubectl apply -f kube-flannel.yml + +# 4. 等待 Flannel 启动 +echo "等待 Flannel 组件就绪..." +kubectl -n kube-flannel rollout status daemonset/kube-flannel-ds --timeout=600s || true +kubectl wait --for=condition=ready pod -l app=flannel -n kube-flannel --timeout=600s || true + +echo "等待 CoreDNS 由 Pending 变为 Ready..." +kubectl -n kube-system rollout status deploy/coredns --timeout=600s || true + +# 5. 验证网络插件 +echo "==== 验证 Flannel 安装 ====" +kubectl get pods -n kube-flannel +kubectl get nodes + +echo "==== Flannel 网络插件安装完成 ====" + diff --git a/docs/kubernetes/k8s-step6-join-nodes.sh b/docs/kubernetes/k8s-step6-join-nodes.sh new file mode 100644 index 0000000000..d94ebf5db7 --- /dev/null +++ b/docs/kubernetes/k8s-step6-join-nodes.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -e + +# Kubernetes 节点加入脚本 +# 功能: 将 Node1 和 Node2 加入 Kubernetes 集群 + +echo "==== 将节点加入 Kubernetes 集群 ====" + +# 检查是否存在加入命令文件 +if [ ! -f "node-join-command.txt" ]; then + echo "错误: 找不到 node-join-command.txt 文件" + echo "请先运行 k8s-step4-init-cluster.sh 初始化集群" + exit 1 +fi + +# 读取加入命令 +JOIN_COMMAND=$(cat node-join-command.txt) + +# SSH 选项与密钥 +SSH_OPTS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes' +SSH_KEY_PATH=${SSH_KEY:-$HOME/.ssh/id_rsa} +[ -f "$SSH_KEY_PATH" ] && SSH_ID="-i $SSH_KEY_PATH" || SSH_ID="" +echo "使用加入命令: $JOIN_COMMAND" + +# 定义节点列表 +NODES=("172.17.0.43:node1" "172.17.0.34:node2") + +# 将节点加入集群 +for node in "${NODES[@]}"; do + IFS=':' read -r ip hostname <<< "$node" + echo "==== 将 $hostname ($ip) 加入集群 ====" + ssh $SSH_OPTS $SSH_ID ubuntu@$ip "sudo $JOIN_COMMAND" + echo "$hostname 加入完成" +done + +# 等待节点加入 +echo "==== 等待节点加入集群 ====" +sleep 30 + +# 验证集群状态 +echo "==== 验证集群状态 ====" +kubectl get nodes +kubectl get pods -n kube-system +kubectl get pods -n kube-flannel + +echo "==== 节点加入完成 ====" +echo "集群信息:" +echo "- Master: 172.17.0.15" +echo "- Node1: 172.17.0.43" +echo "- Node2: 172.17.0.34" +echo "- Kubernetes 版本: v1.32.3" +echo "- 网络插件: Flannel" +echo "- 容器运行时: containerd" diff --git a/docs/kubernetes/kube-flannel.yml b/docs/kubernetes/kube-flannel.yml new file mode 100644 index 0000000000..67abd19251 --- /dev/null +++ b/docs/kubernetes/kube-flannel.yml @@ -0,0 +1,211 @@ +--- +kind: Namespace +apiVersion: v1 +metadata: + name: kube-flannel + labels: + k8s-app: flannel + pod-security.kubernetes.io/enforce: privileged +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + k8s-app: flannel + name: flannel +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + k8s-app: flannel + name: flannel +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: flannel +subjects: +- kind: ServiceAccount + name: flannel + namespace: kube-flannel +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + k8s-app: flannel + name: flannel + namespace: kube-flannel +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: kube-flannel-cfg + namespace: kube-flannel + labels: + tier: node + k8s-app: flannel + app: flannel +data: + cni-conf.json: | + { + "name": "cbr0", + "cniVersion": "0.3.1", + "plugins": [ + { + "type": "flannel", + "delegate": { + "hairpinMode": true, + "isDefaultGateway": true + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + } + ] + } + net-conf.json: | + { + "Network": "10.244.0.0/16", + "EnableNFTables": false, + "Backend": { + "Type": "vxlan" + } + } +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: kube-flannel-ds + namespace: kube-flannel + labels: + tier: node + app: flannel + k8s-app: flannel +spec: + selector: + matchLabels: + app: flannel + template: + metadata: + labels: + tier: node + app: flannel + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + hostNetwork: true + priorityClassName: system-node-critical + tolerations: + - operator: Exists + effect: NoSchedule + serviceAccountName: flannel + initContainers: + - name: install-cni-plugin + image: ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1 + command: + - cp + args: + - -f + - /flannel + - /opt/cni/bin/flannel + volumeMounts: + - name: cni-plugin + mountPath: /opt/cni/bin + - name: install-cni + image: ghcr.io/flannel-io/flannel:v0.27.4 + command: + - cp + args: + - -f + - /etc/kube-flannel/cni-conf.json + - /etc/cni/net.d/10-flannel.conflist + volumeMounts: + - name: cni + mountPath: /etc/cni/net.d + - name: flannel-cfg + mountPath: /etc/kube-flannel/ + containers: + - name: kube-flannel + image: ghcr.io/flannel-io/flannel:v0.27.4 + command: + - /opt/bin/flanneld + args: + - --ip-masq + - --kube-subnet-mgr + resources: + requests: + cpu: "100m" + memory: "50Mi" + securityContext: + privileged: false + capabilities: + add: ["NET_ADMIN", "NET_RAW"] + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: EVENT_QUEUE_DEPTH + value: "5000" + - name: CONT_WHEN_CACHE_NOT_READY + value: "false" + volumeMounts: + - name: run + mountPath: /run/flannel + - name: flannel-cfg + mountPath: /etc/kube-flannel/ + - name: xtables-lock + mountPath: /run/xtables.lock + volumes: + - name: run + hostPath: + path: /run/flannel + - name: cni-plugin + hostPath: + path: /opt/cni/bin + - name: cni + hostPath: + path: /etc/cni/net.d + - name: flannel-cfg + configMap: + name: kube-flannel-cfg + - name: xtables-lock + hostPath: + path: /run/xtables.lock + type: FileOrCreate diff --git a/docs/kubernetes/node-join-command.txt b/docs/kubernetes/node-join-command.txt new file mode 100644 index 0000000000..d45c53ee4e --- /dev/null +++ b/docs/kubernetes/node-join-command.txt @@ -0,0 +1 @@ +kubeadm join 172.17.0.15:6443 --token sydcr1.j3ebcck3ithm3gwk --discovery-token-ca-cert-hash sha256:6de26c1e91e6336c18556b4e8a0e52073ec08450f6f2ff0075c3b8301dd99bbb diff --git a/docs/kubernetes/setup-master-gateway.sh b/docs/kubernetes/setup-master-gateway.sh new file mode 100644 index 0000000000..4fbdd3b566 --- /dev/null +++ b/docs/kubernetes/setup-master-gateway.sh @@ -0,0 +1,51 @@ +#!/bin/bash +set -e + +echo "==== 配置 Master 节点作为网关 ====" + +# 1. 启用 IP 转发 +echo "启用 IP 转发..." +echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf +sudo sysctl -p + +# 2. 配置 iptables NAT 规则 +echo "配置 iptables NAT 规则..." +# 清空现有规则 +sudo iptables -F +sudo iptables -t nat -F +sudo iptables -t mangle -F +sudo iptables -X +sudo iptables -t nat -X +sudo iptables -t mangle -X + +# 设置默认策略 +sudo iptables -P INPUT ACCEPT +sudo iptables -P FORWARD ACCEPT +sudo iptables -P OUTPUT ACCEPT + +# 配置 NAT 规则 - 允许内网节点通过 master 访问外网 +sudo iptables -t nat -A POSTROUTING -s 172.17.0.0/20 -o eth0 -j MASQUERADE + +# 允许转发来自内网的流量 +sudo iptables -A FORWARD -s 172.17.0.0/20 -j ACCEPT +sudo iptables -A FORWARD -d 172.17.0.0/20 -j ACCEPT + +# 3. 保存 iptables 规则 +echo "保存 iptables 规则..." +sudo apt update +sudo apt install -y iptables-persistent +sudo netfilter-persistent save + +# 4. 验证配置 +echo "==== 验证配置 ====" +echo "IP 转发状态:" +cat /proc/sys/net/ipv4/ip_forward + +echo "当前 iptables NAT 规则:" +sudo iptables -t nat -L -n -v + +echo "当前 iptables FORWARD 规则:" +sudo iptables -L FORWARD -n -v + +echo "==== Master 网关配置完成 ====" +echo "Master 节点现在可以作为内网节点的网关使用" diff --git a/docs/kubernetes/setup-node1.sh b/docs/kubernetes/setup-node1.sh new file mode 100644 index 0000000000..eebfbac90a --- /dev/null +++ b/docs/kubernetes/setup-node1.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +echo "==== 配置 Node1 (172.17.0.43) 网络路由 ====" + +echo "==== 当前状态 ====" +echo "当前主机名: $(hostname)" +echo "当前 IP: $(ip route get 1 | awk '{print $7; exit}')" + +# 配置网络路由 - 通过 master 访问外网 +echo "配置网络路由..." +# 删除默认网关(如果存在) +sudo ip route del default 2>/dev/null || true + +# 添加默认网关指向 master +sudo ip route add default via 172.17.0.15 + +echo "==== 验证网络配置 ====" +echo "当前路由表:" +ip route show + +echo "测试网络连通性:" +ping -c 2 172.17.0.15 && echo "✓ 可以访问 master" || echo "✗ 无法访问 master" +ping -c 2 8.8.8.8 && echo "✓ 可以访问外网" || echo "✗ 无法访问外网" + +echo "==== Node1 网络路由配置完成 ====" diff --git a/docs/kubernetes/setup-node2.sh b/docs/kubernetes/setup-node2.sh new file mode 100644 index 0000000000..37e01f8cfd --- /dev/null +++ b/docs/kubernetes/setup-node2.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +echo "==== 配置 Node2 (172.17.0.34) 网络路由 ====" + +echo "==== 当前状态 ====" +echo "当前主机名: $(hostname)" +echo "当前 IP: $(ip route get 1 | awk '{print $7; exit}')" + +# 配置网络路由 - 通过 master 访问外网 +echo "配置网络路由..." +# 删除默认网关(如果存在) +sudo ip route del default 2>/dev/null || true + +# 添加默认网关指向 master +sudo ip route add default via 172.17.0.15 + +echo "==== 验证网络配置 ====" +echo "当前路由表:" +ip route show + +echo "测试网络连通性:" +ping -c 2 172.17.0.15 && echo "✓ 可以访问 master" || echo "✗ 无法访问 master" +ping -c 2 8.8.8.8 && echo "✓ 可以访问外网" || echo "✗ 无法访问外网" + +echo "==== Node2 网络路由配置完成 ===="