Kubernetes学习(三)Service

Service对象

为什么需要Service

每个Pod都有自己的IP地址,但是在Deployment中,在同一时刻运行的Pod集合可能与稍后运行该应用程序的Pod集合不同。

这就导致了一个问题:如果一组Pod(称为后端)为集群内其他Pod(称为前端)提供功能,那么前端如何找出并跟踪要连接的IP地址,以便前端可以使用后端服务?

Service定义

将运行在一组Pods上的应用程序公开为网络服务的抽象方法

使用Kubernetes服务无需修改应用程序即可使用通用的服务发现机制。Kubernetes为Pods提供自己的IP地址,并为一组Pod提供相同的DNS,并且可以在他们之间进行负载均衡。

定义Service

Service在Kubernetes中是一个REST对象,和Pod类似。像所有的REST对象一样,Service定义可以基于POST方式,请求API server创建新的实例。

例如,有一组Pod,它们对外暴露9376端口,同时还被打上app=myapp标签

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 9376
[root@master k8s]# kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1                443/TCP   2d22h
my-service   ClusterIP   10.104.177.192           80/TCP    7s

上述配置创建一个名为my-service的Service对象,它会将请求代理到使用tcp端口的9376,并且具有标签app=myapp的Pod上,Kubernetes为该服务分配了一个IP地址(或集群IP),改IP地址有服务代理使用。

需要注意的是,Service能够将一个接口port映射到任意的tatgetPort。默认情况下,targetPort与port字段值相同。

用Service暴露Pod服务地址

在集群中暴露Pod

创建一个nginx pod,声明具有一个80的容器端口

nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx
          resources:
            limits:
              memory: "128Mi"
              cpu: "500m"
          ports:
            - containerPort: 80

Pod 的 IP 地址:

[root@master k8s]# kubectl get pods -l run=my-nginx -o yaml | grep podIP
    podIP: 10.244.2.23
    podIPs:
    podIP: 10.244.1.11
    podIPs:
[root@master k8s]#

此时能够通过 ssh 登录到集群中的任何一个节点上,使用 curl 也能调通所有 IP 地址。 需要注意的是,容器不会使用该节点上的 80 端口,也不会使用任何特定的 NAT 规则去路由流量到 Pod 上。 这意味着可以在同一个节点上运行多个 Pod,使用相同的容器端口,并且可以从集群中任何其他的 Pod 或节点上使用 IP 的方式访问到它们。

创建Service

Kubernetes Service 从逻辑上定义了运行在集群中的一组 Pod,这些 Pod 提供了相同的功能。 当每个 Service 创建时,会被分配一个唯一的 IP 地址(也称为 clusterIP)。 这个 IP 地址与一个 Service 的生命周期绑定在一起,当 Service 存在的时候它也不会改变。 可以配置 Pod 使它与 Service 进行通信,Pod 知道与 Service 通信将被自动地负载均衡到该 Service 中的某些 Pod 上。

示例:nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx

上述规约将创建一个 Service,对应具有标签  `run: my-nginx`  的 Pod,目标 TCP 端口 80, 并且在一个抽象的 Service 端口(`targetPort`:容器接收流量的端口;`port`:抽象的 Service 端口,可以使任何其它 Pod 访问该 Service 的端口)上暴露。 

[root@master k8s]# kubectl get service my-nginx
NAME       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
my-nginx   ClusterIP   10.111.78.3           80/TCP    57s
[root@master k8s]# 

正如前面所提到的,一个 Service 由一组 backend Pod 组成。这些 Pod 通过  `endpoints`  暴露出来。 Service Selector 将持续观察,结果被 POST 到一个名称为  `my-nginx`  的 Endpoint 对象上。 当 Pod 终止后,它会自动从 Endpoint 中移除,新的能够匹配上 Service Selector 的 Pod 将自动地被添加到 Endpoint 中。 检查该 Endpoint,注意到 IP 地址与在第一步创建的 Pod 是相同的。

[root@master k8s]# kubectl describe  service my-nginx
Name:              my-nginx
Namespace:         default
Labels:            
Annotations:       
Selector:          run=my-nginx
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.111.78.3
IPs:               10.111.78.3
Port:                80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.11:80,10.244.2.23:80
Session Affinity:  None
Events:            
[root@master k8s]# 
[root@master k8s]# kubectl get ep my-nginx
NAME       ENDPOINTS                       AGE
my-nginx   10.244.1.11:80,10.244.2.23:80   2m14s
[root@master k8s]# 

现在,能够从集群中任意节点上使用 curl 命令请求 Nginx Service  `:`  。 注意 Service IP 完全是虚拟的,它从来没有走过网络。

[root@master k8s]# curl 10.111.78.3:80



Welcome to nginx!



Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

[root@master k8s]#

集群内Pod通信机制

Kubernetes支持两种基本的服务发现模式--环境变量和DNS

环境变量

当Pod运行在Node上,kubelet会为每个活跃的Service添加一组环境变量。它同时支持Dockerlinks、简单的{SVCNAME}_SERVICE_HOST和{SVCNAME}_SERVICE_PORT变量。这里Service的名称需大写,横线被转换成下划线。

实例,一个名为my-nginx的Service暴露了TCP端口80,同时分配了Cluster IP地址10.1.180.155,这个Service生成了如下的环境变量:

MY_NGINX_PORT_80_TCP_PORT=80

MY_NGINX_PORT_80_TCP_PROTO=tcp

MY_NGINX_PORT_80_TCP_ADDR=10.1.180/155

注意:当具有需要访问服务的Pod时,并且正在使用环境变量的方法将端口和集群IP发布到客户端Pod时,必须在客户端Pod出现之前创建服务。否则,这些客户端Pod将不会设定其环境变量

DNS

可以使用附加组件为Kubernetes集群设置DNS服务

支持集群的DNS服务器(例如CoreDNS)监视Kubernetes API中的新服务,并为每个服务创建一组DNS记录。如果整个集群中都启用了DNS,则所有的Pod都应该能够通过其DNS名称自动解析服务。

例如,在Kubernetes命名空间my-ns中有一个名为my-service的服务,则控制节点和DNS服务共同为my-service.my-ns创建DNS记录。my-ns命名空间中的Pod能够通过简单的对my-service进行名称查找来找到它。

其他命名空间中的Pod必须将名称限定为my-service.my-ns,这些名称将解析为服务分配的集群IP

Service创建DNS记录

Kubernetes DNS在集群上调度DNS Pod和服务,并配置kubelet以告知各个容器使用DNS服务的IP来解析DNS名称

服务

  • A/AAAA记录

普通服务会以my-svc.my-namespace.svc.cluster-domain.example这种名称的形式被分配一个DNS A或AAAA记录,取决于服务的IP协议族,该名称会解析成对应服务的集群IP

  • Pods A/AAAA记录

经由Deployment或者DaemonSet所创建的所有Pods都会有如下DNS解析项与之对应:

pod-ip-address.deploymnet-name.my-namespace.svc.cluster-domain.example

Pod规约中包含一个可选的hostname字段,可以用来指定Pod的主机名,当这个字段被设置是,它将优先于Pod的名字称为该Pod的主机名、举例,给定一个hostname为my-host的Pod,该Pod的主机名将被设置成my-host

Pod规约中还有一个可选的subdomain字段,可以用来指定Pod子域名。举例,某Pod hostname=foo,subdomain=bar,在命名空间my-ns中对应的完全限定域名为foo.bar.my-ns.svc.cluster-domain.example

实例:dns.yaml

apiVersion: v1
kind: Service
metadata:
  name: busybox
spec:
  selector:
    app: busybox
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox-1
  labels:
    app: busybox
spec:
  hostname: busybox-1
  subdomain: default-subdomain
  containers:
    - name: busybox
      image: busybox:1.28
      command: ["sh", "-c", "sleep 1h"]
      resources:
        limits:
          memory: "128Mi"
          cpu: "500m"
      ports:
        - containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox-2
  labels:
    app: busybox
spec:
  hostname: busybox-2
  subdomain: default-subdomain
  containers:
    - name: myapp
      image: busybox:1.28
      command: ["sh", "-c", "sleep 1h"]
      resources:
        limits:
          memory: "128Mi"
          cpu: "500m"
      ports:
        - containerPort: 80
[root@master k8s]# kubectl exec -it busybox-1 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # hostname -f
busybox-1.default-subdomain.default.svc.cluster.local

从集群外部访问Service

从集群外部访问Service的方法:

1、Cluster IP

仅仅使用一个集群内部的Ip地址(默认值)。选择这个值意味着只想这个服务在集群内部才可以被访问到

2、NodePort

在集群内部IP的基础上,在集群每个节点的端口上开发这个服务。可以再任意NodePort地址上访问这个服务

3、LoadBalancer

在使用一个集群内部IP地址和在NodePort上开放一个服务外,像云提供商申请一个负载均衡器,会让流量转发到每个在节点上移NodePort形式开放的服务上。

在使用一个集群内部IP地址和在NodePort上开放一个Service的基础上,像云提供商申请一个负载均衡器,会让流量转发到每个在节点上移NodePort形式开放的Service上。

示例:

1、创建nginx pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.cn-beijing.aliyuncs.com/qingfeng666/nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80

2、创建NodePort类型的Service

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30001

Ingress

Ingress是对集群中服务的外部访问进行管理的api对象,典型的访问方式是http

Ingress公开了从集群外部带内部服务的http和https路由。流量路由由ingress资源上定义的规则控制

图示是一个将所有流量都发送到同一个Service的简单Ingress示例:

Kubernetes学习(三)Service_第1张图片

可以将Ingress配置为服务提供外部可访问的URL、负载均衡流量、终止SSL/TLS,以及提供基于名称的虚拟主机等能力。Ingress控制器通常负责通过负载均衡器来实现Ingress

环境准备

必须具有Ingress控制器才能满足Ingress的要求,仅创建Ingress资源本身没有任何效果,需要部署Ingress控制器,例如ingress-nginx

Ingress资源

最小的Ingress资源示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: hello-world.info
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 8080

Ingress资源仅支持用于转发http流量的规则

Ingress规则

每个HTTP规则都包含以下信息:

1、可选的host。若果未指定host,则规则只适用于通过指定IP地址的所有入站http通信;如果提供了host(例如foo.bar.com),则规则适用于该host

2、路径列表paths,每个路径都有一个有serviceName和servicePod定义的关联后端。在负载均衡器将流量定向到引用的服务之前,主机和路径都必须匹配传入请求的内容

3、backend是Service服务和端口组合。与规则host和path匹配的Ingress的HTTP请求将发送到列出的backend

安装Nginx Ingress控制器

https://github.com/kubernetes/ingress-nginx

版本对应

Kubernetes学习(三)Service_第2张图片

下载对应版本的ingress-nginx,提取部署文件 deploy/static/provider/cloud/deploy.yaml

# 修改Service(名称:ingress-nginx-controller)的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.5.1
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  externalTrafficPolicy: Local
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  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

替换国内镜像

registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.5.1

registry.aliyuncs.com/google_containers/kube-webhook-certgen:v20220916-gd32f8c343

查询 ingress-nginx 命名空间下的 deployment、pod、service 资源

get deployment,pods,service -n ingress-nginx -o wide
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                                                                    SELECTOR
deployment.apps/ingress-nginx-controller   1/1     1            1           41s   controller   registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.5.1   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx

NAME                                           READY   STATUS      RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
pod/ingress-nginx-admission-create-czqlz       0/1     Completed   0          41s   10.244.2.25   node2              
pod/ingress-nginx-admission-patch-9j694        0/1     Completed   2          41s   10.244.1.13   node1              
pod/ingress-nginx-controller-fbd49d74b-r8cxg   1/1     Running     0          41s   10.244.1.14   node1              

NAME                                         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE   SELECTOR
service/ingress-nginx-controller             NodePort    10.97.172.217           80:19386/TCP,443:13175/TCP   41s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
service/ingress-nginx-controller-admission   ClusterIP   10.109.60.199           443/TCP                      41s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
[root@master k8s]#

Nginx Ingress流量验证

1、创建一个Deployment

[root@master k8s]# kubectl create deployment web --image=registry.cn-beijing.aliyuncs.com/qingfeng666/hello-app:1.0
deployment.apps/web created

2、暴露Deployment

[root@master k8s]# kubectl expose deployment web --type=NodePort --port=8080
service/web exposed

[root@master k8s]# kubectl get service
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1             443/TCP          5d23h
web          NodePort    10.108.4.70           8080:18455/TCP   89s
[root@master k8s]#

访问

[root@master k8s]# curl node1:18455
Hello, world!
Version: 1.0.0
Hostname: web-5978f64c6-jk64w

3、创建Ingress资源

ingress-example.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: hello-world.info
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 8080

创建ingress

[root@master k8s]# kubectl get ingress
NAME              CLASS   HOSTS              ADDRESS         PORTS   AGE
example-ingress   nginx   hello-world.info   10.97.172.217   80      3m34s

修改hosts

[root@master k8s]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
179.220.56.230 master
179.220.56.231 node1
179.220.56.232 node2
10.97.172.217 hello-world.info

访问hello-world.info

[root@master k8s]# curl hello-world.info
Hello, world!
Version: 1.0.0
Hostname: web-5978f64c6-khzk6

你可能感兴趣的:(Kubernetes,kubernetes,学习,docker)