kubernetes Node节点包含如下组件
  • flannel
  • docker
  • kubelet
  • kube-proxy
flannel,docker 根据前面的文章自行部署,这里重要介绍kubelet ,kube-proxy 组件

部署kubelet组件 

Master apiserver启用TLS认证后,Node节点kubelet组件想要加入集群,必须使用CA签发的有效证书才能与apiserver通信,当Node节点很多时,签署证书是一件很繁琐的事情,因此有了TLS Bootstrapping机制,kubelet会以一个低权限用户自动向apiserver申请证书,kubelet的证书由apiserver动态签署。

相关文章:

https://mritd.me/2018/01/07/kubernetes-tls-bootstrapping-note/

在 apiserver 配置中指定了一个 token.csv 文件,该文件中是一个预设的用户配置;同时该用户的 Token 和 apiserver 的 CA 证书被写入了 kubelet 所使用的 bootstrap.kubeconfig 配置文件中;这样在首次请求时,kubelet 使用 bootstrap.kubeconfig 中的 apiserver CA 证书来与 apiserver 建立 TLS 通讯,使用 bootstrap.kubeconfig 中的用户 Token 来向 apiserver 声明自己的 RBAC 授权身份,所以,我们需要生成一个kubeconfig 的文件

1.生成kubeconfig文件 

BOOTSTRAP_TOKEN=4274d4ed9dd65b7bddc521916a218f0a #这个内容可以到api指定的token文件中查看
KUBE_APISERVER="https://10.211.55.8:8443" #对外提供的api安全连接端口
# 设置集群参数

cd /etc/ssl/lkubernetes/ 

kubectl config set-cluster kubernetes \
  --certificate-authority=./ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=bootstrap.kubeconfig
# 设置客户端认证参数
kubectl config set-credentials kubelet-bootstrap \
  --token=${BOOTSTRAP_TOKEN} \
  --kubeconfig=bootstrap.kubeconfig
# 设置上下文参数
kubectl config set-context default \
  --cluster=kubernetes \
  --user=kubelet-bootstrap \
  --kubeconfig=bootstrap.kubeconfig
# 设置默认上下文
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig

这里面授权用到的用户是kubelet-bootstap,所以还需要授权因为在有些用户首次启动时,可能与遇到 kubelet 报 401 无权访问 apiserver 的错误;

这是因为在默认情况下,kubelet 通过 bootstrap.kubeconfig 中的预设用户 Token 声明了自己的身份,然后创建 CSR 请求;
但是不要忘记这个用户在我们不处理的情况下他没任何权限的,包括创建 CSR 请求;所以需要如下命令创建一个 ClusterRoleBinding,
将预设用户 kubelet-bootstrap 与内置的 ClusterRole system:node-bootstrapper 绑定到一起,使其能够发起 CSR 请求
kubectl create clusterrolebinding kubelet-bootstrap \
  --clusterrole=system:node-bootstrapper \
  --user=kubelet-bootstrap

这样基本就完成了认证和授权相关的配置,只需要把生成的  bootstrap.kubeconfig 分发到个node节点上

2.增加配置文件 

vim /etc/kubernetes/kubelet  

KUBELET_OPTS="--logtostderr=true \
--v=2 \
--hostname-override=k8s-node1 \
--bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \
--kubeconfig=/etc/kubernetes/kubelet.kubeconfig \
--cert-dir=/etc/kubernetes/ssl \
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google_containers/pause-amd64:3.1 \
--address=10.211.55.12 \
--hostname-override=k8s-node1 \
--rotate-certificates \
--cluster-dns=10.0.0.2 \
--cluster-domain=cluster.local \
--allow-privileged=true \
--fail-swap-on=false"

kubelet --help 可以查看相关参数 

参考文章:

https://www.jianshu.com/p/087895ba7d87

https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/

https://blog.frognew.com/2017/07/kubelet-production-config.html

最好按最新的官网去参考相应的参数 

几个重要参数说明:

ddress:API 
#监听地址,不能为 127.0.0.1,否则 kube-apiserver、heapster 等不能调用 kubelet 的 API;
readOnlyPort=0:
#关闭只读端口(默认 10255)
authentication.anonymous.enabled:
#设置为 false,不允许匿名访问 10250 端口;
authentication.x509.clientCAFile:
#指定签名客户端证书的 CA 证书,开启 HTTP 证书认证;
authentication.webhook.enabled=true:开启 HTTPs bearer token 认证;
#对于未通过 x509 证书和 webhook 认证的请求(kube-apiserver 或其他客户端),将被拒绝,提示 Unauthorized;
authroization.mode=Webhook:
#kubelet 使用 SubjectAccessReview API 查询 kube-apiserver 某 user、group 是否具有操作资源的权限(RBAC);
featureGates.RotateKubeletClientCertificate、featureGates.RotateKubeletServerCertificate:
#自动 rotate 证书,证书的有效期取决于 kube-controller-manager 的 --experimental-cluster-signing-duration 参数;
–cluster-dns 
#指定kubedns的Service IP(可以先分配,后续创建kubedns 服务时指定该IP)
–cluster-domain
#指定域名后缀,与上面的参数同时指定后才会生效;
–hostname-override 
#如果设置了kube-proxy也需要设置该选项,否则会出现找不到Node的情况;

--rotate-certificates

# kubelet 能够自动重载新证书

--cert-dir 
#管理员通过了CSR请求后,kubelet自动在–cert-dir目录创建证书和私钥文件(kubelet-client.crt和kubelet-client.key),然后写入–kubeconfig文件(自动创建 –kubeconfig指定的文件);
----hairpin-mode 
Kubelet 公开了一个 hairpin-mode 标志,如果 pod 试图访问它们自己的 Service VIP,
就可以让 Service 的 endpoints 重新负载到他们自己身上。hairpin-mode 标志必须设置为 hairpin-veth 或者 promiscuous-bridge。默认是promiscuous-bridge
参考文档:http://docs.kubernetes.org.cn/819.html
--pod-infra-container-image
Pod的pause镜像
3.启动脚本的配置

 vim /usr/lib/systemd/system/kubelet.service

[Unit]
Description=Kubernetes Kubelet
After=docker.service
Requires=docker.service
[Service]
EnvironmentFile=/etc/kubernetes/kubelet
ExecStart=/usr/bin/kubelet $KUBELET_OPTS
Restart=on-failure
KillMode=process
[Install]
WantedBy=multi-user.target
systemctl daemon-reload 
systemctl enable kubelet 
systemctl restart kubelet

 查看启动状态和日志,确保正常

4.在Master审批Node加入集群
kubelet 启动后使用 --bootstrap-kubeconfig 向 kube-apiserver 发送 CSR 请求,当这个 CSR 被 approve 后,kube-controller-manager 为 kubelet 创建 TLS 客户端证书、私钥和 --kubeletconfig 文件。
注意:kube-controller-manager 需要配置 --cluster-signing-cert-file 和 --cluster-signing-key-file 参数,才会为 TLS Bootstrap 创建证书和私钥。
节点的 csr 均处于 pending 状态;

此时kubelet的进程有,但是监听端口还未启动,需要进行下面步骤! 

在Master节点查看请求签名的Node: 
[root@k8s-master1 ssl]# kubectl get csr
NAME                                                   AGE     REQUESTOR           CONDITION
node-csr-TvW12euzSdw9mNF4ZSoXrw2tzuEvmuyvErpQX3LbKcA   8m26s   kubelet-bootstrap   Pending

node-csr-AxONIPr10EUclMcM2Ix0MPmjc_nLrlUoxxY6xL-S-ik               23s   kubelet-bootstrap   Pending 

可以手动或自动 approve CSR 请求。推荐使用自动的方式,因为从 v1.8 版本开始,可以自动轮转approve csr 后生成的证书 

1.手动approve csr请求
[root@k8s-master1 ~]# kubectl certificate approve  node-csr-TvW12euzSdw9mNF4ZSoXrw2tzuEvmuyvErpQX3LbKcA
certificatesigningrequest.certificates.k8s.io "node-csr-TvW12euzSdw9mNF4ZSoXrw2tzuEvmuyvErpQX3LbKcA" approved
查看 Approve 结果:
[root@k8s-master1 ~]# kubectl describe csr  node-csr-TvW12euzSdw9mNF4ZSoXrw2tzuEvmuyvErpQX3LbKcA
[root@k8s-master1 ssl]# kubectl get csr
NAME                                                   AGE   REQUESTOR           CONDITION
node-csr-AxONIPr10EUclMcM2Ix0MPmjc_nLrlUoxxY6xL-S-ik   23s   kubelet-bootstrap   Pending
node-csr-TvW12euzSdw9mNF4ZSoXrw2tzuEvmuyvErpQX3LbKcA   12m   kubelet-bootstrap   Approved,Issued
[root@k8s-master1 ssl]# kubectl get nodes
NAME        STATUS       ROLES    AGE     VERSION
k8s-node1   Ready        <none>    3d16h   v1.14.3
k8s-node2   NotReady    <none>   3d16h   v1.14.3

同理,可以把另一个节点加入

自动方式的配置可以参考下面的文章,这里不在演示了

https://www.orchome.com/1199

https://mritd.me/2018/01/07/kubernetes-tls-bootstrapping-note/  (这个链接没少发了,希望能认真看一次)

在查看服务相关的端口已经启动了

[root@k8s-master2 kubernetes]#  netstat -lnpt|grep kubelet
tcp        0      0 127.0.0.1:10248         0.0.0.0:*               LISTEN      27615/kubelet
tcp        0      0 127.0.0.1:34429         0.0.0.0:*               LISTEN      27615/kubelet
tcp6       0      0 :::10250                :::*                    LISTEN      27615/kubelet
tcp6       0      0 :::10255                :::*                    LISTEN      27615/kubelet

部署kube-proxy组件

kube-proxy 运行在所有node节点上,,它监听 apiserver 中 service 和 Endpoint 的变化情况,创建路由规则来进行服务负载均衡。
本文档讲解部署 kube-proxy 的部署,使用 ipvs 模式。

 1.创建kubeconfig文件

cd /etc/ssl/kubernetes/ 

kubectl config set-cluster kubernetes \
  --certificate-authority=./ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-proxy.kubeconfig

 

kubectl config set-credentials kube-proxy \
  --client-certificate=./kube-proxy.pem \
  --client-key=./kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig

 

kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

说明: 

指定该证书的 User 为 system:kube-proxy

预定义的clusterrolebinding system:node-proxier 将User system:kube-proxy 与 clusterrole system:node-proxier 绑定,

授予了调用 kube-apiserver Proxy 相关 API 的权限;

2.增加配置文件

vim /etc/kube-prxoy 

KUBE_PROXY_OPTS="--logtostderr=true \
--v=2 \
--hostname-override=k8s-node1 \
--cluster-cidr=10.0.0.0/24 \
--proxy-mode=ipvs \
--kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig"

参考文档:

https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/

参数说明: 

--hostname-override 使用该名字作为标识而不是实际的主机名需要和 kubelet 保持一致

--cluster-cidr 与api-server 保持一样 定义集群IP 范围

--proxy-mode 代理模式,这里用的是ipvs 

--kubeconfig   指定认证和授权的kubeconfig 文件

--healthz-port   配置健康检查服务的端口,0表示禁止 (default 10256)

因为上面的代理模式用到ipvs 所以,我需要确保系统安装了ipvs 相关的服务和模块

yum install ipvsadm ipset -y

modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr modprobe -- ip_vs_sh modprobe -- nf_conntrack_ipv4
yum install ipvsadm -y

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
[root@k8s-master2 kubernetes]# lsmod |egrep ip_vs
ip_vs_sh               12688  0
ip_vs_wrr              12697  0
ip_vs_rr               12600  4
ip_vs                 145497  10 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack          137239  7 ip_vs,nf_nat,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_ipv4
libcrc32c              12644  4 xfs,ip_vs,nf_nat,nf_conntrack

3.配置服务脚本

vim /usr/lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Proxy
After=network.target
[Service]
EnvironmentFile=-/etc/kubernetes/kube-proxy
ExecStart=/usr/bin/kube-proxy $KUBE_PROXY_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable kube-proxy
systemctl restart kube-proxy

查看服务状态和日志

journalctl -u kube-proxy 

[root@k8s-master2 kubernetes]# netstat -nulpt |egrep kube-proxy
tcp        0      0 127.0.0.1:10249         0.0.0.0:*               LISTEN      17047/kube-proxy
tcp6       0      0 :::10256                :::*                    LISTEN      17047/kube-proxy

4. 查看ipvs 规则是否创建

ipvsadm -Ln  

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.1:443 rr
  -> 10.211.55.11:6443            Masq    1      1          0
  -> 10.211.55.12:6443            Masq    1      0          0
  -> 10.211.55.13:6443            Masq    1      0          0

可见将所有到 kubernetes cluster ip 443 端口的请求都转发到 kube-apiserver 的 6443 端口。

恭喜!至此node节点部署完成。

这样可以测试一下,因为我们部署完集群,又少一个DNS 来发现服务,所以这里部署一个coreDNS

按官网推荐方式安装,其他组件或者插件都在这个

https://github.com/kubernetes/kubernetes/tree/master/cluster/addons

coredns

https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns/coredns

wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/coredns/coredns.yaml.base

说明一下

镜像可以通过国内阿里云下载,修改标签,或者更换镜像地址都可以,我这里推荐一个下载的地方

docker pull registry.cn-hangzhou.aliyuncs.com/openthings/k8s-gcr-io-coredns:1.3.1

docker tag   registry.cn-hangzhou.aliyuncs.com/openthings/k8s-gcr-io-coredns:1.3.1 k8s.gcr.io/coredns:1.3.1

我这里从dockerhup 下载一个最新的镜像来使用 

 

  containers:
      - name: coredns
        image: coredns/coredns
        imagePullPolicy: IfNotPresent

接下来是需要 修改里面的变量,换成实际的值
kubernetes __PILLAR__DNS__DOMAIN__ in-addr.arpa ip6.arpa  
修改成
kubernetes cluster.local in-addr.arpa ip6.arpa 
memory: __PILLAR__DNS__MEMORY__LIMIT__
按实际情况修改
memory:500M
clusterIP: __PILLAR__DNS__SERVER__
修改成你在kubelet里面定义的DNS 
clusterIP: 10.0.0.2
是deploy 部署,默认是一个POD,所以根据实际情况修改
# replicas: not specified here:   
# 1. In order to make Addon Manager do not reconcile this replicas parameter.  
# 2. Default is 1.   
# 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on. 
replicas: 2
kubectl apply -f coredns.yaml
默认所以的资源都在kube-system名称空间里面,通过yaml 文件也可以看到
[root@k8s-master1 k8s]# kubectl get all -n kube-system
 NAME                           READY   STATUS    RESTARTS   AGE 
pod/coredns-5b8d7c984b-5bvbd   1/1     Running   1            3m 
pod/coredns-5b8d7c984b-hm5q7   1/1     Running   1            3m  
NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE 
service/kube-dns   ClusterIP   10.0.0.2     <none>        53/UDP,53/TCP,9153/TCP    3m  
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE 
deployment.apps/coredns   2/2     2            2           5h53m 
NAME                                 DESIRED   CURRENT   READY   AGE 
replicaset.apps/coredns-5b8d7c984b   2         2         2       3m
可以看到cluster-ip 是10.0.0.2 满足之前的需求
测试一下:
下面编写了一个nginx web 测试案例  

vim nginx-web.yaml 

apiVersion: v1
kind: Service
metadata:
  name: nginx-web
  labels:
    tier: frontend
spec:
  type: NodePort
  selector:
    tier: frontend
  ports:
  - name: http
    port: 80
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
     tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
     containers:
     - name: nginx
       image: nginx
       ports:
       - name: http
         containerPort: 80
[root@k8s-master1 k8s]# kubectl get svc |egrep nginx 
nginx-web    NodePort    10.0.0.15    <none>        80:18401/TCP   11m
[root@k8s-master1 k8s]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP            NODE        NOMINATED NODE   READINESS GATES
nginx-8448bb446d-2q55w   1/1     Running   0          8m30s   172.17.69.3   k8s-node2   <none>           <none>
nginx-8448bb446d-h2km5   1/1     Running   0          8m30s   172.17.51.3   k8s-node1   <none>           <none>
nginx-8448bb446d-vwkg8   1/1     Running   0          8m30s   172.17.51.4   k8s-node1   <none>           <none>
[root@k8s-master1 k8s]# kubectl get ep nginx-web
NAME        ENDPOINTS                                      AGE
nginx-web   172.17.51.3:80,172.17.51.4:80,172.17.69.3:80   12m

测试

[root@k8s-master1 ~]# curl 10.0.0.15
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

我们这里借助DNS 来实现名称访问

启动一个测试pod

[root@k8s-master1 k8s]# kubectl run cirror-$RANDOM --rm -it --image=cirros -- /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # cat /etc/resolv.conf
nameserver 10.0.0.2
search default.svc.cluster.local. svc.cluster.local. cluster.local. localdomain
options ndots:5
/ # nslookup nginx-web

 

Server:    10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
Name:      nginx-web
Address 1: 10.0.0.15 nginx-web.default.svc.cluster.local

成功解析出IP 

/ # curl nginx-web
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
说明各Pod可以通过DNS 来解析服务名称了

总结一下:

如果在kubelet 里面配置 --anonymous-auth=false然后在master 完成csr以后报错

failed to run Kubelet: No authentication method configured  

具体需要理解kubelet 的认证和授权:

kubelet 与 kube-apiserver 之间的通信是双向的, kubelet 既需要访问 kube-apiserver 获取分配到自己节点上的 pod 信息, kube-apiserver 也需要主动访问 kubelet 拉取日志, 状态, 监控数据等信息, 所以对两个组件来说, 认证是双向的, kube-apiserver 需要持有 kubelet 的客户端证书, 以完成 kubelet 对自己身份的校验; kubelet 也需要持有 kube-apiserver 的客户端证书, 完成 kube-apiserver 对自己身份的认证.

默认情况下, 对 kubelet 的 https 请求, 如果没有被配置的其他身份验证拒绝的话, 则被视为匿名请求, 并为这个请求赋予system:anonymous用户名和system:unauthenticated用户组

如需要禁用匿名访问, 可以在启动 kubelet Daemon 时加入--anonymous-auth=false配置, 当有匿名访问时, 将回复401 Unauthorized响应未认证的请求

  • kubelet 启动时添加--client-ca-file参数, 并指定签发客户端证书的 ca 根证书所在路径
  • kube-apiserver 启动时添加--kubelet-client-certificate--kubelet-client-key参数, 并分别为其指定由 kubelet ca 根证书签发的客户端证书和秘钥

任何被成功认证的请求(包括匿名请求)都将被授权. 默认的授权模式为AlwaysAllow, 即允许所有类型的请求

  • 匿名访问启用时, 应限制其调用 kubelet API 的能力
  • 客户端证书身份认证启用时, 只允许配置 CA 签名的客户端证书使用 kubelet API
  • 确保authorization.k8s.io/v1beta1该 API Group 在 kube-apiserver 中是被启动的状态
  • 在 kubelet Daemon 启动参数中, 确保配置了--authorization-mode=Webhook--kubeconfig两个参数

kubelet 在接收到每个请求后, 会向指定的 kube-apiserver 发起 SubjectAccessReview API 的请求, 来确定该请求是否被允许

相关文档:

https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/ 

https://jimmysong.io/kubernetes-handbook/guide/kubelet-authentication-authorization.html

https://www.orchome.com/1199 

转载于:https://www.cnblogs.com/centos-python/articles/11049426.html

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐