Apache APISIX 初体验

2022-02-11 09:20:40 浏览数 (3)

Apache APISIX 是一个基于 OpenResty 和 Etcd 实现的动态、实时、高性能的 API 网关,目前已经是 Apache 的顶级项目。提供了丰富的流量管理功能,如负载均衡、动态路由、动态 upstream、A/B测试、金丝雀发布、限速、熔断、防御恶意攻击、认证、监控指标、服务可观测性、服务治理等。可以使用 APISIX 来处理传统的南北流量以及服务之间的东西向流量。

与传统 API 网关相比,APISIX 具有动态路由和热加载插件功能,避免了配置之后的 reload 操作,同时 APISIX 支持 HTTP(S)、HTTP2、Dubbo、QUIC、MQTT、TCP/UDP 等更多的协议。而且还内置了 Dashboard,提供强大而灵活的界面。同样也提供了丰富的插件支持功能,而且还可以让用户自定义插件。

上图是 APISIX 的架构图,整体上分成数据面和控制面两个部分,控制面用来管理路由,主要通过 etcd 来实现配置中心,数据面用来处理客户端请求,通过 APISIX 自身来实现,会不断去 watch etcd 中的 route、upstream 等数据。

APISIX Ingress

同样作为一个 API 网关,APISIX 也支持作为 Kubernetes 的一个 Ingress 控制器进行使用。APISIX Ingress 在架构上分成了两部分,一部分是 APISIX Ingress Controller,作为控制面它将完成配置管理与分发。另一部分 APISIX(代理) 负责承载业务流量。

当 Client 发起请求,到达 Apache APISIX 后,会直接把相应的业务流量传输到后端(如 Service Pod),从而完成转发过程。此过程不需要经过 Ingress Controller,这样做可以保证一旦有问题出现,或者是进行变更、扩缩容或者迁移处理等,都不会影响到用户和业务流量。

同时在配置端,用户通过 kubectl apply 创建资源,可将自定义 CRD 配置应用到 K8s 集群,Ingress Controller 会持续 watch 这些资源变更,来将相应配置应用到 Apache APISIX(通过 admin api)。

从上图可以看出 APISIX Ingress 采用了数据面与控制面的分离架构,所以用户可以选择将数据面部署在 K8s 集群内部或外部。但 Ingress Nginx 是将控制面和数据面放在了同一个 Pod 中,如果 Pod 或控制面出现一点闪失,整个 Pod 就会挂掉,进而影响到业务流量。这种架构分离,给用户提供了比较方便的部署选择,同时在业务架构调整场景下,也方便进行相关数据的迁移与使用。

APISIX Ingress 控制器目前支持的核心特性包括:

  • 全动态,支持高级路由匹配规则,可与 Apache APISIX 官方 50 多个插件 & 客户自定义插件进行扩展使用
  • 支持 CRD,更容易理解声明式配置
  • 兼容原生 Ingress 资源对象
  • 支持流量切分
  • 服务自动注册发现,无惧扩缩容
  • 更灵活的负载均衡策略,自带健康检查功能
  • 支持 gRPC 与 TCP 4 层代理

安装

我们这里在 Kubernetes 集群中来使用 APISIX,可以通过 Helm Chart 来进行安装,首先添加官方提供的 Helm Chart 仓库:

代码语言:javascript复制
➜ helm repo add apisix https://charts.apiseven.com
➜ helm repo update

由于 APISIX 的 Chart 包中包含 dashboard 和 ingress 控制器的依赖,我们只需要在 values 中启用即可安装 ingress 控制器了:

代码语言:javascript复制
➜ helm fetch apisix/apisix
➜ tar -xvf apisix-0.7.2.tgz
➜ mkdir -p apisix/ci

apisix/ci 目录中新建一个用于安装的 values 文件,内容如下所示:

代码语言:javascript复制
# ci/prod.yaml
apisix:
  enabled: true

  nodeSelector:  # 固定在node2节点上
    kubernetes.io/hostname: node2

gateway:
  type: NodePort
  externalTrafficPolicy: Cluster
  http:
    enabled: true
    servicePort: 80
    containerPort: 9080

etcd:
  enabled: true  # 会自动创建3个节点的etcd集群
  replicaCount: 1  # 多副本需要修改下模板,这里暂时运行一个etcd pod

dashboard:
  enabled: true

ingress-controller:
  enabled: true
  config:
    apisix:
      serviceName: apisix-admin
      serviceNamespace: apisix  # 指定命名空间,如果不是 ingress-apisix 需要重新指定

经测试官方的 Helm Chart 包对 etcd 多节点集群支持不是很好,我测试跑3个节点会出问题,应该还需要重新修改模板去兼容,另外对外部的 etcd tls 集群兼容度也不好,比如 dashboard 的 Chart 需要自己修改模板去支持 tls,所以这里我们测试先改成 1 个副本的 etcd 集群。

APISIX 需要依赖 etcd,默认情况下 Helm Chart 会自动安装一个3副本的 etcd 集群,需要提供一个默认的 StorageClass,如果你已经有默认的存储类则可以忽略下面的步骤,这里我们安装一个 nfs 的 provisioner,用下面的命令可以安装一个默认的 StorageClass:

代码语言:javascript复制
➜ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
➜ helm upgrade --install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner 
--set nfs.server=192.168.31.31   # 指定nfs地址
--set nfs.path=/var/lib/k8s/data   # nfs路径
--set image.repository=cnych/nfs-subdir-external-provisioner 
--set storageClass.defaultClass=true -n kube-system

安装完成后会自动创建一个 StorageClass:

代码语言:javascript复制
➜ kubectl get sc
NAME                   PROVISIONER                                     RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
nfs-client (default)   cluster.local/nfs-subdir-external-provisioner   Delete          Immediate              true                   35s

然后直接执行下面的命令进行一键安装:

代码语言:javascript复制
➜ helm upgrade --install apisix ./apisix -f ./apisix/ci/prod.yaml -n apisix
Release "apisix" does not exist. Installing it now.
NAME: apisix
LAST DEPLOYED: Thu Dec 30 16:28:38 2021
NAMESPACE: apisix
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace apisix -o jsonpath="{.spec.ports[0].nodePort}" services apisix-gateway)
  export NODE_IP=$(kubectl get nodes --namespace apisix -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT

正常就可以成功部署 apisix 了:

代码语言:javascript复制
➜ kubectl get pods -n apisix
NAME                                         READY   STATUS    RESTARTS   AGE
apisix-dashboard-b69d5c768-r6tqk             1/1     Running   0          85m
apisix-etcd-0                                1/1     Running   0          90m
apisix-fb8cdb569-wz9gq                       1/1     Running   0          87m
apisix-ingress-controller-7d5bbf5dd5-r6khq   1/1     Running   0          85m
➜ kubectl get svc -n apisix
NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
apisix-admin                ClusterIP   10.97.108.252    <none>        9180/TCP            3h
apisix-dashboard            NodePort    10.108.202.136   <none>        80:31756/TCP        3h
apisix-etcd                 ClusterIP   10.107.150.100   <none>        2379/TCP,2380/TCP   3h
apisix-etcd-headless        ClusterIP   None             <none>        2379/TCP,2380/TCP   3h
apisix-gateway              NodePort    10.97.214.188    <none>        80:32200/TCP        3h
apisix-ingress-controller   ClusterIP   10.103.176.26    <none>        80/TCP              3h

测试

现在我们可以为 Dashboard 创建一个路由规则,新建一个如下所示的 ApisixRoute 资源对象即可:

代码语言:javascript复制
apiVersion: apisix.apache.org/v2beta2
kind: ApisixRoute
metadata:
  name: dashboard
  namespace: apisix
spec:
  http:
    - name: root
      match:
        hosts:
          - apisix.qikqiak.com
        paths:
          - "/*"
      backends:
      - serviceName: apisix-dashboard
        servicePort: 80

创建后 apisix-ingress-controller 会将上面的资源对象通过 admin api 映射成 APISIX 中的配置:

代码语言:javascript复制
➜ kubectl get apisixroute -n apisix
NAME        HOSTS                    URIS     AGE
dashboard   ["apisix.qikqiak.com"]   ["/*"]   75m

所以其实我们的访问入口是 APISIX,而 apisix-ingress-controller 只是一个用于监听 crds,然后将 crds 翻译成 APISIX 的配置的工具而已,现在就可以通过 apisix-gateway 的 NodePort 端口去访问我们的 dashboard 了:

默认登录用户名和密码都是 admin,登录后在路由菜单下正常可以看到上面我们创建的这个 dashboard 的路由信息:

点击更多下面的查看就可以看到在 APISIX 下面真正的路由配置信息:

所以我们要使用 APISIX,也一定要理解其中的路由 Route 这个概念,路由(Route)是请求的入口点,它定义了客户端请求与服务之间的匹配规则,路由可以与服务(Service)、上游(Upstream)关联,一个服务可对应一组路由,一个路由可以对应一个上游对象(一组后端服务节点),因此,每个匹配到路由的请求将被网关代理到路由绑定的上游服务中。

理解了路由后自然就知道了我们还需要一个上游 Upstream 进行关联,这个概念和 Nginx 中的 Upstream 基本是一致的,在上游菜单下可以看到我们上面创建的 dashboard 对应的上游服务:

其实就是将 Kubernetes 中的 Endpoints 映射成 APISIX 中的 Upstream,然后我们可以自己在 APISIX 这边进行负载。

APISIX 提供的 Dashboard 功能还是非常全面的,我们甚至都可以直接在页面上进行所有的配置,包括插件这些,非常方便。

当然还有很多其他高级的功能,比如流量切分、请求认证等等,这些高级功能在 crds 中去使用则更加方便了,当然也是支持原生的 Ingress 资源对象的,关于 APISIX 的更多高级用法,后续再进行说明。

0 人点赞