Kubernetes相關的問題彙總
1. 設定系統引數 – 允許路由轉發,不對bridge的資料進行處理
- net.bridge.bridge-nf-call-ip6tables=1
- net.bridge.bridge-nf-call-iptables=1
- net.ipv4.ip_forward=1
- vm.swappiness=0
2. 設定iptables的FORWARD鏈,Docker從1.13版本開始調整了預設的防火牆規則,禁用了iptables filter表中FOWARD鏈,這樣會引起Kubernetes叢集中跨Node的Pod無法通訊。
- iptables -P FORWARD ACCEPT
- iptables -nvL #檢視命令
3. Kubernetes 1.8開始要求關閉系統的Swap,如果不關閉,預設配置下kubelet將無法啟動。可以通過kubelet的啟動引數--fail-swap-on=false更改這個限制。
- swapoff -a
- free -mh #檢視命令
4. 通過kubectl命令獲取secret,以及token,用於登入dashboard UI,基於RBAC(基於角色的訪問控制)見附錄
- kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin | awk '{print $1}')
#關鍵字根據你建立的create來,比如admin,dashboard
原理:建立一個ServiceAccount,並將該SA繫結到cluster-admin這個ClusterRole角色上,就擁有了該角色的許可權,而這個角色擁有整個叢集的所有許可權。
#這裡還涉及一個https訪問的問題,需要在master節點(這裡要求dashboard部署在master節點上)生成自簽名的證書,然後在kubernetes-dashboard.yaml檔案中修改:
volumes: - name: kubernetes-dashboard-certs hostPath: path: /usr/share/certs type: Directory
自簽名的步驟如下:
openssl genrsa -des3 -passout pass:x -out dashboard.pass.key 2048 openssl rsa -passin pass:x -in dashboard.pass.key -out dashboard.key rm dashboard.pass.key openssl req -new -key dashboard.key -out dashboard.csr openssl x509 -req -sha256 -days 365 -in dashboard.csr -signkey dashboard.key -out dashboard.crt #將dashboard.key dashboard.crt拷貝至/usr/share/certs目錄即可。
5. 通過kubeadm init命令建立叢集之後,會報錯http://localhost:10255/healthz出錯,發現是kubelet服務沒有啟動
需要建立kubelet.service.d目錄,並在其下建立10-kubeadm.conf檔案,內容如下:
[Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true" Environment="KUBELET_NETWORK_ARGS=--network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin" Environment="KUBELET_DNS_ARGS=--cluster-dns=10.96.0.10 --cluster-domain=cluster.local" Environment="KUBELET_AUTHZ_ARGS=--authorization-mode=Webhook --client-ca-file=/etc/kubernetes/pki/ca.crt" # Value should match Docker daemon settings. # Defaults are "cgroupfs" for Debian/Ubuntu/OpenSUSE and "systemd" for Fedora/CentOS/RHEL Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=cgroupfs" Environment="KUBELET_CADVISOR_ARGS=--cadvisor-port=0" Environment="KUBELET_CERTIFICATE_ARGS=--rotate-certificates=true" ExecStart= ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_SYSTEM_PODS_ARGS $KUBELET_NETWORK_ARGS $KUBELET_DNS_ARGS $KUBELET_AUTHZ_ARGS $KUBELET_CGROUP_ARGS $KUBELET_CADVISOR_ARGS $KUBELET_CERTIFICATE_ARGS $KUBELET_EXTRA_ARGS
這裡也可以直接通過命令從github上下載
curl -O "https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.0/build/debs/kubelet.service" #注意/usr/bin/kubelet路徑問題
再建立kubelet.service.d目錄,並從github上下載
curl -O "https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.0/build/debs/10-kubeadm.conf"
6. 叢集部署成功之後,傳送kubectl命令還是無法獲取叢集資訊,這裡需要export KUBECONFIG引數
為了簡化,可以寫在/etc/profile,並執行source /etc/profile使其生效,注意:master節點和node節點採用不一樣的配置檔案,許可權不一樣。
# master節點上 export KUBECONFIG=/etc/kubernetes/admin.conf # node節點上 export KUBECONFIG=/etc/kubernetes/kubelet.conf
7. kubectl proxy命令目前來說,使用的場景是,自動化部署指令碼中,需要遠端部署Pod至Kubernetes叢集,因為需要http訪問,繞過https。
kubectl proxy --address='0.0.0.0' --port=8080 --accept-hosts='^*$'
這樣在shell指令碼中才可以執行:kubectl -s http://masterIp:8080 apply -f *.yaml
8. 通過kubeadm token命令生成一個forever的token,預設的24h,利於後續join新的節點到叢集。
kubeadm token create --ttl=0
kubeadm join masterIp:6443 --token bhpmca.yz08394xcolahg0y --discovery-token-ca-cert-hash sha256:f2d058d7f6489dd71aba1c780adf4e7e24663a6db54e7e1fbc3ca079f616bd92
另外,如果忘記了sha256,這裡也提供一個查詢方法,如下:
#獲取master上的ca.crt證書sha256編碼hash值 openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
9. 叢集清理命令
# 刪除節點 kubectl drain nodeName --delete-local-data --force --ignore-daemonsets kubectl delete node nodeName # 清理 kubeadm reset ifconfig cni0 down ip link delete cni0 ifconfig flannel.1 down ip link delete flannel.1 rm -rf /var/lib/cni/ rm -rf /etc/kubernetes/ systemctl stop kubelet; docker rm -f -v $(docker ps -q); find /var/lib/kubelet | xargs -n 1 findmnt -n -t tmpfs -o TARGET -T | uniq | xargs -r umount -v; rm -rf /var/lib/kubelet /var/lib/etcd; # 記住要清理iptables iptables -FXZ
10. 通過java -jar啟動jar包專案時,出現服務發現失敗的問題
比如在專案的rabbitmq.properties檔案中定義了Kubernetes的serviceName來訪問節點
但是如果是直接server.host=rabbitmq,程式中訪問失敗,但是檢視dns,ping服務名ip顯示都是正常
root@node:~/k8s# cat /etc/resolv.conf nameserver 10.96.0.10 search default.svc.cluster.local svc.cluster.local cluster.local options ndots:5 root@node:~/k8s# ping rabbitmq PING rabbitmq.default.svc.cluster.local (10.109.82.27): 56 data bytes
最終,通過server.host=rabbitmq .default ,則訪問正常,見附錄2。
11. 通過netstat -npt | grep 30039 | wc -l檢視埠連線個數
- apt-get install -y net-tools
- netstat -anopt|grep 30039|wc -l
12. Node的隔離與恢復
- kubectl replace -f unschedule_node.yaml
apiVersion: v1 kind: Node metadata: name: masterNodename labels: xx.com/hostname: masterNodename spec: unschedulable: true
- kubectl patch node nodeName -p '{"spec":{"unschedulable":true}}'
- 將某個Node脫離排程範圍時,在其上執行的Pod並不會自動停止,管理員需要手動停止在該Node上執行的Pod
13. Node設定標籤,將Pod排程指定Node
- kubectl label nodes nodeName zone=north
- kubectl label nodes nodeName disktype=ssd
- kubectl get node --show-labels #檢視節點label
-
Pod/Deployment的spec.spec.nodeSelector #指定將此 Pod 部署到具有 label
key=value
的 Node 上 - 注意: 如果指定Pod的nodeSelector條件,且叢集中不存在包含相應標籤的Node時,即使還有其他可供排程的Node,這個Pod也最終會排程失敗
14. 應用的滾動升級
- Kubernetes提供了rolling-update(滾動升級),解決服務需要先全部停止然後逐步升級的方式導致的較長時間的服務不可用情況
- 滾動升級通過執行kubectl rolling-update命令一鍵完成,該命令建立了一個新的RC,然後自動控制舊的RC中的Pod副本數量逐漸減少到0,同時新的RC中的Pod副本數量從0逐步增加到目標值,最終實現了Pod的升級。需要注意的是,系統要求新的RC需要與舊的RC在相同的名稱空間(Namespace)內,即不能把別人的資產偷偷轉移到自家名下
- 以redis-master為例,假設當前執行的redis-master Pod是1.0版本,則現在需要升級到2.0版本
- RC的名字(name)不能與舊的RC的名字相同
- 在selector中應至少有一個Label與舊的RC的Label不同,以標識其為新的RC,例如:version: v2
- kubectl rolling-update redis-master -f redis-master-controller-v2.yaml
- 等所有新的Pod啟動完成後,舊的Pod也被全部銷燬,這樣就完成了容器叢集的更新。
- 直接用kubectl rolling-update命令,加上--image引數指定新版映象名稱來完成Pod的滾動升級
- 執行的結果是舊的RC被刪除,新的RC仍將使用舊的RC的名字
- 如果在更新過程中發現配置有誤,則使用者可以中斷更新操作,並通過執行Kubectl rolling-update –rollback完成Pod版本的回滾
kubectl rolling-update redis-master --image=kubeguide/redis-master:2.0 kubectl rolling-update redis-master --image=kubeguide/redis-master:2.0 --rollback
以上是RC的滾動升級方式,目前有更好的Deployment資源管理:
1. 更新deployment,我們只需更新deployment裡面的template,當我們更新deployment時,當有合適的Pod產生,k8s才會刪除老的Pod,當老的Pod被刪除足夠多時,才會繼續產生新的Pod。
2. 定義deployment時,與rolling update相關項
.spec.minReadySeconds: 新建的Pod狀態為ready持續時間至少為它,才認為Pod Available(Ready),預設30s
.spec.strategy.rollingUpdate.maxSurge: 預設是desired Pods數的25%,Scale Up新的ReplicaSet時,允許的maxSurge,可以是整數或者百分比,向上取整
.spec.strategy.rollingUpdate.maxUnavailable: 預設為desired Pods數的25%,Scale Down舊的ReplicaSet時,允許的maxUnavailable,可以是整數或者百分比,向下取整
因此,在Deployment rollout時,需要保證Available(Ready) Pods數不低於 desired pods number - maxUnavailable; 保證所有的Pods數不多於 desired pods number + maxSurge。
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: frontend spec: minReadySeconds: 5 strategy: type: RollingUpdate rollingUpdate: maxSurge: 3 maxUnavailable: 2 replicas: 25 template:
kubectl set image deployment xxx-dep myregistry:5000/xxx=myregistry:5000/xxx:v2 --namespace=default
kubectl rollout undo deployment xxx-dep --namespace=default
kubectl rollout undo deployment xxx-dep --revision=1 --namespace=default
kubectl rollout history deployment xxx-dep --namespace=default
kubectl rollout history deployment xxx-dep --revision=2 --namespace=default
15. 修改k8s叢集的埠範圍,預設是30000-32767,為了不合其他應用衝突,通過修改配置/etc/kubernetes/manifests/kube-apiserver.yaml實現
- --service-cluster-ip-range=10.96.0.0/12
- --service-node-port-range=1-65535
- 修改kube-apiserver.yaml後,kube-apiserver自動重啟,這是因為kubelet在監聽著/etc/kubernetes/manifests目錄下的檔案變化並處理
16. 目前採用的版本是Kubernetes v1.10.0,以下是對應的映象版本
k8s.gcr.io/kube-apiserver-amd64:v1.10.0 k8s.gcr.io/kube-scheduler-amd64:v1.10.0 k8s.gcr.io/kube-controller-manager-amd64:v1.10.0 k8s.gcr.io/etcd-amd64:v1.10.0 k8s.gcr.io/kube-proxy-amd64:v1.10.0 k8s.gcr.io/pause-amd64:3.1 quay.io/coreos/flannel:v0.10.0-amd64 k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3 k8s.gcr.io/k8s-dns-dnsmasq-nanny-amd64:1.14.8 k8s.gcr.io/k8s-dns-sidecar-amd64:1.14.8 k8s.gcr.io/k8s-dns-kube-dns-amd64:1.14.8 k8s.gcr.io/heapster-influxdb-amd64:v1.3.3 k8s.gcr.io/heapster-grafana-amd64:v4.4.3 k8s.gcr.io/heapster-amd64:v1.4.2
17. kubelet指定本地映象
kubelet 修改配置以使用本地自定義pause映象
cat > /etc/systemd/system/kubelet.service.d/10-kubeadm.conf <<EOF [Service] Environment="KUBELET_EXTRA_ARGS=--pod-infra-container-image=local.repo/google_containers/pause-amd64:3.1" EOF systemctl daemon-reload systemctl restart kubelet
附錄1 .RBAC (Role-Base-Access-Control),基於角色的許可權控制策略。
涉及ServiceAccount、Role、RoleBinding,Kubernetes叢集中也有一個預設的ClusterRole、ClusterRoleBinding擁有所有權利的角色。
所以簡單的做法是:建立一個ServiceAccount,讓它通過ClusterRoleBinding繫結到ClusterRole(cluster-admin),則新建立的使用者獲得了叢集的所有許可權。
當然,在kubernetes叢集中,最佳的做法是,為每一個應用程式的服務賬戶授予角色,確保該賬戶在指定名稱空間下控制應用程式的執行。
例如:在tiller-world的namespace下建立tiller使用者,通過RoleBinding繫結到一個自定義的Role上。
$ kubectl create namespace tiller-world namespace "tiller-world" created $ kubectl create serviceaccount tiller --namespace tiller-world serviceaccount "tiller" created
kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: tiller-manager namespace: tiller-world rules: - apiGroups: ["", "extensions", "apps"] resources: ["*"] verbs: ["*"]
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: tiller-binding namespace: tiller-world subjects: - kind: ServiceAccount name: tiller namespace: tiller-world roleRef: kind: Role name: tiller-manager apiGroup: rbac.authorization.k8s.io
RBAC雖然很靈活,但是它的缺點是沒有提供順序操作的機制,導致它無法應用到那些有嚴格操作次序的系統。
附錄2. 服務發現
k8s將Service的名稱當做域名註冊到kube-dns,這樣在叢集中就可以通過serverName訪問服務了。
kube-dns通過nslookup指令檢查DNS查詢服務的健康狀態,pod中的容器查詢DNS時是通過serverName.namespace子域名查詢的,所以最好在serviceName後面加上namespace,避免可能的錯誤,例如: nslookup kubernetes.default
kube-dns支援的域名格式,具體為:<service_name>.<namespace>.svc.<cluster_domain>
其中cluster_domain可以使用kubelet的--cluster-domain=SomeDomain引數進行設定,通常設定為:cluster.local
每個Pod中的/etc/resolv.conf檔案中的引數:nameserver 10.96.0.10,對應就是kube-dns服務的ClusterIp,Pod的域名解析伺服器,當然是通過kubelet的--cluster-dns引數設定的。