💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 贤文杂谈-kubernetes 大纲 * 如何高效部署自建k8s集群 * k8s-master 控制面集群模式优劣分析 * 核心组件性能调优 * 组件版本选择 * ingress 日志分析 * etcd * CNI 网络优选 在2020 这个特殊的寒冬时节,运维圈的兄弟们是不是已感觉,如今在各个微信群中不提Kubernetes、Istio会不会有一种异样的感觉。是的云原生时代已经来临,微服务、容器、服务与治理已经从一线TOP行业公司逐渐向中小规模企业推进。刚入行的小铁们时常面临集群如何快速部署?错综复杂的核心组件如何选择?平台性能如何调优保证SLA。本文以平台选型为视角,为大家分析k8s集群是自建集群还是选择公有云服务托管服务。 ## 如何高效部署k8s集群 无论是马爸爸的ACK还是任爷爷的CCE在公有云平台都提供了自动化部署集群的能力,公有云的容器平台能在短短几分钟内快速拉起一套生产集群。而对于自建IDC的小铁门公有云的服务无法享受时,或者想多折腾的技术控们,我们应该如何自建一套生产标准的k8s集群。是小铁们面临的第一个问题。 如果你是首次阅读kubernetes官方文档,会发现官方推荐使用kubeadm工具部署k8s集群,小铁们有没有在第一步创建CA 、apiserver、etcd、kubelet各类证书文件的时候就卡主就有一种放弃想跳楼的经历。为达到生产环境要求master控制面板如何选择高可用方案?集群计算node节点如何快速水平扩容?各类繁杂网络CNI插件如何选择? 这些最基础的问题如何破解,小编推荐小铁们使用kubespray工具部署集群,Kubespray是Google开源的一个部署生产级别的Kubernetes服务器集群的开源项目,它整合了Ansible作为部署的工具。[Kubespray项目地址](%5Bhttps://github.com/kubernetes-sigs/kubespray%5D(https://github.com/kubernetes-sigs/kubespray)) ### 组件版本如何选择 kuberspray的版本管理会跟随社区版本保持最新版本的的更新,如果我们选择在生产环境部署使用,建议选择比当前最新版本晚半年的版本。比如kubernetes当前最新版本 v1.17.5,倒退两个版本选择v1.15.11 。 ### Kuberspray HA-MODE ![](https://img.kancloud.cn/c8/df/c8dfb0d31c72788a4085c364dcba2ce8_914x674.png) 从架构图中我们获取到kubespray使用三个独立master方式分别部署。在集群kube-system 命名空间巧妙的增加了一个nginx-proxy组件,客户端节点kube-node 通过 nginx-proxy反向代理请求kube-apiserver。 我们在任爷爷家创建容器服务后会发现,CCE的容器服务也是提供了独立的三master 集群模式。虽然master空面需要单独付费,但是这样能更能保证用户的数据安全性及稳定性。 ![](https://img.kancloud.cn/df/47/df47b4a5c4e420d23365bd346a89dc3d_1474x429.png) ### Docker 存储的选择 Docker storage driver 不同的存储驱动直接关乎到 volume 挂在磁盘I/O性能。如果你使用centos7.X 最新发行版本推荐直接使用overlay2作为默认的存储驱动。通过查看[Docker CE 18.03 源码]([https://github.com/docker/docker-ce/blob/18.03/components/engine/daemon/graphdriver/driver\_linux.go#L50](https://github.com/docker/docker-ce/blob/18.03/components/engine/daemon/graphdriver/driver_linux.go#L50))会发现源码排序也是优先推荐使用overlay2。 可以使用`docker info` 命令可以查看当前驱动方式: ![](https://img.kancloud.cn/8b/ee/8bee2ff71d5a3d91872850ebf6de7d60_983x576.png) ### Ingress 日志分析 ingress作为kubernetes南北流量的解决方案,与大家日常熟悉的nginx在架构设计及配置使用方法都有着较大的差异。常见的Ingress controller有ingress-nginx、ingress-Traefik 、ingress-kong 。kubespray 选择ingress-nginx做为ingress controller控制器,其功能特性最为贴合与生产应用需求。例如下图展示了在生产环境应用中我们会通过采集nginx access.log 日志获取一些关键指标: - PV、UV 用户访问流量 - 应用API TOP10 流量 - 2XX 状态码 - 5XX 状态码 - 请求成功率 ![](https://img.kancloud.cn/3f/39/3f39e984c98709265f0a4a4c1f180586_2482x1181.png) 可以通过ingress configmap 给ingress-nginx 定制acces.log日志格式。cm-ingress-nginx.yml 配置内容如下: --- apiVersion: v1 kind: ConfigMap metadata: name: ingress-nginx namespace: kube-system labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx data: enable-underscores-in-headers: 'true' map-hash-bucket-size: '128' ssl-protocols: SSLv2 TLSv1 TLSv1.1 TLSv1.2 enable-underscores-in-headers: "true" client-header-timeout: "120" access-log-path: /var/log/nginx/ingress.access.log error-log-path: /var/log/nginx/ingress.error.log log-format-escape-json: 'true' log-format-upstream: '{ "datetime": "$time_iso8601", "remote_addr": "$remote_addr", "x-forward-for": "$http_x_forwarded_for", "remote_user": "$remote_user", "bytes_sent": $bytes_sent, "request_time": $request_time, "status":$status, "vhost": "$host", "request_proto": "$server_protocol", "path": "$uri", "request_query": "$args", "request_length": $request_length, "upstream_addr": "$upstream_addr", "upstream_response_time": "$upstream_response_time", "method": "$request_method", "http_referrer": "$http_referer", "http_user_agent": "$http_user_agent" }' consolelog-format-upstream: '{ "datetime": "$time_iso8601", "remote_addr": "$remote_addr", "x-forward-for": "$http_x_forwarded_for", "remote_user": "$remote_user", "bytes_sent": $bytes_sent, "request_time": $request_time, "status":$status, "vhost": "$host", "request_proto": "$server_protocol", "path": "$uri", "request_query": "$args", "request_length": $request_length, "upstream_addr": "$upstream_addr", "upstream_response_time": "$upstream_response_time", "method": "$request_method", "http_referrer": "$http_referer", "http_user_agent": "$http_user_agent" }' 核心参数说明: - ssl-protocols 开启SSL 功能。注意默认只添加了SSLv2,需要完整SSL 协议栈 - access-log-path:访问日志访问路径 - error-log-path:错误日志访问路径 - log-format-upstream: 日志输出格式 - consolelog-format-upstream:conso 日志输出格式 日志采集方式: kubespray 使用DaemonSet + nodeSelector 策略,让ingress组件绑定部署在三台master实例主机上。通过上面的设置把ingress-nginx访问日志输出在pod /var/nginx/log/目录里,需要在DaemonSet 配置中添加volume 把日志文件映射到宿主机指定目录(/opt/ingress_log/)。 ds-ingress-nginx-controller.yml 配置文件内容如下: --- apiVersion: apps/v1 kind: DaemonSet metadata: name: ingress-nginx-controller namespace: kube-system labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: selector: matchLabels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx annotations: prometheus.io/port: "10254" prometheus.io/scrape: "true" spec: serviceAccountName: ingress-nginx hostNetwork: true nodeSelector: node-role.kubernetes.io/master: '' tolerations: - effect: NoSchedule key: node-role.kubernetes.io/master operator: Equal value: 'unschedulable' priorityClassName: system-node-critical volumes: - name: ingresslogs hostPath: path: /opt/ingress_logs/ containers: - name: ingress-nginx-controller image: harbor.corp.jccfc.com/kubernetes-ingress-controller/nginx-ingress-controller:0.24.1 imagePullPolicy: Always args: - /nginx-ingress-controller - --configmap=$(POD_NAMESPACE)/ingress-nginx - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --annotations-prefix=nginx.ingress.kubernetes.io securityContext: capabilities: drop: - ALL add: - NET_BIND_SERVICE # www-data -> 33 runAsUser: 33 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace volumeMounts: - name: ingresslogs mountPath: /var/log/nginx/ ports: - name: http containerPort: 80 hostPort: 80 - name: https containerPort: 443 hostPort: 443 livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 ### etcd备份与内存优化 etcd 是一个分布式的k/V存储系统。核心使用了RAFT分布式一致性协议。etcd 集群都是至少 3 台机器,官方也说明了集群容错为 (N-1)/2,所以备份数据一般都是用不到,但是作为生产核心系统也是运维同学不得不考虑的重要一环。etcd使用快照Snapshot文件备份数据,默认备份的快照文件保存在本地磁盘,或者同步到备份服务器。如何保证备份服务器的数据安全又会引出一个新的问题。而在公有云托管k8s服务etcd 的快照文件会自动的备份在对象存储中。同过备份在对象存储解决了这个矛盾的问题。 etcd 备份方法: 在初始创建集群时我们需要修改etcd 两个内存参数: - --quota-backend-bytes ETCD db数据大小,默认是2G,当数据达到2G的时候就不允许写入,必须对历史数据进行压缩才能继续写入; 参加1里面说的,我们启动的时候就应该提前确定大小,官方推荐是8G,这里我们也使用8G的配置 - etcd-memory-limit ## CNI 网络插件 如何选择CNI网络插件关乎整个k8s集群的稳定性及性能,是至关重要的一环。常见的开源CNI 网络解决方案有flannel、Calico 。云厂商也有各家的专属CNI插件,任爷爷家的ICAN与马爸爸家的Terway各家又有独特优势再次一一解答。 - flannel Flannel是CoreOS开源的CNI网络插件,下图flannel官网提供的一个数据包经过封包、传输以及拆包的示意图,从这个图片里面里面可以看出两台机器的docker0分别处于不同的段:10.1.20.1/24 和 10.1.15.1/24 ,如果从Web App Frontend1 pod(10.1.15.2)去连接另一台主机上的Backend Service2 pod(10.1.20.3),网络包从宿主机192.168.0.100发往192.168.0.200,内层容器的数据包被封装到宿主机的UDP里面,并且在外层包装了宿主机的IP和mac地址。这就是一个经典的overlay网络,因为容器的IP是一个内部IP,无法从跨宿主机通信,所以容器的网络互通,需要承载到宿主机的网络之上。 flannel的支持多种网络模式,常用用都是vxlan、UDP、hostgw、ipip,vxlan和UDP的区别是vxlan是内核封包,而UDP是flanneld用户态程序封包,所以UDP的方式性能会稍差;hostgw模式是一种主机网关模式,容器到另外一个主机上容器的网关设置成所在主机的网卡地址,这个和calico非常相似,只不过calico是通过BGP声明,而hostgw是通过中心的etcd分发,所以hostgw是直连模式,不需要通过overlay封包和拆包,性能比较高,但hostgw模式最大的缺点是必须是在一个二层网络中,毕竟下一跳的路由需要在邻居表中,否则无法通行。 ![](https://img.kancloud.cn/03/7e/037e5480319cedd1e662c925bce23b3e_1130x779.jpg) - ICAN 任爷爷家的ICAN网络基于底层VPC网络,另构建了独立的VXLAN隧道化容器网络,适用于一般场景。VXLAN是将以太网报文封装成UDP报文进行隧道传输。容器网络是承载于VPC网络之上的Overlay网络平面,具有付出少量隧道封装性能损耗,获得了通用性强、互通性强、高级特性支持全面(例如Network Policy网络隔离)的优势,可以满足大多数应用需求。 ![](https://img.kancloud.cn/b2/f1/b2f137dab370c74381661496d57a88ef_589x516.png) ICAN 容器网络相比开源的flannel网络性能提升20%。 ![](https://img.kancloud.cn/6c/ef/6cefa1dda42b3e3b08543b51f339e138_1287x722.png) - Terway网络插件 Terway网络插件是阿里云容器服务自研的网络插件,使用原生的弹性网卡分配给Pod实现Pod网络: * 将阿里云的弹性网卡和辅助IP分配给容器。 * 支持基于Kubernetes标准的NetworkPolicy来定义容器间的访问策略,兼容Calico的Network Policy。 ![](https://img.kancloud.cn/aa/50/aa502140e88117b324f4c506b6b392d0_1850x739.png) 在Terway网络插件中,每个Pod拥有自己网络栈和IP地址。同一台ECS内的Pod之间通信,直接通过机器内部的转发,跨ECS的Pod通信,报文通过VPC的弹性网卡直接转发。由于不需要使用VxLAN等的隧道技术封装报文,因此具有较高的通信性能。 通过对以上CNI 网络插件的分析简单总结如下: - 如果你选择自建k8s集群,flannel 网络性能较低 - pod IP 不能与VPC网络互通,在容器化改造中会带来诸多的不便之处。例如开发者无法直连pod进行debug 调试。