kubernetes整理知识点
基本介绍:
编排历史:
服务编排系统 =》容器编排系统
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