目錄
- 1. kubernetes創(chuàng)建跟證書(shū)和秘鑰
- 2. ETCD集群部署及維護(hù)
- 3. kubectl部署以及基本使用
- 4. Master節(jié)點(diǎn)部署及維護(hù)
- 5. Node節(jié)點(diǎn)部署及維護(hù)
kubelet 運(yùn)行在每個(gè) worker 節(jié)點(diǎn)上讳苦,接收 kube-apiserver 發(fā)送的請(qǐng)求昼扛,管理 Pod 容器,執(zhí)行交互式命令赏迟,如 exec轻掩、run、logs 等。
kubelet 啟動(dòng)時(shí)自動(dòng)向 kube-apiserver 注冊(cè)節(jié)點(diǎn)信息
為確保安全贮匕,部署時(shí)關(guān)閉了 kubelet 的非安全 http 端口,對(duì)請(qǐng)求進(jìn)行認(rèn)證和授權(quán)绰播,拒絕未授權(quán)的訪問(wèn)(如 apiserver骄噪、heapster 的請(qǐng)求)。
部署策略:
- 動(dòng)態(tài)創(chuàng)建 bootstrap token蠢箩,而不是在 apiserver 中靜態(tài)配置链蕊;
- 使用 TLS bootstrap 機(jī)制自動(dòng)生成 client 和 server 證書(shū),過(guò)期后自動(dòng)輪轉(zhuǎn)谬泌;
- 在 KubeletConfiguration 類型的 yaml 文件配置主要參數(shù)滔韵;
- 關(guān)閉只讀端口,在安全端口 10250 接收 https 請(qǐng)求掌实,對(duì)請(qǐng)求進(jìn)行認(rèn)證和授權(quán)陪蜻,拒絕匿名訪問(wèn)和非授權(quán)訪問(wèn);
- 使用 kubeconfig 訪問(wèn) apiserver 的安全端口贱鼻;
部署軟件規(guī)劃:
IP | 部署軟件包 |
---|---|
10.40.61.116 | kubelet |
10.40.58.153 | kubelet |
10.40.58.154 | kubelet |
01.創(chuàng)建 Bootstrapping Token
Token可以是任意的包含128 bit的字符串宴卖,可以使用安全的隨機(jī)數(shù)發(fā)生器生成。
export BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')
cat > bootstrap-token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
注意:在進(jìn)行后續(xù)操作前請(qǐng)檢查 bootstrap-token.csv 文件邻悬,確認(rèn)其中的 ${BOOTSTRAP_TOKEN} 環(huán)境變量已經(jīng)被真實(shí)的值替換症昏。
kube-apiserver啟動(dòng)時(shí)需要使用--token-auth-file=bootstrap-token.csv
如果后續(xù)重新生成了 BOOTSTRAP_TOKEN,則需要:
- 更新 bootstrap-token.csv 文件父丰,分發(fā)到所有機(jī)器 (master 和 node)的 /etc/kubernetes/ 目錄下肝谭,分發(fā)到node節(jié)點(diǎn)上非必需;
- 重新生成 bootstrap.kubeconfig 文件蛾扇,分發(fā)到所有 node 機(jī)器的 /etc/kubernetes/ 目錄下攘烛;
- 重啟 kube-apiserver 和 kubelet 進(jìn)程;
- 重新 approve kubelet 的 csr 請(qǐng)求屁桑;
02.創(chuàng)建 bootstrap kubeconfig 文件
執(zhí)行下面的命令時(shí)需要先安裝kubectl命令医寿,請(qǐng)參考安裝kubectl命令行工具。
--embed-certs
為 true 時(shí)表示將 certificate-authority 證書(shū)寫入到生成的 bootstrap.kubeconfig 文件中蘑斧;-
設(shè)置客戶端認(rèn)證參數(shù)時(shí)沒(méi)有指定秘鑰和證書(shū)靖秩,后續(xù)由 kube-apiserver 自動(dòng)生成;
export KUBE_APISERVER="https://apiserver-p001.svc.gxd88.cn:6443"
-
設(shè)置集群參數(shù)
kubectl config set-cluster kubernetes \ --certificate-authority=ca.pem \ --embed-certs=true \ --server=${KUBE_APISERVER} \ --kubeconfig=bootstrap.kubeconfig
-
設(shè)置客戶端認(rèn)證參數(shù)
kubectl config set-credentials kubelet-bootstrap \ --token=${BOOTSTRAP_TOKEN} \ --kubeconfig=bootstrap.kubeconfig
-
設(shè)置上下文參數(shù)
kubectl config set-context default \ --cluster=kubernetes \ --user=kubelet-bootstrap \ --kubeconfig=bootstrap.kubeconfig
-
設(shè)置默認(rèn)上下文
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
- 分發(fā) kubeconfig 文件
將兩個(gè) kubeconfig 文件分發(fā)到所有 Node 機(jī)器的 /srv/kubernetes/kubeconfig 目錄
cp bootstrap.kubeconfig /srv/kubernetes/kubeconfig
03.維護(hù)配置文件
新版本的kubelet很多參數(shù)已經(jīng)廢棄只能通過(guò)創(chuàng)建單獨(dú)的配置文件方式維護(hù), 啟動(dòng)程序時(shí)使用--config
根據(jù)主機(jī)的實(shí)際情況替換address
和healthzBindAddress
cat > /srv/kubernetes/conf/kubelet-config.yaml <<EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: "10.40.61.116"
staticPodPath: ""
syncFrequency: 1m
fileCheckFrequency: 20s
httpCheckFrequency: 20s
staticPodURL: ""
port: 10250
readOnlyPort: 0
rotateCertificates: true
serverTLSBootstrap: true
authentication:
anonymous:
enabled: false
webhook:
enabled: true
x509:
clientCAFile: "/srv/kubernetes/pki/ca.pem"
authorization:
mode: Webhook
registryPullQPS: 0
registryBurst: 20
eventRecordQPS: 0
eventBurst: 20
enableDebuggingHandlers: true
enableContentionProfiling: true
healthzPort: 10248
healthzBindAddress: "10.40.61.116"
clusterDomain: "cluster.local"
clusterDNS:
- "10.244.0.10"
nodeStatusUpdateFrequency: 10s
nodeStatusReportFrequency: 1m
imageMinimumGCAge: 2m
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
volumeStatsAggPeriod: 1m
kubeletCgroups: ""
systemCgroups: ""
cgroupRoot: ""
cgroupsPerQOS: true
cgroupDriver: cgroupfs
runtimeRequestTimeout: 10m
hairpinMode: promiscuous-bridge
maxPods: 220
podCIDR: "10.243.0.0/16"
podPidsLimit: -1
resolvConf: /etc/resolv.conf
maxOpenFiles: 1000000
kubeAPIQPS: 1000
kubeAPIBurst: 2000
serializeImagePulls: false
evictionHard:
memory.available: "100Mi"
nodefs.available: "10%"
nodefs.inodesFree: "5%"
imagefs.available: "15%"
evictionSoft: {}
enableControllerAttachDetach: true
failSwapOn: true
containerLogMaxSize: 20Mi
containerLogMaxFiles: 10
systemReserved: {}
kubeReserved: {}
systemReservedCgroup: ""
kubeReservedCgroup: ""
enforceNodeAllocatable: ["pods"]
EOF
authentication.anonymous.enabled
: 設(shè)置為 false竖瘾,不允許匿名訪問(wèn) 10250 端口沟突;
authentication.x509.clientCAFile
: 指定簽名客戶端證書(shū)的 CA 證書(shū),開(kāi)啟 HTTPs 證書(shū)認(rèn)證捕传;
authentication.webhook.enabled=true
: 開(kāi)啟 HTTPs bearer token 認(rèn)證惠拭。
04.使用systemd管理kubelet
根據(jù)實(shí)際情況替換--hostname-override
, 并且kube-proxy配置的過(guò)程中也需要指定該參數(shù)
cat > /etc/systemd/system/kubelet.service <<EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
[Service]
ExecStart=/srv/kubernetes/bin/kubelet \\
--bootstrap-kubeconfig=/srv/kubernetes/kubeconfig/bootstrap.kubeconfig \\
--cert-dir=/srv/kubernetes/pki \\
--kubeconfig=/srv/kubernetes/kubeconfig/kubelet.kubeconfig \\
--config=/srv/kubernetes/conf/kubelet-config.yaml \\
--hostname-override=py-modelo2o08cn-p005.pek3.example.net \\
--pod-infra-container-image=wcr.example.net/wekube/acs/pause-amd64:3.1 \\
--image-pull-progress-deadline=15m \\
--logtostderr=true \\
--v=2 \\
--log-dir=/srv/kubernetes/log
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
EOF
- 如果設(shè)置了 --hostname-override 選項(xiàng),則 kube-proxy 也需要設(shè)置該選項(xiàng),否則會(huì)出現(xiàn)找不到 Node 的情況职辅;
- --bootstrap-kubeconfig:指向 bootstrap kubeconfig 文件棒呛,kubelet 使用該文件中的用戶名和 token 向 kube-apiserver 發(fā)送 TLS Bootstrapping 請(qǐng)求;
- K8S approve kubelet 的 csr 請(qǐng)求后域携,在 --cert-dir 目錄創(chuàng)建證書(shū)和私鑰文件簇秒,然后寫入 --kubeconfig 文件;
注意:kube-controller-manager 需要配置
--cluster-signing-cert-file
和--cluster-signing-key-file
參數(shù)秀鞭,才會(huì)為 TLS Bootstrap 創(chuàng)建證書(shū)和私鑰趋观。
05.啟動(dòng)/停止 kubelet
sudo /bin/systemctl daemon-reload
sudo /bin/systemctl enable kubelet.service
kube-schedulercan be started and stopped as follows:
sudo systemctl start kubelet.service
sudo systemctl stop kubelet.service
06.驗(yàn)證
0601.授權(quán)
kubelet 首次啟動(dòng)時(shí)向 kube-apiserver 發(fā)送證書(shū)簽名請(qǐng)求,必須通過(guò)后 kubernetes 系統(tǒng)才會(huì)將該 Node 加入到集群锋边。
啟動(dòng)時(shí)會(huì)查找--kubeletconfig參數(shù)對(duì)應(yīng)的文件是否存在皱坛,如果不存在則使用 --bootstrap-kubeconfig 指定的 kubeconfig 文件向 kube-apiserver 發(fā)送證書(shū)簽名請(qǐng)求 (CSR)。
kube-apiserver
收到 CSR 請(qǐng)求后豆巨,對(duì)其中的 Token 進(jìn)行認(rèn)證剩辟,認(rèn)證通過(guò)后將請(qǐng)求的 user 設(shè)置為 kubelet-bootstrap:<Token ID>,user 設(shè)置為 user=kubelet-bootstrap搀矫,這一過(guò)程稱為 Bootstrap Token Auth抹沪。
kubelet 創(chuàng)建 CSR 請(qǐng)求后,下一步需要?jiǎng)?chuàng)建被 approve瓤球,有兩種方式:
- kube-controller-manager 自動(dòng) aprrove融欧;
- 手動(dòng)使用命令 kubectl certificate approve;
CSR 被 approve 后卦羡,kubelet 向 kube-controller-manager 請(qǐng)求創(chuàng)建 client 證書(shū)噪馏,kube-controller-manager 中的 csr approving controller 使用 SubjectAccessReview API 來(lái)檢查 kubelet 請(qǐng)求(對(duì)應(yīng)的 User 是 kubelet-bootstrap)是否具有相應(yīng)的權(quán)限。
默認(rèn)情況下绿饵,這個(gè) user 沒(méi)有創(chuàng)建 CSR 的權(quán)限欠肾,因此 kubelet 會(huì)啟動(dòng)失敗,可通過(guò)如下方式創(chuàng)建一個(gè) clusterrolebinding拟赊,將 user kubelet-bootstrap 和 clusterrole system:node-bootstrapper 綁定刺桃。
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap
注意:
--user=kubelet-bootstrap 是在 [創(chuàng)建 TLS Bootstrapping Token](#創(chuàng)建 TLS Bootstrapping Token) 章節(jié)中bootstrap-token.csv
文件中指定的用戶名,bootstrap-token.csv
同時(shí)也寫入了 bootstrap.kubeconfig 文件
0602.查看kubelet服務(wù)
$ systemctl status kubelet|grep active
Active: active (running) since 四 2020-04-16 16:25:45 CST; 1 day 22h ago
0603.查看端口
netstat -lnpt|grep kubelet
tcp 0 0 10.40.61.116:10248 0.0.0.0:* LISTEN 27496/kubelet
tcp 0 0 10.40.61.116:10250 0.0.0.0:* LISTEN 27496/kubelet
tcp 0 0 127.0.0.1:37325 0.0.0.0:* LISTEN 27496/kubelet
- 10248: healthz http 服務(wù)吸祟;
- 10250: https 服務(wù)瑟慈,訪問(wèn)該端口時(shí)需要認(rèn)證和授權(quán)(即使訪問(wèn) /healthz 也需要);
- 未開(kāi)啟只讀端口 10255屋匕;
07.允許approve CSR 請(qǐng)求葛碧,生成 kubelet client 證書(shū)
如果覺(jué)的手動(dòng)允許approve麻煩可以直接配置自動(dòng)approve
0701.手動(dòng)允許approve CSR
查看未授權(quán)的 CSR 請(qǐng)求:
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR CONDITION
csr-fsk6w 21s kubernetes.io/kubelet-serving system:node:py-modelo2o08cn-p005.pek3.example.net Pending
通過(guò) CSR 請(qǐng)求:
$ kubectl certificate approve csr-fsk6w
certificatesigningrequest "csr-2b308" approved
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
py-modelo2o08cn-p005.pek3.example.net Ready <none> 74m v1.18.1
自動(dòng)生成了 kubelet kubeconfig 文件和公私鑰:
$ ls -l /srv/kubernetes/kubeconfig/kubelet.kubeconfig
-rw------- 1 root root 2326 4月 15 12:23 kubeconfig/kubelet.kubeconfig
$ ls -al /srv/kubernetes/pki/kubelet*
-rw------- 1 root root 1265 4月 15 12:23 /srv/kubernetes/pki/kubelet-client-2020-04-15-12-23-43.pem
lrwxrwxrwx 1 root root 58 4月 15 12:23 /srv/kubernetes/pki/kubelet-client-current.pem -> /srv/kubernetes/pki/kubelet-client-2020-04-15-12-23-43.pem
-rw-r--r-- 1 root root 2355 4月 14 15:38 /srv/kubernetes/pki/kubelet.crt
-rw------- 1 root root 1675 4月 14 15:38 /srv/kubernetes/pki/kubelet.key
-rw------- 1 root root 1342 4月 15 13:37 /srv/kubernetes/pki/kubelet-server-2020-04-15-13-37-56.pem
lrwxrwxrwx 1 root root 58 4月 15 13:37 /srv/kubernetes/pki/kubelet-server-current.pem -> /srv/kubernetes/pki/kubelet-server-2020-04-15-13-37-56.pem
0702.自動(dòng)approve
創(chuàng)建三個(gè) ClusterRoleBinding,分別用于自動(dòng) approve client过吻、renew client 證書(shū)进泼。
根據(jù)官方文檔介紹 renew server證書(shū)基于安全的考慮要自己實(shí)現(xiàn)controller
Note: The CSR approving controllers implemented in core Kubernetes do not approve node serving certificates for security reasons. To use RotateKubeletServerCertificate operators need to run a custom approving controller, or manually approve the serving certificate requests.
$ cat > csr-crb.yaml <<EOF
# Approve all CSRs for the group "system:bootstrappers"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: auto-approve-csrs-for-group
subjects:
- kind: Group
name: system:kubelet-bootstrap
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
apiGroup: rbac.authorization.k8s.io
---
# Approve renewal CSRs for the group "system:nodes"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: auto-approve-renewals-for-nodes
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
EOF
auto-approve-csrs-for-group:自動(dòng) approve node 的第一次 CSR; 注意第一次 CSR 時(shí),請(qǐng)求的 Group 為 system:kubelet-bootstrap乳绕;
auto-approve-renewals-for-nodes:自動(dòng) approve node 后續(xù)過(guò)期的 client 證書(shū)绞惦,自動(dòng)生成的證書(shū) Group 為 system:nodes;
創(chuàng)建資源:
kubectl apply -f csr-crb.yaml
08.授予 kube-apiserver 訪問(wèn) kubelet API 的權(quán)限
因?yàn)閗ubelet啟動(dòng)時(shí)已經(jīng)關(guān)閉了anonymous認(rèn)證, 指定了authentication.x509.clientCAFile
證書(shū)認(rèn)證, 并且kube-apiserver中使用--kubelet-client-certificate和--kubelet-client-key標(biāo)志啟動(dòng)apiserver洋措, 所以需要進(jìn)行對(duì)應(yīng)的授權(quán)
kube-apiserver 的啟動(dòng)參數(shù)如下
/srv/kubernetes/bin/kube-apiserver \
--kubelet-https=true \
--kubelet-client-certificate=/srv/kubernetes/pki/apiserver.pem \
--kubelet-client-key=/srv/kubernetes/pki/apiserver-key.pem
apiserver.pem 中的CN為kubernetes翩隧,所以需要對(duì)該用戶授權(quán)訪問(wèn)kubelet資源的授權(quán)
- verb=*, resource=nodes, subresource=proxy
- verb=*, resource=nodes, subresource=stats
- verb=*, resource=nodes, subresource=log
- verb=*, resource=nodes, subresource=spec
- verb=*, resource=nodes, subresource=metrics
授權(quán)指令
$ kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes
如果不授權(quán)會(huì)報(bào)如下錯(cuò)誤
kubectl logs kubernetes-dashboard-7c4995887f-zt4rp -n kube-system
Error from server (Forbidden): Forbidden (user=kubernetes, verb=get, resource=nodes, subresource=proxy) ( pods/log kubernetes-dashboard-7c4995887f-zt4rp)
更多細(xì)節(jié)請(qǐng)看https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/#kubelet-authentication
09.控制證書(shū)輪轉(zhuǎn)時(shí)間
由于kubelet的證書(shū)是kube-controller-manager負(fù)責(zé)簽發(fā)的, 在kube-controller-manager啟動(dòng)參數(shù)中添加如下配置:
/srv/kubernetes/bin/kube-controller-manager \
--experimental-cluster-signing-duration=24h0m0s
默認(rèn)時(shí)間為8760h0m0s也就是1年
09.Q&A
Q:
遇到了一個(gè)大坑呻纹, 我查看了大量的bootstrap TLS 相關(guān)的文檔, 文檔上大部分的都是說(shuō)使用bootstrap kubeconfig
自動(dòng)的簽名node節(jié)點(diǎn)的證書(shū)专缠,又根據(jù)文檔查看說(shuō)如果不指定--kubeconfig會(huì)自動(dòng)使用bootstrap kubeconfig的APIserver地址雷酪, 但是一直報(bào)錯(cuò)
server.go:560] standalone mode, no API client
A:
啟動(dòng)的時(shí)候要指定--bootstrap-kubeconfig
, 也要指定--kubeconfig
, 這里的--kubeconfig是指證書(shū)生成以后自動(dòng)生成的kubelet.kubeconfig的目錄
Q:
failed to run Kubelet: cannot create certificate signing request: certificatesigningrequests.certificates.k8s.io is forbidden: User "kubelet-bootstrap" cannot create resource "certificatesigningrequests" in API group "certificates.k8s.io" at the cluster scope
A:
kubelet 啟動(dòng)時(shí)向 kube-apiserver 發(fā)送 TLS bootstrapping 請(qǐng)求涝婉,需要先將 bootstrap token 文件中的 kubelet-bootstrap 用戶賦予 system:node-bootstrapper cluster 角色(role)哥力, 然后 kubelet 才能有權(quán)限創(chuàng)建認(rèn)證請(qǐng)求(certificate signing requests):kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper
--user=kubelet-bootstrap
Q:
因?yàn)槲覜](méi)有安裝cni-plugin, 所以我沒(méi)有指定cni相關(guān)的配置墩弯, worker幾點(diǎn)一直是NotReady的狀態(tài)吩跋, 但是查看官方文檔說(shuō)kubelet存在默認(rèn)的docker網(wǎng)絡(luò)插件, 我使用的就是docker渔工, 那么問(wèn)題出現(xiàn)在那里呢锌钮?
kubelet: E0415 12:24:19.385879 22377 kubelet.go:2187] Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
kubelet: W0415 12:24:23.101522 22377 cni.go:237] Unable to update cni config: no networks found in /srv/kubernetes/cni/net.d
A:
經(jīng)過(guò)萬(wàn)能的--help
查看, 他是這么說(shuō)的
--network-plugin string <Warning: Alpha feature> The name of the network plugin to be invoked for various events in kubelet/pod lifecycle. This docker-specific flag only works when container-runtime is set to docker.
但是又看--help人家說(shuō)container-runtime默認(rèn)就是docker引矩, 情急之下刪除了所有cni相關(guān)的配置梁丘, 發(fā)現(xiàn)居然起來(lái)了, 那看來(lái)就是這樣了
Q:
查看kubelet日志報(bào)如下的錯(cuò)誤
kubelet: E0512 13:20:08.674812 17205 controller.go:178] failed to update node lease, error: Operation cannot be fulfilled on leases.coordination.k8s.io "py-modelo2o08cn-p005.pek3.wecash.net": the object has been modified; please apply your changes to the latest version and try again
A:
報(bào)錯(cuò)的主要原因是--hostname-override=py-modelo2o08cn-p005.pek3.wecash.net
三個(gè)節(jié)點(diǎn)配置的相同旺韭, 需要清理rm -rf kubelet-*
證書(shū)文件和rm -rf kubelet.kubeconfig
文件