kubernets(二)

news2025/1/11 11:08:12

集群操作

查看集群信息

 kubectl get查看各组件信息

格式:kubectl get  资源类型  【资源名】  【选项】
events  #查看集群中的所有日志信息
-o wide   # 显示资源详细信息,包括节点、地址...
-o yaml/json    #将当前资源对象输出至 yaml/json 格式文件
--show-labels   #查看当前资源对象的标签
-l   key=value    #基于标签进行筛选查找
-A  #查看所有名称空间下的POD
-n  名字空间    #查看该名字下的资源集合
--show-labels #查看某一资源的标签
-all-namespaces  #查看所有名字空间下的资源

  kubectl get all  # 查看所有的资源信息
  kubectl get ns                     # 获取名称空间
  kubectl get cs                     # 获取集群健康状态(组件的状态)
  kubectl get pods --all-namespaces     # 查看所有名称空间所有的pod
  kubectl get pods -A                   # -A是--all-namespaces的简写
查看service的信息:
[root@kub-k8s-master ~]# kubectl get service
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   22h
​
在不同的namespace里面查看service:
[root@kub-k8s-master ~]# kubectl get service -n kube-system
-n:namespace名称空间
​
查看所有名称空间内的资源:
[root@kub-k8s-master ~]# kubectl get pods --all-namespaces
​
同时查看多种资源信息:
[root@kub-k8s-master ~]# kubectl get pod,svc -n kube-system
​
查看apiserver信息:
[root@kub-k8s-master ~]# kubectl cluster-info 
Kubernetes master is running at https://192.168.246.166:6443
KubeDNS is running at https://192.168.2466.166:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
​
api查询:
[root@kub-k8s-master ~]# kubectl api-versions

1.查看集群信息:
[root@kub-k8s-master ~]# kubectl get nodes 
# -n default可不写
NAME             STATUS   ROLES    AGE   VERSION
kub-k8s-master   Ready    master   16h   v1.16.1
kub-k8s-node1    Ready    <none>   15h   v1.16.1
kub-k8s-node2    Ready    <none>   15h   v1.16.1
2.删除节点(无效且显示的也可以删除)
[root@kub-k8s-master ~]# kubectl delete node kub-k8s-node1
3.查看某一个节点(节点名称可以用空格隔开写多个)
[root@kub-k8s-master ~]# kubectl get node kub-k8s-node1
NAME            STATUS   ROLES    AGE   VERSION
kub-k8s-node1   Ready    <none>   15h   v1.16.1

kubectl describe

查看一个 API 对象的细节

注意:Events(事件):
在 Kubernetes 执行的过程中,对 API 对象的所有重要操作,都会被记录在这个对象的 Events 里,并且显示在 kubectl describe 指令返回的结果中。
​
比如,对于这个 Pod,我们可以看到它被创建之后,被调度器调度(Successfully assigned)到了 node-1,拉取了指定的镜像(pulling image),然后启动了 Pod 里定义的容器(Started container)。
​
这个部分正是我们将来进行 Debug 的重要依据。如果有异常发生,一定要第一时间查看这些 Events,往往可以看到非常详细的错误信息。
查看node的详细信息
[root@k1 ~]# kubectl describe node kub-k8s-node1  #也可以查看pod的信息
Name:               kub-k8s-node1
Roles:              <none>
...
  --------           --------   ------
  cpu                100m (2%)  100m (2%)
  memory             50Mi (1%)  50Mi (1%)
  ephemeral-storage  0 (0%)     0 (0%)
Events:              <none>
#注意:最后被查看的节点名称只能用get nodes里面查到的name!

创建删除更新信息

kubctl create 资源创建

(1)通过文件名创建资源
 #  kubectl create -f 文件名
 选项:
  --record     #记录命令至滚动信息,便于查看每次 revision 的变化
(2)通过标准输入创建资源
  # kubectl create 资源类型 [资源名]
选项:
--help    				#获取命令帮助
--tcp=集群端口:pod端口  #映射容器内端口至哪个端口
--dry-run     			#干跑测试
-o yaml/json  			#将当前资源对象输出至 yaml/json 格式文件中
--image=xxx   			 #指定镜像创建

apply 资源创建/更新

# kubectl apply -f 文件名
选项:
--record     #记录命令至滚动信息,便于查看每次 revision 的变化

删除pod

# kubectl delete pod pod名1 pod名2 
# kubectl delete pod --all   //批量删除
# kubectl delete pod <pod-name> --grace-period=0 --force
--grace-period=0 参数表示立即删除 Pod,而不是等待一段时间。
--force 参数表示强制删除 Pod,即使 Pod 处于未知状态。
​
举例:
[root@kub-k8s-master prome]# kubectl delete pod website
pod "website" deleted
[root@kub-k8s-master prome]# kubectl delete -f pod.yaml  #指定创建pod的yml文件名

重新启动

基于yaml文件的应用(这里并不是重新启动服务)

# kubectl delete -f XXX.yaml   #删除
# kubectl apply -f XXX.yaml   #创建pod

explain 资源字段描述

#查看对象推荐使用的api以及资源对象的描述
# kubectl explain 字段
例如:
# kubectl explain pod.spec  #查看pod类别一级字段帮助文档
# kubectl explain pod.spec.containers  #查看pod类别二级字段帮助文档

创建名称空间 namespace

在k8s中namespace可以用来:
1.将不同的应用隔离开来,避免命名冲突和资源的竞争
2.为不同团队和项目提供独立的运行环境,使他们可以独立的管理和部署应用程序。
3.控制资源配额和访问权限,以确保应用程序之间的安全隔离。
1. 编写yaml文件
[root@kub-k8s-master ~]# mkdir namespace
[root@kub-k8s-master ~]# cd namespace/
[root@kub-k8s-master namespace]# vim namespace.yml
---
apiVersion: v1   #api版本
kind: Namespace  #类型---固定的
metadata:     #元数据,用来描述所创建资源的基本信息
  name: ns-monitor  #起个名字
  labels:     #设置标签
    name: ns-monitor
2. 创建资源
[root@kub-k8s-master namespace]# kubectl apply -f namespace.yml
namespace/ns-monitor created
3. 查看资源
[root@kub-k8s-master namespace]# kubectl get namespace
NAME              STATUS   AGE
default           Active   22h
kube-node-lease   Active   22h
kube-public       Active   22h
kube-system       Active   22h
ns-monitor        Active   34s
4.查看某一个namespace
[root@kub-k8s-master namespace]# kubectl get namespace ns-monitor
5.查看某个namespace的详细信息
[root@kub-k8s-master namespace]# kubectl describe namespace ns-monitor
6.制作namespace资源限制
[root@k8s-master ~]# kubectl explain resourcequota.spec  #查看命令帮助
​
[root@k8s-master namespace]# vim create_ns_quota.yml 
apiVersion: v1
kind: ResourceQuota  #定义限制
metadata:
 name: test-quota
 namespace: ns-monitor #指定要做限制的namespace
spec:
 hard: #定义资源限制集,https://kubernetes.io/docs/concepts/policy/resource-quotas/
  limits.cpu: "2"
  limits.memory: "2Gi"
  requests.cpu: "2"
  requests.memory: "2Gi"
  
limits:定义资源在当前名称空间可以使用的资源是多少。容器可以使用的资源上限
requests:定义资源可以请求(调度)到node节点需要的多少资源,才允许资源调度。容器可以预期获得的最低资源保障
​
查看:
[root@k8s-master namespace]# kubectl get resourcequota -n ns-monitor
NAME         AGE    REQUEST                                             LIMIT
test-quota   3h5m   requests.cpu: 0/2, requests.memory: 0/2Gi   limits.cpu: 0/2, limits.memory: 0/2Gi
​
​
使用:
[root@k8s-master namespace]# vim create_pod.yml 
apiVersion: v1
kind: Pod
metadata:
 name: test-pod-1
 namespace: ns-monitor #指定名称空间
 labels:
  web: nginx-1
spec:
 containers:
  - name: nginx-1
    image: daocloud.io/library/nginx
    imagePullPolicy: IfNotPresent
    ports:
     - containerPort: 80
    resources: #指定资源限制
     limits: #定义容器在当前名称空间可以使用的最大资源
      cpu: "500m"
      memory: "1Gi"
     requests: #定义该pod调度到的节点需要满足的资源
      cpu: "100m"
      memory: "500Mi"
​
查看使用后:
[root@k8s-master namespace]# kubectl get resourcequota -n ns-monitor
NAME         AGE    REQUEST                                             LIMIT
test-quota   3h5m   requests.cpu: 300m/2, requests.memory: 1000Mi/2Gi   limits.cpu: 1/2, limits.memory: 2Gi/2Gi
​
注意:运行pod的node节点的资源,和容器运行所使用的资源一旦超过定义的,那就无法使用调度pod到对应节点。
​
7.删除名称空间,先删除namespace对应的pod
[root@kub-k8s-master namespace]# kubectl delete -f create_pod.yml
[root@kub-k8s-master namespace]# kubectl delete -f namespace.yml
namespace "ns-monitor" deleted

发布容器化应用

1.有镜像

2.部署应用--考虑做不做副本。不做副本就是pod,做副本以deployment方式去创建。做了副本访问还需要做一个service,使用访问。

发布第一个容器化应用

扮演一个应用开发者的角色,使用这个 Kubernetes 集群发布第一个容器化应用。

1. 作为一个应用开发者,你首先要做的,是制作容器的镜像。
2. 有了容器镜像之后,需要按照 Kubernetes 项目的规范和要求,将你的镜像组织为它能够"认识"的方式,然后提交上去。

什么才是 Kubernetes 项目能"认识"的方式?

就是使用 Kubernetes 的必备技能:编写配置文件。
这些配置文件可以是 YAML 或者 JSON 格式的。

Kubernetes 跟 Docker 等很多项目最大的不同,就在于它不推荐你使用命令行的方式直接运行容器(虽然 Kubernetes 项目也支持这种方式,比如:kubectl run),而是希望你用 YAML 文件的方式,即:把容器的定义、参数、配置,统统记录在一个 YAML 文件中,然后用这样一句指令把它运行起来:

# kubectl apply -f 我的配置文件

好处:

你会有一个文件能记录下 Kubernetes 到底"run"了什么
编写yaml文件内容如下:
[root@kub-k8s-master prome]# vim pod.yml
---
apiVersion: v1  #api版本,支持pod的版本
kind: Pod     #Pod,定义类型注意语法开头大写
metadata:     #元数据
  name: website   #这是pod的名字
  labels:
    app: website   #自定义,但是不能是纯数字
spec:    #指定的意思
  containers:   #定义容器
    - name: test-website   #容器的名字,可以自定义
      imagePullPolicy:IfNotPresent
      image: daocloud.io/library/nginx   #镜像
      ports:
        - containerPort: 80   #容器暴露的端口

创建pod

[root@kub-k8s-master prome]# kubectl apply -f pod.yml
pod/website created

查看pod

[root@kub-k8s-master prome]# kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
website   1/1     Running   0          74s
=============================
各字段含义:
NAME: Pod的名称
READY: Pod的准备状况,右边的数字表示Pod包含的容器总数目,左边的数字表示准备就绪的容器数目。
STATUS: Pod的状态。
RESTARTS: Pod的重启次数
AGE: Pod的运行时间。
pod的准备状况指的是Pod是否准备就绪以接收请求,Pod的准备状况取决于容器,即所有容器都准备就绪了,Pod才准备就绪。
​
一个pod刚被创建的时候是不会被调度的,因为没有任何节点被选择用来运行这个pod。调度的过程发生在创建完成之后,但是这个过程一般很快,所以你通常看不到pod是处于unscheduler状态的除非创建的过程遇到了问题。
​
pod被调度之后,分配到指定的节点上运行,这时候,如果该节点没有所需要的image,那么将会自动从默认的Docker Hub上pull指定的image,一切就绪之后,看到pod是处于running状态了

查看pod运行在哪台机器上

[root@kub-k8s-master prome]# kubectl get pods -o wide

可以测试访问:
[root@kub-k8s-master prome]# curl 10.244.1.3   #访问pod的ip
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
...

查看pods定义的详细信息

查看pod的详细信息----指定pod名字(不显示events字段信息)
# kubectl get pod website -o wide
[root@kub-k8s-master prome]# kubectl get pod website -o yaml
-o:output
yaml:yaml格式也可以是json格式

查看kubectl describe 支持查询Pod的状态

[root@kub-k8s-master prome]# kubectl describe pod website
Name:         website
Namespace:    default
Priority:     0
Node:         kub-k8s-node1/192.168.246.167
Start Time:   Thu, 17 Oct 2019 22:31:16 +0800
Labels:       app=website
...
1.各字段含义:
Name: Pod的名称
Namespace: Pod的Namespace。
Image(s): Pod使用的镜像
Node: Pod所在的Node。
Start Time: Pod的起始时间
Labels: Pod的Label。
Status: Pod的状态。
Reason: Pod处于当前状态的原因。
Message: Pod处于当前状态的信息。
IP: Pod的PodIP
Replication Controllers: Pod对应的Replication Controller。
===============================
2.Containers:Pod中容器的信息
Container ID: 容器的ID
Image: 容器的镜像
Image ID:镜像的ID
State: 容器的状态
Ready: 容器的准备状况(true表示准备就绪)。
Restart Count: 容器的重启次数统计
Environment Variables: 容器的环境变量
Conditions: Pod的条件,包含Pod准备状况(true表示准备就绪)
Volumes: Pod的数据卷
Events: 与Pod相关的事件列表
=====
生命周期的介绍
整个pod的生命周期
1.在启动任何容器之前,先创建pause基础容器(pid=1),它初始化Pod的环境并为后续加⼊的容器提供共享的名称空间。
2.按配置文件定义的顺序启动初始化容器,只有全部的初始化容器启动完成后才会启动主容器也就是container字段定义的容器。
3.在主容器启动之后可以通过钩子定义容器启动之后做什么,比如执行什么命令,
4.定义探针
(1)startupprobe启动探针用来检测容器是否启动成功,当容器启动成功后就绪探针和存活探针开始对容器进行检测;
(2)就绪探针的作用:检测容器是否准备就绪,如果就绪就可以接受来自service的请求,没有就不接受service转发过来的请求;
(3)存活探针用来检测容器里面的进程是否健康,如果不健康根据容器的重启策略进行容器的重启。
5.通过钩子定义在容器关闭之前要做什么:比如在容器关闭之前先正常退出nginx进程。
一个Pod 对象在 Kubernetes 中的生命周期:
​
生命周期:指的是status通过
[root@kub-k8s-master ~]# kubectl get pod
#生命周期包括:running、Pending、Failed...
​
Pod 生命周期的变化,主要体现在 Pod API 对象的Status 部分,这是除了 Metadata 和 Spec 之外的第三个重要字段。有如下几种可能的情况:
​
Pending:此状态表示Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中(准备状态)。但这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。
​
Running:此状态表示Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。
​
Succeeded:此状态表示 Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
​
Failed:此状态表示 Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。比如查看 Pod 的 Events 和日志。
​
Unknown:这是一个异常状态(未知状态),表示 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题 

其他状态

completed:         pod里面所有容器正常退出
CrashLoopBackOff: 容器退出,kubelet正在将它重启
InvalidImageName: 无法解析镜像名称
ImageInspectError: 无法校验镜像
ErrImageNeverPull: 策略禁止拉取镜像
ImagePullBackOff: 正在重试拉取
RegistryUnavailable: 连接不到镜像中心
ErrImagePull: 拉取镜像出错
CreateContainerConfigError: 不能创建kubelet使用的容器配置
CreateContainerError: 创建容器失败
m.internalLifecycle.PreStartContainer  执行hook报错
RunContainerError: 启动容器失败
PostStartHookError: 执行hook报错 
ContainersNotInitialized: 容器没有初始化完毕
ContainersNotReady: 容器没有准备完毕 
ContainerCreating:容器创建中
PodInitializing:pod 初始化中 
DockerDaemonNotReady:docker还没有完全启动
NetworkPluginNotReady: 网络插件还没有完全启动

进入Pod对应的容器内部

通过pod名称
[root@kub-k8s-master prome]# kubectl exec -it website /bin/bash
root@website:/#

扩展

create与apply的区别:
create创建的应用如果需要修改yml文件,必须先指定yml文件删除,在创建新的pod。
如果是apply创建的应用可以直接修改yml文件,继续apply创建,不用先删掉。

Yaml文件语法解析

通常,使用配置文件的方式会比直接使用命令行更可取,因为这些文件可以进行版本控制,而且文件的变化和内容也可以进行审核,当使用及其复杂的配置来提供一个稳健、可靠和易维护的系统时,这些点就显得非常重要。

在声明定义配置文件的时候,所有的配置文件都存储在YAML或者JSON格式的文件中并且遵循k8s的资源配置方式。

kubernetes中用来定义YAML文件创建Pod和创建Deployment等资源。

使用YAML配置文件用于K8s的定义的好处:
便捷性:不必添加大量的参数到命令行中执行命令
可维护性:YAML文件可以通过源头控制,跟踪每次操作
灵活性:YAML可以创建比命令行更加复杂的结构
YAML语法规则:
    1. 大小写敏感
    2. 使用缩进表示层级关系
    3. 缩进时不允许使用Tab键,只允许使用空格
    4. 缩进的空格数不重要,只要相同层级的元素左侧对齐即可
    5. " 表示注释,从这个字符一直到行尾,都会被解析器忽略
在 k8s 中,只需要知道两种结构类型:
1.Lists
2.Maps
字典
    a={key:value, key1:{key2:value2}, key3:{key4:[1,{key5:value5},3,4,5]}}
key: value
key1:
 key2: value2
key3:
 key4:
   - 1
   - key5: value5
   - 3
   - 4
   - 5
​
​
YAML  Maps
Map指的是字典,即一个Key:Value 的键值对信息。
例如:
---
apiVersion: v1
kind: Pod
注:--- 为可选的分隔符 ,当需要在一个文件中定义多个结构的时候需要使用。上述内容表示有两个键apiVersion和kind,分别对应的值为v1和Pod。
​
例如:
---
apiVersion: v1
kind: Pod
metadata:
 name: kube100-site
 labels:
  app: web    
    
注:上述的YAML文件中,metadata这个KEY对应的值为一个Maps,而嵌套的labels这个KEY的值又是一个Map。实际使用中可视情况进行多层嵌套。
​
YAML处理器根据行缩进来知道内容之间的关联。上述例子中,使用两个空格作为缩进,但空格的数据量并不重要,只是至少要求一个空格并且所有缩进保持一致的空格数 。例如,name和labels是相同缩进级别,因此YAML处理器知道他们属于同一map;它知道app是lables的值因为app的缩进更大。
注意:在YAML文件中绝对不要使用tab键
YAML   Lists
List即列表,就是数组
例如:
args:
 - beijing
 - shanghai
 - shenzhen
 - guangzhou
​
Maps的value既能够对应字符串也能够对应一个Maps。
可以指定任何数量的项在列表中,每个项的定义以连字符(-)开头,并且与父元素之间存在缩进。
​
在JSON格式中,表示如下:
{
  "args": ["beijing", "shanghai", "shenzhen", "guangzhou"]
}

总结

如果key和value同行,:后面要加空格;
所有的一级key顶格写;
value如有没有嵌套不换行;value如果有嵌套需要换行;
二级key要缩进,同行元素左对齐;
列表元素每行一个,前面加-,后面带空格;
不能使用tab键;

Pod API属性详解

Pod API 对象

Pod是 k8s 项目中的最小编排单位。容器(Container)就成了 Pod 属性里一个普通的字段。

问题:

​ 通过yaml文件创建pod的时候里面有容器,这个文件里面到底哪些属性属于 Pod 对象,哪些属性属于 Container?

解决:

把 Pod 看成传统环境里的"虚拟机机器"、把容器看作是运行在这个"机器"里的"用户程序",那么很多关于 Pod 对象的设计就非常容易理解了。
凡是调度、网络、存储,以及安全相关的属性,基本上是 Pod 级别的

​ 共同特征是,它们描述的是"机器"这个整体,而不是里面运行的"程序"。

比如:
​
配置这个"机器"的网卡(即:Pod 的网络定义)
​
配置这个"机器"的磁盘(即:Pod 的存储定义)
​
配置这个"机器"的防火墙(即:Pod 的安全定义)
​
这台"机器"运行在哪个服务器之上(即:Pod 的调度)
kind:指定了这个 API 对象的类型(Type),是一个 Pod,根据实际情况,此处资源类型可以是Deployment、Job、Ingress、Service等。
​
metadata:包含Pod的一些meta信息,比如名称、namespace、标签等信息.
​
spec:specification of the resource content 指定该资源的内容,包括一些container,storage,volume以及其他Kubernetes需要的参数,以及诸如是否在容器失败时重新启动容器的 属性。可在特定Kubernetes API找到完整的Kubernetes Pod的属性。
ˌ
specification----->[spesɪfɪˈkeɪʃn]
容器可选的设置属性包括:
"name"、"image"、"command"、"args"、"workingDir"、"ports"、"env"、resource、"volumeMounts"、livenessProbe、readinessProbe、livecycle、terminationMessagePath、"imagePullPolicy"、securityContext、stdin、stdinOnce、tty
跟"机器"相关的配置
[root@kub-k8s-master ~]# cd prome/
[root@kub-k8s-master prome]# kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
website   1/1     Running   0          2d23h
[root@kub-k8s-master prome]# kubectl get pod -o wide   #查看pod运行在哪台机器上面

nodeSelector
nodeName
这两个属性的功能是一样的都是用于人工干预调度器
实战
将node1上面的pod删除掉
[root@kub-k8s-master prome]# kubectl delete -f pod.yml 
pod "website" deleted
===========================================
nodeName:是一个供用户将 Pod 与 Node 进行绑定的字段,用法:
现在指定将pod创在node2上面:
[root@kub-k8s-master prome]# vim pod.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
spec:
  containers:
    - name: test-website
      image: daocloud.io/library/nginx
      ports:
        - containerPort: 80
  nodeName: kub-k8s-node2     #指定node节点的名称
创建
[root@kub-k8s-master prome]# kubectl apply -f pod.yml 
pod/website created

第二种方式通过node标签

首先我们需要知道node2上面你的标签有哪些?

1.查看node2上面的标签
[root@kub-k8s-master prome]# kubectl describe node kub-k8s-node2

1.重新创建一个新的pod
"nodeSelector:是一个供用户将 Pod 与 Node 进行绑定的字段",,通过指定标签来指定
​
[root@kub-k8s-master prome]# vim tomcat.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: tomcat
  labels:
    app: tomcat
spec:
  containers:
    - name: test-tomcat
      image: daocloud.io/library/tomcat:8
      ports:
        - containerPort: 8080
  nodeSelector:      #指定标签
    kubernetes.io/hostname: kub-k8s-node2
2.创建pod   
[root@kub-k8s-master prome]# kubectl apply -f tomcat.yml 
pod/tomcat created

表示这个 Pod 永远只能运行在携带了"kubernetes.io/hostname: kub-k8s-node2"标签(Label)的节点上;否则,它将调度失败。
第三个方式主机别名

设置pod容器里面的hosts文件内容,也是做本地解析

HostAliases:定义 Pod 的 hosts 文件(比如 /etc/hosts)里的内容,用法:

注意:在 k8s 中,如果要设置 hosts 文件里的内容,一定要通过这种方法。否则,如果直接修改了 hosts 文件,在 Pod 被删除重建之后,kubelet 会自动覆盖掉被修改的内容。 
1.首先先将刚创建的pod删除掉
[root@kub-k8s-master prome]# kubectl delete -f tomcat.yml 
pod "tomcat" deleted
[root@kub-k8s-master prome]# vim tomcat.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: tomcat
  labels:
    app: tomcat
spec:
  hostAliases:
  - ip: "192.168.246.113"   #给哪个ip做解析。实验环境下这个ip自定义的
    hostnames:
    - "foo.remote"    #解析的名字。用引号引起来可以写多个
    - "bar.remote"
  containers:
    - name: test-tomcat
      image: daocloud.io/library/tomcat:8
      ports:
        - containerPort: 8080
2.创建pod
[root@kub-k8s-master prome]# kubectl apply -f tomcat.yml 
pod/tomcat created
3.连接pod
[root@kub-k8s-master prome]# kubectl exec -it tomcat /bin/bash 
root@tomcat:/usr/local/tomcat# cat /etc/hosts   #查看hosts文件

凡是跟容器的 Linux Namespace 相关的属性,也一定是 Pod 级别的

原因:Pod 的设计,就是要让它里面的容器尽可能多地共享 Linux Namespace,仅保留必要的隔离和限制能力。

举例,一个 Pod 定义 yaml 文件如下:

共享同一个pod里面容器的进程
​
[root@kub-k8s-master prome]# kubectl delete -f pod.yml
pod "website" deleted
[root@kub-k8s-master prome]# vim pod.yml   #修改如下。最好是提前将镜像pull下来。
---
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
spec:
  shareProcessNamespace: true  #共享进程名称空间
  containers:
    - name: test-web
      image: daocloud.io/library/nginx
      ports:
        - containerPort: 80
    - name: busybos
      image: daocloud.io/library/busybox
      stdin: true
      tty: true
      
2.创建
[root@kub-k8s-master prome]# kubectl apply -f pod.yml 
pod/website created
1. 定义了 shareProcessNamespace=true
表示这个 Pod 里的容器要共享进程(PID Namespace)如果是false则为不共享。
2. 定义了两个容器:
一个 nginx 容器
一个开启了 tty 和 stdin 的 busybos 容器
​
在 Pod 的 YAML 文件里声明开启它们俩,等同于设置了 docker run 里的 -it(-i 即 stdin,-t 即 tty)参数。此 Pod 被创建后,就可以使用 shell 容器的 tty 跟这个容器进行交互了。

查看运行在那台机器上面:

我们登录node1的机器连接busybox的容器

[root@kub-k8s-node1 ~]# docker exec -it f684bd1d05b5 /bin/sh

在容器里不仅可以看到它本身的 ps 指令,还可以看到 nginx 容器的进程,以及 /pause 进程。也就是说整个 Pod 里的每个容器的进程,对于所有容器来说都是可见的:它们共享了同一个 PID Namespace。

将shareProcessNamespace=true修改为false
[root@kub-k8s-master prome]# kubectl delete -f pod.yml
[root@kub-k8s-master prome]# vim pod.yml
将shareProcessNamespace=true修改为false
[root@kub-k8s-master prome]# kubectl apply -f pod.yml 
pod/website created

验证:

凡是 Pod 中的容器要共享宿主机的 Namespace,也一定是 Pod 级别的定义。
刚才的都是pod里面容器的Namespace,并没有和本机的Namespace做共享,接下来我们可以做与本机的Namespace共享,可以在容器里面看到本机的进程。
​
[root@kub-k8s-master prome]# kubectl delete -f pod.yml 
pod "website" deleted
[root@kub-k8s-master prome]# vim pod.yml #修改如下
---
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
spec:
  hostNetwork: true  #共享宿主机网络
  hostIPC: true  #共享ipc通信
  hostPID: true  #共享宿主机的pid
  containers:
    - name: test-web
      image: daocloud.io/library/nginx
      ports:
        - containerPort: 80
    - name: busybos
      image: daocloud.io/library/busybox
      stdin: true
      tty: true
创建pod
[root@kub-k8s-master prome]# kubectl apply -f pod.yml 
pod/website created

验证:

定义了共享宿主机的 Network、IPC 和 PID Namespace。这样,此 Pod 里的所有容器,会直接使用宿主机的网络、直接与宿主机进行 IPC 通信、看到宿主机里正在运行的所有进程。

容器属性:
Pod 里最重要的字段"Containers":
"Containers"这个字段属于 Pod 对容器的定义。

k8s 对 Container 的定义,和 Docker 相比并没有什么太大区别。

 Docker中Image(镜像)、Command(启动命令)、workingDir(容器的工作目录)、Ports(容器要开发的端口),以及 volumeMounts(容器要挂载的 Volume)都是构成 k8s 中 Container 的主要字段。   

其他的容器属性:

ImagePullPolicy 字段:定义镜像的拉取策略。之所以是一个 Container 级别的属性,是因为容器镜像本来就是 Container 定义中的一部分。
​
默认值: Always:表示每次创建 Pod 都重新拉取一次镜像。
Never:表示Pod永远不会主动拉取这个镜像
IfNotPresent:表示只在宿主机上不存在这个镜像时才拉取。
​
​
Lifecycle 字段:定义 Container Lifecycle Hooks。作用是在容器状态发生变化时触发一系列"钩子"。
​
注:
lifecycle  /laɪf ˈsaɪkl/ n   生命周期 

例子:这是 k8s 官方文档的一个 Pod YAML 文件

在这个例子中,容器成功启动之后,在 /usr/share/message 里写入了一句"欢迎信息"(即 postStart 定义的操作)。而在这个容器被删除之前,我们则先调用了 nginx 的退出指令(即 preStop 定义的操作),从而实现了容器的"优雅退出"。

[root@kub-k8s-master prome]# kubectl delete -f pod.yml 
pod "website" deleted
[root@kub-k8s-master prome]# cp pod.yml pod.yml.bak
[root@kub-k8s-master prome]# vim pod.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: daocloud.io/library/nginx
    lifecycle:
      postStart:  #容器启动之后
        exec: 
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
      preStop:  #容器关闭之前
        exec: 
          command: ["/usr/sbin/nginx","-s","quit"]

验证:

[root@kub-k8s-node1 ~]# docker exec -it 3d404e658 /bin/bash
root@lifecycle-demo:~# cat /usr/share/message 
Hello from the postStart handler
1. 定义了一个 nginx 镜像的容器
2. 设置了一个 postStart 和 preStop 参数
​
postStart:是在容器启动后,立刻执行一个指定的操作。
注意:postStart 定义的操作,虽然是在 Docker 容器 ENTRYPOINT 执行之后,但它并不严格保证顺序。也就是说,在 postStart 启动时,ENTRYPOINT 有可能还没有结束。
如果 postStart执行超时或者错误,k8s 会在该 Pod 的 Events 中报出该容器启动失败的错误信息,导致 Pod 也处于失败的状态。
​
preStop:是容器被杀死之前(比如,收到了 SIGKILL 信号)。
注意:preStop 操作的执行,是同步的。
所以,它会阻塞当前的容器杀死流程,直到这个 Hook 定义操作完成之后,才允许容器被杀死,这跟 postStart 不一样。

投射数据卷 Projected Volume

注:Projected Volume 是 Kubernetes v1.11 之后的新特性

卷:配置卷、加密卷、数据卷

什么是Projected Volume?

在 k8s 中,有几种特殊的 Volume,它们的意义不是为了存放容器里的数据,"而是为容器提供预先定义好的数据。"
将容器使用的数据(变量)做成一个卷挂载到容器内部供容器使用。
从容器的角度来看,这些 Volume 里的信息仿佛是被 k8s "投射"(Project)进入容器当中的。 

k8s 支持的 Projected Volume 一共有四种方式:

Secret
ConfigMap
Downward API
ServiceAccountToken

Secret详解

secret用来保存小片敏感数据的k8s资源,例如密码,token,或者秘钥。这类数据当然也可以存放在Pod或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,并减少暴露的风险。而不需要把这些敏感数据暴露到镜像或者Pod Spec中。
用户可以创建自己的secret,系统也会有自己的secret。Pod需要先引用才能使用某个secret。
​
Secret类型type
1.kubernetes.io/service-account-token:用于被 serviceaccount 引用。serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的的/run/secrets/kubernetes.io/serviceaccount 目录中。 
2.Opaque:base64编码格式的Secret,用来存储密码、秘钥等。但数据也可以通过base64 –decode解码得到原始数据,所有加密性很弱
3.kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息
4.kubernetes.io/tls:此类型仅用于存储私钥和证书

Pod使用secret方式:

作为环境变量:可以将Secret中的数据作为环境变量暴露给Pod中的容器。这种方式便于应用程序直接读取而不必担心文件路径的问题。
作为Volume挂载:Secret也可以作为一个Volume被一个或多个容器挂载。这种方式适用于需要将Secret作为文件形式访问的情况。
拉取镜像时使用:在Pod的Spec中指定imagePullSecrets字段可以使得Kubelet使用指定的Secret来拉取私有仓库中的镜像。

內建的Secrets:

由ServiceAccount创建的API证书附加的秘钥k8s自动生成的用来访问apiserver的Secret,所有Pod会默认使用这个Secret与apiserver通信

创建自己的Secret:

方式1:使用kubectl create secret命令
方式2:yaml文件创建Secret

实战

yaml方式创建Secret

假如某个Pod要访问数据库,需要用户名密码,现在我们分别设置这个用户名和密码

Secret 对象要求这些数据必须是经过 Base64 转码的,以免出现明文密码显示的安全隐患。

创建一个secret.yaml文件,内容用base64编码:明文显示容易被别人发现,这里先转码。
​
[root@kub-k8s-master ~]# echo -n 'admin' | base64
YWRtaW4=
[root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
​
-w 0  表示不换行

创建一个secret.yaml文件,内容用base64编码

[root@kub-k8s-master prome]# vim secret.yml
---
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque  #模糊
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

创建:

[root@kub-k8s-master prome]# kubectl apply -f secret.yml 
secret/mysecret created

解析Secret中内容,还是经过编码的---需要解码库被辞退了

查看secret
[root@kub-k8s-master ~]# kubectl get secrets # 缩写se
NAME                  TYPE                                  DATA   AGE
default-token-7vc82   kubernetes.io/service-account-token   3      30h
mysecret              Opaque                                2      6s
​
查看secret详细信息
[root@kub-k8s-master prome]# kubectl get secret mysecret -o yaml
apiVersion: v1
data:
  password: MWYyZDFlMmU2N2Rm
  username: YWRtaW4=
kind: Secret
metadata:
  creationTimestamp: "2019-10-21T03:07:56Z"
  name: mysecret
  namespace: default
  resourceVersion: "162855"
  selfLink: /api/v1/namespaces/default/secrets/mysecret
  uid: 36bcd07d-92eb-4755-ac0a-a5843ed986dd
type: Opaque

手动base64解码方式:

[root@kub-k8s-master ~]# echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
使用Secret
secret可以作为数据卷挂载或者作为环境变量暴露给Pod中的容器使用,也可以被系统中的其他资源使用。

一个Pod中引用Secret的列子:

创建一个Secret,多个Pod可以引用同一个Secret
​
修改Pod的定义,在spec.volumes[]加一个volume,给这个volume起个名字,spec.volumes[].secret.secretName记录的是要引用的Secret名字
[root@kub-k8s-master prome]# vim pod_use_secret.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mypod
  labels:
   app:webapp
spec:
  containers:
  - name: testredis
    image: daocloud.io/library/redis
    imagePullPolicy:IfNotPresent
    volumeMounts:    #挂载一个卷
    - name: foo     #这个名字需要与定义的卷的名字一致
      mountPath: "/etc/foo"  #挂载到容器里哪个目录下,随便写
      readOnly: true
  volumes:     #数据卷的定义
  - name: foo   #卷的名字这个名字自定义
    secret:    #卷是直接使用的secret。
      secretName: mysecret   #调用刚才定义的secret
      
创建:
[root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml 
pod/mypod created
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# cd /etc/foo/
root@mypod:/etc/foo# ls
password  username
root@mypod:/etc/foo# cat password 
1f2d1e2e67df
结果中看到,保存在 Etcd 里的用户名和密码信息,已经以文件的形式出现在了容器的 Volume 目录里。
而这个文件的名字,就是 kubectl create secret 指定的 Key,或者说是 Secret 对象的 data 字段指定的 Key。 
每一个被引用的Secret都要在spec.volumes中定义
 如果Pod中的多个容器都要引用这个Secret那么每一个容器定义中都要指定自己的volumeMounts,但是Pod定义中声明一次spec.volumes就好了。 

被挂载的secret内容自动更新

也就是如果修改一个Secret的内容,那么挂载了该Secret的容器中也将会取到更新后的值,但是这个时间间隔是由kubelet的同步时间决定的。

1.设置base64加密
[root@kub-k8s-master prome]# echo qianfeng | base64
cWlhbmZlbmcK
2.将admin替换成qianfeng
[root@kub-k8s-master prome]# vim secret.yml
---
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: cWlhbmZlbmcK   #修改为qianfeng的base64加密后的
  password: MWYyZDFlMmU2N2Rm
  
1.创建
[root@kub-k8s-master prome]# kubectl apply -f secret.yml 
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
secret/mysecret configured
2.连接pod容器
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# cd /etc/foo/my-group
root@mypod:/etc/foo/my-group# ls
my-username
root@mypod:/etc/foo/my-group# cat my-username 
qianfeng

以环境变量的形式使用Secret

[root@kub-k8s-master prome]# kubectl delete -f pod_use_secret.yaml 
pod "mypod" deleted
[root@kub-k8s-master prome]# vim pod_use_secret.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: testredis
    image: daocloud.io/library/redis
    env:  #定义环境变量
     - name: SECRET_USERNAME   #创建新的环境变量名称
       valueFrom:
        secretKeyRef:     #调用的key是什么
         name: mysecret       #变量的值来自于mysecret
         key: username       #username里面的值
​
2.创建使用secret的pod容器
[root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml 
pod/mypod created
3.连接
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash 
root@mypod:/data# echo $SECRET_USERNAME   #打印一下定义的变量
qianfeng 

实战案例:

1.创建数据库用户的密码secret
[root@master test]# echo -n 'QianFeng@123!' | base64
UWlhbkZlbmdAMTIzIQ==
[root@master test]# cat secret.yml 
apiVersion: v1
kind: Secret
metadata:
 name: mysql-secret
type: Opaque
data:
 password: UWlhbkZlbmdAMTIzIQ==
 
[root@master test]# kubectl apply -f secret.yml
​
2.创建数据库并使用secret
[root@master test]# cat myslq.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: my-mysql
spec:
 containers:
 - name: mysql
   image: daocloud.io/library/mysql:5.7
   ports:
    - containerPort: 3306
   env:
    - name: MYSQL_ROOT_PASSWORD
      valueFrom:
       secretKeyRef:
        name: mysql-secret
        key: password
[root@master test]# kubectl apply -f myslq.yaml
[root@master test]# kubectl get pod -o wide 
NAME       READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
my-mysql   1/1     Running   0          2m47s   10.244.2.13   node2   <none>           <none>
​
测试:
[root@master test]# mysql -uroot -p'QianFeng@123!' -h 10.244.2.13 -P3306

注意:

如果报错:上面这条命令会报错如下
# kubectl exec -it test-projected-volume /bin/sh
error: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)
​
解决:绑定一个cluster-admin的权限
# kubectl create clusterrolebinding system:anonymous   --clusterrole=cluster-admin   --user=system:anonymous
clusterrolebinding.rbac.authorization.k8s.io/system:anonymous created
k8s配置harbor仓库
192.168.116.141  harbor  --安装harbor仓库

1.首先在集群中的每个节点上配置登陆harbor仓库的地址

[root@master ~]# cat /etc/docker/daemon.json 
{
"insecure-registries": ["192.168.116.141"]
}
​
[root@node1 ~]# cat /etc/docker/daemon.json 
{
"insecure-registries": ["192.168.116.141"]
}
​
[root@node2 ~]# cat /etc/docker/daemon.json 
{
"insecure-registries": ["192.168.116.141"]
}
​
# systemctl restart docker
​
测试上传镜像

2.配置k8s集群连接harbor的认证secret

核心思路:拉取私有仓库镜像需要配置私有仓库的登陆信息,用Secret存储,并且定义Deployment或者Pod时,指定imagePullSecret为保存了私有仓库登陆信息的Secret名。

如果使用docker login登陆过私有仓库,那么可以直接使用.docker/config.json文件生成的Secret
​
查看master上面认证的密钥文件
[root@master yaml]# cat /root/.docker/config.json 
{
    "auths": {
        "192.168.116.141": {
            "auth": "YWRtaW46SGFyYm9yMTIzNDU="
        }
    }
}
​
将密钥文件进行base64的加密
[root@master yaml]# cat /root/.docker/config.json | base64 -w 0
ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjExNi4xNDEiOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0=
​
创建k8s连接harbor的secret
#注意:
Secret的data项目key是.dockerconfigjson;
.docker/config.json文件BASE64编码,然后粘贴到data[".dockerconfigjson"]。不要有换行
Secret type必须是kubernetes.io/dockerconfigjson;
​
[root@master yaml]# cat harbor-secret.yaml 
apiVersion: v1
kind: Secret
metadata:
 name: harbor-login
type: kubernetes.io/dockerconfigjson
data:
 .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjExNi4xNDEiOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0=
  
[root@master yaml]# kubectl apply -f harbor-secret.yaml 
secret/harbor-login created
​
查看
[root@master yaml]# kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-zdkzq   kubernetes.io/service-account-token   3      10h
harbor-login          kubernetes.io/dockerconfigjson        1      18s

测试--创建一个nginx的应用

[root@master yaml]# vim nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
 name: nginx-web
spec:
 containers:
  - name: nginx-1
    image: 192.168.116.141/nginx/nginx:v1.1 #指定镜像仓库地址
 imagePullSecrets:  #指定使用的harbor仓库的secret
  - name: harbor-login
​
[root@master yaml]# kubectl apply -f nginx-pod.yaml 
pod/nginx-web created
​
查看
[root@master yaml]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
nginx-web   1/1     Running   0          2m47s

设置节点亲和性

taint

污点(Taints)和容忍度(Tolerations)的作用是在节点上设置一些排斥条件,使得没有适当容忍度的 Pod 不会被调度到该节点上。但是,当 nodeName 字段被设置时,调度器会忽略这些条件,直接将 Pod 调度到指定节点上。

nodeName 对污点的作用

直接调度:当在 Pod 规约中设置了 nodeName 字段后,Kubernetes 调度器会忽略这个 Pod,而指定节点上的 kubelet 会尝试将 Pod 放到该节点上 4。
强制匹配:使用 nodeName 的调度规则是强制性的,即 Pod 必须且只能调度到指定的节点上。这种方式可以越过 Taints 污点进行调度 1。
优先级:使用 nodeName 来选择节点的优先级高于使用 nodeSelector 或亲和性与反亲和性的规则 19。

 

apiVersion: v1
kind: Pod
metadata:
  name: webapp2
  labels:
    app: webapp2
spec:
  nodeName: k4
  containers:
  - name: webapp
    image: daocloud.io/library/nginx
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
kubectl taint nodes k4 key1=value1:NoSchedule

taints 是键值数据,用在节点上,定义污点; tolerations 是键值数据,用在pod上,定义容忍度,能容忍哪些污点。

taints的 effect 字段

(必填) 用来定义对pod对象的排斥等级

  • NoSchedule:仅影响pod调度过程,仅对未调度的pod有影响。(例如:这个节点的污点改了,使得之前调度的pod不能容忍了,对现存的pod对象不产生影响)

  • NoExecute:既影响调度过程,又影响现存的pod对象(例如:如果现存的pod不能容忍节点后来加的污点,这个pod就会被驱逐)排斥等级最高

  • PreferNoSchedule:最好不,也可以,是NoSchedule的柔性版本。(例如:pod实在没其他节点调度了,也可以到到这个污点等级的节点上)排斥等级最低

污点增删查操作

#设置(增加)污点
kubectl taint node 节点名 键=值:污点类型
kubectl taint node node01 key1=value1:NoSchedule
 
#节点说明中,查找 Taints 字段
kubectl describe node 节点名 
kubectl describe node node01
kubectl describe node node01 | grep Taints
kubectl describe node node01 | grep -A2 -i taint
 
#去除(删除)污点
kubectl taint node 节点名 键名-
kubectl taint node node01 key1-
kubectl taint node 节点名 键名=值:污点类型-
kubectl taint node node01 key1:NoSchedule-

key2-    这将删除所有键名为key2的污点
-A2       表示显示过滤行及其后两行
-i           表示不区分大小写

容忍度操作符

在Pod上定义容忍度时,它支持两种操作符:Equal和Exists。

  • Equal:容忍度与污点必须在key、value和effect三者完全匹配。

  • Exists:容忍度与污点必须在key和effect二者完全匹配,容忍度中的value字段要使用空值。

ConfigMap配置卷

ConfigMap与 Secret 类似,用来存储配置文件的kubernetes资源对象,所有的配置内容都存储在etcd中。

ConfigMap与 Secret 的区别

ConfigMap 保存的是不需要加密的、应用所需的配置信息。
ConfigMap 的用法几乎与 Secret 完全相同:可以使用 kubectl create configmap 从文件或者目录创建 ConfigMap,也可以直接编写 ConfigMap 对象的 YAML 文件。

创建ConfigMap

创建ConfigMap的方式有4种
​
命令行方式
方式1:通过直接在命令行中指定configmap参数创建,即--from-literal
方式2:通过指定文件创建,即将一个配置文件创建为一个ConfigMap,--from-file=<文件>
方式3:通过指定目录创建,即将一个目录下的所有配置文件创建为一个ConfigMap,--from-file=<目录>
配置文件方式
方式4:事先写好标准的configmap的yaml文件,然后kubectl create -f 创建

1.1 使用 kubectl create configmap 命令创建

kubectl create configmap my-config --from-literal=key1=value1 --from-literal=key2=value2

通过命令行参数--from-literal创建。创建命令:

kubectl create configmap test-configmap --from-literal=user=admin --from-literal=pass=1122334

结果如下面的data内容所示:

[root@kub-k8s-master prome]# kubectl get configmap test-configmap -o yaml
apiVersion: v1
data:
  pass: "1122334"
  user: admin
kind: ConfigMap
metadata:
  creationTimestamp: "2019-10-21T07:48:15Z"
  name: test-configmap
  namespace: default
  resourceVersion: "187590"
  selfLink: /api/v1/namespaces/default/configmaps/test-configmap
  uid: 62a8a0d0-fab9-4159-86f4-a06aa213f4b1

1.2 从文件创建

kubectl create configmap my-config --from-file=example.conf

编辑文件server.conf内容如下:

[root@kub-k8s-master prome]# vim server.conf
server {
listen 80;
server_name localhost;
location / {
root /var/www/html;
index index.html index.htm;
}
}

创建(可以有多个--from-file):

kubectl create configmap test-config2 --from-file=server.conf

结果如下面data内容所示:

[root@kub-k8s-master prome]# kubectl get configmap test-config2 -o yaml
apiVersion: v1
data:
  server.conf: |       #多行字符串开始符号,|前是key是文件名,|后是值是文件内容
    server {
    listen 80;
    server_name localhost;
    localtion / {
    root /var/www/html;
    index index.html index.htm;
    }
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2019-10-21T08:01:43Z"
  name: test-config2
  namespace: default
  resourceVersion: "188765"
  selfLink: /api/v1/namespaces/default/configmaps/test-config2
  uid: 790fca12-3900-4bf3-a017-5af1070792e5

通过指定文件创建时,configmap会创建一个key/value对,key是文件名,value是文件内容。

1.3 从目录创建

kubectl create configmap my-config --from-file=dir/
​configs 目录下的config-1和config-2内容如下所示:
[root@kub-k8s-master prome]# mkdir config
[root@kub-k8s-master prome]# cd config/
[root@kub-k8s-master config]# vim config1
aaa
bbb
c=d
[root@kub-k8s-master config]# vim config2
eee
fff
h=k
创建:
[root@kub-k8s-master config]# cd ..
[root@kub-k8s-master prome]# kubectl create configmap test-config3 --from-file=./config
configmap/test-config3 created
查看data内容:
[root@kub-k8s-master prome]# kubectl get configmap test-config3 -o yaml

指定目录创建时,configmap内容中的各个文件会创建一个key/value对,key是文件名,value是文件内容。

1.4 使用 YAML 文件创建

通过事先写好configmap的标准yaml文件创建

yaml文件内容如下: 注意其中一个key的value有多行内容时要添加竖线|

[root@kub-k8s-master prome]# vim configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-config4
  namespace: default
data:
  cache_host: memcached-gcxt
  cache_port: "11211"
  cache_prefix: gcxt
  my.cnf: |
   [mysqld]
   log-bin = mysql-bin
   user = mysql
   server-id = "1"
  app.conf:
   server {
    listen 80;
    server_name localhost;
    location / {
     root /usr/share/nginx/html;
     index index.html;
    }
   }
  port: "80"
  user: nginx

创建:

[root@kub-k8s-master prome]# kubectl apply -f configmap.yaml 
configmap/test-config4 created 

查看结果:

[root@kub-k8s-master prome]# kubectl get configmap test-config4 -o yaml

查看configmap的详细信息:

# kubectl describe configmap

查看ConfigMap

# 查看命名空间中的所有 ConfigMap
kubectl get configmap -n <namespace>

# 查看名为 game-config 的 ConfigMap 的详细信息
kubectl describe configmap game-config -n <namespace>

# 查看 ConfigMap 的 YAML 格式定义
kubectl get configmap <configmap-name> -n <namespace> -o yaml

# 查看 ConfigMap 中特定键的值
kubectl get configmap <configmap-name> -n <namespace> -o jsonpath='{.data.<key-name>}'
  
# 查看所有命名空间中的 ConfigMap
kubectl get configmap -A

# 查看带有特定标签的 ConfigMap
kubectl get configmap -l <label-key>=<label-value> -n <namespace>

# 使用管道查看 ConfigMap 数据并通过 jq 处理
kubectl get configmap <configmap-name> -n <namespace> -o yaml | jq '.data'

删除ConfigMap

# 删除单个 ConfigMap
kubectl delete configmap <configmap-name> -n <namespace>

# 示例:删除位于 default 命名空间中的名为 game-config 的 ConfigMap
kubectl delete configmap game-config -n default

# 如果当前上下文已经设置为某个命名空间,可以省略 -n 参数
kubectl delete configmap game-config

# 通过标签选择器删除多个 ConfigMap
kubectl delete configmap -l label-key=label-value -n <namespace>

# 示例:删除所有带有 env=production 标签的 ConfigMap
kubectl delete configmap -l env=production -n default

# 通过 YAML 文件删除
kubectl delete -f <path-to-yaml-file>

# 示例:删除文件 configmaps.yaml 中定义的所有 ConfigMap
kubectl delete -f configmaps.yaml

使用ConfigMap

使用ConfigMap的方式,一种是通过环境变量的方式,直接传递pod,另一种是使用volume的方式挂载入到pod内

示例ConfigMap文件:

[root@kub-k8s-master prome]# vim config-map.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-map
  namespace: default
data:
  special.how: very
  special.type: charm  
​
创建  
[root@kub-k8s-master prome]# kubectl apply -f config-map.yml 
configmap/config-map created

2.1 通过变量使用

(1) 使用valueFrom、configMapKeyRef、name、key指定要用的key:

设置指定变量的方式
[root@kub-k8s-master prome]# vim testpod.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: daocloud.io/library/nginx
      env:   #专门在容器里面设置变量的关键字
        - name: SPECIAL_LEVEL_KEY   #这里的-name,是容器里设置的新变量的名字
          valueFrom:
            configMapKeyRef:
              name: config-map   #这里是来源于哪个configMap
              key: special.how      #configMap里的key
        - name: SPECIAL_TYPE_KEY
          valueFrom:
            configMapKeyRef:
              name: config-map
              key: special.type
  restartPolicy: Never
​
创建pod
[root@kub-k8s-master prome]# kubectl apply -f testpod.yml 
pod/dapi-test-pod created

 restartPolicy 

spec.restartPolicy字段在 Pod 定义中进行设置。

Always 表示一直重启,这也是默认的重启策略。Kubelet 会定期查询容器的状态,一旦某个容器处于退出状态,就对其执行重启操作
OnFailure 表示只有在容器异常退出,即退出码不为 0 时,才会对其进行重启操作
Never 表示从不重启

测试:

[root@kub-k8s-master prome]# kubectl exec -it dapi-test-pod /bin/bash
root@dapi-test-pod:/# echo $SPECIAL_TYPE_KEY
charm

(2) 通过envFrom、configMapRef、name使得configmap中的所有key/value对儿 都自动变成环境变量:

[root@kub-k8s-master prome]# kubectl delete -f testpod.yml 
pod "dapi-test-pod" deleted
[root@kub-k8s-master prome]# cp testpod.yml testpod.yml.bak
[root@kub-k8s-master prome]# vim testpod.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: daocloud.io/library/nginx
      envFrom:
      - configMapRef:
          name: config-map
  restartPolicy: Never

这样容器里的变量名称直接使用configMap里的key名:

[root@kub-k8s-master prome]# kubectl apply -f testpod.yml
pod/dapi-test-pod created.
[root@kub-k8s-master prome]# kubectl exec -it dapi-test-pod -- /bin/bash
root@dapi-test-pod:/# env
HOSTNAME=dapi-test-pod
NJS_VERSION=0.3.3
NGINX_VERSION=1.17.1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PKG_RELEASE=1~stretch
KUBERNETES_PORT=tcp://10.96.0.1:443
PWD=/
special.how=very
HOME=/root
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
TERM=xterm
SHLVL=1
KUBERNETES_SERVICE_PORT=443
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
special.type=charm
KUBERNETES_SERVICE_HOST=10.96.0.1
_=/usr/bin/env

2.2 作为volume挂载使用

(1) 把1.4中test-config4所有key/value挂载进来:

[root@kub-k8s-master prome]# kubectl delete -f testpod.yml
pod "dapi-test-pod" deleted
[root@kub-k8s-master prome]# vim volupod.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-configmap
spec:
  containers:
  - name: nginx-configmap
    image: daocloud.io/library/nginx
    volumeMounts:
    - name: config-volume4
      mountPath: "/tmp/config4"
  volumes:
  - name: config-volume4
    configMap:
      name: test-config4
          
创建pod
[root@kub-k8s-master prome]# kubectl apply -f volupod.yml 
pod/nginx-configmap created

进入容器中/tmp/config4查看:

[root@kub-k8s-master prome]#  kubectl  exec -it nginx-configmap -- /bin/bash
root@nginx-configmap:/# ls /tmp/config4/
cache_host  cache_port  cache_prefix  my.cnf
root@nginx-configmap:/# cat /tmp/config4/cache_host 
memcached-gcxt
root@nginx-configmap:/#

可以看到,在config4文件夹下以每一个key为文件名,value为内容,创建了多个文件。

实战一:创建Nginx配置并挂载

创建了一个包含 Nginx 配置的 ConfigMap,并挂载到容器中的 Nginx 配置目录。

1.定义nginx配置文件,使用configmap制作为卷挂载到nginx容器中
[root@k8s-master map]# cat nginx_configmap.yml 
apiVersion: v1
kind: ConfigMap
metadata:
 name: ng-map
data:
 app.conf: |
  server {
   listen 80;
   server_name localhost;
   location / {
     root /data/www/html;
     index index.html;
    }
   }
   
[root@k8s-master map]# kubectl apply -f nginx_configmap.yml
[root@k8s-master map]# kubectl get cm 
NAME               DATA   AGE
kube-root-ca.crt   1      32d
ng-map             1      18m
[root@k8s-master map]# kubectl describe cm ng-map 
Name:         ng-map
Namespace:    default
Labels:       <none>
Annotations:  <none>
​
Data
====
app.conf:
----
server {
 listen 80;
 server_name localhost;
 location / {
   root /data/www/html;
   index index.html;
  }
 }
​
​
BinaryData
====
​
Events:  <none>
​
2.将configmap定义成卷挂载到容器里面
[root@k8s-master map]# cat use_nginx_map.yml 
apiVersion: v1
kind: Pod
metadata:
 name: my-nginx
 labels:
   app: nginx
spec:
 containers:
  - image: daocloud.io/library/nginx
    imagePullPolicy: IfNotPresent
    name: nginx
    ports:
     - containerPort: 80
    lifecycle:
      postStart:
       exec:
        command: ["/bin/bash","-c","mkdir -p /data/www/html"]
      preStop:
       exec:
        command: ["/bin/sh","-c","nginx -s quit"]
    volumeMounts:
     - name: nginx-conf
       mountPath: /etc/nginx/conf.d
 volumes:
  - name: nginx-conf
    configMap:
     name: ng-map
     
[root@k8s-master map]# kubectl apply -f use_nginx_map.yml
[root@k8s-master map]# kubectl get pod 
NAME               READY   STATUS    RESTARTS      AGE
my-nginx           1/1     Running   0             3m17s
[root@k8s-master map]# kubectl exec -it my-nginx /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@my-nginx:/# cd /data/www/
root@my-nginx:/data/www# ls
html
root@my-nginx:/data/www# cd html/
root@my-nginx:/data/www/html# ls
root@my-nginx:/data/www/html# echo 123123 >> index.html 
root@my-nginx:/data/www/html# exit
exit
[root@k8s-master map]# kubectl get pod -o wide 
NAME               READY   STATUS    RESTARTS      AGE     IP              NODE     NOMINATED NODE   READINESS GATES
my-nginx           1/1     Running   0             32s     10.244.247.45   node-2   <none>           <none>
​
[root@k8s-master map]# curl 10.244.247.45
123123

实战二:创建并使用 ConfigMap 配置文件。

创建了一个包含静态网页内容的 ConfigMap,并挂载到容器中的 Nginx 静态文件目录。

创建configmap
[root@kub-k8s-master configmap]# vim configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
 name: nginx-server-conf
 namespace: default
data:
 index.html: |
  Hello, cloud computing
  Hello, Mr. Wang
  
[root@kub-k8s-master configmap]# kubectl get configmap
NAME                DATA   AGE
nginx-server-conf   2      7s
[root@kub-k8s-master configmap]# kubectl get configmap nginx-server-conf -o yaml
​
使用configmap
[root@kub-k8s-master configmap]# vim pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
 name: test-webapp
spec:
 containers:
 - name: nginx-app
   image: daocloud.io/library/nginx
   ports:
    - containerPort: 80
   volumeMounts:
   - name: nginx-volume
     mountPath: "/usr/share/nginx/html"
 volumes:
 - name: nginx-volume
   configMap:
    name: nginx-server-conf
[root@kub-k8s-master configmap]# kubectl apply -f pod.yaml
[root@kub-k8s-master configmap]# kubectl get pod 
NAME          READY   STATUS    RESTARTS   AGE
test-webapp   1/1     Running   0          6s
[root@kub-k8s-master configmap]# kubectl exec -it test-webapp -- /bin/bash
root@test-webapp:/# cd /usr/share/nginx/html/
root@test-webapp:/usr/share/nginx/html# ls
index.html
root@test-webapp:/usr/share/nginx/html# cat index.html 
Hello, cloud computing
Hello, Mr. Wang
​
[root@kub-k8s-master configmap]# curl 10.244.2.25
Hello, cloud computing
Hello, Mr. Wang

Downward API

Downward API
用于在容器中获取 POD 的基本信息,kubernetes原生支持
​
Downward API提供了两种方式用于将 POD 的信息注入到容器内部:
1.环境变量:用于单个变量,可以将 POD 信息直接注入容器内部。
2.Volume挂载:将 POD 信息生成为文件,直接挂载到容器内部中去。

目前 Downward API 支持的字段:

1. 使用 fieldRef 可以声明使用:
spec.nodeName - 宿主机名字
status.hostIP - 宿主机 IP
metadata.name - Pod 的名字
metadata.namespace - Pod 的 Namespace
status.podIP - Pod 的 IP
spec.serviceAccountName - Pod 的 Service Account 的名字
metadata.uid - Pod 的 UID
metadata.labels['<KEY>'] - 指定 <KEY> 的 Label 值
metadata.annotations['<KEY>'] - 指定 <KEY> 的 Annotation 值
metadata.labels - Pod 的所有 Label
metadata.annotations - Pod 的所有 Annotation
​上面这个列表的内容,随着 Kubernetes 项目的发展肯定还会不断增加。所以这里列出来的信息仅供参考,在使用 Downward API 时,还是要记得去查阅一下官方文档。​
所有基本信息可以使用下面的方式去查看(describe方式看不出来):
[root@kub-k8s-master configmap]# kubectl  get pod test-webapp -o yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"test-webapp","namespace":"default"},"spec":{"containers":[{"image":"daocloud.io/library/nginx","name":"nginx-app","volumeMounts":[{"mountPath":"/usr/share/nginx/html","name":"nginx-volume"}]}],"volumes":[{"configMap":{"name":"nginx-server-conf"},"name":"nginx-volume"}]}}
  creationTimestamp: "2021-02-21T09:44:51Z"
  name: test-webapp
  namespace: default
  resourceVersion: "270687"
  selfLink: /api/v1/namespaces/default/pods/test-webapp
  uid: ed92d685-f800-464f-95dc-d6aa5f92fc9c
......
实战

使用fieldRef获取 POD 的基本信息,以环境变量的方式实现

[root@kub-k8s-master prome]# vim test-env-pod.yml
---
apiVersion: v1
kind: Pod
metadata:
    name: test-env-pod
    namespace: kube-system
spec:
    containers:
    - name: test-env-pod
      image: daocloud.io/library/nginx
      env:
      - name: POD_NAME   #第一个环境变量的名字
        valueFrom:      #使用valueFrom方式设置
          fieldRef:    #关联一个字段metadata.name
            fieldPath: metadata.name  #这个字段从当前运行的pod详细信息查看
      - name: POD_NAMESPACE
        valueFrom:
          fieldRef:
            fieldPath: metadata.namespace
      - name: POD_IP
        valueFrom:
          fieldRef:
            fieldPath: status.podIP
注意: POD 的 name 和 namespace 属于元数据,是在 POD 创建之前就已经定下来了的,所以使用 metadata 获取就可以了,但是对于 POD 的 IP 则不一样,因为POD IP 是不固定的,POD 重建了就变了,它属于状态数据,所以使用 status 去获取。

创建上面的 POD:

[root@kub-k8s-master prome]#  kubectl apply -f test-env-pod.yml
pod/test-env-pod created

POD 创建成功后,查看:

[root@kub-k8s-master prome]# kubectl exec -it test-env-pod /bin/bash -n kube-system
root@test-env-pod:/# env | grep POD
POD_NAME=test-env-pod
POD_NAMESPACE=kube-system
POD_IP=10.244.1.35
root@test-env-pod:/#

Volume挂载

通过Downward API将 POD 的 Label、等信息通过 Volume 以文件的形式挂载到容器的某个文件中去,然后在容器中打印出该文件的值来验证。

[root@kub-k8s-master prome]# vim test-volume-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
    name: test-volume-pod
    namespace: kube-system
    labels:
        k8s-app: test-volume
        node-env: test
spec:
    containers:
    - name: test-volume-pod-container
      image: daocloud.io/library/nginx
      volumeMounts:
      - name: podinfo
        mountPath: /etc/podinfo
    volumes:
    - name: podinfo
      downwardAPI:
        items:
        - path: "labels"
          fieldRef:
            fieldPath: metadata.labels

创建上面的 POD :

[root@kub-k8s-master prome]# kubectl apply -f test-volume-pod.yaml pod/test-volume-pod created
[root@kub-k8s-master prome]# kubectl get pod -n kube-system
[root@k8s-master prome]# kubectl exec -it test-volume-pod /bin/bash -n kube-system
Secret、ConfigMap,以及 Downward API 这三种 Projected Volume 定义的信息,大多还可以通过环境变量的方式出现在容器里。但是,通过环境变量获取这些信息的方式,不具备自动更新的能力。一般情况下,建议使用 Volume 文件的方式获取这些信息。

ServiceAccount详解

k8s中提供了良好的多租户认证管理机制,如RBAC、ServiceAccount还有各种Policy等。

官方文档地址:Configure Service Accounts for Pods | Kubernetes/

k8s中账户分为:UserAccounts(用户账户) 和 ServiceAccounts(服务账户) 两种:UserAccount是给kubernetes集群外部用户使用的,使用kubectl访问k8s的时候要用的用户, 而在kubeadm安装的k8s,默认的useraccount用户是kubernetes-admin;

什么是 Service Account ?

Pod里的进程也可以与 apiserver 联系。 当它们在联系 apiserver 的时候,它们就会被认证为一个特定的 Service Account。  

使用场景

    Service Account它并不是给kubernetes集群的用户使用的,而是给pod里面的进程使用的,它为pod提供必要的身份认证。----专门为pod里面的进程和apiserver通信提供认证的。

Service account与User account区别

1. User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API或其他外部服务而设计的
2. User account是跨namespace的,而service account则是仅局限它所在的namespace;
3. 每个namespace都会自动创建一个default service account    
4. Token controller检测service account的创建,并为它们创建secret

Service Account应用

Service Account(服务账号)示例

因为平时系统会使用默认service account,我们不需要自己创建,感觉不到service account的存在,本实验是使用自己手动创建的service account

1、创建serviceaccount
[root@kub-k8s-master ~]# kubectl create serviceaccount mysa
serviceaccount/mysa created
2、查看mysa
[root@kub-k8s-master ~]# kubectl describe sa mysa
Name:                mysa
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   mysa-token-cknwf
Tokens:              mysa-token-cknwf
Events:              <none>
3、查看mysa自动创建的secret
[root@kub-k8s-master ~]# kubectl  get secret
NAME                  TYPE                                  DATA   AGE
db-user-pass          Opaque                                2      11h
default-token-6svwp   kubernetes.io/service-account-token   3      4d23h
mysa-token-cknwf      kubernetes.io/service-account-token   3      76s
mysecret              Opaque                                2      11h
mysecret-01           Opaque                                2      6h58m
pass                  Opaque                                1      7h6m
user                  Opaque                                1      7h7m
​
4、使用mysa的sa资源配置pod
[root@kub-k8s-master ~]# cd prome/
[root@kub-k8s-master prome]# vim mysa-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: my-pod
spec:
  containers:
  - name: my-pod
    image: daocloud.io/library/nginx
    ports:
    - name: http
      containerPort: 80
  serviceAccountName: mysa   #指定serviceaccount的名称
  
5、导入
[root@kub-k8s-master prome]# kubectl apply -f  mysa-pod.yaml
pod/nginx-pod created
6、查看
[root@kub-k8s-master prome]# kubectl describe pod nginx-pod
7、查看使用的token和secret(使用的是mysa的token)
[root@kub-k8s-master prome]# kubectl get pod nginx-pod -o jsonpath={".spec.volumes"}
[map[name:mysa-token-cknwf secret:map[defaultMode:420 secretName:mysa-token-cknwf]]]
[root@kub-k8s-master prome]#

RBAC (基于角色的访问控制)

        在k8s中我们在执行kubectl这个命令的时候需要与apiserver进行通信,而且整个k8s也是通过apiserver对外提供服务,这时候就需要对访问apiserver的这个用户做认证,但是当认证通过后整个用户仅仅是一个被apiserver信任的用户,只能访问apiserver,还没有对各种资源操作的权限,所以这时候就需要对这个用户进行授权。基于角色的访问控制(Role-Based Access Control, RBAC)是一种用于管理用户权限的方法,广泛应用于企业级系统中。在 Kubernetes 中,RBAC 是一种授权机制,用于控制集群对象上的访问权限。Kubernetes 自 1.5 版本开始就支持 RBAC,从 1.8 版本开始成为默认启用的授权模式。

RBAC详解

RBAC 是一种通过给角色赋予相应权限,从而使该角色具有访问相关资源权限的机制。

Kubernetes授权模式(授权策略)

- ABAC (Attribute Based Access Control):基于属性的访问控制。表示使用用户配置的授权
规则对用户请求进行匹配和控制
- RBAC (Role-Based Access Control):基于角色的访问控制。默认使用该规则
- Webhook:一种 HTTP 回调模式,允许使用远程 REST 端点管理授权
- Node:允许节点访问集群。一种特殊用途的授权模式,专门授权由 kubelet 发出的 API 请求
- AlwaysDeny:始终拒绝访问请求。仅用于测试
- AlwaysAllow:始终允许访问请求。如果有集群不需要授权流程,则可以采用该策略

RBAC API类型

RBAC API 所声明的四种顶级类型【Role、ClusterRole、RoleBinding 和 ClusterRoleBinding】。用户可以像与其他 API 资源交互一样,(通过 kubectl API 调用等方式)与这些资源交互。 

Kubernetes 支持两种类型的用户:
- User:为人设计的用户账户如个人使用的账号。跨Namespace的。手动认证,使用 kubeconfig 
文件。用于人类操作、外部监控。
- ServiceAccount:为Pod设计的账号,主要用于Pod内的应用程序与Kubernetes API服务器进
行通信。仅限于其所在命名空间内的操作。自动挂载认证Token至Pod。适用于服务间通信、自动化流程

RBAC 授权步骤:
1. 定义角色:在定义角色时指定此角色对于资源的访问控制规则。
2. 绑定角色:将主体与角色进行绑定,对用户进行访问授权。

RBAC 资源分为两个级别:
- 命名空间级别:`Role` 和 `RoleBinding`,这些资源仅在一个特定的命名空间内生效。
- 集群级别:`ClusterRole` 和 `ClusterRoleBinding`,这些资源在整个集群范围内生效。

Role 和 ClusterRole:
- Role:普通角色,仅用于授予对某一单一命名空间中资源的访问权限。
- ClusterRole:集群角色,适用于整个 Kubernetes 集群范围内的资源访问权限。
Role 和 ClusterRole 的规则:
- 允许的操作:如 `get`, `list`, `update`, `create`, `delete` 等权限。
- 允许操作的对象:如 `pod`, `svc`(服务)等资源。

RoleBinding 和 ClusterRoleBinding:
- RoleBinding:将用户绑定到 Role 上。
- ClusterRoleBinding:将用户绑定到 ClusterRole 上。如果使用 `ClusterRoleBinding` 
绑定到 `ClusterRole` 上,表示绑定的用户拥有所有命名空间的权限。

kubectl config上下文操作

​检查现有的上下文
kubectl config get-contexts
删除现有的上下文
kubectl config delete-context <context-name>
创建新的集群和上下文
# 创建集群配置
kubectl config set-cluster kubernets \
  --certificate-authority=/path/to/ca.pem \
  --server=https://api.kubernets.example.com
# 创建用户配置
kubectl config set-credentials kubernets-admin \
  --client-certificate=/path/to/admin.pem \
  --client-key=/path/to/admin-key.pem
# 创建上下文
kubectl config set-context kubernets-admin@kubernets \
  --cluster=kubernets \
  --user=kubernets-admin
# 设置当前上下文
kubectl config use-context kubernets-admin@kubernets
修改现有的上下文
# 假设已有上下文名为 existing-context
kubectl config rename-context existing-context kubernets-admin@kubernets
测试连接
kubectl cluster-info

rolebinding和clusterrolebinding操作命令

# 创建 RoleBinding
# 通过 YAML 文件创建 RoleBinding
kubectl apply -f path/to/rolebinding.yaml -n <namespace>

# 创建 ClusterRoleBinding
# 通过 YAML 文件创建 ClusterRoleBinding
kubectl apply -f path/to/clusterrolebinding.yaml

# 查看 RoleBinding
kubectl get rolebindings -n <namespace>
# 查看特定命名空间中的 RoleBinding
kubectl get rolebinding <rolebinding-name> -n <namespace>
# 查看所有命名空间中的 RoleBinding
kubectl get rolebindings --all-namespaces

# 查看 ClusterRoleBinding
kubectl get clusterrolebindings
# 查看特定 ClusterRoleBinding
kubectl get clusterrolebinding <clusterrolebinding-name>

# 显示 RoleBinding 的详细信息
kubectl describe rolebinding <rolebinding-name> -n <namespace>
# 显示 ClusterRoleBinding 的详细信息
kubectl describe clusterrolebinding <clusterrolebinding-name>

# 删除 RoleBinding
kubectl delete rolebinding <rolebinding-name> -n <namespace>

# 删除 ClusterRoleBinding
kubectl delete clusterrolebinding <clusterrolebinding-name>

# 更新 RoleBinding
# 修改 YAML 文件后重新应用
kubectl apply -f path/to/modified-rolebinding.yaml -n <namespace>

# 更新 ClusterRoleBinding
# 修改 YAML 文件后重新应用
kubectl apply -f path/to/modified-clusterrolebinding.yaml

# 查看 RoleBinding 的 YAML 定义
kubectl get rolebinding <rolebinding-name> -n <namespace> -o yaml

# 查看 ClusterRoleBinding 的 YAML 定义
kubectl get clusterrolebinding <clusterrolebinding-name> -o yaml

# 使用 JSONPath 输出 RoleBinding 的特定信息
kubectl get rolebinding <rolebinding-name> -n <namespace> -o 'jsonpath={.spec.subjects}'

# 使用 JSONPath 输出 ClusterRoleBinding 的特定信息
kubectl get clusterrolebinding <clusterrolebinding-name> -o 'jsonpath={.spec.roleRef.name}'

# 检查 RoleBinding 的状态
kubectl get rolebinding <rolebinding-name> -n <namespace> -o 'jsonpath={.status}'

# 检查 ClusterRoleBinding 的状态
kubectl get clusterrolebinding <clusterrolebinding-name> -o 'jsonpath={.status}'

# 使用 kubectl auth can-i 检查权限
kubectl auth can-i '*' '*' -n <namespace>
# 或者对于特定用户和服务账户
kubectl auth can-i '*' '*' --as=<username> -n <namespace>
kubectl auth can-i '*' '*' --as=<serviceaccount>:<namespace>:<name> -n <namespace>

# 修复 RoleBinding
# 如果 RoleBinding 损坏,可以删除后重新创建
kubectl delete rolebinding <rolebinding-name> -n <namespace>
kubectl apply -f path/to/rolebinding.yaml -n <namespace>

# 修复 ClusterRoleBinding
# 如果 ClusterRoleBinding 损坏,可以删除后重新创建
kubectl delete clusterrolebinding <clusterrolebinding-name>
kubectl apply -f path/to/clusterrolebinding.yaml

创建k8s账号与RBAC授权使用

[root@k1 ~]#kubectl config view
显示如下:
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://172.16.229.4:6443     #apiserver的地址
  name: kubernetes                         #集群的名字
contexts:  #上下文--环境
- context:
    cluster: kubernetes   #当前环境的名字                   
    user: kubernetes-admin  #使用的用户  
  name: kubernetes-admin@kubernetes     #环境的名字
current-context: kubernetes-admin@kubernetes       #当前上下文的名字
kind: Config
preferences: {}
users:
- name: kubernetes-admin #默认的管理员用户
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

创建账号

1、创建私钥
给自己创建一个私钥
[root@k1 ~]# (umask 077; openssl genrsa -out soso.key 2048)
查看私钥
# kubectl get config 
用此私钥创建一个csr(证书签名请求)文件
[root@k1 ~]# openssl req -new -key soso.key -out soso.csr -subj  "/CN=soso"
2、拿着私钥和请求文件生成证书
[root@k1 ~]# openssl x509 -req -in soso.csr -CA  /etc/kubernetes/pki/ca.crt  -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out soso.crt -days 365
生成账号(如soso用户)
[root@k1 ~]# kubectl config set-credentials soso --client-certificate=soso.crt --client-key=soso.key --embed-certs=true
3、设置上下文环境--指的是创建这个账号的环境在当前名称空间中
[root@k1 ~]# kubectl config set-context soso@kubernetes --cluster=kubernetes --user=soso
查看当前的工作上下文
[root@k1 ~]# kubectl config view
4、切换用户(切换上下文)
[root@k1 ~]# kubectl config use-context soso@kubernetes
验证是否已经切换到了新的上下文
[root@k1 ~]# kubectl config current-context
5、测试(还未赋予权限)
[root@k1 ~]# kubectl get pod
Error from server (Forbidden): pods is forbidden: User "soso" cannot list resource "pods" in API group "" in the namespace "default"
# 检查现有的上下文。带有 * 标记的上下文表示当前使用的上下文
kubectl config get-contexts
查看当前上下文
kubectl config current-context
创建新的集群和上下文
# 创建集群配置
kubectl config set-cluster kubernets \
  --certificate-authority=/path/to/ca.pem \
  --server=https://api.kubernets.example.com
# 创建用户配置
kubectl config set-credentials kubernets-admin \
  --client-certificate=/path/to/admin.pem \
  --client-key=/path/to/admin-key.pem
# 创建上下文
kubectl config set-context kubernets-admin@kubernets \
  --cluster=kubernets \
  --user=kubernets-admin
# 设置当前上下文
kubectl config use-context kubernets-admin@kubernets

修改现有的上下文
# 假设已有上下文名为 existing-context
kubectl config rename-context existing-context kubernets-admin@kubernets

测试连接
kubectl cluster-info

 创建一个角色(role)---设置权限

1.切回管理帐号
[root@k1 ~]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
创建角色(命令):
[root@k1 ~]# kubectl create role role-reader --verb=get,list,watch --resource=pod,svc
     # role-header:role名称  --verb:允许执行的动作 --resource:指定资源类型
yaml文件方式:
[root@k1 ~]# vim role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 name: role-reader
rules: #定义规则
 - apiGroups: [""]  #表示当前pod使用核心的APIserver组,默认用""表示就可以
   resources: ["pods","svcs"]
   verbs: ["get", "list", "watch", "create", "update", "delete"] #["*"]表示所有权限
[root@k1 ~]# kubectl apply -f role.yaml --save-config # --save-config可不写
[root@k1 ~]# kubectl get roles   # 查看角色命令中role/roles都可以,建议用roles
[root@k1 ~]# kubectl describe role role-reader
2.绑定用户soso(上面创建的用户),绑定用户到role-reader
[root@k1 ~]# kubectl create rolebinding myrole-binding --role=role-reader --user=soso
[root@k1 ~]# vim role-binding.yaml       # yaml文件方式:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
 name: myrolebind
subjects:  #定义主体进行操作,三种Subjects:Service Account、User Account、Groups
- kind: User
  name: soso
  apiGroup: rbac.authorization.k8s.io
roleRef:  #定义使用哪个角色
  kind: Role
  name: role-reader
  apiGroup: rbac.authorization.k8s.io
[root@k1 ~]# kubectl apply -f role-binding.yaml 
[root@k8s-master ~]# kubectl get rolebinding 
3.切换用户
[root@k1 ~]# kubectl config use-context soso@kubernetes​
4.查看权限(只授权了default名称空间pod和svc的get,list,watch权限)
[root@k1 ~]# kubectl get pod
[root@k1 ~]# kubectl get pod -n kube-system  #无权访问kube-system
[root@k1 ~]# kubectl delete pod nginx-pod   #无权限删除
5.切换用户
[root@k1 ~]# kubectl config use-context kubernetes-admin@kubernetes

​绑定用户到集群角色

6.删除soso账号之前绑定的rolebinding
[root@k1 ~]# kubectl delete rolebinding myrolebind
rolebinding.rbac.authorization.k8s.io "myrolebind" deleted
7.创建clusterrole #可以访问全部的namespace
[root@k1 ~]# kubectl create clusterrole myclusterrole --verb=get,list,watch --resource=pod,svc
yaml文件方式:
[root@k1 ~]# vim clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: myclusterrole
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
[root@k1 ~]# kubectl apply -f clusterrole.yaml
[root@k1 ~]# kubectl get clusterrole
​
8.绑定集群角色到用户soso
[root@k1 ~]# kubectl create clusterrolebinding my-cluster-rolebinding --clusterrole=myclusterrole --user=soso
​
yaml文件方式:
[root@k1 ~]# vim clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-cluster-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: myclusterrole
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: soso
[root@k1 ~]# kubectl apply -f clusterrolebinding.yaml
[root@k1 ~]# kubectl get clusterrolebinding
​
9.切换账号
[root@k1 ~]# kubectl  config use-context soso@kubernetes
Switched to context "soso@kubernetes".
​
10.查看权限 查看kube-system空间的pod
[root@kub-k8s-master ~]# kubectl  get pod -n kube-system
NAME                                     READY   STATUS    RESTARTS   AGE
coredns-5644d7b6d9-sm8hs                 1/1     Running   0          5d
coredns-5644d7b6d9-vddll                 1/1     Running   0          5d
etcd-kub-k8s-master                      1/1     Running   0          5d
... 
​
注意:11.切换为管理员用户
[root@k1 ~]# kubectl config use-context kubernetes-admin@kubernetes

设置上下文和账户切换

设置工作上下文(前提得有用户)
[root@k1 ~]# kubectl config set-context soso@kubernetes --cluster=kubernetes --user=soso
查看当前的工作上下文
[root@k1 ~]# kubectl config view
切换上下文(切换用户)
[root@k1 ~]# kubectl config use-context soso@kubernetes
切换为管理员用户
[root@k1 prome]# kubectl config use-context kubernetes-admin@kubernetes
查看某个资源类型是由哪个apiserver版本提供
[root@k1 ~]# kubectl explain ClusterRole

容器监控检查及恢复机制

Kubernetes 探针(Probes)

Kubernetes 支持三种类型的探针(probes),它们分别用于不同的目的:启动探针(startupProbe)、
就绪探针(readinessProbe)和存活探针(livenessProbe)。

### 1. 启动探针(Startup Probe)
**定义**:
- 启动探针用于指示容器中的应用程序是否已经启动。
- 如果提供了启动探针,则在它成功之前禁用所有其他探针。
- 如果启动探针失败,kubelet 将杀死容器,并根据其重启策略进行重启。
- 如果容器没有提供启动探针,则默认状态为成功(Success)。
**作用**:
- 确保应用程序完全启动并准备好接收流量之前不会启用其他探针。
- 有助于避免在应用程序尚未准备好时进行健康检查。

### 2. 存活探针(Liveness Probe)
**定义**:
- 存活探针用于指示容器是否正在运行。
- 如果存活探针失败,kubelet 会杀死容器,并根据其重启策略重启容器。
- 如果容器不提供存活探针,则默认状态为成功(Success)。

**作用**:
- 确保即使应用程序处于非健康状态(如内存泄漏)也能及时重启。
- 提供自愈能力,使集群能够自动恢复故障容器。

### 3. 就绪探针(Readiness Probe)
**定义**:
- 就绪探针用于指示容器是否准备好接收请求。
- 如果就绪探针失败,端点控制器会将该 Pod 从与之匹配的所有 Service 的端点列表中移除。
- 初始延迟之前的就绪状态默认为失败(Failure)。
- 如果容器不提供就绪探针,则默认状态为成功(Success)。
**作用**:
- 避免新创建的 Pod 在尚未准备好处理请求的情况下被 Service 选中。
- 确保 Pod 在完全准备好之后才能接收流量,提高服务的可靠性。

### 举例说明

**就绪探针(Readiness Probe)**:
- **问题**:新创建的 Pod 可能会被 Service 立即选择,并将请求转发给 Pod。然而,如果 
Pod 尚未准备好(如需要加载配置或数据,或需要执行预热程序),此时转发请求可能导致请求失败。
- **解决方案**:为 Pod 添加业务就绪探针(Readiness Probe)。只有当检测到 Pod 已准备好时,
才允许 Service 将请求转发给 Pod。

**存活探针(Liveness Probe)**:
- **问题**:即使应用程序内部出现问题(如内存泄漏),只要容器进程仍在运行,Kubernetes 也
不会重启容器。
- **解决方案**:通过定义 Liveness Probe,Kubernetes 可以基于探针的返回值判断容器的健康
状态,并在必要时重启容器,从而确保应用程序始终处于健康状态。

为什么需要容器探针?

容器探针可以确保您的容器在任何时候都处于可预测的状态。
如果没有容器探针,那么容器对于K8S平台而言,就处于一个黑盒状态。下面是没有使用容器探针
可能出现的一些case:
容器未启动,负载均衡就把流量转发给容器,导致请求大量异常
容器内服务不可用/发生异常,负载均衡把流量转发给容器,导致请求大量异常
容器已经不正常工作(如容器死锁导致的应用程序停止响应),K8S平台本身无法感知,不能即时低重启容器。

探针的定义方式(检测方式)

(1)命令探针(Exec)
Probe执行容器中的命令并检查命令退出的状态码,如果状态码为0则说明已经就绪。
Exec 命令探针字段:
    exec:指定要执行的命令。
    command:指定要执行的命令及其参数。
    initialDelaySeconds:指定容器启动后首次执行探测之前的等待时间。
    periodSeconds:指定执行探测的频率。
(2)HTTP 探针(HTTP GET)
往容器的IP:Port发送HTTP GET请求,如果Probe收到2xx或3xx,说明已经就绪。
HTTP 探针字段:
    httpGet:指定发送 HTTP 请求的配置。
        path:指定请求的路径。
        port:指定目标容器的端口号。
        httpHeaders:可选字段,指定自定义的 HTTP 请求头。
    initialDelaySeconds:指定容器启动后首次执行探测之前的等待时间。
    periodSeconds:指定执行探测的频率。
(3)TCP 探针(TCP Socket)
尝试与容器建立TCP连接,如果能建立连接说明已经就绪。
TCP探针字段
    tcpSocket:指定要连接的容器端口。
    initialDelaySeconds:指定容器启动后首次执行探测之前的等待时间。
    periodSeconds:指定执行探测的频率。

探针探测结果有以下值:
1、Success:表示通过检测。
2、Failure:表示未通过检测。
3、Unknown:表示检测没有正常进行。

实战

Exec模式定义启动探针-startupprobe

exec:通过指定命令执行的返回值判断容器是否启动
[root@k1 test]# vim test-start-exec.yml 
apiVersion: v1
kind: Pod
metadata:
 name: pod-1
 labels:
  web: nginx
spec:
 containers:
  - name: nginx-1
    image: daocloud.io/library/nginx
    ports:
     - name: http
       containerPort: 80
    startupProbe: #定义启动探针进行健康检查
     exec: #指定使用的类型为命令类型
      command:
       - "/bin/bash"
       - "-c"
       - "cat /usr/share/nginx/html/index.html"
     initialDelaySeconds: 5 #健康检查,在容器启动5s后开始执行,默认是 0 秒
     periodSeconds: 5 #执行探测的时间间隔(单位是秒),默认为 10s,最小值是1
     timeoutSeconds: 2 #表示容器必须在2s内做出相应反馈给probe,否则视为探测失败,默认值为1
     successThreshold: 1 #连续探测几次成功才认为探测成功,探测1次成功表示成功,最小值为1。
     failureThreshold: 3 #探测失败的重试次数,重试一定次数后将认为失败,默认为3,最小值为1
     
[root@k1 test]# kubectl get pod -w   #-w实时查看
NAME    READY   STATUS    RESTARTS        AGE
pod-1   0/1     Pending   0               0s
pod-1   0/1     Pending   0               0s
pod-1   0/1     ContainerCreating   0               0s
pod-1   0/1     ContainerCreating   0               0s
pod-1   0/1     Running             0               1s
pod-1   1/1     Running             0               10s #等待10秒后后检查成功进入ready状态

 httpget模式

httpget模式
[root@k8s-master test]# vim test-start-http.yml
apiVersion: v1
kind: Pod
metadata:
 name: pod-8
 labels:
  web: nginx
spec:
 containers:
  - name: nginx-tcp
    image: daocloud.io/library/nginx
    ports:
     - name: http
       containerPort: 80
    startupProbe:
      httpGet: #指定使用的类型为http请求
       scheme: HTTP #指定请求的协议
       port: 80 #指定请求的端口
       path: "/index.html" #指定请求的路径
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 2
      successThreshold: 1
      failureThreshold: 3
​
[root@k8s-master test]# kubectl get pod -w 
NAME    READY   STATUS    RESTARTS        AGE
pod-8   0/1     Pending   0               0s
pod-8   0/1     Pending   0               0s
pod-8   0/1     ContainerCreating   0               0s
pod-8   0/1     ContainerCreating   0               1s
pod-8   0/1     Running             0               2s
pod-8   0/1     Running             0               16s
pod-8   1/1     Running             0               16s

存活探针(livenessProbe)------命令模式探针

Kubernetes 文档中的例子

[root@kub-k8s-master prome]# vim ~/prome/test-liveness-exec.yaml
---
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: test-liveness-exec
spec:
  containers:
  - name: liveness
    image: daocloud.io/library/nginx
    args:
    - /bin/sh
    - -c  
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 50
    livenessProbe:
      exec:
        command: 
        - cat 
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5
它在启动之后做的第一件事是在/tmp目录下创建了一个healthy文件,以此作为自己已经正常运行的标志。而30s过后,它会把这个文件删除掉。与此同时,定义了一个这样的 livenessProbe(健康检查)。它的类型是 exec,它会在容器启动后,在容器里面执行一句我们指定的命令,比如:"cat /tmp/healthy"。这时,如果这个文件存在,这条命令的返回值就是 0,Pod就会认为这个容器不仅已经启动,而且是健康的。这个健康检查,在容器启动5s后开始执行(initialDelaySeconds: 5),每5s执行一次(periodSeconds: 5)。
创建Pod:
[root@kub-k8s-master prome]# kubectl apply -f test-liveness-exec.yaml 
pod/test-liveness-exec created
查看 Pod 的状态:
[root@kub-k8s-master prome]# kubectl get pod 
NAME                    READY   STATUS    RESTARTS   AGE
nginx-configmap         1/1     Running   0          16h
nginx-pod               1/1     Running   0          12h
test-liveness-exec      1/1     Running   0          75s
由于已经通过了健康检查,这个 Pod 就进入了 Running 状态。
然后30 s 之后,再查看一下 Pod 的 Events:
[root@kub-k8s-master prome]# kubectl describe pod test-liveness-exec 
发现,这个 Pod 在 Events 报告了一个异常:
Events:
  Type     Reason     Age                  From                    Message
  ----     ------     ----                 ----                    -------
Warning  Unhealthy  54s (x9 over 3m34s)  kubelet, kub-k8s-node1  Liveness probe failed: cat: /tmp/healthy: No such file or directory
这个健康检查探查到 /tmp/healthy 已经不存在了,所以它报告容器是不健康的。那么接下来会发生什么呢?
再次查看一下这个 Pod 的状态:
[root@kub-k8s-master prome]# kubectl get pod test-liveness-exec
NAME                 READY   STATUS    RESTARTS   AGE
test-liveness-exec   1/1     Running   4          5m19s
这时发现,Pod 并没有进入 Failed 状态,而是保持了 Running 状态。这是为什么呢?
RESTARTS 字段从 0 到 1 的变化,就明白原因了:这个异常的容器已经被 Kubernetes 重启了。在
这个过程中,Pod 保持 Running 状态不变。
#注
k8s 中并没有 Docker 的 Stop 语义。所以如果容器被探针检测到有问题,查看状态虽然看到的是 
Restart,但实际却是重新创建了容器。

这个功能就是 Kubernetes 里的Pod 恢复机制,也叫 restartPolicy。它是 Pod 的 Spec 部分的一个标准字段(pod.spec.restartPolicy),默认值是 Always,即:任何时候这个容器发生了异常,它一定会被重新创建。

    Pod 的恢复过程,永远都是发生在当前节点上,而不会跑到别的节点上去。事实上,一旦
一个 Pod 与一个节点(Node)绑定,除非这个绑定发生了变化(pod.spec.node 字段被修改),
否则它永远都不会离开这个节点。这也就意味着,如果这个宿主机宕机了,这个 Pod 也不会主动迁
移到其他节点上去。 

 http get方式定义探针

创建该pod
[root@kub-k8s-master prome]# kubectl create -f liveness-httpget.yaml 
pod/liveness-httpget-pod created 

查看当前pod的状态
[root@kub-k8s-master prome]# kubectl describe pod liveness-httpget-pod
...
Liveness:       http-get http://:http/index.html delay=1s timeout=1s period=3s #success=1 #failure=3
... 

登陆容器
测试将容器内的index.html删除掉
[root@kub-k8s-master prome]# kubectl exec -it liveness-httpget-pod /bin/bash
root@liveness-httpget-pod:/# mv /usr/share/nginx/html/index.html index.html
root@liveness-httpget-pod:/# command terminated with exit code 137
可以看到,当把index.html移走后,这个容器立马就退出了。
此时,查看pod的信息
[root@k1 prome]# kubectl describe pod liveness-httpget-pod
...
Normal   Killing    49s   kubelet, kub-k8s-node2  Container liveness-exec-container failed liveness probe, will be restarted
Normal   Pulled     49s   kubelet, kub-k8s-node2  Container image "daocloud.io/library/nginx" already present on machine
...
看输出,容器由于健康检查未通过,pod会被杀掉,并重新创建

[root@k1 prome]#  kubectl get pods
NAME                    READY   STATUS             RESTARTS   AGE
lifecycle-demo          1/1     Running            1          34h
liveness-httpget-pod    1/1     Running            1          5m42s
​
#restarts 为 1
重新登陆容器,发现index.html又出现了,证明容器是被重拉了。

[root@k1 prome]# kubectl exec -it liveness-httpget-pod /bin/bash
root@liveness-httpget-pod:/# cat /usr/share/nginx/html/index.html

在生产环境最好是一块使用,尤其是就绪和存活探针共用。

容器的重启策略

Pod 的重启策略:
可以通过设置 restartPolicy,改变 Pod 的恢复策略。一共有3种:
    1. Always:      在任何情况下,只要容器不在运行状态,就自动重启容器;
    2. OnFailure:    只在容器 异常时才自动重启容器;
    3. Never:         从来不重启容器。
实际使用时,需要根据应用运行的特性,合理设置这三种恢复策略。

Deployment副本控制器资源详解

如果Pod出现故障,对应的服务也会挂掉,所以Kubernetes提供了一个Deployment的概念 ,目的
是让Kubernetes去管理一组Pod的副本,也就是副本集,这样就能够保证一定数量的副本一直可用,
不会因为某一个Pod挂掉导致整个服务挂掉。
​
Deployment是k8s中最常用的资源对象,为ReplicaSet和Pod的创建提供了一种声明式的定义方法,
官方建议使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,是因为Deployment 
还负责在 Pod 定义发生变化时,对每个副本进行滚动更新(Rolling Update)。
​
每创建一个Deployment控制器都会创建一个对应的ReplicaSet,在通过ReplicaSet去创建pod,删除
Deployment,同时也会删除对应的ReplicaSet和pod。

创建Deployment

使用yaml创建Deployment
k8s deployment资源创建流程:
1. 用户通过 kubectl 创建 Deployment。
2. Deployment 创建 ReplicaSet。
3. ReplicaSet 创建 Pod。
对象的命名方式是:子对象的名字 = 父对象名字 + 随机字符串或数字

Deployment是一个定义及管理多副本应用(即多个副本 Pod)的新一代对象,与Replication Controller相比,它提供了更加完善的功能,使用起来更加简单方便。

apiVersion: apps/v1  # 指定api版本,必需。业务场景一般首选“apps/v1”
kind: Deployment   # 指定创建资源的角色/类型   
metadata:          # 资源的元数据/属性 
  name: demo      # 资源的名字,在同一个namespace中必须唯一
  namespace: default  # 部署在哪个namespace中。不指定时默认为default命名空间
  labels:          # 自定义资源的标签
    app: demo
    version: stable
  annotations:  # 自定义注释列表
    name: string
spec:  # 资源规范字段,定义deployment资源需要的参数属性
  replicas: 2   # 声明副本数目
  revisionHistoryLimit: 3   # 保留历史版本
  selector:     # 标签选择器
    matchLabels:     # 匹配标签,需与上面的标签定义的app保持一致
      app: demo
      version: stable
  strategy:     # 策略
    type: RollingUpdate     # 滚动更新策略
    # ecreate:删除所有已存在的pod,重新创建新的
    # RollingUpdate:滚动升级逐步替换的策略,同时滚动升级时支持更多的附加参数,
    # 例如设置最大不可用pod数量,最小升级间隔时间等等
    rollingUpdate:   # 滚动更新
      maxSurge: 1    # 滚动升级时最大额外可以存在的副本数,可以为百分比或整数
      maxUnavailable: 0   # 更新过程不可用状态Pod最大值,可以为百分比或整数
  template:   # 定义业务模板,如有多个副本,所有副本的属性会按照模板的相关配置进行匹配
    metadata:   # 资源的元数据/属性 
      annotations:      # 自定义注解列表
        sidecar.istio.io/inject: "false"   # 自定义注解名字
      labels:     # 自定义资源的标签
        app: demo    # 模板名称必填
        version: stable
    spec:     # 资源规范字段
      restartPolicy: Always  # Pod的重启策略。[Always | OnFailure | Nerver]
      # Always :任何情况下只要容器不在运行状态,就自动重启容器。默认
      # OnFailure :只在容器异常时才自动容器容器。
             # pod包含多个容器时,其中所有容器都异常pod才会进入Failed状态
     # Nerver :从不重启容器
      nodeSelector:   # 将该Pod调度到含此label的node上,基于简单等值关系定义标签选择器
        caas_cluster: work-node
      containers:        # Pod中容器列表
      - name: demo       # 容器的名字   
        image: demo:v1   # 容器使用的镜像地址   
        imagePullPolicy: IfNotPresent     # 每次Pod启动拉取镜像策略
                   # IfNotPresent :如果本地有就不检查,如果没有就拉取。默认 
                   # Always: 每次都检查
                   # Never : 每次都不检查(不管本地是否有)
        command: [string]     # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
        args: [string]         # 容器的启动命令参数列表
# 如果command和args均没有写,那么用Docker默认的配置;
# 如果command写了,args没写,Docker默认配置被忽略且仅执行.yaml文件的command(不带参数)
# 如果command没写,args写了,Docker默认配置的ENTRYPOINT命令行被执行,调用参数.yaml中的args
# 如果command和args都写了,那么Docker默认的配置被忽略,使用.yaml的配置
        workingDir: string   # 容器的工作目录
        volumeMounts:        # 挂载到容器内部的存储卷配置
        - name: string       # 引用pod定义的共享存储卷的名称,用volumes[]部分定义的卷名
          mountPath: string  # 存储卷在容器内mount的绝对路径,应少于512字符
          readOnly: boolean  # 是否为只读模式
        - name: string
          configMap:    # 类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
            name: string
            items:
            - key: string
              path: string
        ports:    # 需要暴露的端口库号列表
          - name: http     # 端口号名称
            containerPort: 8080     # 容器开放对外的端口 
          # hostPort: 8080    # 容器所在主机需要监听的端口号,默认与Container相同
            protocol: TCP     # 端口协议,支持TCP和UDP,默认TCP
        env:    # 容器运行前需设置的环境变量列表
        - name: string     # 环境变量名称
          value: string    # 环境变量的值
        resources:     # 资源管理。资源限制和请求的设置
          limits:     # 资源限制的设置,最大使用
            cpu: "1"  # CPU,"1"(1核) = 1000m。用于docker run --cpu-shares参数
            memory: 500Mi  # 内存,1G = 1024Mi。用于docker run --memory参数
          requests:  # 资源请求设置。容器运行时最低资源需求
            cpu: 100m
            memory: 100Mi
        livenessProbe:     # pod内部容器的健康检查设置。当探测无响应几次后将自动重启该容器
     # 检查方法:exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
          httpGet: # 通过httpget检查健康,返回200-399之间,则认为容器正常
            path: /healthCheck     # URI地址。如果没有心跳检测接口就为/
            port: 8089         # 端口
            scheme: HTTP     # 协议
            # host: 127.0.0.1     # 主机地址
        # 也可以用这两种方法进行pod内容器的健康检查
        # exec:  # 容器内执行任意命令,检查命令退出状态码为0则探测成功,否则探测失败容器重启
        #   command:   
        #     - cat   
        #     - /tmp/health   
        # 也可以用这种方法   
        # tcpSocket: # 对Pod内容器健康检查方式设置为tcpSocket方式
        #   port: number 
          initialDelaySeconds: 30  # 容器启动完成后首次探测的时间,单位为秒
          timeoutSeconds: 5     # 对容器健康检查等待响应的超时时间,默认1秒
          periodSeconds: 30     # 对容器监控检查的定期探测间隔时间设置,默认10秒一次
          successThreshold: 1     # 成功门槛
          failureThreshold: 5     # 失败门槛,连接失败5次,pod杀掉,重启一个新的pod
        readinessProbe:         # Pod准备服务健康检查设置
          httpGet:
            path: /healthCheck    # 如果没有心跳检测接口就为/
            port: 8089
            scheme: HTTP
          initialDelaySeconds: 30
          timeoutSeconds: 5
          periodSeconds: 10
          successThreshold: 1
          failureThreshold: 5
        lifecycle:        # 生命周期管理  
          postStart:    # 容器运行之前运行的任务  
            exec:  
              command:  
                - 'sh'  
                - 'yum upgrade -y'  
          preStop:        # 容器关闭之前运行的任务  
            exec:  
              command: ['service httpd stop']
      initContainers:        # 初始化容器
      - command:
        - sh
        - -c
        - sleep 10; mkdir /wls/logs/nacos-0
        env:
        image: {{ .Values.busyboxImage }}
        imagePullPolicy: IfNotPresent
        name: init
        volumeMounts:
        - mountPath: /wls/logs/
          name: logs
      volumes:
      - name: logs
        hostPath:
          path: {{ .Values.nfsPath }}/logs
      volumes:     # 在该pod上定义共享存储卷列表
      - name: string   # 共享存储卷名称 (volumes类型有很多种)
        emptyDir: {}   # 类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      - name: string
        hostPath:      # 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
          path: string # Pod所在宿主机的目录,将被用于同期中mount的目录
      - name: string
        secret:        # 类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
          scretname: string  
          items:     
          - key: string
            path: string
      imagePullSecrets:  # 镜像仓库拉取镜像时使用的密钥,以key:secretkey格式指定
      - name: harbor-certification
      hostNetwork: false # 主机网络模式,默认为false,设置为true表示使用宿主机网络
      terminationGracePeriodSeconds: 30  # 优雅关闭时间,这个时间内优雅关闭未结束,k8s强制 kill
      dnsPolicy: ClusterFirst  # 设置Pod的DNS的策略。默认ClusterFirst
 # 支持的策略:[Default | ClusterFirst | ClusterFirstWithHostNet | None]
# Default : Pod继承所在宿主机的设置,直接将宿主机的/etc/resolv.conf内容挂载到容器中
# ClusterFirst : 默认的置,所有请求优先在集群所在域查询,没有才会转发到上游DNS
# ClusterFirstWithHostNet : 和ClusterFirst一样,Pod运行在hostNetwork:true下强制指定
# None : 1.9版本引入的新值,此配置忽略所有配置,以Pod的dnsConfig字段为准
      affinity:  # 亲和性调试
        nodeAffinity:  # 节点亲和性。满足特定条件的pod对象运行在同一个node上。效果同nodeSelector,但功能更强大
          requiredDuringSchedulingIgnoredDuringExecution:  # 硬亲和性
            nodeSelectorTerms:         # 节点满足任何一个条件就可以
            - matchExpressions:  # 有多个选项时,同时满足这些逻辑选项的节点才能运行pod
              - key: beta.kubernetes.io/arch
                operator: In
                values:
                - amd64
        podAffinity:    # pod亲和性。满足特定条件的pod对象运行在同一个node上
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector: 
              matchExpressions: 
              - key: app
                operator: In
                values: 
                - nginx
            topologyKey: kubernetes.io/hostname
        podAntiAffinity:  # pod反亲和性。满足特定条件(相同pod标签)pod对象不能运行在同一个node上
          requiredDuringSchedulingIgnoredDuringExecution: 
          - labelSelector: 
              matchExpressions: 
              - key: app
                operator: In
                values: 
                - nginx
            topologyKey: kubernetes.io/hostname   # 反亲和性的节点标签 key
      tolerations:        # 污点容忍度。允许pod可以运行在匹配的污点上
      - operator: "Equal" # 匹配类型。支持[Exists | Equal(默认值)]。Exists为容忍所有污点
        key: "key1"
        value: "value1"
        effect: "NoSchedule"  # 污点类型:[NoSchedule | PreferNoSchedule | NoExecute]
                              # NoSchedule :不会被调度 
                              # PreferNoSchedule:尽量不调度
                              # NoExecute:驱逐节点

Deployment 的示例1

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

例2:在上面yaml的基础上添加了volume

[root@kub-k8s-master prome]# vim deployment.yaml
apiVersion: apps/v1  #注意版本号
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:  #属性,选择器
    matchLabels:
      app: nginx
  replicas: 2  #管理的副本个数
  template:  #模板属性
    metadata: #对pod的描述
      labels:
        app: nginx
    spec:
      volumes:   #定义共享卷
      - name: nginx-vol
        emptyDir: {}
      containers:
      - name: nginx
        image: daocloud.io/library/nginx
        ports:
        - containerPort: 80
        volumeMounts:  #定义挂载卷
        - mountPath: "/usr/share/nginx/html"
          name: nginx-vol
创建Deployment:
将上述的YAML文件保存为deployment.yaml,然后创建Deployment:
[root@kub-k8s-master prome]# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
​
检查Deployment的列表:启动之后需要创建时间比较长
通过 kubectl get 命令检查这个 YAML 运行起来的状态:
[root@kub-k8s-master prome]# kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           2m22s
​
[root@kub-k8s-master prome]# kubectl get pods -l app=nginx
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-59c4b86474-2llrt   1/1     Running   0          2m51s
nginx-deployment-59c4b86474-n2r2m   1/1     Running   0          2m51s
​
在这里加上了一个 -l 参数,即获取所有匹配 app: nginx 标签的 Pod。需要注意的是,在命令行中,所有 key-value 格式的参数,都使用"="而非":"表示。
​
删除Deployment:
[root@k8s-master ~]# kubectl delete deployments nginx-deployment
deployment "nginx-deployment" deleted
或者
[root@k8s-master ~]# kubectl delete -f   deployment.yaml
apiVersion:注意这里apiVersion对应的值是extensions/v1beta1或者apps/v1.这个版本号需要
根据安装的Kubernetes版本和资源类型进行变化,记住不是写死的。此值必须在kubectl apiversion中 
[root@kub-k8s-master prome]# kubectl api-versions
    apps/v1beta1
    authentication.k8s.io/v1beta1
    authorization.k8s.io/v1beta1
    autoscaling/v1
    batch/v1
    certificates.k8s.io/v1alpha1
    extensions/v1beta1
    policy/v1beta1
    rbac.authorization.k8s.io/v1alpha1
    storage.k8s.io/v1beta1
    v1
​
kind:资源类型指定为Deployment。
metadata:指定一些meta信息,包括名字或标签之类的。每一个 API 对象都有一个叫作 Metadata 的字段,这个字段是 API 对象的"标识",即元数据,也是我们从 Kubernetes 里找到这个对象的主要依据。
labels:Labels是最主要的字段,是一组 key-value 格式的标签,k8s中的所有资源都支持携带label,
默认情况下,pod的label会复制rc的label
k8s使用用户自定义的key-value键值对来区分和标识资源集合(就像rc、pod等资源),这种键值对
称为label。像 Deployment 这样的控制器对象,就可以通过这个 Labels 字段从 Kubernetes 中过滤
出它所关心的被控制对象。
selector:过滤规则的定义,是在 Deployment 的"spec.selector.matchLabels"字段。一般
称之为:Label Selector。
pod的label会被用来创建一个selector,用来匹配过滤携带这些label的pods。

使用labels定位pods

[root@k1 ~]# kubectl get pods -l app=nginx -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP            NODE       
nginx-deployment-59c4b86474-2llrt   1/1     Running   0          16m   10.244.2.15   kub-k8s-node2   
nginx-deployment-59c4b86474-n2r2m   1/1     Running   0          16m   10.244.1.39   kub-k8s-node1   
检查你的Pod的IPs:
[root@k1 ~]# kubectl get pods -l app=nginx -o json | grep podIP # JSON格式输出
                "podIP": "10.244.2.15",
                "podIPs": [
                "podIP": "10.244.1.39",
                "podIPs": [
​spec : 一个 k8s 的 API 对象的定义,大多可以分为 Metadata 和 Spec 两个部分。前者存放
的是这个对象的元数据,对所有 API 对象来说,这一部分的字段和格式基本上是一样的;而后者存
放的,则是属于这个对象独有的定义,用来描述它所要表达的功能。
这里定义需要两个副本,此处可以设置很多属性,主要是受此Deployment影响的Pod的选择器
​
replicas:定义的 Pod 副本个数 (spec.replicas) :2

template:定义了一个 Pod 模版(spec.template),这个模版描述了想要创建的 Pod 的细节。
例子里,这个 Pod 里只有一个容器,这个容器的镜像(spec.containers.image)是 nginx:latest,
这个容器监听端口(containerPort)是 80。

volumes:是属于 Pod 对象的一部分。需要修改 template.spec 字段
    例2中,在 Deployment 的 Pod 模板部分添加了一个 volumes 字段,定义了这个 Pod 声明
的所有 Volume。它的名字叫作 nginx-vol,类型是 emptyDir。 
关于emptyDir 类型:等同于 Docker 的隐式 Volume 参数,即:不显式声明宿主机目录的 Volume。
所以,Kubernetes 也会在宿主机上创建一个临时目录,这个目录将来就会被绑定挂载到容器所声明的
 Volume 目录上。
k8s 的 emptyDir 类型,只是把 k8s 创建的临时目录作为 Volume 的宿主机目录,交给了 Docker。
当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。
​
volumeMounts:Pod 中的容器,使用的是 volumeMounts 字段来声明自己要挂载哪个 Volume,
并通过 mountPath 字段来定义容器内的 Volume 目录,比如:/usr/share/nginx/html。
​
hostPath:k8s 也提供了显式的 Volume 定义,它叫做 hostPath。比如下面的这个 YAML 文件:
    ...   
        volumes:
          - name: nginx-vol
            hostPath: 
              path: /var/data
    这样,容器 Volume 挂载的宿主机目录,就变成了 /var/data

​查看rs

[root@k8s-master ~]# kubectl get rs
NAME                         DESIRED   CURRENT   READY   AGE
nginx-deployment-59c4b86474   2         2         2      2m49s

创建SERVICE

​工作原理:
service对外提供请求,当访问service的时候并将请求转发到集群中的pod中。此过程是通过endpoint
与selector实现的。selector是用于选择带有某个标签的pod,然后将该pod的ip和端口添加到endpoint
中。当访问service时就会从endpoint中选择对应的pod的ip和端口,然后将请求转发到对应的pod中。
​
具体请求如何转发过去的就需要kube-proxy去实现了。
三台安装iptables:
[root@kub-k8s-master prome]# yum install -y iptables iptables-services
1.创建一个depl
[root@kub-k8s-master prome]# kubectl delete -f deployment.yaml
[root@kub-k8s-master prome]# vim nginx-depl.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dep01
spec:
  selector:
    matchLabels:
      app: web
  replicas: 2
  template:
      metadata:
        labels:
          app: web
      spec:
        containers:
          - name: testnginx9
            image: daocloud.io/library/nginx
            ports:
              - containerPort: 80
[root@kub-k8s-master prome]# kubectl apply -f nginx-depl.yml 
deployment.apps/nginx-deployment created
2. 创建service并且以nodePort的方式暴露端口给外网:
[root@kub-k8s-master prome]# vim nginx_svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysvc
spec:
  type: NodePort  #类型
  ports:
    - port: 8080
      nodePort: 30001
      targetPort: 80
  selector:   #选择器
    app: web
    
[root@kub-k8s-master prome]# kubectl apply -f nginx_svc.yaml 
service/mysvc created
3.查看
[root@kub-k8s-master prome]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          5d18h
mysvc        NodePort    10.100.166.208   <none>        8080:30001/TCP   21s
​
4.查看service的详细信息
[root@kub-k8s-master prome]# kubectl describe svc mysvc
Name:              mysvc
......
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.84.130:80,10.244.84.131:80
Session Affinity:  None
Events:            <none>
​
5.当创建好svc之后,k8s会默认给创建一个和svc名字一样的endpoints
[root@kub-k8s-master prome]# kubectl get ep mysvc
NAME         ENDPOINTS                           AGE
mysvc   10.244.84.130:80,10.244.84.131:80       7m15s

端口详解

安装iptables(但是需要关闭iptables),创建service之后k8s会自动添加规则到Iptables里面,而且会生效(虽然iptables处于关闭状态)

服务中的3个端口设置
这几个port的概念很容易混淆,比如创建如下service:
apiVersion: v1
kind: Service
metadata:
  name: mysvc
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30001
      targetPort: 80
  selector:
    app: web
port
这里的port表示:service暴露在cluster ip上的端口,cluster ip:port 是提供给集群内部客户访问service的入口。
nodePort
首先,nodePort是kubernetes提供给集群外部客户访问service入口的一种方式(另一种方式是LoadBalancer),所以,<nodeIP>:nodePort 是提供给集群外部客户访问service的入口。
targetPort
targetPort很好理解,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。
​
NodePort端口的范围是从30000到32767
port、nodePort总结
总的来说,port和nodePort都是service的端口,前者暴露给集群内客户访问服务,后者暴露给集群外客户访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的targetPort,从而到达pod上的容器内。
kube-proxy反向代理
kube-proxy目前支持三种工作模式:
1.userspace 模式
2.iptables 模式:iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。(该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则)
3.ipvs 模式:ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。而且ipvs支持更多的LB算法。

kube-proxy与iptables与ipvsadm

当service有了port和nodePort之后,就可以对内/外提供服务。那么其具体是通过什么原理来实现的呢?原因就在kube-proxy在本地node上创建的iptables规则。
​
Kube-Proxy 通过配置 DNAT  规则(从容器出来的访问,从本地主机出来的访问两方面),将到这个服务地址的访问映射到本地的kube-proxy端口(随机端口)。然后  Kube-Proxy 会监听在本地的对应端口,将到这个端口的访问给代理到远端真实的 pod 地址上去,同时生成lvs的负载规则
​
 不管是通过集群内部服务入口<cluster ip>:port还是通过集群外部服务入口<node  ip>:nodePort的请求都将重定向到本地kube-proxy端口(随机端口)的映射,然后将到这个kube-proxy端口的访问给代理到远端真实的  pod 地址上去。在通过lvs实现负载
​
查看负载规则
[root@kube-k8s-master prome]# ipvsadm -Ln    
 
如果没有规则
[root@master ~]# kubectl edit cm kube-proxy -n kube-system
搜索mode: 添加ipvs
然后将所有的kube-proxy的pod删除,等待重新创建即可​
注意:自k8s1.1以后,service默认使用ipvs规则,若ipvs没有被激活,则降级使用iptables规则.

RC资源(了解)

Replication Controller(简称rc)用来管理Pod的副本,保证集群中存在指定数量的Pod副本。集群中副本的数量大于指定数量,则会停止指定数量之外的多余容器数量,反之,则会启动少于指定数量个数的容器,保证数量不变。Replication Controller是实现弹性伸缩、动态扩容和滚动升级的核心。
​
RC 的主要功能点:
确保pod数量:指定某个服务在Kubernetes中有相应数量的Pod在运行;
确保pod健康:当pod不健康,运行出错或者无法提供服务时,会杀死不健康pod并重新创建,保持pod数量一致;
弹性伸缩:当业务高峰期的时候可以设置扩增pod数量,配合监控就可以做自动伸缩了;
滚动升级:也就是蓝绿发布,当一个pod使用的镜像更新,采用滚动升级模式,RC会自动一个个pod的进行升级,关闭一个pod的同时进行升级,且在原镜像基础上创建一个新pod,当一个pod更新完成再关闭一个旧镜像pod。

使用yaml创建并启动replicas集合

Replication Controller会确保pod的数量在运行的时候会一直保持在一个特殊的数字,即replicas的设置。
[root@kub-k8s-master ~]# cd prome/
[root@kub-k8s-master prome]# vim nginx-rc.yml
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: daocloud.io/library/nginx
        ports:
        - containerPort: 80

如果你在删除rc之前尝试删除pod,rc将会立即启动新的pod来替换被删除的pod

完整TOMCAT实例

Java Web应用

注:Tomcat有可能无法正常启动,原因是虚机的内存和CPU设置过小,请酌情调大!

下载镜像

[root@kub-k8s-node1 ~]#  docker pull daocloud.io/library/tomcat 
构建Tomcat RC定义文件
[root@kub-k8s-master prome]# vim myweb.rc.yml
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb
spec:
  replicas: 2
  selector:
    app: myweb
  template:
    metadata:
      labels:
        app: myweb
    spec:
      containers:
        - name: myweb
          image: daocloud.io/library/tomcat:8
          ports:
          - containerPort: 8080  #在8080端口上启动容器进程,PodIP与容器端口组成Endpoint,代表着一个服务进程对外通信的地址
发布到Kubernetes集群

创建RC

[root@kub-k8s-master prome]# kubectl apply -f myweb.rc.yml 
replicationcontroller/myweb created 

查看RC

[root@kub-k8s-master prome]# kubectl get rc
NAME       DESIRED   CURRENT   READY   AGE
myweb      1         1         1       20s

查看Pod

[root@kub-k8s-master prome]# kubectl get pods
NAME                                READY   STATUS             RESTARTS   AGE
myweb-shjfn                         1/1     Running            0          52s
构建Tomcat Kubernetes Service定义文件
[root@kub-k8s-master prome]# vim myweb-svc.yaml
apiVersion: v1
kind: Service
metadata: 
  name: myweb
spec:
  type: NodePort
  ports:
    - port: 8081
      nodePort: 30009
      targetPort: 8080
  selector:
    app: myweb

创建

[root@kub-k8s-master prome]# kubectl apply -f myweb-svc.yaml 
service/myweb created

查看SVC

[root@kub-k8s-master prome]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          5d22h
mysvc        NodePort    10.110.160.108   <none>        8080:30001/TCP   3h37m
myweb        NodePort    10.96.19.61      <none>        8081:30009/TCP   33s
运行

浏览器中输入http://虚拟机IP:30009即可呈现如下内容:

注意在节点(node)中访问,不是master

[root@kub-k8s-node1 ~]# curl 192.168.246.166:30009

K8S之暴露IP给外网

转发K8S后端服务的四种方式

方式1:ClusterIP

此类型会提供一个集群内部的虚拟IP(与Pod不在同一网段),以供集群内部的pod之间通信使用。ClusterIP也是Kubernetes service的默认类型。    

方式2:NodePort

外网client--->nodeIP+nodePort--->podIP+PodPort
​
为每个节点暴露一个端口,通过nodeip + nodeport可以访问这个服务,同时服务依然会有cluster类型的ip+port。内部通过clusterip方式访问,外部通过nodeport方式访问。

方式3:loadbalance

LoadBalancer在NodePort基础上,K8S可以请求底层云平台创建一个负载均衡器,将每个Node作为后端,进行服务分发。

方式4:Ingress

Ingress是一种HTTP方式的路由转发机制,为K8S服务配置HTTP负载均衡器,通常会将服务暴露给K8S群集外的客户端。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2215732.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows安装VMware虚拟机 在虚拟机中安装Centos系统

文章目录 安装虚拟机Centos7.5 软硬件安装安装Centos所需的硬件配置处理器与内核 安装虚拟机 Centos7.5 软硬件安装 安装Centos所需的硬件 配置处理器与内核 一个CPU可以有多个内核 此处可以看出该电脑一个处理器&#xff0c;四个内核。配置虚拟器的原则是不能超过总数的一半…

Mybatis全局配置介绍

【mybatis全局配置介绍】 mybatis-config.xml&#xff0c;是MyBatis的全局配置文件&#xff0c;包含全局配置信息&#xff0c;如数据库连接参数、插件等。整个框架中只需要一个即可。 1、mybatis全局配置文件是mybatis框架的核心配置&#xff0c;整个框架只需一个&#xff1b…

BFS处理最短路问题

BFS与最短路问题小结 - AcWing 题目 这题就可以BFS&#xff08;边权值相同&#xff09;&#xff08;g[i][j]也可以为inf&#xff0c;g[i][i]还能为0&#xff09; 代码 #include <bits/stdc.h> using namespace std; const int N 510; const int inf 0x3f3f3f3f; int n…

【火山引擎】AIGC图像风格化 | 风格实践 | PYTHON

目录 1 准备工作 2 实践 代码 效果图 1 准备工作 ① 服务开通 确保已开通需要访问的服务。您可前往火山引擎控制台,在左侧菜单中选择或在顶部搜索栏中搜索需要使用的服务,进入服务控制台内完成开通流程。

大话C++:第18篇 类继承与派生

1 类继承的概述 类继承&#xff08;Class Inheritance&#xff09;是面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;中的一个核心概念。它允许我们创建一个新的类&#xff08;子类或派生类&#xff09;&#xff0c;该类继承了另一个已存在的…

深度学习模型量化方法-【文末含实战】主流深度学习框架

目录 一&#xff0c;深度学习模型量化概述 1.1 模型量化定义 1.2 模型量化的方案 1.3&#xff0c;量化的分类 1.4 模型量化好处 总结&#xff1a; 二&#xff0c;常用量化框架 2.1 OpenVINO NCCF OpenVINO NCCF量化流程 OpenVINO NCCF量化优势 2.2 TensorRT量化框架…

如何向两个不同 MySQL 数据源的相同数据库与表写入数据

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

AcWing 3188:Manacher 算法 → 最长回文子串

【题目来源】https://www.acwing.com/problem/content/3190/【题目描述】 给定一个长度为 n 的由小写字母构成的字符串&#xff0c;求它的最长回文子串的长度是多少。【输入格式】 一个由小写字母构成的字符串。【输出格式】 输出一个整数&#xff0c;表示最长回文子串的长度。…

VSCode创建插件HelloWorld找不到指令解决办法

按照网上的教程执行yo code并且生成成功 但是F5打开调试新窗口后&#xff0c;ctrl shift P&#xff0c;输入helloworld并没有指令提示 原因&#xff1a;当前电脑安装的VSCode版本过低&#xff0c;不支持当前插件的使用&#xff08;因为自动生成的插件总是默认使用最新版VSC…

00 springboot项目创建

我们创建SpringBoot项目有两种方式: Spring Initializr spring initerzie 方式创建: 启动类, 依赖 生成,但是需要网络maven的方式 maven方式创建: 启动类, 依赖, 这些都需要手动编写,但是不需要网络 如果你觉得我分享的内容或者我的努力对你有帮助&#xff0c;或者你只是想表…

可看见车辆行人的高清实时视频第5辑

我们在《看见车辆行人的高清实时视频第4辑》分享了10处可看见车辆行人的实时动态高清视频。 现在我们又整理10处为你分享可看见车辆行人的实时动态高清视频&#xff0c;一共有50个摄像头数据&#xff0c;这些视频来自公开的高清摄像头实时直播画面。 我们在文末为你分享了这些…

制造业如何从0-1实现信息化建设?

深度长文&#xff0c;4000 字&#xff0c;融合了众多企业的实践经验和行业观点&#xff0c;一文讲清制造业信息化建设的路径&#xff0c;心急的小伙伴可以先看目录&#xff1a; 关于定义 —— 制造业信息化建设是什么&#xff1f;关于价值 —— 为什么制造业要进行信息化建设…

【C++】精妙的哈希算法

&#x1f680;个人主页&#xff1a;小羊 &#x1f680;所属专栏&#xff1a;C 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 一、哈希结构1、哈希概念2、哈希函数3、哈希冲突3.1 闭散列3.2 开散列 4、完整代码 一、哈希结构 1、哈希概念 A…

漏扫工具Appscan使用(非常详细)从零基础入门到精通,看完这一篇就够了。

1、简介 AppScan是一款商业化的web安全扫描工具&#xff0c;web扫描领域十分受欢迎 2、具体使用规则 1、常用界面 新建扫描文件 选择扫描 对于第一种扫描方式&#xff1a; 设置url和服务器 登录管理&#xff1a;对于需要登陆的页面&#xff08;这种方法不允许有验证码&#…

人工智能AI与机器学习ML基础入门

小学生都能看懂的人工智能入门书籍 第一章 入门简介 TensorFlow 入门 如果你想入门人工智能&#xff08;AI&#xff09;&#xff1f;机器学习&#xff08;ML&#xff09;和深度学习是很好的起点。不过&#xff0c;一开始接触这些概念时&#xff0c;可能会被各种选项和新术语搞…

关于Spring Framework路径遍历漏洞(CVE-2024-38816)的预警提示和修复方案

一、漏洞详情 Spring Framework是一个Java应用程序框架&#xff0c;旨在提供高效且可扩展的开发环境。 近日&#xff0c;监测到Spring Framework中修复了一个路径遍历漏洞&#xff08;CVE-2024-38816&#xff09;。Spring Framework受影响版本中&#xff0c;使用WebMvc.fn 或…

MyBatisCodeHelperPro一直用教程

qq群&#xff1a;984518344 不懂请留言&#xff01;&#xff01;&#xff01; &#xff08;有能力请请支持正版&#xff01;&#xff01;&#xff09; &#xff08;仅供学习交流&#xff0c;严禁用于商业用途&#xff0c;请于24小时内删除&#xff01;&#xff01;&#xff09…

使用标注工具并跑通官方yolov8分割segment自己的数据集

1.下载标注工具用于打标签 使用标注工具&#xff0c;后面会用到智能标注 点击 创建AI多边形后命令行就自动下载对应的模型 单机要选中的图像就行&#xff0c;就可以智能选中&#xff0c;双击设置标签 依次标注所有图片 &#xff0c;最后保存成json格式的文件 2.使用labelme2y…

Nuxt.js 应用中的 modules:before 事件钩子详解

title: Nuxt.js 应用中的 modules:before 事件钩子详解 date: 2024/10/15 updated: 2024/10/15 author: cmdragon excerpt: modules:before 是 Nuxt.js 中一个重要的生命周期钩子,在 Nuxt 应用初始化期间被触发。该钩子允许开发者在安装用户定义的模块之前执行某些操作,如…