diff --git a/README.md b/README.md index 0879034..29b7998 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,26 @@ # 前言 kubernetes实践指南,结合自身实践,并汇总开源社区和各个公司的k8s实践成果。 +前面11章的内容针对CKA(Certificated Kubernetes Admin 官方认证管理员)考试要求做了编排, 希望对备考CKA的童鞋有帮助。 ps: 如无特殊说明, kubernetes的版本默认基于 1.6版本。 目录对应章节名称里的数字代表文章更新进度。 # 目录 -- [概述(99%)](概述.md) -- [部署安装(0%)](部署安装.md) -- [服务发现(0%)](服务发现.md) -- [存储方案(0%)](存储方案.md) -- [网络方案(99%)](网络方案.md) -- [安全与认证(0%)](安全与认证.md) -- [有状态应用(0%)](有状态应用.md) -- [联邦集群(0%)](联邦集群.md) +- [关于K8S相关认证的说明(99%)](关于K8S相关认证的说明.md) +- [集群部署和配置(50%)](集群部署和配置.md) +- [核心概念(99%)](核心概念.md) +- [应用生命周期管理(50%)](应用生命周期管理.md) +- [网络(99%)](网络.md) +- [存储(50%)](存储.md) +- [调度(80%)](调度.md) +- [安全(80%)](安全.md) +- [集群维护(50%)](集群维护.md) - [监控与日志(80%)](监控与日志.md) -- [系统管理(0%)](系统管理.md) -- [生产实践(5%)](生产实践.md) -- [常见问题(0%)](常见问题.md) -- [原理分析(70%)](原理分析.md) -- [源码解读(0%)](源码解读.md) -- [开发指南(30%)](开发指南.md) +- [问题排查(60%)](问题排查.md) +- [有状态应用(5%)](有状态应用.md) +- [联邦集群(0%)](联邦集群.md) +- [生产实践(10%)](生产实践.md) +- [开发指南(50%)](开发指南.md) - [社区生态(20%)](社区生态.md) - [参考资料(99%)](参考资料.md) - [番外篇(10%)](翻外篇.md) # 声明 -本电子书不做商业用途,仅开源阅读。书中部分资料来自互联网博客和文摘,均注明来源。 +本电子书不做商业用途,仅开源阅读。书中部分资料来自互联网博客和文摘,均已注明来源。 diff --git a/_image/2017-09-11-07-43-07.jpg b/_image/2017-09-11-07-43-07.jpg new file mode 100644 index 0000000..c2b6531 Binary files /dev/null and b/_image/2017-09-11-07-43-07.jpg differ diff --git a/_image/2017-09-11-07-44-08.jpg b/_image/2017-09-11-07-44-08.jpg new file mode 100644 index 0000000..c782d0b Binary files /dev/null and b/_image/2017-09-11-07-44-08.jpg differ diff --git a/_image/2017-09-11-09-12-07.jpg b/_image/2017-09-11-09-12-07.jpg new file mode 100644 index 0000000..1befc27 Binary files /dev/null and b/_image/2017-09-11-09-12-07.jpg differ diff --git a/_image/2017-09-11-09-15-06.jpg b/_image/2017-09-11-09-15-06.jpg new file mode 100644 index 0000000..60dcc74 Binary files /dev/null and b/_image/2017-09-11-09-15-06.jpg differ diff --git a/_image/2017-09-16-08-08-46.jpg b/_image/2017-09-16-08-08-46.jpg new file mode 100644 index 0000000..895701b Binary files /dev/null and b/_image/2017-09-16-08-08-46.jpg differ diff --git a/_image/2017-09-24-16-35-30.png b/_image/2017-09-24-16-35-30.png new file mode 100644 index 0000000..727bbd0 Binary files /dev/null and b/_image/2017-09-24-16-35-30.png differ diff --git a/_image/2017-09-24-16-35-49.png b/_image/2017-09-24-16-35-49.png new file mode 100644 index 0000000..cd3c075 Binary files /dev/null and b/_image/2017-09-24-16-35-49.png differ diff --git a/_image/2017-10-08-07-24-35.jpg b/_image/2017-10-08-07-24-35.jpg new file mode 100644 index 0000000..5fe4619 Binary files /dev/null and b/_image/2017-10-08-07-24-35.jpg differ diff --git a/_image/2017-10-08-07-27-57.jpg b/_image/2017-10-08-07-27-57.jpg new file mode 100644 index 0000000..a261c74 Binary files /dev/null and b/_image/2017-10-08-07-27-57.jpg differ diff --git a/_image/2017-10-08-07-30-18.jpg b/_image/2017-10-08-07-30-18.jpg new file mode 100644 index 0000000..6687531 Binary files /dev/null and b/_image/2017-10-08-07-30-18.jpg differ diff --git a/_image/2017-10-08-07-42-11.jpg b/_image/2017-10-08-07-42-11.jpg new file mode 100644 index 0000000..0e66551 Binary files /dev/null and b/_image/2017-10-08-07-42-11.jpg differ diff --git a/_image/2017-10-08-08-25-14.png b/_image/2017-10-08-08-25-14.png new file mode 100644 index 0000000..699f36a Binary files /dev/null and b/_image/2017-10-08-08-25-14.png differ diff --git a/_image/2017-10-08-16-53-11.jpg b/_image/2017-10-08-16-53-11.jpg new file mode 100644 index 0000000..db081bf Binary files /dev/null and b/_image/2017-10-08-16-53-11.jpg differ diff --git a/_image/2017-10-08-16-57-03.jpg b/_image/2017-10-08-16-57-03.jpg new file mode 100644 index 0000000..fdfd922 Binary files /dev/null and b/_image/2017-10-08-16-57-03.jpg differ diff --git a/_image/2017-10-08-16-57-50.jpg b/_image/2017-10-08-16-57-50.jpg new file mode 100644 index 0000000..db081bf Binary files /dev/null and b/_image/2017-10-08-16-57-50.jpg differ diff --git a/_image/2017-10-13-21-20-00.jpg b/_image/2017-10-13-21-20-00.jpg new file mode 100644 index 0000000..6b7b737 Binary files /dev/null and b/_image/2017-10-13-21-20-00.jpg differ diff --git a/_image/2017-10-14-17-10-23.jpg b/_image/2017-10-14-17-10-23.jpg new file mode 100644 index 0000000..944832e Binary files /dev/null and b/_image/2017-10-14-17-10-23.jpg differ diff --git a/_image/2017-10-19-22-36-15.jpg b/_image/2017-10-19-22-36-15.jpg new file mode 100644 index 0000000..ea84689 Binary files /dev/null and b/_image/2017-10-19-22-36-15.jpg differ diff --git "a/\345\205\263\344\272\216K8S\347\233\270\345\205\263\350\256\244\350\257\201\347\232\204\350\257\264\346\230\216.md" "b/\345\205\263\344\272\216K8S\347\233\270\345\205\263\350\256\244\350\257\201\347\232\204\350\257\264\346\230\216.md" new file mode 100644 index 0000000..393dcee --- /dev/null +++ "b/\345\205\263\344\272\216K8S\347\233\270\345\205\263\350\256\244\350\257\201\347\232\204\350\257\264\346\230\216.md" @@ -0,0 +1,220 @@ +2017-09-13 +edited by hackstoic , 转载请注明来源 + +# Kubernetes认证服务提供商(KCSP) +云原生计算基金会(CNCF)负责维护并整合Kubernetes和Prometheus之类的开源技术,今天它在开源峰会上宣布了22多家Kubernetes认证服务提供商(KCSP)的创始成员名单。KCSP是通过初审的企业组织,它们在帮助企业成功地采用Kubernetes方面有着丰富经验。此外,专业人员个人现在可以注册报名新的认证Kubernetes管理员(CKA)计划和考试(https://www.cncf.io/certification/expert/)。 +KCSP的创始成员包括CNCF和Linux基金会的下列成员:埃森哲、博思艾伦、Bitnami、Canonical、Container Solutions、CoreOS、Ghostcloud、Giant Swarm、Heptio、华为、IBM、inwinSTACKInc.、LiveWyer、Mirantis、RX- M LLC、三星SDS、Stackpointcloud、Supergiant和Treasure Data。 +KCSP计划的适用对象是通过初审的服务提供商,它们为踏上Kubernetes之旅的公司企业提供Kubernetes支持、咨询、专业服务和培训。KCSP计划确保企业得到它们在寻求的支持,从而比以前更迅速、更高效地部署新的应用程序,同时确保有一家值得信赖、经过审查的合作伙伴可以支持其生产和运营方面的要求。 +想成为KCSP,**需要至少三名工程师通过认证Kubernetes管理员**(CKA,https://www.cncf.io/certification/expert/)考试,能够证明在Kubernetes社区从事活动(包括积极贡献代码),以及支持企业最终用户的商业模式,包括将工程师派驻客户现场。 + +> 参考 https://mp.weixin.qq.com/s?__biz=MjM5MzM3NjM4MA==&mid=2654684649&idx=2&sn=4bd259d40d4eb33fc07340c07281e6cf 2017-09-13 + +# 认证Kubernetes管理员(CKA) +官方介绍https://www.cncf.io/certification/expert/ +这是CNCF的官方认证。 + +## 认证详情: +在3~4小时内用命令行进行排障, 解决问题, 相关知识点和权重 +- Installation, Configuration & Validation 安装,配置和验证12% + - 设计一个k8s 集群 + - 安装k8s master 和 nodes + - 配置安全的集群通信 + - 配置高可用的k8s集群 + - 知道如何获取k8s的发行的二进制文件 + - 提供底层的基础措施来部署一个集群 + - 选择一个网络方案 + - 选择你的基础设施配置 + - 在你的集群上配置端对端的测试 + - 分析端对端测试结果 + - 运行节点的端对端测试 +- Core Concepts 核心概念 19% + - 理解k8s api原语 + - 理解k8s 架构 + - 理解services和其它网络相关原语 +- Application Lifecycle Management 应用生命周期管理 8% + - 理解Deployment, 并知道如何进行rolling update 和 rollback + - 知道各种配置应用的方式 + - 知道如何为应用扩容 + - 理解基本的应用自愈相关的内容 +- Networking 网络 11% + - 理解在集群节点上配置网络 + - 理解pod的网络概念 + - 理解service networking + - 部署和配置网络负载均衡器 + - 知道如何使用ingress 规则 + - 知道如何使用和配置cluster dns + - 理解CNI +- Storage 存储 7% + - 理解持久化卷(pv),并知道如何创建它们 + - 理解卷(volumes)的access mode + - 理解持久化卷声明(pvc)的原语 + - 理解k8s的存储对象(kubernetes storage objects) + - 知道如何为应用配置持久化存储 +- Scheduling 调度 5% + - 使用label选择器来调度pods + - 理解Daemonset的角色 + - 理解resource limit 会如何影响pod 调度 + - 理解如何运行多个调度器, 以及如何配置pod使用它们 + - 不使用调度器, 手动调度一个pod + - 查看和显示调度事件events + - 知道如何配置kubernetes scheduler +- Security 安全 12% + - 知道如何配置认证和授权 + - 理解k8s安全相关原语 + - 理解如何配置网络策略(network policies) + - 配合使用镜像的安全性 + - 定义安全上下文 + - 安全的持久化保存键值 +- Cluster Maintenance 集群维护 11% + - 理解k8s的集群升级过程 + - 促进操作系统的升级 + - 补充备份和还原的方法论 +- Logging / Monitoring 日志/监控 5% + - 理解如何监控所有的集群组件 + - 理解如何监控应用 + - 管理集群组件日志 + - 管理应用日志 +- Troubleshooting 问题排查 10% + - 排查应用失败故障 + - 排查控制层(control panel)故障 + - 排查工作节点(work node)故障 + - 排查网络故障 + + +> 参考课程大纲https://github.com/cncf/curriculum/blob/master/certified_kubernetes_administrator_exam_V0.9.pdf + +## 考试说明和checklist +- 注册考试 +- 检查系统要求 +- 选择考试日期 +- 获取考生手册 +- 验证姓名 +- 阅读重要提示 +- 参加考试 + +考试期间, 除了考试系统界面上的内容和按钮能操作外, 其它的最好不要动。所有考试无关的内容和资料不允许出现, 包括手机, 参考书等等。 + +考试的时候会提供一个Linux Server Terminal , 是基于Gateone 的web终端,一些快捷键可能跟一般的linux 终端软件不一样, 请提前了解和体验 + +考试由31个问题组成, 需要你用命令来解决这些问题 + +有8套环境, 31个问题在这8套环境里进行操作。 + +平均每套环境有3~5个问题。 + + +![](./_image/2017-10-14-17-10-23.jpg) +通过kubectl config use−context 来切换不同的环境 (集群使用的的k8s 1.6.2版本) + +获取集群信息,要指定对应的context,如 +kubectl get no −l name=hk8s−node−1 −−context=hk8s + + +> 参考官方考试手册 https://www.cncf.io/certification/candidate-handbook + + +## FAQ + +1. 考试费用? +> 300美元, 可以重考一次 + +2. 考试时间长度? +> 最长4个小时,依赖考生的熟练程度 + +3. 如何监考? +> 屏幕共享软件可以让监考官看到考生的屏幕, 所有的音频, 视频和屏幕共享流会被保留一段时间, 用于审查 + +4. 系统要求? +> chrome浏览器, 网络连接, 网络摄像头和麦克风 +> 这个连接可以帮忙检查系统要求https://www.examslocal.com/ScheduleExam/Home/CompatibilityCheck , 注意Select “Linux Foundation” as the Exam Sponsor and “CKA” as the Exam. + +5. 考试期间, 我可以利用什么资源么? +> 除了可以查看考试内容外, 还可以上网浏览考试相关的文档,比如https://kubernetes.io/docs/reference/等 + +6. 考试期间是否可以做笔记? +> 可以做笔记, 但是仅限于在考试控制页面上的工具上 + +7. 需要什么证件? +> 包含考生照片的官方认证证件, 比如护照, 身份证, 驾驶证等(注意,需要证件上要有你的英文名称的全名, 对中国居民来讲, 可以使用护照) +> 需要注册一个Linux Foundation的账号, 到这里注册https://identity.linuxfoundation.org/ + +8. 考试如何打分? +> 24小时内会自动打分, 72~75小时内会邮件发送认证结果 + +9. 认证的有效期? +> 有效期2年, 在过期之前需要重新考试 + +10. 取消和重订 +> 在预定考试日期前24小时外,取消或重订, 可以获得完整退费 + +> 参考 https://www.cncf.io/certification/expert/faq/ + +## 复习资料 + +除了认证大纲内容外, 还可以看看https://feisky.gitbooks.io/kubernetes/, feisky的kubernetes指南包含了上述认证的大部分内容 + +有个CNCF网站提供了免费的分级课程, 可以关注一下:https://kubernauts.io/en/become-a-kubernaut/ , 课程文档 https://www.gitbook.com/@kubernauts +培训课程导图: +https://www.mindmeister.com/zh/920845833/kubernauts-training-plan +新手训练营: +https://kubernetesbootcamp.github.io/kubernetes-bootcamp/index.html +学习资源汇总: +https://github.com/kubernauts/Kubernetes-Learning-Resources +https://github.com/walidshaari/Kubernetes-Certified-Administrator + +linux foundation 提供的免费入门课程: https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-kubernetes +```text +该课程的课程大纲: +Welcome & Introduction +Container Orchestration +Kubernetes +Kubernetes Architecture - Overview +Installing Kubernetes +Setting Up a Single Node Kubernetes Cluster Using Minikube +Accessing Minikube +Kubernetes Building Blocks +Services +Deploying a Stand-Alone Application +Kubernetes Volume Management +Deploying a Multi-Tier Application +ConfigMaps and Secrets +Ingress +Advanced Topics - Overview +Kubernetes Community +Final Exam +ps: 个人觉得这个课程可以不用学, 直接看文档就行了 。 +``` +还有一个收费的课程($299)https://training.linuxfoundation.org/linux-courses/system-administration-training/kubernetes-fundamentals +```text +该课程的课程大纲: +Kubernetes Fundamentals + +Chapter 1. Course Introduction +Chapter 2. Basics of Kubernetes +Chapter 3. Kubernetes Architecture +Chapter 4. Kubernetes Installation and Configuration +Chapter 5. Accessing a k8s Cluster and Using the API +Chapter 6. Replication Controllers and Deployments +Chapter 7. Volumes and Application Data +Chapter 8. Services +Chapter 9. Ingress +Chapter 10. Additional API Objects +Chapter 11. Scheduling +Chapter 12. Logging, Monitoring, and Troubleshooting +Chapter 13. Third-Party Resources +Chapter 14. Kubernetes Federation +Chapter 15. Helm +Chapter 16. Security + +ps: 个人觉得这个课程太贵了,为了省点钱 , 仔细研究下文档就行了 。 + +``` + +培训体系 +https://www.mindmeister.com/zh/920845833/kubernauts-training-plan + +![](./_image/2017-10-13-21-20-00.jpg) + +2017-09-13 +edited by hackstoic , 转载请注明来源 + diff --git "a/\345\205\266\345\256\203\344\270\273\351\242\230.md" "b/\345\205\266\345\256\203\344\270\273\351\242\230.md" deleted file mode 100644 index d435957..0000000 --- "a/\345\205\266\345\256\203\344\270\273\351\242\230.md" +++ /dev/null @@ -1,5 +0,0 @@ -# 参考文献 -- [Kubernetes 1.2 新功能解析:ConfigMap (中)](http://dockone.io/article/1208) -- [深度解析Kubernetes 1.5之支持多容器格式的CRI](http://mp.weixin.qq.com/s?__biz=MjM5ODM3MzkyNQ==&mid=2654379369&idx=1&sn=52f439609dc8a979081b4d7aa0b5e2b0&chksm=bd0982238a7e0b3559483072b565fc1b58611822c9e52820c845d6e9176593878b39b10367d9&mpshare=1&scene=1&srcid=1226qYyfyKOp8MfsbSRcXmuX#rd) -- [Kubernetes 1.6新特性系列 | 高级调度](http://mp.weixin.qq.com/s?__biz=MzI0NjI4MDg5MQ==&mid=2715290924&idx=1&sn=9e8947889e2d139ac1bb671c8fc1ffbb&chksm=cd6d0af8fa1a83ee830439c1a8b7fa05e65bba50bf42c8e303e0acba667590d26a29802e74ed&mpshare=1&scene=1&srcid=0423ad4SgVluiVSCGkAQnvnR#rd) -- [Kubernetes:理解资源的概念](http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649692963&idx=1&sn=a8226eec270d26ddefee3187535f3aae&chksm=88932440bfe4ad5638f4bebeeb31a6ff438fae58bf98215a394b4fb7207b2b552f94bd44f8a6&mpshare=1&scene=1&srcid=0106fPf4t4wTCY2yGYgSGyfy#rd) diff --git "a/\345\216\237\347\220\206\345\210\206\346\236\220.md" "b/\345\216\237\347\220\206\345\210\206\346\236\220.md" deleted file mode 100644 index fdeacb6..0000000 --- "a/\345\216\237\347\220\206\345\210\206\346\236\220.md" +++ /dev/null @@ -1,180 +0,0 @@ -架构设计 - - -![](./_image/2017-03-11-22-48-43.jpg) - -以下是《kubernetes权威指南》的学习笔记,我 对书中的内容做了总结和提炼。 如有谬误之处, 还望各位指出。 -# Apiserver原理分析 -## 概述 -整个系统的数据总线。 -提供以下功能特性: -1. 集群管理的api入口 -2. 资源配额控制的入口 -3. 提供完善的集群安全机制 - -## api 访问 -访问api的三种方式: -1. 直接curl调用api -2. 启动内部代理(kubectl proxy ),然后访问内部代理进行调用,可以进行访问控制,如限制要访问的接口,增加允许访问的client的白名单 -3. 使用k8s提供的client lib ,通过编程的方式访问,这种方式有两种使用场景,一是pod需要发现同属于一个service的其它pod副本的信息来组建集群(如elasticsearch集群), 二是需要通过调用api来我开发基于k8s的管理平台 - -独特的k8s proxy api: - -这种api可以用来代理rest请求, 把收到的请求转发到某一个node上的kubelet进程的端口上,由kubelet进行响应 -示例: curl 127.0.0.1:8080/api/v1/proxy/nodes/node-1/pods -这里返回的pods的信息是由node上的kubelet进程收集的, 而不是从etcd的数据库获取, 二者的信息可能在某个时间点会有偏差。 -这种特殊的api的应用场景是: 通过这类api来直接访问pods上的应用, 可以用来逐一排查同一service的多个pod副本上的应用是否有异常。 -示例一: curl 127.0.0.1:8080/api/v1/proxy/namespaces/default/pods/xxxx-pod-1 -示例二: curl 127.0.0.1:8080/api/v1/proxy/namespaces/default/services/xxxx-svr-1 - -## 集群之间功能模块的通信 -kubelet --> apiserver (汇报自身状态, 侦听pod信息) -controller-manager --> apiserver (实时监控node信息,并做处理) -scheduler --> apiserver (侦听新建pod的信息, 检索符合要求的node列表,并进行调度逻辑的执行) - -为缓解apiserver的压力, 各个模块会缓存从apiserver获取的数据, 某些情况下会直接使用缓存的数据(**什么情况使用缓存, 如何保证数据的一致性?**) - -# controller manager原理分析 -集群内部的管理控制中心,是一个“修正系统”。 -负责以下对象的管理: -- node -- pod副本 -- endpoint -- namespace -- service accout -- resource quota - -包含了以下controller: -- replication controller -- node controller -- resourcequota controller -- namespace controller -- serviceaccount controller -- token controller -- service controller -- endpoint controller - -## replication controller -职责是: 保证pod副本数量始终保持预设值 -应用场景: -1. 确保pod数量, 以保证高可用要求 -2. 系统扩容和缩容 -3. 滚动更新 - -只有当pod的重启策略是Always时(RestartPolicy=Always)时, replication controller 才会管理该pod的操作(例如创建, 销毁, 重启等) - -pod通过修改标签可以脱离replication controller的控制 -## node controller -通过apiserver获取node的信息,实现管理和监控集群的各个node节点的相关控制功能。 -节点的健康状态有三种: 就绪(true), 未就绪(false), 未知(unknown) -master节点的系统时间作为探测时间, 状态变化的时间可能是上一次保存的状态时间,或者本次节点变化的时间。 -如果有段时间没有收到节点信息,则状态设置为unknown. -当状态为非就绪状态时, 将节点加入待删除队列。 - -## resourcequota controller -资源配额管理, 确保指定的资源对象在任何情况下都不会超量占用系统资源,避免业务进程的设计和实现的缺陷导致整个系统的紊乱, 对整个集群的平稳运行起着重要作用。 - -k8s集群对资源配额的管理有三个维度: 容器级别, pod级别, namespace级别。 -容器级别: cpu & memory -pod级别: 所有容器的可用资源 -namespace级别: pod数量, rc数量, svr数量, resourcequota数量, secret数量, pv数量 - -配额管理的控制: -由apiserver中的admission control来控制, 实际上apiserver是配额控制的一个入口。 -两种配额约束方式: limitranger(容器级别, pod级别), resourcequota(namespace级别) - -resourcequota controller组件负责定期统计namespace下pod, rc, svr, resourcequota, secret, pv等资源对象的数量, 还有container实例使用的资源,将统计结果写入etcd。 -这些信息会被admission controller使用, 如果不符合配额约束, 则创建对象失败。 -如果既在namespace上命名了resourcequota约束, 又在pod级别声明了limitranger,admission control 会同时计算二者的情况, 需要同时满足才会创建对象。 - -## namespace controller -用户通过api server创建新的namespace, 并保存在etcd中。 而这个controller可以通过api server读取namespace的相关信息。 -当namespace的状态被设置为terminating时, 这个controller会删除改namespace下的所有对象资源。 -admission controller会通过namespacelifecycle插件来阻止为该namespace创建新的资源。 - -## serviceaccount controller -## token controller -## service controller -k8s集群和外部云平台的一个接口控制器,负责侦听service的变化。如果service的type是loadbalancer, 那么service controller就会负责动态更新创建对于的loadbalancer实例, 和路由转发表等 -## endpoint controller -负责侦听service和相应的pod副本的变化,以及生成和维护所有endpoints对象。 当service被删除时,该controller会负责删除该service同名的endpoints对象。 当新的service被创建或修改, pod产生相关事件时, 该controller就会更新对应service的endpoints对象(更改对应的endpoint条目)。 - -注: endpoints对象维护一个service对应的所有pod副本的访问地址。 - -# scheduler 原理分析 -scheduler是负责pod调度的重要组件。起着承上启下的作用, 从上游接收controller manager 创建的pod, 为起安排node落脚, 然后交给目标node上的kubelet进程, 由其负责pod的“下半生”的生命周期管理。 - -默认调度流程分两步: -1. 预选(predicates): 遍历所有node, 先根据预选策略初步筛选出符合条件的node -2. 优选(priority): 从预选的node中挑出最优的选择 - -调度流程是通过插件的方式加载调度算法提供者。 每个algorithmprovider都要提供3个参数, 算法名称name, 预选策略集合predicatekeys, 优选策略集合prioritykeys - -7个可用的预选策略: -- NoDiskConflict -- PodFirstResources -- PodSelectorMatches -- PodFitsHost -- CheckNodeLablePresence -- CheckServiceAffinity -- PodFitsPorts - -默认的algorithmprovider加载的预选策略: -- NoDiskConflict -- PodFirstResources -- PodSelectorMatches -- PodFitsHost -- PodFitsPorts - - -所有预选策略的说明 -- NoDiskConflict -> 判断备选pod的gcepersistentdisk或者awselasticblockstore和备选的节点已存在的pod是否存在冲突 -- PodFirstResources -> node的资源是否满足备选pod的需求。需要对备选pod和node上已有pod的资源进行求和,看是否超过node所能提供的资源 -- PodSelectorMatches -> node是否有pod的标签选择器所指定的标签, 即nodeselector所指定的标签 -- PodFitsHost -> node的名称是否和pod所指定的node名称一致, 即nodename所指定的名称 -- CheckNodeLablePresence -> 用于判断当策略列出的标签在备选节点存在是, 是否选择该备选节点 -- CheckServiceAffinity -> 用于判断备选节点是否包含策略指定的标签 -- PodFitsPorts -> 判断备选pod所用的端口是否在备选的node中被占用 - -3个优选策略: -- LeastRequestedPriority -- CalculateNodeLabelPriority -- BalancedResourceAllocation - -注:每个节点通过优选策略会算出一个得分, 得分最大的节点作为最终的优选结果。 - -问题: ** 所有的优选策略都要计算一遍么?还是只是挑选其中的一个?如果挑选其中一个,又是如何挑选?** - -所有优选策略的说明: -- LeastRequestedPriority -> 选出资源消耗最少的节点, 即资源最充足的节点(cpu, mem两个维度), 有对应的计算公式 -- CalculateNodeLabelPriority - > 判断策略列出的标签在备选节点出现时,是否选择该备选节点 -- BalancedResourceAllocation -> 从备选节点中选出各项资源使用率最均衡的方法, 与1类似,但是计算公式又不同 - -# kubelet原理分析 -kubelet是k8s集群node端一个服务进程。 主要负责三个任务: -1. 处理master下发到本节点的任务,管理pod和pod中的容器,如启动,删除等 -2. 向apiserver注册节点信息, 定期向apiserver汇报节点资源的使用情况 -3. 使用cAdvisor监控容器和节点资源 - -## 节点管理 -在1.3.6版本中kubelet有130个参数。 下面介绍和节点管理相关的几个参数: -- - api-servers 告诉到哪里去注册和上报信息, 可以支持多个apiserver地址(ip + port), 以逗号分隔 -- - register-node 是否启用上报信息的功能 -- - node-ip 汇报的节点ip地址,汇报给apiserver的是网卡地址, 如果是有NAT IP的机器想要向apiserver注册NAT IP, 需要在这个参数指定 - -## Pod管理 - -## 容器健康检查 -## cAdvisor资源监控 - -# 参考文献 diff --git "a/\345\217\202\350\200\203\350\265\204\346\226\231.md" "b/\345\217\202\350\200\203\350\265\204\346\226\231.md" index f8ade96..a336515 100644 --- "a/\345\217\202\350\200\203\350\265\204\346\226\231.md" +++ "b/\345\217\202\350\200\203\350\265\204\346\226\231.md" @@ -25,6 +25,7 @@ - [awesome-kubernetes](http://ramitsurana.github.io/awesome-kubernetes/) - [community repo](https://github.com/kubernetes/community) 通过这个github 仓库可以了解最新的社区动态 ,和社区工具的发展 - [GitHub - rootsongjc/kubernetes-handbook: For kubernetes users and fans, let's rock it!](https://github.com/rootsongjc/kubernetes-handbook) ***** +- [Kubernetes Handbook (Kubernetes指南)](https://github.com/feiskyer/kubernetes-handbook) # 课程培训 - [才云k8s技术培训](http://www.itdks.com/dakashuo/playback/409) @@ -35,6 +36,18 @@ - [https://www.udacity.com/course/scalable-microservices-with-kubernetes--ud615](https://www.udacity.com/course/scalable-microservices-with-kubernetes--ud615) + +- [Kubernetes完全教程-资料](https://github.com/jolestar/kubernetes-complete-course) +- [Kubernetes完全教程-公开课视频](http://edu.csdn.net/course/detail/6080) +> 预备课:Docker 以及 Docker 网络 +第一课:Kubernetes 架构概述 +第二课:Kubernetes 的安装和运维 +第三课:Kubernetes 的网络和存储 +第四课:Kubernetes 的 API Spec 以及安全机制 +第五课:Kubernetes 的应用管理(案例) +第六课:Kubernetes 的日志监控与故障排除 +第七课:Kubernetes 的扩展开发 + # 出版书籍 - 《容器与容器云》 - 《Kubernetes实战 》 diff --git "a/\345\255\230\345\202\250.md" "b/\345\255\230\345\202\250.md" new file mode 100644 index 0000000..b0daf7b --- /dev/null +++ "b/\345\255\230\345\202\250.md" @@ -0,0 +1,232 @@ +# 存储介绍 +## 认证要求 + - 理解持久化卷(pv),并知道如何创建它们 + - 理解卷(volumes)的access mode + - 理解持久化卷声明(pvc)的原语 + - 理解k8s的存储对象(kubernetes storage objects) + - 知道如何为应用配置持久化存储 + +## 要点摘录 +> 参考 [官方文档之持久化存储](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) + +### 三个概念: pv ,storageclass, pvc + +- pv - 持久化卷, 支持本地存储和网络存储, 例如hostpath,ceph rbd, nfs等,只支持两个属性, capacity和accessModes。其中capacity只支持size的定义,不支持iops等参数的设定,accessModes有三种,ReadWriteOnce(被单个node读写), ReadOnlyMany(被多个nodes读), ReadWriteMany(被多个nodes读写) +- storageclass-另外一种提供存储资源的方式, 提供更多的层级选型, 如iops等参数。 但是具体的参数与提供方是绑定的。 如aws和gce它们提供的storageclass的参数可选项是有不同的。 +- pvc - 对pv或者storageclass资源的请求, pvc 对 pv 类比于pod 对不同的cpu, mem的请求。 + +### 六个生命周期: Provisioning, Binding, Using, Releasing, Reclaiming, Recycling + +k8s对pv和pvc之间的交互的生命周期进行管理。 +- provisioning- 配置阶段, 分为static, dynamic两种方式。静态的方式是创建一系列的pv,然后pvc从pv中请求。 动态的方式是基于storageclass的。 + +- Binding - 绑定阶段, pvc根据请求的条件筛选并绑定对应的pv。 一定pvc绑定pv后, 就会排斥其它绑定,即其它pvc无法再绑定同一个pv,即使这个pv设定的access mode允许多个node读写。 此外 ,pvc 如何匹配不到相应条件的pv, 那么就会显示unbound状态, 直到匹配为止。 需要注意的是,pvc请求100Gi大小的存储,即使用户创建了很多50Gi大小的存储, 也是无法被匹配的。 + +- Using- 使用阶段, pods 挂载存储, 即在pod的template文件中定义volumn使用某个pvc。 + +- Releasing - 释放阶段, 当pvc对象被删除后, 就处于释放阶段。 在这个阶段, 使用的pv还不能被其它的pvc请求。 之前数据可能还会留存下来, 取决于用户在pv中设定的policy, 见persistentVolumeReclaimPolicy。 + +- Reclaiming - 重声明阶段。 到这个阶段, 会告诉cluster如何处理释放的pv。 数据可能被保留(需要手工清除), 回收和删除。动态分配的存储总是会被删除掉的。 + +- Recycling - 回收阶段。回收阶段会执行基本的递归删除(取决于volumn plugins的支持),把pv上的数据删除掉, 以使pv可以被新的pvc请求。 用户也可以自定义一个 recycler pod , 对数据进行删除。 + +### 三种PV的访问模式 + +- ReadWriteOnce:是最基本的方式,可读可写,但只支持被单个Pod挂载。 +- ReadOnlyMany:可以以只读的方式被多个Pod挂载。 +- ReadWriteMany:这种存储可以以读写的方式被多个Pod共享。 +不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是NFS。在PVC绑定PV时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。 + +### 九个PV Plugins + +pv是以plugin的形式来提供支持的, 考虑到私有云的使用场景, 排除掉azure, aws,gce等公有云厂商绑定的plugin, 有9个插件值得关注。这些plugin所支持的accessmode是不同的。 分别是: +```table +存储Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany | 备注 +FC (Fibre Channel) | 支持 | 支持 | 不支持 | +NFS | 支持 | 支持 | 支持 | +iSCSI | 支持 | 支持 | 不支持 | +RBD (Ceph Block Device) | 支持 | 支持 | 不支持 | +CephFS | 支持 | 支持 | 支持 | +Cinder (OpenStack block storage) | 支持 | 不支持 | 不支持 | +Glusterfs | 支持 | 支持 | 支持 | +VsphereVolume | 支持 | 不支持 | 不支持 | +HostPath | 支持 | 不支持 | 不支持 | 只支持单节点, 不支持跨节点 +``` + + +### 三个重声明策略(reclaim policy) + +- Retain – 手动重新使用 +- Recycle – 基本的数据擦除 (“rm -rf /thevolume/*”) +- Delete – 相关联的后端存储卷删除, 后端存储比如AWS EBS, GCE PD, Azure Disk, or OpenStack Cinder +需要特别注意的是只有本地盘和nfs支持数据盘Recycle 擦除回收, AWS EBS, GCE PD, Azure Disk, and Cinder 存储卷支持Delete策略 + + +### 四个阶段(volumn phase) + +一个存储卷会处于下面几个阶段中的一个阶段: +- Available –资源可用, 还没有被声明绑定 +- Bound – 被声明绑定 +- Released – 绑定的声明被删除了,但是还没有被集群重声明 +- Failed – 自动回收失败 + +### 四个PV选择器 +在PVC中绑定一个PV,可以根据下面几种条件组合选择 +- Access Modes, 按照访问模式选择pv +- Resources, 按照资源属性选择, 比如说请求存储大小为8个G的pv +- Selector, 按照pv的label选择 +- Class, 根据StorageClass的class名称选择, 通过annotation指定了Storage Class的名字, 来绑定特定类型的后端存储 + +关于根据class过滤出pv的说明: +> 所有的 PVC 都可以在不使用 StorageClass 注解的情况下,直接使用某个动态存储。把一个StorageClass 对象标记为 “default” 就可以了。StorageClass 用注解storageclass.beta.kubernetes.io/is-default-class 就可以成为缺省存储。 +有了缺省的 StorageClass,用户创建 PVC 就不用 storage-class 的注解了,1.4 中新加入的DefaultStorageClass 准入控制器会自动把这个标注指向缺省存储类。 +> PVC 指定特定storageClassName,如fast时, 绑定名称为fast的storageClass +> PVC中指定storageClassName为“”时, 绑定no class的pv(pv中无class annotation, 或者其值为“”) +> PVC不指定storageClassName时, DefaultStorageClass admission plugin 开启与否(在apiserver启动时可以指定), 对default class的解析行为是不同的。 +当DefaultStorageClass admission plugin启用时, 针对没有storageClass annotation的pvc,DefaultStorageClass会分配一个默认的class, 这个默认的class需要用户指定,比如在创建storageclass对象时加入annotation,如 storageclass.beta.kubernetes.io/is-default-class: “true” 。如果有多个默认的class, 则pvc会被拒绝创建, 如果用户没有指定默认的class, 则这个DefaultStorageClass admission plugin不会起任何作用。 pvc会找那些no class的pv做绑定。 +当DefaultStorageClass admission plugin没有启用时, 针对没有storageClass annotation的pvc, 会绑定no class的pv(pv中无class annotation, 或者其值为“”) + + + +### 五个可移植性建议 +1. 把你的 pvc,和 其它一系列配置放一起, 比如说deployment,configmap +2. 不要把你的pv放在其它配置里, 因为用户可能没有权限创建pv +3. 初始化pvc 模版的时候, 提供一个storageclass +4. 在你的工具软件中,watch那些没有bound的pvc,并呈现给用户 +5. 集群启动的时候启用DefaultStorageClass, 但是不要指定某一类特定的class, 因为不同provisioner的class,参数很难一致 + + +## Volume, Persistent Volume, 以及StorageClass + +K8S 的存储系统从基础到高级又大致分为三个层次:普通 Volume,Persistent Volume 和动态存储供应。 + + +1、普通 Volume + +最简单的普通 Volume 是单节点 Volume。它和 Docker 的存储卷类似,使用的是 Pod 所在 K8S 节点的本地目录。 + +第二种类型是跨节点存储卷,这种存储卷不和某个具体的 K8S 节点绑定,而是独立于 K8S节点存在的,整个存储集群和 K8S 集群是两个集群,相互独立。 + +跨节点的存储卷在 Kubernetes 上用的比较多,如果已有的存储不能满足要求,还可以开发自己的 Volume 插件,只需要实现 Volume.go 里定义的接口。如果你是一个存储厂商,想要自己的存储支持 Kubernetes 上运行的容器,就可以去开发一个自己的 Volume 插件。 + + +2、persistent volume + +它和普通 Volume 的区别是什么呢? + +普通 Volume 和使用它的 Pod 之间是一种静态绑定关系,在定义 Pod 的文件里,同时定义了它使用的 Volume。Volume 是 Pod 的附属品,我们无法单独创建一个 Volume,因为它不是一个独立的 K8S 资源对象。 + +而 Persistent Volume 简称 PV 是一个 K8S 资源对象,所以我们可以单独创建一个 PV。它不和 Pod 直接发生关系,而是通过 Persistent Volume Claim,简称 PVC 来实现动态绑定。Pod 定义里指定的是 PVC,然后 PVC 会根据 Pod 的要求去自动绑定合适的 PV 给 Pod 使用。 + +PV 的访问模式有三种: + +第一种,ReadWriteOnce:是最基本的方式,可读可写,但只支持被单个 Pod 挂载。 + +第二种,ReadOnlyMany:可以以只读的方式被多个 Pod 挂载。 + +第三种,ReadWriteMany:这种存储可以以读写的方式被多个 Pod 共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是 NFS。在 PVC 绑定 PV 时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。 + +刚才提到说 PV 与普通 Volume 的区别是动态绑定,我们来看一下这个过程是怎样的。 + +![](./_image/2017-09-11-09-12-07.jpg) +这是 PV 的生命周期,首先是 Provision,即创建 PV,这里创建 PV 有两种方式,静态和动态。所谓静态,是管理员手动创建一堆 PV,组成一个 PV 池,供 PVC 来绑定。动态方式是通过一个叫 Storage Class 的对象由存储系统根据 PVC 的要求自动创建。 + +一个 PV 创建完后状态会变成 Available,等待被 PVC 绑定。 + +一旦被 PVC 邦定,PV 的状态会变成 Bound,就可以被定义了相应 PVC 的 Pod 使用。 + +Pod 使用完后会释放 PV,PV 的状态变成 Released。 + +变成 Released 的 PV 会根据定义的回收策略做相应的回收工作。有三种回收策略,Retain、Delete 和 Recycle。Retain就是保留现场,K8S 什么也不做,等待用户手动去处理 PV 里的数据,处理完后,再手动删除 PV。Delete 策略,K8S 会自动删除该 PV 及里面的数据。Recycle 方式,K8S 会将 PV 里的数据删除,然后把 PV 的状态变成 Available,又可以被新的 PVC 绑定使用。 + +在实际使用场景里,PV 的创建和使用通常不是同一个人。这里有一个典型的应用场景:管理员创建一个 PV 池,开发人员创建 Pod 和 PVC,PVC 里定义了Pod所需存储的大小和访问模式,然后 PVC 会到 PV 池里自动匹配最合适的 PV 给 Pod 使用。 + +前面在介绍 PV 的生命周期时,提到 PV 的供给有两种方式,静态和动态。其中动态方式是通过 StorageClass 来完成的,这是一种新的存储供应方式。 + +使用 StorageClass 有什么好处呢?除了由存储系统动态创建,节省了管理员的时间,还有一个好处是可以封装不同类型的存储供 PVC 选用。在 StorageClass 出现以前,PVC 绑定一个 PV 只能根据两个条件,一个是存储的大小,另一个是访问模式。在 StorageClass 出现后,等于增加了一个绑定维度。 + +比如这里就有两个 StorageClass,它们都是用谷歌的存储系统,但是一个使用的是普通磁盘,我们把这个 StorageClass 命名为 slow。另一个使用的是 SSD,我们把它命名为 fast。 + +在 PVC 里除了常规的大小、访问模式的要求外,还通过 annotation 指定了 Storage Class 的名字为 fast,这样这个 PVC 就会绑定一个 SSD,而不会绑定一个普通的磁盘。 + +到这里 Kubernetes 的整个存储系统就都介绍完了。总结一下,两种存储卷:普通 Volume 和 Persistent Volume。普通 Volume 在定义 Pod 的时候直接定义,Persistent Volume 通过 Persistent Volume Claim 动态绑定。PV 可以手动创建,也可以通过 StorageClass 来动态创建。 + +> 参考 [K8S 弹药库 | Kubernetes 有状态集群服务部署与管理(上)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483722&idx=2&sn=a8ec119efcf1a5a9c8ab9c04185df1e1&chksm=fc1c2d7acb6ba46cffa1e1c77ac632aa4661de1fd1c48323986463882c971e6a2922a4bc2aa0&mpshare=1&scene=1&srcid=04212ZmcJoz5fSQhSljVunu4#rd) + +## 如何创建和使用PV, PVC +pv示例: +```yml +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv0003 +spec: + capacity: + storage: 5Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Recycle + storageClassName: slow + nfs: + path: /tmp + server: 172.17.0.2 +``` + +pvc示例: +```yml +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: myclaim +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 8Gi + storageClassName: slow + selector: + matchLabels: + release: "stable" + matchExpressions: + - {key: environment, operator: In, values: [dev]} +``` + +在pod中使用pvc,示例 +```yml +kind: Pod +apiVersion: v1 +metadata: + name: mypod +spec: + containers: + - name: myfrontend + image: dockerfile/nginx + volumeMounts: + - mountPath: "/var/www/html" + name: mypd + volumes: + - name: mypd + persistentVolumeClaim: + claimName: myclaim +``` + +# 存储方案 +# 参考文献 +- [官方文档之持久化存储](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) +- [K8S 弹药库 | Kubernetes 有状态集群服务部署与管理(上)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483722&idx=2&sn=a8ec119efcf1a5a9c8ab9c04185df1e1&chksm=fc1c2d7acb6ba46cffa1e1c77ac632aa4661de1fd1c48323986463882c971e6a2922a4bc2aa0&mpshare=1&scene=1&srcid=04212ZmcJoz5fSQhSljVunu4#rd) +- [官方文档之存储方案](http://kubernetes.io/docs/user-guide/volumes/) +- [flocker get started guide](https://clusterhq.com/flocker/getting-started/) +- [k8s-flocker-example](https://github.com/kubernetes/kubernetes/tree/master/examples/volumes/flocker) +- [Docker容器的持久存储模式介绍](http://www.dockerinfo.net/1000.html) +- [开源数据卷管理工具flocker](http://dockone.io/article/1549) +- [flcoker 支持的后端列表](https://docs.clusterhq.com/en/latest/supported/index.html) +- [Docker容器对存储的定义(Volume 与 Volume Plugin)](http://dockone.io/article/1257) +- [典型容器存储项目揭密:Flocker,Portworx和VSAN](http://mp.weixin.qq.com/s?__biz=MzAwNzUyNzI5Mw==&mid=2730790315&idx=1&sn=01fff8ee701b99dbe64eb004e0a1cb46&scene=1&srcid=0919gZliDxa3HMA8vptYv5LX#rd) +- [官方文档之持久化存储](http://kubernetes.io/docs/user-guide/persistent-volumes/) +- [探讨容器中使用块存储](https://www.kubernetes.org.cn/914.html) +- [Configuring a Pod to Use a PersistentVolume for Storage](https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/) +- [Rook存储:Kubernetes中最优秀的存储](http://www.dockone.io/article/2156) +- [基于docker部署ceph以及修改docker image](http://www.dockerinfo.net/4440.html) +- [Kubernetes集群安装文档-v1.6版本](https://www.kubernetes.org.cn/1870.html) +- [K8S 老司机 | Kubernetes 有状态集群服务部署与管理(下)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483727&idx=3&sn=485f783756f9539ba8659ee265d2905f&chksm=fc1c2d7fcb6ba46908b2078bed06b34a6aafeb67d2fe50bde3979baaa4d60eaaa67bf7bc2da9&mpshare=1&scene=1&srcid=0424tZbUNKEy8lozNbfHnwEv#rd) diff --git "a/\345\255\230\345\202\250\346\226\271\346\241\210.md" "b/\345\255\230\345\202\250\346\226\271\346\241\210.md" deleted file mode 100644 index 8f8ccb2..0000000 --- "a/\345\255\230\345\202\250\346\226\271\346\241\210.md" +++ /dev/null @@ -1,17 +0,0 @@ -# 存储方案 -# 参考文献 -- [官方文档之存储方案](http://kubernetes.io/docs/user-guide/volumes/) -- [flocker get started guide](https://clusterhq.com/flocker/getting-started/) -- [k8s-flocker-example](https://github.com/kubernetes/kubernetes/tree/master/examples/volumes/flocker) -- [Docker容器的持久存储模式介绍](http://www.dockerinfo.net/1000.html) -- [开源数据卷管理工具flocker](http://dockone.io/article/1549) -- [flcoker 支持的后端列表](https://docs.clusterhq.com/en/latest/supported/index.html) -- [Docker容器对存储的定义(Volume 与 Volume Plugin)](http://dockone.io/article/1257) -- [典型容器存储项目揭密:Flocker,Portworx和VSAN](http://mp.weixin.qq.com/s?__biz=MzAwNzUyNzI5Mw==&mid=2730790315&idx=1&sn=01fff8ee701b99dbe64eb004e0a1cb46&scene=1&srcid=0919gZliDxa3HMA8vptYv5LX#rd) -- [官方文档之持久化存储](http://kubernetes.io/docs/user-guide/persistent-volumes/) -- [探讨容器中使用块存储](https://www.kubernetes.org.cn/914.html) -- [Configuring a Pod to Use a PersistentVolume for Storage](https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/) -- [Rook存储:Kubernetes中最优秀的存储](http://www.dockone.io/article/2156) -- [基于docker部署ceph以及修改docker image](http://www.dockerinfo.net/4440.html) -- [Kubernetes集群安装文档-v1.6版本](https://www.kubernetes.org.cn/1870.html) -- [K8S 老司机 | Kubernetes 有状态集群服务部署与管理(下)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483727&idx=3&sn=485f783756f9539ba8659ee265d2905f&chksm=fc1c2d7fcb6ba46908b2078bed06b34a6aafeb67d2fe50bde3979baaa4d60eaaa67bf7bc2da9&mpshare=1&scene=1&srcid=0424tZbUNKEy8lozNbfHnwEv#rd) diff --git "a/\345\256\211\345\205\250.md" "b/\345\256\211\345\205\250.md" new file mode 100644 index 0000000..400a724 --- /dev/null +++ "b/\345\256\211\345\205\250.md" @@ -0,0 +1,663 @@ +# 认证要求 +- Security 安全 12% + - 知道如何配置认证和授权 + - 理解k8s安全相关概念 + - 理解如何配置网络策略(network policies) + - 配合使用镜像的安全性 + - 定义安全上下文(Security Context) + - 安全的持久化保存键值 + +# 名词解释 + +# 认证和授权 +用户可以通过kubectl命令, 客户端库, 或者发送REST请求来[访问API](/docs/user-guide/accessing-the-cluster) 。kubernetes用户和[服务账号](/docs/tasks/configure-pod-container/configure-service-account/)都可以用于API访问时的授权。 当请求到达API时, 它会经历几个阶段,如下图所示: + +![](./_image/2017-10-19-22-36-15.jpg) + +## 传输安全 +在一个典型的 Kubernetes集群里, API 的侦听端口是443, TLS连接会被建立。 API server会提供一个证书。 这个证书是自签名的, 因此在`$USER/.kube/config`路径下会包含API server证书的根证书,你可以指定这个证书用来替换系统默认的根证书。 当你使用`kube-up.sh`来创建集群时,这个证书会自动写入到`$USER/.kube/config`目录下。 如果集群有多个用户, 那么集群创建者需要和其它用户共享这个证书。 + +## 认证 + TLS一旦建立连接, HTTP请求就会转到认证这一步, 即图示中标注的步骤1. +集群创建脚本或者集群的管理者通过配置API server可以加载一个或多个认证模块。 认证模块的更多描述信息参考[这里](/docs/admin/authentication/)。 +认证这一步骤的输入就是整个HTTP的请求, 然而,整个认证步骤也是只是检查了HTTP的header信息,和/或者 客户端证书。 +认证模块包括客户端证书, 密码,明文token, 初始token, 和JWT token(用于服务账号)。 +可以同时指定多个认证模块,对于这种情况, 会按照指定的顺序一个个尝试认证,直到有一个认证成功为止。 +在GCE上, 客户端证书, 密码,明文token, 初始token, 和JWT token这几个认证模块都是打开的。 +如果请求不能被认证成功, 那么它会被拒绝,并收到401的状态码。 +如果认证成功, 用户会被指定一个用户名做认证, 这个用户名会被下一个步骤用于下一轮判断。有 一些验证模块还会为该用户提供组成员资格,有些则不会 。 +当Kubernetes将“用户名”用于准入控制的决定和请求日志的记录过程,在它的对象存储中就不会出现`user`对象, 也不会存储有关用户的用户名和其它信息。 +## 授权 +当一个请求被验证来自指定用户时, 这个请求紧接着必须被授权, 即如图示中的步骤**2**所示. +一个请求必须包含请求者的用户名, 请求的动作, 影响动作的对象。 如果有存在的策略声明这个用户有权限完成这个动作,那么该请求就会被授权。 +举个例子, 如果Bob用户有这样一条策略, 那么他可以从命名空间 `projectCaribou`中读取pod信息: +```json +{ + "apiVersion": "abac.authorization.kubernetes.io/v1beta1", + "kind": "Policy", + "spec": { + "user": "bob", + "namespace": "projectCaribou", + "resource": "pods", + "readonly": true + } +} +``` +如果Bob发送这样一个请求, 他可以被成功授权, 因为他读取命名空间 `projectCaribou`里的对象信息的动作是被允许的: +```json +{ + "apiVersion": "authorization.k8s.io/v1beta1", + "kind": "SubjectAccessReview", + "spec": { + "resourceAttributes": { + "namespace": "projectCaribou", + "verb": "get", + "group": "unicorn.example.org", + "resource": "pods" + } + } +} +``` +如果Bob发送往 `projectCaribou`命名空间写(`create` 或者 `update`)对象信息的请求, 那么他会被拒绝授权。 如果发送从一个不同的命名空间, 比如`projectFish` 读取(`get`)对象信息的请求,那么他的授权也会被拒绝。 Kubernetes的授权要求你和已存在的组织范畴或者云供应商范畴的访问控制系统进行交互时, 要使用通用的REST属性。使用REST的格式是非常重要的, 因为这些控制系统也可能会和包括Kubernetes API在内的其它API进行交互。 +Kubernetes支持多个授权模块, 比如ABAC模式, RBAC模式, Webhook模式。 +当一个管理员创建了集群, 他们会配置API server会启用哪些授权模块。 如果配置了多于1个的授权模块, Kubernetes会检查每个模块, 如果其中任何模块授权的请求, 请求会被处理, 如果所有的模块都拒绝了请求, 那么请求会被拒绝掉(返回403状态码)。 +要了解更多关于Kubernetes授权的信息, 包括使用支持的授权模块来创建策略的细节信息,可以参见 [授权概览](/docs/admin/authorization)。 +## 准入控制 +准入控制模块是可以修改或者拒绝请求的模块。 +作为授权模块的补充, 准入控制可以访问一个正在被创建或更新的对象的内容, +它们在对象创建, 删除,更新, 连接(代理)期间起作用,在读取对象时它们不起作用。 +可以配置多个准入控制器, 每个准入控制器会按照顺序被调用。 +如图示中的步骤**3**所示。 +跟认证和授权模块不同的时,如果任何一个准入控制模块拒绝了请求, 那么请求就会立马被拒绝掉。 +除了拒绝对象之外, 准入控制器还可以为字段设置复杂的默认值。 + +可用的准入控制模块的详情请参考[这里](/docs/admin/admission-controllers/)。 + +一但一个请求通过了所有的准则控制器的批准, 那么这个请求会被对应的API对象验证程序证实为有效请求, 然后会被写入到对象存储里(如图中步骤 **4**所示) +## API Server 的端口和IP +之前的讨论的都是请求发往API Server的安全端口的情况(这个也是最典型的情况)。 事实上, API Server可以侦听两个端口: +默认情况下, API Server启动时侦听两个端口: + 1. `本地端口`: + + - 用于测试或者启动集群, 还有master 节点的其它组件跟API的交互 + - 没有TLS + - 默认的侦听端口是8080,可以通过参数 `--insecure-port` 指定别的端口 + - 默认绑定的IP是localhost, 可以通过参数 `--insecure-bind-address`指定别的地址 + - 请求会绕过认证和授权模块 + - 请求会经过准入控制模块处理 + - 通过对主机进行访问控制保护接口 + + 2. `安全端口`: + + - 按需启用 + - 使用 TLS. 通过 `--tls-cert-file`参数指定证书路径, `--tls-private-key-file` 参数指定证书的私钥 + - 默认侦听6443端口, 可以通过`--secure-port`指定别的端口 + - 默认IP绑定在第一个非localhost的网络接口, 可以通过`--bind-address`指定IP地址 + - 请求会经过认证和授权模块的处理 + - 请求会经过准入控制模块的处理 + - 认证和授权模块会运行 +如果在谷歌计算引擎平台(GCE)或者其他一些云提供商上用`kube-up.sh`创建集群的话, API Server会侦听443端口。 在GCE上, 默认会开放防火墙策略允许从外部通过HTTPS访问集群的API. 其它云供应商的策略不尽相同。 + +## 配置认证和授权 +# 网络策略 +网络策略(Network Policy)是一个特定的配置, 用于限制一组pod如何和另外一个pod或网络endpoint进行通信。 +网络策略使用标签(label)来选择pods,并定义规则, 指定那些流量可以达到哪些pods。 +前提: **要是网络策略生效, 必须要安装支持网络策略的网络插件,否则网络策略不会生效** + +默认情况下, 所有的pod都是非隔离,意味着它会放行所有来源的流量。 但是对于应用了网络策略的pod。它就变成隔离的, 它会拒绝所有没有被网络策略放行的连接。 + +示例: +```yml +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: test-network-policy + namespace: default +spec: + podSelector: + matchLabels: + role: db + policyTypes: + - Ingress + - Egress + ingress: + - from: + - ipBlock: + cidr: 172.17.0.0/16 + except: + - 172.17.1.0/24 + - namespaceSelector: + matchLabels: + project: myproject + - podSelector: + matchLabels: + role: frontend + ports: + - protocol: TCP + port: 6379 + egress: + - to: + - ipBlock: + cidr: 10.0.0.0/24 + ports: + - protocol: TCP + port: 5978 +``` +下面对这个网络策略进行说明: +强制必须有的字段: apiVersion,kind, metadata +spec: 包含定义网络策略的所有相关信息 +podSelector: 选择目的pods, 如果为空, 则选择所有的pods +policyTypes: 可选值为Ingress, Egress或二者, 如果为空, 则Ingress会被设定, 当有egress规则时, Egress类型也会被设定 +ingress:入向规则的白名单规则列表, 每条规则放行匹配到from和ports的流量。流量的源要么要么来自namespaceSelector或者来自podSelector的pod, 都会被匹配到。 +egress: 出向规则的白名单规则列表。 每条规则放行匹配到to和ports的流量 +ipBlock: ip块定义CIDR, except则把某段ip, 从大的ip 网段里排除掉 +上述示例中的规则整体的意思是: +1. 隔离pod标签为“role=db”, 命名空间为default的pods的入向和出向流量 +2. 允许pod标签为“role=frontend”, 命名空间为default的pods访问pod标签为“role=db”, 命名空间为default的pods的6379的TCP端口 +3. 允许namespace标签为“project=myproject”的pods访问pod标签为“role=db”, 命名空间为default的pods的6379的TCP端口 +4. 允许pod标签为“role=db”, 命名空间为default的pods访问10.0.0.0/24网段的TCP端口5978 + + +当命名空间里没有任何的网络策略时, 默认情况下,所有pods的出流量和入流量都会被放行。 + +你可以可以定义一些规则来修改默认行为,比如: +- 默认拒绝所有的入流量 +- 默认允许所有的入流量 +- 默认拒绝所有的出流量 +- 默认允许所有的出流量 +- 默认拒绝所有的出流量和入流量 + +> 参考 [官方文档之Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) +# Secret +> 参考 [官方文档之Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) + +## secret概览 +secret是k8s里的一个对象, 它用于存储一些敏感数据,比如说密码, token, 密钥等等。这类信息如果直接明文放在镜像或者pod里, 比较不安全。 用secret来保存会更加安全,可以防止意外泄露。 +secret如何被使用? +> 有两种使用方式: 1. 作为一个卷被pod挂载 2. kubelet 为pod拉取镜像的时候使用 + +内置的secret +> Service Account创建时会自动secret,供集群访问API时使用 + +使用kubectl命令创建secret +1. 先在本地创建两个文本用于存放username和password +```shell +# Create files needed for rest of example. +$ echo -n "admin" > ./username.txt +$ echo -n "1f2d1e2e67df" > ./password.txt +``` +2. 用 kubectl命令创建Secret,把这两个文件的内容打包进Secret, 并在apiserver中创建API 对象 +```shell +$ kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt +secret "db-user-pass" created +``` +3. 查看secret +```shell +$ kubectl get secrets +NAME TYPE DATA AGE +db-user-pass Opaque 2 51s + +$ kubectl describe secrets/db-user-pass +Name: db-user-pass +Namespace: default +Labels: +Annotations: + +Type: Opaque + +Data +==== +password.txt: 12 bytes +username.txt: 5 bytes +``` +4. 解码secret的加密内容 +```shell +$ kubectl get secret mysecret -o yaml +apiVersion: v1 +data: + username: YWRtaW4= + password: MWYyZDFlMmU2N2Rm +kind: Secret +metadata: + creationTimestamp: 2016-01-22T18:41:56Z + name: mysecret + namespace: default + resourceVersion: "164619" + selfLink: /api/v1/namespaces/default/secrets/mysecret + uid: cfee02d6-c137-11e5-8d73-42010af00002 +type: Opaque +$ echo "MWYyZDFlMmU2N2Rm" | base64 --decode +1f2d1e2e67df +``` + +通过yaml编排文件来创建secret +```shell +# 先把内容用base64转换一下 +$ echo -n "admin" | base64 +YWRtaW4= +$ echo -n "1f2d1e2e67df" | base64 +MWYyZDFlMmU2N2Rm +``` +然后创建如下yaml文件 +```yml +apiVersion: v1 +kind: Secret +metadata: + name: mysecret +type: Opaque +data: + username: YWRtaW4= + password: MWYyZDFlMmU2N2Rm +``` +用kubectl创建secret +```shell +$ kubectl create -f ./secret.yaml +secret "mysecret" created +``` + +在pod中使用secret +```yml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret +``` +username.txt和password.txt会出现在/etc/foo/username.txt, /etc/foo/password.txt路径下 +你也可以为username指定不同的路径,用法如下(spec.volumes[].secret.items) +```yml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret + items: + - key: username + path: my-group/my-username +``` +此时, username的值会出现在/etc/foo/my-group/my-username下,而不是/etc/foo/username路径 +为secret文件分配读写权限(spec.volumes[].secret.defaultMode) +```yml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + volumes: + - name: foo + secret: + secretName: mysecret + defaultMode: 256 + +``` +注意这里的256,转成8进制就是0400, JSON不支持8进制,所以在指定值得时候要转换成10进制 +如何在pod里读取挂载的secret的内容, secret的内容挂载到pod里之后变成了文件,直接在挂载的对应路径下读取即可 +```shell +$ ls /etc/foo/ +username +password +$ cat /etc/foo/username +admin +$ cat /etc/foo/password +1f2d1e2e67df +``` + +挂载到pod里的secret的内容, 会进行自动更新, 如果你更新了secret对象的内容, pod里对应的内容也会更新。 内容更新的时间为kubelet 的sync周期 + secret cache的ttl时间。 + +将Secret作为环境变量使用(env[x].valueFrom.secretKeyRef) +```yml +apiVersion: v1 +kind: Pod +metadata: + name: secret-env-pod +spec: + containers: + - name: mycontainer + image: redis + env: + - name: SECRET_USERNAME + valueFrom: + secretKeyRef: + name: mysecret + key: username + - name: SECRET_PASSWORD + valueFrom: + secretKeyRef: + name: mysecret + key: password + restartPolicy: Never +``` +从环境变量中获取Secret的值 +```shell +$ echo $SECRET_USERNAME +admin +$ echo $SECRET_PASSWORD +1f2d1e2e67df +``` + +使用 imagePullSecrets +> imagePullSecret是一个secret, 它会把docker registry的密码传递给kubelet,让kubelet代表pod下载镜像 +> 你可以从创建一个imagePullSecrets, 并在serviceaccount中指向这个imagePullSecrets,所有使用这个serviceaccount的pod, 会自动设置它的imagePullSecret 字段 + +一些限制 +1. secret需要先于使用它的pod创建, 否则pod的启动不会成功 +2. secret只能被相同namespace的pod使用 +3. 单个secret的大小最大为1MB, 这个限制的出发点是为了避免过大的secret的会耗尽apiserver和kubelet的内存, 因此不建议创建非常大的secret。 然而创建大量小的secret对象仍然会耗尽内存。 这个目前无法对其限制。 对secret使用内存的复杂限制是规划中的一个特性。 +4. kubelet目前只支持从apiserver创建的pod使用secret, 包括kubectl直接创建或者从复制控制器中的非直接创建方式。 其它方式,如使用 kubelet的 --manifest-url或 --config参数创建的pod,不能使用secret。 +5. secretKeyRef指定的key如果不存在, 那么pod的启动不会成功 + +secret和pod的生命周期的交互 +1. pod通过api创建时, 这时不会检查引用的secret是否存在 +2. 当pod被调度时,宿主机上的kubelet就会检查secret的值 +3. 当secret不能被获取时, kubelet会做周期性的尝试, 并会记录一个event说明为什么没有启动 +4. 当secret被获取时, kubelet就会创建和挂载一个包含这个secret的存储卷 +5. 在所有的卷被创建和挂载之前, pod不会启动 + +## secret使用场景 + +# 容器安全 +> 参考 [容器安全](https://feisky.gitbooks.io/kubernetes/practice/security.html) + +Kubernetes提供了多种机制来限制容器的行为,减少容器攻击面,保证系统安全性。 + +- Security Context:限制容器的行为,包括Capabilities、ReadOnlyRootFilesystem、Privileged、RunAsNonRoot、RunAsUser以及SELinuxOptions等 +- Pod Security Policy:集群级的Pod安全策略,自动为集群内的Pod和Volume设置Security Context +- Sysctls:允许容器设置内核参数,分为安全Sysctls和非安全Sysctls +- AppArmor:限制应用的访问权限 +- Seccomp:Secure computing mode的缩写,限制容器应用可执行的系统调用 + +## Security Context 安全上下文 +Security Context的目的是限制不可信容器的行为,保护系统和其他容器不受其影响。 +Kubernetes提供了三种配置Security Context的方法: +- Container-level Security Context:仅应用到指定的容器 +- Pod-level Security Context:应用到Pod内所有容器以及Volume +- Pod Security Policies(PSP):应用到集群内部所有Pod以及Volume +### Container-level Security Context +Container-level Security Context仅应用到指定的容器上,并且不会影响Volume。比如设置容器运行在特权模式: +```yml +apiVersion: v1 +kind: Pod +metadata: + name: hello-world +spec: + containers: + - name: hello-world-container + # The container definition + # ... + securityContext: + privileged: true +``` +### Pod-level Security Context +Pod-level Security Context应用到Pod内所有容器,并且还会影响Volume(包括fsGroup和selinuxOptions)。 + +```yml +apiVersion: v1 +kind: Pod +metadata: + name: hello-world +spec: + containers: + # specification of the pod's containers + # ... + securityContext: + fsGroup: 1234 + supplementalGroups: [5678] + seLinuxOptions: + level: "s0:c123,c456" + +``` +### Pod Security Policies(PSP) +Pod Security Policies(PSP)是集群级的Pod安全策略,自动为集群内的Pod和Volume设置Security Context。 +使用PSP需要API Server开启extensions/v1beta1/podsecuritypolicy,并且配置PodSecurityPolicy admission控制器。 +支持的控制项 +```table +控制项 | 说明 +privileged | 运行特权容器 +defaultAddCapabilities | 可添加到容器的Capabilities +requiredDropCapabilities |会从容器中删除的Capabilities +volumes| 控制容器可以使用哪些volume +hostNetwork| host网络 +hostPorts |允许的host端口列表 +hostPID| 使用host PID namespace +hostIPC| 使用host IPC namespace +seLinux | SELinux Context +runAsUser| user ID +supplementalGroups |允许的补充用户组 +fsGroup| volume FSGroup +readOnlyRootFilesystem |只读根文件系统 +``` +示例 + +限制容器的host端口范围为8000-8080: +```yml +apiVersion: extensions/v1beta1 +kind: PodSecurityPolicy +metadata: + name: permissive +spec: + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + runAsUser: + rule: RunAsAny + fsGroup: + rule: RunAsAny + hostPorts: + - min: 8000 + max: 8080 + volumes: + - '*' +``` + +### SELinux +SELinux (Security-Enhanced Linux) 是一种强制访问控制(mandatory access control)的实现。它的作法是以最小权限原则(principle of least privilege)为基础,在Linux核心中使用Linux安全模块(Linux Security Modules)。SELinux主要由美国国家安全局开发,并于2000年12月22日发行给开放源代码的开发社区。 +可以通过runcon来为进程设置安全策略,ls和ps的-Z参数可以查看文件或进程的安全策略。 + +开启与关闭SELinux + +修改/etc/selinux/config文件方法: +开启:SELINUX=enforcing +关闭:SELINUX=disabled +通过命令临时修改: +开启:setenforce 1 +关闭:setenforce 0 +查询SELinux状态:getenforce + +示例 +```yml +apiVersion: v1 +kind: Pod +metadata: + name: hello-world +spec: + containers: + - image: gcr.io/google_containers/busybox:1.24 + name: test-container + command: + - sleep + - "6000" + volumeMounts: + - mountPath: /mounted_volume + name: test-volume + restartPolicy: Never + hostPID: false + hostIPC: false + securityContext: + seLinuxOptions: + level: "s0:c2,c3" + volumes: + - name: test-volume + emptyDir: {} +``` + +这会自动给docker容器生成如下的HostConfig.Binds: +```text +/var/lib/kubelet/pods/f734678c-95de-11e6-89b0-42010a8c0002/volumes/kubernetes.io~empty-dir/test-volume:/mounted_volume:Z +/var/lib/kubelet/pods/f734678c-95de-11e6-89b0-42010a8c0002/volumes/kubernetes.io~secret/default-token-88xxa:/var/run/secrets/kubernetes.io/serviceaccount:ro,Z +/var/lib/kubelet/pods/f734678c-95de-11e6-89b0-42010a8c0002/etc-hosts:/etc/hosts +``` +对应的volume也都会正确设置SELinux: +```shell +$ ls -Z /var/lib/kubelet/pods/f734678c-95de-11e6-89b0-42010a8c0002/volumes +drwxr-xr-x. root root unconfined_u:object_r:svirt_sandbox_file_t:s0:c2,c3 kubernetes.io~empty-dir +drwxr-xr-x. root root unconfined_u:object_r:svirt_sandbox_file_t:s0:c2,c3 kubernetes.io~secret +``` + +> 关于SELinux的介绍可以参考: [图文教程:SELinux政策实施详解](http://os.51cto.com/art/201311/418176.htm) 这篇文章以漫画的形式来讲解 , 深入浅出 +## Sysctls +sysctl接口允许允许管理员在系统运行的状态下动态修改内核参数。 设置的参数在/proc/sys下可以看到。 其配置参数包含了多个Linux的多个子系统,比如: +- kernel(以kernel.开头的参数) +- networking(以net.开头的参数) +- virtual memory (以vm.开头的参数) +- MDADM (以dev.开头的参数) + +namespaced 和 node-level 的sysctl参数: +namespaced级别的sysctl参数运行每个pod各自配置而不冲突。 要在pod的语境里(编排文件中)使用, 必须namespaced级别的sysctl, 这些sysctl参数包括: +- kernel.shm*, +- kernel.msg*, +- kernel.sem, +- fs.mqueue.*, +- net.*. +对于node-level级别的sysctl参数,比如vm.开头,dev.开头的参数, 如果要进行设置,需要管理员在node节点上配置(比如写node的/etc/sysctl.conf文件),或者用DaemonSet启动一个有系统特权的容器来进行设置。 +Sysctls允许容器设置内核参数,分为安全Sysctls和非安全Sysctls +- 安全Sysctls:即设置后不影响其他Pod的内核选项,只作用在容器namespace中,默认开启。包括以下几种 + - kernel.shm_rmid_forced : 这个参数启用后,会销毁未被使用的共享内存, 不要轻易开启 + - net.ipv4.ip_local_port_range: 表示用于向外连接的端口范围。缺省情况下很小:32768到61000 + - net.ipv4.tcp_syncookies: 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭 +- 非安全Sysctls:即设置好有可能影响其他Pod和Node上其他服务的内核选项,默认禁止。如果使用,需要管理员在配置kubelet时开启,如kubelet --experimental-allowed-unsafe-sysctls 'kernel.msg*,net.ipv4.route.min_pmtu' +Sysctls还在alpha阶段,需要通过Pod annotation设置,如: +```yml +apiVersion: v1 +kind: Pod +metadata: + name: sysctl-example + annotations: + security.alpha.kubernetes.io/sysctls: kernel.shm_rmid_forced=1 + security.alpha.kubernetes.io/unsafe-sysctls: net.ipv4.route.min_pmtu=1000,kernel.msgmax=1 2 3 +spec: + ... +``` + +> 关于sysctl的介绍可以参考[sysctl.conf学习和调优](https://wsgzao.github.io/post/sysctl/) 和 [设置Linux内核参数 /etc/sysctl.conf](http://linxucn.blog.51cto.com/1360306/740130) +## AppArmor + +AppArmor(Application Armor)是Linux内核的一个安全模块,允许系统管理员将每个程序与一个安全配置文件关联,从而限制程序的功能。通过它你可以指定程序可以读、写或运行哪些文件,是否可以打开网络端口等。作为对传统Unix的自主访问控制模块的补充,AppArmor提供了强制访问控制机制。 +在使用AppArmor之前需要注意 +- Kubernetes版本>=v1.4 +- apiserver和kubelet已开启AppArmor特性,--feature-gates=AppArmor=true +- 已开启apparmor内核模块,通过cat /sys/module/apparmor/parameters/enabled查看 +- 仅支持docker container runtime +- AppArmor profile已经加载到内核,通过cat /sys/kernel/security/apparmor/profiles查看 +AppArmor还在alpha阶段,需要通过Pod annotation container.apparmor.security.beta.kubernetes.io/来设置。可选的值包括 +- runtime/default: 使用Container Runtime的默认配置 +- localhost/: 使用已加载到内核的AppArmor profile +```shell +$ sudo apparmor_parser -q < + +profile k8s-apparmor-example-deny-write flags=(attach_disconnected) { + #include + + file, + + # Deny all file writes. + deny /** w, +} +EOF' + +$ kubectl create -f /dev/stdin <:应用到指定容器 +而value有三个选项 +- runtime/default: 使用Container Runtime的默认配置 +- unconfined: 允许所有系统调用 +- localhost/: 使用Node本地安装的seccomp,需要放到/var/lib/kubelet/seccomp目录中 +比如使用刚才创建的seccomp配置: +```yml +apiVersion: v1 +kind: Pod +metadata: + name: trustworthy-pod + annotations: + seccomp.security.alpha.kubernetes.io/pod: localhost/chmod +spec: + containers: + - name: trustworthy-container + image: sotrustworthy:latest +``` + +# 参考文献 +- [容器安全](https://feisky.gitbooks.io/kubernetes/practice/security.html) +- [官方文档之Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) +- [官方文档之Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) +[Kubernetes集群安全配置案例](http://www.cnblogs.com/breg/p/5923604.html) +[轻松了解Kubernetes认证功能](http://qinghua.github.io/kubernetes-security/) +[Kubernetes技术分析之安全](http://dockone.io/article/599) +[Kubernetes双向TLS配置-Centos7](http://www.pangxie.space/docker/1164) \ No newline at end of file diff --git "a/\345\256\211\345\205\250\344\270\216\350\256\244\350\257\201.md" "b/\345\256\211\345\205\250\344\270\216\350\256\244\350\257\201.md" deleted file mode 100644 index 859e822..0000000 --- "a/\345\256\211\345\205\250\344\270\216\350\256\244\350\257\201.md" +++ /dev/null @@ -1,7 +0,0 @@ -# 安全方案 -# 具体配置 -# 参考文献 -[Kubernetes集群安全配置案例](http://www.cnblogs.com/breg/p/5923604.html) -[轻松了解Kubernetes认证功能](http://qinghua.github.io/kubernetes-security/) -[Kubernetes技术分析之安全](http://dockone.io/article/599) -[Kubernetes双向TLS配置-Centos7](http://www.pangxie.space/docker/1164) \ No newline at end of file diff --git "a/\345\270\270\350\247\201\351\227\256\351\242\230.md" "b/\345\270\270\350\247\201\351\227\256\351\242\230.md" deleted file mode 100644 index 207fff6..0000000 --- "a/\345\270\270\350\247\201\351\227\256\351\242\230.md" +++ /dev/null @@ -1,6 +0,0 @@ -# 参考文献 -[使用Kubernetes需要注意的一些问题(FAQ of k8s)](http://blog.csdn.net/anzhsoft/article/details/51282254) -[使用Kubernetes 1.2.0的正确姿势](http://mp.weixin.qq.com/s?src=3×tamp=1473267136&ver=1&signature=kbLojrtJp4sfG*s1D9NygesetfogBkNl0F50Ura9CNOiZVuLYV-UNMK*CnMm0sGfSlZU5Qxu8A*KbsDZV0emdXPZk0Rgpjh39pkMqrJN8cWwki8ZCZkyJ0mvp7zbjz*U9IZgE4zu46TzcG77Mph6cQ==) -[k8s petset issues](https://github.com/kubernetes/kubernetes/issues/28718) -[探索 Kubernetes 做为 Mesos 的一个Framework 是否有意义](http://www.dockone.io/article/1719) -[Docker与Kubernetes,是敌是友?](http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649694045&idx=1&sn=e4be89fddc3e8932e992146284500a9b&chksm=8893203ebfe4a928f438ab0b5b4f82de5f3a34e8f14c016503d374fdaf7dfe252b98753f0bdf&mpshare=1&scene=1&srcid=05139sb0VP8DF547uAA4SJI6#rd) \ No newline at end of file diff --git "a/\345\272\224\347\224\250\347\224\237\345\221\275\345\221\250\346\234\237\347\256\241\347\220\206.md" "b/\345\272\224\347\224\250\347\224\237\345\221\275\345\221\250\346\234\237\347\256\241\347\220\206.md" new file mode 100644 index 0000000..0de702e --- /dev/null +++ "b/\345\272\224\347\224\250\347\224\237\345\221\275\345\221\250\346\234\237\347\256\241\347\220\206.md" @@ -0,0 +1,21 @@ +# 认证要求 +- Application Lifecycle Management 应用生命周期管理 8% + - 理解Deployment, 并知道如何进行rolling update 和 rollback + - 知道各种配置应用的方式 + - 知道如何为应用扩容 + - 理解基本的应用自愈相关的内容 + +# 应用生命周期管理 + - 理解Deployment, 并知道如何进行rolling update 和 rollback +> 滚动升级 kubectl set image deployment/ =xxx:v2 , 如果有一个pod升级失败, 升级会停止。 +> 回滚升级操作 kubectl rollout undo deployments +> 查看回滚状态 kubectl rollout status deployments + - 知道各种配置应用的方式 +> kubectl run --image= --port=8080 +> 创建编排文件, 然后使用kubectl create -f <文件名> 创建, 用kubectl replace -f <文件名> 进行替换更新 + - 知道如何为应用扩容 +> kubectl scale deployments --replicas=4 + - 理解基本的应用自愈相关的内容 +> 应用会维持一个稳定的数量,deployment controller会持续监控应用pod的数量, 使其维护在一个设定的数量。 如果发现少于设定数量, 就会自动创建新的应用的pod + +要了解这方面的内容, 可以尝试下新手训练营的交互式课程https://kubernetesbootcamp.github.io/kubernetes-bootcamp diff --git "a/\345\274\200\345\217\221\346\214\207\345\215\227.md" "b/\345\274\200\345\217\221\346\214\207\345\215\227.md" index e47c9af..4934de8 100644 --- "a/\345\274\200\345\217\221\346\214\207\345\215\227.md" +++ "b/\345\274\200\345\217\221\346\214\207\345\215\227.md" @@ -14,7 +14,7 @@ clientset 的使用分两种情况:集群内和集群外。 -集群内:将 controller 容器化后以 pod 的形式在集群里跑,只需调用 rest.InClusterConfig(),默认的 service accoutns 就可以访问 apiserver 的所有资源。 +集群内:将 controller 容器化后以 pod 的形式在集群里跑,只需调用 rest.InClusterConfig(),默认的 service accounts 就可以访问 apiserver 的所有资源。 集群外,比如在本地,可以使用与 kubectl 一样的 kube-config 来配置 clients。如果是在云上,比如 gke,还需要 import Auth Plugin。 @@ -70,6 +70,194 @@ Demo Demo 的代码在 github 上,https://github.com/caesarxuchao/servicelookup。 > 参考[使用 client-go 控制原生及拓展的 Kubernetes API](https://my.oschina.net/caicloud/blog/829365) + +# 源码解读 + +# 原理分析 + +架构设计 + + +![](./_image/2017-03-11-22-48-43.jpg) + +以下是《kubernetes权威指南》的学习笔记,我 对书中的内容做了总结和提炼。 如有谬误之处, 还望各位指出。 +## Apiserver原理分析 +### 概述 +整个系统的数据总线。 +提供以下功能特性: +1. 集群管理的api入口 +2. 资源配额控制的入口 +3. 提供完善的集群安全机制 + +### api 访问 +访问api的三种方式: +1. 直接curl调用api +2. 启动内部代理(kubectl proxy ),然后访问内部代理进行调用,可以进行访问控制,如限制要访问的接口,增加允许访问的client的白名单 +3. 使用k8s提供的client lib ,通过编程的方式访问,这种方式有两种使用场景,一是pod需要发现同属于一个service的其它pod副本的信息来组建集群(如elasticsearch集群), 二是需要通过调用api来我开发基于k8s的管理平台 + +独特的k8s proxy api: + +这种api可以用来代理rest请求, 把收到的请求转发到某一个node上的kubelet进程的端口上,由kubelet进行响应 +示例: curl 127.0.0.1:8080/api/v1/proxy/nodes/node-1/pods +这里返回的pods的信息是由node上的kubelet进程收集的, 而不是从etcd的数据库获取, 二者的信息可能在某个时间点会有偏差。 +这种特殊的api的应用场景是: 通过这类api来直接访问pods上的应用, 可以用来逐一排查同一service的多个pod副本上的应用是否有异常。 +示例一: curl 127.0.0.1:8080/api/v1/proxy/namespaces/default/pods/xxxx-pod-1 +示例二: curl 127.0.0.1:8080/api/v1/proxy/namespaces/default/services/xxxx-svr-1 + +### 集群之间功能模块的通信 +kubelet --> apiserver (汇报自身状态, 侦听pod信息) +controller-manager --> apiserver (实时监控node信息,并做处理) +scheduler --> apiserver (侦听新建pod的信息, 检索符合要求的node列表,并进行调度逻辑的执行) + +为缓解apiserver的压力, 各个模块会缓存从apiserver获取的数据, 某些情况下会直接使用缓存的数据(**什么情况使用缓存, 如何保证数据的一致性?**) + +## controller manager原理分析 +集群内部的管理控制中心,是一个“修正系统”。 +负责以下对象的管理: +- node +- pod副本 +- endpoint +- namespace +- service accout +- resource quota + +包含了以下controller: +- replication controller +- node controller +- resourcequota controller +- namespace controller +- serviceaccount controller +- token controller +- service controller +- endpoint controller + +### replication controller +职责是: 保证pod副本数量始终保持预设值 +应用场景: +1. 确保pod数量, 以保证高可用要求 +2. 系统扩容和缩容 +3. 滚动更新 + +只有当pod的重启策略是Always时(RestartPolicy=Always)时, replication controller 才会管理该pod的操作(例如创建, 销毁, 重启等) + +pod通过修改标签可以脱离replication controller的控制 +### node controller +通过apiserver获取node的信息,实现管理和监控集群的各个node节点的相关控制功能。 +节点的健康状态有三种: 就绪(true), 未就绪(false), 未知(unknown) +master节点的系统时间作为探测时间, 状态变化的时间可能是上一次保存的状态时间,或者本次节点变化的时间。 +如果有段时间没有收到节点信息,则状态设置为unknown. +当状态为非就绪状态时, 将节点加入待删除队列。 + +### resourcequota controller +资源配额管理, 确保指定的资源对象在任何情况下都不会超量占用系统资源,避免业务进程的设计和实现的缺陷导致整个系统的紊乱, 对整个集群的平稳运行起着重要作用。 + +k8s集群对资源配额的管理有三个维度: 容器级别, pod级别, namespace级别。 +容器级别: cpu & memory +pod级别: 所有容器的可用资源 +namespace级别: pod数量, rc数量, svr数量, resourcequota数量, secret数量, pv数量 + +配额管理的控制: +由apiserver中的admission control来控制, 实际上apiserver是配额控制的一个入口。 +两种配额约束方式: limitranger(容器级别, pod级别), resourcequota(namespace级别) + +resourcequota controller组件负责定期统计namespace下pod, rc, svr, resourcequota, secret, pv等资源对象的数量, 还有container实例使用的资源,将统计结果写入etcd。 +这些信息会被admission controller使用, 如果不符合配额约束, 则创建对象失败。 +如果既在namespace上命名了resourcequota约束, 又在pod级别声明了limitranger,admission control 会同时计算二者的情况, 需要同时满足才会创建对象。 + +### namespace controller +用户通过api server创建新的namespace, 并保存在etcd中。 而这个controller可以通过api server读取namespace的相关信息。 +当namespace的状态被设置为terminating时, 这个controller会删除改namespace下的所有对象资源。 +admission controller会通过namespacelifecycle插件来阻止为该namespace创建新的资源。 + +### serviceaccount controller +### token controller +### service controller +k8s集群和外部云平台的一个接口控制器,负责侦听service的变化。如果service的type是loadbalancer, 那么service controller就会负责动态更新创建对于的loadbalancer实例, 和路由转发表等 +### endpoint controller +负责侦听service和相应的pod副本的变化,以及生成和维护所有endpoints对象。 当service被删除时,该controller会负责删除该service同名的endpoints对象。 当新的service被创建或修改, pod产生相关事件时, 该controller就会更新对应service的endpoints对象(更改对应的endpoint条目)。 + +注: endpoints对象维护一个service对应的所有pod副本的访问地址。 + +## scheduler 原理分析 +scheduler是负责pod调度的重要组件。起着承上启下的作用, 从上游接收controller manager 创建的pod, 为起安排node落脚, 然后交给目标node上的kubelet进程, 由其负责pod的“下半生”的生命周期管理。 + +默认调度流程分两步: +1. 预选(predicates): 遍历所有node, 先根据预选策略初步筛选出符合条件的node +2. 优选(priority): 从预选的node中挑出最优的选择 + +调度流程是通过插件的方式加载调度算法提供者。 每个algorithmprovider都要提供3个参数, 算法名称name, 预选策略集合predicatekeys, 优选策略集合prioritykeys + +7个可用的预选策略: +- NoDiskConflict +- PodFirstResources +- PodSelectorMatches +- PodFitsHost +- CheckNodeLablePresence +- CheckServiceAffinity +- PodFitsPorts + +默认的algorithmprovider加载的预选策略: +- NoDiskConflict +- PodFirstResources +- PodSelectorMatches +- PodFitsHost +- PodFitsPorts + + +所有预选策略的说明 +- NoDiskConflict +> 判断备选pod的gcepersistentdisk或者awselasticblockstore和备选的节点已存在的pod是否存在冲突 +- PodFirstResources +> node的资源是否满足备选pod的需求。需要对备选pod和node上已有pod的资源进行求和,看是否超过node所能提供的资源 +- PodSelectorMatches +> node是否有pod的标签选择器所指定的标签, 即nodeselector所指定的标签 +- PodFitsHost +> node的名称是否和pod所指定的node名称一致, 即nodename所指定的名称 +- CheckNodeLablePresence +> 用于判断当策略列出的标签在备选节点存在是, 是否选择该备选节点 +- CheckServiceAffinity +> 用于判断备选节点是否包含策略指定的标签 +- PodFitsPorts +> 判断备选pod所用的端口是否在备选的node中被占用 + +3个优选策略: +- LeastRequestedPriority +- CalculateNodeLabelPriority +- BalancedResourceAllocation + +注:每个节点通过优选策略会算出一个得分, 得分最大的节点作为最终的优选结果。 + +问题: ** 所有的优选策略都要计算一遍么?还是只是挑选其中的一个?如果挑选其中一个,又是如何挑选?** + +所有优选策略的说明: +- LeastRequestedPriority +> 选出资源消耗最少的节点, 即资源最充足的节点(cpu, mem两个维度), 有对应的计算公式 +- CalculateNodeLabelPriority + > 判断策略列出的标签在备选节点出现时,是否选择该备选节点 +- BalancedResourceAllocation +> 从备选节点中选出各项资源使用率最均衡的方法, 与1类似,但是计算公式又不同 + +## kubelet原理分析 +kubelet是k8s集群node端一个服务进程。 主要负责三个任务: +1. 处理master下发到本节点的任务,管理pod和pod中的容器,如启动,删除等 +2. 向apiserver注册节点信息, 定期向apiserver汇报节点资源的使用情况 +3. 使用cAdvisor监控容器和节点资源 + +### 节点管理 +在1.3.6版本中kubelet有130个参数。 下面介绍和节点管理相关的几个参数: +- - api-servers 告诉到哪里去注册和上报信息, 可以支持多个apiserver地址(ip + port), 以逗号分隔 +- - register-node 是否启用上报信息的功能 +- - node-ip 汇报的节点ip地址,汇报给apiserver的是网卡地址, 如果是有NAT IP的机器想要向apiserver注册NAT IP, 需要在这个参数指定 + +### Pod管理 + +#### 容器健康检查 +#### cAdvisor资源监控 + # 参考文献 - [Accessing Clusters](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/) - [使用 client-go 控制原生及拓展的 Kubernetes API](https://my.oschina.net/caicloud/blog/829365) +- [kubernetes中的端对端测试](https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-tests.md) +[flannel源码分析](http://cizixs.com/2016/07/16/flannel-source-code-insight) +[Kubernetes监控之Heapster源码实现](http://www.dockone.io/article/2201) +[kubernetes代码阅读-apiserver之list-watch篇](http://dockone.io/article/1538) diff --git "a/\346\234\211\347\212\266\346\200\201\345\272\224\347\224\250.md" "b/\346\234\211\347\212\266\346\200\201\345\272\224\347\224\250.md" index f772f51..f762b89 100644 --- "a/\346\234\211\347\212\266\346\200\201\345\272\224\347\224\250.md" +++ "b/\346\234\211\347\212\266\346\200\201\345\272\224\347\224\250.md" @@ -1,7 +1,51 @@ # 什么是有状态应用 +在 K8S 运行的服务,从简单到复杂可以分成三类:无状态服务、普通有状态服务和有状态集群服务。下面分别来看 K8S 是如何运行这三类服务的。 + +无状态服务,K8S 使用 RC(或更新的 Replica Set)来保证一个服务的实例数量,如果说某个 Pod 实例由于某种原因 Crash 了,RC 会立刻用这个 Pod 的模版新启一个 Pod 来替代它,由于是无状态的服务,新启的 Pod 与原来健康状态下的 Pod 一模一样。在 Pod 被重建后它的IP地址可能发生变化,为了对外提供一个稳定的访问接口,K8S 引入了 Service 的概念。一个 Service 后面可以挂多个 Pod,实现服务的高可用。 +普通有状态服务,和无状态服务相比,它多了状态保存的需求。Kubernetes 提供了以 Volume 和 Persistent Volume 为基础的存储系统,可以实现服务的状态保存。 +有状态集群服务,与普通有状态服务相比,它多了集群管理的需求。K8S 为此开发了一套以 Pet Set 为核心的全新特性,方便了有状态集群服务在 K8S 上的部署和管理。具体来说是通过 Init Container 来做集群的初始化工作,用 Headless Service 来维持集群成员的稳定关系,用动态存储供给来方便集群扩容,最后用Pet Set来综合管理整个集群。 +要运行有状态集群服务要解决的问题有两个,一个是状态保存,另一个是集群管理。 我们先来看如何解决第一个问题:状态保存。Kubernetes 有一套以Volume插件为基础的存储系统,通过这套存储系统可以实现应用和服务的状态保存。 +> 参考 [K8S 弹药库 | Kubernetes 有状态集群服务部署与管理(上)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483722&idx=2&sn=a8ec119efcf1a5a9c8ab9c04185df1e1&chksm=fc1c2d7acb6ba46cffa1e1c77ac632aa4661de1fd1c48323986463882c971e6a2922a4bc2aa0&mpshare=1&scene=1&srcid=04212ZmcJoz5fSQhSljVunu4#rd) + +什么是Pet Set?在数据结构里Set是集合的意思,所以顾名思义Pet Set就是Pet的集合,那什么是Pet呢?我们提到过Cattle和Pet的概念,Cattle代表无状态服务,而Pet代表有状态服务。具体在K8S资源对象里,Pet是一种需要特殊照顾的Pod。它有状态、有身份、当然也比普通的Pod要复杂一些。 + +![](./_image/2017-09-11-07-43-07.jpg) +具体来说,一个Pet有三个特征。 + +一是有稳定的存储,这是通过我们前面介绍的PV/PVC 来实现的。 + +二是稳定的网络身份,这是通过一种叫 Headless Service 的特殊Service来实现的。要理解Headless Service是如何工作的,需要先了解Service是如何工作。我们提到过Service可以为多个Pod实例提供一个稳定的对外访问接口。这个稳定的接口是如何实现的的呢,是通过Cluster IP来实现的,Cluster IP是一个虚拟IP,不是真正的IP,所以稳定。K8S会在每个节点上创建一系列的IPTables规则,实现从Cluster IP到实际Pod IP的转发。同时还会监控这些Pod的IP地址变化,如果变了,会更新IP Tables规则,使转发路径保持正确。所以即使Pod IP有变化,外部照样能通过Service的ClusterIP访问到后面的Pod。 + +普通Service的Cluster IP 是对外的,用于外部访问多个Pod实例。而Headless Service的作用是对内的,用于为一个集群内部的每个成员提供一个唯一的DNS名字,这样集群成员之间就能相互通信了。所以Headless Service没有Cluster IP,这是它和普通Service的区别。 + +Headless Service为每个集群成员创建的DNS名字是什么样的呢?右下角是一个例子,第一个部分是每个Pet自己的名字,后面foo是Headless Service的名字,default是PetSet所在命名空间的名字,cluser.local是K8S集群的域名。对于同一个Pet Set里的每个Pet,除了Pet自己的名字,后面几部分都是一样的。所以要有一个稳定且唯一的DNS名字,就要求每个Pet的名字是稳定且唯一的。 + +三是序号命名规则。Pet是一种特殊的Pod,那么Pet能不能用Pod的命名规则呢?答案是不能,因为Pod的名字是不稳定的。Pod的命名规则是,如果一个Pod是由一个RC创建的,那么Pod的名字是RC的名字加上一个随机字符串。为什么要加一个随机字符串,是因为RC里指定的是Pod的模版,为了实现高可用,通常会从这个模版里创建多个一模一样的Pod实例,如果没有这个随机字符串,同一个RC创建的Pod之间就会由名字冲突。 + +如果说某个Pod由于某种原因死掉了,RC会新建一个来代替它,但是这个新建里的Pod名字里的随机字符串与原来死掉的Pod是不一样的。所以Pod的名字跟它的IP一样是不稳定的。 + +为了解决名字不稳定的问题,K8S对Pet的名字不再使用随机字符串,而是为每个Pet分配一个唯一不变的序号,比如 Pet Set 的名字叫 mysql,那么第一个启起来的Pet就叫 mysql-0,第二个叫 mysql-1,如此下去。 + +当一个Pet down 掉后,新创建的Pet 会被赋予跟原来Pet一样的名字。由于Pet名字不变所以DNS名字也跟以前一样,同时通过名字还能匹配到原来Pet用到的存储,实现状态保存。 + +![](./_image/2017-09-11-07-44-08.jpg) +这些是Pet Set 相关的一些操作: + +Peer discovery,这和我们上面的Headless Service有密切关系。通过Pet Set的 Headless Service,可以查到该Service下所有的Pet 的 DNS 名字。这样就能发现一个Pet Set 里所有的Pet。当一个新的Pet起来后,就可以通过Peer Discovery来找到集群里已经存在的所有节点的DNS名字,然后用它们来加入集群。 +更新Replicas的数目、实现扩容和缩容。 +更新Pet Set里Pet的镜像版本,实现升级。 +删除 Pet Set。删除一个Pet Set 会先把这个Pet Set的Replicas数目缩减为0,等到所有的Pet都被删除了,再删除 Pet Set本身。注意Pet用到的存储不会被自动删除。这样用户可以把数据拷贝走了,再手动删除。 +以上,与有状态服集群服务相关的K8S特性就介绍完了。 + +> 参考 [K8S 老司机 | Kubernetes 有状态集群服务部署与管理(下)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483727&idx=3&sn=485f783756f9539ba8659ee265d2905f&chksm=fc1c2d7fcb6ba46908b2078bed06b34a6aafeb67d2fe50bde3979baaa4d60eaaa67bf7bc2da9&mpshare=1&scene=1&srcid=0424tZbUNKEy8lozNbfHnwEv#rd) + + # 创建一个有状态应用 +Pet的三个特性: 稳定的存储, 稳定的网络身份, 序号命名规则。 把这些特性和有状态集群服务关联起来串一下,我们可以用Pet Set来管理一个有状态服务集群,Pet Set里每个Pet对应集群的一个成员,集群的初始化可以用 Init Container来完成。集群里每个成员的状态由Volume, Persistent Volume来存储,集群里每个Pet 唯一的DNS名字通过Headless Service来提供,集群里的成员之间就可以通过这个名字,相互通信。 # 常见问题 # 参考文献 +- [K8S 弹药库 | Kubernetes 有状态集群服务部署与管理(上)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483722&idx=2&sn=a8ec119efcf1a5a9c8ab9c04185df1e1&chksm=fc1c2d7acb6ba46cffa1e1c77ac632aa4661de1fd1c48323986463882c971e6a2922a4bc2aa0&mpshare=1&scene=1&srcid=04212ZmcJoz5fSQhSljVunu4#rd) +- [K8S 老司机 | Kubernetes 有状态集群服务部署与管理(下)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483727&idx=3&sn=485f783756f9539ba8659ee265d2905f&chksm=fc1c2d7fcb6ba46908b2078bed06b34a6aafeb67d2fe50bde3979baaa4d60eaaa67bf7bc2da9&mpshare=1&scene=1&srcid=0424tZbUNKEy8lozNbfHnwEv#rd) - [《Kubernetes与云原生应用》系列之Kubernetes的系统架构与设计理念](http://www.infoq.com/cn/articles/kubernetes-and-cloud-native-applications-part01?utm_source=tuicool&utm_medium=referral) ***** - [对话李春龙:如何用Kubernetes管理有状态服务](http://www.tuicool.com/articles/n6Jbiez) - [使用Kubernets Pet Set部署上千个Cassandra实例](http://dockone.io/article/1577) diff --git "a/\346\234\215\345\212\241\345\217\221\347\216\260.md" "b/\346\234\215\345\212\241\345\217\221\347\216\260.md" deleted file mode 100644 index 11e9981..0000000 --- "a/\346\234\215\345\212\241\345\217\221\347\216\260.md" +++ /dev/null @@ -1,25 +0,0 @@ -# 域名解析 -# 负载均衡 -# 外部访问 -# 参考文献 -- [ Kubernetes DNS服务的安装与配置](http://blog.csdn.net/bluishglc/article/details/52438917) -- [Understanding SkyDNS ](https://github.com/k8sp/issues/issues/32) -- [Kubernetes技术分析之DNS](http://dockone.io/article/543) -- [Kubernetes高级实践之集成DNS](https://www.zybuluo.com/dujun/note/83702) -- [Using DNS Pods and Services](https://kubernetes.io/docs/admin/dns/) -- [Kubernetes(k8s)如何使用kube-dns实现服务发现](http://www.kubernetes.org.cn/273.html) -- [官方文档之服务简介](http://kubernetes.io/docs/user-guide/services/) -- - [KUBERNETES入门之KUBE-PROXY实现原理](http://www.cnblogs.com/xuxinkun/p/5799986.html) -- [kubernetes中port、target port、node port的对比分析,以及kube-proxy代理](http://blog.csdn.net/xinghun_4/article/details/50492041) -- [Consul + fabio 实现自动服务发现、负载均衡](http://dockone.io/article/1567) -- [Keepalived+LVS-DR模式配置高可用负载均衡集群](http://blog.csdn.net/m582445672/article/details/7670015) -- [官方文档之负载均衡器](http://kubernetes.io/docs/user-guide/load-balancer/) -- [Kubernetes 1.2 中利用 Ingress 简化复杂网络](http://blog.fleeto.us/translation/simplifying-advanced-networking-ingress) -- [Kubernetes 1.2 新功能介绍:Ingress 原理及实例](http://www.dockerinfo.net/1132.html) -- [微服务动态路由实现:OpenResty与kubernetes](http://www.dockerinfo.net/1700.html) -- [Traefik Kubernetes 初试](https://www.kubernetes.org.cn/1237.html) -- [Ingress Resources](https://kubernetes.io/docs/user-guide/ingress/) -- [使用 NGINX 和 NGINX Plus 的 Ingress Controller 进行 Kubernetes 的负载均衡](http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649693301&idx=1&sn=b1a316cbb882e41906f0ff82cdd4bac3&chksm=88932316bfe4aa005af924e7edb76337bd8ad067c907b71b0728d98bfb791fc4214616ca4781&mpshare=1&scene=1&srcid=0213VOBUD0R21SrWHnNxVYLN#rd) -- [教程 | Kubernetes的边缘节点配置](http://mp.weixin.qq.com/s?__biz=MzI4NDYxOTgwMw==&mid=2247483822&idx=1&sn=8f857113e21ab8097d51d1064d567187&chksm=ebf9e4dadc8e6dccf1e9cb85bededc927deab129fd17b77b6163937276103ed5d02dac108488&mpshare=1&scene=1&srcid=0510SJG4Xr6H1lDhYN4EcJAL#rd) -- [Kubernetes1.6 Ingress配置](http://mp.weixin.qq.com/s?__biz=MzUzMTA1NTM5NA==&mid=2247483667&idx=1&sn=f976fddff0adc1c94865b09ac6dcd6d8&chksm=fa49175ecd3e9e48db40168c312b12b51cc1cca4cb55051333907171c5319823215fcbc6defb&mpshare=1&scene=1&srcid=0505RWMiNM7qdx0gvzfS4PqA#rd) -- [Kubernetes ingress解析 - Jimmy Song](http://rootsongjc.github.io/blogs/kubernetes-ingress-resource/?from=groupmessage&isappinstalled=0) diff --git "a/\346\246\202\350\277\260.md" "b/\346\240\270\345\277\203\346\246\202\345\277\265.md" similarity index 67% rename from "\346\246\202\350\277\260.md" rename to "\346\240\270\345\277\203\346\246\202\345\277\265.md" index 87efd25..7399686 100644 --- "a/\346\246\202\350\277\260.md" +++ "b/\346\240\270\345\277\203\346\246\202\345\277\265.md" @@ -1,4 +1,12 @@ +# 认证要求 +- Core Concepts 核心概念 19% + - 理解k8s api原语 + - 理解k8s 架构 + - 理解services和其它网络相关原语 + # Kubernetes简介 +kubernetes是什么?kubernetes是一个便携式(支持多云, 支持私有云,公有云, 混合云), 扩展性强(模块化, 插件化, 钩子化,可编排), 提供自愈能力(自动替换, 自动重启, 自动复制,自动收缩)的容器集群管理平台。 它方便了应用的快速部署,伸缩, 滚动升级, 并且可以限制应用能使用的资源。kubernetes满足了生产环境下的应用相关的普遍需求,比如服务发现,负载均衡,存储卷挂载, 分发秘钥, 应用健康检查, 应用实例复制, 应用的水平伸缩, 滚动升级, 资源监控, 日志查看, 应用调试, 认证和鉴权, 总而言之, 使用kubernetes可以方便应用的部署和运维管理。 + Kubernetes一个用于容器集群的自动化部署、扩容以及运维的开源平台。 目前支持docker和rkt作为容器引擎。 使用Kubernetes,你可以快速高效地响应客户需求: @@ -26,20 +34,42 @@ Kubernetes不提供: - 不提供机器配置、维护、管理。 ps: 如何向技术小白解释什么是kubernetes?使用最通俗易懂的解释,可以参见插图漫画《*闺女也能看懂的插画版Kubernetes指南*》 +ps: 关于为什么使用容器, 使用容器的好处在哪里,也可以参考下面的文档。 +> 参考 https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/ # 概念和术语 +## 组件及说明 +```table +名词 | 描述 +kube-apiserver | 这个组件是kubernetes控制平面的前端, 用于暴露kubernetes 的api。 该组件可以水平扩展。 +etcd | kubernetes集群的后端存储, 所有的持久状态数据存储在etcd集群中。它提供了一种分布式的方式来可靠地存储配置数据 +kube-controller-manager | 该组件运行控制器,这些控制是一些在后台路由和处理任务的线程。这些控制器包括node controller, replication controller, endpoint controller, service account & token controller +cloud-manager-controller(alpha, v1.6+) | 用于将kubernetes的核心代码和云供应商的平台功能代码解耦, 未来云厂商相关的功能代码由厂商自行维护, 然后通过该组件进行链接 +kube-scheduler | 调度新创建的pod到节点上 +addons | 重要的插件有: dns, web ui(dashboard),container resource monitoring(heapster,cadvisor,grafana, influxdb等), cluster-level logging(elk, efk 等) +kubelet | 它是节点上重要的agent。 负责为pod挂载目录, 下载pod的secret, 运行pod里的容器,周期性的存活性检查, 向master汇报节点和pod的状态 +kube-proxy | 维护主机上的网络规则, 并负责转发连接 +docker | 用于运行容器 +rkt | docker的替代方案, 目前为实验性的支持 +``` + ## 主要概念说明 ```table -|名词| 描述| -|cluster|集群, 一组物理机或虚拟机(或两者)与使用Kubernetes运行应用程序等基础资源的总和| -|etcd|所有的持久状态数据存储在etcd集群中。它提供了一种分布式的方式来可靠地存储配置数据| -|namespace|命名空间, 一个资源名称的前缀, 命名空间帮助不同的项目,环境(例如,开发和生产),团队或客户共享同一个集群。它能够阻止名称冲突。| -|kubctl|操作整个调度系统使用的命令行工具| -| pod | 一组容器的集合,pod内的容器一起被部署,是Kubernetes管理最小部署单元, 所有在Pod的应用使用相同的网络命名空间,IP地址及端口空间 | -| volume | Pod中能够被多个容器访问的共享目录 | -| label | 组织和选择基于键值对的对象组, 它们被用于每一个Kubernetes组件。例如:复制控制器使用他们做服务发现 | -| replication controller | 复制控制器, 管理Pod的生命周期, 用以保证集群内的容器在任何时刻都有指定数据的副本在运行 | -|service | 服务为一组Pod提供单一稳定的名称和地址。他们作为基本负载均衡器而存在。 | -| Secret | 存储敏感的数据并可以被容器所访问 | +名词 | 描述 | | +cluster | 集群, 一组物理机或虚拟机(或两者)与使用Kubernetes运行应用程序等基础资源的总和 | | +names | 每个对象的名称是唯一的, 这个名称由客户端产生。长度最大为253个字符, 可以由小写字母, - , . 组成 | | +UID | 由系统产生的资源对象的唯一标识, 在资源对象的生命周期中有一个独一无二的UID | | +namespace | 命名空间, 一个资源名称的前缀, 命名空间帮助不同的项目,环境(例如,开发和生产),团队或客户共享同一个集群。它能够阻止名称冲突。大部分资源,如pod, replication controller, service等, 是在命名空间下的。但是一些底层资源,如node, 持久化卷不会在某个具体的命名空间下。 | | +kubctl | 操作整个调度系统使用的命令行工具 | | +pod | 一组容器的集合,pod内的容器一起被部署,是Kubernetes管理最小部署单元, 所有在Pod的应用使用相同的网络命名空间,IP地址及端口空间 | | +volume | Pod中能够被多个容器访问的共享目录 | | +label | 组织和选择基于键值对的对象组, 它们被用于识别和选择Kubernetes的资源对象。例如:复制控制器使用他们做服务发现. label使得用户能够以松耦合的形式在系统的对象上构建有组织的结构。 服务部署经常需要多个维度, 用户可以为他们的部署的对象打上诸\release\\" : \\"stable\\" | \\"release\\" : \\"canary\\"的标签. 标签的key可以由可选的前缀和必选的名称组成,以/隔开。 前缀必须是以域名的形式出现,此外kubernetes.io是系统保留的前缀,用户不能占用。 名称长度最大为63字符。value的长度最大为63字符。 名称和value的命名可以由大小写字母, -, _ | . 组成。\" +label selector | 标签选择器。 支持等于式(例如environment=production,tier!=frontend)和集合式两种选择器(例如environment in (production, qa))。 service 和 replication controller只支持等于式, 而一些新的资源对象, 如replicaset, deployment, job, daemonset支持集合式。 另外node的选择(亲和性和反亲和性)支持集合式。 | | +annotation | 注解。 和label不一样, 注解不用于识别和选择资源对象。 注解完善了资源对象的metadata信息, 它可以是结构化或者非结构化的, 它可以包含label不支持的字符。 一些记录到注解里的信息用例如:发行版本信息, git分支, 作者信息等 | | +kubernetes api | kubernetes 的api 考虑到了兼容性问题, 它支持api的版本化, 这样也方便了代码的持续发布,api的版本分为alpha, beta和stable。 对于alpha版本的api(例如v1alpha1),可能会有较多的bug, 支持的特性默认是关闭的, 而且后期可能会不经过通知随时下线, beta版本的api(如v2beta3), 经过了很好的测试, 特性默认开启, 如果api发生变化, 会进行通知和提供迁移说明。 stable 的api (如v3)不做赘述。 api分组: /apis/$GROUP_NAME/$VERSION, 例如apiVersion: batch/v1, 启用api groups时,要在apiserver启动时指定--runtime-config的值。 | | +node | kubernetes上的工作节点, 可以是虚拟机或者物理机, 每个节点会由master组件来集中管理, 节点上有运行pod所需的服务, 如kubelet, kube-proxy,docker进程等 | | +replication controller | 复制控制器, 管理Pod的生命周期, 用以保证集群内的容器在任何时刻都有指定数据的副本在运行 | | +service | 服务为一组Pod提供单一稳定的名称和地址。他们作为基本负载均衡器而存在。 | | +Secret | 存储敏感的数据并可以被容器所访问 | | ``` ## 概念详细介绍之Pod @@ -195,6 +225,62 @@ Kubernetes集群启动后,会创建一个名为“default”的Namespace,如 当你创建一个服务时,它将创建相应的 DNS 条目。此条目是窗体..svc.cluster.local,这意味着如果一个容器只是使用 它将解析为命名空间的本地的服务。这是用于跨多个命名空间,比如开发、分期和生产使用相同的配置。如果你想要达到整个命名空间,您需要使用完全限定的域名称(FQDN)。 使用Namespace来组织Kubernetes的各种对象,可以实现对用户的分组,即“多租户”的管理。对不同的租户还可以进行单独的资源配额设置和管理,使得整个集群的资源配置非常灵活、方便。一个集群中的资源总是有限的,当这个集群被多个租户的应用同时使用时,为了更好地使用这种有限的共享资源,需要将资源配额的管理单元提升到租户级别,通过在不同租户对应的Namespace上设置对应的ResourceQuota即可达到目的。 + +## 概念详细介绍之Node + +运行中的节点的5种状态 +```table +Node Condition| Description +OutOfDisk| True if there is insufficient free space on the node for adding new pods, otherwise False +Ready| True if the node is healthy and ready to accept pods, False if the node is not healthy and is not accepting pods, and Unknown if the node controller has not heard from the node in the last 40 seconds +MemoryPressure| True if pressure exists on the node memory – that is, if the node memory is low; otherwise False +DiskPressure| True if pressure exists on the disk size – that is, if the disk capacity is low; otherwise False +NetworkUnavailable| True if the network for the node is not correctly configured, otherwise False +``` +节点的状态是以yaml或者json描述的,如下格式 +```json +"conditions": [ + { + "kind": "Ready", + "status": "True" + } +] +``` +如果节点一直处于Unknown或者False状态, 超过pod-eviction-timeout(默认5分钟), 那么该node上的pod会被重新调度到新的节点上。node上的pod会被删除。对于版本1.5之前,该失联的node上的pod会被强制删除,无论是否能和api-server进行通信, 对于1.5之后, master会等待节点重新和apiserver建立通信后, 再执行删除pod的动作。 + +node的容量信息(capacity) +> 描述节点上游多少可用的资源, 多少CPU, 内存, 可以调度到该node上的最大pod数量 + +一般信息 +> 系统内核版本, kubelet, kube-proxy版本, docker版本, 系统名称等 + +node的管理 +你可以手动创建node对象, 然后系统会通过metadata.name来检验该对象是否有效, 格式如 +```json +{ + "kind": "Node", + "apiVersion": "v1", + "metadata": { + "name": "10.240.79.157", + "labels": { + "name": "my-first-k8s-node" + } + } +} +``` +node控制器(node controller)的三个功能 +1. 为node分配CIDR(如果参数CIDR分配打开的话) +2. 检查和更新内部的node清单, 如果运行在云上, 那么node controller会向cloud provider确认node是否可用, 如果不可用,node 控制器就会把node从清单里面删除 +3. 监控节点的健康状态, node 控制器会以--node-monitor-period设定的频率对node进行周期性的状态检查 + +node驱逐pod的速率控制 +对于一个可用区都不可用或者可用区内出现大量node不可用的情况, node controller会默认会控制pod的驱逐速率。 +--node-eviction-rated的默认值是0.1, 意味着,node控制器不会以超过10秒一个node的速率去驱逐node上的pod。 +如果不可用的node的比例大于--unhealthy-zone-threshold(默认是0.55), 那么驱逐速率会被降低: 当集群的规模小于等于--large-cluster-size-threshold(默认是50个node)时,对pod的驱逐停止,否则速率会被降低到--secondary-node-eviction-rate(默认是0.01)。 这些针对可用区(az) 的补充策略, 是考虑到用户的可用区可能会和master出现网络隔离的情况,如果你的集群没有跨多供应商的可用区,那么你的集群只有一个可用区。 + +为了提高你的应用的可用性, 建议你的集群跨多个可用区。 这样你的集群工作负载就可以跨可用区进行迁移, 即使你有其中一个可用区出现异常。 这样的话, 如果一个可用区出现异常, 那么控制器会以--node-eviction-rated的速率驱逐pod, 但是如果所有可用区都出现异常且所有的节点都unhealthy, 那么控制器会认为master的网络连接有问题, 会停止所有的驱逐动作。 + +> 参考https://kubernetes.io/docs/concepts/architecture/nodes/ # 系统架构 ![](./_image/2016-09-06 23-43-12.jpg) @@ -228,6 +314,7 @@ kube-scheduler:集群中的调度器,负责Pod在集群节点中的调度分 kube-controller-manager:集群内部的管理控制中心,主要实现Kubernetes集群的故障检查和恢复自动化的工作。比如endpoints控制器负责Endpoints对象的创建,更新。node控制器负责节点的发现,管理和监控。复制控制器负责pod的数量符合预期定义。 # 参考文献 +- [官方文档之核心概念介绍](https://kubernetes.io/docs/concepts/) - [闺女也能看懂的插画版Kubernetes指南](http://www.yunweipai.com/archives/8056.html) - [容器技术漫谈(3)-Kubernetes](https://github.com/ruizeng/blog/blob/master/Container/container-kubernetes.md) - [Kubernetes基本要素介绍](http://dockone.io/article/1260) diff --git "a/\346\272\220\347\240\201\350\247\243\350\257\273.md" "b/\346\272\220\347\240\201\350\247\243\350\257\273.md" deleted file mode 100644 index bbc4a9b..0000000 --- "a/\346\272\220\347\240\201\350\247\243\350\257\273.md" +++ /dev/null @@ -1,2 +0,0 @@ -# 参考文献 -[flannel源码分析](http://cizixs.com/2016/07/16/flannel-source-code-insight) \ No newline at end of file diff --git "a/\347\224\237\344\272\247\345\256\236\350\267\265.md" "b/\347\224\237\344\272\247\345\256\236\350\267\265.md" index f395c00..c216a05 100644 --- "a/\347\224\237\344\272\247\345\256\236\350\267\265.md" +++ "b/\347\224\237\344\272\247\345\256\236\350\267\265.md" @@ -14,7 +14,178 @@ RAM资源以bytes为单位。你可以将RAM表示为纯整数或具有这些后 关于为什么要指定限制的相信信息,参考 Setting Pod CPU and Memory Limits。 关于如果没有指定CPU和RAM资源请求的发生情况,参考Resource Requests and Limits of Pod and Container。 > 参考- [文档解读 | K8S中的Pod和容器配置(二)](http://mp.weixin.qq.com/s?__biz=MzI4NDYxOTgwMw==&mid=2247483755&idx=1&sn=418ed8bb83454ac158a2634b995cd4ff) + + +为你的容器应用label, 以便能够多维度的观察你的集群。 作为参考, 你可以为你的应用设置如下的标签: +- Frontend/Backend +- Application (website, mobile app, database, cache…) +- Environment (prod, staging, dev…) +- Team +- Version +![](./_image/2017-10-08-16-53-11.jpg) + + + +关于nodePort的使用 +尽量避免使用nodeport, nodeport在集群里是全局占用的,使用nodeport有可能导致调度失败, 可能的原因是: +1. 两个pod要声明占用主机上同样的端口 + +## init container +什么是Init Container? + +从名字来看就是做初始化工作的容器。可以有一个或多个,如果有多个,这些 Init Container 按照定义的顺序依次执行,只有所有的Init Container 执行完后,主容器才启动。由于一个Pod里的存储卷是共享的,所以 **Init Container 里产生的数据可以被主容器使用到**。 + +Init Container可以在多种 K8S 资源里被使用到如 Deployment、Daemon Set, Pet Set, Job等,但归根结底都是在Pod启动时,**在主容器启动前执行,做初始化工作**。 + +我们在什么地方会用到 Init Container呢? + +第一种场景是等待其它模块Ready,比如我们有一个应用里面有两个容器化的服务,一个是Web Server,另一个是数据库。其中Web Server需要访问数据库。但是当我们启动这个应用的时候,并不能保证数据库服务先启动起来,所以可能出现在一段时间内Web Server有数据库连接错误。为了解决这个问题,我们可以在运行Web Server服务的Pod里**使用一个Init Container,去检查数据库是否准备好,直到数据库可以连接**,Init Container才结束退出,然后Web Server容器被启动,发起正式的数据库连接请求。 + +第二种场景是做初始化配置,比如**集群里检测所有已经存在的成员节点,为主容器准备好集群的配置信息**,这样主容器起来后就能用这个配置信息加入集群。 + +还有其它使用场景,如将pod注册到一个中央数据库、下载应用依赖等。 + +这些东西能够放到主容器里吗?从技术上来说能,但从设计上来说,可能不是一个好的设计。首先不符合单一职责原则,其次这些操作是只执行一次的,如果放到主容器里,还需要特殊的检查来避免被执行多次。 + +![](./_image/2017-09-11-09-15-06.jpg) +这个例子创建一个Pod,这个Pod里跑的是一个nginx容器,Pod里有一个叫workdir的存储卷,访问nginx容器服务的时候,就会显示这个存储卷里的index.html 文件。 + +而这个index.html 文件是如何获得的呢?是由一个Init Container从网络上下载的。这个Init Container 使用一个busybox镜像,起来后,执行一条wget命令,获取index.html文件,然后结束退出。 + +由于Init Container和nginx容器共享一个存储卷(这里这个存储卷的名字叫workdir),所以在Init container里下载的index.html文件可以在nginx容器里被访问到。 + +可以看到 Init Container 是在 annotation里定义的。Annotation 是K8S新特性的实验场,通常一个新的Feature出来一般会先在Annotation 里指定,等成熟稳定了,再给它一个正式的属性名或资源对象名。 + +> 参考 [K8S 老司机 | Kubernetes 有状态集群服务部署与管理(下)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483727&idx=3&sn=485f783756f9539ba8659ee265d2905f&chksm=fc1c2d7fcb6ba46908b2078bed06b34a6aafeb67d2fe50bde3979baaa4d60eaaa67bf7bc2da9&mpshare=1&scene=1&srcid=0424tZbUNKEy8lozNbfHnwEv#rd) + + +## Service +**targetPort的值可以是字符串类型,这是暴露port的名称**, 这个设计,为用户的应用部署升级提供了更多的灵活性, 比如用户可以在新版本的pod暴露新的端口(port名称不变), 此时service就无需重新构建, 从而无需切断客户端连接, 提高应用的可用性。 +在deployment或者pod文件里定义暴露的containerPort的名称, 这样在service里的targetPort就可以使用这个名称了 。 + + +有一类特殊的无选择器的service无需定义endpoint, 它是ExternalName Service +```yml +kind: Service +apiVersion: v1 +metadata: + name: my-service + namespace: prod +spec: + type: ExternalName + externalName: my.database.example.com +``` +当你访问这个service时, 会去通过集群dns, 集群的dns会返回一条CNAME的记录, 即my.database.example.com, **这个重定向是发生在dns层的, 没有任何的流量代理或者转发**。 也就是说不是通过主机上的kube-proxy和iptables。 +集群外部的一些服务, 建议以ExternalName的形式管理起来, 但有一点需要注意的是, 这个特性需要kubernetes的1.7版本支持, 或者高版本的kube-dns支持。 + + + +直接用iptables转发, 好处是转发性能更好,更稳定。 缺点是如果一开始选择的pod没有响应,iptables无法选择另外一个pod发起重试。客户端和后端的pod的连接就可能会出现错误连接状态, 除非客户端能够断开连接进行重连。 **这个问题可以通过配置readiness probe来解决**。当你为一个应用配置了准备就绪探针(readiness probe)时,kubelet进程会使用这个探针来判断哪些pod可以开始接受网络请求流量,即是否处于准备就绪状态。 + + +## 集群部署 +用static pod来部署kubernetes的kube-proxy, kube-scheduler, kube-controller-manager, kube-apiserver等组件。其中部署kubernetes的kube-proxy, kube-scheduler, kube-controller-manager, kube-apiserver组件的机器,最好设置为不可调度状态(使用kubectl cordon ),防止其它不相干的pod调度到master节点机器上, 影响master的可用性。 + +使用daemonset来运行一个需要在每个节点都起来的pod, 比如filebeat, rbd工具等 + +高可用的建议 +- 把apiserver和etcd的数据目录放到可靠的存储上,防止数据丢失 +- 主机宕机后能自动重启 +- 应用能支持无预期的重启 + +## service account +- 为serviceaccount关联imagePullSecret,这样所有使用这个serviceaccount的pod, 会自动设置它的imagePullSecret 字段,就不要再一个个手动指定了 +> 如何配置可以参考https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#adding-imagepullsecrets-to-a-service-account # 应用场景 +## 应用管理 +> 参考 https://feisky.gitbooks.io/kubernetes/apps/ + +目前最常用的是手动管理manifest,比如kubernetes github代码库就提供了很多的manifest示例 +- https://github.com/kubernetes/kubernetes/tree/master/examples +- https://github.com/kubernetes/contrib +- https://github.com/kubernetes/ingress +手动管理的一个问题就是繁琐,特别是应用复杂并且Manifest比较多的时候,还需要考虑他们之间部署关系。Kubernetes开源社区正在推动更易用的管理方法,如 +- Helm提供了一些常见应用的模版 +- operator则提供了一种有状态应用的管理模式 +- Deis在Kubernetes之上提供了一个PaaS平台 +- Draft是微软Deis团队开源的容器应用开发辅助工具,可以帮助开发人员简化容器应用程序的开发流程 +- Kompose是一个将docker-compose配置转换成Kubernetes manifests的工具 + +## 应用生命周期管理 + - 理解Deployment, 并知道如何进行rolling update 和 rollback +> 滚动升级 kubectl set image deployment/ =xxx:v2 , 如果有一个pod升级失败, 升级会停止。 +> 回滚升级操作 kubectl rollout undo deployments +> 查看回滚状态 kubectl rollout status deployments + - 知道各种配置应用的方式 +> kubectl run --image= --port=8080 +> 创建编排文件, 然后使用kubectl create -f <文件名> 创建, 用kubectl replace -f <文件名> 进行替换更新 + - 知道如何为应用扩容 +> kubectl scale deployments --replicas=4 + - 理解基本的应用自愈相关的内容 +> 应用会维持一个稳定的数量,deployment controller会持续监控应用pod的数量, 使其维护在一个设定的数量。 如果发现少于设定数量, 就会自动创建新的应用的pod + +要了解这方面的内容, 可以尝试下新手训练营的交互式课程https://kubernetesbootcamp.github.io/kubernetes-bootcamp + +### 一般准则 +#### 一般准则 +- 分离构建和运行环境 +- 使用dumb-int等避免僵尸进程 +- 不推荐直接使用Pod,而是推荐使用Deployment/DaemonSet等 +- 不推荐在容器中使用后台进程,而是推荐将进程前台运行,并使用探针保证服务确实在运行中 +- 推荐容器中应用日志打到stdout和stderr,方便日志插件的处理 +- 由于容器采用了COW,大量数据写入有可能会有性能问题,推荐将数据写入到Volume中 +- 不推荐生产环境镜像使用latest标签,但开发环境推荐使用并设置imagePullPolicy为Always +- 推荐使用Readiness探针检测服务是否真正运行起来了 +- 使用activeDeadlineSeconds避免快速失败的Job无限重启 +- 引入Sidecar处理代理、请求速率控制和连接控制等问题 + +#### 分离构建和运行环境 + +注意分离构建和运行环境,直接通过Dockerfile构建的镜像不仅体积大,包含了很多运行时不必要的包,并且还容易引入安全隐患,如包含了应用的源代码。 +可以使用Docker多阶段构建来简化这个步骤。 +```dockerfile +FROM golang:1.7.3 as builder +WORKDIR /go/src/github.com/alexellis/href-counter/ +RUN go get -d -v golang.org/x/net/html +COPY app.go . +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . + +FROM alpine:latest +RUN apk --no-cache add ca-certificates +WORKDIR /root/ +COPY --from=builder /go/src/github.com/alexellis/href-counter/app . +CMD ["./app"] +``` + +#### 僵尸进程和孤儿进程 + +孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。 +僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。 +在容器中,很容易掉进的一个陷阱就是init进程没有正确处理SIGTERM等退出信号。这种情景很容易构造出来,比如 +```shell +# 首先运行一个容器 +$ docker run busybox sleep 10000 + +# 打开另外一个terminal +$ ps uax | grep sleep +sasha 14171 0.0 0.0 139736 17744 pts/18 Sl+ 13:25 0:00 docker run busybox sleep 10000 +root 14221 0.1 0.0 1188 4 ? Ss 13:25 0:00 sleep 10000 + +# 接着kill掉第一个进程 +$ kill 14171 +# 现在会发现sleep进程并没有退出 +$ ps uax | grep sleep +root 14221 0.0 0.0 1188 4 ? Ss 13:25 0:00 sleep 10000 + +``` +解决方法就是保证容器的init进程可以正确处理SIGTERM等退出信号,比如使用dumb-init +```shell +$ docker run quay.io/gravitational/debian-tall /usr/bin/dumb-init /bin/sh -c "sleep 10000" +``` + + + + ## 大数据 ## 深度学习 ### 案例1 @@ -90,6 +261,9 @@ ESContainer最大的特色是能够让Kubernetes与OpenStack深度融合,带来1 - [2.12 K8S Meetup 回顾|小米·陈迪豪《深度学习模型应用与实践》](https://mp.weixin.qq.com/s?__biz=MzIzMzExNDQ3MA==&mid=2650093132&idx=1&sn=9d2e8685a665a8140b15ae8ce861a226) - [EasyStack发布容器,成为中国首个OpenStack+K8S专业开源企业](https://mp.weixin.qq.com/s?__biz=MzA3MjQxMjcxNQ==&mid=2649232237&idx=1&sn=276abca704f42107adc461f7dbdf80db) - [文档解读 | K8S中的Pod和容器配置(二)](http://mp.weixin.qq.com/s?__biz=MzI4NDYxOTgwMw==&mid=2247483755&idx=1&sn=418ed8bb83454ac158a2634b995cd4ff) +- [K8S 老司机 | Kubernetes 有状态集群服务部署与管理(下)](http://mp.weixin.qq.com/s?__biz=MzU1OTAzNzc5MQ==&mid=2247483727&idx=3&sn=485f783756f9539ba8659ee265d2905f&chksm=fc1c2d7fcb6ba46908b2078bed06b34a6aafeb67d2fe50bde3979baaa4d60eaaa67bf7bc2da9&mpshare=1&scene=1&srcid=0424tZbUNKEy8lozNbfHnwEv#rd) +- [Kubernetes应用管理](https://feisky.gitbooks.io/kubernetes/apps/) +- [Kubernetes生产环境经验告诉你如何实现蓝绿部署和负载均衡](http://www.tuicool.com/articles/6R73qmn) [基于kubernetes的docker集群实践](https://segmentfault.com/a/1190000002978115) [搜狐基于Docker+Kubernetes的一站式运维管理实践](http://dockone.io/article/1195) diff --git "a/\347\233\221\346\216\247\344\270\216\346\227\245\345\277\227.md" "b/\347\233\221\346\216\247\344\270\216\346\227\245\345\277\227.md" index 555b823..c4bfc10 100644 --- "a/\347\233\221\346\216\247\344\270\216\346\227\245\345\277\227.md" +++ "b/\347\233\221\346\216\247\344\270\216\346\227\245\345\277\227.md" @@ -1,11 +1,162 @@ +# 认证要求 +- Logging / Monitoring 日志/监控 5% + - 理解如何监控所有的集群组件 + - 理解如何监控应用 + - 管理集群组件日志 + - 管理应用日志 + + # 监控方案 关于Kubernetes的监控,有几种方案: -1. Prometheus + Influxdb + Grafana (强烈推荐) -2. Heapster + Influxdb + Grafana(推荐) -3. Satellite(不推荐) -4. Open-falcon + Grafana +1. Prometheus + Influxdb + Grafana +2. Heapster + Influxdb + Grafana +3. Satellite +4. Open-falcon + Heapster + Grafana + +在kubernetes中的监控需要考虑到这几个方面: + + +![](./_image/2017-10-08-07-24-35.jpg) + +- 应该给Pod打上哪些label,这些label将成为监控的metrics。tags和labels变的非常重要,是应用分组的重要依据 + +![](./_image/2017-10-08-16-57-50.jpg) + +- 当应用的Pod漂移了之后怎么办?因为要考虑到Pod的生命周期比虚拟机和物理机短的多,如何持续监控应用的状态? +- 更多的监控项,kubernetes本身、容器、应用等。多维度的监控,包括集群内的所有节点、容器、容器内的应用以及Kubernetes自身 + +![](./_image/2017-10-08-16-57-03.jpg) + +- 监控指标的来源,是通过heapster收集后汇聚还是直接从每台主机的docker上取? +- 天生的分布式,对复杂应用的监控聚合是个挑战 + +关于docker 容器的命名: +kubernetes容器命名规则解析,见下图所示。 + +![](./_image/2017-10-08-07-27-57.jpg) + +在kubernetes代码中pkg/kubelet/dockertools/docker.go中的BuildDockerName方法定义了容器的名称规范。 + + +> 参考 [集群及应用监控](https://jimmysong.io/kubernetes-handbook/practice/monitor.html) +> [Kubernetes监控](https://feisky.gitbooks.io/kubernetes/monitor/) +> [Monitoring in the Kubernetes era](https://www.datadoghq.com/blog/monitoring-kubernetes-era/) +## kubernetes集群组件监控 +- kube-apiserver +- kube-controller-manager +- kube-scheduler +- kube-dns addon + +## node节点的监控 +对node的监控, 和对vm和物理机的监控是一样的。 可以通过安装open-falcon的agent,采集node节点的内存, CPU, 网络, 磁盘等使用情况。 + +此外, 官方还推荐了另外一种node的监控方案作为补充, 即使用Node problem detector插件。 +它以daemonset的方式部署, 收集各种各样的节点问题, 并以nodeCondition和Event的方式汇报给apiserver。 + +目前这种方案支持一些常见的内核问题的监测。对于监测到的问题, k8s master不会触发任何修复措施。但是以后修复系统(remedy system)会被引进来处理node问题。 + +一些限制 +- 对kernel issue的监测,只支持kernel log, 不支持jounald +- 默认支持Ubuntu和Debian上的kernel log的格式, 如果需要支持其它类型的格式, 需要进行扩展, 扩展比较方便 + +部署Node problem detector +node-problem-detector.yaml (不修改默认配置) +```yml +apiVersion: extensions/v1beta1 +kind: DaemonSet +metadata: + name: node-problem-detector-v0.1 + namespace: kube-system + labels: + k8s-app: node-problem-detector + version: v0.1 + kubernetes.io/cluster-service: "true" +spec: + template: + metadata: + labels: + k8s-app: node-problem-detector + version: v0.1 + kubernetes.io/cluster-service: "true" + spec: + hostNetwork: true + containers: + - name: node-problem-detector + image: gcr.io/google_containers/node-problem-detector:v0.1 + securityContext: + privileged: true + resources: + limits: + cpu: "200m" + memory: "100Mi" + requests: + cpu: "20m" + memory: "20Mi" + volumeMounts: + - name: log + mountPath: /log + readOnly: true + volumes: + - name: log + hostPath: + path: /var/log/ +``` + +node-problem-detector.yaml (挂载configmap, 修改默认配置) +```yml +apiVersion: extensions/v1beta1 +kind: DaemonSet +metadata: + name: node-problem-detector-v0.1 + namespace: kube-system + labels: + k8s-app: node-problem-detector + version: v0.1 + kubernetes.io/cluster-service: "true" +spec: + template: + metadata: + labels: + k8s-app: node-problem-detector + version: v0.1 + kubernetes.io/cluster-service: "true" + spec: + hostNetwork: true + containers: + - name: node-problem-detector + image: gcr.io/google_containers/node-problem-detector:v0.1 + securityContext: + privileged: true + resources: + limits: + cpu: "200m" + memory: "100Mi" + requests: + cpu: "20m" + memory: "20Mi" + volumeMounts: + - name: log + mountPath: /log + readOnly: true + - name: config # Overwrite the config/ directory with ConfigMap volume + mountPath: /config + readOnly: true + volumes: + - name: log + hostPath: + path: /var/log/ + - name: config # Define ConfigMap volume + configMap: + name: node-problem-detector-config +``` +> 具体可以参考https://kubernetes.io/docs/tasks/debug-application-cluster/monitor-node-health/ ## 容器监控 +## cAdvisor +cAdvisor是一个来自Google的容器监控工具,也是kubelet内置的容器资源收集工具。它会自动收集本机容器CPU、内存、网络和文件系统的资源占用情况,并对外提供cAdvisor原生的API(默认端口为--cadvisor-port=4194)。cAdvisor提供了container和pod维度的监控。 + +![](./_image/2017-10-08-08-25-14.png) + ### Satellite Satellite是硅谷初创公司Gravitational公司旗下一个用Go写的开源项目,可用来收集Kubernetes集群的健康信息,它既是一个library,也是一个应用。作为library,可以用做监控方案。适合小的集群, 比如说8个节点。 @@ -142,6 +293,48 @@ istio 提供了一个工具叫 istioctl,这个工具的功能之一,就是 > 参考 [Istio,Kubernetes 的微服务支持](https://www.kubernetes.org.cn/2350.html) , 2017-07-16 +### weave scope +对于复杂的应用编排和依赖关系,我们希望能够有清晰的图标一览应用状态和拓扑关系,因此我们用到了Weaveworks开源的scope。 + +安装scope + +我们在kubernetes集群上使用standalone方式安装,详情参考Installing Weave Scope。 + +使用scope.yaml文件安装scope,该服务安装在kube-system namespace下。 + +```shell +$ kubectl apply -f scope.yaml +``` + +创建一个新的Ingress:kube-system.yaml,配置如下: + +```yml +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: traefik-ingress + namespace: kube-system +spec: + rules: + - host: scope.weave.io + http: + paths: + - path: / + backend: + serviceName: weave-scope-app + servicePort: 80 + +``` +执行kubectl apply -f kube-system.yaml后在你的主机上的/etc/hosts文件中添加一条记录: +```text +172.20.0.119 scope.weave.io +``` +在浏览器中访问scope.weave.io就可以访问到scope了 + +![](./_image/2017-10-08-07-42-11.jpg) +如上图所示,scope可以监控kubernetes集群中的一系列资源的状态、资源使用情况、应用拓扑、scale、还可以直接通过浏览器进入容器内部调试等。 + + # 日志方案 评估容器云平台日志系统的标准: @@ -161,6 +354,7 @@ istio 提供了一个工具叫 istioctl,这个工具的功能之一,就是 其中Fluentd或Filebeat打包成容器,以kubernetes的 daemonset的形式运行,每个node节点上都会启动一个Fluentd或Filebeat的Pod。 整体来说两种方案大同小异。 对于ElasticSearch 和 Kibana可以容器化,也可以用传统的ansible的方式部署。 +## Fluentd + ElasticSearch + Kibana 先看方案一:Fluentd + ElasticSearch + Kibana Fluentd在Kubernetes集群中的部署架构 每个Node节点上都要有Fluentd-Elasticsearch这个Pod,有两种方式支持:1. 放在/etc/kubernetes/manifest下,用脚本自动启动;2. 用DaemonSet启动。这两种模式都是为了保证在每一个Kubernetes集群节点上都有一个Fluentd的驻留Pod运行来收集日志。Kubernetes中DaemonSet这个API对象就是为了驻留Pod而设计的。 @@ -175,6 +369,21 @@ Fluentd在Kubernetes集群中的部署架构 关于如何配置 Fluentd 来采集 Kubernetes 的日志, 可以参考 [Kubernetes Logging with Fluentd](http://docs.fluentd.org/v0.12/articles/kubernetes-fluentd) +## Filebeat + ElasticSearch + Kibana +日志的话用的elk + filebeat。对于另外一个常用的方案fluentd我们也做过调研。 为什么不用fluentd,而用filebeat呢?有三个理由: +1. 我们内部有一个elk集群,filebeat和elk几乎是配套的, 他的升级和elk是同步的, 兼容性比fluentd好(fluentd默认不支持输出到logstash,一般都是直接输出到es集群) +2. filebeat的功能也一样很强大,足够轻量级, 能够满足我们的日志采集和分割需求。 +3. 我们对filebeat的配置比较熟悉 ,因此我们没有必要再去维护一个fluentd。 + +具体实施方式 +- 将所有的Pod的日志都挂载到宿主机上,每台主机上单独起一个日志收集Pod +- filebeat的配置使用configmap管理,更加灵活 +- filebeat的应用pod使用daemonset部署, 每个主机上都会独立起一个filebeat pod +- 在logstash的indexer上使用grok做日志切割, 切割后查看kibana日志, 可以看到会多出container_name, container_id, pod_name, namespace等字段 + +该方式的局限性 +- 需要统一日志收集规则,目录和输出方式, 应用的日志需要打到标准输出(stdout) +- 没有应用的service的信息, 当然你也可以将type,即filebeat配置文件里的document_type字段设置为service的name,这样的话,就可以根据应用来检索日志了 # 参考文献 - [Kubernetes容器集群中的日志系统集成实践](http://www.yunweipai.com/archives/8797.html) - [一张图读懂Kubernetes监控与日志](https://www.kubernetes.org.cn/993.html) @@ -187,3 +396,8 @@ Fluentd在Kubernetes集群中的部署架构 - [Tools for Monitoring Compute, Storage, and Network Resources](https://kubernetes.io/docs/tasks/debug-application-cluster/resource-usage-monitoring/) - [使用Netsil监控Kubernetes上的微服务](https://www.kubernetes.org.cn/939.html) - [Istio,Kubernetes 的微服务支持](https://www.kubernetes.org.cn/2350.html) +- [集群及应用监控](https://jimmysong.io/kubernetes-handbook/practice/monitor.html) +- [Kubernetes监控](https://feisky.gitbooks.io/kubernetes/monitor/) +- [官方文档之Monitor Node Health](https://kubernetes.io/docs/tasks/debug-application-cluster/monitor-node-health/) +- [Monitoring in the Kubernetes era](https://www.datadoghq.com/blog/monitoring-kubernetes-era/) +- [Kubernetes监控之Heapster介绍](http://www.dockone.io/article/1881) \ No newline at end of file diff --git "a/\347\263\273\347\273\237\347\256\241\347\220\206.md" "b/\347\263\273\347\273\237\347\256\241\347\220\206.md" deleted file mode 100644 index f8050e5..0000000 --- "a/\347\263\273\347\273\237\347\256\241\347\220\206.md" +++ /dev/null @@ -1,12 +0,0 @@ -# kubectl常用指令 -# trouble shooting -# 常用工具 -# 参考文献 -[Kubernetes NODE维护模式](http://mp.weixin.qq.com/s?src=3×tamp=1473267170&ver=1&signature=PKi78rifAcWNCn5gsYgNsqDUPN7nOrCadA5MO7alA6SA7kEwIVutnjiIr0NHS6N4fqVQuu-uMfKE3RAjqN4NsrGO0BGsWU5NFCFgXxPzg3E4mUkInU-ldZrvDKgykboG2MH3x5NTGThhTEAR1Ku-dQ==) -[Kubernetes 1.2新功能解析:使用Deployment](https://caicloud.io/article_detail/573d8b6c824168110000002a) -[Kubernetes用户指南(三)--在生产环境中使用Pod来工作、管理部署](http://blog.csdn.net/qq1010885678/article/details/49156557) -[ Kubernetes用户指南(四)--应用检查和调试](http://blog.csdn.net/qq1010885678/article/details/49405435) -[如何在生产环境中运用dashboard](http://blog.kubernetes.io/2016/10/Production-Kubernetes-Dashboard-UI-1.4-improvements_3.html) -[Apprenda发布Kubernetes自动化运维工具KET](http://www.infoq.com/cn/news/2016/11/apprenda-kubernetes-ket) -[Kubernetes从部署到运维详解](http://geek.csdn.net/news/detail/115128) -[Kubernetes系统运维操作和技巧](https://t.goodrain.com/t/kubernetes/131) \ No newline at end of file diff --git "a/\347\275\221\347\273\234\346\226\271\346\241\210.md" "b/\347\275\221\347\273\234.md" similarity index 56% rename from "\347\275\221\347\273\234\346\226\271\346\241\210.md" rename to "\347\275\221\347\273\234.md" index 4daf607..4ee27e8 100644 --- "a/\347\275\221\347\273\234\346\226\271\346\241\210.md" +++ "b/\347\275\221\347\273\234.md" @@ -1,3 +1,13 @@ +# 认证要求 +- Networking 网络 11% + - 理解在集群节点上配置网络 + - 理解pod的网络概念 + - 理解service networking + - 部署和配置网络负载均衡器 + - 知道如何使用ingress 规则 + - 知道如何使用和配置cluster dns + - 理解CNI + # Docker原生网络 在docker 1.9之前主支持none/host/bridge/container四种网络模型。而在docker 1.9版本后实现了原本实验性的Networking组件的支持,可以在Swarm中使用它或者将其作为Compose 工具。创建虚拟网络并将其连接到容器实现多个主机上容器相互通讯。(kernel版本需要在3.19之上) @@ -12,6 +22,7 @@ docker原生网络的问题在于: - 容器需要自行规划端口 - 容器无法跨主机进行编排 + # CNI VS CNM 首先,向大家科普下Kubernetes所选择的CNI网络接口,简单介绍下网络实现的背景。 @@ -44,6 +55,8 @@ Sandbox就是容器的网络命名空间,Endpoint为容器连接到网络中 当然,Kubernetes也提供一些取巧的方法,将CNI接口转化为对CNM模型的调用,从而实现两种模型的通用。例如to_docker,这个脚本就将Kubernetes对CNI的调用转换为Docker CNM网络的对应操作,从而实现CNI到CNM的转换。 > 参考 [基于Neutron的Kubernetes SDN实践经验之谈*****](http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649693914&idx=1&sn=19fda53b4afd626bdc8ad0141e9f7a9b&chksm=889321b9bfe4a8af3c4d9b78e8c299893e49d33e71d878d3fbb0324f468aebaf08efa7b35deb&mpshare=1&scene=1&srcid=0428luoASGP9HYZD8M0mjgIW#rd) +# POD的网络模型 +每个Pod都会被分配一个唯一的IP地址。Pod中的所有容器共享网络空间,包括IP地址和端口。Pod内部的容器可以使用localhost互相通信。Pod中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射)。 # 网络方案 在网络概念上,Kubernetes中有两种核心IP: @@ -138,6 +151,19 @@ aws-vpc:在 Amazon AWS 实例表中注册新增机器子网。该实例表最 host-gw:通过远程机器 IP ,创建到子网的 IP 路由。这要求运行 flannel 的不同主机在二层直接互通。 > 参考[一个适合 Kubernetes 的最佳网络互联方案](http://dockone.io/article/1115) +flannel的subnet 的租约时间是24小时, 这个是硬编码在local_manager.go这个文件里的 +```go +const ( + raceRetries = 10 + subnetTTL = 24 * time.Hour +) +``` +在租约过期前的一个小时内, 会发起续约。可以通过启动参数--subnet-lease-renew-margin来修改发起续约的时间。 + +flannel连接etcd或者k8s 的api server 获取和配置网段信息, **建议使用使用连接k8s api server 的方式替代etcd**。 启动参数: +```shell +--kube-subnet-mgr: Contact the Kubernetes API for subnet assignement instead of etcd or flannel-server. +``` ## calico   Project Calico 是纯三层的 SDN 实现,没有使用重载网络,它基于 BPG 协议和 Linux 自己的路由转发机制,不依赖特殊硬件,没有使用 NAT 或 Tunnel 等技术。能够方便的部署在物理服务器、虚拟机(如 OpenStack)或者容器环境下。同时它自带的基于 Iptables 的 ACL 管理组件非常灵活,能够满足比较复杂的安全隔离需求。 @@ -205,7 +231,7 @@ Weave网络中的fast datapath 使用了Linux内核的Open vSwitch datapath modu ## openvswitch -# 方案对比 +## 方案对比 ![](./_image/2017-07-15-11-38-03.jpg) > 参考[程序猿成长日记 | Docker跨主机通信解决方案探讨](http://www.bocloud.com.cn/news/show-195.html) @@ -254,6 +280,393 @@ ports: ``` 它指定约束,具有role:db标签的POD只能被具有role:frontend标签的POD访问,除此之外拒绝所有流量。从功能上来讲,Network Policy可以等价于Neutron的安全组。 +# Service Networking +> 参考[Services](https://kubernetes.io/docs/concepts/services-networking/service/) + +理解service networking +service存在的意义: 在k8s里, pod的生命周期可能是很短暂的, pod的动态创建和销毁有可能是一个很频繁的操作,每次创建都会启动新的pod ip。 如果应用要让其它应用来访问, 要怎么办呢, 要如何追踪到这个应用有哪些后端pod呢。 service这个资源对象就是对pod的逻辑组合以及如何访问它们的策略的抽象。 +## 如何定义一个service +```yml +kind: Service +apiVersion: v1 +metadata: + name: my-service +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +``` + +这里port是service上暴露的端口, targetPort是请求转发到pod上的端口, 如例子所示, 上述的service定义的是如果有一个访问service的80端口, 那么service会把请求转发到后端pod的9376端口上 + +如果 targetPort不指定, 则默认取port的值。 +**targetPort的值可以是字符串类型,这是暴露port的名称**, 这个设计,为用户的应用部署升级提供了更多的灵活性, 比如用户可以在新版本的pod暴露新的端口(port名称不变), 此时service就无需重新构建, 从而无需切断客户端连接, 提高应用的可用性。 + +service支持TCP,和UDP协议。 + +## 无选择器的service +无选择器的service一般用于下面的集中场景: +1. 有个外部的数据库集群, 要通过自定义endpoint指向这个数据的访问 +2. 想要把你的service指向另外一个命名空间下的service或者另外一个集群下的service +3. 你要把工作负载迁移到集群之外 + +无选择器的service除了要定义service之外,还要定义endpoint,如下例所示 +service.yaml +```yml +kind: Service +apiVersion: v1 +metadata: + name: my-service +spec: + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +``` +endpoint.yaml +```yml +kind: Endpoints +apiVersion: v1 +metadata: + name: my-service +subsets: + - addresses: + - ip: 1.2.3.4 + ports: + - port: 9376 +``` +二者通过metadata的name字段自动关联, 需要名称一致 + +有一类特殊的无选择器的service无需定义endpoint, 它是ExternalName Service +```yml +kind: Service +apiVersion: v1 +metadata: + name: my-service + namespace: prod +spec: + type: ExternalName + externalName: my.database.example.com +``` +当你访问这个service时, 会去通过集群dns, 集群的dns会返回一条CNAME的记录, 即my.database.example.com, **这个重定向是发生在dns层的, 没有任何的流量代理或者转发**。 也就是说不是通过主机上的kube-proxy和iptables。 + +## VIP 和服务代理 + Kubernetes的Services可以认为是工作在4层上(TCP/UDP over IP)。 +每一个工作节点上都会运行kube-proxy进程,这个进程为service提供了某种形式的虚拟IP. +kube-proxy有两种代理模式: userspace proxy mode, iptables proxy mode。 +在1.0时,使用的是userspace模式, 在1.1时加入了iptables模式的支持,但没有作为默认模式, 1.2之后iptables模式作为默认的模式。 +两种模式的原理图如下: +userspace mode + +![](./_image/2017-09-24-16-35-30.png) +iptables mode + +![](./_image/2017-09-24-16-35-49.png) + +两种模式的共同点和差异 +```table +模式 | 原理 | 共同点 | 差异点 +usespace mode | 1. kube-proxy进程负责watch apiserver的endpoint的增加和移除 2. 每个service都会在本地节点上随机侦听一个端口, 访问到这个proxy port的流量会被转发到后端的pod上 3. 本地会建立iptables规则以捕捉和转发访问service ip:port的网络流量到kube-proxy侦听的对应的service的proxy port上 | 1. client访问service无需知道kubernetes的services和pods的细节 2. 默认支持轮询访问pod, 也支持ip hash的形式, 根据客户端ip的session来限定负载策略,需要将service.spec.sessionAffinity的值设为\"ClientIP\" | 需要建立在系统的用户空间建立侦听端口,用于转发流量到后端的pod,这样做会让性能变差 +iptables mode | 1. kube-proxy进程负责watch apiserver的endpoint的增加和移除 2. 本地会建立iptables规则以捕捉和转发访问service ip:port的网络流量到kube-proxy侦听的对应的service的proxy port上 | 同上 | 直接用iptables转发, 好处是转发性能更好,更稳定。 缺点是如果一开始选择的pod没有响应,iptables无法选择另外一个pod发起重试。客户端和后端的pod的连接就可能会出现错误连接状态, 除非客户端能够断开连接进行重连。 **这个问题可以通过配置readiness probe来解决**。 +``` + +## 发现服务 +查找一个服务有两种方式: 环境变量和DNS. +**环境变量** +当创建了一个service的时候, kubelet会为每一个活动的service增加一系列环境变量到pod里, 变量的格式如下: +{SVCNAME}_SERVICE_HOST , {SVCNAME}_SERVICE_PORT + +举个例子, 有个 Service "redis-master" 暴露了 TCP端口 6379, 并分配了cluster IP address 10.0.0.11 会产生下面的环境变量 +```shell +REDIS_MASTER_SERVICE_HOST=10.0.0.11 +REDIS_MASTER_SERVICE_PORT=6379 +REDIS_MASTER_PORT=tcp://10.0.0.11:6379 +REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379 +REDIS_MASTER_PORT_6379_TCP_PROTO=tcp +REDIS_MASTER_PORT_6379_TCP_PORT=6379 +REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11 + +``` +这种方式的限制在于, service要先于POD创建, 相应的环境变量才能被加载到pod里。 例如如果有pod A要访问redis master的service, 就需要先创建redis master, 再创建pod A,这样pod A才能读取到redis master service的相关环境变量。 (ps: **新创建的service的环境变量不会别加载老的pod里**) + +**DNS** +假设用户在命名空间my-ns下创建了一个名叫 my-service的service, 这时kube dns会自动增加一条dns记录: my-service.my-ns . 域名解析得到的ip是service的cluster ip。 + +**假设用户在service上暴露了一个名叫http的TCP端口, 用户可以使用下面的方式获取到端口:** +"_http._tcp.my-service.my-ns" + + +## 无头service (headless service) +为spec.clusterIP指定值为None,此时就创建了一个无头service。 这个选项允许用户选择自己的服务发现方式, 和kubernetes进行解耦。 kubernetes不为无头service分配cluster ip, kube-proxy不为这些处理service的负载均衡和流量代理。 + +无头service有selector和无selector时,dns配置不一样。 +有selector: endpoint controller会创建对应的endpoint, 并修改DNS的A记录直接指向POD 的 ip +无selector: 不会创建endpoint。 DNS 会为这两种情形做配置。 1. 为ExternalName类型的service创建C记录。 2. 为任何类型的service 匹配和servcie同名的endpoint。 + + +## 发布service的几种类型 +```table +Type | 描述 +ClusterIP | 以集群内部IP的形式暴露Service,这个cluster ip只能在集群内访问 +NodePort | 在集群的每个节点上IP的上绑定一个静态端口的方式来暴露Service。 集群外部可以通过:的方式来访问这个Service +LoadBalancer | 对接云供应商的负载均衡器,此时 ClusterIP或NodePort Service会被自动创建。 +ExternalName | 通过返回C记录的方式, 对接外部名称如(foo.bar.example.com)。 此时任何形式的流量代理都不会被创建。 这个特性需要kubernetes的1.7版本支持, 或者高版本的kube-dns支持。 +``` +NodePort类型 +> 如果不指定spec.ports[*].nodePort的值, 那么会从node-range里随机选择(node port的范围有master指定分配, 默认是30000~32767) + +LoadBalancer类型 +> 负载均衡器的创建的是异步的, 且和负载均衡器配置相关的信息会在status.loadBalancer这个字段显示 +```yml +kind: Service +apiVersion: v1 +metadata: + name: my-service +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 + nodePort: 30061 + clusterIP: 10.0.171.239 + loadBalancerIP: 78.11.24.19 + type: LoadBalancer +status: + loadBalancer: + ingress: + - ip: 146.148.47.155 +``` + +网络请求流量会直接从Loadbalancer到后端的pods。 +如果云供应商支持, 你还可以自己指定loadBalancerIP, 如果云供应商不支持, 你自行指定的这个字段的值会被忽略。 + +问题: +1. k8s和外部的loadbalancer是怎么交互的? +2. k8s需要在哪里指定外部loadbalancer? +3. k8s支持哪些外部loadbalancer? +4. 如果一个云供应商要把自己的loadbalancer产品对接k8s, 需要做哪些工作? + +# 域名解析 +> 参考 [官方文档之Using DNS Pods and Services](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/) + +知道如何使用和配置cluster dns +## Services +从kubernetes1.3版本开始, dns作为一个内建服务, 通过插件插件管理器(add-on manager)的方式自动创建。 +域名解析格式: +同个namespace, 直接用做域名访问 +跨namespace, 用.做域名访问 + +普通的service(非无头service): my-svc.my-namespace.svc.cluster.local , 解析得到的是service的cluster ip +无头service: my-svc.my-namespace.svc.cluster.local, 解析得到的是**一组pod的ip** + +SRV 记录: +> 普通和无头service的port 名称的域名格式: _my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local +> 对于普通的service, 还会得到一个CNAME记录my-svc.my-namespace.svc.cluster.local +> 对应无头service, 得到的CNAME记录的格式为auto-generated-name.my-svc.my-namespace.svc.cluster.local + +备注: 原先老的DNS域名形式my-svc.my-namespace.cluster.local不再支持 + +## Pods +A记录 +> 形式如 pod-ip-address.my-namespace.pod.cluster.local + +基于hostname 和 子域名(subdomain)的A记录 + +```table +版本 | 指定hostname | 指定POD的子域名 | hostname-map +v1.2 | 在annotation里指定pod.beta.kubernetes.io/hostname的值 | 在annotation里指定pod.beta.kubernetes.io/subdomain的值 | 在ENDPOINT的对象annotation里指定endpoints.beta.kubernetes.io/hostnames-map的值, 如{“10.245.1.6”:{HostName: “my-webserver”}} +v1.3 | pod的编排文件里指定hostname的值 | pod的编排文件里指定subdomain的值 | 在ENDPOINT的编排文件的字段里指定hostname即可 +``` + +对于pod的子域名, 做一个说明: 如果pod的hostname为foo, 子域名为bar,则pod的FQDN: foo.bar.my-namespace.svc.cluster.local, 这个域名解析得到的是pod的ip + +例子: +```yml +apiVersion: v1 +kind: Pod +metadata: + name: busybox1 + labels: + name: busybox +spec: + hostname: busybox-1 + subdomain: default-subdomain + containers: + - image: busybox + command: + - sleep + - "3600" + name: busybox +--- +apiVersion: v1 +kind: Pod +metadata: + name: busybox2 + labels: + name: busybox +spec: + hostname: busybox-2 + subdomain: default-subdomain + containers: + - image: busybox + command: + - sleep + - "3600" + name: busybox +``` + +备注: 在1.3版本里, 废除了pod.beta.kubernetes.io/hostname, pod.beta.kubernetes.io/subdomain, endpoints.beta.kubernetes.io/hostnames-map的annotation用法 + +## 检查DNS的可用性 +检查dns是否可用 +```shell +kubectl exec -ti busybox -- nslookup kubernetes.default +``` +检查dns配置 +```shell +kubectl exec busybox cat /etc/resolv.conf +``` + +DNS 策略 +> 默认情况下, DNS 给pod的策略是ClusterFirst, 在这个策略下, 跑在hostNetwork的pod无法解析域名,需要给这类pod指定ClusterFirstWithHostNet策略, 编排文件例如: +```yml +apiVersion: v1 +kind: Pod +metadata: + name: busybox + namespace: default +spec: + containers: + - image: busybox + command: + - sleep + - "3600" + imagePullPolicy: IfNotPresent + name: busybox + restartPolicy: Always + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet +``` + +## 快速诊断 +如果出现nslookup: can't resolve 'kubernetes.default'错误, 如何快速诊断和排障呢,步骤如下: +1. 检查DNS pod是否运行? +```shell +kubectl get pods --namespace=kube-system -l k8s-app=kube-dns +``` +> NAME READY STATUS RESTARTS AGE +... +kube-dns-v19-ezo1y 3/3 Running 0 1h +... +2. 检查dns pod是否有报错? +```shell +kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c kubedns +kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c dnsmasq +kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c sidecar +``` +3. 检查DNS的service是否正常 +```shell +kubectl get svc --namespace=kube-system +``` +> NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE +... +kube-dns 10.0.0.10 53/UDP,53/TCP 1h +... +4. DNS的endpoint是否正常暴露? +```shell +kubectl get ep kube-dns --namespace=kube-system +``` +> NAME ENDPOINTS AGE +kube-dns 10.180.3.17:53,10.180.3.17:53 1h + +## 工作原理 +DNS的pod有三个容器: kubedns, dnsmasq 和 health check ( healthz). + +```table +组件 | 功能 +kube-dns | watch master中endpoint和service的变化, 并在内存里维护查询结构,用来服务dns请求 +dnsmasq | 增加dns缓存,来提高性能 +healthz | 对kube-dns和dnsmaq的健康检查, 提供健康检查的唯一入口 +``` + +dns会启动一个service, 并指定一个静态ip。 在每个节点的kubelet启动时要加上--cluster-dns=10.0.0.10,--cluster-domain= + +## 从node继承dns配置 +kubelet启动时使用--resolv-conf参数, 指定容器要使用的dns配置 + +## 已知问题 +Linux’s libc 限制了dns server和 search 记录的数量(最大3个dns server, 6个search 记录), kubernetes系统需要占用1个dns server和3个search记录。 +# 负载均衡 +部署和配置网络负载均衡器 +# 外部访问 +知道如何使用ingress 规则 +ingress 是k8s里的一种资源对象, 它定义了一系列的规则运行外部访问的集群里的应用服务。 +ingress的编排文件示例: +```yml +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: test-ingress + annotations: + ingress.kubernetes.io/rewrite-target: / +spec: + rules: + - http: + paths: + - path: /testpath + backend: + serviceName: test + servicePort: 80 +``` + +ingress 要配合ingress controller 才能正常工作,单纯创建ingress没有意义。 + +ingress支持导入TLS的证书,用法如下 +```yml +apiVersion: v1 +data: + tls.crt: base64 encoded cert + tls.key: base64 encoded key +kind: Secret +metadata: + name: testsecret + namespace: default +type: Opaque +``` +```yml +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: no-rules-map +spec: + tls: + - secretName: testsecret + backend: + serviceName: s1 + servicePort: 80 +``` +目前官方的ingress controller有nginx , GCE等 +非官方的有: +* [Dummy controller backend](/examples/custom-controller) +* [HAProxy Ingress controller](https://github.com/jcmoraisjr/haproxy-ingress) +* [Linkerd](https://linkerd.io/config/0.9.1/linkerd/index.html#ingress-identifier) +* [traefik](https://docs.traefik.io/toml/#kubernetes-ingress-backend) +* [AWS Application Load Balancer Ingress Controller](https://github.com/coreos/alb-ingress-controller) +* [kube-ingress-aws-controller](https://github.com/zalando-incubator/kube-ingress-aws-controller) +* [Voyager: HAProxy Ingress Controller](https://github.com/appscode/voyager) + +> 参考https://github.com/kubernetes/ingress/blob/master/docs/catalog.md + +ingress的几种替代方案 +- Service.Type=LoadBalancer +- Service.Type=NodePort +- Port Proxy +- 部署Service loadbalancer # 参考文献 - [官方文档之网络篇*****](https://kubernetes.io/docs/concepts/cluster-administration/networking/) @@ -278,4 +691,27 @@ ports: - [基于Neutron的Kubernetes SDN实践经验之谈*****](http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649693914&idx=1&sn=19fda53b4afd626bdc8ad0141e9f7a9b&chksm=889321b9bfe4a8af3c4d9b78e8c299893e49d33e71d878d3fbb0324f468aebaf08efa7b35deb&mpshare=1&scene=1&srcid=0428luoASGP9HYZD8M0mjgIW#rd) - [利用听云Server和听云Network实测Kubernetes和Mesos在高并发下的网络性能](http://blog.tingyun.com/web/article/detail/406) - [docker网络方案之weave原理篇](http://blog.csdn.net/happyanger6/article/details/71316188) -- [ docker网络方案之weave实战篇](http://blog.csdn.net/happyanger6/article/details/71104577) \ No newline at end of file +- [ docker网络方案之weave实战篇](http://blog.csdn.net/happyanger6/article/details/71104577) +- [官方文档之Services](https://kubernetes.io/docs/concepts/services-networking/service/) +- [官方文档之Using DNS Pods and Services](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/) +- [官方文档之ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) +- [官方文档之服务简介](http://kubernetes.io/docs/user-guide/services/) +- [KUBERNETES入门之KUBE-PROXY实现原理](http://www.cnblogs.com/xuxinkun/p/5799986.html) +- [kubernetes中port、target port、node port的对比分析,以及kube-proxy代理](http://blog.csdn.net/xinghun_4/article/details/50492041) +- [ Kubernetes DNS服务的安装与配置](http://blog.csdn.net/bluishglc/article/details/52438917) +- [Understanding SkyDNS ](https://github.com/k8sp/issues/issues/32) +- [Kubernetes技术分析之DNS](http://dockone.io/article/543) +- [Kubernetes高级实践之集成DNS](https://www.zybuluo.com/dujun/note/83702) +- [Kubernetes(k8s)如何使用kube-dns实现服务发现](http://www.kubernetes.org.cn/273.html) +- [官方文档之负载均衡器](http://kubernetes.io/docs/user-guide/load-balancer/) +- [Consul + fabio 实现自动服务发现、负载均衡](http://dockone.io/article/1567) +- [Keepalived+LVS-DR模式配置高可用负载均衡集群](http://blog.csdn.net/m582445672/article/details/7670015) +- [Kubernetes 1.2 中利用 Ingress 简化复杂网络](http://blog.fleeto.us/translation/simplifying-advanced-networking-ingress) +- [Kubernetes 1.2 新功能介绍:Ingress 原理及实例](http://www.dockerinfo.net/1132.html) +- [微服务动态路由实现:OpenResty与kubernetes](http://www.dockerinfo.net/1700.html) +- [Traefik Kubernetes 初试](https://www.kubernetes.org.cn/1237.html) +- [Ingress Resources](https://kubernetes.io/docs/user-guide/ingress/) +- [使用 NGINX 和 NGINX Plus 的 Ingress Controller 进行 Kubernetes 的负载均衡](http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649693301&idx=1&sn=b1a316cbb882e41906f0ff82cdd4bac3&chksm=88932316bfe4aa005af924e7edb76337bd8ad067c907b71b0728d98bfb791fc4214616ca4781&mpshare=1&scene=1&srcid=0213VOBUD0R21SrWHnNxVYLN#rd) +- [教程 | Kubernetes的边缘节点配置](http://mp.weixin.qq.com/s?__biz=MzI4NDYxOTgwMw==&mid=2247483822&idx=1&sn=8f857113e21ab8097d51d1064d567187&chksm=ebf9e4dadc8e6dccf1e9cb85bededc927deab129fd17b77b6163937276103ed5d02dac108488&mpshare=1&scene=1&srcid=0510SJG4Xr6H1lDhYN4EcJAL#rd) +- [Kubernetes1.6 Ingress配置](http://mp.weixin.qq.com/s?__biz=MzUzMTA1NTM5NA==&mid=2247483667&idx=1&sn=f976fddff0adc1c94865b09ac6dcd6d8&chksm=fa49175ecd3e9e48db40168c312b12b51cc1cca4cb55051333907171c5319823215fcbc6defb&mpshare=1&scene=1&srcid=0505RWMiNM7qdx0gvzfS4PqA#rd) +- [Kubernetes ingress解析 - Jimmy Song](http://rootsongjc.github.io/blogs/kubernetes-ingress-resource/?from=groupmessage&isappinstalled=0) \ No newline at end of file diff --git "a/\350\260\203\345\272\246.md" "b/\350\260\203\345\272\246.md" new file mode 100644 index 0000000..a2bb52c --- /dev/null +++ "b/\350\260\203\345\272\246.md" @@ -0,0 +1,284 @@ +# 认证要求 +- Scheduling 调度 5% + - 使用label选择器来调度pods + - 理解Daemonset的角色 + - 理解resource limit 会如何影响pod 调度 + - 理解如何运行多个调度器, 以及如何配置pod使用它们 + - 不使用调度器, 手动调度一个pod + - 查看和显示调度事件events + - 知道如何配置kubernetes scheduler + +# 使用label选择器来调度pods +1. 查看节点信息 +```shell +kubectl get nodes +``` +输出如下: +```text +NAME STATUS AGE VERSION + worker0 Ready 1d v1.6.0+fff5156 + worker1 Ready 1d v1.6.0+fff5156 + worker2 Ready 1d v1.6.0+fff5156 +``` +2. 选择一个节点, 并给这个节点打上label +```shell +kubectl label nodes disktype=ssd +``` +3. 验证节点上是否有成功打上对应label +```shell +kubectl get nodes --show-labels +``` +输出结果类似于 +```text + NAME STATUS AGE VERSION LABELS + worker0 Ready 1d v1.6.0+fff5156 ...,disktype=ssd,kubernetes.io/hostname=worker0 + worker1 Ready 1d v1.6.0+fff5156 ...,kubernetes.io/hostname=worker1 + worker2 Ready 1d v1.6.0+fff5156 ...,kubernetes.io/hostname=worker2 +``` +4. 创建一个pod, 调度到这个node上 +在pod的配置里, 要指定nodeSelector, 比如disktype=ssd。 这意味着pod启动后会调度到打上了disktype=ssd标签的node上 +```yml +apiVersion: v1 +kind: Pod +metadata: + name: nginx + labels: + env: test +spec: + containers: + - name: nginx + image: nginx + imagePullPolicy: IfNotPresent + nodeSelector: + disktype: ssd + +``` + +6. 验证pod启动后是否调度到指定节点上 +```shell +kubectl get pods --output=wide +``` +输出类似于 +```text +AME READY STATUS RESTARTS AGE IP NODE + nginx 1/1 Running 0 13s 10.200.0.4 worker0 +``` + +> 参考 [Assign Pods to Nodes](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/) +# 理解Daemonset的角色 +## 什么是daemonset以其使用场景 +daemonset会在每一个节点上运行一个pod的副本,当有node加入集群时,会自动在新节点上启动pod副本, 当node被移出节点时, 上面的pod副本会被自动删除。 +使用场景: +- 运行storage进程,如 glusterd, ceph等 +- 进行日志收集进程fluentd, logstash , filebeat等 +- 监控进程,比如prometheus node exporter, collectd, datadog agent, new relic agent, ganglia gmond等 + +## 创建一个daemonset +```yml +apiVersion: apps/v1beta2 +kind: DaemonSet +metadata: + name: fluentd-elasticsearch + namespace: kube-system + labels: + k8s-app: fluentd-logging +spec: + selector: + matchLabels: + name: fluentd-elasticsearch + template: + metadata: + labels: + name: fluentd-elasticsearch + spec: + containers: + - name: fluentd-elasticsearch + image: gcr.io/google-containers/fluentd-elasticsearch:1.20 + resources: + limits: + memory: 200Mi + requests: + cpu: 100m + memory: 200Mi + volumeMounts: + - name: varlog + mountPath: /var/log + - name: varlibdockercontainers + mountPath: /var/lib/docker/containers + readOnly: true + terminationGracePeriodSeconds: 30 + volumes: + - name: varlog + hostPath: + path: /var/log + - name: varlibdockercontainers + hostPath: + path: /var/lib/docker/containers +``` + +如果只想调度到某些主机上, 可以指定nodeSelector的值。 + +## Daemon Pods如何调度 +通常情况下pod要运行的机器是由scheduler来选择的的。但是DaemonSet controller创建的pod要运行的机器是已经被选择好的(pod在创建的时候.spec.nodeName字段就指定了, 因此会被scheduler忽略) + +因此: +- unschedulable字段对daemonset controller创建的pod不起作用,当你尝试kubectl drain 时, 驱赶不了daemonset创建的pod +- 即使scheduler没有起来, daemonset创建的pod也可以正常调度,因为它的调度不依赖scheduler + +但是如果node被标记为以下的两种状态: +node.alpha.kubernetes.io/notReady +node.alpha.kubernetes.io/unreachable + +daemon pods就不会调度到上面。 + +## 如何和daemonset的pod通信 +- 使用hostPort +- 创建headless service(指定pod 的选择器标签),使用dns解析得到一堆endpoint +- 创建service(指定pod 的选择器标签), 用service 的cluster ip或者域名进行连接 + +## 如何更新一个daemonset +node的label改变时,daemonset会自动将pod启动在新匹配上的节点,或者把pod移除出不匹配的节点 + +当你用kubectl删除daemonset时,指定参数--cascade=false, 这时daemonset会被删除, 但是pod会被保留, 重新使用新的模板创建daemonset, 新的daemonset会识别和匹配到已经存在于node上的pods, 但是不会修改和删除它们, 你需要手动执行删除这些pod, 才能让新的pod能够创建。 + +值得注意的是, 在kubernetes 1.6版本之后, daemonset可以执行滚动更新了。 具体操作可以参考https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/ + +## daemonset的几种替代方案 +- init, upstartd, 和systemd +> 但是daemonset的好处在于 +> 可以像k8s上的应用一样, 监控和记录日志 +> 可以像k8s上的应用一样使用模板进行编排,比如Pod Template,并使用k8s的工具, 比如kubectl +> 在未来版本中, 可以和node的升级工作流和daemonset创建的pod进行整合 +> 可以通过资源限制, 更好和应用的容器做隔离 +> 可以方便的进行滚动升级 +> 安装部署方便, 而且有新的节点移入移除时,进程的添加和删除都是自动执行的 + +- bare pods +> 在pod中指定特定的节点运行。 daemonset的方式优于这种方式, 它会自动替换和删除有故障主机上的pod, 或者处于维护中(比如内核升级)的节点上的pod +- static pods +> static pod不能被 kubectl和其它的kubernetes 的api client。 static pods 有可能在未来的版本中被废弃。 +- Deployments +> deployment更适合有滚动升级, 扩缩容需求的无状态服务 +> daemonset适合那些需要运行在所有或特定主机上的服务, 或者需要先于其它pod启动的服务 + +# 理解resource limit 会如何影响pod 调度 +# 理解如何运行多个调度器, 以及如何配置pod使用它们 +1. 打包自定义的scheduler镜像 +2. 为你的scheduler制作deployment +```yml +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + labels: + component: scheduler + tier: control-plane + name: my-scheduler + namespace: kube-system +spec: + replicas: 1 + template: + metadata: + labels: + component: scheduler + tier: control-plane + version: second + spec: + containers: + - command: + - /usr/local/bin/kube-scheduler + - --address=0.0.0.0 + - --leader-elect=false + - --scheduler-name=my-scheduler + image: gcr.io/my-gcp-project/my-kube-scheduler:1.0 + livenessProbe: + httpGet: + path: /healthz + port: 10251 + initialDelaySeconds: 15 + name: kube-second-scheduler + readinessProbe: + httpGet: + path: /healthz + port: 10251 + resources: + requests: + cpu: '0.1' + securityContext: + privileged: false + volumeMounts: [] + hostNetwork: false + hostPID: false + volumes: [] +``` +这个scheduler pod启动的时候, 要指定--scheduler-name, 这个名称是要唯一的。另外其它pod要指定调度器的时候用的是这里指定的调度器名称。 +3. 在集群中运行scheduler +```shell +kubectl create -f my-scheduler.yaml +``` +如果要让多个调度器之间进行选主操作, 要修改pod yaml里的启动参数, 增加如下参数 +- --leader-elect=true +- --lock-object-namespace=lock-object-namespace +- --lock-object-name=lock-object-name + +如果你开启了RBAC, 要更新你的cluster role - system:kube-scheduler. +在resourceNames:那一行,加上你的调度器名称 + +4. pod启动时指定调度器 +```yml +apiVersion: v1 +kind: Pod +metadata: + name: annotation-second-scheduler + labels: + name: multischeduler-example +spec: + schedulerName: my-scheduler + containers: + - name: pod-with-second-annotation-container + image: gcr.io/google_containers/pause:2.0 +``` + +spec.schedulerName指定的调度器的名称要和 scheduler的启动参数--scheduler-name里指定的名称一致,才能正常调度。 + +5. 验证pod有没有被期望的调度器调度 +```shell +kubectl get events +``` +从events可以看出调度行为 + +> 参考 [Configure Multiple Schedulers](https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/) +# 不使用调度器, 手动调度一个pod +使用static pod可以实现手动调度一个pod。 + +static pod的特点总结如下: +1. 不通过apiserver watch, 由本机的kubelet进程执行watch,并拉起 +2. 只在本机进行调度 +3. 没有健康检查 +4. 不被controller manager调度 +5. 因为apiserver里有pod的镜像信息, 通过apiserver还是可以看到pod的信息 +## 如何创建? +方法一: kubelet启动时要指定参数kubelet --pod-manifest-path=,这里的the directory要放置static pod的编排文件的目录。 把static pod的编排文件放到此目录下, kubelet可以监听到变化, 并根据编排文件创建pod。 + +方法二: 指定--manifest-url=, kubelet会从这个URL下载编排文件, 并创建pod + +## 如何删除? +当我们直接用kubectl的命令kubectl delete pod删除一个静态pod时, 我们会发现static pod过一段时间又会被kubelet拉起。 + +要完全删除一个static pod, 可以移除把该static pod的编排文件, 从--pod-manifest-path=所指定的目录里移除即可。 + +## 使用场景? +因为static pod有一个特性是我们的应用的docker 容器被删除,或者pod被kubectl误删了之后, static pod还能被kubelet进程拉起。通过这种方式保证了应用的可用性。 有点相当于systemd的功能, 但比systemd好的一点是, static pod的镜像信息会在apiserver中注册。 这样的话, 我们就可以统一对部署信息进行可视化管理。 另外static调度了的是容器, 无需拷贝二进制文件到主机上, 应用封装在镜像里也保证了环境的一致性, 无论是应用的编排文件还是应用的镜像都方便进行版本管理和分发。 + +实际生产中, static pod可以用来部署kubernetes的kube-proxy, kube-scheduler, kube-controller-manager, kube-apiserver等进程。 + +当我们要部署一个有状态的应用, 有几种方式: +1. 使用statefulset +2. 给主机打上label,只允许主机在这几台主机上调度 +3. 通过挂载ceph盘来存储有状态数据(要求master和node节点上都要安装rbd工具) +4. 使用static pod ,但是这种方式适合那些无滚动升级需求, 无扩缩容需求,不频繁进行升级的应用 +# 查看和显示调度事件events +# 知道如何配置kubernetes scheduler + +# 参考文献 +- [Assign Pods to Nodes](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/) +- [Configure Multiple Schedulers](https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/) \ No newline at end of file diff --git "a/\351\203\250\347\275\262\345\256\211\350\243\205.md" "b/\351\203\250\347\275\262\345\256\211\350\243\205.md" deleted file mode 100644 index 10b7822..0000000 --- "a/\351\203\250\347\275\262\345\256\211\350\243\205.md" +++ /dev/null @@ -1,21 +0,0 @@ -# 单点安装 -# 高可用方案 -# 部署常见的坑 -# 资源及工具列表 -# 参考文献 -- [ Kubernetes概念介绍和v1版本部署过程](http://blog.csdn.net/qq1010885678/article/details/48719923) -- [Kubernetes 1.3版本之简单安装](http://my.oschina.net/fufangchun/blog/727795) -- [Kubernetes集群生产环境搭建全过程](https://segmentfault.com/a/11900000053454663) -- [在CentOS7上部署Kubernetes集群](https://mos.meituan.com/library/37/how-to-setup-k8s-cluster-on-CentOS7/) -- [ Kubernetes用户指南(二)--部署组合型的应用、连接应用到网络中](http://blog.csdn.net/qq1010885678/article/details/49026825) -- [Kubernetes用户指南(三)--在生产环境中使用Pod来工作、管理部署](http://blog.csdn.net/qq1010885678/article/details/49156557) -- [kubernetes官方指南](http://kubernetes.io/docs/) -- [Sextant一小步,Kubernetes一大步!](http://mp.weixin.qq.com/s?src=3×tamp=1473267136&ver=1&signature=4olKSipUP3ysjTJnJPgkfFH7b*bhsfxVRCTsRoypeKyP6iv-NLO8ZGv7GQv4vYmiLdyoxh1T08sHs03B8EDaqoz8KH6dVw46bsPH9CFWAgZrhDfj3colGXwWoRubIVgAksvVK0QUuC6etjTt-E5qRGkYm5zxwksfridilKqrEr0=) -- [kubernetes 1.6.0 高可靠集群部署](https://addops.cn/post/kubernetes-deployment.html) -- [Kubernetes高可用Master节点安装](https://www.kubernetes.org.cn/1865.html) -- [Kubernetes集群安装文档-v1.6版本](https://www.kubernetes.org.cn/1870.html) -- [一键部署kubernetes 1.6高可用集群](https://zhuanlan.zhihu.com/p/26550959) -- [和我一步步部署 kubernetes 集群](https://github.com/opsnull/follow-me-install-kubernetes-cluster) -- [Kubernetes1.6集群部署完全指南 ——二进制文件部署开启TLS基于CentOS7发布 - Jimmy Song](http://rootsongjc.github.io/projects/kubernetes-installation-document/) -- [Kubernetes的企业部署目标](http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649693898&idx=1&sn=3c2b6ab8a66381d1ec470e4b781c4fb0&chksm=889321a9bfe4a8bf7c89be683499aca039135100d9cccb12a62ac9045a620c2e05bdead365db&mpshare=1&scene=1&srcid=04260mmcz8dt53rEXQzc0WIQ#rd) -- [在阿里云上部署生产级别Kubernetes集群](http://mp.weixin.qq.com/s?__biz=MzI4MTQyMDAxMA==&mid=2247483667&idx=1&sn=60ed79699044ebf44de85ebf61ad633f&chksm=eba8c896dcdf41808c39ac1f208538b18d9a08afd317df3d5363ffedacf1905ef9dd574c4b31&mpshare=1&scene=1&srcid=0302JP1QlAe6X85d4l4xzqbu#rd) \ No newline at end of file diff --git "a/\351\227\256\351\242\230\346\216\222\346\237\245.md" "b/\351\227\256\351\242\230\346\216\222\346\237\245.md" new file mode 100644 index 0000000..60250a6 --- /dev/null +++ "b/\351\227\256\351\242\230\346\216\222\346\237\245.md" @@ -0,0 +1,252 @@ +# 认证要求 +- Troubleshooting 问题排查 10% + - 排查应用失败故障 + - 排查控制层(control panel)故障 + - 排查工作节点(work node)故障 + - 排查网络故障 + +# trouble shooting +## 学会看termination message +容器退出时, 会往容器的/dev/termination-log写终止日志。 +可以通过命令查看这个日志内容: +```shell + kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}" +``` +这个终止日志的路径默认是/dev/termination-log, 但是可以自定义。 比如你的应用退出时会往/tmp/my-log写终止日志。 你希望改变终止日志的路径, 就可以指定terminationMessagePath 的值。 +```yml +apiVersion: v1 +kind: Pod +metadata: + name: msg-path-demo +spec: + containers: + - name: msg-path-demo-container + image: debian + terminationMessagePath: "/tmp/my-log" +``` +> 参考 [官方文档之Determine the Reason for Pod Failure](https://kubernetes.io/docs/tasks/debug-application-cluster/determine-reason-pod-failure/) + + +## 调试Pod, Replication Controller 和 Service +调试一个pod的第一个步骤是查看它的状态。 可以通过命令查看pod的最新的状态和最近的event。 +```shell +$ kubectl describe pods ${POD_NAME} +``` +pod的几种状态及可能原因 +- pending状态 +> 这种情况pod没有被调度成功,一般情况下可能的原因是是资源不足(pod reqeust的的资源大于当前集群所能提供的资源), hostPort冲突 +- waiting 状态 +> pod已被成功调度, 但是不能成功在工作节点上启动, 最常见的原因是不能下载镜像, 需要你做如下检查: 1. 镜像名称是否正确? 2. 是否有push镜像到镜像蹭课 3. 手动运行docker pull 看是否能正常拉取镜像 +- crash状态或者unhealthy状态 +> $ kubectl logs ${POD_NAME} ${CONTAINER_NAME}, 通过日志查看 +> $ kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME} 查看上次crash状态的日志 +> kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN} 在运行中的pod里执行命令 +> 比如$ kubectl exec cassandra -- cat /var/log/cassandra/system.log + +replication controller +> kubectl describe pods + +service +假定别人告诉我们创建了service, 叫hostnames。有个pod要连接这个service时, 报了一个错误 +```shell +u@pod$ wget -qO- hostnames +wget: bad address 'hostname' +``` +接下来就是排障过程: +1. service是否存在? +```shell +$ kubectl get svc hostnames +Error from server (NotFound): services "hostnames" not found +``` +说明service不存在, 赶紧创建一个 +```shell +$ kubectl expose deployment hostnames --port=80 --target-port=9376 +service "hostnames" exposed +``` +重新检查一遍 +```shell +$ kubectl get svc hostnames +NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE +hostnames 10.0.0.226 80/TCP 5s +``` +service已经创建了, 但是服务依然不可用 +2. DNS是否能为解析这个service的名称? +```shell +# 假设service的namespace是default +# 在default namespace的pod里做dns解析 +u@pod$ nslookup hostnames +Server: 10.0.0.10 +Address: 10.0.0.10#53 + +Name: hostnames +Address: 10.0.1.175 + +# 在其它 namespace的pod里做dns解析 +u@pod$ nslookup hostnames.default +Server: 10.0.0.10 +Address: 10.0.0.10#53 + +Name: hostnames.default +Address: 10.0.1.175 + +# 在其它 namespace的pod里做dns解析完整域名,其中cluster.local是你的集群域名, 这个域名根据你创建集群的情况确定, 默认是cluster.local +u@pod$ nslookup hostnames.default.svc.cluster.local +Server: 10.0.0.10 +Address: 10.0.0.10#53 + +Name: hostnames.default.svc.cluster.local +Address: 10.0.1.175 +``` +如果dns能正常解析完整域名,但是不能解析部分域名, 那么需要你检查下kubelet的--cluster-dns和--cluster-domain两个参数的配置 + +如果上面的检查都失败了,接下来可以看看是否DNS能解析kubernetes的service , kubernetes master的service总是存在的 + +3. 检查是否dns中有存在任何的service +```shell +u@pod$ nslookup kubernetes.default +Server: 10.0.0.10 +Address 1: 10.0.0.10 + +Name: kubernetes +Address 1: 10.0.0.1 +``` + +如果上述失败了, 就要检查下dns或者kube-proxy + +4. service的ip是否可以正常工作 +在node上发起访问 +```shell +u@node$ curl 10.0.1.175:80 +hostnames-0uton + +u@node$ curl 10.0.1.175:80 +hostnames-yp2kp + +u@node$ curl 10.0.1.175:80 +hostnames-bvc05 +``` +如果service正常工作, 你会得到正确的响应,如果不能正常工作, 那么需要做一堆检查了。 + +5. service是否正确? +```shell +$ kubectl get service hostnames -o json +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "hostnames", + "namespace": "default", + "selfLink": "/api/v1/namespaces/default/services/hostnames", + "uid": "428c8b6c-24bc-11e5-936d-42010af0a9bc", + "resourceVersion": "347189", + "creationTimestamp": "2015-07-07T15:24:29Z", + "labels": { + "app": "hostnames" + } + }, + "spec": { + "ports": [ + { + "name": "default", + "protocol": "TCP", + "port": 80, + "targetPort": 9376, + "nodePort": 0 + } + ], + "selector": { + "app": "hostnames" + }, + "clusterIP": "10.0.1.175", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} +``` +检查下spec.ports[]里的内容,比如target port是否是你要的应用实例暴露的port, 端口的协议(protocol)是否正确,是TCP, UDP, 还是HTTP + +6. service是否有对应的Endpoint? +```shell +$ kubectl get endpoints hostnames +NAME ENDPOINTS +hostnames 10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376 +``` +如果上述结果为空, 那么要确认下service的spec.selector和pods的metadata.labels是否能对应上 + +7. Pod是否正常工作? +直接访问pod的ip + 端口 +```shell +u@pod$ wget -qO- 10.244.0.5:9376 +hostnames-0uton + +pod $ wget -qO- 10.244.0.6:9376 +hostnames-bvc05 + +u@pod$ wget -qO- 10.244.0.7:9376 +hostnames-yp2kp +``` +如果不能返回正确的结果, 就要用kubectl logs查看pod的日志, 或者使用kubectl exec 进到pod一探究竟 + +8. kube-proxy是否正常工作 +假定你的service正常运行,也有对应的endpoint, pod也正常服务。如果服务还是不能正常访问, 那么就要怀疑kube-proxy是否正常工作了。 +```shell +# 先看下kube-proxy有没有在你的node里正常运行 +u@node$ ps auxw | grep kube-proxy +root 4194 0.4 0.1 101864 17696 ? Sl Jul04 25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2 +# 再看kube-proxy的日志是否正常 +tail /var/log/kube-proxy.log 或者 journalctl -u kube-proxy +# 接着看kube-proxy是否有写入iptables规则 +u@node$ iptables-save | grep hostnames +-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000 +-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376 +-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000 +-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376 +-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000 +-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376 +-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3 +-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ +-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3 +-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR + +正常情况下有1条KUBE-SERVICES规则,每个endpoint会有1~2条KUBE-SVC-(hash)规则, 1个 KUBE-SEP-(hash)规则, 还有若干KUBE-SEP-(hash)的 +``` + +9. 其它问题 +如service没有endpoint, 网络流量没有转发, pod 的ip不能访问自己的service的vip(一般和kubelet的hairpin-mode的设置有关), 请参考官方文档 + +> 参考 [官方文档之Debug Pods and Replication Controllers](https://kubernetes.io/docs/tasks/debug-application-cluster/debug-pod-replication-controller/) +> [官方文档之Debug Services](https://kubernetes.io/docs/tasks/debug-application-cluster/debug-service/) +## 集群故障调试 +1. kubectl get nodes 看有多少node处于ready状态 +2. 查看日志, 使用jounalctl或者tail查看master(kube-scheduler, kube-apiserver, kube-controller-manager), node(kubelet, kube-proxy)的日志 +3. 可能导致集群故障的原因(VM故障, 集群之中或集群和用户之间的网络中断隔离故障,kubernetes的软件崩溃, 持久化存储不可用或数据丢失, 操作错误比如错误配置了kubernetes集群等 ) + +```table +故障 | 现象 | 缓解措施 +Apiserver VM shutdown or apiserver crashing | 1. 不能停止,更新, 启动pod, service, replication controller 2. 原有的pod和service不受影响, 除非它们依赖kubernetes api | 1.主机自动重启 2. 使用高可用架构部署 +Apiserver backing storage lost | 1. apiserver不能启动 2. kubelet不能连接到apiserver 3.在apiserver restart之前, 手动恢复和重建apiserver的状态是必须的 | 1. 在主机上挂载可靠的存储,用于apiserver+etcd 2. 使用高可用架构部署3.定期对apiserver的数据做快照 +安装kubernetes组件的vm宕机 | 因为目前apiserver, controller-manager, scheduler必须部署在一起,如果部署组件的虚机宕机 ,则三个组件会同时故障。未来可能会支持独立部署, 且不保留各自的持久化状态 | 1. 主机自动重启2. 使用高可用架构部署 +个别的node宕机 | 在该node的pod停止运行 | 1. 主机自动重启 2. 使用replication controller和service,而不是单独创建pod 3. 应用设计上允许不可预期的重启 +网络分区故障(network partition) | master和node互相认为对方宕掉 | 无 +kubelet软件错误 | 1. crash掉的kubelet不能在node上启动新的pod, 2. kubelet可能会也可能不会删除pod, 3. 所在的node会被apiserver标记为unhealthy状态 4. replication controller会在别的node启动pod | 1. 使用replication controller和service,而不是单独创建pod 2. 应用设计上允许不可预期的重启 +集群操作错误 | 1. pods,service等对象丢失 2. apiserver的后端存储失联 3. 用户不能读取api 4. 其它 | 1.定期对apiserver的数据做快照 +``` + +## 应用故障调试 +pod的调试 +- pending: 资源不足,或者 启用了hostport导致端口冲突 +- waiting: 检查一下是否有正确的docker镜像名称, 或者仓库里有推送镜像, 可以手动在node上执行一下docker pull image 命令 +- crash / unhealthy: 查看应用的log(kubectl logs ), 或者进入到容器里检查(kubectl exec) +- pod运行但是结果不是我想要的: 删除pod, 用kubectl create --validate -f mypod.yaml重建看看是否有报错, 或者 使用kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml ,和你的yaml做比较,看是否有重大差异 + +replication controller的调试, service的调试见前面的章节(调试Pod, Replicaton Controller, service) +# 常用工具 + +# 常见问题 + +# 参考文献 +- [官方文档之集群管理](https://kubernetes.io/docs/tasks/administer-cluster/cluster-management/) +- [使用Kubernetes需要注意的一些问题(FAQ of k8s)](http://blog.csdn.net/anzhsoft/article/details/51282254) \ No newline at end of file diff --git "a/\351\233\206\347\276\244\347\273\264\346\212\244.md" "b/\351\233\206\347\276\244\347\273\264\346\212\244.md" new file mode 100644 index 0000000..085fa0f --- /dev/null +++ "b/\351\233\206\347\276\244\347\273\264\346\212\244.md" @@ -0,0 +1,24 @@ +# 认证要求 +- Cluster Maintenance 集群维护 11% + - 理解k8s的集群升级过程 + - 促进操作系统的升级 + - 补充备份和还原的方法论 + +# 集群升级和维护 +k8s版本升级: +对于GCE , 升级集群需要删除并重建master, 对于node也是如此 +对应GKE, 集群的master和系统的add-on会自动更新 + +k8s节点维护: +当你重启机器时,kubelet会在机器重启后把原先分配在上面的pod也启动。 但是如果机器重启需要的时间较长,超过了--pod-eviction-timeout指定的时间(默认是5分钟),这时候node controller会把终结这个node上的pod,并进行重新调度。 +相比重启, 更加优雅的做法是: +kubectl cordon 对机器置维护, +kubectl drain 优雅的终结并驱逐pod +kubectl uncordon 解除维护状态 + +> 参考 [官方文档之集群管理](https://kubernetes.io/docs/tasks/administer-cluster/cluster-management/) + +# 常用kubectl命令总结 + +# 参考文献 +- [官方文档之集群管理](https://kubernetes.io/docs/tasks/administer-cluster/cluster-management/) \ No newline at end of file diff --git "a/\351\233\206\347\276\244\351\203\250\347\275\262\345\222\214\351\205\215\347\275\256.md" "b/\351\233\206\347\276\244\351\203\250\347\275\262\345\222\214\351\205\215\347\275\256.md" new file mode 100644 index 0000000..17573bd --- /dev/null +++ "b/\351\233\206\347\276\244\351\203\250\347\275\262\345\222\214\351\205\215\347\275\256.md" @@ -0,0 +1,291 @@ +# 认证要求 +- Installation, Configuration & Validation 安装,配置和验证12% + - 设计一个k8s 集群 + - 安装k8s master 和 nodes + - 配置安全的集群通信 + - 配置高可用的k8s集群 + - 知道如何获取k8s的发行的二进制文件 + - 提供底层的基础措施来部署一个集群 + - 选择一个网络方案 + - 选择你的基础设施配置 + - 在你的集群上配置端对端的测试 + - 分析端对端测试结果 + - 运行节点的端对端测试 + +# Installation, Configuration & Validation 安装,配置和验证 +## 设计一个k8s 集群 +> 参考[一键部署高可用kubernetes集群](https://zhuanlan.zhihu.com/p/26550959) +### 软件版本 +```table +| 组件或系统 | 版本 | 备注 +| Kubernetes | 1.6.0 | 1.6版本支持单集群5000节点, 15万容器(官方数据) | +| Docker | 1.12.3 | 需要系统内核版本3.10以上支持 | +| Etcd | 3.1.5 | Etcd3的性能优于etcd2,k8s1.6版本使用etcd3做为状态存储组件。 | +| Flanneld | 0.7 | backend为vxlan网络, 需要系统内核版本3.7以上 支持 | +| CentOS | 7.2 | 建议系统内核3.10及以上 | +``` +### 机器配置 +> 下面的配置是POC环境的机器配置情况。 实际生产部署可以选择更好的机器,目前没有最优的建议, 可以根据成本预算和使用应用承载量而定。 + + +```table +| 组件 |机器配置 | 备注 +| ETCD | 建议4核CPU, 4G内存及以上配置, 3台 | 可以和k8s master组件共用机器混合部署,如果机器资源充足,建议分开部署 | +| K8S Master | 建议4核CPU, 4G内存及以上配置, 3台 | 同上建议 | +| LoadBalance | 建议4核CPU, 4G内存及以上配置, 2台 | 主备, 注意这个不要和master,node组件混合部署, 影响稳定性和可用性 | +| Node | 4核CPU, 4G内存, 1台以上 | 配置需求与运行的容器数量和应用类型相关 | +``` +### 防火墙策略 +>如果k8s不是在一个扁平的大二层网络里, 如果跨了多个网段, 且网段之间有防火墙隔离, 那么还需要考虑防火墙问题(以下不考虑加密传输的情况下,且使用默认启用的端口, 如果你修改了默认的端口,那么相应的修改防火墙即可) + +```table +| source | destination | port | +| kubelet / kube-proxy | api server | 8080 | +| controller-manager / scheduler | api server | 8080 | +| api server | etcd | 2379 | +| dockerd | docker registry | 5000 | +| flanneld | etcd | 2379 | +| flanneld | flanneld | 8285 | +``` + +### 集群规划 +> 网络和端口规划, 以下针对的是单个k8s集群的情况 + +```table +| 变量 | 注解 | 配置 | 备注 | +| FLANNEL_NET | flannel的网段 | 192.168.0.0/16 | 注意不要和现有的网段规划冲突,另外此处掩码为16, 意味着支持2^(26-16),约1024个node节点 | +| FLANNEL_SUBNETLEN | flannel的子网掩码 | 26 | 掩码26,意味着单个主机可以最多分配2^(32-26) -2 , 约62个容器 | +| SERVICE_CLUSTER_IP_RANGE | service 的 ip 网段 | 10.10.1.0/22 | 假设每个应用占用1个service ip, 则可以支持约2^(32-22) -2 ,约1022个应用部署 | +| NODE_PORT_RANGE | node port的端口范围 | 30000 ~ 32767 | service的node port 可以使用主机上2767个端口 | +``` + +## 安装k8s master 和 nodes +### Master节点 +部署考虑了master组件的高可用, 由三个节点构成一个集群。 +apiserver是无状态的,前端提供负载均衡,暴露vip +controller manager 和 scheduler 是有状态的,需要进行leader elect, 同一时间只能有一个实例对集群信息进行读写。 + +```table +| 组件名称 | 启动参数 | 参数说明| +| api server | --etcd-servers | 以逗号分隔的etcd服务url列表, etcd服务以http://ip:port格式表示 | +| api server | --insecure-bind-address | 绑定不安全的ip地址, 默认且localhost, 设置为0.0.0.0就可以侦听所有网络接口 | +| api server | --insecure-port | 提供非安全认证的监控端口, 默认为8080 | +| api server | --kubelet-port | kubelet侦听的端口 | +| api server | --service-node-port-range | Service的node port 能使用的主机端口范围, 默认为30000 ~ 32767, 包括30000和32767 | +| api server | --allow-privileged | 允许pod允许具有系统特权的容器, 默认值为false | +| api server | --service-cluster-ip-range | service的cluster ip (虚拟ip)池, 这个不能和集群所在物理网络重合 | +| controller manager / scheduler | --master | api server的url地址 | +| controller manager / scheduler | --leader-elect | 设置为true时,表示进行leader选举, 一般用于master的高可用部署, 默认值是false | +| controller manager / scheduler | --leader-elect-lease-duration | leader选举过程中非leader等待选举的时间间隔, 默认是15秒 | +| controller manager / scheduler | --leader-elect-renew-deadline | leader选举过程中在定制leading角色之前再次renew的时间间隔,应小于等于eader-elect-lease-duration, 默认为10秒 | +| controller manager / scheduler | --leader-elect-retry-period | leader选举过程中,获取leader角色和renew之间的等待时间, 默认为2秒 | + + +``` +Tips建议和提示 +> controller manager和scheduler的启动参数一致, 将 --leader-elect 设置为true,其它elect参数保持默认即可。 + +### Node节点 + +```table +| 组件名称 | 启动参数 | 参数说明| +| kubelet | --address | 绑定主机的地址, 默认为0.0.0.0, 表示使用主机上的所有网络接口 | +| kubelet | --port | 进程侦听的端口 | +| kubelet | --api-servers | api server地址列表, 以ip:port 格式表示,以逗号分隔 | +| kubelet | -allow-privileged | 是否允许以特权模式启动容器, 默认是false | +| kubelet | --cluster_dns | 集群内dns服务的ip地址 | +| kubelet | --cluster_domain | 集群内dns服务所用域名 | +| kubelet | --pod_infra_container_image | 用于pod内网络命名空间共享的基础的pause镜像, 默认值为gcr.io/google_containers/pause-amd64:3.0 | +| kube-proxy | --master | api server的url地址 | +| flannel | -etcd-endpoints | 以逗号分隔的etcd服务url列表, etcd服务以http://ip:port格式表示 | +| flannel | -etcd-prefix | etcd的前缀, 默认是/coreos.com/network | +| docker | --insecure-registry | 设置私有仓库url地址 | +| docker | --bip | 绑定的bridge网卡地址 | +| docker | --ip-masq | 启用ip伪装技术,一般用于NAT , 默认为false | +| docker | --mtu | 网络包的大小, 默认为 1450 | + +``` +Tips建议和提示 +> pause镜像默认是从gcr.io上拉取的, 但是由于gfw的缘故, 国内无法正常下载。 可以通过--pod_infra_container_image指定私有仓库或者可以访问的仓库镜像地址,让k8s到这些仓库去下载,而不是从gcr.io +> 如果集群中有的node节点位于非dmz区域, 有的node节点位于dmz网络区域, 那么dmz区的docker启动的时候一定要设置--ip-masq 为true, 同时flanneld启动的时候要指定-public-ip 为nat转换后的ip,否则无法和非dmz区的docker容器正常通信,具体原理涉及flannel和vxlan网络原理,限于篇幅,不在这里赘述 + + +## 配置安全的集群通信 +kubernetes 系统的各组件需要使用 TLS 证书对通信进行加密,本文档使用 CloudFlare 的 PKI 工具集 cfssl 来生成 Certificate Authority (CA) 和其它证书; + +生成的 CA 证书和秘钥文件如下: + +- ca-key.pem +- ca.pem +- kubernetes-key.pem +- kubernetes.pem +- kube-proxy.pem +- kube-proxy-key.pem +- admin.pem +- admin-key.pem +使用证书的组件如下: + +- etcd:使用 ca.pem、kubernetes-key.pem、kubernetes.pem; +- kube-apiserver:使用 ca.pem、kubernetes-key.pem、kubernetes.pem; +- kubelet:使用 ca.pem; +- kube-proxy:使用 ca.pem、kube-proxy-key.pem、kube-proxy.pem; +- kubectl:使用 ca.pem、admin-key.pem、admin.pem; +kube-controller、kube-scheduler 当前需要和 kube-apiserver 部署在同一台机器上且使用非安全端口通信,故不需要证书。 + + +> 参考 https://jimmysong.io/kubernetes-handbook/practice/create-tls-and-secret-key.html + +关于数字证书和CA的扫盲 +◇ 什么是CA? + +CA是Certificate Authority的缩写,也叫“证书授权中心”。类似于现实中的公证处的角色。 + + +◇ 什么是CA证书? + +CA 证书,顾名思义,就是CA颁发的证书。类似于介绍信上公证处的盖章。 + +◇ 什么是证书之间的信任关系? + +在俺的例子里谈到,引入中介后,业务员要同时带两个介绍信。第一个介绍信包含了两个公章,并注明,公章C信任公章A。证书间的信任关系,就和这个类似。就是用一个证书来证明另一个证书是真实可信滴。 + +◇ 什么是证书信任链? + +实际上,证书之间的信任关系,是可以嵌套的。比如,C 信任 A1,A1 信任 A2,A2 信任 A3……这个叫做证书的信任链。只要你信任链上的头一个证书,那后续的证书,都是可以信任滴。 + +◇ 什么是根证书? +“根证书”的洋文叫“root certificate”,专业的解释看“这里”。为了说清楚根证书是咋回事,再来看个稍微复杂点的例子。 +假设 C 证书信任 A 和 B;然后 A 信任 A1 和 A2;B 信任 B1 和 B2。则它们之间,构成如下的一个树形关系(一个倒立的树)。 +  处于最顶上的树根位置的那个证书,就是“根证书”。除了根证书,其它证书都要依靠上一级的证书,来证明自己。那谁来证明“根证书”可靠捏?实际上,根证书自己证明自己是可靠滴(或者换句话说,根证书是不需要被证明滴)。 + +★ 证书有啥用? + +- 验证网站是否可信(针对HTTPS) +- 验证某文件是否可信(是否被篡改) + +> [数字证书及 CA 的扫盲介绍](http://blog.jobbole.com/104919/) + +## 配置高可用的k8s集群 +部署考虑了master组件的高可用, 由三个节点构成一个集群。 +apiserver是无状态的,前端提供负载均衡,暴露vip +controller manager 和 scheduler 是有状态的,需要进行leader elect, 同一时间只能有一个实例对集群信息进行读写。 + +![](./_image/2017-09-16-08-08-46.jpg) + +## 知道如何获取k8s的发行的二进制文件 +二进制文件的获取: +https://github.com/kubernetes/kubernetes/releases/ +## 提供底层的基础设施来部署一个集群 +### 独立方案 +- 使用[minikube](https://kubernetes.io/docs/getting-started-guides/minikube/) +> minikube适用于快速体验和尝鲜的学习环境和开发环境。 它支持配置网络,持久化卷, services, 证书, , dns, nodeport, configmap, ingress等。 需要注意的是minikube不支持依赖cloud的特性,如LoadBalancers, 和需要多节点的特性,比如高级调度策略。 +- 使用[kubeadm]() +> +- 从零部署 + +### 托管方案 +- Google Container Engine +- Azure Container Service +- IBM Blumix Container Service +### 一站式云方案 +- On Google Compute Engine +- On AWS EC2 +- On Azure +- On Alibaba Cloud(阿里云) +- On CentureLink Cloud(世纪互联) +- On IBM Blumix +- On MultiCloud with Stackpoint.io +### 定制方案 +- 定制云方案 +- 企业内网VM +## 选择一个网络方案 +## 选择你的基础设施配置 +# 端到端测试 +## 什么是端对端测试 +端到端测试(E2E)本身是一种专门的技术。端到端测试的概念和过程测试的概念非常相似。端到端测试有时也被称为技术过程(Technical Process)或是系统集成测试(System Integration Test),它其实就是对多个系统进行系统测试。在端到端测试中,业务流程是最重要的。 +端到端测试中可能会发现一些"惊喜"。 +  -数据不一致(在不同的系统中出现的同一个人具有不同的地址)。 +  -错误(面向用户的)的数据解释(8-9-10究竟表示哪个日期?)。 +  -数据在一种情况下是强制的,而在另一种情况下却不是。 +  -定时和顺序问题(错误的消息顺序处理)。 +对于分布式系统, 通过了单元测试和集成测试, 然后又可能出现不可预期的问题, 因此端对端测试对分布式系统的测试是必要的。 + +## 在k8s集群上配置和运行端对端测试 +构建kubernetes, 启动集群, 运行测试, 拆除 +> go run hack/e2e.go -- -v --build --up --test --down + +构建代码 +> go run hack/e2e.go -- -v --build + +创建一个新集群, 会先删除已经存在的集群 +> go run hack/e2e.go -- -v --up + +运行所有的测试 +> go run hack/e2e.go -- -v --test + +在本地集群上运行特性性能测试, 通过--provider=local来指定本地集群 +> go run hack/e2e.go -- -v --test --test_args="--ginkgo.focus=\[Feature:Performance\]" --provider=local + +跳过匹配到Pods.*env的测试 +> go run hack/e2e.go -- -v --test --test_args="--ginkgo.skip=Pods.*env" + +并行的跑测试, 但是跳过那些需要串行运行的测试 +> GINKGO_PARALLEL=y go run hack/e2e.go -- -v --test --test_args="--ginkgo.skip=\[Serial\]" + +并行的跑测试, 但是跳过那些需要串行运行的测试, 如果测试失败, 保留namspace +> GINKGO_PARALLEL=y go run hack/e2e.go -- -v --test --test_args="--ginkgo.skip=\[Serial\] --delete-namespace-on-failure=false" + +调用kubectl命令, 在测试失败时查看事件和状态是很有用 +> go run hack/e2e.go -- -v -ctl='get events' +go run hack/e2e.go -- -v -ctl='delete pod foobar' + +拆除环境 +> go run hack/e2e.go -- -v --down + + +kubernetes的端对端测试还可以指定特定的kubernetes版本进行测试,或者使用现有集群测试 +> 参考 - [kubernetes中的端对端测试](https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-tests.md) + +## 节点的端对端测试 +Node e2e仅测试Kubelet的相关功能,可以在本地或者集群中测试 + +准备条件: 需要在机器上安装etcd, ginkgo + +开始测试: make test-e2e-node, 这个命令会执行下面的这些动作 +- 请求sudo权限 +- 编译kubernetes代码 +- 预拉取测试需要用到的docker镜像 +- 启动etcd的一个本地实例 +- 启动apiserver的一个本地实例 +- 启动kubelet的一个本地实例 +- 使用本地的进程运行测试 +- 输出结果到标准输出 +- 停止kubelet, apiserver, etcd实例 + +## 分析端对端测试结果 + + +# 单机部署 +创建Kubernetes cluster(单机版)最简单的方法是minikube: 支持mac, linux , windows。 +具体方式请参考: https://github.com/kubernetes/minikube +中文安装指引,可以参考以下博文: +- https://feisky.gitbooks.io/kubernetes/deploy/single.html + +# 高可用方案 +# 部署常见的坑 +# 资源及工具列表 +# 参考文献 +- [ Kubernetes概念介绍和v1版本部署过程](http://blog.csdn.net/qq1010885678/article/details/48719923) +- [kubernetes 1.6.0 高可靠集群部署](https://addops.cn/post/kubernetes-deployment.html) +- [Kubernetes高可用Master节点安装](https://www.kubernetes.org.cn/1865.html) +- [Kubernetes集群安装文档-v1.6版本](https://www.kubernetes.org.cn/1870.html) +- [一键部署kubernetes 1.6高可用集群](https://zhuanlan.zhihu.com/p/26550959) +- [和我一步步部署 kubernetes 集群](https://github.com/opsnull/follow-me-install-kubernetes-cluster) +- [Kubernetes1.6集群部署完全指南 ——二进制文件部署开启TLS基于CentOS7发布 - Jimmy Song](http://rootsongjc.github.io/projects/kubernetes-installation-document/) +- [ Kubernetes用户指南(二)--部署组合型的应用、连接应用到网络中](http://blog.csdn.net/qq1010885678/article/details/49026825) +- [Kubernetes用户指南(三)--在生产环境中使用Pod来工作、管理部署](http://blog.csdn.net/qq1010885678/article/details/49156557) +- [kubernetes官方指南](http://kubernetes.io/docs/) +- [Sextant一小步,Kubernetes一大步!](http://mp.weixin.qq.com/s?src=3×tamp=1473267136&ver=1&signature=4olKSipUP3ysjTJnJPgkfFH7b*bhsfxVRCTsRoypeKyP6iv-NLO8ZGv7GQv4vYmiLdyoxh1T08sHs03B8EDaqoz8KH6dVw46bsPH9CFWAgZrhDfj3colGXwWoRubIVgAksvVK0QUuC6etjTt-E5qRGkYm5zxwksfridilKqrEr0=) +- [Kubernetes的企业部署目标](http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649693898&idx=1&sn=3c2b6ab8a66381d1ec470e4b781c4fb0&chksm=889321a9bfe4a8bf7c89be683499aca039135100d9cccb12a62ac9045a620c2e05bdead365db&mpshare=1&scene=1&srcid=04260mmcz8dt53rEXQzc0WIQ#rd) +- [在阿里云上部署生产级别Kubernetes集群](http://mp.weixin.qq.com/s?__biz=MzI4MTQyMDAxMA==&mid=2247483667&idx=1&sn=60ed79699044ebf44de85ebf61ad633f&chksm=eba8c896dcdf41808c39ac1f208538b18d9a08afd317df3d5363ffedacf1905ef9dd574c4b31&mpshare=1&scene=1&srcid=0302JP1QlAe6X85d4l4xzqbu#rd) +- [kubernetes中的端对端测试](https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-tests.md) \ No newline at end of file