前言
本文讲述如果在 Linux 搭建内/公网 Kubernetes 集群的详细步骤,解决搭建过程中的问题。
准备工作
- Linux CentOS 7.x 两台及以上,本文用的 7.6
- 本文配置默认是在内网环境下,即服务器在同一个局域网环境,公网的差异配置有额外标注 [差异-序号],在后面可看到对应配置。
- 如果是云服务器记得提前在安全组中放开使用到的端口 [主节点 6443] [工作节点测试使用的 80]。
- 安装步骤多个节点可以并行操作,注意某些操作仅主/工作节点执行。
- 部署成功后可以尝试使用 Kubesphere 或 Rancher 容器管理平台进行管理。
Linux 环境设置
# 停止、关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
# 关闭 SELinux
# 永久
sed -i 's/enforcing/disabled/' /etc/selinux/config
# 临时
setenforce 0
# 关闭 Swap
# 永久
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 临时
swapoff -a
- 设置主机名
# 示例 hostnamectl set-hostname k8s-master
# 示例 hostnamectl set-hostname k8s-node1
hostnamectl set-hostname <hostname>
- 将桥接的 IPv4 流量传递到 iptables 的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
- 添加 hosts【仅主节点执行】差异-1
cat >> /etc/hosts << EOF
192.168.2.1 k8s-master
192.168.2.2 k8s-node1
# 192.168.2.3 k8s-node2 ...
EOF
- 使以上配置生效
sysctl --system
- 时间同步
yum install ntpdate -y
ntpdate time.windows.com
Docker 安装
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum -y install docker-ce-18.06.1.ce-3.el7
# 设置开机启动 && 启动
systemctl enable docker && systemctl start docker
# 查看版本
docker --version
- 设置 Docker 仓库地址。可直接用,也可自己在阿里云创建账号用自己的地址
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
- 重启 Docker
systemctl restart docker
K8s 组件安装
- 添加 yum 源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[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
EOF
- 安装Kubeadm、Kubelet、Kubectl
yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
# 设置开机启动
systemctl enable kubelet
- Kubeadm 初始化【仅主节点执行】差异-2
kubeadm init \
# 主节点 IP
--apiserver-advertise-address=192.168.2.1 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
# service、pod 网段设置,不冲突即可
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
- Kubectl 设置,Kubeadm 初始化成功后控制台会打印这些指令(一模一样)【仅主节点执行】
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
- 查看节点
kubectl get nodes
- 执行 join 脚本,kubeadm 初始化成功后控制台会打印出这些脚本【仅工作节点执行】
kubeadm join 192.168.1.1:6443 --token esce21.q6hetwm8si29qxwn \
--discovery-token-ca-cert-hash sha256:00603a05805807501d7181c3d60b478788408cfe6cedefedb1f97569708be9c5
- 如果忘记了 join 脚本,可以在主节点执行以下命令重新生成
kubeadm token create --print-join-command
- 安装 Pod 网络插件(CNI)【仅主节点执行】
# 也可以将 kube-flannel.yml 下载到当前目录执行以下语句
# kubectl apply -f kube-flannel.yml
kubectl apply -f <kube-flannel.yml 链接,网上很多>
测试
# 部署 nginx (deployment,pod)
kubectl create deployment nginx --image=nginx
# 暴露 nginx 端口给外网访问 (service)
kubectl expose deployment nginx --port=80 --type=NodePort
# 获取 pod 和 service 信息
kubectl get pod,svc
# 访问地址:http://NodeIP:<service随机暴露的端口>
外网差异配置
- 差异-1 hosts 配置
cat >> /etc/hosts << EOF
<外网 IP> k8s-master
<外网 IP> k8s-node1
# <外网 IP> k8s-node2 ...
EOF
- 差异-2 kubeadm 初始化
kubeadm init \
# 主节点 IP
--apiserver-advertise-address=<外网 IP> \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
# service、pod 网段设置,不冲突即可
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
执行完上面的初始化脚本后会卡在 etcd 初始化的位置,因为 etcd 绑定端口的时候使用了外网 IP,而云服务器外网 IP 并不是本机的网卡,而是网关分配的一个供外部访问的 IP,从而导致初始化进程一直重试绑定,长时间卡住后失败。
解决办法:在卡住过程中,修改初始化生成的 etcd.yaml 中的配置成示例图一样,进程会自动重试并初始化成功。
# - --listen-client-urls=https://0.0.0.0:2379
# - --listen-peer-urls=https://0.0.0.0:2380
vim /etc/kubernetes/manifests/etcd.yaml
- [差异-3] 集群内部互相访问不通
集群按上面步骤搭建好后,Pod 之间互相访问不了,StatefulSet 也无法通过 <podName.serviceName> 这种方式直接访问,但是通过 NodePort 暴露给外部访问确是可以访问到的目标服务的。
主节点执行 kubectl exec -it <PodName> bash 进入 Pod 命令会连接超时最终失败,并打印出超时信息,显示使用的 IP 是工作节点的内网 IP,它们不在同一个局域网中自然是访问不通的。
如果网络互通,进入 Pod 容器直接 ping 其他 Pod/Service 的 IP 或者 StatefuSet 虚拟 DNS 地址 [PodName].[ServiceName].[Namespace].svc.cluster.local 是可以通的。
解决办法:使用 iptables IP 重定向,如这种情况下让系统访问工作节点内网 IP 时转而访问工作节点的外网 IP。
iptables -t nat -A OUTPUT -d <内网 IP> -j DNAT --to-destination <外网 IP>
其他问题
警告 Cgroup Driver 不一致
节点加入集群会警告 docker 和 kubelet 的 Cgroup Driver 不一致,但是暂未发现影响,如图:
解决办法:修改 docker 的 Cgroup Driver 为 systemd
vim /usr/lib/systemd/system/docker.service
# 修改下面这项,后面加上 --exec-opt native.cgroupdriver=systemd
ExecStart=/usr/bin/dockerd --exec-opt native.cgroupdriver=systemd
# 重新加载并重启
systemctl daemon-reload
systemctl restart docker
# 查看当前 Docker Cgroup 驱动
docker info | grep Cgroup
重复 init/join 集群报错
比如:主节点初始化失败,再次尝试报错;加入集群时出错了修改后再次加入报错;主节点删除了工作节点,工作节点再次加入报错等情况。如图:
解决办法:使用 kubeadm 重置后再执行 Join 命令
# 询问时输入 y 回车
kubeadm reset
forward 策略为 drop
我不确定这个会不会引发集群问题,先记录下
解决办法:就是修改 iptables forward 策略为 ACCEPT。可以在系统中直接改,但是重启后又会复原。可以通过修改docker配置达到永久生效的目的
vim /lib/systemd/system/docker.service
# 在[Service]标签下加入如下参数
ExecStartPost=/sbin/iptables -P FORWARD ACCEPT
# 重新加载并重启
systemctl daemon-reload
systemctl restart docker
# 前后查看 iptables 策略
iptables -nL
Rancher安装
- Master 节点执行以下指令就行,官网有 快速开始 介绍
- Rancher 是一个容器管理平台,可以直接创建集群,也可以将原有集群添加进去交给它管理。通过UI界面创建集群中各个容器/组件非常方便。
- 安装好后通过 80/443 端口访问,云服务器记得开放这两个端口
sudo docker run --privileged -d --restart=unless-stopped -p 80:80 -p 443:443 rancher/rancher