前言
Kubernetes 是当下热门的容器编排系统,在 Devbox 上搭建 Kubernetes 集群是一种较为便捷的学习方式。目前网上资料以搭建 IPv4 集群为主,在公司大力推进 IPv6 改造的当下,本文提供了双协议栈集群的一种搭建方式。
通过本文你可以:
-
快速搭建一个双协议栈 K8s 集群
-
创建一个支持双协议栈的 Web 服务
准备工作
整个搭建过程均在 root 角色下进行的。
配置
本文使用的环境配置,可以作为参考。
两台开发机一台Master节点,一台工作节点 | Debian 10系统8核16G |
---|---|
containerd | 版本v1.6.8 |
K8s | 版本v1.25 |
Flannel | 版本v0.19.2 |
swap | swap 会导致集群无法启动,建议永久关闭 sed -i '/swap/s/^/#/' /etc/fstab |
安装 containerd
可参考官方安装指令:Install Docker Engine on Debian
Shell
apt-get update
apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release \
apt-transport-https
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
因为 containerd 默认镜像拉取地址为国外仓库下载速度较慢,可能会报错"net/http: TLS handshake timeout",可以安装镜像加速器。在 /etc/docker/daemon.json 文件括号内添加下面的值。
Shell
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"]
}
保存修改后重启 containerd 使配置生效。
Shell
# 守护进程重启
systemctl daemon-reload
# 重启containerd服务
systemctl restart containerd
安装 K8s
从 1.21 版本开始,K8s 集群默认启用 IPv4/IPv6 双协议栈网络,以支持同时分配 IPv4 和 IPv6 地址。而官网建议使用 v1.23 版本之后的,这里选择安装了 K8s 的最新版本 v1.25 。
Shell
apt-get update
curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update -y
apt-get install -y kubelet kubeadm kubectl
搭建集群
启动 Master 节点
Shell
kubeadm init --pod-network-cidr=10.244.0.0/16,2001:db8:42:0::/56 --service-cidr=10.96.0.0/16,2001:db8:42:1::/112 --image-repository=registry.aliyuncs.com/google_containers --ignore-preflight-errors=all
初始化成功后会返回下面内容,保存一下,这个命令用于其他节点加入到集群中,而且 Token 是有时效性的,过期时间一般是1天。
Shell
kubeadm join *** --token *** \
--discovery-token-ca-cert-hash ***
如果忘了保存,可以执行下面指令查看。
Shell
kubeadm token create --print-join-command
安装网络通信插件
初始化集群后, Master 节点处于 Not-ready 的状态,需要安装网络通信插件,这里使用 Flannel 进行演示。从 kube-flannel.yml获取网页内容到本地,并在 ConfigMap.data.net-conf.json 字段新增"EnableIPv6"和"IPv6Network"表示支持双栈。
接着执行下面命令安装 Flannel 插件。
Shell
kubectl apply -f kube-flannel.yml
可执行下面命令查看安装结果。
Shell
cat /run/flannel/subnet.env
如图所示,新增了两个字段:
-
FLANNEL_IPV6_NETWORK
-
FLANNEL_IPV6_SUBNET
工作节点加入集群
首先在工作节点上根据以上步骤安装好 containerd 和 K8s 。执行以下命令,将工作节点加入到 Master 节点的集群中。
Shell
kubeadm join *** --token *** \
--discovery-token-ca-cert-hash ***
如下表示加入集群成功。
等待节点创建成功,分别执行以下命令查看 nodes 和 pods 状态。
Shell
kubectl get nodes
kubectl get pod -A -o wide
验证 IPv4 /IPv6 双****协议栈
验证寻址
每个双协议栈节点应分配一个 IPv4 块和一个 IPv6 块。 通过运行以下命令来验证是否配置了 IPv4/IPv6 Pod 地址范围。 将示例节点名称替换为集群中的有效双协议栈节点。 在此示例中,节点的名称为 n248-173-091。
Shell
kubectl get nodes n248-173-091 -o go-template --template='{{range .spec.podCIDRs}}{{printf "%s\n" .}}{{end}}'
Shell
10.244.1.0/24
2001:db8:42:2::/64
验证服务支持双栈
下面通过创建一个 Nginx 服务验证双协议栈生效。
- 创建 nginx 的发布 deployment , K8s 通过 deployment 来部署应用
创建 nginx-dep.yml 文件并执行以下命令。
Shell
kubectl apply -f nginx-dep.yml
YAML
# nginx-dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
执行以下命令查看 deployment 状态,可以看到3个 pod 均处于READY状态。
Shell
kubectl get deploy -o wide
Shell
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deployment 3/3 3 3 2d17h nginx nginx:alpine app=nginx
- 创建 nginx 的服务 Service , K8s 使用 Service 来实现服务发现
创建 nginx-svc.yml 文件,执行以下命令。
Shell
kubectl apply -f nginx-svc.yml
YAML
# nginx-svc.yml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ipFamilyPolicy: PreferDualStack
ipFamilies:
- IPv6
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
type: NodePort
其中.spec.ipFamilyPolicy可设置为PreferDualStack或RequireDualStack以激活双栈支持,默认为SingleStack。
.spec.ipFamilies字段用来设置 IPv4 和 IPv6 的首选项顺序。
执行以下命令查看 Service 状态。
Shell
kubectl get svc nginx-service -o wide
为了验证在外部正常访问 nginx,打开浏览器,输入工作节点的 ip+port ,可以看到 nginx 的欢迎页面,说明 nginx-service 创建成功。
常见问题
以下是我在搭建过程中遇到的一些问题,仅供参考。
- 当执行集群初始化命令时,出现 timed out waiting for the condition 的报错
执行journalctl -xeu kubelet查询日志,检查是不是 pause 镜像没有下载成功,因为阿里的kubernetes仓库虽然可以下载到 K8s v1.23+以上的镜像,但是有一个问题,其pause容器还是用的k8s.gcr.io/pause:3.6,该镜像在国内服务器下载不成功,需要手工下载。
Shell
# 由于k8s.gcr.io 需要连外网才可以拉取到,导致 k8s 的基础容器 pause 经常无法获取。k8s docker 可使用代理服拉取,再利用 docker tag 解决问题
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6 k8s.gcr.io/pause:3.6
# 但是我们k8s集群中使用的CRI是containerd。所以只能通过 docker tag 镜像,再使用 ctr 导入镜像.
docker save k8s.gcr.io/pause -o pause.tar
ctr -n k8s.io images import pause.tar
# 重启
systemctl restart containerd
kubeadm reset
# 重新执行初始化命令
kubeadm init --pod-network-cidr=10.244.0.0/16,2001:db8:42:0::/56 --service-cidr=10.96.0.0/16,2001:db8:42:1::/112 --image-repository=registry.aliyuncs.com/google_containers --ignore-preflight-errors=all
- 当节点加入master后报错:Config not found: /etc/kubernetes/admin.conf
在工作节点的 /etc/kubernetes/ 位置创建 admin.conf ,把 master 节点的 admin.conf 内容复制进去,再新增环境变量。
Shell
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile
- pod****中的coredns 一直重启
执行kubeadm reset 重置,并执行ifconfig,cni0 的IP地址段不属于 Flannel 的IP地址段里,需要清理一下网络,删除 cni0 ,之后会自动重建。
Shell
ifconfig cni0 down
ip link delete cni0
如果网卡 cni0 删除后没有重建时,重启 containerd 。
Shell
systemctl daemon-reload
systemctl restart containerd
总结
本文演示了如何在 Devbox 上搭建一个双协议栈 Kubernetes 集群,并通过部署一个 Nginx 服务进行了验证。未来会提供更多实践类的文章,比如基于 Devbox 搭建一个高可用的 Kubernetes 集群。