service是k8s中的一个重要概念,主要是提供负载均衡和服务自动发现。前端
Service 是由 kube-proxy 组件,加上 iptables 来共同实现的。node
建立Service的方法有两种:nginx
1.经过kubectl expose建立后端
#kubectl expose deployment nginx --port=88 --type=NodePort --target-port=80 --name=nginx-service 这一步说是将服务暴露出去,其实是在服务前面加一个负载均衡,由于pod可能分布在不一样的结点上。 –port:暴露出去的端口 –type=NodePort:使用结点+端口方式访问服务 –target-port:容器的端口 –name:建立service指定的名称
2.经过yaml文件建立api
建立一个名为hostnames-yaohong的服务,将在端口80接收请求并将连接路由到具备标签选择器是app=hostnames的pod的9376端口上。架构
使用kubectl creat来建立seriviceapp
apiVersion: v1 kind: Service metadata: name: hostnames-yaohong spec: selector: app: hostnames ports: - name: default protocol: TCP port: 80 //该服务的可用端口 targetPort: 9376 //具备app=hostnames标签的pod都属于该服务
使用以下命令来检查服务:负载均衡
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.187.0.1 <none> 443/TCP 18d
使用kubectl exec 命令来远程执行容器中命令less
$ kubectl -n kube-system exec coredns-7b8dbb87dd-pb9hk -- ls / bin coredns dev etc home lib media mnt proc root run sbin srv sys tmp usr var
双横杠(--)表明kubectl命令项的结束,在双横杠后面的内容是指pod内部须要执行的命令。
服务并非和pod直接相连的,介于他们之间的就是Endpoint资源。curl
Endpoint资源就是暴露一个服务的IP地址和端口列表。
经过service查看endpoint方法以下:
$ kubectl -n kube-system get svc kube-dns NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterI P 10.187.0.2 <none> 53/UDP,53/TCP 19d $ kubectl -n kube-system describe svc kube-dns Name: kube-dns Namespace: kube-system Labels: addonmanager.kubernetes.io/mode=Reconcile k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=CoreDNS Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"prometheus.io/scrape":"true"},"labels":{"addonmanager.kubernetes.io/mode":... prometheus.io/scrape: true Selector: k8s-app=kube-dns Type: ClusterIP IP: 10.187.0.2 Port: dns 53/UDP TargetPort: 53/UDP Endpoints: 10.186.0.2:53,10.186.0.3:53 //表明服务endpoint的pod的ip和端口列表 Port: dns-tcp 53/TCP TargetPort: 53/TCP Endpoints: 10.186.0.2:53,10.186.0.3:53 Session Affinity: None Events: <none>
直接查看endpoint信息方法以下:
#kubectl -n kube-system get endpoints kube-dns NAME ENDPOINTS AGE kube-dns 10.186.0.2:53,10.186.0.3:53,10.186.0.2:53 + 1 more... 19d #kubectl -n kube-system describe endpoints kube-dns Name: kube-dns Namespace: kube-system Labels: addonmanager.kubernetes.io/mode=Reconcile k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=CoreDNS Annotations: <none> Subsets: Addresses: 10.186.0.2,10.186.0.3 NotReadyAddresses: <none> Ports: Name Port Protocol ---- ---- -------- dns 53 UDP dns-tcp 53 TCP Events: <none>
若是建立pod时不包含选择器,则k8s将不会建立endpoint资源。这样就须要建立endpoint来指的服务的对应的endpoint列表。
service中建立endpoint资源,其中一个做用就是用于service知道包含哪些pod。
除了手动配置来访问外部服务外,还可使用彻底限定域名(FQDN)访问外部服务。
apiVersion: v1 kind: Service metadata: name: Service-yaohong spec: type: ExternalName //代码的type被设置成了ExternalName
externalName: someapi.somecompany.com // 实际服务的彻底限定域名(FQDN)
port: - port: 80
服务建立完成后,pod能够经过external-service.default.svc.cluster.local域名(甚至是external-service)链接外部服务。
有3种方式在外部访问服务:
1.将服务的类型设置成NodePort;
2.将服务的类型设置成LoadBalance;
3.建立一个Ingress资源。
NodePort 服务是引导外部流量到你的服务的最原始方式。NodePort,正如这个名字所示,在全部节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。
YAML 文件相似以下:
apiVersion: v1 kind: Service metadata: name: Service-yaohong spec: type: NodePort //为NodePort设置服务类型 ports: - port: 80 targetPort: 8080 nodeport: 30123 //经过集群节点的30123端口能够访问服务 selector: app: yh
这种方法有许多缺点:
1.每一个端口只能是一种服务
2.端口范围只能是 30000-32767
若是节点/VM 的 IP 地址发生变化,你须要能处理这种状况
基于以上缘由,我不建议在生产环境上用这种方式暴露服务。若是你运行的服务不要求一直可用,或者对成本比较敏感,你可使用这种方法。这样的应用的最佳例子是 demo 应用,或者某些临时应用。
LoadBalancer 服务是暴露服务到 internet 的标准方式。在 GKE 上,这种方式会启动一个 Network Load Balancer[2],它将给你一个单独的 IP 地址,转发全部流量到你的服务。
经过以下方法来定义服务使用负载均衡
apiVersion: v1 kind: Service metadata: name: loadBalancer-yaohong spec: type: LoadBalancer //该服务从k8s集群的基础架构获取负载均衡器 ports: - port: 80 targetPort: 8080 selector: app: yh
什么时候使用这种方式?
若是你想要直接暴露服务,这就是默认方式。全部通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎能够发送任何种类的流量到该服务,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。
这个方式的最大缺点是每个用 LoadBalancer 暴露的服务都会有它本身的 IP 地址,每一个用到的 LoadBalancer 都须要付费,这将是很是昂贵的。
为何使用Ingress,一个重要的缘由是LoadBalancer服务都须要建立本身的负载均衡器,以及独有的公有Ip地址,而Ingress只须要一个公网Ip就能为许多服务提供访问。
Ingress 事实上不是一种服务类型。相反,它处于多个服务的前端,扮演着“智能路由”或者集群入口的角色。
你能够用 Ingress 来作许多不一样的事情,各类不一样类型的 Ingress 控制器也有不一样的能力。
编写以下ingress.yml文件
kind: Ingress metadata: name: ingressyaohong spec: rules: - host: kubia.example.com http: paths: - path: / backend: serviceName: kubia-nodeport servicePort: 80
经过以下命令进行查看ingress
# kubectl create -f ingress.yml
经过kubectl get ing命令进行查看ingress
# kubectl get ing NAME HOSTS ADDRESS PORTS AGE ingressyaohong kubia.example.com 80 2m
了解Ingress的工做原理
什么时候使用这种方式?
Ingress 多是暴露服务的最强大方式,但同时也是最复杂的。Ingress 控制器有各类类型,包括 Google Cloud Load Balancer, Nginx,Contour,Istio,等等。它还有各类插件,好比 cert-manager[5],它能够为你的服务自动提供 SSL 证书。
若是你想要使用同一个 IP 暴露多个服务,这些服务都是使用相同的七层协议(典型如 HTTP),那么Ingress 就是最有用的。若是你使用本地的 GCP 集成,你只须要为一个负载均衡器付费,且因为 Ingress是“智能”的,你还能够获取各类开箱即用的特性(好比 SSL、认证、路由等等)。
1.将不一样的服务映射到相同的主机不一样的路径
apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: rules: - host: kubia.example.com http: paths: - path: /yh //对kubia.example.com/yh请求转发至kubai服务 backend: serviceName: kubia servicePort:80 - path: /foo //对kubia.example.com/foo请求转发至bar服务 backend: serviceName: bar servicePort:80
2.将不一样的服务映射到不一样的主机上
apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: rules: - host: yh.example.com http: paths: - path: / //对yh.example.com请求转发至kubai服务 backend: serviceName: kubia servicePort:80 - host: bar.example.com http: paths: - path: / //对bar.example.com请求转发至bar服务 backend: serviceName: bar servicePort:80
客户端和控制器之间的通讯是加密的,而控制器和后端pod之间的通讯则不是。
apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: tls: //在这个属性中包含全部的TLS配置 - hosts: - yh.example.com //将接收来自yh.example.com的TLS链接 serviceName: tls-secret //从tls-secret中得到以前创立的私钥和证书 rules: - host: yh.example.com http: paths: - path: / //对yh.example.com请求转发至kubai服务 backend: serviceName: kubia servicePort:80
就绪探针有三种类型:
1.Exec探针,执行进程的地方。容器的状态由进程的退出状态代码肯定。
2.HTTP GET探针,向容器发送HTTP GET请求,经过响应http状态码判断容器是否准备好。
3.TCP socket探针,它打开一个TCP链接到容器的指定端口,若是链接创建,则认为容器已经准备就绪。
启动容器时,k8s设置了一个等待时间,等待时间后才会执行一次准备就绪检查。以后就会周期性的进行调用探针,并根据就绪探针的结果采起行动。
若是某个pod未就绪成功,则会从该服务中删除该pod,若是pod再次就绪成功,则重新添加pod。
与存活探针区别:
就绪探针若是容器未准备就绪,则不会终止或者重启启动。
存活探针经过杀死异常容器,并用新的正常的容器来替代他保证pod正常工做。
就绪探针只有准备好处理请求pod才会接收他的请求。
重要性;
确保客户端只与正常的pod进行交互,而且永远不会知道系统存在问题。
添加的yml文件以下
apiVersion: v1 kind: deployment ... spec: ... port: containers: - name: kubia-yh imgress: luksa/kubia readinessProbe: failureThreshold: 2 httpGet: path: /ping port: 80 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 5 successThreshold: 1 timeoutSeconds: 3
相关参数解释以下:
HTTP探针在httpGet上的配置项:
模拟就绪探针
# kubectl exec <pod_name> -- curl http://10.187.0.139:80/ping % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
Headless Service
也是一种Service
,但不一样的是会定义spec:clusterIP: None
,也就是不须要Cluster IP
的Service
。
顾名思义,Headless Service
就是没头的Service
。有什么使用场景呢?
第一种:自主选择权,有时候client
想本身来决定使用哪一个Real Server
,能够经过查询DNS
来获取Real Server
的信息。
第二种:Headless Services
还有一个用处(PS:也就是咱们须要的那个特性)。Headless Service
的对应的每个Endpoints
,即每个Pod
,都会有对应的DNS
域名;这样Pod
之间就能够互相访问。