前言
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 集群。