zoukankan      html  css  js  c++  java
  • K8S入门系列之集群二进制部署--> node篇(三)

    node节点组件

    • docker
    • kubelet
    • kube-proxy

    kubernetes-server-linux-amd64.tar.gz(相关的这里都能找到二进制文件!)

    • falnnel

    1. 系统初始化

    1.01 系统环境&&基本环境配置

    [root@localhost ~]# uname -a
    Linux localhost.localdomain 4.18.0-80.11.2.el8_0.x86_64 #1 SMP Tue Sep 24 11:32:19 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
    [root@localhost ~]# cat /etc/redhat-release 
    CentOS Linux release 8.0.1905 (Core) 
    

    1.02 修改各个节点的对应hostname, 并分别写入/etc/hosts

    hostnamectl set-hostname k8s-node01
    ...
    vi /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.2.201 k8s-master01
    192.168.2.202 k8s-master02
    192.168.2.203 k8s-master03
    192.168.2.11 k8s-node01
    192.168.2.12 k8s-node02
    

    1.03 安装依赖包和常用工具

    yum install -y wget vim yum-utils net-tools tar chrony curl jq ipvsadm ipset conntrack iptables sysstat libseccomp
    

    1.04 所有节点关闭firewalld, dnsmasq, selinux以及swap

    # 关闭防火墙并清空防火墙规则
    systemctl disable --now firewalld
    iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat
    iptables -P FORWARD ACCEP
    
    # 关闭dnsmasq否则可能导致docker容器无法解析域名!
    systemctl disable --now dnsmasq 
    
    # 关闭selinux  --->selinux=disabled 需重启生效!
    setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
    
    # 关闭swap --->注释掉swap那一行, 需重启生效!
    swapoff -a && sed -i '/ swap / s/^(.*)$/# 1/g' /etc/fstab
    

    1.04 所有节点设置时间同步

    timedatectl set-timezone Asia/Shanghai
    timedatectl set-local-rtc 0
    
    systemctl enable chronyd && systemctl restart chronyd
    

    1.05 调整内核参数, k8s必备参数!

    # 先加载模块
    modprobe br_netfilter
    
    cat> kubernetes.conf <<EOF
    net.bridge.bridge-nf-call-iptables = 1
    net.bridge.bridge-nf-call-ip6tables = 1
    net.ipv6.conf.all.disable_ipv6=1
    net.netfilter.nf_conntrack_max = 6553500
    net.nf_conntrack_max = 6553500
    net.ipv4.tcp_max_tw_buckets = 4096
    EOF
    
    cp kubernetes.conf  /etc/sysctl.d/kubernetes.conf
    sysctl -p /etc/sysctl.d/kubernetes.conf
    

    1.06 kube-proxy开始ipvs的前置条件

    cat> /etc/sysconfig/modules/ipvs.modules <<EOF
    #!/bin/bash
    modprobe -- ip_vs
    modprobe -- ip_vs_rr
    modprobe -- ip_vs_wrr
    modprobe -- ip_vs_sh
    modprobe -- nf_conntrack_ipv4
    EOF
    
    # 引导和验证!
    chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4
    

    1.07 在每台node上预建目录

    # 在每台机器上预创建目录:
    mkdir -p /opt/k8s/{bin,cert}
    mkdir -p /opt/flanneld/{bin,cert}
    mkdir -p /opt/docker/{bin,cert}
    mkdir -p /opt/lib/{kubelet,kube-proxy}
    mkdir -p /root/.kube/    
    
    # 在每台node上添加环境变量:
    sh -c "echo 'PATH=/opt/k8s/bin:/opt/flanneld/bin:/opt/docker/bin:$PATH:$HOME/bin:$JAVA_HOME/bin' >> /etc/profile.d/k8s.sh"
    
    source /etc/profile.d/k8s.sh
    

    1.08 需要从master拷贝的文件(CA证书, flannel证书, kubect配置文件等等!)

    # 在matser上建立如下脚本并运行
    [root@k8s-master01 ~]# vi /opt/k8s/script/scp_node_init.sh
    
    NODE_IPS=("$1" "$2" "$3")
    for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        # 导入CA证书
        scp /opt/k8s/cert/ca*.pem root@${node_ip}:/opt/k8s/cert/
        # 导入flanneld证书
        scp /opt/flanneld/cert/* root@${node_ip}:/opt/flanneld/cert/
        # 导入flannel二进制文件和mk-docker-opts.sh
        scp /opt/flanneld/bin/{flanneld,mk-docker-opts.sh} root@${node_ip}:/opt/flanneld/bin/
        # 导入flannel.service文件
        scp /etc/systemd/system/flanneld.service root@${node_ip}:/etc/systemd/system/
        # 导入kubectl配置文件  
        scp /root/.kube/config root@${node_ip}:/root/.kube/
        # 导入k8s-node所需的二进制文件
        scp /root/kubernetes/server/bin/{kubectl,kubelet,kube-proxy} root@${node_ip}:/opt/k8s/bin/
    done
    
    # 注意传参, 根据需要修改脚本参数传递:
    [root@k8s-master01 ~]# bash /opt/k8s/script/scp_node_init.sh 192.168.2.11 192.168.2.12
    

    2. 部署flannel网络

    • kubernetes要求集群内各节点(包括master节点)能通过Pod网段互联互通。flannel使用vxlan技术为各节点创建一个可以互通的Pod网络,使用的端口为UDP 8472,需要开放该端口(如公有云 AWS 等)。
    • flannel第一次启动时,从etcd获取Pod网段信息,为本节点分配一个未使用的 /24段地址,然后创建 flannel.1(也可能是其它名称) 接口。
    • flannel将分配的Pod网段信息写入/run/flannel/docker文件,docker后续使用这个文件中的环境变量设置docker0网桥。

    2.01 下载flannel二进制文件(*** 已从master导入! ***)

    [root@k8s-node01 ~]# wget https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
    # 解压到/opt/k8s/bin目录
    [root@k8s-node01 ~]# tar -xvf flannel-v0.11.0-linux-amd64.tar.gz 
    

    2.02 创建flanneld的systemd unit文件(*** 已从master导入! 目录存放位置设置一致, 所以可以复用! ***)

    [root@k8s-node01 ~]# vi /opt/flanneld/flanneld.service.template
    
    [Unit]
    Description=Flanneld overlay address etcd agent
    After=network.target
    After=network-online.target
    Wants=network-online.target
    After=etcd.service
    Before=docker.service
    
    [Service]
    Type=notify
    ExecStart=/opt/flanneld/bin/flanneld 
    -etcd-cafile=/opt/k8s/cert/ca.pem 
    -etcd-certfile=/opt/flanneld/cert/flanneld.pem 
    -etcd-keyfile=/opt/flanneld/cert/flanneld-key.pem 
    -etcd-endpoints=https://192.168.2.201:2379,https://192.168.2.202:2379,https://192.168.2.203:2379 
    -etcd-prefix=/atomic.io/network 
    -iface=eth0
    ExecStartPost=/opt/flanneld/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target
    RequiredBy=docker.service
    
    • mk-docker-opts.sh脚本将分配给flanneld的Pod子网网段信息写入/run/flannel/docker文件,后续docker启动时使用这个文件中的环境变量配置docker0 网桥;
    • flanneld使用系统缺省路由所在的接口与其它节点通信,对于有多个网络接口(如内网和公网)的节点,可以用-iface参数指定通信接口,如上面的eth1接口;
    • flanneld 运行时需要 root 权限;

    2.03 启用flanneld以及设置,验证!

    [root@k8s-node01 ~]# systemctl daemon-reload && systemctl enable flanneld && systemctl restart flanneld && systemctl status flanneld
    

    3. 部署 docker 组件

    • docker 是容器的运行环境,管理它的生命周期。kubelet 通过 Container Runtime Interface (CRI) 与 docker 进行交互

    3.01 下载docker 二进制文件

    [root@k8s-node01 ~]# wget https://download.docker.com/linux/static/stable/x86_64/docker-19.03.4.tgz
    
    [root@k8s-node01 ~]# tar -xvf docker-19.03.4.tgz 
    [root@k8s-node01 ~]# cp ~/docker/* /opt/docker/bin/ 
    

    3.02 创建 docker 的 systemd unit 文件

    [root@k8s-node01 ~]# vi /opt/docker/docker.service.template
    
    [Unit]
    Description=Docker Application Container Engine
    Documentation=http://docs.docker.io
    After=network-online.target
    After=flanneld.service
    Wants=network-online.target
    
    [Service]
    Environment="PATH=/opt/docker/bin:/bin:/sbin:/usr/bin:/usr/sbin"
    EnvironmentFile=-/run/flannel/docker
    ExecStart=/opt/docker/bin/dockerd 
        --log-level=error  
        $DOCKER_NETWORK_OPTIONS
    ExecReload=/bin/kill -s HUP $MAINPID
    Restart=on-failure
    RestartSec=5
    LimitNOFILE=infinity
    LimitNPROC=infinity
    LimitCORE=infinity
    Delegate=yes
    KillMode=process
    
    [Install]
    WantedBy=multi-user.target
    
    • EOF 前后有双引号,这样 bash 不会替换文档中的变量,如 $DOCKER_NETWORK_OPTIONS;
    • dockerd 运行时会调用其它 docker 命令,如 docker-proxy,所以需要将 docker 命令所在的目录加到 PATH 环境变量中;
    • flanneld 启动时将网络配置写入 /run/flannel/docker 文件中,dockerd 启动前读取该文件中的环境变量 DOCKER_NETWORK_OPTIONS ,然后设置 docker0 网桥网段;
    • 如果指定了多个 EnvironmentFile 选项,则必须将 /run/flannel/docker 放在最后(确保 docker0 使用 flanneld 生成的 bip 参数);
    • docker 需要以 root 用于运行;
    • docker 从 1.13 版本开始,可能将 iptables FORWARD chain的默认策略设置为DROP,从而导致 ping 其它 Node 上的 Pod IP 失败,遇到这种情况时,需要手动设置策略为 ACCEPT:$ sudo iptables -P FORWARD ACCEPT;并且把以下命令写入 /etc/rc.local 文件中,防止节点重启iptables FORWARD chain的默认策略又还原为DROP:$ /sbin/iptables -P FORWARD ACCEPT

    3.03 配置docker 配置文件

    • 使用国内的仓库镜像服务器以加快 pull image 的速度,同时增加下载的并发数 (需要重启 dockerd 生效):
    [root@k8s-node01 ~]# cat > /opt/docker/daemon.json <<EOF
    {
        "registry-mirrors": ["http://registry.aliyuncs.com/google_containers","https://hub-mirror.c.163.com"],
        "max-concurrent-downloads": 20
    }
    EOF
    

    3.04 启动docker并检查服务

    # 准备(文件位置调整!)
    [root@k8s-node01 ~]# cp /opt/docker/docker.service.template /etc/systemd/system/docker.service
    # 启动并添加开机启动, 检查服务状态
    [root@k8s-node01 ~]# systemctl daemon-reload && systemctl enable docker && systemctl restart docker && systemctl status docker | grep Active
    
    # 检查docker0网桥
    [root@k8s-node01 ~]# /usr/sbin/ip addr show flannel.1 && /usr/sbin/ip addr show docker0
    3: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default 
        link/ether 06:c3:76:09:95:c2 brd ff:ff:ff:ff:ff:ff
        inet 10.30.65.0/32 scope global flannel.1
           valid_lft forever preferred_lft forever
        inet6 fe80::4c3:76ff:fe09:95c2/64 scope link 
           valid_lft forever preferred_lft forever
    4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
        link/ether 02:42:76:65:08:06 brd ff:ff:ff:ff:ff:ff
        inet 10.30.96.1/24 brd 10.30.65.255 scope global docker0
           valid_lft forever preferred_lft forever
    

    4. 部署 kubelet 组件

    • kublet 运行在每个 worker 节点上,接收 kube-apiserver 发送的请求,管理 Pod 容器,执行交互式命令,如 exec、run、logs 等。
    • kublet 启动时自动向 kube-apiserver 注册节点信息,内置的 cadvisor 统计和监控节点的资源使用情况。
    • 为确保安全,本文档只开启接收 https 请求的安全端口,对请求进行认证和授权,拒绝未授权的访问(如 apiserver、heapster)。

    4.01 下载二进制kubelet文件(*** 已从master导入 ***)

    kubernetes-server-linux-amd64.tar.gz    # 我在这里, 在这里! 哪里找? 自己想办法!  里面事kubectl工具!!!
    

    4.02 在 k8s-master01 上为每一个要加入的 node 创建 kubelet-bootstrap.kubeconfig 文件

    用kubeadm创建token

    [root@k8s-master01 ~]# cp kubernetes/server/bin/kubeadm /opt/k8s/bin/
    
    [root@k8s-master01 ~]# vi /opt/k8s/script/bootstrap_kubeconfig.sh
    
    NODE_NAMES=("$1" "$2")
    for node_name in ${NODE_NAMES[@]};do
        echo ">>> ${node_name}"
    
        # 用kubeadm创建 token --> 并写入/root/.kube/config
        export BOOTSTRAP_TOKEN=$(kubeadm token create 
        --description kubelet-bootstrap-token 
        --groups system:bootstrappers:${node_name} 
        --kubeconfig /root/.kube/config)
    
        # 设置集群参数
        kubectl config set-cluster kubernetes 
        --certificate-authority=/opt/k8s/cert/ca.pem 
        --embed-certs=true 
        --server=https://192.168.2.210:8443 
        --kubeconfig=/opt/k8s/kubelet/kubelet-bootstrap-${node_name}.kubeconfig
    
        # 设置客户端认证参数
        kubectl config set-credentials kubelet-bootstrap 
        --token=${BOOTSTRAP_TOKEN} 
        --kubeconfig=/opt/k8s/kubelet/kubelet-bootstrap-${node_name}.kubeconfig
    
        # 设置上下文参数
        kubectl config set-context default 
        --cluster=kubernetes 
        --user=kubelet-bootstrap 
        --kubeconfig=/opt/k8s/kubelet/kubelet-bootstrap-${node_name}.kubeconfig
    
        # 设置默认上下文
        kubectl config use-context default --kubeconfig=/opt/k8s/kubelet/kubelet-bootstrap-${node_name}.kubeconfig
    done
    
    
    • 证书中写入 Token 而非证书,证书后续由 controller-manager 创建。
    [root@k8s-master01 ~]# bash /opt/k8s/script/bootstrap_kubeconfig.sh k8s-node01 k8s-node02
    
    • 查看 kubeadm 创建的 token:
    [root@k8s-master01 ~]# kubeadm token list --kubeconfig ~/.kube/config
    TOKEN                     TTL       EXPIRES                     USAGES                   DESCRIPTION               EXTRA GROUPS
    3atb7y.gsq4t23paxjutx2n   23h       2019-11-16T01:37:09+08:00   authentication,signing   kubelet-bootstrap-token   system:bootstrappers:k8s-node02
    54ixvq.ote8az8qffgq3lug   23h       2019-11-16T01:37:09+08:00   authentication,signing   kubelet-bootstrap-token   system:bootstrappers:k8s-node01
    
    • 创建的 token 有效期为 1 天,超期后将不能再被使用,且会被 kube-controller-manager 的 tokencleaner 清理(如果启用该 controller 的话)

    kube-apiserver 接收 kubelet 的 bootstrap token 后,将请求的 user 设置为 system:bootstrap:,group 设置为 system:bootstrappers;

    查看各token 关联的 Secret命令:

    [root@k8s-master01 ~]# kubectl get secrets -n kube-system
    

    4.03 在 k8s-master01 上创建kubelet 参数配置文件

    [root@k8s-master01 ~]# vi /opt/k8s/kubelet/kubelet.config.json.template
    
    {
      "kind": "KubeletConfiguration",
      "apiVersion": "kubelet.config.k8s.io/v1beta1",
      "authentication": {
        "x509": {
          "clientCAFile": "/opt/k8s/cert/ca.pem"
        },
        "webhook": {
          "enabled": true,
          "cacheTTL": "2m0s"
        },
        "anonymous": {
          "enabled": false
        }
      },
      "authorization": {
        "mode": "Webhook",
        "webhook": {
          "cacheAuthorizedTTL": "5m0s",
          "cacheUnauthorizedTTL": "30s"
        }
      },
      "address": "##NODE_IP##",
      "port": 10250,
      "readOnlyPort": 0,
      "cgroupDriver": "cgroupfs",
      "hairpinMode": "promiscuous-bridge",
      "serializeImagePulls": false,
      "featureGates": {
        "RotateKubeletClientCertificate": true,
        "RotateKubeletServerCertificate": true
      },
      "clusterDomain": "cluster.local",
      "clusterDNS": ["10.90.0.2"]
    }
    

    4.04 在k8s-master01上创建kubelet 的 systemd unit 文件

    [root@k8s-master01 ~]# vi /opt/k8s/kubelet/kubelet.service.template
    
    [Unit]
    Description=Kubernetes Kubelet
    Documentation=https://github.com/GoogleCloudPlatform/kubernetes
    After=docker.service
    Requires=docker.service
    
    [Service]
    WorkingDirectory=/opt/lib/kubelet
    ExecStart=/opt/k8s/bin/kubelet 
    --bootstrap-kubeconfig=/opt/k8s/kubelet-bootstrap.kubeconfig 
    --cert-dir=/opt/k8s/cert/ 
    --kubeconfig=/opt/k8s/kubelet.kubeconfig 
    --config=/opt/k8s/kubelet.config.json 
    --hostname-override=##NODE_NAME## 
    --pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest 
    --alsologtostderr=true 
    --logtostderr=false 
    --log-dir=/var/log/kubernetes 
    --v=2
    Restart=on-failure
    RestartSec=5
    
    [Install]
    WantedBy=multi-user.target
    

    4.05 Bootstrap Token Auth 和授予权限

    • kublet 启动时查找配置的 --kubeletconfig 文件是否存在,如果不存在则使用 --bootstrap-kubeconfig 向 kube-apiserver 发送证书签名请求 (CSR)。

    • kube-apiserver 收到 CSR 请求后,对其中的 Token 进行认证(事先使用 kubeadm 创建的 token),认证通过后将请求的 user 设置为 system:bootstrap:,group 设置为 system:bootstrappers,这一过程称为 Bootstrap Token Auth。

    • 默认情况下,这个 user 和 group 没有创建 CSR 的权限,kubelet 启动失败!!!!!!!!!

    • 解决办法是:创建一个 clusterrolebinding,将 group system:bootstrappers 和 clusterrole system:node-bootstrapper 绑定:

    # 在k8s-master01节点上操作!
    [root@k8s-master01 ~]# kubectl create clusterrolebinding kubelet-bootstrap 
    --clusterrole=system:node-bootstrapper 
    --group=system:bootstrappers
    
    #查看kubelet-bootstrap绑定信息
    [root@k8s-master01 ~]# kubectl describe clusterrolebinding kubelet-bootstrap
    #删除kubelet-bootstrap绑定信息
    [root@k8s-master01 ~]# kubectl delete clusterrolebinding kubelet-bootstrap
    

    4.06 在 k8s-master01 上分发 bootstrap.kubeconfig, kubelet 配置文件到所有 node 节点, 并启动 kubelet 服务

    [root@k8s-master01 ~]# vi /opt/k8s/script/kubelet_service.sh
    
    # 变量根据需求调整, 两个相对应不能多也不能少!!
    NODE_IPS=("192.168.2.11" "192.168.2.12")
    NODE_NAMES=("k8s-node01" "k8s-node02")
    
    # 分发kubelet-bootstrap.kubeconfig配置文件
    for node_name in ${NODE_NAMES[@]};do
        echo ">>> ${node_name}"
        scp /opt/k8s/kubelet/kubelet-bootstrap-${node_name}.kubeconfig root@${node_name}:/opt/k8s/kubelet-bootstrap.kubeconfig
    done
    
    # 分发kubelet.config.json
    for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        sed -e "s/##NODE_IP##/${node_ip}/" /opt/k8s/kubelet/kubelet.config.json.template > /opt/k8s/kubelet/kubelet.config-${node_ip}.json
        scp /opt/k8s/kubelet/kubelet.config-${node_ip}.json root@${node_ip}:/opt/k8s/kubelet.config.json
    done
    
    #分发kubelet systemd unit 文件
    for node_name in ${NODE_NAMES[@]};do 
        echo ">>> ${node_name}"
        sed -e "s/##NODE_NAME##/${node_name}/" /opt/k8s/kubelet/kubelet.service.template > /opt/k8s/kubelet/kubelet-${node_name}.service
        scp /opt/k8s/kubelet/kubelet-${node_name}.service root@${node_name}:/etc/systemd/system/kubelet.service
    done
    #开启检查kubelet 服务
    for node_ip in ${NODE_IPS[@]};do
        ssh root@${node_ip} "mkdir -p /opt/lib/kubelet"
        ssh root@${node_ip} "mkdir -p /var/log/kubernetes"
        ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kubelet && systemctl restart kubelet"
        ssh root@${node_ip} "systemctl status kubelet | grep Active"
    done 
    
    [root@k8s-master01 ~]# bash /opt/k8s/script/kubelet_service.sh
    

    4.06 手动和自动 approve kubelet CSR 请求(*** 在master上操作!! ***)

    • 新加入node节点处于Pending, 需在master节点approve csr请求!

    4.06.01 手动approve csr 请求!

    # 查看 CSR 列表:
    [root@k8s-master01 ~]# kubectl get csr
    NAME                                                   AGE   REQUESTOR                 CONDITION
    node-csr-DzSCvZQM86B7X8wkZV6mK8TQCOBBtVg1RMUohpx2P2c   25s   system:bootstrap:3atb7y   Pending
    node-csr-Rctd6tMgFECldiqhkP2ZOirO_VIBACu0foTJxK7Skf4   63s   system:bootstrap:54ixvq   Pending
    
    # 手动approve csr:
    [root@k8s-master01 ~]#  kubectl certificate approve node-csr-ADMwXCLrvlOo0Hoal7ttm3E9Ova1QOtRciO66Pd4Wqc
    
    # )查看 approve 结果:
    [root@k8s-master01 ~]# kubectl get csr
    NAME                                                   AGE   REQUESTOR                 CONDITION
    node-csr-ADMwXCLrvlOo0Hoal7ttm3E9Ova1QOtRciO66Pd4Wqc   24m   system:bootstrap:n9t3z1   Approved,Issued
    

    4.06.02 自动approve csr 请求!

    创建三个 ClusterRoleBinding,分别用于自动 approve client、renew client、renew server 证书:

    [root@k8s-master01 ~]# cat > /opt/k8s/csr-crb.yaml <<EOF
     # Approve all CSRs for the group "system:bootstrappers"
     kind: ClusterRoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: auto-approve-csrs-for-group
     subjects:
     - kind: Group
       name: system:bootstrappers
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
       apiGroup: rbac.authorization.k8s.io
    ---
     # To let a node of the group "system:nodes" renew its own credentials
     kind: ClusterRoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: node-client-cert-renewal
     subjects:
     - kind: Group
       name: system:nodes
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
       apiGroup: rbac.authorization.k8s.io
    ---
    # A ClusterRole which instructs the CSR approver to approve a node requesting a
    # serving cert matching its client cert.
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: approve-node-server-renewal-csr
    rules:
    - apiGroups: ["certificates.k8s.io"]
      resources: ["certificatesigningrequests/selfnodeserver"]
      verbs: ["create"]
    ---
     # To let a node of the group "system:nodes" renew its own server credentials
     kind: ClusterRoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: node-server-cert-renewal
     subjects:
     - kind: Group
       name: system:nodes
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: approve-node-server-renewal-csr
       apiGroup: rbac.authorization.k8s.io
    EOF
    
    • auto-approve-csrs-for-group:自动 approve node 的第一次 CSR; 注意第一次 CSR 时,请求的 Group 为 system:bootstrappers;
    • node-client-cert-renewal:自动 approve node 后续过期的 client 证书,自动生成的证书 Group 为 system:nodes;
    • node-server-cert-renewal:自动 approve node 后续过期的 server 证书,自动生成的证书 Group 为 system:nodes;

    生效配置:

    [root@k8s-master01 ~]# kubectl apply -f /opt/k8s/csr-crb.yaml
    clusterrolebinding.rbac.authorization.k8s.io/auto-approve-csrs-for-group created
    clusterrolebinding.rbac.authorization.k8s.io/node-client-cert-renewal created
    clusterrole.rbac.authorization.k8s.io/approve-node-server-renewal-csr created
    clusterrolebinding.rbac.authorization.k8s.io/node-server-cert-renewal created
    
    • 需要等待1-10分钟才能处理完毕!!!!!!

    4.07 查看 kublet 的情况

    [root@k8s-master01 ~]# kubectl get csr
    NAME                                                   AGE     REQUESTOR                 CONDITION
    node-csr-DzSCvZQM86B7X8wkZV6mK8TQCOBBtVg1RMUohpx2P2c   3m40s   system:bootstrap:3atb7y   Approved,Issued
    node-csr-Rctd6tMgFECldiqhkP2ZOirO_VIBACu0foTJxK7Skf4   4m18s   system:bootstrap:54ixvq   Approved,Issued
    
    # 节点已经ready
    [root@k8s-master01 ~]# kubectl get nodes
    NAME         STATUS   ROLES    AGE   VERSION
    k8s-node01   Ready    <none>   7s    v1.16.2
    k8s-node02   Ready    <none>   5s    v1.16.2
    
    # kube-controller-manager 为各 node 生成了 kubeconfig 文件和公私钥:(*** 在node节点保存! ***)
    [root@k8s-node01 ~]# ll /opt/k8s/kubelet.kubeconfig 
    -rw------- 1 root root 2299 11月 14 02:19 /opt/k8s/kubelet/kubelet.kubeconfig
    
    [root@k8s-node01 ~]# ll /opt/k8s/cert/ | grep kubelet
    -rw------- 1 root root 1273 11月 14 02:19 kubelet-client-2019-11-14-02-19-31.pem
    lrwxrwxrwx 1 root root   60 11月 14 02:19 kubelet-client-current.pem -> /opt/k8s/kubelet/cert/kubelet-client-2019-11-14-02-19-31.pem
    -rw-r--r-- 1 root root 2185 11月 14 00:43 kubelet.crt
    -rw------- 1 root root 1675 11月 14 00:43 kubelet.key
    

    4.08 kubelet 提供的 API 接口

    kublet 启动后监听多个端口,用于接收 kube-apiserver 或其它组件发送的请求:

    [root@k8s-node02 ~]# ss -nutlp |grep kubelet
    
    tcp    LISTEN   0        128             127.0.0.1:33313          0.0.0.0:*      users:(("kubelet",pid=3416,fd=15))                                             
    tcp    LISTEN   0        128             127.0.0.1:10248          0.0.0.0:*      users:(("kubelet",pid=3416,fd=34))                                             
    tcp    LISTEN   0        128          192.168.2.12:10250          0.0.0.0:*      users:(("kubelet",pid=3416,fd=31))              
    

    kubelet 接收 10250 端口的 https 请求

    • /pods、/runningpods
    • /metrics、/metrics/cadvisor、/metrics/probes
    • /spec
    • /stats、/stats/container
    • /logs
    • /run/、"/exec/", "/attach/", "/portForward/", "/containerLogs/" 等管理;

    由于关闭了匿名认证,同时开启了 webhook 授权,所有访问 10250 端口 https API 的请求都需要被认证和授权

    [root@k8s-node01 ~]# kubectl describe clusterrole system:kubelet-api-admin
    Name:         system:kubelet-api-admin
    Labels:       kubernetes.io/bootstrapping=rbac-defaults
    Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
    PolicyRule:
      Resources      Non-Resource URLs  Resource Names  Verbs
      ---------      -----------------  --------------  -----
      nodes/log      []                 []              [*]
      nodes/metrics  []                 []              [*]
      nodes/proxy    []                 []              [*]
      nodes/spec     []                 []              [*]
      nodes/stats    []                 []              [*]
      nodes          []                 []              [get list watch proxy]
    

    4.09 kublet api 认证和授权

    1、kublet 配置了如下认证参数:

    • authentication.anonymous.enabled:设置为 false,不允许匿名访问 10250 端口;
    • authentication.x509.clientCAFile:指定签名客户端证书的 CA 证书,开启 HTTPs 证书认证;
    • authentication.webhook.enabled=true:开启 HTTPs bearer token 认证;
      同时配置了如下授权参数:
    • authroization.mode=Webhook:开启 RBAC 授权;

    2、kubelet 收到请求后,使用 clientCAFile 对证书签名进行认证,或者查询 bearer token 是否有效。如果两者都没通过,则拒绝请求,提示 Unauthorized:

    3、通过认证后,kubelet 使用 SubjectAccessReview API 向 kube-apiserver 发送请求,查询证书或 token 对应的 user、group 是否有操作资源的权限(RBAC);

    • 使用部署 kubectl 命令行工具时创建的、具有最高权限的 admin 证书;

    4、bear token 认证和授权:

    4.10 获取 kublet 的配置

    占位!!!

    5. 部署 kube-proxy 组件

    • kube-proxy 运行在所有 worker 节点上,,它监听 apiserver 中 service 和 Endpoint 的变化情况,创建路由规则来进行服务负载均衡。(因为要监听apiserver 所以client证书, 去CA上创建吧!!)
    • 本文档讲解部署 kube-proxy 的部署,使用 ipvs 模式。

    5.01 下载 kube-proxy 二进制文件(*** 已从master导入 *** )

    5.02 安装依赖包

    • 各节点需要安装 ipvsadm 和 ipset 命令,加载 ip_vs 内核模块。

    5.03 在 k8s-master01 上创建 kube-proxy 证书

    在 k8s-master01 上创建请求文件

    [root@k8s-master01 ~]# cat > /opt/k8s/cert/kube-proxy-csr.json << EOF
    {
      "CN": "system:kube-proxy",
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names": [
        {
          "C": "CN",
          "ST": "BeiJing",
          "L": "BeiJing",
          "O": "k8s",
          "OU": "steams"
        }
      ]
    }
    EOF
    
    • CN:指定该证书的 User 为 system:kube-proxy;
    • 预定义的 RoleBinding system:node-proxier 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限;
    • 该证书只会被 kube-proxy 当做 client 证书使用,所以 hosts 字段为空;

    在 k8s-master01 上生成证书和私钥

    [root@k8s-master01 ~]# cfssl gencert -ca=/opt/k8s/cert/ca.pem 
    -ca-key=/opt/k8s/cert/ca-key.pem 
    -config=/opt/k8s/cert/ca-config.json 
    -profile=kubernetes /opt/k8s/cert/kube-proxy-csr.json | cfssljson -bare /opt/k8s/cert/kube-proxy
    

    5.04 在 k8s-master01 上创建kube-proxy.kubeconfig 文件

    [root@kube-master ~]# kubectl config set-cluster kubernetes 
    --certificate-authority=/opt/k8s/cert/ca.pem 
    --embed-certs=true 
    --server=https://192.168.2.210:8443 
    --kubeconfig=/opt/k8s/kube-proxy/kube-proxy.kubeconfig
    
     [root@kube-master ~]# kubectl config set-credentials kube-proxy 
    --client-certificate=/opt/k8s/cert/kube-proxy.pem 
    --client-key=/opt/k8s/cert/kube-proxy-key.pem 
    --embed-certs=true 
    --kubeconfig=/opt/k8s/kube-proxy/kube-proxy.kubeconfig
    
     [root@kube-master ~]# kubectl config set-context kube-proxy@kubernetes 
    --cluster=kubernetes 
    --user=kube-proxy 
    --kubeconfig=/opt/k8s/kube-proxy/kube-proxy.kubeconfig
    
    [root@kube-master ~]# kubectl config use-context kube-proxy@kubernetes --kubeconfig=/opt/k8s/kube-proxy/kube-proxy.kubeconfig
    
    • --embed-certs=true:将 ca.pem 和 admin.pem 证书内容嵌入到生成的 kubectl-proxy.kubeconfig 文件中(不加时,写入的是证书文件路径);

    5.05 在 k8s-master01 上创建 kube-proxy 配置文件模板

    • 从 v1.10 开始,kube-proxy 部分参数可以配置文件中配置。可以使用 --write-config-to 选项生成该配置文件,
    [root@k8s-master01 ~]# cat >/opt/k8s/kube-proxy/kube-proxy.config.yaml.template <<EOF
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: ##NODE_IP##
    clientConnection:
      kubeconfig: /opt/k8s/kube-proxy.kubeconfig
    clusterCIDR: 10.96.0.0/16
    healthzBindAddress: ##NODE_IP##:10256
    hostnameOverride: ##NODE_NAME##
    kind: KubeProxyConfiguration
    metricsBindAddress: ##NODE_IP##:10249
    mode: "ipvs"
    EOF
    
    • bindAddress: 监听地址;
    • clientConnection.kubeconfig: 连接 apiserver 的 kubeconfig 文件;
    • clusterCIDR: kube-proxy 根据 --cluster-cidr 判断集群内部和外部流量,指定 --cluster-cidr 或 --masquerade-all选项后 kube-proxy 才会对访问 Service IP 的请求做 SNAT;
    • hostnameOverride: 参数值必须与 kubelet 的值一致,否则 kube-proxy 启动后会找不到该 Node,从而不会创建任何 ipvs 规则;
    • mode: 使用 ipvs 模式;

    5.06 在 k8s-master01 上创建kube-proxy 的 systemd unit 文件

    [root@k8s-master01 ~]# vi /opt/k8s/kube-proxy/kube-proxy.service.template
    
    [Unit]
    Description=Kubernetes Kube-Proxy Server
    Documentation=https://github.com/GoogleCloudPlatform/kubernetes
    After=network.target
    
    [Service]
    WorkingDirectory=/opt/lib/kube-proxy
    ExecStart=/opt/k8s/bin/kube-proxy 
      --config=/opt/k8s/kube-proxy.config.yaml 
      --alsologtostderr=true 
      --logtostderr=false 
      --log-dir=/var/log/kubernetes 
      --v=2
    Restart=on-failure
    RestartSec=5
    LimitNOFILE=65536
    
    [Install]
    WantedBy=multi-user.target
    

    5.07 在 k8s-master01上 分发 .kubeconfig、kube-proxy 的 systemd unit 文件;启动并检查kube-proxy 服务

    [root@k8s-master01 ~]# vi /opt/k8s/script/kube-proxy_service.sh
    
    # 变量根据需求调整, 两个相对应不能多也不能少!
    NODE_IPS=("192.168.2.11" "192.168.2.12")
    NODE_NAMES=("k8s-node01" "k8s-node02")
    
    # 注意循环内的变量要根据node数量也做相应调整!
    for (( i=0; i < 2; i++ ));do 
            echo ">>> ${NODE_NAMES[i]}"
            sed -e "s/##NODE_NAME##/${NODE_NAMES[i]}/" -e "s/##NODE_IP##/${NODE_IPS[i]}/" /opt/k8s/kube-proxy/kube-proxy.config.yaml.template > /opt/k8s/kube-proxy/kube-proxy-${NODE_NAMES[i]}.config.yaml
            scp /opt/k8s/kube-proxy/kube-proxy-${NODE_NAMES[i]}.config.yaml root@${NODE_NAMES[i]}:/opt/k8s/kube-proxy.config.yaml
    done
    
    for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        scp /opt/k8s/kube-proxy/kube-proxy.kubeconfig root@${node_ip}:/opt/k8s/
        scp /opt/k8s/kube-proxy/kube-proxy.service.template root@${node_ip}:/etc/systemd/system/kube-proxy.service
        ssh root@${node_ip} "mkdir -p /opt/lib/kube-proxy"
        ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kube-proxy && systemctl restart kube-proxy"
        ssh root@${node_ip} "systemctl status kube-proxy|grep Active"
    done
    
    [root@k8s-master01 ~]# bash /opt/k8s/script/kube-proxy_service.sh 
    

    5.08 在node节点上-->查看监听端口和 metrics

    [root@k8s-node01 ~]# ss -nutlp |grep kube-prox
    
    tcp    LISTEN   0        128          192.168.2.11:10249          0.0.0.0:*      users:(("kube-proxy",pid=7089,fd=16))                                          
    tcp    LISTEN   0        128          192.168.2.11:10256          0.0.0.0:*      users:(("kube-proxy",pid=7089,fd=17)) 
    
    • 10249:http prometheus metrics port;
    • 10256:http healthz port;

    5.09 在node节点上-->查看 ipvs 路由规则

    [root@k8s-node01 ~]# /usr/sbin/ipvsadm -ln
    
    IP Virtual Server version 1.2.1 (size=4096)
    Prot LocalAddress:Port Scheduler Flags
      -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
    TCP  10.96.0.1:443 rr
      -> 192.168.2.201:6443           Masq    1      0          0         
      -> 192.168.2.202:6443           Masq    1      0          0         
      -> 192.168.2.203:6443           Masq    1      0          0     
    

    node节点基本组件已经部署完毕!!

    此篇根据大佬的文章一步步排坑安装的, 足够详细, 一步步验证而来!

  • 相关阅读:
    【CF1015D】Walking Between Houses(构造,贪心)
    【CF1068D】Array Without Local Maximums(计数DP)
    【CF1068C】Colored Rooks(构造)
    172.处理机控制与杂项指令
    171.控制转移指令
    170.串处理指令
    169.逻辑指令
    168.算术指令
    Volume 1. Big Number(uva)
    Volume 1. String(uva)
  • 原文地址:https://www.cnblogs.com/colman/p/11875118.html
Copyright © 2011-2022 走看看