我们现在面临的问题,就是如何实际的利用技术来容器化这些应用
我们的应用可能是Java web和mysql的组合,可能是Cassadra的分布式系统,使用容器将后者运行起来是没有用的
我们要处理不同容器之间的编排问题,哪些Cassandra容器是主,哪些是从,主从之间的界限
如何彼此发现进行通信,Cassdara容器的持久化
我们反复强调kubernetes项目的主要原因,这个项目表现的容器化的表达能力,具有独有的先进性和完备性,如何处理复杂编排的问题
那么我们先从如何部署kubernetes来说起,Kubernetes作为一个Golang的项目,省去了很多其他语言需要先安装语言的麻烦,但是我们还是需要为不同的k8s模块,编写配置文件,配置启动脚本等
对于有实力的厂商,尝试使用SaltStack Ansible运维工具来自动化的执行部署
不过,即时这样,部署的过程还是比较的繁琐,因为SaltStack这种专业运维的工具,学习成本较高
直到kubeadm的出现
可以利用这个工具,直接两个指令部署一个k8s的集群
创建一个Master节点
kubeadm init
将一个Node节点加入到当前集群
kubeadm join <Master的节点IP和端口>
那么,我们先说下kubeadm的工作原理
kubernetes的架构和其组件,再部署的时候,每一个组件都是需要被执行的,单独的二进制组件,SlatStack这样的运维工具,就是将不同的二进制文件传到指定的机器汇总,然后编写控制脚本来进行启停
那么,既然都是容器化了,如何不考虑容器部署Kubernetes呢?
给不同的kubernetes组件来分别做容器镜像,最后在每个宿主机上使用docker run来启动不同的组件容器,部署不就完成了?
但是,这会带来一个新的问题,如何去容器化kubelet,kubelet是kubernetes项目用来操作Docker父容器运行时的核心组件,但是Kubernetes作为一个管理平台,需要配置容器网络,容器的数据卷,这都需要操作宿主机
如果kubelet在一个容器内,那么操作宿主机会很麻烦,对于网络配置还好,可以利用host network模式来共享主机的网络栈,但是,让kubelet隔着容器的Mount Namespace和文件系统,操作宿主机的文件系统,有点困难的
比如挂载一个NFS,kubelet如何去帮助一个容器去挂载呢?kubelet是运行在容器内的,这就说明要做的这个mount -F nfs命令,是在一个单独的Mount Namespace中,不能传播到宿主机中
对于这个问题,可以使用setns()系统调用,在宿主机的Mount Namespace中执行这些挂载,但是还是不如人意
所以kubeadm采用的方式是一种折中的方案
将kubelet运行在宿主机上,将其他的组件利用容器部署其他的kubernetes组件
这样,我们使用kubeadm的第一步,在机器上手动安装kubeadm kubelet kubectl 三个二进制文件
当然,因为准备好了对应的安装包,所以只需要
apt-get install kubeadm
然后就可以使用kubeadm init 来部署Master节点
kubeadm init的工作流程
kubeadm 指令执行的过程中,会进行检查工作,确认这个设备可以部署kubernetes,这一步叫Prefight Checks,可以省去很多后续的麻烦
检查的项目包括但不限于
Linux 内核版本是否是3.10
Linux Cgroups是否是可用的
机器的hostname是否标准,在k8s项目里,机器的名字以及一切在Etcd中的API对象,都是标准的DNS命名
用户的kubeadm和kubelet版本是否匹配?
是不是已经安装了kubernetes的二进制文件
kubernetes的工作端口10250/10251/10252是不是已经被占用了
ip mount的指令是否可用
Docker是否已经安装
验证通过了之后,kubeadm做的,就是生成各种对外服务的证书和对应的工作目录
kubernetes对外提供服务的时候,除非开启不安全模式,不然后需要通过HTTPS才能访问kube-apisever,不然就需要为kubernetes配置好证书文件
kubeadm为kubernetes项目生成的证书文件都在Master节点的/etc/kubernetes/pki目录下,在这个目录下,有着对应的ca.crt和ca.key
除此,用户在使用kubectl获取容器日志等streaming操作时候,也需要向kube-apiserver发起请求,也需要是安全的,kubeadm生成的是apiserver-kubelet-client.crt文件,对应的私钥apisever-kubelet-client.key
除此之外,kubernetes集群中还有Aggregate APIServer等特性,需要用到专门的证书,这里就不列举了,或者可以考虑将证书直接拷贝到如下目录,跳过生成的流程,交给用户去直接处理
证书生成后,kubeadm会为其他的组件生成kube-apiserver所需要的配置文件
放在了/etc/kubernetes/xxx.conf
ls /etc/kubernetes/
admin.conf controller-manager.conf kubelet.conf scheduler.conf
这些文件中,记录这个Master节点的服务器地址,监听端口,证书目录等信息,对应客户端scheduler,kubelet等,可以直接加载对应的文件,来和kube-apiserver建立连接
然后kubeadm会为Master组件生成Pod配置文件,在整个Master节点上,有着kube-apiserver
kube-controller-manager kube-scheduler三个组件,都会以Pod的方式部署
但是kubeadm如何启动这些特定容器呢?
这些kubernetes中,有一种特殊的容器启动方式叫做Static Pod,可以将要部署的Pod的YAML文件放在一个指定的目录上,当这个机器上的kubelet启动的时候,会自动检查这个目录,加载所有的Pod YAML文件,然后启动
从这点看出来,kubelet的地位非常高,在设计上就是一个完全独立的组件,而其他的Master组件,就好比是辅助性的系统容器
在kubeadm中,Master组件的YAML文件在/etc/kubernetes/manifests路径下,比如kube-apiserver.yaml
具体的yaml如下
apiVersion: v1
kind: Pod metadata: annotations: scheduler.alpha.kubernetes.io/critical-pod: “” creationTimestamp: null labels: component: kube-apiserver tier: control-plane name: kube-apiserver namespace: kube-system spec: containers: – command: – kube-apiserver – –authorization-mode=Node,RBAC – –runtime-config=api/all=true – –advertise-address=10.168.0.2 … – –tls-cert-file=/etc/kubernetes/pki/apiserver.crt – –tls-private-key-file=/etc/kubernetes/pki/apiserver.key image: k8s.gcr.io/kube-apiserver-amd64:v1.11.1 imagePullPolicy: IfNotPresent livenessProbe: … name: kube-apiserver resources: requests: cpu: 250m volumeMounts: – mountPath: /usr/share/ca-certificates name: usr-share-ca-certificates readOnly: true … hostNetwork: true priorityClassName: system-cluster-critical volumes: – hostPath: path: /etc/ca-certificates type: DirectoryOrCreate name: etc-ca-certificates … |
在这个文件中
定义了一个容器,使用的镜像是k8s.gcr.io/kube-apiserver-amd64:v1.11.1
是Kubernetes官方维护的一个组件镜像
然后启动的command是kuber-apiserver–authorization-mode=Node,RBAC…
这些是指定了启动项
然后kubeadm还会生成一个Etcd的Pod YAML文件,通过相同的Static Pod方式启动Etcd,最后Master组件的Pod YAML文件如下所示
$ ls /etc/kubernetes/manifests/
etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml
这些YAML文件创建完成了
kubelet会开始创建YAML对应的Pod,Master相关组件的容器
Master启动开始了,kubeadm会检查 localhost:6443/healthz这个Master组件的检查URL,等待完全的运行完成
然后kubeadm会为集群生成一个bootstrap token,在后面,只要有这个token的节点,就可以kubeadm join加入这个集群中
token生成了,kubeadm会将ca.crt等Master节点的重要信息,通过ConfigMap的方式保存在Etcd
供后续的Node节点使用,
最后一步,就是安装默认的插件,kubernetes默认需要kube-proxy和DNS两个插件,分别需要提供整个集群的服务发现和DNS功能,也就是两个容器镜像,也就是创建两个Pod就可以了
kubeadm join的工作流程
init在生成了token之后,就可以在任何一台安装了kubelet和kubeadm的机器上执行kubeadm join了
任何一台机器想要成为kubernetes集群中一个节点,就必须在集群的kube-apiserver中注册,但是需要跟apiserver打交道,就需要获取到对应的证书文件CA文件,可是,为了能够一键安装,不能去手动拷贝证书
那么需要先获取到ConfigMap中的CA证书,也是先去访问一次kube-apisever,而bootstrap token,就是这个安全验证的角色
这样先发起一次请求,获取到了kube-apiserver的端口和证书,kubelet就可以以安全模式连接到apiserver上了,这样一个新的节点就完成了
最后就是
如何利用kubeadm来定制集群组件参数
指定kube-apiserver的启动参数
可以在kubeadmin init部署Master节点的时候,使用下面的指令
kubeadm init — config kubeadm.yaml
我们就可以给kubeadm提供一个YAML的文件,内容如下
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration kubernetesVersion: v1.11.0 api: advertiseAddress: 192.168.0.102 bindPort: 6443 … etcd: local: dataDir: /var/lib/etcd image: “” imageRepository: k8s.gcr.io kubeProxy: config: bindAddress: 0.0.0.0 … kubeletConfiguration: baseConfig: address: 0.0.0.0 … networking: dnsDomain: cluster.local podSubnet: “” serviceSubnet: 10.96.0.0/12 nodeRegistration: criSocket: /var/run/dockershim.sock … |
通过这个部署参数配置文件,就可以在这个文件中指定部署参数了,比如,kube-apiserver的参数,就需要在这个文件上加上这样一段信息
…
apiServerExtraArgs: advertise-address: 192.168.0.103 anonymous-auth: false enable-admission-plugins: AlwaysPullImages,DefaultStorageClass audit-log-path: /home/johndoe/audit.log |
这样,kubeadm就会进行替换了
当然YAML提供的可配置项还有很多,比如,可以修改kubelet和kube-proxy的配置,修改Kubernetes基础镜像的URL,因为国内不好访问基本的镜像地址,指定证书文件等
本次中,我们说了kubeadm这个部署工具的工作原理和使用方法
kubeadm的设计很简洁,而且很大的程度上重用了k8s已有的功能,这样,就有一种原生的感觉,一点都不会突兀
而kubeadm的源码,就在kubernetes/cmd/kubeadm目录下,是k8s的一部分
但是,现在kubeadm最欠缺的是一个部署高可用的kubernetes集群.现在,还是无法一键部署一个高可用的集群
1.在Linxu上为类似Kube-apiserver的Web Server制作证书,有什么工具
2.基于前面的K8S的架构,各个K8S组件之间,有什么建立连接或者调用的方式?