龙空技术网

动手动脑学Kubernetes系列之Pod介绍

Char的沉淀 460

前言:

当前姐妹们对“kubernetes登录pod”大体比较着重,看官们都需要分析一些“kubernetes登录pod”的相关内容。那么小编也在网摘上网罗了一些关于“kubernetes登录pod””的相关内容,希望看官们能喜欢,朋友们快快来了解一下吧!

在之前的文章中, 介绍了搭建好的minikube环境,如果你现在还没有一个可用的minikube环境, 那么可以去该篇文章中直接下载;

在之前的两篇文章中, 先后介绍了如何从源代码开始构建一个Node.js应用和Spring Boot 应用, 并且部署到Kubernetes 中(这个Kubernetes 环境主要是之前建好的#minikube#) , 现在我们开始进一步深入的学习Kubernetes, 用一个个可以实际运行的例子的形式, 深入理解Kubernetes的概念以及原理.

本篇是动手动脑学Kubernetes系列的第一篇, 动手动脑学Kubernetes, 就是先动手体验, 然后再理论学习, 让你从例子中体会Kubernetes 的具体用法, 然后再去学习Kubernetes的理论知识, 达到实际操作的升华!

首先来从Pod 开始!

先从镜像开始

我们之前的文章里面, 都是先从源代码开始, 然后制作镜像, 这次我们省略源代码的步骤, 直接从镜像注册中心拉取一个镜像.

本着先动手, 在动脑的方法, 我们先来下载一个Docker 镜像, 这次我们需要使用DockerHub 之外的另外一个镜像注册中心: Quay.io.

Quay.io是什么呢? 这就得先从镜像注册中心(Container Registry)开始谈起了.

什么是容器注册表(Container Registry)?

容器注册表的用途非常简单明了:它们托管您创建的容器和/或其他人创建并要使用的容器的映像。它们还允许您上载容器映像的新版本,并跟踪多次迭代中的版本历史。

从这个意义上讲,容器注册表类似于GitHub(或GitLab,或者国内的Gitee)存储库,不同之处在于容器注册表托管容器映像而不是源代码。

确实,与容器注册表相关的一些关键术语也与Git相似。例如,用于从存储库下载容器映像的术语是pull,它或多或少与Git中的pull命令等效。同样,push是Docker CLI和Git中的命令,用于将容器镜像或源代码上传到注册表或存储库。

实际上,我们认为,如果我们将容器注册表称为容器存储库,那么会减少混乱。

集装箱登记处的类型

那里有很多容器注册表。它们可以分为几个不同的类别:

基于云的注册表:由第三方提供商(例如Docker Hub)托管在公共云中的注册表。本地注册表:您可以在自己的基础结构上安装的注册表。您可以使用Docker,通过Docker Registry(不同于Docker Hub)或使用第三方注册表(如Quay)手动创建本地注册表。公共注册表:任何人都可以访问的注册表。 Docker Hub就是一个例子。 Quay.io也是如此,它是使用Quay构建的托管公共注册表。 (要清楚,您可以将Quay本身安装在基础结构上; Quay.io是Quay的托管实现,旨在供公众访问。)私人注册表:需要权限才能上载或下载容器映像的注册表。即使可以公开访问许多Docker Hub注册表,也可以使用Docker Hub之类的服务来创建私有注册表。

这次我们不采用DockerHub的镜像, 而是使用另外一个镜像, Quay.io, 一个Redhat OpenShift 支持的注册中心, 实际上用法差不多.

Quay.io是一个容器注册表,用于存储容器,Helm图表和其他与容器相关的内容。 对于想要建立自己的公共存储库的人来说,该服务是免费的;如果您要创建私人存储库,则需要付费。 Quay.io还包括用于构建和扫描镜像的功能。

不过你首先需要登录到Quay.io 页面上去创建账号:

然后需要在命令行里登录一下:

vis

输入配置好的账号密码就可以了, 然后可以尝试下载一个镜像试一下:

docker pull quay.io/openshiftlabs/simpleservice:0.5.0
在Kubernetes中运行镜像, 创建Pod

没有问题之后, 就可以在minikube 上面直接运行这个镜像:

kubectl run sise --image=quay.io/openshiftlabs/simpleservice:0.5.0 --port=9876

这里面需要注意的一个点就是, 老版本的kubectl版本将产生一个Deployment资源,而较新的版本将产生单个pod资源。

我们来验证一下运行的结果:

kubectl get podskubectl get deployments

运行结果:

从结果中我们可以看出, sise 这个pod 是创建成功了而且处于运行状态; 而并没有产生Deployment 资源.而且, 这就与我们之前的练习结果有所不同, 之前都是先创建一个Deployment 文件, 通过这个文件来指明需要创建的Deployment 资源, Kubernetes 根据这个Deployment 描述来创建Pod, 而这次直接使用kubectl run --image, 也可以产生pod 资源.

来看看kubectl run的作用, 学习各种命令的最好的方法, 就是看帮助文档, 因此我们来看这个kubectl run --help:

[vagrant@control-plane ~]$ kubectl run --help

Create and run a particular image in a pod.

Examples:

# Start a nginx pod.

kubectl run nginx --image=nginx

# Start a hazelcast pod and let the container expose port 5701.

kubectl run hazelcast --image=hazelcast/hazelcast --port=5701

# Start a hazelcast pod and set environment variables "DNS_DOMAIN=cluster" and

"POD_NAMESPACE=default" in the container.

kubectl run hazelcast --image=hazelcast/hazelcast --env="DNS_DOMAIN=cluster"

--env="POD_NAMESPACE=default"

# Start a hazelcast pod and set labels "app=hazelcast" and "env=prod" in the container.

kubectl run hazelcast --image=hazelcast/hazelcast --labels="app=hazelcast,env=prod"

# Dry run. Print the corresponding API objects without creating them.

kubectl run nginx --image=nginx --dry-run=client

# Start a nginx pod, but overload the spec with a partial set of values parsed from JSON.

kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'

# Start a busybox pod and keep it in the foreground, don't restart it if it exits.

kubectl run -i -t busybox --image=busybox --restart=Never

# Start the nginx pod using the default command, but use custom arguments (arg1 .. argN) for that

command.

kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>

# Start the nginx pod using a different command and custom arguments.

kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>

可以看到, kubectl 可以根据容器镜像直接生成一个Pod 资源, 可以指定这个Pod 资源的端口, 设置Pod 资源里面运行容器的变量, 还可以指定dry run(也就是干烧, 只冒烟不实际运行), 相当于模拟运行.

之前我们使用kubectl 创建Deployment 部署文件的时候, 其实也借助了这个kubectl create --dry-run选项, 这个是kubectl 一个比较强大的功能!

kubectl create deployment hello-springwebflux --image=hintcnuie/hello-springwebflux --dry-run=client  -o=yaml > deployment.yaml

回到我们这个例子, 此容器镜像包含curl的命令,因此我们可以用另一种方式来验证主web服务进程是否正在响应(至少在本地网络上):

kubectl exec sise -t -- curl -s localhost:9876/info

结果:

$ kubectl exec sise -t -- curl -s localhost:9876/info

{"host": "localhost:9876", "version": "0.5.0", "from": "127.0.0.1"}

可以看到, 我们直接调用在Pod 资源里面运行的容器的命令, 成功调用了容器里面的本机端口, 来看看kubectl exec的用法:

Execute a command in a container.Examples:  # Get output from running 'date' command from pod mypod, using the firstcontainer by default  kubectl exec mypod -- date    # Get output from running 'date' command in ruby-container from pod mypod  kubectl exec mypod -c ruby-container -- date    # Switch to raw terminal mode, sends stdin to 'bash' in ruby-container frompod mypod  # and sends stdout/stderr from 'bash' back to the client  kubectl exec mypod -c ruby-container -i -t -- bash -il    # List contents of /usr from the first container of pod mypod and sort bymodification time.  # If the command you want to execute in the pod has any flags in common (e.g.-i),  # you must use two dashes (--) to separate your command's flags/arguments.  # Also note, do not surround your command and its flags/arguments with quotes  # unless that is how you would execute it normally (i.e., do ls -t /usr, not"ls -t /usr").  kubectl exec mypod -i -t -- ls -t /usr    # Get output from running 'date' command from the first pod of the deploymentmydeployment, using the first container by default  kubectl exec deploy/mydeployment -- date    # Get output from running 'date' command from the first pod of the servicemyservice, using the first container by default  kubectl exec svc/myservice -- date

可以看到, kubectl exec 可以直接在Pod里面的容器里面运行命令, 所要运行的命令通过-- 后面的字符串指定, 通过-c 来指定是Pod 中的哪个容器, 要知道Pod 里面的容器, 有可能是一个, 也有可能会是多个(这称之为sidecar模式), 所以可以用-c 来进一步过滤.

kubectl exec可以在线检查Pod 容器情况, 相当于打开在Pod 里面的容器里面打开了一个命令行, 因而对于故障排查非常有帮助.

最后, 我们清除环境, 删除了这个sise pod 以及相关资源:

kubectl delete pod,deployment sise
Pod 究竟是什么

来看看Pod 的正式定义:

Pod是Kubernetes中可以创建和管理的最小的可部署计算单元。

Pod是一组一个或多个容器,具有共享的存储和网络资源,以及有关如何运行这些容器的规范。 Pod的内容始终位于同一位置,并在同一时间安排,并在共享上下文中运行。

Pod为特定于应用程序的“逻辑主机”建模:它包含一个或多个相对紧密耦合的应用程序容器。 在非云环境中,在同一物理或虚拟机上执行的应用程序类似于在同一逻辑主机上执行的云应用程序。

除应用程序容器外,Pod还可包含在Pod启动期间运行的init容器。 如果集群提供此功能,则还可以注入临时容器进行调试。

这一段的定义很是简单明了, 就是说Pod 是Kubernetes创建和管理的最小单元, 里面包含一个或者多个容器, 而且共享上下文(Context), 在这里有一个比喻, 我看很多国内的文档里面并没有讲到, 可以扩展一下.

首先要讲一下Pod 这个词, Pod, 原意是一个几何词语。球形或方形的小物件,

Pod这个词我们其实是不陌生的, 我第一反应就是,iPod, 当年乔布斯推广的音乐播放器, 现在来看也是很漂亮的一个设备.

Apple 公司似乎对于Pod 这个名字是情有独钟, 现在流行的Air Pods, 仍然是以Pod 结尾:

Air Pods

现在有这么几个含义:

豆荚, 扁豆类植物的长而狭窄的扁平部分,例如豆类和豌豆,含有种子,通常皮厚. 这个是植物方面的一个名词, 比如豌豆荚,我们玩的植物大战僵尸的豌豆战士...

看看这个豌豆战士, 是不是很形象地表达出豆荚的含义?

细长容器(例如安装在飞机上的),用于运输发动机、武器、以及额外的燃料等, 比如飞机的吊舱, 航空舱等。

其实本质意思可以用"匣" 这个汉字来表达. 匣子, 就是特指这类细长类物体的容器.

这个是一个现代的用语, 同时有一个引申的用法, 就是是特指小型的简单建筑物,或建筑物中的小型简单结构,通常是圆形的. 对于这类物体, 这里我们中文一般用xx舱来标识,

这方面,我们有很多例子, 比如返回舱, 其实就是space pod:

神舟五号返回舱

3.一些海洋哺乳动物组成的社交型的群体, 例如鲸鱼或者海豚组成的"队伍", 这里面我用的是"队伍", 而不仅仅是'群', 因为这是一个社交型的团队, 其中母亲和下一代的关系是最亲密的, 而且团队成员之间会相互保护, 所以不能称之为"群", 而是团队, 队伍.

Whale Pod

鲸鱼团队中的成员规模, 按照鲸鱼的类别不同, 其成员数量也不一样:

可以看出, 对于齿鲸来说, 一般在6个以上, 多的在20个左右.

对于团队管理而言, <<天下无贼>>里面, 黎叔有句名言: 人心散了, 队伍不好带了. 放在Pod的语境中, 其实就是当一个Pod 里面包含的容器很多时, 整个Pod就会陷入混乱! 如果没有高明的管理手段,

人心散了

队伍不好带了

通过对上面对Pod 这个英语单词的三种释义, 我们能更好的理解Kubernetes Pod 的含义.

首先, Pod 在国内大多数是以第一类为主, 也就是豌豆荚的含义, 这个从容器的角度是很好解释的, Pod 里面可以包含一个或者多个容器, 就像一个豆荚里面会包含几颗豆子一样, 这里豆子类似于容器, 豆荚会给予豆子以保护和营养(豆荚的管理功能).

其次, 从Pod中容器的相互关系来看, 把Pod 类比于鲸鱼群的社交单位也是可以的, Pod 里面的容器并不是孤立的, 他们是相互合作的, 这里面可以这么细分:

Pod 里面只有一个容器,"one-container-per-Pod"----一个Pod 一个容器, 这种属于"独生儿女", 不需要合作.“每个容器一个容器”模型反而是最常见的Kubernetes的用法。 在这种情况下,类似于豆荚,可以将Pod视为单个容器的包装盒(匣); Kubernetes管理Pod而不是直接管理容器。

Pod 里面有多个相互合作的容器,这属于"一个Pod多个容器"模型. Pod可以封装一个应用程序,这个应用程序由紧密关联且需要共享资源的多个位于同一地点的容器组成。 这些位于同一地点的容器形成了一个单一的服务单元.

例如,一个容器向公众提供存储在共享卷中的数据,而一个单独的sidecar容器则刷新或更新这些文件。 Pod将这些容器,存储资源和临时网络标识包装在一起,成为一个单元。

在这里Kubernetes 有一个注意提示, 提示这种"单Pod多容器"模型是高级用法, 谨慎使用:

在单个Pod中将多个位于同一地点并受共同管理的容器分组是一个相对高级的用例。 您仅应在容器紧密耦合的特定实例中使用此模式。

尽管Pod 有上面这两种模型, 但是Pod 的用法是一致的, 每个Pod 都是一个给定应用程序的一个实例(instance), 如果需要水平扩展一个应用程序的话(水平扩展, 意味着提供更多的资源, 运行更多的实例), 那么就需要扩展更多的Pod, 每个Pod 代表一个实例. 这种水平扩展, 在Kubernetes术语中称之为"复制(replication)", 复制的多个Pod会被作为一个组来创建和管理, 而管理这些组的则是工作负荷(workload)资源以及相应的控制器(controller).

Pods 和 控制器(controllers)

资源的控制器在Pod失败的情况下处理复制和退回(rollout)以及自动修复。 例如,如果某个节点发生故障,则控制器会注意到该节点上的Pod已停止工作,并创建了一个替换Pod。 调度程序将替换的Pod放置在健康的节点上。

下面几个控制器是管理一个或多个Pod的工作负载资源的一些示例:

DeploymentStatefulSetDaemonSet

我们最先接触的就是Deployment资源, 我们在之前的用法中就已经了解到, 一个Deployment 文件就是可以描述和定义一个Pod, 而这个Deployment 文件, 实际上就相当于一个PodTemplate,也就是Pod 模板.

PodTemplate是创建Pod 的规范, 每个工作负荷资源(workload resource, 比如Deployment, Job, 以及DaemonSet) 的控制器(controller), 都会使用PodTemplate来创建实际的Pod, PodTemplate就是一个目标状态的定义, 而背后的工作资源对象以及控制器会在背后去实现这个目标状态, 这也是为什么称Kubernetes的资源管理为"声明式", 就是在这里.

下面是一个Job 的模板的声明

apiVersion: batch/v1kind: Jobmetadata:  name: hellospec:  template:    # This is the pod template    spec:      containers:      - name: hello        image: busybox        command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']      restartPolicy: OnFailure    # The pod template ends here
PodTemplate的修改和生效

对于Pod template模板的修改,或者切换到新的pod template, 对于已经存在的Pod 来说并没有直接的效果; 如果更改了工作负荷资源的Pod template 模板, 这些资源需要创建"替代版"的Pod, 这些替代版Pod使用的是更新过的新"版本"template.

例如, StatefulSet Controller能够确保, 对于每个StatefulSet对象, 其正在运行的Pod都会和当前的Pod template模板保持一致; 如果你编辑StatefulSet对象并更新了里面的pod 模板, 那么StatefulSet就会基于新的Pod template来创建新的Pod, 最终所有的旧的Pod会被新的Pod所取代, 这时更新才算结束.

每个工作负荷资源的实现都有其单独的规则(rule)去处理Pod template的更新, 对于StatefulSet以及其更新策略, 会在后续的文章中给予介绍.

Pod的更新和替换

Kubenetes并不会阻止用户直接管理Pod, 更新一个正在运行的Pod的某些值是允许的, 但是, Pod的更新操作,例如patchreplace, 有一些限制:

关于Pod的大多数元数据都是不可变的。 例如,您不能更改namespace,name,uid或creationTimestamp字段。 generation是独一无二的。 它仅接受会增加字段当前值的更新。如果设置了metadata.deletionTimestamp,则不能将新条目添加到metas.finalizers列表中。Pod更新可能不会更改spec.containers [*].image,spec.initContainers [*].image,spec.activeDeadlineSeconds、spec.tolerations以外的其他字段。 对于spec.tolerations,您只能添加新条目。更新spec.activeDeadlineSeconds字段时,允许两种类型的更新:将未分配字段设置为正数;将字段从正数更新为较小的非负数。Pod中的资源共享和通信

Pod 允许其中的容器之间数据共享和相互通信

Pod的存储空间(Storage)

Pod可以指定一组共享存储卷(volume)。 Pod中的所有容器都可以访问共享卷,从而使这些容器可以共享数据。 卷还允许Pod中的持久数据保留下来,以防其中的容器之一需要重新启动。 有关Kubernetes如何实现共享存储并将其提供给Pods的更多信息,请参见存储。

Pod的网络通信

针对每个网络系列,每个Pod都会被分配一个唯一的IP地址。

Pod中的每个容器都共享网络名称空间,包括IP地址和网络端口。在Pod内部(并且只有那时),属于Pod的容器可以使用localhost相互通信。

当Pod中的容器与Pod外部的实体进行通信时,它们必须协调它们如何使用共享的网络资源(例如端口)。在Pod中,容器共享一个IP地址和端口空间,并且可以通过localhost找到彼此。

Pod中的容器还可以使用标准的进程间通信(例如System V信号量或POSIX共享内存)相互通信。不同Pod中的容器具有不同的IP地址,并且没有特殊配置就无法通过IPC进行通信。想要与在其他Pod中运行的容器进行交互的容器可以使用IP网络进行通信。

Pod中的容器将系统主机名视为与Pod的配置名称相同。

Kubernetes 网络结构图

Pod网络还是比较复杂的, 这个需要在以后的文章中用更多的篇幅来介绍, 这里只需要暂时理解这些基础就可以了.

容器的特权模式

Pod中的任何容器都可以使用容器规范的安全上下文上的特权标志来启用特权模式。这对于想要使用操作系统管理功能(如操纵网络堆栈或访问硬件设备)的容器很有用。特权容器中的进程几乎获得与容器外部进程相同的特权。

注意:容器运行时必须支持特权容器的概念才能使此设置相关。

回顾

在这篇文章中, 我们先学习了容器注册中心, 并介绍了#Quay.io#, 一个和DockerHub 不同的注册中心, 然后我们通过kubectl run来创建一个运行的Pod, 并通过kubectl exec来验证Pod 中运行的容器功能;

docker login quay.io

登录容器注册中心

kubectl run --image=

运行指定的镜像, 生成Pod

kubectl exec <pod>

-- <cmd>

在Pod特定容器上运行指令

kubectl delete

删除资源

在第二部分,我们从原理部分学习Pod知识, 先从字面意思上了解Pod的三个含义, 然后结合这三方面的含义, 来学习Pod的两种模型, 以及PodTemplate和修改情况; 最后, 了解Pod 的数据存储和网络模型情况.

下一篇是讲解Kubernetes中标签(Label)的使用,标签用起来很简单, 但是在Kubernetes世界里面, 是非常强大的工具, 用来进行资源选择和过滤, 有等值选择和集合选择两种语法, 具体参见动手动脑学Kubernetes系列之Label介绍

Whales Pod

标签: #kubernetes登录pod