当前位置: 首页 > article >正文

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     # 查看所有名称空间所有的pod
  kubectl 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-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@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:IfNotPresent
      image: 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-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@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: website
  labels:
    app: website
spec:
  containers:
    - name: test-website
      image: daocloud.io/library/nginx
      ports:
        - containerPort: 80
  nodeName: 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: 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方式:

(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: 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@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-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字段要使用空值。

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  containers:
    - name: example-container
      image: nginx:latest
  tolerations:
    # 使用 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-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

测试:

[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@k1 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@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-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

  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-webapp
  namespace: default
  resourceVersion: "270687"
  selfLink: /api/v1/namespaces/default/pods/test-webapp
  uid: ed92d685-f800-464f-95dc-d6aa5f92fc9c
......
实战

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

[root@k1 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@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-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@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-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@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+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@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-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 作为一种控制器,主要用于管理一组 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 和 Pod
  template:
    metadata:
      labels:
        app: nginx
      # 设置 Pod 的标签,这使得 Deployment 能够通过选择器找到这些 Pod
    spec:
      containers:
      - name: nginx
        # 设置容器名称
        image: nginx:1.14.2
        # 设置容器使用的镜像
        ports:
        - containerPort: 80
          # 设置容器监听的端口
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 15
          periodSeconds: 20
          # 设置存活探针,检查容器是否存活
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
          # 设置就绪探针,检查容器是否准备好接收流量

Deployment示例

[root@k1 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@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-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 # -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) :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

ReplicaSet(简称 RS)是一种工作负载资源,它保证某个版本的 Pod 的稳定副本数(称为副本),即使有 Pod 崩溃或需要更新。ReplicaSet 通常由更高级别的控制器如 Deployment 控制。

[root@k1 ~]# kubectl get rs    # 列出所有的 ReplicaSet
NAME                         DESIRED   CURRENT   READY   AGE
nginx-deployment-59c4b86474   2         2         2      2m49s

kubectl 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: web
  replicas: 2
  template:
      metadata:
        labels:
          app: web
      spec:
        containers:
          - name: testnginx9
            image: daocloud.io/library/nginx
            ports:
              - 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: 8080
      nodePort: 30001
      targetPort: 80
  selector:   #选择器
    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: NodePort
  ports:
    - port: 8080
      nodePort: 30001
      targetPort: 80
  selector:
    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: 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@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: 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@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: NodePort
  ports:
    - port: 8081
      nodePort: 30009
      targetPort: 8080
  selector:
    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: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - 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: 600
  replicas: 3   #将这里原来的4改为3
  revisionHistoryLimit: 10
  selector:
    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/v1
    kind: Deployment
    name: my-app-deployment
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 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: RollingUpdate
    rollingUpdate:
      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: web1
  replicas: 2
  template:
      metadata:
        name: testnginx9
        labels:
          app: web1
      spec:
        containers:
        - name: testnginx9
          image: daocloud.io/library/nginx:1.14 #注意修改
          ports:
          - containerPort: 80
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 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.16
        imagePullPolicy: Always
        name: testnginx9
        ports:
        - 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 2
  Normal  ScalingReplicaSet  9s    deployment-controller  Scaled up replica set dep02-58f8d5678 to 1
  Normal  ScalingReplicaSet  8s    deployment-controller  Scaled down replica set dep02-846bf8775b to 1
  Normal  ScalingReplicaSet  8s    deployment-controller  Scaled up replica set dep02-58f8d5678 to 2
  Normal  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

回滚到更早之前的版本:

  1. 使用 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=web1
    pod-template-hash=8594cd6447
  Containers:
   testnginx9:
    Image:  daocloud.io/library/nginx:1.14
    Port:   80/TCP
    Host Port:  0/TCP
    Environment:    <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: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.3.0
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  minReadySeconds: 0
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/name: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
    spec:
      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/key
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: LD_PRELOAD
          value: /usr/local/lib/libmimalloc.so
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5 #将原来的镜像替换成阿里云仓库的镜像
        imagePullPolicy: IfNotPresent
        lifecycle:
          preStop:
            exec:
              command:
              - /wait-shutdown
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        name: controller
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
        - containerPort: 443
          name: https
          protocol: TCP
        - containerPort: 8443
          name: webhook
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          requests:
            cpu: 100m
            memory: 90Mi
        securityContext:
          allowPrivilegeEscalation: true
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          runAsUser: 101
        volumeMounts:
        - mountPath: /usr/local/certificates/
          name: webhook-cert
          readOnly: true
      dnsPolicy: ClusterFirst
      nodeSelector:
        custom/ingress-controller-ready: "true"  #指定运行ingress的node标签
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 300
      volumes:
      - name: webhook-cert
        secret:
          secretName: ingress-nginx-admission
---
​
#注意:一共有两个镜像需要替换成阿里云仓库的镜像:
[root@k1 ~]# cat deploy.yaml | grep image
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5
        imagePullPolicy: IfNotPresent
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
        imagePullPolicy: IfNotPresent
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
        imagePullPolicy: 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-apache
 replicas: 2
 template:
  metadata:
   labels:
    run: my-apache
  spec:
   containers:
   - name: my-apache
     image: daocloud.io/library/httpd:2.4
     ports:
     - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
 name: my-apache
 labels:
  run: my-apache
spec:
 #type: NodePort
 ports:
 - port: 80
   targetPort: 80
   #nodePort: 30002
 selector:
  run: my-apache
  
  
[root@k1 ~]# vim my-nginx.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
 name: my-nginx
spec:
 selector:
   matchLabels:
     run: my-nginx
 replicas: 2
 template:
  metadata:
   labels:
    run: my-nginx
  spec:
   containers:
   - name: my-nginx
     image: daocloud.io/library/nginx:1.7.9
     ports:
     - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
 name: my-nginx
 labels:
  run: my-nginx
spec:
 #type: NodePort
 ports:
 - port: 80
   targetPort: 80
   #nodePort: 30001
 selector:
  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-ingress
 namespace: default
 annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
 ingressClassName: nginx #指定ingress的类型
 rules:  #定义转发规则
 - host: test.apache.ingress  #指定域名方式
   http:
    paths:
    - path: /  #指定访问的路径
      pathType: Prefix  #定义路径的类型
      backend:   #定义转发后端的服务
       service:  #定义转发的service
         name: my-apache
         port:
          number: 80
 - host: test.nginx.ingress
   http:
    paths:
    - path: /
      pathType: Prefix
      backend:
       service:
         name: my-nginx
         port:
          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


http://www.kler.cn/news/355697.html

相关文章:

  • 【OpenGL】创建窗口/绘制图形
  • mailx邮件服务器的配置
  • 使用docker-compose搭建redis7集群-3主3从
  • Docker 教程十(Docker Compose)
  • 011_django基于大数据的足球数据分析与可视化系统2024_096va8x0
  • c++ 中虚函数和纯虚函数
  • Android Camera2在textureView中的预览和拍照
  • 【微信小程序_19_自定义组件(1)】
  • Leetcode 分割等和子集
  • 渗透实战 JS文件怎么利用
  • LabVIEW智能螺杆空压机测试系统
  • 机器学习篇-day08-聚类Kmeans算法
  • Java项目-基于Springboot的在线外卖系统项目(源码+说明).zip
  • 腾讯PAG 动画库Android版本的一个问题与排查记录
  • CVE-2022-26965靶机渗透
  • LLM - 配置 ModelScope SWIFT 测试 Qwen2-VL 图像微调(LoRA) 教程(2)
  • react里实现左右拉伸实战
  • YOLO11改进 | 注意力机制 | 添加双重注意力机制 DoubleAttention【附代码+小白必备】
  • 86.#include预处理命令(1)
  • 【最新华为OD机试E卷-支持在线评测】VLAN资源池(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)