TOC

容器编排

    整个k8s它的控制平面,有三个核心组件第一个是API Server,它部署完成之后默认监听在本机的6443端口,而API Server默认情况下,要做客户端双向认证,意思就是说不是直接类似传统的http请求就你直接访问到的,这里的API Server是做双向认证的,API Server不但会向客户端发送它的证书,它也要求客户端发送客户端的证书,而且必须是API Server自身信任的CA所颁发的证书,才能够获得API Server的认可,而这个CA通常是我们的在部署Kubernetes的时候默认自动生成的,它在 /etc/kubernetes/pki/ca.crt目录下,这是私有CA的CA的证书,而/etc/kubernetes/admin.conf文件中就持有一个CA所颁发的客户端证书,这也就是为什么我们必须复制这个文件,才能让kubectl接入API Server的关键因素之一,任何人想要接入Kubernetes集群请求创建pod等资源时,没有其他接口,之能通过API Server来进行,而且还必须有证书;
    因此我们使用kubectl命令就可以向Kubernetes集群请求创建Pod资源,而创建Pod由我们的Sch'eduler负责调度给某一节点运行,而调度完成以后由Controller来监控,如果出现故障Controller可以进行冗余扩展缩容等操作,确保精确有指定数量的Pod资源属于运行状态,当然我们创建好Controller由Controller创建Pod以后还是不够的,毕竟客户端去访问Pod,所以得通过Service来完成,我们还需要手动去创建它;
    因此,在Kubernetes最重要的几个组件:
        Pod、Pod Controller、Service
    对于Pod创建有两种方式第一直接使用Pod创建,这种创建方式没有关联到Pod Controller;
    第二种方式就是通过Pod Controller来创建,Pod Controller是一个统称,Pod Controller有多种类型,其中最常用的是Deployment,Deployment是一个控制器的类型,我们需要将这个类型的属性赋值以后创建出具体的特定的控制器来,然后才能工作的,因此我们需要借助于Deployment来创建一个真正意义上的Deployment比如nginx_Deployment,这可以表示我们用来专门管理某个项目的Nginx的控制器,这个Deployment会自动的帮我们去创建出对应的nginx Pod来,那接下来我们还要利用Service;
    Service也是一种类型,所以我们还需要借助Service属性来创建出一个特定的Service实例来,比如nginx_Service,而这个Service能够关联到Nginx的Pod上从而实现调度用户请求至Nginx Pod。不过Kubernetesc除了控制平面之外,要运行Pod还需要依靠Node,我们称之为工作平面,每一个Node要负责两件事,第一运行Pod,第二给Pod设定把Pod相关的Service转换为当前节点上的Iptables或ipvs规则,而这一切靠的是每一个Node节点上的kube-proxy来完成的。
    kube-proxy说白了,它也是我们的Kubernetes一个客户端,它随时wath,监视者Kubernetes ApiServer上的变动,尤其是Service的资源的变动,它会把每一个Service资源的变动反应在当前节点上的对应的iptables或Ipvs规则;
    node是集群级别的资源,在Kubernetes上资源有两个级别,第一个级别是集群级别,而整个集群又可以划分成多个名称空间namespaces,默认Kubernetes安装完成之后会生成三个名称空间;

名称空间

查看现有的名称空间
[root@node1 ~]# kubectl get namespaces
NAME STATUS AGE
default Active 108m # 没有指明名称空间下都在default
kube-node-lease Active 108m 
kube-public Active 108m # 公共的,任何人都可以访问的
kube-system Active 108m # 系统级的Pod都运行在这个空间下
查看名称空间下面的Pod
[root@node1 ~]# kubectl get pods -n kube-system
创建一个名称空间资源
首先查看可以创建的资源
[root@node1 ~]# kubectl api-resources
创建一个名称空间资源
[root@node1 ~]# kubectl create namespace develop
namespace/develop created
删除一个名称空间
[root@node1 ~]# kubectl delete namespace testing prod
查看名称空间的信息
[root@node1 ~]# kubectl get namespaces default -o json
查看名称空间的描述
[root@node1 ~]# kubectl describe namespaces default 

控制器

创建控制器
    控制器可以控制Pod运行起来,可以指定名称,指定镜像;
[root@node1 ~]# kubectl create deployment nginx --image=nginx:1.14-alpine
没指定名称空间会进入到defalut里面来
[root@node1 ~]# kubectl get pods -n default
NAME READY STATUS RESTARTS AGE
nginx-6867cdf567-r7mg4 1/1 Running 0 96s

总结

    此时我们如果删除Pod会发现会自从重建,这是因为用户期望有一个,那就必须有一个,少了就会重建,那么重建就会带来一个问题,就是Pod的IP会变动,所以这个时候我们的Service的组件就来了,正常情况下,客户端要访问调度器,由调度器调度至后端节点上来,调度器自己得有自己的IP和端口,被调用的后端也必须得有自己的IP和端口,然后创建iptables或者ipvs的DNAT规则,其实Service就是帮你去生成这个规则而已,但是这个规则在每一个节点上都有,因此每一个节点上的Pod,如果作为客户端去访问这3个地址的时候,会自动被这个规则拦截到,会自动的给他转成目标规则,所以客户端与服务端进行通信的时候,就成了一个DNAT过程;

Service

    Service四种类型,我们用的最多的,也是最简单的就是clusterip,当你创建完成了Service之后,再关联至所创建的deployment,此时如果你手动停止容器或者使用kubectl删除pods,只要你不动Service,你会发现即使程序暂时无法访问,因为这个时候我们的deployment后面的pods被删除了或者宕机了,你会发现几秒钟之后我们的Kubernetes会重新启动一个一模一样的pods来替代原有的pods,实现无缝切换,因为pods的变动会得到deployment实时监控,一旦有问题直接反应给API Service进行相关处理;
clusterip类型的Service
创建一个Service,并且映射80端口,指定deployment的对应的名字,如果名字和deployment名字一致,则service自动关联至deployment下面的pods
[root@node1 ~]# kubectl create service clusterip webcluster1 --tcp=80:80
[root@node1 ~]# kubectl describe service webcluster1 
Name: webcluster1
Namespace: default
Labels: app=webcluster1
Annotations: <none>
Selector: app=webcluster1
Type: ClusterIP
IP: 10.110.117.67
Port: 80-80 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.6:80
Session Affinity: None
Events: <none>
[root@node1 ~]# curl -I 10.110.117.67 -o /dev/null -s -w %{http_code}
200
查看service
[root@node1 ~]# kubectl get service
删除service
[root@node1 ~]# kubectl delete service web
使用域名的方式去访问我们的service
    格式:service_name.namespace_name.svc.cluster.local  # .cluster.local是固定格式,默认在初始化k8s的时候可以通过--service-dns-domain来指定,默认值是cluster.local;
[root@node3 ~]# curl webcluster1.default.svc.cluster.local -o /dev/null -s -w %{http_code}
200
nodeport类型的Service
    顾名思义,直接将node节点上的Pod进行端口暴露,让集群外部主机直接访问,注意访问的是我们集群中的节点的宿主机的IP,我们在同一组的Pod上,如果我们创建的时候,不是指clusterip,而是指定的Node Pod我们甚至还能再一次被转发以后在集群外部进行访问,因为这些规则都会反映在每一个宿主机的iptables规则当中,这就是kube-proxy规则;
[root@node3 ~]# kubectl create service nodeport myweb --tcp=80:80
[root@node3 ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13h
myweb NodePort 10.99.170.26 <none> 80:31992/TCP 12s # 80映射到了31992,这个31992是宿主机的端口
webcluster1 ClusterIP 10.110.117.67 <none> 80/TCP 55m
测试在宿主机访问
[root@node1 ~]# curl http://172.16.1.2:31992/ -o /dev/null -s -w %{http_code} # 172.16.1.2是master的端口,其实在任何节点都可以访问端口都是一致,不论的master还是node
200

Pod扩容

动态扩容Pod
    默认调度方式是随机调度,它是使用的iptables调用的,如果我们使用ipvs的话还能使用ipvs自身的调度算法;
创建一个deployment
[root@node3 ~]# kubectl create deployment myweb --image=ikubernetes/myapp:v1
创建一个service
[root@node3 ~]# kubectl create service clusterip myweb --tcp=80:80
实现pod扩缩容至3个Pod节点
[root@node1 ~]# kubectl scale --replicas=3 deployment myweb 
扩容之后会自动反映在service上
[root@node1 ~]# kubectl describe service myweb 
Name: myweb
Namespace: default
Labels: app=myweb
Annotations: <none>
Selector: app=myweb
Type: ClusterIP
IP: 10.108.224.119
Port: 80-80 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.7:80,10.244.2.8:80,10.244.2.9:80 # 可以看到已经有四个节点了
Session Affinity: None
Events: <none>
实现动态负载均衡
[root@node3 ~]# for i in {1..4}; do curl http://10.108.224.119/hostname.html; done
myweb-889fc5486-vmmtc
myweb-889fc5486-8jb5t
myweb-889fc5486-8jb5t
myweb-889fc5486-8jb5t
进行缩容到2个节点
[root@node3 ~]# kubectl scale --replicas=2 deployment myweb

总结

    API Server对于Kubernetes至关重要,你的所有操作,都只能,而且必须经过API Server,所有其他组件包括控制器管理器、Scheduler都必须只能与API Server进行交互,所以API Server是整个Kubernetes,也只有API Server才能去操作etcd中的数据,kubelet或kube-proxy以及kubectl也都需要与API Server进行交互,他们也都是API Server的客户端,他们都必须认证到API Server中才能进行操作,API Server也是唯一一个etcd的客户端,也就意味着能管理或操作etcd集群的也只有API Server,所以etcd被称为cluster store整个集群的所有资源的状态定义的信息都保存在etcd当中,所以etcd如果蹦了,那么整个集群的过去的运行记录都没了;
    所以作为运维工程师来讲,我们应当定期去备份etcd当中的数据,并且为了保障etcd的可用,应该把etcd做成高可用的;
    API Server自身作为整个集群的网关,我们与API Server打交道的时候可以使用客户端命令工具kubectl,以后还有一个dashboard可以实现图形化操作,Kubernetes的API是一个http的API, 默认使用json格式的数据,我们在使用http协议提交配置的时候,也是使用的json,即使我们提交的是一个yaml,它还是会自动转化为json,所以唯一接收的序列化方案是json;
    API Server是一个resetfull风格的API,在resetfull风格中,reset叫做表征状态转移,它是一种架构范式,是一种能让分布式组件之间能够互相调用的一种范式;
    对于我们的Kubernetes来讲,不论有多少种不同类型的资源,最后事实上他们都应该位于整个API Server的某个API版本下,比如Service改变了,如果大家都依赖于这个Service那么整个API Server所有版本都得变更,所以Kubernetes把它的API Server把它的API分解到了不同的群组当中,其中每个组合组合通常都是一组相关的类型,我们称为API Group群组,这些群组可以使用kubectl api-versions来查看,v1是核心群组,并且多版本可以并存,所以你的每一个资源一定是某个群组下的一组运行的属性赋值,不同的版本相同的群组他的属性是不一样的,所以假如你在v1下面定义一个资源在v1beta1下面未必有用;
    kubectl get deployments.apps myweb -o json该命令执行后可以看到apiVersion是apps/v1

发表回复

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