环境规划

虚拟机环境是ProxmoxVE,当然你也可以用VMware或VirtualBox。

另外:最好有科学上网的环境,操作过程中尽量把需要科学上网的源都改成了国内源,但是并不是所有的镜像都有国内源。

  • 虚拟机操作系统:Debian11,从Debian官网下载的iso镜像,最小化安装,不包含图形界面。

  • 虚拟机配置:

    主机名 IP地址 配置 节点角色
    k8s-master1 192.168.32.204 2核2G master
    k8s-master2 192.168.32.205 2核2G master
    k8s-master3 192.168.32.206 2核2G master
    k8s-worker1 192.168.32.207 2核2G worker
    k8s-worker2 192.168.32.208 2核2G worker
    k8s-worker3 192.168.32.209 2核2G worker
  • VIP(虚拟IP):192.168.32.250

    3个master节点,主要作用是使master节点高可用,实际工作过程中只有一个master在发挥作用,另外两个只是备份。在工作master节点出现问题时,通过IP地址漂移将master节点的IP地址自动漂移到其它的master节点达到高可用的目的。因此每个master除了需要有一个自己的IP,还需要有一个可以在三个节点中自动漂移的VIP。

环境准备-所有节点

虚拟机环境安装可以先在一个虚拟机上准备好环境,然后直接克隆

在开始之前当然是先配置国内源,然后更新下系统,这个不多说了。

  1. 关闭swap,需要两步操作

    • 修改/etc/fstab文件,注释掉挂载swap分区的指令,然后重启

    • 在最新版的debian系统中,就算操作完上一步,还是无法关闭swap。还得屏蔽掉systemd的服务,然后重启

    • 重启之后检查一下swap分区是否成功关闭:

      Swap total 为0 说明已经关闭

  2. 安装容器运行时:参考Docker官方文档

    # 首先安装一些依赖软件
    apt-get install ca-certificates curl gnupg
    # 添加docker仓库的GPG key
    mkdir -m 0755 -p /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    # 添加docker仓库,注意这里把docker官方仓库地址,修改为了ustc的国内地址
    echo \
      "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.ustc.edu.cn/docker-ce/linux/debian \
      "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
      tee /etc/apt/sources.list.d/docker.list > /dev/null
    # 安装容器运行时
    apt update
    apt install containerd.io
    # 锁定版本,防止系统更新时更新版本导致兼容问题
    apt-mark hold containerd.io

    说明:这里不需要安装所有的docker环境,只需要一个containerd.io的包。这还需要了解一下docker和k8s之间的爱恨情仇的小历史:

    • 2014年k8s刚刚诞生,Docker如日中天已成为容器的代名词,所以k8s自然选择了依附Docker;
    • 2016年k8s已经相对成熟,加入了CNCF,成为了第一个CNCF托管项目。然后引入了CRI(Container Runtime Interface),提供了一个统一的容器运行时接口,和docker完全不兼容。意思很明显,想要提供一套标准接口,自己来掌握标准的制定。
    • 但是这个时候Docker仍然是最火的容器,因此k8s也提供了一个折中的方案,在kubelet和docker之间加入了一个适配器,把docker的接口转换成cri接口,即dockershim。
    • 随着k8s的逐渐强大,docker也只得“断臂求生”,把Dcoker Engine拆分成了多个模块,其中的Docker Daemon部分捐献给了CNCF,符合CRI标准,就是现在的containerd。
    • 所以docker本身也是通过Docker Engine调用containerd,外部与CRI不兼容。
    • k8s操作容器可以通过dockershim调用docker的接口,也可以直接通过CRI调用containerd的接口。
    • 2020年k8s1.20版本的时候宣布弃用docker,在1.24版本时候彻底弃用了docker,本质上弃用的只是dockershim,底层调用的还是相同的containerd。
  3. 配置containerd

    将containerd的配置文件置为默认:

    containerd config default | tee /etc/containerd/config.toml

    然后修改/etc/containerd/config.toml:

    # 搜索并修改sandbox_image地址,改为国内地址
    sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.6"
    # 修改Cgroup类型为systemd
    SystemdCgroup = true

    重启containerd

    systemctl restart containerd
  4. 安装kubeadm、kubelet、kubectl,参考 官方文档

    # 安装依赖包
    apt install -y apt-transport-https ca-certificates curl
    
    # 导入google cloud公开签名(可能需要科学上网)
    curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg 
    https://packages.cloud.google.com/apt/doc/apt-key.gpg
    
    # 添加kubernetes仓库,这里把官方源改成了国内源
    echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.ustc.edu.cn/kubernetes/apt kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

    安装:

    apt update
    apt install -y kubelet kubeadm kubectl
    # 锁定版本
    apt-mark hold kubelet kubeadm kubectl
  5. 修改iptables配置

    cat <<EOF | tee /etc/modules-load.d/k8s.conf
    overlay
    br_netfilter
    EOF
    
    cat <<EOF | tee /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    net.ipv4.ip_forward=1
    EOF
    
    sysctl --system

节点配置

上面的环境准备完成后,可以关闭虚拟机了,然后根据这个虚拟机克隆出另外5个:

image-20230331123802629

每个节点按照之前的规划,修改好主机名和静态的IP地址,这里展示只展示k8s-master1的操作:

使用以下命令修改主机名,修改完之后别忘了修改/etc/hosts文件中的主机名

hostnamectl set-hostname k8s-master1

修改静态IP:/etc/network/interfaces

image-20230331132113541

最后重启生效。

master节点配置

  1. 创建kube-vip的静态pod文件:参考kube-vip文档这一步是为了实现master节点的高可用,如果只有一个master节点,忽略这一步

    文档中提供了两种方案:keepalived+haproxy,kube-vip,我们使用更简单的kube-vip。

    我们最终的目的只需要一个kube-vip.yaml文件,生成这个文件的过程稍微有点复杂,这里提供一个生成好的。

    apiVersion: v1
    kind: Pod
    metadata:
      creationTimestamp: null
      name: kube-vip
      namespace: kube-system
    spec:
      containers:
      - args:
        - manager
        env:
        - name: vip_arp
          value: "true"
        - name: port
          value: "6443"
        - name: vip_interface
          value: enp6s18
        - name: vip_cidr
          value: "32"
        - name: cp_enable
          value: "true"
        - name: cp_namespace
          value: kube-system
        - name: vip_ddns
          value: "false"
        - name: vip_leaderelection
          value: "true"
        - name: vip_leaseduration
          value: "5"
        - name: vip_renewdeadline
          value: "3"
        - name: vip_retryperiod
          value: "1"
        - name: vip_address
          value: 192.168.32.250
        - name: prometheus_server
          value: :2112
        image: ghcr.io/kube-vip/kube-vip:v0.5.10
        imagePullPolicy: Always
        name: kube-vip
        resources: {}
        securityContext:
          capabilities:
            add:
            - NET_ADMIN
            - NET_RAW
        volumeMounts:
        - mountPath: /etc/kubernetes/admin.conf
          name: kubeconfig
      hostAliases:
      - hostnames:
        - kubernetes
        ip: 127.0.0.1
      hostNetwork: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/admin.conf
        name: kubeconfig
    status: {}

    以上文件需要根据自己的环境进行修改:

    • vip_interface: 改成你自己的网卡名字,这个网卡是与外部通信的网卡,通过ip addr可以查看
    • vip_address:改成你自己的VIP地址

    最终这个文件要复制到:/etc/kubernetes/manifests/kube-vip.yaml,位于这个目录的yaml文件在集群启动时会自动应用。

  2. 创建初始化集群的配置文件master-init.yaml

    # master init
    apiVersion: kubeadm.k8s.io/v1beta3
    kind: InitConfiguration
    nodeRegistration:
      criSocket: unix:///var/run/containerd/containerd.sock
    
    ---
    # 会自动应用到全局
    apiVersion: kubeadm.k8s.io/v1beta3
    kind: ClusterConfiguration
    kubernetesVersion: stable
    controlPlaneEndpoint: 192.168.32.250
    imageRepository: registry.aliyuncs.com/google_containers
    
    ---
    # 所有节点添加的配置
    apiVersion: kubelet.config.k8s.io/v1beta1
    kind: KubeletConfiguration
    cgroupDriver: systemd
    • kubernetesVersion: 要部署的kubernetes的版本,需要填写完整的版本号,stable表示最新的稳定版,截止到这篇文章是v1.26.3 。查看所有版本

    • controlPlaneEndpoint: 控制平面地址,即VIP地址,也可以是域名的形式

    • imageRepository: 镜像仓库地址

  3. 使用上面的配置文件创建集群

    在创建集群之前,需要先通过科学上网把kube-vip的镜像拉下来,containerd的管理工具是crictl,在之前安装环境的时候,这个工具已经自动装好了。

    crictl --runtime-endpoint unix:///run/containerd/containerd.sock pull ghcr.io/kube-vip/kube-vip:v0.5.10

    初始化集群:

    kubeadm init --upload-certs --config master-init.yaml

    初始化成功之后,会提示如何配置环境变量来使用集群,并且给出了加入master节点和加入worker节点的指令(包含了需要用到的token和cert),如下图所示:

    image-20230331150820457

    因为以后主要用普通用户操作k8s集群,所以按照上面的提示,切换成普通用户(这个普通用户需要有sudo的权限),然后执行:

    mkdir -p $HOME/.kube
     sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
     sudo chown $(id -u):$(id -g) $HOME/.kube/config

    另外查看网卡信息,会看到多了一个ip地址,即我们设置的VIP:

    image-20230331151246324

加入master节点

可以直接使用上一步的初始化完成之后的提示,在master节点上直接执行,这里是通过配置文件来执行。

  1. 登录其它的master节点:修改好 主机名、IP地址、添加好kube-vip.yaml、下载好kube-vip的镜像。

  2. 然后创建一个master-join.yaml文件,内容如下

    # 所有节点添加的配置
    apiVersion: kubelet.config.k8s.io/v1beta1
    kind: KubeletConfiguration
    cgroupDriver: systemd
    
    ---
    # master join
    apiVersion: kubeadm.k8s.io/v1beta3
    kind: JoinConfiguration
    discovery:
      bootstrapToken:
        token: [上一步初始化完成提示的token]
        apiServerEndpoint: 192.168.32.250:6443
        caCertHashes:
        - sha256:[上一步初始化完成提示的sha256]
    controlPlane:
      certificateKey: [上一步初始化完成提示的cert]
  3. 通过配置文件加入:

    kubeadm join --config master-join.yaml

加入worker节点

可以直接使用上一步的初始化完成之后的提示,在worker节点上直接执行,这里是通过配置文件来执行。

  1. 登录其它的worker节点:修改好 主机名、IP地址。这里不需要kube-vip.yaml,也不需要下载kube-vip的镜像

  2. 然后创建一个worker-join.yaml文件,内容如下

    # 所有节点添加的配置
    apiVersion: kubelet.config.k8s.io/v1beta1
    kind: KubeletConfiguration
    cgroupDriver: systemd
    
    ---
    # worker join
    apiVersion: kubeadm.k8s.io/v1beta3
    kind: JoinConfiguration
    discovery:
      bootstrapToken:
        token: [上一步初始化完成提示的token]
        apiServerEndpoint: 192.168.32.250:6443
        caCertHashes:
        - sha256:[上一步初始化完成提示的sha256]
  3. 通过配置文件加入:

    kubeadm join --config worker-join.yaml

安装网络插件cilium

经过之前的操作,我们已经搭建好了一个k8s集群,但是此时的集群还不能使用,还需要在集群里安装一个网络插件才能真正使用起来。

在任意一个master节点查看node信息,可以看到status都是NotReady。

image-20230331154113531

这里我们选择的网络插件是cilium,因为安装起来非常简单,只需两步,参考:官方文档,但是在下载cilium的时候可能需要科学上网

# 首先下载cilium命令行工具
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/master/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

# 然后执行安装
cilium install

安装完之后再次查看集群节点状态:

image-20230331155045841

结束

到此为止,一个基本的k8s集群环境就搭建好了。

但是如果要部署项目,还需要ingress-nginx(七层代理)、nfs-provisioner(自动分配nfs类型的pv)、cert-manager(自动部署https证书)等插件。

这些在以后的博客中会慢慢总结。