k8s基础篇-服务发布入门

发布时间 2023-07-31 08:27:01作者: 就往丶

基础概念

image-20230730160648358

Label 和 Selector

定义 Label

应用案例:

公司与 xx 银行有一条专属的高速光纤通道,此通道只能与 192.168.7.0 网段进行通信,因此只能将与 xx 银行通信的应用部署到 192.168.7.0 网段所在的节点上,此时可以对节点添加 Label:

# kubectl label node k8s-node02 region=subnet7
node/k8s-node02 labeled

然后可以通过 Selector 对其筛选:

# kubectl get no -l region=subnet7
NAME        STATUS    ROLES    AGE     VERSION
k8s-node02   Ready     <none>   3d17h   v1.12.3

最后在 Deployment 或其他控制器中指定将 Pod 部署到该节点:

containers:
......
dnsPolicy: ClusterFirst  
nodeSelector:
  region: subnet7
restartPolicy: Always
......

也可以用同样的方式对 Service 添加 Label:

# kubectl label svc canary-v1 -n canary-production env=canary version=v1
service/canary-v1 labeled

查看该 Service 的标签:

# kubectl get svc -n canary-production --show-labels 
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     LABELS
canary-v1    ClusterIP   10.110.253.62    <none>        8080/TCP   24h     env=canary,version=v1

还可以查看所有 version 为 v1 的 Service:

# kubectl get svc --all-namespaces -l version=v1
NAMESPACE        NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
canary-production   canary-v1   ClusterIP   10.110.253.62    <none>        8080/TCP        25h

上述演示了对节点、Service 添加自定义标签,对于其他资源的 Label 方式相同。

Selector 选择器

首先使用 --show-labels 查看指定资源目前已有的 Label:

# kubectl get service --show-labels
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE     LABELS
details      ClusterIP   10.99.9.178     <none>        9080/TCP   45h     app=details
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    3d19h   component=apiserver,provider=kubernetes
nginx        ClusterIP   10.106.194.137  <none>        80/TCP     2d21h   app=productpage,version=v1
nginx-v2     ClusterIP   10.108.176.132  <none>        80/TCP     2d20h   <none>
productpage  ClusterIP   10.105.229.52   <none>        9080/TCP   45h     app=productpage,tier=frontend
ratings      ClusterIP   10.96.104.95    <none>        9080/TCP   45h     app=ratings
reviews      ClusterIP   10.102.188.143  <none>        9080/TCP   45h     app=reviews

选择匹配 app 为 details 或者 productpage 的 Service:

# kubectl get svc -l 'app in (details, productpage)' --show-labels
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE     LABELS
details      ClusterIP   10.99.9.178      <none>        9080/TCP  45h     app=details
nginx        ClusterIP   10.106.194.137   <none>        80/TCP    2d21h   app=productpage,version=v1
productpage  ClusterIP   10.105.229.52    <none>        9080/TCP  45h     app=productpage,tier=frontend

选择 app 为 productpage 或 reviews 但不包括 version=v1 的 svc:

# kubectl get svc -l version!=v1,'app in (details, productpage)' --show-labels
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     LABELS
details      ClusterIP   10.99.9.178     <none>        9080/TCP  45h     app=details  
productpage  ClusterIP   10.105.229.52   <none>        9080/TCP  45h     app=productpage,tier=frontend

选择 label 的 key 名为 app 的 svc:

# kubectl get svc -l app --show-labels
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     LABELS
details      ClusterIP   10.99.9.178      <none>        9080/TCP   45h     app=details
nginx        ClusterIP   10.106.194.137   <none>        80/TCP     2d21h   app=productpage,version=v1
productpage  ClusterIP   10.105.229.52    <none>        9080/TCP   45h     app=productpage,tier=frontend
ratings      ClusterIP   10.96.104.95     <none>        9080/TCP   45h     app=ratings
reviews      ClusterIP   10.102.188.143   <none>        9080/TCP   45h     app=reviews

修改标签(Label)

比如将 version=v1 改为 version=v2:

# kubectl get svc -n canary-production --show-labels
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     LABELS
canary-v1    ClusterIP   10.110.253.62    <none>        8080/TCP   26h     env=canary,version=v1

# kubectl label svc canary-v1 -n canary-production version=v2 --overwrite
service/canary-v1 labeled

# kubectl get svc -n canary-production --show-labels
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     LABELS
canary-v1    ClusterIP   10.110.253.62    <none>        8080/TCP   26h     env=canary,version=v2

删除标签(Label)

删除 key 名为 version 的标签:

# kubectl label svc canary-v1 -n canary-production version-
service/canary-v1 labeled 

# kubectl get svc -n canary-production --show-labels
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     LABELS  
canary-v1    ClusterIP   10.110.253.62    <none>        8080/TCP   26h     env=canary

Service

每个Pod都会获取到它自己的JIP地址,但是这些IP地址不总是稳定和可依赖的,这样就会导致一个问题在Kubernetes集群中,如果一组Pod(比如后端的Pod)为其他Pod(比如前端的Pod)提供服务,那么如果它们之间使用Pod的IP地址进行通信,在Pod重建后,将无法再进行连接。于是Kubernetes引用了Service这样一种抽象概念:逻辑上的一组Pod,即一种可以访问Pod的策略。这一组Pod能够被Service通过标签选择器访问到,之后就可以使用Service进行通信

定义 Service

定义 Service 的 yaml 文件如下:

kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:  
    app: nginx
  ports:
  - protocol: TCP 
    port: 80
    targetPort: 80

创建服务:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
labels:
  app: nginx  
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    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 协议。

Service 类型

Kubernetes Service Type(服务类型)主要包括以下几种:

  • ClusterIP:在集群内部使用,默认值,只能从集群中访问。
  • NodePort:在所有安装了 Kube-Proxy 的节点上打开一个端口,此端口可以代理至后端 Pod,可以通过 NodePort 从集群外部访问集群内的服务,格式为 NodeIP:NodePort。
  • LoadBalancer:使用云提供商的负载均衡器公开服务,成本较高。
  • ExternalName:通过返回定义的 CNAME 别名,没有设置任何类型的代理,需要 1.7 或更高版本 kube-dns 支持。

NodePort 类型

如果将 Service 的 type 字段设置为 NodePort,则 Kubernetes 将从 --service-node-port-range 参数指定的范围(默认为 30000-32767)中自动分配端口,也可以手动指定 NodePort,创建该 Service 后,集群每个节点都将暴露一个端口,通过某个宿主机的 IP+端口即可访问到后端的应用。你的服务在其 .spec.ports[*].nodePort 字段中报告已分配的端口。

对于 NodePort 服务,Kubernetes 额外分配一个端口(TCP、UDP 或 SCTP 以匹配服务的协议)。 集群中的每个节点都将自己配置为监听分配的端口并将流量转发到与该服务关联的某个就绪端点。 通过使用适当的协议(例如 TCP)和适当的端口(分配给该服务)连接到所有节点, 你将能够从集群外部使用 通过某个宿主机的 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

使用 Service 代理 K8s 外部服务

使用场景:

  • 希望在生产环境中使用某个固定的名称而非 IP 地址访问外部的中间件服务;
  • 希望 Service 指向另一个 Namespace 中或其他集群中的服务;
  • 正在将工作负载转移到 Kubernetes 集群,但是一部分服务仍运行在 Kubernetes 集群之外的 backend。
  • 两个的名字,协议都需要一样
# 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
# 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

上面部分参数说明:

  • subsets.addresses.ip(string):必需端点的 IP。不可以是本地回路(127.0.0.0/8)、链路本地(169.254.0.0/16)或链路本地多播(224.0.0.0/24)地址。 IPv6 也被接受,但并非在所有平台上都完全支持。 此外,诸如 kube-proxy 等某些 Kubernetes 组件还没有准备好支持 IPv6。
  • subsets.ports.port (int32):必需端点的端口号。
  • subsets.ports.protocol (string):此端口的 IP 协议。必须是 UDP、TCP 或 SCTP。默认值为 TCP。
  • subsets.ports.name (string):端口的名称。此字段必须与相应 ServicePort 中的 name 字段匹配。必须是 DNS_LABEL。 仅当定义了一个端口时才可选。

注意: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。

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: my.database.example.com

当查找主机 my-service.prod.svc.cluster.local 时,集群 DNS 服务返回 CNAME 记录, 其值为 my.database.example.com。 访问 my-service 的方式与其他服务的方式相同,但主要区别在于重定向发生在 DNS 级别,而不是通过代理或转发。 如果以后你决定将数据库移到集群中,则可以启动其 Pod,添加适当的选择算符或端点以及更改服务的 type

多端口 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

什么是Ingress?

Ingress为Kubernetes集群中的服务提供了入口,可以提供负载均衡、SSL终和基于名称(域名)的虚拟主机、应用的灰度发布等功能,在生产环境中常用的lngress有Treafik、Nginx、HAProxy、Istio等。

image-20230730205021309

image-20230730205154445image-20230730205213710

通俗来讲,Ingress和之前提到的Service、Deployment等类似,也是一个Kubernetes的资源对象,Deployment是用来部署应用的,Ingress就是实现用域名的方式访问应用。Ingress实现的方式有很多,比如Nginx、HAProxy、Treafik等,就Nginx而言,和上述提到的传统服务架构用Nginx类似。Ingress控制器在每个符合条件的宿主机上部署一个Pod,这个Pod里面运行的就是Nginx进程,里面的实现逻辑和宿主机部署Nginx的方式并无太大区别,关键区别是宿主机部署的Nginx需要更改Nginx的配置文件配置域名,而Ingress则和其他Kubernetes资源文件一样,使用YAML文件进行配置,之后Ingress控制器根据YAML文件定义的内容自动生成对应的配置文件。

在Kubernetes v1.1版中正式引用Ingress的概念,用于从集群外部到集群内部Service的HTTP和HTTPS路由,可以配置提供服务外部访问的URL、负载均衡和终止SSL,并提供基于域名的虚拟主机。流量从Internet到Ingress再到Services最后到Pod上,通常情况下,Ingress部署在所有的Node节点上,暴露443和80端口(一般通过hostNetwork的方式部署Ingress),之后再通过F5或公有云LB代理到对应的Ingress节点上,之后将域名解析到F5或公有云LB即可实现基于域名的服务发布。

Ingress Controller 安装

官方安装文档:https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters

apiVersion: v1
kind: Namespace
metadata:
  labels:
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  name: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx
  namespace: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-admission
  namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx
  namespace: ingress-nginx
rules:
- apiGroups:
  - ""
  resources:
  - namespaces
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - configmaps
  - pods
  - secrets
  - endpoints
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses/status
  verbs:
  - update
- apiGroups:
  - networking.k8s.io
  resources:
  - ingressclasses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resourceNames:
  - ingress-controller-leader
  resources:
  - configmaps
  verbs:
  - get
  - update
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - create
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-admission
  namespace: ingress-nginx
rules:
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - get
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  - endpoints
  - nodes
  - pods
  - secrets
  - namespaces
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses/status
  verbs:
  - update
- apiGroups:
  - networking.k8s.io
  resources:
  - ingressclasses
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-admission
rules:
- apiGroups:
  - admissionregistration.k8s.io
  resources:
  - validatingwebhookconfigurations
  verbs:
  - get
  - update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx
  namespace: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ingress-nginx
subjects:
- kind: ServiceAccount
  name: ingress-nginx
  namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-admission
  namespace: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
  name: ingress-nginx-admission
  namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ingress-nginx
subjects:
- kind: ServiceAccount
  name: ingress-nginx
  namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-admission
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
  name: ingress-nginx-admission
  namespace: ingress-nginx
---
apiVersion: v1
data:
  allow-snippet-annotations: "true"
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-controller
  namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  ports:
  - appProtocol: http
    name: http
    port: 80
    protocol: TCP
    targetPort: http
  - appProtocol: https
    name: https
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  type: NodePort
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-controller-admission
  namespace: ingress-nginx
spec:
  ports:
  - appProtocol: https
    name: https-webhook
    port: 443
    targetPort: webhook
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  minReadySeconds: 0
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/name: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --election-id=ingress-controller-leader
        - --controller-class=k8s.io/ingress-nginx
        - --ingress-class=nginx
        - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
        - --validating-webhook=:8443
        - --validating-webhook-certificate=/usr/local/certificates/cert
        - --validating-webhook-key=/usr/local/certificates/key
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: LD_PRELOAD
          value: /usr/local/lib/libmimalloc.so
        image: registry.cn-beijing.aliyuncs.com/dotbalo/controller:v1.2.0 
        imagePullPolicy: IfNotPresent
        lifecycle:
          preStop:
            exec:
              command:
              - /wait-shutdown
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        name: controller
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
        - containerPort: 443
          name: https
          protocol: TCP
        - containerPort: 8443
          name: webhook
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          requests:
            cpu: 100m
            memory: 90Mi
        securityContext:
          allowPrivilegeEscalation: true
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          runAsUser: 101
        volumeMounts:
        - mountPath: /usr/local/certificates/
          name: webhook-cert
          readOnly: true
      dnsPolicy: ClusterFirst
      nodeSelector:
        kubernetes.io/os: linux
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 300
      volumes:
      - name: webhook-cert
        secret:
          secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-admission-create
  namespace: ingress-nginx
spec:
  template:
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.2.0
      name: ingress-nginx-admission-create
    spec:
      containers:
      - args:
        - create
        - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
        - --namespace=$(POD_NAMESPACE)
        - --secret-name=ingress-nginx-admission
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        image: registry.cn-beijing.aliyuncs.com/dotbalo/kube-webhook-certgen:v1.1.1 
        imagePullPolicy: IfNotPresent
        name: create
        securityContext:
          allowPrivilegeEscalation: false
      nodeSelector:
        kubernetes.io/os: linux
      restartPolicy: OnFailure
      securityContext:
        fsGroup: 2000
        runAsNonRoot: true
        runAsUser: 2000
      serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-admission-patch
  namespace: ingress-nginx
spec:
  template:
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.2.0
      name: ingress-nginx-admission-patch
    spec:
      containers:
      - args:
        - patch
        - --webhook-name=ingress-nginx-admission
        - --namespace=$(POD_NAMESPACE)
        - --patch-mutating=false
        - --secret-name=ingress-nginx-admission
        - --patch-failure-policy=Fail
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        image: registry.cn-beijing.aliyuncs.com/dotbalo/kube-webhook-certgen:v1.1.1 
        imagePullPolicy: IfNotPresent
        name: patch
        securityContext:
          allowPrivilegeEscalation: false
      nodeSelector:
        kubernetes.io/os: linux
      restartPolicy: OnFailure
      securityContext:
        fsGroup: 2000
        runAsNonRoot: true
        runAsUser: 2000
      serviceAccountName: ingress-nginx-admission
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: nginx
spec:
  controller: k8s.io/ingress-nginx
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.2.0
  name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
  - v1
  clientConfig:
    service:
      name: ingress-nginx-controller-admission
      namespace: ingress-nginx
      path: /networking/v1/ingresses
  failurePolicy: Fail
  matchPolicy: Equivalent
  name: validate.nginx.ingress.kubernetes.io
  rules:
  - apiGroups:
    - networking.k8s.io
    apiVersions:
    - v1
    operations:
    - CREATE
    - UPDATE
    resources:
    - ingresses
  sideEffects: None
# 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

使用域名发布 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 的默认配置;

多域名匹配到相同服务

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

Ingress 特例:不配置域名发布服务

# 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

说明:如果你创建的 Ingress 资源没有在 rules 中定义的任何 hosts,则可以匹配指向 Ingress 控制器 IP 地址的任何网络流量,而无需基于名称的虚拟主机。

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可能不一致