个人笔记,仅本人查阅使用,不保证正确。

零、微服务

微服务架构专注于应用解耦合,通过将应用彻底地组件化和服务化,每个微服务只包含一个非常小的功能,比如权限管理、日志收集等等。由这一组微服务组合起来,提供一个应用的完整功能。

这样的好处是:

  1. 开发更方便了。各微服务不再需要关注其他服务内的细节,直接调用 API 就行。
  2. 方便持续集成。升级只需要重新部署更新了的微服务,不需要更新整个应用。
  3. 方便拓展。遇到性能瓶颈时,只需要拓展瓶颈所在的微服务,不需要拓展整个应用。

当然,这也带来了一些难点:

  1. 业务型微服务,要尽量无状态化。因为只有无状态微服务,才可以方便地做拓展,而不会导致状态不一致。

    • 注:而数据层服务,尽量使用云平台提供的服务,而不是自己搭建。(这样数据层的负载均衡,数据一致性,就都可以甩锅了。)
  2. 成百上千个微服务,需要相互协作。这对运维提出了更高的要求。
  3. bug 追踪更难了,出现 bug 可能很难定位到原因。

于是,kubernetes 应运而生。曾经还有个比 k8s 简单很多的 mesos 与它竞争,但是现在 k8s 已经几乎一统天下了。。

一、基础概念

1. kubernetes 中的对象与资源

Kubernetes 包含若干抽象用来表示系统状态,这些抽象被称作 kubernetes 对象。

而对象(Objects)的实例(Instances),被称做资源(Resources)

对象被用于表示已部署的容器化应用和负载、与它们相关的网络和磁盘资源以及有关集群正在运行的其他操作的信息。

基本的 kubernetes 对象包括:

1). Pod 容器组

Pod 是 k8s 管理的最小的可执行单元,它可包含多个容器,但是通常只有一个。

Pod 封装了应用程序的容器(组)、存储资源、唯一的网络 IP,以及一些容器运行的参数。

同一个 Pod 中的容器,就好像是跑在同一个虚拟机上的应用一样,他们:

  1. 可以通过 localhost 发现对方(即共享网络)
  2. 也共享同一个 Service(也是共享网络)
  3. 也可以共享存储资源

因此,如果一个多容器的应用需要如上三个特性之一,那这个应用以多容器Pod的形式来部署。比如 nginx 静态文件服务器和 nginx_upload 文件上传服务两个容器,一个负责对外提供文件访问,一个服务将文件上传到 nginx 存储空间中。他们显然就需要共享同一个存储资源。

P.S. 生产环境尽量不要直接创建 Pod,应该通过 Deployment 来管理 Pod.

2). Service 服务:用于为 pod 提供稳定的网络 ip

最常用的资源之一!

Service 是一种抽象方式,它将在一组Pod上运行的应用程序公开为网络服务。

如果一个客户端需要使用一项特定的服务,它只需要使用该服务的名称就能找到对应的服务提供者(Pod)。

客户端不需要关心该服务后面的 Pod 有多少个,运行在哪些节点上,ip 是多少等等。

只要你在 kubernetes 为这一组 Pod 定义了一个【服务】,kubernetes 就保证客户端能够通过该服务找到对应的 Pod,不论这些 Pod 现在运行在哪些节点上。

从概念上说, Service 其实就是负载均衡,或者说反向代理。

传统的负载均衡方式,就是用一台 Nginx 服务器做反向代理。

但是这种方式下,虽然后端是负载均衡了,但是 Nginx 服务器却只有一台,它一出问题,系统就挂了。

kubernetes 的 Service 则不同,它在每个节点(Node)上都部署了一个 Proxy,所有对集群服务的访问,都会被节点上的这个 Proxy 转换成对服务(Service)后端容器组(Pod)的访问。

为了满足各类需求,kubernetes 提供了四种类型的 service:

  1. ClusterIP: (默认使用的类型)集群内部 ip,仅用于集群内部 Pods 的通信。
  2. NodePort: 在每个节点上暴露出一个静态 ip。这样可以通过<节点ip>:<port>来访问指定节点上的 Service
  3. LoadBalancer: 使用云提供商(所以本地集群用不了)的 Load Balancer 创建 Service,这会为服务提供一个静态的外网 ip。
  4. ExternalName: 将服务 xxx 映射到一个外部域名上,如 myapp.xxx.me。这样在集群内部访问 xxx.<namespace>.svc.cluster.local,实际上就是访问了外部的 myapp.xxx.me
    • 这种方式隐藏了外部服务的具体服务名称和 pod 的位置。你甚至可以随时将它迁移到别的集群中,或者再将它重新变回 ClusterIP

要将一个 Pod 暴露出去,可以使用 ClusterIP 之外的另外三种 Service Type。

此外,也可以使用 Ingress,和 Service 不同的是,Ingress 提供了一个集中式的集群网络入口。

客户从外网访问 Ingress Controller,然后 Ingress Controller 根据 Ingress 规则,将请求转发到对应的 Service 上。

集群对外只暴露 Ingress Controller(以 NodePort 或 LoadBalancer 的方式),外部请求通过 Ingress Controller 转发到内部对应的 Service 上。

这样集群就只有一个公网 IP,就是 Ingress Controller 的公网 IP,其他所有服务都只能通在内网访问。

Ingress 也可以添加 TLS/SSL 协议,作为一个 SSL/TLS Proxy.

3). Volume 数据卷:在 Pod 之间共享数据/持久化数据

详见 Kubernetes 学习笔记(五):数据卷

4). Namespace 名字空间

名字空间使我们能够在一个物理集群上部署多个虚拟集群,这样的一个虚拟集群,就被称做一个名字空间。

5). Ingress 集群入口网关

Ingress 是一种将进入集群的流量集中管理的资源,目前只支持 http/websocket 这两种协议(不同的 Ingress-controller 实现,对协议的支持也会有差别)。

Ingress 本身只相当于一份配置,它依赖下层的 Ingress-Controller 提供实际的功能。

比如说你本地运行了一个 Ingress Controller,它使用 NodePort 的方式监听所有节点的 80 和 443 端口。

  1. 你修改本地的 /etc/hostsC:\Windows\System32\drivers\etc\hosts 文件,将 nginx.mykubernetes.io 解析到 127.0.0.1(解析到你的节点 ip)
  2. 然后你通过浏览器访问 http://nginx.mykubernetes.io
  3. 这时 ingress-controller 就会受理你的 http 请求,它会将你的请求域名 nginx.mykubernetes.io 已经 http/ws 路径 / 和所有的 Ingress 规则进行匹配,匹配成功,就将请求转发到规则中所定义的 Service.

所以说 Ingress 就是一个基于域名和路径进行请求转发的代理(第七层应用层转发)。相比 Service 的好处是:

  1. 所有流量都集中从这一个入口进入了,不再需要每个对外服务都暴露一个 NodePort。
  2. 通过域名和路径来匹配对应的服务,很直观。
  3. 因为流量集中了,就可以对流量做更多的管控。比如灰度发布。

P.S. 既然有入口网关,自然就有出口网关。出口网关可对集群的对外请求进行限制,比如域名白名单。

K8s 本身没有实现出口网关的功能,但是 Istio 提供了这项功能。

控制器

另外,Kubernetes 包含大量的被称作控制器(controllers) 的高级抽象。控制器基于基本对象构建并提供额外的功能和方便使用的特性。具体包括:

1). ReplicaSet 副本集

副本集的目的是为了在任何时候,都能有一组稳定的副本 Pods 能够正常运行。这通常都是为了保证一组特定的 Pod 一直可用。

  1. 如果一个 Pod 状态为 failed(通常是由于磁盘压力等导致 pod 启动失败),replicaset 会重新创建一个新 pod。(failed 的 pod 不会被自动删除)
  2. 如果一个 Pod 没通过 readiness/liveness 探针,它会被不断重启。

我们通常也不会直接创建 ReplicaSet,而是通过 Deployment 来管理 ReplicaSet 和 Pod

1). Deployment 部署控制器

最常用的资源之一!

Deployment 控制器为 Pod 和 ReplicaSets. 提供声明式的更新。

你为一个 Pod 声明一个你希望达到的状态,然后 Deployment 控制器就会尽力使该 Pod 迁移到这个状态去。

比如说你希望它始终有三个副本正常运行。正常情况下,如果你修改了 Deployment 的 ReplicaSet 模板,Deployment 会立即新建一个 ReplicaSet,然后将流量慢慢切到新的 ReplicaSet 上,慢慢缩容老的 ReplicaSet,最终完全删除掉老的 ReplicaSet。实现平滑更新。

而如果更新后发现问题,也可以随时回退到以前的版本。

3). StatefulSet 有状态副本集

Pod 有两种:

  1. 一种是无状态的,可以通过 Deployment/ReplicaSet 管理,因为它们可以随时被替换,不同的副本之间没有任何区别,请求可以被由任一副本处理。
  2. 而另一种,是有状态 Pod,这类 Pod 需要挂载数据卷,并且保证 Pod 的重启、更新、移动,不会导致数据(状态)的丢失。

但是 Pod 不会自愈,我们需要类似 Deployment 这样的控制器来声明式地管理有状态的 Pod。

那么有状态的 Pod,能不能用 ReplicaSet 管理呢?可当然是可以,但是这只适合单节点的有状态应用。对于数据库集群等分布式应用,它就无能为力了。

为此 k8s 提供了 StatefulSet,它解决的问题有:

  1. 为每个 Pod 提供固定的、唯一的 dns 解析(其实就是通过使用递增整数替代 hash 做 pod 后缀实现的),固定的集群 ip 地址。(注意是每个 Pod,不是通过 Service)
  2. 顺序性 - StatefulSet 中 pod 的启动、更新、销毁默认都是按顺序进行的。而且一次只变更一个 Pod,不会并发!
  3. 唯一的、稳定的持久化存储 - 不同的 Pod 可以使用不同的存储卷,而且当 pod 被重新调度后,仍然能挂载原有的 PersistentVolume,保证了数据的完整性和一致性。

但是 StatefulSet 真用起来还是很复杂,需要考虑很多东西。所以 CoreOS 又出了个 kubernetes operator 来部署这类复杂应用,后续可以了解下。

另外不缺钱的话,存储还是尽量买云服务吧。。

4). DaemonSet 守护进程集

守护进程集会保证每个 Node 上有运行着属于该集合的 Pod 的一个副本,并且它会自动管理这些 Pod 的增删。当节点被添加或删除时,DaemonSet 会自动处理 Pod 的增删以确保每个节点上都有该 Pod 的一个副本。

DaemonSet 常被用于运行每个节点都需要的服务,如日志收集(Fluentd/logstash)、存储(ceph/glusterd)、节点监控(Promethus)等,并且经常会通过 hostPath 类型的数据卷读写节点上的数据。

5). Job 任务

Job 就是一次性的任务,跑完就结束。Job 会确保这个任务正常地终止,否则 Job 会被重新启动。任务成功结束后,会留下一条记录在 kubernetes 中,记录的存留时间是可设定的。

此外还有 CronJob,顾名思义,就是定时自动执行的周期性 Job。

2. kubernetes 控制面

2.1. 节点

kubernetes 是一个“集群操作系统”,既然是集群,自然是会包含多种多样的节点。kubernetes 有两种节点:

  1. 主节点(master):主节点是集群的控制中心,它上面运行了如下几个组件:

    1. kube-apiserver:集群控制层的前端,我们使用 kubectl 时就是一直在与它打交道。
    2. etcd:存放集群数据的键值数据库。(确保该数据有备份)
    3. kube-scheduler:调度器,负责把新建的 pod 选择找个坑(node)“埋”好,它会考虑到各种因素。
    4. kube-controller-manager:控制器都由它运行。
    5. cloud-controller-manager:负责管理与下层的云服务提供商交互的控制器。(实验特性)
  2. 工作节点(Node):提供 kubernetes 运行环境,所有的 pods 都运行在工作节点上。它包含如下几个组件:
    1. kubelet:在每个节点上运行的代理,它确保容器在 pod 中运行。
    2. kube-proxy:它通过维护一组主机上的网络规则和连接转发,实现了 kubernetes 的网络抽象。
    3. 容器运行时:Docker

2.2. 附加组件(Addons)

附加组件使用 kubernetes 的资源来实现一些特性。

  1. CoreDNS:通过 DNS 解析使服务之间能方便地互相发现。
  2. Kubernetes Dashboard:kubernetes 的 Web UI,方便直观地了解集群的状态,并进行一些简单的操作。
  3. Ingress Controller: 集群的流量入口,是 Ingress 的底层支持组件。比较流行的有官方的 Nignx-Controller、Kong 还有 Trafik。

二、基本使用

0. 安装阿里版的 minikube: AliyunContainerService/minikube

学了些理论,到底还是要实际使用过才能真正理解。这就需要一个可用的 kubernetes 集群。

安装一个 k8s 的入门学习环境,最好最简单的选择,官方的 minikube 是其中之一。

minikube 是一个官方推出的单节点 k8s 集群,适用于本地学习/开发。

但是由于某种大家都晓得的原因,官方的 minikube 在国内是访问不到的,所以建议大家安装阿里版的 minikube: AliyunContainerService/minikube,阿里官方的教程就很详细。

1. 在 kubernetes 上运行一个 nginx 应用

minikube 是一个 k8s 集群,前面介绍过,k8s 集群是通过一个 apiserver 提供对集群的操控功能的。

要对一个 k8s 集群进行操作,就需要去访问这个 apiserver,官方提供了一个命令行工具:kubectl,这个工具将 restful api 包装成了方便易用的命令行工具。

下面就来学习一下 kubectl 的基本使用。

P.S. 既然是 restful api,当然就可以通过任何实现了 http 协议的工具访问。kubernetes 官方提供了各种语言的客户端包供使用:https://github.com/kubernetes-client

1.1 kubectl run

首先使用 kubectl run 在集群上运行指定的镜像。

kubectl run nginx --image=nginx:1.10.0

上面这条命令会从 nginx 镜像创建一个容器(单容器的 Pod),然后再创建一个 Deployment 来管理这个 Pod.

1.2 查看 Pods

接下来就可以通过 kubectl get pods 查看到 kubectl run 创建的 Pod 了。

kubectl get pods

1.3 从外部访问集群的 Pods

现在 nginx 已经跑起来了,但是我们不知道它跑在集群的哪个节点上,而且我们也没为它指定任何端口映射,我们没办法访问到它。

为了访问 nginx,我们需要给它分配一个固定的地址,不论它跑在哪个 k8s 节点上,我们都应该能通过这个地址访问到它。k8s 通过 service 提供了这个功能。

可以通过 kubectl expose 命令,为刚刚创建好的 Pod/Depolyment 创建一个 Service,这样就能访问到它了。

kubectl expose deployments nginx --port=80 --type LoadBalancer

如果是在阿里云上跑这个命令,Service 会被分配到一个公网 ip。但 minikube 是本地单节点集群,它的 LoadBalancer 只能分配一个局域网 ip。

而且不能直接通过 kubectl get service 看到局域网的 ip 地址。需要通过 minikube service <schema>:<service-name>:<port> 访问该服务

参考

问题

最新文章

  1. js中push(),pop(),unshift(),shift()的用法小结
  2. 【HOW】如何允许编辑用户配置文件属性
  3. Android IOS WebRTC 音视频开发总结(八十)-- NUBOMEDIA: 首个WebRTC PaaS
  4. Java中length,length(),size()区别
  5. AdaBoosting 3
  6. js之函数
  7. mongoDB研究笔记:复制集数据同步机制
  8. lucene索引日期和数字
  9. PHP Console工具使用分享
  10. Windows下PHP+Eclipse开发环境搭建 及错误解决(apache2.2服务无法启动 发生服务特定错误:1)
  11. POJ 1504 Adding Reversed Numbers (水题,高精度整数加法)
  12. VB语言基础
  13. Mysql表锁定解决
  14. UNIX环境高级编程——环境变量表读取/添加/修改/删除
  15. scrapy中 Mongo的存储
  16. JUC--ConcurrentHashMap
  17. python基础(七)
  18. jenkins安装部署全过程
  19. 浅谈python函数签名
  20. JVM GC-----3、垃圾标记算法(二)

热门文章

  1. BAT 电脑名 用户名
  2. 聊聊Beaglebone Black的cape和device tree overlay和dtc命令【转】
  3. Linux下不借助工具实现远程linux服务器上传下载文件
  4. Docs-.NET-C#-指南-语言参考-预处理器指令:#endregion(C# 参考)
  5. Flutter Drawer 侧边栏、以及侧边栏内 容布局
  6. typeScript模块&lt;二&gt;
  7. ISO/IEC 9899:2011 条款6.2——概念
  8. 安装mysql报错:Can&#39;t find messagefile &#39;/usr/share/mysql/english/errmsg.sys&#39;和/usr/bin/mysqladmin: error while loading shared libraries: libmysqlclient.so.16: cannot open shared object file: No such file or
  9. 面向对象(实际就像python跳用自己写的库那样)
  10. F5 BIG-IP – Useful SNMP oids to monitor