文章目录
一、什么是服务(Service)
它是指将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
使用 Kubernetes,你无需修改应用程序即可使用不熟悉的服务发现机制。 Kubernetes 为 Pod 提供自己的 IP 地址,并为一组 Pod 提供相同的 DNS 名, 并且可以在它们之间进行负载均衡。
动机创建和销毁 Kubernetes Pod 以匹配集群的期望状态。 Pod 是非永久性资源。 如果你使用 Deployment 来运行你的应用程序,则它可以动态创建和销毁 Pod。
每个 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一时刻运行的 Pod 集合可能与稍后运行该应用程序的 Pod 集合不同。
这导致了一个问题: 如果一组 Pod(称为“后端”)为集群内的其他 Pod(称为“前端”)提供功能, 那么前端如何找出并跟踪要连接的 IP 地址,以便前端可以使用提供工作负载的后端部分?
进入 Services。
Service资源
Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常称为微服务。 Service 所针对的 Pod 集合通常是通过选择算符来确定的。 要了解定义服务端点的其他方法,请参阅不带选择算符的服务。
举个例子,考虑一个图片处理后端,它运行了 3 个副本。这些副本是可互换的 —— 前端不需要关心它们调用了哪个后端副本。 然而组成这一组后端程序的 Pod 实际上可能会发生变化, 前端客户端不应该也没必要知道,而且也不需要跟踪这一组后端的状态。
Service 定义的抽象能够解耦这种关联。
Service理解
Service可以看作是一组提供相同服务的Pod对外的访问接口。借助Service,应
用可以方便地实现服务发现和负载均衡。
• service默认只支持4层负载均衡能力,没有7层功能。(可以通过Ingress实现)
• service的类型:
• ClusterIP:默认值,k8s系统给service自动分配的虚拟IP,只能在集群内部访问。
• NodePort:将Service通过指定的Node上的端口暴露给外部,访问任意一个
NodeIP:nodePort都将路由到ClusterIP。
• LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部的负载均
衡器,并将请求转发到 :NodePort,此模式只能在云服务器上使用。
• ExternalName:将服务通过 DNS CNAME 记录方式转发到指定的域名(通过
spec.externlName 设定)
二、创建svc.yaml
利用命令创建一个svc模板yaml文件,并修改
[root@k8s1 ~]# kubectl expose deployment deployment-example --port 80 --target-port 80 --dry-run=client -o yaml >svc.yaml
[root@k8s1 ~]# ls
anaconda-ks.cfg deployment.yaml liveness.yaml original-ks.cfg svc.yaml
cronjob.yaml job.yaml nginx-1.21.1 pod.yaml
daemonset.yaml kube-flannel.yml nginx-1.21.1.tar.gz replicaset-example.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
name: svc1
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: ClusterIP
生效svc1.yaml,并查看
[root@k8s1 ~]# vim svc.yaml
[root@k8s1 ~]# kubectl apply -f svc.yaml
service/svc1 created
[root@k8s1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
liveness-http ClusterIP 10.99.7.186 <none> 80/TCP 17h
svc1 ClusterIP 10.98.180.114 <none> 80/TCP 6s
[root@k8s1 ~]# kubectl describe svc svc1
Name: svc1
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.180.114
IPs: 10.98.180.114
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.36:80,10.244.2.44:80,10.244.2.45:80
Session Affinity: None
Events: <none>
[root@k8s1 ~]# iptables -t nat -nL |grep :80
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc1 */ tcp to:10.244.2.45:80
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc1 */ tcp to:10.244.1.36:80
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc1 */ tcp to:10.244.2.44:80
KUBE-SVC-DZERXHZGH3HKTTEJ tcp -- 0.0.0.0/0 10.98.180.114 /* default/svc1 cluster IP */ tcp dpt:80
KUBE-MARK-MASQ tcp -- !10.244.0.0/16 10.98.180.114 /* default/svc1 cluster IP */ tcp dpt:80
三、IPVS模式的service
Service 是由 kube-proxy 组件,加上 iptables 来共同实现的. • kube-proxy 通过 iptables 处理 Service 的过程,需要在宿主机上设置相当多的
iptables 规则,如果宿主机有大量的Pod,不断刷新iptables规则,会消耗大量的CPU
资源。
• IPVS模式的service,可以使K8s集群支持更多量级的Pod
开启kube-proxy的ipvs模式:
[root@k8s1 ~]# kubectl edit cm kube-proxy -n kube-system
configmap/kube-proxy edited
切换之后要进行重启容器,更新kube-proxy pod
kubectl get pod -n kube-system |grep kube-proxy | awk'{system("kubectl delete pod "$1" -n kube-system")}'
此时使用ipvsadm
查看svc,发现比iptables
更为简洁
[root@k8s1 ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 10.244.3.12:6443 Masq 1 0 0
TCP 10.96.0.10:53 rr
-> 10.244.0.2:53 Masq 1 0 0
-> 10.244.0.3:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 10.244.0.2:9153 Masq 1 0 0
-> 10.244.0.3:9153 Masq 1 0 0
TCP 10.98.180.114:80 rr
-> 10.244.1.36:80 Masq 1 0 0
-> 10.244.2.44:80 Masq 1 0 0
-> 10.244.2.45:80 Masq 1 0 0
TCP 10.99.7.186:80 rr
UDP 10.96.0.10:53 rr
-> 10.244.0.2:53 Masq 1 0 0
-> 10.244.0.3:53 Masq 1 0 0
切换为ipvs模式,一是可以减少CPU资源消耗,二是可以支持更多Pod
IPVS模式下,kube-proxy会在service创建后,在宿主机上添加一个虚拟网卡:kube-ipvs0,并分配service IP
kube-proxy通过linux的IPVS模块,以rr轮询方式调度service中的Pod
四、flannel插件
k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel,calico等。
CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist
插件使用的解决方案如下:
• 虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。
• 多路复用:MacVLAN,多个容器共用一个物理网卡进行通信。
• 硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。
• 容器间通信:同一个pod内的多个容器间的通信,通过lo即可实现;
• pod之间的通信:
• 同一节点的pod之间通过cni网桥转发数据包。
• 不同节点的pod之间的通信需要网络插件支持。
• pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做
负载均衡,而做不了nat转换。
• pod和外网通信:iptables的MASQUERADE。
• Service与集群外部客户端的通信;(ingress、nodeport、loadbalancer)
• flannel支持多种后端:
• Vxlan
• vxlan //报文封装,默认
• Directrouting //直接路由,跨网段使用vxlan,同网段使用host-gw模式。
• host-gw: //主机网关,性能好,但只能在二层网络中,不支持跨网络,
如果有成千上万的Pod,容易产生广播风暴,不推荐
• UDP: //性能差,不推荐
• 配置flannel为host-gw
后端:
[root@k8s1 flannel]# kubectl -n kube-flannel edit cm kube-flannel-cfg
configmap/kube-flannel-cfg edited
[root@k8s1 flannel]# kubectl -n kube-flannel delete pod --all
pod "kube-flannel-ds-4jfqv" deleted
pod "kube-flannel-ds-fmzxq" deleted
pod "kube-flannel-ds-fsnnh" deleted
[root@k8s1 flannel]# kubectl -n kube-flannel get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel-ds-8vrhj 1/1 Running 0 10s 10.244.3.12 k8s1 <none> <none>
kube-flannel-ds-cccf7 1/1 Running 0 10s 10.244.3.13 k8s2 <none> <none>
kube-flannel-ds-dthnm 1/1 Running 0 10s 10.244.3.14 k8s3 <none> <none>
[root@k8s1 flannel]#
此时的网关为主机网关10.244.3.13,10.244.3.14
[root@k8s1 flannel]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.244.3.2 0.0.0.0 UG 0 0 0 eth0
10.244.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
10.244.1.0 10.244.3.13 255.255.255.0 UG 0 0 0 eth0
10.244.2.0 10.244.3.14 255.255.255.0 UG 0 0 0 eth0
10.244.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
[root@k8s1 flannel]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
liveness-http ClusterIP 10.99.7.186 <none> 80/TCP 17h
svc1 ClusterIP 10.98.180.114 <none> 80/TCP 46m
[root@k8s1 flannel]# curl 10.98.180.114
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
五、Headless Service无头服务
Headless Service “无头服务” • Headless Service不需要分配一个VIP,而是直接以DNS记录的方式解析出被代理Pod
的IP地址。
• 域名格式: ( s e r v i c e n a m e ) . (servicename). (servicename).(namespace).svc.cluster.local
[root@k8s1 ~]# vim svc.yaml
[root@k8s1 ~]# kubectl delete -f svc.yaml
service "svc1" deleted
[root@k8s1 ~]# kubectl apply -f svc.yaml
service/svc1 created
此时的svc没有分配IP地址
[root@k8s1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12d
liveness-http ClusterIP 10.99.7.186 <none> 80/TCP 18h
svc1 ClusterIP None <none> 80/TCP 18s
直接解析到pod的IP地址上,并且是负载均衡的
[root@k8s1 ~]# dig -t A svc1.default.svc.cluster.local. @10.96.0.1
; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A svc1.default.svc.cluster.local. @10.96.0.1
;; global options: +cmd
;; connection timed out; no servers could be reached
[root@k8s1 ~]# dig -t A svc1.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A svc1.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45726
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;svc1.default.svc.cluster.local. IN A
;; ANSWER SECTION:
svc1.default.svc.cluster.local. 30 IN A 10.244.1.36
svc1.default.svc.cluster.local. 30 IN A 10.244.2.45
svc1.default.svc.cluster.local. 30 IN A 10.244.2.44
;; Query time: 30 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Fri Oct 28 11:58:10 CST 2022
;; MSG SIZE rcvd: 197
[root@k8s1 ~]#
Pod滚动更新后,依然可以解析
当删除pod重建后,pod地址改变,DNS地址解析会跟着改变
[root@k8s1 ~]# kubectl delete pod --all
pod "deployment-example-77cd76f9c5-bgksh" deleted
pod "deployment-example-77cd76f9c5-cdz8h" deleted
pod "deployment-example-77cd76f9c5-hl4nt" deleted
[root@k8s1 ~]# dig -t A svc1.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A svc1.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13821
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;svc1.default.svc.cluster.local. IN A
;; ANSWER SECTION:
svc1.default.svc.cluster.local. 30 IN A 10.244.1.45
svc1.default.svc.cluster.local. 30 IN A 10.244.2.48
svc1.default.svc.cluster.local. 30 IN A 10.244.1.44
;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Fri Oct 28 11:59:39 CST 2022
;; MSG SIZE rcvd: 197
六、从外部访问 Service :NodePort方式
NodePort方式
apiVersion: v1
kind: Service
metadata:
name: svc2
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: NodePort
[root@k8s1 ~]# vim svc2.yaml
[root@k8s1 ~]# kubectl apply -f svc2.yaml
service/svc2 created
[root@k8s1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12d
liveness-http ClusterIP 10.99.7.186 <none> 80/TCP 20h
svc2 NodePort 10.104.27.126 <none> 80:31268/TCP 9s
[root@k8s1 ~]# curl 10.244.3.12:31268
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8s1 ~]# curl 10.104.27.126
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8s1 ~]# curl 10.244.3.13:31268
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8s1 ~]# curl 10.244.3.14:31268
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
修改端口为3333,无效值,因为范围在30000-32767
解决该问题:
修改大端口范围
[root@k8s1 ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
成功修改创建svc2,注意一个端口只能访问一个服务
[root@k8s1 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s1 Ready control-plane,master 12d v1.23.12
k8s2 Ready <none> 11d v1.23.12
k8s3 Ready <none> 11d v1.23.12
[root@k8s1 ~]# kubectl apply -f svc2.yaml
service/svc2 created
[root@k8s1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12d
liveness-http ClusterIP 10.99.7.186 <none> 80/TCP 20h
svc2 NodePort 10.110.96.34 <none> 80:33333/TCP 9s
[root@k8s1 ~]# curl 10.244.3.12:33333
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
七、从外部访问 Service : LoadBalancer
• 从外部访问 Service 的第二种方式,适用于公有云上的 Kubernetes 服务。这时
候,你可以指定一个 LoadBalancer 类型的 Service
apiVersion: v1
kind: Service
metadata:
name: svc3
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: nginx
type: LoadBalancer
[root@k8s1 ~]# vim svc3.yaml
[root@k8s1 ~]# kubectl apply -f svc3.yaml
service/svc3 created
[root@k8s1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12d
svc3 LoadBalancer 10.107.53.216 <pending> 80:51075/TCP 4s
[root@k8s1 ~]# kubectl describe svc svc3
Name: svc3
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.107.53.216
IPs: 10.107.53.216
Port: http 80/TCP
TargetPort: 80/TCP
NodePort: http 51075/TCP
Endpoints: 10.244.1.44:80,10.244.1.45:80,10.244.2.48:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
[root@k8s1 ~]# curl 10.107.53.216
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8s1 ~]# curl 10.244.3.12:51075
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
在service提交后,Kubernetes就会调用 CloudProvider 在公有云上为你创建
一个负载均衡服务,并且把被代理的 Pod 的 IP地址配置给负载均衡服务做
后端。
搭建云端环境:metallb
1.如果你在IPVS模式下使用kube-proxy,从Kubernetes v1.14.2开始,你必须启用严格的ARP模式。注意,如果你使用kube-router作为服务代理,你不需要这样做,因为它默认是启用严格的ARP。
你可以通过编辑当前集群中的kube-proxy配置来实现这一点:
[root@k8s1 ~]# kubectl edit configmaps -n kube-system kube-proxy
configmap/kube-proxy edited
2.重置pod
[root@k8s1 ~]# kubectl get pod -n kube-system |grep kube-proxy
kube-proxy-dnrn9 1/1 Running 0 3h30m
kube-proxy-gzmnr 1/1 Running 0 3h30m
kube-proxy-zs5hr 1/1 Running 0 3h30m
[root@k8s1 ~]# kubectl get pod -n kube-system |grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'
pod "kube-proxy-dnrn9" deleted
pod "kube-proxy-gzmnr" deleted
pod "kube-proxy-zs5hr" deleted
[root@k8s1 ~]# kubectl get pod -n kube-system |grep kube-proxy kube-proxy-4skbb 1/1 Running 0 7s
kube-proxy-65x7t 1/1 Running 0 6s
kube-proxy-ln86l 1/1 Running 0 8s
或者
# see what changes would be made, returns nonzero returncode if different
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl diff -f - -n kube-system
# actually apply the changes, returns nonzero returncode on errors only
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system
3.拉取yaml文件
[root@k8s1 ~]# cd metallb/
[root@k8s1 metallb]# wget https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml
--2022-10-28 14:22:56-- https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 67376 (66K) [text/plain]
Saving to: ‘metallb-native.yaml’
100%[================================================================>] 67,376 --.-K/s in 0.07s
2022-10-28 14:22:56 (991 KB/s) - ‘metallb-native.yaml’ saved [67376/67376]
[root@k8s1 metallb]# ls
metallb-native.yaml
更改yaml文件仓库镜像位置
vim metallb-native.yaml
4.将所需要的镜像传输到harbor仓库,做本地化处理
搭载harbor仓库主机执行以下命令:
docker pull quay.io/metallb/controller:v0.13.7
docker pull quay.io/metallb/speaker:v0.13.7
docker tag quay.io/metallb/speaker:v0.13.7 www.hanxuan.com/metallb/speaker:v0.13.7
docker tag quay.io/metallb/controller:v0.13.7 www.hanxuan.com/metallb/controller:v0.13.7
docker push www.hanxuan.com/metallb/controller:v0.13.7
docker push www.hanxuan.com/metallb/speaker:v0.13.7
5.生效yaml文件
[root@k8s1 metallb]# kubectl apply -f metallb-native.yaml
namespace/metallb-system created
customresourcedefinition.apiextensions.k8s.io/addresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created
customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created
customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created
serviceaccount/controller created
serviceaccount/speaker created
role.rbac.authorization.k8s.io/controller created
role.rbac.authorization.k8s.io/pod-lister created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/controller created
rolebinding.rbac.authorization.k8s.io/pod-lister created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
secret/webhook-server-cert created
service/webhook-service created
deployment.apps/controller created
daemonset.apps/speaker created
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created
自动为我们创建了一个namespace
[root@k8s1 metallb]# kubectl get ns
NAME STATUS AGE
default Active 12d
kube-flannel Active 12d
kube-node-lease Active 12d
kube-public Active 12d
kube-system Active 12d
metallb-system Active 6s
发现每个节点上都搭载了一个控制器
[root@k8s1 metallb]# kubectl get all -n metallb-system
NAME READY STATUS RESTARTS AGE
pod/controller-f45548cb9-b4746 1/1 Running 0 63s
pod/speaker-l8fpm 1/1 Running 0 63s
pod/speaker-lvlm8 1/1 Running 0 63s
pod/speaker-rf9vl 1/1 Running 0 63s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/webhook-service ClusterIP 10.108.193.33 <none> 443/TCP 63s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/speaker 3 3 3 3 3 kubernetes.io/os=linux 63s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/controller 1/1 1 1 63s
NAME DESIRED CURRENT READY AGE
replicaset.apps/controller-f45548cb9 1 1 1 63s
地址池:定义要分配给负载平衡器服务的IP
为了给服务分配一个IP,MetalLB必须通过IPAddressPool CR来指示这样做。
所有通过IPAddressPools(地址池)分配的IP都有助于MetalLB用来为服务分配IP(及负载均衡器)的IP池。
在L2Advertisement实例中不设置IPAddressPool选择器,被解释为该实例与所有可用的IPAddressPools相关。因此,如果有专门的IPAddressPools,并且只有其中一些必须通过L2Advertisement实例,那么必须声明我们想要广告IP的IPAddressPools列表(另外,可以使用一个标签选择器)。
[root@k8s1 metallb]# vim config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 10.244.3.100-10.244.3.150
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
~
生效yaml文件,发现EXTERNAL-IP已经分配
[root@k8s1 metallb]# kubectl apply -f config.yaml
ipaddresspool.metallb.io/first-pool created
l2advertisement.metallb.io/example created
[root@k8s1 metallb]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12d
svc3 LoadBalancer 10.107.53.216 10.244.3.100 80:51075/TCP 39m
(此处的service是一个ip对应一个服务,如果需要节省资源,一个IP对应多个服务需要用到ingress,后文笔记将会提到)
八、从外部访问 Service:ExternalName
从外部访问的第三种方式叫做ExternalName
vim svc4.yaml
apiVersion: v1
kind: Service
metadata:
name: svc4
spec:
type: ExternalName
externalName: test.westos.org
生效后,可以访问到映射的域名test.westos.org
[root@k8s1 ~]# kubectl apply -f svc4.yaml
service/svc4 created
[root@k8s1 ~]# dig -t A svc1.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A svc1.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 11113
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;svc1.default.svc.cluster.local. IN A
;; AUTHORITY SECTION:
cluster.local. 30 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1666940253 7200 1800 86400 30
;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Fri Oct 28 14:58:15 CST 2022
;; MSG SIZE rcvd: 152
[root@k8s1 ~]# dig -t A svc4.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A svc4.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;svc4.default.svc.cluster.local. IN A
;; ANSWER SECTION:
svc4.default.svc.cluster.local. 30 IN CNAME test.westos.org.
;; Query time: 51 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Fri Oct 28 14:58:24 CST 2022
;; MSG SIZE rcvd: 118