我们现在面临的问题,就是如何实际的利用技术来容器化这些应用

我们的应用可能是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组件之间,有什么建立连接或者调用的方式?

发表评论

邮箱地址不会被公开。 必填项已用*标注