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版本
  1. RC的名字(name)不能與舊的RC的名字相同
  2. 在selector中應至少有一個Label與舊的RC的Label不同,以標識其爲新的RC,例如:version: v2
  3. kubectl rolling-update redis-master -f redis-master-controller-v2.yaml
  4. 等所有新的Pod啓動完成後,舊的Pod也被全部銷燬,這樣就完成了容器集羣的更新。
  • 直接用kubectl rolling-update命令,加上--image參數指定新版鏡像名稱來完成Pod的滾動升級
  1. 執行的結果是舊的RC被刪除,新的RC仍將使用舊的RC的名字
  2. 如果在更新過程中發現配置有誤,則用戶可以中斷更新操作,並通過執行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參數設置的。

本文轉自開源中國-Kubernetes相關的問題彙總

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章