kubenetes的学习笔记

  • Borg是k8s在谷歌的前身

  • K8s的特点 轻量级消耗小,开源,弹性伸缩,负载均衡,资源管理功能齐全,扩展性好。

  • 网络通信模型

  • 组件通讯模型

  • 资源清单是剧本,k8s组件时演员。资源清单的语法就是Yaml配置

  • 掌握各种控制器的特点,使用定义的方法。

  • k8s的Pod是最小粒度,它不会直接暴露给客户端,而是以service的方式暴露给网络中的client.这个称之为服务发现,我们开源类比dubbo等rpc组件中的服务发现的概念。但是k8s中的service对外的接口解耦程度更加宽松(client不需要实现RPC consumer的SDK这么笨重的客户端)

  • k8s的服务是提倡无状态的,而涉及到状态的部分由存储组件负责,比如存放配置的configMap,存放密码资源的secret,存放普通数据的volume,以及存放缓存的PV组件。我们要掌握存储的特点和选型。

  • 掌握调度器的原理和用法,根据要求,让pod在指定节点运行。

  • k8s的安全:认证与鉴权,访问控制流程。

  • HELM等价于我们linux里面的yum源管理器。掌握HELM插件和自定义方法。
    实现根据CPU等资源使用率自动进行平滑扩展。

  • 整个K8s系统从业务上来看,就是一个高可用的应用系统,它带有自动作业的scheduler调度器,也有无状态业务系统,也有持久化的存储(用分布式存储etcd等实现),以及各种系统配置文件,和后台管理UI或者是命令行UI。而它和普通的应用系统的区别在于它的管理对象是pod,控制器,service,网络,和运维资源等抽象实体。

  • kubelet是节点上的探针,kube proxy是负载均衡器,可以理解为pod对外的拦截器,而节点对外采用防火墙组进行虚拟(这个防火墙组受kubeproxy代理)。

  • k8s核心组件: 管理界面, Api server, 分布式存储组件etcd, 副本控制器, 调度器,kubelet(容器代理), kubeproxy(网络代理)。

  • 还有一些增强组件: coreDNS增强域名解析功能,ingress 增强网络7层代理(默认4层)

  • pod有两种,一种是控制器管理的pod,一种是自主的pod(这种就类似我们自己起一个docker进程一样单调)。

  • 可见控制器是k8s的灵魂

  • 同一个Pod里的进程共享存储和网络端口。

  • replicationSet是ReplicationController的增加版本,多一个分类标签字段,是的replication更加好管理。

  • 一般不会直接使用replicationset而是使用deployment这个高级工具代理(可以实现版本回滚)

  • 虽然我们经常提倡无状态,但是k8s依然支持有状态的pod,即 statefulSet,其体现在:PVC实现数据存储和 无网络代理的hostname不可变,以及有顺序部署pod,3个功能(带存储,有name,有order)。

  • DeamonSet 也是一种特殊的pod,它的特点就是确保每一个Node节点都有一个pod副本。通常用来部署日志采集器或者是性能监控器。

  • Job和CronJob也是一种副本功能。

  • 不管是什么副本,他们底层实现都是k8s控制器和scheduler调度器以及Pod。

  • K8s假定所有pod都在一个扁平的网络中,Pod之间可以直连访问和自由组网。但是事实上这个K8s在我们的私有云并不存在这样的网络,因此我们需要自己实现构建这么一个网络。我们需要先将各个节点Node上的docker容器之间的网络先打通,然后再搭建k8s.

  • k8s可以分为4个组件核心:

  • api server, 用于与node进行交互,或者提供接口给用户输入管理命令(webUI, kubectrl,restAPI).

  • etcd, 分布式存储,把所有集群数据都放再这里,是的K8s程序无状态话,实现轻易的横向扩展。

  • controller-manager, 实现一些具体的api功能。

  • scheduler,使得k8s可以实现自动化管理功能。

  • k8s 的node 也有3个核心组件:

    • kube proxy,相当于一个防火墙的角色,最终实现所有Pod都处于同一个桥接网络里
      (使得结构化复杂的node网络变成扁平化pod网络)。
    • kubelet作为node的容器引擎管理探针
    • 容器引擎,比如docker.
  • 新手入门可以去 kuberneters online 进行练习,利用kubectl命令与cluster交互

  • 对于k8s而已,所谓的镜像是k8s对容器引擎镜像的抽象(功能更加丰富的镜像),而不是具体到某一种容器的镜像(换而言之,不要认为k8s镜像就是docker image镜像,千万不要这样理解)

视频来源: https://www.youtube.com/watch?v=HsvAVGjlN9k 【sunwu51/notebook】

  • service的type 是NodePort,
    创建 service的命令如下:

kubectl expose deployment deployment的名称 --target-port 80 --type NodePort
这就可以把早先创建的deployment对象暴露给集群外部了
,kube-proxy组件会自动生成一个对外的虚拟IP并通过–target-port对外进行暴露。
这个功能的实现对象就是service.

  • 其次类似service和deployment或者是Pod对象,都会一个IP(内外网IP)和一个定义的对象名称(对象ID)
    我们要清楚,这个对象名称可不是简单的一个称号,而是一个被k8s的DNS组件(可能是coreDNS)
    域名解析的一个域名映射。他就是我们实现k8s对象间通信一个非常强大的工具。

  • 但是我们service暴露的也仅仅只是一个K8s集群内部的端口,我们需要进一步的暴露给K8s集群外,就得通过Ingress实现http协议代理对外提供入口了。
    (值得提的一点,就是如果没有ingress,我们就算再Master节点也无法访问到任何k8s对象,因为coreDNSz只能再node之间起到域名解析的作用,master与node之间是没用这个作用的。)

  • 最有趣的是,我们通过ingress暴露出去的Node服务,对方提供访问的IP是master的IP,因为外部访问k8s的node依赖的是k8s集群的api server组件,这个组件时安装在master集群里的。

解读k8s的yaml定义


apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp1
  template:
    metadata:
      labels:
        app: webapp1
    spec:
      containers:
      - name: webapp1
        image: katacoda/docker-http-server:latest
        ports:
        - containerPort: 80

  • 我们可以把它理解为是一份对象实例的声明,

其中 apiVersion 就是接口的版本。
kind 是类定义,这里声明是 Deployment 类
Deployment 的对象名 metadata.name
Deployment的参数表
spec.replicas 参数副本个数
spec.selector.matchLabels.app 外键声明 webapp1,用来给别的实例引用。
spec.template 这里是给容器对象作声明,可以认为它就是一份compose文件。

[ kubectl describe 类型 主键 ]可以查看实例类型
[ kubectl get 类型] 可以查看实例列表

  • service --type=NodePort 可以将Pod暴露到Node端口上(内网),如果需要暴露给外网,则需要采用ingress暴露到api-server中了。

  • 我可以通过标签选择器 Label-Selector 将一组Pods通过 service抽象对象暴露给内网或者外网。

  • service定义访问的方法和策略。

  • 几种service类型:

Cluster IP 这个是service的默认类型,创建这种类型的service,就等于声明可以通过一个分配的clusterIp去访问一组 pods ,可以通过 spec.ports.port去声明service的端口(前提是Pods的端口和spec.ports.port一样)。

【推荐】Target Ports 如果pods的端口和spec.ports.port不一样,那么我们需要用targetport去声明Pods的端口。
比如我们启动一组pods是80端口,我们需要外部用8080访问就得这样声明:

spec:
  ports:
  - port: 8080
    targetPort: 80
  selector:
    app: webapp1-clusterip-targetport

NodePort 将服务暴露到Node节点的端口上,我们可以通过任何Node的内外网IP+Nodeport都能访问到这组pods。(比较特别,需要特意声明–type)

External IPs 我们可以通过如下方式暴露Pods给指定的外网IP(而不是所有node节点)

spec:
  ports:
  - port: 80
  externalIPs:
  - 172.17.0.44
  selector:
    app: webapp1-externalip

Load Balancer 我们可以这样的方式声明service为一个负载均衡器,这个类似看起来就是Ingress组件所支持的功能,有点像加强版的external-ips。

spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: webapp1-loadbalancer

  • ingress是一个external loadbalance. (spec.type为loadbalance的service也是一个external loadbalance)
apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress
  namespace: nginx-ingress
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    targetPort: 443
    protocol: TCP
    name: https
  selector:
    app: nginx-ingress
  externalIPs:
    - 172.17.0.53

从本质上,我们可以看出,这个ingress其实也是一个serivice, 它是NodePort类型,并且指定了spec.externalIPs的对外IP和spec.port对外端口,还声明了443-tcp协议(https)与80-tcp(http)协议端口。而转发规则和权限则由nginx代理了,而路由规则的声明则需要一个 kind: Ingress 的kubenetes对象来负责了,其中ingress对象与nginx-ingress对象的IO是基于约定来实现的。

controlplane $ cat ingress-rules.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: webapp-ingress
spec:
  rules:
  - host: my.kubernetes.example
    http:
      paths:
      - path: /webapp1
        backend:
          serviceName: webapp1-svc
          servicePort: 80
      - path: /webapp2
        backend:
          serviceName: webapp2-svc
          servicePort: 80
      - backend:
          serviceName: webapp3-svc
          servicePort: 80

  • ingress支持负载均衡,SSL,虚拟IP,ingress类似k8s集群里的一个nginx反向代理,整个集群只需要一个ingress代理即可,新增的ingress规则会自动与他绑定。

  • kubelet 使用 liveness probe(存活探针)来确定何时重启容器。例如,当应用程序处于运行状态但无法做进一步操作,liveness 探针将捕获到 deadlock,重启处于该状态下的容器,使应用程序在存在 bug 的情况下依然能够继续运行下去。

  • Kubelet 使用 readiness probe(就绪探针)来确定容器是否已经就绪可以接受流量。只有当 Pod 中的容器都处于就绪状态时 kubelet 才会认定该 Pod处于就绪状态。该信号的作用是控制哪些 Pod应该作为service的后端。如果 Pod 处于非就绪状态,那么它们将会被从 service 的 load balancer中移除。

  • 我们可以通过 kubectl describe pod $pod 来得知监控错误的原因,其实就是了解他在启动过程中的哪一步出错,以及监听接口返回的状态码。

  • 总结:liveness与 readiness 都是用来检测pod是否正常,都是基于HTTP协议(可以基于command,我们不搞这么复杂,适用即可)。他们的区别就是,readiness处理异常的Pod时会直接将他从service的负载均衡清单中移除(待恢复后就可以继续干活),而liveness则会尝试重启抢救一下(重启可以解决90%的问题),由于前两者是基于HTTP协议的,如果程序启动时间太长,就会导致误判,因此,这两个probe需要startup probe 来触发,startup probe会在程序启动成功后才会触发readiness与liveness。

  • readiness prode,可以用来处理流量暴增导致请求队列被塞满,这个时候我们就将他从路由表中临时撤走(并不表示故障),等他不忙了,再安排回来。(就像临时工一样,除了事就让他休个假,等风头过了再回来。)

  • 污点taint 是kubenetes定义的一个Node概念,如果一个node被标记为taint,那么它将无法执行 pod的调度和部署或者是驱逐正在执行的Pod(调度,部署,驱逐这三种行为是可选的)。
    参看: https://blog.frognew.com/2018/05/taint-and-toleration.html,比如我们熟悉的master节点就是一个五点taint节点。

  • 容忍Tolerations,则是taint的孪生概念,它是指一种不挑剔污点的Pod,我们理解为,taint和tolreations都是用来声明 pod与node亲和关系的概念。

  • Container Network Interface (CNI) 比如weave-kube 也可以是一种kube对象的方式存在于集群中。

  • CRI-0 兼容了docker,所以可以运行docker 镜像(理论上不是所有镜像都支持)

  • kubenetes用PersistentVolume对象统一了持久卷的访问接口,它可以支持很多协议,例如 AWS EBS volumes, GCE storage, OpenStack Cinder, Glusterfs and NFS(网络文件系统).

yaml声明如下:


apiVersion: v1
kind: PersistentVolume
metadata:
  name: <friendly-name>
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    server: <server-name>
    path: <shared-path>

spec.nfs.server:
spec.nfs.path: 服务器上文件系统的目录
声明了nfs协议持久卷的服务器地址,
spec.capacity.storage 声明了可用容量大小。
spec.accessModes 声明可支持的访问模式。

这个声明过程只是象征性的挂在磁盘到Kubenetes集群中,如果要分配给应用还得进一步做声明如下:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: claim-mysql
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

只需要声明 用到的磁盘大小和访问模式,之后kubenetes会自动匹配支持这个大小参数的持久卷PersistentVolume

之后我们才可以正式的将卷声明挂载到具体的容器中,声明如下:

spec:
      volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql/data
  volumes:
    - name: mysql-persistent-storage
      persistentVolumeClaim:
        claimName: claim-mysql

  • 总结一下整个过程,将文件系统 映射成K8s的持久卷对象,然后声明持久卷的访问方式和大小,最后将【卷声明】persisteneVolumeClaim 挂在到具体的pod中即可。

pod使用 persisteneVolumeClaim 的yaml配置:

apiVersion: v1
kind: Pod
metadata:
  name: mysql
  labels:
    name: mysql
spec:
  containers:
  - name: mysql
    image: openshift/mysql-55-centos7
    env:
      - name: MYSQL_ROOT_PASSWORD
        value: yourpassword
      - name: MYSQL_USER
        value: wp_user
      - name: MYSQL_PASSWORD
        value: wp_pass
      - name: MYSQL_DATABASE
        value: wp_db
    ports:
      - containerPort: 3306
        name: mysql
    volumeMounts:
      - name: mysql-persistent-storage
        mountPath: /var/lib/mysql/data
  volumes:
    - name: mysql-persistent-storage
      persistentVolumeClaim:
        claimName: claim-mysql
apiVersion: v1
kind: Pod
metadata:
  name: www
  labels:
    name: www
spec:
  containers:
  - name: www
    image: nginx:alpine
    ports:
      - containerPort: 80
        name: www
    volumeMounts:
      - name: www-persistent-storage
        mountPath: /usr/share/nginx/html
  volumes:
    - name: www-persistent-storage
      persistentVolumeClaim:
        claimName: claim-http
  • 最终的效果就是,我们只要改变了持久卷中文件系统的文件内容,容器上的目录文件也会被更新,其次就是容器被删除或者重启,我们依然能够保留数据。

  • 持久卷可用理解为是文件系统的载k8s系统的本地映射,而持久卷声明则可用认为是持久卷的逻辑层,pod用的是逻辑层的存储。

  • 创建secret对象到kubenetes中, data是键值。


apiVersion: v1
kind: Secret
metadata:
   name: test-secret
type: Opaque
data:
   username: $username
   password: $password

Pod使用secret对象的方法:

spec:
  containers:
    - name: mycontainer
      image: alpine:latest
      env:
        - name: SECRET_USERNAME
          valueFrom:
            secretKeyRef:
              name: test-secret
              key: username
        - name: SECRET_PASSWORD
          valueFrom:
            secretKeyRef:
              name: test-secret
              key: password

valueFrom 用来给环境变量赋值。

我们也可以把Secret对象声明卷,然后挂在到同期中,适合证书或者签名配置等文件。

spec:
	volumes:
		- name: secret-volume
    	secret:
    		secretName: test-secret

test-secret就是我们声明kubenetes的secret对象。

我们可以看到, spec.volumes.secret就是一个secret类型的卷(secret的key名会被映射为文件名)。
类比我们之前学的持久卷类型的卷是这样的 spec.volumes.persistentVolumeClaim

spec:
  volumes:
    - name: www-persistent-storage
    persistentVolumeClaim:
        claimName: claim-http

经过多次学习yaml的使用,我们渐渐地就掌握了Yaml的用法了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值