阿里云容器服务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搭建和管理企业级网站应用
目录
相关文章
|
4天前
|
运维 安全 Devops
构建高效稳定的云基础设施:DevOps与容器化技术融合实践
在数字化转型的浪潮中,企业对于IT基础设施的要求越来越高,不仅需要快速响应市场变化,还要确保系统的稳定与安全。本文深入探讨了如何通过融合DevOps文化和容器化技术来构建一个高效、稳定且易于管理的云基础设施。通过实际案例分析,阐述了持续集成/持续部署(CI/CD)流程的优化、自动化测试、监控以及日志管理等关键环节的实施策略,旨在为运维专业人员提供一套切实可行的解决方案。
16 3
|
7天前
|
缓存 Kubernetes Docker
容器服务ACK常见问题之容器服务ACK ingress websocket配置失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
存储 Kubernetes Docker
容器服务ACK常见问题之阿里云控制台进不去了如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
存储 运维 Kubernetes
容器服务ACK常见问题之容器服务ACK 淘宝源过期了如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
运维 Kubernetes Devops
构建高效可靠的云基础设施:DevOps与容器化技术融合实践
【2月更文挑战第30天】 在当今快速迭代和竞争激烈的软件开发领域,传统的IT运维模式已难以满足业务发展的需要。本文将探讨如何通过整合DevOps文化和容器化技术,构建一个既高效又可靠的云基础设施。文章首先回顾了DevOps的核心理念及其对运维工作流的影响,接着深入讨论了容器化技术的优势和挑战,并提出了一套结合两者的实施方案。最后,通过案例分析展示了该方案在实际环境中的应用效果和潜在益处。
|
2天前
|
运维 Kubernetes 监控
构建高效稳定的云基础设施:DevOps与容器化技术融合实践
在当今云计算时代,企业追求敏捷性、可扩展性以及成本效益的云基础设施。本文将探讨如何通过DevOps文化与容器化技术的融合,打造一个既高效又稳定的运维环境。文章不仅阐述了DevOps和容器化技术各自的优势,还提供了一个具体的实施案例,展示了这种结合如何优化资源利用、提高部署速度并降低运维复杂性。
|
5天前
|
运维 监控 Devops
构建高效自动化运维体系:基于容器技术的持续集成与持续部署实践
在数字化转型的浪潮中,企业的IT基础设施和软件交付模式正经历着深刻的变革。传统的运维方式已难以满足快速迭代、灵活扩展的现代业务需求。本文将探讨如何通过容器技术实现高效的自动化运维体系,重点分析持续集成(CI)与持续部署(CD)的实践方法及其对企业运维效率的影响。通过引入微服务架构、容器编排、DevOps文化等概念,我们旨在为读者提供一套全面的自动化运维解决方案,以支持业务的敏捷性和可扩展性。
|
7天前
|
弹性计算 网络协议 关系型数据库
网络技术基础阿里云实验——企业级云上网络构建实践
实验地址:<https://developer.aliyun.com/adc/scenario/65e54c7876324bbe9e1fb18665719179> 本文档指导在阿里云上构建跨地域的网络环境,涉及杭州和北京两个地域。任务包括创建VPC、交换机、ECS实例,配置VPC对等连接,以及设置安全组和网络ACL规则以实现特定服务间的互访。例如,允许北京的研发服务器ECS-DEV访问杭州的文件服务器ECS-FS的SSH服务,ECS-FS访问ECS-WEB01的SSH服务,ECS-WEB01访问ECS-DB01的MySQL服务,并确保ECS-WEB03对外提供HTTP服务。
|
7天前
|
存储 Kubernetes 监控
容器服务ACK常见问题之容器服务ACK启动时readiness告警如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
存储 Kubernetes 监控
容器服务ACK常见问题之容器服务ACK worker节点选择不同地域失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。

相关产品

  • 容器服务Kubernetes版