k8s之service
ExternalName介绍ExternalName Service是Service的特例,它没有selector,也没有定义任何的端口和 Endpoint。 相反地,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。ExternalName类型的Service用于引入集群外部的服务,它通过externalName 属性指定外部一个服务的地址,然后在集群内部访问此servic
实验环境
k8s环境参考: k8s-v1.20.10 二进制部署指导文档
ExternalName
介绍
- ExternalName Service是Service的特例,它
没有selector,也没有定义任何的端口和 Endpoint
。 相反地,对于运行在集群外部的服务
,它通过返回该外部服务的别名
这种方式来提供服务。 - ExternalName类型的Service用于引入集群外部的服务,它通过externalName 属性指定外部一个服务的地址,然后在集群
内部访问此service就可以访问到外部的服务了变现为集群内部提供了服务,且还是只有内部访问外部
- service FQDN为:
<service-name>.<namespace>.svc.cluster.local
应用场景:跨名称空间访问,default名称空间下的client 服务想要访问nginx-ns名称空间下的nginx-svc服务
实例一
ExternalName类型的Service用于引入集群外部的服务,它通过externalName 属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了
# 创建service
[root@k8s-master-1 external]# cat external.yaml
apiVersion: v1
kind: Service
metadata:
name: external-service
namespace: default
spec:
type: ExternalName
externalName: www.baidu.com #可写ip | 域名
# 测试
[root@k8s-master-1 external]# kubectl run -it busybox --rm --image=busybox:1.28 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup external-service.default.svc.cluster.local 10.0.0.10
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: external-service.default.svc.cluster.local
Address 1: 220.181.38.149
Address 2: 220.181.38.150
# 即实现了在k8s集群内部访问了www.baidu.com
实例二
实现跨namespace访问
[root@k8s-master-1 external]# cat external.yaml
apiVersion: v1
kind: Namespace
metadata:
name: nginx-ns
---
apiVersion: v1
kind: Service
metadata:
name: nginx-ns
namespace: nginx-ns
spec:
selector:
app: "nginx"
type: ClusterIP
ports:
- name: http
port: 88
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: nginx-ns
spec:
replicas: 2
selector:
matchLabels:
app: "nginx"
template:
metadata:
name: nginx
labels:
app: "nginx"
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: external-service
namespace: default
spec:
type: ExternalName
externalName: nginx-ns.nginx-ns.svc.cluster.local #当访问external-service.default.svc.cluster.local时,实际上会去访问nginx-ns.nginx-ns.svc.cluster.local
# 应用
[root@k8s-master-1 external]# kubectl apply -f external.yaml
# 查看pods
[root@k8s-master-1 external]# kubectl get pods -n nginx-ns
NAME READY STATUS RESTARTS AGE
nginx-d89c7cdcb-l668x 1/1 Running 0 9s
nginx-d89c7cdcb-l7g98 1/1 Running 0 9s
# 跨namesapce访问
[root@k8s-master-1 external]# kubectl run -it nginx --rm --image=nginx -- sh
If you don't see a command prompt, try pressing enter.
# curl -I external-service.default.svc.cluster.local:88
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 14:22:33 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes
ClusterIP
介绍
-
ClusterIP的
不能设置service.spec.ports.nodePort
,不允许,ClusterIP只对集群内提供服务 -
ClusterIP 主要在每个 node 节点使用
ipvs/iptables
,将发向ClusterIP对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 Service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口
-
apiserver 用户通过 kubectl命令向 apiserver 发送创建 service 的命令,apiserver 接收到请求后将数据存储到 etcd 中。
-
kube-proxy 在 kubernetes 的每个节点中都有一个叫做 kube-porxy 的进程,这个进程负责感知 service 和 pod 的变化,并将变化的信息写入本地的 ipvs/iptables 规则中
-
ipvs/iptables 使用 NAT 等技术将 VirtualIP 的流量转至 endpoint 中
实例一
# 对应配置文件,如下所示:
[root@k8s-master-1 cluster]# cat deployment-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-nginx
namespace: default
spec:
selector:
cluster-nginx: "true"
type: ClusterIP
clusterIP: 10.0.0.254
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-nginx
namespace: default
spec:
minReadySeconds: 10
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
cluster-nginx: "true"
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
name: cluster-nginx
labels:
cluster-nginx: "true"
app: "nginx"
spec:
restartPolicy: Always
serviceAccountName: default
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
# 启动服务
[root@k8s-master-1 cluster]# kubectl apply -f deployment-nginx.yaml
# 查看SVC服务
[root@k8s-master-1 cluster]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster-nginx ClusterIP 10.0.0.254 <none> 80/TCP 2m11s
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 9d
# 查看POD服务
[root@k8s-master-1 cluster]# kubectl get pods
NAME READY STATUS RESTARTS AGE
cluster-nginx-86d96df9cd-2l5hv 1/1 Running 0 2m25s
cluster-nginx-86d96df9cd-swgtt 1/1 Running 0 2m25s
# pod内通过FQDN访问
[root@k8s-master-1 cluster]# kubectl exec -it cluster-nginx-86d96df9cd-2l5hv -- curl -I cluster-nginx.default.svc.cluster.local
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:23:39 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes
# 通过service IP访问
[root@k8s-master-1 cluster]# curl -I 10.0.0.254:80
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:24:56 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes
# 解析SVC,这里可以看出解析出来的IP是service的IP,而不是后端Pod IP,headless解析出来的是后端POD IP,导致设置port实际上是没有生效的
[root@k8s-master-1 headless]# kubectl run busybox -it --rm --image=busybox:1.28 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup cluster-nginx.default.svc.cluster.local
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: cluster-nginx.default.svc.cluster.local
Address 1: 10.0.0.254 cluster-nginx.default.svc.cluster.local
NodePort
介绍
- 如果设置type的值为 “NodePort”,
Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个Node将从该端口(每个 Node 上的同一端口)代理到Service
。该端口将通过Service的spec.ports[].nodePort字段被指定。如果需要指定的端口号,可以配置nodePort的值,系统将分配这个端口,否则调用 API 将会失败(比如,需要关心端口冲突的可能性)。这可以让开发人员自由地安装他们自己的负载均衡器,并配置 Kubernetes 不能完全支持的环境参数,或者直接暴露一个或多个 Node 的IP 地址。需要注意的是,Service 将能通过<NodeIP>:spec.ports[].nodePort和 spec.clusterIp:spec.ports[*].port 而对外可见
- nodePort 的原理在于在
每个运行了kube-proxy上开了一个端口
,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod client -> Node IP:Port -> Service IP:Port -> Pod IP:Container Port
实例一
[root@k8s-master-1 nodeport]# cat deployment-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-nginx
namespace: default
spec:
selector:
cluster-nginx: "true"
type: NodePort
ports:
- name: http
port: 8888
protocol: TCP
targetPort: 80
nodePort: 33333 #这个可以不写,系统分配,30000-32767范围
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-nginx
namespace: default
spec:
minReadySeconds: 10
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
cluster-nginx: "true"
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
name: cluster-nginx
labels:
cluster-nginx: "true"
app: "nginx"
spec:
restartPolicy: Always
serviceAccountName: default
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
# 查看svc
[root@k8s-master-1 nodeport]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster-nginx NodePort 10.0.0.161 <none> 8888:33333/TCP 2m
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 9d
# 通过nodeport访问nginx
[root@k8s-master-1 nodeport]# curl -I 192.168.0.10:33333
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:33:46 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes
# 通过service IP访问nginx
[root@k8s-master-1 nodeport]# curl -I 10.0.0.161:8888
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:36:28 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes
# 通过FQDN访问
[root@k8s-master-1 nodeport]# kubectl exec -it cluster-nginx-86d96df9cd-dxwcm -- curl -I cluster-nginx.default.svc.cluster.local:8888
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:38:35 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes
kubernetes中的服务之间访问的端口,尽管cluster-nginx容器暴露了80端口,但是集群内其他容器需要通过service:8888端口访问该服务,外部通过nodeport:33333来访问
,port和nodeport不会冲突
No-Selector
介绍
Service 抽象了该如何访问 Kubernetes Pod
,但也能够抽象其它类型的 backend,例如:
- 希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
- 希望服务指向另一个
Namespace
中或其它集群中的服务。 - 正在将工作负载转移到 Kubernetes 集群,和运行在 Kubernetes 集群之外的 backend
卸载service时候,会连带把同名的endpoint一起卸载了
实例一
映射外部服务案例:k8s-node-1 上运行mariadb,最后实现访问service,来到达访问mariadb(这里的mariadb可以是集群外的服务)
# 查看yaml文件
[root@k8s-master-1 no-selector]# cat noselect.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 3306
---
apiVersion: v1
kind: Endpoints
metadata:
name: mysql #默认创建service时就会生成一个与service名字一样的endpoints,并且会自动去关联
subsets:
- addresses:
- ip: 192.168.0.11
ports:
- port: 3306
# 运行
[root@k8s-master-1 no-selector]# kubectl apply -f noselect.yaml
# 查看service
[root@k8s-master-1 no-selector]# kubectl describe svc mysql
Name: mysql
Namespace: default
Labels: <none>
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP Families: <none>
IP: 10.0.158.63
IPs: 10.0.158.63
Port: <unset> 80/TCP
TargetPort: 3306/TCP
Endpoints: 192.168.0.11:3306
Session Affinity: None
Events: <none>
# 访问外部mariadb数据库
[root@k8s-master-1 no-selector]# kubectl run mysql -it --rm --image=mysql -- sh
If you don't see a command prompt, try pressing enter.
# mysql -uroot -ppassword -hmysql.default.svc.cluster.local -P80
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.5.68-MariaDB MariaDB Server
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> #可以发现集群内部通过service登陆了外部数据库
# 访问流程
访问Service IP:80 -> 192.168.0.11:3306
Headless
介绍
- 有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。(
这个service是没有IP
)。因为没有ClusterIP,kube-proxy 并不处理此类服务,因为没有load balancing或 proxy 代理设置,在访问服务的时候回返回后端的全部的Pods IP地址,主要用于开发者自己根据pods进行负载均衡器的开发(设置了selector) 或 StatefulSet
- 这个选项允许开发人员自由寻找他们自己的方式,从而降低与 Kubernetes 系统的耦合性。 应用仍然可以使用一种自注册的模式和适配器,对其它需要发现机制的系统能够很容易地基于这个 API 来构建。
对这类 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由
。DNS如何实现自动配置,依赖于Service是否定义了 selector
不同的pod通过域名进行通信
实例一
含有selector
[root@k8s-master-1 headless]# cat headless-selector.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: ClusterIP
clusterIP: None
selector:
app: nginx
ports:
- port: 88
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
restartPolicy: Always
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
# 查看svc
[root@k8s-master-1 headless]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 11h
nginx ClusterIP None <none> 88/TCP 21s
[root@k8s-master-1 headless]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Families: <none>
IP: None
IPs: None
Port: <unset> 88/TCP
TargetPort: 80/TCP
Endpoints: 10.70.2.13:80,10.70.2.14:80
Session Affinity: None
Events: <none>
# 运行busybox
[root@k8s-master-1 headless]# kubectl run busybox -it --rm --image=busybox:1.28 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx.default.svc.cluster.local
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: nginx.default.svc.cluster.local
Address 1: 10.70.2.14 10-70-2-14.nginx.default.svc.cluster.local
Address 2: 10.70.2.13 10-70-2-13.nginx.default.svc.cluster.local
/ # telnet nginx.default.svc.cluster.local 88 这里为啥不能通
telnet: can't connect to remote host (10.70.2.19): Connection refused
/ # telnet nginx.default.svc.cluster.local 80 这里可以通,为啥
^C
Console escape. Commands are:
# 测试访问
[root@k8s-master-1 headless]# kubectl run nginx -it --rm --image=nginx -- sh
If you don't see a command prompt, try pressing enter.
# curl -I nginx.default.svc.cluster.local
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Sat, 16 Oct 2021 13:23:36 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes
# curl -I nginx.default.svc.cluster.local:88
curl: (7) Failed to connect to nginx.default.svc.cluster.local port 88: Connection refused
# 配置 Selector
对定义selector的Headless Service,Endpoint 控制器在 API 中创建了 Endpoints 记录,并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达Service的后端Pod上,`也就是DNS返回的是后端pod的IP,而不是SVC IP,所以才导致访问service:port才会连接不上`
# 不配置 Selector
对没有定义 selector 的 Headless Service,Endpoint 控制器不会创建Endpoints记录
# 我们在容器里面ping FQDN , service解析出的地址是clusterip(正常的clusterIP),headless service 解析出来的地址是 pod ip(无头)
# 通过headless service 可以轻松找到statefulSet 的所有节点。特别是在部署集群的时候,很多服务需要配置节点信息来创建集群,
# statefulSet.spec.serviceName
当serviceName 配置成与headless service的Name 相同的时候,可以通过 {hostName}.{service-name}.{namespace}.svc.cluster.local 解析出节点IP。hostName 由 {statefulSet name}-{编号} 组成。
# 待确认是否是的
更多推荐
所有评论(0)