"本文主要从docker、docker-compose由浅到深介绍了Kubernetes核心功能"
1、Docker
Docker是基于操作系统的沙盒技术,使得用户更简单和完整的去打包自己的应用。
为了说明docker底层实现,现在介绍下面几个概念。
docker底层是基于linux的操作系统级别的虚拟化技术LXC实现;
LXC是通过CGroup实现了虚拟化资源管理,用来保证应用资源的隔离和应用系统资源的限制;
服务器运行了多个服务,这些服务之间是可以互相影响的,其中的一个服务可以查看另外一个服务,这些是我们不愿意看到的,我们更希望同一台机器运行的服务能够完全隔离,互不影响就像运行在多台机器上一样。而linux为我们提供了NameSpaces为我们提供了分离进程树、网络接口、资源挂载点的方法,docker正是利用了linux的NameSpaces技术实现了不同容器间资源的隔离;
如果我们进入docker命令进入容器内部会发现只能看到当前容器的目录而不能看到原系统的目录,而linux的chroot又称(change root)具有改变当前系统的根目录功能。docker正是利用chroot的功能而实现了容器内部目录与原系统目录隔离的效果。
通过NameSpaces文件系统、网络并与宿主机器之间的进程相互隔离,CGroup实现了CPU、内存等物理资源的隔离,docker镜像本质上是一个基于linux底层文件系统的压缩包,虽然Docker是最近几年流行起来即使,但是 Docker 的核心技术其实已经有很多年的历史了,Linux Namespaces、CGroup和 UnionFS 三大技术支撑了目前 Docker 的实现,也是 Docker 能够出现的最重要原因。
具体使用可借鉴:如何使用docker?
2、docker-compose
Docker-compose是一个单节点编排技术。
如果把docker比喻成一堆杂乱无章的集装箱,而compose能够对这些集装箱整理归类,作为一个整体启动运行,docker-compose是以docker为核心进行构建的,本身只支持单节点编排,在复杂多变的生产环境是无法投入使用的。
具体使用可借鉴:起飞的感觉,docker-compose
3、Kubernetes
工业级的编排平台主要提供服务的部署、弹性和管理;
Kubernetes是希腊语,翻译中文是“舵手、飞行员”的意思。
k8s,省略中间8个ubernete替换为8,而得来k8s。
如果说docke把应用打包成镜像,那么Kubernetes保证容器化应用简单高效运行。他跟docker-swarm、moby项目不同,它不在以docker为核心,而是把docker作为一个运行时组件,更多是提供应用部署,规划,更新,维护,在复杂多变的生产环境中,这些往往是我们更加需要的。
3.1、Kubernetes核心功能
1 服务发现和负载均衡;
主要通过Service资源对象其底层是基于iptables实现。
2 服务自动装箱;
主要是通过调度 组件Scheduler实现,它能够自动给帮助我们把容器调度到某几台机器上自动启动运行。
3 容器存储编排;
Kubernetes有跟compose类似的编排yml文件,让存储的生命周期和容器的生命周期有一个链接。
4 容器故障恢复;
在集群环境中经常会因为系统原因、以及宿主机问题导致容器不可用,Kubernetes会帮助我们把不可用的容器进行恢复或者转移到正常节点上面去。
5 自动发布和回滚;
Kubernetes能够对我们的应用进行自动的发布和回滚,并且根据不同应用场景提供了不同发布和回滚策略。
6 配置和密钥存储;
Kubernetes提供了ConfigMap解决了集群环境中配置文件的存储问题,其底层是基于数据卷实现,原应用不用修改任何代码即可无缝对接。
7 服务水平伸缩;
Kubernetes为了让集群更具有弹性提供了水平伸缩功能,如果线上有某种大流量活动,我们可以直接水平扩展应用部署应用的数量,当活动结束后,再减少应用部署的数量,从而高效应对高并发场景。
8 批量执行以及守护进程任务;
Kubernentes可以对Job类型的任务,进行批量的执行,比如数据同步、备份等;如果我们想要集群环境中每个节点都运行一份守护进程进行节点任务执行,我们可以使用Kubernetes DeamonSet资源类型进行任务执行。
9 探针。
Kubernetes主要提供了存活和就绪两种探针,支持http、tcp、socket或者脚本的形式进行检测服务是否正常,对原有服务架构没有任何侵入性。
3.2、图文演示Kubernetes部分特性
- Kubernetes的调度器Scheduler可以把用户提交的容器,根据其规格大小调度到其中的一个节点上。如下动图所示:
- Kubernetes平台有健康检查的功能,当集群中的某个节点或者应用出现故障时,能够自动转移到健康节点上。如下动图所示:
- Kubernetes具备HPA自动扩容的能力,目前只支持按照CPU指标和用户自定义(比如TPS或QPS)达到某个数量级触发自动扩容,当请求高峰过去之后,pod可以恢复到原来的水平。如下图所示检测到白色节点负载过高,自动把服务复制两份,分发到其它节点运行:
3.3、架构介绍
Kubernetes基于两层架构设计,主要包含主节点master和计算节点node,master包含web UI界面和cli命令行,支持多个master高可用部署,master主要下发命令到node,node主要用于容器任务执行。
- master
master主要包含 APIServer、Scheduler、Controller、Etcd等组件。
API Server提供了资源的增、删、改、查等操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制,集群内部组件与组件之间不能直接调用,调用过程都要经过ApiServer,其中Apiserver支持高可用配置。
Scheduler负责资源的调度策略,能够按照预设的策略把pod调度到相应的节点上,支持热备。
Controller负责维护集群的状态,资源对象的自动化控制中心,比如故障检测、自动扩展、滚动更新、服务帐户和令牌控制器等功能都是由Kubernetes Controller完成,支持热备。
etcd主要功能保存整个集群的状态;etcd本身是一个独立与Kubernetes集群之外的分布式存储系统。支持高可用配置。
- node
Kubernetes的业务是在node上运行,而业务都是以最小单元pod进行运行的,而pod中可以运行一个或者多个容器,pod本身在kubelet组件上运行,它通过跟apiserver进行交互获得pod的状态。
node主要包含Kubelet、kube-proxy、Container Runtime、存储插件、网路插件等。
kubelet主要负责pod的创建、启动停止等任务,与master节点密切交互完成集群管理和运行的基本功能。
kube-proxy 主要用于通过Service提供集群内部的服务发现和负载均衡。
Container Runtime主要负责镜像管理以及pod内容器运行环境配置。
- Kubernetes提供了多种资源对象,可以根据需求选择使用,如下表所示:
资源对象 | Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、Job、CronJob、HorizontalPodAutoscaling |
---|---|
配置对象 | Node、Namespace、Service、Secret、ConfigMap、Ingress、Label、ThirdPartyResource、 ServiceAccount |
存储对象 | Volume、Persistent Volume及三方插件(NFS、ceph、gfs) |
策略对象 | SecurityContext、ResourceQuota、LimitRange |
3.4、图文说明pod在Kubernetes集群平台执行过程
用户可以通过命令行提交一个pod到API Server,API Server把pod当前信息存储到etcd数据库中,Scheduler调度器根据pod规格资源配置调度某个节点上,通知API Server把调度的节点信息和pod存储到etcd中,API Server会通知相应节点的kubelet执行启动,kubelet首先调用Container RunTime配置容器以及运行环境,然后调度存储插件配置存储,网络插件配置网络,从而完成容器的运行。
3.5、核心概念介绍
- pod
- 最小调度以及资源单位,这里我们思考下为什么pod是最小调度单位?这里我们举个例子:我们有个多进程应用(比如rsyslog就是多进程应用),其中包含三个进程p1,p2,p3,这三个进程必须运行在一台机器上,每个进程需要占用0.5GB内存,现在我们有三台机器,node1(2G)node2(1G)node3(1G);假设pod不是最小调度单位,p1调度到node2上,这完全是有可能的,因为node2资源足够p1使用,紧接着p2也被调度到node2上,那么问题来了p3呢?当然我们可以通过加锁的方式解决,但是如何加锁呢,都是问题,但是Kubernetes通过把pod作为最小调度单位从而解决了此问题;
- 包含一个或者多个容器,如果说我们服务之间存在大量rpc调用,这时我们可以把应用放在一个pod中运行,共享同一个网络环境,直接本地调用,而pod和pod之间是网络隔离,可以通过Service访问;
- 定义容器运行时方式(命令和环境变量);
- 提供给容器共享的运行环境(网络和进程空间)。
- Deployment
- 定义pod副本数量、版本等;
- 通过ReplicaSet控制pod数量(自动重启失败的pod);
- 按照指定策略控制版本 (版本升级、回滚、重新生成);
deployment是一个控制器,能够用来控制pod数量跟期望数量一致,配置pod的发布方式,Deployment会按照给定策略进行发布pod,保证在更新过程中不可用数量在限定范围内。看了上面的介绍感觉像是Deployment直接控制pod,其实不然,Deployment控制ReplicateSet ReplicateSet控制pod副本的数量,pod所属于replicaset,同一个replicaset下的pod版本都是一样的。
- Volume
- Pod中一个或者多个容器可以访问的目录
- 支持多种存储的抽象 本地存储、分布式存储、云存储
在docker中volume就是对应磁盘或者其它容器中的目录,docker对它的管理比较松散,没有生命周期管理,而Kubernetes中的volume的生命周期和pod的生命周期相同。相比与pod中的容器来说,存储数据可能比容器生命周期更长,并且在容器重新启动后保留存储信息。在Kubernetes支持多种类型的卷,而Pod可以同时使用各种类型和任意数量的存储卷。
- Service
提供访问多个pod的稳定访问方式 (IP、域名、环境变量)。
说到Service不得不介绍kubernetes网络模型和通信方式
- 网络模型 一个完整的Kubernetes集群应该包含三层网络,首先第一层是mater和node节点之间的网络,这个网络需要在部署kubernetes集群之前配置完成 第二层网络是pod的网络通过kubenet或者cni插件实现,用于pod之间或者内部的通信,集群中的所有pod均处在同一个网络平面空间内,可以直接通信。 第三层网络是Service资源的网络,是一个虚拟网络,用于为Kubernetes集群配置IP地址,但此地址并不配置于任何主机或者容器的网络接口之上,而是通过kubeproxy配置为iptables规则,将发往该地址的所有流量调度至后端的pod之上。
- 通信方式 同一个pod的内部通信; 各个pod彼此通信; pod和service的通信; 集群外部流向service的通信。
- 端口介绍
containerPort:一个信息性数据,只是为集群提供一个可以快速了解相关 pod可以访问端口的途径,而且显式指定容器端口,无论你是否指定都不影响其他节点上的客户端pod对其进行访问;
port:服务提供端口,用于kubernetes集群内部服务访问;
targetPort:pod目标端口,如果不设置使用默认port端口,port和 nodePort的数据通过这个端口进入到Pod内部,Pod里面的container的端口映射到这个端口,提供服务;
nodePort:外部用户访问端口。
3.6、API基础知识
通过命令行提交一个pod到时候,其提交的内容是yml,yml是一种特殊资源配置文件,主要包含apiversion、kind、metadata、spec几部分组成。
apiVersion 描述当前操作的资源对象。
kind:资源类型,比如Pod、Department等
metadata就是写上当前pod的名称,比如nginx。刚刚介绍的 Deployment,它可能是代表一组的 Pod,它是一组 Pod 的抽象,一组 Pod 就是通过 label selector 来表达的,Service通过选择一组pod统一进行访问。
spec描述了pod预期达到状态,比如内部需要哪些container运行,需要哪些镜像,暴露什么端口等等信息,需要在这里定义。
代码语言:javascript复制apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2 # tells deployment to run 2 pods matching the template
template: # create pods using pod definition in this template
metadata:
# unlike pod-nginx.yaml, the name is not included in the meta data as a unique name is
# # generated from the deployment name
labels:
app: nginx
spec:
containers:
- name: nginx
image: docker.hub.com/ops/openresty:1.15.8.2-6
ports:
- containerPort: 80
3.7、操作演示
1 查看集群当前状态
代码语言:javascript复制[root@k8s-master ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 161d v1.14.2
k8s-node1 Ready <none> 161d v1.14.2
k8s-node2 Ready <none> 29d v1.14.2
2 查看deployments资源
代码语言:javascript复制[root@k8s-master src]# kubectl get deployments
No resources found.
3 执行
代码语言:javascript复制[root@k8s-master src]# kubectl apply -f nginx_deploy.yaml
deployment.apps/nginx-deployment created
4 查看执行状态,可以发现容器已经按照期望执行
代码语言:javascript复制[root@k8s-master src]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 28s
[root@k8s-master src]# kubectl describe deployment nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sun, 02 Feb 2020 09:55:48 0800
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1beta1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},"spec":{"re...
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: docker.hub.com/ops/openresty:1.15.8.2-6
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-66db8ddc49 (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 58s deployment-controller Scaled up replica set nginx-deployment-66db8ddc49 to 2
4 修改nginx_deploy.yaml文件,把副本数量修改为4
代码语言:javascript复制apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 4 # tells deployment to run 2 pods matching the template
template: # create pods using pod definition in this template
metadata:
# unlike pod-nginx.yaml, the name is not included in the meta data as a unique name is
# # generated from the deployment name
labels:
app: nginx
spec:
containers:
- name: nginx
image: docker.hub.com/ops/openresty:1.15.8.2-6
ports:
- containerPort: 80
5 扩容 nginx deployment,发现副本数量已经从2变成4个
代码语言:javascript复制[root@k8s-master src]# kubectl apply -f nginx_deploy.yaml
deployment.apps/nginx-deployment configured
[root@k8s-master src]# kubectl describe deployment nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sun, 02 Feb 2020 09:55:48 0800
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1beta1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},"spec":{"re...
Selector: app=nginx
Replicas: 4 desired | 4 updated | 4 total | 4 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: docker.hub.com/ops/openresty:1.15.8.2-6
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Progressing True NewReplicaSetAvailable
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-66db8ddc49 (4/4 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 9m15s deployment-controller Scaled up replica set nginx-deployment-66db8ddc49 to 2
Normal ScalingReplicaSet 8s deployment-controller Scaled up replica set nginx-deployment-66db8ddc49 to 4
如上所述主要演示了deployment对象的启动和扩容过程,当然我们也可以执行升级,回退等操作。
代码语言:javascript复制参考 https://k8s.io/examples/application/deployment-update.yaml
4、总结
本文主要介绍了从docker到Kubernetes编排平台的演进过程,然后介绍了Kubenetes自身架构以及核心概念,最后演示了应用的部署和扩容。