基本介紹:
編排歷史:
服務編排系統 =》容器編排系統
docker compose\swarm\docker machine
mesos,marathon
kubernets
集群節點:
聚合了所有node的cpu和內存,能自動尋找適合的node
運行單元:
pods
master組成:
APIserver接收請求放到etcd,其他如kubectl、scheduler、controller與apiserver打交道
scheduler調度,給一個pod找一個node
controller負責監控執行,有個循環loop
etcd(保存整個集群的配置,key-value),服務端口(其他證書)和集群內通信端口(點到點證書)
node組成:
kubelet負責和master連接,注冊node, listen-watch 本node的任務等
kube-proxy用於k8s service對象,監控service的變動,變為當前node的iptables
container runtime除了docker k8s還支持 rkt等容器實現
Addons附件:
DNS(kube-dns ==> coredns)主要用來解析service域名
CNI網絡容器接口(如fannel calico),pod,網絡是節點網絡類型,提供網絡策略通過名稱空間來隔離租戶
flannel網絡配置,疊加網絡,不支持網絡策略
calico網絡配置、網絡策略,三層隧道網絡
canel:結合兩者
weave網絡策略
web ui
container resource monitoring
cluster-level logging
證書:
5套證書,分內部和外部服務通信
常用對象:
Workload:
分為Pod ReplicaSet Deployment statefulSet DaemonSet Job CronJob
pods,k8s管理的最小對象,是一組共享uts, network, ipc namespace的容器(也支持共享pid,默認不開啟)
rc和rs等controller(管理pods)
deployment
簡單地說deployment是rc的上一層,用來管理rc的
主要功能是管理pod運行的版本
服務發現與均衡:
service
pod是非持久的,會不斷的重啟,導致pod的ip是隨時變化的,同時pod的數量會是動態變化的,客戶端很難和pod直接通訊,service是用來解決這一問題的
service 為提供同一服務的pods 提供了統一的入口
service 的生命周期內其綁定ip是不會變化的
通過環境變量或者DNS 可以查詢service 的ip和端口
之前創建的service只有一個集群內的固定ip,如果需要在集群外訪問有三種方法
默認的service 的類型是 'ClusterIP',修改為NodePort即可
創建一個loadbalance
創建Ingress resource
Ingress
配置與存儲:
Volume
集群級資源:
namespace,node,role,clusterRole,RoleBinding
部署與安裝:
部署要點:
測試環境:
可以使用單master節點,單etcd實例
node數量按需
nfs或glusterfs等存儲
生產環境:
高可用etcd集群,建立3/5/7
高可用master
-kube-apiserver無狀態,可多實例,借助nginx\happorxy負載
kube-scheduler及kube-controller-manager各自只能有一個活動實例,可以選舉備用
多node
IScsi、fcsan
網絡(本地多vm):
節點網絡:172.20.0.0/16
pod網絡:10.244.0.0/16 fannel默認使用
service網絡:10.96.0.0/12
常用部署工具:
kubeadm
kops
kubespray
kontena pharos
集群架構組成:
初始化:
所有節點啟動docker
初始化master(運行三個controller、etcd)和node(kube-proxy)
基礎組件:
master和node啟動kubelet和CNI
kubeadm部署流程:
1.更新下載源
配置yum或apt阿里雲源,yum下載gpg,定義.repo文件
https://developer.aliyun.com/mirror/kubernetes
ubuntu下:
sudo apt-get update && sudo apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
k8s_version="1.18.0-00"
apt-get update
apt-get install -y kubelet=${k8s_version} kubeadm=${k8s_version} kubectl=${k8s_version}
2.安裝軟件
install docker-ce kubelet kubeadm=v1.11.0 kubectl,並且enable docker-ce kubelet
3.docker拉取所需鏡像
通過代理拉取:
路徑是/etc/systemd/system/docker.service.d/http-proxy.conf或/usr/lib/systemd/system/docker.service
Environment="HTTPS_PROXY=http://www.ik8s.io:10080"
Environment="NO_PROXY=127.0.0.0/8,172.20.0.0/16"
systemctl daemon-reload
systemctl start docker
通過tag重命名的方式:
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.18.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.18.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.18.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.18.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.4.3-0
docker pull coredns/coredns:1.6.7
docker images |grep registry.cn-hangzhou.aliyuncs.com/google_containers |awk '{print "docker tag ",$1":"$2,$1":"$2}' |sed -e 's#registry.cn-hangzhou.aliyuncs.com/google_containers#k8s.gcr.io#2' |sh -x
docker tag docker.io/coredns/coredns:1.6.7 k8s.gcr.io/coredns:1.6.7
docker images |grep mirrorgooglecontainers |awk '{print "docker rmi ", $1":"$2}' |sh -x
4.初始化部署
swapoff -a
kubeadm reset -f && rm -rf /etc/kubernetes/
kubeadm init --kubernetes-version=v1.11.0 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 初始化
--ignore-preflight-errors=SystemVerification --ignore-preflight-errors=KubeletVersion
--control-plane-endpoint=apulis-china-infra01.sigsus.cn
--image-repository=harbor.sigsus.cn:8443/library/k8s.gcr.io
執行后續提示步驟
出錯原因查看:journalctl -xeu kubelet
如果還不是很明確,可以繼續通過docker ps -a和docker logs xxx查看容器具體的報錯的信息
標准的初始化流程可以參考官方文檔https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
配置kubectl的文件
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
5.部署其他組件:
CNI:
部署flannel:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=v1.18.1"
sudo scp dlwsadmin@apulis-sz-sanbox-master:/etc/kubernetes/admin.conf ./deploy/sshkey/admin.conf
部署weave:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')&env.IPALLOC_RANGE=10.32.0.0/16"
DNS(coredns):
https://github.com/kubernetes/kubernetes/blob/e176e477195f92919724bd02f81e2b18d4477af7/cluster/addons/dns/coredns/coredns.yaml.sed
修改clusterIP為10.3.0.53,刪除配置中的loop
效果:
部署完后,集群內pod之間、service與pod之間就可以訪問域名通信。
service的更新實時通過kube-proxy獲取api-server來更新dns的service地址到本地
刪除dns后又重新添加,dns的service網絡地址不變
問題:
1.部署機可以訪問pod網絡,但因為resolv.conf不變,不能訪問service域名
2.無法解析集群外域名
解決:修改resolv.conf,但unable to resolve host,因為本地host依賴本地的dns,編輯/etc/hosts,把主機名加到127.0.0.1即可。
或者啟動coredns時,指定forward . 8.8.8.8
6.worker節點部署:
安裝docker
使用kubeadm join的方式初始化子節點:
token可以通過kubeadm token create和openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
組合成kubeadm join --token %s %s:6443 --discovery-token-ca-cert-hash sha256:%s
kubeadm token create --ttl 0 --print-join-command
多次部署:
systemctl stop kube-proxy
systemctl stop kubelet
systemctl stop docker
iptables --flush # 修復no route to host
iptables -tnat --flush
iptables -P INPUT ACCEPT # 設置filter表INPUT默認規則是 ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F # 清空所有規則
systemctl start kubelet
systemctl start docker
運維操作:
刪除節點:
kubectl drain k8snode02 --delete-local-data --force --ignore-daemonsets node/k8snode02
kubectl delete node k8snode02
kubeadm reset(systemctl stop kubelet && rm -rf /etc/kubernetes/*)
master的ip變更:
kubeadm部署的:
1.重新生成證書,可以通過kubeadm alpha phase certs
2.把config文件、kubebconfig文件、/etc/kubernetes/文件夾里的*.conf文件的舊ip都改為新的IP
3.重啟服務
二進制部署:
只要簽發的證書沒有指定master的ip,那么是不用重新生成證書的
只要把conf文件都改掉舊的ip即可
注意事項:
admin.conf、kubelet.conf以及crt文件里面都需要改動ip
方法:
systemctl stop kubelet docker
cd /etc/
mv kubernetes kubernetes-backup
mv /var/lib/kubelet /var/lib/kubelet-backup
mkdir -p kubernetes
cp -r kubernetes-backup/pki kubernetes
rm kubernetes/pki/{apiserver.*,etcd/peer.*}
systemctl start docker
# reinit master with data in etcd
# add --kubernetes-version, --pod-network-cidr and --token options if needed
# 原文使用如下命令:
# kubeadm init --ignore-preflight-errors=DirAvailable--var-lib-etcd
# 但是由於我使用的是Flannel網絡,所以一定要加上參數,否則后續安裝 flannel addon無法啟動pod
# kubeadm init --ignore-preflight-errors=DirAvailable--var-lib-etcd --pod-network-cidr=10.244.0.0/16
kubeadm init --ignore-preflight-errors=all --kubernetes-version=v1.18.2
# update kubectl config
cp kubernetes/admin.conf ~/.kube/config
常見問題點:
初始化:
1.10250這個端口一直被/snap/kubelet/1388/kubelet的掛載目錄給占用了。
umount -fl即可
如果強制卸載后,還是ps -ef|grep kube還是存在,可以rm /dev/loop0試試
2.子節點join失敗。
查看具體原因log -v 256
3.日志提示Error response from daemon: readlink /var/lib/docker/overlay2/l: invalid argument
刪除該目錄會報錯,link來的,然后重新拉取鏡像就沒問題了
4.worker節點reset后提示沒有/etc/kubernetes/bootstrap-kubelet.conf
systemctl status kubelet查看配置文件
復制其他worker節點的文件過來,kubelet即可運行
5.提示error while creating mount source path '/var/lib/kubelet/pods/etc-hosts': mkdir /var/lib/kubelet: read-only file system
重啟docker
6.kubeadm init初始化失敗,報node "ubuntu" not found
原因:
通過docker logs查看pod啟動失敗原因,發現是k8s集群鏡像的架構不同導致的,樹莓派上的鏡像之前已經自帶的,導致apiserver啟動失敗。
7.Failed to create pod sandbox: open /run/systemd/resolve/resolv.conf: no such file or directory
解決:
ln -s /run/resolvconf/ /run/systemd/resolve
8.kubelet提示panic: runtime error: invalid memory address or nil pointer dereference,不斷重啟
原因:calico鏡像有問題,delete掉deployment后,還殘留了容器,docker ps -a查看,一直拉取舊的鏡像。前一行提示了error image not found while inspecting docker container
9.init失敗:
# /etc/kubernetes/work-kubernetes.yaml需要配置,讀取/etc/kubernetes/ssl/里面的相關證書
# 這是join用到的kubelet配置,會影響主節點的部署/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
# 后來發現是之前部署的10-kubeadm.conf遺留造成的影響,換為一個能用的就行
# 沒有10-kubeadm.conf會一直空跑
網絡CNI:
1.weave端口被占用也會導致容器網絡失敗,通過lsof -i:xxx 查看,然后kill -9 pid即可重啟weave,但有可能open /weavedb/weave-netdata.db失敗,delete pod然后再啟動一次即可。
2.新節點加入weave報錯Could not get peers: Get https://10.96.0.1:443/api/v1/nodes: dial tcp 10.96.0.1:443: connect: no route to host
kube-proxy還沒啟動,導致無法路由
3.提示[192.168.3.2:6783|be:87:40:f0:e9:c2(atlas01-worker01)]: connection shutting down due to error: IP allocation was seeded by different peers (received: [ca:1c:e7:11:2c:9f],ours: [02:61:5f:88:9a:d9(atlas01)])
關聯問題:On a network with multiple interfaces weave uses different ones on different hosts
解決方案:
some Weave Net peers were initialized into one cluster and some into another cluster; Weave Net cannot operate in this state.
https://www.weave.works/docs/net/latest/tasks/ipam/troubleshooting-ipam/#seeded-different-peers
https://github.com/weaveworks/weave/issues/3588
rm -rf /var/lib/weave
重啟weave
4.FATA: 2020/09/17 14:57:45.957005 [kube-peers] Could not get peers: Get "https://10.96.0.1:443/api/v1/nodes": dial tcp 10.96.0.1:443: i/o timeout
Failed to get peers
查看kube-proxy的log:
10.96.0.1 in clusterIP has incorrect IP version (service default/kubernetes)
解決:
看kubelet status可以看到NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized,weave引起的
主要解決weave即可
curl -vk https://10.96.0.1
懷疑和機器本身的網卡驅動有關
x86也遇到過,禁用ipv6后成功啟動weave
sysctl net.ipv6.conf.all.disable_ipv6=1
vim /etc/sysctl.d/10-disable-ipv6.conf
write_files:
- path: /etc/sysctl.d/10-disable-ipv6conf
permissions: 0644
owner: root
content: |
net.ipv6.conf.eth0.disable_ipv6 = 1
后來發現是機器本身的內核問題,換一台機器就好了,但不是根治之法
默認要有一個default router
查閱了一下,手動添加route:
ip route add 10.96.0.0/12 dev eno1 src 10.31.3.63 無效
可能與iptables-save規則有關
iptables -A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443
或者直接reset整個iptables
驗證:
iptables -A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j REJECT
刪掉weave pod后果然起不來
還是無效的話,重啟reboot看看
發現與coredns解析連不了8.8.8.8有關,因為看到了域名解析錯誤,將機器連上網后正常。
一般不用管iptables
5.kubernetes ha vip起來,但其他組件無法訪問vip,查看VIP的log發現ipv6達不到
手動添加對應的inet6無效
swapoff -a
sed -i 's/.*swap.*/#&/' /etc/fstab
setenforce 0
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
echo 1 > /proc/sys/net/bridge/bridge-nf-call-ip6tables
echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv6/conf/default/forwarding
sysctl -w net.bridge.bridge-nf-call-iptables=1
vim /etc/sysctl.conf
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
sysctl -p
重啟電腦后才生效
6.weave組件Inconsistent bridge state detected. Please do 'weave reset' and try again
下載weave腳本,執行weave reset,會短暫斷網
https://github.com/weaveworks/weave/blob/master/weave
wget https://raw.githubusercontent.com/weaveworks/weave/master/weave
7.weave組件啟動異常,提示Network 10.32.0.0/12 overlaps with existing route 0.0.0.0/1 on host
確認是否啟動了全局代理vpn,先移除再啟動
8.weave組件啟動后,interface的ip和在controller中cluster ip設置的范圍不一樣,造成了pod內無法通信
yaml文件里面定義:
containers:
- name: weave
env:
- name: IPALLOC_RANGE
value: 10.0.0.0/16
先停止,刪掉interface,再reset,然后啟動即可。
9.weave報錯的情況下,pod還能分配到node上,擁有host???
問題:
發現master無法部署,即使去掉taints,后來發現dns無法nodenotready,原來是weave啟動失敗,
更換flannel后,同時edit master的pod_cidr為相同的network,就可以啟動。
運維:
1.遇到pod rpc deallock等error,一直pengind、terminating中
重新加入worker節點
2.pod一直處於Terminating,docker ps查看進程存在,stop kill rm -f都不成功
原因:/var/lib/docker/containers/文件存在,可能是container清理時網絡問題導致文件未清理掉,造成進程已退,但文件存在的假container
npu的腳本報錯會導致kill不掉,原因是sudo -E bash -c cd /data/code/mindspore/example/resnet50_cifar10/ && ./run_8p.sh &&sleep infinity的./run_8p.sh報錯了
如果正常執行,則不會出現該情況
解決:
刪除/var/lib/docker/containers/下的對應文件夾
systemctl restart docker
或kubectl delete pod --force xxx 但docker沒清掉
或docker top xxx查看容器停留進程,然后kill 進程號試試
重現:
再次跑job后,仍然出現該情況
3.pod的port通過service轉發,pod內進程是啟動的,內網ip+targetport可以訪問,但通過service的cluster_ip+port或外網ip+nodeport不能訪問
iptables-save |grep 10.104.74.188
-A KUBE-SERVICES -d 10.104.74.188/32 -p tcp -m comment --comment "default/e-461e6f51-66fc-4969-8eec-65ec74960c91-ipython:ipython has no endpoints" -m tcp
--dport 44460 -j REJECT --reject-with icmp-port-unreachable
意思是44460端口不可訪問
網上搜索說selector錯誤,但pod是啟動的
4.pod內Unable to connect to the server: dial tcp 10.96.0.1:443: i/o timeout,kubectl或python接口都超時
原因: ufw啟動,本地訪問6443端口是可以的,但容器內不能訪問。容器內網絡是正常的。
解決: ufw allow 6443
5.樹莓派出現[ERROR SystemVerification]: missing cgroups: memory
解決:
/boot/firmware/cmdline.txt和/boot/firmware/nobtcmd.txt添加cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1
6.pod一直處於containcreating狀態。kubernetes Get https://[10.96.0.1]:443/apis/crd.projectcalico.org/v1/clusterinformations/default: x509: certificate signed by unknown authority
/etc/cni/net.d/目錄下面有其他的網絡插件,比如calio,刪除掉
ip route flush proto bird
ip link list | grep cali
iptables-save|grep cali
modprobe -r ipip
service kubelet restart
7.pod狀態出現diskpresure
vi /var/lib/kubelet/config.yaml
evictionHard:
nodefs.available: "5%"
8.pod內resolf.conf文件沒有nameserver
過程:
該節點卸載過avahi,該軟件導致了默認route的改變,增加了網卡,卸載導致systemd-resolved.service起不來。
解決:
重啟,然后服務正常,但nslookup查找失敗
ls -l /etc/resolv.conf可以看到指向不正常
rm /etc/resolv.conf
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf正常的軟鏈才是正常的,pod內使用的/etc/resolv.conf文件也是這個,systemd-resolved 實時更新 /run/systemd/resolve/stub-resolv.conf
9.容器內其他用戶執行kubectl提示error: You must be logged in to the server (Unauthorized)
原因:
每個pod都掛載了default token,對應serviceaccount的default,該token由TokenController 作為 kube-controller-manager 的一部分運行。
使用了該default token導致kubectl返回401錯誤(kubenretes的python api也會401)
from kubernetes import client as k8s_client
from kubernetes import config as k8s_config
k8s_config.load_incluster_config()
k8s_core_api = k8s_client.CoreV1Api()
k8s_core_api.list_namespaced_config_map(namespace="default")
該token可以通過jwt解,但只是一些基本信息。看kubelet的報錯,原因可能是掛載的token是舊的,對應的已經被刪除了。
解決:
刪掉token,等待自動生成。
9.pod一直處於pulling,同時有多個pod
原因:kubelet默認串行拉取鏡像,改為並行
查找:kubelet -v可以設置更高的級別,輸出更多的log
DNS:
1.coredns問題
查看本地dns服務是否啟動,排除weave是否正常,ping內網ip是否通,
查看coredns的pod,依賴配置configmap:coredns,kgk cm coredns -o yaml查看配置
查看coredns的log,發現dial udp [fdcd:55c4:4289::1]:53: connect: cannot assign requested address
通過netcat工具,nc -z -v -u [hostname/IP address] [port number]
原因:fdcd:55c4:4289::1是根據configmap中的forward . /etc/resolv.conf來導向的,看看/etc/resolv.conf是否有問題
一直CrashLoopBackOff
[FATAL] plugin/loop: Loop (127.0.0.1:37845 -> :53) detected for zone ".", see https://coredns.io/plugins/loop#troubleshooting. Query: "HINFO 5239076309015988897.2370766897435033976."
原因: loop
修改本地127.0.0.53為8.8.8.8
常用指令:
kubectl get nodes
pods -n kube-system -o wide\yaml\json
ns
svc
run nginx-dep --image=nginx:1.14-alpine --port=80 --replicas=1 # 啟動的是deployment,如果想運行pod的話,kubectl run nginx --image=nginx --port=80 --restart=Never
expose deployment nginx-dep --name=xxx --port=80 --target-port=80 --protocol=TCP --type=ClusterIP
創建service來動態綁定端口,nodePort類型才能被外網訪問
edit svc xx
scale deployment xx --replicas=5
set image deployment myapp myapp=ikuberbetes/myapp:v2
rollout status deployment myapp灰度更新
history\undo\pause\resume
patch deployment myapp -p '{"spec":{"replicas":5}}'
create ns(namespace) xxx
deploy ngx --image=nginx:1.14-alpine # 自動重啟,ip會變(集群內才能訪問該ip),加service層
會啟動pod
service clusterip my-cs --tcp=5378:8000 # 與deploy同名會自動關聯過來
service nodeport my-ns --tcp= # 區別是外網可以訪問,但不是指定端口
delete ns/xxx ns/yyy 可以一次輸入多個
api-resources
describe
exec -it xxx /bin/bash
pod-demo -c 某個container -n prod -it -- /bin/bash
scale --replicas=3 deployment mydeploy擴容后svc自動添加負載
log pod xxx -n prod -c container
cluster-info
概念介紹:
Controller種類:
概述:
Kubernetes 通常不會直接創建 Pod,而是通過 Controller 來管理 Pod 的。
分類:
ReplicationController(舊)
ReplicaSet:指定數量的副本,不建議直接使用,而是使用deployment ;擴縮容可以scale或edit;
升級edit不會更新已存在的pod,只能藍綠更新
Deployment:通過控制ReplicaSet來控制pod,功能大於replicas,支持灰度滾動更新(管理多個rs來實現)
配置更新可以編輯文件然后apply\set image\patch
DaemonSet:每個節點運行,node守護進程,適合node節點收集路徑日志的服務,由k8s維護重啟
StatefulSet:狀態,如redis,持久存儲
Job:執行一次
Ctonjob:周期執行
HPA
網絡:
節點網絡:
與外部網絡接口,運維提供,而其他兩種網絡由插件通過
service網絡:
概述:
內部網絡,無法外部訪問,通過coreDns注冊;被刪前穩定ip
實現原理:
不是實體組件,而是一套iptable規則,其service名稱通過自身的dns來解析
請求通過service訪問pod,而iptable將負載交給ipvs提供負載平衡功能,即相當於生成了ipvs規則
當pod狀態變更時,service通過守護進程kube-proxy改變節點的相關ipvs規則
pod網絡:
概述:
由cni提供,一般加一層service網絡代理,service通過label與pod綁定
實現原理:
pod之間可以通過overlay network疊加網絡相互訪問,而service只是規則
(如果直接物理橋橋接,pod數量多了不夠分,通過疊加網絡二層轉發或隧道轉發三層)
訪問過程:
docker之間先轉發出節點,再相互通信
pod要訪問service,先請求網關,到達臨橋地址通過iptabel規則表找到service
service資源:
工作原理:
pod之間請求通過service,pod的更新到apiserver后,apiserver通過kube-proxy通知service進行更新
工作模式:
userspace、iptable、ipvs
type類型:
ExternalName, ClusterIP, NodePort,LoadBalancer,Headless.
NodePort
會將對本地集群任何一個機器ip的某一個port的請求轉發到相應的cluster ip+port上
Port的范圍是所有機器共享的
Headless
無頭service,clusterIP: None #None表示是無頭service
會直接解析為具體多個pod的ip
該服務不會分配Cluster IP,也不通過kube-proxy做反向代理和負載均衡。而是通過DNS提供穩定網絡ID來訪問,DNS會將headless service的后端直接解析為podIP列表。主要供StatefulSet使用。
LoadBalancer:
和nodePort類似,不過除了使用一個Cluster IP和nodePort之外,還會向所使用的公有雲申請一個負載均衡器(負載均衡器后端映射到各節點的nodePort),實現從集群外通過LB訪問服務。
雲平台底層將請求負載轉發給各個nodePort的service,service再分發給pod
ExternalName:
集群內的pod訪問外部服務,私網ip回不來
建一個service,由service請求外部服務,請求先回到service,再轉發給pod
是 Service 的特例。此模式主要面向運行在集群外部的服務,通過它可以將外部服務映射進k8s集群,且具備k8s內服務的一些特征(如具備namespace等屬性),來為集群內部提供服務。
訪問url格式:
svc_name.ns_name.domain.ltd
例如redis.default.svc.cluster.local.
配置示例:
apiVersion:v1
kind: Service
metadata:
name:
namespace
spec:
selector:
app:nginx
clusterIP: # 分配
type: ClusterIP # nodePort 會在宿主機上映射一個端口,供外部應用訪問模式。
ports:
- port:6379 # service映射端口
targetPort: 6379 # 容器內端口
nodePort: 33080 # 指定node的端口,默認30000-32767
Ingress:
作用:
外部https請求到達nginx,nginx通過url前綴轉發給不同的services,再由service轉發給對應一組pod
部署方案:
方法一:將nginx部署為daemonset,部分節點,nginx內配置多個location,location代理給services。
再為多個nginx部署一個nodeport的service,指定nodePort,就可以接入外部請求
方法二:Ingress controller資源,先部署一個nginx的deployment,再部署一個ingress,路由多個path。
安裝:
1.創建namespace\configmap\rbac\tcp-services-configmap\with-rbac yaml文件
2.kubectl apply -f ./部署nginx
3.定義ingress
apiVersion:extensions/v1beta1
kind:Ingress
metadata:
name:ingress
namespace
annotations:
kubernetes.io//ingress.class:"nginx"
spec:
tls:
- hosts:
- tomcat.com
secretName:tomcat-ingress-secret
rules:
-host:myapp.com
http:
paths:
- path: #空為根路徑
backend:
serviceName:myapp
servicePort:80 # service端口,而ingress的nginx端口默認為80和443,現在不能更改
4.定義后nginx自動更新配置
#pod更新后,nginx的upstream也會自動更新
5.https,先openssl生成證書和密鑰,然后創建secret對象
openssl genrsa -out tls.key 2048
openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/0=DevOps/CN=tomcat.com
kubectl create secret tls tomcat-secret --cert=tls.crt --key=tls.key
kube-ApiServer:
restful api server,上面的指令實際都是http請求的不同action,get\put\post
資源對應着url
資源對象的配置格式:
kind:用於標識對象所屬的資源類型、api群組
apiVersion
metadata:名稱、namespace、標簽
spec:包括一些container,storage,volume以及其他Kubernetes需要的參數,以及諸如是否在容器失敗時重新啟動容器的屬性。
status:
資源對象管理方式:
創建:
陳述式命令 run
陳述式對象配置 create -f
聲明式對象配置 apply,用於添加,刪除使用陳述式對象配置的delete,配置文件修改了可以再次apply。可以目錄
區別:
run創建deploymnet,pod由控制器管理,而后兩種只是創建pod
Pod:
pod對象創建過程:
1.提交create pod
2.apiserver寫入etcd,etcd成功后響應
3.apiserver調度scheduler,watch new pod
4.scheduler bind pod給apiserver
5.apiserver寫入etcd
6.apiserver請求kubelet,watch bound pod
7.kubelet請求docker run
8.kubelet update pod status給apiserver
9.apiserver寫入etcd
pod的終止過程:
1.提交delete請求,apiserver標記為terminating
2.apiserver寫入etcd,設置grace period
3.apiserver請求kubelet,watch pod marked as terminating
4.kubelet send term signal給docker
5.kubelet run preStop hook
6.apiserver請求endpoint controller,remove pod from endpoint of all service
7.apiserver watch expiry of grace period,請求kubelet,kubelet send SIGKILL給docker
8.docker 立刻刪除pod
9.apiserver 請求刪除etcd對應的object
pod生命周期:
狀態:
Pending API Server已經創建該Pod,但在Pod內還有一個或多個容器的鏡像沒有創建,包括正在下載鏡像的過程。
Runnung Pod內所有容器均已創建,且至少有一個容器處於運行狀態、正在啟動狀態或正在重啟狀態。
Succeeded Pod內所有容器均成功執行后退出,且不會再重啟。
Failed Pod內所有容器均已退出,但至少有一個容器退出為失敗狀態。
Unknown 由於某種原因無法獲取該Pod的狀態,可能由於網絡通信不暢導致
相關鈎子:
postStart:
httpGet\exec\tcpSocket
容器啟動后立刻執行,如果執行失敗會根據policy重啟與否
preStop:
存活探測:
livenessProbe健康監測: 位於containers層面
exec:(0表示成功)
command
httpGet(返回200狀態碼)
host
port:必須,name或數字
path:
tcpSocket
host
port
failureThreshold
initialDelaySeconds
periodSeconds
timeoutSeconds
就緒探測:
readinessProbe:
無論就緒ready與否,不能重啟,只是不能作為服務被引用
ready后才被server引用會更合理,比如多個replicas的一個,還沒就緒會導致502
重啟策略:
always:但凡對象終止就重啟
onfailure
never
pod security:
級別:
pod.spec.securityContext
pod.spec.container.securityContext
capabilities add/drop
資源設置:
cpu一個核心=1000m
pods.spec.containers.resources
limits最高限制
requests申請資源
pod服務質量:
Guaranteed:為cpu和內存設置了相同request和limit的pod會自動歸屬此類,最高優先級
Burstable:至少一個容器設置了cpu和內存資源的request
BestEffort:未設置requests或limit屬性,最低優先級
其他知識點:
priorityClass
limitRange
關於Command和args:
如果定義了args,會使用docker鏡像的entrypoint,忽略cmd
關於yaml格式的書寫:
[]string這種,可以使用["/usr/sbin/nginx","-s","quit"]來表示,也可以- -
多個容器:
邊車,side car
一個主容器,其他容器輔助,如日志收集、后台服務的proxy代理
共享IPC、UTS、network、volumes
yaml文件示例:
apiVersion: v1 #必選,版本號,例如v1
kind: Pod #必選,Pod
metadata: #必選,元數據
name: string #必選,Pod名稱
namespace: string #必選,Pod所屬的命名空間
labels: #自定義標簽
- name: string #自定義標簽名字
annotations: #自定義注釋列表
- name: string
spec: #必選,Pod中容器的詳細定義
containers: #必選,Pod中容器列表
- name: string #必選,容器名稱
image: string #必選,容器的鏡像名稱
imagePullPolicy: [Always | Never | IfNotPresent] #獲取鏡像的策略 Alawys表示下載鏡像 IfnotPresent表示優先使用本地鏡像,否則下載鏡像,Nerver表示僅使用本地鏡像
command: [string] #容器的啟動命令列表,如不指定,使用打包時使用的啟動命令
args: [string] #容器的啟動命令參數列表
workingDir: string #容器的工作目錄
volumeMounts: #掛載到容器內部的存儲卷配置
- name: string #引用pod定義的共享存儲卷的名稱,需用volumes[]部分定義的的卷名
mountPath: string #存儲卷在容器內mount的絕對路徑,應少於512字符
readOnly: boolean #是否為只讀模式
ports: #需要暴露的端口庫號列表
- name: string #端口號名稱
containerPort: int #容器需要監聽的端口號
hostPort: int #容器所在主機需要監聽的端口號,默認與Container相同,
protocol: string #端口協議,支持TCP和UDP,默認TCP
env: #容器運行前需設置的環境變量列表
- name: string #環境變量名稱
value: string #環境變量的值
resources: #資源限制和請求的設置
limits: #資源限制的設置
cpu: string #Cpu的限制,單位為core數,將用於docker run --cpu-shares參數
memory: string #內存限制,單位可以為Mib/Gib,將用於docker run --memory參數
requests: #資源請求的設置
cpu: string #Cpu請求,容器啟動的初始可用數量
memory: string #內存清楚,容器啟動的初始可用數量
livenessProbe: #對Pod內個容器健康檢查的設置,當探測無響應幾次后將自動重啟該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設置其中一種方法即可
exec: #對Pod容器內檢查方式設置為exec方式
command: [string] #exec方式需要制定的命令或腳本
httpGet: #對Pod內個容器健康檢查方法設置為HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #對Pod內個容器健康檢查方式設置為tcpSocket方式
port: number
initialDelaySeconds: 0 #容器啟動完成后首次探測的時間,單位為秒
timeoutSeconds: 0 #對容器健康檢查探測等待響應的超時時間,單位秒,默認1秒
periodSeconds: 0 #對容器監控檢查的定期探測時間設置,單位秒,默認10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged:false
restartPolicy: [Always | Never | OnFailure]#Pod的重啟策略,Always表示一旦不管以何種方式終止運行,kubelet都將重啟,OnFailure表示只有Pod以非0退出碼退出才重啟,Nerver表示不再重啟該Pod
nodeSelector: obeject #設置NodeSelector表示將該Pod調度到包含這個label的node上,以key:value的格式指定
imagePullSecrets: #Pull鏡像時使用的secret名稱,以key:secretkey格式指定
- name: string
hostNetwork:false #是否使用主機網絡模式,默認為false,如果設置為true,表示使用宿主機網絡
volumes: #在該pod上定義共享存儲卷列表
- name: string #共享存儲卷名稱 (volumes類型有很多種)
emptyDir: {} #類型為emtyDir的存儲卷,與Pod同生命周期的一個臨時目錄。為空值
hostPath: string #類型為hostPath的存儲卷,表示掛載Pod所在宿主機的目錄
path: string #Pod所在宿主機的目錄,將被用於同期中mount的目錄
secret: #類型為secret的存儲卷,掛載集群與定義的secre對象到容器內部
scretname: string
items:
- key: string
path: string
configMap: #類型為configMap的存儲卷,掛載預定義的configMap對象到容器內部
name: string
items:
- key: string
path: string
label:
標簽就是鍵值
key:字母、數字、_、-、.
value:可以為空,只能字母或數字開頭及結尾
一個對象可多個標簽,一個標簽可添加到多個資源上
key通常由鍵前綴和鍵名組成,前綴可選
使用:
metadata定義后apply應用
kubectl label --overwrite pod key=val key-刪除
快速清空label:
kubectl edit編輯刪除
label selector:
基於等值關系
= == !=
基於集合關系
key in\not in ()
key 所有存在此key的資源
key
!key
邏輯:
多個選擇權為“與”
空值意味着每個資源對象都被選中
空的選擇器將無法選出任何資源
使用:
kubectl get pods --show-labels -l app=myapp
-l "app in (myapp,dep)" -L app 顯示該標簽 -l是選擇
-l '!app'
控制器配置文件使用:
matchLabels:直接給定鍵值
matchExpressions:給定表達式,{key:"KEY",operator:"OPERATOR",values:[value1,value2..]}
operator操作符:
In,notIn:非空列表
Exists,NotExists:必須空列表
資源注解annotation:
僅用於為資源提供元數據信息,不能用於挑選資源對象。沒有長度限制
apply就用到這個來對比更新
更新策略:
重建:
概述:
會終止所有正在運行的實例,然后用較新的版本來重新創建它們。
示例:
spec:
replicas: 3
strategy:
type: Recreate
藍綠發布:
概述:
同時運行兩個版本的應用,如上圖所示,藍綠部署的時候,並不停止掉老版本,而是直接部署一套新版本,等新版本運行起來后,再將流量切換到新版本上。
缺點:
對硬件的要求就是日常所需的二倍
示例:
創建新舊兩個deployment(兩個label,app和version)和service(selector不同),在測試新版本滿足要求后,替換 label selector 中的版本標簽
滾動更新:
概述:
滾動更新通過逐個替換實例來逐步部署新版本的應用,直到所有實例都被替換完成為止。
示例:
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2 # 一次可以添加多少個Pod
maxUnavailable: 1 # 滾動更新期間最大多少個Pod不可用
灰度發布:
概述:
也叫金絲雀發布,起源是,礦井工人發現,金絲雀對瓦斯氣體很敏感,礦工會在下井之前,先放一只金絲雀到井中,如果金絲雀不叫了,就代表瓦斯濃度高。
流程:
先啟動一個新版本應用,但是並不直接將流量切過來,而是測試人員對新版本進行線上測試,啟動的這個新版本應用,就是我們的金絲雀。
如果沒有問題,那么可以將少量的用戶流量導入到新版本上,然后再對新版本做運行狀態觀察,收集各種運行時數據,如果此時對新舊版本做各種數據對比,就是所謂的A/B測試(A/B測試是效果測試)。
當確認新版本運行良好后,再逐步將更多的流量導入到新版本上,在此期間,還可以不斷地調整新舊兩個版本的運行的服務器副本數量,以使得新版本能夠承受越來越大的流量壓力。
直到將100%的流量都切換到新版本上,最后關閉剩下的老版本服務,完成灰度發布。
示例:
方式一:
具有相同 Pod 標簽的 Deployment,通過數量來控制流量的比例。
方式二:
需要更精確的控制策略,建議使用服務網格(如 Istio),它們可以通過權重或 HTTP 頭等更好地控制流量。
statefulset:
概述:
Pod發生re-schedule后仍然要保持之前的網絡標識和持久化存儲
特點:
1.部署、擴展、更新、刪除都要有順序。
2.每個pod都有自己存儲,所以都用volumeClaimTemplates,為每個pod都生成一個自己的存儲,保存自己的狀態
3.pod名字始終是固定的
4.service沒有ClusterIP,是headlessservice,所以無法負載均衡,返回的都是pod名,所以pod名字都必須固定,StatefulSet在Headless Service的基礎上又為StatefulSet控制的每個Pod副本創建了一個DNS域名:$(podname).(headless server name).namespace.svc.cluster.local
組件:
headless service、statefulset、volumeClaimTemplate
適合場景:
有狀態的應用
擴縮容:
scale\set image
創建示例:
spec:
serviceName:
template:
spec:
containers:
- name:myapp
volumeMounts:
volumeClaimTemplate: # 類似pvc
- metadata:
name:myappdata
spec:
accessModes:["readwriteOnce"]
resources:
request:
storage:2Gi
updateStrategy:
type:
rollingUpdate:
partition:默認0,指定大於數字才進行更新。一般先指定較大,更新沒問題后修改為0全部更新
ReplicaSet:
概述:
運行維護一組副本pod
建議使用 Deployment 而不是直接使用 ReplicaSet
創建示例:
apiVersion
kind
metadata
spec
replicas:2
selector:
matchLabels:以標簽來選擇pod是否符和,如果其他label碰撞了,隨機kill一個
app:myapp
template:
metadata:
name:
labels:至少符合selector規則
spec:
containers:
Deployment:
概述:
ReplicaSet的更高級
pod之間沒有順序
所有pod共享存儲
pod名字包含隨機數字
service都有ClusterIP,可以負載均衡
創建示例:
apiVersion
kind:Deployment
metadata
name
namespace
spec:
replicas:
selector:
matchLabels:
app:myapp
template:
metadata:
labels:
spec:
containers:
-
strategy:
type: recreate刪一個建一個 or rollingUpdate
rollingUpdate:
maxSurge:
maxUnavailable:
reversionHistoryLimit:10
DaemonSet:
概述:
DaemonSet 確保全部(或者某些)節點上運行一個 Pod 的副本。 當有節點加入集群時, 也會為他們新增一個 Pod 。
當有節點從集群移除時,這些 Pod 也會被回收。刪除 DaemonSet 將會刪除它創建的所有 Pod。
適合場景:
在每個節點上運行集群守護進程
在每個節點上運行日志收集守護進程
在每個節點上運行監控守護進程
創建示例
apiVersion
kind:DaemonSet
metadata
name
namespace
spec:
selector:
matchLabels:
app:myapp
template:
metadata:
labels:
spec:
containers:
-
updateStrategy:
type:onDelete類似recreate or rollingUpdate
rollingUpdate:
maxUnavailable:只能少不能多
reversionHistoryLimit
存儲卷:
種類:
emptyDir臨時路徑、hostPath
底層存儲:
傳統存儲:
SAN:iSCSI...
NAS:nfs,cifs
分布式存儲:
glusterfs,rbd,cephfs
雲存儲:
EBS\Azure
emptyDir:
volumes:
- name:xxx
emptyDir:
medium:""或Memory
sizeLimit:
然后在containers中volumeMounts
mountPath:
name:
readOnly:
subPath:子路徑
gitRepo:
clone一份到emptydir中使用,更新不會同步
hostPath:
volumes:
- name:xxx
hostPath:
path:
type:默認空字符串,不執行檢查掛載文件類型,DirectoryOrCreate\FileOrCreate\Socket\CharDevice\BlockDevice
共享存儲:
使用服務器部署nfs:
安裝nfs-utils sudo apt-get install nfs-kernel-server
vim /etc/exports /dev/share *(rw,fsid=1,sync,no_subtree_check,no_root_squash) *表示不限制ip,fsid注意需不同
rw,sync,no_root_squash,insecure
sync 將數據同步寫入內存緩沖區與磁盤中,效率低,但可以保證數據的一致性
async 將數據先保存在內存緩沖區中,必要時才寫入磁盤
systemctl start nfs # ubuntu下是sudo service nfs-kernel-server restart\sudo systemctl start nfs-kernel-server
# 如果nfs而不是nfs4,原因可能是配置有問題
apt-get purge nfs-kernel-server
重新安裝apt-get install nfs-kernel-server
sudo showmount -e localhost
sudo exportfs -rv #將配置文件中的目錄全部重新export一次!無需重啟服務。
sudo nfsstat #查看NFS的運行狀態
客戶端測試連接:
#查看網絡端口,NFS默認是使用111端口。要確保端口已開,不建議通過外網訪問,而是集群內相互通信,這樣就不需要內網與外網之間的端口映射(即開放外網端口)
sudo apt install nfs-common
sudo showmount -e apulis-china-infra01.sigsus.cn
sudo mount -t nfs4 apulis-china-infra01:/mnt/share /dlwsdata # 會暫時覆蓋原來的目錄
sudo mount -t nfs4 -o vers=4 -o mountvers=4 sandbox2-storage:/data/share /mntdlw
其他服務器進行掛載:
mount -t nfs 192.168.255.1:/data/volumes /mnt
umount /mnt
volumes:
- name:xxx
nfs:
path:/data/volumes
server:store01.com
能夠多個pod共享讀寫,不能填寫相對路徑
問題:
mount.nfs: access denied by server while mounting # ip和掩碼的問題,改為*就可以
同一個集群內
一個機器訪問另一個機器,訪問域名時注意的是使用內網ip,如果填的是公網段才能訪問,那么將會access denied,只能192.168.0.0/24,
表示32-24=8,2的8次方表示256個可用ip,即最后一位是主機部分,前面三位是網絡部分
27位的網掩碼是: 255.255.255.224,表示
這個時候公網ip的111端口可以不開
華為集群
沒有內網ip,直接通過外網ip通信,那么116.66.187.0/24,其他同一網段的機器可以訪問,但本機的域名解析為127.0.0.1,不符合公網限制,所以access denied
或者將/etc/hosts里面的映射去掉也可以
mount.nfs: requested NFS version or transport protocol is not supported
確認已經開啟了nfs server
掛載卡住:
配置nfs
RPCMOUNTDOPTS="--manage-gids -p 13025"
重啟
systemctl restart nfs-kernel-server
確認防火牆已經開放了端口111,2049,和配置的port
persistentVolumeClaim:
創建pv:
定義了多個nfs后,即可創建,定義和volumes差不多
apiversion
kind: PersistentVolume
metadata:
name:pv001
# 沒有namespace,屬於集群資源,這點比較關鍵!!!
labels:
name:
spec:
nfs: # 除了nfs外,還支持hostpath、cephfs等,k8s內置支持。
path:
server:
accessModes:["ReadWriteOnce","ReadOnlyMany","ReadWritemany"]
capacity:
storage:2Gi # 這個大小貌似不影響,用的是整個目錄,目前只有 capacity 這個label可作為 resource request 的依據,用於pvc的申請
persistentVolumeReclaimPolicy: Retain (default) and Recycle.
storageClassName: xxx # 每個 PV 可以屬於某個類(Class),通過將其 storageClassName 屬性設置為某個 StorageClass 的名稱來指定。
# 特定類的 PV 卷只能綁定到請求該類存儲卷的 PVC 申領。 未設置 storageClassName 的 PV 卷沒有類設定,只能綁定到那些沒有指定特定 存儲類的 PVC 申領。
hostPath:
path:
創建pvc:
kind:PersistentVolumeClaim
metadata:
name:pvc
namespace:default #和pod同一個命名空間
spec:
accessModes:[]
resources:
requests:
storage:6Gi
selector:
matchLabels # 不加selector時,任意匹配滿足容量的
volumeMode: Filesystem # 掛載為pod內的目錄,此外還有Block,掛載為原始塊設備。
volumeName: aiplatform-model-data-pv # 指定pv,當前版本18.2不能綁定已經綁定過的pv(一對一),會一直pending。
storageClassName: nfs # 對應pv的類型,可以是手動創建的pv,或者由storageClass動態創建的。
不同名稱空間的pvc可以同名字,pv是集群級別的資源,同名字肯定只能一個
pv和pvc是one to one的關系
使用:
volumeMounts: #掛載容器中的目錄到pvc nfs中的目錄
- name: www
mountPath: /usr/share/nginx/html
subPath: nginxpvc-test
volumes:
- name: www
persistentVolumeClaim: #指定pvc
claimName: pvc-nfs
readOnly
storageClass:
動態創建nfs目錄,創建pv來滿足pvc的需求
configMap:
放置配置,明文,pod掛載路徑即可,key-value字典來設置data的方式
創建configMap:
kubectl create configmap myconfig --from-file=key1=/path/txt --from-literal=key1=config1 # key都放到data下
apiversion
kind
metadata
data:
binaryData:
env使用:
env:
- name:Nginx_Port
valueFrom:
configMapKeyRef:
name: nginx-cofig # configmap名字為nginx-cofig
key: nginx_port # data下的key為Nginx_Port的數據
optional: # 是否configmap要事先定義
更新后pod中不會自動更新
volume使用:
volumeMounts:
- name: config
mountPath: "/config" # key為文件名/config/key,value為內容
readOnly: true
volumes:
- name: config
configMap:
name: nginx-config
items:
- key: # 指定要掛載的key,如果不指定,則生成多個文件。
path: # 指定key生成的file名字,可以替代默認的名字key
更新后短暫時間后同步到pod
secret:
加密的方式來存儲
創建secret:
類型:
三種,kubectl create secret docker-registry\generic\tls
docker-registry
docker-registry用於spec.imagePullSecrets,生成后指定name即可
generic
type為Opaque
tls
示例:
kubectl create secret generic mysql-root-password --from-literal=password=MyP@ss.8*9
kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
kubectl create secret docker-registry harborsecret --docker-server=harbor.demo.com.cn --docker-username='docker-admin' --docker-password='==pwd==' --docker-email='admin@demo.com'
使用:
generic的使用類似configmap,可以在env或volume中使用。
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
mode: 077
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
認證:
認證=》授權=》准入控制
認證支持token令牌和證書tls
授權支持node、abac、RBAC、webhook等
訪問apiserver可以curl訪問kubelet proxy,然后再轉發
kubectl如何認證:
kubeconfig
pod如何認證:
默認的使用default-token-xxx,僅有權限訪問自身的屬性,要想訪問其他pod,需手動創建
serviceAccountName
restful api\verb\http action
subject針對user\group\serviceaccount
object針對resource\group
action:get,list,watch,patch,delete,deleteconllection
objectUrl:
/apis/<GROUP>/<VERSION>/namespace/<NAMESPACE>/<KIND>/<object_id>/
不同的action
兩者分別對應起來,組合不同的permission
permission給不同的role
用戶賬號serviceAccount:
主要是pod的賬號,用來指定pod的管理其他pod權限,如一些系統級的pod,flannel
pod生成時默認有一個default-token存儲卷,通過get secret查看
生成serviceAccount:
kubectl create serviceaccount mysa -o yaml 還沒任何權限,可以包含image pull secrets(也可pod直接指定)
創建后,生成mysa-token-xxx的secret
如何使用:
spec:
serviceAccount: # 需先使用rolebinding或clusterrolebinding綁定到role或clusterrole上
# 只能使用對應名稱空間下的
賬號:
kubectl config view查看配置信息
生成證書密鑰,用k8s的證書openssl簽發,然后config創建用戶
相關操作:kubectl config use-context/set-cluster/set-context
(umask 077;openssl genrsa -out czl.key 2048) 生成私鑰
openssl req -new -key dashboard.key -out dashboard.csr -subj "/O=czl/CN=czl" 證書簽屬請求
用系統ca簽:openssl x509 -req -in dashboard.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out dashboard.crt -days 365
創建賬號kubectl config set-credentials czl --client-certificate=./mage.crt --client-key=./czl.key --embed-certs=true
創建context:kubectl config set-context czl@kubernetes --cluster=kubernets --user=czl
創建集群: kubectl config set-cluster --kubeconfig=/tmp/admin.conf --server="https://172.20.0.73:6443" --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true
創建secret:create secret generic xxx -n kube-system --from-file=xx.crt=./xxx.crt --from-file=./xxx.key
刪除:
kubectl --kubeconfig=config-demo config unset users.<name>
kubectl --kubeconfig=config-demo config unset clusters.<name>
kubectl --kubeconfig=config-demo config unset contexts.<name>
問題:
1.提示需要輸入密碼:
正常的config view輸入應該如下:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.1.184:6443
name: DLWS
contexts:
- context:
cluster: DLWS
user: admin
name: context-DLWS-admin
current-context: context-DLWS-admin
kind: Config
preferences: {}
users:
- name: admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
看看set-credentials的參數是否對齊
2.kubeconfig文件生成后,如果需要更改user等,需要刪掉文件后重新生成,set-context等命令不會覆蓋
RBAC:(用於pod的屬性serviceAccount)
kubeadm init搭建的集群默認是啟用了rbac --authorization-mode=Node,RBAC
role:
operations:
objects
rolebinding
位於一個名稱空間下
user account或service account
role
# 也可以綁定clusterRole,作為當前binding所在ns下的管理員!!!
# 可以建立一個clusterrole,然后rolebing為各個namespace下的管理員
clusterRole\clusterrolebinding
集群級別
創建role:
create role reader --verb=get,list --resources=pods
kind:Role
rules:
- apiGroups:
- "" # 一般不需指定
resources:
- pods
verbs:
- get
- list
創建rolebinding
create rolebinding name --clusterrole=name|--role=name
kind:RoleBinding
metadata:
name
namespace
roleRef:
apiGroup:rbac.authorization.k8s.io
kind:Role
name:pods-reader
subjects:
- apiGroup:rbac.authorization.k8s.io
kind:User # 可以是group,例如kubernetes-admin就屬於system:masters組
# openssl x509 -in ./apiserver-kubelet-client.crt -text -noout
# serviceAccount
name:czl
創建clusterrole
create clusterrole NAME --verb=get,list,watch --resource=pods -o yaml
其他類似
創建clusterrolebinding
create clusterrolebinding NAME --cluster-role=xxx --user=xxx
kubectl create clusterrolebinding default-cluster-admin --clusterrole=cluster-admin --serviceaccount=default:default --dry-run -o yaml
為node添加role:
kubectl label node master02 kubernetes.io/role=master
dashboard:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml
更改為nodePort后即可訪問
選擇serviceaccount的令牌或kubeconfig讓dashboard認證到k8s集群
生成專門證書:
(umask 077;openssl genrsa -out dashboard.key 2048)
openssl req -new -key dashboard.key -out dashboard.csr -subj "/O=czl/CN=domain" 證書簽屬請求
用系統ca簽:openssl x509 -req -in dashboard.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out dashboard.crt -days 365
創建secret:create secret generic xxx -n kube-system --from-file=xx.crt=./xxx.crt --from-file=./xxx.key
創建serviceaccount
create serviceaccount xxx -n kue-system
進行rolebinding
create clusterrolebinding xxx --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
找到綁定后生成的secret,describe打開復制令牌token即可
要想使用證書
權限控制
創建一個serviceaccount
create rolebinding xxx --clusterrole=admin --serviceaccount=default:xxx
config set-cluster kubernetes --certificate-authority=./ca.crt --server="https://172.20.0.0:6443" -embed-certs=true --kubeconfig=/tmp/admin.conf
設置用戶賬號
# 解密token: kubectl get secret xxx -o json這個其實就是describe獲取到的base64加密后的,每個sa賬號自動創建
config set-credentials admin --token=xxxxxx --kubeconfig=/tmp/admin.conf
kubectl config set-context xxx@kuberbetes --cluster=kubernetes --user=admin --kubeconfig=/tmp/admin.conf
config use-context xxx@kuberbetes --kubeconfig=/tmp/admin.conf
自定義證書如何生成配置:
config set-credentials xxx --client-certificate=./xxx.crt --client-key=./xxx.key導入證書
使用set-context設置所綁定的用戶:set-context xxx --cluster=kuberbetes --user=xxx
CNI:
概述:
容器間通信
包含兩個,一個是cni工具bin(coredns和kubelet都依賴),一個是cni插件,如weave
flannel:
背景:
container1要想與外界通信並且回來,本身生成的虛擬網卡eth0,關聯到docker臨橋veth上;
離開宿主機時在eth0做源地址轉換
container2要想服務被訪問,也要在物理機上做目標地址轉換,暴露出來
通信種類:
1.容器間通信:同一個pod內,通過lo
2.pod之間通信
3.pod與service通信 # 不在同一網段,通過itable或ipvs通信,切換mode在configmap中切換集群使用哪個
4.service與集群外通信
解決方案:
虛擬網橋,一半在pod,一半在宿主機上接入網橋中,還可以接入真實接口相關的網橋上使用物理橋接的方式
多路復用:MacVLAN
硬件交換:SR-IOV單根虛擬化
配置路徑:
/etc/cni/net.d/ k8s會自動加載該路徑下的網絡插件
flannel優缺點:
簡單,但不提供網絡策略,進行網絡隔離,集群內不同ns可以訪問
方法:
使用VxLAN,經過隧道接口封裝報文進行通信,支持vxlan\directrouting
host-gw主機網關,使用主機網關,要求同一網段
VxLAN+host-gw:directrouting同一網段使用host-gw,隔路由使用VxLAN
UDP:性能差,舊版本使用
部署:
任何kubelet的node都需要flannel來與pod通信,系統進程\kaemonset方式,每個node一個
配置參數:
Network:flannel使用的CIDR格式的網絡地址,用於為pod配置網絡功能
10.244.0.0/16 =》 master:10.244.0.0/24 node01:10.244.1.0/24 ... 10.244.255.0/24
SubnetLen:把network切分子網供各節點使用時,使用多長的掩碼進行切分,默認24位
SubnetMin:10.244.10.0/24
SubnetMax:10.244.100.0/24
Backend:vxlan,host-gw,udp
配置示例:
{"Network":"","Backend":{"Type":"vxlan","Directrouting":true}}
下載配置文件,修改backend即可
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/k8s-manifests/kube-flannel-legacy.yml
配置修改后需要重啟pod才生效
calico:
作為網絡插件時,網段是192.168.0.0/16
僅用來部署policy
部署:
使用k8s自帶的etcd來存儲數據
1.如果啟用了rbac,需要配置role和綁定
kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/rbac.yaml
2.kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/canal.yaml
應用:
部署calico后,就可以使用policy控制不同命名空間之間的通信
Egress出棧控制to,ports
Ingress入棧控制from,要去的ports
# 注意policy控制的是對應命名空間下的pod的出入棧
定義networkpolicy:
apiVersion:networking.k8s.io/v1
spec:
egress:
- ports:
- port:
protocal
to:
- podSelector: # 控制pod之間通信
namespaceSelector: # 控制名稱空間
ipBlock # ip塊
ingress: # - {} 表示允許所有
- from:
- ipBlock:
cidr: 10.244.0.0/16
except:
- 10.244.1.2/32
ports:
- port:80
protocol:TCP
podSelector: # {}全部pod
matchLabels:
app: myapp
policyTypes:["Egress"] # 默認定義了都生效,如果沒定義的話,默認應用拒絕
調度器scheduler:
默認scheduler調度資源,返回給apiserver,存入etcd
資源限制:
下限和上限
調度策略:
1.Predicate預選過程:排除不符合的node
2.Priority優選:計算各個node的優先級
3.Select取最高優先級的
Pod選擇:
nodeName
nodeSelector 影響調度策略的范圍
調度方式:
1.nodeAffinity節點傾向性\親和性,通過nodeSelector、nodename完成調度
2.podAffinity\podAntiAffinity pod傾向性,運行在同一個node
3.Taints污點\污點容忍Tolerations:打上污點后不運行pod,pod要想運行必須容忍所有的污點
預選策略:
CheckNodeCondition檢測node是否正常
GeneralPredicates包含了幾種
hostname:檢測pod對象是否定義了pod.spec.hostname,調度到匹配的主機
PodFitsHostPorts:pods.spec.containers.ports.hostPort檢測端口是否占用
MatchNodeSelector:pod.spec.nodeSelector
PodFitsResources:檢測node資源是否足夠
NoDiskConflict:沒有磁盤沖突,存儲卷類型需求(不是默認)
PodToleratesNodeTaints:檢查pod的spec.toleration是否包含node的污點
PodToleratesNodeNoExecuteTaints:檢查
CheckNodeLabelPresence:默認禁用
CheckServiceAffinity:傾向於service已有pod的node
MaxEBSVolumeCount
MaxGCEPDVolumeCount
MaxAzureDiskVolumeCount
CheckVolumeBinding:查看所需pvc的node
NoVolumeZoneConflict:
CheckNodeMemoryPressure:
CheckNodePIDPressure:
CheckNodeDiskPressure:
MatchInterPodAffinity:檢查pod的親和性
優選函數:
least_requested:占用node資源比例最低的
balanced_resource_allocation:資源占用比率相近
node_prefer_avoid_pods:根據node注解信息scheduler.alpha.kubernetes.io/preferAvoidPods
taint_toleration:將pod對象的tolerations與node的taints對比
selector_spreading:散開pod對象
InterPodAffinity:pod親和性
NodeAffinity:
(未啟動)
MostRequested:傾向於集中node運行任務,空閑其他node
NodeLabel:看標簽即可,不看值
ImageLocality:node是否有所需的鏡像
# 看綜合得分
使用nodeSelector:
spec:
containers:
nodeSelector:
app:myapp
使用affinity:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions
- key:zone
operator:In
value:
- foo
- bar
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
weight:1-100
podaffinity可以通過nodeaffinity來實現,但需要編排兩次
podAffinity49472:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key:app,operator:In,value:["myapp"]}
topologyKey:kubernetes.io/hostname # 使用這個來區分node位置
preferredDuringSchedulingIgnoredDuringExecution#類似
podAffinityTerm
labelSelector
topologyKey: kubernetes.io/hostname # 根據節點hostname來判斷親和
podAntiAffinity類似,效果相反
使用taints:node選擇pod
effect:定義對pod的排斥效果
NoSchedule僅影響調度、NoExecute不能運行、PreferNoSchedule:柔性影響調度
管理node污點:
kubectl taint node name key1=value1:effect1 ...
taint key1-
設置pod的toleration:
spec:
tolerations:
- key:"node-type"
operator:"Equal" # Exists
value:"production"
effect:"NoSchedule" # 要准確對應污點的effect,空時匹配所有效果
# tolerationSeconds:3600
每次更改pod的toleration后會重新調度
容器的資源需求:
cpu可壓縮,內存不可壓縮,會OOM
requests和limits,調度pod時看node上運行的pod的requests之和,作為已分配出去的資源
CPU:
兩核四線程為4個邏輯CPU
1=1000微核心millicores
內存:
E\P\T\G\M\K
Ei\Pi\Ti\Gi\Mi\Ki 1024
定義:
containers:
- name:
resources:
requests:
cpu:"500m"
memory:"256Mi"
limits:
cpu:
memory:
Qos:
Guranteed:每個同時設置了cpu和內存的requests和limits,且相同
Burstable:至少有一個容器設置了cpu或內存的requests屬性,優先終止占用request資源比例大的pod
BestEffort:沒有任何一個容器設置了request或limits屬性,最低優先級
HeadpSter:
kubelet中采集node資源情況的是內置的cAdvisor
HeadpSter收集各個node的cAdvisor,緩存一段時間
持久歷史放在InfluxDB,通過grafana進行可視化
部署influxdb:
https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/influxdb.yaml
wget下載,修改version為apps/v1,修改nodeselector,修改存儲卷,services
部署heapster:
https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/rbac/heapster-rbac.yaml
https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/heapster.yaml
先進行role綁定,再部署serviceaccount\deployment
修改version為apps/v1,修改nodeselector
command連接到influxdb,指定source=kubernetes:https://kubernetes.default定義了如何連接apiserver
--sink=influxdb:http://monitoring-influxdb.kube-system.svc:8086指向influxdb的service
部署grafana:
https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/grafana.yaml
wget,修改apiversion為apps/v1,添加對應的selector,修改service的type為nodePort
https證書自動掛載本地的/etc/ssl/certs
添加dashborad即可可視化
如果經過nginx代理,grafana可能會找不到靜態文件,需要修改homepage之類的。
hostNetwork為true,直接訪問其他端口3000,而不是更改url則沒問題
命令行查看:
kubectl top node\pod
資源指標與自定義指標:
一些HPA、top命令早期依賴heapster,僅支持內存和cpu指標
heapster為了適配各種存儲后端,整合了多個適配器,更新緩慢,導致代碼大
新一代依靠metrics-server這個API server服務與資源指標,部署為pod
自定義指標:premetheus,組件k8s-prometheus-adapter
新一代架構:
核心指標流水線:由kubelet、metrics-server以及API server提供的api組成,CPu累積使用率、內存實時使用率,pod資源占用以及容器磁盤使用率
監控流水線:用於從系統收集各種指標數據並提供終端用戶、存儲系統以及HPA,包含許多核心指標和非核心指標。
metrics-server提供資源指標,由kube-aggregator聚合metrics-server和apiserver的原生指標,通過/apis/metrics.k8s.io/v1beta1
部署metrics-server:
https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/metrics-server
for file in auth-delegator.yaml auth-reader.yaml metrics-apiserver.yaml metrics-server-deployment.yaml
metrics-server-service.yaml resource-reader.yaml;do wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/metrics-server/$file;done
apply后kubectl api-versions即可查看新url
查看metrics資源:
master下用kubectl proxy --port=8080
然后curl http://localhost:8080/apis/metrics.k8s.io/v1beta1
問題:獲取不了數據
1.修改command:改默認10255為10250
默認通過http的kubernetes.summary_api的默認鏈接來訪問,但被默認禁用了
/metris-server --source=kubernetes.summary_api:https://kubernetes.default?kubeletHttps=true&kubeletPort=10250&insecure=true
# 新版的不用修改了
2.修改clusterRole的resources添加一個nodes/stats
部署prometheus獲取其他指標:
Prometheus為server,client為node_exporter采集系統數據,其他數據需要如mysql_exporter
通過PromQL提供restful接口數據,經過Prometheus adapter轉為metrics api的數據
git clone https://github.com/iKubernetes/k8s-prom.git
1.部署node-exporter,daemonset的形式,采集node的數據
kubectl apply -f ./k8s-prom/node_exporter/
2.部署prometheus以及相應的serviceaccount、rolebinding、service,即可訪問webui
默認監聽9090
將service端口30090加到nginx中,但還是有非根目錄導致404靜態文件的問題
kubectl apply -f ./k8s-prom/prometheus/
在啟動的時候設置web.external-url使用下面的命令:
./prometheus --web.external-url=prometheus --config.file=prometheus.yml
nginx配置為 location /prometheus proxy_pass http://prometheus.prom.svc.cluster.local:9090/prometheus
登錄網頁即可查看指標
curl http://localhost:9091/prometheus/api/v1/label/__name__/values # grafana通過這個接口來查詢metrics
3.部署kube-state-metrics轉為metrics api指標
./k8s-prom/kube-state-metrics/
4.部署kube-prometheus-adapter,自制k8s簽署的證書cm-adapter-serving-certs,生成generic secret供https使用
cd /etc/kubernetes/pki/
(umask 077;openssl genrsa -out serving.key 2048)
openssl req -new -key serving.key -out serving.csr -subj "/CN=serving"
openssl x509 -req -in serving.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out serving.crt -days 3650
kubectl create secret generic cm-adapter-serving-certs --from-file=./serving.crt --from-file=serving.key -n prom
apply -f ./k8s-prom/k8s-prometheus-adapter/ # deploy取自https://github.com/DirectXMan12/k8s-prometheus-adapter/tree/master/deploy/manifests
即可看到自定義的custom.metrics.k8s.io/v1beta1
curl http://localhost:8080/apis/custom.metrics.k8s.io/v1beta1
配合HPA或grafana定義數據源導入模板即可
應用grafana,注釋掉env中的influxdb,修改namespace
# 進入所在pod,修改配置/etc/grafana/grafana.ini,修改root_url = http://apulis-china-infra01.sigsus.cn/grafana
修改yaml中的env的GF_SERVER_ROOT_URL為/grafana/ # 進入pod查看root_url沒變
nginx代理數據源為proxy_pass http://prometheus.prom.svc.cluster.local:9090/;
在grafana dashborad搜索kubernetes模板,下載json,在home導入即可
# 數據源也可以配置
如何調試:
頁面登錄賬號后,就可以編輯pannel,添加數據源等,在pannel中調試數據源的指標,點擊Query Inspector即可顯示url
這個url可以前端請求來獲取資源數據
HPA:
自動伸縮容
kubectl autoscale deployment myapp --min=1 --max=8 --cpu-percent=60 # 默認使用v1控制器
進行請求壓測install httpd-utils
ab -c 1000 -n 500000 http://xxx
v2控制器可以使用其他評估指標
kind:HorizontalPodAutoscaler
metadata:
spec:
scaleTargetRef:
apiversion:apps/v1
kind:Deployment
name:myapp
minReplicas:1
maxReplicas:8
metrics:
- type:Resource
resource:
name:cpu
targetAverageUtilization:55
- type:resource
resource:
name:memory
targetAverageValue:50Mi # v1不支持內存
自定義指標輸出:如pod的最大請求數,hpa收集
- type:Pods
pods:
metricName:http_requests
targetAverageValue:800m # 個
Helm入門:
命令行工具,不直接交互apiserver,而是Tiller,運行為pod
下載需要的chart到本地,不同的配置文件成為不同的release
helm支持chart版本更新,查詢和卸載等操作,將配置清單可復用
核心術語:
Chart:一個helm程序包
Repository:倉庫
Release:特定的Chart部署於目標集群上的一個實例
架構:
chart->config->release
tiller接收helm發送的charts和config,合並為release
安裝:
wget https://get.helm.sh/helm-v2.9.1-linux-amd64.tar.gz --no-check-certificate
helm使用kubectl的配置文件來訪問apiserver
配置role:
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
安裝tiller:
helm init --service-account tiller
鏡像下載不了,kubectl edit deploy tiller-deploy -n kube-system改為jinxiaoyuan/tiller
# 或者先pull鏡像,tag
# docker pull jinxiaoyuan/tiller:v2.9.1
sudo apt install socat
倉庫:
https://hub.helm.sh/
helm repo update
helm search redis
heml inspect stable/redis
helm install --name myredis -f value.yaml stable/redis
helm delete/status/history xx
create/fetch/get(不解包)/package/verify
目錄結構:
xxx:
Chart.yaml # helm本身維護的chart元信息
README.md
charts: # 放置依賴
requirements.yaml #
templates
_helpers.tpl
xxx.yaml # 大量利用go模板語法生成字段
values-production.yaml
values.yaml # 配置變量,install -f可以指定自定義變量文件
自定義chart:
go模板語法:{{.Values.imageRegistry}} 表示引用values.yaml文件的第一層次字段imageRegistry
{{default "" .Values.imageRegistry}}
helm create myapp編輯好values后
helm lint myapp
helm serve
helm package myapp
helm search myapp
helm install --name myapp local/myapp
helm status myapp
helm delete --purge myapp
日志系統:
部署方案:
1.sidecar,不建議一個pod超過兩個容器
2.部署為daemonset
ELK:
使用每個node的fluentd+logstash server+elastic master接收請求+data處理后端
部署:
helm fetch stable/elasticsearch
修改values文件
helm install --name els --namespace=prom -f values.yaml stable/elasticsearch
運行測試程序:
kubectl run cirror --rm -it -image=cirros -- /bin/bash
curl elasticd的域名:9200/_cat/nodes
部署fluentd每個node收集日志:
helm fetch stable/fluentd-elasticsearch
填寫es域名和9200,如果master要收集要填寫tolerations,要監控填寫prometheus
helm install --name flu --namespace=prom -f values.yaml stable/fluentdel-asticsearch
部署kibana:
helm etch stable/kibana
填寫es地址
helm install --name kib --namespace=prom -f values.yaml stable/kibana
Paas概述:
CI(Continuous Integration)\CD\CD
發布過程:
developer->git->Jenkins/CI->application->docker build->docker hub->k8s
developer->git->docker file->docker build->docker hub->k8s
developer用python寫一段代碼,實現自動發布到k8s
Paas:
openshit:包含一整套k8s以及日志監控、自動發布上線的os
命名空間:
示例:
kubectl get ns default -o yaml --export
---
apiVersion:v1
kind:Namespace
metadata:
name:develop # 其他的createTime\selfLink會自動生成
spec:
finalizers:
- kunernetes # 負責回收,可以不定義
搭建DLWS:
用到的服務:
PXE預啟動執行環境,提供一種網絡接口啟動計算機的機制
重定向服務(DHCP代理)
TFTP協議下載到內存
資源:
一台服務器時可以起docker在里面部署本機為master,部署機本身始終沒有啟動任何服務,都是通過腳本ssh到遠程執行命令
(按道理可以本機部署本機?)
域名注冊和dns解析(阿里雲購買域名后免費提供解析)
更新hostname為子域名
流程:
前置:
如果部署過kubeadm,記得apt remove\autoremove清空,然后重新./deploy.py -y build
1.在部署機ubuntu上安裝基本所需工具
如果是docker內部署本機,sudo docker run -v /var/run/docker.sock:/var/run/docker.sock -v ~/:/home/dlwsadmin -it ubuntu:16.04
sh ../../install_prerequisites.sh
兩個node一個master:
apt install net-tools,vim,sudo,openssh-server
sudo systemctl start ssh
passwd
vim /etc/ssh/sshd_config #PermitRootLogin prohibit-password為PermitRootLogin yes,再運行密碼登錄,重啟ssh
etc/init.d/ssh start
apt-get install openssh-server
最后因為docker沒有bus,進行不下去
2.配置集群config.yaml,配置id,domain,machine
3.如果系統未安裝,部署機可以安裝PXE
4.執行./deploy.py -y build
wget http://ccsdatarepo.westus.cloudapp.azure.com/data/containernetworking/cni-amd64-v0.5.2.tgz
mkdir ./deploy/bin && mv cni-amd64-v0.5.2.tgz ./deploy/bin/
5.將賬號密碼輸入echo dlwsadmin > ./deploy/sshkey/rootpasswd ./deploy/sshkey/rootuser以便部署機使用賬號密碼訪問
6.安裝key ./deploy.py sshkey install
7.查看key是否安裝成功./deploy.py execonall sudo ls -al
8.遠程為node安裝基本工具./deploy.py runscriptonall ./scripts/prepare_ubuntu.sh
./deploy.py execonall sudo usermod -aG docker dlwsadmin
9.下載鏡像
./deploy.py execonall docker pull dlws/pause-amd64:3.0
./deploy.py execonall docker tag dlws/pause-amd64:3.0 gcr.io/google_containers/pause-amd64:3.0
10.開始部署kubernets
./deploy.py -y deploy # 如果部署失敗,systemctl status kubelet查看原因,如/etc/hosts沒有加入短域名,端口1443未外網開放
./deploy.py -y updateworker # 不同集群的機器作為worker的話,執行這個沒有成功加入。如果集群內兩台機器,則稍等后可以看到node
./deploy.py labelworker
./deploy.py -y kubernetes labelservice # 根據域名來label node,如果域名不一致,會失敗
在master上啟動workload
./deploy.py -y kubernetes uncordon
創建軟鏈
sudo ln -s /home/ubuntu/QianJiangYuan/src/ClusterBootstrap/deploy/bin/kubectl /usr/bin/kubectl
11.掛載分享文件盤
./deploy.py mount
./deploy.py mount stop
12.deploy nvidia-device
准備:安裝顯卡驅動
./deploy.py kubectl label node apulis-sz-dev-worker01 gpuType=nvidia
./deploy.py kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.9/nvidia-device-plugin.yml
# v1.9版本與kubelet相關,要看版本,k8s版本1.15以上用v1.11
sudo apt-get install nvidia-container-runtime
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
&& curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \
&& curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
curl -s -L https://nvidia.github.io/nvidia-container-runtime/experimental/$distribution/nvidia-container-runtime.list | sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
apt-get update
apt-get install -y nvidia-docker2
cat /proc/driver/nvidia/version
設置/etc/docker/daemon.json
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
},
"registry-mirrors": ["https://expuzg6d.mirror.aliyuncs.com"]
}
# 遇到too old to support healtchecking with error: %!s(MISSING). Marking it unhealthy
給plugin添加env DP_DISABLE_HEALTHCHECKS=xids
13.部署各個service
./deploy.py webui
./deploy.py docker push restfulapi
./deploy.py docker push webui3
./deploy.py docker push init-container
./deploy.py docker push prometheus # 監控組件
./deploy.py docker push grafana
./deploy.py docker push collectd
./deploy.py docker push influxdb
./deploy.py docker push nginx
./deploy.py nginx fqdn
./deploy.py nginx webui3
./deploy.py nginx config # 復制文件到/etc/nginx/conf.other
./deploy.py setconfigmap
./deploy.py kubernetes start mysql jobmanager2 restfulapi2 webui3 monitor nginx custommetrics repairmanager2 openresty
# 會以集群name為前綴拉起image,修改config.yaml可以生效
# nginx的certbot需要解析域名,如果是local域名,需要配置/etc/resolv.conf為本地,如果是公網域名,/etc/resolv.conf為公開dns地址即可
14.清理集群
./deploy.py cleanworker
./deploy.py cleanmasteretcd
./deploy.py clean
./deploy.py kubeadm reset
kubeadm部署方式
10. ./deploy.py --verbose kubeadm init
11. ./deploy.py --verbose kubeadm join
其余相同
修改apiserver的nodeport的范圍
vim /etc/kubernetes/manifests/kube-apiserver.yaml
增加參數- --service-node-port-range=1-65535
# 好像不用重啟
systemctl daemon-reload
systemctl restart kubelet
備份配置文件:
./deploy.py backup [backup_file_prefix] [password] # 前綴
./deploy.py restore [backup_file] [password]
./deploy.py restorebin # 第二個command為restore的地方會被第一個攔截,修改為restorebin
需要用到鏡像
docker pull rancher/hyperkube:v1.16.9-rancher1
docker tag rancher/hyperkube:v1.16.9-rancher1 gcr.azk8s.cn/google-containers/hyperkube:v1.15.2
即可正常執行kubernetes命令
HA:
官方文檔:
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/
1.利用vip鏡像生成/etc/kubernetes/manifests/vip.yaml
2.通過命令生成ha初始集群
kubeadm init --v=8 --control-plane-endpoint=10.31.3.207 --kubernetes-version=v1.18.2 --upload-certs
3.加入剩余的master和worker
kubeadm init --v=8 phase upload-certs --upload-certs
kubeadm token create
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
kubeadm join --v=8 --token %s %s:%s --discovery-token-ca-cert-hash sha256:%s --control-plane --certificate-key %s
sudo kubeadm join --v=8 --token %s %s:%s --discovery-token-ca-cert-hash sha256:%s
vip原理:
docker容器先檢測本地的物理接口eno1,增加inet6,然后容器能夠ping通后,生成vip到具體的master上,局域網內可以訪問這個vip
二進制搭建kubernetes集群:
微軟方式:
生成ca證書
mkdir -p ca
openssl genrsa -out ca/ca-key.pem 2048
openssl req -x509 -new -nodes -key ca/ca-key.pem -days 10000 -out ca/ca.pem -subj "/CN=kube-ca"
生成kubelet證書:
編輯文件openssl-kubelet.cnf:
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
DNS.5 = *.sigsus.cn
DNS.6 = *.redmond.corp.microsoft.com
DNS.7 = *.corp.microsoft.com
mkdir -p kubelet
openssl genrsa -out kubelet/apiserver-key.pem 2048
openssl req -new -key kubelet/apiserver-key.pem -out kubelet/apiserver.csr -subj "/CN=kube-apiserver" -config openssl-kubelet.cnf
openssl x509 -req -in kubelet/apiserver.csr -CA ca/ca.pem -CAkey ca/ca-key.pem -CAcreateserial -out kubelet/apiserver.pem -days 3650 -extensions v3_req -extfile openssl-kubelet.cnf
cp ca/ca.pem kubelet
rm ca/ca.srl
rm kubelet/apiserver.csr
生成etcd證書
mkdir -p etcd
openssl genrsa -out etcd/etcd-key.pem 2048
openssl req -new -key etcd/etcd-key.pem -out etcd/etcd.csr -subj "/CN=kube-apiserver" -config openssl-etcd.cnf
openssl x509 -req -in etcd/etcd.csr -CA ca/ca.pem -CAkey ca/ca-key.pem -CAcreateserial -out etcd/etcd.pem -days 3650 -extensions v3_req -extfile openssl-etcd.cnf
cp ca/ca.pem etcd
rm etcd/etcd.csr
復制到指定目錄下:
mkdir -p /etc/etcd/ssl
cp etcd/ca.pem /etc/etcd/ssl
cp etcd/etcd.pem /etc/etcd/ssl
cp etcd/etcd-key.pem /etc/etcd/ssl
配置etcd3 service:
編輯文件/etc/systemd/system/etcd3.service
[Service]
ExecStart=/usr/bin/docker run -v /usr/share/ca-certificates/mozilla:/etc/ssl/certs -v /etc/etcd/ssl:/etc/etcd/ssl -v /var/etcd:/var/etcd -p 2379:2379 -p 2380:2380 \
--net=host \
--name etcd3 dlws/etcd:3.1.10 /usr/local/bin/etcd \
-name dlworkspace-etcd1 \
-initial-cluster dlworkspace-etcd1=https://worker.sigsus.cn:2380 \
-initial-cluster-state new \
-initial-cluster-token 536eea5f-280e-453e-81a3-6198e66fb56d \
-advertise-client-urls https://worker.sigsus.cn:2379 \
-listen-client-urls https://0.0.0.0:2379 \
-initial-advertise-peer-urls https://worker.sigsus.cn:2380 \
-listen-peer-urls https://0.0.0.0:2380 \
-data-dir /var/etcd/data \
-client-cert-auth \
-trusted-ca-file=/etc/etcd/ssl/ca.pem \
-cert-file=/etc/etcd/ssl/etcd.pem \
-key-file=/etc/etcd/ssl/etcd-key.pem \
-peer-client-cert-auth \
-peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \
-peer-cert-file=/etc/etcd/ssl/etcd.pem \
-peer-key-file=/etc/etcd/ssl/etcd-key.pem
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
編輯文件/opt/etcd_ssl.sh
#ETCD_VER=v3.3.2 && DOWNLOAD_URL=https://github.com/coreos/etcd/releases/download && \
#curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz && \
#mkdir -p /tmp/test-etcd && \
#tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/test-etcd --strip-components=1 && \
#mkdir -p /opt/bin && \
#mv /tmp/test-etcd/etcd /opt/bin && \
#mv /tmp/test-etcd/etcdctl /opt/bin
#rm -r /tmp/test-etcd
docker rm -f etcd3
systemctl daemon-reload
systemctl start etcd3
systemctl enable etcd3
啟動etcd3服務
chmod +x /opt/etcd_ssl.sh
systemctl start etcd3
這一步嘗試去拉取鏡像,然后啟動容器,監聽端口2379
等待服務起來:
curl --cacert /etc/etcd/ssl/ca.pem --cert /etc/etcd/ssl/etcd.pem --key /etc/etcd/ssl/etcd-key.pem "https://127.0.0.1:2379/v2/keys"
設置network范圍:
curl --cacert /etc/etcd/ssl/ca.pem --cert /etc/etcd/ssl/etcd.pem --key /etc/etcd/ssl/etcd-key.pem -X PUT -d "value={\"Network\":\"10.2.0.0/16\",\"Backend\":{\"Type\":\"vxlan\"}}" "https://127.0.0.1:2379/v2/keys/coreos.com/network/config"
生成apiserver證書
編輯文件openssl-apiserver.cnf:
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
DNS.5 = worker.sigsus.cn
IP.0 = 10.3.0.1
IP.1 = 127.0.0.1
IP.2 = 127.0.1.1
mkdir -p apiserver
openssl genrsa -out apiserver/apiserver-key.pem 2048
openssl req -new -key apiserver/apiserver-key.pem -out apiserver/apiserver.csr -subj "/CN=kube-apiserver" -config openssl-apiserver.cnf
openssl x509 -req -in apiserver/apiserver.csr -CA ca/ca.pem -CAkey ca/ca-key.pem -CAcreateserial -out apiserver/apiserver.pem -days 3650 -extensions v3_req -extfile openssl-apiserver.cnf
cp ca/ca.pem apiserver
cp ca/ca-key.pem apiserver
rm apiserver/apiserver.csr
生成kubernetes證書:
執行腳本./gencerts_aggregator.sh,利用easyrsa生成pki/private/ca.key和pki/ca.crt,cfssl和cfssljson基於ca證書生成pki/issued/proxy-client.crt和pki/private/proxy-client.key,用於apiserver組件--proxy-client-cert-file
官方kubeadm的yaml除了--proxy-client-cert-file還有--kubelet-client-certificate等,需要的crt和key更多。
下載kubectl二進制文件
可以從鏡像獲取
docker create -it --name test dumb008/hyperkube:1.15.0
docker cp --follow-link=true test:/kubelet /opt/bin/kubelet
docker cp --follow-link=true test:/kubectl /usr/bin/kubectl
生成kubelet.service服務文件:
[Service]
Environment=KUBELET_VERSION=v1.5.2_coreos.0
Environment="RKT_OPTS=--uuid-file-save=/var/run/kubelet-pod.uuid \
--volume var-log,kind=host,source=/var/log \
--mount volume=var-log,target=/var/log \
--volume dns,kind=host,source=/etc/resolv.conf \
--mount volume=dns,target=/etc/resolv.conf"
ExecStartPre=/bin/bash -c 'mkdir -p /etc/kubernetes/manifests'
ExecStartPre=/bin/bash -c 'mkdir -p /var/log/containers'
#ExecStartPre=-/usr/bin/rkt rm --uuid-file=/var/run/kubelet-pod.uuid
ExecStartPre=/bin/bash -c 'if lspci | grep -qE "[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F].[0-9] (3D|VGA compatible) controller: NVIDIA Corporation.*"; then if [ -e /etc/systemd/system/nvidia-docker.service ] ; then until wget -q -O - http://localhost:3476/gpu/info ; do /bin/echo "waiting for nvidia-docker..." ; /bin/sleep 2 ; done fi fi'
#
# https://github.com/kubernetes/kubernetes/issues/48937
# Glusterfs currently need docker-disable-shared-pid option, will evaluate in future kubernete release
#
# https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/
ExecStart=/opt/bin/kubelet \
--volume-plugin-dir=/etc/kubernetes/volumeplugins \
--kubeconfig=/etc/kubernetes/worker-kubeconfig.yaml \
--register-with-taints=node-role.kubernetes.io/master=:NoSchedule \
--pod-infra-container-image=dlws/pause-amd64:3.0 \
--container-runtime=docker \
--feature-gates="DevicePlugins=true,PodShareProcessNamespace=true" \
--pod-manifest-path=/etc/kubernetes/manifests \
--network-plugin=cni \
--cluster_dns=10.3.0.53 \
--cluster_domain=cluster.local
#ExecStop=-/usr/bin/rkt stop --uuid-file=/var/run/kubelet-pod.uuid
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
復制證書文件、bin文件、kube系統的yaml文件以及其他文件到master
/etc/kubernetes/ssl/ca-key.pem
/etc/kubernetes/ssl/ca.pem
/etc/kubernetes/ssl/apiserver.pem
/etc/kubernetes/ssl/apiserver-key.pem
...
kube-apiserver.yaml # 里面的image為hyperkube,但可以參考官方的yaml文件
kube-controller-manager.yaml
kube-scheduler.yaml
3.啟動kubelet
sudo cp /etc/kubernetes/ssl/ca.pem /etc/ssl/etcd/ca.pem
sudo cp /etc/kubernetes/ssl/ca-key.pem /etc/ssl/etcd//ca-key.pem
sudo cp /etc/kubernetes/ssl/apiserver.pem /etc/ssl/etcd/apiserver.pem
sudo cp /etc/kubernetes/ssl/apiserver-key.pem /etc/ssl/etcd/apiserver-key.pem
sudo chmod +x /opt/bin/*
sudo systemctl daemon-reload
sudo systemctl stop kubelet
sudo systemctl start kubelet
sudo systemctl start rpc-statd
sudo systemctl enable kubelet
kubelet啟動后,查看status是否正常,docker ps查看manifests的幾個組件是否啟動
systemctl status kubelet
journalctl -xeu kubelet查看具體報錯原因,比如image拉取問題
docker ps
注:kubelet維護kube-apiserver kube-controller-manager kube-scheduler的正常運行,另外一種做法就是將kube-apiserver kube-controller-manager kube-scheduler單獨維護service,無需kubelet來維護,也可以用kubectl
kubelet此外還負責pod管理、節點管理等
等待8080端口(scheduler監聽)啟動后,kubectl即可用
kubectl get node
kubectl apply
通過kubectl和yaml啟動weave、dns-addon、kube-proxy
kubectl apply -f /opt/addons/kube-addons/weave.yaml --validate=false
kubectl apply -f /opt/addons/kube-addons/dns-addon.yml --validate=false
kubectl apply -f /opt/addons/kube-addons/kube-proxy.json --validate=false
問題:
1.weave啟動失敗,獲取kubernetes service失敗Get https://10.3.0.1:443/api/v1/nodes: dial tcp 10.3.0.1:443: i/o timeout
原因1:
發現apiserver組件log異常,Resetting endpoints for master service "kubernetes" to [127.0.0.1]
原來是yaml里面的--advertise-address指定了127.0.0.1
原因2:
kube-proxy是否正常啟動,它負責了iptables的建立,實現service與pod間的iptables調度或ipvs調度、即pod與集群間通信
2.kube-dns服務不好用
dns-addon組件log是否異常,然后定位本地的systemd-resolved是否啟動。
如何clean集群:
sudo systemctl stop kubelet
sudo systemctl stop etcd3
sudo timeout 10 docker rm -f $(docker ps -a | grep 'k8s_kube\|k8s_POD\|k8s_' | awk '{print $1}')
sudo rm -r /etc/kubernetes
sudo rm -r /etc/ssl/etcd
rm -r /var/etcd/data
rm -r /etc/etcd/ssl
sudo rm -r /etc/flannel
sudo rm -r /opt/addons
sudo systemctl daemon-reload
二進制做法:
1.安裝chrony時間服務
apt remove -y ntp
apt install chrony
配置一下主master上的/etc/chrony/chrony.conf,修改一下server地址、allow等
然后配置其他節點的pool為第一個master
2.生成CA根證書和私鑰
安裝cfssl:
apt install golang-cfssl
配置文件ca-config.json、ca-csr.json,里面不包含具體信息
執行cfssl gencert -initca ca-csr.json|cfssljson -bare ca生成ca.csr、ca-key.pem、ca.pem
3.生成對應的數字證書和私鑰用於kubectl、proxy、manager、scheduler
設置kubectl
配置admin-csr.json簽名請求,里面不包含具體ip信息,只有admin這個用戶名
簽發數字證書和私鑰,生成admin.csr、admin-key.pem、admin.pem
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
設置集群參數kubectl config set-cluster DLWS --certificate-authority=/root/kubernetes/ssl/ca.pem --embed-certs=true --server=https://192.168.1.184:6443 # 沒有指定路徑的話,生成文件/root/.kube/config
設置客戶端認證參數kubectl config set-credentials admin --client-certificate=/root/kubernetes/ssl/admin.pem --embed-certs=true --client-key=/root/kubernetes/ssl/admin-key.pem # --embed-certs為true,將證書寫入文件
設置上下文參數kubectl config set-context context-DLWS-admin --cluster=DLWS --user=admin
選擇默認上下文kubectl config use-context context-DLWS-admin
確認:kubectl config view
設置proxy,作為該組件的kubeconfig以獲取集群資源:
准備文件kube-proxy-csr.json,里面不包含具體信息
簽發:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
設置集群參數kubectl config set-cluster DLWS --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.1.184:6443 --kubeconfig=./kube-proxy.kubeconfig
設置客戶端認證參數kubectl config set-credentials kube-proxy --client-certificate=kube-proxy.pem --embed-certs=true --client-key=kube-proxy-key.pem --kubeconfig=./kube-proxy.kubeconfig
設置上下文參數kubectl config set-context default --cluster=DLWS --user=kube-proxy --kubeconfig=./kube-proxy.kubeconfig
選擇默認上下文kubectl config use-context default --kubeconfig=./kube-proxy.kubeconfig
設置kube-controller-manager,作為該組件的kubeconfig以獲取集群資源
准備文件kube-controller-manager-csr.json,里面不包含具體信息
簽發:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
設置集群參數kubectl config set-cluster DLWS --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.1.184:6443 --kubeconfig=./kube-controller-manager.kubeconfig
設置客戶端認證參數kubectl config set-credentials system:kube-controller-manager --client-certificate=kube-controller-manager.pem --embed-certs=true --client-key=kube-controller-manager-key.pem --kubeconfig=./kube-controller-manager.kubeconfig
設置上下文參數kubectl config set-context default --cluster=DLWS --user=system:kube-controller-manager --kubeconfig=./kube-controller-manager.kubeconfig
選擇默認上下文kubectl config use-context default --kubeconfig=./kube-controller-manager.kubeconfig
設置kube-scheduler,作為該組件的kubeconfig以獲取集群資源:
准備文件kube-scheduler-csr.json,里面不包含具體信息
簽發:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
生成config文件kubectl config set-cluster DLWS --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.1.184:6443 --kubeconfig=./kube-scheduler.kubeconfig
設置客戶端認證參數kubectl config set-credentials system:kube-scheduler --client-certificate=kube-scheduler.pem --embed-certs=true --client-key=kube-scheduler-key.pem --kubeconfig=./kube-scheduler.kubeconfig
設置上下文參數kubectl config set-context default --cluster=DLWS --user=system:kube-scheduler --kubeconfig=./kube-scheduler.kubeconfig
選擇默認上下文kubectl config use-context default --kubeconfig=./kube-scheduler.kubeconfig
復制到節點的對應目錄:
cp kube-proxy.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig /etc/kubernetes/ # 如果復制到其他master,需要替換掉其中的server ip
4.下載bin文件,生成etcd證書和私鑰,systemctl維護etcd服務(可以宿主機上后台進程)
ETCD_VER=v3.4.13
wget --tries=10 https://github.com/etcd-io/etcd/releases/download/$ETCD_VER/etcd-$ETCD_VER-linux-amd64.tar.gz
tar zxf etcd-$ETCD_VER-linux-amd64.tar.gz && cd etcd-$ETCD_VER-linux-amd64 && cp etcd etcdctl /opt/kube/bin
准備文件etcd-csr.json,里面包含具體ip信息hosts
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes etcd-csr.json | cfssljson -bare etcd
cp etcd-key.pem etcd.pem /etc/etcd/ssl/
mkdir /etc/kubernetes/ssl/
cp ca.pem ca-key.pem ca-config.json /etc/kubernetes/ssl/
准備etcd的service文件,復制到/etc/systemd/system/etcd.service
mkdir /var/lib/etcd
systemctl enable etcd
systemctl daemon-reload && systemctl restart etcd
服務起來后,監聽端口2379,用於與client端交互,監聽peer端口2380用於etcd內部交互
5.下載二進制文件,生成k8s證書,創建aggregator proxy相關證書,然后systemctl維護kube-apiserver kube-controller-manager kube-scheduler(可以宿主機上后台進程),kubectl即可用
K8S_VER=v1.18.0
wget --tries=10 https://dl.k8s.io/$K8S_VER/kubernetes-server-linux-amd64.tar.gz
tar zxf kubernetes-server-linux-amd64.tar.gz && cd kubernetes/server/bin && cp kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy kubectl /opt/kube/bin
mkdir /opt/cni/bin
准備cni插件,必須,kubeadm安裝的話自帶,二進制的話必須手動復制(cni插件是給coredns用的,默認讀取/opt/cni/bin/路徑)
CNI_VER=v0.8.7
wget --tries=10 https://github.com/containernetworking/plugins/releases/download/$CNI_VER/cni-plugins-linux-amd64-$CNI_VER.tgz
tar zxf cni-plugins-linux-amd64-$CNI_VER.tgz && cp bridge flannel host-local loopback portmap tuning /opt/cni/bin
准備文件kubernetes-csr.json,填上允許的ip,用於apiserver來決定從哪些ip(即kubeconfig中的server)可以訪問它(如果用了vip,則建議除了各master的ip,加上vip)
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
准備aggregator-proxy-csr.json,不包含ip信息
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes aggregator-proxy-csr.json | cfssljson -bare aggregator-proxy
准備三個系統組件的service文件
cp kube-apiserver.service kube-controller-manager.service kube-scheduler.service /etc/systemd/system/
復制相應的證書
cp kubernetes-key.pem kubernetes.pem /etc/kubernetes/ssl/
cp aggregator-proxy-key.pem aggregator-proxy.pem /etc/kubernetes/ssl/
cp admin-key.pem admin.pem /etc/kubernetes/ssl/
systemctl enable kube-apiserver kube-controller-manager kube-scheduler
systemctl daemon-reload
systemctl start kube-apiserver kube-controller-manager kube-scheduler
各個狀態均為running即可。
6.master部署kubelet和kube-proxy,然后kubectl get node信息才獲取到。
7.部署網絡組件、dns(順序可選最后),node變為ready
kubectl apply -f weave-role.yaml
kubectl apply -f weave.yaml
刪除原有cni配置/etc/cni/net.d/10-default.conf
ip link set mynet0 down
ip link del mynet0
重啟docker、kubelet、kube-proxy
准備coredns文件
kubectl apply -f coredns.yaml
8.kubelet證書和kubeconfig,kube-proxy證書和kubeconfig,worker節點復制證書、部署kubelet和kube-proxy
准備文件kubelet-csr.json,包含節點具體ip信息
證書除了用於生成kubeconfig,還用於kubelet的tlsCertFile。tlsCertFile包含的ip信息也會用於kubelet來與apiserver(ca證書)通信驗證hosts,所以新的節點ip也要更新。
否則,Error from server: Get https://192.168.1.153:10250/containerLogs/kube-system/kube-vip-3/kube-vip?follow=true: x509: certificate is valid for 127.0.0.1, 192.168.1.83, not 192.168.1.153
至於kubeconfig中的ca證書hosts是否包含ip,目前好像沒影響,只要求對應的user是相應的system:node:192.168.1.153即可。
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kubelet-csr.json | cfssljson -bare kubelet
cp kubelet-key.pem kubelet.pem /etc/kubernetes/ssl/ # 其他節點的話,就用scp即可
生成config文件kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.1.184:6443 --kubeconfig=./kubelet.kubeconfig
設置客戶端認證參數kubectl config set-credentials system:node:192.168.1.184 --client-certificate=kubelet.pem --embed-certs=true --client-key=kubelet-key.pem --kubeconfig=./kubelet.kubeconfig
設置上下文參數kubectl config set-context default --cluster=kubernetes --user=system:node:192.168.1.184 --kubeconfig=./kubelet.kubeconfig
選擇默認上下文kubectl config use-context default --kubeconfig=./kubelet.kubeconfig,使得kubelet可以訪問集群資源,role為system:node
cp ./kubelet.kubeconfig /etc/kubernetes/
准備cni配置/etc/cni/net.d/10-default.conf # 用於初始化master的時候kubelet變為ready用的,不然一直不ready,因為這個時候network插件還沒部署。Unable to update cni config: no networks found in /etc/cni/net.d
准備kubelet yaml文件/var/lib/kubelet/config.yaml
准備kubelet.service文件/etc/systemd/system/kubelet.service
systemctl enable kubelet
systemctl daemon-reload && systemctl restart kubelet
准備kube-proxy文件/etc/systemd/system/kube-proxy.service
mkdir /var/lib/kube-proxy
systemctl enable kube-proxy
systemctl daemon-reload && systemctl restart kube-proxy
為節點打上相應的role名字kubectl label node 192.168.1.184 kubernetes.io/role=master --overwrite
擴容worker:
cp ca.pem ca-key.pem ca-config.json /etc/kubernetes/ssl/
准備/opt/cni/bin和/opt/kube/bin/
swapoff -a && sed -i '/swap/d' /etc/fstab && sysctl -w vm.swappiness=0
為該節點生成對應ip的kubelet-key.pem kubelet.pem(kubeconfig要重新生成,否則提示system:node:192.168.1.83cannot get resource,can only access node lease with the same name)
scp ca.pem ca-key.pem ca-config.json /etc/kubernetes/ssl/
准備文件/var/lib/kubelet/config.yaml和/etc/systemd/system/kube-proxy.service、/etc/systemd/system/kube-proxy.service
啟動kubelet和kube-proxy
擴容master:
在worker的基礎上
scp kube-proxy.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig /etc/kubernetes/ # 每個master的可以不同。
關於etcd:
原有的etcd高可用集群,一開始初始化的時候都配置好了集群的成員member,而且/var/lib/etcd/為空,master一個個順序起來是可以的。
擴容相當於在/var/lib/etcd/數據已存在,member已確定的情況下,再添加一個node,這是不允許的。
對於擴容,由於member信息已經寫好,需要通過命令行增加member才行
./etcdctl member list
./etcdctl member add etcd2 --peer-urls=https://192.168.1.162:2380 # 否則error validating peerURLs,member count is unequal
然后etcd的service文件中需要配置--initial-cluster-state=existing # 否則提示cluster ID mismatc,is starting a new election at term 173
service文件中的name要修改對應
不重新簽發證書會提示rejected connection from "192.168.1.162:60004" (error "remote error: tls: bad certificate", ServerName "")
重新簽發etcd證書,增加新的ip, # 每個master的該證書可以不同,只保留自己ip。
准備/etc/systemd/system/etcd.service
啟動etcd
重新簽發apiserver證書-kubernetes,增加新的hosts ip來允許從哪個節點上可以訪問它,復制到每個master上。該證書每個節點也可以不同。
cp kube-apiserver.service kube-controller-manager.service kube-scheduler.service /etc/systemd/system/ # kube-apiserver.service中的etcd server看情況需要增加
cp kubernetes-key.pem kubernetes.pem aggregator-proxy-key.pem aggregator-proxy.pem admin-key.pem admin.pem /etc/kubernetes/ssl/
cp kube-proxy.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig /etc/kubernetes/
systemctl enable kube-apiserver kube-controller-manager kube-scheduler
systemctl start kube-apiserver kube-controller-manager kube-scheduler
問題:etcd不斷在選擇,is starting a new election at term 1109,原因有兩個
1.高可用的集群中,etcd的數量不夠2個。
2.etcd初始化由於各種原因加入失敗,一直嘗試加入。
關於kube-vip,可以在kuernetes的主要組件起來后,啟用network后,再啟用vip.yaml文件,pod起來后,即可搭建一個vip供訪問。
部署方式一:先啟動kube-vip組件就提供一個虛擬ip,
kubeadm部署的話,沒有指定配置文件,但是傳了kubeconfig,也可以獲取到localPeer、remotePeers的信息。
kubeadm init初始化的時候指定--control-plane-endpoint為vip,為所有控制平面節點設置共享端點。
部署:
vip=192.168.1.35
docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod --interface ens3 --vip $vip --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml
kubeadm init --kubernetes-version=v1.18.2 --control-plane-endpoint $vip --upload-certs
初始化完成后,會給出其余master和worker join的命令
這個時候節點還沒ready,因為Unable to update cni config: no networks found in /etc/cni/net.d,部署weave后coredns和集群網絡正常,node變為ready
kubeadm join 192.168.1.35:6443 --token ixbsy4.ku7tjmmzgjp307io --discovery-token-ca-cert-hash sha256:4572e960edd6ea8 --control-plane --certificate-key 1ac26cc40c9f6d8a23eb414e361ed8d8a3d9fe1d6df2fc076f61dbc7425d7ab5
其中的certificate-key可以通過kubeadm init phase upload-certs --upload-certs得出,token可以通過kubeadm token create或kubeadm token create --print-join-command,
discovery-token-ca-cert-hash可以通過openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
問題:
如果一開始join失敗,后面再join會出現etcd等待第二個節點選舉的問題,導致vip等待etcd一直起不來,導致apiserver(6443)用vip無法訪問,同時也導致kubelet無法訪問apiserver無法提供管理服務,
將主節點重新部署后,一次性加入即可成功。如果嘗試清空/var/lib/etcd會導致集群信息丟失。
兩個master節點的集群當一個master停機時也會這樣。
docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod --interface ens3 --vip $vip --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml
注意不同節點的網卡可能不同。
高可用:
一個非leader的node停機時,其他節點的etcd會嘗試連接該節點,vip繼續正常工作。
兩個非leader的node停機時,當前leader的vip由於etcd忙於選舉,起不來,整個服務停止。開機后恢復正常。
leader所在node停機時,vip組件切換leader,提示This node is starting with leadership of the cluster,Broadcasting ARP update。
delete一個node時,該node上還存在vip,vip不會漂移,因為kubelet服務沒停,manifest還存在,直到kubeadm reset停掉container。
delete的節點需要處理etcd才能重新作為master加入。如果是worker則不用。如果是vip節點,還要ip ad del。
ETCDCTL_API=3 ./etcdctl --endpoints=127.0.0.1:2379 member list --cacert /etc/kubernetes/pki/etcd/server.crt --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key
ETCDCTL_API=3 ./etcdctl --endpoints=127.0.0.1:2379 member remove xxx --cacert /etc/kubernetes/pki/etcd/server.crt --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key
目前來看主要體現為
1.生成的kubeconfig文件里的server ip為vip。各個master的kubelet、apiserver等的ip還是自己的。
2.apiserver使用的證書多加上了vip。
部署方式二:集群各個node起來后,通過kube-vip組件提供一個高可用的vip
流程:
1.准備配置文件config.yaml,里面配置了localPeer、remotePeers、loadBalancers等,用於選舉leader和負載均衡
2.cp config.yaml /etc/kube-vip/config.yaml
3.准備yaml文件kube-vip.yaml,每個kube-vip需要指定運行的nodeName,不然會重復分配到一個節點上
4.kubectl apply -f kube-vip.yaml
5.同時,之前簽發的kubeconfig要確保server地址為vip,才能高可用(否則當最初節點停機后,其他master不能調度)。
注意:
kubeconfig要確保server地址為vip
HA高可用原理:
vip在多個master之間漂移,多個master的ip中之一。訪問的是當前leader所在節點的業務服務,要求master之間都有有完整的業務系統。
多個master啟動kube-apiserver kube-controller-manager kube-scheduler的address填的都是自己的ip,但etcd的--etcd-servers填的是同一個,這樣存儲是相同的。
也就是說,多master能實現同一個集群而不是單獨的集群,是通過同一個etcd來實現的。
worker的kubelet通過--kubeconfig里指定的server ip(vip)(set-cluster步驟生成)來向master通信請求,如表示worker自己處於ready狀態,master可以向worker分配job。
master和worker的kubelet.kubeconfig權限不一樣(通過clusterrolebinding指定User或者Group,非ServiceAccount)。
只要worker上的kubelet和kube-proxy起來后,kubectl get node就可以看到node了。這時候role還沒分配而已。這時候可以分配job了。
role沒有實際的用途,taint還有一點。
那么,如果vip組件在k8s之上的一層組件的話,可以在集群master都起來后再啟動。
master和worker節點的區別:
worker節點上只運行了kubelet和kube-proxy。
master除了運行了三個系統組件外,和worker的區別就是role的不同,導致了taint的不同。(可以將worker標記為master,但沒有三個組件,會異常)
vip工作原理:
arp廣播,配置localPeer、remotePeers、loadBalancers等,用於選舉leader,至少兩個節點(超過配置的半數)才能選舉成功。單個節點也可以。
需要startAsLeader: false # 是否一開始就作為leader,多個實例時后面的實例需要為false。不然都廣播,arp會收到多個包。
實現方式:
1.網卡雙ip的方式
ifconfig ens3:1 192.168.1.42/24或ip ad add 192.168.1.42/24 dev ens3
手動增加可以體驗arping收到多個來源
2.網卡雙ip+arp廣播實時更新其他機器(除沒有重啟的舊leader)的arp表
gratuitousARP: true(在2.2版本上為enableARP)
3.BGP方式
4.Packet方式
擴容:
一個kube-vip節點起來后,開始當leader
新加入master后,需要先修改之前master的配置,增加ip,重啟(否則新節點的投票會被拒絕), 然后新的master才能正常啟動。
測試:
通過stop docker可以看到選舉過程。
1.至少需要兩票,所以節點數量得為單數。
2.leader負責與其他候選人通信,當失聯時一直嘗試,直到恢復。
3.當leader失聯時,兩個節點進行選舉,選出新的leader
問題:
選舉新的leader后,如果機器沒有停電,只是關閉docker:
1.除了剩余master所在的機器(永遠實時更新),其他機器ip指向還是舊的(可以收到新的和舊的arp包,ssh登錄使用舊的)。
新增:可以通過ip route get 192.168.1.42查看可能的路由,如果是舊leader,雙網卡,返回的是dev lo
2.提供的6443還能訪問舊的節點服務。
3.使用arping/arp指令獲取到的mac地址是新的,但ping、ssh等命令還是用舊的。
4.tcpdump、nc等命令試了沒效果,可以嘗試arp -an和ip neigh查看arp緩存還是舊的mac地址,使用ip neigh flush清空后再ping可以獲取新的mac地址。
但一段時間后,機器的arp表又變回舊的mac地址,估計舊的一直在廣播。
新的機器如果從來沒有獲取過vip,可能優先選擇舊的。
5.原leader可以ip add show查看到vip綁定到網卡的inet上。執行刪除ip ad del 192.168.1.42/24 dev ens3和清空arp后其他機器不再收到舊的arp包(leader切換會自動在舊機器執行這個)。
原leader的雙ip不會自動刪除,需要重新上線后由pod自己刪除。
特點:
1.采用Chrony進行時間同步
NTP 客戶端的替代品,更快的同步只需要數分鍾而非數小時時間,從而最大程度減少了時間和頻率誤差,對於並非全天 24 小時運行的虛擬計算機而言非常有用
2.Cfssl與openssl區別在於cfssl可以使用json格式,較方便。
證書對比kubeadm:
admin-key.pem 用於apiserver的--kubelet-client-key(kubelet TLS 客戶端密鑰文件)pki/apiserver-kubelet-client.key
admin.pem 用於apiserver的--kubelet-client-certificate pki/apiserver-kubelet-client.crt
aggregator-proxy-key.pem 用於apiserver的--proxy-client-key-file(調用外部程序以處理請求)pki/front-proxy-client.key
aggregator-proxy.pem 用於apiserver的--proxy-client-cert-file pki/front-proxy-client.crt
ca-key.pem 用於controller-manager的--cluster-signing-key-file pki/ca.key
用於controller-manager的--service-account-private-key-file pki/sa.key
ca.pem 用於controller-manager的--cluster-signing-cert-file pki/ca.crt
用於controller-manager的--root-ca-file pki/ca.crt
/var/lib/kubelet/config.yaml pki/ca.crt
用於etcd的--trusted-ca-file pki/etcd/ca.crt
用於etcd的--peer-trusted-ca-file pki/etcd/ca.crt
用於apiserver的--client-ca-file pki/ca.crt
用於apiserver的--etcd-cafile(用於保護 etcd 通信的 SSL 證書頒發機構文件)pki/etcd/ca.crt
用於apiserver的--kubelet-certificate-authority kubeadm中沒有,證書頒發機構的證書文件的路徑。
用於apiserver的--service-account-key-file pki/sa.pub
用於apiserver的--requestheader-client-ca-file(驗證接入請求中客戶端證書的根證書包)pki/front-proxy-ca.crt
etcd-key.pem 用於etcd的--key-file pki/etcd/server.key
用於etcd的--peer-key-file pki/etcd/peer.key
etcd.pem 用於etcd的--cert-file pki/etcd/server.crt
用於etcd的--peer-cert-file pki/etcd/peer.crt
kube-controller-manager-key.pem
kube-controller-manager.pem
kube-controller-manager.kubeconfig 用於controller-manager的--kubeconfig controller-manager.conf
kubelet-key.pem 用於/var/lib/kubelet/config.yaml的tlsPrivateKeyFile kubeadm中的kubelet沒用上
kubelet.pem 用於/var/lib/kubelet/config.yaml的tlsCertFile kubeadm中的kubelet沒用上
kube-proxy-key.pem
kube-proxy.pem
kube-proxy.kubeconfig 用於kube-proxy service的--kubeconfig kubeadm中的daemon資源的kube-proxy這個configmap
kubernetes-key.pem 用於apiserver的--etcd-keyfile(用於保護 etcd 通信的 SSL 密鑰文件)pki/apiserver-etcd-client.key
用於apiserver的--tls-private-key-file(候選service-account-key-file)pki/apiserver.key
kubernetes.pem 用於kube-apiserver的--tls-cert-file pki/apiserver.crt
用於apiserver的--etcd-certfile pki/apiserver-etcd-client.crt
kube-scheduler-key.pem
kube-scheduler.pem
kube-scheduler.kubeconfig 用於kube-scheduler的--kubeconfig scheduler.conf
卸載weave流程:
1.刪除weave的k8s資源
2.rm -rf /etc/cni/net.d/10-weave.conflist
卸載集群:
1.清理etcd
systemctl stop etcd
systemctl disable etcd
rm -rf /var/lib/etcd /etc/etcd/ /etc/systemd/system/etcd.service
2.清理三個系統組件
systemctl stop kube-apiserver kube-controller-manager kube-scheduler
systemctl disable kube-apiserver kube-controller-manager kube-scheduler
rm -rf /var/run/kubernetes /etc/systemd/system/kube-apiserver.service /etc/systemd/system/kube-controller-manager.service /etc/systemd/system/kube-scheduler.service
3.清理kubelet和kube-proxy
systemctl stop kubelet kube-proxy
systemctl disable kubelet kube-proxy
mount | grep '/var/lib/kubelet'| awk '{print $3}'|xargs umount || exit 0
rm -rf /var/lib/kubelet/ /var/lib/kube-proxy/ /etc/systemd/system/kubelet.service /etc/systemd/system/kube-proxy.service /opt/kube/kube-system/ /etc/kubernetes/
umount目錄:
/var/run/docker/netns/default
echo /var/lib/docker/overlay2/*/merged|xargs umount
/var/lib/docker/overlay
echo /var/lib/docker/containers/*/mounts/shm|xargs umount
echo /var/run/docker/netns/*|xargs umount