引用三个问题来叙述Kubernetes的pod容器

  1.为什么不直接在一个Docker容器中运行所有的应用进程。

  2.为什么pod这种容器中要同时运行多个Docker容器(可以只有一个)

  3.为什么k8s使用pod这种容器而不直接使用Docker容器

  一个由多个进程进行组成的应用程序,无论是通过ipc(进程间通信)还是本地存储文件进行通信,都要求它们运行于同一台机器上。Docker容器非常像一台独立的机器,此时你可能认为在单个容器中运行多个进程是合乎逻辑的,然而在实践中这种做法并不合理。
  容器被设计为每个容器只运行一个进程(除非进程本身产生子进程)。如果在单个容器中运行多个不相关的进程,那么保持所有进程运行、管理它们的日志等将会是我们的责任。例如,我们需要包含一种在进程奔溃时能够自动重启的机制。同时这些进程都将记录到相同的标准输出中,而此时我们将很难确定每个进程分别记录了什么
综上所述,我们需要让每个进程运行于自己的容器中,而这就是Docker和Kubernetes期望使用的方式。
  由于不能将多个进程聚集在一个单独的容器中,我们需要另一种更高级的结构来将容器绑定在一起,并将它们作为一个单元进行管理,这就是pod背后的根本原理。
  在包含容器的pod下,我们可以同时运行一些密切相关的进程,并为它们提供(几乎)相同的环境,此时这些进程就好像全部运行于单个容器中一样,同时又保持着一定的隔离。这样一来,我们便能全面地利用容器所提供的特性,同时对这些进程来说它们就像运行在一起一样,实现两全其美。
  Docker容器之间彼此是完全隔离的,但此时我们期望的是隔离容器组,而不是单个容器,并让每个容器组内的容器共享一些资源,而不是全部(换句话说,没有完全隔离)。Kubernetes通过配置Docker来让一个pod内的所有容器共享相同的Linux命名空间,而不是每个容器都有自己的一组命名空间。
  由于一个pod中的所有容器都在相同的network和UTS命名空间下运行(在这里我们讨论的是Linux命名空间),所以它们都共享相同的主机名和网络接口。同样地,这些容器也都在相同的IPC命名空间下运行,因此能够通过IPC进行通信。在最新的Kubernetes和Docker版本中,它们也能够共享相同的PID命名空间,但是该特征默认是未激活的。
  注意:当同一个pod中的容器使用单独的PID命名空间时,在容器中执行psaux就只会看到容器自己的进程。
  但当涉及文件系统时,情况就有所不同。由于大多数容器的文件系统来自容器镜像,因此默认情况下,每个容器的文件系统与其他容器完全隔离。但我们可以使用名为Volume的Kubermetes资源来共享文件目录。
  需要强调的一点是,由于一个pod中的容器运行于相同的Network命名空间中,因此它们共享相同的IP地址和端口空间。这意味着在同一pod中的容器运行的多个进程需要注意不能绑定到相同的端口号,否则会导致端口冲突,但这只涉及同一pod中的容器。由于每个pod都有独立的端口空间,对于不同pod中的容器来说则永远不会遇到端口冲突。此外,一个pod中的所有容器也都具有相同的loopback网络接口,因此容器可以通过localhost与同一pod中的其他容器进行通信。
  Kubernetes 集群中的所有pod 都在同一个共享网络地址空间中,这意味着每个pod都可以通过其他pod的IP地址来实现相互访问。换句话说,这也表示它们之间没有NAT(网络地址转换)网关。当两个pod彼此之间发送网络数据包时,它们都会将对方的实际IP地址看作数据包中的源IP。
  因此,pod之间的通信其实是非常简单的。不论是将两个pod安排在单一的还是不同的工作节点上,同时不管实际节点间的网络拓扑结构如何,这些pod内的容器都能够像在无NAT的平坦网络中一样相互通信,就像局域网(LAN)上的计算机一样。此时,每个pod都有自己的IP地址,并且可以通过这个专门的网络实现pod之间互相访问。这个专门的网络通常是由额外的软件基于真实链路实现的。
  总结本文主要内容:pod是逻辑主机,其行为与非容器世界中的物理主机或虚拟机非常相似。此外,运行在同一个pod中的进程与运行在同一物理机或虚拟机上的进程相似,只是每个进程都封装在一个容器之中。
  如何决定何时在pod中使用多个容器?当决定是将两个容器放入一个pod还是两个单独的pod时,我们需要问自己以下问题:·
    1.它们需要一起运行还是可以在不同的主机上运行?
    2.它们代表的是一个整体还是相互独立的组件?
    3.它们必须一起进行扩缩容还是可以分别进行?
  基本上,我们应该倾向于在单独的pod中运行容器,除非有特定的原因要求它们是同一pod的一部分。容器不应该包含多个进程,pod也不应该包含多个并不需要运行在同一主机上的容器。
 
⒉以YAML或JSON描述文件创建pod
  pod和其他Kubernetes资源通常是通过向Kubernetes RESTAPI提供JSON或YAML描述文件来创建的。此外还有其他更简单的创建资源的方法,比如使用kubectl run命令,但这些方法通常只允许你配置一组有限的属性。另外,通过YAML文件定义所有的Kubernetes对象之后,还可以将它们存储在版本控制系统中,充分利用版本控制所带来的便利性。
  pod定义由这么几个部分组成:
    首先是YAML中使用的KubernetesAPI版本和YAML描述的资源类型;
    其次是几乎在所有Kubernetes资源中都可以找到的三大重要部分:·
      1.metadata包括名称、命名空间、标签和关于该容器的其他信息。
      2.spec包含pod内容的实际说明,例如pod的容器、卷和其他数据。
      3·status包含运行中的pod的当前信息,例如pod所处的条件、每个容器的描述和状态,以及内部IP和其他基本信息。
  status部分包含只读的运行时数据,该数据展示了给定时刻的资源状态。而在创建新的pod时,永远不需要提供status部分。
  上述三部分展示了KubernetesAPI对象的典型结构。其他对象也都具有相同的结构,这使得理解新对象相对来说更加容易。
apiVersion: v1  #指定当前描述文件遵循v1版本的KubernetesAPI
kind: Pod #我们在描述一个pod
metadata:
name: kubia-manual #指定pod的名称
namespace: custom-namespace #指定当前描述的pod所在的命名空间
labels: #指定pod标签
creation_method: manual
env: prod
spec:
nodeSelector: #告诉k8s我们希望把当前pod部署到拥有指定标签的节点上,k8s节点拥有一个默认的节点标签,其中键为kubernetes.io/hostname,值为该节点的实际主机名,因此我们可以将pod调度到某个确定的节点。但如果指定节点处于离线状态,通过hostname 标签将nodeSelector设置为特定节点可能会导致pod不可调度。
labelKey: "labelValue"
containers:
- image: fanqisoft/coreqi #创建容器所使用的镜像
name: coreqi #容器的名称
ports:
-containerPort: #应用监听的端口
protocol: TCP
livenessProbe:
httpGet: #一个Http Get 存活探针
path: / #Http请求的路径
port: #探针连接的网络端口
initialDelaySeconds: #kubernetes会在第一次探测前等待15秒,没有没有设置该选项,探针将在启动时立即开始探测容器,如果使用探针,务必设置该选项。

⒊向pod发送请求

  向pod发送请求可以使用kubectl expose命令创建服务然后暴露出来,也可以通过端口转发将本地网络端口转发到pod中的端口访问pod,Kubernetes允许我们配置端口转发到pod,可以通过kubectl port-forward命令完成上述操作。例如以下命令会将机器的本地端口8888转发到我们的kubia-manual pod的8080端口
kubectl port-forward kubia-manual :

⒋pod健康

  1.存活探针(liveness probe)

  Kubernetes可以通过存活探针(liveness probe)检查容器是否还在运行。可以为pod中的每个容器单独指定存活探针。如果探测失败,Kubernetes将定期执行探针并重新启动容器。
  除了存活探针(liveness probe),Kubernetes还支持就绪探针(readiness probe),一定不要混淆两者。它们适用于两种不同的场景。
  Kubernetes有以下三种探测容器的机制:·
    HTTP GET探针对容器的IP地址(你指定的端口和路径)执行HTTPGET请求。如果探测器收到响应,并且响应状态码不代表错误(换句话说,如果HTTP响应状态码是2xx或3xx),则认为探测成功。如果服务器返回错误响应状态码或者根本没有响应,那么探测就被认为是失败的,容器将被重新启动。
    TCP套接字探针尝试与容器指定端口建立TCP连接。如果连接成功建立,则探测成功。否则,容器重新启动。
    Exec探针在容器内执行任意命令,并检查命令的退出状态码。如果状态码是0,则探测成功。所有其他状态码都被认为失败。
  k8s的退出代码有特殊含义,例如退出代码为137,这有特殊的含义——表示该进程由外部信号终止。数字137是两个数字的总和:128+x,其中x是终止进程的信号编号。在这个例子中,x等于9,这是SIGKILL的信号编号,意味着这个进程被强行终止。
  注意,当容器被强行终止时,会创建一个全新的容器—一而不是重启原来的容器。
  对于在生产中运行的pod,一定要定义一个存活探针。没有探针的话,Kubernetes无法知道你的应用是否还活着。只要进程还在运行,Kubernetes会认为容器是健康的。
  简易的存活探针仅仅检查了服务器是否响应。虽然这看起来可能过于简单,但即使是这样的存活探针也可以创造奇迹,因为如果容器内运行的web服务器停止响应HTTP请求,它将重启容器。与没有存活探针相比,这是一项重大改进,而且在大多数情况下可能已足够。
  但为了更好地进行存活检查,需要将探针配置为请求特定的URL路径(例如/health),并让应用从内部对内部运行的所有重要组件执行状态检查,以确保它们都没有终止或停止响应。
  提示:请确保/health HTTP端点不需要认证,否则探测会一直失败,导致你的容器无限重启。
  一定要检查应用程序的内部,而没有任何外部因素的影响。例如,当服务器无法连接到后端数据库时,前端Web服务器的存活探针不应该返回失败。如果问题的底层原因在数据库中,重启Web服务器容器不会解决问题。由于存活探测将再次失败,你将反复重启容器直到数据库恢复。
  存活探针不应消耗太多的计算资源,并且运行不应该花太长时间。默认情况下,探测器执行的频率相对较高,必须在一秒之内执行完毕。一个过重的探针会大大减慢你的容器运行。探针的CPU时间计入容器的CPU时间配额,因此使用重量级的存活探针将减少主应用程序进程可用的CPU时间。
  提示:如果你在容器中运行Java应用程序,请确保使用HTTP GET存活探针,而不是启动全新JVM以获取存活信息的Exec探针。任何基于JVM或类似的应用程序也是如此,它们的启动过程需要大量的计算资源。
  探针的失败阀值是可配置的,并且通常在容器被终止之前探针必须失败多次。但即使你将失败阀值设置为1,Kubernetes为了确认一次探测的失败,会尝试若干次。因此在探针中自己实现重试循环是浪费精力。
  Kubernetes会在你的容器崩溃或其存活探针失败时,通过重启容器来保持运行。这项任务由承载pod的节点上的Kubelet执行——在主服务器上运行的Kubernetes Control Plane组件不会参与此过程。
  但如果节点本身崩溃,那么Control Plane必须为所有随节点停止运行的pod创建替代品。它不会为你直接创建的pod执行此操作。这些pod只被Kubelet管理,但由于Kubelet本身运行在节点上,所以如果节点异常终止,它将无法执行任何操作。
  为了确保你的应用程序在另一个节点上重新启动,需要使用Replicationcontroller或类似机制管理pod。
  
  2.ReplicationController

  ReplicationController是一种Kubernetes资源,可确保它的pod始终保持运行状态。
  如果pod因任何原因消失(例如节点从集群中消失或由于该pod己从节点中逐出),则ReplicationController会注意到缺少了pod并创建替代pod。
  非托管的pod节点异常退出后将没有东西负责重建它,而由ReplicationController管理的pod异常退出后,ReplicationController将会创建一个新的pod来替换异常退出的pod。
  一般而言,ReplicationController旨在创建和管理一个pod的多个副本(replicas)。这就是ReplicationController名字的由来。

  当节点故障时,只有ReplicationController 管理的pod 会被重新创建。

  ReplicationController会持续监控正在运行的pod列表,并保证相应“类型”的pod的数目与期望相符。如正在运行的pod太少,它会根据pod模板创建新的副本。如正在运行的pod太多,它将删除多余的副本。

  你可能会对有多余的副本感到奇怪。这可能有几个原因:

  ·有人会手动创建相同类型的pod。
  ·有人更改现有的pod的“类型”。
  ·有人减少了所需的pod的数量,等等。

  一个ReplicationController有三个主要部分:
    label selector(标签选择器),用于确定ReplicationController作用域中有哪些
    pod·replica count(副本个数),指定应运行的pod数量
    pod template(pod模板),用于创建新的pod副本 

  ReplicationController的副本个数、标签选择器,甚至是pod模板都可以随时修改,但只有副本数目的变更会影响现有的pod。
  更改ReplicationController的标签选择器和pod模板对现有pod没有影响。更改标签选择器会使现有的pod 脱离ReplicationController的监视范围,因此ReplicationController将会停止关注它们。
  在创建pod后,ReplicationController并不关心其pod的实际“内容”(容器镜像、环境变量及其他)。因此,修改ReplicationController的pod模板仅影响由此ReplicationController创建的新pod。
  使用ReplicationController的好处像Kubernetes中的许多事物一样,ReplicationController尽管是一个令人难以置信的简单概念,却提供或启用了以下强大功能:
    ·确保一个pod(或多个pod副本)持续运行,解决方法是在监控的pod丢失时启动一个新pod。
    ·集群节点发生故障时,它将为故障节点上运行的所有pod(即受ReplicationController 控制的节点上的那些pod)创建替代副本。
    ·它能轻松实现pod的水平伸缩,手动和自动都可以
  注意:pod实例永远不会重新安置到另一个节点。ReplicationController的解决方案是根据pod模板创建一个全新的pod实例而不是去移动当前实例,它与正在替换的实例无关。

  ReplicationController的创建

    就像pod和其他Kubernetes资源,可以通过上传JSON或YAML描述文件到Kubernetes API 服务器来创建ReplicationController。

apiVersion: v1  #指定当前描述文件遵循v1版本的KubernetesAPI
kind: ReplicationController #我们在描述一个ReplicationController
metadata:
name: coreqi-manual #指定ReplicationController的名称
spec:
replicas: #pod实例的目标数目
selector: #pod选择器决定了ReplicationController的操作对象
app: coreqi #当前ReplicationController将确保符合标签选择器app=coreqi的pod实例始终是三个,当没有足够的pod时,将使用下面的pod模板创建新的pod
template: #创建新pod所使用的pod模板
metadata:
labels:
app: coreqi #模板中的pod标签显然必须和ReplicationController的标签选择器相匹配,否则控制器将无休止的创建新的pod实例。因为创建新的pod不会使实际的副本数量接近期望的副本数量。为了防止出现这种情况,Kubernetes API服务会校验ReplicationController的定义不会接收错误的配置。
#不指定ReplicationController的标签选择器也是一种选择,因为ReplicationController会自动从模板中提取标签,而且描述文件也将更简短
spec:
containers:
- name: coreqi
image: fanqisoft/coreqi
ports:
- containerPort:

  创建了ReplicationController的描述文件后我们就可以通过相应的指令去创建它了。

kubectl create -f coreqi-rc.yaml

  由ReplicationController创建的pod并不是绑定到ReplicationController。ReplicationController只会管理与当前ReplicationController标签选择器相匹配的pod。通过更改pod的标签,可以将它从ReplicationController的作用域中添加或删除。它甚至可以从一个ReplicationController移动到另一个。
  提示:尽管一个pod没有绑定到一个ReplicationController,但该pod在metadata.ownerReferences字段中引用它,可以轻松使用它来找到一个pod属于哪个ReplicationController。
  如果你更改了一个pod的标签,使它不再与ReplicationController的标签选择器相匹配,那么该pod就变得和其他手动创建的pod一样了。它不再被任何东西管理。如果运行该节点的pod异常终止,它显然不会被重新调度。但请记住,当你更改pod的标签时,ReplicationController发现一个pod丢失了,将会启动一个新的pod替换它。
  例如,一个ReplicationController管理具有app=coreqi标签的pod,当我们对一个pod删除这个标签或修改其值时,ReplicationController会将该pod移出管理范围。添加新的标签并没有用,因为ReplicationController 并不关心该pod是否有任何附加标签,它只关心该pod是否具有当前ReplicationController标签选择器中引用的所有标签。

  更改ReplicationController的pod模板只影响之后创建的pod,并且不会影响现有的pod。要修改旧的pod,需要删除它们,并让ReplicationController根据新模板将其替换为新的pod。

Kubernetes基石-pod容器的更多相关文章

  1. kubernetes concepts -- Pod Overview

    This page provides an overview of Pod, the smallest deployable object in the Kubernetes object model ...

  2. 基于Kubernetes构建企业容器云

    前言 团队成员有DBA.运维.Python开发,由于需要跨部门向公司私有云团队申请虚拟机, 此时我在思考能否在现有已申请的虚拟机之上,再进行更加细粒度的资源隔离和划分,让本团队的成员使用, 也就是在私 ...

  3. 腾讯基于Kubernetes的企业级容器云平台GaiaStack (转)

    GaiaStack介绍 GaiaStack是腾讯基于Kubernetes打造的容器私有云平台.这里有几个关键词: 腾讯:GaiaStack可服务腾讯内部所有BG的业务: Kubernetes:Gaia ...

  4. Kubernetes之POD

    什么是Pod Pod是可以创建和管理Kubernetes计算的最小可部署单元.一个Pod代表着集群中运行的一个进程. Pod就像是豌豆荚一样,它由一个或者多个容器组成(例如Docker容器),它们共享 ...

  5. Kubernetes探索学习004--深入Kubernetes的Pod

    深入研究学习Pod 首先需要认识到Pod才是Kubernetes项目中最小的编排单位原子单位,凡是涉及到调度,网络,存储层面的,基本上都是Pod级别的!官方是用这样的语言来描述的: A Pod is ...

  6. Kubernetes+Docker+Istio 容器云实践

    随着社会的进步与技术的发展,人们对资源的高效利用有了更为迫切的需求.近年来,互联网.移动互联网的高速发展与成熟,大应用的微服务化也引起了企业的热情关注,而基于Kubernetes+Docker的容器云 ...

  7. Kubernetes之Pod使用

    一.什么是Podkubernetes中的一切都可以理解为是一种资源对象,pod,rc,service,都可以理解是 一种资源对象.pod的组成示意图如下,由一个叫”pause“的根容器,加上一个或多个 ...

  8. 026.[转] 基于Docker及Kubernetes技术构建容器云平台 (PaaS)

    [编者的话] 目前很多的容器云平台通过Docker及Kubernetes等技术提供应用运行平台,从而实现运维自动化,快速部署应用.弹性伸缩和动态调整应用环境资源,提高研发运营效率. 本文简要介绍了与容 ...

  9. kubernetes之pod健康检查

    目录 kubernetes之pod健康检查 1.概述和分类 2.LivenessProbe探针(存活性探测) 3.ReadinessProbe探针(就绪型探测) 4.探针的实现方式 4.1.ExecA ...

随机推荐

  1. 【模板】强连通分量和tarjan算法

    看了好久才终于明白了这个算法..复杂度是O(n+m). 我觉得这个算法不是很好理解,但是看懂了以后还是觉得听巧妙的. 下面给出模板代码和三组简单数据帮助理解. 代码如下: #include <s ...

  2. 【转】Qt编写串口通信程序全程图文讲解

    本文章原创于www.yafeilinux.com 转载请注明出处. (说明:我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写,程序稍有不同,请自 ...

  3. Python可变参数函数用法详解

    来自:http://c.biancheng.net/view/2257.html 很多编程语言都允许定义个数可变的参数,这样可以在调用函数时传入任意多个参数.Python 当然也不例外,Python ...

  4. Bootstrap4从入门到精通视频教程

    一.布局 0.课件1.Bootstrap介绍_栅格系统2.禁用响应式_响应式分界点 二.内容 3.排版_代码4.图片_图片框5.表格 三.公共样式 6.边框_浮动7.颜色_Display显示属性8.文 ...

  5. adb、pm命令操作apk包

    1.adb shell pm list package 打印出来所有安装到手机上的APP包名 2.adb shell pm path com.xxx.xxx 找出安装后的包名应用的apk所在位置 3. ...

  6. pytorch-Alexnet 网络

    Alexnet网络结构, 相比于LeNet,Alexnet加入了激活层Relu, 以及dropout层 第一层网络结构: 11x11x3x96, 步长为4, padding=2 第二层网络结构: 5x ...

  7. mysql授权指定ip远程登录

    use user //更新用户表: UPDATE `user` SET `Host` = '175.6.6.230' where `Host` = '175.6.6.230'; //授权用户表: GR ...

  8. 记一个微信支付-1错误JSAPI缺少参数app|get_brand_request:Fail

    最近公司要做一个H5小游戏里边涉及到微信公众号支付,中间摸爬滚打遇到了很多坑.记录一下,留待后人看. 我们来看一下这个方法 GetJsApiParameters 怎么样,看起来像不像输出了一个JSON ...

  9. 动态绑定v-model

    <template> <div class="pieAll" > <template v-for="(item, index) in tes ...

  10. Thinkphp5 的sesssion在同一个控制器不同的方法无法获取session的原因和对策

    这一段在用thinkPHP5开发微信小程序接口的时候,在同一个控制器一个方法中存入session,在另一个方法中取出session,一直都是无法取出. 查阅各种资料得到原因:thinkPHP5里面的s ...