集群操作
查看集群信息
kubectl get查看各组件信息
格式:kubectl get 资源类型 【资源名】 【选项】
events #查看集群中的所有日志信息
-o wide # 显示资源详细信息,包括节点、地址...
-o yaml/json #将当前资源对象输出至 yaml/json 格式文件
--show-labels #查看当前资源对象的标签
-l key=value #基于标签进行筛选查找
-A #查看所有名称空间下的POD
-n 名字空间 #查看该名字下的资源集合
--show-labels #查看某一资源的标签
-all-namespaces #查看所有名字空间下的资源
kubectl get all # 查看所有的资源信息
kubectl get ns # 获取名称空间
kubectl get cs # 获取集群健康状态(组件的状态)
kubectl get pods --all-namespaces # 查看所有名称空间所有的pod
kubectl get pods -A # -A是--all-namespaces的简写
查看service的信息:
[root@kub-k8s-master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 22h
在不同的namespace里面查看service:
[root@kub-k8s-master ~]# kubectl get service -n kube-system
-n:namespace名称空间
查看所有名称空间内的资源:
[root@kub-k8s-master ~]# kubectl get pods --all-namespaces
同时查看多种资源信息:
[root@kub-k8s-master ~]# kubectl get pod,svc -n kube-system
查看apiserver信息:
[root@kub-k8s-master ~]# kubectl cluster-info
Kubernetes master is running at https://192.168.246.166:6443
KubeDNS is running at https://192.168.2466.166:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
api查询:
[root@kub-k8s-master ~]# kubectl api-versions
1.查看集群信息:
[root@kub-k8s-master ~]# kubectl get nodes
# -n default可不写
NAME STATUS ROLES AGE VERSION
kub-k8s-master Ready master 16h v1.16.1
kub-k8s-node1 Ready <none> 15h v1.16.1
kub-k8s-node2 Ready <none> 15h v1.16.1
2.删除节点(无效且显示的也可以删除)
[root@kub-k8s-master ~]# kubectl delete node kub-k8s-node1
3.查看某一个节点(节点名称可以用空格隔开写多个)
[root@kub-k8s-master ~]# kubectl get node kub-k8s-node1
NAME STATUS ROLES AGE VERSION
kub-k8s-node1 Ready <none> 15h v1.16.1
kubectl describe
查看一个 API 对象的细节
注意:Events(事件): 在 Kubernetes 执行的过程中,对 API 对象的所有重要操作,都会被记录在这个对象的 Events 里,并且显示在 kubectl describe 指令返回的结果中。 比如,对于这个 Pod,我们可以看到它被创建之后,被调度器调度(Successfully assigned)到了 node-1,拉取了指定的镜像(pulling image),然后启动了 Pod 里定义的容器(Started container)。 这个部分正是我们将来进行 Debug 的重要依据。如果有异常发生,一定要第一时间查看这些 Events,往往可以看到非常详细的错误信息。
查看node的详细信息
[root@k1 ~]# kubectl describe node kub-k8s-node1 #也可以查看pod的信息
Name: kub-k8s-node1
Roles: <none>
...
-------- -------- ------
cpu 100m (2%) 100m (2%)
memory 50Mi (1%) 50Mi (1%)
ephemeral-storage 0 (0%) 0 (0%)
Events: <none>
#注意:最后被查看的节点名称只能用get nodes里面查到的name!
创建删除更新信息
kubctl create 资源创建
(1)通过文件名创建资源
# kubectl create -f 文件名
选项:
--record #记录命令至滚动信息,便于查看每次 revision 的变化
(2)通过标准输入创建资源
# kubectl create 资源类型 [资源名]
选项:
--help #获取命令帮助
--tcp=集群端口:pod端口 #映射容器内端口至哪个端口
--dry-run #干跑测试
-o yaml/json #将当前资源对象输出至 yaml/json 格式文件中
--image=xxx #指定镜像创建
apply 资源创建/更新
# kubectl apply -f 文件名
选项:
--record #记录命令至滚动信息,便于查看每次 revision 的变化
删除pod
# kubectl delete pod pod名1 pod名2
# kubectl delete pod --all //批量删除
# kubectl delete pod <pod-name> --grace-period=0 --force
--grace-period=0 参数表示立即删除 Pod,而不是等待一段时间。
--force 参数表示强制删除 Pod,即使 Pod 处于未知状态。
举例:
[root@kub-k8s-master prome]# kubectl delete pod website
pod "website" deleted
[root@kub-k8s-master prome]# kubectl delete -f pod.yaml #指定创建pod的yml文件名
重新启动
基于yaml文件的应用(这里并不是重新启动服务)
# kubectl delete -f XXX.yaml #删除
# kubectl apply -f XXX.yaml #创建pod
explain 资源字段描述
#查看对象推荐使用的api以及资源对象的描述
# kubectl explain 字段
例如:
# kubectl explain pod.spec #查看pod类别一级字段帮助文档
# kubectl explain pod.spec.containers #查看pod类别二级字段帮助文档
创建名称空间 namespace
在k8s中namespace可以用来: 1.将不同的应用隔离开来,避免命名冲突和资源的竞争 2.为不同团队和项目提供独立的运行环境,使他们可以独立的管理和部署应用程序。 3.控制资源配额和访问权限,以确保应用程序之间的安全隔离。
1. 编写yaml文件 [root@kub-k8s-master ~]# mkdir namespace [root@kub-k8s-master ~]# cd namespace/ [root@kub-k8s-master namespace]# vim namespace.yml --- apiVersion: v1 #api版本 kind: Namespace #类型---固定的 metadata: #元数据,用来描述所创建资源的基本信息 name: ns-monitor #起个名字 labels: #设置标签 name: ns-monitor 2. 创建资源 [root@kub-k8s-master namespace]# kubectl apply -f namespace.yml namespace/ns-monitor created 3. 查看资源 [root@kub-k8s-master namespace]# kubectl get namespace NAME STATUS AGE default Active 22h kube-node-lease Active 22h kube-public Active 22h kube-system Active 22h ns-monitor Active 34s 4.查看某一个namespace [root@kub-k8s-master namespace]# kubectl get namespace ns-monitor 5.查看某个namespace的详细信息 [root@kub-k8s-master namespace]# kubectl describe namespace ns-monitor 6.制作namespace资源限制 [root@k8s-master ~]# kubectl explain resourcequota.spec #查看命令帮助 [root@k8s-master namespace]# vim create_ns_quota.yml apiVersion: v1 kind: ResourceQuota #定义限制 metadata: name: test-quota namespace: ns-monitor #指定要做限制的namespace spec: hard: #定义资源限制集,https://kubernetes.io/docs/concepts/policy/resource-quotas/ limits.cpu: "2" limits.memory: "2Gi" requests.cpu: "2" requests.memory: "2Gi" limits:定义资源在当前名称空间可以使用的资源是多少。容器可以使用的资源上限 requests:定义资源可以请求(调度)到node节点需要的多少资源,才允许资源调度。容器可以预期获得的最低资源保障 查看: [root@k8s-master namespace]# kubectl get resourcequota -n ns-monitor NAME AGE REQUEST LIMIT test-quota 3h5m requests.cpu: 0/2, requests.memory: 0/2Gi limits.cpu: 0/2, limits.memory: 0/2Gi 使用: [root@k8s-master namespace]# vim create_pod.yml apiVersion: v1 kind: Pod metadata: name: test-pod-1 namespace: ns-monitor #指定名称空间 labels: web: nginx-1 spec: containers: - name: nginx-1 image: daocloud.io/library/nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 resources: #指定资源限制 limits: #定义容器在当前名称空间可以使用的最大资源 cpu: "500m" memory: "1Gi" requests: #定义该pod调度到的节点需要满足的资源 cpu: "100m" memory: "500Mi" 查看使用后: [root@k8s-master namespace]# kubectl get resourcequota -n ns-monitor NAME AGE REQUEST LIMIT test-quota 3h5m requests.cpu: 300m/2, requests.memory: 1000Mi/2Gi limits.cpu: 1/2, limits.memory: 2Gi/2Gi 注意:运行pod的node节点的资源,和容器运行所使用的资源一旦超过定义的,那就无法使用调度pod到对应节点。 7.删除名称空间,先删除namespace对应的pod [root@kub-k8s-master namespace]# kubectl delete -f create_pod.yml [root@kub-k8s-master namespace]# kubectl delete -f namespace.yml namespace "ns-monitor" deleted
发布容器化应用
1.有镜像
2.部署应用--考虑做不做副本。不做副本就是pod,做副本以deployment方式去创建。做了副本访问还需要做一个service,使用访问。
发布第一个容器化应用
扮演一个应用开发者的角色,使用这个 Kubernetes 集群发布第一个容器化应用。
1. 作为一个应用开发者,你首先要做的,是制作容器的镜像。 2. 有了容器镜像之后,需要按照 Kubernetes 项目的规范和要求,将你的镜像组织为它能够"认识"的方式,然后提交上去。
什么才是 Kubernetes 项目能"认识"的方式?
就是使用 Kubernetes 的必备技能:编写配置文件。 这些配置文件可以是 YAML 或者 JSON 格式的。
Kubernetes 跟 Docker 等很多项目最大的不同,就在于它不推荐你使用命令行的方式直接运行容器(虽然 Kubernetes 项目也支持这种方式,比如:kubectl run),而是希望你用 YAML 文件的方式,即:把容器的定义、参数、配置,统统记录在一个 YAML 文件中,然后用这样一句指令把它运行起来:
# kubectl apply -f 我的配置文件
好处:
你会有一个文件能记录下 Kubernetes 到底"run"了什么
编写yaml文件内容如下:
[root@kub-k8s-master prome]# vim pod.yml --- apiVersion: v1 #api版本,支持pod的版本 kind: Pod #Pod,定义类型注意语法开头大写 metadata: #元数据 name: website #这是pod的名字 labels: app: website #自定义,但是不能是纯数字 spec: #指定的意思 containers: #定义容器 - name: test-website #容器的名字,可以自定义 imagePullPolicy:IfNotPresent image: daocloud.io/library/nginx #镜像 ports: - containerPort: 80 #容器暴露的端口
创建pod
[root@kub-k8s-master prome]# kubectl apply -f pod.yml pod/website created
查看pod
[root@kub-k8s-master prome]# kubectl get pods NAME READY STATUS RESTARTS AGE website 1/1 Running 0 74s ============================= 各字段含义: NAME: Pod的名称 READY: Pod的准备状况,右边的数字表示Pod包含的容器总数目,左边的数字表示准备就绪的容器数目。 STATUS: Pod的状态。 RESTARTS: Pod的重启次数 AGE: Pod的运行时间。
pod的准备状况指的是Pod是否准备就绪以接收请求,Pod的准备状况取决于容器,即所有容器都准备就绪了,Pod才准备就绪。 一个pod刚被创建的时候是不会被调度的,因为没有任何节点被选择用来运行这个pod。调度的过程发生在创建完成之后,但是这个过程一般很快,所以你通常看不到pod是处于unscheduler状态的除非创建的过程遇到了问题。 pod被调度之后,分配到指定的节点上运行,这时候,如果该节点没有所需要的image,那么将会自动从默认的Docker Hub上pull指定的image,一切就绪之后,看到pod是处于running状态了
查看pod运行在哪台机器上
[root@kub-k8s-master prome]# kubectl get pods -o wide
可以测试访问: [root@kub-k8s-master prome]# curl 10.244.1.3 #访问pod的ip <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> ...
查看pods定义的详细信息
查看pod的详细信息----指定pod名字(不显示events字段信息) # kubectl get pod website -o wide [root@kub-k8s-master prome]# kubectl get pod website -o yaml -o:output yaml:yaml格式也可以是json格式
查看kubectl describe 支持查询Pod的状态
[root@kub-k8s-master prome]# kubectl describe pod website Name: website Namespace: default Priority: 0 Node: kub-k8s-node1/192.168.246.167 Start Time: Thu, 17 Oct 2019 22:31:16 +0800 Labels: app=website ...
1.各字段含义: Name: Pod的名称 Namespace: Pod的Namespace。 Image(s): Pod使用的镜像 Node: Pod所在的Node。 Start Time: Pod的起始时间 Labels: Pod的Label。 Status: Pod的状态。 Reason: Pod处于当前状态的原因。 Message: Pod处于当前状态的信息。 IP: Pod的PodIP Replication Controllers: Pod对应的Replication Controller。 =============================== 2.Containers:Pod中容器的信息 Container ID: 容器的ID Image: 容器的镜像 Image ID:镜像的ID State: 容器的状态 Ready: 容器的准备状况(true表示准备就绪)。 Restart Count: 容器的重启次数统计 Environment Variables: 容器的环境变量 Conditions: Pod的条件,包含Pod准备状况(true表示准备就绪) Volumes: Pod的数据卷 Events: 与Pod相关的事件列表 =====
生命周期的介绍
整个pod的生命周期 1.在启动任何容器之前,先创建pause基础容器(pid=1),它初始化Pod的环境并为后续加⼊的容器提供共享的名称空间。 2.按配置文件定义的顺序启动初始化容器,只有全部的初始化容器启动完成后才会启动主容器也就是container字段定义的容器。 3.在主容器启动之后可以通过钩子定义容器启动之后做什么,比如执行什么命令, 4.定义探针 (1)startupprobe启动探针用来检测容器是否启动成功,当容器启动成功后就绪探针和存活探针开始对容器进行检测; (2)就绪探针的作用:检测容器是否准备就绪,如果就绪就可以接受来自service的请求,没有就不接受service转发过来的请求; (3)存活探针用来检测容器里面的进程是否健康,如果不健康根据容器的重启策略进行容器的重启。 5.通过钩子定义在容器关闭之前要做什么:比如在容器关闭之前先正常退出nginx进程。
一个Pod 对象在 Kubernetes 中的生命周期: 生命周期:指的是status通过 [root@kub-k8s-master ~]# kubectl get pod #生命周期包括:running、Pending、Failed... Pod 生命周期的变化,主要体现在 Pod API 对象的Status 部分,这是除了 Metadata 和 Spec 之外的第三个重要字段。有如下几种可能的情况: Pending:此状态表示Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中(准备状态)。但这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。 Running:此状态表示Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。 Succeeded:此状态表示 Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。 Failed:此状态表示 Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。比如查看 Pod 的 Events 和日志。 Unknown:这是一个异常状态(未知状态),表示 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题
其他状态
completed: pod里面所有容器正常退出 CrashLoopBackOff: 容器退出,kubelet正在将它重启 InvalidImageName: 无法解析镜像名称 ImageInspectError: 无法校验镜像 ErrImageNeverPull: 策略禁止拉取镜像 ImagePullBackOff: 正在重试拉取 RegistryUnavailable: 连接不到镜像中心 ErrImagePull: 拉取镜像出错 CreateContainerConfigError: 不能创建kubelet使用的容器配置 CreateContainerError: 创建容器失败 m.internalLifecycle.PreStartContainer 执行hook报错 RunContainerError: 启动容器失败 PostStartHookError: 执行hook报错 ContainersNotInitialized: 容器没有初始化完毕 ContainersNotReady: 容器没有准备完毕 ContainerCreating:容器创建中 PodInitializing:pod 初始化中 DockerDaemonNotReady:docker还没有完全启动 NetworkPluginNotReady: 网络插件还没有完全启动
进入Pod对应的容器内部
通过pod名称 [root@kub-k8s-master prome]# kubectl exec -it website /bin/bash root@website:/#
扩展
create与apply的区别: create创建的应用如果需要修改yml文件,必须先指定yml文件删除,在创建新的pod。 如果是apply创建的应用可以直接修改yml文件,继续apply创建,不用先删掉。
Yaml文件语法解析
通常,使用配置文件的方式会比直接使用命令行更可取,因为这些文件可以进行版本控制,而且文件的变化和内容也可以进行审核,当使用及其复杂的配置来提供一个稳健、可靠和易维护的系统时,这些点就显得非常重要。
在声明定义配置文件的时候,所有的配置文件都存储在YAML或者JSON格式的文件中并且遵循k8s的资源配置方式。
kubernetes中用来定义YAML文件创建Pod和创建Deployment等资源。
使用YAML配置文件用于K8s的定义的好处: 便捷性:不必添加大量的参数到命令行中执行命令 可维护性:YAML文件可以通过源头控制,跟踪每次操作 灵活性:YAML可以创建比命令行更加复杂的结构
YAML语法规则: 1. 大小写敏感 2. 使用缩进表示层级关系 3. 缩进时不允许使用Tab键,只允许使用空格 4. 缩进的空格数不重要,只要相同层级的元素左侧对齐即可 5. " 表示注释,从这个字符一直到行尾,都会被解析器忽略
在 k8s 中,只需要知道两种结构类型: 1.Lists 2.Maps
字典 a={key:value, key1:{key2:value2}, key3:{key4:[1,{key5:value5},3,4,5]}}
key: value key1: key2: value2 key3: key4: - 1 - key5: value5 - 3 - 4 - 5 YAML Maps Map指的是字典,即一个Key:Value 的键值对信息。 例如: --- apiVersion: v1 kind: Pod 注:--- 为可选的分隔符 ,当需要在一个文件中定义多个结构的时候需要使用。上述内容表示有两个键apiVersion和kind,分别对应的值为v1和Pod。 例如: --- apiVersion: v1 kind: Pod metadata: name: kube100-site labels: app: web 注:上述的YAML文件中,metadata这个KEY对应的值为一个Maps,而嵌套的labels这个KEY的值又是一个Map。实际使用中可视情况进行多层嵌套。 YAML处理器根据行缩进来知道内容之间的关联。上述例子中,使用两个空格作为缩进,但空格的数据量并不重要,只是至少要求一个空格并且所有缩进保持一致的空格数 。例如,name和labels是相同缩进级别,因此YAML处理器知道他们属于同一map;它知道app是lables的值因为app的缩进更大。 注意:在YAML文件中绝对不要使用tab键
YAML Lists List即列表,就是数组 例如: args: - beijing - shanghai - shenzhen - guangzhou Maps的value既能够对应字符串也能够对应一个Maps。 可以指定任何数量的项在列表中,每个项的定义以连字符(-)开头,并且与父元素之间存在缩进。 在JSON格式中,表示如下: { "args": ["beijing", "shanghai", "shenzhen", "guangzhou"] }
总结
如果key和value同行,:后面要加空格; 所有的一级key顶格写; value如有没有嵌套不换行;value如果有嵌套需要换行; 二级key要缩进,同行元素左对齐; 列表元素每行一个,前面加-,后面带空格; 不能使用tab键;
Pod API属性详解
Pod API 对象
Pod是 k8s 项目中的最小编排单位。容器(Container)就成了 Pod 属性里一个普通的字段。
问题:
通过yaml文件创建pod的时候里面有容器,这个文件里面到底哪些属性属于 Pod 对象,哪些属性属于 Container?
解决:
把 Pod 看成传统环境里的"虚拟机机器"、把容器看作是运行在这个"机器"里的"用户程序",那么很多关于 Pod 对象的设计就非常容易理解了。 凡是调度、网络、存储,以及安全相关的属性,基本上是 Pod 级别的
共同特征是,它们描述的是"机器"这个整体,而不是里面运行的"程序"。
比如: 配置这个"机器"的网卡(即:Pod 的网络定义) 配置这个"机器"的磁盘(即:Pod 的存储定义) 配置这个"机器"的防火墙(即:Pod 的安全定义) 这台"机器"运行在哪个服务器之上(即:Pod 的调度)
kind:指定了这个 API 对象的类型(Type),是一个 Pod,根据实际情况,此处资源类型可以是Deployment、Job、Ingress、Service等。 metadata:包含Pod的一些meta信息,比如名称、namespace、标签等信息. spec:specification of the resource content 指定该资源的内容,包括一些container,storage,volume以及其他Kubernetes需要的参数,以及诸如是否在容器失败时重新启动容器的 属性。可在特定Kubernetes API找到完整的Kubernetes Pod的属性。 ˌ specification----->[spesɪfɪˈkeɪʃn]
容器可选的设置属性包括:
"name"、"image"、"command"、"args"、"workingDir"、"ports"、"env"、resource、"volumeMounts"、livenessProbe、readinessProbe、livecycle、terminationMessagePath、"imagePullPolicy"、securityContext、stdin、stdinOnce、tty
跟"机器"相关的配置
[root@kub-k8s-master ~]# cd prome/ [root@kub-k8s-master prome]# kubectl get pods NAME READY STATUS RESTARTS AGE website 1/1 Running 0 2d23h [root@kub-k8s-master prome]# kubectl get pod -o wide #查看pod运行在哪台机器上面
nodeSelector nodeName 这两个属性的功能是一样的都是用于人工干预调度器
实战
将node1上面的pod删除掉 [root@kub-k8s-master prome]# kubectl delete -f pod.yml pod "website" deleted =========================================== nodeName:是一个供用户将 Pod 与 Node 进行绑定的字段,用法: 现在指定将pod创在node2上面: [root@kub-k8s-master prome]# vim pod.yml --- apiVersion: v1 kind: Pod metadata: name: website labels: app: website spec: containers: - name: test-website image: daocloud.io/library/nginx ports: - containerPort: 80 nodeName: kub-k8s-node2 #指定node节点的名称 创建 [root@kub-k8s-master prome]# kubectl apply -f pod.yml pod/website created
第二种方式通过node标签
首先我们需要知道node2上面你的标签有哪些?
1.查看node2上面的标签 [root@kub-k8s-master prome]# kubectl describe node kub-k8s-node2
1.重新创建一个新的pod "nodeSelector:是一个供用户将 Pod 与 Node 进行绑定的字段",,通过指定标签来指定 [root@kub-k8s-master prome]# vim tomcat.yml --- apiVersion: v1 kind: Pod metadata: name: tomcat labels: app: tomcat spec: containers: - name: test-tomcat image: daocloud.io/library/tomcat:8 ports: - containerPort: 8080 nodeSelector: #指定标签 kubernetes.io/hostname: kub-k8s-node2 2.创建pod [root@kub-k8s-master prome]# kubectl apply -f tomcat.yml pod/tomcat created
表示这个 Pod 永远只能运行在携带了"kubernetes.io/hostname: kub-k8s-node2"标签(Label)的节点上;否则,它将调度失败。
第三个方式主机别名
设置pod容器里面的hosts文件内容,也是做本地解析
HostAliases:定义 Pod 的 hosts 文件(比如 /etc/hosts)里的内容,用法:
注意:在 k8s 中,如果要设置 hosts 文件里的内容,一定要通过这种方法。否则,如果直接修改了 hosts 文件,在 Pod 被删除重建之后,kubelet 会自动覆盖掉被修改的内容。
1.首先先将刚创建的pod删除掉 [root@kub-k8s-master prome]# kubectl delete -f tomcat.yml pod "tomcat" deleted [root@kub-k8s-master prome]# vim tomcat.yml --- apiVersion: v1 kind: Pod metadata: name: tomcat labels: app: tomcat spec: hostAliases: - ip: "192.168.246.113" #给哪个ip做解析。实验环境下这个ip自定义的 hostnames: - "foo.remote" #解析的名字。用引号引起来可以写多个 - "bar.remote" containers: - name: test-tomcat image: daocloud.io/library/tomcat:8 ports: - containerPort: 8080 2.创建pod [root@kub-k8s-master prome]# kubectl apply -f tomcat.yml pod/tomcat created 3.连接pod [root@kub-k8s-master prome]# kubectl exec -it tomcat /bin/bash root@tomcat:/usr/local/tomcat# cat /etc/hosts #查看hosts文件
凡是跟容器的 Linux Namespace 相关的属性,也一定是 Pod 级别的
原因:Pod 的设计,就是要让它里面的容器尽可能多地共享 Linux Namespace,仅保留必要的隔离和限制能力。
举例,一个 Pod 定义 yaml 文件如下:
共享同一个pod里面容器的进程 [root@kub-k8s-master prome]# kubectl delete -f pod.yml pod "website" deleted [root@kub-k8s-master prome]# vim pod.yml #修改如下。最好是提前将镜像pull下来。 --- apiVersion: v1 kind: Pod metadata: name: website labels: app: website spec: shareProcessNamespace: true #共享进程名称空间 containers: - name: test-web image: daocloud.io/library/nginx ports: - containerPort: 80 - name: busybos image: daocloud.io/library/busybox stdin: true tty: true 2.创建 [root@kub-k8s-master prome]# kubectl apply -f pod.yml pod/website created
1. 定义了 shareProcessNamespace=true 表示这个 Pod 里的容器要共享进程(PID Namespace)如果是false则为不共享。 2. 定义了两个容器: 一个 nginx 容器 一个开启了 tty 和 stdin 的 busybos 容器 在 Pod 的 YAML 文件里声明开启它们俩,等同于设置了 docker run 里的 -it(-i 即 stdin,-t 即 tty)参数。此 Pod 被创建后,就可以使用 shell 容器的 tty 跟这个容器进行交互了。
查看运行在那台机器上面:
我们登录node1的机器连接busybox的容器
[root@kub-k8s-node1 ~]# docker exec -it f684bd1d05b5 /bin/sh
在容器里不仅可以看到它本身的 ps 指令,还可以看到 nginx 容器的进程,以及 /pause 进程。也就是说整个 Pod 里的每个容器的进程,对于所有容器来说都是可见的:它们共享了同一个 PID Namespace。
将shareProcessNamespace=true修改为false [root@kub-k8s-master prome]# kubectl delete -f pod.yml [root@kub-k8s-master prome]# vim pod.yml 将shareProcessNamespace=true修改为false [root@kub-k8s-master prome]# kubectl apply -f pod.yml pod/website created
验证:
凡是 Pod 中的容器要共享宿主机的 Namespace,也一定是 Pod 级别的定义。
刚才的都是pod里面容器的Namespace,并没有和本机的Namespace做共享,接下来我们可以做与本机的Namespace共享,可以在容器里面看到本机的进程。 [root@kub-k8s-master prome]# kubectl delete -f pod.yml pod "website" deleted [root@kub-k8s-master prome]# vim pod.yml #修改如下 --- apiVersion: v1 kind: Pod metadata: name: website labels: app: website spec: hostNetwork: true #共享宿主机网络 hostIPC: true #共享ipc通信 hostPID: true #共享宿主机的pid containers: - name: test-web image: daocloud.io/library/nginx ports: - containerPort: 80 - name: busybos image: daocloud.io/library/busybox stdin: true tty: true 创建pod [root@kub-k8s-master prome]# kubectl apply -f pod.yml pod/website created
验证:
定义了共享宿主机的 Network、IPC 和 PID Namespace。这样,此 Pod 里的所有容器,会直接使用宿主机的网络、直接与宿主机进行 IPC 通信、看到宿主机里正在运行的所有进程。
容器属性:
Pod 里最重要的字段"Containers":
"Containers"这个字段属于 Pod 对容器的定义。
k8s 对 Container 的定义,和 Docker 相比并没有什么太大区别。
Docker中Image(镜像)、Command(启动命令)、workingDir(容器的工作目录)、Ports(容器要开发的端口),以及 volumeMounts(容器要挂载的 Volume)都是构成 k8s 中 Container 的主要字段。
其他的容器属性:
ImagePullPolicy 字段:定义镜像的拉取策略。之所以是一个 Container 级别的属性,是因为容器镜像本来就是 Container 定义中的一部分。 默认值: Always:表示每次创建 Pod 都重新拉取一次镜像。 Never:表示Pod永远不会主动拉取这个镜像 IfNotPresent:表示只在宿主机上不存在这个镜像时才拉取。 Lifecycle 字段:定义 Container Lifecycle Hooks。作用是在容器状态发生变化时触发一系列"钩子"。 注: lifecycle /laɪf ˈsaɪkl/ n 生命周期
例子:这是 k8s 官方文档的一个 Pod YAML 文件
在这个例子中,容器成功启动之后,在 /usr/share/message 里写入了一句"欢迎信息"(即 postStart 定义的操作)。而在这个容器被删除之前,我们则先调用了 nginx 的退出指令(即 preStop 定义的操作),从而实现了容器的"优雅退出"。
[root@kub-k8s-master prome]# kubectl delete -f pod.yml pod "website" deleted [root@kub-k8s-master prome]# cp pod.yml pod.yml.bak [root@kub-k8s-master prome]# vim pod.yml --- apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: daocloud.io/library/nginx lifecycle: postStart: #容器启动之后 exec: command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] preStop: #容器关闭之前 exec: command: ["/usr/sbin/nginx","-s","quit"]
验证:
[root@kub-k8s-node1 ~]# docker exec -it 3d404e658 /bin/bash root@lifecycle-demo:~# cat /usr/share/message Hello from the postStart handler
1. 定义了一个 nginx 镜像的容器 2. 设置了一个 postStart 和 preStop 参数 postStart:是在容器启动后,立刻执行一个指定的操作。 注意:postStart 定义的操作,虽然是在 Docker 容器 ENTRYPOINT 执行之后,但它并不严格保证顺序。也就是说,在 postStart 启动时,ENTRYPOINT 有可能还没有结束。 如果 postStart执行超时或者错误,k8s 会在该 Pod 的 Events 中报出该容器启动失败的错误信息,导致 Pod 也处于失败的状态。 preStop:是容器被杀死之前(比如,收到了 SIGKILL 信号)。 注意:preStop 操作的执行,是同步的。 所以,它会阻塞当前的容器杀死流程,直到这个 Hook 定义操作完成之后,才允许容器被杀死,这跟 postStart 不一样。
投射数据卷 Projected Volume
注:Projected Volume 是 Kubernetes v1.11 之后的新特性
卷:配置卷、加密卷、数据卷
什么是Projected Volume?
在 k8s 中,有几种特殊的 Volume,它们的意义不是为了存放容器里的数据,"而是为容器提供预先定义好的数据。" 将容器使用的数据(变量)做成一个卷挂载到容器内部供容器使用。 从容器的角度来看,这些 Volume 里的信息仿佛是被 k8s "投射"(Project)进入容器当中的。
k8s 支持的 Projected Volume 一共有四种方式:
Secret ConfigMap Downward API ServiceAccountToken
Secret详解
secret用来保存小片敏感数据的k8s资源,例如密码,token,或者秘钥。这类数据当然也可以存放在Pod或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,并减少暴露的风险。而不需要把这些敏感数据暴露到镜像或者Pod Spec中。 用户可以创建自己的secret,系统也会有自己的secret。Pod需要先引用才能使用某个secret。 Secret类型type 1.kubernetes.io/service-account-token:用于被 serviceaccount 引用。serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的的/run/secrets/kubernetes.io/serviceaccount 目录中。 2.Opaque:base64编码格式的Secret,用来存储密码、秘钥等。但数据也可以通过base64 –decode解码得到原始数据,所有加密性很弱 3.kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息 4.kubernetes.io/tls:此类型仅用于存储私钥和证书
Pod使用secret方式:
作为环境变量:可以将Secret中的数据作为环境变量暴露给Pod中的容器。这种方式便于应用程序直接读取而不必担心文件路径的问题。 作为Volume挂载:Secret也可以作为一个Volume被一个或多个容器挂载。这种方式适用于需要将Secret作为文件形式访问的情况。 拉取镜像时使用:在Pod的Spec中指定imagePullSecrets字段可以使得Kubelet使用指定的Secret来拉取私有仓库中的镜像。
內建的Secrets:
由ServiceAccount创建的API证书附加的秘钥k8s自动生成的用来访问apiserver的Secret,所有Pod会默认使用这个Secret与apiserver通信
创建自己的Secret:
方式1:使用kubectl create secret命令 方式2:yaml文件创建Secret
实战
yaml方式创建Secret
假如某个Pod要访问数据库,需要用户名密码,现在我们分别设置这个用户名和密码
Secret 对象要求这些数据必须是经过 Base64 转码的,以免出现明文密码显示的安全隐患。
创建一个secret.yaml文件,内容用base64编码:明文显示容易被别人发现,这里先转码。 [root@kub-k8s-master ~]# echo -n 'admin' | base64 YWRtaW4= [root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' | base64 MWYyZDFlMmU2N2Rm -w 0 表示不换行
创建一个secret.yaml文件,内容用base64编码
[root@kub-k8s-master prome]# vim secret.yml --- apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque #模糊 data: username: YWRtaW4= password: MWYyZDFlMmU2N2Rm
创建:
[root@kub-k8s-master prome]# kubectl apply -f secret.yml secret/mysecret created
解析Secret中内容,还是经过编码的---需要解码库被辞退了
查看secret [root@kub-k8s-master ~]# kubectl get secrets # 缩写se NAME TYPE DATA AGE default-token-7vc82 kubernetes.io/service-account-token 3 30h mysecret Opaque 2 6s 查看secret详细信息 [root@kub-k8s-master prome]# kubectl get secret mysecret -o yaml apiVersion: v1 data: password: MWYyZDFlMmU2N2Rm username: YWRtaW4= kind: Secret metadata: creationTimestamp: "2019-10-21T03:07:56Z" name: mysecret namespace: default resourceVersion: "162855" selfLink: /api/v1/namespaces/default/secrets/mysecret uid: 36bcd07d-92eb-4755-ac0a-a5843ed986dd type: Opaque
手动base64解码方式:
[root@kub-k8s-master ~]# echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
使用Secret
secret可以作为数据卷挂载或者作为环境变量暴露给Pod中的容器使用,也可以被系统中的其他资源使用。
一个Pod中引用Secret的列子:
创建一个Secret,多个Pod可以引用同一个Secret 修改Pod的定义,在spec.volumes[]加一个volume,给这个volume起个名字,spec.volumes[].secret.secretName记录的是要引用的Secret名字
[root@kub-k8s-master prome]# vim pod_use_secret.yaml apiVersion: v1 kind: Pod metadata: name: mypod labels: app:webapp spec: containers: - name: testredis image: daocloud.io/library/redis imagePullPolicy:IfNotPresent volumeMounts: #挂载一个卷 - name: foo #这个名字需要与定义的卷的名字一致 mountPath: "/etc/foo" #挂载到容器里哪个目录下,随便写 readOnly: true volumes: #数据卷的定义 - name: foo #卷的名字这个名字自定义 secret: #卷是直接使用的secret。 secretName: mysecret #调用刚才定义的secret 创建: [root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml pod/mypod created [root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash root@mypod:/data# cd /etc/foo/ root@mypod:/etc/foo# ls password username root@mypod:/etc/foo# cat password 1f2d1e2e67df
结果中看到,保存在 Etcd 里的用户名和密码信息,已经以文件的形式出现在了容器的 Volume 目录里。 而这个文件的名字,就是 kubectl create secret 指定的 Key,或者说是 Secret 对象的 data 字段指定的 Key。
每一个被引用的Secret都要在spec.volumes中定义 如果Pod中的多个容器都要引用这个Secret那么每一个容器定义中都要指定自己的volumeMounts,但是Pod定义中声明一次spec.volumes就好了。
被挂载的secret内容自动更新
也就是如果修改一个Secret的内容,那么挂载了该Secret的容器中也将会取到更新后的值,但是这个时间间隔是由kubelet的同步时间决定的。
1.设置base64加密 [root@kub-k8s-master prome]# echo qianfeng | base64 cWlhbmZlbmcK 2.将admin替换成qianfeng [root@kub-k8s-master prome]# vim secret.yml --- apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: cWlhbmZlbmcK #修改为qianfeng的base64加密后的 password: MWYyZDFlMmU2N2Rm 1.创建 [root@kub-k8s-master prome]# kubectl apply -f secret.yml Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply secret/mysecret configured 2.连接pod容器 [root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash root@mypod:/data# cd /etc/foo/my-group root@mypod:/etc/foo/my-group# ls my-username root@mypod:/etc/foo/my-group# cat my-username qianfeng
以环境变量的形式使用Secret
[root@kub-k8s-master prome]# kubectl delete -f pod_use_secret.yaml pod "mypod" deleted [root@kub-k8s-master prome]# vim pod_use_secret.yaml --- apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: testredis image: daocloud.io/library/redis env: #定义环境变量 - name: SECRET_USERNAME #创建新的环境变量名称 valueFrom: secretKeyRef: #调用的key是什么 name: mysecret #变量的值来自于mysecret key: username #username里面的值 2.创建使用secret的pod容器 [root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml pod/mypod created 3.连接 [root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash root@mypod:/data# echo $SECRET_USERNAME #打印一下定义的变量 qianfeng
实战案例:
1.创建数据库用户的密码secret [root@master test]# echo -n 'QianFeng@123!' | base64 UWlhbkZlbmdAMTIzIQ== [root@master test]# cat secret.yml apiVersion: v1 kind: Secret metadata: name: mysql-secret type: Opaque data: password: UWlhbkZlbmdAMTIzIQ== [root@master test]# kubectl apply -f secret.yml 2.创建数据库并使用secret [root@master test]# cat myslq.yaml apiVersion: v1 kind: Pod metadata: name: my-mysql spec: containers: - name: mysql image: daocloud.io/library/mysql:5.7 ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password [root@master test]# kubectl apply -f myslq.yaml [root@master test]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-mysql 1/1 Running 0 2m47s 10.244.2.13 node2 <none> <none> 测试: [root@master test]# mysql -uroot -p'QianFeng@123!' -h 10.244.2.13 -P3306
注意:
如果报错:上面这条命令会报错如下 # kubectl exec -it test-projected-volume /bin/sh error: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy) 解决:绑定一个cluster-admin的权限 # kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous clusterrolebinding.rbac.authorization.k8s.io/system:anonymous created
k8s配置harbor仓库
192.168.116.141 harbor --安装harbor仓库
1.首先在集群中的每个节点上配置登陆harbor仓库的地址
[root@master ~]# cat /etc/docker/daemon.json { "insecure-registries": ["192.168.116.141"] } [root@node1 ~]# cat /etc/docker/daemon.json { "insecure-registries": ["192.168.116.141"] } [root@node2 ~]# cat /etc/docker/daemon.json { "insecure-registries": ["192.168.116.141"] } # systemctl restart docker 测试上传镜像
2.配置k8s集群连接harbor的认证secret
核心思路:拉取私有仓库镜像需要配置私有仓库的登陆信息,用Secret存储,并且定义Deployment或者Pod时,指定imagePullSecret为保存了私有仓库登陆信息的Secret名。
如果使用docker login登陆过私有仓库,那么可以直接使用.docker/config.json文件生成的Secret 查看master上面认证的密钥文件 [root@master yaml]# cat /root/.docker/config.json { "auths": { "192.168.116.141": { "auth": "YWRtaW46SGFyYm9yMTIzNDU=" } } } 将密钥文件进行base64的加密 [root@master yaml]# cat /root/.docker/config.json | base64 -w 0 ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjExNi4xNDEiOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0= 创建k8s连接harbor的secret #注意: Secret的data项目key是.dockerconfigjson; .docker/config.json文件BASE64编码,然后粘贴到data[".dockerconfigjson"]。不要有换行 Secret type必须是kubernetes.io/dockerconfigjson; [root@master yaml]# cat harbor-secret.yaml apiVersion: v1 kind: Secret metadata: name: harbor-login type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjExNi4xNDEiOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0= [root@master yaml]# kubectl apply -f harbor-secret.yaml secret/harbor-login created 查看 [root@master yaml]# kubectl get secret NAME TYPE DATA AGE default-token-zdkzq kubernetes.io/service-account-token 3 10h harbor-login kubernetes.io/dockerconfigjson 1 18s
测试--创建一个nginx的应用
[root@master yaml]# vim nginx-pod.yaml apiVersion: v1 kind: Pod metadata: name: nginx-web spec: containers: - name: nginx-1 image: 192.168.116.141/nginx/nginx:v1.1 #指定镜像仓库地址 imagePullSecrets: #指定使用的harbor仓库的secret - name: harbor-login [root@master yaml]# kubectl apply -f nginx-pod.yaml pod/nginx-web created 查看 [root@master yaml]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-web 1/1 Running 0 2m47s
设置节点亲和性
taint
污点(Taints)和容忍度(Tolerations)的作用是在节点上设置一些排斥条件,使得没有适当容忍度的 Pod 不会被调度到该节点上。但是,当 nodeName
字段被设置时,调度器会忽略这些条件,直接将 Pod 调度到指定节点上。
nodeName 对污点的作用
直接调度:当在 Pod 规约中设置了 nodeName 字段后,Kubernetes 调度器会忽略这个 Pod,而指定节点上的 kubelet 会尝试将 Pod 放到该节点上 4。
强制匹配:使用 nodeName 的调度规则是强制性的,即 Pod 必须且只能调度到指定的节点上。这种方式可以越过 Taints 污点进行调度 1。
优先级:使用 nodeName 来选择节点的优先级高于使用 nodeSelector 或亲和性与反亲和性的规则 19。
apiVersion: v1
kind: Pod
metadata:
name: webapp2
labels:
app: webapp2
spec:
nodeName: k4
containers:
- name: webapp
image: daocloud.io/library/nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
kubectl taint nodes k4 key1=value1:NoSchedule
taints 是键值数据,用在节点上,定义污点; tolerations 是键值数据,用在pod上,定义容忍度,能容忍哪些污点。
taints的 effect 字段
(必填) 用来定义对pod对象的排斥等级
-
NoSchedule:仅影响pod调度过程,仅对未调度的pod有影响。(例如:这个节点的污点改了,使得之前调度的pod不能容忍了,对现存的pod对象不产生影响)
-
NoExecute:既影响调度过程,又影响现存的pod对象(例如:如果现存的pod不能容忍节点后来加的污点,这个pod就会被驱逐)排斥等级最高
-
PreferNoSchedule:最好不,也可以,是NoSchedule的柔性版本。(例如:pod实在没其他节点调度了,也可以到到这个污点等级的节点上)排斥等级最低
污点增删查操作
#设置(增加)污点
kubectl taint node 节点名 键=值:污点类型
kubectl taint node node01 key1=value1:NoSchedule
#节点说明中,查找 Taints 字段
kubectl describe node 节点名
kubectl describe node node01
kubectl describe node node01 | grep Taints
kubectl describe node node01 | grep -A2 -i taint
#去除(删除)污点
kubectl taint node 节点名 键名-
kubectl taint node node01 key1-
kubectl taint node 节点名 键名=值:污点类型-
kubectl taint node node01 key1:NoSchedule-
key2- 这将删除所有键名为key2的污点
-A2 表示显示过滤行及其后两行
-i 表示不区分大小写
容忍度操作符
在Pod上定义容忍度时,它支持两种操作符:Equal和Exists。
-
Equal:容忍度与污点必须在key、value和effect三者完全匹配。
-
Exists:容忍度与污点必须在key和effect二者完全匹配,容忍度中的value字段要使用空值。
ConfigMap配置卷
ConfigMap与 Secret 类似,用来存储配置文件的kubernetes资源对象,所有的配置内容都存储在etcd中。
ConfigMap与 Secret 的区别
ConfigMap 保存的是不需要加密的、应用所需的配置信息。 ConfigMap 的用法几乎与 Secret 完全相同:可以使用 kubectl create configmap 从文件或者目录创建 ConfigMap,也可以直接编写 ConfigMap 对象的 YAML 文件。
创建ConfigMap
创建ConfigMap的方式有4种 命令行方式 方式1:通过直接在命令行中指定configmap参数创建,即--from-literal 方式2:通过指定文件创建,即将一个配置文件创建为一个ConfigMap,--from-file=<文件> 方式3:通过指定目录创建,即将一个目录下的所有配置文件创建为一个ConfigMap,--from-file=<目录> 配置文件方式 方式4:事先写好标准的configmap的yaml文件,然后kubectl create -f 创建
1.1 使用 kubectl create configmap
命令创建
kubectl create configmap my-config --from-literal=key1=value1 --from-literal=key2=value2
通过命令行参数--from-literal创建。创建命令:
kubectl create configmap test-configmap --from-literal=user=admin --from-literal=pass=1122334
结果如下面的data内容所示:
[root@kub-k8s-master prome]# kubectl get configmap test-configmap -o yaml
apiVersion: v1
data:
pass: "1122334"
user: admin
kind: ConfigMap
metadata:
creationTimestamp: "2019-10-21T07:48:15Z"
name: test-configmap
namespace: default
resourceVersion: "187590"
selfLink: /api/v1/namespaces/default/configmaps/test-configmap
uid: 62a8a0d0-fab9-4159-86f4-a06aa213f4b1
1.2 从文件创建
kubectl create configmap my-config --from-file=example.conf
编辑文件server.conf内容如下:
[root@kub-k8s-master prome]# vim server.conf
server {
listen 80;
server_name localhost;
location / {
root /var/www/html;
index index.html index.htm;
}
}
创建(可以有多个--from-file):
kubectl create configmap test-config2 --from-file=server.conf
结果如下面data内容所示:
[root@kub-k8s-master prome]# kubectl get configmap test-config2 -o yaml
apiVersion: v1
data:
server.conf: | #多行字符串开始符号,|前是key是文件名,|后是值是文件内容
server {
listen 80;
server_name localhost;
localtion / {
root /var/www/html;
index index.html index.htm;
}
}
kind: ConfigMap
metadata:
creationTimestamp: "2019-10-21T08:01:43Z"
name: test-config2
namespace: default
resourceVersion: "188765"
selfLink: /api/v1/namespaces/default/configmaps/test-config2
uid: 790fca12-3900-4bf3-a017-5af1070792e5
通过指定文件创建时,configmap会创建一个key/value对,key是文件名,value是文件内容。
1.3 从目录创建
kubectl create configmap my-config --from-file=dir/
configs 目录下的config-1和config-2内容如下所示:
[root@kub-k8s-master prome]# mkdir config
[root@kub-k8s-master prome]# cd config/
[root@kub-k8s-master config]# vim config1
aaa
bbb
c=d
[root@kub-k8s-master config]# vim config2
eee
fff
h=k
创建:
[root@kub-k8s-master config]# cd ..
[root@kub-k8s-master prome]# kubectl create configmap test-config3 --from-file=./config
configmap/test-config3 created
查看data内容:
[root@kub-k8s-master prome]# kubectl get configmap test-config3 -o yaml
指定目录创建时,configmap内容中的各个文件会创建一个key/value对,key是文件名,value是文件内容。
1.4 使用 YAML 文件创建
通过事先写好configmap的标准yaml文件创建
yaml文件内容如下: 注意其中一个key的value有多行内容时要添加竖线|
[root@kub-k8s-master prome]# vim configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config4
namespace: default
data:
cache_host: memcached-gcxt
cache_port: "11211"
cache_prefix: gcxt
my.cnf: |
[mysqld]
log-bin = mysql-bin
user = mysql
server-id = "1"
app.conf:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
port: "80"
user: nginx
创建:
[root@kub-k8s-master prome]# kubectl apply -f configmap.yaml
configmap/test-config4 created
查看结果:
[root@kub-k8s-master prome]# kubectl get configmap test-config4 -o yaml
查看configmap的详细信息:
# kubectl describe configmap
查看ConfigMap
# 查看命名空间中的所有 ConfigMap
kubectl get configmap -n <namespace>
# 查看名为 game-config 的 ConfigMap 的详细信息
kubectl describe configmap game-config -n <namespace>
# 查看 ConfigMap 的 YAML 格式定义
kubectl get configmap <configmap-name> -n <namespace> -o yaml
# 查看 ConfigMap 中特定键的值
kubectl get configmap <configmap-name> -n <namespace> -o jsonpath='{.data.<key-name>}'
# 查看所有命名空间中的 ConfigMap
kubectl get configmap -A
# 查看带有特定标签的 ConfigMap
kubectl get configmap -l <label-key>=<label-value> -n <namespace>
# 使用管道查看 ConfigMap 数据并通过 jq 处理
kubectl get configmap <configmap-name> -n <namespace> -o yaml | jq '.data'
删除ConfigMap
# 删除单个 ConfigMap
kubectl delete configmap <configmap-name> -n <namespace>
# 示例:删除位于 default 命名空间中的名为 game-config 的 ConfigMap
kubectl delete configmap game-config -n default
# 如果当前上下文已经设置为某个命名空间,可以省略 -n 参数
kubectl delete configmap game-config
# 通过标签选择器删除多个 ConfigMap
kubectl delete configmap -l label-key=label-value -n <namespace>
# 示例:删除所有带有 env=production 标签的 ConfigMap
kubectl delete configmap -l env=production -n default
# 通过 YAML 文件删除
kubectl delete -f <path-to-yaml-file>
# 示例:删除文件 configmaps.yaml 中定义的所有 ConfigMap
kubectl delete -f configmaps.yaml
使用ConfigMap
使用ConfigMap的方式,一种是通过环境变量的方式,直接传递pod,另一种是使用volume的方式挂载入到pod内
示例ConfigMap文件:
[root@kub-k8s-master prome]# vim config-map.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: config-map
namespace: default
data:
special.how: very
special.type: charm
创建
[root@kub-k8s-master prome]# kubectl apply -f config-map.yml
configmap/config-map created
2.1 通过变量使用
(1) 使用valueFrom、configMapKeyRef、name、key指定要用的key:
设置指定变量的方式
[root@kub-k8s-master prome]# vim testpod.yml
---
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: daocloud.io/library/nginx
env: #专门在容器里面设置变量的关键字
- name: SPECIAL_LEVEL_KEY #这里的-name,是容器里设置的新变量的名字
valueFrom:
configMapKeyRef:
name: config-map #这里是来源于哪个configMap
key: special.how #configMap里的key
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: config-map
key: special.type
restartPolicy: Never
创建pod
[root@kub-k8s-master prome]# kubectl apply -f testpod.yml
pod/dapi-test-pod created
restartPolicy
spec.restartPolicy字段在 Pod 定义中进行设置。
Always 表示一直重启,这也是默认的重启策略。Kubelet 会定期查询容器的状态,一旦某个容器处于退出状态,就对其执行重启操作
OnFailure 表示只有在容器异常退出,即退出码不为 0 时,才会对其进行重启操作
Never 表示从不重启
测试:
[root@kub-k8s-master prome]# kubectl exec -it dapi-test-pod /bin/bash
root@dapi-test-pod:/# echo $SPECIAL_TYPE_KEY
charm
(2) 通过envFrom、configMapRef、name使得configmap中的所有key/value对儿 都自动变成环境变量:
[root@kub-k8s-master prome]# kubectl delete -f testpod.yml
pod "dapi-test-pod" deleted
[root@kub-k8s-master prome]# cp testpod.yml testpod.yml.bak
[root@kub-k8s-master prome]# vim testpod.yml
---
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: daocloud.io/library/nginx
envFrom:
- configMapRef:
name: config-map
restartPolicy: Never
这样容器里的变量名称直接使用configMap里的key名:
[root@kub-k8s-master prome]# kubectl apply -f testpod.yml
pod/dapi-test-pod created.
[root@kub-k8s-master prome]# kubectl exec -it dapi-test-pod -- /bin/bash
root@dapi-test-pod:/# env
HOSTNAME=dapi-test-pod
NJS_VERSION=0.3.3
NGINX_VERSION=1.17.1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PKG_RELEASE=1~stretch
KUBERNETES_PORT=tcp://10.96.0.1:443
PWD=/
special.how=very
HOME=/root
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
TERM=xterm
SHLVL=1
KUBERNETES_SERVICE_PORT=443
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
special.type=charm
KUBERNETES_SERVICE_HOST=10.96.0.1
_=/usr/bin/env
2.2 作为volume挂载使用
(1) 把1.4中test-config4所有key/value挂载进来:
[root@kub-k8s-master prome]# kubectl delete -f testpod.yml
pod "dapi-test-pod" deleted
[root@kub-k8s-master prome]# vim volupod.yml
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-configmap
spec:
containers:
- name: nginx-configmap
image: daocloud.io/library/nginx
volumeMounts:
- name: config-volume4
mountPath: "/tmp/config4"
volumes:
- name: config-volume4
configMap:
name: test-config4
创建pod
[root@kub-k8s-master prome]# kubectl apply -f volupod.yml
pod/nginx-configmap created
进入容器中/tmp/config4查看:
[root@kub-k8s-master prome]# kubectl exec -it nginx-configmap -- /bin/bash
root@nginx-configmap:/# ls /tmp/config4/
cache_host cache_port cache_prefix my.cnf
root@nginx-configmap:/# cat /tmp/config4/cache_host
memcached-gcxt
root@nginx-configmap:/#
可以看到,在config4文件夹下以每一个key为文件名,value为内容,创建了多个文件。
实战一:创建Nginx配置并挂载
创建了一个包含 Nginx 配置的 ConfigMap,并挂载到容器中的 Nginx 配置目录。
1.定义nginx配置文件,使用configmap制作为卷挂载到nginx容器中
[root@k8s-master map]# cat nginx_configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: ng-map
data:
app.conf: |
server {
listen 80;
server_name localhost;
location / {
root /data/www/html;
index index.html;
}
}
[root@k8s-master map]# kubectl apply -f nginx_configmap.yml
[root@k8s-master map]# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 32d
ng-map 1 18m
[root@k8s-master map]# kubectl describe cm ng-map
Name: ng-map
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
app.conf:
----
server {
listen 80;
server_name localhost;
location / {
root /data/www/html;
index index.html;
}
}
BinaryData
====
Events: <none>
2.将configmap定义成卷挂载到容器里面
[root@k8s-master map]# cat use_nginx_map.yml
apiVersion: v1
kind: Pod
metadata:
name: my-nginx
labels:
app: nginx
spec:
containers:
- image: daocloud.io/library/nginx
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
lifecycle:
postStart:
exec:
command: ["/bin/bash","-c","mkdir -p /data/www/html"]
preStop:
exec:
command: ["/bin/sh","-c","nginx -s quit"]
volumeMounts:
- name: nginx-conf
mountPath: /etc/nginx/conf.d
volumes:
- name: nginx-conf
configMap:
name: ng-map
[root@k8s-master map]# kubectl apply -f use_nginx_map.yml
[root@k8s-master map]# kubectl get pod
NAME READY STATUS RESTARTS AGE
my-nginx 1/1 Running 0 3m17s
[root@k8s-master map]# kubectl exec -it my-nginx /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@my-nginx:/# cd /data/www/
root@my-nginx:/data/www# ls
html
root@my-nginx:/data/www# cd html/
root@my-nginx:/data/www/html# ls
root@my-nginx:/data/www/html# echo 123123 >> index.html
root@my-nginx:/data/www/html# exit
exit
[root@k8s-master map]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-nginx 1/1 Running 0 32s 10.244.247.45 node-2 <none> <none>
[root@k8s-master map]# curl 10.244.247.45
123123
实战二:创建并使用 ConfigMap 配置文件。
创建了一个包含静态网页内容的 ConfigMap,并挂载到容器中的 Nginx 静态文件目录。
创建configmap
[root@kub-k8s-master configmap]# vim configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-server-conf
namespace: default
data:
index.html: |
Hello, cloud computing
Hello, Mr. Wang
[root@kub-k8s-master configmap]# kubectl get configmap
NAME DATA AGE
nginx-server-conf 2 7s
[root@kub-k8s-master configmap]# kubectl get configmap nginx-server-conf -o yaml
使用configmap
[root@kub-k8s-master configmap]# vim pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: test-webapp
spec:
containers:
- name: nginx-app
image: daocloud.io/library/nginx
ports:
- containerPort: 80
volumeMounts:
- name: nginx-volume
mountPath: "/usr/share/nginx/html"
volumes:
- name: nginx-volume
configMap:
name: nginx-server-conf
[root@kub-k8s-master configmap]# kubectl apply -f pod.yaml
[root@kub-k8s-master configmap]# kubectl get pod
NAME READY STATUS RESTARTS AGE
test-webapp 1/1 Running 0 6s
[root@kub-k8s-master configmap]# kubectl exec -it test-webapp -- /bin/bash
root@test-webapp:/# cd /usr/share/nginx/html/
root@test-webapp:/usr/share/nginx/html# ls
index.html
root@test-webapp:/usr/share/nginx/html# cat index.html
Hello, cloud computing
Hello, Mr. Wang
[root@kub-k8s-master configmap]# curl 10.244.2.25
Hello, cloud computing
Hello, Mr. Wang
Downward API
Downward API 用于在容器中获取 POD 的基本信息,kubernetes原生支持 Downward API提供了两种方式用于将 POD 的信息注入到容器内部: 1.环境变量:用于单个变量,可以将 POD 信息直接注入容器内部。 2.Volume挂载:将 POD 信息生成为文件,直接挂载到容器内部中去。
目前 Downward API 支持的字段:
1. 使用 fieldRef 可以声明使用:
spec.nodeName - 宿主机名字
status.hostIP - 宿主机 IP
metadata.name - Pod 的名字
metadata.namespace - Pod 的 Namespace
status.podIP - Pod 的 IP
spec.serviceAccountName - Pod 的 Service Account 的名字
metadata.uid - Pod 的 UID
metadata.labels['<KEY>'] - 指定 <KEY> 的 Label 值
metadata.annotations['<KEY>'] - 指定 <KEY> 的 Annotation 值
metadata.labels - Pod 的所有 Label
metadata.annotations - Pod 的所有 Annotation
上面这个列表的内容,随着 Kubernetes 项目的发展肯定还会不断增加。所以这里列出来的信息仅供参考,在使用 Downward API 时,还是要记得去查阅一下官方文档。 所有基本信息可以使用下面的方式去查看(describe方式看不出来):
[root@kub-k8s-master configmap]# kubectl get pod test-webapp -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"test-webapp","namespace":"default"},"spec":{"containers":[{"image":"daocloud.io/library/nginx","name":"nginx-app","volumeMounts":[{"mountPath":"/usr/share/nginx/html","name":"nginx-volume"}]}],"volumes":[{"configMap":{"name":"nginx-server-conf"},"name":"nginx-volume"}]}}
creationTimestamp: "2021-02-21T09:44:51Z"
name: test-webapp
namespace: default
resourceVersion: "270687"
selfLink: /api/v1/namespaces/default/pods/test-webapp
uid: ed92d685-f800-464f-95dc-d6aa5f92fc9c
......
实战
使用fieldRef获取 POD 的基本信息,以环境变量的方式实现
[root@kub-k8s-master prome]# vim test-env-pod.yml
---
apiVersion: v1
kind: Pod
metadata:
name: test-env-pod
namespace: kube-system
spec:
containers:
- name: test-env-pod
image: daocloud.io/library/nginx
env:
- name: POD_NAME #第一个环境变量的名字
valueFrom: #使用valueFrom方式设置
fieldRef: #关联一个字段metadata.name
fieldPath: metadata.name #这个字段从当前运行的pod详细信息查看
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
注意: POD 的 name 和 namespace 属于元数据,是在 POD 创建之前就已经定下来了的,所以使用 metadata 获取就可以了,但是对于 POD 的 IP 则不一样,因为POD IP 是不固定的,POD 重建了就变了,它属于状态数据,所以使用 status 去获取。
创建上面的 POD:
[root@kub-k8s-master prome]# kubectl apply -f test-env-pod.yml
pod/test-env-pod created
POD 创建成功后,查看:
[root@kub-k8s-master prome]# kubectl exec -it test-env-pod /bin/bash -n kube-system
root@test-env-pod:/# env | grep POD
POD_NAME=test-env-pod
POD_NAMESPACE=kube-system
POD_IP=10.244.1.35
root@test-env-pod:/#
Volume挂载
通过Downward API将 POD 的 Label、等信息通过 Volume 以文件的形式挂载到容器的某个文件中去,然后在容器中打印出该文件的值来验证。
[root@kub-k8s-master prome]# vim test-volume-pod.yaml --- apiVersion: v1 kind: Pod metadata: name: test-volume-pod namespace: kube-system labels: k8s-app: test-volume node-env: test spec: containers: - name: test-volume-pod-container image: daocloud.io/library/nginx volumeMounts: - name: podinfo mountPath: /etc/podinfo volumes: - name: podinfo downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels
创建上面的 POD :
[root@kub-k8s-master prome]# kubectl apply -f test-volume-pod.yaml pod/test-volume-pod created [root@kub-k8s-master prome]# kubectl get pod -n kube-system [root@k8s-master prome]# kubectl exec -it test-volume-pod /bin/bash -n kube-system
Secret、ConfigMap,以及 Downward API 这三种 Projected Volume 定义的信息,大多还可以通过环境变量的方式出现在容器里。但是,通过环境变量获取这些信息的方式,不具备自动更新的能力。一般情况下,建议使用 Volume 文件的方式获取这些信息。
ServiceAccount详解
k8s中提供了良好的多租户认证管理机制,如RBAC、ServiceAccount还有各种Policy等。
官方文档地址:Configure Service Accounts for Pods | Kubernetes/
k8s中账户分为:UserAccounts(用户账户) 和 ServiceAccounts(服务账户) 两种:UserAccount是给kubernetes集群外部用户使用的,使用kubectl访问k8s的时候要用的用户, 而在kubeadm安装的k8s,默认的useraccount用户是kubernetes-admin;
什么是 Service Account ?
Pod里的进程也可以与 apiserver 联系。 当它们在联系 apiserver 的时候,它们就会被认证为一个特定的 Service Account。
使用场景
Service Account它并不是给kubernetes集群的用户使用的,而是给pod里面的进程使用的,它为pod提供必要的身份认证。----专门为pod里面的进程和apiserver通信提供认证的。
Service account与User account区别
1. User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API或其他外部服务而设计的 2. User account是跨namespace的,而service account则是仅局限它所在的namespace; 3. 每个namespace都会自动创建一个default service account 4. Token controller检测service account的创建,并为它们创建secret
Service Account应用
Service Account(服务账号)示例
因为平时系统会使用默认service account,我们不需要自己创建,感觉不到service account的存在,本实验是使用自己手动创建的service account
1、创建serviceaccount [root@kub-k8s-master ~]# kubectl create serviceaccount mysa serviceaccount/mysa created 2、查看mysa [root@kub-k8s-master ~]# kubectl describe sa mysa Name: mysa Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: mysa-token-cknwf Tokens: mysa-token-cknwf Events: <none> 3、查看mysa自动创建的secret [root@kub-k8s-master ~]# kubectl get secret NAME TYPE DATA AGE db-user-pass Opaque 2 11h default-token-6svwp kubernetes.io/service-account-token 3 4d23h mysa-token-cknwf kubernetes.io/service-account-token 3 76s mysecret Opaque 2 11h mysecret-01 Opaque 2 6h58m pass Opaque 1 7h6m user Opaque 1 7h7m 4、使用mysa的sa资源配置pod [root@kub-k8s-master ~]# cd prome/ [root@kub-k8s-master prome]# vim mysa-pod.yaml --- apiVersion: v1 kind: Pod metadata: name: nginx-pod labels: app: my-pod spec: containers: - name: my-pod image: daocloud.io/library/nginx ports: - name: http containerPort: 80 serviceAccountName: mysa #指定serviceaccount的名称 5、导入 [root@kub-k8s-master prome]# kubectl apply -f mysa-pod.yaml pod/nginx-pod created 6、查看 [root@kub-k8s-master prome]# kubectl describe pod nginx-pod 7、查看使用的token和secret(使用的是mysa的token) [root@kub-k8s-master prome]# kubectl get pod nginx-pod -o jsonpath={".spec.volumes"} [map[name:mysa-token-cknwf secret:map[defaultMode:420 secretName:mysa-token-cknwf]]] [root@kub-k8s-master prome]#
RBAC (基于角色的访问控制)
在k8s中我们在执行kubectl这个命令的时候需要与apiserver进行通信,而且整个k8s也是通过apiserver对外提供服务,这时候就需要对访问apiserver的这个用户做认证,但是当认证通过后整个用户仅仅是一个被apiserver信任的用户,只能访问apiserver,还没有对各种资源操作的权限,所以这时候就需要对这个用户进行授权。基于角色的访问控制(Role-Based Access Control, RBAC)是一种用于管理用户权限的方法,广泛应用于企业级系统中。在 Kubernetes 中,RBAC 是一种授权机制,用于控制集群对象上的访问权限。Kubernetes 自 1.5 版本开始就支持 RBAC,从 1.8 版本开始成为默认启用的授权模式。
RBAC详解
RBAC 是一种通过给角色赋予相应权限,从而使该角色具有访问相关资源权限的机制。
Kubernetes授权模式(授权策略)
- ABAC (Attribute Based Access Control):基于属性的访问控制。表示使用用户配置的授权
规则对用户请求进行匹配和控制
- RBAC (Role-Based Access Control):基于角色的访问控制。默认使用该规则
- Webhook:一种 HTTP 回调模式,允许使用远程 REST 端点管理授权
- Node:允许节点访问集群。一种特殊用途的授权模式,专门授权由 kubelet 发出的 API 请求
- AlwaysDeny:始终拒绝访问请求。仅用于测试
- AlwaysAllow:始终允许访问请求。如果有集群不需要授权流程,则可以采用该策略
RBAC API类型
RBAC API 所声明的四种顶级类型【Role、ClusterRole、RoleBinding 和 ClusterRoleBinding】。用户可以像与其他 API 资源交互一样,(通过 kubectl API 调用等方式)与这些资源交互。
Kubernetes 支持两种类型的用户:
- User:为人设计的用户账户如个人使用的账号。跨Namespace的。手动认证,使用 kubeconfig
文件。用于人类操作、外部监控。
- ServiceAccount:为Pod设计的账号,主要用于Pod内的应用程序与Kubernetes API服务器进
行通信。仅限于其所在命名空间内的操作。自动挂载认证Token至Pod。适用于服务间通信、自动化流程
RBAC 授权步骤:
1. 定义角色:在定义角色时指定此角色对于资源的访问控制规则。
2. 绑定角色:将主体与角色进行绑定,对用户进行访问授权。
RBAC 资源分为两个级别:
- 命名空间级别:`Role` 和 `RoleBinding`,这些资源仅在一个特定的命名空间内生效。
- 集群级别:`ClusterRole` 和 `ClusterRoleBinding`,这些资源在整个集群范围内生效。
Role 和 ClusterRole:
- Role:普通角色,仅用于授予对某一单一命名空间中资源的访问权限。
- ClusterRole:集群角色,适用于整个 Kubernetes 集群范围内的资源访问权限。
Role 和 ClusterRole 的规则:
- 允许的操作:如 `get`, `list`, `update`, `create`, `delete` 等权限。
- 允许操作的对象:如 `pod`, `svc`(服务)等资源。
RoleBinding 和 ClusterRoleBinding:
- RoleBinding:将用户绑定到 Role 上。
- ClusterRoleBinding:将用户绑定到 ClusterRole 上。如果使用 `ClusterRoleBinding`
绑定到 `ClusterRole` 上,表示绑定的用户拥有所有命名空间的权限。
kubectl config上下文操作
检查现有的上下文
kubectl config get-contexts
删除现有的上下文
kubectl config delete-context <context-name>
创建新的集群和上下文
# 创建集群配置
kubectl config set-cluster kubernets \
--certificate-authority=/path/to/ca.pem \
--server=https://api.kubernets.example.com
# 创建用户配置
kubectl config set-credentials kubernets-admin \
--client-certificate=/path/to/admin.pem \
--client-key=/path/to/admin-key.pem
# 创建上下文
kubectl config set-context kubernets-admin@kubernets \
--cluster=kubernets \
--user=kubernets-admin
# 设置当前上下文
kubectl config use-context kubernets-admin@kubernets
修改现有的上下文
# 假设已有上下文名为 existing-context
kubectl config rename-context existing-context kubernets-admin@kubernets
测试连接
kubectl cluster-info
rolebinding和clusterrolebinding操作命令
# 创建 RoleBinding
# 通过 YAML 文件创建 RoleBinding
kubectl apply -f path/to/rolebinding.yaml -n <namespace>
# 创建 ClusterRoleBinding
# 通过 YAML 文件创建 ClusterRoleBinding
kubectl apply -f path/to/clusterrolebinding.yaml
# 查看 RoleBinding
kubectl get rolebindings -n <namespace>
# 查看特定命名空间中的 RoleBinding
kubectl get rolebinding <rolebinding-name> -n <namespace>
# 查看所有命名空间中的 RoleBinding
kubectl get rolebindings --all-namespaces
# 查看 ClusterRoleBinding
kubectl get clusterrolebindings
# 查看特定 ClusterRoleBinding
kubectl get clusterrolebinding <clusterrolebinding-name>
# 显示 RoleBinding 的详细信息
kubectl describe rolebinding <rolebinding-name> -n <namespace>
# 显示 ClusterRoleBinding 的详细信息
kubectl describe clusterrolebinding <clusterrolebinding-name>
# 删除 RoleBinding
kubectl delete rolebinding <rolebinding-name> -n <namespace>
# 删除 ClusterRoleBinding
kubectl delete clusterrolebinding <clusterrolebinding-name>
# 更新 RoleBinding
# 修改 YAML 文件后重新应用
kubectl apply -f path/to/modified-rolebinding.yaml -n <namespace>
# 更新 ClusterRoleBinding
# 修改 YAML 文件后重新应用
kubectl apply -f path/to/modified-clusterrolebinding.yaml
# 查看 RoleBinding 的 YAML 定义
kubectl get rolebinding <rolebinding-name> -n <namespace> -o yaml
# 查看 ClusterRoleBinding 的 YAML 定义
kubectl get clusterrolebinding <clusterrolebinding-name> -o yaml
# 使用 JSONPath 输出 RoleBinding 的特定信息
kubectl get rolebinding <rolebinding-name> -n <namespace> -o 'jsonpath={.spec.subjects}'
# 使用 JSONPath 输出 ClusterRoleBinding 的特定信息
kubectl get clusterrolebinding <clusterrolebinding-name> -o 'jsonpath={.spec.roleRef.name}'
# 检查 RoleBinding 的状态
kubectl get rolebinding <rolebinding-name> -n <namespace> -o 'jsonpath={.status}'
# 检查 ClusterRoleBinding 的状态
kubectl get clusterrolebinding <clusterrolebinding-name> -o 'jsonpath={.status}'
# 使用 kubectl auth can-i 检查权限
kubectl auth can-i '*' '*' -n <namespace>
# 或者对于特定用户和服务账户
kubectl auth can-i '*' '*' --as=<username> -n <namespace>
kubectl auth can-i '*' '*' --as=<serviceaccount>:<namespace>:<name> -n <namespace>
# 修复 RoleBinding
# 如果 RoleBinding 损坏,可以删除后重新创建
kubectl delete rolebinding <rolebinding-name> -n <namespace>
kubectl apply -f path/to/rolebinding.yaml -n <namespace>
# 修复 ClusterRoleBinding
# 如果 ClusterRoleBinding 损坏,可以删除后重新创建
kubectl delete clusterrolebinding <clusterrolebinding-name>
kubectl apply -f path/to/clusterrolebinding.yaml
创建k8s账号与RBAC授权使用
[root@k1 ~]#kubectl config view
显示如下:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://172.16.229.4:6443 #apiserver的地址
name: kubernetes #集群的名字
contexts: #上下文--环境
- context:
cluster: kubernetes #当前环境的名字
user: kubernetes-admin #使用的用户
name: kubernetes-admin@kubernetes #环境的名字
current-context: kubernetes-admin@kubernetes #当前上下文的名字
kind: Config
preferences: {}
users:
- name: kubernetes-admin #默认的管理员用户
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
创建账号
1、创建私钥
给自己创建一个私钥
[root@k1 ~]# (umask 077; openssl genrsa -out soso.key 2048)
查看私钥
# kubectl get config
用此私钥创建一个csr(证书签名请求)文件
[root@k1 ~]# openssl req -new -key soso.key -out soso.csr -subj "/CN=soso"
2、拿着私钥和请求文件生成证书
[root@k1 ~]# openssl x509 -req -in soso.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out soso.crt -days 365
生成账号(如soso用户)
[root@k1 ~]# kubectl config set-credentials soso --client-certificate=soso.crt --client-key=soso.key --embed-certs=true
3、设置上下文环境--指的是创建这个账号的环境在当前名称空间中
[root@k1 ~]# kubectl config set-context soso@kubernetes --cluster=kubernetes --user=soso
查看当前的工作上下文
[root@k1 ~]# kubectl config view
4、切换用户(切换上下文)
[root@k1 ~]# kubectl config use-context soso@kubernetes
验证是否已经切换到了新的上下文
[root@k1 ~]# kubectl config current-context
5、测试(还未赋予权限)
[root@k1 ~]# kubectl get pod
Error from server (Forbidden): pods is forbidden: User "soso" cannot list resource "pods" in API group "" in the namespace "default"
# 检查现有的上下文。带有 * 标记的上下文表示当前使用的上下文
kubectl config get-contexts
查看当前上下文
kubectl config current-context
创建新的集群和上下文
# 创建集群配置
kubectl config set-cluster kubernets \
--certificate-authority=/path/to/ca.pem \
--server=https://api.kubernets.example.com
# 创建用户配置
kubectl config set-credentials kubernets-admin \
--client-certificate=/path/to/admin.pem \
--client-key=/path/to/admin-key.pem
# 创建上下文
kubectl config set-context kubernets-admin@kubernets \
--cluster=kubernets \
--user=kubernets-admin
# 设置当前上下文
kubectl config use-context kubernets-admin@kubernets
修改现有的上下文
# 假设已有上下文名为 existing-context
kubectl config rename-context existing-context kubernets-admin@kubernets
测试连接
kubectl cluster-info
创建一个角色(role)---设置权限
1.切回管理帐号
[root@k1 ~]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
创建角色(命令):
[root@k1 ~]# kubectl create role role-reader --verb=get,list,watch --resource=pod,svc
# role-header:role名称 --verb:允许执行的动作 --resource:指定资源类型
yaml文件方式:
[root@k1 ~]# vim role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-reader
rules: #定义规则
- apiGroups: [""] #表示当前pod使用核心的APIserver组,默认用""表示就可以
resources: ["pods","svcs"]
verbs: ["get", "list", "watch", "create", "update", "delete"] #["*"]表示所有权限
[root@k1 ~]# kubectl apply -f role.yaml --save-config # --save-config可不写
[root@k1 ~]# kubectl get roles # 查看角色命令中role/roles都可以,建议用roles
[root@k1 ~]# kubectl describe role role-reader
2.绑定用户soso(上面创建的用户),绑定用户到role-reader
[root@k1 ~]# kubectl create rolebinding myrole-binding --role=role-reader --user=soso
[root@k1 ~]# vim role-binding.yaml # yaml文件方式:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myrolebind
subjects: #定义主体进行操作,三种Subjects:Service Account、User Account、Groups
- kind: User
name: soso
apiGroup: rbac.authorization.k8s.io
roleRef: #定义使用哪个角色
kind: Role
name: role-reader
apiGroup: rbac.authorization.k8s.io
[root@k1 ~]# kubectl apply -f role-binding.yaml
[root@k8s-master ~]# kubectl get rolebinding
3.切换用户
[root@k1 ~]# kubectl config use-context soso@kubernetes
4.查看权限(只授权了default名称空间pod和svc的get,list,watch权限)
[root@k1 ~]# kubectl get pod
[root@k1 ~]# kubectl get pod -n kube-system #无权访问kube-system
[root@k1 ~]# kubectl delete pod nginx-pod #无权限删除
5.切换用户
[root@k1 ~]# kubectl config use-context kubernetes-admin@kubernetes
绑定用户到集群角色
6.删除soso账号之前绑定的rolebinding
[root@k1 ~]# kubectl delete rolebinding myrolebind
rolebinding.rbac.authorization.k8s.io "myrolebind" deleted
7.创建clusterrole #可以访问全部的namespace
[root@k1 ~]# kubectl create clusterrole myclusterrole --verb=get,list,watch --resource=pod,svc
yaml文件方式:
[root@k1 ~]# vim clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: myclusterrole
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
[root@k1 ~]# kubectl apply -f clusterrole.yaml
[root@k1 ~]# kubectl get clusterrole
8.绑定集群角色到用户soso
[root@k1 ~]# kubectl create clusterrolebinding my-cluster-rolebinding --clusterrole=myclusterrole --user=soso
yaml文件方式:
[root@k1 ~]# vim clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-cluster-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: myclusterrole
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: soso
[root@k1 ~]# kubectl apply -f clusterrolebinding.yaml
[root@k1 ~]# kubectl get clusterrolebinding
9.切换账号
[root@k1 ~]# kubectl config use-context soso@kubernetes
Switched to context "soso@kubernetes".
10.查看权限 查看kube-system空间的pod
[root@kub-k8s-master ~]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5644d7b6d9-sm8hs 1/1 Running 0 5d
coredns-5644d7b6d9-vddll 1/1 Running 0 5d
etcd-kub-k8s-master 1/1 Running 0 5d
...
注意:11.切换为管理员用户
[root@k1 ~]# kubectl config use-context kubernetes-admin@kubernetes
设置上下文和账户切换
设置工作上下文(前提得有用户)
[root@k1 ~]# kubectl config set-context soso@kubernetes --cluster=kubernetes --user=soso
查看当前的工作上下文
[root@k1 ~]# kubectl config view
切换上下文(切换用户)
[root@k1 ~]# kubectl config use-context soso@kubernetes
切换为管理员用户
[root@k1 prome]# kubectl config use-context kubernetes-admin@kubernetes
查看某个资源类型是由哪个apiserver版本提供
[root@k1 ~]# kubectl explain ClusterRole
容器监控检查及恢复机制
Kubernetes 探针(Probes)
Kubernetes 支持三种类型的探针(probes),它们分别用于不同的目的:启动探针(startupProbe)、
就绪探针(readinessProbe)和存活探针(livenessProbe)。
### 1. 启动探针(Startup Probe)
**定义**:
- 启动探针用于指示容器中的应用程序是否已经启动。
- 如果提供了启动探针,则在它成功之前禁用所有其他探针。
- 如果启动探针失败,kubelet 将杀死容器,并根据其重启策略进行重启。
- 如果容器没有提供启动探针,则默认状态为成功(Success)。
**作用**:
- 确保应用程序完全启动并准备好接收流量之前不会启用其他探针。
- 有助于避免在应用程序尚未准备好时进行健康检查。
### 2. 存活探针(Liveness Probe)
**定义**:
- 存活探针用于指示容器是否正在运行。
- 如果存活探针失败,kubelet 会杀死容器,并根据其重启策略重启容器。
- 如果容器不提供存活探针,则默认状态为成功(Success)。
**作用**:
- 确保即使应用程序处于非健康状态(如内存泄漏)也能及时重启。
- 提供自愈能力,使集群能够自动恢复故障容器。
### 3. 就绪探针(Readiness Probe)
**定义**:
- 就绪探针用于指示容器是否准备好接收请求。
- 如果就绪探针失败,端点控制器会将该 Pod 从与之匹配的所有 Service 的端点列表中移除。
- 初始延迟之前的就绪状态默认为失败(Failure)。
- 如果容器不提供就绪探针,则默认状态为成功(Success)。
**作用**:
- 避免新创建的 Pod 在尚未准备好处理请求的情况下被 Service 选中。
- 确保 Pod 在完全准备好之后才能接收流量,提高服务的可靠性。
### 举例说明
**就绪探针(Readiness Probe)**:
- **问题**:新创建的 Pod 可能会被 Service 立即选择,并将请求转发给 Pod。然而,如果
Pod 尚未准备好(如需要加载配置或数据,或需要执行预热程序),此时转发请求可能导致请求失败。
- **解决方案**:为 Pod 添加业务就绪探针(Readiness Probe)。只有当检测到 Pod 已准备好时,
才允许 Service 将请求转发给 Pod。
**存活探针(Liveness Probe)**:
- **问题**:即使应用程序内部出现问题(如内存泄漏),只要容器进程仍在运行,Kubernetes 也
不会重启容器。
- **解决方案**:通过定义 Liveness Probe,Kubernetes 可以基于探针的返回值判断容器的健康
状态,并在必要时重启容器,从而确保应用程序始终处于健康状态。
为什么需要容器探针?
容器探针可以确保您的容器在任何时候都处于可预测的状态。
如果没有容器探针,那么容器对于K8S平台而言,就处于一个黑盒状态。下面是没有使用容器探针
可能出现的一些case:
容器未启动,负载均衡就把流量转发给容器,导致请求大量异常
容器内服务不可用/发生异常,负载均衡把流量转发给容器,导致请求大量异常
容器已经不正常工作(如容器死锁导致的应用程序停止响应),K8S平台本身无法感知,不能即时低重启容器。
探针的定义方式(检测方式)
(1)命令探针(Exec)
Probe执行容器中的命令并检查命令退出的状态码,如果状态码为0则说明已经就绪。
Exec 命令探针字段:
exec:指定要执行的命令。
command:指定要执行的命令及其参数。
initialDelaySeconds:指定容器启动后首次执行探测之前的等待时间。
periodSeconds:指定执行探测的频率。
(2)HTTP 探针(HTTP GET)
往容器的IP:Port发送HTTP GET请求,如果Probe收到2xx或3xx,说明已经就绪。
HTTP 探针字段:
httpGet:指定发送 HTTP 请求的配置。
path:指定请求的路径。
port:指定目标容器的端口号。
httpHeaders:可选字段,指定自定义的 HTTP 请求头。
initialDelaySeconds:指定容器启动后首次执行探测之前的等待时间。
periodSeconds:指定执行探测的频率。
(3)TCP 探针(TCP Socket)
尝试与容器建立TCP连接,如果能建立连接说明已经就绪。
TCP探针字段
tcpSocket:指定要连接的容器端口。
initialDelaySeconds:指定容器启动后首次执行探测之前的等待时间。
periodSeconds:指定执行探测的频率。
探针探测结果有以下值:
1、Success:表示通过检测。
2、Failure:表示未通过检测。
3、Unknown:表示检测没有正常进行。
实战
Exec模式定义启动探针-startupprobe
exec:通过指定命令执行的返回值判断容器是否启动
[root@k1 test]# vim test-start-exec.yml
apiVersion: v1
kind: Pod
metadata:
name: pod-1
labels:
web: nginx
spec:
containers:
- name: nginx-1
image: daocloud.io/library/nginx
ports:
- name: http
containerPort: 80
startupProbe: #定义启动探针进行健康检查
exec: #指定使用的类型为命令类型
command:
- "/bin/bash"
- "-c"
- "cat /usr/share/nginx/html/index.html"
initialDelaySeconds: 5 #健康检查,在容器启动5s后开始执行,默认是 0 秒
periodSeconds: 5 #执行探测的时间间隔(单位是秒),默认为 10s,最小值是1
timeoutSeconds: 2 #表示容器必须在2s内做出相应反馈给probe,否则视为探测失败,默认值为1
successThreshold: 1 #连续探测几次成功才认为探测成功,探测1次成功表示成功,最小值为1。
failureThreshold: 3 #探测失败的重试次数,重试一定次数后将认为失败,默认为3,最小值为1
[root@k1 test]# kubectl get pod -w #-w实时查看
NAME READY STATUS RESTARTS AGE
pod-1 0/1 Pending 0 0s
pod-1 0/1 Pending 0 0s
pod-1 0/1 ContainerCreating 0 0s
pod-1 0/1 ContainerCreating 0 0s
pod-1 0/1 Running 0 1s
pod-1 1/1 Running 0 10s #等待10秒后后检查成功进入ready状态
httpget模式
httpget模式
[root@k8s-master test]# vim test-start-http.yml
apiVersion: v1
kind: Pod
metadata:
name: pod-8
labels:
web: nginx
spec:
containers:
- name: nginx-tcp
image: daocloud.io/library/nginx
ports:
- name: http
containerPort: 80
startupProbe:
httpGet: #指定使用的类型为http请求
scheme: HTTP #指定请求的协议
port: 80 #指定请求的端口
path: "/index.html" #指定请求的路径
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 2
successThreshold: 1
failureThreshold: 3
[root@k8s-master test]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
pod-8 0/1 Pending 0 0s
pod-8 0/1 Pending 0 0s
pod-8 0/1 ContainerCreating 0 0s
pod-8 0/1 ContainerCreating 0 1s
pod-8 0/1 Running 0 2s
pod-8 0/1 Running 0 16s
pod-8 1/1 Running 0 16s
存活探针(livenessProbe)------命令模式探针
Kubernetes 文档中的例子
[root@kub-k8s-master prome]# vim ~/prome/test-liveness-exec.yaml
---
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: test-liveness-exec
spec:
containers:
- name: liveness
image: daocloud.io/library/nginx
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 50
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
它在启动之后做的第一件事是在/tmp目录下创建了一个healthy文件,以此作为自己已经正常运行的标志。而30s过后,它会把这个文件删除掉。与此同时,定义了一个这样的 livenessProbe(健康检查)。它的类型是 exec,它会在容器启动后,在容器里面执行一句我们指定的命令,比如:"cat /tmp/healthy"。这时,如果这个文件存在,这条命令的返回值就是 0,Pod就会认为这个容器不仅已经启动,而且是健康的。这个健康检查,在容器启动5s后开始执行(initialDelaySeconds: 5),每5s执行一次(periodSeconds: 5)。
创建Pod:
[root@kub-k8s-master prome]# kubectl apply -f test-liveness-exec.yaml
pod/test-liveness-exec created
查看 Pod 的状态:
[root@kub-k8s-master prome]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-configmap 1/1 Running 0 16h
nginx-pod 1/1 Running 0 12h
test-liveness-exec 1/1 Running 0 75s
由于已经通过了健康检查,这个 Pod 就进入了 Running 状态。
然后30 s 之后,再查看一下 Pod 的 Events:
[root@kub-k8s-master prome]# kubectl describe pod test-liveness-exec
发现,这个 Pod 在 Events 报告了一个异常:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Unhealthy 54s (x9 over 3m34s) kubelet, kub-k8s-node1 Liveness probe failed: cat: /tmp/healthy: No such file or directory
这个健康检查探查到 /tmp/healthy 已经不存在了,所以它报告容器是不健康的。那么接下来会发生什么呢?
再次查看一下这个 Pod 的状态:
[root@kub-k8s-master prome]# kubectl get pod test-liveness-exec
NAME READY STATUS RESTARTS AGE
test-liveness-exec 1/1 Running 4 5m19s
这时发现,Pod 并没有进入 Failed 状态,而是保持了 Running 状态。这是为什么呢?
RESTARTS 字段从 0 到 1 的变化,就明白原因了:这个异常的容器已经被 Kubernetes 重启了。在
这个过程中,Pod 保持 Running 状态不变。
#注
k8s 中并没有 Docker 的 Stop 语义。所以如果容器被探针检测到有问题,查看状态虽然看到的是
Restart,但实际却是重新创建了容器。
这个功能就是 Kubernetes 里的Pod 恢复机制,也叫 restartPolicy。它是 Pod 的 Spec 部分的一个标准字段(pod.spec.restartPolicy),默认值是 Always,即:任何时候这个容器发生了异常,它一定会被重新创建。
Pod 的恢复过程,永远都是发生在当前节点上,而不会跑到别的节点上去。事实上,一旦
一个 Pod 与一个节点(Node)绑定,除非这个绑定发生了变化(pod.spec.node 字段被修改),
否则它永远都不会离开这个节点。这也就意味着,如果这个宿主机宕机了,这个 Pod 也不会主动迁
移到其他节点上去。
http get方式定义探针
创建该pod
[root@kub-k8s-master prome]# kubectl create -f liveness-httpget.yaml
pod/liveness-httpget-pod created
查看当前pod的状态
[root@kub-k8s-master prome]# kubectl describe pod liveness-httpget-pod
...
Liveness: http-get http://:http/index.html delay=1s timeout=1s period=3s #success=1 #failure=3
...
登陆容器
测试将容器内的index.html删除掉
[root@kub-k8s-master prome]# kubectl exec -it liveness-httpget-pod /bin/bash
root@liveness-httpget-pod:/# mv /usr/share/nginx/html/index.html index.html
root@liveness-httpget-pod:/# command terminated with exit code 137
可以看到,当把index.html移走后,这个容器立马就退出了。
此时,查看pod的信息
[root@k1 prome]# kubectl describe pod liveness-httpget-pod
...
Normal Killing 49s kubelet, kub-k8s-node2 Container liveness-exec-container failed liveness probe, will be restarted
Normal Pulled 49s kubelet, kub-k8s-node2 Container image "daocloud.io/library/nginx" already present on machine
...
看输出,容器由于健康检查未通过,pod会被杀掉,并重新创建
[root@k1 prome]# kubectl get pods
NAME READY STATUS RESTARTS AGE
lifecycle-demo 1/1 Running 1 34h
liveness-httpget-pod 1/1 Running 1 5m42s
#restarts 为 1
重新登陆容器,发现index.html又出现了,证明容器是被重拉了。
[root@k1 prome]# kubectl exec -it liveness-httpget-pod /bin/bash
root@liveness-httpget-pod:/# cat /usr/share/nginx/html/index.html
在生产环境最好是一块使用,尤其是就绪和存活探针共用。
容器的重启策略
Pod 的重启策略:
可以通过设置 restartPolicy,改变 Pod 的恢复策略。一共有3种:
1. Always: 在任何情况下,只要容器不在运行状态,就自动重启容器;
2. OnFailure: 只在容器 异常时才自动重启容器;
3. Never: 从来不重启容器。
实际使用时,需要根据应用运行的特性,合理设置这三种恢复策略。
Deployment副本控制器资源详解
如果Pod出现故障,对应的服务也会挂掉,所以Kubernetes提供了一个Deployment的概念 ,目的
是让Kubernetes去管理一组Pod的副本,也就是副本集,这样就能够保证一定数量的副本一直可用,
不会因为某一个Pod挂掉导致整个服务挂掉。
Deployment是k8s中最常用的资源对象,为ReplicaSet和Pod的创建提供了一种声明式的定义方法,
官方建议使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,是因为Deployment
还负责在 Pod 定义发生变化时,对每个副本进行滚动更新(Rolling Update)。
每创建一个Deployment控制器都会创建一个对应的ReplicaSet,在通过ReplicaSet去创建pod,删除
Deployment,同时也会删除对应的ReplicaSet和pod。
创建Deployment
使用yaml创建Deployment
k8s deployment资源创建流程:
1. 用户通过 kubectl 创建 Deployment。
2. Deployment 创建 ReplicaSet。
3. ReplicaSet 创建 Pod。
对象的命名方式是:子对象的名字 = 父对象名字 + 随机字符串或数字
Deployment是一个定义及管理多副本应用(即多个副本 Pod)的新一代对象,与Replication Controller相比,它提供了更加完善的功能,使用起来更加简单方便。
apiVersion: apps/v1 # 指定api版本,必需。业务场景一般首选“apps/v1”
kind: Deployment # 指定创建资源的角色/类型
metadata: # 资源的元数据/属性
name: demo # 资源的名字,在同一个namespace中必须唯一
namespace: default # 部署在哪个namespace中。不指定时默认为default命名空间
labels: # 自定义资源的标签
app: demo
version: stable
annotations: # 自定义注释列表
name: string
spec: # 资源规范字段,定义deployment资源需要的参数属性
replicas: 2 # 声明副本数目
revisionHistoryLimit: 3 # 保留历史版本
selector: # 标签选择器
matchLabels: # 匹配标签,需与上面的标签定义的app保持一致
app: demo
version: stable
strategy: # 策略
type: RollingUpdate # 滚动更新策略
# ecreate:删除所有已存在的pod,重新创建新的
# RollingUpdate:滚动升级逐步替换的策略,同时滚动升级时支持更多的附加参数,
# 例如设置最大不可用pod数量,最小升级间隔时间等等
rollingUpdate: # 滚动更新
maxSurge: 1 # 滚动升级时最大额外可以存在的副本数,可以为百分比或整数
maxUnavailable: 0 # 更新过程不可用状态Pod最大值,可以为百分比或整数
template: # 定义业务模板,如有多个副本,所有副本的属性会按照模板的相关配置进行匹配
metadata: # 资源的元数据/属性
annotations: # 自定义注解列表
sidecar.istio.io/inject: "false" # 自定义注解名字
labels: # 自定义资源的标签
app: demo # 模板名称必填
version: stable
spec: # 资源规范字段
restartPolicy: Always # Pod的重启策略。[Always | OnFailure | Nerver]
# Always :任何情况下只要容器不在运行状态,就自动重启容器。默认
# OnFailure :只在容器异常时才自动容器容器。
# pod包含多个容器时,其中所有容器都异常pod才会进入Failed状态
# Nerver :从不重启容器
nodeSelector: # 将该Pod调度到含此label的node上,基于简单等值关系定义标签选择器
caas_cluster: work-node
containers: # Pod中容器列表
- name: demo # 容器的名字
image: demo:v1 # 容器使用的镜像地址
imagePullPolicy: IfNotPresent # 每次Pod启动拉取镜像策略
# IfNotPresent :如果本地有就不检查,如果没有就拉取。默认
# Always: 每次都检查
# Never : 每次都不检查(不管本地是否有)
command: [string] # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] # 容器的启动命令参数列表
# 如果command和args均没有写,那么用Docker默认的配置;
# 如果command写了,args没写,Docker默认配置被忽略且仅执行.yaml文件的command(不带参数)
# 如果command没写,args写了,Docker默认配置的ENTRYPOINT命令行被执行,调用参数.yaml中的args
# 如果command和args都写了,那么Docker默认的配置被忽略,使用.yaml的配置
workingDir: string # 容器的工作目录
volumeMounts: # 挂载到容器内部的存储卷配置
- name: string # 引用pod定义的共享存储卷的名称,用volumes[]部分定义的卷名
mountPath: string # 存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean # 是否为只读模式
- name: string
configMap: # 类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string
ports: # 需要暴露的端口库号列表
- name: http # 端口号名称
containerPort: 8080 # 容器开放对外的端口
# hostPort: 8080 # 容器所在主机需要监听的端口号,默认与Container相同
protocol: TCP # 端口协议,支持TCP和UDP,默认TCP
env: # 容器运行前需设置的环境变量列表
- name: string # 环境变量名称
value: string # 环境变量的值
resources: # 资源管理。资源限制和请求的设置
limits: # 资源限制的设置,最大使用
cpu: "1" # CPU,"1"(1核) = 1000m。用于docker run --cpu-shares参数
memory: 500Mi # 内存,1G = 1024Mi。用于docker run --memory参数
requests: # 资源请求设置。容器运行时最低资源需求
cpu: 100m
memory: 100Mi
livenessProbe: # pod内部容器的健康检查设置。当探测无响应几次后将自动重启该容器
# 检查方法:exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
httpGet: # 通过httpget检查健康,返回200-399之间,则认为容器正常
path: /healthCheck # URI地址。如果没有心跳检测接口就为/
port: 8089 # 端口
scheme: HTTP # 协议
# host: 127.0.0.1 # 主机地址
# 也可以用这两种方法进行pod内容器的健康检查
# exec: # 容器内执行任意命令,检查命令退出状态码为0则探测成功,否则探测失败容器重启
# command:
# - cat
# - /tmp/health
# 也可以用这种方法
# tcpSocket: # 对Pod内容器健康检查方式设置为tcpSocket方式
# port: number
initialDelaySeconds: 30 # 容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 5 # 对容器健康检查等待响应的超时时间,默认1秒
periodSeconds: 30 # 对容器监控检查的定期探测间隔时间设置,默认10秒一次
successThreshold: 1 # 成功门槛
failureThreshold: 5 # 失败门槛,连接失败5次,pod杀掉,重启一个新的pod
readinessProbe: # Pod准备服务健康检查设置
httpGet:
path: /healthCheck # 如果没有心跳检测接口就为/
port: 8089
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
periodSeconds: 10
successThreshold: 1
failureThreshold: 5
lifecycle: # 生命周期管理
postStart: # 容器运行之前运行的任务
exec:
command:
- 'sh'
- 'yum upgrade -y'
preStop: # 容器关闭之前运行的任务
exec:
command: ['service httpd stop']
initContainers: # 初始化容器
- command:
- sh
- -c
- sleep 10; mkdir /wls/logs/nacos-0
env:
image: {{ .Values.busyboxImage }}
imagePullPolicy: IfNotPresent
name: init
volumeMounts:
- mountPath: /wls/logs/
name: logs
volumes:
- name: logs
hostPath:
path: {{ .Values.nfsPath }}/logs
volumes: # 在该pod上定义共享存储卷列表
- name: string # 共享存储卷名称 (volumes类型有很多种)
emptyDir: {} # 类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
- name: string
hostPath: # 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string # Pod所在宿主机的目录,将被用于同期中mount的目录
- name: string
secret: # 类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
scretname: string
items:
- key: string
path: string
imagePullSecrets: # 镜像仓库拉取镜像时使用的密钥,以key:secretkey格式指定
- name: harbor-certification
hostNetwork: false # 主机网络模式,默认为false,设置为true表示使用宿主机网络
terminationGracePeriodSeconds: 30 # 优雅关闭时间,这个时间内优雅关闭未结束,k8s强制 kill
dnsPolicy: ClusterFirst # 设置Pod的DNS的策略。默认ClusterFirst
# 支持的策略:[Default | ClusterFirst | ClusterFirstWithHostNet | None]
# Default : Pod继承所在宿主机的设置,直接将宿主机的/etc/resolv.conf内容挂载到容器中
# ClusterFirst : 默认的置,所有请求优先在集群所在域查询,没有才会转发到上游DNS
# ClusterFirstWithHostNet : 和ClusterFirst一样,Pod运行在hostNetwork:true下强制指定
# None : 1.9版本引入的新值,此配置忽略所有配置,以Pod的dnsConfig字段为准
affinity: # 亲和性调试
nodeAffinity: # 节点亲和性。满足特定条件的pod对象运行在同一个node上。效果同nodeSelector,但功能更强大
requiredDuringSchedulingIgnoredDuringExecution: # 硬亲和性
nodeSelectorTerms: # 节点满足任何一个条件就可以
- matchExpressions: # 有多个选项时,同时满足这些逻辑选项的节点才能运行pod
- key: beta.kubernetes.io/arch
operator: In
values:
- amd64
podAffinity: # pod亲和性。满足特定条件的pod对象运行在同一个node上
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
podAntiAffinity: # pod反亲和性。满足特定条件(相同pod标签)pod对象不能运行在同一个node上
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname # 反亲和性的节点标签 key
tolerations: # 污点容忍度。允许pod可以运行在匹配的污点上
- operator: "Equal" # 匹配类型。支持[Exists | Equal(默认值)]。Exists为容忍所有污点
key: "key1"
value: "value1"
effect: "NoSchedule" # 污点类型:[NoSchedule | PreferNoSchedule | NoExecute]
# NoSchedule :不会被调度
# PreferNoSchedule:尽量不调度
# NoExecute:驱逐节点
Deployment 的示例1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
例2:在上面yaml的基础上添加了volume
[root@kub-k8s-master prome]# vim deployment.yaml
apiVersion: apps/v1 #注意版本号
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector: #属性,选择器
matchLabels:
app: nginx
replicas: 2 #管理的副本个数
template: #模板属性
metadata: #对pod的描述
labels:
app: nginx
spec:
volumes: #定义共享卷
- name: nginx-vol
emptyDir: {}
containers:
- name: nginx
image: daocloud.io/library/nginx
ports:
- containerPort: 80
volumeMounts: #定义挂载卷
- mountPath: "/usr/share/nginx/html"
name: nginx-vol
创建Deployment:
将上述的YAML文件保存为deployment.yaml,然后创建Deployment:
[root@kub-k8s-master prome]# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
检查Deployment的列表:启动之后需要创建时间比较长
通过 kubectl get 命令检查这个 YAML 运行起来的状态:
[root@kub-k8s-master prome]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 2m22s
[root@kub-k8s-master prome]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-deployment-59c4b86474-2llrt 1/1 Running 0 2m51s
nginx-deployment-59c4b86474-n2r2m 1/1 Running 0 2m51s
在这里加上了一个 -l 参数,即获取所有匹配 app: nginx 标签的 Pod。需要注意的是,在命令行中,所有 key-value 格式的参数,都使用"="而非":"表示。
删除Deployment:
[root@k8s-master ~]# kubectl delete deployments nginx-deployment
deployment "nginx-deployment" deleted
或者
[root@k8s-master ~]# kubectl delete -f deployment.yaml
apiVersion:注意这里apiVersion对应的值是extensions/v1beta1或者apps/v1.这个版本号需要
根据安装的Kubernetes版本和资源类型进行变化,记住不是写死的。此值必须在kubectl apiversion中
[root@kub-k8s-master prome]# kubectl api-versions
apps/v1beta1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1beta1
autoscaling/v1
batch/v1
certificates.k8s.io/v1alpha1
extensions/v1beta1
policy/v1beta1
rbac.authorization.k8s.io/v1alpha1
storage.k8s.io/v1beta1
v1
kind:资源类型指定为Deployment。
metadata:指定一些meta信息,包括名字或标签之类的。每一个 API 对象都有一个叫作 Metadata 的字段,这个字段是 API 对象的"标识",即元数据,也是我们从 Kubernetes 里找到这个对象的主要依据。
labels:Labels是最主要的字段,是一组 key-value 格式的标签,k8s中的所有资源都支持携带label,
默认情况下,pod的label会复制rc的label
k8s使用用户自定义的key-value键值对来区分和标识资源集合(就像rc、pod等资源),这种键值对
称为label。像 Deployment 这样的控制器对象,就可以通过这个 Labels 字段从 Kubernetes 中过滤
出它所关心的被控制对象。
selector:过滤规则的定义,是在 Deployment 的"spec.selector.matchLabels"字段。一般
称之为:Label Selector。
pod的label会被用来创建一个selector,用来匹配过滤携带这些label的pods。
使用labels定位pods
[root@k1 ~]# kubectl get pods -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment-59c4b86474-2llrt 1/1 Running 0 16m 10.244.2.15 kub-k8s-node2
nginx-deployment-59c4b86474-n2r2m 1/1 Running 0 16m 10.244.1.39 kub-k8s-node1
检查你的Pod的IPs:
[root@k1 ~]# kubectl get pods -l app=nginx -o json | grep podIP # JSON格式输出
"podIP": "10.244.2.15",
"podIPs": [
"podIP": "10.244.1.39",
"podIPs": [
spec : 一个 k8s 的 API 对象的定义,大多可以分为 Metadata 和 Spec 两个部分。前者存放
的是这个对象的元数据,对所有 API 对象来说,这一部分的字段和格式基本上是一样的;而后者存
放的,则是属于这个对象独有的定义,用来描述它所要表达的功能。
这里定义需要两个副本,此处可以设置很多属性,主要是受此Deployment影响的Pod的选择器
replicas:定义的 Pod 副本个数 (spec.replicas) :2
template:定义了一个 Pod 模版(spec.template),这个模版描述了想要创建的 Pod 的细节。
例子里,这个 Pod 里只有一个容器,这个容器的镜像(spec.containers.image)是 nginx:latest,
这个容器监听端口(containerPort)是 80。
volumes:是属于 Pod 对象的一部分。需要修改 template.spec 字段
例2中,在 Deployment 的 Pod 模板部分添加了一个 volumes 字段,定义了这个 Pod 声明
的所有 Volume。它的名字叫作 nginx-vol,类型是 emptyDir。
关于emptyDir 类型:等同于 Docker 的隐式 Volume 参数,即:不显式声明宿主机目录的 Volume。
所以,Kubernetes 也会在宿主机上创建一个临时目录,这个目录将来就会被绑定挂载到容器所声明的
Volume 目录上。
k8s 的 emptyDir 类型,只是把 k8s 创建的临时目录作为 Volume 的宿主机目录,交给了 Docker。
当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。
volumeMounts:Pod 中的容器,使用的是 volumeMounts 字段来声明自己要挂载哪个 Volume,
并通过 mountPath 字段来定义容器内的 Volume 目录,比如:/usr/share/nginx/html。
hostPath:k8s 也提供了显式的 Volume 定义,它叫做 hostPath。比如下面的这个 YAML 文件:
...
volumes:
- name: nginx-vol
hostPath:
path: /var/data
这样,容器 Volume 挂载的宿主机目录,就变成了 /var/data
查看rs
[root@k8s-master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-59c4b86474 2 2 2 2m49s
创建SERVICE
工作原理:
service对外提供请求,当访问service的时候并将请求转发到集群中的pod中。此过程是通过endpoint
与selector实现的。selector是用于选择带有某个标签的pod,然后将该pod的ip和端口添加到endpoint
中。当访问service时就会从endpoint中选择对应的pod的ip和端口,然后将请求转发到对应的pod中。
具体请求如何转发过去的就需要kube-proxy去实现了。
三台安装iptables:
[root@kub-k8s-master prome]# yum install -y iptables iptables-services
1.创建一个depl
[root@kub-k8s-master prome]# kubectl delete -f deployment.yaml
[root@kub-k8s-master prome]# vim nginx-depl.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep01
spec:
selector:
matchLabels:
app: web
replicas: 2
template:
metadata:
labels:
app: web
spec:
containers:
- name: testnginx9
image: daocloud.io/library/nginx
ports:
- containerPort: 80
[root@kub-k8s-master prome]# kubectl apply -f nginx-depl.yml
deployment.apps/nginx-deployment created
2. 创建service并且以nodePort的方式暴露端口给外网:
[root@kub-k8s-master prome]# vim nginx_svc.yaml
apiVersion: v1
kind: Service
metadata:
name: mysvc
spec:
type: NodePort #类型
ports:
- port: 8080
nodePort: 30001
targetPort: 80
selector: #选择器
app: web
[root@kub-k8s-master prome]# kubectl apply -f nginx_svc.yaml
service/mysvc created
3.查看
[root@kub-k8s-master prome]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d18h
mysvc NodePort 10.100.166.208 <none> 8080:30001/TCP 21s
4.查看service的详细信息
[root@kub-k8s-master prome]# kubectl describe svc mysvc
Name: mysvc
......
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.84.130:80,10.244.84.131:80
Session Affinity: None
Events: <none>
5.当创建好svc之后,k8s会默认给创建一个和svc名字一样的endpoints
[root@kub-k8s-master prome]# kubectl get ep mysvc
NAME ENDPOINTS AGE
mysvc 10.244.84.130:80,10.244.84.131:80 7m15s
端口详解
安装iptables(但是需要关闭iptables),创建service之后k8s会自动添加规则到Iptables里面,而且会生效(虽然iptables处于关闭状态)
服务中的3个端口设置
这几个port的概念很容易混淆,比如创建如下service:
apiVersion: v1
kind: Service
metadata:
name: mysvc
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
targetPort: 80
selector:
app: web
port
这里的port表示:service暴露在cluster ip上的端口,cluster ip:port 是提供给集群内部客户访问service的入口。
nodePort
首先,nodePort是kubernetes提供给集群外部客户访问service入口的一种方式(另一种方式是LoadBalancer),所以,<nodeIP>:nodePort 是提供给集群外部客户访问service的入口。
targetPort
targetPort很好理解,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。
NodePort端口的范围是从30000到32767
port、nodePort总结
总的来说,port和nodePort都是service的端口,前者暴露给集群内客户访问服务,后者暴露给集群外客户访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的targetPort,从而到达pod上的容器内。
kube-proxy反向代理
kube-proxy目前支持三种工作模式: 1.userspace 模式 2.iptables 模式:iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。(该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则) 3.ipvs 模式:ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。而且ipvs支持更多的LB算法。
kube-proxy与iptables与ipvsadm
当service有了port和nodePort之后,就可以对内/外提供服务。那么其具体是通过什么原理来实现的呢?原因就在kube-proxy在本地node上创建的iptables规则。
Kube-Proxy 通过配置 DNAT 规则(从容器出来的访问,从本地主机出来的访问两方面),将到这个服务地址的访问映射到本地的kube-proxy端口(随机端口)。然后 Kube-Proxy 会监听在本地的对应端口,将到这个端口的访问给代理到远端真实的 pod 地址上去,同时生成lvs的负载规则
不管是通过集群内部服务入口<cluster ip>:port还是通过集群外部服务入口<node ip>:nodePort的请求都将重定向到本地kube-proxy端口(随机端口)的映射,然后将到这个kube-proxy端口的访问给代理到远端真实的 pod 地址上去。在通过lvs实现负载
查看负载规则
[root@kube-k8s-master prome]# ipvsadm -Ln
如果没有规则
[root@master ~]# kubectl edit cm kube-proxy -n kube-system
搜索mode: 添加ipvs
然后将所有的kube-proxy的pod删除,等待重新创建即可
注意:自k8s1.1以后,service默认使用ipvs规则,若ipvs没有被激活,则降级使用iptables规则.
RC资源(了解)
Replication Controller(简称rc)用来管理Pod的副本,保证集群中存在指定数量的Pod副本。集群中副本的数量大于指定数量,则会停止指定数量之外的多余容器数量,反之,则会启动少于指定数量个数的容器,保证数量不变。Replication Controller是实现弹性伸缩、动态扩容和滚动升级的核心。 RC 的主要功能点: 确保pod数量:指定某个服务在Kubernetes中有相应数量的Pod在运行; 确保pod健康:当pod不健康,运行出错或者无法提供服务时,会杀死不健康pod并重新创建,保持pod数量一致; 弹性伸缩:当业务高峰期的时候可以设置扩增pod数量,配合监控就可以做自动伸缩了; 滚动升级:也就是蓝绿发布,当一个pod使用的镜像更新,采用滚动升级模式,RC会自动一个个pod的进行升级,关闭一个pod的同时进行升级,且在原镜像基础上创建一个新pod,当一个pod更新完成再关闭一个旧镜像pod。
使用yaml创建并启动replicas集合
Replication Controller会确保pod的数量在运行的时候会一直保持在一个特殊的数字,即replicas的设置。
[root@kub-k8s-master ~]# cd prome/ [root@kub-k8s-master prome]# vim nginx-rc.yml --- apiVersion: v1 kind: ReplicationController metadata: name: my-nginx spec: replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: daocloud.io/library/nginx ports: - containerPort: 80
如果你在删除rc之前尝试删除pod,rc将会立即启动新的pod来替换被删除的pod
完整TOMCAT实例
Java Web应用
注:Tomcat有可能无法正常启动,原因是虚机的内存和CPU设置过小,请酌情调大!
下载镜像
[root@kub-k8s-node1 ~]# docker pull daocloud.io/library/tomcat
构建Tomcat RC定义文件
[root@kub-k8s-master prome]# vim myweb.rc.yml --- apiVersion: v1 kind: ReplicationController metadata: name: myweb spec: replicas: 2 selector: app: myweb template: metadata: labels: app: myweb spec: containers: - name: myweb image: daocloud.io/library/tomcat:8 ports: - containerPort: 8080 #在8080端口上启动容器进程,PodIP与容器端口组成Endpoint,代表着一个服务进程对外通信的地址
发布到Kubernetes集群
创建RC
[root@kub-k8s-master prome]# kubectl apply -f myweb.rc.yml replicationcontroller/myweb created
查看RC
[root@kub-k8s-master prome]# kubectl get rc NAME DESIRED CURRENT READY AGE myweb 1 1 1 20s
查看Pod
[root@kub-k8s-master prome]# kubectl get pods NAME READY STATUS RESTARTS AGE myweb-shjfn 1/1 Running 0 52s
构建Tomcat Kubernetes Service定义文件
[root@kub-k8s-master prome]# vim myweb-svc.yaml apiVersion: v1 kind: Service metadata: name: myweb spec: type: NodePort ports: - port: 8081 nodePort: 30009 targetPort: 8080 selector: app: myweb
创建
[root@kub-k8s-master prome]# kubectl apply -f myweb-svc.yaml service/myweb created
查看SVC
[root@kub-k8s-master prome]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d22h mysvc NodePort 10.110.160.108 <none> 8080:30001/TCP 3h37m myweb NodePort 10.96.19.61 <none> 8081:30009/TCP 33s
运行
浏览器中输入http://虚拟机IP:30009即可呈现如下内容:
注意在节点(node)中访问,不是master
[root@kub-k8s-node1 ~]# curl 192.168.246.166:30009
K8S之暴露IP给外网
转发K8S后端服务的四种方式
方式1:ClusterIP
此类型会提供一个集群内部的虚拟IP(与Pod不在同一网段),以供集群内部的pod之间通信使用。ClusterIP也是Kubernetes service的默认类型。
方式2:NodePort
外网client--->nodeIP+nodePort--->podIP+PodPort 为每个节点暴露一个端口,通过nodeip + nodeport可以访问这个服务,同时服务依然会有cluster类型的ip+port。内部通过clusterip方式访问,外部通过nodeport方式访问。
方式3:loadbalance
LoadBalancer在NodePort基础上,K8S可以请求底层云平台创建一个负载均衡器,将每个Node作为后端,进行服务分发。
方式4:Ingress
Ingress是一种HTTP方式的路由转发机制,为K8S服务配置HTTP负载均衡器,通常会将服务暴露给K8S群集外的客户端。