目 录CONTENT

文章目录

服务发布

简中仙
2022-05-10 / 0 评论 / 0 点赞 / 42 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2024-01-14,若内容或图片失效,请留言反馈。 本文如有错误或者侵权的地方,欢迎您批评指正!

这篇学习笔记是基于杜宽老师在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
0

评论区