k8s相关服务与负载均衡
一,服务基础
1,多容器集群,多副本会自动分配到不同的计算节点上(2副本实验)
[root@master config]# vim pod-apache.yaml
replicas: 2 #副本数改成2
[root@master config]# kubectl apply -f pod-apache.yaml
[root@master config]# kubectl get pod -o wide #查看,此时运行两个资源都在zsl节点上
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-apache-695fd775fd-jpsgr 1/1 Running 0 27s 10.244.2.30 zsl
my-apache-695fd775fd-x8c4d 1/1 Running 0 27s 10.244.2.29 zsl
2,会变化的pod资源,当发现某一个pod不能使用的时候,RS会在其他节点上再创建一个相同的pod,及其对应的容器。
例:模拟其中一个资源容器不可用,此时会再创建出一个新的pod资源,而且可以在任何节点上生成,且ip地址也会发生改变。
[root@master config]# kubectl delete pod my-apache-695fd775fd-x8c4d #删除其中一个资源
[root@master config]# kubectl get pod -o wide #再次查看,又新生一个pod资源在node节点上
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-apache-695fd775fd-4bng8 1/1 Running 0 16s 10.244.1.13 node
my-apache-695fd775fd-jpsgr 1/1 Running 0 6m53s 10.244.2.30 zsl
3,service服务
①,pod存在生命周期,每个一段时间,pod就会自动重新创建,ip地址也会发生变化,所以直接对pod中的服务产生很大影响,因为访问地址在不断地变化。
②,service服务作用是创建一个cluster ip,也可以实现pod的负载均衡。用户访问web服务时,先访问service的cluster ip,由service代替用户找到对应的pod,最后访问pod中的web服务器。
③,会变化的pod给我们带来了诸多的不变,service就是解决这一问题的方法,会创建一个cluster ip,这个地址对应资源地址,且不会变化,会在多个服务上实现负载均衡的访问效果。
④,service服务通过port、nodeport、targetport将访问的请求最终映射到pod的容器内部服务上。
4,service服务端口
①,port:是service暴露在cluster ip上的端口,是提供给集群内部客户访问service的入口,供集群内部服务访问使用。
②,targetport:是pod上容器服务监听的端口,从port或nodeport上到来的数据最终经过kube-proxy流入到后端pod的targetport上进入容器,从而达到访问pod容器内部服务的目的。
5,service服务资源文件
①,作修改
[root@master config]# vim pod-apache.yaml #修改Apache资源文件
matchLabels: #匹配具体的东西
app: mytest #更改标签名字,与下面的labels相同
replicas: 2
template:
metadata:
labels:
app: mytest #更改标签名字
②,编辑
[root@master config]# vim pod-service.yaml #编辑新的yaml资源文件
---
apiVersion: v1
kind: Service
metadata:
name: httpd-service
spec:
ports:
- protocol: TCP
port: 80 #设置端口
targetPort: 80
selector:
app: mytest #要和上面pod-apache.yaml文件的标签一致
type: ClusterIP
[root@master config]# kubectl delete -f pod-apache.yaml #删除原来的
[root@master config]# kubectl apply -f pod-apache.yaml #运行修改后的
[root@master config]# kubectl apply -f pod-service.yaml #运行新创建的
③,查看k8s集群中service信息
[root@master config]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-service ClusterIP 10.96.79.49
80/TCP 64s kubernetes ClusterIP 10.96.0.1
443/TCP 2d1h
④,此时直接使用10.96.79.49这个ip地址是访问不了的,需要进入到容器访问。
创建一个资源类型为pod的资源文件
[root@master config]# vim pod-httpd.yaml
---
apiVersion: v1 #版本
kind: Pod #资源类型
metadata:
name: my-pod
labels:
app: mypod
spec:
containers:
- name: my-pod-httpd #容器名字
image: 192.168.1.134:5000/myapache:httpd #指定镜像
stdin: true #开启交互式和终端
tty: true
#ports: #注释掉端口和协议
#- protocol: TCP
# containerPort: 80
⑤,创建资源
[root@master config]# kubectl apply -f pod-httpd.yaml
pod/my-pod created
[root@master config]# kubectl get pod -o wide #查看,pod下两个容器在运行
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-apache-f9b95d95f-jn4vv 1/1 Running 0 10m 10.244.2.32 zsl
my-apache-f9b95d95f-skjh7 1/1 Running 0 10m 10.244.2.31 zsl
my-pod 1/1 Running 0 2m46s 10.244.1.14 node
[root@master config]# kubectl get service #查看集群中service服务信息
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-service ClusterIP 10.96.79.49
80/TCP 11m kubernetes ClusterIP 10.96.0.1
443/TCP 2d1h
⑥,进入容器
[root@master config]# kubectl exec -it my-pod -- /bin/bash
[root@my-pod html]#
⑦,访问成功
[root@my-pod html]# curl 10.96.79.49 #访问的是service服务中的httpd服务地址
[root@my-pod html]# curl 10.96.79.49/info.php #访问成功,多访问几次,此时是轮询的,可以看到php_host: 处的变化,不同的容器在提供服务
Array
(
[REMOTE_ADDR] => 10.244.1.14
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /info.php
)
php_host: my-apache-f9b95d95f-skjh7
1229
二,服务自动发现
1,创建服务:kubectl apply -f 资源文件
2,查询服务:kubectl get service
3,服务自动发现:cluster ip是集群分配的服务ip,供集群访问,在集群内部也可以通过服务的名称访问,服务的名称是通过coredns解析的,每个服务在创建的过程中都会完成自动注册。
服务名称:<服务名称>.<名称空间>.svc.cluster.local
4,在刚才的容器里,直接访问服务名称
[root@my-pod html]# curl httpd-service #服务名称,从service查看
[root@my-pod /]# curl httpd-service.default.svc.cluster.local #也可以加上后缀访问
[root@my-pod /]# cat /etc/resolv.conf #后缀所在文件
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
5,多资源文件,多个资源可以写到同一个文件中,使用---分割
[root@master config]# cat pod-apache.yaml > web.apache.yaml
[root@master config]# cat pod-service.yaml >> web.apache.yaml #写到一个文件中
[root@master config]# kubectl delete -f pod-apache.yaml #删除资源
[root@master config]# kubectl delete -f pod-service.yaml #删除资源
[root@master config]# kubectl get pod -o wide #查看,还剩一个pod资源在运行
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-pod 1/1 Running 0 90m 10.244.1.14 node
6,查看并创建运行资源
[root@master config]# vim web.apache.yaml
#tty: true
ports:
- protocol: TCP
containerPort: 80
--- #两个资源文件,分割
apiVersion: v1
kind: Service
metadata:
name: httpd-service
[root@master config]# kubectl apply -f web.apache.yaml #一次创建出两个
deployment.apps/my-apache created
service/httpd-service created
[root@master config]# kubectl get service #查看
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-service ClusterIP 10.96.211.116
80/TCP 50s kubernetes ClusterIP 10.96.0.1
443/TCP 2d2h [root@master config]# kubectl get pod #查看
NAME READY STATUS RESTARTS AGE
my-apache-f9b95d95f-8m8qv 1/1 Running 0 56s
my-apache-f9b95d95f-zfkhh 1/1 Running 0 56s
my-pod 1/1 Running 0 95m
三,服务原理
1,代理模式:
k8s v1.0服务支持userspace代理模式
k8s v1.1服务支持iptables代理模式
k8s v1.8服务支持IPVS代理模式
在k8s v1.2中,kube-proxy的iptables模式成为模式设置,现在默认使用IPVS,如果不能满足,要求退回至iptables模式
2,userspace用户空间代理模式:
用户访问的还是cluster ip,cluster ip并不是把请求转发给后端的容器,而是把请求转发给kube-proxy,再由kube-proxy转发给后端的容器,各个服务中,此时由于所有的请求都给了kube-proxy,对于这个软件的要求就比较高,性能很差,为了解决这个问题,就需要使用其他模式。
3,iptables模式:
此模式在用户访问的时候发生了变化,用户访问到cluster ip之后,由iptables实现端口映射,把请求转发到后端,此时kube-proxy只是设置负载均衡映射的访问策略和端口转发规则,但是算法有限,更多的功能支持不了,此时就有了IPVS模式,此模式架构不变,只是用户访问的是lvs模块。
4,IPVS模式:与iptables模式架构相同,只是用户访问的是lvs模块。
四,在外部访问集群
1,service允许指定一个type类型,默认是cluster ip。
2,type类型:
①,cluster ip:通过集群的内部ip暴露服务,服务只能够在集群内部可以访问,这就是默认的servicetype。
②,nodeport:通过每个node的ip和静态端口(nodeport)暴露服务,nodeport服务会路由到cluster ip服务。
③,loadbalancer:使用云提供商的负载均衡器,外部的负载均衡器可以路由到nodeport服务和cluster ip服务。
3,nodeport:是提供给集群外部用户访问service入口的一种方式,是提供给集群外部用户访问service的入口。
五,对外发布服务
1,之前构建的服务已经可以在集群内部运转起来了,但集群外部还是无法访问集群内部的服务。
2,有时候服务可能来自第三方或者其他团队,无法把所有服务都放入集群内部,这时候就需要集群内部和集群外部的服务实现互访。
①,loadbalancer:使用外部的云服务(需要支持,externallps)
②,nodeport:基于端口对外提供服务(四层)
③,lngress:使用ingress规则控制器(七层)
例:修改服务类型
[root@master config]# vim pod-service.yaml
app: mytest
type: NodePort #改为nodeport,基于端口对外提供服务
[root@master config]# kubectl apply -f pod-apache.yaml#运行Apache资源
[root@master config]# kubectl apply -f pod-service.yaml #创建资源
[root@master config]# kubectl get service #查看
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-service NodePort 10.96.161.244
80:30552/TCP 49s kubernetes ClusterIP 10.96.0.1
443/TCP 2d3h 测试访问,都可以访问成功
访问:curl 节点主机名(IP地址):服务映射端口,任何节点都可以
[root@master config]# curl node:30552
[root@master config]# curl zsl:30552
[root@master config]# curl node:30552/info.php
Array
(
[REMOTE_ADDR] => 10.244.1.0
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /info.php
)
php_host: my-apache-f9b95d95f-thtrp
1229
五,headless服务
1,有时不需要或不想要负载均衡,以及单独的cluster ip,遇到这种情况,我们可以创建headless服务。
2,headless服务会把ip通过多个A记录的形式解析到具体的容器ip上面,多用于有状态的服务。
3,测试,复制service服务资源文件
[root@master config]# cp pod-service.yaml headless.yaml
[root@master config]# vim headless.yaml
---
apiVersion: v1
kind: Service
metadata:
name: headless #名字可改可不改
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
app: mytest
type: ClusterIP #更改为ClusterIP类型
clusterIP: None #设置为none,不设置ip
4,创建资源
[root@master config]# kubectl apply -f headless.yaml #运行headless资源文件
[root@master config]# kubectl apply -f pod-httpd.yaml#运行pod类型资源文件
[root@master config]# kubectl exec -it my-pod -- /bin/bash #进入容器
5,安装需要的软件
[root@my-pod html]# cd /etc/yum.repos.d/ #这里需要配置yum源
[root@my-pod yum.repos.d]# ls
dv
[root@my-pod yum.repos.d]# vim dvd.repod.repo
[dvd]
name=dvd
baseurl=http://192.168.1.134/mnt #去访问另外一个节点的挂载点,需要把挂载点放到/var/www/html下
enabled=1
gpgcheck=0
[root@my-pod ~]# yum -y install bind-utils #安装软件
6,访问测试
[root@my-pod yum.repos.d]# host headless #如果访问不了,是dns域名解析失败
六,lngress控制器
1,lngress公开了集群外部到集群内部的service路由。
2,可以将lngress配置为提供服务、外部可访问的URL负载均衡流量。
3,lngress控制器通常由负载均衡器来实现。
4,必须具有ingress控制器才能满足lngress的要求,仅创建资源无效。
5,lngress:是从集群外部访问集群内部的路由。
6,lngress控制器接收用户的域名访问请求,将请求分发给集群中的service服务,由service服务以负载均衡的方式,将请求分发给pod,由pod中的容器提供对应的服务。
7,安装lngress
我这里已经准备好了ingress的安装tar包
[root@master ~]# cd ingress/
[root@master ingress]# ls
ingress-example.yaml ingress-nginx.tar.gz ingress-service.yaml mandatory.yaml
[root@master ingress]# docker load -i ingress-nginx.tar.gz #恢复镜像
[root@master ingress]# docker tag quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 192.168.1.134:5000/nginx-ingress:0.30.0 #打标签
[root@master ingress]# docker push 192.168.1.134:5000/nginx-ingress:0.30.0 #传到私有仓库
[root@master ingress]# curl 192.168.1.134:5000/v2/_catalog #查看,已上传到私有仓库
{"repositories":["centos","myapache","nginx","nginx-ingress","redis","ububtu"]}
8,编辑安装ingress的资源文件
[root@master ingress]# vim mandatory.yaml
221 image: 192.168.1.134:5000/nginx-ingress:0.30.0 #改成私有仓库地址
[root@master ingress]# kubectl apply -f mandatory.yaml #创建资源
9,验证是否成功,需要指定命名空间,因为ingress创建的有自己的命名空间
[root@master ingress]# kubectl -n ingress-nginx get pod
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-5cdb8dbb4c-rz5qp 0/1 CrashLoopBackOff 2 40s
10,创建
[root@master ~]# kubectl delete -f config/web.apache.yaml #把原来的资源停掉
[root@master ~]# kubectl apply -f config/web.apache.yaml #重新创建
[root@master ~]# kubectl apply -f ingress/ingress-example.yaml #创建ingress资源
[root@master ~]# kubectl get ingresses #查看
NAME CLASS HOSTS ADDRESS PORTS AGE
my-app
* 80 23s 11,访问,任何一个节点的ip都可以访问了,公开了内部、外部之间的路由
[root@master ~]# curl 192.168.1.133
[root@master ~]# curl 192.168.1.134
[root@master ~]# curl 192.168.1.135