Kubernetes:让容器编排管理变得容易高效_命名空间本文是一篇读书笔记,个人觉得内容可以进一步加深了解容器技术应用。

Kubernetes是什么?

Kubernetes(简称k8s) 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、支持和工具广泛可用。

pod介绍

pod是一组并置的容器,是Kubernetes的基本构建模型。一个pod的所有容器(docker)都运行在同一个工作节点上,绝不会跨越多个工作节点。

pod是Kubernetes中最为重要的核心概念,本文主要围绕 pod 的概念、管理及使用展开。

Kubernetes:让容器编排管理变得容易高效_选择器_02

为什么需要pod而不直接使用容器

多个容器比单个容器中包含多个进程要好,如果一个容器运行多个进程,在需要查看每个进程的运行日志将非常困难,不利于排查问题。

了解pod

pod是逻辑主机,其行为与非容器世界中的物理主机或者虚拟机非常相似。

由于不能将多个进程聚集在一个单独的容器中,因此就需要pod将容器作为一个单元进行管理。在包含容器的pod下,既可以同时运行密切相关的进程,又能保持一定的隔离。

同一个Pod中容器之间的部分隔离

同一个pod中的所有容器都在相同的network和UTS命名空间下运行,因此它们都共享相同的主机名和网络接口。当涉及文件系统时,每个容器的文件系统和其他容器是完全隔离的。

容器如何共享相同的ip和端口空间

由于一个pod中的容器运行于相同的Network命名空间中,因此他们共享相同的IP地址和端口空间,可以通过localhost与同一个pod中的其他容器通信。

对于端口,同一pod中的容器运行的多个进程绑定到相同的端口号会导致冲突,对于不同pod中的容器则永远不会出现端口冲突。

平坦pod间网络

Kubernetes集群中所有pod都在同一个共享网络地址空间中,可以通过IP地址来实现相互访问。

Kubernetes:让容器编排管理变得容易高效_选择器_03

通过pod合理管理容器

由于pod比较轻量,可以在几乎不导致任何额外开销的前提下拥有尽可能多的pod,将应用组织到多个pod中,而每个pod只包含紧密相关的组件或进程。

  • 将多层应用分散到多个pod中:如果有一个双节点的Kubernetes集群,如果只用一个pod,始终只会用一个工作节点,而不会充分利用第二个节点上的计算资源。合理做法是前端后端分别部署在不同节点上。
  • 基于扩缩容考虑而分割到多个Pod中:pod也是扩缩容的基本单位,如果全部部署在一个pod中,扩缩容会导致所有的应用层都将受影响。如前端和后端,就无法只对后端进行扩缩容。不利于资源利用。
  • 何时在Pod中使用多个容器:应用由一个主进程和一个或多个辅助进程组成
  • 决定何时在Pod中使用多个容器:容器不应该包含多个进程,Pod也不应该包含多个并不需要运行在同一个主机上的容器

Kubernetes:让容器编排管理变得容易高效_docker_04

以YAML或者JSON描述文件创建Pod

使用YAML描述文件创建,可以存储在版本控制系统中,方便维护

Kubernetes:让容器编排管理变得容易高效_命名空间_05

主要部分:

* `metadata`:包括名称、命名空间、标签和关于该容器的其他信息
* `spec`:包含pod内容的实际说明,如容器、卷和其他数据
* `status`:包含运行中的pod的当前信息,如条件、描述、状态、IP等

为pod创建一个简单的YAML描述文件

apiVersion: v1
kind: Pod
metadata:
name: kubia-manual //pod名称
spec:
containers:
- image: luksa/kubia
name: kubia
ports:
- containerPort: 8080 //应用监听的端口
protocol: TCP

使用kubectl create 创建pod

​kubectl create -f kubia-manual.yaml​

获得运行中Pod的完整定义

  • 返回yaml格式:​​kubectl get po kubia-manual -o yaml​
  • 返回json格式:​​kubectl get po kubia-manual -o json​

在pod列表中查看新创建的pod

​kubectl get pods​

查看应用日志

使用 docker logs

容器化的应用程序会将日志记录到标准输出和标准错误流,不会写入文件,允许用户可以通过简单、标准的方式查看。

容器运行是将这些流重定向到文件,可以通过以下命令获取容器日志:

​docker logs <container id>​

可以通过ssh命名登录到pod正在运行的节点,并使用docker logs命令查看其日志。

使用kubectl logs

查看pod的日志,只需要在本地机器上运行以下命令:​​kubectl logs kubia-manual​

获取多容器pod的日志

获取多容器pod的日志时需指定容器名称,使用​​-c <容器名称>​​来显式指定容器名称

​kubectl logs kubia-manual -c kubia​

向pod发送请求

将本地网络端口转发到pod中的端口

Kubernetes允许配置端口转发到该pod,如将本地端口8888转发到kubia-manual pod的端口8080。这样就可以通过本地端口连接到pod。

​kubectl port-forward kubia-manual 8888:8080​

通过端口转发连接到pod

在另外的终端上,可以通过运行localhost:8888上的代理,向pod发送一个Http请求:

​curl localhost:8888​

Kubernetes:让容器编排管理变得容易高效_选择器_06

使用标签组织pod

在实际运营中,随着Pod数量的增加,使用标签可以有效的组织。

举例:微服务架构

部署的微服务数量可以很轻松就超过20个,在实际运营过程中面临版本发布、快速扩容等,很容易导致混乱。如图:

Kubernetes:让容器编排管理变得容易高效_命名空间_07

很明显需要一种方式,可以通过一次操作对所有或者某些pod进行操作,而不必要为每个pod执行操作。

因此就需要使用标签来组织pod,标签是Kubernetes的一种简单却强大的特征,可以组织pod,也可以组织其他资源。

还是上面的示例,为pod添加两个标签:

  • ​app​​:指定pod属于那些应用、组件或者微服务
  • ​rel​​:指定pod中运行的应用所属的版本,如stable、beta

Kubernetes:让容器编排管理变得容易高效_Kubernetes_08

创建pod时指定标签

​kubia-manual-with-labels.yaml​

apiVersion: v1
kind: Pod
metadata:
name: kubia-manual-v2
labels: //附加标签到pod上
creation_method: manual
env: prod
spec:
containers:
- image: luksa/kubia
name: kubia
ports:
- containerPort: 8080
protocol: TCP

执行命令创建:​​kubectl create -f kubia-manual-with-labels.yaml​

默认不会列出任何标签,需要执行下面命令来查看:

执行命令:​​kubectl get po --show labels​

如果需要筛选某些标签,可以使用​​-L​​选项来指定,如:

​kubectl get po -L creation_method,env​

修改现有pod的标签

标签可以在现有的pod上进行添加和修改,下面通过命令为​​kubia-manual​​添加标签:

​kubectl label po kubia-manual creation_method=manual​

将名为​​kubia-manual-v2​​​的pod的标签​​env=prod​​​更改为​​env=debug​​​,更改现有标签需要使用​​--overwrite​​选项。

​kubectl label po kubia-manual-v2 env=debug --overwrite​

通过标签选择器列出pod子集

前面我们了解了标签的使用,现在我们来介绍标签选择器,实际使用过程中标签要与标签选择器结合使用才能发挥其作用。

使用标签选择器列出pod

  • 列出包含creation_method标签并且标签值为manual的pod:​​kubectl get po -l creation_method=manual​
  • 列出包含env标签的pod:​​kubectl get po -l env​
  • 列出没有env标签的pod:​​kubectl get po -l '!env'​
  • 其他选择条件:
  • ​creation_method!=manual​​:选择带有creation_method标签并且值不等于manual的pod
  • ​env in (prod,devel)​​:选择带有env标签且值为prod或者devel的pod
  • ​env notin (prod,devel)​​:选择带有env标签,但其值不是pord或者devel的pod

在标签选择器中使用多个条件

标签选择器中同时使用多个条件,每个条件使用逗号分隔,选择的pod或者资源需要全部匹配才算。

​kubectl get po -l app=pc,rel=beta​

使用标签和选择器来约束pod的调度

由于Kubernetes将集群中的所有节点抽象为一个整体的大型部署平台,对于pod实际调度到哪个节点无关紧要。对于每个pod,获得所请求的确切数量的计算资源(CPU、内存等)及其他pod的可访问性,不受该pod所调度到的节点的影响。

在实际情况中,我们有将那些pod调度到哪里的需求,不需要特别说明pod应该调度到哪个节点上,这会使应用程序与基础架构强耦合,违背了Kubernetes对运行在其上的应用程序隐藏实际的基础架构的构想。因此这时可以对节点使用标签和标签选择器,使Kubernetes选择符合一定条件的节点。

使用标签分类工作节点

加入集群中有一个用于通用GPU计算的GPU,希望向节点添加标签来标记这个功能特征,通过将标签gpu=true来实现。

​kubectl label node gke-kubia-85f6-node-orrx gpu=true​

现在就可以使用标签选择器来列出节点:

​kubectl get nodes -l gpu=true​

将pod调度到特定节点

现在创建一个需要执行GPU的新pod,为了让调度器只在提供适当GPU的节点进行选择,在YAML文件中添加一个节点选择器

apiVersion: v1
kind: Pod
metadata:
name: kubia-gpu
spec:
nodeSelector:
gpu: "true" //只将pod部署到包含标签gpu=true的节点上
containers:
- image: luksa/kubia
name: kubia

调度到一个特定的节点

同样,可以将pod调度到某个确定的节点,使用键值:​​kubernetes.io/hostname​​,即节点实际主机名。不建议pod调度到按个节点上,而应该通过标签选择器来选择特定的逻辑节点组。

注解pod

除标签外,pod和其他对象还可以包含注解,也是键值对,本质和标签相似。不同的是注解不能像标签一样用于分组。

注解可以容纳更多的信息,大量使用注解可以为每个pod或者其他API对象添加说明,方便使用者协作。

使用命名空间对资源进行分组

如果将对象分割成完全独立且不重叠的组时,可以考虑命名空间。Kubernetes命名空间简单的为对象名称提供了一个作用域。

命名空间的需求

使用多个命名空间的前提下,可以将包含大量组件的复杂系统拆分为更小的不同组,这些不同组也可以用于在多租户环境中分配资源,如生产、开发、测试环境等。资源名称只需在命名空间内保持唯一即可。

发现其他命名空间及其pod

列出集群中所有命名空间:​​kubectl get ns​

使用​​kubectl get​​命令列出资源时,默认只列出default命名空间下的对象。

列出命名空间​​kube-system​​​的pod:​​kubectl get po --namespace kube-system​

命名空间可以将不属于一组的资源分到不重叠的组中,并为资源名称提供了一个作用域。

创建一个命名空间

命名空间是一种和其他资源一样的Kubernetes资源,因此也可以通过YAML文件来创建。

从YAML文件创建命名空间:

custom-namespace.yaml

apiVersion: v1kind: Namespacemetadata:  name: custom-namespace复制代码

执行命令:​​kubectl create -f custom-namespace.yaml​

使用kubectl create namespace命令创建命名空间

命名空间名称规则:比附符合域名中规定的命名规范,但不允许包含点号,即只能包含字母、数字、横杆(-)

创建:​​kubectl create namespace custom-namespace​

管理其他命名空间中的对象

在指定命名空间中创建资源:

​kubectl create -f kubia-manual.yaml -n custom-namespace​

命名空间提供的隔离

命名空间将对象分隔到不同的组,只允许对属于特定命名空间的对象进行操作,但实际上并不提供正在运行的对象的任何隔离。命名空间之间是否提供网络隔离取决于Kubernetes所使用的网络解决方案。

停止和移除pod

按名称删除pod

删除pod的过程,是先终止pod所有容器

删除单个:​​kubectl delete po kubia-gpu​

删除多个:​​kubectl delete po pod1 pod2​

使用标签选择器删除pod

​kubectl delete po -l create_method=manual​

通过删除整个命名空间来删除pod

​kubectl delete ns custom-namespace​

删除命名空间中的所有pod,但保留命名空间

对于使用kubectl run命名创建的pod,如果需要全部删除掉,需要删除​​ReplicationCcontroller​

删除命名空间中的(几乎)所有资源

​kubectl delete all --all​

使用该命令可以删除当前命名空间中的所有资源,也可以删除​​ReplicationCcontroller​​。当然还是会有些资源会被保留下来,如Secret。