想不明白,什么情况才用得上这玩意。
当然,我说的不是 Docker 或 Kubernetes 的使用,而是「Kubernetes 服务端架设」。
本来学习这个项目,是为了公司间合作创业,合建机房,自建私有容器云。可惜近年来行情如此,看来是再也不会有机会。而且 Kubernetes 官方的 kubeadm 也已经开发相当长的一段时间了,上次关注还都是 all alpha,现在部分功能的成熟程度已经是 beta 甚至是 GA 了。
把学习成果总结出来,做个归档,从此可能再不过问了。
目录导航
适用版本
文档适用于版本:zeronokubernetes_package_201902241606
前言
Docker 的诞生大幅的降低了服务端部署的难度和成本,从项目打包到服务上线,都将开发人员从复杂且危险的手工维护解脱出来,说简单点,门口负责升降栏杆的大爷点一下鼠标,新版本就能上线,和比刷卡开门还容易。
而 Kubernetes 的存在则大幅度的降低了集群式服务端的部署,从往常很难想象的集群开发,转变为只要改改配置文件就能简单的轻易横向扩展。虽然对老大爷困难了一点,但是在难度上,将一种不可能变为了可能。
那么有两个疑问:什么样的需求,才会用到「Kubernetes 服务端架设」?什么样的硬件,才能提供「Kubernetes 服务」?
是这样的需求吗?
- 拥有几十亿的注册用户?
- 秒活用户几百万?
是这样的场景吗?
- 买一台超高配的服务器(约:128核,512G内存,1TB 纯 SSD RAID),虚拟出 48 台虚拟机,再在上面搭建集群
- 在阿里云上租上 10 台 ECS,再建立私有网络,再在上面搭建集群
我觉得能干出上面两件事的公司,脑子都进过水之后又被门夹了。建议去太空舱里睡上天,嘣,啪——啾啾啾啾,再涨一个脑袋比较好。科技的力量啊。
环境准备
首先 Kubernetes 虽然已经正式产品化非常久了,不论是原创方谷歌云,还是抄袭王阿里云、山寨王腾讯云、拿来主义华为云,甚至是垄断王微软云,他们都提供 Kubernetes 服务。然而 Kubernetes 仍然处于高速开发状态,不论是技术实现还是专业名词还是配置文件都几乎是日新月异。前老板买了一本半年前刚出版的 Kubernetes 相关书籍,翻开一看,至少有半斤都是废纸了。
所以最新技术都请优先参考 Google Kubernetes 的官方文档。
本文将基于以下环境进行讲解:
- Ubuntu-18.04.2-server-amd64
- Kubernetes: v1.11.1
- etcd: v3.3.5
- flanneld: v0.10.0
- Docker: 18.03.0-ce
硬件环境,有台服务器是最好。不过如果只是为了学习的话,其实只要本地 PC 配置高一些就好,16G 内存即可。装 4 个虚拟机,每个主机 30G 硬盘,2G 内存即可。
准备
开始学习并假设 Kubernetes 之前,请先完成以下环境的准备
- Ubuntu
- Docker
- 必要的偷听敌台之法
注意: 默认路由一定要配置 ,别以为由于是在内网操作,不跨网段,就不设置默认路由了。由于 iptables 在此起非常关键的作用,但很多流量在逻辑上是跨网段,如果没有默认路由,很多流量就会还没走到 iptables,就被系统给拒绝了。所以一定要配置默认路由。
基本架构
组件解释
Kubernetes 是干啥的我就不讲了。
etcd 是负责配置文件同步的。
flanneld 是负责私有网络的。
说白了,Kubernetes 很多事情都不负责,都是由其他开源软件来做,也就是说,除了使用 etcd 和 flanneld,也可以选择其他相同功能软件进行。反观来,这也意味着学习成本不仅仅是 Kubernetes,还包括其他软件。
kube-apiserver,提供 API 接口,可以理解为负责接收控制请求的
kube-controller-manager,运行控制器,可以理解为控制 Kubernetes 集群的
kubectl,负责控制的,多数状况下我们需要调用此命令来控制 Kubernetes
kuberlet,负责干活的
kube-proxy,负责将容器中的服务抽象出来的
kube-scheduler,调度器,简单来讲就是分配 Pod 的
不需要完全理解这些东西,除非你打算研究 Kubernetes 的开发。
名词解释
node,集群中的物理节点,可以理解为一台主机。当然,我们的试验中都是虚拟机。一个集群中一般存在很多 node 。
pod,集群中的虚拟节点,简单理解的话,其实就是 「一个 docker 容器」。一个集群中真正负责给用户提供功能服务的就是这些 pod。
deployment,部署 pod 用的。
daemonset,同样是部署 pod 用的。
deployment 与 daemonset 的区别。deployment 对部署在哪个 node 上不关心,只关心 pod。daemonset 在所有(或指定的)node 上运行,一个 node 上只运行一个 pod。这也就意味着,使用 deployment 部署给用户提供服务,使用 daemonset 部署用于给 Kubernetes 服务的服务,比如监控和负载均衡。
svc,全称 service,负责将一组相同的 pod 提供的服务进行抽象。
traefik,Kubernetes-ingress 为 Kubernetes 存在的负载均衡场景。
由 deployment 部署的一组 Pod,他们都提供相应的服务。在任意 node 上,都可以通过 pod-ip 进行访问。然而 pod-ip 是动态生成的,且每个 pod 都有自己的 pod-ip,不方便调用。service 将这些 pod-ip 抽象为统一的 CLUSTER-IP。注意 pod 的 pod-ip 和 service 的 CLUSTER-IP 都不是真实存在的 IP,只是由 iptables 中转出来的,所以只在 node 上可以直接访问,离对外提供服务还有一段距离。
traefik 则可以把所有跑着 pod 的 node 的 service 汇总为统一一个对外服务。我们从外部发起的请求,首先由 traefik 接收,再尤其进行负载均衡,将流量转发到 node 上,再进入 node 上的 service,最终进入 pod。
的确是一个很复杂的流程。
看张图解释:
经过 traefik 之后,就可以通过访问任何一个 node 上对应的端口,访问 pod 提供的服务。当然,只指定一个 node 作为对外服务的话,会出现单点故障,所以最外层还需要一层负载均衡才可以,不过这就不是 Kubernetes 要负责的事情了。
实战架设
我已经完成了一套可以简单架设的脚本。脚本包含大量注释,适用于初学者进行学习。接下来也将基于这些脚本进行实践。具体都做了啥,看脚本就成了。
下载地址和源码链接在文章末尾。
下载解压拷贝
首先解压压缩包,之后修改 list-master.list
和 list-node.list
。请保证 master 只有一台,node 至少三台。
之后执行 s0-deploy-to-master.sh
,将所需文件复制到 master 。
Master 节点上
登录到 master,进入 /root/kubernetes/
,执行 s1-ssh-nopasswd-copy.sh
,将创建免密登录密钥,并复制到所有 node 节点上,这样接下来所有远程执行命令都不需要再输入密钥了。
执行 s2-sync-scripts.sh
,将所需文件部署到 node。
执行 mastery.sh
,脚本将在 master 和所有 node 上一次执行 x01.sh
至 x07.sh
脚本(部分脚本只在 master 上或 node 上执行)。
执行完成后,Kubernetes 集群就创建好了。
很方便吧。
当然,还是需要简单描述下这些脚本都执行了啥。
脚本简述
x01.sh 至 x07.sh
这些脚本只是引用了其他脚本。
00.全局环境变量
00-0-env-global.sh,所有全局变量都保存于此文件。其他文件均使用 source 引用此文件中的变量。
01.二进制文件和镜像文件部署
01-1-env-setup.sh,负责集群上二进制文件的安装,Docker.service 的更新,并将 Kubernetes 可执行文件添加进 .bashrc 的 $PATH。
注:$PATH 只写入文件,不立即生效。想要生效就得触发一次 .bashrc。很多脚本写的不是绝对路径,所以在 $PATH 未生效之前可能会执行失败。
01-2-image-load.sh,导入必要的 Docker 镜像文件。与 Docker 不同的是,Kubernetes 默认使用谷歌的镜像仓库,这会产生什么问题你懂的。所以我在打包时已经提前引入的所需的镜像文件,这样即使在无网络环境下也可能部署服务器,用于学习。
02.证书CA文件
Kuberentes 很多地方都使用 HTTPS 双向认证。虽然使用 Token 是未来趋势,不过至少现在还做不完全。所以这步得做。
HTTPS 证书靠 cloudflare 提供的工具就能做,这一步只做CA文件,后面每个会使用证书的工具都会生成对应的证书。
证书CA文件只需要生成一份就行,本次只需要在 Master 上运行。
03.etcd 集群创建
etcd 是 Kubernetes 的后端存储。etcd 集群独立于 Kubernetes。
04.kubectl 部署
本步骤生成并部署 kubeconfig,给 kubectl 用。
kubectl 是负责控制 Kubernetes 的命令。本项目为了简单,在所有节点上都安装了 kubectl,方便控制。也就是说,你可以在任何一台机器上,不论是 master 还是 node,都可以执行 kubectl。
05.flanneld
Flannel 是一个可以用于 Kubernetes 的 overlay 网络提供者。
06.kube-apiserver 和 kube-controller-manager 和 kube-scheduler
这些名词都已经讲过了。
本步骤只在 Master 安装 kube-apiserver,kube-controller-manager,kube-scheduler-systemd”
07.kubelet
kubelet 是真正干活的。
本步骤是在节点安装 kubelet、kube-proxy。
至此,Kubernetes 服务器的基本功能就安装完了。
集群功能验证
my-php-test
my-php-test 是我制作的一个包含 Apache 和 PHP 的测试用镜像,里面只包含一个 index2.php 文件。index2.php 可以用来检测服务器的部分信息。
注:my-php-test 项目中包含一个 MYSQL 连接,默认地址是 127.0.1.1,是 pod 自身。这个连接是肯定会失败的,会报错 Failed to connect to MySQL: (2002) Connection refused。之所以要这么做,是为了展示 deployment 配置文件中的环境变量。如果你有可用的 MYSQL Server,可以修改 deployment 配置文件,测试连接。
本文只着重于对 Kubernetes 的服务端建设。对于 Kubernetes 的使用,请参考其它文档。
安装 my-php-test
首先在 Master 上执行 ./t1.sh
,在所有 node 上导入镜像 php-www-data_20180717170240。
进入 my-php-test 目录,执行 apply-my-php-test.sh
,my-php-test 就可以部署完成。
验证
首先在节点上执行 kubectl get pods -o wide
查看各 pod 的信息。之后在节点上访问 pod-ip,查看访问效果
在节点上可以直接访问 pod。当然,再次强调下,pod-ip 并不存在于网卡之上,也不存在于集群上任何一个物理位置。之所以可以访问,都是 iptables 的功劳。
接下来执行 kubectl get svc
查看 service 的信息,之后在节点上访问 CLUSTER-IP,查看访问效果
在节点上同样可以直接访问 service 。同样 CLUSTER-IP 并不存在于网卡之上,也不存在于集群上任何一个物理位置。这同样是 iptables 的功劳。
到这里,Kubernetes 集群功能就算是能用了。
试试直接访问 node-ip ,可以发现是不能直接访问的。
traefik
就如同我前文说的一样,kubernetes 集群是架好了,但是从外网是看不到 pod-ip 和 CLUSTER-IP 。不可以每次都依靠在外部主机上以写 iptables 或 静态路由的方式来将流量引入 kubernetes 集群,因为 Kubernetes 集群生成的 pod-ip 和 CLUSTER-IP 都是动态的。
所有可以确定的东西,除了配置文件,就是 Node-IP 了。配置文件是为了部署我们的产品应用而存在的,所以应专注于应用的配置。
所以按理来讲,直接访问 Node-IP 才更符合使用习惯。
traefik 正是做这个的。
严格来讲,本步骤是将 traefik 作为 Kubernetes Ingress Controller 使用。
traefik 的安装,已经在本文中 Kubernetes 服务器安装过程中完成了,所以我们这里只需要使用即可。
进入 traefik 目录,执行 traefik-test.sh 即可。
traefik 当然是要以 daemonset 的方式执行,而且由于这玩意的意义不一样,所以还要有不同的安全措施。具体细节请参考 traefik 的官方文档。
执行 ./get-namespace-kube-system.sh
检查 traefik 的运行状态
执行 ./get-ingress.sh
检查 ingress 状态
从可以访问集群的任意位置,访问 noded-ip。
好了,能用了。
从外部访问
直接将请求流量引入到单个 Node 是不好的,别光说单点故障,动态迁移,后期维护,以及安全性,都是问题。
有个最为简单的方案,如果是自建机房的话,在网络最外层,是必须买硬件防火墙的,可以将请求负载均衡到所有节点上。如果防火墙没有这个功能,则最好再自建负载均衡服务器,这方面的方案非常多,就不介绍了。
出口负载均衡或者出口防火墙如果故障了,那就是活该断网。
「为什么不插网线不连无线,就不能上网呢?」——某产品经理
实践建议
目前的互联网服务架构,一般都是以:「应用 + 数据库 + 文件存储」来实现的。
如果抛开集群,则不仅仅是应用,数据库和存储都可以使用 Docker 来部署。即使不使用容器进行存储,Docker 也支持卷存储甚至是块存储。不考虑集群概念的话,在单机模式,这的确是一个 「易用性高,维护易,成本低」 的方案,值得鼓励,值得赞扬。
然而引入集群之后,一切都变了。横向扩展或紧缩是集群最关注的问题之一。
存储
我们首先讨论存储。如果存储使用传统的卷存储,那么要面临的问题将极为棘手:
如果我们将同一个卷挂载到所有 pod 上?
- 如何同时挂在同一个卷? (最可怕的一点,挂载出错可能会导致整个卷受损)
- 文件上锁怎么办?
- 同时写同一个文件怎么办?
如果所有 pod 都各自使用自己的卷?
- 文件同步怎么办?
- 同时写同一个文件怎么办?
- 增减 Pod 时怎么办?
这些问题都不是很好解决的问题,真要认真考虑的话,就要大幅修改我们自己开发的软件。要废这么多精力,都可以自己开发一套自用的集群了,还用什么 Kubernetes!这怎么成了 新技术还没有旧技术好用。
「不要更新了,老子学不动了」——中国开发者
Kubernetes 确确实实的将集群搭建大幅度降低了门槛,不过在那之前,也是有不少人直到现在依旧骂着 Docker 垃圾,容器难用。
如果使用一个死思维,比如建立集群必须重写代码以适应所有要调用的资源,那 Kubernetes 就是负担。
动动脑子,可以解决文件上锁,可以解决同时写同一文件,方案有得时,不需要挂载,甚至都不关心你集群的存储也就在那站着。
对象存储,就是一个既简单又有效的方案。将所有的文件存储都使用 对象存储 来完成,上面说的所有问题就都不是问题了。
当然,你得额外准备对象存储服务器,或者买对象存储服务,或者自己买存储服务器自己搭建对象存储。
数据库
说完存储再说数据库。大多情况下我们以 MYSQL 举例。单机情况下用 Docker 跑个 MYSQL 把数据存在卷里面或者容器卷里面,那么集群怎么做?
首先逆转下思维,数据库也是一种应用,那么他的集群是什么样子?「应用 + 数据库(他自己就是数据库) + 文件存储」,我们前文已经说明了,传统思维行不通,而数据库也是没办法使用对象存储的。
那么难道你要自己开发数据库?(你咋不上天呢)
或者自己照着野生教程从头搭建复杂而且难以维护的容器高可用数据库?(还不闲折腾?)
为什么不直接使用分布式数据库呢?比如 MySQL Cluster 或 Percona XtraDB Cluster 或 MariaDB Galera Cluster,现成的
「为什么不问问神奇海螺呢?」
实践方案建议
当然了,还有很多可选方案,但对于一般开发者来讲,降低学习难度和维护成本是第一目的,所以:
- 服务应用采用容器
- 数据库采用现成的分布式数据库方案
- 文件存储采用现成的对象存储
当然,你要是真打算自己做文件同步和数据库同步,就是摆明了要做 技术流氓,要跟公司做 技术绑架,就看是你先把公司耗死,还是公司资金链先断裂。反正都是死路一条,现在去工商局排队都能排一天呢。
已知问题
- etcd 和 flanneld
没搞明白到底在 master 上用不用装这俩,没搞明白。
- 重启后可能失败
kube-apiserver 在重启之后有时候起不来,手动可以重启。
- kubectl get csr 没输出
不知道为啥。
- 物理节点增删
完全没测。
总结
这个只是个用于学习理解的项目,安全性以及硬件的横向扩展都没有考虑,所以不适合在生产环境下使用。
这个项目的存在意义:为没有 Kubernetes 环境的开发者提供学习环境。
另外文章标题是 neta 自 《从零开始的魔法书》,别理解错了。
链接
- GitHub: https://github.com/catscarlet/zeronokubernetes 不包含二进制文件
- MEGA: https://mega.nz/#!TktwlarQ 密码: pgvKZxboQ6BxZbmifrZdfsGNw9r1_DBvwV765r37pBU
- 腾讯微云: https://share.weiyun.com/5kKHUzg 密码:zerono
1 comment
响石潭
2019 年 3 月 3 日 在 上午 8:10 (UTC 8) Link to this comment
Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0
学习