kubernets(二)
集群操作
查看集群信息
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 # 查看所有名称空间所有的podkubectl get pods -A # -A是--all-namespaces的简写
查看service的信息:
[root@k1 ~]# 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@k1 ~]# kubectl get service -n kube-system
-n:namespace名称空间
查看所有名称空间内的资源:
[root@k1 ~]# kubectl get pods --all-namespaces
同时查看多种资源信息:
[root@k1 ~]# kubectl get pod,svc -n kube-system
查看集群的概览信息:
[root@k1 ~]# 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@k1 ~]# kubectl api-versions
1.查看集群信息:
[root@k1 ~]# 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@k1 ~]# kubectl delete node kub-k8s-node1
3.查看某一个节点(节点名称可以用空格隔开写多个)
[root@k1 ~]# 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.控制资源配额和访问权限,以确保应用程序之间的安全隔离。
创建和使用namespace
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-quotanamespace: 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-1namespace: ns-monitor #指定名称空间labels:web: nginx-1
spec:containers:- name: nginx-1image: daocloud.io/library/nginximagePullPolicy: IfNotPresentports:- containerPort: 80resources: #指定资源限制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@k1 prome]# vim pod.yml
---
apiVersion: v1 #api版本,支持pod的版本
kind: Pod #Pod,定义类型注意语法开头大写
metadata: #元数据name: website #这是pod的名字labels:app: website #自定义,但是不能是纯数字
spec: #指定的意思containers: #定义容器- name: test-website #容器的名字,可以自定义imagePullPolicy:IfNotPresentimage: daocloud.io/library/nginx #镜像ports:- containerPort: 80 #容器暴露的端口
创建pod
[root@k1 prome]# kubectl apply -f pod.yml
pod/website created
查看pod
[root@k1 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@k1 prome]# kubectl get pods -o wide

可以测试访问:
[root@kub-k8s-master prome]# curl 10.244.1.3 #访问pod的ip
查看pods定义的详细信息
查看pod的详细信息----指定pod名字(不显示events字段信息)
[root@k1 prome]# kubectl get pod website -o yaml
-o:output
yaml:yaml格式也可以是json格式
查看kubectl describe 支持查询Pod的状态
[root@k1 prome]# kubectl describe pod website
kubectl describe返回字段含义
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
之外的第三个重要字段。有如下几种可能的情况:
pod状态
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语法规则
大小写敏感
使用缩进表示层级关系
缩进时不允许使用Tal键,只允许使用空格
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
”#” 表示注释,从这个字符一直到行尾,都会被解析器忽略
注:- - - 为可选的分隔符 ,当需要在一个文件中定义多个结构的时候需要使用
在 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
YAML Maps
Map指的是字典,即一个Key:Value 的键值对信息。
例如:
---
apiVersion: v1
kind: Pod
注:--- 为可选的分隔符 ,当需要在一个文件中定义多个结构的时候需要使用。上述内容表示有
两个键apiVersion和kind,分别对应的值为v1和Pod。
例如:
---
apiVersion: v1
kind: Pod
metadata:name: kube100-sitelabels: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@k1 ~]# cd prome/
[root@k1 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
这两个属性的功能是一样的都是用于人工干预调度器
第一种方式nodeName
将node1上面的pod删除掉
[root@k1 prome]# kubectl delete -f pod.yml
pod "website" deleted
===========================================
nodeName:是一个供用户将 Pod 与 Node 进行绑定的字段,用法:
现在指定将pod创在node2上面:
[root@k1 prome]# vim pod.yml
---
apiVersion: v1
kind: Pod
metadata:name: websitelabels:app: website
spec:containers:- name: test-websiteimage: daocloud.io/library/nginxports:- containerPort: 80nodeName: kub-k8s-node2 #指定node节点的名称
创建
[root@k1 prome]# kubectl apply -f pod.yml
pod/website created

第二种方式通过node标签
首先我们需要知道node2上面你的标签有哪些?
1.查看node2上面的标签
# 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: tomcatlabels:app: tomcat
spec:containers:- name: test-tomcatimage: daocloud.io/library/tomcat:8ports:- containerPort: 8080nodeSelector: #指定标签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: tomcatlabels:app: tomcat
spec:hostAliases:- ip: "192.168.246.113" #给哪个ip做解析。实验环境下这个ip自定义的hostnames:- "foo.remote" #解析的名字。用引号引起来可以写多个- "bar.remote"containers:- name: test-tomcatimage: daocloud.io/library/tomcat:8ports:- 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: websitelabels:app: website spec:shareProcessNamespace: true #共享进程名称空间containers:- name: test-webimage: daocloud.io/library/nginxports:- containerPort: 80- name: busybosimage: daocloud.io/library/busyboxstdin: truetty: true2.创建 [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: websitelabels:app: website spec:hostNetwork: true #共享宿主机网络hostIPC: true #共享ipc通信hostPID: true #共享宿主机的pidcontainers:- name: test-webimage: daocloud.io/library/nginxports:- containerPort: 80- name: busybosimage: daocloud.io/library/busyboxstdin: truetty: 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-containerimage: daocloud.io/library/nginxlifecycle: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方式:
(1)作为环境变量:可以将Secret中的数据作为环境变量暴露给Pod中的容器。这种方式便于应用程序
直接读取而不必担心文件路径的问题。
(2)作为Volume挂载:Secret也可以作为一个Volume被一个或多个容器挂载。这种方式适用于需要将
Secret作为文件形式访问的情况。
(3)拉取镜像时使用:在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: MWYyZDFlMmU2N2Rmusername: YWRtaW4=
kind: Secret
metadata:creationTimestamp: "2019-10-21T03:07:56Z"name: mysecretnamespace: defaultresourceVersion: "162855"selfLink: /api/v1/namespaces/default/secrets/mysecretuid: 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: mypodlabels:app:webapp spec:containers:- name: testredisimage: daocloud.io/library/redisimagePullPolicy:IfNotPresentvolumeMounts: #挂载一个卷- name: foo #这个名字需要与定义的卷的名字一致mountPath: "/etc/foo" #挂载到容器里哪个目录下,随便写readOnly: truevolumes: #数据卷的定义- 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: MWYyZDFlMmU2N2Rm1.创建 [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: testredisimage: daocloud.io/library/redisenv: #定义环境变量- name: SECRET_USERNAME #创建新的环境变量名称valueFrom:secretKeyRef: #调用的key是什么name: mysecret #变量的值来自于mysecretkey: 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: mysqlimage: daocloud.io/library/mysql:5.7ports:- containerPort: 3306env:- name: MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name: mysql-secretkey: 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@k1 yaml]# cat /root/.docker/config.json
{"auths": {"192.168.116.141": {"auth": "YWRtaW46SGFyYm9yMTIzNDU="}}
}
将密钥文件进行base64的加密
[root@k1 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@k1 ~]# cat harbor-secret.yaml
apiVersion: v1
kind: Secret
metadata:name: harbor-login
type: kubernetes.io/dockerconfigjson
data:.dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjExNi4xNDEiOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0=[root@k1 ~]# kubectl apply -f harbor-secret.yaml
secret/harbor-login created
查看
[root@k1 ~]# 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-1image: 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: webapp2labels:app: webapp2
spec:nodeName: k4containers:- name: webappimage: daocloud.io/library/nginximagePullPolicy: IfNotPresentports:- 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字段要使用空值。
apiVersion: v1
kind: Pod
metadata:name: example-pod
spec:containers:- name: example-containerimage: nginx:latesttolerations:# 使用 Equal 操作符,要求 key、value 和 effect 完全匹配- key: "example-key"operator: "Equal"value: "example-value"effect: "NoSchedule"# 使用 Exists 操作符,只要 key 和 effect 匹配即可- key: "example-key"operator: "Exists"effect: "NoSchedule"# 特殊情况:匹配所有 key、value 和 effect 为 NoSchedule 的污点- key: ""operator: "Exists"effect: "NoSchedule"
ConfigMap配置卷
ConfigMap 主要用于存储非敏感数据,如应用配置文件、环境变量、命令行参数等。它允许你将配置信
息以键值对的形式存储,并可以在 Pod 的环境变量、命令行参数或者配置卷中使用它们。
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-configmapnamespace: defaultresourceVersion: "187590"selfLink: /api/v1/namespaces/default/configmaps/test-configmapuid: 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-config2namespace: defaultresourceVersion: "188765"selfLink: /api/v1/namespaces/default/configmaps/test-config2uid: 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-config4namespace: default
data:cache_host: memcached-gcxtcache_port: "11211"cache_prefix: gcxtmy.cnf: |[mysqld]log-bin = mysql-binuser = mysqlserver-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-mapnamespace: default
data:special.how: veryspecial.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-containerimage: daocloud.io/library/nginxenv: #专门在容器里面设置变量的关键字- name: SPECIAL_LEVEL_KEY #这里的-name,是容器里设置的新变量的名字valueFrom:configMapKeyRef:name: config-map #这里是来源于哪个configMapkey: special.how #configMap里的key- name: SPECIAL_TYPE_KEYvalueFrom:configMapKeyRef:name: config-mapkey: special.typerestartPolicy: Never
创建pod
[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:/# 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-containerimage: daocloud.io/library/nginxenvFrom:- configMapRef:name: config-maprestartPolicy: 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-configmapimage: daocloud.io/library/nginxvolumeMounts:- name: config-volume4mountPath: "/tmp/config4"volumes:- name: config-volume4configMap: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-nginxlabels:app: nginx
spec:containers:- image: daocloud.io/library/nginximagePullPolicy: IfNotPresentname: nginxports:- containerPort: 80lifecycle:postStart:exec:command: ["/bin/bash","-c","mkdir -p /data/www/html"]preStop:exec:command: ["/bin/sh","-c","nginx -s quit"]volumeMounts:- name: nginx-confmountPath: /etc/nginx/conf.dvolumes:- name: nginx-confconfigMap: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@k1 configmap]# vim configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:name: nginx-server-confnamespace: default
data:index.html: |Hello, cloud computingHello, Mr. Wang[root@k1 configmap]# kubectl get configmap
NAME DATA AGE
nginx-server-conf 2 7s
[root@k1 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-appimage: daocloud.io/library/nginxports:- containerPort: 80volumeMounts:- name: nginx-volumemountPath: "/usr/share/nginx/html"volumes:- name: nginx-volumeconfigMap: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
restartPolicy
spec.restartPolicy字段在 Pod 定义中进行设置。Always 表示一直重启,这也是默认的重启策略。Kubelet 会定期查询容器的状态,一旦某个容器处于退出状态,就对其执行重启操作
OnFailure 表示只有在容器异常退出,即退出码不为 0 时,才会对其进行重启操作
Never 表示从不重启
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@k1 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-webappnamespace: defaultresourceVersion: "270687"selfLink: /api/v1/namespaces/default/pods/test-webappuid: ed92d685-f800-464f-95dc-d6aa5f92fc9c
......
实战
使用fieldRef获取 POD 的基本信息,以环境变量的方式实现
[root@k1 prome]# vim test-env-pod.yml
---
apiVersion: v1
kind: Pod
metadata:name: test-env-podnamespace: kube-system
spec:containers:- name: test-env-podimage: daocloud.io/library/nginxenv:- name: POD_NAME #第一个环境变量的名字valueFrom: #使用valueFrom方式设置fieldRef: #关联一个字段metadata.namefieldPath: metadata.name #这个字段从当前运行的pod详细信息查看- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespace- name: POD_IPvalueFrom:fieldRef:fieldPath: status.podIP
注意: POD 的 name 和 namespace 属于元数据,是在 POD 创建之前就已经定下来了的,所以使用metadata 获取就可以了,但是对于 POD 的 IP 则不一样,因为POD IP 是不固定的,POD 重建了
就变了,它属于状态数据,所以使用 status 去获取。
创建上面的 POD:
[root@k1 prome]# kubectl apply -f test-env-pod.yml
pod/test-env-pod created
POD 创建成功后,查看:
[root@k1 prome]# kubectl exec -it test-env-pod -n kube-system -- /bin/bash
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@k1 prome]# vim test-volume-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:name: test-volume-podnamespace: kube-systemlabels:k8s-app: test-volumenode-env: test
spec:containers:- name: test-volume-pod-containerimage: daocloud.io/library/nginxvolumeMounts:- name: podinfomountPath: /etc/podinfovolumes:- name: podinfodownwardAPI:items:- path: "labels"fieldRef:fieldPath: metadata.labels
创建上面的 POD :
[root@k1 prome]# kubectl apply -f test-volume-pod.yaml
[root@k1 prome]# kubectl get pod -n kube-system
[root@k1 prome]# kubectl exec -it test-volume-pod -n kube-system -- /bin/bash
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 ?
(1)定义
ServiceAccount 是 Kubernetes (K8s) 中的一种内置对象,它提供了应用和服务的一个身份,
使得它们可以与API服务器交互或者与其他服务通信。
(2)使用场景
Service Account它并不是给kubernetes集群的用户使用的,而是给pod里面的进程使用的,
它为pod提供必要的身份认证。----专门为pod里面的进程和apiserver通信提供认证的。
默认的ServiceAccount
(3)默认的ServiceAccount
每个命名空间都会自动创建一个名为default的ServiceAccount,这个ServiceAccount会在没有显式
指定其他ServiceAccount的情况下被分配给新创建的Pod。
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
1、创建serviceaccount
[root@k1 ~]# kubectl create serviceaccount mysa
serviceaccount/mysa created
2、查看mysa
[root@k1 ~]# 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@k1 ~]# 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-podlabels:app: my-pod
spec:containers:- name: my-podimage: daocloud.io/library/nginxports:- name: httpcontainerPort: 80serviceAccountName: mysa #指定serviceaccount的名称5、导入
[root@k1 prome]# kubectl apply -f mysa-pod.yaml
pod/nginx-pod created
6、查看
[root@k1 prome]# kubectl describe pod nginx-pod
7、查看使用的token和secret(使用的是mysa的token)
[root@1 prome]# kubectl get pod nginx-pod -o jsonpath={".spec.volumes"}
[map[name:mysa-token-cknwf secret:map[defaultMode:420 secretName:mysa-token-cknwf]]]
RBAC (基于角色的访问控制)
在k8s执行kubectl命令需要与apiserver进行通信,且k8s通过apiserver对外提供服务,需要对访问
apiserver的用户做认证。当认证通过后整个用户只是被apiserver信任的用户,只能访问apiserver,
没有对各种资源操作权限,需要对此用户进行授权。基于角色的访问控制(Role-Based Access Control, RBAC)是一种用于管理用户权限的方法,广泛
应用于企业级系统中。在 Kubernetes 中,RBAC 是一种授权机制,用于控制集群对象上的访问权限。
Kubernetes 自 1.5 版本开始就支持 RBAC,从 1.8 版本开始成为默认启用的授权模式。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+OMITTEDserver: 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: REDACTEDclient-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: Username: sosoapiGroup: rbac.authorization.k8s.io
roleRef: #定义使用哪个角色kind: Rolename: role-readerapiGroup: 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:- podsverbs:- 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.iokind: ClusterRolename: myclusterrole
subjects:
- apiGroup: rbac.authorization.k8s.iokind: Username: 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@k1 ~]# 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-1labels:web: nginx
spec:containers:- name: nginx-1image: daocloud.io/library/nginxports:- name: httpcontainerPort: 80startupProbe: #定义启动探针进行健康检查exec: #指定使用的类型为命令类型command:- "/bin/bash"- "-c"- "cat /usr/share/nginx/html/index.html"initialDelaySeconds: 5 #健康检查,在容器启动5s后开始执行,默认是 0 秒periodSeconds: 5 #执行探测的时间间隔(单位是秒),默认为 10s,最小值是1timeoutSeconds: 2 #表示容器必须在2s内做出相应反馈给probe,否则视为探测失败,默认值为1successThreshold: 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-8labels:web: nginx
spec:containers:- name: nginx-tcpimage: daocloud.io/library/nginxports:- name: httpcontainerPort: 80startupProbe:httpGet: #指定使用的类型为http请求scheme: HTTP #指定请求的协议port: 80 #指定请求的端口path: "/index.html" #指定请求的路径initialDelaySeconds: 5periodSeconds: 5timeoutSeconds: 2successThreshold: 1failureThreshold: 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: livenessname: test-liveness-exec
spec:containers:- name: livenessimage: daocloud.io/library/nginxargs:- /bin/sh- -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 50livenessProbe:exec:command: - cat - /tmp/healthyinitialDelaySeconds: 5periodSeconds: 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 作为一种控制器,主要用于管理一组 Pod 的副本。它通过创建和管理 ReplicaSet 来
间接管理 Pod,而不是直接管理 Pod 本身。这意味着,当你创建一个 Deployment 时,Kubernetes
会在后台为你创建一个或多个 ReplicaSet,这些 ReplicaSet 确保始终有指定数量的 Pod 复本在运行。主要功能
1.声明式更新机制:
定义应用的期望状态,如 Pod 的副本数量、容器镜像版本等。Deployment控制器负责确保实际状态
与期望状态一致。
当用户更新 Deployment的Pod模板时,k8s会逐步替换旧的ReplicaSet并创建新的ReplicaSet。
2.滚动更新:
滚动更新策略,允许逐步替换旧版本的 Pod 实例,实现应用平滑升级。
通过设置spec.strategy定义更新策略,例如 RollingUpdate 或 Recreate。
3.自动回滚:
更新过程中出现问题,可以自动回滚到前一个稳定的版本,也可以手动选择回滚到特定的修订版本。
4.版本历史记录:
Deployment 会保留旧的 ReplicaSet,以便进行回滚。可以查看Deployment的修订版本历史记录。
5.金丝雀发布:
支持更新过程中的控制,如“暂停”或“继续”更新操作。
可以选择在更新过程中暂停,观察新版本的行为,然后再决定是否继续或回滚。
创建Deployment
使用yaml创建Deployment
k8s deployment资源创建流程:
1. 用户通过 kubectl 创建 Deployment。
2. Deployment 创建 ReplicaSet。
3. ReplicaSet 创建 Pod。
对象的命名方式是:子对象的名字 = 父对象名字 + 随机字符串或数字

Deployment是一个定义及管理多副本应用(即多个副本 Pod)的新一代对象,与Replication Controller相比,它提供了更加完善的功能,使用起来更加简单方便。
apiVersion: apps/v1
# 指定使用的 API 版本
kind: Deployment
# 指定这是一个 Deployment 类型的资源
metadata:name: nginx-deployment# 设置 Deployment 的名称labels:app: nginx# 设置标签,用于后续选择和管理
spec:replicas: 3# 设置副本数量,这里设置为 3 个副本selector:matchLabels:app: nginx# 设置选择器,用于匹配由 Deployment 管理的 ReplicaSet 和 Podtemplate:metadata:labels:app: nginx# 设置 Pod 的标签,这使得 Deployment 能够通过选择器找到这些 Podspec:containers:- name: nginx# 设置容器名称image: nginx:1.14.2# 设置容器使用的镜像ports:- containerPort: 80# 设置容器监听的端口livenessProbe:httpGet:path: /port: 80initialDelaySeconds: 15periodSeconds: 20# 设置存活探针,检查容器是否存活readinessProbe:httpGet:path: /port: 80initialDelaySeconds: 5periodSeconds: 10# 设置就绪探针,检查容器是否准备好接收流量
Deployment示例
[root@k1 prome]# vim deployment.yaml
apiVersion: apps/v1 #注意版本号
kind: Deployment
metadata:name: nginx-deployment
spec:selector: #属性,选择器matchLabels:app: nginxreplicas: 2 #管理的副本个数template: #模板属性metadata: #对pod的描述labels:app: nginxspec:volumes: #定义共享卷- name: nginx-volemptyDir: {}containers:- name: nginximage: daocloud.io/library/nginxports:- containerPort: 80volumeMounts: #定义挂载卷- mountPath: "/usr/share/nginx/html"name: nginx-vol
创建Deployment:
将上述的YAML文件保存为deployment.yaml,然后创建Deployment:
[root@k1 prome]# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
检查Deployment的列表:启动之后需要创建时间比较长
通过 kubectl get 命令检查这个 YAML 运行起来的状态:
[root@k1 prome]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 2m22s
[root@k1 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@k1 ~]# kubectl delete deployments nginx-deployment
deployment "nginx-deployment" deleted
或者
[root@k1 ~]# kubectl delete -f deployment.yaml
apiVersion:注意这里apiVersion对应的值是extensions/v1beta1或者apps/v1.这个版本号需要
根据安装的Kubernetes版本和资源类型进行变化,记住不是写死的。此值必须在kubectl apiversion中
[root@k1 prome]# kubectl api-versionsapps/v1beta1authentication.k8s.io/v1beta1authorization.k8s.io/v1beta1autoscaling/v1batch/v1certificates.k8s.io/v1alpha1extensions/v1beta1policy/v1beta1rbac.authorization.k8s.io/v1alpha1storage.k8s.io/v1beta1v1
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 # -l 是 --selector
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) :2template:定义了一个 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-volhostPath: path: /var/data这样,容器 Volume 挂载的宿主机目录,就变成了 /var/data
查看rs
ReplicaSet(简称 RS)是一种工作负载资源,它保证某个版本的 Pod 的稳定副本数(称为副本),即使有 Pod 崩溃或需要更新。ReplicaSet 通常由更高级别的控制器如 Deployment 控制。
[root@k1 ~]# kubectl get rs # 列出所有的 ReplicaSet
NAME DESIRED CURRENT READY AGE
nginx-deployment-59c4b86474 2 2 2 2m49skubectl get rs --selector=app=nginx -n default
创建Service
Kubernetes 中的服务(Service)是一种抽象概念,它定义了 Pod 的逻辑集和访问 Pod 的协议。
Service 使从属 Pod 之间的松耦合成为可能。 和所有 Kubernetes 对象清单一样, Service 用
YAML 或者 JSON 来定义。 Service 下的一组 Pod 通常由一个 标签选择算符 来标记
Service 允许 Pod中唯一的IP地址公开到集群外部以pod中的应用能够接收流量。
设置Service的spec中的type,你可以用不同的方式公开 Service:
暴露服务的五种方式
(1)ClusterIP(默认)
- 在集群的内部 IP 上公开 Service。这种类型使得 Service 只能从集群内访问。此类型会提供一个集群内部的虚拟IP(与Pod不在同一网段),以供集群内部的pod之间通信使用。ClusterIP也是Kubernetes service的默认类型。
能够让其所属Pod能够负载均衡且需要有一个虚拟IP(VIP)提供给IPtables。由于VIP没有挂接到网络设备,所以不能直接访问。

(2)NodePort
外网client--->nodeIP+nodePort--->podIP+PodPort
- 使用 NAT 在集群中每个选定 Node 的相同端口上公开 Service ,为每个节点暴露一个端口,通过nodeip + nodeport可以访问这个服务,同时服务依然会有cluster类型的ip+port。内部通过clusterip方式访问,外部通过nodeport方式访问。是 ClusterIP 的超集。
缺点:(1)每个端口只能是一种服务(2)端口范围只能是 30000-32767(k8s规定)。
使用场景:demo应用或临时应用上使用这种方式。生产环境上不推荐使用

(3)LoadBalancer
- 在当前云中创建一个外部负载均衡器(如果支持的话),并为 Service 分配一个固定的外部IP。是 NodePort 的超集。LoadBalancer在NodePort基础上,K8S可以请求底层云平台创建一个负载均衡器,将每个Node作为后端,进行服务分发。
缺点:每一个用LoadBalancer暴露的服务都需要付费

(4)ExternalName
- 将 Service 映射到 externalName 字段的内容(例如 foo.bar.example.com),通过返回带有该名称的 CNAME 记录实现。不设置任何类型的代理。这种类型需要 kube-dns 的 v1.7 或更高版本,或者 CoreDNS 的 0.8 或更高版本。
使用场景:Kubernetes集群内部,调用外部服务。如DB、没迁移到Kubernetes上的应用。使用ExternalName面向的场景大多是临时调用,建议使用完后,删除或恢复为原配置

(5)Ingress(envoy)
Ingress 并不是 Service 的类型,但可以充当集群的入口点。可以将路由规则整合到一个资源中,并扮演“智能路由”的角色。ngress是一种HTTP方式的路由转发机制,为K8S服务配置HTTP负载均衡器,通常会将服务暴露给K8S群集外的客户端。支持 SSL、认证等功能。需要使用同一个 IP 暴露多个服务。支持 HTTP/HTTPS 协议和服务发现。可以使用不同的 Ingress 控制器,如 Nginx、Traefik、Istio 等。
实验
工作原理:
service对外提供请求,当访问service的时候并将请求转发到集群中的pod中。此过程是通过endpoint
与selector实现的。selector用于选择带有某个标签的pod,然后将该pod的ip和端口添加到endpoint
中。当访问service时就会从endpoint中选择对应的pod的ip和端口,然后将请求转发到对应的pod中。
具体请求如何转发过去需要kube-proxy实现。
三台安装iptables:
[root@k1 prome]# yum install -y iptables iptables-services
1.创建一个depl
[root@k1 prome]# kubectl delete -f deployment.yaml
[root@k1 prome]# vim nginx-depl.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: dep01
spec:selector:matchLabels:app: webreplicas: 2template:metadata:labels:app: webspec:containers:- name: testnginx9image: daocloud.io/library/nginxports:- containerPort: 80
[root@k1 prome]# kubectl apply -f nginx-depl.yml 2. 创建service并且以nodePort的方式暴露端口给外网:
[root@k1 prome]# vim nginx_svc.yaml
apiVersion: v1
kind: Service
metadata:name: mysvc
spec:type: NodePort #类型ports:- port: 8080nodePort: 30001targetPort: 80selector: #选择器app: web
[root@k1 prome]# kubectl apply -f nginx_svc.yaml
3.查看
[root@k1 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@k1 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@k1 prome]# kubectl get ep mysvc
NAME ENDPOINTS AGE
mysvc 10.244.84.130:80,10.244.84.131:80 7m15s
NodePort端口详解
安装iptables(但是需要关闭iptables),创建service之后k8s会自动添加规则到Iptables里面,而且会生效(虽然iptables处于关闭状态)。
服务中的3个端口设置
这几个port的概念很容易混淆,比如创建如下service:
apiVersion: v1
kind: Service
metadata:name: mysvc
spec:type: NodePortports:- port: 8080nodePort: 30001targetPort: 80selector:app: web
port
- service暴露在cluster ip上的端口,cluster ip:port 是给集群内部客户访问
service的入口。
nodePort
- nodePort是kubernetes提供给集群外部客户访问service入口的方式。nodePort端口范围是从30000到32767
targetPort
- pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort
上进入容器。
port、nodePort总结
总的来说,port和nodePort都是service的端口,前者暴露给集群内客户访问服务,后者暴露给集
群外客户访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的
targetPort,从而到达pod上的容器内。
kube-proxy反向代理
kube-proxy支持的三种工作模式
1.userspace 模式
实现简单,但性能较低,适用于早期的测试和开发环境。
可以直接看kube-proxy访问日志/var/log/kube-proxy
(1).kube-proxy 监听 Kubernetes API 服务器中 Service 和 Endpoint 的变化。
(2)当有新的 Service 创建时,kube-proxy 会在节点上打开一个端口,并将这个端口映射到
Service 对应的后端 Pod。
(3).任何对这个端口的访问请求,都会被 kube-proxy 捕捉,并转发到后端的 Pod。kube-proxy 使
用用户空间程序来进行这些转发操作。
2.iptables 模式
(1).kube-proxy 同样监听 Kubernetes API 服务器中 Service 和 Endpoint 的变化。
不同的是,kube-proxy 使用 iptables 来设置网络规则。这些规则会直接在内核空间进行处理,而
不是通过用户空间。
(2).当有新的 Service 创建时,kube-proxy 会生成相应的 iptables 规则,定义从 Service IP
和端口到后端 Pod 的 NAT 转发规则。
(3).数据包在内核空间直接被转发到相应的后端 Pod,减少了上下文切换,提高了转发性能。
性能较好,适用于大多数生产环境,但在处理大量规则时可能复杂。
iptables使用数组遍历方式处理规则,当服务增加到1000+, 效率比用hash表处理规则的ipvs差了。
3.ipvs 模式
流量转发流程和iptables 模式相似
(1).kube-proxy 监听 Kubernetes API 服务器中 Service 和 Endpoint 的变化
(2).kube-proxy 使用 IPVS 来创建和维护负载均衡规则。IPVS 是内核中的一个模块,专门用于负载均衡,支持多种调度算法。
(3).当有新的 Service 创建时,kube-proxy 会使用 IPVS 创建相应的负载均衡规则,定义从
Service IP 和端口到后端 Pod 的转发规则。
(4).数据包在内核空间通过 IPVS 直接转发,性能更高,同时支持更多的负载均衡算法(如轮询、
最小连接数、最短延迟等)。
基于netfilter钩子函数实现类似iptables功能,但使用hash表作为底层数据结构来查找路由规则,
性能最佳,支持更多的负载均衡算法和规则,适用于高性能和大规模集群
需要高版本内核,低版本内核没有ipvs模块,这个时候如果设置ipvs模式,kube-proxy会自动降级到
iptables模式。
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@k1 prome]# ipvsadm -Ln 如果没有规则
[root@k1 ~]# 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@k1 ~]# cd prome/
[root@k1 prome]# vim nginx-rc.yml
---
apiVersion: v1
kind: ReplicationController
metadata:name: my-nginx
spec:replicas: 2template:metadata:labels:app: nginxspec:containers:- name: nginximage: daocloud.io/library/nginxports:- containerPort: 80
如果你在删除rc之前尝试删除pod,rc将会立即启动新的pod来替换被删除的pod
完整TOMCAT实例
Java Web应用
注:Tomcat有可能无法正常启动,原因是虚机的内存和CPU设置过小,请酌情调大!
下载镜像
[root@k1 ~]# docker pull daocloud.io/library/tomcat
构建Tomcat RC定义文件
[root@k1 prome]# vim myweb.rc.yml
---
apiVersion: v1
kind: ReplicationController
metadata:name: myweb
spec:replicas: 2selector:app: mywebtemplate:metadata:labels:app: mywebspec:containers:- name: mywebimage: daocloud.io/library/tomcat:8ports:- containerPort: 8080
#在8080端口上启动容器进程,PodIP与容器端口组成Endpoint,代表着一个服务进程对外通信的地址
发布到Kubernetes集群
创建RC
[root@k1 prome]# kubectl apply -f myweb.rc.yml
replicationcontroller/myweb created
查看RC
[root@k1 prome]# kubectl get rc
NAME DESIRED CURRENT READY AGE
myweb 1 1 1 20s
查看Pod
[root@k1 prome]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myweb-shjfn 1/1 Running 0 52s
构建Tomcat Kubernetes Service定义文件
[root@k1 prome]# vim myweb-svc.yaml
apiVersion: v1
kind: Service
metadata: name: myweb
spec:type: NodePortports:- port: 8081nodePort: 30009targetPort: 8080selector:app: myweb
创建
[root@k1 prome]# kubectl apply -f myweb-svc.yaml
service/myweb created
查看SVC
[root@k1 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@k1 ~]# curl 192.168.246.166:30009
控制器模式解析
k8s项目通过一个称作"控制器模式"(controller pattern)的设计方法,来统一地实现对各种不同
的对象或者资源进行的编排操作。k8s核心就是用一个东西去控制另一个东西,所有的内容都是被控制的。
容器镜像虽然好用,但是容器这样一个"沙盒"的概念,对于描述应用来说太过简单。好比,集装箱固然好用,
如果它四面都光秃秃的,吊车还怎么把这个集装箱吊起来并摆放好呢?
所以,Pod 对象,其实就是容器的升级版。它对容器进行了组合,添加了更多的属性和字段。这就好比
给集装箱四面安装了吊环,使得 Kubernetes 这架"吊车",可以更轻松地操作它。
而 k8s 操作这些"集装箱"的逻辑,都由控制器(Controller)完成
回顾 Deployment 这个最基本的控制器对象。之前讲过一个 nginx-deployment 的例子:
例1:
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deployment
spec:selector:matchLabels:app: nginxreplicas: 2template:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.7.9ports:- containerPort: 80
这个 Deployment 定义的编排动作为:
确保携带了 app=nginx 标签的 Pod 的个数,永远等于 spec.replicas 指定的个数,即 2 个。
如果在这个集群中,携带 app=nginx 标签的 Pod 的个数大于 2 的时候,就会有旧的 Pod 被删除;
反之,就会有新的 Pod 被创建。
究竟是 Kubernetes 项目中的哪个组件,在执行这些操作呢?
kube-controller-manager 组件
这个组件,就是一系列控制器的集合
所有控制器
deployment job podautoscaler
cloud disruption namespace
replicaset serviceaccount volume
cronjob garbagecollector nodelifecycle
replication statefulset daemonset
上面的每一个控制器,都以独有的方式负责某种编排功能。而Deployment,正是这些控制器中的一种。
而被控制对象的定义,则来自于一个"模板"。比如,Deployment 里的 template 字段。所有被这个Deployment 管理的 Pod 实例,都是根据这个 template 字段的内容创建出来的。
对 Deployment 以及其他类似的控制器,做一个总结:

如图,类似 Deployment 的一个控制器,都是由两部分组成:
上半部分的控制器定义(包括期望状态)
下半部分的被控制对象的模板组成的。
也正是在这个统一的编排框架下,不同的控制器可以在具体执行过程中,设计不同的业务逻辑,从而达到不同的编排效果。这个实现思路,正是 k8s 进行容器编排的核心原理。
水平扩展/收缩与滚动更新
水平扩展/收缩
在Kubernetes中,水平扩展的方法通常是通过添加或删除节点来实现的。启动新的Pod时,Kubernetes会自动将应用程序负载均衡到新Pod上,以提高群集的处理能力,从而实现水平扩展。
手动缩放
手动缩放 StatefulSet
kubectl scale statefulset my-app-statefulset --replicas=5
kubectl scale命令扩缩容
kubectl scale deployment <deployment-name> --replicas=<number>
yaml配置扩缩容
[root@k1 prome]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
dep01 2/2 2 2 4h41m
nginx-deployment 2/2 2 2 5h13m
我们将dep01的副本数量变成4个,现在2个
[root@k1 prome]# vim deployment.yaml #修改如下内容
将replicas: 2
修改为:
replicas: 4

创建上节的:nginx-deployment
[root@k1 prome]# kubectl apply -f deployment.yaml --record
deployment.apps/nginx-deployment configured
--record kubectl apply 每次更新应用时 Kubernetes 都会记录下当前的配置,保存为一个
revision(版次),这样就可以回滚到某个特定 revision。
检查nginx-deployment 创建后的状态信息:
[root@k1 prome]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
dep01 4/4 4 4 4h53m
nginx-deployment 2/2 2 2 5h25m
返回结果中四个状态字段含义
DESIRED:
如果有就表示用户期望的 Pod 副本个数(spec.replicas 的值);
CURRENT:
当前处于 Running 状态的 Pod 的个数;
UP-TO-DATE:
当前处于最新版本的 Pod 的个数,所谓最新版本指的是 Pod 的 Spec 部分与 Deployment 里
Pod 模板里定义的完全一致;
AVAILABLE:
当前已经可用的 Pod 的个数,即:既是 Running 状态,又是最新版本,并且已经处于 Ready
(健康检查正确)状态的 Pod 的个数。只有这个字段,描述的才是用户所期望的最终状态。
收缩Deployment
[root@k1 prome]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
dep01 4/4 4 4 4h59m
nginx-deployment 2/2 2 2 5h32m
将dep01的副本将4变为3个
[root@k1 prome]# kubectl edit deployment/dep01
# reopened with the relevant failures.
#
apiVersion: apps/v1
...
spec:progressDeadlineSeconds: 600replicas: 3 #将这里原来的4改为3revisionHistoryLimit: 10selector:matchLabels:
...
保存退出,vim的方式
[root@k1 prome]# kubectl edit deployment/dep01
deployment.apps/dep01 edited
[root@k1 prome]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
dep01 3/3 3 3 5h16m
nginx-deployment 2/2 2 2 5h48m
自动缩放 Deployment
定义了一个自动扩展 Deployment 的 HorizontalPodAutoscaler 对象 my-app-hpa。它指定了要管理的 Deployment 对象的名称 my-app-deployment,以及自动扩展的最小和最大副本数。
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:name: my-app-hpa
spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: my-app-deploymentminReplicas: 3maxReplicas: 10targetCPUUtilizationPercentage: 50
滚动更新
将一个集群中正在运行的多个 Pod 版本,交替地逐一升级的过程,就是"滚动更新"。
命令
# 创建或更新Deployment
kubectl apply -f <deployment-file>.yaml
# 触发滚动更新,例如更新容器镜像
kubectl set image deployment/<deployment-name> <container-name>=<new-image>:<tag>
# 实现在线更新
kubectl edit deployment xxx
# 监控滚动更新的状态
kubectl rollout status deployment/<deployment-name>
# 如果需要回滚到旧版本
kubectl rollout undo deployment/<deployment-name>
2种更新升级策略
1、Recreate 重建更新
这种更新策略会杀掉所有正在运行的pod,再重新创建的pod
在 Deployment 的 YAML 文件中,设置 spec.strategy.type 为 Recreate
apiVersion: apps/v1
kind: Deployment
metadata:name: example-deployment
spec:strategy:type: Recreate
2、rollingUpdate 滚动更新:这种更新策略,deployment会以滚动更新的方式来逐个更新pod,
配置参数 maxUnavailable 和 maxSurge 来控制更新过程中的最大不可用 Pod 副本数和超过期望副
本数的最大数量。
apiVersion: apps/v1
kind: Deployment
metadata:name: example-deployment
spec:strategy:type: RollingUpdaterollingUpdate:maxUnavailable: 1 # 或者 "25%" 表示最大不可用 Pod 的比例maxSurge: 1 # 或者 "25%" 表示超过期望副本数的最大数量
版本升级
创建一个新的deploy
[root@k1 prome]# cp nginx-depl.yml nginx-depl02.yml
[root@k1 prome]# vim nginx-depl02.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: dep02 #注意修改
spec:selector:matchLabels:app: web1replicas: 2template:metadata:name: testnginx9labels:app: web1spec:containers:- name: testnginx9image: daocloud.io/library/nginx:1.14 #注意修改ports:- containerPort: 80strategy:type: RollingUpdaterollingUpdate:maxUnavailable: 1maxSurge: 1
[root@k1 prome]# kubectl apply -f nginx-depl02.yml
deployment.apps/dep02 created
[root@k1 prome]# kubectl get pods
NAME READY STATUS RESTARTS AGE
dep01-58f6d4d4cb-997jw 1/1 Running 0 16m
dep01-58f6d4d4cb-g6vtg 1/1 Running 0 5h32m
dep01-58f6d4d4cb-k6z47 1/1 Running 0 5h32m
dep02-78dbd944fc-47czr 1/1 Running 0 44s
dep02-78dbd944fc-4snsj 1/1 Running 0 25s
将nginx的版本从1.14升级到1.16
[root@k1 prome]# kubectl edit deployment/dep02
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
...
spec:containers:- image: daocloud.io/library/nginx:1.16 #将这里原来的nginx:1.14修改为nginx:1.16imagePullPolicy: Alwaysname: testnginx9ports:- containerPort: 80
...
保存退出,vim的方式
[root@k1 prome]# kubectl edit deployment/dep02
deployment.apps/dep01 edited
这时可以通过查看 Deployment 的 Events,看到这个"滚动更新"的流程:
[root@kub-k8s-master prome]# kubectl describe deployment dep02
...
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal ScalingReplicaSet 50s deployment-controller Scaled up replica set dep02-846bf8775b to 2Normal ScalingReplicaSet 9s deployment-controller Scaled up replica set dep02-58f8d5678 to 1Normal ScalingReplicaSet 8s deployment-controller Scaled down replica set dep02-846bf8775b to 1Normal ScalingReplicaSet 8s deployment-controller Scaled up replica set dep02-58f8d5678 to 2Normal ScalingReplicaSet 5s deployment-controller Scaled down replica set dep02-846bf8775b to 0
如此交替进行,新 ReplicaSet 管理的 Pod 副本数,从0个变成1个,再变成2个,最后变成3个。
而旧的 ReplicaSet 管理的 Pod 副本数则从3个变成2个,再变成1个,最后变成0个。这样就完成了这一组Pod 的版本升级过程。
验证
[root@k1 prome]# kubectl get pods
NAME READY STATUS RESTARTS AGE
dep02-78dbd944fc-69t8x 1/1 Running 0 11h
dep02-78dbd944fc-7cn86 1/1 Running 0 11h
[root@k1 prome]# kubectl exec -it dep02-78dbd944fc-69t8x -- /bin/bash
root@dep02-78dbd944fc-69t8x:/# nginx -v
nginx version: nginx/1.16.1
root@dep02-78dbd944fc-69t8x:/# exit
滚动更新的好处:
在升级刚开始的时候,集群里只有 1 个新版本的 Pod。如果这时,新版本 Pod 有问题启动不起来,
那么"滚动更新"就会停止,从而允许开发和运维人员介入。而在这个过程中,由于应用本身还有两个
旧版本的 Pod 在线,所以服务并不会受到太大的影响。
版本回滚
# 查看发布历史记录
kubectl rollout history deployment <deployment-name>
# 如果需要回滚到上一个版本
kubectl rollout undo deployment <deployment-name>
# 或者回滚到指定版本(例如修订版本3)
kubectl rollout undo deployment <deployment-name> --to-revision=3
# 验证回滚状态
kubectl rollout status deployment <deployment-name>
# 查看详细的回滚信息
kubectl describe deployment <deployment-name># 创建Deployment并记录更改
kubectl create deployment <deployment-name> --image=<image-name> --record
# 更新Deployment并记录更改
kubectl set image deployment <deployment-name> <container>=<new-image>:<tag> --record
查看版本历史
[root@k1 prome]# kubectl rollout history deployment/dep02
deployment.apps/dep02
REVISION CHANGE-CAUSE
1 <none>
2 <none>
回滚到以前的旧版本:
把整个 Deployment 回滚到上一个版本:[root@k1 prome]# kubectl rollout undo deployment/dep02
deployment.apps/dep02 rolled back
查看回滚状态
[root@k1 prome]# kubectl rollout status deployment/dep02
deployment "dep02" successfully rolled out
验证:
[root@k1 prome]# kubectl get pods
NAME READY STATUS RESTARTS AGE
dep02-8594cd6447-pqtxk 1/1 Running 0 55s
dep02-8594cd6447-tt4h4 1/1 Running 0 51s
[root@k1 prome]# kubectl exec -it dep02-8594cd6447-tt4h4 /bin/bash
root@dep02-8594cd6447-tt4h4:/# nginx -v
nginx version: nginx/1.14.2
回滚到更早之前的版本:
-
使用 kubectl rollout history 命令查看每次 Deployment 变更对应的版本。
[root@k1 prome]# kubectl rollout history deployment/dep02
deployment.apps/dep02
REVISION CHANGE-CAUSE
2 <none>
3 <none>
默认配置下,Kubernetes只会保留最近10个revision。
在Deployment配置文件中通过 spec.revisionHistoryLimit属性增加revision数量。如:
spec:revisionHistoryLimit: 15
由于在创建这个 Deployment 的时候,指定了--record 参数,会将创建这些版本时执行的 kubectl 时文件中的配置,都会记录下来。
查看每个版本对应的 Deployment 的 API 对象的细节
[root@k1 prome]# kubectl rollout history deployment/dep02 --revision=3
deployment.apps/dep02 with revision #3
Pod Template:Labels: app=web1pod-template-hash=8594cd6447Containers:testnginx9:Image: daocloud.io/library/nginx:1.14Port: 80/TCPHost Port: 0/TCPEnvironment: <none>Mounts: <none>Volumes: <none>
2.在 kubectl rollout undo 命令行最后,加上要回滚到的指定版本号,就可以回滚到指定版本了。
[root@k1 prome]# kubectl rollout undo deployment/dep02 --to-revision=2
deployment.apps/dep02 rolled back
验证:
[root@k1 prome]# kubectl get pods
NAME READY STATUS RESTARTS AGE
dep02-78dbd944fc-8nvxl 1/1 Running 0 86s
dep02-78dbd944fc-sb9sj 1/1 Running 0 88s
[root@kub-k8s-master prome]# kubectl exec -it dep02-78dbd944fc-8nvxl /bin/bash
root@dep02-78dbd944fc-8nvxl:/# nginx -v
nginx version: nginx/1.16.1
Ingress服务接入控制器
ingress官方:Installation Guide - Ingress-Nginx Controller/
要理解ingress,需要区分两个概念,ingress和ingress-controller: ingress对象: 指的是k8s中的一个api对象,一般用yaml配置。作用是定义请求如何转发到service的规则,可以理解为配置模板。 ingress-controller: 具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发。 简单来说,ingress-controller才是负责具体转发的组件,通过各种方式将它暴露在集群入口,外部对集群的请求流量会先到ingress-controller,而ingress对象是用来告诉ingress-controller该如何转发请求,比如哪些域名哪些path要转发到哪些服务等等。 service 的表现形式为IP:PORT,即工作在第四层传输层(TCP/IP层),对于不同的URL地址经常应用不同的后端服务或者虚拟服务器,这些应用层的转发机制仅通过kubernetes的service机制是无法实现的,这种情况我么可以使用ingress策略定义和一个具体的ingress Controller. Ingress提供七层负载均衡能力,可以通过 Ingress 配置提供外部可访问的 URL、负载均衡、SSL、基于名称的虚拟主机等。作为集群流量接入层,Ingress 的高可靠性显得尤为重要。
ingress工作原理
基于nginx七层反向代理来实现负载均衡,ingress工作原理如下图:

- 外部客户端通过访问负载均衡器,然后调度到service上,然后在调度到IngressController,IngressController通过Ingress规则(域名或虚拟主机)访问到后端pod,而在Ingress规则当中对应的主机是由service分组来设定的,可以看到,上面的service1是用来对外提供服务的,而下面的service2仅仅是用来分pod组的。
- pod处理完请求返回服务是原路返回,不直接返回。
Kubernetes 并没有自带 Ingress Controller,实际上ingress-controller只是一个统称,具体实现有多种,需要自己单独安装,目前,由k8s维护的ingress-controller只有google云的GCE与ingress-nginx两个,常用的是 Ingress-nginx Controller.Ingress 一般由三个组件组成: 1. Nginx 反向代理负载均衡器 2. Ingress Controller 可以理解为控制器,它通过不断的跟 Kubernetes API 交互,实时获取后端 Service、Pod 等的变化,比如新增、删除等,然后结合 Ingress 定义的规则生成配置,然后动态更新上边的 Nginx 负载均衡器,并刷新使配置生效,来达到服务自动发现的作用。 3. Ingress 定义规则,通过定义某个域名的请求过来之后转发到集群中指定的 Service。通过 Yaml 文件定义,给一个或多个 Service 定义一个或多个 Ingress 规则。
如何创建 Ingress 资源
Ingress 中的spec字段是Ingress资源的核心组成部分,主要包含以下3个字段:
- rules:用于定义当前Ingress资源的转发规则列表;由rules定义规则,或没有匹配到规则时,所有的流量会转发到由backend定义的默认后端。
- backend:默认的后端;是Service 和端口名称的组合。定义Ingress资源时,必须要定义backend或rules两者之一,该字段用于让负载均衡器指定一个全局默认的后端。
- tls:TLS配置,目前仅支持通过默认端口443提供服务,如果要配置指定的列表成员指向不同的主机,则需要通过SNI TLS扩展机制来支持该功能。
部署 Ingress 控制器
下载 ingress controller
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml
如果下载不下来,记得本机解析github地址
[root@k1 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.116.138 master
192.168.116.130 node1
192.168.116.131 node2
199.232.28.133 raw.githubusercontent.com
Ingress-Nginx GitHub地址
https://github.com/kubernetes/ingress-nginx


[root@k1 mnt]# wget https://github.com/kubernetes/ingress-nginx/archive/refs/tags/controller-v1.3.0.zip #下载压缩包
[root@k1 mnt]# unzip ingress-nginx-controller-v1.3.0.zip
[root@k1 mnt]# cd ingress-nginx-controller-v1.3.0/deploy/static/provider/cloud/
[root@k1 cloud]# vim deploy.yaml
1、下载配置ingress controller
[root@k1 ~]# cd /mnt/ [root@k1 mnt]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml [root@k1 mnt]# cp deploy.yaml /root/ [root@k1 mnt]# cd [root@k1 ~]# vim deploy.yaml #修改配置文件,并替换成阿里云的镜像 找到以下apiserver的版本: --- apiVersion: apps/v1 kind: DaemonSet #将原来的Deployment修改为DaemonSet metadata:labels:app.kubernetes.io/component: controllerapp.kubernetes.io/instance: ingress-nginxapp.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxapp.kubernetes.io/version: 1.3.0name: ingress-nginx-controllernamespace: ingress-nginx spec:minReadySeconds: 0revisionHistoryLimit: 10selector:matchLabels:app.kubernetes.io/component: controllerapp.kubernetes.io/instance: ingress-nginxapp.kubernetes.io/name: ingress-nginxtemplate:metadata:labels:app.kubernetes.io/component: controllerapp.kubernetes.io/instance: ingress-nginxapp.kubernetes.io/name: ingress-nginxspec:hostNetwork: true #添加共享到主机网络containers:- args:- /nginx-ingress-controller- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller- --election-id=ingress-controller-leader- --controller-class=k8s.io/ingress-nginx- --ingress-class=nginx- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller- --validating-webhook=:8443- --validating-webhook-certificate=/usr/local/certificates/cert- --validating-webhook-key=/usr/local/certificates/keyenv:- name: POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.name- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespace- name: LD_PRELOADvalue: /usr/local/lib/libmimalloc.soimage: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5 #将原来的镜像替换成阿里云仓库的镜像imagePullPolicy: IfNotPresentlifecycle:preStop:exec:command:- /wait-shutdownlivenessProbe:failureThreshold: 5httpGet:path: /healthzport: 10254scheme: HTTPinitialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 1name: controllerports:- containerPort: 80name: httpprotocol: TCP- containerPort: 443name: httpsprotocol: TCP- containerPort: 8443name: webhookprotocol: TCPreadinessProbe:failureThreshold: 3httpGet:path: /healthzport: 10254scheme: HTTPinitialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 1resources:requests:cpu: 100mmemory: 90MisecurityContext:allowPrivilegeEscalation: truecapabilities:add:- NET_BIND_SERVICEdrop:- ALLrunAsUser: 101volumeMounts:- mountPath: /usr/local/certificates/name: webhook-certreadOnly: truednsPolicy: ClusterFirstnodeSelector:custom/ingress-controller-ready: "true" #指定运行ingress的node标签serviceAccountName: ingress-nginxterminationGracePeriodSeconds: 300volumes:- name: webhook-certsecret:secretName: ingress-nginx-admission --- #注意:一共有两个镜像需要替换成阿里云仓库的镜像: [root@k1 ~]# cat deploy.yaml | grep imageimage: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5imagePullPolicy: IfNotPresentimage: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660imagePullPolicy: IfNotPresentimage: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660imagePullPolicy: IfNotPresent
需要修改的地方
kind: DaemonSet:
官方原始文件使用的是deployment,replicate 为 1,这样将会在某一台节点上启动对应的nginx-ingress-controller pod。外部流量访问至该节点,由该节点负载分担至内部的service。测试环境考虑防止单点故障,改为DaemonSet然后删掉replicate ,配合亲和性部署在制定节点上启动nginx-ingress-controller pod,确保有多个节点启动nginx-ingress-controller pod,后续将这些节点加入到外部硬件负载均衡组实现高可用性。
hostNetwork: true:
添加该字段,暴露nginx-ingress-controller pod的服务端口(80)
nodeSelector:
增加亲和性部署,有custom/ingress-controller-ready 标签的节点才会部署该DaemonSet
为需要部署nginx-ingress-controller的节点设置lable
给两个node节点设置label
[root@k1 ~]# kubectl label nodes k8s-node1 custom/ingress-controller-ready=true
[root@k1 ~]# kubectl label nodes k8s-node2 custom/ingress-controller-ready=true
同时在两个node节点下载镜像
[root@k8s-node1 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0
[root@k8s-node1 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1
创建ingress-controller
[root@k8s-master ~]# kubectl apply -f deploy.yaml 查看ingress-controller资源 [root@k8s-master ~]# kubectl get pods -n ingress-nginx NAME READY STATUS RESTARTS AGE nginx-ingress-controller-s8vnl 1/1 Running 0 98m nginx-ingress-controller-ztxz4 1/1 Running 0 97m
测试ingress
创建两个应用和service
[root@k1 ~]# vim my-apache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: my-apache
spec:selector:matchLabels:run: my-apachereplicas: 2template:metadata:labels:run: my-apachespec:containers:- name: my-apacheimage: daocloud.io/library/httpd:2.4ports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: my-apachelabels:run: my-apache
spec:#type: NodePortports:- port: 80targetPort: 80#nodePort: 30002selector:run: my-apache[root@k1 ~]# vim my-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: my-nginx
spec:selector:matchLabels:run: my-nginxreplicas: 2template:metadata:labels:run: my-nginxspec:containers:- name: my-nginximage: daocloud.io/library/nginx:1.7.9ports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: my-nginxlabels:run: my-nginx
spec:#type: NodePortports:- port: 80targetPort: 80#nodePort: 30001selector:run: my-nginx
创建pod和service
[root@k1 ~]# kubectl apply -f my-apache.yaml
[root@k1 ~]# kubectl apply -f my-nginx.yaml
查看资源
[root@k1 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
my-apache-d49c8b95c-8z8l9 1/1 Running 0 125m
my-apache-d49c8b95c-d9q5s 1/1 Running 0 125m
my-nginx-5fdc96f9b4-bmf6s 1/1 Running 0 124m
my-nginx-5fdc96f9b4-qfw8c 1/1 Running 0 124m
[root@k1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 20d
my-apache NodePort 10.99.178.186 <none> 80/TCP 125m
my-nginx NodePort 10.97.171.188 <none> 80/TCP 124m
配置ingress转发文件
[root@k8s-master ~]# cat ingress-test.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata:name: test-ingressnamespace: defaultannotations:nginx.ingress.kubernetes.io/rewrite-target: / spec:ingressClassName: nginx #指定ingress的类型rules: #定义转发规则- host: test.apache.ingress #指定域名方式http:paths:- path: / #指定访问的路径pathType: Prefix #定义路径的类型backend: #定义转发后端的服务service: #定义转发的servicename: my-apacheport:number: 80- host: test.nginx.ingresshttp:paths:- path: /pathType: Prefixbackend:service:name: my-nginxport:number: 80[root@k8s-master ~]# kubectl apply -f ingress-test.yaml [root@k8s-master ~]# kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE test-ingress <none> test.apache.ingress,test.nginx.ingress 80 119m
nginx-ingress-controller运行在node1,node2两个节点上。
如果网络中有dns服务器,在dns中把这两个域名映射到nginx-ingress-controller运行的任意一个节点上,如果没有dns服务器只能修改host文件了。
任意一个节点上操作:(客户端解析)
我这里有两个节点部署了控制器,ip分别为172.16.229.5,172.16.229.6 ,如果有多个,可以随便选。
在wind电脑设置本地解析
172.16.229.5 test.nginx.ingress 172.16.229.6 test.apache.ingress
相关文章:
kubernets(二)
集群操作 查看集群信息 kubectl get查看各组件信息 格式:kubectl get 资源类型 【资源名】 【选项】 events #查看集群中的所有日志信息 -o wide # 显示资源详细信息,包括节点、地址... -o yaml/json #将当前资源对象输出至 yaml/json 格式文…...
《YOLO 标注工具全览》
《YOLO 标注工具全览》 一、YOLO 标注工具的重要性二、常见的 YOLO 标注工具介绍(一)LabelImg(二)Yolo_Label(三)在线标注工具 Make Sense(四)Ybat - YOLO BBox Annotation Tool&…...
财富思维学习
四大象限: 人类财富创造史经历的五个阶段: 1、黄色(土地)财务阶段:拥有土地和劳动力是财富的要求 2、蓝色(海)财富阶段:谁拥有贸易的通道谁就拥有财富(如港口ÿ…...
python爬虫加解密分析及实现
第一种: 1、找到加密的接口地址,通过加密的接口地址全局搜索 2、通过打断点的方式,操作页面,跑到断点处时,即可找到加密串,如图二; 3、找到用的是哪种加密方式,如: cr…...
用Java做智能客服,基于私有知识库
构建Java智能客服系统的整体思路 使用Java构建智能客服系统的整体思路是: 首先将客服QA文档以Word形式导入到系统中,通过向量化处理存入知识库。 当用户提出问题时,系统会根据问题内容从知识库中检索相关的上下文信息,并结合大…...
软考(网工)——网络安全
文章目录 🕐网络安全基础1️⃣网络安全威胁类型2️⃣网络攻击类型 🕑现代加密技术1️⃣私钥密码/对称密码体制2️⃣对称加密算法总结3️⃣公钥密码/非对称密码4️⃣混合密码5️⃣国产加密算法 - SM 系列6️⃣认证7️⃣基于公钥的认证 🕒Hash …...
如何给手机换ip地址
在当今数字化时代,IP地址作为设备在网络中的唯一标识,扮演着举足轻重的角色。然而,有时出于隐私保护、网络访问需求或其他特定原因,我们可能需要更改手机的IP地址。本文将详细介绍几种实用的方法,帮助您轻松实现手机IP…...
kafkamanager安装
一.下载kafkamanager2.0 https://download.csdn.net/download/cyw8998/89892482 二.修改配置文件 解压缩 unzip kafka-manager-2.0.0.0.zip vim application.conf /opt/module/kafka-manager-2.0.0.0/conf/application.conf 添加以下内容:(连接zooke…...
笔记本电脑U口保护分享
在前司时候,经常遇到各种硬件类的问题,但是之前没时间分享,现在来给大家分享一下,常见的问题及如何保护。 1.接口接触不良。这个一般发生于使用时间长了,可以用细砂纸,轻轻摩擦后再进行尝试。 2.接口失灵…...
OpenCV高级图形用户界面(20)更改窗口的标题函数setWindowTitle()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在OpenCV中,cv::setWindowTitle函数用于更改窗口的标题。这使得您可以在程序运行时动态地更改窗口的标题文本。 函数原型 void cv::…...
结构体指针的初始化以及结构体变量作为函数实参传递时易混淆的知识点
结构体指针初始化以及结构体变量作为函数实参传递时易混淆的知识点 首先要明确,结构体类型是用户自己定义的一种数据类型,其本质上与int, char等标准数据类型是一致的 **1.**因此,在进行结构体指针的初始化时,应该这样写&#x…...
Github 2024-10-20 php开源项目日报Top10
根据Github Trendings的统计,今日(2024-10-20统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10Blade项目1Laravel:表达力和优雅的 Web 应用程序框架 创建周期:4631 天开发语言:PHP, BladeStar数量:75969 个Fork数量:24281 次…...
C++ 算法学习——1.3 双向深度优先搜索
双向深度优先搜索(Bidirectional Depth-First Search)是一种图搜索算法,旨在通过从起始节点和目标节点同时开始,沿着深度优先搜索的路径向前探索,以减少搜索空间并提高搜索效率。 1. 基本原理 双向深度优先搜索同时从…...
Artistic Oil Paint 艺术油画着色器插件
只需轻轻一点,即可将您的视频游戏转化为艺术品!(也许更多…)。 ✓ 整个商店中最可配置的选项。 ✓ 六种先进算法。 ✓ 细节增强算法。 ✓ 完整的源代码(脚本和着色器)。 ✓ 包含在“艺术包”中。 …...
记一次left join联表查询的索引失效场景
结论:关联表的列的字符集不一致导致的 场景:user_t(用户表)、org_t(机构表),user_t的org_id和org_t的id是一对一关系 1.explain发现org_t表未走索引,但是org_t的id字段默认存在主键…...
从零到一:前端开发者学习 Cocos Creator 的全攻略
大家好,我是小蜗牛。 作为一名前端开发者,掌握 Cocos Creator 是一个非常有趣且充满潜力的技能。Cocos Creator 是一款免费开源的游戏开发引擎,它的工作流和前端开发非常相似,因此前端开发者可以较快上手,并通过开发小…...
JavaWeb 19 AJAX
目录 一、什么是AJAX 同步交互和异步交互 同步交互 异步交互 Ajax工作原理 Ajax实现方式 原生JavaScript方式进行ajax(了解): "我就是希望你好,就像很多人希望我好一样,特别简单,特别真挚。也不为了什么,就是希望…...
element plus中menu菜单技巧
我在使用element plus的menu(侧边栏)组件的过程中遇到了一些问题,就是menu编写样式和路由跳转,下面给大家分享以下,我是怎么解决的。 1.页面效果 我要实现的网站布局是这样的: 侧边栏折叠以后的效果&#…...
数据结构-贪心算法笔记
前言:贪心无套路,狠狠刷就完事 分发饼干 455. 分发饼干 - 力扣(LeetCode) class Solution {/*** 找出最多有多少个孩子可以得到糖果。** param g 一个数组,表示每个孩子对糖果大小的满意度。* param s 一个数组&…...
基于SpringBoot的在线汽车票预订平台
1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理汽车票网上预订系统的相关信息成为必然。开…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...
