ASP.NET Core on K8S深入学习(12)Ingress

简介: 本文介绍了Ingress的基本概念与Nginx Ingress的安装与配置,然后通过部署两个ASP.NET Core WebAPI服务到K8s集群进行Ingress的快速验证。

本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。

一、关于Ingress

Kubernetes对外暴露Service主要有三种方式:NodePortLoadBalancer 以及 Ingress。前两种我们在第四篇《你必须知道的Service》一文中已经加以介绍,这里我们主要来看看Ingress是个什么鬼。

官网对 Ingress 的定义为 管理对外服务到集群内服务之间规则的集合,通俗点讲就是它定义规则来允许进入集群的请求被转发到集群中对应服务上,从来实现服务暴漏。Ingress 能把集群内 Service 配置成外网能够访问的 URL,流量负载均衡,终止SSL,提供基于域名访问的虚拟主机等等。

我们可以再次回顾一下我们通常访问一个业务的流程:

  • User在浏览中输入一个域名
  • DNS至业务入口,这里一般指外部负载均衡器(Load Balancer),比如阿里云的SLB服务
  • 外部负载均衡器反向代理到K8S的入口,比如Ingress
  • Ingress将请求转交给对应的Service
  • Service将请求对应到某一个具体的Pod  

了解了整个流程,我们再结合官网的定义来看Ingress,可以知道Ingress就是一个K8S集群业务的入口,一个统一访问入口。我们可以使用Traefik、Istio、Nginx、HAProxy来作为Ingress使用,这里我们主要介绍Nginx Ingress,因为我们比较熟悉Nginx一些。

二、Nginx Ingress的安装与配置

这里我们在k8s-master上执行以下的yaml文件来通过DaemonSet的方式部署Nginx Ingress,这个yaml文件可以从ingress-nginx的github上获取,这里我选择的是0.30.0版本。

获取方式:https://github.com/kubernetes/ingress-nginx/tree/nginx-0.30.0/deploy

在static目录下,将mandatory.yaml文件获取下来如下代码所示,这里我做了一点修改(注意我标红的配置):

(1)将原本为Deployment的类型换为了DaemonSet

(2)为Ingress-Controller增加hostNetwork: true的配置,即直接占用宿主机80/443端口

(3)将Ingress-Controller部署到有ingressHost: yes这个label的Node节点上,即我的k8s-node1服务器上

(4)将Ingress-Controller的镜像源改为阿里云镜像仓库:registry.cn-hangzhou.aliyuncs.com

    apiVersion: v1
    kind: Namespace
    metadata:
      name: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: nginx-configuration
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: tcp-services
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: udp-services
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: nginx-ingress-serviceaccount
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRole
    metadata:
      name: nginx-ingress-clusterrole
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    rules:
      - apiGroups:
          - ""
        resources:
          - configmaps
          - endpoints
          - nodes
          - pods
          - secrets
        verbs:
          - list
          - watch
      - apiGroups:
          - ""
        resources:
          - nodes
        verbs:
          - get
      - apiGroups:
          - ""
        resources:
          - services
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - ""
        resources:
          - events
        verbs:
          - create
          - patch
      - apiGroups:
          - "extensions"
          - "networking.k8s.io"
        resources:
          - ingresses
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - "extensions"
          - "networking.k8s.io"
        resources:
          - ingresses/status
        verbs:
          - update
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: Role
    metadata:
      name: nginx-ingress-role
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    rules:
      - apiGroups:
          - ""
        resources:
          - configmaps
          - pods
          - secrets
          - namespaces
        verbs:
          - get
      - apiGroups:
          - ""
        resources:
          - configmaps
        resourceNames:
          # Defaults to "<election-id>-<ingress-class>"
          # Here: "<ingress-controller-leader>-<nginx>"
          # This has to be adapted if you change either parameter
          # when launching the nginx-ingress-controller.
          - "ingress-controller-leader-nginx"
        verbs:
          - get
          - update
      - apiGroups:
          - ""
        resources:
          - configmaps
        verbs:
          - create
      - apiGroups:
          - ""
        resources:
          - endpoints
        verbs:
          - get
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: RoleBinding
    metadata:
      name: nginx-ingress-role-nisa-binding
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: nginx-ingress-role
    subjects:
      - kind: ServiceAccount
        name: nginx-ingress-serviceaccount
        namespace: ingress-nginx
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
      name: nginx-ingress-clusterrole-nisa-binding
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: nginx-ingress-clusterrole
    subjects:
      - kind: ServiceAccount
        name: nginx-ingress-serviceaccount
        namespace: ingress-nginx
    
    ---
    
    apiVersion: apps/v1
    **kind: DaemonSet**
    metadata:
      name: nginx-ingress-controller
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      # replicas: 1
      selector:
        matchLabels:
          app.kubernetes.io/name: ingress-nginx
          app.kubernetes.io/part-of: ingress-nginx
      template:
        metadata:
          labels:
            app.kubernetes.io/name: ingress-nginx
            app.kubernetes.io/part-of: ingress-nginx
          annotations:
            prometheus.io/port: "10254"
            prometheus.io/scrape: "true"
        spec:
          # wait up to five minutes for the drain of connections
          terminationGracePeriodSeconds: 300
          serviceAccountName: nginx-ingress-serviceaccount
          nodeSelector:
            kubernetes.io/os: linux
            **ingressHost: ****"yes"****
          hostNetwork: true**
          containers:
            - name: nginx-ingress-controller
              image: **registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:****0.30.0**
              args:
                - /nginx-ingress-controller
                - --configmap=$(POD_NAMESPACE)/nginx-configuration
                - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
                - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
                - --publish-service=$(POD_NAMESPACE)/ingress-nginx
                - --annotations-prefix=nginx.ingress.kubernetes.io
              securityContext:
                allowPrivilegeEscalation: true
                capabilities:
                  drop:
                    - ALL
                  add:
                    - NET_BIND_SERVICE
                # www-data -> 101
                runAsUser: 101
              env:
                - name: POD_NAME
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              ports:
                - name: http
                  containerPort: 80
                  protocol: TCP
                - name: https
                  containerPort: 443
                  protocol: TCP
              livenessProbe:
                failureThreshold: 3
                httpGet:
                  path: /healthz
                  port: 10254
                  scheme: HTTP
                initialDelaySeconds: 10
                periodSeconds: 10
                successThreshold: 1
                timeoutSeconds: 10
              readinessProbe:
                failureThreshold: 3
                httpGet:
                  path: /healthz
                  port: 10254
                  scheme: HTTP
                periodSeconds: 10
                successThreshold: 1
                timeoutSeconds: 10
              lifecycle:
                preStop:
                  exec:
                    command:
                      - /wait-shutdown
    
    ---
    
    apiVersion: v1
    kind: LimitRange
    metadata:
      name: ingress-nginx
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      limits:
      - min:
          memory: 90Mi
          cpu: 100m
        type: Container

这里顺便说下Ingress的两种部署方式:

(1)基于NodePort方式

基于NodePort的部署思路就是通过在每个节点上开辟NodePort的端口,将流量引入进来,而后通过iptables首先转发到ingress-controller容器中(图中的nginx容器),而后由nginx根据ingress的规则进行判断,将其转发到对应的应用web容器中。

(2)基于HostNetwork方式

相比较起来,HostNetwork模式不再需要创建一个nodePort的svc,而是直接在每个节点都创建一个ingress-controller的容器,而且将该容器的网络模式设为HostNetwork。也就是说每个节点物理机的80和443端口将会被ingress-controller中的nginx容器占用。当流量通过80/443端口进入时,将直接进入到nginx中。而后nginx根据ingress规则再将流量转发到对应的web应用容器中。

OK,两种模式我们就了解到这里,本文采用的是基于hostNetwork的方式占用宿主机80/443端口来作为流量入口。

然后,我们就可以运行创建命令来创建Ingress-Controller了:

    kubectl apply -f mandatory.yaml

执行后的显示如下图所示,它会执行一系列的创建工作如namespace、configmap、serviceaccount、rbac以及daemonset等:

Ingress-Controller创建好之后,我们再来创建一个指导Ingress进行路由转发的规则集ingress-nginx.yaml,其配置如下:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: xdp-poc
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /api/$2
spec:
  rules:
  - host: portal.k8s.xi-life.cn
    http:
      paths:
      - path: /apple(/|$)(.*)
        backend:
          serviceName: apple-api-svc
          servicePort: 80
      - path: /banana(/|$)(.*)
        backend:
          serviceName: banana-api-svc
          servicePort: 80

它的作用其实是帮助Nginx生成正确的Nginx.conf,帮助Nginx将请求转发不同的K8s集群中的Service入口进行处理。这里,我定义了两个后端Service服务,稍后我会介绍这两个Service,现在我们现将其创建一下:

kubectl apply -f ingress-nginx.yaml

现在可以通过kubectl看看是否已经Running:

好了,搭建和配置部分到此为止,下面我们可以准备刚刚提到的两个Service来进行一个简单的验证了。

三、Nginx Ingress的快速验证

3.1 后端API项目准备

这里我准备两个ASP.NET Core WebAPI项目,他们的代码很简单,就只有一个HomeController,负责请求到api/home路由时返回一个json即可。

其中,AppleApi项目返回:

// GET api/home
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    return new string[] { "AppleApi-Home", "v1.0", "Welcome to use AppleApi!" };
}

BananApi项目返回:

// GET api/home
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    return new string[] { "BananaApi-Home", "v1.0", "Welcome to use BananaApi!" };
}

这部分的代码文件可以在我的github上获取:点此获取

然后,我们将这两个项目分别打一个docker镜像并上传到docker hub上,你可以直接使用我的镜像进行这个实验,具体的打包镜像和上传镜像的过程我就不演示了。

直接拉取镜像:docker pull xilife/apple-api-demo:1.0 / docker pull xilife/banana-api-demo:1.0 

3.2 部署yaml文件准备

接下来,我们就分别为两个API项目准备部署yaml文件,并应用该yaml文件创建pod和service:

(1)deploy-appleapi-svc.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: apple-api-demo
  namespace: xdp-poc
  labels:
    name: apple-api-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      name: apple-api-demo
  template:
    metadata:
      labels:
        name: apple-api-demo
    spec:
      containers:
      - name: apple-api-demo
        image: edisonsaonian/apple-api-demo:1.0
        ports:
        - containerPort: 80
        imagePullPolicy: IfNotPresent

---

kind: Service
apiVersion: v1
metadata:
  name: apple-api-svc
  namespace: xdp-poc
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
  selector:
    name: apple-api-demo

需要注意的就是:确保这里Service中定义的namespace(这里是xdp-poc)、服务名(这里是apple-api-svc)以及端口(这里是80)跟之前我们在ingress-nginx.yaml中设置的后端服务名和端口保持一致,否则无法实现请求转发。下面的BananaApi也是需要保持一致,就不再赘述。

(2)deploy-bananaapi-svc.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: banana-api-demo
  namespace: xdp-poc
  labels:
    name: banana-api-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      name: banana-api-demo
  template:
    metadata:
      labels:
        name: banana-api-demo
    spec:
      containers:
      - name: banana-api-demo
        image: edisonsaonian/banana-api-demo:1.0
        ports:
        - containerPort: 80
        imagePullPolicy: IfNotPresent

---

kind: Service
apiVersion: v1
metadata:
  name: banana-api-svc
  namespace: xdp-poc
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
  selector:
    name: banana-api-demo

最后,我们将其部署到K8s集群:

kubectl apply -f deploy-appleapi-svc
kubectl apply -f deploy-bananaapi-svc

现在可以通过kubectl看看是否已经Running:

3.3 快速验证Ingress

由于我们设置的host是portal.k8s.xi-life.cn,因此我们现在自己的客户机上修改一下hosts文件(Windows的话在system32/etc/drivers/hosts)增加一条记录,然后就可以通过浏览器输入域名来进行访问测试了:

(1)apple-api

(2)banana-api

四、小结

本文介绍了Ingress的基本概念与Nginx Ingress的安装与配置,然后通过部署两个ASP.NET Core WebAPI服务到K8s集群进行Ingress的快速验证。当然,我们也可以使用自己的网关来代替Ingress作为外部统一流量入口,也可以使用云产品的LoadBalancer或API网关来替代Ingress也都是可以的(不缺钱的情况下)。

参考资料

(1)梁宽,《再也不踩坑的Kubernetes实战指南

(2)李振良,《一天入门Kubernets教程

(3)马哥(马永亮),《Kubernetes快速入门

(4)花田犯的错,《K8S Nginx Ingress介绍

(5)Lucie_xxm,《Ingress 统一访问入口

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
目录
相关文章
|
1月前
|
缓存 Kubernetes Docker
容器服务ACK常见问题之容器服务ACK ingress websocket配置失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
3月前
|
开发框架 前端开发 JavaScript
盘点72个ASP.NET Core源码Net爱好者不容错过
盘点72个ASP.NET Core源码Net爱好者不容错过
71 0
|
3月前
|
开发框架 .NET
ASP.NET Core NET7 增加session的方法
ASP.NET Core NET7 增加session的方法
37 0
|
3月前
|
开发框架 JavaScript .NET
ASP.NET Core的超级大BUG
ASP.NET Core的超级大BUG
42 0
|
3月前
|
Kubernetes 负载均衡 应用服务中间件
kubernetes—Ingress详解
kubernetes—Ingress详解
72 0
|
3月前
|
Kubernetes 应用服务中间件 nginx
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
42 0
|
1月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
63 0
|
1月前
|
容器
在容器服务ACK中,如果你想更改ALB Ingress的域名和端口
【2月更文挑战第15天】在容器服务ACK中,如果你想更改ALB Ingress的域名和端口
13 3
|
2月前
|
机器学习/深度学习 存储 编解码
多任务学习新篇章 | EMA-Net利用Cross-Task Affinity实现参数高效的高性能预测
多任务学习新篇章 | EMA-Net利用Cross-Task Affinity实现参数高效的高性能预测
42 0

推荐镜像

更多