service暴露端口的方式和代理方式
service 概念
SVC 通过 Label Selector 标签选择的方式,匹配一组 Pod,对外访问服务。每一个 SVC可以理解成为一个微服务。
service 能够提供负载均衡的能力,但是在使用上有以下限制:
只提供4层负载均衡能力(只有 RR 轮询算法),而没有7层功能,如果需要更多的匹配规则来转发请求,4层上的负载均衡是不支持的。
service 类型
Clusterip:默认类型,自动分配一个仅 Cluster 内部可以访问的 虚拟IP,一般用作集群内部负载均衡。
NodePort(service向外暴露):在ClusterIP 基础上为 Service 在每台机器上绑定一个映射端口,外网客户端可以通过 NodeIP,Nodeport访问。
LoadBalancer(service向外暴露):在 NodePort 基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到 NodeIP 和 NodePort
ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,只有1.7之后版本的 kube-dns支持。
SVC 访问流程组件
首先 apiserver 监听 kube-proxy 去进行服务和端口的发现。
通过kube-proxy监控,kube-proxy监控所有 Pod 节点信息,标签、IP、port 等,并负责把它们写入到 iptables 规则当中。
client 访问 SVC,其实访问的是 iptables规则。再由 iptables 导向后端 Pod 节点。
ipvs,图片上没有,现在的ClusterIP,NodePort 都是采取 ipvs 调度算法对后端 Pod 节点进行调度访问。
ipvs 代理模式
ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs可以将基于TCP和UDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。
ipvs 对比 iptables 我们知道kube-proxy支持 iptables 和 ipvs 两种模式, 在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于netfilter的,那么 ipvs 模式和 iptables 模式之间有哪些差异呢?
- ipvs 为大型集群提供了更好的可扩展性和性能
- ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
- ipvs 支持服务器健康检查和连接重试等功能
ipvs为负载均衡提供算法:
- rr:轮询带哦都
- lc:最小连接数
- dh:目标地址哈希
- sh:源地址哈希
- sed:最短期望延迟
- nq:不排队调度
client Pod 访问 Server Pod
- 首先,service IP 的 iptables代理变成了 ipvs 模块,实现负载均衡和流量导向。
- client 访问到 IPvs 服务,将流量分发到不同的 Pod 上运行。
kubernetes暴露端口的方式
集群内部实现访问:Clusterip
Clusterip是集群内部的私有ip,在集群内部访问服务非常方便,也是kuberentes集群默认的方式,直接通过service的Clusterip访问,也可以直接通过ServiceName访问。集群外部则是无法访问的。
默认类型,自动分配一个仅Cluster内部能够访问的虚拟IP
[root@master ~]# cat cluster.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: apache
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: apache
template:
metadata:
labels:
app: apache
spec:
containers:
- image: bravealove1/apache:v1.0
imagePullPolicy: IfNotPresent
name: apache
---
apiVersion: v1
kind: Service
metadata:
name: apache
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: apache
type: ClusterIP #指定网络模式
[root@master ~]# kubectl apply -f cluster.yml
deployment.apps/apache created
service/apache created
[root@master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/apache-599bc546b8-xp5rg 1/1 Running 0 12s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/apache ClusterIP 10.98.249.13 <none> 80/TCP 12s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d12h
[root@master ~]# curl 10.98.249.13
hello,this is a test page 1
集群外部方式访问:NodePort
NodePort在kubenretes里是一个早期广泛应用的服务暴露方式。Kubernetes中的service默认情况下都是使用的ClusterIP这种类型,这样的service会产生一个ClusterIP,这个IP只能在集群内部访问,要想让外部能够直接访问service,需要将service type修改为 nodePort。将service监听端口映射到node节点。
nodePort的原理在于在node上开了一个端口,将向该端口的流量导入到kube-proxy,然后由 kube-proxy进一步到给对应的pod
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: apache
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: apache
template:
metadata:
labels:
app: apache
spec:
containers:
- image: aimmi/apache:v1.0
imagePullPolicy: IfNotPresent
name: apache
---
apiVersion: v1
kind: Service
metadata:
name: apache
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
nodePort: 30000 指定对外端口
selector:
app: apache
type: NodePort #指定网络模式
[root@master ~]# kubectl apply -f nodeport.yml
deployment.apps/apache created
service/apache created
[root@master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/apache-599bc546b8-w6xnd 1/1 Running 0 10s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/apache NodePort 10.96.90.92 <none> 80:30000/TCP 10s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d12h
[root@master ~]# curl 192.168.145.188:30000
hello,this is a test page 1
DNS解析
Service
- 创建普通service 会以my-svc.my-namespace.svc.cluster.local 的形式指派一个 DNS A 记录,并解析到该service的Cluster IP。
- 创建“Headless” Service(没有Cluster IP)也会以 my-svc.my-namespace.svc.cluster.local 的形式被指派一个 DNS A 记录,但是并不会解析到的Cluster IP,而是解析到一组被选中的- - pod 的IP,如果没有backend则不做处理。
Pod
- 创建Pod 会以 pod-ip-address.my-namespace.pod.cluster.local 这种形式被指派一个 DNS A 记录。
案例
[root@master ~]# cat deploy.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
参数--record可以记录当前版本的Deployment都执行过哪些命令
[root@master ~]# kubectl create -f deploy.yml --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deployment created
创建完成后立即执行get命令查看这个Deployment
[root@master ~]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 2m14s
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-74d589986c-kxcvx 1/1 Running 0 2m11s
nginx-deployment-74d589986c-s277p 1/1 Running 0 2m11s
nginx-deployment-74d589986c-zlf8v 1/1 Running 0 2m11s
使用 nginx:1.9.1 的镜像来代替原来的 nginx的镜像
[root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated
查看更新进度
[root@master ~]# kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
查看镜像信息
[root@master ~]# kubectl describe deployment/nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Fri, 24 Dec 2021 22:24:10 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 4
kubernetes.io/change-cause: kubectl create --filename=deploy.yml --record=true
Selector: app=nginx
Replicas: 3 desired | 3 updated | 4 total | 3 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
使用rollout history命令查看Deployment的版本(revision)
[root@master ~]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl create --filename=deploy.yml --record=true
2 kubectl create --filename=deploy.yml --record=true
使用rollout undo命令回滚到前一个revision
[root@master ~]# kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment rolled back
查看镜像信息
[root@master ~]# kubectl describe deployment/nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Fri, 24 Dec 2021 22:24:10 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 3
kubernetes.io/change-cause: kubectl create --filename=deploy.yml --record=true
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
给一个应用扩容副本数为3
[root@master ~]# kubectl apply -f cluster.yml
deployment.apps/apache created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod/apache-599bc546b8-6tctl 1/1 Running 0 28s
[root@master ~]# kubectl scale deployment apache --replicas 4
deployment.apps/apache scaled
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod/apache-599bc546b8-6gx4p 0/1 ContainerCreating 0 2s
pod/apache-599bc546b8-6tctl 1/1 Running 0 2m3s
pod/apache-599bc546b8-8qzr4 0/1 ContainerCreating 0 2s
pod/apache-599bc546b8-j48v5 0/1 ContainerCreating 0 2s
创建一个pod,其中运行着nginx、redis、memcached 3个容器
[root@master ~]# vim pod.yml
---
apiVersion: v1
kind: Pod
metadata:
name: hellok8s
namespace: default
labels:
app: myapp
spec:
containers:
- name: mynginx
image: nginx
ports:
- containerPort: 80
- name: myredis
image: redis
ports:
- containerPort: 6379
- name: memcached
image: memcached
[root@master ~]# kubectl apply -f pod.yml
pod/hellok8s created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
hellok8s 3/3 Running 0 2m49s
给一个pod创建service,并可以通过ClusterlP/NodePort访问
[root@master ~]# vi nodeport.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: apache
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: apache
template:
metadata:
labels:
app: apache
spec:
containers:
- image: bravealove1/apache:v1.0
imagePullPolicy: IfNotPresent
name: apache
---
apiVersion: v1
kind: Service
metadata:
name: apache
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
nodePort: 30000 指定对外端口
selector:
app: apache
type: NodePort 指定网络模式
[root@master ~]# kubectl apply -f nodeport.yml
deployment.apps/apache created
service/apache created
[root@master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/apache-599bc546b8-w6xnd 1/1 Running 0 10s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/apache NodePort 10.96.90.92 <none> 80:30000/TCP 10s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d12h
[root@master ~]# curl 192.168.145.188:30000
hello,this is a test page 1
创建deployment和service,使用busybox容器nslookup解析service
[root@master ~]# cat host.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: httpd
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: myapp-externalname
namespace: default
spec:
type: ExternalName
externalName: web.test.example.com
部署
[root@master ~]# kubectl apply -f host.yml
deployment.apps/myapp-deploy created
service/apache created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-55bd85c8b-9jgf2 1/1 Running 0 107s
查看pods,service状态
[root@master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/myapp-deploy-55bd85c8b-9jgf2 1/1 Running 0 18m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d14h
service/myapp-externalname ExternalName <none> web.test.example.com <none> 3m35s
[root@master ~]# vibusybox.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: busybox-pod
name: test-busybox
spec:
containers:
- command:
- sleep
- "3600"
image: busybox
imagePullPolicy: Always
name: test-busybox
部署
[root@master ~]# kubectl apply -f busybox.yaml
pod/test-busybox created
查看pod状态
[root@master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/myapp-deploy-55bd85c8b-9jgf2 1/1 Running 0 19m
pod/test-busybox 1/1 Running 0 8m15s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d14h
service/myapp-externalname ExternalName <none> web.test.example.com <none> 4m49s
使用exec -it 与busybox进行交互
[root@master ~]# kubectl exec -it test-busybox /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # nslookup myapp-externalname.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10:53
myapp-externalname.default.svc.cluster.local canonical name = web.test.example.com