文章目录
- 系列文章目录
- 一、简介
- 二、Service 的类型
- 三、Service资源规范
- 四、ClusterIP 类型
- 五、NodePort 类型
- 1、新建 NodePort 类型 service
- 2、修改 nodeport 端口范围
- 六、暴露多个端口
- 七、命令行方式暴露端口
一、简介
利用 Deployment 可以创建一组 Pod 来提供具有高可用性的服务。
虽然每个 Pod 都会分配一个单独的 IP,然而却存在如下两问题,可以通过 service 解决
- Pod IP 会随着Pod的重建产生变化
- Pod IP 仅仅是集群内可见的虚拟IP,外部无法访问(主从结点外的机器无法访问)
在 K8s 的 yaml 配置文件中,name 属性只能包含小写字母数字字符 和 -,并且端口名称还必须以字母数字字符开头和结尾。
接上一篇 : k8s入门:部署应用到 k8s 集群,创建的 deployment/test-k8s-deployment,和其对应的 pod 如下,下面 service 会用到
二、Service 的类型
- clusterIP:通过集群内部 IP 地址暴露服务,仅在集群内部可见、集群外部无法访问,Service 的默认类型
- NodePort::暴露端口到节点,提供了集群外部访问的入口,端口范围固定 30000 ~ 32767
- LoadBalancer: 会额外生成一个 IP 对外服务,需要公有云支持
- ExternalName:通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。 无需创建任何类型代理。kube-dns 1.7 及以上版本或者 CoreDNS 0.0.8 及以上版本才能使用 ExternalName 类型
你也可以使用 Ingress 来暴露自己的服务。 Ingress 不是一种服务类型,但它充当集群的入口点。 它可以将路由规则整合到一个资源中,因为它可以在同一IP地址下公开多个服务。
三、Service资源规范
apiVersion: v1
kind: Service
metadata:
name: ..
namespace: ...
labels:
key1: value1
key2: value2
spec:
type <string> #Service类型,默认为ClusterIP
selector <map[string]string> #等值类型的标签选择器,内含“与"逻辑
ports: # Service的端口对象列表,数组类型,配置多个则必须配置 name
- name <string> # 端口名称
protocol <string> # 协议,目前仅支持TCP、UDP和SCTP,默认为TCP
port <integer> # Service的端口号
targetPort <string> # 后端目标进程的端口号或名称,名称需由Pod规范定义
nodePort <integer> # 节点端口号,仅适用于NodePort和LoadBalancer类型
clusterIP <string> # Service的集群IP,建议由系统自动分配
externalTrafficPolicy <string> # 外部流量策略处理方式,Local表示由当前节点处理,#Cluster表示向集群范围调度
loadBalancerIP <string> # 外部负载均衡器使用的IP地址,仅适用于LoadBlancer
externalName <string> # 外部服务名称,该名称将作为Service的DNS CNAME值
四、ClusterIP 类型
新建 test-k8s-deployment-service.yaml 添加如下内容
apiVersion: v1
kind: Service
metadata:
name: test-k8s-deployment-service
spec:
selector:
# 对应 deployment 名字
app: test-k8s-deployment
# 默认 ClusterIP 集群内可访问,NodePort 节点可访问,LoadBalancer 负载均衡模式(需要负载均衡器才可用)
type: ClusterIP
ports:
- port: 8080 # 本 Service 的端口
targetPort: 8080 # 容器端口
创建 service 并查看状态,并保证 Endpoints 包含集群内部 IP
[root@master ~]# kubectl apply -f test-k8s-deployment-service.yaml
service/test-k8s-deployment-service created
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10h
test-k8s-deployment-service ClusterIP 10.96.45.184 <none> 8080/TCP 10s
[root@master ~]# kubectl describe svc test-k8s-deployment-service
Name: test-k8s-deployment-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=test-k8s-deployment
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.45.184
IPs: 10.96.45.184
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
Endpoints: 10.244.1.7:8080,10.244.2.7:8080,10.244.2.8:8080
Session Affinity: None
Events: <none>
服务的默认类型是ClusterIP,只能在集群内部访问,kubectl exec -it pod-name -- bash
进入集群,我们可以进入到 Pod 里面访问:curl http://test-k8s-deployment-service:8080
,我的容器内没有 curl 命令暂不测试
如果要在集群外部访问,可以通过端口转发实现(只适合临时测试用),注意:一定要添加 service/,否则默认 pod
# 只支持本机访问
[root@master ~]# kubectl port-forward service/test-k8s-deployment-service 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Handling connection for 8080
# 支持所有地址
[root@master ~]# kubectl port-forward service/test-k8s-deployment-service --address 0.0.0.0 8080:8080
Forwarding from 0.0.0.0:8080 -> 8080
ClusterIP 适用于一个 pod 中有多个容器,容器之间可相互通信
五、NodePort 类型
1、新建 NodePort 类型 service
新建 test-k8s-deployment-service-NodePort.yaml 添加如下内容
apiVersion: v1
kind: Service
metadata:
# 必须小写
name: test-k8s-deployment-service-nodeport
spec:
selector:
# 对应 deployment 名字
app: test-k8s-deployment
type: NodePort
ports:
- port: 8080 # 本 Service 的端口
targetPort: 8080 # 容器端口
nodePort: 30001 # 节点端口,范围固定 30000 ~ 32767
创建查看详情
[root@master ~]# kubectl apply -f test-k8s-deployment-service-NodePort.yaml
service/test-k8s-deployment-service-nodeport created
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h
test-k8s-deployment-service-nodeport NodePort 10.96.227.136 <none> 8080:30001/TCP 135m
[root@master ~]# kubectl describe svc test-k8s-deployment-service-nodeport
Name: test-k8s-deployment-service-nodeport
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=test-k8s-deployment
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.227.136
IPs: 10.96.227.136
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 30001/TCP
Endpoints: 10.244.1.9:8080,10.244.2.10:8080,10.244.2.11:8080
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
测试,可以看到转发到了不同的 pod,和 service 中 Endpoints 的地址一致
2、修改 nodeport 端口范围
nodeport 默认端口范围 30000-32767,如果我指定 Nginx:80 端口会报如下错误
[root@master ant]# kubectl apply -f ant-service.yaml
The Service "ant-deployment-service-nodeport" is invalid: spec.ports[0].nodePort: Invalid value: 80: provided port is not in the valid range. The range of valid ports is 30000-32767
解决办法,修改 /etc/kubernetes/manifests/kube-apiserver.yaml
文件,添加 - --service-node-port-range=1-65535 # 限定端口范围 1~65535
[root@master ant]# cat /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.25.100:6443
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.25.100
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --service-node-port-range=1-65535 # 限定端口范围 1~65535
- --feature-gates=RemoveSelfLink=false # 添加这条
- --client-ca-file=/etc/kubernetes/pki/ca.crt
使用 systemctl restart kubelet
重启服务即可生效,如下 80 端口指定成功
[root@master ant]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ant-deployment-service-nodeport NodePort 10.96.166.157 <none> 80:80/TCP 2m8s
六、暴露多个端口
多端口时必须配置 name,新增 test-k8s-deployment-service-NodePort-many.yaml 添加如下内容
apiVersion: v1
kind: Service
metadata:
# 必须小写
name: test-k8s-deployment-service-nodeport
spec:
selector:
# 对应 deployment 名字
app: test-k8s-deployment
type: NodePort
ports:
- port: 8080 # 本 Service 的端口
name: default # 必须配置
targetPort: 8080 # 容器端口
nodePort: 30001 # 节点端口,范围固定 30000 ~ 32767
- port: 8088
name: other
targetPort: 8088
nodePort: 30002
创建发现两个端口暴露成功
[root@master ~]# kubectl apply -f test-k8s-deployment-service-NodePort-many.yaml
service/test-k8s-deployment-service-nodeport-many created
[root@master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27h
test-k8s-deployment-service-nodeport-many NodePort 10.96.111.32 <none> 8080:30001/TCP,8088:30002/TCP 6s
七、命令行方式暴露端口
通过命令行,不能暴露多个端口,NodePort 类型不能指定 nodePort 端口号,会随机分配
[root@master ~]# kubectl expose deployment test-k8s-deployment --name=test-k8s-deployment-service2 --type=NodePort --port=8080 --target-port=8080
service/test-k8s-deployment-service2 exposed
[root@master ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
test-k8s-deployment 3/3 3 3 22h
[root@master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27h
test-k8s-deployment-service2 NodePort 10.96.71.19 <none> 8080:32459/TCP 18s