文章目录
示例应用介绍
代码:https://github.com/Hugh-yw/kubernetes-example
源码目录结构如下:
$ ls
backend deploy frontend
backend 目录为后端源码,frontend 目录为前端源码,deploy 目录是应用的 K8s Manifest,前后端都已经包含构建镜像所需的 Dockerfile。
示例应用由三个服务组成:
1. 前端;
2. 后端;
3. 数据库。
其中,前端采用 React 编写,它也是应用对外提供服务的入口;后端由 Python 编写;数据库采用流行的 Postgres。
应用整体架构如下图所示:
应用的 K8s 部署架构图如下:
部署应用到k8s
1.创建ns
$ kubectl create namespace example
2.部署db
$ kubectl create -f https://github.com/Hugh-yw/kubernetes-example/blob/main/deploy/database.yaml -n example
3.部署前后端
$ kubectl create -f https://github.com/Hugh-yw/kubernetes-example/blob/main/deploy/frontend.yaml -n example
$ kubectl create -f https://github.com/Hugh-yw/kubernetes-example/blob/main/deploy/backend.yaml -n example
4.创建ingressroute和hpa
cat front-ingroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: frontend-service
spec:
entryPoints:
- web
routes:
- match: Host(`frontend.demo.com`)
kind: Rule
services:
- name: frontend-service
port: 3000
- match: Host(`frontend.demo.com`) && PathPrefix(`/api`)
kind: Rule
services:
- name: backend-service
port: 5000
$ kubectl create -f https://github.com/Hugh-yw/kubernetes-example/blob/main/deploy/hpa.yaml -n example
5.通过域名“frontend.demo.com”访问前端页面,测试新增、删除数据。
如何使用命名空间隔离团队及应用环境?
NameSpace简介
创建和删除
在一个 K8s 集群中,命名空间可以划分为两种类型:系统级命名空间和用户自定义命名空间。
系统级的命名空间是 K8s 集群默认创建的命名空间,主要用来隔离系统级的对象和业务对象,系统级的命名空间下面四种。
- default:默认命名空间,也就是在不指定命名空间时的默认命名空间。
- kube-system:K8s 系统级组件的命名空间,所有 K8s 的关键组件(例如 kube-proxy、coredns、metric-server 等)都在这个命名空间下。
- kube-public:开放的命名空间,所有用户(包括未经认证)的用户都可以读取,这个命名空间是一个约定,但不是必须。
- kube-node-lease:和集群扩展相关的命名空间。
在这几个命名空间中,除了 default 命名空间,你都不应该将业务应用部署在其他系统默认创建的命名空间下,也不要尝试去删除它们,这可能会导致集群异常。
创建:
kubectl create ns xxx
kubectl create -f test-ns.yaml
删除:
kubectl delete ns xxx
删除命名空间将会删除该命名空间下的所有资源,所以在实际项目中请谨慎操作。另外,由于删除动作是异步的,因此删除中的命名空间状态会由正常的 Active 转变为 Terminating,也就是“终止中的状态”。
什么时候使用命名空间?
当有以下场景需求时,我建议你考虑使用命名空间。
- 环境管理:你可以使用命名空间来隔离开发环境、预发布环境和生产环境。例如用 dev、staging、prod 命名空间来区分这三个环境。命名空间的隔离特性可以让开发环境的的操作不会影响到其他环境的工作。实际上,对于这种情况,我更建议使用不同的集群进行硬隔离,命名空间的隔离方式只是一种选择。
- 隔离: 当你有多个团队,或者多个产品线运行在同一个集群时,你可以使用命名空间来隔离这些团队或者产品线,让他们相互之间不受影响。你甚至可以为每一个开发分配一个命名空间,让他们独立进行开发工作。
- 资源控制: 你可以在命名空间级别配置 CPU、内存等资源配额。通过这个方法,你可以为某个团队或者某条业务线设置总的资源配额,而不需要关注他们具体在每一个工作负载上怎么分配这些资源。此外,命名空间的资源配额还能够合理确保每一个项目所需要的资源配额,避免出现资源恶性竞争导致业务不稳定的情况。
- 权限控制:K8s 的 RBAC 可以帮助我们对某个用户仅授权一个或者多个命名空间,确保只有特定的用户能访问特定命名空间下的资源。
- 提高集群性能: 命名空间有利于提高集群性能。在进行资源搜索时,命名空间有利于 K8s API 缩小查找范围,对减小搜索延迟和提升性能具有一定的帮助。
如何跨命名空间通信?
如何为业务选择最适合的工作负载类型?
如何解决服务发现问题?
ExternalName 类型的Service Manifest示例:
apiVersion: v1
kind: Service
metadata:
name: backend-service
namespace: default
spec:
type: ExternalName
externalName: backend-service.example.svc.cluster.local
当应用到集群之后,在 default 命名空间下访问 http://backend-serivce:5000 时,
请求将会被转发到 example 命名空间下的 backend-service。会发现虽然目标 Service 和请求发起方不在同一个命名空间下,
但可以通过这种方法屏蔽它们在不同命名空间的调用差异,使得两个服务看起来像是在同一个命名空间下。
此外,当需要通过 Service 名称的方式请求外部服务时,例如请求在集群外的数据库服务,也可以使用这种方法。
如何迁移应用配置?
Kubernetes 应用配置的三种方案:
- Env 环境变量
- ConfigMap
- Secret
其中,Env 可以向 Pod 注入环境变量,使得业务应用在容器内可以直接读取它们。ConfigMap 经常用于为 Pod 注入配置文件,例如 ini、conf、.env 配置文件等。Secret 一般用来向 Pod 注入机密信息,例如第三方应用的 Token 等。
如何将集群的业务服务暴露外网访问?
在 Kubernetes 环境下,对外暴露服务则需要通过 Service 来实现。由于 Service 的 IP 默认是一个集群内的 IP,无法从外部访问,所以需要为 Service 赋予外网 IP 地址。其中,NodePort 类型可以通过 Kubernetes 节点外网 IP + 端口号的方式提供外网访问能力,不过并不推荐在生产环境使用这种方式。
LoadBalancer 类型则需要依赖云厂商的负载均衡器,一般由云厂商实现。在对 Service 配置为 LoadBalancer 类型后,云厂商将会异步创建负载均衡器实例,这种方式将暴露服务和 Kubernetes 节点进行了解耦,是一种常用的服务暴露方式。
不过在生产环境下,也不推荐以 LoadBalancer 的方式暴露所有需要在外网访问的业务服务,因为这不利于统一管理访问流量,并且还要为多个负载均衡器实例支付高昂的费用。为了解决这个问题,强大的社区引入了 Ingress 来暴露服务。
值得注意的是,要使用 Ingress 除了声明 Ingress 对象以外,还需要为集群安装 Ingress-Controller,例如最常见的 Ingress-Nginx、Traefik等。在生产环境下,Ingress-Nginx 正是通过 LoadBalancer 类型的 Service 来自身暴露在公网环境的。
通过 Ingress 暴露服务的方式是我们在生产环境下最常用的方法,同时也是服务暴露的最佳实践。
如何保障业务资源需求和自动弹性扩容?
如何自动检查业务真实的健康状态?
背景:
如果业务应用没有做好垃圾回收或者产生死锁,那么再运行一段时间后,它的内存和 CPU 消耗会迅速飙升。显然,这时候 Pod 已经处于不健康状态了,怎么让 kubernetes 识别并将它重启呢?
这时就需要使用到 kubernetes 的健康检查特性
。