在kubernetes中Node,Pod,Replication Controller,Service等概念都可以看作一种资源对象,通过kubernetes提供的kubectl工具或API调用进行操作
在kubernetes中Node,Pod,Replication Controller,Service等概念都可以看作一种资源对象,通过kubernetes提供的kubectl工具或API调用进行操作,并保存在etcd中1.Node(节点)Node是kubernetes集群中相对于Master而言的工作主机,在早期版本中成为minion,Node可以是一台物理机,也可以是一台虚拟机,在每个Node上运行用于启动和管理Pod的服务-kubectl,并且能够被Master管理,在Node上运行的服务进程包括kubelet,kube-proxy和docker daemon Node的信息如下: Node地址:主机ip,或者NodeId Node运行状态:包括Pending,Runing,Terminated三种状态 Node Condition:描述Running状态Node的运行条件,目前只有一种Ready,表示Node处于健康状态,可以接受从master发来的创建Pod指令 Node系统容量:描述Node可用的系统资源,包括CPU,内存,最大可调度Pod数量等 其他:Node的其他信息,包括实例内核版本,kubernetes版本号,docker版本号,操作系统等可以通过kubectl describe node node_name来查看Node的详细信息[root@localhost ~]# kubectl describe node 127.0.0.1Name: 127.0.0.1Role: Labels: beta.kubernetes.io/arch=amd64 beta.kubernetes.io/os=linux kubernetes.io/hostname=127.0.0.1Taints: <none>CreationTimestamp: Thu, 15 Jun 2017 02:31:36 +0800Phase: Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- OutOfDisk False Thu, 15 Jun 2017 16:11:00 +0800 Thu, 15 Jun 2017 02:31:36 +0800 KubeletHasSufficientDisk kubelet has sufficient disk space available MemoryPressure False Thu, 15 Jun 2017 16:11:00 +0800 Thu, 15 Jun 2017 02:31:36 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Thu, 15 Jun 2017 16:11:00 +0800 Thu, 15 Jun 2017 02:31:36 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure Ready True Thu, 15 Jun 2017 16:11:00 +0800 Thu, 15 Jun 2017 02:31:36 +0800 KubeletReady kubelet is posting ready statusAddresses: 127.0.0.1,127.0.0.1,127.0.0.1Capacity: alpha.kubernetes.io/nvidia-gpu: 0 cpu: 1 memory: 999936Ki pods: 110Allocatable: alpha.kubernetes.io/nvidia-gpu: 0 cpu: 1 memory: 999936Ki pods: 110System Info: Machine ID: 9d4ea80aa7594758813e8fed1f572e2b System UUID: DDBF4D56-3C3C-F602-0160-ACD94A574B9A Boot ID: 92f6fecd-61e0-4e6a-8698-663c9baa053e Kernel Version: 3.10.0-514.el7.x86_64 OS Image: CentOS Linux 7 (Core) Operating System: linux Architecture: amd64 Container Runtime Version: docker://1.12.6 Kubelet Version: v1.5.2 Kube-Proxy Version: v1.5.2ExternalID: 127.0.0.1Non-terminated Pods: (6 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits --------- ---- ------------ ---------- --------------- ------------- default frontend-kkb8q 0 (0%) 0 (0%) 0 (0%) 0 (0%) default frontend-p5hwm 0 (0%) 0 (0%) 0 (0%) 0 (0%) default frontend-r70dz 0 (0%) 0 (0%) 0 (0%) 0 (0%) default redis-master-1t0n6 0 (0%) 0 (0%) 0 (0%) 0 (0%) default redis-slave-0nh1g 0 (0%) 0 (0%) 0 (0%) 0 (0%) default redis-slave-cz342 0 (0%) 0 (0%) 0 (0%) 0 (0%)Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted. CPU Requests CPU Limits Memory Requests Memory Limits ------------ ---------- --------------- ------------- 0 (0%) 0 (0%) 0 (0%) 0 (0%)Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 12m 12m 1 {kubelet 127.0.0.1} Normal Starting Starting kubelet. 12m 12m 1 {kubelet 127.0.0.1} Warning ImageGCFailed unable to find data for container / 12m 12m 1 {kubelet 127.0.0.1} Normal NodeHasSufficientDisk Node 127.0.0.1 status is now: NodeHasSufficientDisk 12m 12m 1 {kubelet 127.0.0.1} Normal NodeHasSufficientMemory Node 127.0.0.1 status is now: NodeHasSufficientMemory 12m 12m 1 {kubelet 127.0.0.1} Normal NodeHasNoDiskPressure Node 127.0.0.1 status is now: NodeHasNoDiskPressure 12m 12m 1 {kubelet 127.0.0.1} Warning Rebooted Node 127.0.0.1 has been rebooted, boot id: 92f6fecd-61e0-4e6a-8698-663c9baa053e 12m 12m 2 {kubelet 127.0.0.1} Warning MissingClusterDNS kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "redis-master-1t0n6_default(8eefc9c3-5131-11e7-8b46-000c29574b9a)". Falling back to DNSDefault policy. 12m 12m 2 {kubelet 127.0.0.1} Warning MissingClusterDNS kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "frontend-r70dz_default(57a259d8-5138-11e7-8b46-000c29574b9a)". Falling back to DNSDefault policy. 12m 12m 2 {kubelet 127.0.0.1} Warning MissingClusterDNS kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "redis-slave-0nh1g_default(7b71e8e9-5136-11e7-8b46-000c29574b9a)". Falling back to DNSDefault policy. 12m 12m 2 {kubelet 127.0.0.1} Warning MissingClusterDNS kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "frontend-kkb8q_default(57a24b8d-5138-11e7-8b46-000c29574b9a)". Falling back to DNSDefault policy. 12m 11m 2 {kubelet 127.0.0.1} Warning MissingClusterDNS kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "redis-slave-cz342_default(7b725553-5136-11e7-8b46-000c29574b9a)". Falling back to DNSDefault policy. 12m 11m 2 {kubelet 127.0.0.1} Warning MissingClusterDNS kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "frontend-p5hwm_default(57a26405-5138-11e7-8b46-000c29574b9a)". Falling back to DNSDefault policy.1.1 Node的管理 使用Node Controller对Node进行管理,它是kubernetes Master中一个组件用于管理Node对象。 它的主要功能: 集群范围内的Node信息同步 单个Node生命周期管理 Node信息同步可以通过kube-controller-manager启动参数--node-sync-period设置同步的时间周期 Node的自注册当kubelet的--register-node参数设置为ture默认也为ture,kubelet会向apiserver注册自己这也是kubernetes推荐的Node管理方式 kubelet进行自注册启动参数如下 --apiserver:apiserver地址 --kubeconfig:登录apiserver所需证书目录 --cloud_provider:云服务商地址,用于获取metadata --register-node:设置ture表示自动注册到apiserver 手动管理Node 要手动管理Node需要把kubelet启动参数--register-node参数设置为false,这样Node上的kubelet不会自动注册到apiserver中去1.2 Pod kubernetes的最基本操作单元,包含一个或多个紧密相关的容器,一个Pod可以被一个容器化的环境看作应用层的逻辑宿主机,一个Pod中的多个容器通常是紧耦合的,Pod在Node上创建,启动,销毁 kubernetes在容器之上在封装一层Pod,一个重要的原因是docker容器之间的通信收到docker网络机制的限制,一个容器需要link方式才能访问另外一个容器提供的服务,大量容器之间的link将是一件非常繁重的工作,通过Pod将多个容器组合在一个虚拟的主机内可以实现容器之间仅需要Localhost就能互相通信了 container N--->Pod N--->Node N----->Master 一个Pod中的应用容器共享一组资源: Pid命名空间:Pod中不同应用程序可以看到其他应用程序进程的ID 网络命名空间:Pod中的多个容器能够访问统一个IP和端口范围 IPC命名空间:Pod中的多个容器能够使用systemV IPC或POSIX消息队列进行通信 UTS命名空间:Pod中的多个容器共享一个主机名 Volumes共享存储卷:Pod中的各个容器可以访问在Pod级别定义的Volumes 对Pod的定义通过yaml或json格式的配置文件来完成下面的配置文件内容是定义一个redis-slave的Pod,其中kind为Pod,spec中包含了对container的定义,可以定义多个容器apiVersion: v1kind: Podmetadata: name: redis-slave labels: name: redis-slavespec: containers: - name: slave image: kubeguide/guestbook-redis-slave env: - name: GET_HOSTS_FROM value: env ports: - containerPort: 6379 Pod的生命周期是通过RC(Replication Controller)来管理的Pod的生命周期包括:通过模版定义,然后分配到一个Node上运行,在Pod所含容器运行结束后Pod也结束,整个过程Pod处于以下4中状态 Pengding:Pod定义正确,提交到Master后,但其所包含容器镜像还未完全创建,通常Master对Pod进行调度需要一些时间,之后Node对镜像进行下载也需要一些时间 Running:Pod已经被分配到某个Node上且包含所有容器镜像已经创建完成并成功运行起来 Succeeded:Pod中所有容器都成功结束,并且不会被重启这是Pod的一种最终状态 Failed:Pod中所有容器都结束了,但是至少一个容器是以失败状态结束的这也是Pod的一种最终状态 kubernetes为Pod设计了一套独特的网络配置:包括为每个Pod分配一个IP地址使用Pod名作为容器之间通信的主机名, 1.3 Label kubernetes的一个核心概念,Label已key/value键值对的形式附加到各种对象上,Pod,Service,RC,Node;Label定义了这些对象的可识别属性,用来对他们进行管理和选择,Label可以创建对象时附加到对象,也可以在对象创建后通过API进行管理 在为对象定义好Label后,其他对象就可以使用Label Sekector来定义其作用的对象了 当前有两种label Selector 基于等式的: name=redis-slave:选择所有包含Label中key=name且value=redis-slave的对象 env !=production:选择所有包括Label中key=env且value不等于production的对象 基于集合的: name in (redis-master,redis-slave):选择所有Label中key=name且value=redis-master或redis-slave的对象 在某些对象需要对另一些对象进行选择时,可以将多个Label Selector进行组合,使用逗号分隔,等式和集合都任意组合 name=redis-slave,env!=production name notin (php-frontend),env!=production 一般来说我们会给一个Pod定义多个Labels以便于配置,部署,例如部署不同版本的应用到不同的环境中,或者监控和分析应用等,通过对多个Label的设置,就可以多维度对Pod或其他对象进行精细的管理 前面我们的例子都使用一个name=xxxx的Label Selector,来一个更复杂的 假设Pod定义了3个Label:release,env,role,不同的Pod定义了不同的取值 Node1:Labels release:a env:development role:frontend Node2:Labels release:b env:test role:frontend Node3:Labels release:b env:production role:backend 如果设置role=frontend的Selector只会选择到Node1和Node2上的Pod,设置了release=b的Selector则会选择到Node2和Node3上Pod 这样使用Label创建多组标签,Service,RC等组件通过Label Selector来选择范围对象,Label和Label Selector共同组成了kubernetes系统中最核心的应用模型,使用被管理的对象能够精细的分组管理。1.4 RC Replication Controller 用于定义Pod副本的数量,在master内Controller Manager进程通过RC定义来完成Pod的创建监控启停等 根据RC的定义,kubernetes能够在任何时刻都能运行用户指定的Pod副本replica数量,如果有过多的Pod副本在运行,系统就会停掉一些Pod,如果运行Pod副本数量太少,系统就会再启动一些Pod,总之通过RC的定义,kubernetes总是保证集群中运行用户期望的副本数量 同时kubernetes会对全部运行的Pod进行监控和管理,如果有需要,就会将Pod重启命令提交给Node上的某个程序来完成 通过对RC的使用,kubernetes实现了应用集群的高可用并且大大减少了系统管理员在传统IT环境中需要手动运维的工作 在运行时可以通过修改RC的副本数量来实现Pod的动态缩放scaling kubernetes提供kubectl scale来完成 kubectl scale rc redis-slave --replicas=3 注意:删除RC并不会影响通过该RC已创建好的Pod,为了删除所有Pod可以设置replicas的值为0,然后更新RC,另外kubectl提供了stop和delete来完成一次性删除RC和RC控制的全部Pod 另外通过RC可以实现应用的滚动升级1.5 Service服务 在kubernetes中每个Pod都会被分配到一个单独的ip地址,但是这个ip地址会随着Pod的销毁而消失,那么如果有一组Pod组成一个集群来提供服务那么该如何访问他们呢? kubernetes的Service服务就是解决这个问题的 一个Service可以看组一组提供相同服务的Pod的对外访问借口,Service作用于那些Pod是通过Label Selector来定义的 例如,redis-salve Pod运行两个副本replica,这两个副本对于前端程序来说没有区别,所以前端程序不关心那个后端副本提供服务,并且后端redis-slave Pod发生变化时,也不需要跟踪这些变化,Service就是用来实现这种解耦的抽象概念 对Service的定义 同样使用Yaml或者Json格式进行配置 apiVersion: v1 kind: Service metadata: name: redis-slave labels: name: redis-slave spec: ports: - port: 6379 selector: name: redis-slave 通过定义kubernetes会创建一个名为redis-slave的服务并在6379端口上监听,spec.selector的定义表示将所有包含name=redis-slave的Label的Pod 在Pod正常启动后,系统将会根据Service的定义创建出与Pod对应的Endpoint对象,以建立起Service和后端Pod的对应关系,随着Pod的创建销毁,Endpoint对象也将被更新,Endpoint对象主要用Pod的Ip地址和容器需要监听的端口号组成,通过kubectl get endpoints命令可以查看 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集群中生命周期较短,可能被ReplicationController销毁,新创建的Pod将会分配到一个新的IP地址 外部访问Service 用于Service对象在cluster ip range池中分配到的IP只能在内部访问,所以其他Pod都可以无障碍的访问到他,但如果这个Service作为前端服务,准备为集群外的客户提供服务,这就需要公共IP了 kubernetes支持两种对外服务的Service的type定义 NodePort:在定义Service时指定spec.type=NodePort并指定spec.ports.nodePort的值,系统就会在kubernetes集群中每个Node上打开一个主机上真实的端口号,这样就能够访问Node的客户就能过这个端口号访问到内部的Service 以php-frontend service的定义为例,nodePort=80这样,在每一个启动该php-frontend Pod的Node节点上都打开80端口 假设有3个php-frontend Pod运行在三个不同的Node上,客户端访问其中任意一个Node都可以访问到这个服务 LoadBalancer:如果云服务提供商支持外界负载均衡负载器,则可以通过spec.type=LoadBalancer定义Service,同时需要指定负载均衡器的IP地址,使用这种类型需要指定Service的nodePort和clusterIP apiVersion: v1 kind: Service metadata:{ "kind": "Service", "apiVersion": "v1", "metadata": { "name": "my-service" }, "sepc": { "type": "LoadBanlancer", "clusterIP": "1.1.1.1", "selector": { "app": "MyApp" }, "ports": [ { "protocol": "TCP", "port": 80, "targetPort":9376, "nodePort":30061 } ], }, "status" : { "loadBanlancer": { "ingress": [ { "ip": "2.2.2.2" } ] } } } 在这个例子中status.loadBanlancer.ingress.ip设置的2.2.2.2为云服务商提供的负载均衡器的IP地址,之后对该Service的访问请求会通过LoadBanlancer转发后到后端Pod上去,负载分发的实现方式依赖于云服务提供商的LoadBanlancer的实现机制 在很多情况下一个服务需要暴露多个端口号在这种情况下可以对端口进行命名 { "kind": "Service", "apiVersion": "v1", "metadata": { "name": "my-service" }, "sepc": { "type": "LoadBanlancer", "clusterIP": "1.1.1.1", "selector": { "app": "MyApp" }, "ports": [ { "name": "http" "protocol": "TCP", "port": 80, "targetPort":9376 }, { "name": "https" "protocol": "TCP", "port": 443, "targetPort":9377 } ] } }1.6 volume 存储卷 Volume是Pod中能够被多个容器访问的共享目录,kubernetes的volume与docker的volume比较类似,但不完全相同,kubernetes的volume与Pod的生命周期相同,但与容器的生命周期不相关,当容器终止或者重启时,volume中的数据不会丢失,kubernetes支持多种类型的volume,并且一个Pod可以同时使用任意多个volume。 kubernetes提供非常丰富的volume类型 1.EmptyDir:一个EmptyDir volume是在Pod分配到Node时创建的,从它的名称可以看出它的初始内容为空,在同一个Pod中的所有容器都可以读和写EmptyDir中的相同文件。当Pod从Node上移除的时候,EmptyDir中的数据也会永久删除。 用于临时空间,长时间任务的中间过程CheckPoint临时保存目录 一个容器需要从另一个容器中获取数据的目录,目前无法控制EmptyDir使用介质类型种类,如果kubelet的配置是使用硬盘,那么所有EmptyDir都将创建在该硬盘上,Pod在将来可以设置EmptyDir是位于硬盘还是基于内存的tmpfs上 2.hostPath:在Pod上挂载宿主机上的文件或目录 通常用于:应用程序生成的日志文件需要永久保存,可以好似用宿主机的告诉文件系统进行存储,需要访问宿主机上Docker引擎内部数据库的容器应用,可以通过定义hostPath为宿主机的/var/lib/docker目录,使容器内部的应用可以直接访问docker的文件系统 在使用这种类型volume的时候需要注意: 在不同Node上具有相同配置的Pod可能会因为宿主机上的目录和文件不同导致对volume上目录和文件访问结果不一致。 如果使用了资源配额管理则kubernetes无法将hostPath在宿主机上使用的资源纳入管理 以redis-master为例,使用宿主机的/data目录作为其容器内部挂载点/data的volume apiVersion: v1kind: ReplicationControllermetadata: name: redis-master labels: name: redis-masterspec: replicas: 1 selector: name: redis-master template: metadata: labels: name: redis-master spec: volume: - name: "persistent-storage" hostPath: path: "/data" containers: - name: master image: kubeguide/redis-master ports: - containerPort: 6379 volumeMounts: - name: "persitent-storage" mountPath: "/data" 3. gccPersistentDisk:使用这种类型的volume表示使用谷歌计算引擎GCE上永久磁盘PD上的文件与EmptyDir不同PD上的内容会永久保存,当Pod删除时,PD只是被卸载,但不会被删除,需要注意的是,你需要先创建一个永久磁盘才能使用gccPersistentDisk 使用gccPersistentDisk有一些限制:Node需要是GCE虚拟机,这些虚拟机需要与PD存在于相同的GCE项目和Zone中 通过gcloud命令可以创建一个PD: gcloud compute disks create --size=500G --zone=cn-centrall-a my-data-disk 在Pod定义中使用gccPersistentDiskapiVersion: v1kind: Podmetadata: name: test-pdspec: containers: - image: kubeguide/redis-master name: test-container volumeMounts: - mountPath: /test-pd name: test-volume volumes: - name: test-volume gccPersistentDisk pdName: my-data-disk fstype: ext4 4.awsElasticBlockStore:与GCE类似,该类型的volume使用Amazon提供的Amazon Web Service的EBS volume,并可以挂载到Pod中去,需要注意的是需要先创建一个EBS volume才能使用awsElasticBlockStore 限制条件:Node需要是AWS EC2实例 aws ec2 create-volume --availability-zone cn-sc --size 10 --volume-type gp2 在Pod定义中apiVersion: v1kind: Podmetadata: name: test-ebsspec: containers: - image: kubeguide/redis-master name: test-container volumeMounts: - mountPath: /test-ebs name: test-volume volumes: - name: test-volume awsElasticBlockStore volumeID: aws://<availability-zone>/<volume-id> fstype: ext4 5.nfs:使用NFS提供的共享目录挂载到Pod中,在系统中需要一个运行中NFS系统 在Pod定义中apiVersion: v1kind: Podmetadata: name: nfs-webspec: containers: - name: test-container image: nginx ports: - name: web containerPort: 80 volumeMounts: - name: nfs mountPath: "/usr/local/nginx/html" volumes: - name: nfs nfs server: nfs-server.localhost path: "/" 6.iscsi:使用iscsi存储设备上的目录挂载Pod中 7.glusterfs:使用开源GlusterFS网络文件系统的目录挂载到Pod 8.rbd:使用linux块设备共享存储挂载到Pod中 9.gitRepo:通过挂载一个空目录,并从git库中clone一个git repository以供Pod使用 10.secret:一个secret volume用于Pod提供加密的信息,你可以将定义在kubernetes中secret直接挂载为文件让Pod访问,secret volume是通过tmfs实现的,所以volume不会持久化 11.persistentVoluemClaim:从PV中申请所需空间,PV通常是一个网络存储1.7 Namespace 通过将系统内部的对象分配到不同的Namespace中形成逻辑上分组的不同项目,小组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理kubernetes集群在启动后会自动有一个名为default的Namespace,通过kubectl可以查看[root@localhost ~]# kubectl get namespacesNAME STATUS AGEdefault Active 4dkube-system Active 4d接下来如果不特别致命Namespace则用户创建的Pod,RC,Service都将被系统闯将到default的Namespace中用户可以根据需要创建新的Namespace,通过如下namesapce.yaml文件进行创建apiVersion: v1kind: Namespacemetadata: name: development[root@localhost ~]# kubectl get namespacesNAME STATUS AGEdefault Active 4dkube-system Active 4d[root@localhost ~]# vim namespace.yaml[root@localhost ~]# kubectl create -f namespace.yaml namespace "development" created[root@localhost ~]# kubectl get namespacesNAME STATUS AGEdefault Active 4ddevelopment Active 3skube-system Active 4d接着在创建Pod时候可以指定Pod属于那个NamespaceapiVersion: v1kind: Podmetadata: name: busybox namespace: developmentspec: containers: - image: gcr.io/google_containers/busybox command: - sleep - "3600" name: busybox 在集群中新创建的Pod将会属于development的命名空间[root@localhost ~]# kubectl create -f busybox_pod.yaml pod "busybox" created[root@localhost ~]# kubectl get podsNAME READY STATUS RESTARTS AGEfrontend-kkb8q 1/1 Running 3 4dfrontend-p5hwm 1/1 Running 3 4dfrontend-r70dz 1/1 Running 3 4dredis-master-1t0n6 1/1 Running 3 4dredis-slave-0nh1g 1/1 Running 3 4dredis-slave-cz342 1/1 Running 3 4d此时在kubectl get命令无法显示刚才创建的busybox因为不加参数kubectl仅仅显示default的命名空间的对象[root@localhost ~]# kubectl get pods --namespace=developmentNAME READY STATUS RESTARTS AGEbusybox 1/1 Running 0 1m使用Namespace来组织kubernetes的各种对象可以实现对用户的分组1.8 Annotation注释 Annotation与label类似,也使用key/value键值对形式进行定义,Label具有严格的命名规则,定义的是kubernetes对象的元数据,并且用于label Selector, Annotation则是用户任意定义的附加信息,便于外部工具进行查找 用Annotation来记录的信息包括 build信息,release信息,docker镜像信息 日志库,监控库,分析库等资源库的地址信息 程序调试工具信息 团队联系信息以上这些组件就是kubernetes系统的核心组件,他们共同构成了kubernetes系统的框架和计算模型,可以通过灵活组合,用户就可以快速的方便的对容器集群进行配置,创建和管理,除了以上组件还有许多可以配置的资源对象,LimitRange,ResourceQuota