2-4-基础ansible部署k8s

熊 0 阅读 容器

根据公司业务场景的不同, 你可能需要部署几套或几十套 二进制K8S高可用集群, 面对繁琐的部署步骤, 你可能望而却步, 急需自动化的K8S部署工具, kubeasz就可以很好的解决你的问题。

k8s 集群环境主要是 kubernetes 管理端服务(kube-apiserver、kube-controller-manager、kube-scheduler)的⾼可⽤实现 , 以及 node 节点上的(kubelet、kube-proxy)客户端服务的部署。

如果是公司托管的 IDC 环境 , 建议直接将 harbor 和 node 节点部署在物理机环境 , master 节点、etcd、负载均衡等可以是虚拟机。

本次安装使用的服务器资源为: harbor 1台( 高可用环境可以2台做harbor镜像同步) 、haproxy+keepalived 2台、master 节点3台( 高可用环境最少2台) 、node 节点3台( 高可用环境2~N台) 、etcd 3台( 高可用环境最少3台才能选举leader) 。

类型

服务器IP

主机名

VIP 地址

备注

k8s-master01

192.168.71.29

k8s-master01.cbear.top

/

/

k8s-master02

192.168.71.30

k8s-master02.cbear.top

/

/

k8s-master03

192.168.71.31

k8s-master03.cbear.top

/

最后新增节点

ha1

192.168.71.32

ha1.cbear.top

192.168.71.150

代理master api

ha2

192.168.71.33

ha2.cbear.top

192.168.71.150

代理master api

harbor

192.168.71.34

harbor.cbear.top

/

安装 ansible , kubeasz 部署 k8s

k8s-node01

192.168.71.35

k8s-node01.cbear.top

/

/

k8s-node02

192.168.71.36

k8s-node02.cbear.top

/

/

k8s-node03

192.168.71.37

k8s-node03.cbear.top

/

最后新增节点

k8s-etcd01

192.168.71.42

k8s-etcd01.cbear.top

/

/

k8s-etcd02

192.168.71.43

k8s-etcd02.cbear.top

/

/

k8s-etcd03

192.168.71.44

k8s-etcd03.cbear.top

/

/

kubeasz-install-1

kubeasz是一个利用ansible-playbook基于二进制方式自动化部署和运维k8s集群的开源项目 , 目前该项目最新发布版本为3.6.3 , 基于该版本我们可以快速实现部署最高版本为1.29的k8s集群。

基于kubeasz安装的k8s高可用架构方案如上 , kubeasz以前的官方文档中Node节点还使用的是haproxy处理自身高可用 , 但实际上kubeasz-3.3.0是使用kube-lb代替了haproxy。

对于没有安装ansible的部署服务器。可以通过kubeasz容器。实现整个部署流程

#启动kubeasz容器
./ezdown -S

安装过程中默认会创建如下别名

root@harbor:~# cat .bashrc
alias dk='docker exec -it kubeasz'  # generated by kubeasz

之后直接使用dk 切换到容器,运行安装过程中的命令即可。通过以下类似命令实现部署过程。整个

dk ezctl setup k8s-cluster all 

1. 基础环境准备

1.1 服务器配置

192.168.71.34服务器安装 ansible , 初始化配置。

  1. 安装ansible

    root@harbor:~# apt install ansible
  2. 准备ansible环境

    root@harbor:~# mkdir /etc/ansible 
    root@harbor:/etc# cd /etc/kubeasz/
    root@harbor:/etc/kubeasz# ls
    ansible.cfg  bin  docs  down  example  ezctl  ezdown  manifests  pics  playbooks  README.md  roles  tools
    root@harbor:/etc/kubeasz# cp example/
    config.yml        hosts.allinone    hosts.multi-node  
    root@harbor:/etc/kubeasz# cp example/hosts.multi-node /etc/ansible/hosts
  3. 配置ssh密钥登录

    这里有一个集群互通的shell脚本, 通过读取文件cluster_config.txt中的IP 和主机名。这个脚本主要用于配置ssh互通和主机名设置

    root@harbor:~# cat cluster_config.txt 
    192.168.71.29 k8s-master01.cbear.top
    192.168.71.30 k8s-master02.cbear.top
    192.168.71.31 k8s-master03.cbear.top
    192.168.71.32 ha1.cbear.top
    192.168.71.33 ha2.cbear.top
    192.168.71.33 ha2.cbear.top
    192.168.71.34 harbor.cbear.top
    192.168.71.35 k8s-node01.cbear.top
    192.168.71.36 k8s-node02.cbear.top
    192.168.71.37 k8s-node03.cbear.top
    192.168.71.42 k8s-etcd01.cbear.top
    192.168.71.43 k8s-etcd02.cbear.top
    192.168.71.44 k8s-etcd03.cbear.top
    #!/bin/bash
    
    # 集群配置文件路径
    CONFIG_FILE="cluster_config.txt"
    REMOTE_PORT="22"
    REMOTE_USER="root"
    REMOTE_PASS="daemon"
    PASSPHRASE=""
    declare -A NODES_MAP
    SSH_OPTIONS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null)
    
    # 检查配置文件是否存在
    if [ ! -f "$CONFIG_FILE" ]; then
        echo "Configuration file not found: $CONFIG_FILE"
        exit 1
    fi
    function read_env() {
    echo "--------------------------"
    echo "开始读取配置文件中的主机名和IP"
    while IFS=' ' read -r ip hostname; do
        # 忽略空行
        if [[ -z "$ip" || -z "$hostname" ]]; then
            continue
        fi
    
        # 将IP和hostname存储到映射中
        NODES_MAP["$ip"]="$hostname"
    done < "$CONFIG_FILE"
    }
    
    # 安装sshpass软件包
    function install_sshpass() {
        echo "--------------------------"
        echo "开始检查并安装sshpass软件包"
    
        for ip in "${!NODES_MAP[@]}"; do
            echo "检查节点 ${NODES_MAP[$ip]} ($ip) 上的sshpass安装状态"
            # 检查sshpass是否已经安装
            if  sshpass -p "${REMOTE_PASS}" ssh "${SSH_OPTIONS[@]}" "${REMOTE_USER}@${ip}" "dpkg -s sshpass" &> /dev/null; then
                echo "节点 $ip 上已经安装sshpass"
                continue
            else
                echo "节点 $ip 上未安装sshpass, 开始安装..."
                # 如果sshpass未安装, 则执行安装
                if  sshpass -p "${REMOTE_PASS}" ssh "${SSH_OPTIONS[@]}" "${REMOTE_USER}@${ip}" "apt-get update && apt-get install -y sshpass"; then
                    echo "节点 $ip 上sshpass安装成功"
                else
                    echo "节点 $ip 上sshpass安装失败" >&2
                    # 安装失败可以选择退出脚本或继续
                    # exit 1 # 或者使用 continue 来继续其他节点的安装
                    continue
                fi
            fi
        done
    }
    
    function remove_ssh_file()
    {
    echo "--------------------------"
    echo "初始化远程主机ssh配置信息"
    for ip in "${!NODES_MAP[@]}" ; do
        echo “删除节点$ip ssh信息”
        sshpass -p "${REMOTE_PASS}" ssh "${REMOTE_USER}@${ip}" "${SSH_OPTIONS[@]}" "rm -rf /root/.ssh"
        
    done
    }
    #每个节点生成公钥函数
    function keygen_rsa() {
        echo "--------------------------"
        echo "开始为每个节点生成SSH公钥"
        
        for ip in "${!NODES_MAP[@]}"; do
            echo "为节点 $ip 生成公钥"
            # 使用sshpass传递密码进行远程命令执行, 但请注意这并不安全
            # 推荐使用SSH密钥认证
            sshpass -p "$REMOTE_PASS" ssh "${SSH_OPTIONS[@]}" "${REMOTE_USER}@${ip}" \
                "ssh-keygen -f /root/.ssh/id_rsa -t rsa -N \"$PASSPHRASE\"" || \
                { echo "为 $ip 生成公钥失败"; continue; }
        done
    }
    
    #配置hosts文件
    function set_hosts() {
    echo "--------------------------"
    echo "配置hosts文件"
    > /etc/hosts
    cat > /etc/hosts << EOF
    127.0.0.1 localhost
    127.0.1.1 ubuntu2204
    
    # The following lines are desirable for IPv6 capable hosts
    ::1     ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    EOF
    for ip in "${!NODES_MAP[@]}" ;do
         echo "$ip ${NODES_MAP[$ip]}" >> /etc/hosts
    done
    }
    
    #获取集群中每个节点的公钥信息
    function collect_pub_to_knowns(){
    echo "--------------------------"
    echo "配置knowns_hosts文件"
    > /root/.ssh/known_hosts
    for ip in "${!NODES_MAP[@]}" ; do
        ssh-keyscan  -t rsa ${NODES_MAP[$ip]} >> /root/.ssh/known_hosts
    done
    }
    
    function transferring_hosts_files {
    echo "--------------------------"
    echo "传输known_hosts和hosts文件"
    for ip in "${!NODES_MAP[@]}" ;do
         sshpass -p ${REMOTE_PASS}  scp /root/.ssh/known_hosts root@${NODES_MAP[$ip]}:/root/.ssh/
         echo "给${NODES_MAP[$ip]}节点传递known_hosts文件"
         sshpass -p ${REMOTE_PASS}  scp /etc/hosts root@${NODES_MAP[$ip]}:/etc/hosts
         echo "给${NODES_MAP[$ip]}节点传递hosts文件"
    done
    }
    
    
    
    function node_interconnection() {
        echo "--------------------------"
        echo "配置节点间的SSH互通"
    
        for LOGIN_HOST in "${!NODES_MAP[@]}"; do
            LOGIN_IP=${NODES_MAP[$LOGIN_HOST]}
            for REMOTE_HOST in "${!NODES_MAP[@]}"; do
                REMOTE_IP=${NODES_MAP[$REMOTE_HOST]}
                # 使用sshpass传递密码执行ssh-copy-id, 但请注意这并不安全
                # 推荐使用SSH密钥认证
                sshpass -p "$REMOTE_PASS" ssh "${SSH_OPTIONS[@]}" "${REMOTE_USER}@$LOGIN_IP" \
                    "sshpass -p "$REMOTE_PASS" ssh-copy-id -i ~/.ssh/id_rsa.pub ${REMOTE_USER}@$REMOTE_IP" || \
                    { echo "SSH互通设置失败: $LOGIN_IP 到 $REMOTE_IP"; continue; }
            done
        done
    }
    
    function set_hostname(){
    echo "--------------------------"
    echo "设置节点主机名"
    for ip in "${!NODES_MAP[@]}" ; do
        # 设置远程节点的主机名
        echo "将节点$ip 设置为主机名 ${NODES_MAP[$ip]} " ;
        sshpass -p "${REMOTE_PASS}" ssh root@"${NODES_MAP[$ip]}" "sudo hostnamectl set-hostname ${NODES_MAP[$ip]}" ;
    done
    
    }
    
    function transferring_harbor_certs_files(){
       echo "--------------------------"
       echo "传输harbor证书文件"
       for ip in "${!NODES_MAP[@]}" ; do
           sshpass -p "${REMOTE_PASS}" ssh "${REMOTE_USER}@${NODES_MAP[$ip]}"  "mkdir -p /etc/docker/certs.d/harbor.cbear.top"
           
    done
    
       
    }
    
    
    read_env
    install_sshpass
    remove_ssh_file
    keygen_rsa
    sleep 2
    set_hosts
    sleep 2
    set_hostname
    sleep 2
    collect_pub_to_knowns
    transferring_hosts_files
    node_interconnection
    echo "Cluster setup completed."

1.2 harbor配置

  1. 为harbor生成对应证书

    证书中参数-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=yourdomain.com"

    #生成CA私钥信息
    root@harbor:/usr/local/harbor/certs# openssl genrsa -out ca.key 4096
    #生成CA公钥信息
    root@harbor:/usr/local/harbor/certs# openssl req -x509 -new -nodes -sha512 -days 3650 \
     -subj "/CN=harbor.cbear.top" \
     -key ca.key \
     -out ca.crt
    
    #生成服务器私钥信息
    root@harbor:/usr/local/harbor/certs# openssl genrsa -out harbor.cbear.top.key 4096
    
    #生成服务器证书请求
    root@harbor:/usr/local/harbor/certs# openssl req -sha512 -new \
        -subj "/CN=harbor.cbear.top" \
        -key harbor.cbear.top.key \
        -out harbor.cbear.top.csr
    
    #生成一个x509 v3扩展文件
    root@harbor:/usr/local/harbor/certs# cat > v3.ext <<-EOF
    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
    extendedKeyUsage = serverAuth
    subjectAltName = @alt_names
    
    [alt_names]
    DNS.1=harbor.cbear.top
    DNS.2=harbor
    EOF
    
    # 使用该v3.ext文件为您的Harbor主机生成证书
    root@harbor:/usr/local/harbor/certs# openssl x509 -req -sha512 -days 3650 \
        -extfile v3.ext \
        -CA ca.crt -CAkey ca.key -CAcreateserial \
        -in harbor.cbear.top.csr \
        -out harbor.cbear.top.crt
    
    #将服务器证书yourdomain.com.crt的编码格式转换为yourdomain.com.cert, 提供Docker使用
    root@harbor:/usr/local/harbor/certs# openssl x509 -inform PEM -in harbor.cbear.top.crt -out harbor.cbear.top.cert
    
  2. 安装harbor, 并为harbor配置证书

    root@harbor:/usr/local/harbor# cat  harbor.yml
    # Configuration file of Harbor
    
    # The IP address or hostname to access admin UI and registry service.
    # DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
    hostname: harbor.cbear.top
    
    # http related config
    http:
      # port for http, default is 80. If https enabled, this port will redirect to https port
      port: 80
    
    # https related config
    https:
      # https port for harbor, default is 443
      port: 443
      # The path of cert and key files for nginx
      certificate: /usr/local/harbor/certs/harbor.cbear.top.crt
      private_key: /usr/local/harbor/certs/harbor.cbear.top.key
    .....
    
    root@harbor:/usr/local/harbor# ./prepare 
    root@harbor:/usr/local/harbor# ./install.sh 
  3. 配置docker证书

    root@harbor:/etc/docker# mkdir -p /etc/docker/certs.d/harbor.cbear.top
    root@harbor:/etc/docker# cp /usr/local/harbor/certs/ca.crt /etc/docker/certs.d/harbor.cbear.top/
    root@harbor:/etc/docker# cp /usr/local/harbor/certs/harbor.cbear.top.cert /etc/docker/certs.d/harbor.cbear.top/
    root@harbor:/etc/docker# cp /usr/local/harbor/certs/harbor.cbear.top.key /etc/docker/certs.d/harbor.cbear.top/
    root@harbor:~# ll /etc/docker/certs.d/harbor.cbear.top/
    total 20
    drwxr-xr-x 2 root root 4096 May 20 11:32 ./
    drwxr-xr-x 3 root root 4096 May 20 11:24 ../
    -rw-r--r-- 1 root root 1826 May 20 11:23 ca.crt
    -rw-r--r-- 1 root root 1915 May 20 11:23 harbor.cbear.top.cert
    -rw------- 1 root root 3268 May 20 11:23 harbor.cbear.top.key
    image-20240520193842342

1.3 服务器安装 containerd 和 nerdctl

  1. 临时配置ansible的hosts文件

    root@harbor:~# cat /etc/ansible/hosts 
    [k8s-master]
    k8s-master01.cbear.top
    k8s-master02.cbear.top
    k8s-master03.cbear.top
    [haproxy]
    ha1.cbear.top
    ha2.cbear.top
    [harbor]
    harbor.cbear.top
    [k8s-node]
    k8s-node01.cbear.top
    k8s-node02.cbear.top
    k8s-node03.cbear.top
    [k8s-etcd]
    k8s-etcd01.cbear.top
    k8s-etcd02.cbear.top
    k8s-etcd03.cbear.top

  2. 准备二进制包和安装脚本

    wget https://github.com/containerd/containerd/releases/download/v1.7.17/cri-containerd-cni-1.7.17-linux-amd64.tar.gz
    wget https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-1.7.6-linux-amd64.tar.gz
    #!/bin/bash
    #程序包名称
    CONTAINERD_VERSION=1.7.17
    NETDCTL_VERSION=1.7.6
    containerd_package_name=cri-containerd-cni-${CONTAINERD_VERSION}-linux-amd64.tar.gz
    netdctl_package_name=nerdctl-${NETDCTL_VERSION}-linux-amd64.tar.gz
    #程序包解压目录
    package_dir=/usr/local/containerd
    echo 正在创建程序包目录: ${package_dir}
    #创建程序包解压目录
    mkdir -p ${package_dir}
    
    echo 正在解压${containerd_package_name}到${package_dir}
    #解压程序包
    tar xf ${containerd_package_name} -C ${package_dir}
    
    echo 正在安装 cri、containerd、cni、runc
    #拷贝文件到指定目录
    cp -r ${package_dir}/usr/local/bin /usr/local/
    cp -r ${package_dir}/usr/local/sbin /usr/local/
    cp -r ${package_dir}/opt/* /opt
    cp -r ${package_dir}/etc/cni /etc/
    cp -r ${package_dir}/etc/crictl.yaml /etc/
    cp -r ${package_dir}/etc/systemd/system/containerd.service  /lib/systemd/system/
    
    echo 正在初始化 containerd 配置
    #创建 containerd 配置文件目录
    mkdir -p /etc/containerd
    #生成 containerd 默认配置文件
    #可以用这个命令生成默认配置文件
    #containerd config default > /etc/containerd/config.toml
    #以下配置文件中, 主要修改了容器仓库的位置。
    cat > /etc/containerd/config.toml << EOF
    disabled_plugins = []
    imports = []
    oom_score = 0
    plugin_dir = ""
    required_plugins = []
    root = "/var/lib/containerd" 
    state = "/run/containerd"
    temp = ""
    version = 2
    
    [cgroup]
      path = ""
    
    [debug]
      address = ""
      format = ""
      gid = 0
      level = ""
      uid = 0
    
    [grpc]
      address = "/run/containerd/containerd.sock"
      gid = 0
      max_recv_message_size = 16777216
      max_send_message_size = 16777216
      tcp_address = ""
      tcp_tls_ca = ""
      tcp_tls_cert = ""
      tcp_tls_key = ""
      uid = 0
    
    [metrics]
      address = ""
      grpc_histogram = false
    
    [plugins]
    
      [plugins."io.containerd.gc.v1.scheduler"]
        deletion_threshold = 0
        mutation_threshold = 100
        pause_threshold = 0.02
        schedule_delay = "0s"
        startup_delay = "100ms"
    
      [plugins."io.containerd.grpc.v1.cri"]
        device_ownership_from_security_context = false
        disable_apparmor = false
        disable_cgroup = false
        disable_hugetlb_controller = true
        disable_proc_mount = false
        disable_tcp_service = true
        enable_selinux = false
        enable_tls_streaming = false
        enable_unprivileged_icmp = false
        enable_unprivileged_ports = false
        ignore_image_defined_volumes = false
        max_concurrent_downloads = 3
        max_container_log_line_size = 16384
        netns_mounts_under_state_dir = false
        restrict_oom_score_adj = false
        sandbox_image = "harbor.cbear.top/easzlab/pause:3.9"
        selinux_category_range = 1024
        stats_collect_period = 10
        stream_idle_timeout = "4h0m0s"
        stream_server_address = "127.0.0.1"
        stream_server_port = "0"
        systemd_cgroup = false
        tolerate_missing_hugetlb_controller = true
        unset_seccomp_profile = ""
    
        [plugins."io.containerd.grpc.v1.cri".cni]
          bin_dir = "/opt/cni/bin"
          conf_dir = "/etc/cni/net.d"
          conf_template = "/etc/cni/net.d/10-default.conf"
          max_conf_num = 1
    
        [plugins."io.containerd.grpc.v1.cri".containerd]
          default_runtime_name = "runc"
          disable_snapshot_annotations = true
          discard_unpacked_layers = false
          ignore_rdt_not_enabled_errors = false
          no_pivot = false
          snapshotter = "overlayfs"
    
          [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]
            base_runtime_spec = ""
            container_annotations = []
            pod_annotations = []
            privileged_without_host_devices = false
            runtime_engine = ""
            runtime_root = ""
            runtime_type = ""
    
            [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options]
    
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
    
            [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
              base_runtime_spec = ""
              container_annotations = []
              pod_annotations = []
              privileged_without_host_devices = false
              runtime_engine = ""
              runtime_root = ""
              runtime_type = "io.containerd.runc.v2"
    
              [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
                BinaryName = ""
                CriuImagePath = ""
                CriuPath = ""
                CriuWorkPath = ""
                IoGid = 0
                IoUid = 0
                NoNewKeyring = false
                NoPivotRoot = false
                Root = ""
                ShimCgroup = ""
                SystemdCgroup = true
    
          [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime]
            base_runtime_spec = ""
            container_annotations = []
            pod_annotations = []
            privileged_without_host_devices = false
            runtime_engine = ""
            runtime_root = ""
            runtime_type = ""
    
            [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime.options]
    
        [plugins."io.containerd.grpc.v1.cri".image_decryption]
          key_model = "node"
    
        [plugins."io.containerd.grpc.v1.cri".registry]
    
          [plugins."io.containerd.grpc.v1.cri".registry.auths]
    
          [plugins."io.containerd.grpc.v1.cri".registry.configs]
            [plugins."io.containerd.grpc.v1.cri".registry.configs."harbor.cbear.top".tls]
              ca_file = "/etc/containerd/certs.d/harbor.cbear.top/ca.crt"
              cert_file = "/etc/containerd/certs.d/harbor.cbear.top/harbor.cbear.top.cert"
              key_file = "/etc/containerd/certs.d/harbor.cbear.top/harbor.cbear.top.key"
              insecure_skip_verify = false
    
          [plugins."io.containerd.grpc.v1.cri".registry.headers]
    
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.cbear.top"]
              endpoint = ["https://harbor.cbear.top"]
    
    
        [plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming]
          tls_cert_file = ""
          tls_key_file = ""
    
      [plugins."io.containerd.internal.v1.opt"]
        path = "/opt/containerd"
    
      [plugins."io.containerd.internal.v1.restart"]
        interval = "10s"
    
      [plugins."io.containerd.metadata.v1.bolt"]
        content_sharing_policy = "shared"
    
      [plugins."io.containerd.monitor.v1.cgroups"]
        no_prometheus = false
    
      [plugins."io.containerd.runtime.v1.linux"]
        no_shim = false
        runtime = "runc"
        runtime_root = ""
        shim = "containerd-shim"
        shim_debug = false
    
      [plugins."io.containerd.service.v1.diff-service"]
        default = ["walking"]
    
      [plugins."io.containerd.snapshotter.v1.aufs"]
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.btrfs"]
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.devmapper"]
        async_remove = false
        base_image_size = ""
        pool_name = ""
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.native"]
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.overlayfs"]
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.zfs"]
        root_path = ""
    
    [proxy_plugins]
    
    [stream_processors]
    
      [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
        accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
        args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
        env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
        path = "ctd-decoder"
        returns = "application/vnd.oci.image.layer.v1.tar"
    
      [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
        accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
        args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
        env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
        path = "ctd-decoder"
        returns = "application/vnd.oci.image.layer.v1.tar+gzip"
    
    [timeouts]
      "io.containerd.timeout.shim.cleanup" = "5s"
      "io.containerd.timeout.shim.load" = "5s"
      "io.containerd.timeout.shim.shutdown" = "3s"
      "io.containerd.timeout.task.state" = "2s"
    
    [ttrpc]
      address = ""
      gid = 0
      uid = 0
    EOF
    
    
    echo 正在启动 containerd
    #启动 containerd 并设置服务开机启动
    systemctl daemon-reload
    systemctl restart containerd.service
    systemctl enable containerd.service
    
    echo 正在安装 nerdctl
    package_dir=/etc/local/netdctl
    
    echo 正在创建程序包目录: ${package_dir}
    #创建程序包解压目录
    mkdir -p ${package_dir}
    
    echo 正在解压 ${netdctl_package_name} 到 ${package_dir}
    #解压程序包
    tar xf ${netdctl_package_name} -C ${package_dir}
    
    echo 正在安装 nerdctl
    #拷贝文件到指定目录
    cp -r ${package_dir}/nerdctl /usr/local/bin/
    
    echo 正在初始化 nerdctl 配置
    mkdir -p /etc/nerdctl
    
    cat > /etc/nerdctl/nerdctl.toml <<EOF
    namespace = "k8s.io"
    debug = false
    debug_full = false
    insecure_registry = true
    EOF
    
    echo 安装完成
  3. 配置ansible的yaml

    root@harbor:~# cat install-containerd.yaml 
    - hosts: k8s-master,k8s-etcd,k8s-node
      remote_user: root
      tasks:
        - name: "拷贝 nerdctl-1.3.1-linux-amd64.tar.gz 文件"
          copy:
            src: /root/nerdctl-1.7.6-linux-amd64.tar.gz
            dest: /tmp
            owner: root
            group: root
            mode: 0644
        - name: "拷贝 cri-containerd-cni-1.6.20-linux-amd64.tar.gz 文件"
          copy:
            src: /root//cri-containerd-cni-1.7.17-linux-amd64.tar.gz
            dest: /tmp/
            owner: root
            group: root
            mode: 0644
        - name: "拷贝 install.sh 文件"
          copy:
            src: /root/install.sh
            dest: /tmp/
            owner: root
            group: root
            mode: 0744
        - name: "执行安装脚本"
          shell: cd /tmp/ && bash install.sh
  4. 运行ansible脚本

    root@harbor:~# ansible-playbook install-containerd.yaml
  5. 检查containerd和nerdctl版本信息

    root@harbor:~# ansible k8s-master,k8s-etcd,k8s-node -m shell -a "containerd -v && nerdctl version"
  6. 在master和work节点中为containerd配置证书

    - hosts: k8s-master,k8s-etcd,k8s-node
      remote_user: root
      tasks:
        - name: "创建containerd证书目录:/etc/containerd/harbor.cbear.top"
          file:
            path: /etc/containerd/harbor.cbear.top
            state: directory
            owner: root
            group: root
            mode: 0644
        - name: "拷贝ca.crt 证书文件"
          copy:
            src: /usr/local/harbor/certs/ca.crt
            dest: /etc/containerd/harbor.cbear.top
            owner: root
            group: root
            mode: 0644
        - name: "拷贝 cri-containerd-cni-1.6.20-linux-amd64.tar.gz 文件"
          copy:
            src: /root//cri-containerd-cni-1.7.17-linux-amd64.tar.gz
            dest: /tmp/
            owner: root
            group: root
            mode: 0644
        - name: "拷贝 install.sh 文件"
          copy:
            src: /root/install.sh
            dest: /tmp/
            owner: root
            group: root
            mode: 0744
        - name: "执行安装脚本"
          shell: cd /tmp/ && bash install.sh
  7. 以下配置文件为kubeasz自动生成的配置文件。这个文件可以作为参考

    disabled_plugins = []
    imports = []
    oom_score = 0
    plugin_dir = ""
    required_plugins = []
    root = "/var/lib/containerd" 
    state = "/run/containerd"
    temp = ""
    version = 2
    
    [cgroup]
      path = ""
    
    [debug]
      address = ""
      format = ""
      gid = 0
      level = ""
      uid = 0
    
    [grpc]
      address = "/run/containerd/containerd.sock"
      gid = 0
      max_recv_message_size = 16777216
      max_send_message_size = 16777216
      tcp_address = ""
      tcp_tls_ca = ""
      tcp_tls_cert = ""
      tcp_tls_key = ""
      uid = 0
    
    [metrics]
      address = ""
      grpc_histogram = false
    
    [plugins]
    
      [plugins."io.containerd.gc.v1.scheduler"]
        deletion_threshold = 0
        mutation_threshold = 100
        pause_threshold = 0.02
        schedule_delay = "0s"
        startup_delay = "100ms"
    
      [plugins."io.containerd.grpc.v1.cri"]
        device_ownership_from_security_context = false
        disable_apparmor = false
        disable_cgroup = false
        disable_hugetlb_controller = true
        disable_proc_mount = false
        disable_tcp_service = true
        enable_selinux = false
        enable_tls_streaming = false
        enable_unprivileged_icmp = false
        enable_unprivileged_ports = false
        ignore_image_defined_volumes = false
        max_concurrent_downloads = 3
        max_container_log_line_size = 16384
        netns_mounts_under_state_dir = false
        restrict_oom_score_adj = false
        sandbox_image = "harbor.cbear.top/easzlab/pause:3.9"
        selinux_category_range = 1024
        stats_collect_period = 10
        stream_idle_timeout = "4h0m0s"
        stream_server_address = "127.0.0.1"
        stream_server_port = "0"
        systemd_cgroup = false
        tolerate_missing_hugetlb_controller = true
        unset_seccomp_profile = ""
    
        [plugins."io.containerd.grpc.v1.cri".cni]
          bin_dir = "/opt/cni/bin"
          conf_dir = "/etc/cni/net.d"
          conf_template = "/etc/cni/net.d/10-default.conf"
          max_conf_num = 1
    
        [plugins."io.containerd.grpc.v1.cri".containerd]
          default_runtime_name = "runc"
          disable_snapshot_annotations = true
          discard_unpacked_layers = false
          ignore_rdt_not_enabled_errors = false
          no_pivot = false
          snapshotter = "overlayfs"
    
          [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]
            base_runtime_spec = ""
            container_annotations = []
            pod_annotations = []
            privileged_without_host_devices = false
            runtime_engine = ""
            runtime_root = ""
            runtime_type = ""
    
            [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options]
    
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
    
            [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
              base_runtime_spec = ""
              container_annotations = []
              pod_annotations = []
              privileged_without_host_devices = false
              runtime_engine = ""
              runtime_root = ""
              runtime_type = "io.containerd.runc.v2"
    
              [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
                BinaryName = ""
                CriuImagePath = ""
                CriuPath = ""
                CriuWorkPath = ""
                IoGid = 0
                IoUid = 0
                NoNewKeyring = false
                NoPivotRoot = false
                Root = ""
                ShimCgroup = ""
                SystemdCgroup = true
    
          [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime]
            base_runtime_spec = ""
            container_annotations = []
            pod_annotations = []
            privileged_without_host_devices = false
            runtime_engine = ""
            runtime_root = ""
            runtime_type = ""
    
            [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime.options]
    
        [plugins."io.containerd.grpc.v1.cri".image_decryption]
          key_model = "node"
    
        [plugins."io.containerd.grpc.v1.cri".registry]
    
          [plugins."io.containerd.grpc.v1.cri".registry.auths]
    
          [plugins."io.containerd.grpc.v1.cri".registry.configs]
            [plugins."io.containerd.grpc.v1.cri".registry.configs."easzlab.io.local:5000".tls]
              insecure_skip_verify = true
            [plugins."io.containerd.grpc.v1.cri".registry.configs."harbor.cbear.top".tls]
              insecure_skip_verify = true
    
          [plugins."io.containerd.grpc.v1.cri".registry.headers]
    
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."easzlab.io.local:5000"]
              endpoint = ["http://easzlab.io.local:5000"]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.cbear.top"]
              endpoint = ["https://harbor.cbear.top"]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
              endpoint = ["https://docker.nju.edu.cn/", "https://kuamavit.mirror.aliyuncs.com"]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
              endpoint = ["https://gcr.nju.edu.cn"]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
              endpoint = ["https://gcr.nju.edu.cn/google-containers/"]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
              endpoint = ["https://quay.nju.edu.cn"]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]
              endpoint = ["https://ghcr.nju.edu.cn"]
            [plugins."io.containerd.grpc.v1.cri".registry.mirrors."nvcr.io"]
              endpoint = ["https://ngc.nju.edu.cn"]
    
        [plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming]
          tls_cert_file = ""
          tls_key_file = ""
    
      [plugins."io.containerd.internal.v1.opt"]
        path = "/opt/containerd"
    
      [plugins."io.containerd.internal.v1.restart"]
        interval = "10s"
    
      [plugins."io.containerd.metadata.v1.bolt"]
        content_sharing_policy = "shared"
    
      [plugins."io.containerd.monitor.v1.cgroups"]
        no_prometheus = false
    
      [plugins."io.containerd.runtime.v1.linux"]
        no_shim = false
        runtime = "runc"
        runtime_root = ""
        shim = "containerd-shim"
        shim_debug = false
    
      [plugins."io.containerd.service.v1.diff-service"]
        default = ["walking"]
    
      [plugins."io.containerd.snapshotter.v1.aufs"]
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.btrfs"]
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.devmapper"]
        async_remove = false
        base_image_size = ""
        pool_name = ""
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.native"]
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.overlayfs"]
        root_path = ""
    
      [plugins."io.containerd.snapshotter.v1.zfs"]
        root_path = ""
    
    [proxy_plugins]
    
    [stream_processors]
    
      [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
        accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
        args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
        env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
        path = "ctd-decoder"
        returns = "application/vnd.oci.image.layer.v1.tar"
    
      [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
        accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
        args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
        env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
        path = "ctd-decoder"
        returns = "application/vnd.oci.image.layer.v1.tar+gzip"
    
    [timeouts]
      "io.containerd.timeout.shim.cleanup" = "5s"
      "io.containerd.timeout.shim.load" = "5s"
      "io.containerd.timeout.shim.shutdown" = "3s"
      "io.containerd.timeout.task.state" = "2s"
    
    [ttrpc]
      address = ""
      gid = 0
      uid = 0

1.4 镜像构建软件准备

社区中目前有三款工具可以支持无 docker daemon 化的构建:kaniko,img 和 buildkit。

  • Kaniko 是由 Google 开发的在 k8s 上做 docker 构建的命令行工具,使用非常简洁,只需要 build 一个二进制工具即可,支持 dockerfile 构建、push、credentail 文件读取。

  • Buildkit 是 docker 公司开发,目前由社区和 docker 公司合理维护的“含着金钥匙出生”的新一代构建工具,拥有良好的扩展性、极大地提高了构建速度,以及更好的安全性,功能上配合 docker 使用还是没问题的,独立使用功能其实有残缺,这个放到后面来讲。

  • img 是社区贡献者开发,基于 buildkit 封装的类 docker 化命令行工具,无需 daemon 进程,无需 privilege,可以独立运行的二进制工具,非常小巧易用,而且有着和 buildkit 一样的性能优势。

1503305-20230529003335494-1506673074
  1. 下载buildkitd二进制包

    wget https://github.com/moby/buildkit/releases/download/v0.13.2/buildkit-v0.13.2.linux-amd64.tar.gz
  2. 解压对应软件包

    root@k8s-master01:~# mkdir /usr/local/src/buildkit
    root@k8s-master01:~# tar -xf buildkit-v0.13.2.linux-amd64.tar.gz -C /usr/local/src/buildkit
  3. 创建对应二进制软链接文件

    root@k8s-master01:~# ln -sv /usr/local/src/buildkit/bin/* /usr/local/bin/
    '/usr/local/bin/buildctl' -> '/usr/local/src/buildkit/bin/buildctl'
    '/usr/local/bin/buildkit-cni-bridge' -> '/usr/local/src/buildkit/bin/buildkit-cni-bridge'
    '/usr/local/bin/buildkit-cni-firewall' -> '/usr/local/src/buildkit/bin/buildkit-cni-firewall'
    '/usr/local/bin/buildkit-cni-host-local' -> '/usr/local/src/buildkit/bin/buildkit-cni-host-local'
    '/usr/local/bin/buildkit-cni-loopback' -> '/usr/local/src/buildkit/bin/buildkit-cni-loopback'
    '/usr/local/bin/buildkitd' -> '/usr/local/src/buildkit/bin/buildkitd'
    '/usr/local/bin/buildkit-qemu-aarch64' -> '/usr/local/src/buildkit/bin/buildkit-qemu-aarch64'
    '/usr/local/bin/buildkit-qemu-arm' -> '/usr/local/src/buildkit/bin/buildkit-qemu-arm'
    '/usr/local/bin/buildkit-qemu-i386' -> '/usr/local/src/buildkit/bin/buildkit-qemu-i386'
    '/usr/local/bin/buildkit-qemu-mips64' -> '/usr/local/src/buildkit/bin/buildkit-qemu-mips64'
    '/usr/local/bin/buildkit-qemu-mips64el' -> '/usr/local/src/buildkit/bin/buildkit-qemu-mips64el'
    '/usr/local/bin/buildkit-qemu-ppc64le' -> '/usr/local/src/buildkit/bin/buildkit-qemu-ppc64le'
    '/usr/local/bin/buildkit-qemu-riscv64' -> '/usr/local/src/buildkit/bin/buildkit-qemu-riscv64'
    '/usr/local/bin/buildkit-qemu-s390x' -> '/usr/local/src/buildkit/bin/buildkit-qemu-s390x'
    '/usr/local/bin/buildkit-runc' -> '/usr/local/src/buildkit/bin/buildkit-runc'
  4. 准备systemd服务文件。对应文件可以在github文件中下载:https://github.com/moby/buildkit/tree/master/examples/systemd/system

    image-20240531234101765

    root@k8s-master01:~# cat /lib/systemd/system/buildkit.service
    [Unit]
    Description=BuildKit
    Requires=buildkit.socket
    After=buildkit.socket
    Documentation=https://github.com/moby/buildkit
    [Service]
    ExecStart=/usr/local/bin/buildkitd --oci-worker=false --containerd-worker=true
    [Install]
    WantedBy=multi-user.target
    
    root@k8s-master01:~# cat  /lib/systemd/system/buildkit.socket
    [Unit]
    Description=BuildKit
    Documentation=https://github.com/moby/buildkit
    [Socket]
    ListenStream=%t/buildkit/buildkitd.sock
    [Install]
    WantedBy=sockets.target

2. 使用kubeasz部署kubernetes

2.1 部署环境准备

  1. 准备脚本, 二进制和镜像文件

    export release=3.6.3
    wget https://github.com/easzlab/kubeasz/releases/download/${release}/ezdown
    chmod +x ./ezdown
  2. 修改ezdown shell脚本中的默认本地仓库。这里这个脚本默认下载镜像的过程中, 会在本地启动一个镜像仓库https://easzlab.io.local:5000。这个需要将这个默认仓库修改为手动创建仓库harbor.cbear.top

    cd /etc/kubeasz
    sed -i "s/easzlab.io.local:5000/harbor.cbear.top/g" /etc/kubeasz/ezdown 
    sed -i "s/easzlab.io.local/harbor.cbear.top/g" /etc/kubeasz/ezdown
  3. 下载镜像, 这里会将下载的镜像传递到指定的镜像库中。这里需要在harbor创建calico、coredns、easzlab、kubenetesui这几个仓库

    ./ezdown -D
  4. 下载离线系统包

    root@harbor:/etc/kubeasz# cat /etc/lsb-release 
    DISTRIB_ID=Ubuntu
    DISTRIB_RELEASE=22.04
    DISTRIB_CODENAME=jammy
    DISTRIB_DESCRIPTION="Ubuntu 22.04.4 LTS"
    
    
    root@harbor:/etc/kubeasz# ./ezdown -P ubuntu_22
    2024-05-20 12:12:18 INFO Action begin: get_sys_pkg ubuntu_22
    2024-05-20 12:12:18 INFO downloading system packages kubeasz-sys-pkg:1.0.0_ubuntu_22
    1.0.0_ubuntu_22: Pulling from easzlab/kubeasz-sys-pkg
    91d30c5bc195: Pull complete 
    651615f46b5f: Pull complete 
    Digest: sha256:4e715196e5e84e679955eb0f38129d2c976e6698f990219b4a9804bc56c822ed
    Status: Downloaded newer image for easzlab/kubeasz-sys-pkg:1.0.0_ubuntu_22
    docker.io/easzlab/kubeasz-sys-pkg:1.0.0_ubuntu_22
    2024-05-20 12:12:26 DEBUG run a temporary container
    07baf343cbaa1b1ad87f9e3d1a97e0d464d0b2ec075d73af7c9a46f3307cf66d
    2024-05-20 12:12:27 DEBUG cp system packages
    Successfully copied 9.72MB to /etc/kubeasz/down
    2024-05-20 12:12:27 DEBUG stop&remove temporary container
    temp_sys_pkg
    2024-05-20 12:12:28 INFO Action successed: get_sys_pkg ubuntu_22
  5. 单独为flannel功能下载镜像。需要再harbor中创建flannel仓库。下载额外容器镜像(cilium,flannel,prometheus等)

    root@harbor:/etc/kubeasz# ./ezdown -X flannel

上述脚本运行成功后, 所有文件(kubeasz代码、二进制、离线镜像)均已整理好放入目录/etc/kubeasz, /etc/kubeasz包 kubeasz版本为 ${release} 的发布代码, /etc/kubeasz/bin 包含 k8s/etcd/docker/cni 等二进制文件, /etc/kubeasz/down 包含集群安装时需要的离线容器镜像, /etc/kubeasz/down/packages 包含集群安装时需要的系统基础软件

2.2 创建集群配置实例

  1. 使用ezctl命令生成集群配置

    root@harbor:/etc/kubeasz# ./ezctl new k8s-cluster
    2024-05-20 07:38:25 DEBUG generate custom cluster files in /etc/kubeasz/clusters/k8s-cluster
    2024-05-20 07:38:25 DEBUG set versions
    2024-05-20 07:38:25 DEBUG disable registry mirrors
    2024-05-20 07:38:25 DEBUG cluster k8s-cluster: files successfully created.
    2024-05-20 07:38:25 INFO next steps 1: to config '/etc/kubeasz/clusters/k8s-cluster/hosts'
    2024-05-20 07:38:25 INFO next steps 2: to config '/etc/kubeasz/clusters/k8s-cluster/config.yml'

    说明: 然后根据提示配置/etc/kubeasz/clusters/k8s-cluster/hosts和 /etc/kubeasz/clusters/k8s-cluster/config.yml; 根据前面节点规划修改hosts文件和其他集群层面的主要配置选项; 其他集群组件等配置项可以在config.yml文件中修改。

  2. 配置hosts文件

    hosts和config.yml文件需要根据自己部署需求和实际环境情况进行修改。

    root@harbor:/etc/kubeasz/clusters/k8s-cluster# cat hosts 
    # 'etcd' cluster should have odd member(s) (1,3,5,...)
    [etcd]
    192.168.71.42
    192.168.71.43
    192.168.71.44
    
    # master node(s), set unique 'k8s_nodename' for each node
    # CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
    # and must start and end with an alphanumeric character
    [kube_master]
    192.168.71.29 k8s_nodename='k8s-master01.cbear.top'
    192.168.71.30 k8s_nodename='k8s-master02.cbear.top'
    
    # work node(s), set unique 'k8s_nodename' for each node
    # CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
    # and must start and end with an alphanumeric character
    [kube_node]
    192.168.71.35 k8s_nodename='k8s-node01.cbear.top'
    192.168.71.36 k8s_nodename='k8s-node02.cbear.top'
    
    # [optional] harbor server, a private docker registry
    # 'NEW_INSTALL': 'true' to install a harbor server; 'false' to integrate with existed one
    [harbor]
    #192.168.1.8 NEW_INSTALL=false
    
    # [optional] loadbalance for accessing k8s from outside
    [ex_lb]
    192.168.71.32 LB_ROLE=backup EX_APISERVER_VIP=192.168.71.150 EX_APISERVER_PORT=8443
    192.168.71.33 LB_ROLE=master EX_APISERVER_VIP=192.168.71.150 EX_APISERVER_PORT=8443
    
    # [optional] ntp server for the cluster
    [chrony]
    #192.168.1.1
    
    [all:vars]
    # --------- Main Variables ---------------
    # Secure port for apiservers
    SECURE_PORT="6443"
    
    # Cluster container-runtime supported: docker, containerd
    # if k8s version >= 1.24, docker is not supported
    CONTAINER_RUNTIME="containerd"
    
    # Network plugins supported: calico, flannel, kube-router, cilium, kube-ovn
    CLUSTER_NETWORK="flannel"
    
    # Service proxy mode of kube-proxy: 'iptables' or 'ipvs'
    PROXY_MODE="ipvs"
    
    # K8S Service CIDR, not overlap with node(host) networking
    SERVICE_CIDR="10.68.0.0/16"
    
    # Cluster CIDR (Pod CIDR), not overlap with node(host) networking
    CLUSTER_CIDR="172.20.0.0/16"
    
    # NodePort Range
    NODE_PORT_RANGE="30000-32767"
    
    # Cluster DNS Domain
    CLUSTER_DNS_DOMAIN="cbear.local"
    
    # -------- Additional Variables (don't change the default value right now) ---
    # Binaries Directory
    bin_dir="/opt/kube/bin"
    
    # Deploy Directory (kubeasz workspace)
    base_dir="/etc/kubeasz"
    
    # Directory for a specific cluster
    cluster_dir="{{ base_dir }}/clusters/k8s-cluster"
    
    # CA and other components cert/key Directory
    ca_dir="/etc/kubernetes/ssl"
    
    # Default 'k8s_nodename' is empty
    k8s_nodename=''
    
    # Default python interpreter
    ansible_python_interpreter=/usr/bin/python3
  3. 配置config.yml

    root@harbor:/etc/kubeasz/clusters/k8s-cluster# cat config.yml 
    ############################
    # prepare
    ############################
    # 可选离线安装系统软件包 (offline|online)
    INSTALL_SOURCE: "offline"
    
    # 可选进行系统安全加固 github.com/dev-sec/ansible-collection-hardening
    # (deprecated) 未更新上游项目, 未验证最新k8s集群安装, 不建议启用
    OS_HARDEN: false
    
    
    ############################
    # role:deploy
    ############################
    # default: ca will expire in 100 years
    # default: certs issued by the ca will expire in 50 years
    CA_EXPIRY: "876000h"
    CERT_EXPIRY: "438000h"
    
    # force to recreate CA and other certs, not suggested to set 'true'
    CHANGE_CA: false
    
    # kubeconfig 配置参数
    CLUSTER_NAME: "cluster1"
    CONTEXT_NAME: "context-{{ CLUSTER_NAME }}"
    
    # k8s version
    K8S_VER: "1.29.0"
    
    # set unique 'k8s_nodename' for each node, if not set(default:'') ip add will be used
    # CAUTION: 'k8s_nodename' must consist of lower case alphanumeric characters, '-' or '.',
    # and must start and end with an alphanumeric character (e.g. 'example.com'),
    # regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*'
    K8S_NODENAME: "{%- if k8s_nodename != '' -%} \
                        {{ k8s_nodename|replace('_', '-')|lower }} \
                   {%- else -%} \
                        {{ inventory_hostname }} \
                   {%- endif -%}"
    
    ############################
    # role:etcd
    ############################
    # 设置不同的wal目录, 可以避免磁盘io竞争, 提高性能
    ETCD_DATA_DIR: "/var/lib/etcd"
    ETCD_WAL_DIR: ""
    
    
    ############################
    # role:runtime [containerd,docker]
    ############################
    # [.]启用拉取加速镜像仓库
    ENABLE_MIRROR_REGISTRY: true
    
    # [.]添加信任的私有仓库
    INSECURE_REG:
      - "http://easzlab.io.local:5000"
      - "https://harbor.cbear.top"
    
    # [.]基础容器镜像
    SANDBOX_IMAGE: "harbor.cbear.top/easzlab/pause:3.9"
    
    # [containerd]容器持久化存储目录
    CONTAINERD_STORAGE_DIR: "/var/lib/containerd"
    
    # [docker]容器存储目录
    DOCKER_STORAGE_DIR: "/var/lib/docker"
    
    # [docker]开启Restful API
    DOCKER_ENABLE_REMOTE_API: false
    
    
    ############################
    # role:kube-master
    ############################
    # k8s 集群 master 节点证书配置, 可以添加多个ip和域名( 比如增加公网ip和域名) 
    MASTER_CERT_HOSTS:
      - "192.168.71.150"
      - "k8s.easzlab.io"
      #- "www.test.com"
    
    # node 节点上 pod 网段掩码长度( 决定每个节点最多能分配的pod ip地址) 
    # 如果flannel 使用 --kube-subnet-mgr 参数, 那么它将读取该设置为每个节点分配pod网段
    # https://github.com/coreos/flannel/issues/847
    NODE_CIDR_LEN: 24
    
    
    ############################
    # role:kube-node
    ############################
    # Kubelet 根目录
    KUBELET_ROOT_DIR: "/var/lib/kubelet"
    
    # node节点最大pod 数
    MAX_PODS: 110
    
    # 配置为kube组件( kubelet,kube-proxy,dockerd等) 预留的资源量
    # 数值设置详见templates/kubelet-config.yaml.j2
    KUBE_RESERVED_ENABLED: "no"
    
    # k8s 官方不建议草率开启 system-reserved, 除非你基于长期监控, 了解系统的资源占用状况; 
    # 并且随着系统运行时间, 需要适当增加资源预留, 数值设置详见templates/kubelet-config.yaml.j2
    # 系统预留设置基于 4c/8g 虚机, 最小化安装系统服务, 如果使用高性能物理机可以适当增加预留
    # 另外, 集群安装时候apiserver等资源占用会短时较大, 建议至少预留1g内存
    SYS_RESERVED_ENABLED: "no"
    
    
    ############################
    # role:network [flannel,calico,cilium,kube-ovn,kube-router]
    ############################
    # ------------------------------------------- flannel
    # [flannel]设置flannel 后端"host-gw","vxlan"等
    FLANNEL_BACKEND: "vxlan"
    DIRECT_ROUTING: false
    
    # [flannel] 
    flannel_ver: "v0.22.2"
    
    # ------------------------------------------- calico
    # [calico] IPIP隧道模式可选项有: [Always, CrossSubnet, Never],跨子网可以配置为Always与CrossSubnet(公有云建议使用always比较省事, 其他的话需要修改各自公有云的网络配置, 具体可以参考各个公有云说明)
    # 其次CrossSubnet为隧道+BGP路由混合模式可以提升网络性能, 同子网配置为Never即可.
    CALICO_IPV4POOL_IPIP: "Always"
    
    # [calico]设置 calico-node使用的host IP, bgp邻居通过该地址建立, 可手工指定也可以自动发现
    IP_AUTODETECTION_METHOD: "can-reach={{ groups['kube_master'][0] }}"
    
    # [calico]设置calico 网络 backend: bird, vxlan, none
    CALICO_NETWORKING_BACKEND: "bird"
    
    # [calico]设置calico 是否使用route reflectors
    # 如果集群规模超过50个节点, 建议启用该特性
    CALICO_RR_ENABLED: false
    
    # CALICO_RR_NODES 配置route reflectors的节点, 如果未设置默认使用集群master节点 
    # CALICO_RR_NODES: ["192.168.1.1", "192.168.1.2"]
    CALICO_RR_NODES: []
    
    # [calico]更新支持calico 版本: ["3.19", "3.23"]
    calico_ver: "v3.26.4"
    
    # [calico]calico 主版本
    calico_ver_main: "{{ calico_ver.split('.')[0] }}.{{ calico_ver.split('.')[1] }}"
    
    # ------------------------------------------- cilium
    # [cilium]镜像版本
    cilium_ver: "1.14.5"
    cilium_connectivity_check: true
    cilium_hubble_enabled: false
    cilium_hubble_ui_enabled: false
    
    # ------------------------------------------- kube-ovn
    # [kube-ovn]离线镜像tar包
    kube_ovn_ver: "v1.11.5"
    
    # ------------------------------------------- kube-router
    # [kube-router]公有云上存在限制, 一般需要始终开启 ipinip; 自有环境可以设置为 "subnet"
    OVERLAY_TYPE: "full"
    
    # [kube-router]NetworkPolicy 支持开关
    FIREWALL_ENABLE: true
    
    # [kube-router]kube-router 镜像版本
    kube_router_ver: "v1.5.4"
    
    
    ############################
    # role:cluster-addon
    ############################
    # coredns 自动安装
    dns_install: "yes"
    corednsVer: "1.11.1"
    ENABLE_LOCAL_DNS_CACHE: true
    dnsNodeCacheVer: "1.22.23"
    # 设置 local dns cache 地址
    LOCAL_DNS_CACHE: "169.254.20.10"
    
    # metric server 自动安装
    metricsserver_install: "yes"
    metricsVer: "v0.6.4"
    
    # dashboard 自动安装
    dashboard_install: "yes"
    dashboardVer: "v2.7.0"
    dashboardMetricsScraperVer: "v1.0.8"
    
    # prometheus 自动安装
    prom_install: "no"
    prom_namespace: "monitor"
    prom_chart_ver: "45.23.0"
    
    # kubeapps 自动安装, 如果选择安装, 默认同时安装local-storage( 提供storageClass: "local-path") 
    kubeapps_install: "no"
    kubeapps_install_namespace: "kubeapps"
    kubeapps_working_namespace: "default"
    kubeapps_storage_class: "local-path"
    kubeapps_chart_ver: "12.4.3"
    
    # local-storage (local-path-provisioner) 自动安装
    local_path_provisioner_install: "no"
    local_path_provisioner_ver: "v0.0.24"
    # 设置默认本地存储路径
    local_path_provisioner_dir: "/opt/local-path-provisioner"
    
    # nfs-provisioner 自动安装
    nfs_provisioner_install: "no"
    nfs_provisioner_namespace: "kube-system"
    nfs_provisioner_ver: "v4.0.2"
    nfs_storage_class: "managed-nfs-storage"
    nfs_server: "192.168.1.10"
    nfs_path: "/data/nfs"
    
    # network-check 自动安装
    network_check_enabled: false 
    network_check_schedule: "*/5 * * * *"
    
    ############################
    # role:harbor
    ############################
    # harbor version, 完整版本号
    HARBOR_VER: "v2.8.4"
    HARBOR_DOMAIN: "harbor.easzlab.io.local"
    HARBOR_PATH: /var/data
    HARBOR_TLS_PORT: 8443
    HARBOR_REGISTRY: "{{ HARBOR_DOMAIN }}:{{ HARBOR_TLS_PORT }}"
    
    # if set 'false', you need to put certs named harbor.pem and harbor-key.pem in directory 'down'
    HARBOR_SELF_SIGNED_CERT: true
    
    # install extra component
    HARBOR_WITH_NOTARY: false
    HARBOR_WITH_TRIVY: false
    root@harbor:/etc/kubeasz/clusters/k8s-cluster# 

2.3 部署k8s环境

部署k8s环境过程中,主要是通过ezctl命令实现

root@harbor:/etc/kubeasz# ./ezctl upgrade
Usage: ezctl COMMAND [args]
-------------------------------------------------------------------------------------
Cluster setups:
    list		             to list all of the managed clusters
    checkout    <cluster>            to switch default kubeconfig of the cluster
    new         <cluster>            to start a new k8s deploy with name 'cluster'
    setup       <cluster>  <step>    to setup a cluster, also supporting a step-by-step way
    start       <cluster>            to start all of the k8s services stopped by 'ezctl stop'
    stop        <cluster>            to stop all of the k8s services temporarily
    upgrade     <cluster>            to upgrade the k8s cluster
    destroy     <cluster>            to destroy the k8s cluster
    backup      <cluster>            to backup the cluster state (etcd snapshot)
    restore     <cluster>            to restore the cluster state from backups
    start-aio		             to quickly setup an all-in-one cluster with default settings

Cluster ops:
    add-etcd    <cluster>  <ip>      to add a etcd-node to the etcd cluster
    add-master  <cluster>  <ip>      to add a master node to the k8s cluster
    add-node    <cluster>  <ip>      to add a work node to the k8s cluster
    del-etcd    <cluster>  <ip>      to delete a etcd-node from the etcd cluster
    del-master  <cluster>  <ip>      to delete a master node from the k8s cluster
    del-node    <cluster>  <ip>      to delete a work node from the k8s cluster

Extra operation:
    kca-renew   <cluster>            to force renew CA certs and all the other certs (with caution)
    kcfg-adm    <cluster>  <args>    to manage client kubeconfig of the k8s cluster

Use "ezctl help <command>" for more information about a given command.

安装主要通过ezctl setup 命令安装集群

root@harbor:/etc/kubeasz# ./ezctl setup --help
Usage: ezctl setup <cluster> <step>
available steps:
    01  prepare            to prepare CA/certs & kubeconfig & other system settings 
    02  etcd               to setup the etcd cluster
    03  container-runtime  to setup the container runtime(docker or containerd)
    04  kube-master        to setup the master nodes
    05  kube-node          to setup the worker nodes
    06  network            to setup the network plugin
    07  cluster-addon      to setup other useful plugins
    90  all                to run 01~07 all at once
    10  ex-lb              to install external loadbalance for accessing k8s from outside
    11  harbor             to install a new harbor server or to integrate with an existed one

examples: ./ezctl setup test-k8s 01  (or ./ezctl setup test-k8s prepare)
	  ./ezctl setup test-k8s 02  (or ./ezctl setup test-k8s etcd)
          ./ezctl setup test-k8s all
          ./ezctl setup test-k8s 04 -t restart_master

kubeasz 使用的相关 ansible-playbook 文件

root@harbor:/etc/kubeasz/playbooks# ls
01.prepare.yml      05.kube-node.yml      11.harbor.yml     31.deletcd.yml    91.start.yml    95.restore.yml
02.etcd.yml         06.network.yml        21.addetcd.yml    32.delnode.yml    92.stop.yml     96.update-certs.yml
03.runtime.yml      07.cluster-addon.yml  22.addnode.yml    33.delmaster.yml  93.upgrade.yml  99.clean.yml
04.kube-master.yml  10.ex-lb.yml          23.addmaster.yml  90.setup.yml      94.backup.yml
  1. 准备CA和基础环境初始化

    root@harbor:/etc/kubeasz# ./ezctl setup k8s-cluster 01
    ansible-playbook -i clusters/k8s-cluster/hosts -e @clusters/k8s-cluster/config.yml  playbooks/01.prepare.yml
    *** Component Version *********************
    *******************************************
    *   kubernetes: v1.29.0
    *   etcd: v3.5.10
    *   flannel: v0.22.2
    *******************************************
    2024-05-20 14:53:15 INFO cluster:k8s-cluster setup step:01 begins in 5s, press any key to abort:
    
    
    PLAY [kube_master,kube_node,etcd,ex_lb,chrony] ***********************************************************************************************
    
    TASK [Gathering Facts] ***********************************************************************************************************************
    ok: [192.168.71.29]
    ok: [192.168.71.30]
    ....
  2. 部署 etcd 集群

    root@harbor:/etc/kubeasz# ./ezctl setup k8s-cluster 02
    ansible-playbook -i clusters/k8s-cluster/hosts -e @clusters/k8s-cluster/config.yml  playbooks/02.etcd.yml
    *** Component Version *********************
    *******************************************
    *   kubernetes: v1.29.0
    *   etcd: v3.5.10
    *   flannel: v0.22.2
    *******************************************
    2024-05-20 15:21:02 INFO cluster:k8s-cluster setup step:02 begins in 5s, press any key to abort:
    ....

    验证etcd集群配置

    export NODE_IPS="192.168.1.1 192.168.1.2 192.168.1.3"
    for ip in ${NODE_IPS}; do
      ETCDCTL_API=3 etcdctl \
      --endpoints=https://${ip}:2379  \
      --cacert=/etc/kubernetes/ssl/ca.pem \
      --cert=/etc/kubernetes/ssl/etcd.pem \
      --key=/etc/kubernetes/ssl/etcd-key.pem \
      endpoint health; done
      
    root@k8s-etcd01:~# export NODE_IPS="192.168.71.42 192.168.71.43 192.168.71.44"
    root@k8s-etcd01:~# for ip in ${NODE_IPS}; do   ETCDCTL_API=3 etcdctl   --endpoints=https://${ip}:2379    --cacert=/etc/kubernetes/ssl/ca.pem   --cert=/etc/kubernetes/ssl/etcd.pem   --key=/etc/kubernetes/ssl/etcd-key.pem   endpoint health; done
    https://192.168.71.42:2379 is healthy: successfully committed proposal: took = 25.595102ms
    https://192.168.71.43:2379 is healthy: successfully committed proposal: took = 25.620095ms
    https://192.168.71.44:2379 is healthy: successfully committed proposal: took = 21.691977ms
  3. 部署master节点

    配置

    root@harbor:/etc/kubeasz# ./ezctl setup k8s-cluster 04
    ansible-playbook -i clusters/k8s-cluster/hosts -e @clusters/k8s-cluster/config.yml  playbooks/04.kube-master.yml
    *** Component Version *********************
    *******************************************
    *   kubernetes: v1.29.0
    *   etcd: v3.5.10
    *   flannel: v0.22.2
    *******************************************
    2024-05-20 15:54:30 INFO cluster:k8s-cluster setup step:04 begins in 5s, press any key to abort:
    
    ....

    检查master节点服务状态

    root@k8s-master01:~# systemctl status kube-apiserver
    root@k8s-master01:~#systemctl status kube-controller-manager
    root@k8s-master01:~#systemctl status kube-scheduler
    
    root@harbor:/etc/kubeasz# kubectl get cs
    Warning: v1 ComponentStatus is deprecated in v1.19+
    NAME                 STATUS    MESSAGE   ERROR
    scheduler            Healthy   ok        
    controller-manager   Healthy   ok        
    etcd-0               Healthy   ok    
  4. 部署kube-node节点

    root@harbor:/etc/kubeasz# ./ezctl setup k8s-cluster 05
    ansible-playbook -i clusters/k8s-cluster/hosts -e @clusters/k8s-cluster/config.yml  playbooks/05.kube-node.yml
    *** Component Version *********************
    *******************************************
    *   kubernetes: v1.29.0
    *   etcd: v3.5.10
    *   flannel: v0.22.2
    *******************************************
    2024-05-20 16:23:24 INFO cluster:k8s-cluster setup step:05 begins in 5s, press any key to abort:

    检查安装之后的效果

    root@harbor:/etc/kubeasz# kubectl get nodes
    NAME                     STATUS                     ROLES    AGE     VERSION
    k8s-master01.cbear.top   Ready,SchedulingDisabled   master   4m17s   v1.29.0
    k8s-master02.cbear.top   Ready,SchedulingDisabled   master   4m17s   v1.29.0
    k8s-node01.cbear.top     Ready                      node     63s     v1.29.0
    k8s-node02.cbear.top     Ready                      node     63s     v1.29.0
  5. 部署网络插件flannel

    这里需要注意, kubeasz默认使用的仓库为部署节点中的easzlab.io.local:5000。这里这个仓库是使用ezdown -D默认在本地配置的仓库。由于已经迁移到harbor.cbear.top中。这里需要修改安装配置文件中的yaml配置文件中的仓库位置。由easzlab.io.local:5000修改为harbor.cbear.top。需要注意, kubeasz安装后续插件的过程中均需要有类型修改仓库操作。

    root@harbor:~# sed -i.bak "s/easzlab.io.local:5000/harbor.cbear.top/g" /etc/kubeasz/roles/flannel/templates/kube-flannel.yaml.j2

    这一步就可以直接使用kubectl apply -f .yaml文件安装这个网络插件即可。另外可以使用以下命令实现同样操作。推荐使用以下命令

    root@harbor:/etc/kubeasz# ./ezctl setup k8s-cluster 06
    ansible-playbook -i clusters/k8s-cluster/hosts -e @clusters/k8s-cluster/config.yml  playbooks/06.network.yml
    *** Component Version *********************
    *******************************************
    *   kubernetes: v1.29.0
    *   etcd: v3.5.10
    *   flannel: v0.22.2
    *******************************************
    2024-05-21 08:01:11 INFO cluster:k8s-cluster setup step:06 begins in 5s, press any key to abort:

    使用以下命令测试网络插件已经安装完成

    root@harbor:/etc/kubeasz# kubectl get pods -A
    NAMESPACE     NAME                    READY   STATUS    RESTARTS   AGE
    kube-system   kube-flannel-ds-64xfx   1/1     Running   0          95s
    kube-system   kube-flannel-ds-dsbxg   1/1     Running   0          95s
    kube-system   kube-flannel-ds-nz7pl   1/1     Running   0          95s
    kube-system   kube-flannel-ds-xbpvz   1/1     Running   0          95s
  6. 至此基本已经都安装完成

    root@harbor:/etc/kubeasz# kubectl run net-test1 --image=alpine sleep 36000
    pod/net-test1 created
    root@harbor:/etc/kubeasz# kubectl get pods -A
    NAMESPACE     NAME                    READY   STATUS    RESTARTS   AGE
    default       net-test1               1/1     Running   0          11s
    kube-system   kube-flannel-ds-64xfx   1/1     Running   0          3m39s
    kube-system   kube-flannel-ds-dsbxg   1/1     Running   0          3m39s
    kube-system   kube-flannel-ds-nz7pl   1/1     Running   0          3m39s
    kube-system   kube-flannel-ds-xbpvz   1/1     Running   0          3m39s
    root@harbor:/etc/kubeasz# kubectl get pods
    NAME        READY   STATUS    RESTARTS   AGE
    net-test1   1/1     Running   0          17s
    root@harbor:/etc/kubeasz# kubectl exec -it net-test1 sh
    kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
    / # ping baidu.com
    ^C
    / # ping 8.8.8.8
    PING 8.8.8.8 (8.8.8.8): 56 data bytes
    64 bytes from 8.8.8.8: seq=0 ttl=48 time=64.044 ms
    64 bytes from 8.8.8.8: seq=1 ttl=48 time=63.291 ms
    64 bytes from 8.8.8.8: seq=2 ttl=48 time=62.878 ms
    64 bytes from 8.8.8.8: seq=3 ttl=48 time=62.761 ms
    64 bytes from 8.8.8.8: seq=4 ttl=48 time=62.797 ms
    64 bytes from 8.8.8.8: seq=5 ttl=48 time=62.698 ms
    ^C
    --- 8.8.8.8 ping statistics ---
    6 packets transmitted, 6 packets received, 0% packet loss
    round-trip min/avg/max = 62.698/63.078/64.044 ms
  7. 剩余的插件基本可以通过直接使用kubectl命令一个一个安装。另外可以使用./ezctl setup k8s-cluster 07直接按照配置文件中的要求一起安装。接下来的所有步骤。均是按照一个一个插件的安装来。

    可以查看kubeasz推荐安装步骤。这里可以看到kubeasz首先复制对应的yaml文件到指定位置之后。直接使用kubectl apply -f .yaml文件

    root@harbor:/etc/kubeasz/roles/cluster-addon/tasks# cat coredns.yml 
    - block:
        - name: 准备 DNS的部署文件
          template: src=dns/coredns.yaml.j2 dest={{ cluster_dir }}/yml/coredns.yaml
    
        - name: 删除coredns部署
          shell: "{{ base_dir }}/bin/kubectl delete -f {{ cluster_dir }}/yml/coredns.yaml || echo true; sleep 3"
          tags: force_change_certs
          when: 'CHANGE_CA|bool'
    
        - name: 创建coredns部署
          shell: "{{ base_dir }}/bin/kubectl apply -f {{ cluster_dir }}/yml/coredns.yaml"
          tags: force_change_certs
      when: 'dns_install == "yes"'

    剩余步骤大致按照kubeasz插件流程来处理。将对应coredns.yaml.j2文件复制到集群目录的yml文件中

    root@harbor:~# cp /etc/kubeasz/roles/cluster-addon/templates/dns/coredns.yaml.j2 /etc/kubeasz/clusters/k8s-cluster/yml/coredns.yaml 

    切换到指定集群的yaml目录中

    root@harbor:~#cp /etc/
    root@harbor:~# cd /etc/kubeasz/clusters/k8s-cluster/yml/
    root@harbor:/etc/kubeasz/clusters/k8s-cluster/yml# 

    修改指定yaml文件中的镜像仓库位置

    root@harbor:/etc/kubeasz/clusters/k8s-cluster/yml# sed -i.bak "s/easzlab.io.local:5000/harbor.cbear.top/g"  coredns.yaml 

    默认给的配置文件中的coredns.yaml文件中引用了一个CLUSTER_DNS_SVC_IP变量。默认这个变量的值为SERVICE_CIDR。这里为10.68.0.2

    root@harbor:/etc/kubeasz# cat ./roles/cluster-addon/vars/main.yml
    # default values
    
    # coredns 服务地址, 根据SERVICE_CIDR 设置, 默认选择网段第二个地址
    CLUSTER_DNS_SVC_IP: "{{ SERVICE_CIDR.split('.')[0] }}.{{ SERVICE_CIDR.split('.')[1] }}.{{ SERVICE_CIDR.split('.')[2] }}.{{ SERVICE_CIDR.split('.')[3]|int + 2 }}"

    修改完yaml文件中的版本信息之后, 直接运行kubectl apply -f .yaml。

    这里只是简单介绍一下。直接直接使用./ezctl setup k8s-cluster 07 更方便一点。

  8. 在主节点中配置kubectl使用环境参数。这一步之后基本整体安装完成了。这里只有harbor节点中才能使用kubectl命令。这里需要为master节点配置kubectl 使用运行环境。配置完成之后重新登录即可

    #将/etc/kubeasz/clusters/k8s-cluster/目录中的各个节点的kubectl 的kubeconfig文件拷贝到各个master节点中
    root@harbor:/etc/kubeasz/clusters/k8s-cluster# scp k8s-master01.cbear.top-kubectl.kubeconfig root@k8s-master01.cbear.top:/root/
    k8s-master01.cbear.top-kubectl.kubeconfig                                                                   100% 6197     4.0MB/s   00:00    
    root@harbor:/etc/kubeasz/clusters/k8s-cluster# scp k8s-master02.cbear.top-kubectl.kubeconfig root@k8s-master02.cbear.top:/root/
    k8s-master02.cbear.top-kubectl.kubeconfig                                                                   100% 6197     4.1MB/s   00:00    
    root@harbor:/etc/kubeasz/clusters/k8s-cluster# scp k8s-master03.cbear.top-kubectl.kubeconfig root@k8s-master03.cbear.top:/root/
    k8s-master03.cbear.top-kubectl.kubeconfig                                                                   100% 6197     4.0MB/s   00:00 
    
    #将拷贝到各个节点的kubeconfig文件拷贝到/root/.kube/目录中
    root@k8s-master01:~# cp k8s-master01.cbear.top-kubectl.kubeconfig .kube/config
    root@k8s-master02:~# cp   k8s-master02.cbear.top-kubectl.kubeconfig .kube/config
    root@k8s-master03:~# cp k8s-master03.cbear.top-kubectl.kubeconfig .kube/config

3. 集群管理

3.1 管理master节点

扩容节点分为扩容master节点和work节点

3.1.1 扩容master节点

新增kube_master节点大致流程为: (参考ezctl 中add-master函数和playbooks/23.addmaster.yml)

  • [可选]新节点安装 chrony 时间同步

  • 新节点预处理 prepare

  • 新节点安装 container runtime

  • 新节点安装 kube_master 服务

  • 新节点安装 kube_node 服务

  • 新节点安装网络插件相关

  • 禁止业务 pod调度到新master节点

  • 更新 node 节点 haproxy 负载均衡并重启( 这个实验中, 整体流程中没有配置ex_lb。因此最好是在2.2j节中, 设置[ex_lb]注释掉对应内容 , 避免扩容节点过程中报错)

root@harbor:/etc/kubeasz# ./ezctl add-master k8s-cluster 192.168.71.31 k8s_nodename=·k8s-master03.cbear.top

这里新扩容的节点需要提前安装对应的containerd环境, 不然会默认自动安装kubeasz默认的containerd容器环境

另外需将配置免密码登录

# ssh 免密码登录
$ ssh-copy-id k8s-master03.cbear.top

另外这个命令的使用示例如下:

# 新增节点
$ ezctl add-master test-k8s 192.168.1.11

# 同理, 重复上面步骤再新增节点并自定义nodename
$ ezctl add-master test-k8s 192.168.1.12 k8s_nodename=master-03

通过以下命令验证

# 在新节点master 服务状态
$ systemctl status kube-apiserver 
$ systemctl status kube-controller-manager
$ systemctl status kube-scheduler

# 查看新master的服务日志
$ journalctl -u kube-apiserver -f

# 查看集群节点, 可以看到新 master节点 Ready, 并且禁止了POD 调度功能
root@harbor:/etc/kubeasz# kubectl get nodes 
NAME                     STATUS                     ROLES    AGE     VERSION
k8s-master01.cbear.top   Ready,SchedulingDisabled   master   4h28m   v1.29.0
k8s-master02.cbear.top   Ready,SchedulingDisabled   master   4h28m   v1.29.0
k8s-master03.cbear.top   Ready,SchedulingDisabled   master   11m     v1.29.0
k8s-node01.cbear.top     Ready                      node     4h27m   v1.29.0
k8s-node02.cbear.top     Ready                      node     4h27m   v1.29.0

3.1.2 缩容master节点

删除kube_master节点大致流程为: (参考ezctl 中del-master函数和playbooks/33.delmaster.yml)

  • 检测是否可以删除

  • 迁移节点 pod

  • 删除 master 相关服务及文件

  • 删除 node 相关服务及文件

  • 从集群删除 node 节点

  • 从 ansible hosts 移除节点

  • 在 ansible 控制端更新 kubeconfig

  • 更新 node 节点 haproxy 配置

命令如下:

root@harbor:/etc/kubeasz# ./ezctl del-master k8s-cluster 192.168.71.31  #指定删除的节点为192.168.71.31

3.2 管理node节点

3.2.1 扩容节点

新增kube_node节点大致流程为: (参考ezctl 里面add-node函数 和 playbooks/22.addnode.yml)

  • [可选]新节点安装 chrony 时间同步

  • 新节点预处理 prepare

  • 新节点安装 container runtime

  • 新节点安装 kube_node 服务

  • 新节点安装网络插件相关

使用用法如下

# ssh 免密码登录
$ ssh-copy-id 192.168.1.11

# 新增节点
$ ezctl add-node test-k8s 192.168.1.11

# 同理, 重复上面步骤再新增节点并自定义nodename
$ ezctl add-node test-k8s 192.168.1.12 k8s_nodename=worker-03

整体的扩容思路与扩容master类似

root@harbor:/etc/kubeasz# ./ezctl add-node  k8s-cluster 192.168.71.37 k8s_nodename='k8s-node03.cbear.top'

用以下命令验证扩容结果

# 验证新节点状态
$ kubectl get node

# 验证新节点的网络插件calico 或flannel 的Pod 状态
$ kubectl get pod -n kube-system

3.2.2 缩容节点

删除 node 节点流程: (参考ezctl 里面del-node函数 和 playbooks/32.delnode.yml)

  • 检测是否可以删除

  • 迁移节点上的 pod

  • 删除 node 相关服务及文件

  • 从集群删除 node

操作步骤

$ ezctl del-node k8s-cluster 192.168.71.37 # 假设待删除节点为 192.168.71.37

3.3 升级版本

升级的主要原理是直接在master/work节点中, 直接下载二进制包。并将对应二进制包, 直接替换原本/opt/kube/bin/中的二进制文件。并重启对应服务即可

#该目录为kubeasz安装之后的二进制包, 每个节点中配置的二进制文件存放位置
root@k8s-master01:~# ll /opt/kube/bin/
total 556360
drwxr-xr-x 3 root root      4096 May 21 03:23 ./
drwxr-xr-x 4 root root      4096 May 20 14:58 ../
drwxr-xr-x 2 root root      4096 May 21 03:23 containerd-bin/
-rwxr-xr-x 1 root root  54939628 May 21 03:23 crictl*
-rwxr-xr-x 1 root root 123715584 May 20 15:54 kube-apiserver*
-rwxr-xr-x 1 root root 118345728 May 20 15:55 kube-controller-manager*
-rwxr-xr-x 1 root root  49704960 May 20 15:55 kubectl*
-rwxr-xr-x 1 root root 111808512 May 20 15:55 kubelet*
-rwxr-xr-x 1 root root  55234560 May 20 15:56 kube-proxy*
-rwxr-xr-x 1 root root  55939072 May 20 15:55 kube-scheduler*

集群升级存在一定风险, 请谨慎操作。

  • 支持k8s相同大版本基础上升级任意小版本, 比如当前安装集群为1.25.0, 你可以方便的升级到任何1.25.x版本

  • 不建议跨大版本升级, 一般大版本更新时k8s api有一些变动

3.3.1 备份etcd数据

  • 自动备份

    kubeasz项目也可以如下方便执行备份(假设集群名为k8s-01),

    dk ezctl backup k8s-01
  • 手动备份 etcd数据, 在任意 etcd节点上执行:

    # snapshot备份
    $ ETCDCTL_API=3 etcdctl snapshot save backup.db
    # 查看备份
    $ ETCDCTL_API=3 etcdctl --write-out=table snapshot status backup.db

3.3.2 小版本升级

快速升级k8s小版本, 比较常见如Bug修复 特性发布时使用。

  • 首先去官网release下载待升级的k8s版本, 例如https://dl.k8s.io/v1.25.4/kubernetes-server-linux-amd64.tar.gz

    直接在对应github下载

    kubernetes/CHANGELOG/CHANGELOG-1.29.md at master · kubernetes/kubernetes · GitHub

    image-20240521234327842
    root@harbor:~# wget https://dl.k8s.io/v1.29.5/kubernetes-server-linux-amd64.tar.gz

  • 解压下载的tar.gz文件, 找到如下kube*开头的二进制, 复制替换kubeasz控制端目录/etc/kubeasz/bin对应文件

    • kube-apiserver

    • kube-controller-manager

    • kubectl

    • kubelet

    • kube-proxy

    • kube-scheduler

  • 切换当前所在集群为升级集群, 在kubeasz控制端执行dk ezctl checkout k8s-01

    root@harbor:/etc/kubeasz# ezctl checkout k8s-cluster
    2024-05-21 16:45:59 INFO set default kubeconfig: cluster k8s-cluster (current)
  • 在kubeasz控制端执行dk ezctl upgrade k8s-01 即可完成k8s 升级, 不会中断业务应用

    #先拷贝对应的二进制文件到/etc/kubeasz/bin目录中
    root@harbor:~# cd kubernetes/server/bin/
    root@harbor:~/kubernetes/server/bin# cp kube-apiserver kube-controller-manager kubectl kubelet kube-proxy kube-scheduler /etc/kubeasz/bin/
    
    #验证拷贝之后的版本信息
    root@harbor:/etc/kubeasz/bin# ./kube-apiserver --version
    Kubernetes v1.29.5
    root@harbor:/etc/kubeasz/bin# ./kube-controller-manager --version
    Kubernetes v1.29.5
    root@harbor:/etc/kubeasz/bin# ./kubectl version
    Client Version: v1.29.5
    Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
    Server Version: v1.29.0
    
    root@harbor:/etc/kubeasz/bin# ./kubelet --version
    Kubernetes v1.29.5
    
    root@harbor:/etc/kubeasz/bin# ./kube-proxy --version
    Kubernetes v1.29.5
    root@harbor:/etc/kubeasz/bin# ./kube-scheduler --version
    Kubernetes v1.29.5
    
    
    #直接运行升级命令
    root@harbor:/etc/kubeasz# ezctl upgrade k8s-cluster

3.3.3 其他升级说明

其他升级是指升级k8s组件包括: etcd版本 docker版本, 一般不需要用到, 不建议升级, 以下仅作说明。

  • 1.下载所有组件相关新的二进制解压并替换 /etc/kubeasz/bin/ 目录下文件

  • 2.升级 etcd: ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml -t upgrade_etcd playbooks/02.etcd.yml

  • 3.升级 docker ( 建议使用k8s官方支持的docker稳定版本)

    • 如果可以接受短暂业务中断, 执行 ansible-playbook -t upgrade_docker 03.docker.yml

    • 如果要求零中断升级, 执行

      ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml -t download_docker playbooks/03.runtime.yml

      , 然后手动执行如下

      • 待升级节点, 先应用kubectl cordon和kubectl drain命令迁移业务pod

      • 待升级节点执行 systemctl restart docker

      • 恢复节点可调度 kubectl uncordon

3.4 管理 etcd 集群

Etcd集群支持在线改变集群成员节点, 可以增加、修改、删除成员节点; 不过改变成员数量仍旧需要满足集群成员多数同意原则quorum), 另外请记住集群成员数量变化的影响:

  • 注意: 如果etcd 集群有故障节点, 务必先删除故障节点, 然后添加新节点

  • 增加 etcd 集群节点, 提高集群稳定性

  • 增加 etcd 集群节点, 提高集群读性能 ( 所有节点数据一致, 客户端可以从任意节点读取数据)

  • 增加 etcd 集群节点, 降低集群写性能 ( 所有节点数据一致, 每一次写入会需要所有节点数据同步)

3.4.1 备份 etcd 数据

  1. 手动在任意正常 etcd 节点上执行备份:

    # snapshot备份
    $ ETCDCTL_API=3 etcdctl snapshot save backup.db
    # 查看备份
    $ ETCDCTL_API=3 etcdctl --write-out=table snapshot status backup.db

  2. 使用 kubeasz 备份 cluster_name 为 k8s-01

    ezctl backup k8s-01

使用 crontab 定时备份示例(使用容器化的 kubeasz , 每日01:01 备份)

1 1 * * * /usr/bin/docker exec -i kubeasz ezctl backup k8s-01

备份文件在

{{ base_dir }}/clusters/k8s-01/backup

3.4.2 etcd集群节点操作

执行如下 (假设待操作节点为 192.168.1.11 , 集群名称test-k8s):

  • 增加 etcd 节点:

    # ssh 免密码登录
    $ ssh-copy-id 192.168.1.11
    
    # 新增节点
    $ ezctl add-etcd test-k8s 192.168.1.11
  • 删除 etcd 节点: $ ezctl del-etcd test-k8s 192.168.1.11

具体操作流程参考 ezctl中 add-etcd/del-etcd 相关函数和playbooks/目录的操作剧本

3.4.3 验证 etcd 集群

# 登录任意etcd节点验证etcd集群状态
$ export ETCDCTL_API=3 
$ etcdctl member list

# 验证所有etcd节点服务状态和日志
$ systemctl status etcd
$ journalctl -u etcd -f

3.5 K8S 集群备份与恢复

虽然 K8S 集群可以配置成多主多节点的高可用的部署 , 还是有必要了解下集群的备份和容灾恢复能力 ; 在高可用k8s集群中 etcd集群保存了整个集群的状态 , 因此这里的备份与恢复重点就是:

  • 从运行的etcd集群备份数据到磁盘文件

  • 从etcd备份文件恢复数据 , 从而使集群恢复到备份时状态

备份与恢复操作说明

  • 首先搭建一个测试集群 , 部署几个测试deployment , 验证集群各项正常后 , 进行一次备份(假设集群名为k8s-01):

    $ ezctl backup k8s-01
    # 或者如下手动执行ansible命令
    # ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml  playbooks/94.backup.yml

    执行完毕可以在部署主机的备份目录下检查备份情况 , 示例如下:

    /etc/kubeasz/clusters/k8s-01/backup/
    ├── snapshot_202106201205.db
    ├── snapshot_202106211406.db
    └── snapshot.db

    其中 , snapshot.db始终为最近一次备份文件

  • 模拟误删除操作( 略)

  • 恢复集群及验证

    可以在 roles/cluster-restore/defaults/main.yml 文件中配置需要恢复的 etcd备份版本( 从上述备份目录中选取) , 默认使用最近一次备份 ; 执行恢复后 , 需要一定时间等待 pod/svc 等资源恢复重建。

    $ ezctl restore k8s-01
    # 或者如下手动执行ansible命令
    # ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml  playbooks/95.restore.yml

如果集群主要组件( master/etcd/node) 等出现不可恢复问题 , 可以尝试使用如下步骤 清理--> 创建--> 恢复

$ ezctl clean k8s-01
# 或者如下手动执行ansible命令
# ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml  playbooks/99.clean.yml
$ ezctl setup k8s-01 01
$ ezctl setup k8s-01 02
$ ezctl setup k8s-01 03
$ ezctl setup k8s-01 04
$ ezctl setup k8s-01 05
...
$ ezctl restore k8s-01
# ansible-playbook -i clusters/k8s-01/hosts -e @clusters/k8s-01/config.yml  playbooks/95.restore.yml

3.6 管理客户端kubeconfig

默认 k8s集群安装成功后生成客户端kubeconfig,它拥有集群管理的所有权限(不要将这个admin权限、50年期限的kubeconfig流露出去) ; 而我们经常需要将限定权限、限定期限的kubeconfig 分发给普通用户 ; 利用cfssl签发自定义用户证书和k8s灵活的rbac权限绑定机制,ezctl 工具封装了这个功能。

使用帮助

ezctl help kcfg-adm
Usage: ezctl kcfg-adm <cluster> <args>
available <args>:
    -A     to add a client kubeconfig with a newly created user
    -D     to delete a client kubeconfig with the existed user
    -L     to list all of the users
    -e     to set expiry of the user certs in hours (ex. 24h, 8h, 240h)
    -t     to set a user-type (admin or view)
    -u     to set a user-name prefix

examples: ./ezctl kcfg-adm test-k8s -L
          ./ezctl kcfg-adm default -A -e 240h -t admin -u jack
          ./ezctl kcfg-adm default -D -u jim-202101162141
  • 可以设置过期时间

  • 可以设置权限:管理员权限(admin)和只读权限(view)

使用举例

  • 查看集群k8s-01当前自定义kubeconfig

    ezctl kcfg-adm k8s-01 -L
    2021-01-24 16:32:43 INFO list-kcfg k8s-01
    2021-01-24 16:32:43 INFO list-kcfg in cluster:k8s-01
    
    USER                           TYPE            EXPIRY(+8h if in Asia/Shanghai)
    ---------------------------------------------------------------------------------
    
    2021-01-24 16:32:43 INFO list-kcfg k8s-01 success

    初始情况下列表为空

  • 增加集群k8s-01一个自定义用户kubeconfig,用户名user01,期限24h,只读权限

    ezctl kcfg-adm k8s-01 -A -u user01 -e 24h -t view
    2021-01-24 17:32:33 INFO add-kcfg k8s-01
    2021-01-24 17:32:33 INFO add-kcfg in cluster:k8s-01 with user:user01-202101241732
    
    PLAY [localhost] *****************************************************************************************************
    
    ...(此处省略输出) 
    
    TASK [deploy : debug] ************************************************************************************************
    ok: [localhost] => {
        "msg": "查看user01-202101241732自定义kubeconfig:/etc/kubeasz/clusters/k8s-01/ssl/users/user01-202101241732.kubeconfig"
    }
    
    PLAY RECAP ***********************************************************************************************************
    localhost                  : ok=12   changed=10   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    
    2021-01-24 17:32:41 INFO add-kcfg k8s-01 success

    生成的kubeconfig位于 /etc/kubeasz/clusters/k8s-01/ssl/users/user01-202101241732.kubeconfig

  • 再增加一个用户user02,期限240h,admin权限

    ezctl kcfg-adm k8s-01 -A -u user02 -e 240h -t admin
    2021-01-24 18:38:47 INFO add-kcfg k8s-01
    2021-01-24 18:38:47 INFO add-kcfg in cluster:k8s-01 with user:user02-202101241838
    
    PLAY [localhost] *****************************************************************************************************
    
    ...(此处省略输出)
    
    TASK [deploy : debug] ************************************************************************************************
    ok: [localhost] => {
        "msg": "查看user02-202101241838自定义kubeconfig:/etc/kubeasz/clusters/k8s-01/ssl/users/user02-202101241838.kubeconfig"
    }
    
    PLAY RECAP ***********************************************************************************************************
    localhost                  : ok=12   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    
    2021-01-24 18:38:55 INFO add-kcfg k8s-01 success
  • 再次查看集群k8s-01当前自定义kubeconfig

    ezctl kcfg-adm k8s-01 -L
    2021-01-24 18:40:30 INFO list-kcfg k8s-01
    2021-01-24 18:40:30 INFO list-kcfg in cluster:k8s-01
    
    USER                           TYPE            EXPIRY(+8h if in Asia/Shanghai)
    ---------------------------------------------------------------------------------
    user02-202101241838            cluster-admin   2021-02-03T10:34:00Z
    user01-202101241732            view            2021-01-25T09:28:00Z
    
    2021-01-24 18:40:31 INFO list-kcfg k8s-01 success
  • 删除user01-202101241732 权限

    ezctl kcfg-adm k8s-01 -D -u user01-202101241732
    2021-01-24 21:41:50 INFO del-kcfg k8s-01
    2021-01-24 21:41:50 INFO del-kcfg in cluster:k8s-01 with user:user01-202101241732
    clusterrolebinding.rbac.authorization.k8s.io "crb-user01-202101241732" deleted
    2021-01-24 21:41:50 INFO del-kcfg k8s-01 success
    
    ezctl kcfg-adm k8s-01 -L
    2021-01-24 21:42:02 INFO list-kcfg k8s-01
    2021-01-24 21:42:02 INFO list-kcfg in cluster:k8s-01
    
    USER                           TYPE            EXPIRY(+8h if in Asia/Shanghai)
    ---------------------------------------------------------------------------------
    user02-202101241838            cluster-admin   2021-02-03T10:34:00Z
    
    2021-01-24 21:42:02 INFO list-kcfg k8s-01 success

3.7 修改 APISERVER(MASTER)证书

kubeasz 创建集群后,APISERVER(MASTER)证书默认 CN 包含如下域名和IP:参见roles/kube-master/templates/kubernetes-csr.json.j2

  "hosts": [
    "127.0.0.1",
{% if groups['ex_lb']|length > 0 %}
    "{{ hostvars[groups['ex_lb'][0]]['EX_APISERVER_VIP'] }}",
{% endif %}
{% for host in groups['kube_master'] %}
    "{{ host }}",
{% endfor %}
    "{{ CLUSTER_KUBERNETES_SVC_IP }}",
{% for host in MASTER_CERT_HOSTS %}
    "{{ host }}",
{% endfor %}
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],

有的时候(比如apiserver地址通过边界防火墙的NAT转换成公网IP访问,或者需要添加公网域名访问)我们需要在 APISERVER(MASTER)证书中添加一些域名或者IP,可以方便操作如下:

  1. 修改配置文件/etc/kubeasz/clusters/${集群名}/config.yaml

    # k8s 集群 master 节点证书配置,可以添加多个ip和域名(比如增加公网ip和域名)
    MASTER_CERT_HOSTS:
      - "10.1.1.1"
      - "k8s.test.io"
      #- "www.test.com"
  2. 执行新证书生成并重启apiserver

    $ ezctl setup ${集群名} 04 -t change_cert,restart_master

3.8 强制更新CA和所有证书

  • WARNNING: 此命令使用需要小心谨慎,确保了解功能背景和可能的结果 ; 执行后,它会重新创建集群CA证书以及由它颁发的所有其他证书 ; 一般适合于集群admin.conf不小心泄露,为了避免集群被非法访问,重新创建CA,从而使已泄漏的admin.conf失效。

  • 如果需要分发受限的kubeconfig,强烈建议使用自定义权限和期限的kubeconfig

3.8.1 使用帮助

确认需要强制更新后,在ansible 控制节点使用如下命令:(xxx 表示需要操作的集群名)

docker exec -it kubeasz ezctl kca-renew xxx
# 或者使用 dk ezctl kca-renew xxx

上述命令执行后,按序进行以下的操作:详见playbooks/96.update-certs.yml

  • 重新生成CA证书,以及各种kubeconfig

  • 签发新etcd证书,并使用新证书重启etcd服务

  • 签发新kube-apiserver 证书,并重启kube-apiserver/kube-controller-manager/kube-scheduler 服务

  • 签发新kubelet 证书,并重启kubelet/kube-proxy 服务

  • 重启网络组件pod

  • 重启其他集群组件pod

  • 特别注意: 如果集群中运行的业务负载pod需要访问apiserver,需要重启这些pod

3.8.2 检查验证

更新完毕,注意检查集群组件日志和容器pod日志,确认集群处于正常状态

  • 集群组件日志:使用journalctl -u xxxx.service -f 依次检查 etcd.service/kube-apiserver.service/kube-controller-manager.service/kube-scheduler.service/kubelet.service/kube-proxy.service

  • 容器pod日志:使用 kubectl logs 方式检查容器日志

3.9 配置负载转发 ingress nodeport

向集群外暴露 ingress-controller 本身的服务端口(80/443/8080)一般有以下三种方法:

  • 部署ingress-controller时使用hostNetwork: true,这样就可以直接使用上述端口,可能与host已listen端口冲突

  • 部署ingress-controller时使用LoadBalancer类型服务,需要集群支持LoadBalancer

  • 部署ingress-controller时使用nodePort类型服务,然后在集群外使用 haproxy/f5 等配置 virtual server 集群

本文档讲解使用 haproxy 配置 ingress的 VS 集群,前提是配置了自建ex_lb节点

  1. 配置 ex_lb 参数开启转发 ingress nodeport

    # 编辑 roles/ex-lb/defaults/main.yml,配置如下变量
    INGRESS_NODEPORT_LB: "yes"
    INGRESS_TLS_NODEPORT_LB: "yes"
  2. 重新配置启动LB节点服务

    $ ezctl setup ${集群名} ex-lb 

  3. 验证 ex_lb 节点的 haproxy 服务配置 /etc/haproxy/haproxy.cfg 包含如下配置

    ... 前文省略
    listen kube_master
            bind 0.0.0.0:8443
            mode tcp
            option tcplog
            balance roundrobin
            server 192.168.1.1 192.168.1.1:6443 check inter 2000 fall 2 rise 2 weight 1
            server 192.168.1.2 192.168.1.2:6443 check inter 2000 fall 2 rise 2 weight 1
    
    listen ingress-node
            bind 0.0.0.0:80
            mode tcp
            option tcplog
            balance roundrobin
            server 192.168.1.3 192.168.1.3:23456 check inter 2000 fall 2 rise 2 weight 1
            server 192.168.1.4 192.168.1.4:23456 check inter 2000 fall 2 rise 2 weight 1
    
    listen ingress-node-tls
            bind 0.0.0.0:443
            mode tcp
            option tcplog
            balance roundrobin
            server 192.168.1.3 192.168.1.3:23457 check inter 2000 fall 2 rise 2 weight 1
            server 192.168.1.4 192.168.1.4:23457 check inter 2000 fall 2 rise 2 weight 1