K8S 进阶 -1(pod,deployment,service,namespace...)

写在前面:

K8s是什么?

k8s是一个编排容器的工具,(服务编排工具,集群化管理工具)其实也是管理应用的全生命周期的一个工具,从创建应用,应用的部署,应用提供服务,扩容缩容应用,应用更新,都非常的方便,而且可以做到故障自愈,例如一个服务器损坏,可以自动将这个服务器上的服务调度到另外一个主机上进行运行,无需进行人工干涉。k8s可以更快的更新新版本,打包应用,更新的时候可以做到不用中断服务,服务器故障不用停机,从开发环境到测试环境到生产环境的迁移极其方便,一个配置文件搞定,一次生成image,到处运行。

一, K8S--NAMESPACE

Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。这些虚拟集群被称为命名空间。在一个Kubernetes集群中可以拥有多个命名空间,它们在逻辑上彼此隔离。 他们可以为您和您的团队提供组织,安全甚至性能方面的帮助!

大多数的Kubernetes中的集群默认会有一个叫default的namespace。实际上,应该是3个:

  • default:你的service和app默认被创建于此。
  • kube-system:kubernetes系统组件使用。
  • kube-public:公共资源使用。但实际上现在并不常用。

这个默认(default)的namespace并没什么特别,但你不能删除它。这很适合刚刚开始使用kubernetes和一些小的产品系统。但不建议应用于大型生产系统。因为,这种复杂系统中,团队会非常容易意外地或者无意识地重写或者中断其他服务service。相反,请创建多个命名空间来把你的服务service分割成更容易管理的块。

接下来,我们看看 namespace的yaml文件,也就是如何创建namespace.

nginx-namespace.yaml:

  #nginx-namespace.yaml:

   kind: Namespace
   apiVersion: v1
   metadata:
     name: nginx
     labels:
       name: nginx

创建namespace命令如下, 

kubectl apply/create -f nginx-namespace.yaml

有了namespace就可以在其中创建资源了,比如pod, deplyment,service 等,这些都必须指定namespace。不指定的话默认就是 default。

 

二,K8S--POD

有了namespace之后我们第一个要创建的就是pod,他是k8s 的最小资源单位。也叫容器集

Pod封装了一个或多个应用程序的容器(比如nginx等),被部署在一个或多个节点上。统一容共享IP, IPC,主机名及其他资源。容器集会将网络和存储从底层容器抽象出来,这样就可以轻松移动容器了。

接下来我们看看pod的 yaml文件,也就是如何创建pod。

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: nginx
    image: nginx
  - name: mysql
    image: mysql

可以看到这个pod容器集创建/启动了两个容器,值得注意的是,我们在pod的yaml文件上面 并没有看到端口,ip这样的信息,这里应该提出疑问,那怎么做端口映射,服务转发呢?

这个时候,我们在回过头来 看看上面说的一句话,容器集会将网络和存储从底层容器抽象出来,也就是网络与资源的最小单位pod分割开来。这样无论网络如何波动都不会影响资源(pod)的更新,分片等操作。基于这个理念(其中还涉及replication的概念),k8s 也衍生了灰度部署这种服务上线部署方式。那既然网络与资源存储分离开来了,谁做网络这部分的工作呢?请看下文

 

三,K8S--SERVICE

Kubernetes中一个应用服务会有一个或多个实例(Pod,Pod可以通过rs进行多复本的建立),每个实例(Pod)的IP地址由网络插件动态随机分配(Pod重启后IP地址会改变)。为屏蔽这些后端实例的动态变化和对多实例的负载均衡,引入了Service这个资源对象。

Service 做服务发现 指定 Deployment 或者特定集合 Pod 的网络层抽象。

我们先看看service 的yaml文件:

nginx-service.yaml:

#nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx-service
  namespace: nginx
spec:
  type: NodePort
  ports:
#配置NodePort,外部流量可访问k8s中的服务
  - port: 80      
    name: nginx-service80
    protocol: TCP
    # 服务访问端口(外部访问)
    targetPort: 80
    # pod控制器中定义的端口
    nodePort: 80
  - port: 81
    name: nginx-service81
    protocol: TCP
    targetPort: 81
    nodePort: 81
  selector:
    app: nginx

3.1根据创建Service的type类型不同,可分成4种模式:

  • ClusterIP: 默认方式。根据是否生成ClusterIP又可分为普通Service和Headless Service两类:
    • 普通Service:通过为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP),实现集群内的访问。为最常见的方式。
    • Headless Service:该服务不会分配Cluster IP,也不通过kube-proxy做反向代理和负载均衡。而是通过DNS提供稳定的络ID来访问,DNS会将headless service的后端直接解析为podIP列表。主要供StatefulSet使用。
  • NodePort:除了使用Cluster IP之外,还通过将service的port映射到集群内每个节点的相同一个端口,实现通过nodeIP:nodePort从集群外访问服务。
  • LoadBalancer:和nodePort类似,不过除了使用一个Cluster IP和nodePort之外,还会向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的nodePort),实现从集群外通过LB访问服务。
  • ExternalName:是 Service 的特例。此模式主要面向运行在集群外部的服务,通过它可以将外部服务映射进k8s集群,且具备k8s内服务的一些特征(如具备namespace等属性),来为集群内部提供服务。此模式要求kube-dns的版本为1.7或以上。这种模式和前三种模式(除headless service)最大的不同是重定向依赖的是dns层次,而不是通过kube-proxy。
    比如,在service定义中指定externalName的值"my.database.example.com":

3.2 Service中主要涉及三种Port:

port 这里的port表示service暴露在clusterIP上的端口,clusterIP:Port 是提供给集群内部访问kubernetes服务的入口。

  • targetPort
    containerPort,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。

  • nodePort
    nodeIP:nodePort 是提供给从集群外部访问kubernetes服务的入口。

总的来说,port和nodePort都是service的端口,前者暴露给从集群内访问服务,后者暴露给从集群外访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端具体pod的targetPort,从而进入到pod上的容器内。

3.3 使用Service服务还会涉及到几种IP:

  • ClusterIP
    Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,但clusterIP就不一样了,没有网络设备承载这个地址。它是一个虚拟地址,由kube-proxy使用iptables规则重新定向到其本地端口,再均衡到后端Pod。当kube-proxy发现一个新的service后,它会在本地节点打开一个任意端口,创建相应的iptables规则,重定向服务的clusterIP和port到这个新建的端口,开始接受到达这个服务的连接。

  • Pod IP
    Pod的IP,每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause的容器,Pod内部其他容器的网络模式使用container模式,并指定为pause容器的ID,即:network_mode: "container:pause容器ID",使得Pod内所有容器共享pause容器的网络,与外部的通信经由此容器代理,pause容器的IP也可以称为Pod IP。

  • 节点IP
    Node-IP,service对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。指定service的spec.type=NodePort,这个类型的service,系统会给它在集群的各个代理节点上分配一个节点级别的端口,能访问到代理节点的客户端都能访问这个端口,从而访问到服务。

四,K8S--DEPLOYMENT

其实,基于namespace,pod,service 已经完全可以启动服务集群了,但是为什么会出现deployemnt呢?

因为在大业务量的情况下,一个pod(也可以说一个资源部署)压力会很大,在微服务的概念下,往往会出现服务分片,扩容等概念。

在早期版本使用Replication Controller对Pod副本数量进行管理,在新的版本中官方推荐使用Deployment来代替RC,Deployment相对RC有这些好处

  • Deployment拥有更加灵活强大的升级、回滚功能,并且支持滚动更新
  • 使用Deployment升级Pod只需要定义Pod的最终状态,k8s会为你执行必要的操作(RC要自己定义如何操作)

 

docker-compose 可以简单地通过 docker-compose scale 来扩容,现在用k8s扩容

在k8s中管理 Pod 的称作 Controller,我们可以使用 Deployment 这种 Controller 来为 Pod 进行扩容,当然它还可以滚动升级,回滚,金丝雀等等关于部署的事情。下面我们看看 deployment 的 yaml文件。

nginx-deployment.yaml:

#nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
  #指定域
  namespace: nginx
spec:
  strategy: 
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.0
        name: nginx
        volumeMounts:
        - name: conf
          mountPath: /etc/nginx/nginx.conf
        - name: log
          mountPath: /var/log/nginx/
        - name: html
          mountPath: /etc/nginx/html
      #标签选择器(集群状态下,可以指定服务部署在特定node节点上,这就是标签的作用)
      #nodeSelector:
        #type: nginx
      #设置污点可以调度到对应服务器
      tolerations:
      - key: "key"
        operator: "Equal"
        value: "nginx"
        effect: "NoSchedule"
      volumes:
      - name: conf
        hostPath:
          path: /usr/local/nginx/conf/nginx.conf
      - name: log
        hostPath:
          path: /usr/local/nginx/logs
          type: Directory
      - name: html
        hostPath:
          path: /usr/local/nginx/html
          type: Directory
  • spec.template: 指定要部署的 Pod

  • spec.replicas: 指定要部署的个数

  • spec.selector: 定位需要管理的 Pod

  • spec.strategy: 可选项为Recreate,RollingUpdate。默认是 RollingUpdate,滚动发布

  • spec.strategy.rollingUpdate.maxUnavailable 是可选配置项,用来指定在升级过程中不可用Pod的最大数量。可以配置绝对值与百分比(5 / 10%)。

       该值设置成30%,启动rolling update后旧的ReplicatSet将会立即缩容到期望的Pod数量的70%。新的Pod ready后,随着新的ReplicaSet的扩容,旧的ReplicaSet会进一步缩容,确保在升级的所有时刻可以用的Pod数量至少是期望Pod数量的70%。

       假如replicas=100。他的历程可能如下(100旧 - > 70旧+30新  ->  49旧+21新+30新 -> ......-> 100新 )

     

  • spec.strategy.rollingUpdate.maxSurge 是可选配置项,用来指定可以超过期望的Pod数量的最大个数。可以配置绝对值与百分比(5 / 10%)。

      该值设置成30%,启动rolling update后新的ReplicatSet将会立即扩容,新老Pod的总数不能超过期望的Pod数量的130%。旧的Pod被杀掉后,新的ReplicaSet将继续扩容,旧的ReplicaSet会进一步缩容,确保在升级的所有时刻所有的Pod数量和不会超过期望            Pod数量的130%。他的历程可能如下(100旧 - >100旧+30新  ->  70旧+30新+30新 -> ......->100新 )

可以看到deployment基本涵盖了pod的定义,但是他还包含了 replicas,strategy这样的配置,这个就起到了管理pod的作用。

4.1 deployment可以做什么

  • 定义一组Pod期望数量,Controller会维持Pod数量与期望数量一致
  • 配置Pod的发布方式,controller会按照给定的策略更新Pod,保证更新过程中不可用Pod维持在限定数量范围内
  • 如果发布有问题支持回滚

4.2 deployment工作原理

实际开发/部署过程中,你肯定有过这样的操作。kubectl delete pod "pod名称" -n "命名空间"。删除成功之后,会有新的pod生成。你有没有想过为什么会这样,是pod自带的重启功能还是...呢?很显然这不是pod的能力范围,你也看不到这样的配置项,但是仔细想想还是可以想明白的。deployment 的配置项里面不是有个 replicas 副本数量吗,当你删除pod之后,副本数量不就是0了吗,不等于配置的1。也就是说状态发生了变化,与期望的状态并不一样。deployment检测到之后,肯定要有相应的动作喽。接着往下看。。。

  • 控制器模型

在Kubernetes架构中,有一个叫做kube-controller-manager的组件。这个组件,是一系列控制器的集合。其中每一个控制器,都以独有的方式负责某种编排功能。而Deployment正是这些控制器中的一种。它们都遵循Kubernetes中一个通用的编排模式,即:控制循环

用一段go语言伪代码,描述这个控制循环

# := 为golang声明新变量的格式规范
for {
    实际状态 := 获取集群中对象X的实际状态
    期望状态 := 获取集群中对象X的期望状态
    if 实际状态 == 期望状态 {
        什么都不做
    }else{
        执行编排动作,将实际状态调整为期望状态
    }
}

 

在具体实现中,实际状态往往来自于Kubernetes集群本身。比如Kubelet通过心跳汇报的容器状态和节点状态,或者监控系统中保存的应用监控数据,或者控制器主动收集的它感兴趣的信息,这些都是常见的实际状态的来源;期望状态一般来自用户提交的YAML文件,这些信息都保存在Etcd中

对于Deployment,它的控制器简单实现如下:

  1. Deployment Controller从Etcd中获取到所有携带 “app:nginx”标签的Pod,然后统计它们的数量,这就是实际状态
  2. Deployment对象的replicas的值就是期望状态
  3. Deployment Controller将两个状态做比较,然后根据比较结果,确定是创建Pod,还是删除已有Pod
  • 滚动更新

Deployment滚动更新的实现,依赖的是Kubernetes中的ReplicaSet

Deployment控制器实际操纵的,就是Replicas对象,而不是Pod对象。对于Deployment、ReplicaSet、Pod它们的关系如下图:

ReplicaSet负责通过“控制器模式”,保证系统中Pod的个数永远等于指定的个数。这也正是Deployment只允许容器的restartPolicy=Always的主要原因:只有容器能保证自己始终是running状态的前提下,ReplicaSet调整Pod的个数才有意义。

Deployment同样通过控制器模式,操作ReplicaSet的个数和属性,进而实现“水平扩展/收缩”和“滚动更新”两个编排动作对于“水平扩展/收缩”的实现,Deployment Controller只需要修改replicas的值即可。用户执行这个操作的指令如下:

kubectl scale deployment nginx-deployment --replicas=4
#下面这种写法也支持
#kubectl scale deployment/nginx-deployment --replicas=4

如果集群支持 horizontal pod autoscaling 的话,还可以为Deployment设置自动扩展:

下面自动扩容的命令变化如下:最小10个最大15个副本,当cpu利用率高于80%的时候,会增加副本的数量

kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80

 

4.3 deployment演示

 

  • deployment_nginx.yml文件
  • apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.14.0
            ports:
            - containerPort: 80
  • 创建deployment
  1. kubectl create -f deployment_nginx.yml

  2. kubectl get deployment

  3. kubectl get rs

  4. kubectl get pods

 

  • deployment信息

可以看到这个deloyment

kubectl get deployment -o wide

  • deployment的升级

针对目前的nginx1.14.0升级成latest的命令,老的下面自动移除了,全部都在新的下面。

scale 进行deployment扩容与压缩

kubectl set image deployment nginx-deployment nginx=nginx:1.13 --record=true
kubectl get deployment
kubectl get deployment -o wide
kubectl get pods

注意:--record=true 起到记录的作用,下面回滚操作查看历史的时候,可以看到change-reason

 

除了 kubectl set image deployment/nginx-deployment ...我们还可以使用edit命令来编辑修改 deloyment

就像vim编辑器一样 只需要保存即可更新deployment

 

  • deployment查看历史版本
kubectl rollout history deployment nginx-deployment

  • deployment 回滚到之前的版本

又变成了nginx 1.14.0

kubectl rollout undo deployment nginx-deployment -n nginx --to-revision=5

到现在,不知道你能不能领悟到 《容器集会将网络和存储从底层容器抽象出来,这样就可以轻松移动容器了》这句话的涵义。即,无论你的deployment(也就是pod)怎么变,service一点都不会变,外部访问的方式不变。看下图。

 更多操作见(K8S 进阶 -2(deployment,replicateSet...)

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值