k8s_day02_04
k8s_day02_04node 介绍查看所有节点[root@master01 ~]# kubectlget nodeNAMESTATUSROLESAGEVERSIONmaster01Readymaster7dv1.19.4node01Ready<none>6d23hv1.19.4node02Ready<none>6d23hv1.19.4
k8s_day02_04
node 介绍
查看所有节点
[root@master01 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
master01 Ready master 7d v1.19.4
node01 Ready <none> 6d23h v1.19.4
node02 Ready <none> 6d23h v1.19.4
[root@master01 ~]#
name 节点名称
status 显示节点状态
role 显示是否为主节点 角色 none 表示的就是node 工作节点
AGE: 存活的时长
查看指定节点
[root@master01 ~]# kubectl get node/node01
NAME STATUS ROLES AGE VERSION
node01 Ready <none> 6d23h v1.19.4
查看指定节点 以yaml 格式查看详细信息
[root@master01 ~]# kubectl get node/node01 -o yaml
查看分配给pod 所属的子网段
节点控制器 可以节点对象声明周期的管理 , 比如节点加入集群时给他分配一个子网、与服务器列表交互,以维护可用的节点列表信息,监控节点的健康状态,一旦节点不健康可以拒绝调度器把pod调度到这台机器上去,这些都是基操。对于每个节点对象,节点控制器都会根据它的元数据中name执行健康状态检测,以随时验证节点是否可用。k8s 上的资源必须有相应的资源控制器管理,否则所有创建的数据也仅仅是能保存在apiserver上的数据项,并不能真正意义上发挥作用,一个控制器可能控制多个类型,所以二者不是一一对应的
kubelet是运行在节点上的代理程序, 它负载从apiserver 接收并且执行 自身pod 相关的管理任务,并且向master 上报自身的状态==【kubelet心跳信息】== 以维持集群正常运行》
心跳检查是这样做的:
kubelet 每隔10秒钟,向apiserver报告自己的状态 【发送一次心跳信息】,告诉它自己还活着,仍然能接收pod的运行任务。一旦连续4个周期apisever没有 接收到特定节点的心跳信息,apiserver 就会把这个节点置为
NotReady
, 之前在该节点创建的pod 就会被调度到其他server在k8s -1.13版本之前,向apiserver报告自己的状态 同时会发送node status 信息,node status中有个image字段,非常非常大(存储了这个节点的所有image 可用信息),带来的缺点就是 如歌节点过多,每10s发一次会占用很大的流量带宽资源。
在k8s -1.13版本之后,为了解决这个问题 引入给节点专门使用的租约概念: lease , 资源类型就叫leases , 都放在kube-node-lease 名称空间之下
[root@master01 ~]# kubectl get leases -n kube-node-lease NAME HOLDER AGE master01 master01 7d10h node01 node01 7d9h node02 node02 7d9h [root@master01 ~]#
有了租约之后,可以把节点的状态以租约的形式保存在节点之上
[root@master01 ~]# kubectl get leases/node02 -n kube-node-lease -o yaml apiVersion: coordination.k8s.io/v1 kind: Lease metadata: creationTimestamp: "2021-11-24T17:09:25Z" name: node02 namespace: kube-node-lease ownerReferences: - apiVersion: v1 kind: Node name: node02 uid: 7e330895-413f-4347-b967-2e7e9704d2bc resourceVersion: "228716" selfLink: /apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/node02 uid: 50eedbd7-152f-491d-af93-79b1c78ed212 spec: holderIdentity: node02 leaseDurationSeconds: 40 renewTime: "2021-12-02T03:02:42.745544Z" [root@master01 ~]#
大体报告了租约的更新时间 leaseDurationSeconds:40 ,如歌40秒没有发生变化, 就会报告故障
之后的心跳只更新租约,而不是更新status 了,nodestatu只有真正发生变化 Transition 了才上告,要不就等到5五分钟才上报一次
查看node status 信息
[root@master01 ~]# kubectl get no/node01 -o yaml
status:
addresses:
- address: 192.168.2.2
type: InternalIP
- address: node01
type: Hostname
allocatable: #可分配的资源
cpu: "2"
ephemeral-storage: "48294789041"
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 3759112Ki
pods: "110"
capacity: #实际容量
cpu: "2"
ephemeral-storage: 51175Mi
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 3861512Ki
pods: "110"
ephemeral-storage : 临时存储 节点本地 可被被容器作为存储卷使用的空间
pods: “110” 默认最多节点可分配的最多数量 ,可以调整
conditions 表示 当前节点所处的处境,会汇报 NetworkUnavailable、MemoryPressure、DiskPressure、PIDPressure 类型的心跳检测, 如果status取值为false 就表示为正常。类型 Ready为True 表示正常
conditions:
- lastHeartbeatTime: "2021-12-01T11:27:25Z"
lastTransitionTime: "2021-12-01T11:27:25Z"
message: Flannel is running on this node
reason: FlannelIsUp
status: "False"
type: NetworkUnavailable
- lastHeartbeatTime: "2021-12-02T03:31:56Z"
lastTransitionTime: "2021-12-01T10:00:40Z"
message: kubelet has sufficient memory available
reason: KubeletHasSufficientMemory
status: "False"
type: MemoryPressure
- lastHeartbeatTime: "2021-12-02T03:31:56Z"
lastTransitionTime: "2021-12-01T10:00:40Z"
message: kubelet has no disk pressure
reason: KubeletHasNoDiskPressure
status: "False"
type: DiskPressure
- lastHeartbeatTime: "2021-12-02T03:31:56Z"
lastTransitionTime: "2021-12-01T10:00:40Z"
message: kubelet has sufficient PID available
reason: KubeletHasSufficientPID
status: "False"
type: PIDPressure
- lastHeartbeatTime: "2021-12-02T03:31:56Z"
lastTransitionTime: "2021-12-01T11:26:59Z"
message: kubelet is posting ready status
reason: KubeletReady
status: "True"
type: Ready
单单靠一个配置文件是无法创建一个节点的, 因为控制器无法随便给变一个物理节点存在,也不会部署kubelet存在
[root@master01 ~]# cat no3.yml
apiVersion: v1
kind: Node
metadata:
name: node3
spec:
podCIDR: 10.244.20.0/24
podCIDRs: [10.244.20.0/24]
[root@master01 ~]#
[root@master01 ~]# kubectl create -f no3.yml
node/node3 created
[root@master01 ~]# kubectl get no
NAME STATUS ROLES AGE VERSION
master01 Ready master 7d12h v1.19.4
node01 Ready <none> 7d12h v1.19.4
node02 Ready <none> 7d12h v1.19.4
node3 Unknown <none> 14s
所以node3 的状态是notready, unkonw是因为未解析
验证: 在master 上添加解析 就会成为notReady
[root@master01 ~]# echo "192.168.2.4 node3 " >> /etc/hosts
[root@master01 ~]# kubectl get no
NAME STATUS ROLES AGE VERSION
master01 Ready master 7d13h v1.19.4
node01 Ready <none> 7d12h v1.19.4
node02 Ready <none> 7d12h v1.19.4
node3 NotReady <none> 5m15s
[root@master01 ~]#
查看节点描述的信息
[root@master01 ~]# kubectl describe no/node01
PodCIDR: 10.244.5.0/24
PodCIDRs: 10.244.5.0/24
Non-terminated Pods: (5 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
default demoapp-5f7d8f9847-lkwxw 0 (0%) 0 (0%) 0 (0%) 0 (0%) 14h
default mypod 0 (0%) 0 (0%) 0 (0%) 0 (0%) 14h
kube-system coredns-6d56c8448f-7lwtf 100m (5%) 0 (0%) 70Mi (1%) 170Mi (4%) 18h
kube-system kube-flannel-ds-w62zd 100m (5%) 100m (5%) 50Mi (1%) 50Mi (1%) 18h
kube-system kube-proxy-k9jmf 0 (0%) 0 (0%) 0 (0%) 0 (0%) 18h
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 200m (10%) 100m (5%)
memory 120Mi (3%) 220Mi (5%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
Events: <none>
可以看到Non-terminated Pods 运行状态pod个数 非系统空间
Allocated resources 已经分配出去的资源 100m 表示0.1 个cpu
删除节点
[root@master01 ~]# kubectl delete no/node3
node "node3" deleted
[root@master01 ~]# kubectl get no
NAME STATUS ROLES AGE VERSION
master01 Ready master 7d13h v1.19.4
node01 Ready <none> 7d12h v1.19.4
node02 Ready <none> 7d12h v1.19.4
[root@master01 ~]#
pod的 status 叫做 pod 的phase ,相位 ,一个pod 有5个常见的相位
1、Running: 运行中
2、Pending: 挂起
主要原因是未调度成功,或者仍然处于下载镜像的过程当中
3、Succeed: 表示pod 中所有容器已经成功终止
job类型的pod 一旦运行完成了就处于succeed状态,如果有一个未能终止就显示为Failed
4、Failed
5、Unknown:
如果apiserver 无法获取 pod 的运行状态, 通常是无法与kubelet 建立联系通信导致的,如节点网络拥塞,kubelet 故障等等
当然除了以上五种状态 还有CrashLoopBackOff,Error。 这些状态通常来说不能称为POD的状态,而是pod内容器的状态。 比如 容器内应用没有放在前台运行 ,所监听的端口被占用等等所导致的pod 异常退出
pod内容器的组织方式有如下几种
1、sidecar: 用于为主容器提供辅助功能的 如日志采集器
2、Adapter: 一般来说, 一个pod 内的应用数据输出格式 与我们规范的格式不兼容,会加一些代码转换让他们兼容起来, 比如监控系统的agent 就是专门用来做格式转换的 。nginx 的status 无法与Prometheus指标格式相兼容,如果使用Prometheus去监视nginx内建的start staus几个数据,这时候就可以额外部署一个转换器,让nginx 指标兼容于Prometheus格式
3、Ambassador 如果pod内的主容器一些功能不方便去实现对外联络,这时候可以专门部署一个容器实现这种功能,这容器就可以称为大使容器。redis-cluster 用于构建其他节点时可能用到
在启动pod 的时候,最先启动的容器叫 初始化容器 ,初始化容器可能会有一个或者多个 ,且串行运行(一个初始化容器运行完成以后再运行另外一个初始化容器容器),初始化容器存在生命周期,最终肯定是要终止的。
一旦初始化容器 运行完 才开始运行 主容器,其他的sidecar、 适配器、或者大使类的辅助类容器同时运行,默认情况无法人为控制
一个pod的运行过程中存在2个非常重要的钩子 hook ,还有3个探针。钩子的作用是运行人为运行一些命令或程序 做一些自定义的功能。
post start hook: 容器启动后执行 单次执行
刚启动完一个主容器就有一个 钩子: post start hook. 主要做的是一些初始化操作,类似于linux 系统中的/etc/profile 文件
pre stop hook:容器结束前执行 单次执行
主容器结束之前也有个钩子 pre stop hook ,用于容器结束前执行一些清理类工作,比如清缓存
探针可以理解为传感器, 用于做健康状态检测的,自定义的健康状态检查机制. 默认情况下 kubelet 就可以做健康状态检测,如果pod 处于运行状态就是健康的,但是pod 处于运行状态而容器不一定是健康的,因为容器内的进程虽然在运行状态,但是可能会假死 无法回应正常客户端的请求,但是kubelet又探测不到。 所以我们可以自定义 更精确的探测机制
livness probe: 存活探针: 判定容器健康与否 周期性执行
readyness probe: 就绪探针,存活但是不一定就绪。 周期性执行
生产环境中,有很大的war 包, tomcat 展开到运行能正常访问,可能需要10~20秒都不止,容器一旦运行起来就存活了,但是容器一运行起来不意味着就能马上 接收用户访问了,所以当容器内的程序可以正常提供访问时,我们才认为它是就绪的。
startup probe: 启动探针 容器启动之后执行一定的时长 单次执行
pod 内有这样一种功能, 在pod 中内置一个liveness probe健康探针 ,pod 一启动就会周期性检测,比如2秒检测一次,如果容器内的进程(如java)花非的时间比较长 ,在检测周期内没有启动 pod就会无限重启这个容器,就GG。 所以第一次检测 就应该延后一点,另外还可能需要额外的特殊条件,所以需要startup探针额外构建来判断是否启动成功
在其他容器 无论是主容器还是sidecar adaptor 之类的 容器内部都可以构建2个钩子,3个探针
pod 需要关注的关键信息
[root@master01 ~]# kubectl get po/demoapp-5f7d8f9847-4t7sk -o yaml
priority: 0 # 容器的优先级
spec:
containers:
- image: ikubernetes/demoapp:v1.0
name: demoapp
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount # 存储器挂载点
qosClass: BestEffort # 服务质量级别 尽量满足
Tolerations 污点容忍度
容器如何配置?
可以在容器中传递环境变量,通过环境变量向容器传递信息和数据,向容器传值
dockerfile entrypoint cmd 区别
如果只有cmd ,最后一个生效,如果 entrypoint cmd 都有则 entrypoint 生效,而且cmd 要作为参数传给 entrypoint
这种设计的好处是:
entrypoint 的作用是让你在运行主程序之前,先运行一个初始化脚本,这脚本可以用来让那些 并非设计直接在容器中运行的应用,给他传一些环境变量替换到应用的配置文件中去的。所以entrypoint 一般是一个特殊化脚本 ,在这脚本之后去运行容器的主进程
什么叫云原生应用? 本身就运行在容器中 可以直接使用环境变量配置的 ,非原生只能借助 entrypoint 脚本了
例子: 向pod 容器传入变量
[root@master01 ~]# kubectl explain po.spec.containers.env
[root@master01 ~]# mkdir manifests
[root@master01 ~]# cd manifests/
[root@master01 manifests]# cat mypod-with-env-var.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod-with-env-var
labels:
app: mypod
release: canary
spec:
containers:
- name: demoapp
image: ikubernetes/demoapp:v1.0
env:
- name: HOST
value: 127.0.0.1
- name: PORT
value: "8080"
[root@master01 manifests]# kubectl apply -f mypod-with-env-var.yaml
验证
[root@master01 manifests]# kubectl exec mypod-with-env-var -- netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN
[root@master01 manifests]#
前提是容器支持这变量 ,否则除了在容器中看见。没啥用
[root@master01 manifests]# kubectl exec mypod-with-env-var -- printenv |head -5
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=mypod-with-env-var
HOST=127.0.0.1
PORT=8080
KUBERNETES_SERVICE_HOST=10.96.0.1
[root@master01 manifests]#
pod 创建的过程:
1 、用户发送create Pod的过程会发送给 APIserver 【create pod】
2、APIserver 先存储在etcd 中 【write】
3、scheduler 会看到etcd 中这个pod 处于未调度状态 【watch new pod】
4、scheduler会挑一个node 执行pod,【 bind pod 】
5、scheduler再存回apiserver 中 【write】
6、kubelet 会监视到和自己有关pod 的创建 【watch new pod】 ,然后拿到配置 开始启动容器【Start Container through CRI】 ,并且运行完以后再存回apiserver 【 update pod status.】
7. 由apiserver 存回到 etcd 中
删除的过程与之向反
能与etcd打交道的只有 apiserver
如何暴露POD端口?
pod 上暴露端口好像没什么用? 因为 pod 到pod 的通信 跨主机也是可以直接通信的,也就是说 po.spec.containers.ports.containerPort 没必要设置
如果与集群外l流量 信.POD 做不到 ,要么使用 node port 类型的sevice, 要么共享宿主机网络名称空间. 设置po.spec.hostNetwork 字段
或者 在po.spec.containers.ports.hostPort 设置字段就行,可以实现类似docker expose效果但是这种的暴露方式缺点很大
[root@master01 manifests]# kubectl explain po.spec.containers.ports
FIELDS:
containerPort <integer> -required-
Number of port to expose on the pod's IP address. This must be a valid port
number, 0 < x < 65536.
hostIP <string>
What host IP to bind the external port to.
hostPort <integer>
Number of port to expose on the host. If specified, this must be a valid
port number, 0 < x < 65536. If HostNetwork is specified, this must match
ContainerPort. Most containers do not need this.
name <string>
If specified, this must be an IANA_SVC_NAME and unique within the pod. Each
named port in a pod must have a unique name. Name for the port that can be
referred to by services.
protocol <string>
Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".
例子:
[root@master01 manifests]# cat mypod-with-ports.yml
apiVersion: v1
kind: Pod
metadata:
name: mypod-with-ports
labels:
app: mypod
release: canary
spec:
containers:
- name: demoapp
image: ikubernetes/demoapp:v1.0
ports:
- containerPort: 80
name: http
protocol: TCP
hostPort: 8080
[root@master01 manifests]#
[root@master01 manifests]# kubectl apply -f mypod-with-ports.yml
验证结果
缺点是 只能通过被调度到的节点访问, 因为pod 的调度是不确定的 ,作为外部用户是不知道pod 所在主机地址的
Pod直接共享宿主机的网络名称空间,无论调度到哪个节点都是
[root@master01 manifests]# kubectl explain po.spec.hostNetwork
KIND: Pod
VERSION: v1
FIELD: hostNetwork <boolean>
DESCRIPTION:
Host networking requested for this pod. Use the host's network namespace.
If this option is set, the ports that will be used must be specified.
Default to false.
例子
[root@master01 manifests]# kubectl apply -f mypod-with-hostnetwork.yml
pod/mypod-with-hostnetwork created
[root@master01 manifests]# cat mypod-with-hostnetwork.yml
apiVersion: v1
kind: Pod
metadata:
name: mypod-with-hostnetwork
labels:
app: mypod
release: canary
spec:
containers:
- name: demoapp
image: ikubernetes/demoapp:v1.0
env:
- name: PORT
value: "8080"
hostNetwork: True
[root@master01 manifests]#
发生诡异的一幕来了,因为直接共享的宿主机的名称地址 , 所以看到的 servername 和serverip 都不对!
在容器内执行ip a 看到的是物理机的信息 ,所以特别危险 ,生产环境要禁止使用
[root@master01 ~]# kubectl exec mypod-with-hostnetwork -- ip a
更多推荐
所有评论(0)