k8s學習筆記-Node節點的部署和CoreDNS的部署


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 \

--feature-gates=RotateKubeletServerCertificate=true \
--feature-gates=RotateKubeletClientCertificate=true \

--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.cnblogs.com/centos-python/articles/13168559.html (后面補發的文章)

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
modprobe br_netfilter
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 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM