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必备参数!

cat> kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ipt6ables=1
net.ipv6.conf.all.disable_ipv6=1
EOF
cp kubernetes.conf  /etc/sysctl.d/kubernetes.conf
sysctl -p /etc/sysctl.d/kubernetes.conf

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

# 加载模块
modprobe br_netfilter
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 ~]# cp /opt/flanneld/flanneld.service.template /etc/systemd/system/flanneld.service 

[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

[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 文件

[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/scp_kubelet_init.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/scp_kubelet_init.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-node01 ~]# ss -nutlp |grep kubelet tcp LISTEN 0 128 127.0.0.1:45593 0.0.0.0:* users:(("kubelet",pid=897,fd=14)) tcp LISTEN 0 128 127.0.0.1:10248 0.0.0.0:* users:(("kubelet",pid=897,fd=31)) tcp LISTEN 0 128 192.168.2.11:10250 0.0.0.0:* users:(("kubelet",pid=897,fd=28))

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/scp_kube-proxy_init.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/scp_kube-proxy_init.sh 

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

悲剧是 kube-proxy 启动不起来, 报错如下:

11月 16 03:09:34 k8s-node01 kube-proxy[1557]: W1116 03:09:34.023681    1557 server.go:208] WARNING: all flags other than --config, --write-config-to, and --cleanup are deprecated. Please be>
11月 16 03:09:34 k8s-node01 kube-proxy[1557]: F1116 03:09:34.023783    1557 server.go:439] failed validate: no arguments are supported
11月 16 03:09:34 k8s-node01 systemd[1]: kube-proxy.service: Main process exited, code=exited, status=255/n/a
11月 16 03:09:34 k8s-node01 systemd[1]: kube-proxy.service: Failed with result 'exit-code'.

不知道哪个参数不支持, 排查不出来

本来已经kubeadm了, 因为对k8s一无所知, 所以二进制安装测试了一把, 深入了解一下

K8S入门系列之集群二进制部署-->node篇(三)的更多相关文章

  1. K8S入门系列之集群二进制部署-->master篇(二)

    组件版本和配置策略 组件版本 Kubernetes 1.16.2 Docker 19.03-ce Etcd 3.3.17 https://github.com/etcd-io/etcd/release ...

  2. k8s入门系列之集群安装篇

    关于kubernetes组件的详解介绍,请阅读上一篇文章<k8s入门系列之介绍篇> Kubernetes集群安装部署 •Kubernetes集群组件: - etcd 一个高可用的K/V键值 ...

  3. k8s 入门系列之集群安装篇

    关于kubernetes组件的详解介绍,请阅读上一篇文章<k8s入门系列之介绍篇> Kubernetes集群安装部署 •Kubernetes集群组件: - etcd 一个高可用的K/V键值 ...

  4. K8S入门系列之集群yum安装(一)

    kubernetes master 节点包含的组件: 1.kube-apiserver :集群核心,集群API接口.集群各个组件通信的中枢:集群安全控制: 2.kube-scheduler: 集群调度 ...

  5. 附: K8S入门系列之集群健康检查

    Kubernetes的kubectl常用命令 1. pod操作 # 获取所有的pod kubectl get pods --all-namespaces -o wide # 使用yaml文件创建pod ...

  6. k8s入门系列之扩展组件(一)DNS安装篇

    DNS (domain name system),提供域名解析服务,解决了难于记忆的IP地址问题,以更人性可读可记忆可标识的方式映射对应IP地址. Cluster DNS扩展插件用于支持k8s集群系统 ...

  7. 使用Kubeadm创建k8s集群之部署规划(三十)

    前言 上一篇我们讲述了使用Kubectl管理k8s集群,那么接下来,我们将使用kubeadm来启动k8s集群. 部署k8s集群存在一定的挑战,尤其是部署高可用的k8s集群更是颇为复杂(后续会讲).因此 ...

  8. Kubernetes学习之路(二)之ETCD集群二进制部署

    ETCD集群部署 所有持久化的状态信息以KV的形式存储在ETCD中.类似zookeeper,提供分布式协调服务.之所以说kubenetes各个组件是无状态的,就是因为其中把数据都存放在ETCD中.由于 ...

  9. SpringCloud微服务实战——搭建企业级开发框架(三十四):SpringCloud + Docker + k8s实现微服务集群打包部署-Maven打包配置

      SpringCloud微服务包含多个SpringBoot可运行的应用程序,在单应用程序下,版本发布时的打包部署还相对简单,当有多个应用程序的微服务发布部署时,原先的单应用程序部署方式就会显得复杂且 ...

随机推荐

  1. Oracle VM VirtualBOX桥接网卡

    1.在VirtualBOX设置中的网络菜单,连接方式选择桥接网卡 2.启动系统,设置静态IP sudo vim /etc/network/interfaces auto enp0s3         ...

  2. Python制作有道翻译小工具

    该工具主要是利用了爬虫,爬取web有道翻译的内容. 然后利用简易GUI来可视化结果. 首先我们进入有道词典的首页,并点击翻译结果的审查元素 之后request响应网页,并分析网页,定位到翻译结果. 使 ...

  3. Vue-CLI项目中路由传参

    Vue-CLI项目中路由传参 一.标签传参方式:<router-link></router-link> 第一种 router.js { path: '/course/detai ...

  4. msf假冒令牌

    记录下 msf中令牌假冒的过程 环境 kai Linux 靶机 xp meterpreter得到一个返回的shell,test用户,假设无法提升至管理权限. 使用use incognito命令进入该模 ...

  5. 基于STL的队列略解

    什么是STL 以下内容摘自这儿. STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称.它是由Alexander Stepanov.Meng Le ...

  6. CF401D Roman and Numbers 状压DP

    CF401D 题意翻译 将n(n<=10^18)的各位数字重新排列(不允许有前导零) 求 可以构造几个mod m等于0的数字 题目描述 Roman is a young mathematicia ...

  7. 算法---区间K大数查找 Java 蓝桥杯ALGO-1

    import java.util.Arrays; import java.util.Scanner; public class Main { public static void main(Strin ...

  8. python中的随机函数

    python--随机函数(random,uniform,randint,randrange,shuffle,sample) 本文转载自:[chamie] random() random()方法:返回随 ...

  9. 简单理解TCP通信的三次握手

    TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接. 位码(可以理解为请求状态): 有6种标示:SYN(synchronous建立联机) ACK(acknowledg ...

  10. python中list切片详解

    语法:[start:stop:step] step代表切片步长:切片区间为[start,stop),包含start但不包含stop 1.step > 0,从左往右切片 2.step <0, ...