阿里云容器服务Kubernetes实践系列 - Ingress篇

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 本文是我司近期对阿里云容器服务落地实践经验的总结之ingress篇,从原理、实践、到避坑等多方面进行总结。

作者:荣滨,酷划在线后端架构师,关注微服务治理,容器化技术,Service Mesh等技术领域

背景篇

现状

前面一篇文章主要是落地容器化之前对基础网络组件的调研及性能测试,感兴趣的同学请参考:阿里云开源K8S CNI插件terway网络性能测试

目前公司的后端架构基本上是微服务的架构模式,如下图,所有的入站流量均通过API网关进入到后端服务,API网关起到一个“保护神”的作用,监控着所有进入的请求,并具备防刷,监控接口性能,报警等重要功能,流量通过网关后服务间的调用均为RPC调用。

过渡期

在经历完微服务改造后,虽然微服务架构给我们带来了不少红利,但是也不免引入一些问题:

  • 服务拆分导致机器数增多
  • 为了降低资源浪费,多个服务部署到一台主机造成的端口管理成本
  • 不一致的交付环境,造成的排查问题成本

为了解决上述问题,经过调查,我们将目光锁定容器服务Kubernetes,以解决我们的问题,本篇文章主要关注nginx-ingress-controller(后面统一简称NGINX IC)部分,所以下面的架构主要突出API网关及IC。
下图是我们的过渡期方案:
通过引入一个内网的SLB来解决IC做为我们API网关upstream时,服务发现的问题。并且,可以通过逐步切换接口到SLB上达到渐进式迁移的效果,粒度可以做到接口+百分比级别。
过渡期间架构图如下所示:

终态

全部迁移完成后,所有的机器回收,如下图所示:

其实两层SLB是会有浪费的,但由于我们的API网关目前承担着重要的作用,必须找到替代方案才能去掉。
我们也尝试调研了用定制IC,或者Service Mesh架构的Istio方案来解决,由于当时Istio 1.1还没发布,并且大规模使用的案例太少,所以我们保守的选择了目前的这种折中方案,后续要切换到Istio上也不是很麻烦。

按业务线分组IC


默认Kubernetes所有的流量都由一组默认的IC来承担,这个方案我们从一开始就是否定的,所以通过部署多组IC来达到一定的隔离是必要的。最终会是上面图的那个形态。

实践篇

如何启用多IC

查看IC的启动命令参数,可以找到:

其意思是只关注携带annotation为"kubernetes.io/ingress.class",并且与IC启动参数参数--ingress-class的值相同的Ingress定义,不符合的会被忽略,这样就做到了多组IC,Ingress定义之间的隔离。
例如:

containers:
  - args:
    - /nginx-ingress-controller
    - --ingress-class=xwz #看这里
    - --configmap=$(POD_NAMESPACE)/xwz-nginx-configuration
    - --tcp-services-configmap=$(POD_NAMESPACE)/xwz-tcp-services
    - --udp-services-configmap=$(POD_NAMESPACE)/xwz-udp-services
    - --annotations-prefix=nginx.ingress.kubernetes.io
    - --publish-service=$(POD_NAMESPACE)/xwz-nginx-ingress-lb
    - --v=2

以及

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "xwz" #看这里
  labels:
    app: tap-revision-ing
    wayne-app: tap-revision
    wayne-ns: coohua
  name: tap-revision-ing
  namespace: coohua
spec:
  rules:
  - host: staging.coohua.com
    http:
      paths:
      - backend:
          serviceName: tap-revision-stable
          servicePort: 80
        path: /

接下来我们来看下IC在Kubernetes内部署的资源结构,如图所示:

可以看到一组IC其实由以下几部分组成:

  • ServiceAccount,ClusterRole,ClusterRoleBinding:权限RBAC定义
  • Deployment:控制controller的部署,并依赖ServiceAccount,Configmap,Service
  • ConfigMap:三个configmap都是保存自定义的controller配置用的
  • Service:这里使用type为LoadBalancer的svc主要是利用阿里云基础服务实现的自动绑定到SLB实例的功能

我们的场景是不需要特殊的权限配置的,所以我们就简单的把红框里面的几个资源复制一份修改下其中的几个配置(例如--ingress-class=xwz),然后直接引用默认IC的ServiceAccount,就完成了一组全新IC的部署,并且与Kubernetes自带的IC是互相隔离的。
这里我把我写好的配置放到我的github上,读者可以参考:ingress resources

创建好新IC后,如果发现IC有如下错误

E0416 11:31:50.831279       6 leaderelection.go:304] Failed to update lock: configmaps "ingress-controller-leader-xwz" is forbidden: User "system:serviceaccount:kube-system:nginx-ingress-controller" cannot update resource "configmaps" in API group "" in the namespace "kube-system"

参考issue,需要修改clusterrole:nginx-ingress-controller,增加如下内容

...
- apiGroups:
  - ""
  resourceNames:
  - ingress-controller-leader-nginx
  - ingress-controller-leader-xwz #将新增加的configmap增加进来,不然会报上面提到的错误
  resources:
  - configmaps
...

扩容的IC实例如何自动添加到SLB的后端服务列表中

方式一 externalTrafficPolicy=Cluster

Service的spec.externalTrafficPolicy当为Cluster的时候:
集群当中的每台主机都可以充当三层路由器,起到负载均衡及转发的作用,但是由于其对请求包进行了SNAT操作,如图所示:

这样导致IC的POD内获取到的client-ip会是转发包过来的那个worker节点的IP,所以在这个模式下我们无法获取客户端的真实IP,如果我们不关心客户端真实IP的情况,可以使用这种方式,然后将所有的worker节点IP加入到SLB的后端服务列表当中即可。

方式二 externalTrafficPolicy=Local

Service的spec.externalTrafficPolicy当为Local的时候:
节点只会把请求转给节点内的IC的POD,由于不经过SNAT操作,IC可以获取到客户端的真实IP,如果节点没有POD,就会报错。这样我们就需要手工维护IC POD,节点,与SLB后端服务之间的关系。那么有没有一种方式可以自动管理维护这个关系呢?其实是有的,阿里云容器服务为我们做好了这一切,只要在type为LoadBalancer的Service上增加如下几个annotation,它就可以为我们将启动了POD的worker节点的端口及IP自动添加到SLB后端服务当中,扩容缩容自动更新,如下所示(注意我们使用的是内网SLB,type为intranet,大家根据实际情况修改):

metadata:
  annotations:
    service.beta.kubernetes.io/alicloud-loadbalancer-address-type: intranet
    service.beta.kubernetes.io/alicloud-loadbalancer-force-override-listeners: "true"
    service.beta.kubernetes.io/alicloud-loadbalancer-id: lb-2zec8x×××××××××965vt
方式一(Cluster) vs 方式二(Local)
对比 Cluster Local
优点 简单,K8S的默认方式 减少网络转发,性能好,能获取客户端真实IP
缺点 SNAT地址伪装网络上增加一跳,性能下降,无法获取客户端真实IP 需要对节点的端口是否打开做检查,需要自定义服务发现(阿里云这块已经做了与SLB的集成)

绕坑篇

nginx worker进程数的问题

我们知道nginx的默认配置worker_processes为auto的时候,会根据当前主机cpu信息自动计算,但是nginx并不是一个cgroups aware的应用,所以其会盲目“自大”的认为有“好多”cpu可以用,这里我们就需要对其进行指定,可以在configmap中设置参数:

apiVersion: v1
data:
  worker-processes: "8"
kind: ConfigMap
metadata:
  annotations:
  labels:
    app: ingress-nginx
  name: xwz-nginx-configuration
  namespace: kube-system

内核参数设置

这块我们暂时使用默认的deployment当中给定的参数,后续调优的时候会根据情况调整

initContainers:
- command:
  - /bin/sh
    - -c
    - |
      sysctl -w net.core.somaxconn=65535
      sysctl -w net.ipv4.ip_local_port_range="1024 65535"
      sysctl -w fs.file-max=1048576
      sysctl -w fs.inotify.max_user_instances=16384
      sysctl -w fs.inotify.max_user_watches=524288
      sysctl -w fs.inotify.max_queued_events=16384

客户端真实IP问题

小流量灰度期间业务同学反馈说第三方的反作弊发现我们调用他们的接口异常,一轮分析下来发现,原来是发给第三方请求中携带的客户端IP被写为了我们API网关的主机IP
还记得前面的架构图吗?

出现这个问题的原因就是我们的IC被放到了OpenResty后面,查看到IC的template中对X-REAL-IP设置的代码部分如下:

这个the_real_ip又是哪来的呢?

可以看到默认情况下,是从remote_addr这个变量获取,在我们的场景下remote_addr就会是API网关的主机IP,所以我们需要修改其为API网关为我们设置好的名为X_REAL_IP的header。我们的做法是将template文件导出修改并以congfigmap的方式挂载进镜像,覆盖原来的配置,配置如下:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  ...
spec:
  template:
    spec:
      containers:
        name: nginx-ingress-controller
        ...
        volumeMounts:
        - mountPath: /etc/nginx/template
          name: nginx-template-volume
          readOnly: true
      ....
      volumes:
      - name: nginx-template-volume
        configMap:
          name: xwz-nginx-template
          items:
          - key: nginx.tmpl
            path: nginx.tmpl

至此问题解决

监控篇 monitoring

在现有的CooHua API网关上,已经有比较详细的各种指标监控,由于ingress-controller也暴露了prometheus的metrics,所以也很简单的直接部署了社区版的dashboard,并对其进行了简单的修改,如下图所示:


监控部署的参考文档奉上:请点击我
自定义的dashboard上传到我个人的github上了:请点击我

Troubleshooting篇

dump nginx.conf文件

请参考这篇文章
https://docs.nginx.com/nginx/admin-guide/monitoring/debugging/#dumping-nginx-configuration-from-a-running-process

Refs

https://yq.aliyun.com/articles/692732?spm=a2c4e.11163080.searchblog.53.764b2ec1hJYa02
https://yq.aliyun.com/articles/645856?spm=a2c4e.11163080.searchblog.97.764b2ec1hJYa02
http://bogdan-albei.blogspot.com/2017/09/kernel-tuning-in-kubernetes.html
https://danielfm.me/posts/painless-nginx-ingress.html
https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies

相关实践学习
Docker镜像管理快速入门
本教程将介绍如何使用Docker构建镜像,并通过阿里云镜像服务分发到ECS服务器,运行该镜像。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
1月前
|
运维 安全 Devops
构建高效稳定的云基础设施:DevOps与容器化技术融合实践
在数字化转型的浪潮中,企业对于IT基础设施的要求越来越高,不仅需要快速响应市场变化,还要确保系统的稳定与安全。本文深入探讨了如何通过融合DevOps文化和容器化技术来构建一个高效、稳定且易于管理的云基础设施。通过实际案例分析,阐述了持续集成/持续部署(CI/CD)流程的优化、自动化测试、监控以及日志管理等关键环节的实施策略,旨在为运维专业人员提供一套切实可行的解决方案。
29 3
|
1月前
|
存储 Kubernetes Docker
容器服务ACK常见问题之阿里云控制台进不去了如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
28天前
|
SQL 存储 API
阿里云实时计算Flink的产品化思考与实践【下】
本文整理自阿里云高级产品专家黄鹏程和阿里云技术专家陈婧敏在 FFA 2023 平台建设专场中的分享。
110744 85
阿里云实时计算Flink的产品化思考与实践【下】
|
1天前
|
存储 Kubernetes Docker
Kubernetes(K8S)集群管理Docker容器(概念篇)
Kubernetes(K8S)集群管理Docker容器(概念篇)
|
10天前
|
运维 Kubernetes Devops
构建高效自动化运维体系:DevOps与容器技术融合实践
【4月更文挑战第15天】 在当今快速发展的信息技术时代,传统的IT运维模式已难以满足业务敏捷性的需求。本文旨在探讨如何通过整合DevOps理念和容器技术来构建一个高效的自动化运维体系。文章将详细阐述DevOps的核心原则、容器技术的基础知识,以及两者结合的优势。此外,文中还将分享一系列实践经验,包括持续集成/持续部署(CI/CD)流程的搭建、微服务架构的应用,以及监控和日志管理策略的优化,以期帮助企业实现快速、可靠且安全的软件交付过程。
|
12天前
|
运维 Devops 持续交付
构建高效稳定的云基础设施:DevOps与容器化技术融合实践
【4月更文挑战第13天】 在当今快速迭代和持续部署的软件开发环境中,传统的IT运维模式已难以满足业务发展的需求。本文聚焦于如何通过融合DevOps理念与容器化技术,构建一个高效、稳定且易于管理的云基础设施。文章将探讨持续集成/持续交付(CI/CD)流程的优化、容器化技术的最佳实践、以及微服务架构下的应用管理,以期为企业提供一种改进运维效率、加速产品上市时间,同时保障系统稳定性的解决方案。
|
13天前
|
JSON Kubernetes Go
无缝集成:在IntelliJ IDEA中利用Kubernetes插件轻松管理容器化应用
无缝集成:在IntelliJ IDEA中利用Kubernetes插件轻松管理容器化应用
24 0
无缝集成:在IntelliJ IDEA中利用Kubernetes插件轻松管理容器化应用
|
24天前
|
消息中间件 Kubernetes Kafka
Terraform阿里云创建资源1分钟创建集群一键发布应用Terraform 创建 Kubernetes 集群
Terraform阿里云创建资源1分钟创建集群一键发布应用Terraform 创建 Kubernetes 集群
16 0
|
26天前
|
人工智能 监控 Serverless
如何基于ACK Serverless快速部署AI推理服务
通过上述步骤,可以在ACK Serverless上快速部署AI推理服务,实现高可用、弹性扩展的服务架构。
19 1
|
26天前
|
Kubernetes 网络协议 Docker
K8S核心插件-coredns服务
K8S核心插件-coredns服务
15 0

相关产品

  • 容器计算服务
  • 容器服务Kubernetes版
  • 推荐镜像

    更多