#!/bin/bash
# 仅在master节点执行,通过SSH远程操作node节点
# 支持交互式输入主机IP和密码,提高脚本适用性
# 核心配置(文档指定版本与网络参数)
# 修复了master命名的bug
K8S_VERSION="1.23.0"
POD_SUBNET="10.244.0.0/16"
SERVICE_SUBNET="10.96.0.0/12"
DOCKER_MIRROR="https://ae28b7f23d3d4baa939ef3e0290e0376.mirror.swr.myhuaweicloud.com"
# 新增:指定稳定的Docker版本(20.10系列LTS,兼容K8s 1.23.0)
DOCKER_STABLE_VERSION="20.10.24"
CALICO_YAML_URL="https://docs.tigera.io/archive/v3.25/manifests/calico.yaml"
K8S_REPO_CONTENT="[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg"
# 日志与错误处理(统一格式)
log() {
echo -e "\033[1;34m[$(date +'%Y-%m-%d %H:%M:%S')] $1\033[0m"
}
error_exit() {
echo -e "\033[1;31m[$(date +'%Y-%m-%d %H:%M:%S')] 错误:$1\033[0m"
exit 1
}
# 交互式输入主机信息
input_host_info() {
log "===== 请输入集群主机信息 ====="
# 获取master节点IP
while true; do
read -p "请输入master节点IP地址(例如:192.168.10.101):" MASTER_IP
if [[ $MASTER_IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
break
else
echo "IP地址格式错误,请重新输入!"
fi
done
# 获取node01节点IP
while true; do
read -p "请输入node01节点IP地址(例如:192.168.10.102):" NODE01_IP
if [[ $NODE01_IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
break
else
echo "IP地址格式错误,请重新输入!"
fi
done
# 获取node02节点IP
while true; do
read -p "请输入node02节点IP地址(例如:192.168.10.103):" NODE02_IP
if [[ $NODE02_IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
break
else
echo "IP地址格式错误,请重新输入!"
fi
done
# 获取root密码(所有节点使用相同密码)
while true; do
read -s -p "请输入所有节点的root用户密码:" NODE_PASS
echo
read -s -p "请再次输入密码确认:" NODE_PASS_CONFIRM
echo
if [ "$NODE_PASS" = "$NODE_PASS_CONFIRM" ]; then
break
else
echo "两次输入的密码不一致,请重新输入!"
fi
done
# 保存节点IP列表
NODE_IPS=("$NODE01_IP" "$NODE02_IP")
log "===== 主机信息输入完成 ====="
}
# 检查sshpass并安装(远程执行必备)
check_sshpass() {
if ! command -v sshpass &> /dev/null; then
log "安装sshpass(远程登录工具)"
yum install -y sshpass >/dev/null 2>&1 || error_exit "sshpass安装失败,请手动执行:yum install -y sshpass"
fi
}
# 验证node节点SSH连通性(前置检查)
verify_node_connection() {
log "验证node节点SSH连接"
for node_ip in "${NODE_IPS[@]}"; do
log "测试连接 node: $node_ip"
sshpass -p "$NODE_PASS" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 root@$node_ip "echo '连接成功'" >/dev/null 2>&1
if [ $? -ne 0 ]; then
error_exit "node节点$node_ip连接失败!请检查:1.IP是否正确 2.SSH服务是否启动 3.密码是否正确"
fi
done
}
# 修改三台主机名(优先执行,确保后续配置依赖正确)
modify_hostnames() {
log "===== 开始修改主机名 ====="
# 1. 修改本地master主机名
log "修改master节点($MASTER_IP)主机名为k8s-master"
hostnamectl set-hostname k8s-master || error_exit "master主机名修改失败"
log "master节点已修改为:k8s-master"
# 2. 远程修改node01主机名
log "远程修改node01($NODE01_IP)主机名为k8s-node01"
sshpass -p "$NODE_PASS" ssh -o StrictHostKeyChecking=no root@$NODE01_IP "hostnamectl set-hostname k8s-node01"
if [ $? -eq 0 ]; then
log "node01已修改为:k8s-node01"
else
error_exit "node01主机名修改失败(检查SSH或密码)"
fi
# 3. 远程修改node02主机名
log "远程修改node02($NODE02_IP)主机名为k8s-node02"
sshpass -p "$NODE_PASS" ssh -o StrictHostKeyChecking=no root@$NODE02_IP "hostnamectl set-hostname k8s-node02"
if [ $? -eq 0 ]; then
log "node02已修改为:k8s-node02"
else
error_exit "node02主机名修改失败(检查SSH或密码)"
fi
log "===== 主机名修改完成 ====="
}
# 远程执行命令(带重试机制)
run_on_nodes() {
local cmd="$1"
local retry=3 # 重试3次
log "在所有node节点执行命令:$cmd"
for node_ip in "${NODE_IPS[@]}"; do
log "执行 node: $node_ip"
for ((i=1; i<=$retry; i++)); do
sshpass -p "$NODE_PASS" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 root@$node_ip "$cmd" >/dev/null 2>&1
if [ $? -eq 0 ]; then
break # 成功则退出重试
elif [ $i -eq $retry ]; then
error_exit "node节点$node_ip执行命令失败(已重试$retry次)"
else
log "重试 node:$node_ip(第$i次)"
sleep 2
fi
done
done
}
# 1. 基础环境配置(文档4.基础环境准备)
configure_base_env() {
log "===== 执行文档「基础环境准备」步骤 ====="
# 1.1 关闭防火墙(文档5.部署docker环境步骤1)
log "关闭防火墙"
# master本地
systemctl stop firewalld >/dev/null 2>&1
systemctl disable firewalld >/dev/null 2>&1 || error_exit "master关闭防火墙失败"
# node远程
run_on_nodes "systemctl stop firewalld; systemctl disable firewalld"
# 1.2 禁用SELinux(文档5.步骤2)
log "禁用SELinux"
# master本地
sed -i '/^SELINUX=/s/enforcing/disabled/' /etc/selinux/config || error_exit "master修改SELinux失败"
setenforce 0 >/dev/null 2>&1
# node远程
run_on_nodes "sed -i '/^SELINUX=/s/enforcing/disabled/' /etc/selinux/config; setenforce 0 || true"
# 1.3 关闭swap(文档6.步骤3)
log "关闭swap分区"
# master本地
swapoff -a >/dev/null 2>&1
sed -i '/swap/s/^/#/' /etc/fstab || error_exit "master关闭swap失败"
# node远程
run_on_nodes "swapoff -a; sed -i '/swap/s/^/#/' /etc/fstab"
# 1.4 配置hosts(文档4.步骤2,依赖已修改的主机名)
log "配置hosts映射(与主机名对应)"
local hosts_content="$MASTER_IP k8s-master\n$NODE01_IP k8s-node01\n$NODE02_IP k8s-node02"
# master本地(先清空旧映射,避免重复)
sed -i '/k8s-master/d; /k8s-node01/d; /k8s-node02/d' /etc/hosts
echo -e "$hosts_content" >> /etc/hosts || error_exit "master配置hosts失败"
# node远程
run_on_nodes "sed -i '/k8s-master/d; /k8s-node01/d; /k8s-node02/d' /etc/hosts; echo -e '$hosts_content' >> /etc/hosts"
# 1.5 安装基础工具(vim、wget等)
log "安装基础工具(vim、wget等)"
# master本地
yum install -y vim wget net-tools lrzsz >/dev/null 2>&1 || error_exit "master安装工具失败"
# node远程
run_on_nodes "yum install -y vim wget net-tools lrzsz >/dev/null 2>&1"
# 1.6 配置内核参数(文档5.步骤5)
log "配置内核参数(网络转发)"
local sysctl_content="net.ipv4.ip_forward=1\nnet.bridge.bridge-nf-call-ip6tables = 1\nnet.bridge.bridge-nf-call-iptables = 1"
# master本地
echo -e "$sysctl_content" >> /etc/sysctl.conf || error_exit "master配置内核参数失败"
modprobe br_netfilter >/dev/null 2>&1 # 加载桥接模块(文档隐含依赖)
sysctl -p >/dev/null 2>&1 || error_exit "master加载内核参数失败,请手动执行:modprobe br_netfilter && sysctl -p"
# node远程
run_on_nodes "echo -e '$sysctl_content' >> /etc/sysctl.conf; modprobe br_netfilter; sysctl -p >/dev/null 2>&1"
log "===== 基础环境配置完成 ====="
}
# 2. 部署Docker环境(文档5.部署docker环境)- 优化:指定稳定版本
deploy_docker() {
log "===== 执行文档「部署docker环境」步骤 ====="
# 2.1 安装Docker依赖并配置源(文档5.步骤3)
log "配置Docker YUM源(阿里源)"
local docker_repo="https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo"
# master本地
yum install -y yum-utils device-mapper-persistent-data lvm2 >/dev/null 2>&1 || error_exit "master安装Docker依赖失败"
yum-config-manager --add-repo $docker_repo >/dev/null 2>&1
# node远程
run_on_nodes "yum install -y yum-utils device-mapper-persistent-data lvm2 >/dev/null 2>&1; yum-config-manager --add-repo $docker_repo >/dev/null 2>&1"
# 2.2 安装指定稳定版本的Docker CE(优化点:避免默认拉取最新版的不稳定问题)
log "安装Docker CE $DOCKER_STABLE_VERSION(长期支持版,兼容K8s $K8S_VERSION)"
# master本地:指定版本+避免依赖冲突
yum -y install docker-ce-$DOCKER_STABLE_VERSION docker-ce-cli-$DOCKER_STABLE_VERSION containerd.io --setopt=obsoletes=0 >/dev/null 2>&1 || error_exit "master安装Docker失败,建议手动执行:yum -y install docker-ce-$DOCKER_STABLE_VERSION docker-ce-cli-$DOCKER_STABLE_VERSION containerd.io --setopt=obsoletes=0"
# node远程:与master保持相同版本,确保集群一致性
run_on_nodes "yum -y install docker-ce-$DOCKER_STABLE_VERSION docker-ce-cli-$DOCKER_STABLE_VERSION containerd.io --setopt=obsoletes=0 >/dev/null 2>&1"
# 2.3 配置Docker加速器与cgroup驱动(文档5.步骤4,保持原逻辑)
log "配置Docker加速器和systemd驱动"
local daemon_json="{\"registry-mirrors\": [\"$DOCKER_MIRROR\"], \"exec-opts\": [\"native.cgroupdriver=systemd\"]}"
# master本地
mkdir -p /etc/docker
echo "$daemon_json" > /etc/docker/daemon.json || error_exit "master配置daemon.json失败"
systemctl daemon-reload >/dev/null 2>&1
systemctl start docker >/dev/null 2>&1
systemctl enable docker >/dev/null 2>&1 || error_exit "master启动Docker失败"
# node远程
run_on_nodes "mkdir -p /etc/docker; echo '$daemon_json' > /etc/docker/daemon.json; systemctl daemon-reload; systemctl start docker; systemctl enable docker >/dev/null 2>&1"
log "===== Docker部署完成(已安装版本:$DOCKER_STABLE_VERSION) ====="
}
# 3. 安装K8s组件(文档6.步骤5-7)
install_k8s() {
log "===== 执行文档「部署Kubernetes集群」步骤 ====="
# 3.1 配置K8s YUM源(文档6.步骤5)
log "配置K8s YUM源(阿里源)"
# master本地
echo -e "$K8S_REPO_CONTENT" > /etc/yum.repos.d/kubernetes.repo || error_exit "master配置K8s源失败"
yum clean all >/dev/null 2>&1
# node远程
run_on_nodes "echo -e '$K8S_REPO_CONTENT' > /etc/yum.repos.d/kubernetes.repo; yum clean all >/dev/null 2>&1"
# 3.2 安装kubeadm、kubelet、kubectl(文档6.步骤6)
log "安装K8s组件(v$K8S_VERSION)"
# master本地
yum install -y kubelet-$K8S_VERSION kubeadm-$K8S_VERSION kubectl-$K8S_VERSION --nogpgcheck >/dev/null 2>&1 || error_exit "master安装K8s组件失败"
systemctl enable kubelet >/dev/null 2>&1
# node远程
run_on_nodes "yum install -y kubelet-$K8S_VERSION kubeadm-$K8S_VERSION kubectl-$K8S_VERSION --nogpgcheck >/dev/null 2>&1; systemctl enable kubelet >/dev/null 2>&1"
log "===== K8s组件安装完成 ====="
}
# 4. 初始化Master节点(文档6.步骤8-12、17)
init_master() {
log "===== 执行文档「初始化k8s-master」步骤 ====="
# 4.1 生成并修改初始化配置(文档6.步骤8-9)
kubeadm config print init-defaults > init-config.yaml || error_exit "生成init-config.yaml失败"
sed -i "s/advertiseAddress: 1.2.3.4/advertiseAddress: $MASTER_IP/" init-config.yaml
sed -i "s/imageRepository: k8s.gcr.io/imageRepository: registry.aliyuncs.com\/google_containers/" init-config.yaml
sed -i "/kubernetesVersion: /c kubernetesVersion: v$K8S_VERSION" init-config.yaml
sed -i "/podSubnet: /c podSubnet: $POD_SUBNET" init-config.yaml
sed -i "/serviceSubnet: /c serviceSubnet: $SERVICE_SUBNET" init-config.yaml
# 修改nodeRegistration.name为master
sed -i '/nodeRegistration:/,/name:/s/name: .*/name: master/' init-config.yaml
# 4.2 拉取镜像(文档6.步骤10)
log "拉取K8s镜像"
kubeadm config images pull --config=init-config.yaml >/dev/null 2>&1 || error_exit "拉取镜像失败,请检查网络或手动执行:kubeadm config images pull --config=init-config.yaml"
# 4.3 初始化Master(文档6.步骤11)
log "初始化Master节点(约5分钟)"
kubeadm init --config=init-config.yaml --ignore-preflight-errors=all || error_exit "Master初始化失败,请执行kubeadm reset后重试"
# 4.4 配置kubectl(文档6.步骤12)
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config || error_exit "复制admin.conf失败"
chown $(id -u):$(id -g) $HOME/.kube/config
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile >/dev/null 2>&1
# 4.5 部署Calico网络插件(文档6.步骤17)
log "部署Calico网络插件(v3.25)"
curl -O $CALICO_YAML_URL || error_exit "下载Calico配置失败,请手动下载:curl -O $CALICO_YAML_URL"
kubectl apply -f calico.yaml || error_exit "部署Calico失败,请检查yaml文件"
log "===== Master初始化完成 ====="
}
# 5. Node节点加入集群(文档6.步骤13)
join_nodes() {
log "===== 执行文档「node节点加入集群」步骤 ====="
# 获取加入命令(文档6.步骤11生成的token)
local join_cmd=$(kubeadm token create --print-join-command) || error_exit "生成join命令失败,请手动执行:kubeadm token create --print-join-command"
log "node节点加入命令:$join_cmd"
# 远程执行加入命令
run_on_nodes "$join_cmd --ignore-preflight-errors=all"
log "===== 所有node节点加入完成 ====="
}
# 主流程(按依赖顺序执行)
main() {
input_host_info # 1. 交互式输入主机信息
check_sshpass # 2. 检查远程工具
verify_node_connection # 3. 验证节点连通性
modify_hostnames # 4. 修改主机名
configure_base_env # 5. 基础环境配置
deploy_docker # 6. 部署Docker(已优化稳定版本)
install_k8s # 7. 安装K8s组件
init_master # 8. 初始化Master
join_nodes # 9. 节点加入集群
log "===== 集群部署完成!验证方法(文档验证步骤):====="
log "1. 查看节点状态:kubectl get nodes(所有节点应为Ready)"
log "2. 查看系统组件:kubectl get pods -n kube-system(所有组件应为Running)"
log "3. 验证Docker版本:docker --version(应显示 $DOCKER_STABLE_VERSION)"
}
main© 2025 Lekovsky
200字
k8s1.23一键安装脚本(1master+2node)