ASP.NET Core on K8S学习之旅(12)Ingress
本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。
一、关于Ingress
Kubernetes对外暴露Service主要有三种方式:NodePort、LoadBalancer 以及 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
好了,搭建和配置部分到此为止,下面我们可以准备刚刚提到的两个Service来进行一个简单的验证了。
三、Nginx Ingress的使用验证
3.1 WebAPI项目准备
这里我准备两个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 统一访问入口》

ASP.NET Core on K8S学习之旅(12)Ingress的更多相关文章
- ASP.NET Core on K8S学习之旅(13)Ocelot API网关接入
本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 上一篇介绍了Ingress的基本概念和Nginx Ingress的基本配置和使 ...
- ASP.NET Core on K8S学习之旅(14)Ingress灰度发布
本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 之前一篇介绍了Ingress的基本概念和Nginx Ingress的基本配置和 ...
- ASP.NET Core on K8S学习初探(1)K8S单节点环境搭建
当近期的一个App上线后,发现目前的docker实例(应用服务BFF+中台服务+工具服务)已经很多了,而我司目前没有专业的运维人员,发现运维的成本逐渐开始上来,所以容器编排也就需要提上议程.因此我决定 ...
- ASP.NET Core on K8S学习初探(3)部署API到K8S
在上一篇<基本概念快速一览>中,我们把基本的一些概念快速地简单地不求甚解地过了一下,本篇开始我们会将ASP.NET Core WebAPI部署到K8S,从而结束初探的旅程. Section ...
- ASP.NET Core on K8S学习初探(2)K8S基本概念快速一览
在上一篇<单节点环境搭建>中,通过Docker for Windows在Windows开发机中搭建了一个单节点的K8S环境,接下来就是动人心弦的部署ASP.NET Core API到K8S ...
- ASP.NET Core on K8S深入学习(1)K8S基础知识与集群搭建
在上一个小系列文章<ASP.NET Core on K8S学习初探>中,通过在Windows上通过Docker for Windows搭建了一个单节点的K8S环境,并初步尝试将ASP.NE ...
- ASP.NET Core on K8S 入门学习系列文章目录
一.关于这个系列 自从2018年底离开工作了3年的M公司加入X公司之后,开始了ASP.NET Core的实践,包括微服务架构与容器化等等.我们的实践是渐进的,当我们的微服务数量到了一定值时,发现运维工 ...
- .NET Core on K8S学习实践系列文章索引(Draft版)
一.关于这个系列 自从去年(2018年)底离开工作了3年的M公司加入X公司之后,开始了ASP.NET Core的实践,包括微服务架构与容器化等等.我们的实践是渐进的,当我们的微服务数量到了一定值时,发 ...
- ASP.NET Core on K8S深入学习(2)部署过程解析与Dashboard
上一篇<K8S集群部署>中搭建好了一个最小化的K8S集群,这一篇我们来部署一个ASP.NET Core WebAPI项目来介绍一下整个部署过程的运行机制,然后部署一下Dashboard,完 ...
随机推荐
- delphi中DateTimePicker控件同时输入日期和时间
将DateTimePicker的Format属性中加入日期格式设成 'yyyy-MM-dd HH:mm',注意大小写 , 将kind设置为dtkTime即可,可以在每次Form onShow时将Dat ...
- AJAX教程——检视阅读
AJAX教程--检视阅读 参考 AJAX 教程--菜鸟 AJAX 教程--w3cschool AJAX 教程--w3school.cn AJAX 教程--易百 AJAX = Asynchronous ...
- tensorflow1.0 变量加法
import tensorflow as tf state = tf.Variable(0,name='counter') print(state.name) one = tf.constant(1) ...
- ElasticSearch的高级复杂查询:非聚合查询和聚合查询
一.非聚合复杂查询(这儿展示了非聚合复杂查询的常用流程) 查询条件QueryBuilder的构建方法 1.1 精确查询(必须完全匹配上,相当于SQL语句中的“=”) ① 单个匹配 termQuery ...
- php微信公众号开发curl返回false
最近刚接触温馨公众号开发,在自定义菜单用curl请求时,碰到了一个小坑.一时半会没有解决,便去问度娘,谷歌.发现都是说$url里面有空格导致的失败. 然而我的并没有空格,一直返回false,这个时候我 ...
- git在push时候出现timeout的解决方法
1.先对照一下公钥是否正确:linux下生成的.ssh在~/.ssh,命令行直接cd ~/.ssh即可:2.本次出现的问题如下: 出现了连接不上的情况,传输协议用的是ssh,此时需要进行如下操作: 进 ...
- 实用的linux 命令(上)
今天介绍几个我常用的Linux 命令,每个命令这里只介绍其常用参数. 对于每个Linux 命令都可以使用man + 命令名称,查看其完整使用方法. 0,man man 命令是一个非常有用的命令,当你不 ...
- 利用python将excel数据导入mySQL
主要用到的库有xlrd和pymysql, 注意pymysql不支持python3 篇幅有限,只针对主要操作进行说明 连接数据库 首先pymysql需要连接数据库,我这里连接的是本地数据库(数据库叫ld ...
- Mybatis 使用 SQL 递归获取单表中的树结构
xml 代码 <resultMap type="xxx.xxx.xxx.xxx.实体类" id="xxxListTree"> <result ...
- opencv-5-图像遍历与图像改变
opencv-5-图像遍历与图像改变 opencvc++qt 目录 目录 开始 图像的像素点访问与遍历 opencv 座标定义 下标访问 指针访问 迭代器法访问 遍历访问时间对比 图像操作 图像叠加 ...