第一章 Kubernetes入门
第一章 Kubernetes入门
kubernetes是基于容器技术的分布式架构领先方案,是一个完备的分布式系统支撑平台。
kubernetes带来的好处:1)全面拥抱微服务;2)统可以随时随地整体“搬迁”到公有云上;3)Kubernetes系统架构具备了超强的横向扩容能力。
基本概念和术语
在Kubernetes中,Node、Pod、Replication Controller、Service等概念都可以看作一种资源对象,通过Kubernetes提供的Kubectl工具或者API调用进行操作,并保存在etcd中。
master
master上运行etcd server,API server,controller Manager,scheduler等进程,每个kubernetes集群需要有一个master节点来负责整个集群的管理和控制。
node
node作为工作负载节点,运行以下一组关键进程。
kubelet:负责pod对应的容器创建,启停等任务,同时与master节点密切协作,实现集群管理的基本功能。
kube-proxy:实现kubernetes Service的通信与负载均衡机制的重要组件。
Docker Engine:Docker引擎,负责本机的容器创建和管理工作。
查看集群中多少个node:kubectl get nodes
查看某个Node的详细信息:kubectl describe node <node_name>
pod
Pod是Kubernetes的最基本操作单元,包含一个活多个紧密相关的容器,类似于豌豆荚的概念。一个Pod可以被一个容器化的环境看作应用层的“逻辑宿主机”(Logical Host)。一个Pod中的多个容器应用通常是紧耦合的。Pod在Node上被创建、启动或者销毁。
apiVersion: v1 kind: Pod metadata: name: redis-slave labels: name: redis-slave spec: containers: - name: slave image: kubeguide/guestbook-redis-slave env: - name: GET_HOSTS_FROM value: env ports: - containerPort: 6379 resources: requests: 该资源的最小申请量,系统必须满足要求 memory:"64Mi" cpu:"250m" limits: 资源最大允许使用量,超过将重启 memory:"128Mi" cpu:"500m"
Label
Label以key/value键值对的形式附加到各种对象上,如Pod、Service、RC、Node等。Label定义了这些对象的可识别属性,用来对它们进行管理和选择。Label可以在创建时附加到对象上,也可以在对象创建后通过API进行管理。
基于等式的Label Selector使用等式类的表达式来进行选择:
- name = redis-slave: 选择所有包含Label中key="name"且value="redis-slave"的对象;
- env != production: 选择所有包括Label中的key="env"且value不等于"production"的对象。
基于集合的Label Selector使用集合操作的表达式来进行选择:
- name in (redis-master, redis-slave): 选择所有包含Label中的key="name"且value="redis-master"或"redis-slave"的对象;
- name not in (php-frontend): 选择所有包含Label中的key="name"且value不等于"php-frontend"的对象。
将多个Label Selector进行组合
name=redis-slave,env!=production
name not in (php-frontend),env!=production
总结:使用label可以给对象创建多组标签,Lable和label Selector共同构成了Kubernetes系统中最核心的应用模型,使得被管理对象能够被精细的分组管理,同时实现了整个集群的高可用性。
RC
RC定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所以RC的定义包括如下几个部分:
1)pod期待的副本数
2)用于刷选目标Pod的label Selector
3)当pod的副本数量小于预期数量的时候,用于创建新pod的pod模板。
apiVersion: v1 kind: ReplicationController metadata: name: redis-slave labels: redis-slave name: redis-slave spec: replicas: 2 selector: name: redis-slave 标签name=redis-slave的pod存在2个副本 template: metadata: labels: name: redis-slave spec: container: - name: slave image: kubeguide/guestbook-redis-slave env: - name: GET_HOSTS_FROM value: env ports: - containerPort: 6379
Deployment
deployment在内部使用Replica Set来实现目的,无论从Deployment的作用与目的,它的YAM定义,还是从它的具体命令行操作来看,我们都可以把它看做RC的一次升级。
HPA(pod横向自动扩容)
通过追踪分析RC控制的所有目标pod的负载变化情况,来确定是否需要针对性的调整目标pod的副本数,这是HPA的实现原理。
下面是HPA定义的案例:
apiVersion:autoscaling/v1 kind:HorizontalPodAutoscaler metadata: name:php-apache namespace:default spec: maxReplicas:10 minReplicas:1 scaleTargetRef: kind:Deployment name:php-apache targetCPUUtilizationPercentage:90 #根据上面的定义,我们知道这个HPA控制的目标对象为Deployment里一个名叫php-apache的Pod副本,这个副本的CPUUtilizationPercentage值超过90%就会触发自动扩容行为,伸缩的副本数介于1-10之间。 #通过kubectl create创建HPA资源对象 或者 kubectl autoscale deployment php-apache --cpu-percent=90 --min=1 --max=10
service
一个Service可以看作一组提供相同服务的Pod的对外访问接口。Service作用于哪些Pod是通过Label Selector来定义的。
Pod的IP地址和Service的Cluster IP地址
Pod的IP地址是Docker Daemon根据docker0网桥的IP地址段进行分配的,但Service的Cluster IP地址是Kubernetes系统中的虚拟IP地址,由系统动态分配。Service的Cluster IP地址相对于Pod的IP地址来说相对稳定,Service被创建时即被分配一个IP地址,在销毁该Service之前,这个IP地址都不会再变化了。而Pod在Kubernetes集群中生命周期较短,可能被ReplicationContrller销毁、再次创建,新创建的Pod将会分配一个新的IP地址。
部署一个负载均衡器,为这组pod开启一个对外服务端口如8000端口,并且将pod的endpoint列表加入8000端口的转发列表中,客户端就可以通过负载均衡器的对外IP地址+服务端口来访问此服务,而客户端的请求最后会被转发到哪个pod,则由负载均衡器算法决定。
外部访问service
Node IP:Node节点的IP地址 Pod IP:Pod的IP地址 Cluster IP:Service的IP地址
Kubernetes支持两种对外提供服务的Service的type定义:NodePort和LoadBalancer。
NodePort
apiVersion: v1 kind: Service metadata: name: frontend labels: name: frontend spec: type: NodePort * ports: - port: 80 nodePort: 30001 * selector: name: frontend
LoadBalancer
如果云服务商支持外接负载均衡器,则可以通过spec.type=LoadBalaner定义Service,同时需要制定负载均衡器的IP地址。使用这种类型需要指定Service的nodePort和clusterIP。例如:
apiVersion: v1 kind: Service metadata: { "kind" "Service", "apiVersion": "v1", "metadata": { "name": "my-service" }, "spec": { "type": "LoadBalaner", "clusterIP": "10.0.171.239", "selector": { "app": "MyApp" }, "ports": [ { "protocol": "TCP", "port": 80, "targetPort": 9376, "nodePort": 30061 } ], }, "status": { "loadBalancer": { "ingress": [ { "ip": "146.148.47.155" } ] } } }
volume(存储卷)
Volume是Pod中能够被多个容器访问的共享目录。当容器终止或者重启时,Volume中的数据也不会丢失。另外,Kubernetes支持多种类型的Volume,并且一个Pod可以同时使用任意多个Volume。Kubernetes提供了非常丰富的Volume类型,下面逐一进行说明。
#举例来说,我们要给之前的tomcat pod增加一个名字为dataVol的volume,并且Mount到容器的/mydata-data目录,则只要对pod的定义文件做如下修改: template: metadata: labels: app:app-demo tier:frontend spec: volumes: -name:datavol emptyDir:{} containers: -name:tomcat-demo image:tomcat volumeMount: - mountPath:/mydata-data name:datavol
- EmptyDir:一个EmptyDir Volume是在Pod分配到Node时创建的。从它的名称就可以看出,它的初始内容为空。在同一个Pod中所有容器可以读和写EmptyDir中的相同文件。当Pod从Node上移除时,EmptyDir中的数据也会永久删除。
- hostPath:在Pod上挂载宿主机上的文件或目录。
使用宿主主机的/data目录定义hostPath类型的volume: volumes: -name:"persistent-storage" hostPah: path:"/data"
- gcePersistentDisk:使用这种类型的Volume表示使用谷歌计算引擎(Google Compute Engine,GCE)上永久磁盘(Persistent Disk,PD)上的文件。与EmptyDir不同,PD上的内容会永久保存,当Pod被删除时,PD只是被卸载(Unmount),但不会被删除。需要注意的是,你需要先创建一个永久磁盘(PD)才能使用gcePersistentDisk。
- awsElasticBlockStore:与GCE类似,该类型的Volume使用Amazon提供的Amazon Web Service(AWS)的EBS Volume,并可以挂在到Pod中去。需要注意到是,需要首先创建一个EBS Volume才能使用awsElasticBlockStore。
- nfs:使用NFS(网络文件系统)提供的共享目录挂载到Pod中。在系统中需要一个运行中的NFS系统。
- iscsi:使用iSCSI存储设备上的目录挂载到Pod中。
- glusterfs:使用开源GlusterFS网络文件系统的目录挂载到Pod中。
- rbd:使用Linux块设备共享存储(Rados Block Device)挂载到Pod中。
- gitRepo:通过挂载一个空目录,并从GIT库clone一个git respository以供Pod使用。
- secret:一个secret volume用于为Pod提供加密的信息,你可以将定义在Kubernetes中的secret直接挂载为文件让Pod访问。secret volume是通过tmfs(内存文件系统)实现的,所以这种类型的volume总是不会持久化的。
- persistentVolumeClaim:从PV(PersistentVolume)中申请所需的空间,PV通常是一种网络存储,不属于任何node,例如GCEPersistentDisk、AWSElasticBlockStore、NFS、iSCSI等。
namespace
Namespace(命名空间)是Kubernetes系统中的另一个非常重要的概念,通过将系统内部的对象“分配”到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
Kubernetes集群在启动后,会创建一个名为“default”的Namespace,通过Kubectl可以查看到。
使用Namespace来组织Kubernetes的各种对象,可以实现对用户的分组,即“多租户”管理。对不同的租户还可以进行单独的资源配额设置和管理,使得整个集群的资源配置非常灵活、方便。
kubectl get namespaces --查看命名空间 在yaml中定义名为development的namespace: apiVersion:v1 kind:Namespace metadata: name:development 将一个名为busybox的pod放入到development命名空间中: apiVersion:v1 kind:Pod metadata: name:busybox namespace:development spec: containers: .............. ............ 在对应的命名空间中查找pod: kubectl get pods --namespace=development
Annotation
Annotation与Label类似,也使用key/value键值对的形式进行定义。Label具有严格的命名规则,它定义的是Kubernetes对象的元数据(Metadata),并且用于Label Selector。Annotation则是用户任意定义的“附加”信息,以便于外部工具进行查找。
用Annotation来记录的信息包括:
- build信息、release信息、Docker镜像信息等,例如时间戳、release id号、PR号、镜像hash值、docker registry地址等;
- 日志库、监控库、分析库等资源库的地址信息;
- 程序调试工具信息,例如工具名称、版本号等;
- 团队的联系信息,例如电话号码、负责人名称、网址等。
总结
Kubernetes集群由两类节点组成:Master和Node。在Master上运行etcd、API Server、Controller Manager和Scheduler四个组件,其中后三个组件构成了Kubernetes的总控中心,负责对集群中所有资源进行管理和调度。在每个Node上运行Kubelet、Proxy和Docker Daemon三个组件,负责对本节点上的Pod的生命周期进行管理,以及实现服务代理的功能。另外在所有节点上都可以运行Kubectl命令行工具,它提供了Kubernetes的集群管理工具集。