k8s网络、存储分享

k8s概述

k8s组件

Node组件

一组工作机器,称为节点, 会运行容器化应用程序。每个集群至少有一个工作节点。

Pod

Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

Pod 是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的 “逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。

控制平面组件(Control Plane Components

控制平面组件会为集群做出全局决策,比如资源的调度。 以及检测和响应集群事件,例如当不满足部署的 replicas 数量时, 要启动新的 pod。

 插件

  • DNS

尽管其他插件都并非严格意义上的必需组件,但几乎所有 Kubernetes 集群都应该有集群 DNS。

服务的应用

在集群中暴露 Pod

创建一组 Nginx Pod

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: nginx

        ports:

        - containerPort: 80

命令行执行:

kubectl apply -f ./run-my-nginx.yaml

创建完成后查看一下pods:

kubectl get pods -l run=my-nginx -o wide

##输出结果##

NAME                        READY     STATUS    RESTARTS   AGE       IP            NODE

my-nginx-3800858182-jr4a2   1/1       Running   0          13s       10.244.3.4    kubernetes-minion-905m

my-nginx-3800858182-kna2y   1/1       Running   0          13s       10.244.2.5    kubernetes-minion-ljyd

至此,就可以通过 ssh 登录到集群中的任何一个节点上,并使用诸如 curl 之类的工具向这两个 IP 地址发出查询请求。 需要注意的是,容器 不会 使用该节点上的 80 端口,也不会使用任何特定的 NAT 规则去路由流量到 Pod 上。 这意味着可以在同一个节点上运行多个 Nginx Pod,使用相同的 containerPort,并且可以从集群中任何其他的 Pod 或节点上使用 IP 的方式访问到它们。

创建 Service

现在我们有了一组在一个扁平的、集群范围的地址空间中运行 Nginx 服务的 Pod。 理论上,你可以直接连接到这些 Pod,但如果某个节点死掉了会发生什么呢? Pod 会终止,Deployment 将创建新的 Pod,且使用不同的 IP。这正是 Service 要解决的问题。

Kubernetes Service 是集群中提供相同功能的一组 Pod 的抽象表达。 当每个 Service 创建时,会被分配一个唯一的 IP 地址(也称为 clusterIP)。 这个 IP 地址与 Service 的生命周期绑定在一起,只要 Service 存在,它就不会改变。

可以使用 kubectl expose 命令为 2 Nginx 副本创建一个 Service

kubectl expose deployment/my-nginx

##输出结果##

service/my-nginx exposed

这等价于使用 kubectl create -f 命令及如下的 yaml 文件创建:

apiVersion: v1

kind: Service

metadata:

  name: my-nginx

  labels:

    run: my-nginx

spec:

  ports:

  - protocol: TCP

    port: 80

    targetPort: 80

  selector:

    run: my-nginx

上述规约将创建一个 Service,该 Service 会将所有具有标签 run: my-nginx Pod TCP 80 端口暴露到一个抽象的 Service 端口上(targetPort:容器接收流量的端口;port:可任意取值的抽象的 Service 端口,其他 Pod 通过该端口访问 Service)。

查看Service 资源:

kubectl get svc my-nginx

##输出结果##

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

my-nginx   ClusterIP   10.0.162.149   <none>        80/TCP    21s

现在,就能够从集群中任意节点上使用 curl 命令向 <CLUSTER-IP>:<PORT> 发送请求以访问 Nginx Service。 注意 Service IP 完全是虚拟的,它从来没有走过网络。

暴露 Service(服务类型)

ClusterIP

通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是没有为服务显式指定 type 时使用的默认值。

NodePort

NodePort 类型的service.yaml

apiVersion: v1

kind: Service

metadata:

  name: my-nginx

  labels:

    run: my-nginx

spec:

  type: NodePort

  ports:

  - port: 8080

    targetPort: 80

    protocol: TCP

    name: http

    nodePort: 31704

  - port: 443

    protocol: TCP

    name: https

  selector:

    run: my-nginx

查看service

kubectl get svc my-nginx

##输出结果##

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

my-nginx       NodePort    10.0.162.149   <none>        8080:31704/TCP,443:32453/TCP      21s

如果你将 type 字段设置为 NodePort,则 Kubernetes 控制平面将在 --service-node-port-range 标志指定的范围内分配端口(默认值:30000-32767)。 每个节点将那个端口(每个pod相同的端口号,如上述的8080、443)代理到你的服务中。 你的服务在其 .spec.ports[*].nodePort 字段中报告已分配的端口。

换一种查看方式

kubectl get svc my-nginx -o yaml | grep nodePort -C 5

##输出结果##

  uid: 07191fb3-f61a-11e5-8ae5-42010af00002

spec:

  clusterIP: 10.0.162.149

  ports:

  - name: http

    nodePort: 31704

    port: 8080

    protocol: TCP

    targetPort: 80

  - name: https

    nodePort: 32453

    port: 443

    protocol: TCP

    targetPort: 443

  selector:

    run: my-nginx

选择使用NodePort类型可能的理由:

  • 在K8S集群外部,通过访问节点IP+NodePort的方式,就可直接访问到集群的内部服务
  • 使用 NodePort 可以让你自由设置自己的负载均衡解决方案, 配置 Kubernetes 不完全支持的环境。

nodePort的端口号,在实际操作中一般会自行指定、不采用系统自动分配的默认值。会实际占用物理机的该端口,所以需要注意规划好,避开端口冲突。

企搜的举例

以企搜为例,为web-fe配置了8085的外部访问端口,来自【宿主机IP:8085】的访问会路由到目标pod(也就是app=web-fe的这组前端pod)的8080端口上。

在web-fe的内部,以nginx侦听了8080的请求,并通过其配置文件(nginx.conf),完成了不同路径向不同k8s服务的转发。

如上所示,8080下所有以mpks打头的请求,都将路由到gateway服务。

gateway中做了登录鉴权处理,并在通过鉴权后继续向业务服务做分发。如上所示是gateway工程的路由配置,mpks打头的请求最终路由到了search-server服务中。

search-server本身是个java应用,侦听了8662上的请求并响应。至此,完成了从宿主机->svc->web-fe->gateway->search-server的网络穿透。

深入了解k8s网络

Pod网络

所谓Pod网络,就是能够保证K8s集群中的所有Pods(包括同一节点上的,也包括不同节点上的Pods),逻辑上看起来都在同一个平面网络内,能够相互做IP寻址和通信的网络。

同一节点上的Pod网络

一个Pod中可以住一个或者多个(大多数场景住一个)应用容器,这些容器共享Pod的网络栈。

  • eth0是节点主机上的网卡,这个是支持该节点流量出入的设备,也是支持集群节点间IP寻址和互通的设备。
  • docker0是节点内的一个虚拟网桥,可以简单理解为一个虚拟交换机,它是支持该节点上的Pod之间进行IP寻址和互通的设备。
  • veth0则是Pod1的虚拟网卡,是支持该Pod内容器互通和对外访问的虚拟设备。

docker0网桥和veth0网卡,都是linux支持和创建的虚拟网络设备。

上图Pod1内部住了3个容器,它们都共享一个虚拟网卡veth0。内部的这些容器可以通过localhost相互访问,但是它们不能在同一端口上开启服务,否则会有端口冲突,这就是共享网络栈的意思。Pod1中还有一个比较特殊的叫pause的容器,这个容器运行的唯一目的是为Pod建立共享的veth0网络接口。如果你SSH到K8s集群中一个有Pod运行的节点上去,然后运行docker ps,可以看到通过pause命令运行的容器。

PodIP是由docker0网桥分配的,例如上图docker0网桥的IP172.17.0.1,它给第一个Pod1分配IP172.17.0.2。如果该节点上再启一个Pod2,那么相应的分配IP172.17.0.3,如果再启动Pod可依次类推。因为这些Pods都连在同一个网桥上,在同一个网段内,它们可以进行IP寻址和互通,如下图所示:

从上图我们可以看到,节点内Pod网络在172.17.0.0/24这个地址空间内,而节点主机在10.100.0.0/24这个地址空间内,也就是说Pod网络和节点网络不在同一个网络内,那么不同节点间的Pod该如何IP寻址和互通呢?

不同节点间的Pod网络

  • 路由方案

通过路由设备为K8s集群的Pod网络单独划分网段,并配置路由器支持Pod网络的转发。例如上图中,对于目标为172.17.1.0/24这个范围内的包,转发到10.100.0.3这个主机上,同样,对于目标为172.17.0.0/24这个范围内的包,转发到10.100.0.2这个主机上。当主机的eth0接口接收到来自Pod网络的包,就会向内部网桥转发,这样不同节点间的Pod就可以相互IP寻址和通信。这种方案依赖于底层的网络设备,但是不引入额外性能开销

  • 覆盖(Overlay)网络方案

所谓覆盖网络,就是在现有网络之上再建立一个虚拟网络,实现技术有很多,例如flannel/weavenet等等,这些方案大都采用隧道封包技术。简单理解,Pod网络的数据包,在出节点之前,会先被封装成节点网络的数据包,当数据包到达目标节点,包内的Pod网络数据包会被解封出来,再转发给节点内部的Pod网络。这种方案对底层网络没有特别依赖,但是封包解包会引入额外性能开销

CNI简介

考虑到Pod网络实现技术众多,为了简化集成,K8s支持CNI(Container Network Interface)标准,不同的Pod网络技术可以通过CNI插件形式和K8S进行集成。节点上的Kubelet通过CNI标准接口操作Pod网路,例如添加或删除网络接口等,它不需要关心Pod网络的具体实现细节。

Service网络

Service网络概念模型

  • 服务发现

Account-Service提供统一的ClusterIP来解决服务发现问题,Client只需通过ClusterIP就可以访问Account-App的Pod集群,不需要关心集群中的具体Pod数量和PodIP,即使是PodIP发生变化也会被ClusterIP所屏蔽。注意,这里的ClusterIP实际是个虚拟IP,也称Virtual IP(VIP)。

  • 负载均衡

Account-Service抽象层具有负载均衡的能力,支持以不同策略去访问Account-App集群中的不同Pod实例,以实现负载分摊和HA高可用。K8s中默认的负载均衡策略是RoundRobin,也可以定制其它复杂策略。

Service网络原理

在K8s平台的每个Worker节点上,都部署有两个组件,一个叫Kubelet,另外一个叫Kube-Proxy,这两个组件+Master是K8s实现服务注册和发现的关键。

服务注册发现流程:

  1. 在服务Pod实例发布时(可以对应K8s发布中的Kind: Deployment),Kubelet会负责启动Pod实例,启动完成后,Kubelet会把服务的PodIP列表汇报注册到Master节点。
  2. 通过服务Service的发布(对应K8s发布中的Kind: Service),K8s会为服务分配ClusterIP,相关信息也记录在Master上。
  3. 在服务发现阶段,Kube-Proxy会监听Master并发现服务ClusterIP和PodIP列表映射关系,并且修改本地的linux iptables转发规则,指示iptables在接收到目标为某个ClusterIP请求时,进行负载均衡并转发到对应的PodIP上。
  4. 运行时,当有消费者Pod需要访问某个目标服务实例的时候,它通过ClusterIP发起调用,这个ClusterIP会被本地iptables机制截获,然后通过负载均衡,转发到目标服务Pod实例上。

实际消费者Pod也并不直接调服务的ClusterIP,而是先调用服务名,因为ClusterIP也会变(例如针对TEST/UAT/PROD等不同环境的发布,ClusterIP会不同),只有服务名一般不变。为了屏蔽ClusterIP的变化,K8s在每个Worker节点上还引入了一个KubeDNS组件,它也监听Master并发现服务名和ClusterIP之间映射关系,这样, 消费者Pod通过KubeDNS可以间接发现服务的ClusterIP。

NodePort

如果我们要将K8s内部的一个服务通过NodePort方式暴露出去,可以将服务发布(kind: Service)的type设定为NodePort。服务发布以后,K8s在每个Worker节点上都会开启这个监听端口。这个端口的背后是Kube-Proxy,它掌握Service网络的所有信息,知道怎么和Service网络以及Pod网络互通互联。当K8s外部有Client要访问K8s集群内的某个服务,它通过这个服务的NodePort端口发起调用,这个调用通过Kube-Proxy转发到内部的Servcie抽象层,然后再转发到目标Pod上。

Service DNS

你可以(几乎总是应该)使用“附加组件” 为 Kubernetes 集群设置 DNS 服务。

支持集群的 DNS 服务器(例如 CoreDNS)监视 Kubernetes API 中的新服务,并为每个服务创建一组 DNS 记录。 如果在整个集群中都启用了 DNS,则所有 Pod 都应该能够通过其 DNS 名称自动解析服务。

例如,如果你在 Kubernetes 命名空间 my-ns 中有一个名为 my-service 的服务, 则控制平面和 DNS 服务共同为 my-service.my-ns 创建 DNS 记录。 my-ns 命名空间中的 Pod 应该能够通过按名检索 my-service 来找到服务 (my-service.my-ns 也可以工作)。跨命名空间的服务需要增加my-ns后缀。

流量策略

  • 外部流量策略

可以在serviceyaml文件中设置 spec.externalTrafficPolicy 字段来控制来自于外部的流量是如何路由的。 可选值有 Cluster Local。字段设为 Cluster 会将外部流量路由到所有就绪的端点, 设为 Local 会只路由到当前节点上就绪的端点。 如果流量策略设置为 Local,而且当前节点上没有就绪的端点,kube-proxy 不会转发请求相关服务的任何流量。

  • 内部流量策略

可以在serviceyaml文件中设置spec.internalTrafficPolicy字段来控制内部来源的流量是如何转发的。可设置的值有Cluster和Local。 将字段设置为Cluster会将内部流量路由到所有就绪端点,设置为Local只会路由到当前节点上就绪的端点。 如果流量策略是Local,而且当前节点上没有就绪的端点,那么 kube-proxy 会丢弃流量。

存储

有多种存储类型可选,例如nfs(网络文件系统) 、cephfs,接下来以nfs为示例:

安装nfs

所有节点

#所有机器安装

yum install -y nfs-utils

主节点

#nfs主节点

echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports

mkdir -p /nfs/data

systemctl enable rpcbind --now

systemctl enable nfs-server --now

#配置生效

exportfs -r

从节点

showmount -e 172.31.0.4  # 查看哪些客户端可以访问NFS服务器上的哪些目录

#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /nfs/data

mkdir -p /nfs/data

mount -t nfs 172.31.0.4:/nfs/data /nfs/data

# 写入一个测试文件

echo "hello nfs server" > /nfs/data/test.txt

原生方式数据挂载

apiVersion: apps/v1

kind: Deployment

metadata:

  labels:

    app: nginx-pv-demo

  name: nginx-pv-demo

spec:

  replicas: 2

  selector:

    matchLabels:

      app: nginx-pv-demo

  template:

    metadata:

      labels:

        app: nginx-pv-demo

    spec:

      containers:

      - image: nginx

        name: nginx

        volumeMounts:

        - name: html // 引用定义的存储资源

          mountPath: /usr/share/nginx/html  // pod内部的路径

      volumes:

        - name: html // 真正定义存储资源

          nfs:

            server: 172.31.0.4

            path: /nfs/data/nginx-pv

静态制备

持久卷(Persistent Volume

持久卷(PersistentVolumePV是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。

创建PV

静态供应

#nfs主节点

mkdir -p /nfs/data/01

mkdir -p /nfs/data/02

mkdir -p /nfs/data/03

创建PV

apiVersion: v1

kind: PersistentVolume

metadata:

  name: pv01-10m

spec:

  capacity:

    storage: 10M

  accessModes:

    - ReadWriteMany

  storageClassName: nfs

  nfs:

    path: /nfs/data/01

    server: 172.31.0.4

---

apiVersion: v1

kind: PersistentVolume

metadata:

  name: pv02-1gi

spec:

  capacity:

    storage: 1Gi

  accessModes:

    - ReadWriteMany

  storageClassName: nfs

  nfs:

    path: /nfs/data/02

    server: 172.31.0.4

---

apiVersion: v1

kind: PersistentVolume

metadata:

  name: pv03-3gi

spec:

  capacity:

    storage: 3Gi

  accessModes:

    - ReadWriteMany

  storageClassName: nfs

  nfs:

    path: /nfs/data/03

    server: 172.31.0.4

持久卷申明(Persistent Volume Claim

持久卷申明(PersistentVolumeClaimPVC表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnceReadOnlyMany ReadWriteMany 模式之一来挂载)。

创建PVC

kind: PersistentVolumeClaim

apiVersion: v1

metadata:

  name: nginx-pvc

spec:

  accessModes:

    - ReadWriteMany

  resources:

    requests:

      storage: 200Mi

  storageClassName: nfs  // 需要与想要绑定的PV中storageClassName字段的值保持一致

创建Pod绑定PVC

apiVersion: apps/v1

kind: Deployment

metadata:

  labels:

    app: nginx-deploy-pvc

  name: nginx-deploy-pvc

spec:

  replicas: 2

  selector:

    matchLabels:

      app: nginx-deploy-pvc

  template:

    metadata:

      labels:

        app: nginx-deploy-pvc

    spec:

      containers:

      - image: nginx

        name: nginx

        volumeMounts:

        - name: html

          mountPath: /usr/share/nginx/html

      volumes:

        - name: html

          persistentVolumeClaim:

            claimName: nginx-pvc

动态制备

如果管理员所创建的所有静态 PV 卷都无法与用户的 PersistentVolumeClaim 匹配, 集群可以尝试为该 PVC 申领动态制备一个存储卷。 这一制备操作是基于 StorageClass 来实现的:PVC 申领必须请求某个存储类, 同时集群管理员必须已经创建并配置了该类,这样动态制备卷的动作才会发生。 如果 PVC 申领指定存储类为"",则相当于为自身禁止使用动态制备的卷。

动态创建PV流程简述

  1. 部署 制备器服务(本文使用 “nfs-client-provisioner”

首先,需要在 Kubernetes 集群中部署 nfs-client-provisioner。可以通过使用 Kubernetes 配置文件或 Helm Chart 进行部署。这将创建一个运行在集群中的容器,用于监听 PVC 的创建。

  1. 创建 StorageClass

需要创建一个 StorageClass,其中定义了与 nfs-client-provisioner 通信所需的配置信息,如 NFS 服务器地址、共享路径等。

  1. 创建 PVC

当在集群中创建一个 PVC 并引用了之前定义的 StorageClass,nfs-client-provisioner 将监听 PVC 的创建。

  1. nfs-client-provisioner 的处理

一旦 PVC 创建,nfs-client-provisioner 会检测到 PVC 的存在。它会解析 PVC 中定义的存储需求和 StorageClass 的配置,然后使用这些信息通过 NFS 协议与 NFS 服务器进行通信,并在 NFS 服务器上创建一个目录以供存储。

  1. 绑定 PV PVC

一旦 NFS 服务器上的目录创建成功,nfs-client-provisioner 将创建一个 PV,并将其与创建 PVC 绑定起来,从而使 PVC 获得一个可用的 PV。

  1. PVC 使用

现在,PVC 已经与一个动态创建的 PV 绑定。可以在 Pod 中使用这个 PVC,使 Pod 能够挂载 NFS 存储并访问其中的数据。

制备器(Provisioner

每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。 该字段必须被StorageClass指定。

部署nfs-client-provisioner服务

kind: Deployment

apiVersion: apps/v1

metadata:

  name: nfs-client-provisioner

spec:

  replicas: 1

  selector:

    matchLabels:

      app: nfs-client-provisioner

  strategy:

    type: Recreate

  template:

    metadata:

      labels:

        app: nfs-client-provisioner

    spec:

      serviceAccountName: nfs-client-provisioner

      containers:

        - name: nfs-client-provisioner

          image: quay.io/vbouchaud/nfs-client-provisioner:latest

          volumeMounts:

            - name: nfs-client-root

              mountPath: /persistentvolumes

          env:

            - name: PROVISIONER_NAME

              value: fuseim.pri/ifs

            - name: NFS_SERVER

              value: 192.168.20.11

            - name: NFS_PATH

              value: /data/nfs/rw

      volumes:

        - name: nfs-client-root

          nfs:

            server: 192.168.20.11

            path: /data/nfs/rw

存储类(StorageClass

每个 StorageClass 都包含 provisionerparameters reclaimPolicy 字段, 这些字段会在 StorageClass 需要动态制备 PersistentVolume 时会使用到。

创建存储类

apiVersion: storage.k8s.io/v1

kind: StorageClass

metadata:

  name: managed-nfs-storage

provisioner: fuseim.pri/ifs   # 要与部署制备器服务时环境变量 PROVISIONER_NAME 的值对应起来

parameters:

  server: 192.168.20.11       # NFS服务器的主机名或 IP 地址。

  path: /data/nfs/rw          # NFS 服务器导出的路径。

  archiveOnDelete: "false"

reclaimPolicy: Retain         # 回收策略,默认为delete

如果在创建存储类时通过archiveOnDelete: "true"参数指定备份,那么删除PVC的时候,PV也会被删除但是主机上存储的数据不会删除,而会重命名为一个archived开头的目录。

如果没有设置这一条,那么删除PVC的时候,数据就真的全部被删掉了。

如果回收策略设为了Retain,那么删除PVC后PV不会被删除,这个时候的PV处于Released状态,需要管理员手动干预修改配置,才能恢复到Available状态并被重新可绑定,同时,PV如果处于Released状态,那么他是不可用的。

创建PVC

kind: PersistentVolumeClaim

apiVersion: v1

metadata:

  name: test-claim

spec:

  storageClassName: managed-nfs-storage

  accessModes:

    - ReadWriteMany

  resources:

    requests:

      storage: 10Mi

Statefulset

StatefulSet是Kubernetes中的一种控制器对象,用于管理有状态应用程序的部署和管理。相比于Deployment,StatefulSet更适合部署有状态的应用程序,如数据库或分布式存储系统。

官方给出的建议是,如果你部署的应用满足以下一个或多个部署需求,则建议使用StatefulSet。

  • 稳定的、唯一的网络标识。
  • 稳定的、持久的存储。
  • 有序的、优雅的部署和伸缩。
  • 有序的、优雅的删除和停止。
  • 有序的、自动的滚动更新。

statefulsetdeployment的区别

使用StatefulSet的典型场景

  • 数据库集群:StatefulSet非常适合部署数据库集群,如MySQL、PostgreSQL等。StatefulSet可以确保每个Pod都有唯一的标识符和稳定的网络标识,这对于数据库复制和故障恢复非常重要。
  • 分布式存储系统:如果你正在部署分布式存储系统,如Elasticsearch、Cassandra等,StatefulSet是一个理想的选择。StatefulSet可以按照预定义的顺序启动和终止Pod,确保数据的有序迁移和重新启动。
  • 消息队列集群:StatefulSet可用于管理消息队列集群,如Kafka。每个Pod都可以具有唯一的标识符和稳定的网络标识,这样可以确保消息队列的有序处理和分片扩展。

无头服务(Headless Services

无头服务(Headless Service)是一种特殊类型的 Kubernetes 服务,它不提供负载均衡和集群IP,最大的特点就是没有clusterIP,如下图所示。无头服务的主要作用是提供一个可靠的方式来直接访问Pod,而不是通过负载均衡器。这在某些场景下非常有用,例如当你需要保持稳定的网络标识或在分布式系统中保持状态。

场景:

  • 比如kubernetes部署某个kafka集群,这种就不需要service来代理,客户端需要的是一组pod的所有的ip。
  • 还有一种场景客户端自己处理负载均衡的逻辑,比如kubernates部署两个mysql,由客户端处理负载请求,或者根本不处理这种负载,就要两套mysql。

StatefulSet应用示例

apiVersion: v1

kind: Service

metadata:

  name: nginx

  labels:

    app: nginx

spec:

  ports:

  - port: 80

    name: web

  clusterIP: None

  selector:

    app: nginx

---

apiVersion: apps/v1

kind: StatefulSet

metadata:

  name: web

spec:

  selector:

    matchLabels:

      app: nginx

  serviceName: "nginx"

  replicas: 3

  template:

    metadata:

      labels:

        app: nginx

    spec:

      containers:

      - name: nginx

        image: registry.k8s.io/nginx-slim:0.8

        ports:

        - containerPort: 80

          name: web

        volumeMounts:

        - name: www

          mountPath: /usr/share/nginx/html

  volumeClaimTemplates:

  - metadata:

      name: www

    spec:

      accessModes: [ "ReadWriteOnce" ]

      storageClassName: "my-storage-class"

      resources:

        requests:

          storage: 1Gi

配置

ConfigMap

ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pod可以将其用作环境变量、命令行参数或者存储卷中的配置文件。

  • ConfigMap 将你的环境配置信息和容器镜像解耦,便于应用配置的修改。
  • 被挂载的 ConfigMap 内容会被自动更新。
  • Python程序可以通过该方式外挂代码,方便调试

使用 ConfigMap

假若已有一个配置文件:redis.conf

appendonly yes

将已有配置文件创建为配置集

# 创建为configmap对象,将配置保存到k8s的etcd;

kubectl create cm redis-conf --from-file=redis.conf

# 然后查看创建好的configmap

kubectl get cm redis-conf -oyaml

apiVersion: v1

kind: ConfigMap

metadata:

  name: redis-conf

  namespace: default

data:    #data是所有真正的数据,key:默认是文件名   value:配置文件的内容

  redis.conf: |

    appendonly yes

创建pod使用configmap

apiVersion: v1

kind: Pod

metadata:

  name: redis

spec:

  containers:

  - name: redis

    image: redis

    command:

      - redis-server

      - "/redis-master/new_redis.conf"  #指的是redis容器内部的位置

    ports:

    - containerPort: 6379

    volumeMounts:

    - mountPath: /redis-master

      name: config

  volumes:

    - name: config

      configMap:

        name: redis-conf

        items:

        - key: redis.conf  #原文件名

          path: new_redis.conf  #修改之后,实际挂载到pod中的文件名

Secret

Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比直接放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。

可以将secret用于以下场景中:

  • 允许 kubelet 从私有镜像仓库中拉取镜像。
  • 设置容器的环境变量。
  • 向 Pod 提供 SSH 密钥或密码等凭据。

使用Secret拉取镜像

执行命令创建镜像仓库类型的secret

kubectl create secret docker-registry xyh-docker \

--docker-server=<你的镜像仓库服务器> \

--docker-username=xyh \

--docker-password=xyh123456 \

--docker-email=XXXXXXXXXXX@163.com

使用secret拉取私有镜像

apiVersion: v1

kind: Pod

metadata:

  name: private-nginx

spec:

  containers:

  - name: private-nginx

    image: xyh/xyhnginx:v1.0

  imagePullSecrets:

  - name: xyh-docker

使用来自 Secret 中的数据定义容器变量

执行命令创建Opaque类型的secret

kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'

创建pod使用secret

apiVersion: v1

kind: Pod

metadata:

  name: env-single-secret

spec:

  containers:

  - name: envars-test-container

    image: nginx

    env:

    - name: SECRET_USERNAME

      valueFrom:

        secretKeyRef:

          name: backend-user

          key: backend-username

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值