前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >k8s 实践经验(三):实操中学 k8s 五种资源(1)Pod

k8s 实践经验(三):实操中学 k8s 五种资源(1)Pod

作者头像
看、未来
发布2022-05-06 17:43:25
3880
发布2022-05-06 17:43:25
举报
文章被收录于专栏:CSDN搜“看,未来”
在这里插入图片描述
在这里插入图片描述

文章目录

本期我们在 k8s 集群上部署 nginx 服务。

namespace

Namespace是kubernetes系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。

默认情况下,kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中,可能不想让两个Pod之间进行互相的访问,那此时就可以将两个Pod划分到不同的namespace下。kubernetes通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的"组",以方便不同的组的资源进行隔离使用和管理。

可以通过kubernetes的授权机制,将不同的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用量、内存使用量等等,来实现租户可用资源的管理。

在这里插入图片描述
在这里插入图片描述

kubernetes在集群启动之后,会默认创建几个namespace:

代码语言:javascript
复制
[root@master ~]# kubectl  get namespace
NAME              STATUS   AGE
default           Active   5d1h	#  所有未指定Namespace的对象都会被分配在default命名空间
kube-node-lease   Active   5d1h	#  集群节点之间的心跳维护,v1.13开始引入
kube-public       Active   5d1h	#  此命名空间下的资源可以被所有人访问(包括未认证用户)
kube-system       Active   5d1h	#  所有由Kubernetes系统创建的资源都处于这个命名空间  

增删查改

1、创建命名空间

代码语言:javascript
复制
[root@k8s-master ~]# kubectl create ns test
namespace/test created

2、查看命名空间 全局查看的演示已经在上面了。 此处再学一个专项查看的:

代码语言:javascript
复制
[root@k8s-master ~]# kubectl describe ns/default
Name:         default
Labels:       <none>
Annotations:  <none>
Status:       Active

No resource quota.

No LimitRange resource.
在这里插入图片描述
在这里插入图片描述

3、删除命名空间

代码语言:javascript
复制
[root@k8s-master ~]# kubectl delete ns test
namespace "test" deleted

删除会比较慢一些、


配置文件操作

代码语言:javascript
复制
vi ns-test.yaml
代码语言:javascript
复制
apiVersion: v1
kind: Namespace
metadata:
  name: test

这种 yaml 脚本,说真的我只会看不会写。但是看多了,就该会了。

代码语言:javascript
复制
创建:kubectl create -f ns-test.yaml

删除:kubectl delete -f ns-test.yaml

Pod

前面那个只是开胃菜,这个才是重头戏哈。

● Pod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中。 ● Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器。

为什么需要 Pod?

对于这些对pod概念的总结大多殊路同归。

在理解概念前不妨先想一个问题:

明明有了容器,为什么还需要pod?

因为:

为了解决容器不足,或者说容器无法满足需求。

确实是这样,先分析一下容器的本质:

namespace做隔离 Cgroup做限制 rootfs做文件系统

三者相辅相成组成容器基本模型

但是,宏观的来说,容器的本质是系统中的一个进程。只不过这个进程启动时被附加了以上等等一些特殊的属性。

所谓容器只是一个恰当的说法。

就如系统中的大多数进程来说,不是单个进程独自工作,而是以“进程组”的方式“原则性”的组织在一起,互相协作,完成复杂任务。当然,它们之间也会共享一些资源,例如pid,namespace,存储等等。

在实际开发和运维中也是随处可见的这种问题,应用之间有深切的联系和依赖。

比如说,我要将一个应用容器化,这个应用由负责各个功能的5个进程组成,这时候,问题来了。

正是容器的局限性:单进程模型

单进程不是指容器中只能运行一个进程,而是容器无法去管理多个进程 例如,容器中有pid=1的进程,还有一个pid=5的进程,当这个pid=5的进程异常退出时,后续的垃圾回收等处理工作又由谁去做呢?

所以,这个应用的5个模块就必须分别制成5个容器,而且必须在同一个机器上运行。

随之而来的又是一个问题:

也就是容器调度问题,例如有两个容器调度节点node1和node2,可用内存分别为5G和4.5G,

每个容器分1G内存。由于5个容器必须在一台机器,正常全部调度到node1刚刚好,没有任何问题。

但是,因为是以容器为单位调度,有这样一些特殊情况。当前4个容器被调度到node2上时,空间只有0.5G,不足以运行最后一个容器,它有只能在node1运行,这就是以容器为调度单位的缺点。

当然也有解决方案:如Mesos中的资源囤积(resource hoarding),也就是所有调度任务都到达了才进行调度,也有谷歌Omega论文提出乐观调度,就是先不管冲突,而是在冲突之后通过一系列回滚机制解决冲突。

但这些都没有很完善的解决容器调度问题,但是在kubernetes中,这些问题都迎刃而解。

因为不在按照传统思维的将容器作为调度单位

kubernetes中的项目调度器是统一按照pod的资源需求做调度计算

也就是开始总结的那句话: pod是kubernetes项目的原子调度单位


pod结构

img
img

如图所示,一个pod包含了两类容器:

  • 用户容器
  • Pause容器,也常常被称为“根容器”(貌似老版本叫做infra容器)

用户容器好理解,但是Pause容器,也就是根容器,他是做什么用的呢?

pause容器主要为每个用户容器提供以下功能:

① PID命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID。

② 网络命名空间:Pod中的多个容器能够访问同一个IP和端口范围。

③ IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信。

④ UTS命名空间:Pod中的多个容器共享一个主机名;Volumes(共享存储卷):

⑤ Pod中的各个容器可以访问在Pod级别定义的Volumes。


pod实现原理

一定要明白一点:pod只是一个逻辑上的概念

因为kubernetes真正处理的还是宿主机操作系统上容器的Namespace和Cgroup,也就是说没有所谓的pod边界或隔离环境。

所以说,pod就是一组共享了某些资源的容器

在一个pod中所有容器是共享一个Network Namespace的,根据声明的不同来实现不同的资源共享

但是容器间的复杂关系在容器上难以解决,所以kubernetes项目里,pod的实现借用了一个中间容器,也就是常常说的根容器(也叫pause容器或infra容器,现在好像都统称pause容器,infra容器已经不再使用)。

在pod中,根容器永远是第一个创建的容器,用户后面定义的容器会加入进pod的Network Namespace,从而在视图上容器都在pod里。

不妨在k8s中看看这个容器镜像:

代码语言:javascript
复制
[root@master ~]# docker images | grep pause
registry.aliyuncs.com/google_containers/pause                     3.2        80d28bedfe5d   15 months ago   683kB

#当然,主机上有多少个pod就能docker ps 过滤看到多少pause容器

pause镜像大小只有683k,它是由汇编语言写的镜像

在一个pod中的容器,他们的Namespace文件,是一样的

也就意味着:

  • pod内的容器可以使用localhost进行通信
  • 根容器能看到的网络资源,其他容器都能看到,也就是pod的网络资源和pod内的容器共享
  • 一个pod有一个ip地址,和pod对应的Network namespace的ip一致
  • pod的生命周期只与根容器有关,与pod内的容器无关
  • 从pod里的容器的视角来说,它们的流量进出可以看做是通过根容器完成的

pod 操作

1、当我们搭建成功集群之后,可以看到已经有几个 Pod 在运行中了,这是支持我们集群运行的重要组件:

代码语言:javascript
复制
kubectl get pods -A
在这里插入图片描述
在这里插入图片描述

在实习的时候不常用 -A,实在太多了,都是用 -n 筛选一下命名空间,比如这里就可以这样:

在这里插入图片描述
在这里插入图片描述

当然,有时候晒过还是很多,再细分这个就是我们的经验了。


2、 创建一个 pod

代码语言:javascript
复制
kubectl run mynginx --image=nginx[:1.17.1] --port=80 [--namespace=dev]

这里的镜像它会去下载,如果本地没有的话。这里的本地指的是 k8s 存储镜像的地方,这些比较细的东西可能后面会整个社群讲吧。


3、 查看 pod 的详细信息

代码语言:javascript
复制
kubectl describe pod pod的名称 [-n 命名空间名称]

4、访问容器

代码语言:javascript
复制
kubectl get pods -n dev -o wide
在这里插入图片描述
在这里插入图片描述

获取到容器 IP。

在这里插入图片描述
在这里插入图片描述

配置文件形式

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: pod
    ports: 
    - name: nginx-port
      containerPort: 80
      protocol: TCP
代码语言:javascript
复制
kubectl create -f pod-nginx.yaml
代码语言:javascript
复制
kubectl delete -f pod-nginx.yaml

发现上面那个小细节还真不好找,找半天我也没看到离线的时候到底是从哪里找的镜像去进行的安装。

注意看这一行:imagePullPolicy: IfNotPresent k8s 有三个镜像拉取策略: Always 镜像标签为latest或镜像不存在时总是从指定的仓库中获取镜像 IfNotPresent 仅当本地镜像缺失时方才从目标仓库下载镜像 Never 禁止从仓库下载镜像,即仅使用本地镜像

对于标签latest的镜像文件,其默认的镜像获取策略即为Always,而对于其他标签的镜像,其默认策略则为IfNotPresent。需要注意的是,使用私有仓库中的镜像时通常需要由Registry服务器完成认证后才能进行。认证过程要么需要在相关节点上交互式执行docker login命令来进行,要么就是将认证信息定义为专有的Secret资源,并配置Pod通过imagePullSecredtes字段调用此认证信息完成。


对于这个配置文件的写法,我特地做了个表格,不放出来可惜了。

Pod 定义

属性名称

取值类型

是否必选

取值说明

apiVersion: v1

String

Requried

版本号,例如v1,版本号必须可以用 kubectl api-versions 查询到

kind: Pod

String

Requried

Pod

metadata:

Object

Requried

元数据

name: string

String

Requried

Pod名称,需符合RFC 1035规范

namespace: string

String

Requried

Pod所属的命名空间,默认为"default"

labels:

List

自定义标签

- name: string

String

自定义标签名字

annotations:

List

自定义注释列表

- name: string

spec:

Object

Requried

Pod中容器的详细定义

containers:

List

Requried

Pod中容器列表

- name: string

String

Requried

容器名称,需符合RFC 1035规范

image: string

String

Requried

容器的镜像名称

imagePullPolicy: [ Always|Never|IfNotPresent ]

String

获取镜像的策略,默认值为Alawys,Alawys表示每次都尝试下载镜像,IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像

command: [string]

List

容器的启动命令列表,如不指定,使用打包时使用的启动命令

args: [string]

List

容器的启动命令参数列表

workingDir: string

String

容器的工作目录

volumeMounts:

List

挂载到容器内部的存储卷配置

- name: string

String

引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名

mountPath: string

String

存储卷在容器内mount的绝对路径,应少于512字符

readOnly: boolean

Boolean

是否为只读模式,默认为读写模式

ports:

List

需要暴露的端口库号列表

- name: string

String

端口的名称

containerPort: int

Int

容器需要监听的端口号

hostPort: int

Int

容器所在主机需要监听的端口号,默认与Container相同

protocol: string

String

端口协议,支持TCP和UDP,默认TCP

env:

List

容器运行前需设置的环境变量列表

- name: string

String

环境变量名称

value: string

String

环境变量的值

resources:

Object

资源限制和请求的设置

limits:

Object

资源限制的设置

cpu: string

String

CPU的限制,单位为core数,将用于docker run --cpu-shares参数

memory: string

String

内存限制,单位可以为Mib/Gib,将用于docker run --memory参数

requests:

Object

资源限制的设置

cpu: string

String

CPU请求,容器启动的初始可用数量

memory: string

String

内存请求,容器启动的初始可用数量

livenessProbe:

Object

对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器,可设置的方法包括exec、httpGet和tcpSocket,对一个容器仅需设置其中一种健康检查方法

exec:

Object

对Pod容器内检查方式设置为exec方式

command: [string]

String

exec方式需要制定的命令或脚本

httpGet:

Object

对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port

path: string

port: number

host: string

scheme: string

HttpHeaders:

- name: string

value: string

tcpSocket:

Object

对Pod内个容器健康检查方式设置为tcpSocket方式

port: number

initialDelaySeconds: 0

Number

容器启动完成后首次探测的时间,单位为秒

timeoutSeconds: 0

Number

对容器健康检查探测等待响应的超时时间,单位秒,默认1秒,若超过该超时时间设置,则认为该容器不健康,会重启该容器

periodSeconds: 0

Number

对容器监控检查的定期探测时间设置,单位秒,默认10秒一次

successThreshold: 0

failureThreshold: 0

securityContext:

privileged: false

restartPolicy: [Always | Never | OnFailure]

String

Pod的重启策略,(1)Always表示一旦不管以何种方式终止运行,kubelet都将重启它,(2)OnFailure表示只有Pod以非0退出码退出才重启,如果容器正常结束(退出码为0)kubelet将不会重启它,(3)Nerver:Pod终止后,kubelet将退出码报告给Master,不会再重启该Pod。

nodeSelector: obeject

Object

设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定

imagePullSecrets:

Object

Pull镜像时使用的secret名称,以name:secretkey格式指定

- name: string

hostNetwork: false

Boolean

是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络,不再使用Docker网桥,该Pod将无法在同一宿主机上启动第2哥副本

volumes:

List

在该pod上定义共享存储卷列表

- name: string

String

共享存储卷名称 ,在一个Pod中每个存储卷定义一个名称,应符合RFC 1035规范。容器定义部分的containers[].volumeMounts[].name将引用该共享存储卷的名称。Volume的类型包括:emptyDir、hostPath、gcePersistentDisk、awsElasticBlockStore、gitRepo、secret、nfs、iscsi、glusterfs、persistentVolumeClaim、rbd、flexVolume、cinder、cephfs、flocker、downwardAPI、fc、azureFile、configMap、vsphereVolume,可以定义多个Volume,每个Volume的name保持唯一。

emptyDir: {}

Object

类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值

hostPath: string

Object

类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录

path: string

String

Pod所在宿主机的目录,将被用于同期中mount的目录

secret:

Object

类型为secret的存储卷,挂载集群与定义的secre对象到容器内部

scretname: string

items:

- key: string

path: string

configMap:

Object

类型为configMap的存储卷,挂载预定义的configMap对象到容器内部

name: string

items:

- key: string

path: string


滚动更新 pod

  • 更新
代码语言:javascript
复制
kubectl replace -f hello-world-pod.yaml

但是由于Pod的很多属性没办法修改,比如容器镜像,这时候可以采用–force参数

  • 重建Pod
代码语言:javascript
复制
kubectl replace --force -f hello-world-pod.yaml
img
img

删除Pod

  • 通过kubectl delete删除指定Pod
代码语言:javascript
复制
kubectl delete pod hello-world
  • 通过kubectl delete批量删除全部Pod
代码语言:javascript
复制
kubectl delete pod --all
img
img

不过只要那个 pod 是健康的,这样删不掉。


静态 Pod

什么是 Static Pod

静态 Pod 在指定的节点上由 kubelet 守护进程直接管理,不需要 API 服务器监管。 与由控制面管理的 Pod(例如,[Deployment]) 不同;kubelet 监视每个静态 Pod(在它崩溃之后重新启动)。

静态 Pod 永远都会绑定到一个指定节点上的 [Kubelet]。

kubelet 会尝试通过 Kubernetes API 服务器为每个静态 Pod 自动创建一个 [镜像 Pod]。 这意味着节点上运行的静态 Pod 对 API 服务来说是可见的,但是不能通过 API 服务器来控制。 Pod 名称将把以连字符开头的节点主机名作为后缀。

最常见的 Static Pod

  • etcd
  • kube-apiserver
  • kube-controller-manager
  • kube-scheduler

创建静态Pod有两种方式:配置文件方式和HTTP方式。

配置文件方式

可以通过kubelet的启动参数查看kubelet扫描静态Pod配置文件的路径,如下:

可以到kubelet是由这个配置文件进行启动的,在通过查看此配置文件,内容如下:

代码语言:javascript
复制
apiVersion: kubelet.config.k8s.io/v1beta1
.....
.....
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s

其中staticPodPath: /etc/kubernetes/manifests就是正在运行的kubelet需要监控的配置文件所在的目录,kubelet会定期扫描该目录,并根据该目录下的.yaml或.json文件进行创建操作。

在目录/etc/kubernetes/manifests中放入static-web.yaml文件,内容如下:

代码语言:javascript
复制
---

apiVersion: v1
kind: Pod
metadata:
   name: static-web
   labels:
     name: static-web
spec:
    containers:
    - name: static-web
      image: nginx
      ports:
      - name: web
        containerPort: 80

等待一会儿,查看本机中已经启动的容器:

代码语言:javascript
复制
[root@k8s-node0 ~]# docker ps|grep static-web
85fd075aaddd        nginx                                               "/docker-entrypoint.…"   About an hour ago   Up About an hour                        k8s_static-web_static-web-k8s-node0_default_d9890f08374e33f99c31a2a034276178_0

可以看到一个Nginx容器已经被kubelet成功创建了出来。

到Master上查看Pod列表,可以看到这个static pod:

代码语言:javascript
复制
[root@k8s-master ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-gn2wn   1/1     Running   1          17h
static-web-k8s-node0    1/1     Running   0          12s

由于静态Pod无法通过API Server直接管理,所以在Master上尝试删除这个Pod时,会使其变成Pending状态,且不会被删除。

代码语言:javascript
复制
[root@k8s-master ~]# kubectl delete pod static-web-k8s-node0
pod "static-web-k8s-node0" deleted
[root@k8s-master ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-gn2wn   1/1     Running   1          18h
static-web-k8s-node0    0/1     Pending   0          2s

删除该Pod的操作只能是到其所在Node上将其定义文件static-web.yaml从/etc/kubernetes/manifests目录下删除。

代码语言:javascript
复制
[root@k8s-node0 ~]# rm /etc/kubernetes/manifests/static_pod_web_nginx.yaml
rm: remove regular file ‘/etc/kubernetes/manifests/static_pod_web_nginx.yaml’? y
[root@k8s-node0 ~]# docker ps|grep static-web
[root@k8s-node0 ~]# docker ps|grep static-web

在Master上查看这个Pod:

代码语言:javascript
复制
[root@k8s-master ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-gn2wn   1/1     Running   1          18h
HTTP方式

通过设置kubelet的启动参数–manifest-url或kubelet的配置文件加上此配置项,kubelet将会定期从该URL地址下载Pod的定义文件,并以.yaml或.json文件的格式进行解析,然后创建Pod。其实现方式与配置文件方式是一致的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • namespace
    • 增删查改
      • 配置文件操作
      • Pod
        • 为什么需要 Pod?
          • pod结构
            • pod实现原理
              • pod 操作
                • 配置文件形式
                  • Pod 定义
                    • 滚动更新 pod
                      • 删除Pod
                      • 静态 Pod
                        • 什么是 Static Pod
                          • 最常见的 Static Pod
                            • 配置文件方式
                            • HTTP方式
                        相关产品与服务
                        容器服务
                        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档