用户数从 0 到亿,我的 K8s 踩坑血泪史
作者 | 平名 阿里服务端开发技术专家
导读:容器服务 Kubernetes 是目前炙手可热的云原生基础设施,作者过去一年上线了一个用户数极速增长的应用:该应用一个月内日活用户从零至四千万,用户数从零到一亿的裂变式增长,充分享受了容器服务快速简便的扩容操作和高可用特性。作者使用容器服务 Kubernetes 集群将公司内系统完全上云 1 年多,本篇文章记录了其中的踩坑与优化记录。
关注“阿里巴巴云原生”公众号,回复关键词“资料”,即可获得 2019 全年meetup 活动 PPT 合集及 K8s 最全知识图谱。
创建集群
创建集群时,做好规划,选择优化好的集群配置,可以大大减少后期运维工作,其中部分集群的配置在建立后再也没法修改或者修改极其麻烦。
集群规划
- 网络规划:
Terway 是阿里云容器服务自研的网络插件,功能上完全兼容 Flannel,如果保守,还是使用 Flannel
- Pod 网络 CIDR
默认 16 的大网段,有效的网段或者其子网 10.0.0.0/8,172.16-31.0.0/12-16,192.168.0.0/16
Service CIDR
- 默认 20 的网段,可选:10.0.0.0/16-24,172.16-31.0.0/16-24,192.168.0.0/16-24
- 网段不能冲突重复,建立后没法修改;
- 多个区域的多个交换机。
公网访问 ApiServer
- 对于线上等安全要求高的集群,可以选择不暴露 apiserver, 只有私网 SLB, 但是这样没法使用云效发布;
- 日常预发等集群,可以暴露公网 SLB 到 apiserver, 集群建立后立即为 slb 建立访问控制,限制 slb 只能云效访问;
注: K8s 每次安全漏洞几乎都与 ApiServer 有关,对于线上 K8s 集群,要及时升级补丁,或者不开放公网 apiserver,使用严格的安全组和访问控制。
- 安全组
- 设置安全组限定访问范围,为 master 与 worker 机器使用。
- Master 机器规划
为了高可用,一般使用 3 节点,Master 选择规则如下:
节点数 | master 规格 |
---|---|
1-5个 | 4C8G |
6-20个节点 | 4C16G |
21-100个节点 | 8C32G |
100-200个节点 | 16C64G |
master 机器的存储建议高性能的 50-100G SSD,因为会运行 ETCD,操作系统占用不超过 8G。
- Worker 机器规划
- 阿里云首推神龙机器,没有神龙机器的区域,选用高配 ECS,配置规格根据部署的 POD 规格乘以一定倍数,比如 Java 应用 pod 一般选择 4C8G,ECS 则购买 32C64G 或者 64C128G 为好,设置部署的时候为 pod 设置固定的 request/limit;
- 我们选用的机器配置:
- 32C64G ECS
- 存储。系统盘:100G SSD, 数据盘:400G 高效云盘
- 操作系统:centos 7.4 64 位
集群建立与配置
建立集群时设置:
- 通过控制台建立集群,阿里云容器服务提供的非常简易的一键部署集群功能,通过向导完成 K8S 集群的建立;
- 按照以上规划设置 master,worker 节点,挂载 /var/lib/docker 到数据盘;
- 设置合理的 Pod 网络 CIDR, Service CIDR ip 网段;
- 设置合理的安全策略,是否暴露 apiserver(需要直接云效发布的,需要开放公网暴露,并做严格的访问控制);
- ingress 选择安全,可以使用内网,如果需要公网,可以在控制台很方便建立,同时做好访问控制;
- kube-proxy 模式,因为 iptables 模式在更新一条规则时把 iptables 锁住引发的性能问题,建议使用 IPVS 模式;
- 节点 POD 数量,默认 128 太大,一个节点不可能部署这么多,建议改为 64;
- 节点服务端口访问 (NodePort,SLB),可以适当扩大,默认的也一般足够用。
集群配置修改:
- 集群扩容,添加已有节点(节点配置参考上文,挂载数据盘使用 /var/lib/docker)
- Master 机器升配:
- worker 节点变配或者移除:
- kubectl drain --ignore-daemonsets {node.name}
- kubectl delete node {node.name}
- ECS 升配变配
- 添加已有节点到集群
- 命名空间:
- 按照应用分组建立 namespace,对于资源占用厉害需要限制的应用分组,设置该 NameSpace 的资源配额与限制;
- 授权:
部署设置
无状态部署
使用无状态部署 Deployment,参考这篇文章实现分批发布。
优化设置模板:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: '34'
# 标签,映射 service
labels:
app: {app_name}-aone
name: {app_name}-aone-1
namespace: {app_name}
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: {app_name}-aone
# 批量重启更新策略
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: {app_name}-aone
spec:
containers:
# 环境变量增加时区
- env:
- name: TZ
value: Asia/Shanghai
- image: >-
registry-vpc.cn-north-2-gov-1.aliyuncs.com/{namespace}/{app_name}:20190820190005
imagePullPolicy: Always
# 启动前执行优雅下线摘除 服务注册
lifecycle:
preStop:
exec:
command:
- sudo
- '-u'
- admin
- /home/{user_name}/{app_name}/bin/appctl.sh
- {app_name}
- stop
# 存活检查,强烈建议设置
livenessProbe:
failureThreshold: 10
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 5900
timeoutSeconds: 1
name: {app_name}-aone
# 就绪检查,强烈建议设置
readinessProbe:
failureThreshold: 10
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 5900
timeoutSeconds: 1
# 资源限制,这个一定要合理设置
resources:
limits:
cpu: '4'
memory: 8Gi
requests:
cpu: '4'
memory: 8Gi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
# 日志存放目录,映射到节点的/var/lib/docker/logs 数据盘,应用日志目录设置到/home/{user_name}/logs 下
volumeMounts:
- mountPath: /home/{user_name}/logs
name: volume-1553755418538
dnsPolicy: ClusterFirst
## 私有镜像仓库的密钥,从保密字段获取
imagePullSecrets:
- name: {app_name}-987
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
# 日志存放目录,映射到节点的/var/lib/docker/logs 数据盘
volumes:
- hostPath:
path: /var/lib/docker/logs/{app_name}
type: ''
name: volume-1553755418538
服务设置
因为容器服务的 Cloud Controller Manager 会同步删除 service 建立关联的 SLB,为了防止 service 配置修改误删除 slb 故障,并导致域名、安全等配置需要修改的坑,强烈建议 service 与 slb 解耦,service 采用 NodePort 的方式,slb 另外建立后端服务器指向集群节点,如果需要透传真实 IP,并考虑负载均衡,需要遵守一定的配置规则和方法,参考这个文章。
NodePort:
apiVersion: v1
kind: Service
metadata:
name: {app_name}
namespace: {namespaces}
spec:
clusterIP: 10.1.50.65
## 策略关系到是否透传真实 IP
externalTrafficPolicy: Cluster
ports:
- name: {app_name}-80-7001
nodePort: 32653
port: 80
protocol: TCP
targetPort: 7001
- name: {app_name}-5908-5908
nodePort: 30835
port: 5108
protocol: TCP
targetPort: 5108
selector:
app: {app_name}
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
然后在负载均衡管理页面,选择后端服务器指向集群的 worker 机器,设置端口为以上服务的端口:32653,完成配置,这样在集群 service 修改或者删除重建的时候,slb 不会被集群的 CCM 删除,不会涉及到域名,安全等配置修改。同时,可以设置一些策略,需要升级修改服务配置时,分批切流等。
总结
阿里云容器服务控制台虽然是云上新产品,提供了极其简单的一键部署功能,以及简便的控制台管理。过去一年中,笔者一路见识阿里云容器服务控制台从简陋向强大的转变过程,虽然多次踩坑,但阿里云容器服务同学认真负责和极好的服务态度让人佩服。
容器服务管理控制台还需要更多的考虑实际运维需求,并紧密结合已有的云产品,比如云效、EDAS、云监控、日志服务等,以应用为单位,提供更好服务。
扫描下方二维码添加小助手,与 8000 位云原生爱好者讨论技术趋势,实战进阶!
进群暗号:公司-岗位-城市
用户数从 0 到亿,我的 K8s 踩坑血泪史的更多相关文章
- k8s踩坑记第1篇--rc无法创建
六一快乐!!! 什么是k8s,我不想解释,百度资料有很多,本系列只踩坑,不科普. 问题描述: 做Hello World的例子,结果get pods一直显示没有资源? 应用配置代码: apiVersio ...
- k8s踩坑记 - kubeadm join 之 token 失效
抛砖引玉 环境 centos 7 amd64 两台 kubernetes 1.10 伴随着k8s1.10版本的发布,前天先在一台机器上搭建了k8s单机版集群,即既是master,也是node,按照经验 ...
- k8s踩坑记第2篇--3个IP折磨人的故事
例子来源于<Kubernetes实践指南>一书.问题依然没有解决,求助大神. 测试环境 Centos 7.0 docker 1.13.1 kubectl v1.5.2 etcd 3.2.1 ...
- K8S踩坑篇-master节点作为node节点加入集群
前面我们二进制部署K8S集群时,三台master节点仅仅作为集群管理节点,所以master节点上中并未部署docker.kubelet.kube-proxy等服务.后来我在部署mertics-serv ...
- 实现TensorRT-7.0插件自由!(如果不踩坑使用TensorRT插件功能)
本系列为新TensorRT的第一篇,为什么叫新,因为之前已经写了两篇关于TensorRT的文章,是关于TensorRT-5.0版本的.好久没写关于TensorRT的文章了,所幸就以新来开头吧~ 接下来 ...
- NET Core2.0 Memcached踩坑,基于EnyimMemcachedCore整理MemcachedHelper帮助类。
DotNetCore2.0下使用memcached缓存. Memcached目前微软暂未支持,暂只支持Redis,由于项目历史原因,先用博客园开源项目EnyimMemcachedCore,后续用到的时 ...
- Asp.Net Core 2.0 项目实战(5)Memcached踩坑,基于EnyimMemcachedCore整理MemcachedHelper帮助类。
Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...
- .NET Core 从1.1升级到2.0记录(Cookie中间件踩坑)
.NET Core 2.0 新时代 万众瞩目的.NET Core 2.0终于发布了,原定于9.19的dotnetconf大会的发布时间大大提前了1个月,.NET Core 2.0/.NET Stand ...
- manjaro xfce 18.0 踩坑记录
manjaro xfce 18.0 踩坑记录 1 简介1.1 Manjaro Linux1.2 开发桌面环境2 自动打开 NumLock3 系统快照3.1 安装timeshift3.2 使用times ...
随机推荐
- EF Core的Code First 基础
一.创建实体类与映射类 通过NuGet引用Microsoft.EntityFrameworkCore 1.创建实体类 Code First可以通过为实体类字段添加相应特性,来创建对应的字段类型等,举例 ...
- 七分钟理解什么是 KMP 算法
本文是介绍 什么是 BF算法.KMP算法.BM算法 三部曲之一. KMP算法 内部涉及到的数学原理与知识太多,本文只会对 KMP算法 的运行过程. 部分匹配表 .next数组 进行介绍,如果理解了这三 ...
- spring学习笔记之---bean管理
bean管理(xml) (一)spring的工厂类 FileSystemXmlApplicationContext 读取磁盘配置文件 (二)bean实例化的三种方式 (1)使用类构造器实例化(默认无参 ...
- 使用Junit测试一个 spring静态工厂实例化bean 的例子,所有代码都没有问题,但是出现java.lang.IllegalArgumentException异常
使用Junit测试一个spring静态工厂实例化bean的例子,所有代码都没有问题,但是出现 java.lang.IllegalArgumentException 异常, 如下图所示: 开始以为是代码 ...
- Hadoop学习(5)-zookeeper的安装和命令行,java操作
zookeeper是干嘛的呢 Zookeeper的作用1.可以为客户端管理少量的数据kvkey:是以路径的形式表示的,那就意味着,各key之间有父子关系,比如/ 是顶层key用户建的key只能在/ 下 ...
- 第二十二章 跳出循环-shift参数左移-函数的使用 随堂笔记
第二十二章 跳出循环-shift参数左移-函数的使用 本节所讲内容: 22.1 跳出循环 22.2 Shift参数左移指令 22.3 函数的使用 22.4 实战-自动备份mysql数据库和nginx服 ...
- JVM总结(二)
JVM总结(2)java内存区域.字节码执行引擎 1.内存区域 程序计数器:知道线程执行位置,保证线程切换后能恢复到正确的执行位置. 虚拟机栈:存栈帧.栈帧里存局部变量表.操作栈.动态连接.方法返回地 ...
- JAVA基础知识(二):List接口、ArrayList类和LinkedList类
List接口继承了Collection接口,位于java.util包中.它包含Collection接口的所有方法,外加其他一些方法(具体实现参考源码),比较重要的有: anyType get(int ...
- 从零开发一款自己的小程序UI组件库(二)
写在前面:从零开发一款自己的小程序UI组件库(一) 上节我们讲到初始化组件库模板.模板文件概述.模板上传npm以及npm包文件下载至本地并运用到项目.这节我们继续,内容主要有基础UI组件库的搭建(bu ...
- 【CodeForces - 1200C】Round Corridor (数论gcd)
Round Corridor Descriptions Amugae位于一个非常大的圆形走廊中.走廊由两个区域组成.内部区域等于nñ扇区,外部区域等于m米部门.在相同区域(内部或外部)的每对扇区之间 ...