K8s常见面试题20问
灰度发布:也被叫作金丝雀发布。灰度发布属于增量发布方法。也就是说,服务升级的过程中,新旧版本会同时为用户提供服务。先将一小部分用户流量切换到新版本上,测试版本性能与功能.确认没有问题后在对整个集群进行升级.灰度发布就是把部署好的服务分批次,逐步暴露给越来越多的用户,最终完成版本切替上线.优点灵活,粒度细无需(少量)侵入代码用户无感知,平滑过渡对自动化要求较高从LB拆除灰度服务器,升级后再加入少量用
K8s常见面试题19问
收集了一些K8s常见问题和同学们面试常被问到的问题.
如果有新的面试题私聊或者留言给我
1. Docker和虚拟机有那些不同
虚拟化环境下每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统。
容器之间可以共享操作系统,比起 VM 被认为是更轻量级.且与 VM 类似,每个容器都具有自己的文件系统、CPU、内存、进程空间.
容器与虚拟化比有以下优点:
- 敏捷应用程序的创建和部署:与使用 VM 镜像相比,提高了容器镜像创建的简便性和效率。
- 持续开发、集成和部署:通过快速简单的回滚(由于镜像不可变性), 提供可靠且频繁的容器镜像构建和部署。
- 关注开发与运维的分离:在构建、发布时创建应用程序容器镜像,而不是在部署时, 从而将应用程序与基础架构分离。
- 可观察性:不仅可以显示 OS 级别的信息和指标,还可以显示应用程序的运行状况和其他指标信号。
- 跨开发、测试和生产的环境一致性:在笔记本计算机上也可以和在云中运行一样的应用程序。
- 跨云和操作系统发行版本的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、 Google Kubernetes Engine 和其他任何地方运行。
- 以应用程序为中心的管理:提高抽象级别,从在虚拟硬件上运行 OS 到使用逻辑资源在 OS 上运行应用程序。
- 松散耦合、分布式、弹性、解放的微服务:应用程序被分解成较小的独立部分, 并且可以动态部署和管理 - 而不是在一台大型单机上整体运行。
- 资源隔离:可预测的应用程序性能。
- 资源利用:高效率和高密度。
2. 简述K8s和Docker关系
Docker是一个开源的应用容器引擎.通过Dockerfile中的配置,将应用,配置与依赖打包成一个镜像,通过镜像实现应用的部署.
K8s是开源的容器集群管理系统,可以实现容器集群的自动化部署,自动扩缩容,维护等功能.
K8s是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。
K8s提供了以下容器不具备的功能:
- 服务发现和负载均衡
- 存储编排
- 自动部署和回滚
- 自动完成装箱计算
- 自我修复
- 密钥与配置管理
3. 简述Kube-proxy ipvs和iptables的异同
ipvs和iptables都是基于Netfilter实现.
iptables是为防火墙设计的它采用规则表实现,service数量越多iptables的规则条目越多,而iptables是从上到下逐一匹配,就会导致效率低下.
ipvs采用hash表实现,当service数量达到一定规模时,hash查表的速度优势会显现出来,从而提高service的服务性能.
iptables的优点:
- 灵活
- 功能强大(根据tcp连接状态对包进行控制)
- 默认安装,老版本兼容
ipvs的优点:
- 支持hash转发效率高
- 支持backend健康检测
- 调度算法丰富(静态算法:轮询rr,加强轮询wrr,目的地址dh,源地址sh,动态算法:最少连接lc,加权最少连接wlc,局部最少连接数LBLC,带复制的局部最少连接数LBLCR,最短延迟NQ,加权最少连接增强版SED…)
- 可以动态设置ipset集合
4. 简述kube-proxy切换ipvs负载的方法
步骤如下:
- 安装ipvs
- 将kube-proxy模式改为ipvs
- 重启kube-proxy
- 确认切换完成
具体步骤如下:
- 查看是否使用了ipvs
[ $(ipvsadm -Ln|wc -l) -gt 1 ] && echo "有ipvs"||echo "没ipvs"
- 载入ipvs模块
# ubuntu for i in `ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs/|sed -E 's/(.*)\.ko/\1/g'`;do /sbin/modprobe $i;done # centos/redhat for i in `ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs/|sed -E 's/(.*)\.ko\.xz/\1/g'`;do /sbin/modprobe $i;done
确认加载完成
# lsmod |grep ip_vs ip_vs_wlc 16384 0 ip_vs_sed 16384 0 ip_vs_pe_sip 16384 0 nf_conntrack_sip 36864 1 ip_vs_pe_sip ip_vs_ovf 16384 0 ip_vs_nq 16384 0 ip_vs_mh 16384 0 ip_vs_lc 16384 0 ip_vs_lblcr 16384 0 ip_vs_lblc 16384 0 ip_vs_ftp 16384 0 ip_vs_fo 16384 0 ip_vs_dh 16384 0 ip_vs_sh 16384 0 ip_vs_wrr 16384 0 ip_vs_rr 16384 121 ip_vs 155648 176 ip_vs_wlc,ip_vs_rr,ip_vs_dh,ip_vs_lblcr,ip_vs_sh,ip_vs_ovf,ip_vs_fo,ip_vs_nq,ip_vs_lblc,ip_vs_pe_sip,ip_vs_wrr,ip_vs_lc,ip_vs_mh,ip_vs_sed,ip_vs_ftp nf_nat 45056 4 ip6table_nat,iptable_nat,xt_MASQUERADE,ip_vs_ftp nf_conntrack 139264 7 xt_conntrack,nf_nat,nf_conntrack_sip,nf_conntrack_netlink,xt_CT,xt_MASQUERADE,ip_vs nf_defrag_ipv6 24576 2 nf_conntrack,ip_vs libcrc32c 16384 6 nf_conntrack,nf_nat,btrfs,xfs,raid456,ip_vs
- 修改kube-proxy模式
kubectl edit cm kube-proxy -n kube-system
# 将原来的mode: ""修改为下行 mode: ipvs
- 重启kube-proxy容器
kubectl rollout -n kube-system restart daemonset kube-proxy
- 确认是否切换完成
kubectl logs -n kube-system $(kubectl get pods -n kube-system |grep kube-proxy |tail -1 |awk '{print $1}')|grep ipvs
5. 简述微服务部署中的蓝绿发布
常见发布有:蓝绿发布,金丝雀发布,滚动发布
蓝绿发布主要用作测试环境,正式环境多使用金丝雀或滚动发布蓝绿部署(Blue/Green Deployment)一共有2套系统.一套是正在提供服务的系统,标记为"绿色";另一套是准备发布的系统,标记为"蓝色".两套系统都是功能完善的,正在运行的系统,只是系统版本和对外提供服务的情况不同.
蓝色系统用来做发布前测试,测试发现问题直接在蓝色系统上进行修改,不干扰用户正在使用的绿色系统.
蓝色系统经过反复的测试,修改,验证,确定达到上线标准后,直接将用户切换到蓝色系统.
- 升级切换与回退速度快
- 版本切换时无需停机,风险最小
不足之处:
- 它是一个全量切换.无法切分流量
- 需要2倍的资源
- 如果蓝色版本有问题,对用户体验有影响
6. 什么是灰度发布
灰度发布:也被叫作金丝雀发布。灰度发布属于增量发布方法。也就是说,服务升级的过程中,新旧版本会同时为用户提供服务。
先将一小部分用户流量切换到新版本上,测试版本性能与功能.确认没有问题后在对整个集群进行升级.灰度发布就是把部署好的服务分批次,逐步暴露给越来越多的用户,最终完成版本切替上线.
- 灵活,粒度细
- 无需(少量)侵入代码
- 用户无感知,平滑过渡
- 对自动化要求较高
部署过程:
- 从LB拆除灰度服务器,升级后再加入
- 少量用户切换到新版本进行测试
- 如果没问题,调整灰度服务器数量,重复步骤2将更多的用户流量切换到新版本.直至所有用户流量完成切换.
7. 什么是滚动发布
k8sdeployment是滚动发布.按批次依次替换老版本(maxSurge默认25%),逐步升级到新版本.发布过程中应用不中断,用户体验平滑.
8. 简述Kubernetes静态Pod
静态Pod由kubelet创建并且总是在kubelet所在节点上运行.
它们不能通过API Server进行管理,无法与==
ReplicationController
,Deployment
,Daemonset
==进行关联,它就是一个Pod,并且kubelet也无法对其健康检查创建静态Pod有两种方式:
配置文件方式
和HTTP方式
。配置文件方式: 通过在manifests目录下创建yaml,由kubelet定期扫描自动创建Pod资源
HTTP方式:kubelet启动参数–manifest-url,kubelet定期访问此url,下载Pod定义文件,以yaml或json格式进行解析,并创建Pod.
kubeadm安装集群配置文件路径:/var/lib/kubelet/config.yaml中staticPodPath: /etc/kubernetes/manifests
二进制安装配置文件路径:由/usr/lib/systemd/system/kubelet.service的–pod-manifest-path=值定义
etcd,kube-apiserver,kube-controller-manager,kube-scheduler都是静态Pod
如果需要创建自己的静态pod,直接将yaml放置在 /etc/kubernetes/manifests 目录下即可
配置文件方式创建:
/etc/kubernetes/manifests/static-web.yaml
文件内容如下
apiVersion: v1 kind: Pod metadata: name: static-web labels: role: myrole spec: containers: - name: web image: nginx ports: - name: web containerPort: 80 protocol: TCP
当文件被创建后该pod就会被kubelet自动创建,且当停止该容器后马上会被自动再次创建.
root@ks-master:~# kubectl get pods NAME READY STATUS RESTARTS AGE busybox 1/1 Running 58 22d nfs-client-provisioner-68c8fcd77-hg8hl 1/1 Running 15 23d static-web-ks-master 1/1 Running 0 7m54s root@ks-master:~# docker ps|head -2 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fe2aab2799e1 nginx "/docker-entrypoint.…" 7 minutes ago Up 7 minutes k8s_web_static-web-ks-master_default_b2f5f5f4465db575a93c8173ea740eed_0 root@ks-master:~# docker stop fe2aab2799e1 fe2aab2799e1 root@ks-master:~# docker ps|head -2 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d514ae256d77 nginx "/docker-entrypoint.…" 1 second ago Up Less than a second k8s_web_static-web-ks-master_default_b2f5f5f4465db575a93c8173ea740eed_1
想要删除把配置文件删除即可
9. 简述K8s存储卷有哪些,说明它们的特征和用途
- emptyDir: Pod调度到节点创建的临时空目录,Pod删除随之删除,用于容器存放临时文件
- hostPath: 节点存储卷,将宿主机的文件或目录挂载到Pod
- Pv/Pvc: 外部存储挂载到Pod,生命周期独立于Pod,具有持久性
- StorageClass: 充当PV模板,从而可以动态创建PV,自动构建相应的持久化数据存储
- configmap: 明文,热更新,支持多个pod共享,避免重复修改.
- secret: 密文
10. 简述Dockerfile中copy和add的异同
Copy: 将宿主机的文件复制到容器内
Add: 除了复制功能以外,还带有解压缩功能.支持url
copy后解压,需要先确认容器内有解压所需的命令.当对容器镜像大小要求比较苛刻时add显然更好.使用空镜像scratch时特别明显
常见较小的镜像有:
镜像版本 大小 Alpine 7.05 MB Busybox 4.86MB Debian:stable 124 MB Ubuntu:18.04 63.1 MB CentOS:7.9.2009 204 MB 11. 简述Dockerfile中CMD 和ENDPOINTS区别
CMD: 指定启动容器时执行的命令,每个 Dockerfile只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。
Endpoint:配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。
两者区别:
1、CMD指令指定的容器启动时命令可以被docker run指定的命令覆盖ENTRYPOINT指令指定的命令不能被覆盖,而是将docker run指定的参数当做ENTRYPOINT指定命令的参数。
2、CMD与ENTRYPOINT同时存在时,CMD指令可以为ENTRYPOINT指令设置默认参数,而且CMD可以被docker run指定的参数覆盖;12. K8s如何添加和移除节点
12.1 移除节点
12.1.1 设置节点为不可调度
kubectl cordon k8s-node2
12.1.2 驱逐节点上的Pod
kubectl drain ks-node2 --ignore-daemonsets --delete-local-data --force
12.1.3 删除节点
kubectl delete node k8s-node2
12.1.4 清空节点上数据
kubeadm reset -f systemctl disable --now kubelet systemctl disable --now docker rm -rf /var/lib/cni/ rm -rf /var/lib/kubelet/ rm -rf /etc/cni/ ifconfig cni0 down ifconfig flannel.1 down ifconfig docker0 down ip link delete cni0 ip link delete flannel.1 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X ipvsadm -C
12.2 添加节点
12.2.1 kubesphere
./kk add nodes -f sample.yaml
12.2.2 kubeadmin
先检查是否有token
kubeadm token list
如果没有,创建token
## 默认24小时token kubeadm token create --print-join-command ## 永久 kubeadm token create --print-join-command --ttl 0
在新节点上执行,添加节点
kubeadm join 192.168.31.131:6443 --token 9q1zfx.r2wrn6kzu03qr9df --discovery-token-ca-cert-hash sha256:94ab137b5f15edd2b7f09b570372dcf6545129a362dfc332250c5e1c68df5a06
12.2.3 二进制安装的k8s
- 复制配置文件
scp kubelet kube-proxy bootstrap.kubeconfig kube-proxy.kubeconfig root@192.168.31.151:/data/kubernetes/cfg/ scp kubelet.service kube-proxy.service flanneld.service root@192.168.31.151:/usr/lib/systemd/system
scp ca-key.pem ca.pem server-key.pem server.pem root@192.168.31.151:/data/etcd/ssl/ scp ca.pem ca-key.pem server.pem server-key.pem kube-proxy.pem kube-proxy-key.pem root@192.168.31.151:/data/kubernetes/ssl/
- 修改kubelet和kube-proxy,将地址改为本地
## kubelet --address=192.168.31.151 \ --hostname-override=192.168.31.151 \ ## kube-proxy --hostname-override=192.168.31.151 \
systemctl start docker;systemctl enable docker systemctl start flanneld;systemctl enable flanneld systemctl start kubelet;systemctl enable kubelet systemctl start kube-proxy;systemctl enable kube-proxy
- master节点允许加入
kubectl get csr kubectl certificate approve node-csr-TLFAeDwUhcScypkpi-wokn7Hv5JFr34D17IJSFFClik
13. 如何将SVC的NodePort设置成40000端口
- 默认svc NodePort范围是30000-32767
- 修改kube-apiserver.yaml添加–service-node-port-range=30000-45000
/etc/kubernetes/manifests/kube-apiserver.yaml - --service-node-port-range=30000-45000
修改后执行kubectl时会有报错
The connection to the server lb.kubesphere.local:6443 was refused - did you specify the right host or port?
删除apiserver静态pod(或在master节点删除apiserver的容器),后恢复
kubectl delete pod -n kube-system `kubectl get pods -n kube-system --selector=component=kube-apiserver --output=jsonpath={.items..metadata.name}`
此时再创建40000的nodeport就不会报错了
14. 简述K8s常用控制器及特点
- Deployment 无状态控制器,启动顺序是无序的,Pod名字和ip是随机的,后台存储往往是共享的.(web网站)
- StatefulSet 有状态控制器,有序启动,Pod名字固定,后台存储是独占的.(主从数据库)
- Daemonset 每个节点都部署.(日志采集和监控)
- CronJob 定时运行Pod
- Job 一次性运行Pod
15. K8s无法拉伸和收缩副本可能的原因
手动拉伸或者收缩
kubectl scale deployment nginx --replicas=2
生产中常用HPA实现Deployment的自动伸缩
## 设置deployment中容器的cpu和内存 kubectl set resources deployment nginx --limits=cpu=200m,memory=512Mi ## 设置autoscal kubectl autoscale deployment nginx --min=4 --max=8 --cpu-percent=80 ## 查看autoscal kubectl get hpa
- yaml方式
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: hpa-nginx spec: maxReplicas: 8 minReplicas: 4 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx targetCPUUtilizationPercentage: 80
- 当手动伸缩值与HPA的最小值冲突时,收缩不生效
- 当手动伸缩值与HPA的最大值冲突时,扩展不生效
- 当对deployment有requests参数时,当(namespace或节点)可用资源不满足时,扩展失效.
16. Node容忍节点异常事件如何设置
node节点异常故障触发迁移默认时间是300秒.
tolerationSeconds: 300
也就是node节点故障了,但Pod任然为健康状态,此时用户访问就会造成异常
因此服务中断时间=停机等待时间300秒+Pod重建时间+服务启动时间+readiness探针检测正常时间.
可以使用以下方法缩短收敛时间
- 将容忍时间从300秒改为100秒,但不能过短,一旦网络延迟或抖动造成频繁切换
编写yaml
nginx-patch.yaml
spec: template: spec: tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 100 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 100
以补丁的方式打入deployment中
kubectl patch deployment nginx-deployment --patch "$(cat nginx-patch.yaml)"
此时所有pod会被重建
root@ks-master:~# kubectl patch deployment nginx-deployment --patch "$(cat nginx-patch.yaml)" deployment.apps/nginx-deployment patched root@ks-master:~# kubectl get pods NAME READY STATUS RESTARTS AGE busybox 1/1 Running 63 22d nfs-client-provisioner-68c8fcd77-hg8hl 1/1 Running 19 23d nginx-deployment-78cd64ff75-f6d87 1/1 Terminating 1 110m nginx-deployment-78cd64ff75-g8nv4 1/1 Terminating 1 68m nginx-deployment-78cd64ff75-h7swc 1/1 Terminating 1 68m nginx-deployment-78cd64ff75-lx4ps 1/1 Terminating 1 110m nginx-deployment-78cd64ff75-md2rv 1/1 Terminating 1 68m nginx-deployment-78cd64ff75-n2z4t 1/1 Terminating 1 68m nginx-deployment-78cd64ff75-rzs9h 1/1 Terminating 1 68m nginx-deployment-78cd64ff75-w9rs9 1/1 Terminating 1 68m nginx-deployment-7957b6f749-2n8jf 1/1 Running 0 18s nginx-deployment-7957b6f749-2vcct 1/1 Running 0 19s nginx-deployment-7957b6f749-42px5 1/1 Running 0 16s nginx-deployment-7957b6f749-cqfsk 1/1 Running 0 16s nginx-deployment-7957b6f749-dsqpl 1/1 Running 0 18s nginx-deployment-7957b6f749-hmfbd 1/1 Running 0 16s nginx-deployment-7957b6f749-nv28k 1/1 Running 0 15s nginx-deployment-7957b6f749-wzwvg 1/1 Running 0 18s static-web-ks-master 1/1 Running 1 5h45m
此时not-ready和unreachable的时间都变成了100秒
root@ks-master:~# kubectl describe pod nginx-deployment-7957b6f749-2n8jf |grep 100 Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 100s node.kubernetes.io/unreachable:NoExecute op=Exists for 100s
- kube-proxy负载方式由iptables改为ipvs
17. 简述Deployment控制器的升级和回滚
nginx-blue.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx revisionHistoryLimit: 5 # 记录多少个版本用来回滚 template: metadata: labels: app: nginx spec: containers: - name: nginx image: harbor.intra.com/nginx/nginx-blue:v1 ports: - containerPort: 80
kubectl apply -f nginx-blue.yaml --record
# curl 12.233.106.215 web-app1-blue version 2.0.0
部署green版本
cp nginx-blue.yaml nginx-green.yaml sed -i 's/blue/green/g' nginx-green.yaml kubectl apply -f nginx-green.yaml --record # curl 12.233.106.223 web-app1-green version 1.0.0
# kubectl rollout history deployment nginx-deployment 1 kubectl apply --filename=nginx-blue.yaml --record=true 2 kubectl apply --filename=nginx-green.yaml --record=true
回滚到blue版本
kubectl rollout undo deployment nginx-deployment --to-revision=1 # curl 12.233.106.224 web-app1-blue version 2.0.0
# kubectl rollout history deployment nginx-deployment 2 kubectl apply --filename=nginx-green.yaml --record=true 3 kubectl apply --filename=nginx-blue.yaml --record=true
18. kubectl自动补全
- 安装依赖包
# Centos yum install bash-completion # ubuntu apt install bash-completion
- 修改~/.bashrc
echo "source <(kubectl completion bash)" >> ~/.bashrc source ~/.bashrc
19. 生产环境中如何阻止内核及其他软件更新版本
19.1 Ubuntu环境
- 查看当前内核
root@ks-master:~# uname -r 5.4.0-148-generic root@ks-master:~# dpkg --get-selections|grep -E 'linux-image-5.4.0-148-generic|linux-headers-5.4.0-148-generic' linux-headers-5.4.0-148-generic install linux-image-5.4.0-148-generic install
- 禁止这2个软件包更新
root@ks-master:~# apt-mark hold linux-headers-5.4.0-148-generic linux-image-5.4.0-148-generic linux-headers-5.4.0-148-generic set on hold. linux-image-5.4.0-148-generic set on hold.
再次查看可以看到这2个都已经被锁定了
root@ks-master:~# dpkg --get-selections|grep -E 'linux-image-5.4.0-148-generic|linux-headers-5.4.0-148-generic' linux-headers-5.4.0-148-generic hold linux-image-5.4.0-148-generic hold root@ks-master:~# apt-mark showhold linux-headers-5.4.0-148-generic linux-image-5.4.0-148-generic
- 使用unhold恢复更新
root@ks-master:~# apt-mark unhold linux-headers-5.4.0-148-generic linux-image-5.4.0-148-generic Canceled hold on linux-headers-5.4.0-148-generic. Canceled hold on linux-image-5.4.0-148-generic. root@ks-master:~# dpkg --get-selections|grep -E 'linux-image-5.4.0-148-generic|linux-headers-5.4.0-148-generic' linux-headers-5.4.0-148-generic install linux-image-5.4.0-148-generic install root@ks-master:~# apt-mark showhold
19.2 Redhat系列
临时生效:在执行yum update的时候加上参数
yum update --exclude=kernel*
永久生效:在/etc/yum.conf的[main]下面追加exclude=kernel*
echo "exclude=kernel*" >> /etc/yum.conf
20. 简述Dockerfile中ENV和ARG的区别
两个都是Dockerfile中的变量
两者都不能被CMD和ENTRYPOINT
- 变量的生命周期
ARG的生命周期仅是docker构建中有效,一旦构建完ARG的值失效.
ENV的不仅构建时有效,当使用此镜像再次构建或者使用此镜像生成容器,ENV的值任有效.
- 变量值的传递参数
ARG构建时通过–build-arg参数将变量传给Dockerfile
ENV在docker run 命令中通过 -e标记来传递环境变量