这篇学习笔记是基于杜宽老师在51CTO上发布的视频课程制作的。在此,感谢杜宽老师的分享和教学。如有侵权,请及时联系我。版权归原作者所有,未经允许不得转载或使用。
一、Service
1、什么是Service
每个Pod都会获取到它自己的IP地址,但是这些IP地址不总是稳定和可依赖的,这样就会导致一个问题:在Kubernetes集群中,如果一组Pod(比如后端的Pod)为其他Pod(比如前端的Pod)提供服务,那么如果它们之间使用Pod的IP地址进行通信,在Pod重建后,将无法再进行连接。于是Kubernetes引用了Service这样一种抽象概念:逻辑上的一组Pod,即一种可以访问Pod的策略。这一组Pod能够被Service通过标签选择器访问到,之后就可以使用Service进行通信。
Service可以简单的理解为逻辑上的一组Pod。一种可以访问Pod的策略,而且其他Pod可以通过这个Service访问到这个Service代理的Pod。相对于Pod而言,它会有一个固定的名称,一旦创建就固定不变。
2、创建一个简单的Service
# cat nginx-svc.yaml
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: nginx # 和pod的标签一致
ports:
- protocol: TCP
port: 80 # Service本身的端口号
targetPort: 80 # 容器的端口号
# 创建一个服务
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx # Deployment的标签和Service的标签可以不同
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx # 和Service的标签一致
spec:
containers:
- name: nginx
image: nginx:1.15.12
ports:
- containerPort: 80
该示例为 my-service:80 即可访问到具有 app=myapp 标签的 Pod 的 80 端口上。
需要注意的是,Service 能够将一个接收端口映射到任意的 targetPort,如果 targetPort 为空,targetPort 将被设置为与 Port 字段相同的值。targetPort 可以设置为一个字符串,引用 backend Pod 的一个端口的名称,这样的话即使更改了 Pod 的端口,也不会对 Service 的访问造成影响。
Kubernetes Service 能够支持 TCP、UDP、SCTP 等协议,默认为 TCP 协议。
3、Service类型
Kubernetes Service Type(服务类型)主要包括以下几种
类型 | 说明 |
---|---|
ClusterIP | 在集群内部使用,默认值,只能从集群中访问 |
ExternalName | 通过返回定义的 CNAME 别名,没有设置任何类型的代理,需要 1.7 或更高版本 kube-dns 支持 |
NodePort | 在所有安装了 Kube-Proxy 的节点上打开一个端口,此端口可以代理至后端Pod,可以通过 NodePort 从集群外部访问集群内的服务,格式为 NodeIP:NodePort。NodePort端口范围默认是30000-32767 |
LoadBalancer | 使用云提供商的负载均衡器公开服务,成本较高 |
4、NodePort 类型
如果将 Service 的 type 字段设置为 NodePort,则 Kubernetes 将从--service-node-port-range 参数指定的范围(默认为 30000-32767)中自动分配端口,也可以手动指定 NodePort,创建该 Service后,集群每个节点都将暴露一个端口,通过某个宿主机的 IP+端口即可访问到后端的应用。
定义一个 NodePort 类型的 Service 格式如下
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
spec:
type: NodePort
ports:
- port: 443
targetPort: 8443
nodePort: 30000
selector:
k8s-app: kubernetes-dashboard
5、使用Service代理k8s外部应用
使用场景:
- 希望在生产环境中使用某个固定的名称而非 IP 地址访问外部的中间件服务
- 希望 Service 指向另一个 Namespace 中或其他集群中的服务
- 正在将工作负载转移到 Kubernetes 集群,但是一部分服务仍运行在 Kubernetes 集群之外的 backend
# cat nginx-svc-external.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
sessionAffinity: None
type: ClusterIP
# cat nginx-ep-external.yaml
---
apiVersion: v1
kind: Endpoints
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
subsets:
- addresses:
- ip: 140.205.94.189
ports:
- name: http
port: 80
protocol: TCP
Endpoint IP 地址不能是 loopback(127.0.0.0/8)、link-local(169.254.0.0/16)或者 link-local 多播地址(224.0.0.0/24)
访问没有 Selector 的 Service 与有 Selector 的 Service 的原理相同,通过 Service 名称即可访问,请求将被路由到用户定义的 Endpoint
6、ExternalName Service代理域名
ExternalName Service 是 Service 的特例,它没有 Selector,也没有定义任何端口和 Endpoint,它通过返回该外部服务的别名来提供服务。
比如可以定义一个 Service,后端设置为一个外部域名,这样通过 Service 的名称即可访问到该域名。使用 nslookup 解析以下文件定义的 Service,集群的 DNS 服务将返回一个值为my.database.example.com 的 CNAME 记录
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: www.baidu.com
# create svc
# kubectl create -f nginx-externalName.yaml
service/nginx-externalname created
# 查看svc
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d4h
nginx-externalname ExternalName <none> www.baidu.com <none> 27s
nginx-svc ClusterIP 10.96.141.65 <none> 80/TCP,443/TCP 4d3h
nginx-svc-external ClusterIP 10.109.18.238 <none> 80/TCP 18m
7、多端口 Service
例如将 Service 的 80 端口代理到后端的 9376,443 端口代理到后端的 9377
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: myapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
二、Ingress
1、Ingress概念
通俗来讲,ingress和之前提到的Service、Deployment,也是一个k8s的资源类型,ingress用于实现用域名的方式访问k8s内部应用。
Ingress为Kubernetes集群中的服务提供了入口,可以提供负载均衡、SSL终止和基于名称(域名)的虚拟主机、应用的灰度发布等功能,在生产环境中常用的Ingress有Treafik、Nginx、HAProxy、lstio等。
2、Ingress Controller 安装
官方安装文档:https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters
# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.0/deploy/static/provider/baremetal/deploy.yaml # 官方,需要修改镜像
# kubectl create -f deploy-ingress.yaml # 课程自带(推荐)
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
serviceaccount/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
configmap/ingress-nginx-controller created
service/ingress-nginx-controller created
service/ingress-nginx-controller-admission created
deployment.apps/ingress-nginx-controller created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
3、使用域名发布 K8s 的服务
创建一个 web 服务
kubectl create deploy nginx --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12
暴露服务
kubectl expose deploy nginx --port 80
创建 Ingress
vim web-ingress.yaml
apiVersion: networking.k8s.io/v1 # k8s >= 1.22 必须 v1
kind: Ingress
metadata:
name: nginx-ingress
spec:
ingressClassName: nginx
rules:
- host: nginx.test.com
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: ImplementationSpecific
参数 | 说明 |
---|---|
pathType | 路径的匹配方式,目前有 ImplementationSpecific、Exact 和 Prefix 方式 |
Exact | 精确匹配,比如配置的 path 为/bar,那么/bar/将不能被路由 |
Prefix | 前缀匹配,基于以 / 分隔的 URL 路径。比如 path 为/abc,可以匹配到/abc/bbb 等,比较常用的配置 |
ImplementationSpecific | 这种类型的路由匹配根据 Ingress Controller 来实现,可以当做一个单独的类型,也可以当做 Prefix 和 Exact。ImplementationSpecific是 1.18 版本引入 Prefix 和 Exact 的默认配置 |
4、Ingress 特例:不配置域名发布服务
# vim ingress-no-host.yaml
apiVersion: networking.k8s.io/v1 # k8s >= 1.22 必须 v1
kind: Ingress
metadata:
name: nginx-ingress-no-host
spec:
ingressClassName: nginx
rules:
- http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /no-host
pathType: ImplementationSpecific
5、Ingress 接口变化解析
1.19 之前的 v1beta1
apiVersion: networking.k8s.io/v1beta1 # 1.22 之前可以使用 v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
kubernetes.io/ingress.class: "nginx" # 不同的 controller,ingress.class可能不一致
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
serviceName: service1
servicePort: 4200
- path: /bar
pathType: ImplementationSpecific
backend:
serviceName: service2
servicePort: 8080
评论区