从Docker到Kubernetes——Kubernetes设计解读之Pod

Kubernetes是个什么样的项目

简单的说,k8s是一个管理跨主机容器化应用的系统,实现了包括应用部署、高可用管理和弹性伸缩在内的一系列基础功能并封装成为一套完整、简单易用的RESTful API对外提供服务。

k8s的设计哲学之一就是维护应用容器集群一直处于用户所期待的状态,为了践行这一价值观,k8s建立了一套健壮的集群自恢复机制,包括容器的自动重启、自动重调度以及自动备份等等。

不难发现,k8s主要的服务对象是由多个容器组成而成的复杂应用,如弹性、分布式的服务架构。为此k8s引入了专门对容器进行分组管理的pod,从而建立了一套将非容器化应用平滑的迁入到容器云上的机制。

k8s对外提供容器服务的模式是这样的:用户提交容器集群运行所需资源的申请(通常是一个配置文件),然后由k8s负责完成这些容器的调度任务,即自动为这些容器选择运行的宿主机

Kubernetes的设计解读

典型案例:GuestBook

在这个例子重,Kubernets集群重会部署这样一个应用:

  • PHP网站,并运行3个副本来实现高可用。
  • PHP网站在Redis里存储了一个数据,不定期的进行读写。
  • Redis服务包含1个master和2个slave,读请求由slave处理,写请求交给master。

我们之前的Docker案例同样也能运行这样一个集群,然后使用负载均衡组建来完成多个Redis slave之间以及php实例之间的请求分配,当然这其中也会自己搭建一些服务发现的组件,来保证自动化管理的过程。

那么这样一个集群在k8s的管理下又是什么样的呢?

  • 在k8s下,所有容器(包括php和redis的节点)都会被分配到一个“副本控制器”(replication controller),并且指定了php副本的数量为3,redis salve数量为2,redis master的数量为1。
  • 用户在创建容器的时候,会给每个容器指定一个用来分组的标签label:比如所有php网站容器都属于name=frontend这个组。在调度的时候,k8s就可以根据这些标签来进行一些决策。比如,从高可用的角度除法,用户可以指定所有name=frontend标签的容器不会被调度在同一台node上。
  • 这些容器可以直接使用IP:Port的方式进行通信,但是由于重新调度或者重启之后Docker容器的IP会发生变化,所以k8s内置了一个名为service的代理组件。当为某些容器分配了一个service代理后,这些容器就可以被一个固定的ip(cluster IP)访问到,省去了用户自己搭建负载均衡的麻烦(当然也可以自己使用负载均衡的组件代替service)。
  • 最后,也是最重要的,上述replication controller、label以及service,真正的操作对象都是一个称为pod的逻辑对象,而非容器。pod可以想象成一个篮子,容器则是篮子里的鸡蛋,当k8s调度容器的时候,是把一个篮子连同里面的鸡蛋从一个宿主机调度到另一个宿主机。篮子和鸡蛋的关系表现如下:1.label是贴在篮子上的。2.IP分配给篮子而不是容器,篮子里的容器共享这个IP。3.哪怕只有一个鸡蛋(容器),k8s也会给它一个篮子。

pod设计解读

在k8s中,能被创建、调度和管理的最小单位是pod,而非单个容器。pod里的容器共享network namespace,并通过volume机制共享一部分存储。

  • pod是IP等网络资源的分配的基本单位,在IP及其对应的network namespace是有pod里的容器共享
  • pod内的所有容器共享volume。当又一个volume被挂载在同属一个pod的多个Docker容器的文件系统上时,该volume可以被这些容器共享

这样做的好处是,一是,通过k8s volume机制,在容器之间共享存储。二是,可以通过localhost直接访问另一个容器。

试想一下,之前我们单机部署容器的时候,说明了非单机下容器之间的联系十分麻烦,比如需要共享volume,需要知道PID等等,所以跨主机连接我们直接干脆没学。k8s提供的机制,就将上述难题迎刃而解了。

所以,当系统运行着数量庞大的pod的时候,用户或者系统管理员如何有效的定位与组织这些pod就成了一个重要问题。k8s的解决方案是label,每个pod都有一个属性"labels"的键值对,比如:

"labels":{
	"key1":"value1",
	"key2":"value2"
}

通过命令-l key=value参数,可以方便的实现定位。比如例举所有标签{“name”:“nginx”}的pod可以这么操作:

kubectl get pods -l name=nginx

pod使用实例

k8s的安装:云服务器下Kubernetes的安装和配置

使用k8s的客户端工具kubectl来创建pod,该命令行工具支持对k8s对象(pod、replication controller、service)的CRUD操作以及其他对集群的管理操作。

创建Kubernetes资源对象的一般方法如下所示。

[root@master kubernetes]# kubectl create -f obj.json

回过头来,再来看看命令中的obj.json,这个JSON文件可以是定义pod、replication controller、service等k8s对象的资源配置文件
这里说明一下obj.json的配置信息:

{
	"kind":"Pod",
	"apiVersion":"v1",
	"metadata":{
		"name":"podtest",
		"labels":{
			"name":"redis-master"
		}
	},
	"spec":{
		"containers":[{
			"name":"master1",
			"image":"k8stest/redis:test",
			"ports":[{
				"containerPort":6379,
				"hostPort":6388
			}]
		},
		{
			"name":"master2",
			"image":"k8stest/sshd:test",
			"ports":[{
				"containerPort":22,
				"hostPort":8888
			}]
		}]
	}
}

以上配置信息,描述了一个name是podtest的对象,而该配置信息的kind表明该对象是一个pod。apiVersion表明客户端使用的服务端API的版本是v1。labels字段即该pod的标签,该pod只有一个标签:redis-master。

spec:container描述了pod内容器的属性,包括name(容器名),image(镜像),ports(端口映射)等。

其中ports字段由两个属性值组成:containerPort(容器端口)和hostPort(主机端口)。这样k8s 自动实现了用户容器端口到宿主机端口的映射关系

这里说明下spec字段,所有资源对象都会在spec字段下告诉k8s系统自己的期望状态,而k8s负责收集该资源对象的当前状态与期望状态进行匹配。例如,当创建一个pod时,声明该pod容器正常运行所需的计算资源,那么k8s无论发生什么都要保证pod内容器的正常运行。如果没有正常运行,k8s就会不停的重新创建pod对象,直到使用者删除该pod,或者正常运行为止。

将以上内容写入obj.json,会创建出一个包含两个容器的pod。这里要注意两类端口冲突问题:

  • pod内部的端口冲突,即同一个pod内的容器端口不能重复。
  • 宿主机端口冲突,即同一个pod的不同容器的端口可能会映射到宿主机的同一个端口。

创建Pod:

[root@master ~]# vi obj.json
[root@master ~]# kubectl create -f obj.json 
pod/podtest created

查看创建的pod的信息:

[root@master ~]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
podtest   0/2     Pending   0          93s

Pending状态说明pod还在准备。我们使用kubectl describe pod <pod_name>来查看一下为什么一直在准备:

[root@master ~]# kubectl describe pod podtest
Name:         podtest
Namespace:    default
Priority:     0
Node:         <none>
Labels:       name=redis-master
Annotations:  <none>
Status:       Pending
中间一段信息跳过。。。
Events:
  Type     Reason            Age        From               Message
  ----     ------            ----       ----               -------
  Warning  FailedScheduling  <unknown>  default-scheduler  0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.

在结尾处我们看到原来是没有主机节点来处理这个pod,因为我们这里是单机模式。使用下面这个命令让主机也能处理node。(默认情况下kubernetes中的master并不能运行用户的Pod. 因此需要删除 Train,允许master执行Pod)

[root@master ~]# kubectl taint nodes --all node-role.kubernetes.io/master-
node/master untainted

现在查询pod的情况:

[root@master ~]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
podtest   1/1     Running   0          5m36s

如果要查看pod容器中输出的log信息,可以使用kubectl log pod {container}来获取,比如以master1容器为例。

[root@master ~]# kubectl logs podtest master1
1:C 22 Oct 2019 07:07:36.644 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 22 Oct 2019 07:07:36.644 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 22 Oct 2019 07:07:36.644 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
1:M 22 Oct 2019 07:07:36.645 * Running mode=standalone, port=6379.
1:M 22 Oct 2019 07:07:36.645 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 22 Oct 2019 07:07:36.645 # Server initialized
1:M 22 Oct 2019 07:07:36.645 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
1:M 22 Oct 2019 07:07:36.645 * Ready to accept connections

pod内容器网络与通信

前面说过,pod内容器是共享network namespace的,那k8s是怎么做到这一点的呢?假设pod内一共有三个容器,那么这个pod对应的Dokcer容器信息应该如下图所示:
docker ps或者docker ps -a
在这里插入图片描述
其中上面两个是用户容器,第三个是k8s的网络容器,这就是关键。

只要保证每个pod都会自动运行这样一个网络容器,并且pod中其他容器都借助--net="container"的方式使用它间接定义自身的网络,就实现了这些容器network namespace的共享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值