【k8s】——Kubernetes知识盘点

目录

1.前言

2.基本概念

3.高可用集群

4.组件之间的关系图

5.Service介绍

5.1.1.1.什么是Service

5.1.1.2.Service的创建

5.1.1.3.检测服务

5.1.1.4.在运行的容器中远程执行命令

5.2.连接集群外部的服务

5.2.1.介绍服务endpoint

5.2.2.手动配置服务的endpoint

5.2.3.为外部服务创建别名

5.3.将服务暴露给外部客户端

5.3.1.使用nodeport类型的服务

5.3.2.通过Loadbalance将服务暴露出来

5.4.通过Ingress暴露服务

5.4.1.创建Ingress资源

5.4.2.通过Ingress访问服务

5.4.3.通过相同的Ingress暴露多少服务

5.4.4.配置Ingress处理TLS传输

5.5.pod就绪后发出信号

5.5.1.介绍就绪探针

5.5.2.向pod添加就绪探针

5.6.使用headless服务发现独立的pod

5.6.1.创建headless服务

6.kubernetes  磁盘、PV、PVC

6.1.介绍卷

6.1.1.卷的类型

6.2.通过卷在容器间共享数据

6.2.1.使用emptyDir卷

6.3.访问工作节点文件系统上的文件

6.3.1.hostPath卷

6.4.使用持久化

6.4.1.使用NFS存储

6.4.2.configmap和secert

6.5.从底层存储技术解耦pod

6.5.1.介绍持久卷和持久卷声明

6.5.2.创建持久卷

6.5.3.通过持久卷声明来获取持久卷

6.5.4.在pod中使用持久卷声明

6.5.5.回收持久卷

6.6.持久卷的动态配置

6.6.1.通过StorageClass资源定义可用存储类型

6.6.2.PV&&PVC在应用在mysql的持久化存储

7.kubernetes ConfigMap和Secret:配置应用程序

7.1.配置容器化应用程序

7.2.向容器传递命令行参数

7.2.1.待Docker中定义命令与参数

7.2.2.在kubernetes中覆盖命令行和参数

7.3.为容器设置环境变量

7.3.1.在容器定义中指定环境变量

7.3.2.在环境变量值中引用其他环境变量

7.4.利用ConfigMap解耦配置

7.4.1.ConfigMap介绍

7.4.2.创建ConfigMap

7.4.3.给容器传递ConfigMap条目作为环境变量

7.4.4.一次性传递ConfigMap的所有条目作为环境变量

7.4.5.使用ConfigMap卷将条目暴露为文件

7.5.使用Secert给容器传递敏感数据

7.5.1.介绍Secert

7.5.2.默认令牌Secret

7.5.3.创建Secret

7.5.4.对比ConfigMap与Secret

7.5.5.在pod中使用Secret

9.deployment:声明式的升级应用

9.1.使用RC实现滚动升级

9.2.使用Deployment声明式的升级应用

9.3.触发deployment升级

9.4.回滚deployment

9.5.控制滚动升级的速率

9.6.金丝雀发布和蓝绿发布

10.Statefulset:部署有状态的多副本应用

10.1.什么是Statefulset

10.2.statefulset的创建

10.3.statefulset中发现伙伴的节点

10.4.更新statefulset

11.k8s部分组件介绍

11.1.了解调度器

11.2.介绍控制器管理器中运行的控制器

11.3.kubelet做了什么

11.4.k8s如何使用etcd

11.5.API Server

12.kubernetes API服务器的安全防护

12.1.了解认证机制

12.1.1.用户和组

12.1.2 ServiceAccount介绍

12.1.3创建ServiceAccount

12.1.4将ServiceAccount分配给pod

12.2通过基于角色的权限控制加强集群安全

12.2.1.介绍RBAC授权插件

12.2.2介绍RBAC授权资源

12.2.3使用Role和RoleBinding

12.2.4使用ClusterRole和ClusterRoleBinding

12.2.5了解默认的ClusterRole和ClusterRoleBinding

13.Kubernetes-保障集群内节点和网络安全

13.1.在pod中使用宿主节点的Linux命名空间

13.1.1.在pod中使用宿主节点的网络命名空间

13.1.2.绑定宿主节点上的端口而不使用宿主节点的网络命名空间

13.1.3.使用宿主节点的PID与IPC

13.2.配置节点的安全上下文

13.2.1.使用指定用户运行容器

13.2.2.阻止容器以root用户运行

13.2.3.使用特权模式运行pod

13.2.4.为容器单独添加内核功能

13.2.5.在容器中禁止使用内核功能

13.2.6.阻止对容器根文件系统的写入

13.3.限制pod使用安全相关的特性

13.3.1.PodSecurityPolicy资源介绍

13.3.2.了解runAsUser、fsGroups和supplementalGroup策略

13.3.3.配置允许、默认添加、禁止使用的内核功能

13.4.隔离pod网络

13.4.1.在一个命名空间中使用网络隔离

13.4.2.在 不同的kubernetes命名空间之间进行网络隔离

13.4.3.使用CIDR网络隔离

13.4.4.限制pod对外访问流量


1.前言

     K8s的主要职责是容器编排(Container Orchestration),即在一组服务器上启动、监控、回收容器,在满足排程的同时,保证容器可以健康的运行。k8s号称是“未来的操作系统”,知识点较多。

2.基本概念

2.1. Master

    集群的控制节点,负责整个集群的管理和控制,kubernetes的所有的命令基本都是发给Master,由它来负责具体的执行过程。

1.1. Master的组件

  • kube-apiserver:资源增删改查的入口
  • kube-controller-manager:资源对象的大总管
  • kube-scheduler:负责资源调度(Pod调度)
  • etcd Server:kubernetes的所有的资源对象的数据保存在etcd中。

2. Node

    Node是集群的工作负载节点,默认情况kubelet会向Master注册自己,一旦Node被纳入集群管理范围,kubelet会定时向Master汇报自身的情报,包括操作系统,Docker版本,机器资源情况等。如果Node超过指定时间不上报信息,会被Master判断为“失联”,标记为Not Ready,随后Master会触发Pod转移。

2.1. Node的组件

  • kubelet:Pod的管家,与Master通信
  • kube-proxy:实现kubernetes Service的通信与负载均衡机制的重要组件
  • Docker:容器的创建和管理

2.2. Node相关命令

kubectl get nodes

kuebctl describe node {node_name}

2.3. describe命令的Node信息

  • Node基本信息:名称、标签、创建时间等
  • Node当前的状态,Node启动后会进行自检工作,磁盘是否满,内存是否不足,若都正常则切换为Ready状态。
  • Node的主机地址与主机名
  • Node上的资源总量:CPU,内存,最大可调度Pod数量等
  • Node可分配资源量:当前Node可用于分配的资源量
  • 主机系统信息:主机唯一标识符UUID,Linux kernel版本号,操作系统,kubernetes版本,kubelet与kube-proxy版本
  • 当前正在运行的Pod列表及概要信息
  • 已分配的资源使用概要,例如资源申请的最低、最大允许使用量占系统总量的百分比
  • Node相关的Event信息。

3. Pod

     Pod是Kubernetes中操作的基本单元。每个Pod中有个根容器(Pause容器),Pause容器的状态代表整个容器组的状态,其他业务容器共享Pause的IP,即Pod IP,共享Pause挂载的Volume,这样简化了同个Pod中不同容器之间的网络问题和文件共享问题。

【k8s】——Kubernetes知识盘点_第1张图片

  1. Kubernetes集群中,同宿主机的或不同宿主机的Pod之间要求能够TCP/IP直接通信,因此采用虚拟二层网络技术来实现,例如Flannel,Openvswitch(OVS)等,这样在同个集群中,不同的宿主机的Pod IP为不同IP段的IP,集群中的所有Pod IP都是唯一的,不同Pod之间可以直接通信。
  2. Pod有两种类型:普通Pod和静态Pod。静态Pod即不通过K8S调度和创建,直接在某个具体的Node机器上通过具体的文件来启动。普通Pod则是由K8S创建、调度,同时数据存放在ETCD中。
  3. Pod IP和具体的容器端口(ContainnerPort)组成一个具体的通信地址,即Endpoint。一个Pod中可以存在多个容器,可以有多个端口,Pod IP一样,即有多个Endpoint。
  4. Pod Volume是定义在Pod之上,被各个容器挂载到自己的文件系统中,可以用分布式文件系统实现后端存储功能。
  5. Pod中的Event事件可以用来排查问题,可以通过kubectl describe pod xxx 来查看对应的事件。
  6. 每个Pod可以对其能使用的服务器上的计算资源设置限额,一般为CPU和Memory。K8S中一般将千分之一个的CPU配置作为最小单位,用m表示,是一个绝对值,即100m对于一个Core的机器还是48个Core的机器都是一样的大小。Memory配额也是个绝对值,单位为内存字节数。
  7. 资源配额的两个参数
  • Requests:该资源的最小申请量,系统必须满足要求。
  • Limits:该资源最大允许使用量,当超过该量,K8S会kill并重启Pod。

【k8s】——Kubernetes知识盘点_第2张图片

4. Label

  1. Label是一个键值对,可以附加在任何对象上,比如Node,Pod,Service,RC等。Label和资源对象是多对多的关系,即一个Label可以被添加到多个对象上,一个对象也可以定义多个Label。
  2. Label的作用主要用来实现精细的、多维度的资源分组管理,以便进行资源分配,调度,配置,部署等工作。
  3. Label通俗理解就是“标签”,通过标签来过滤筛选指定的对象,进行具体的操作。k8s通过Label Selector(标签选择器)来筛选指定Label的资源对象,类似SQL语句中的条件查询(WHERE语句)。
  4. Label Selector有基于等式和基于集合的两种表达方式,可以多个条件进行组合使用。
  • 基于等式:name=redis-slave(匹配name=redis-slave的资源对象);env!=product(匹配所有不具有标签env=product的资源对象)
  • 基于集合:name in (redis-slave,redis-master);name not in (php-frontend)(匹配所有不具有标签name=php-frontend的资源对象)

使用场景

  1. kube-controller进程通过资源对象RC上定义的Label Selector来筛选要监控的Pod副本数,从而实现副本数始终保持预期数目。
  2. kube-proxy进程通过Service的Label Selector来选择对应Pod,自动建立每个Service到对应Pod的请求转发路由表,从而实现Service的智能负载均衡机制。
pod可以想象成一个篮子,而容器则是篮子里的鸡蛋,他们之间的关系主要变现为以下几点:

1. 一个pod里的容器能有多少资源也取决于这个篮子的大小。
2. label也是贴在篮子上的。
3. IP分配给篮子而不是容器,篮子里面的所有容器共享这个IP。(pod是IP等网络资源的分配的基本单位,这个IP及其对应的network namespace是由pod里的容器共享的;)
4. 哪怕只有一个鸡蛋(容器),Kubernetes仍然会给它分配一个篮子。
5. pod里的容器共享network namespace,并通过volume机制共享一部分存储。

5. Replication Controller(RC)

     RC是k8s系统中的核心概念,定义了一个期望的场景。

主要包括:

  • Pod期望的副本数(replicas)
  • 用于筛选目标Pod的Label Selector
  • 用于创建Pod的模板(template)

RC特性说明:

  1. Pod的缩放可以通过以下命令实现:kubectl scale rc redis-slave --replicas=3
  2. 删除RC并不会删除该RC创建的Pod,可以将副本数设置为0,即可删除对应Pod。或者通过kubectl stop /delete命令来一次性删除RC和其创建的Pod。
  1. 改变RC中Pod模板的镜像版本可以实现滚动升级(Rolling Update)。具体操作见https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/
  2. Kubernetes1.2以上版本将RC升级为Replica Set,它与当前RC的唯一区别在于Replica Set支持基于集合的Label Selector(Set-based selector),而旧版本RC只支持基于等式的Label Selector(equality-based selector)。
  3. Kubernetes1.2以上版本通过Deployment来维护Replica Set而不是单独使用Replica Set。即控制流为:Delpoyment→Replica Set→Pod。即新版本的Deployment+Replica Set替代了RC的作用。

6. Deployment

      Deployment是kubernetes 1.2引入的概念,用来解决Pod的编排问题。Deployment可以理解为RC的升级版(RC+Reolicat Set)。特点在于可以随时知道Pod的部署进度,即对Pod的创建、调度、绑定节点、启动容器完整过程的进度展示。

使用场景

  1. 创建一个Deployment对象来生成对应的Replica Set并完成Pod副本的创建过程。
  2. 检查Deployment的状态来确认部署动作是否完成(Pod副本的数量是否达到预期值)。
  3. 更新Deployment以创建新的Pod(例如镜像升级的场景)。
  4. 如果当前Deployment不稳定,回退到上一个Deployment版本。
  5. 挂起或恢复一个Deployment。

可以通过kubectl describe deployment来查看Deployment控制的Pod的水平拓展过程。

7. Horizontal Pod Autoscaler(HPA)

    Horizontal Pod Autoscaler(HPA)即Pod横向自动扩容,与RC一样也属于k8s的资源对象。HPA原理:通过追踪分析RC控制的所有目标Pod的负载变化情况,来确定是否针对性调整Pod的副本数。

Pod负载度量指标:

  • CPUUtilizationPercentage:Pod所有副本自身的CPU利用率的平均值。即当前Pod的CPU使用量除以Pod Request的值。
  • 应用自定义的度量指标,比如服务每秒内响应的请求数(TPS/QPS)。

8. Service(服务)

8.1. Service概述

【k8s】——Kubernetes知识盘点_第3张图片

    Service定义了一个服务的访问入口地址,前端应用通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service与其后端的Pod副本集群之间是通过Label Selector来实现“无缝对接”。RC保证Service的Pod副本实例数目保持预期水平。

8.2. kubernetes的服务发现机制

       主要通过kube-dns这个组件来进行DNS方式的服务发现。

8.3. 外部系统访问Service的问题

IP类型 说明
Node IP Node节点的IP地址
Pod IP Pod的IP地址
Cluster IP Service的IP地址

8.3.1. Node IP

     NodeIP是集群中每个节点的物理网卡IP地址,是真实存在的物理网络,kubernetes集群之外的节点访问kubernetes内的某个节点或TCP/IP服务的时候,需要通过NodeIP进行通信。

8.3.2. Pod IP

      Pod IP是每个Pod的IP地址,是Docker Engine根据docker0网桥的IP段地址进行分配的,是一个虚拟二层网络,集群中一个Pod的容器访问另一个Pod中的容器,是通过Pod IP进行通信的,而真实的TCP/IP流量是通过Node IP所在的网卡流出的。

8.3.3. Cluster IP

  1. Service的Cluster IP是一个虚拟IP,只作用于Service这个对象,由kubernetes管理和分配IP地址(来源于Cluster IP地址池)。
  2. Cluster IP无法被ping通,因为没有一个实体网络对象来响应。
  3. Cluster IP结合Service Port组成的具体通信端口才具备TCP/IP通信基础,属于kubernetes集群内,集群外访问该IP和端口需要额外处理。
  4. k8s集群内Node IP 、Pod IP、Cluster IP之间的通信采取k8s自己的特殊的路由规则,与传统IP路由不同。

8.3.4. 外部访问Kubernetes集群

通过宿主机与容器端口映射的方式进行访问,例如:Service定位文件如下:

可以通过任意Node的IP 加端口访问该服务。也可以通过Nginx或HAProxy来设置负载均衡。

9. Volume(存储卷)

9.1. Volume的功能

  1. Volume是Pod中能够被多个容器访问的共享目录,可以让容器的数据写到宿主机上或者写文件到网络存储中
  2. 可以实现容器配置文件集中化定义与管理,通过ConfigMap资源对象来实现。

9.2. Volume的特点

k8s中的Volume与Docker的Volume相似,但不完全相同。

  1. k8s上Volume定义在Pod上,然后被一个Pod中的多个容器挂载到具体的文件目录下。
  2. k8s的Volume与Pod生命周期相关而不是容器是生命周期,即容器挂掉,数据不会丢失但是Pod挂掉,数据则会丢失。
  3. k8s中的Volume支持多种类型的Volume:Ceph、GlusterFS等分布式系统。

9.3. Volume的使用方式

先在Pod上声明一个Volume,然后容器引用该Volume并Mount到容器的某个目录。

9.4. Volume类型

9.4.1. emptyDir

emptyDir Volume是在Pod分配到Node时创建的,初始内容为空,无须指定宿主机上对应的目录文件,由K8S自动分配一个目录,当Pod被删除时,对应的emptyDir数据也会永久删除。

作用

  1. 临时空间,例如程序的临时文件,无须永久保留
  2. 长时间任务的中间过程CheckPoint的临时保存目录
  3. 一个容器需要从另一个容器中获取数据的目录(即多容器共享目录)

说明

目前用户无法设置emptyVolume的使用介质,如果kubelet的配置使用硬盘则emptyDir将创建在该硬盘上。

9.4.2. hostPath

hostPath是在Pod上挂载宿主机上的文件或目录。

作用

  1. 容器应用日志需要持久化时,可以使用宿主机的高速文件系统进行存储
  2. 需要访问宿主机上Docker引擎内部数据结构的容器应用时,可以通过定义hostPath为宿主机/var/lib/docker目录,使容器内部应用可以直接访问Docker的文件系统。

注意点:

  1. 在不同的Node上具有相同配置的Pod可能会因为宿主机上的目录或文件不同导致对Volume上目录或文件的访问结果不一致。
  2. 如果使用了资源配额管理,则kubernetes无法将hostPath在宿主机上使用的资源纳入管理。

9.4.3. gcePersistentDisk

表示使用谷歌公有云提供的永久磁盘(Persistent Disk ,PD)存放Volume的数据,它与EmptyDir不同,PD上的内容会被永久保存。当Pod被删除时,PD只是被卸载时,但不会被删除。需要先创建一个永久磁盘,才能使用gcePersistentDisk。

使用gcePersistentDisk的限制条件:

  • Node(运行kubelet的节点)需要是GCE虚拟机。
  • 虚拟机需要与PD存在于相同的GCE项目中和Zone中。

10. Persistent Volume

Volume定义在Pod上,属于“计算资源”的一部分,而Persistent Volume和Persistent Volume Claim是网络存储,简称PV和PVC,可以理解为k8s集群中某个网络存储中对应的一块存储。

  • PV是网络存储,不属于任何Node,但可以在每个Node上访问。
  • PV不是定义在Pod上,而是独立于Pod之外定义。
  • PV常见类型:GCE Persistent Disks、NFS、RBD等。

PV是有状态的对象,状态类型如下:

  • Available:空闲状态
  • Bound:已经绑定到某个PVC上
  • Released:对应的PVC已经删除,但资源还没有回收
  • Failed:PV自动回收失败

11. Namespace

Namespace即命名空间,主要用于多租户的资源隔离,通过将资源对象分配到不同的Namespace上,便于不同的分组在共享资源的同时可以被分别管理。

k8s集群启动后会默认创建一个“default”的Namespace。可以通过kubectl get namespaecs查看。

可以通过kubectl config use-context namespace配置当前k8s客户端的环境,通过kubectl get pods获取当前namespace的Pod。或者通过kubectl get pods --namespace=NAMESPACE来获取指定namespace的Pod。

Namespace yaml文件的定义

12. Annotation(注解)

Annotation与Label类似,也使用key/value的形式进行定义,Label定义元数据(Metadata),Annotation定义“附加”信息。

通常Annotation记录信息如下:

  • build信息,release信息,Docker镜像信息等。
  • 日志库、监控库等。

3.高可用集群

 

     上图的K8s高可用部署中有3个管理结点。etcd自身是一个分布式数据存储系统,按照其多实例部署方案,结点只需在启动时知道其它结点的IP和端口号即可组成高可用环境。和通常的应用服务器一样,API Server是无状态的,可以运行任意多个实例,且彼此之间无需互相知道。为了能使kubectl等客户端和Kubelet等组件连接到健康的API Server、减轻单台API Server的压力,需使用基础架构提供的负载均衡器作为多个API Server实例的入口。如上图的部署方法,每个主结点上都运行了一个etcd实例,这样API Server只需连接本地的etcd实例即可,无需再使用负载均衡器作为etcd的入口。

    Controller Manager和Scheduler需要修改K8s集群,同时修改时可能引发并发问题。假设两个ReplicaSet Controller同时监视到需创建一个Pod,然后同时进行创建操作,就会创建出两个Pod。K8s为了避免这个问题,一组此类组件的实例将选举出一个leader,仅有leader处于活动状态,其它实例处于待命状态。Controller Manager和Scheduler也可以独立于API server部署,通过负载均衡器连接到多个API server实例。

4.组件之间的关系图

è¿éåå¾çæè¿°

 

è¿éåå¾çæè¿°

 

5.Service介绍

5.1.1.1.什么是Service

  service是k8s中的一个重要概念,主要是提供负载均衡和服务自动发现。

  Service 是由 kube-proxy 组件,加上 iptables 来共同实现的。

5.1.1.2.Service的创建

   创建Service的方法有两种:

  1.通过kubectl expose创建

#kubectl expose deployment nginx --port=88 --type=NodePort --target-port=80 --name=nginx-service
 
这一步说是将服务暴露出去,实际上是在服务前面加一个负载均衡,因为pod可能分布在不同的结点上。
–port:暴露出去的端口
–type=NodePort:使用结点+端口方式访问服务
–target-port:容器的端口
–name:创建service指定的名称

      2.通过yaml文件创建

  创建一个名为hostnames-yaohong的服务,将在端口80接收请求并将链接路由到具有标签选择器是app=hostnames的pod的9376端口上。使用kubectl creat来创建serivice

1

2

3

4

5

6

7

8

9

10

11

12

apiVersion: v1

kind: Service

metadata:

  name: hostnames-yaohong

spec:

  selector:

    app: hostnames

  ports:

  - name: default

    protocol: TCP

    port: 80     //该服务的可用端口

    targetPort: 9376    //具有app=hostnames标签的pod都属于该服务

5.1.1.3.检测服务

  使用如下命令来检查服务:

1

2

3

$ kubectl get svc

NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE

kubernetes   ClusterIP   10.187.0.1           443/TCP   18d

5.1.1.4.在运行的容器中远程执行命令

  使用kubectl exec 命令来远程执行容器中命令

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

$ kubectl -n kube-system exec coredns-7b8dbb87dd-pb9hk -- ls /

bin

coredns

dev

etc

home

lib

media

mnt

proc

root

run

sbin

srv

sys

tmp

usr

var

双横杠(--)代表kubectl命令项的结束,在双横杠后面的内容是指pod内部需要执行的命令。

 

5.2.连接集群外部的服务

5.2.1.介绍服务endpoint

服务并不是和pod直接相连的,介于他们之间的就是Endpoint资源。

Endpoint资源就是暴露一个服务的IP地址和端口列表。

通过service查看endpoint方法如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

$ kubectl -n kube-system get svc kube-dns

NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE

kube-dns   ClusterI

P   10.187.0.2           53/UDP,53/TCP   19d

 

$ kubectl -n kube-system describe svc kube-dns

Name:              kube-dns

Namespace:         kube-system

Labels:            addonmanager.kubernetes.io/mode=Reconcile

                   k8s-app=kube-dns

                   kubernetes.io/cluster-service=true

                   kubernetes.io/name=CoreDNS

Annotations:       kubectl.kubernetes.io/last-applied-configuration:

                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"prometheus.io/scrape":"true"},"labels":{"addonmanager.kubernetes.io/mode":...

                   prometheus.io/scrape: true

Selector:          k8s-app=kube-dns

Type:              ClusterIP

IP:                10.187.0.2

Port:              dns  53/UDP

TargetPort:        53/UDP

Endpoints:         10.186.0.2:53,10.186.0.3:53     //代表服务endpoint的pod的ip和端口列表

Port:              dns-tcp  53/TCP

TargetPort:        53/TCP

Endpoints:         10.186.0.2:53,10.186.0.3:53

Session Affinity:  None

Events:           

  

直接查看endpoint信息方法如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

#kubectl -n kube-system get endpoints kube-dns

NAME       ENDPOINTS                                               AGE

kube-dns   10.186.0.2:53,10.186.0.3:53,10.186.0.2:53 + 1 more...   19d

 

#kubectl -n kube-system describe  endpoints kube-dns

Name:         kube-dns

Namespace:    kube-system

Labels:       addonmanager.kubernetes.io/mode=Reconcile

              k8s-app=kube-dns

              kubernetes.io/cluster-service=true

              kubernetes.io/name=CoreDNS

Annotations: 

Subsets:

  Addresses:          10.186.0.2,10.186.0.3

  NotReadyAddresses: 

  Ports:

    Name     Port  Protocol

    ----     ----  --------

    dns      53    UDP

    dns-tcp  53    TCP

 

Events: 

  

5.2.2.手动配置服务的endpoint

 如果创建pod时不包含选择器,则k8s将不会创建endpoint资源。这样就需要创建endpoint来指的服务的对应的endpoint列表。

service中创建endpoint资源,其中一个作用就是用于service知道包含哪些pod。

【k8s】——Kubernetes知识盘点_第4张图片

5.2.3.为外部服务创建别名

 除了手动配置来访问外部服务外,还可以使用完全限定域名(FQDN)访问外部服务。

1

2

3

4

5

6

apiVersion: v1

kind: Service

metadata:

  name: Service-yaohong

spec:

  type: ExternalName                     //代码的type被设置成了ExternalName

1

externalName: someapi.somecompany.com    // 实际服务的完全限定域名(FQDN)
port: - port: 80

  服务创建完成后,pod可以通过external-service.default.svc.cluster.local域名(甚至是external-service)连接外部服务。

5.3.将服务暴露给外部客户端

有3种方式在外部访问服务:

  1.将服务的类型设置成NodePort;

  2.将服务的类型设置成LoadBalance;

  3.创建一个Ingress资源。

5.3.1.使用nodeport类型的服务

NodePort 服务是引导外部流量到你的服务的最原始方式。NodePort,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。

【k8s】——Kubernetes知识盘点_第5张图片

 

YAML 文件类似如下:

1

2

3

4

5

6

7

8

9

10

11

12

apiVersion: v1

kind: Service

metadata:

  name: Service-yaohong

spec:

  type: NodePort  //为NodePort设置服务类型

  ports:

  - port: 80 

    targetPort: 8080

    nodeport: 30123    //通过集群节点的30123端口可以访问服务

  selector:

    app: yh

这种方法有许多缺点:

  1.每个端口只能是一种服务

  2.端口范围只能是 30000-32767

如果节点/VM 的 IP 地址发生变化,你需要能处理这种情况

基于以上原因,我不建议在生产环境上用这种方式暴露服务。如果你运行的服务不要求一直可用,或者对成本比较敏感,你可以使用这种方法。这样的应用的最佳例子是 demo 应用,或者某些临时应用。

5.3.2.通过Loadbalance将服务暴露出来

LoadBalancer 服务是暴露服务到 internet 的标准方式。在 GKE 上,这种方式会启动一个 Network Load Balancer[2],它将给你一个单独的 IP 地址,转发所有流量到你的服务。

【k8s】——Kubernetes知识盘点_第6张图片

 

 

通过如下方法来定义服务使用负载均衡

1

2

3

4

5

6

7

8

9

10

11

apiVersion: v1

kind: Service

metadata:

  name: loadBalancer-yaohong

spec:

  type: LoadBalancer  //该服务从k8s集群的基础架构获取负载均衡器

  ports:

  - port: 80 

    targetPort: 8080

  selector:

    app: yh

何时使用这种方式?

如果你想要直接暴露服务,这就是默认方式。所有通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。这个方式的最大缺点是每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址,每个用到的 LoadBalancer 都需要付费,这将是非常昂贵的。

5.4.通过Ingress暴露服务

为什么使用Ingress,一个重要的原因是LoadBalancer服务都需要创建自己的负载均衡器,以及独有的公有Ip地址,而Ingress只需要一个公网Ip就能为许多服务提供访问。

【k8s】——Kubernetes知识盘点_第7张图片

 

5.4.1.创建Ingress资源

Ingress 事实上不是一种服务类型。相反,它处于多个服务的前端,扮演着“智能路由”或者集群入口的角色。

你可以用 Ingress 来做许多不同的事情,各种不同类型的 Ingress 控制器也有不同的能力。

【k8s】——Kubernetes知识盘点_第8张图片

 

 

编写如下ingress.yml文件

1

2

3

4

5

6

7

8

9

10

11

12

kind: Ingress

metadata:

  name: ingressyaohong

spec:

  rules:

  - host: kubia.example.com

    http:

      paths:

      - path: /

        backend:

          serviceName: kubia-nodeport

          servicePort: 80

通过如下命令进行查看ingress

1

# kubectl create  -f ingress.yml

 

5.4.2.通过Ingress访问服务

通过kubectl get ing命令进行查看ingress

1

2

3

# kubectl get ing

NAME             HOSTS               ADDRESS   PORTS   AGE

ingressyaohong   kubia.example.com             80      2m

了解Ingress的工作原理

 

【k8s】——Kubernetes知识盘点_第9张图片

 

何时使用这种方式?

    Ingress 可能是暴露服务的最强大方式,但同时也是最复杂的。Ingress 控制器有各种类型,包括 Google Cloud Load Balancer, Nginx,Contour,Istio,等等。它还有各种插件,比如 cert-manager[5],它可以为你的服务自动提供 SSL 证书。如果你想要使用同一个 IP 暴露多个服务,这些服务都是使用相同的七层协议(典型如 HTTP),那么Ingress 就是最有用的。如果你使用本地的 GCP 集成,你只需要为一个负载均衡器付费,且由于 Ingress是“智能”的,你还可以获取各种开箱即用的特性(比如 SSL、认证、路由等等)。

5.4.3.通过相同的Ingress暴露多少服务

1.将不同的服务映射到相同的主机不同的路径

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

apiVersion: v1

kind: Ingress

metadata:

  name: Ingress-yaohong

spec:

  rules:

  - host: kubia.example.com

    http:

      paths:

      - path: /yh                //对kubia.example.com/yh请求转发至kubai服务

        backend:

          serviceName: kubia

          servicePort:80

      - path: /foo              //对kubia.example.com/foo请求转发至bar服务

        backend:

          serviceName: bar

          servicePort:80

  

2.将不同的服务映射到不同的主机上

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

apiVersion: v1

kind: Ingress

metadata:

  name: Ingress-yaohong

spec:

  rules:

  - host: yh.example.com

    http:

      paths:

      - path: /                //对yh.example.com请求转发至kubai服务

        backend:

          serviceName: kubia

          servicePort:80

  - host: bar.example.com

    http:

      paths:

      - path: /                //对bar.example.com请求转发至bar服务

        backend:

          serviceName: bar

          servicePort:80

 

5.4.4.配置Ingress处理TLS传输

客户端和控制器之间的通信是加密的,而控制器和后端pod之间的通信则不是。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

apiVersion: v1

kind: Ingress

metadata:

  name: Ingress-yaohong

spec:

 tls:                     //在这个属性中包含所有的TLS配置

 - hosts:

   - yh.example.com       //将接收来自yh.example.com的TLS连接

   serviceName: tls-secret     //从tls-secret中获得之前创立的私钥和证书

  rules:

  - host: yh.example.com

    http:

      paths:

      - path: /                //对yh.example.com请求转发至kubai服务

        backend:

          serviceName: kubia

          servicePort:80

5.5.pod就绪后发出信号

5.5.1.介绍就绪探针

就绪探针有三种类型:

1.Exec探针,执行进程的地方。容器的状态由进程的退出状态代码确定。

2.HTTP GET探针,向容器发送HTTP GET请求,通过响应http状态码判断容器是否准备好。

3.TCP socket探针,它打开一个TCP连接到容器的指定端口,如果连接建立,则认为容器已经准备就绪。

     启动容器时,k8s设置了一个等待时间,等待时间后才会执行一次准备就绪检查。之后就会周期性的进行调用探针,并根据就绪探针的结果采取行动。

如果某个pod未就绪成功,则会从该服务中删除该pod,如果pod再次就绪成功,则从新添加pod。

与存活探针区别:

  • 就绪探针如果容器未准备就绪,则不会终止或者重启启动。
  • 存活探针通过杀死异常容器,并用新的正常的容器来替代他保证pod正常工作。
  • 就绪探针只有准备好处理请求pod才会接收他的请求。

重要性;

确保客户端只与正常的pod进行交互,并且永远不会知道系统存在问题。

 

5.5.2.向pod添加就绪探针

添加的yml文件如下

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

apiVersion: v1

kind: deployment

...

spec:

  ...

  port:

    containers:

    - name: kubia-yh

        imgress: luksa/kubia

        readinessProbe:

          failureThreshold: 2

          httpGet:

            path: /ping

            port: 80

            scheme: HTTP

          initialDelaySeconds: 30

          periodSeconds: 5

          successThreshold: 1

          timeoutSeconds: 3

相关参数解释如下:

  • initialDelaySeconds:容器启动和探针启动之间的秒数。
  • periodSeconds:检查的频率(以秒为单位)。默认为10秒。最小值为1。
  • timeoutSeconds:检查超时的秒数。默认为1秒。最小值为1。
  • successThreshold:失败后检查成功的最小连续成功次数。默认为1.活跃度必须为1。最小值为1。
  • failureThreshold:当Pod成功启动且检查失败时,Kubernetes将在放弃之前尝试failureThreshold次。放弃生存检查意味着重新启动Pod。而放弃就绪检查,Pod将被标记为未就绪。默认为3.最小值为1。

HTTP探针在httpGet上的配置项:

  • host:主机名,默认为pod的IP。
  • scheme:用于连接主机的方案(HTTP或HTTPS)。默认为HTTP。
  • path:探针的路径。
  • httpHeaders:在HTTP请求中设置的自定义标头。 HTTP允许重复的请求头。
  • port:端口的名称或编号。数字必须在1到65535的范围内

 

模拟就绪探针

1

2

3

4

# kubectl   exec -- curl http://10.187.0.139:80/ping

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0

 

5.6.使用headless服务发现独立的pod

5.6.1.创建headless服务

Headless Service也是一种Service,但不同的是会定义spec:clusterIP: None,也就是不需要Cluster IPService

顾名思义,Headless Service就是没头的Service。有什么使用场景呢?

  • 第一种:自主选择权,有时候client想自己来决定使用哪个Real Server,可以通过查询DNS来获取Real Server的信息。

  • 第二种:Headless Services还有一个用处(PS:也就是我们需要的那个特性)。Headless Service的对应的每一个Endpoints,即每一个Pod,都会有对应的DNS域名;这样Pod之间就可以互相访问。

6.kubernetes  磁盘、PV、PVC

6.1.介绍卷

6.1.1.卷的类型

emptyDir-用于存储临时数据的简单空目录

hostPath-用于将目录从工作节点的文件系统挂载到pod

nfs-挂载到pod中的NFS共享卷。

还有其他的如gitRepo、gcepersistenDisk

6.2.通过卷在容器间共享数据

6.2.1.使用emptyDir卷

卷的生命周期与pod的生命周期项关联,所以当删除pod时,卷的内容就会丢失。

使用empty示例代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

apiVersion: v1

kind: Pod

metadata:

  name: fortune

spec:

  containers:

  - image: luksa/fortune

    name: html-gener

    volumeMounts:

    - name: html

      mountPath: /usr/share/nginx

      readOnly: true

  - image: nginx/aplin

    name: web-service

    volumeMounts:

    - name: html

      mountPath: /usr/share

      readOnly: true

  volumes:

  - name: html                        //一个名为html的单独emptyDir卷,挂载在上面的两个容器中

    emptyDir: {}

6.3.访问工作节点文件系统上的文件

6.3.1.hostPath卷

hostPath是持久性存储,emptyDir卷的内容随着pod的删除而删除。

使用hostPath会发现当删除一个pod,并且下一个pod使用了指向主机上相同路径的hostPath卷,则新pod将会发现上一个pod留下的数据,但前提是必须将其调度到与第一个pod相同的节点上。

所以当你使用hostPath时请务必考虑清楚,当重新起一个pod时候,必须要保证pod的节点与之前相同。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

apiVersion: v1

kind: Pod

metadata:

  name: test-pd

spec:

  containers:

  - image: k8s.gcr.io/test-webserver

    name: test-container

    volumeMounts:

    - mountPath: /test-pd

      name: test-volume

  volumes:

  - name: test-volume

    hostPath:

      # directory location on host

      path: /data

      # this field is optional

      type: Directory

 

6.4.使用持久化存储

怎样保证pod重新启动后调度到任意一个节点都有相同的数据可用,这就需要做到持久化存储。

因此必须要将数据存储在某种类型的网络存储(NAS)中。

各种支持的方式不尽相同,例如 GlusterFS 需要创建 Endpoint,Ceph/NFS 之流就没这么麻烦了。

6.4.1.使用NFS存储

以NFS为例,yml代码如下:

【k8s】——Kubernetes知识盘点_第10张图片

 

6.4.2.configmap和secert

secret和configmap可以理解为特殊的存储卷,但是它们不是给Pod提供存储功能的,而是提供了从集群外部向集群内部的应用注入配置信息的功能。ConfigMap扮演了K8S集群中配置中心的角色。ConfigMap定义了Pod的配置信息,可以以存储卷的形式挂载至Pod中的应用程序配置文件目录,从configmap中读取配置信息;也可以基于环境变量的形式,从ConfigMap中获取变量注入到Pod容器中使用。但是ConfigMap是明文保存的,如果用来保存数据库账号密码这样敏感信息,就非常不安全。一般这样的敏感信息配置是通过secret来保存。secret的功能和ConfigMap一样,不过secret是通过Base64的编码机制保存配置信息。

从ConfigMap中获取配置信息的方法有两种:

  • 一种是利用环境变量将配置信息注入Pod容器中的方式,这种方式只在Pod创建的时候生效,这就意味着在ConfigMap中的修改配置信息后,更新的配置不能被已经创建Pod容器所应用。
  • 另一种是将ConfigMap做为存储卷挂载至Pod容器内,这样在修改ConfigMap配置信息后,Pod容器中的配置也会随之更新,不过这个过程会有稍微的延迟。

ConfigMap当作存储卷挂载至Pod中的用法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

apiVersion: v1

kind: Pod

metadata:

  name: pod-configmap-vol-2

  labels:

    name: pod-configmap-vol-2

spec:

  containers:

  - name: myapp

    image: ikubernetes/myapp:v1

    volumeMounts:

    - name: my-cm-www

      mountPath: /etc/nginx/conf.d/       # 将名为my-www的configmap挂载至Pod容器的这个目录下。

  volumes:

  - name: my-cm-www

    configMap:               # 存储卷类型选configMap

  secert的方法类似,只是secert对数据进行了加密

6.5.从底层存储技术解耦pod

6.5.1.介绍持久卷和持久卷声明

  当集群用户需要在其pod中使用持久化存储时,他们首先创建持久化声明(PVC)清单,指定所需要的最低容量要求,和访问模式,然后用户将持久卷声明清单提交给kubernetes API服务器,kubernetes将找到可以匹配的持久卷并将其绑定到持久卷声明。

  持久卷声明可以当做pod中的一个卷来使用,其他用户不能使用相同的持久卷,除非先通过删除持久卷声明绑定来释放。

6.5.2.创建持久卷

下面创建一个 PV mypv1,配置文件pv1.yml 如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

apiVersion: v1

kind: PersistentVolume

metadata:

  name: yh_pv1

spec:

  capacity:

    storage: 1Gi                //capacity 指定 PV 的容量为 1G

  accessModes:                 //accessModes 指定访问模式为 ReadWriteOnce

    - ReadWriteOnce           

  persistentVolumeReclaimpolicy: Recycle  //persistentVolumeReclaimPolicy 指定当 PV 的回收策略为 Recycle

  storageClassName: nfs         //storageClassName 指定 PV 的 class 为 nfs。相当于为 PV 设置了一个分类,PVC 可以指定 class 申请相应 class 的 PV。

  nfs:

    path: /nfs/data             //指定 PV 在 NFS 服务器上对应的目录

    server: 10.10.0.11

1.accessModes 指定访问模式为 ReadWriteOnce,支持的访问模式有:

  ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
  ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
  ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点。

2.persistentVolumeReclaimPolicy 指定当 PV 的回收策略为 Recycle,支持的策略有:
  Retain – 需要管理员手工回收。
  Recycle – 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
  Delete – 删除 Storage Provider 上的对应存储资源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。

 

创建 pv

1

2

# kubectl apply -f pv1.yml

persistentvolume/yh-pv1 created

 

查看pv:

1

2

3

# kubectl get pv

NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE

yh-pv1   1Gi        RWO            Recycle          Available           nfs                     17m

  

STATUS 为 Available,表示 yh-pv1就绪,可以被 PVC 申请。

6.5.3.通过持久卷声明来获取持久卷

接下来创建 PVC mypvc1,配置文件 pvc1.yml 如下:

1

2

3

4

5

6

7

8

9

10

11

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: yh-pvc

spec:

  accessModes:

    - ReadWriteOnce

  resources:

    requests:

      storage: 1Gi

  storageClassName: nfs

PVC 就很简单了,只需要指定 PV 的容量,访问模式和 class。

执行命令创建 mypvc1

1

2

# kubectl apply -f pvc1.yml

persistentvolumeclaim/yh-pvc created

查看pvc

1

2

3

# kubectl get pvc

NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE

yh-pvc   Bound    yh-pv1   1Gi        RWO            nfs            64s

 

从 kubectl get pvc 和 kubectl get pv 的输出可以看到 yh-pvc1 已经 Bound 到yh- pv1,申请成功。

 

1

2

3

# kubectl get pv

NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE

yh-pv1   1Gi        RWO            Recycle          Bound    default/yh-pvc   nfs                     47m

  

6.5.4.在pod中使用持久卷声明

上面已经创建好了pv和pvc,pod中直接使用这个pvc即可

【k8s】——Kubernetes知识盘点_第11张图片

与使用普通 Volume 的格式类似,在 volumes 中通过 persistentVolumeClaim 指定使用 mypvc1 申请的 Volume。

 通过命令创建mypod1

【k8s】——Kubernetes知识盘点_第12张图片

可见,在 Pod 中创建的文件 /mydata/hello 确实已经保存到了 NFS 服务器目录 /nfsdata中。

如果不再需要使用 PV,可用删除 PVC 回收 PV。

6.5.5.回收持久卷

当 PV 不再需要时,可通过删除 PVC 回收。

未删除pvc之前  pv的状态是Bound

删除pvc之后pv的状态变为Available,,此时解除绑定后则可以被新的 PVC 申请。

/nfsdata文件中的文件被删除了

 

因为 PV 的回收策略设置为 Recycle,所以数据会被清除,但这可能不是我们想要的结果。如果我们希望保留数据,可以将策略设置为 Retain

【k8s】——Kubernetes知识盘点_第13张图片

通过 kubectl apply 更新 PV:

 

回收策略已经变为 Retain,通过下面步骤验证其效果:

 【k8s】——Kubernetes知识盘点_第14张图片

① 重新创建 mypvc1

② 在 mypv1 中创建文件 hello

③ mypv1 状态变为 Released

④ PV 中的数据被完整保留。

虽然 mypv1 中的数据得到了保留,但其 PV 状态会一直处于 Released,不能被其他 PVC 申请。为了重新使用存储资源,可以删除并重新创建 mypv1。删除操作只是删除了 PV 对象,存储空间中的数据并不会被删除。

 【k8s】——Kubernetes知识盘点_第15张图片

新建的 mypv1 状态为 Available,已经可以被 PVC 申请。

PV 还支持 Delete 的回收策略,会删除 PV 在 Storage Provider 上对应存储空间。NFS 的 PV 不支持 Delete,支持 Delete 的 Provider 有 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。

6.6.持久卷的动态配置

6.6.1.通过StorageClass资源定义可用存储类型

前面的例子中,我们提前创建了 PV,然后通过 PVC 申请 PV 并在 Pod 中使用,这种方式叫做静态供给(Static Provision)。

与之对应的是动态供给(Dynamical Provision),即如果没有满足 PVC 条件的 PV,会动态创建 PV。相比静态供给,动态供给有明显的优势:不需要提前创建 PV,减少了管理员的工作量,效率高。

动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建 PV,下面是两个例子。

StorageClass standard

【k8s】——Kubernetes知识盘点_第16张图片

StorageClass slow

【k8s】——Kubernetes知识盘点_第17张图片

这两个 StorageClass 都会动态创建 AWS EBS,不同在于 standard 创建的是 gp2 类型的 EBS,而 slow 创建的是 io1 类型的 EBS。不同类型的 EBS 支持的参数可参考 AWS 官方文档。

StorageClass 支持 Delete 和 Retain 两种 reclaimPolicy,默认是 Delete

与之前一样,PVC 在申请 PV 时,只需要指定 StorageClass 和容量以及访问模式,比如:

 【k8s】——Kubernetes知识盘点_第18张图片

除了 AWS EBS,Kubernetes 支持其他多种动态供给 PV 的 Provisioner,完整列表请参考 https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner

 

6.6.2.PV&&PVC在应用在mysql的持久化存储

下面演示如何为 MySQL 数据库提供持久化存储,步骤为:

  1. 创建 PV 和 PVC。

  2. 部署 MySQL。

  3. 向 MySQL 添加数据。

  4. 模拟节点宕机故障,Kubernetes 将 MySQL 自动迁移到其他节点。

  5. 验证数据一致性。

首先创建 PV 和 PVC,配置如下:

mysql-pv.yml

 【k8s】——Kubernetes知识盘点_第19张图片

mysql-pvc.yml

【k8s】——Kubernetes知识盘点_第20张图片

创建 mysql-pv 和 mysql-pvc

 【k8s】——Kubernetes知识盘点_第21张图片

接下来部署 MySQL,配置文件如下:

 【k8s】——Kubernetes知识盘点_第22张图片

 PVC mysql-pvc Bound 的 PV mysql-pv 将被 mount 到 MySQL 的数据目录 var/lib/mysql

【k8s】——Kubernetes知识盘点_第23张图片

MySQL 被部署到 k8s-node2,下面通过客户端访问 Service mysql

kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword

 

更新数据库:

【k8s】——Kubernetes知识盘点_第24张图片

① 切换到数据库 mysql。

② 创建数据库表 my_id。

③ 插入一条数据。

④ 确认数据已经写入。

 关闭 k8s-node2,模拟节点宕机故障。

 【k8s】——Kubernetes知识盘点_第25张图片

验证数据的一致性:

 由于node2节点已经宕机,node1节点接管了这个任务。

通过kubectl run 命令 进入node1的这个pod里,查看数据是否依旧存在

【k8s】——Kubernetes知识盘点_第26张图片

 

MySQL 服务恢复,数据也完好无损。

7.kubernetes ConfigMap和Secret:配置应用程序

7.1.配置容器化应用程序

7.2.向容器传递命令行参数

7.2.1.待Docker中定义命令与参数

1.了解ENTRYPOINT与CMD

  ENTRYPOINT定义容器启动时被调用的可以执行程序

  CMD指定传递给ENTRYP的参数

dockerfile 内容如下

1

2

3

4

5

6

FROM daocloud.io/centos:latest

 

ADD aaa /usr/local/aaa

 

CMD ["-f","/var/log/aa.log"]

ENTRYPOINT ["tail"]

当启动镜像时,容器启动时执行如下命令:tail -f /var/log/aa.log

或者在docker run 中指定,arguments会覆盖CMD中内容

7.2.2.在kubernetes中覆盖命令行和参数

 在k8s中定义容器时,镜像的ENTRYPOINT和CMD都可以被覆盖,仅需在容器定义中设置熟悉command和args的值

对应参数如下:

Docker kubernetes 描述
ENTRYPOINT command 容器中运行的可执行文件
CMD args 传给可执行文件的参数

 

 

 

 

相关yml代码如下:

1

2

3

4

5

6

kind: pod

spec:

  containers:

  - image: some/image

    command: ["/bin/command"]

    args: ["args1","args2","args3"]

7.3.为容器设置环境变量

7.3.1.在容器定义中指定环境变量

与容器的命令和参数设置相同,环境变量列表无法在pod创建后被修改。

在pod的yml文件中设置容器环境变量代码如下:

1

2

3

4

5

6

7

8

kind: pod

spec:

  containers:

  - image: luksa/fortune:env

    env:

    - name: INTERVAL

      value: "30"

    name: value-test-yh

  

7.3.2.在环境变量值中引用其他环境变量

使用$( VAR )引用环境变量,

相关ym代码如下:

1

2

3

4

5

env:

- name: FIRST_VAR

  value: "foo"

- name: SECOND_VAR

  value: "$(FIRST_VAR)bar"   //最终变量值为foobar

 

7.4.利用ConfigMap解耦配置

7.4.1.ConfigMap介绍

kubernetes允许将配置选项分离到独立的资源对象ConfigMap中,本质上就是一个键/值对映射,值可以是短字面变量,也可以是完整的配置文件。

应用无须直接读取ConfigMap,甚至根本不需要知道其是否存在。

映射的内容通过环境变量或者卷文件的形式传递给容器,而并非直接传递给容器,命令行参数的定义中也是通过$(ENV_VAR)语法变量

7.4.2.创建ConfigMap

使用kubectl creat configmap创建ConfigMap中间不用加-f。

1.使用指令创建ConfigMap

1

#kubectl creat configmap configmap-yaohong --from-literal=foo=bar --from-literal=sleep-interval=25

2.从文件内容创建ConfigMap条目

1

#kubectl create configmap my-conf-yh --from-file=config-file.conf

使用如下命令,会将文件内容存储在自定义的条目下。与字面量使用相同

1

#kubectl create configmap my-conf-yh --from-file=customkey=config-file.conf

3.从文件夹创建ConfigMap

1

#kubectl create configmap my-conf-yh --from-file=/path/to/dir

4.合并不同选项

1

2

3

4

#kubectl create configmap my-conf-yh

  --from-file=/path/to/dir/

  --from-file=bar=foobar.conf

  --from-literal=some=thing

  

5.获取ConfigMap

1

#kubectl -n get configmap

  

7.4.3.给容器传递ConfigMap条目作为环境变量

引用环境变量中的参数值给当前变量

1

2

3

4

5

6

7

8

9

10

11

12

13

apiVersion: v1

kind: pod

metadata:

  name: fortune-env-from-configmap

spec:

  containers:

  - image: luksa/fortune:env

    env:

    - name: INTERVAL                  //设置环境变量

      valueFrom:

        configMapkeyRef:

          name: fortune-configmap    

          key: sleep-interval         //变量的值取自fortune-configmap的slee-interval对应的值

  

7.4.4.一次性传递ConfigMap的所有条目作为环境变量

1

2

3

4

5

6

7

8

9

10

11

apiVersion: v1

kind: pod

metadata:

  name: fortune-env-from-configmap

spec:

  containers:

  - image: luksa/fortune:env

    envFrom:

    - prefix: CONFIG_

      confgMapRef:

        name: my-confg-map    //引用my-config-map的ConfigMap并在变量前面都加上CONFIG_

  

7.4.5.使用ConfigMap卷将条目暴露为文件

apiVersion: v1
kind: pod
metadata:
  name: configmap-volume-yh
spec:
  containers:
  - image: nginx:aplin
    name: web-server
    volumeMounts:
    ...
    - name: config
      defaultMode: "6600"     //设置文件的权限为rw-rw       mountPath: /etc/nginx/con.conf
      subPath: my.conf        //subPath字段可以用于挂载卷中某个独立的文件或者文件夹,而且不覆盖该卷下其他文件     ...   volume:   ...   - name: config     configMap:       name: fortune-config     //引用fortune-config configMap的卷,然后挂载在/etc/nginx/conf.d

  可以使用如下命令查看到/etc/nginx/conf.d文件下面包含fortune-config

1

#kubectl exec config-volume-yh -c web-server ls /etc/nginx/conf.d

7.5.使用Secert给容器传递敏感数据

7.5.1.介绍Secert

Secret结构和ConfigMap类似,均是键/值对的映射。

使用方法也和ConfigMap一样,可以:

  1.将Secret条目作为环境变量传递给容器,

  2.将Secret条目暴露为卷中文件

 ConfigMap存储非敏感的文本配置数据,采用Secret存储天生敏感的数据

7.5.2.默认令牌Secret

1.查看secret

1

2

3

# kubectl get secrets

NAME                  TYPE                                  DATA   AGE

default-token-x9cjb   kubernetes.io/service-account-token   3      78d

2.描述secret

1

2

3

4

5

6

7

8

9

10

11

12

13

14

# kubectl describe secrets default-token-x9cjb

Name:         default-token-x9cjb

Namespace:    default

Labels:      

Annotations:  kubernetes.io/service-account.name: default

              kubernetes.io/service-account.uid: 64a41a09-98ce-11e9-9fa5-fa163e6fdb6b

 

Type:  kubernetes.io/service-account-token

 

Data

====

token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5lduaW8vc2VydmljZTxCv6HdtP-ZW3ZC2IKKR5YBhaokFIl35mix79pU4Ia2pJ_fuPTBGNyrCHyNQYH4ex5DhND3_b2puQmn8RSErQ

ca.crt:     1298 bytes

namespace:  7 bytes

 

7.5.3.创建Secret

1.创建一个名为https-yh的generic secret

1

#kubectl create secret generic https-yh --from-file=https.key  --from-file=https.cert  --from-file=foo

 

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

$ echo -n 'admin' | base64
YWRtaW4=
$ echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

yaml文件内容:

创建:

$ kubectl create -f ./secret.yaml
secret "mysecret" created

 

解析Secret中内容

$ kubectl get secret mysecret -o yaml
apiVersion: v1
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm
kind: Secret
metadata:
  creationTimestamp: 2016-01-22T18:41:56Z
  name: mysecret
  namespace: default
  resourceVersion: "164619"
  selfLink: /api/v1/namespaces/default/secrets/mysecret
  uid: cfee02d6-c137-11e5-8d73-42010af00002
type: Opaque

base64解码:

$ echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
1f2d1e2e67df

  

7.5.4.对比ConfigMap与Secret

Secret的条目内容会进行Base64格式编码,而ConfigMap直接以纯文本展示。

1.为二进制数据创建Secret

  Base64可以将二进制数据转换为纯文本,并以YAML或Json格式进行展示

  但要注意Secret的大小限制是1MB

2.stringDate字段介绍

  Secret可以通过StringDate字段设置条目的纯文本

1

2

3

4

5

6

7

kind: Secret

apiVersion: v1

stringDate:

  foo: plain txt

date:

  https.cert: HGIOPUPSDF63456BJ3BBJL34563456BLKJBK634563456BLBKJBLKJ63456BLK3456LK

  http.key: OHOPGPIU42342345OIVBGOI3456345OVB6O3456BIPO435B6IPU345UI

  

7.5.5.在pod中使用Secret

secret可以作为数据卷挂载或者作为环境变量暴露给Pod中的容器使用,也可以被系统中的其他资源使用。比如可以用secret导入与外部系统交互需要的证书文件等。

在Pod中以文件的形式使用secret

  1. 创建一个Secret,多个Pod可以引用同一个Secret
  2. 修改Pod的定义,在spec.volumes[]加一个volume,给这个volume起个名字,spec.volumes[].secret.secretName记录的是要引用的Secret名字
  3. 在每个需要使用Secret的容器中添加一项spec.containers[].volumeMounts[],指定spec.containers[].volumeMounts[].readOnly = truespec.containers[].volumeMounts[].mountPath要指向一个未被使用的系统路径。
  4. 修改镜像或者命令行使系统可以找到上一步指定的路径。此时Secret中data字段的每一个key都是指定路径下面的一个文件名

下面是一个Pod中引用Secret的列子:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret

每一个被引用的Secret都要在spec.volumes中定义

如果Pod中的多个容器都要引用这个Secret那么每一个容器定义中都要指定自己的volumeMounts,但是Pod定义中声明一次spec.volumes就好了。

映射secret key到指定的路径

可以控制secret key被映射到容器内的路径,利用spec.volumes[].secret.items来修改被映射的具体路径

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:
      - key: username
        path: my-group/my-username

发生了什么呢?

  • username被映射到了文件/etc/foo/my-group/my-username而不是/etc/foo/username
  • password没有变

Secret文件权限

可以指定secret文件的权限,类似linux系统文件权限,如果不指定默认权限是0644,等同于linux文件的-rw-r--r--权限

设置默认权限位

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      defaultMode: 256

 

上述文件表示将secret挂载到容器的/etc/foo路径,每一个key衍生出的文件,权限位都将是0400

由于JSON不支持八进制数字,因此用十进制数256表示0400,如果用yaml格式的文件那么就很自然的使用八进制了

同理可以单独指定某个key的权限

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:
      - key: username
        path: my-group/my-username
        mode: 511

 

从volume中读取secret的值

值得注意的一点是,以文件的形式挂载到容器中的secret,他们的值已经是经过base64解码的了,可以直接读出来使用。

$ ls /etc/foo/
username
password
$ cat /etc/foo/username
admin
$ cat /etc/foo/password
1f2d1e2e67df

被挂载的secret内容自动更新

也就是如果修改一个Secret的内容,那么挂载了该Secret的容器中也将会取到更新后的值,但是这个时间间隔是由kubelet的同步时间决定的。最长的时间将是一个同步周期加上缓存生命周期(period+ttl)

特例:以subPath形式挂载到容器中的secret将不会自动更新

以环境变量的形式使用Secret

  1. 创建一个Secret,多个Pod可以引用同一个Secret
  2. 修改pod的定义,定义环境变量并使用env[].valueFrom.secretKeyRef指定secret和相应的key
  3. 修改镜像或命令行,让它们可以读到环境变量
apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
  - name: mycontainer
    image: redis
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
  restartPolicy: Never

容器中读取环境变量,已经是base64解码后的值了:

$ echo $SECRET_USERNAME
admin
$ echo $SECRET_PASSWORD
1f2d1e2e67df

使用imagePullSecrets

创建一个专门用来访问镜像仓库的secret,当创建Pod的时候由kubelet访问镜像仓库并拉取镜像,具体描述文档在 这里

设置自动导入的imagePullSecrets

可以手动创建一个,然后在serviceAccount中引用它。所有经过这个serviceAccount创建的Pod都会默认使用关联的imagePullSecrets来拉取镜像,

9.deployment:声明式的升级应用

 

Deployment 的控制器,实际上控制的是 ReplicaSet 的数目,以及每个 ReplicaSet 的属性。

而一个应用的版本,对应的正是一个 ReplicaSet;这个版本应用的 Pod 数量,则由 ReplicaSet 通过它自己的控制器(ReplicaSet Controller)来保证。

通过这样的多个 ReplicaSet 对象,Kubernetes 项目就实现了对多个“应用版本”的描述。

                               【k8s】——Kubernetes知识盘点_第27张图片

9.1.使用RC实现滚动升级

1

#kubectl rolling-update kubia-v1 kubia-v2 --image=luksa/kubia:v2

  使用kubia-v2版本应用来替换运行着kubia-v1的RC,将新的复制控制器命名为kubia-v2,并使用luksa/kubia:v2最为镜像。

  升级完成后使kubectl describe rc kubia-v2查看升级后的状态。

  为什么现在不再使用rolling-update?

  1.直接更新pod和RC的标签并不是一个很的方案;

  2.kubectl只是执行升级中的客户端,但如果执行kubectl过程中是去了网络连接,升级将会被中断,pod和RC将会处于一个中间的状态,所以才有了Deployment资源的引入。

9.2.使用Deployment声明式的升级应用

  Rs替代Rc来复制个管理pod。

  创建Deployment前确保删除所有的RC和pod,但是暂时保留Service,

  kubectl delete rc --all

  创建Deployment

1

2

3

4

5

6

7

8

#kubectl create -f kubectl.depl-v1.yaml --record  //--record可以记录历史版本

 

#查看Deployment的相关信息

#kubectl get deployment

#kubectl describe deployment

 

#查看部署状态:

#kubectl rollout status deployment kubia

  

9.3.触发deployment升级

1

2

3

4

#kubectl edit deployment kubia //修改完后资源对象会被更新

#kubectl patch deployment kubia -p '{...}' //只能包含想要更新的字段

#kubectl apply -f kubia-deploy-v2.yml //如果yml中定义的资源不存在,会自动被创建

#kubectl replace -f kubia-deploy-v2.yml //如果yml中定义的资源不存在,则会报错

  修改configmap并不会触发升级,如果想要触发,可以创建新的configmap并修改pod模板引用新的configmap。

9.4.回滚deployment

  在上述升级deployment过程中可以使用如下命令来观察升级的过程

1

#kubectl rollout status deployment kubia

  如果出现报错,如何进行停止?可以使用如下命令进行回滚到先前部署的版本

1

#kubectl rollout undo deployment kubia

  如何显示deployment的历史版本?

1

#kubectl rollout history deployment kubia

  如何回滚到特定的版本?

1

#kubectl rollout undo deployment kubia --to-revision=1

9.5.控制滚动升级的速率

  在deployment的滚动升级过程中,有两个属性决定一次替换多少个pod:maxSurge、maxUnavailable,可以通过strategy字段下的rollingUpdate的属性来配置,

  maxSurge:决定期望的副本数,默认值为25%,如果副本数设置为4个,则在滚动升级过程中,不会运行超过5个pod。

  maxUnavaliable: 决定允许多少个pod处于不可用状态,默认值为25%,如果副本数为4,那么只能有一个pod处于不可用状态,

       默认情况下如果10分钟内没有升级完成,将被视为失败,如果要修改这个参数可以使用kubectl describe deploy kubia 查看到一条ProgressDeadline-Exceeded的记录,可以修改此项参数修改判断时间。

 

9.6.金丝雀发布和蓝绿发布

金丝雀部署:优先发布一台或少量机器升级,等验证无误后再更新其他机器。优点是用户影响范围小,不足之处是要额外控制如何做自动更新。
蓝绿部署:2组机器,蓝代表当前的V1版本,绿代表已经升级完成的V2版本。通过LB将流量全部导入V2完成升级部署。优点是切换快速,缺点是影响全部用户。

10.Statefulset:部署有状态的多副本应用

10.1.什么是Statefulset

  StatefulSet是Kubernetes提供的管理有状态应用的负载管理控制器API。

       特点:

  1.具有固定的网络标记(主机名)

  2.具有持久化存储

  3.需要按顺序部署和扩展

  4.需要按顺序终止和删除

  5.需要按顺序滚动和更新

 

  有状态应用:这种实例之间有不对等关系,以及实例对外部数据有依赖关系的应用,就被称为“有状态应用”(Stateful Application)。

10.2.statefulset的创建

  statefulset的创建顺序从0到N-1,终止顺序则相反,如果需要对satateful扩容,则之前的n个pod必须存在,如果要终止一个pod,则他的后续pod必须全部终止。

       创建statefulset

1

#kubectl create -f ss-nginx.yml

  查看statefulset

1

#kubectl get statefulset

  

  statefulset会使用一个完全一致的pod来替换被删除的pod。

  statefulset扩容和缩容时,都会删除最高索引的pod,当这个pod完全被删除后,才回删除拥有次高索引的pod。

10.3.statefulset中发现伙伴的节点

  通过DNS中SRV互相发现。

10.4.更新statefulset

1

#kuebctl edit statefulset kubia

  但修改后pod不会自动 被更新,需要手动delete pod后会重新调度更新。

11.k8s部分组件介绍

11.1.了解调度器

  调度器指定pod运行在哪个集群节点上。

  调度器不会命令选中节点取运行pod,调度器做的就是通过api服务器更新pod的定义。然后api服务器再去通知kubelet该pod已经被调用。当目标节点的kubelet发现该pod被调度到本节点,就会创建并运行pod容器。

  【k8s】——Kubernetes知识盘点_第28张图片

调度方法:

  1.通过算法过滤所有节点,找到最优节点

   2.查找可用节点

    (1)是否满足对硬件的资源要求

    (2)节点是否资源耗尽

    (3)pod是否要求被调度到指定的节点、

    (4)是否和要求的lable一致

    (5)需求端口是否被占用

    (6)是否有符合要求的存储卷

    (7)是否容忍节点的污染

 

11.2.介绍控制器管理器中运行的控制器

(1)RC控制器

  启动RC资源的控制器叫做Replication管理器。

  RC的操作可以理解为一个无限的循环,每次循环,控制器都会查找符合其pod选择器的pod数量,并且将该数值和期望的复制集数量做比较。

(2)RS控制器

  与RC类似

(3)DaemonSet以及job控制器

  从他们各自资源集中定义pod模板创建pod资源,

(4)Deployment控制器

  Deployment控制器负责使deployment的实际状态与对应的Deployment API对象期望状态同步。

  每次Deployment对象修改后,Deployment控制器会滚动升级到新的版本。通过创建ReplicaSet,然后按照Deployment中定义的策略同时伸缩新、旧RelicaSet,直到旧pod被新的替代。

(5)StatefulSet控制器

  StatefulSet控制器会初始化并管理每个pod实例的持久声明字段。

(6)Node控制器

  Node控制器管理Node资源,描述了集群的工作节点。

(7)Service控制器

  Service控制器就是用来在loadBalancer类型服务被创建或删除,从基础设施服务请求,释放负载均衡器的。

  当Endpoints监听到API服务器中Aervice资源和pod资源发生变化时,会对应修改、创建、删除Endpoints资源。

 (8)Endpoint资源控制器

  Service不会直接连接到pod,而是通过一个ip和端口的列表,EedPoint管理器就是监听service和pod的变化,将ip和端口更新endpoint资源。

 【k8s】——Kubernetes知识盘点_第29张图片

(9)Namespace控制器

  当收到删除namespace对象的通知时,控制器通过API服务群删除后所有属于该命名空间的资源。

(10)PV控制器

  创建一个持久卷声明时,就找到一个合适的持久卷进行绑定到声明。

 

11.3.kubelet做了什么

了解kubelet的工作内容

  简单来说,就是负责所有运行在工作节点上的全部内容。

  第一个任务,在api服务器中创建一个node资源来注册该节点;第二任务,持续监控api服务器是否把该节点分配给pod;第三任务,启动pod;第四任务,持续监控运行的容器,向api服务器报告他们的状态,事件和资源消耗。

  第五任务,kubelet也是运行容器的存活探针的组件,当探针报错时,他会重启容器;第六任务,当pod从api服务器删除时,kubelet终止容器,并通知服务器pod已经终止。

 

11.1.7.kube-proxy的作用

  service是一组pod的服务抽象,相当于一组pod的LB,负责将请求分发给对应的pod。service会为这个LB提供一个IP,一般称为cluster IP。
  kube-proxy的作用主要是负责service的实现,具体来说,就是实现了内部从pod到service和外部的从node port向service的访问。

   kube-proxy有两种代理模式,userspace和iptables,目前都是使用iptables。

11.4.k8s如何使用etcd

   etcd是一个响应快,分布式,一致的key-value存储。

  是k8s存储集群状态和元数据唯一的地方,具有乐观锁特性,

   

1

2

3

关于乐观锁并发控制

    乐观锁并发控制(有时候指乐观锁),是指一段数据包含一个版本数字,而不是锁住该段数据并阻止读写操作。每当更新数据,版本数就会增加。当更新数据时,版本就会增加。当更新数据时,就会检查版本值是否在客户端读取数据时间和提交时间之间被增加过。如果增加过,那么更新会被拒绝,客户端必须重新读取新数据,重新尝试更新。

    两个客户端尝试更新同一个数据条目,只有一个会被更新成功。

资源如何存储在etcd中

  flannel操作etcd使用的是v2的API,而kubernetes操作etcd使用的v3的API,所以在下面我们执行etcdctl的时候需要设置ETCDCTL_API环境变量,该变量默认值为2。

  etcd是使用raft一致性算法实现的,是一款分布式的一致性KV存储,主要用于共享配置和服务发现。

  Etcd V2和V3之间的数据结构完全不同,互不兼容。

 

确保etcd集群一致性

  一致性算法要求大部分节点参与,才能进行到下一个状态,需要有过半的节点参与状态的更新,所以导致etcd的节点必须为奇数个。

 

11.5.API Server

  Kubernetes APIserver为API对象验证和配置数据,这些对象包含Pod,Service,ReplicationController等等。API Server提供REST操作以及前端到集群的共享状态,所有其它组件可以通过这些共享状态交互。

  1.API提供RESTful API的形式,进行CRUD(增删查改)集群状态

  2.进行校验

  3.处理乐观锁,用于处理并发问题,

  4.认证客户端

    (1)通过认证插件认证客户端

    (2)通过授权插件认证客户端

    (3)通过准入插件验证AND/OR修改资源请求

  API服务器如何通知客户端资源变更

    API服务器不会去创建pod,同时他不会去管理服务的端点,

    它做的是,启动控制器,以及一些其他的组件来监控一键部署的资源变更,是得组件可以再集群元数据变化时候执行任何需要做的任务,

12.kubernetes API服务器的安全防护

12.1.了解认证机制

  启动API服务器时,通过命令行选项可以开启认证插件。

12.1.1.用户和组

了解用户:

  分为两种连接到api服务器的客户端:

  1.真实的人

  2.pod,使用一种称为ServiceAccount的机制

了解组:

  认证插件会连同用户名,和用户id返回组,组可以一次性给用户服务多个权限,不用单次赋予,

  system:unauthenticated组:用于所有认证插件都不会认证客户端身份的请求。

  system:authenticated组:会自动分配给一个成功通过认证的用户。

  system:serviceaccount组:包含 所有在系统中的serviceaccount。

  system:serviceaccount:组:包含了所有在特定命名空间中的serviceAccount。

12.1.2 ServiceAccount介绍

  每个pod中都包含/var/run/secrets/kubernetes.io/serviceaccount/token文件,如下图所示,文件内容用于对身份进行验证,token文件持有serviceaccount的认证token。

  

  应用程序使用token去连接api服务器时,认证插件会对serviceaccount进行身份认证,并将serviceaccount的用户名传回到api服务器内部。

       serviceaccount的用户名格式如下:

  system:serviceaccount::

  ServiceAccount是运行在pod中的应用程序,和api服务器身份认证的一中方式。

了解ServiceAccount资源

  ServiceAcount作用在单一命名空间,为每个命名空间创建默认的ServiceAccount。

       

  多个pod可以使用相同命名空间下的同一的ServiceAccount,

 ServiceAccount如何与授权文件绑定

   在pod的manifest文件中,可以指定账户名称的方式,将一个serviceAccount赋值给一个pod,如果不指定,将使用该命名空间下默认的ServiceAccount.

   可以 将不同的ServiceAccount赋值给pod,让pod访问不同的资源。

12.1.3创建ServiceAccount

  为了集群的安全性,可以手动创建ServiceAccount,可以限制只有允许的pod访问对应的资源。

        创建方法如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

$ kubectl get sa

NAME      SECRETS   AGE

default   1         21h

 

 

$ kubectl create serviceaccount yaohong

serviceaccount/yaohong created

 

 

$ kubectl get sa

NAME      SECRETS   AGE

default   1         21h

yaohong   1         3s

  使用describe来查看ServiceAccount。

1

2

3

4

5

6

7

8

9

$ kubectl describe sa yaohong

Name:                yaohong

Namespace:           default

Labels:              <none>

Annotations:         <none>

Image pull secrets:  <none>

Mountable secrets:   yaohong-token-qhbxn   //如果强制使用可挂载秘钥。那么使用这个serviceaccount的pod只能挂载这个秘钥

Tokens:              yaohong-token-qhbxn

Events:              <none>

  查看该token,

$ kubectl describe secret yaohong-token-qhbxn
Name:         yaohong-token-qhbxn
Namespace:    default
Labels:       
Annotations:  kubernetes.io/service-account.name: yaohong
              kubernetes.io/service-account.uid: a3d0d2fe-bb43-11e9-ac1e-005056870b4d
Type:  kubernetes.io/service-account-token
Data
====
ca.crt:     1342 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Inlhb2hvbmctdG9rZW4tcWhieG4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoieWFvaG9uZyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImEzZDBkMmZlLWJiNDMtMTFlOS1hYzFlLTAwNTA1Njg3MGI0ZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0Onlhb2hvbmcifQ.BwmbZKoM95hTr39BuZhinRT_vHF-typH4anjkL0HQxdVZEt_eie5TjUECV9UbLRRYIqYamkSxmyYapV150AQh-PvdcLYPmwKQLJDe1-7VC4mO2IuVdMCI_BnZFQBJobRK9EdPdbZ9uxc9l0RL5I5WyWoIjiwbrQvtCUEIkjT_99_NngdrIr7QD9S5SxHurgE3HQbmzC6ItU911LjmxtSvBqS5NApJoJaztDv0cHKvlT67ZZbverJaStQdxr4yiRbpSycRNArHy-UZKbNQXuzaZczSjVouo5A5hzgSHEBBJkQpQ6Tb-Ko5XGjjCgV_b9uQvhmgdPAus8GdFTTFAbCBw

 

12.1.4将ServiceAccount分配给pod

  在pod中定义的spec.serviceAccountName字段上设置,此字段必须在pod创建时设置后续不能被修改。

  自定义pod的ServiceAccount的方法如下图

      【k8s】——Kubernetes知识盘点_第30张图片

 

12.2通过基于角色的权限控制加强集群安全

12.2.1.介绍RBAC授权插件

  RBAC授权插件将用户角色作为决定用户能否执行操作的关机因素。

12.2.2介绍RBAC授权资源

  RBAC授权规则通过四种资源来进行配置的,他们可以分为两组:

    Role和ClusterRole,他们决定资源上可执行哪些动词。

         RoleBinding和ClusterRoleBinding,他们将上述角色绑定到特定的用户,组或者ServiceAccounts上。

  Role和RoleBinding是namespace级别资源

  ClusterRole和ClusterRoleBinding是集群级别资源

12.2.3使用Role和RoleBinding

   Role资源定义了哪些操作可以在哪些资源上执行,

创建Role

  service-reader.yml

1

2

3

4

5

6

7

8

9

apiVersion: rbac.authorization.k8s.io/v1

kind: Role

metadata:

  namespace: kube-system

  name: service-reader

rules:

- apiGroups: [""]

  verbs: ["get", "list"]

  resources: ["services"]

  在kube-system中创建Role

1

#kubectl -n kube-system create -f service-reader.yml

  查看该namespace下的role

1

2

3

4

5

6

7

8

9

10

$ kubectl -n kube-system get role

NAME                                             AGE

extension-apiserver-authentication-reader        41h

kube-state-metrics-resizer                       41h

service-reader                                   2m17s

system::leader-locking-kube-controller-manager   41h

system::leader-locking-kube-scheduler            41h

system:controller:bootstrap-signer               41h

system:controller:cloud-provider                 41h

system:controller:token-cleaner                  41h

绑定角色到ServiceAccount

   将service-reader角色绑定到default ServiceAccount

1

2

$ kubectl  create rolebinding test --role=service-reader

rolebinding.rbac.authorization.k8s.io/test created

  【k8s】——Kubernetes知识盘点_第31张图片

1

2

3

4

5

6

7

8

9

10

11

12

13

14

$ kubectl  get rolebinding test -o yaml

apiVersion: rbac.authorization.k8s.io/v1

kind: RoleBinding

metadata:

  creationTimestamp: 2019-08-11T03:40:51Z

  name: test

  namespace: default

  resourceVersion: "239323"

  selfLink: /apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings/test

  uid: d0aff243-bbe9-11e9-ac1e-005056870b4d

roleRef:

  apiGroup: rbac.authorization.k8s.io

  kind: Role

  name: service-reader

12.2.4使用ClusterRole和ClusterRoleBinding

 查看集群ClusterRole

1

2

3

4

5

6

7

8

9

# kubectl get clusterrole

NAME                                                                   AGE

admin                                                                  42h

cluster-admin                                                          42h

edit                                                                   42h

flannel                                                                42h

kube-state-metrics                                                     42h

system:aggregate-to-admin                                              42h

...

创建ClusterRole

1

kubectl create clusterrole flannel --verb=get,list -n kube-system 

查看yaml文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

# kubectl get  clusterrole flannel -o yaml

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRole

metadata:

  annotations:

    kubectl.kubernetes.io/last-applied-configuration: |

      {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRole","metadata":{"annotations":{},"name":"flannel"},"rules":[{"apiGroups":[""],"resources":["pods"],"verbs":["get"]},{"apiGroups":[""],"resources":["nodes"],"verbs":["list","watch"]},{"apiGroups":[""],"resources":["nodes/status"],"verbs":["patch"]}]}

  creationTimestamp: 2019-08-09T09:58:42Z

  name: flannel

  resourceVersion: "360"

  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/flannel

  uid: 45100f6f-ba8c-11e9-8f57-005056870608

rules:

- apiGroups:

  - ""

  resources:

  - pods

  verbs:

  - get

- apiGroups:

  - ""

  resources:

  - nodes

  verbs:

  - list

  - watch

- apiGroups:

  - ""

  resources:

  - nodes/status

  verbs:

  - patch

 

创建clusterRoleBinding

1

2

$ kubectl  create clusterrolebinding  cluster-tetst  --clusterrole=pv-reader  --serviceaccount=kuebsystem:yaohong

clusterrolebinding.rbac.authorization.k8s.io/cluster-tetst created

  【k8s】——Kubernetes知识盘点_第32张图片

 

12.2.5了解默认的ClusterRole和ClusterRoleBinding

如下所示使用kubectl get clusterroles和kubectl get clusterrolesbinding可以获取k8s默认资源。

用edit ClusterRole允许对资源进行修改

用admin ClusterRole赋予一个命名空间全部的权限

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

$ kubectl get clusterroles

NAME                                                                   AGE

admin                                                                  44h

cluster-admin                                                          44h

edit                                                                   44h

flannel                                                                44h

kube-state-metrics                                                     44h

system:aggregate-to-admin                                              44h

system:aggregate-to-edit                                               44h

system:aggregate-to-view                                               44h

system:auth-delegator                                                  44h

system:aws-cloud-provider                                              44h

system:basic-user                                                      44h

system:certificates.k8s.io:certificatesigningrequests:nodeclient       44h

system:certificates.k8s.io:certificatesigningrequests:selfnodeclient   44h

system:controller:attachdetach-controller                              44h

system:controller:certificate-controller                               44h

system:controller:clusterrole-aggregation-controller                   44h

。。。

  

1

2

3

4

5

6

7

8

9

10

11

12

13

$ kubectl get clusterrolebindings

NAME                                                   AGE

clust-tetst                                            17m

cluster-admin                                          44h

cluster-tetst                                          13m

flannel                                                44h

kube-state-metrics                                     44h

kubelet-bootstrap                                      44h

system:aws-cloud-provider                              44h

system:basic-user                                      44h

system:controller:attachdetach-controller              44h

system:controller:certificate-controller               44h

。。。

 

13.Kubernetes-保障集群内节点和网络安全

13.1.在pod中使用宿主节点的Linux命名空间

13.1.1.在pod中使用宿主节点的网络命名空间

   在pod的yaml文件中就设置spec.hostNetwork: true  

   这个时候pod使用宿主机的网络,如果设置了端口,则使用宿主机的端口。

1

2

3

4

5

6

7

8

9

apiVersion: v1

kind: pod

metadata:

    name: pod-host-yaohong

spec:

    hostNetwork: true  //使用宿主节点的网络命名空间

    containers:

    - image: luksa/kubia

      command: ["/bin/sleep", "9999"]

13.1.2.绑定宿主节点上的端口而不使用宿主节点的网络命名空间

   在pod的yaml文件中就设置spec.containers.ports字段来设置

   在ports字段中可以使用

  containerPorts设置通过pod 的ip访问的端口

  container.hostPort设置通过所在节点的端口访问

1

2

3

4

5

6

7

8

9

10

11

12

apiVersion: v1

kind: pod

metadata:

    name: kubia-hostport-yaohong

spec:

    containers:

    - image: luksa/kubia

    - name: kubia

      ports:

      - containerport: 8080 //该容器通过pod IP访问该端口

        hostport: 9000  //该容器可以通过它所在节点9000端口访问

        protocol: Tcp

13.1.3.使用宿主节点的PID与IPC

   PID是进程ID,PPID是父进程ID。

   在linux下的多个进程间的通信机制叫做IPC(Inter-Process Communication),它是多个进程之间相互沟通的一种方法。

1

2

3

4

5

6

7

8

9

10

11

apiVersion: v1

kind: pod

metadata:

    name: pod-with-host-pid-and-ipc-yaohong

spec:

    hostPID: true //你希望这个pod使用宿主节点的PID命名空间

    hostIPC: true //你希望pod使用宿主节点的IPC命名空间

    containers:

    - name: main

      image: alpine

      command: ["/bin/sleep", "99999"]

 

13.2.配置节点的安全上下文

13.2.1.使用指定用户运行容器

  查看某个pod运行的用户

1

2

$ kubectl -n kube-system exec coredns-7b8dbb87dd-6ll7z id

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

  容器的运行用户再DockerFile中指定,如果没有指定则为root

  指定pod的运行的用户方法如下

1

2

3

4

5

6

7

8

9

10

11

apiVersion: v1

kind: pod

metadata:

    name: pod-as-user

spec:

    containers:

    - name: main

      image: alpine

      command: ["/bin/sleep", "99999"]

      securityContext:

        runAsUser: 405   //你需要指定的用户ID,而不是用户名

13.2.2.阻止容器以root用户运行

  runAsNonRoot来设置

1

2

3

4

5

6

7

8

9

10

11

apiVersion: v1

kind: pod

metadata:

    name: pod-as-user

spec:

    containers:

    - name: main

      image: alpine

      command: ["/bin/sleep", "99999"]

      securityContext:

        runAsNonRoot: true   //这个容器只允许以非root用户运行

13.2.3.使用特权模式运行pod

  为了获得宿主机内核完整的权限,该pod需要在特权模式下运行。需要添加privileged参数为true。

1

2

3

4

5

6

7

8

9

10

11

apiVersion: v1

kind: pod

metadata:

    name: pod-as-privileged

spec:

    containers:

    - name: main

      image: alpine

      command: ["/bin/sleep", "99999"]

      securityContext:

        privileged: true   //这个容器将在特权模式下运行

13.2.4.为容器单独添加内核功能

1

2

3

4

5

6

7

8

9

10

11

12

13

apiVersion: v1

kind: pod

metadata:

    name: pod-as-capability

spec:

    containers:

    - name: main

      image: alpine

      command: ["/bin/sleep", "99999"]

      securityContext:

        capabilities:    //该参数用于pod添加或者禁用某项内核功能

          add:

          - SYS_TIME      //添加修改系统时间参数

13.2.5.在容器中禁止使用内核功能

1

2

3

4

5

6

7

8

9

10

11

12

13

apiVersion: v1

kind: pod

metadata:

    name: pod-as-capability

spec:

    containers:

    - name: main

      image: alpine

      command: ["/bin/sleep", "99999"]

      securityContext:

        capabilities:    //该参数用于pod添加或者禁用某项内核功能

          drop:

          - CHOWN      //禁用容器修改文件的所有者

13.2.6.阻止对容器根文件系统的写入

  securityContext.readyOnlyFilesystem设置为true来实现阻止对容器根文件系统的写入。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

apiVersion: v1

kind: pod

metadata:

    name: pod-with-readonly-filesystem

spec:

    containers:

    - name: main

      image: alpine

      command: ["/bin/sleep", "99999"]

      securityContext:

         readyOnlyFilesystem: true  //这个容器的根文件系统不允许写入

      volumeMounts:

      - name: my-volume

        mountPath: /volume    //volume写入是允许的,因为这个目录挂载一个存储卷

        readOnly: false 

13.3.限制pod使用安全相关的特性

13.3.1.PodSecurityPolicy资源介绍

   PodSecurityPolicy是一种集群级别(无命名空间)的资源,它定义了用户能否在pod中使用各种安全相关的特性。

13.3.2.了解runAsUser、fsGroups和supplementalGroup策略

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

runAsUser:

  runle: MustRunAs

  ranges:

  - min: 2             //添加一个max=min的range,来指定一个ID为2的user

    max: 2

  fsGroup:

    rule: MustRunAs

    ranges:

    - min: 2

      max: 10         //添加多个区间id的限制,为2-10 或者20-30

    - min: 20

      max: 30

  supplementalGroups:

    rule: MustRunAs

    ranges:

    - min: 2

      max: 10

    - min: 20

      max: 30

13.3.3.配置允许、默认添加、禁止使用的内核功能

   三个字段会影响容器的使用

  allowedCapabilities:指定容器可以添加的内核功能

  defaultAddCapabilities:为所有容器添加的内核功能

  requiredDropCapabilities:禁止容器中的内核功能

1

2

3

4

5

6

7

8

9

apiVersion: v1

kind: PodSecurityPolicy

spec:

  allowedCapabilities:

  - SYS_TIME                 //允许容器添加SYS_time功能

  defaultAddCapabilities:

  - CHOWN                    //为每个容器自动添加CHOWN功能

  requiredDropCapabilities:

  - SYS_ADMIN                //要求容器禁用SYS_ADMIN和SYS_MODULE功能

13.4.隔离pod网络

13.4.1.在一个命名空间中使用网络隔离

  podSelector进行对一个命名空间下的pod进行隔离

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: postgres-netpolicy

spec:

  podSelector:         //这个策略确保了对具有app=databases标签的pod的访问安全性

    matchLabels:

      app: database

  ingress:

  - from:

    - podSelector:    //它只允许来自具有app=webserver标签的pod的访问

      matchLabels:

        app: webserver

    ports:

    - port: 5432      //允许对这个端口的访问

13.4.2.在 不同的kubernetes命名空间之间进行网络隔离

   namespaceSelector进行对不同命名空间间进行网络隔离

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: postgres-netpolicy

spec:

  podSelector:         //这个策略确保了对具有app=databases标签的pod的访问安全性

    matchLabels:

      app: database

  ingress:

  - from:

    - namespaceSelector:    //只允许tenant: manning标签的命名空间中运行的pod进行互相访问

      matchLabels:

        tenant: manning  

    ports:

    - port: 5432      //允许对这个端口的访问

13.4.3.使用CIDR网络隔离

1

2

3

4

ingress:

- from:

  - ipBlock:

      cidr: 192.168.1.0/24    //指明允许访问的ip段

13.4.4.限制pod对外访问流量

   使用egress进行限制

1

2

3

4

5

6

7

8

9

spec:

  podSelector:         //这个策略确保了对具有app=databases标签的pod的访问安全性

    matchLabels:

      app: database

  egress:              //限制pod的出网流量

  - to:

    - podSelector:

        matchLables:   //database的pod只能与有app: webserver的pod进行通信

          app: webserver

你可能感兴趣的:(kubernetes)