Service
service是kubernetes核心资源之一,通常被看作微服务的一种实现.它事实上是一种服务发现的,是一种抽象,在k8s资源对象创建以后,是一种规则的抽象,要不然是iptables要不然是ipvs,它事实上是一组规则的抽象,service通过endpoint,endpoint通过标签选择器的方式和pod关联上,把你的pod给绑定到指定的endpoint,未来通过指定的ip就能访问到service
定义一个Service
type 类型 Service 的类型
service资源类型分为多少种种类,默认情况是Cluster Ip 除了这个以外还是ExternalName 还有个叫LoadBalancer还有个叫NodePort
就是service的四种类型
[root@k8s-master1 deployment]# kubectl explain service.spec.type
KIND: Service
VERSION: v1
FIELD: type <string>
DESCRIPTION:
type determines how the Service is exposed. Defaults to ClusterIP. Valid
options are ExternalName, ClusterIP, NodePort, and LoadBalancer.
"ClusterIP" allocates a cluster-internal IP address for load-balancing to
endpoints. Endpoints are determined by the selector or if that is not
specified, by manual construction of an Endpoints object or EndpointSlice
objects. If clusterIP is "None", no virtual IP is allocated and the
endpoints are published as a set of endpoints rather than a virtual IP.
"NodePort" builds on ClusterIP and allocates a port on every node which
routes to the same endpoints as the clusterIP. "LoadBalancer" builds on
NodePort and creates an external load-balancer (if supported in the current
cloud) which routes to the same endpoints as the clusterIP. "ExternalName"
aliases this service to the specified externalName. Several other fields do
not apply to ExternalName services. More info:
https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
Possible enum values:
- `"ClusterIP"` means a service will only be accessible inside the cluster,
#service 第一种类型 也是默认的
via the cluster IP.
- `"ExternalName"` means a service consists of only a reference to an
#service 第二种类型
external name that kubedns or equivalent will return as a CNAME record,
with no exposing or proxying of any pods involved.
- `"LoadBalancer"` means a service will be exposed via an external load
#service 第三种类型
balancer (if the cloud provider supports it), in addition to 'NodePort'
type.
- `"NodePort"` means a service will be exposed on one port of every node,
#service 第四种类型
in addition to 'ClusterIP' type.
Selector 标签选择器 Service的标签选择器
这个标签选择器主要是和pod关联的
[root@k8s-master1 deployment]# kubectl explain service.spec.selector
KIND: Service
VERSION: v1
FIELD: selector <map[string]string>
DESCRIPTION:
Route service traffic to pods with label keys and values matching this
selector. If empty or not present, the service is assumed to have an
external process managing its endpoints, which Kubernetes will not modify.
Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if
type is ExternalName. More info:
https://kubernetes.io/docs/concepts/services-networking/service/
ports
[root@k8s-master1 deployment]# kubectl explain service.spec.ports
KIND: Service
VERSION: v1
RESOURCE: ports <[]Object>
DESCRIPTION:
The list of ports that are exposed by this service. More info:
https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
ServicePort contains information on service's port.
FIELDS:
appProtocol <string>
#协议
The application protocol for this port. This field follows standard
Kubernetes label syntax. Un-prefixed names are reserved for IANA standard
service names (as per RFC-6335 and
https://www.iana.org/assignments/service-names). Non-standard protocols
should use prefixed names such as mycompany.com/my-custom-protocol.
name <string>
#名字 可写可不写
The name of this port within the service. This must be a DNS_LABEL. All
ports within a ServiceSpec must have unique names. When considering the
endpoints for a Service, this must match the 'name' field in the
EndpointPort. Optional if only one ServicePort is defined on this service.
nodePort <integer>
#如果这种service 的类型(type)本身是NodePort的时候,这个字段nodePort在这里面才有效,不是那个是无效的
The port on each node on which this service is exposed when type is
NodePort or LoadBalancer. Usually assigned by the system. If a value is
specified, in-range, and not in use it will be used, otherwise the
operation will fail. If not specified, a port will be allocated if this
Service requires one. If this field is specified when creating a Service
which does not need it, creation will fail. This field will be wiped when
updating a Service to no longer need it (e.g. changing type from NodePort
to ClusterIP). More info:
https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
port <integer> -required-
#必选字段,定义我们service的端口号
The port that will be exposed by this service.
protocol <string>
#协议
The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". Default
is TCP.
Possible enum values:
- `"SCTP"` is the SCTP protocol.
- `"TCP"` is the TCP protocol.
- `"UDP"` is the UDP protocol.
targetPort <string>
#定义后端的pod的端口号 他和上面那个port字段 通常一块出现 是个映射关系 这说白了就是iptalbes或者ipvs的一个规则,不管是nat还是dr 在lvs定义的时候 要定义ip+端口号映射到后端真实服务器的某个ip和端口号
Number or name of the port to access on the pods targeted by the service.
Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If
this is a string, it will be looked up as a named port in the target Pod's
container ports. If this is not specified, the value of the 'port' field is
used (an identity map). This field is ignored for services with
clusterIP=None, and should be omitted or set equal to the 'port' field.
More info:
https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service
ClusterIP
clusterip和上面的nodeport 如果不自定义 会给我们自动生成的 如果我们类型(type)本身是Cluster IP 和nodeport类型的时候他会自动给我们产生一个ip 不需要人为定义的
externalTrafficPolicy 外部流量引用策略
这个外部流量引用策略只有在类型(type)为ExternalName的类型的service 这个才有效
loadBalancerIP
负载均衡使用的ip地址,这个只有类型(type)为LoadBalancer 的类型的service 这个才有效
ExternalName
对应的externalName类型
我们开始定义一个Service
[root@k8s-master1 service]# cat service-v1.yaml
apiVersion: v1 #service是核心群组,所有版本为v1
kind: Service
metadata:
name: my-service-nginx
labels:
run: nginx #给service定义标签没有任何意义 以后查询可能方便点
spec:
selector: #标签选择器
app: nginx #在生产上需要定义大量标签 比如你的项目名 运行环境 层级 那个团队 版本号 都要对应
env: test #测试环境 生产环境 准生产环境 预发布环境 为了区分不同的应用 因为应用名称是意义 通过标签区分
version: v1 #定义大量标签选择器 为了区分不用应用的
type: ClusterIP #类型 默认就是Cluster IP 不写也是
ports:
- protocol: TCP #协议
port: 80
targetPort: 80 #你的后端应用程序端口号 也就是你的pod端口号
--- #两个不通的资源对象 用三个-分割
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-svc-1
spec:
replicas: 3
selector: #这个是pod控制器的标签选择器
matchLabels: #这个是deployment 去控制pod的标签
app: nginx
env: test
version: v1
template:
metadata:
labels:
app: nginx #这个必须包含 pod控制器的标签选择器的那三个标签 也就是上面的那三
env: test #这三个必须和service的标签关联上 只有关联上才能把对应的pod创建到 service endpoint上面
version: v1
spec:
containers:
- name: nginx
image: images.guoguo.com/apps/nginx:1.22.1
ports:
- containerPort: 80
deployment标签选择器和service本身没有什么关系通常我们三个都写一样的 service 的标签 deployment的标签选择器还有pod的标签都一样
[root@k8s-master1 service]# kubectl apply -f service-v1.yaml
service/my-service-nginx created
deployment.apps/nginx-svc-1 created
看下创建的deployment
[root@k8s-master1 service]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-svc-1 3/3 3 3 7s
看下创建的service
[root@k8s-master1 service]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service-nginx ClusterIP 10.106.205.251 <none> 80/TCP 7s
看下创建的endpoint
[root@k8s-master1 service]# kubectl get endpoints
NAME ENDPOINTS AGE
my-service-nginx 192.17.65.206:80,192.26.131.189:80,192.28.252.208:80 7s
#endpoint是一组ip加端口号
看下pod的ip是不是被endpoint关联了
[root@k8s-master1 service]# kubectl get pods -l env=test -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-svc-1-7b5444f57-6s6rg 1/1 Running 0 7s 192.28.252.208 k8s-node2.guoguo.com <none> <none>
nginx-svc-1-7b5444f57-7dqxw 1/1 Running 0 7s 192.17.65.206 k8s-node3.guoguo.com <none> <none>
nginx-svc-1-7b5444f57-drxtg 1/1 Running 0 7s 192.26.131.189 k8s-node1.guoguo.com <none> <none>
意味着三个创建的pod被endpoint关联上了,我就可以通过service的ip地址加端口号访问后端资源
试一下
[root@k8s-master1 service]# curl 10.106.205.251
test
endpoint是怎么关联的pod
就是靠标签选择器
[root@k8s-master1 service]# kubectl describe endpoints
kubernetes my-service-nginx nginx-deployment
[root@k8s-master1 service]# kubectl describe endpoints my-service-nginx
Name: my-service-nginx
Namespace: default
Labels: run=nginx
Annotations: endpoints.kubernetes.io/last-change-trigger-time: 2023-08-14T08:53:48Z
Subsets:
Addresses: 192.17.65.206,192.26.131.189,192.28.252.208
#关联的pod地址
NotReadyAddresses: <none>
Ports:
Name Port Protocol
---- ---- --------
<unset> 80 TCP
#端口号 协议
Events: <none>
比如我们把pod的标签修改一个
endpoint会发现期望值变了,会把该标签的踢出去,然后新建一个pod
[root@k8s-master1 deployment]# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-svc-1-7b5444f57-6s6rg 1/1 Running 0 14m 192.28.252.208 k8s-node2.guoguo.com <none> <none>
nginx-svc-1-7b5444f57-7dqxw 1/1 Running 0 14m 192.17.65.206 k8s-node3.guoguo.com <none> <none>
nginx-svc-1-7b5444f57-drxtg 1/1 Running 0 14m 192.26.131.189 k8s-node1.guoguo.com <none> <none>
#比如我们修改 ip为192.168.65.206的 他的名字叫nginx-svc-1-7b5444f57-7dqxw
[root@k8s-master1 service]# kubectl label pods nginx-svc-1-7b5444f57-7dqxw version=v2 --overwrite
deployment.apps/nginx-svc-1 labeled
[root@k8s-master1 deployment]# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-svc-1-7b5444f57-6s6rg 1/1 Running 0 15m 192.28.252.208 k8s-node2.guoguo.com <none> <none>
nginx-svc-1-7b5444f57-7dqxw 1/1 Running 0 15m 192.17.65.206 k8s-node3.guoguo.com <none> <none>
nginx-svc-1-7b5444f57-9drkd 1/1 Running 0 26s 192.17.65.208 k8s-node3.guoguo.com <none> <none>
nginx-svc-1-7b5444f57-drxtg 1/1 Running 0 15m 192.26.131.189 k8s-node1.guoguo.com <none> <none>
#随着他就新建了一个,并将206踢出去了 并加入新的ip为192.17.65.208 名字为nginx-svc-1-7b5444f57-9drkd
[root@k8s-master1 deployment]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 172.17.8.1:6443,172.17.8.2:6443,172.17.8.3:6443 11d
my-service-nginx 192.17.65.208:80,192.26.131.189:80,192.28.252.208:80 16m
这个就是通过标签和标签选择器匹配,如果你的pod的标签变更了,endpoint会给你新创建一个pod,和你pod的标签一样并挂载到endpoint里面
这个就是通过service和标签标签选择器关联的对应的pod
Service类型 Type
Kubernetes Service Type (服务类型)主要包括以下几种
ClusterIP:在集群内部使用,默认值,只能从集群中访问.
在你的service产生一个ip地址出来,默认情况下,这个ip可以自己指定,但是要求在service网段内,如果不指定会随机在网段里分配一个ip地址,通过ClusterIP可以访问到deployment绑定的pod
NodePort:在所有安装了Kube-Proxy 的节点上打开一个端口,此端口可以代理至后端Pod,可以通过NodePort从集群外部访问集群内的服务,格式为NodeIP:NodePort.
就相当于端口映射,通过这个节点ip加端口号形式访问service和pod的资源,这个就是nodeIP加端口号,就可以访问,dashboard就是nodeport类型的service
LoadBalanCer:使用云提供商的负载均衡器公开服务,成本较高
通常在公有云上:阿里云或aws云服务厂商提供的负载均衡服务器
ExternalName:通过返回定义的CNAME别名,没有设置任何类型的代理,需要1.7或更高版本kube-dns支持
通过一个cname别名,去访问
NodePort类型
Kubenetes在创建集群的时候默认有个Service-node-port-range 端口号范围参数,创建集群就有这个范围,(默认范围在30000-32767)两千多个端口号随机找个端口号给你做映射,和定义的service端口号做映射,然后通过这个映射就可以访问到pod资源对象
写一个
我们看下我们之前创建的Dashboard
[root@k8s-master1 manifests]# kubectl get pods -n kubernetes-dashboard
NAME READY STATUS RESTARTS AGE
dashboard-metrics-scraper-b4dcbdc8f-pkndv 1/1 Running 10 (26m ago) 10d
kubernetes-dashboard-5964546dfc-czrpk 1/1 Running 11 (26m ago) 10d
#看下标签
[root@k8s-master1 manifests]# kubectl get pods -n kubernetes-dashboard --show-labels
NAME READY STATUS RESTARTS AGE LABELS
dashboard-metrics-scraper-b4dcbdc8f-pkndv 1/1 Running 10 (27m ago) 10d k8s-app=dashboard-metrics-scraper,pod-template-hash=b4dcbdc8f
kubernetes-dashboard-5964546dfc-czrpk 1/1 Running 11 (27m ago) 10d k8s-app=kubernetes-dashboard,pod-template-hash=5964546dfc
#第二个是
我们得到了Dashboard的标签可以创建一个Service可以和这个标签关联
[root@k8s-master1 service]# vim service-nodeport-1.yml
apiVersion: v1
kind: Service
metadata:
name: kubernetes-dashboard-1
namespace: kubernetes-dashboard #这里要注意 必须名称空间要统一!!!
spec:
type: NodePort #类型使用NodePort
ports:
- port: 443 #因为dashboard是https的
targetPort: 8443 #这个8443是dashboard的pod端口号
nodePort: 30000 #这个端口号生产上都是随机的 如果我们不写这个值那他就是随机的
selector:
k8s-app: kubernetes-dashboard #写一个就可以 这个是dashboard的标签
[root@k8s-master1 service]# kubectl apply -f service-nodeport-1.yml
#启动
[root@k8s-master1 service]# kubectl get service -n kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.101.27.2 <none> 8000/TCP 10d
kubernetes-dashboard NodePort 10.99.155.12 <none> 443:31416/TCP 10d
kubernetes-dashboard-1 NodePort 10.105.148.237 <none> 443:30000/TCP 6m16s
#这个-1是我们创建的
#再看下endpoints
[root@k8s-master1 service]# kubectl get endpoints -n kubernetes-dashboard
NAME ENDPOINTS AGE
dashboard-metrics-scraper 192.17.65.210:8000 10d
kubernetes-dashboard 192.28.252.210:8443 10d
kubernetes-dashboard-1 192.28.252.210:8443 7m1s
#这个-1是我们创建的 也关联上了
他是通过ipvs或者iptalbes进行的规则转换 我安装的时候把iptables改为ipvs了所以去任何一个node节点查看就能看到3000的端口号
[root@k8s-node2 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.28.252.192:30000 rr #在这里
-> 192.28.252.210:8443 Masq 1 0 0
TCP 192.28.252.192:31416 rr
-> 192.28.252.210:8443 Masq 1 0 0
TCP 192.168.1.102:30000 rr #在这里
-> 192.28.252.210:8443 Masq 1 0 0
TCP 192.168.1.102:31416 rr
-> 192.28.252.210:8443 Masq 1 0 0
TCP 10.96.0.1:443 rr
-> 192.168.1.11:6443 Masq 1 1 0
-> 192.168.1.12:6443 Masq 1 0 0
-> 192.168.1.13:6443 Masq 1 1 0
TCP 10.96.0.10:53 rr
-> 192.22.96.223:53 Masq 1 0 0
-> 192.22.96.224:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 192.22.96.223:9153 Masq 1 0 0
-> 192.22.96.224:9153 Masq 1 0 0
TCP 10.99.155.12:443 rr
-> 192.28.252.210:8443 Masq 1 0 0
TCP 10.101.27.2:8000 rr
-> 192.17.65.210:8000 Masq 1 0 0
TCP 10.102.8.242:80 rr
-> 192.17.65.217:80 Masq 1 0 0
-> 192.26.131.151:80 Masq 1 0 0
-> 192.28.252.208:80 Masq 1 0 0
TCP 10.103.4.127:443 rr
-> 192.28.252.202:4443 Masq 1 0 0
TCP 10.105.49.165:5473 rr
-> 192.168.1.101:5473 Masq 1 0 0
TCP 10.105.148.237:443 rr
-> 192.28.252.210:8443 Masq 1 0 0
UDP 10.96.0.10:53 rr
-> 192.22.96.223:53 Masq 1 0 0
-> 192.22.96.224:53 Masq 1 0 0
我们精准查找下
[root@k8s-node2 ~]# ipvsadm -Ln | grep -A2 3000
TCP 192.28.252.192:30000 rr #这就可以看到了 3000端口转发8443
-> 192.28.252.210:8443 Masq 1 0 0
TCP 192.28.252.192:31416 rr
--
TCP 192.168.1.102:30000 rr
-> 192.28.252.210:8443 Masq 1 0 0
TCP 192.168.1.102:31416 rr
自然浏览器就可以访问到了
这就是第二种NodePort类型service
#
使用Service代理K8s外部服务
External类型
使用Service代理k8s外部服务,我们现在访问的资源都是集群内部的,如果想访问集群外部的,就需要用到External
我们需要一个External IP我们可以把外部的某一个资源给映射进来,事实上是通过Endpoints来做的
这时候需要启动一个机器,安装个nginx吧
这里就不演示了
要求:启动一个nginx服务器:我的nginx服务器ip为192.168.1.123
因为我们创建service他会自动给我们创建一个endpoints节点然后绑定pod,如果我们想映射集群外部的进来我们就不能让service自动的去创建endpoints了,我们人为去创建endpoints去绑定集群外部资源,然后创建一个同名的service,endpoints会自动的把endpoint和service绑定起来
创建的endpoints名字要和service一样!意义就是不让service自动的去创建endpoints了
其实endpoints就是snat字段 绑定ip 只要网络可达都可以绑定过来
[root@k8s-master1 service]# curl 192.168.1.123
test-123
IP:192.168.1.123
NAME:NGINX
#现在我们的外部nginx服务器是可以访问的,也就是网络可达
我们现在思路是创建一个CLusterIP的Service 然后不让他关联endpoints 所以我们要自己先把同名的endpoints创建出来
我们先看下endpoints字段的介绍
[root@k8s-master1 service]# kubectl explain endPoints
KIND: Endpoints
VERSION: v1
DESCRIPTION:
Endpoints is a collection of endpoints that implement the actual service.
Example:
Name: "mysvc", Subsets: [ { Addresses: [{"ip": "10.10.1.1"}, {"ip":
"10.10.2.2"}], Ports: [{"name": "a", "port": 8675}, {"name": "b", "port":
309}] }, { Addresses: [{"ip": "10.10.3.3"}], Ports: [{"name": "a", "port":
93}, {"name": "b", "port": 76}] }, ]
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
subsets <[]Object>
The set of all endpoints is the union of all subsets. Addresses are placed
into subsets according to the IPs they share. A single address with
multiple ports, some of which are ready and some of which are not (because
they come from different containers) will result in the address being
displayed in different subsets for the different ports. No address will
appear in both Addresses and NotReadyAddresses in the same subset. Sets of
addresses and ports that comprise a service.
#没有spec 这是个特殊的资源对象类型,百分之99的资源对象都有五个字段:apiVersion kind metadata spec status
#但是 endpoint没有 spec 和status 他多了个subsets字段
看下subsets字段
[root@k8s-master1 service]# kubectl explain endpoints.subsets
KIND: Endpoints
VERSION: v1
RESOURCE: subsets <[]Object>
DESCRIPTION:
The set of all endpoints is the union of all subsets. Addresses are placed
into subsets according to the IPs they share. A single address with
multiple ports, some of which are ready and some of which are not (because
they come from different containers) will result in the address being
displayed in different subsets for the different ports. No address will
appear in both Addresses and NotReadyAddresses in the same subset. Sets of
addresses and ports that comprise a service.
EndpointSubset is a group of addresses with a common set of ports. The
expanded set of endpoints is the Cartesian product of Addresses x Ports.
For example, given:
{ Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], Ports: [{"name":
"a", "port": 8675}, {"name": "b", "port": 309}] }
The resulting set of endpoints can be viewed as:
a: [ 10.10.1.1:8675, 10.10.2.2:8675 ], b: [ 10.10.1.1:309, 10.10.2.2:309 ]
FIELDS:
addresses <[]Object>
#ip地址 这个是个列表 需要查看一下
IP addresses which offer the related ports that are marked as ready. These
endpoints should be considered safe for load balancers and clients to
utilize.
notReadyAddresses <[]Object>
IP addresses which offer the related ports but are not currently marked as
ready because they have not yet finished starting, have recently failed a
readiness check, or have recently failed a liveness check.
ports <[]Object>
#端口号 列表也需要查看一下
Port numbers available on the related IP addresses.
看下addresses字段
[root@k8s-master1 service]# kubectl explain Endpoints.subsets.addresses
KIND: Endpoints
VERSION: v1
RESOURCE: addresses <[]Object>
DESCRIPTION:
IP addresses which offer the related ports that are marked as ready. These
endpoints should be considered safe for load balancers and clients to
utilize.
EndpointAddress is a tuple that describes single IP address.
FIELDS:
hostname <string>
The Hostname of this endpoint
ip <string> -required-
#ip地址
The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local
(169.254.0.0/16), or link-local multicast ((224.0.0.0/24). IPv6 is also
accepted but not fully supported on all platforms. Also, certain kubernetes
components, like kube-proxy, are not IPv6 ready.
nodeName <string>
Optional: Node hosting this endpoint. This can be used to determine
endpoints local to a node.
targetRef <Object>
Reference to object providing the endpoint.
看下ports
[root@k8s-master1 service]# kubectl explain Endpoints.subsets.ports
KIND: Endpoints
VERSION: v1
RESOURCE: ports <[]Object>
DESCRIPTION:
Port numbers available on the related IP addresses.
EndpointPort is a tuple that describes a single port.
FIELDS:
appProtocol <string>
The application protocol for this port. This field follows standard
Kubernetes label syntax. Un-prefixed names are reserved for IANA standard
service names (as per RFC-6335 and
https://www.iana.org/assignments/service-names). Non-standard protocols
should use prefixed names such as mycompany.com/my-custom-protocol.
name <string>
The name of this port. This must match the 'name' field in the
corresponding ServicePort. Must be a DNS_LABEL. Optional only if one port
is defined.
port <integer> -required-
The port number of the endpoint.
protocol <string>
The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.
Possible enum values:
- `"SCTP"` is the SCTP protocol.
- `"TCP"` is the TCP protocol.
- `"UDP"` is the UDP protocol.
写一个
[root@k8s-master1 service]# cat service-external.yml
apiVersion: v1
kind: Service
metadata:
name: external-nginx
spec:
type: ClusterIP
ports:
- port: 80 #如果说想给这个port加个名称 在下面也需要加 相同的名称 要么都不加 要么都加
targetPort: 80 #ExternalName类型不需要标签选择器 因为它不需要去和pod关联
protocol: TCP
---
apiVersion: v1 #因为我们不想让service自动创建endpoint然后关联 所以我们直接创建同名的endpoint
kind: Endpoints
metadata:
name: external-nginx #这个名称必须和service 的名称相同 否则无法关联
subsets: #这个是特殊的字段 类似spec吧
- addresses: #ip
- ip: 192.168.1.123 #nginx 的ip
ports: #如果说想给这个port加个名称 在上面也需要加 相同的名称 要么都不加 要么都加
- port: 80 #端口号
protocol: TCP #协议
[root@k8s-master1 service]# kubectl apply -f service-external.yml
service/external-nginx created
endpoints/external-nginx created
查看一下
[root@k8s-master1 service]# kubectl get endpoints
NAME ENDPOINTS AGE
external-nginx 192.168.1.123:80 2m6s
[root@k8s-master1 service]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
external-nginx ClusterIP 10.104.149.57 <none> 80/TCP 2m25s
然后这时候我们访问service的ip就能访问到nginx的地址了
[root@k8s-master1 service]# curl 10.104.149.57
test-123
IP:192.168.1.123
NAME:NGINX
这样就可以把我们集群外部的服务发布到集群内部,不光master node节点可以访问,因为他的网段和pod在一个网段 pod里面也是可以访问的
这种方式生产上用的比较多,如果你在k8s以内想监控k8s以外的东西就得需要这种方式来创建
比如监控服务装在k8s里面但是你想监控集群外部的服务就需要这个方式来去监控集群之外的服务
第四种Service类型
ExternalName
ExternalName是一种特殊的Service资源,也不需要关联标签选择器关联任何Pod,也无需定义任何端口号或Endpoints,但是必须使用spec.ExternalName属性定义一个别名(CNAME)记录,
类似于我访问一个百度,集群里面访问百度,我就可以给百度做一个别名,然后用别名去访问百度
生产上用的少
这种和External类似,他事实上也是把集群外部的资源弄到集群内部,只是弄得域名,上面是使用endpoints把多个ip地址通过subsets把addresses ip地址导进去的
这个是拓展域名的方式,把集群外部通过域名的某一个服务给你映射集群内部去,最终不是通过域名访问是通过cluster名称访问
写一个
[root@k8s-master1 ~]# kubectl explain service.spec
KIND: Service
VERSION: v1
RESOURCE: spec <Object>
DESCRIPTION:
Spec defines the behavior of a service.
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
ServiceSpec describes the attributes that a user creates on a service.
FIELDS:
externalName <string>
#用这个之前type类型必须是ExternalName才可以
#这里是指定要映射进来的域名是谁
externalName is the external reference that discovery mechanisms will
return as an alias for this service (e.g. a DNS CNAME record). No proxying
will be involved. Must be a lowercase RFC-1123 hostname
(https://tools.ietf.org/html/rfc1123) and requires `type` to be
"ExternalName".
ports <[]Object>
#需要写端口号 域名的端口号 和映射进来的端口号
The list of ports that are exposed by this service. More info:
https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
selector <map[string]string>
#虽然不用写标签选择器内容 但是得写上为空 {} 两个大括号就代表为空
Route service traffic to pods with label keys and values matching this
selector. If empty or not present, the service is assumed to have an
external process managing its endpoints, which Kubernetes will not modify.
Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if
type is ExternalName. More info:
https://kubernetes.io/docs/concepts/services-networking/service/
type <string>
#类型 这个写上 ExternalName
type determines how the Service is exposed. Defaults to ClusterIP. Valid
options are ExternalName, ClusterIP, NodePort, and LoadBalancer.
"ClusterIP" allocates a cluster-internal IP address for load-balancing to
endpoints. Endpoints are determined by the selector or if that is not
specified, by manual construction of an Endpoints object or EndpointSlice
objects. If clusterIP is "None", no virtual IP is allocated and the
endpoints are published as a set of endpoints rather than a virtual IP.
"NodePort" builds on ClusterIP and allocates a port on every node which
routes to the same endpoints as the clusterIP. "LoadBalancer" builds on
NodePort and creates an external load-balancer (if supported in the current
cloud) which routes to the same endpoints as the clusterIP. "ExternalName"
aliases this service to the specified externalName. Several other fields do
not apply to ExternalName services. More info:
https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
Possible enum values:
- `"ClusterIP"` means a service will only be accessible inside the cluster,
via the cluster IP.
- `"ExternalName"` means a service consists of only a reference to an
external name that kubedns or equivalent will return as a CNAME record,
with no exposing or proxying of any pods involved.
- `"LoadBalancer"` means a service will be exposed via an external load
balancer (if the cloud provider supports it), in addition to 'NodePort'
type.
- `"NodePort"` means a service will be exposed on one port of every node,
in addition to 'ClusterIP' type.
写一个
[root@k8s-master1 service]# cat externalname-1.yml
apiVersion: v1
kind: Service
metadata:
name: baidu-externalname #这里是映射的域名,
spec:
type: ExternalName
externalName: www.baidu.com #映射前的域名
selector: {} #不需要写标签内容 但是要写为空 {} 代表为空
ports:
- port: 80 #映射后的端口号
protocol: TCP
targetPort: 80 #映射前 百度的端口号
[root@k8s-master1 service]# kubectl apply -f externalname-1.yml
service/baidu-externalname created
测试一下
[root@k8s-master1 service]# kubectl exec nginx-67c6f5c7bf-65x25 -- nslookup baidu-externalname
Server: 10.96.0.10
Address: 10.96.0.10#53
baidu-externalname.default.svc.cluster.local canonical name = www.baidu.com.
www.baidu.com canonical name = www.a.shifen.com.
Name: www.a.shifen.com
Address: 110.242.68.4
Name: www.a.shifen.com
Address: 110.242.68.3
#可以正常解析到
这就是我们通过externalname的方式把我们集群外部的某一个域名映射进来,通过别名的方式来解析
公司很少直接使用ip方式,刚才那个service subsets 用ip方式少
因为生产上ip可能会变,但是域名不会
上面那种通过cluster ip的方式去关联ip的方式和这个用域名关联的方式类似的,只是后面这种不需要创建endpoints,标签选择器为空,字段类型为ExternalName就可以了
多端口Service
就是我们定义ports本身就是个列表,ports可以定义多个
就是同时可以把80和443都映射出来
[root@k8s-master1 chapter03]# cat service-ports.yaml
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: myapp
ports: #ports是个列表 代表可以定义多个端口号 这样80和443 都可以同时映射出来 多个端口号对应多个端口号
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377