pod漂移问题,可以理解成pod ip是变化的。
k8s具有强大的副本控制能力,能保证再任意副本pod挂掉时,自动从其他机器启动一个新的,还可以动态库容。通俗地说,这个pod可能任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上。那么自然随着pod的创建和销毁,pod ip是变化的,如何把这个动态的pod ip暴露出去?
这里借助k8s的色弱ice机制,service可以以标签形式选定一组带指定标签的pod,并监控和自动负载他们的pod ip,那么我们向外暴露只暴露了service ip就行了。
这里就是NodePort模式:即在每个节点上开启一个端口,然后转发到内部pod ip上。
svc域名组成:svc名称.svc所在名称空间.svc.cluster.local
这个只能在集群内部访问,即只能在pod里面去访问这个域名,因为svc域名是由cordns解析的,物理机用的dns可以通过cat /etc/resolv.conf
查看,这俩个dns不是同一个网段的。
Service可以通过标签选择器找到它所关联的pod,但是属于四层代理,只能基于ip和端口代理。
# svc创建后,会对应创建endpoint
# ENDPOINTS 存的就是这个service对应的后端pod所对应的ip+port
[root@master ~]# k get ep -n kube-system
NAME ENDPOINTS AGE
kube-dns 10.244.140.72:53,10.244.140.75:53,10.244.140.72:53 + 3 more... 43d
metrics-server 10.244.140.71:4443 42d
# 这里svc和pod的ip怎么保存到防火墙规则里面? 通过kube-proxy实现,保存到ipvs规则里面
# 通过ipvsadm -Ln可以看到
Service的type类型有很多,如NodePort、ClusterIp、LoadBalancer、Externalname,如果Service想要被k8s集群外部访问,需要用NodePort类型,但这有以下几个问题:
+++++++++++++++
1、nodeport会在物理机映射一个端口,绑定到物理机上,导致每个服务都要映射一个端口,端口过多,维护困难。
2、service底层使用的是iptables或者ipvs,仅支持四层代理,无法基于https协议做代理。
+++++++++++++++
四层负载:基于ip和端口的负载均衡。在三层负载基础上通过发布三层的ip地址(VIP)然后加上四层的端口号,来决定哪些流量需要做负载均衡;
对需要处理的流量进行NAT处理,然后转发至后台服务器,并记录 下这个TCP或者UDP的流量是由那台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。
七层负载: 基于虚拟的URL或主机IP的负载均衡,在四层的基础上,再考虑应用层的特征,比如同一个web服务器的负载均衡,除了根据VIP加80端口辨别是否需要处理的流量,还可以根据七层的URL、浏览器类别、语言来决定是否需要进行负载均衡。
举个例子,如果你的Web服务器分成两组,一组是中文语言的,一组是英文语言的,那么七层负载均衡就可以当用户来访问你的域名时,自动辨别用户语言,然后选择对应的语言服务器组进行负载均衡处理。
四层负载均衡工作在传输层,七层负载均衡工作在应用层
OSI七层模型:
官网定义
Ingress可以把进入到集群内部的请求转发到集群中的一些服务上,从而可以把服务映射到集群外部。
Ingress能把集群内Service配置成外网能够访问的URL、流量负载均衡,提供基于域名访问的虚拟主机等。
简单理解
原来需要修改nginx配置,然后配置各种域名对应哪个service,现在把这个动作抽象出来,变成一个Ingress对象,你可以用yaml创建,每次不要去改nginx了,直接改yaml然后创建/更新就行了。
Ingress总结
Ingress是k8s中的资源,主要是管理ingress-controller这个代理的配置文件。
Ingress Controller解决的是“nginx的处理方式”,它通过与kubernetes api交互,动态感知集群中Ingress规则变化,动态读取,然后按照自己的模板生成一段nginx配置,再写到nginx pod里面,最后reload一下
Ingress Controller是一个七层负载均衡调度器,客户端的请求先到达这个七层负载均衡调度器,由七层负载均衡器在反向代理到后端pod。
常见的七层负载均衡器有nginx、traefik,以我们熟悉的nginx为例,假如请求到达nginx,会通过upstream反向代理到后端pod应用,但是后端pod的ip地址是一直在变化的,因此在后端pod前需要加一个service,这个service只是起到分组的作用,那么我们upstream只需要填写service地址即可。
Ingress-controller里面封装就是nginx,直接在物理机上装个nginx,为啥还弄个Ingress-controller?
Nginx:nginx配置文件一改动,你还需要手动reload一下才可以生效,但是如果用ingress-controller封装的nginx,你ingress维护配置,ingress创建好之后,会自动的把配置文件传到ingress-controller这个pod里,会自动进行reload,然后配置就生效了。
步骤:
【1】部署Ingress Controller,这里ingress controller 使用的是nginx
【2】创建pod应用,可以通过控制器创建pod
【3】创建service,用来分组pod
【4】创建Ingress http,测试通过http访问权限
【5】创建Ingress https,测试通过https访问应用
1、Ingress Controller结合Ingress 定义的规则生成配置,然后动态更新ingress-controller里的Nginx 或者trafik负载均衡器,并刷新使配置生效,来达到服务自动发现的作用。
2、Ingress 则是定义规则,通过它定义某个域名的请求过来之后转发到集群中指定的 Service。它可以通过 Yaml 文件定义,可以给一个或多个 Service 定义一个或多个 Ingress 规则。
Ingress Controller 是集群流量的接入层,对它做高可用非常重要,可以基于keepalive实现nginx-ingress-controller高可用:
Ingress-controler根据deployment+nodeselector+pod反亲和性方式部署在k8s指定的俩个work节点,nginx-ingress-controller这个pod共享宿主机ip,然后通过keepalive+nginx实现nginx-ingress-controller高可用。
https://github.com/kubernetes/ingress-nginx
https://github.com/kubernetes/ingress-nginx/tree/main/deploy/static/provider/baremetal
【1】在工作节点上传镜像文件,然后解压。
[root@node01 package]# ctr -n=k8s.io images import ingress-nginx-controllerv1.1.0.tar.gz
[root@node01 package]# ctr -n=k8s.io images import kube-webhook-certgen-v1.1.0.tar.gz
[root@node02 package]# ctr -n=k8s.io images import ingress-nginx-controllerv1.1.0.tar.gz
[root@node02 package]# ctr -n=k8s.io images import kube-webhook-certgen-v1.1.0.tar.gz
【2】运行yaml文件
[root@master 17]# kubectl apply -f ingress-deploy.yaml
[root@master 17]# kubectl get pod -n ingress-nginx -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-2zhnk 0/1 Completed 0 6m18s 10.244.196.130 node01 <none> <none>
ingress-nginx-admission-patch-htsrd 0/1 Completed 1 6m18s 10.244.196.129 node01 <none> <none>
ingress-nginx-controller-64bdc78c96-6c9c6 1/1 Running 0 41s 10.32.1.148 node01 <none> <none>
ingress-nginx-controller-64bdc78c96-fpvlf 1/1 Running 0 6m18s 10.32.1.149 node02 <none> <none>
# 如果ingress-nginx-controller-xx的pod出现问题,用kubectl logs -f 或者kubectl describe去排查,我出现问题的原因是节点上的80端口被占用了
ingress-nginx-controller–里面封装的就是nginx七层代理。
这里的pod使用的是宿主机的ip。
在工作节点执行yum install epel-release nginx keepalived nginx-mod-stream -y
[root@node01 ~]# yum install epel-release nginx keepalived nginx-mod-stream -y
[root@node02 ~]# yum install epel-release nginx keepalived nginx-mod-stream -y
修改nginx配置文件。主备一样
[root@node01 ~]# cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
# 四层负载均衡,为两台Master apiserver组件提供负载均衡
stream {
log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
access_log /var/log/nginx/k8s-access.log main;
upstream k8s-ingress-controller {
server 10.32.1.148:80 weight=5 max_fails=3 fail_timeout=30s; # 修改成自己工作节点的ip
server 10.32.1.149:80 weight=5 max_fails=3 fail_timeout=30s; # 修改成自己工作节点的ip
}
server {
listen 30080;
proxy_pass k8s-ingress-controller;
}
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
}
备注:
server
反向服务地址和端口weight
权重max_fails
失败多少次,认为主机已挂掉,则踢出fail_timeout
踢出后重新探测时间主配置
[root@node01 ~]# cat /etc/keepalived/keepalived.conf
global_defs {
notification_email {
[email protected]
[email protected]
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_MASTER
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state MASTER
interface ens32 # 修改为实际网卡名
virtual_router_id 51 # VRRP 路由 ID实例,每个实例是唯一的
priority 100 # 优先级,备服务器设置 90
advert_int 1 # 指定VRRP 心跳包通告间隔时间,默认1秒
authentication {
auth_type PASS
auth_pass 1111
}
# 虚拟IP
virtual_ipaddress {
10.32.1.155/24
}
track_script {
check_nginx
}
}
备配置 (和主配置的区别就是优先级 priority 和state)
[root@node02 package]# cat /etc/keepalived/keepalived.conf
global_defs {
notification_email {
[email protected]
[email protected]
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_MASTER
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state BACKUP
interface ens32 # 修改为实际网卡名
virtual_router_id 51 # VRRP 路由 ID实例,每个实例是唯一的
priority 90 # 优先级,备服务器设置 90
advert_int 1 # 指定VRRP 心跳包通告间隔时间,默认1秒
authentication {
auth_type PASS
auth_pass 1111
}
# 虚拟IP
virtual_ipaddress {
10.32.1.155/24
}
track_script {
check_nginx
}
}
#vrrp_script:指定检查nginx工作状态脚本(根据nginx状态判断是否故障转移)
#virtual_ipaddress:虚拟IP(VIP)
[root@node01 keepalived]# cat check_nginx.sh
#!/bin/bash
#1、判断Nginx是否存活
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
if [ $counter -eq 0 ]; then
#2、如果不存活则尝试启动Nginx
service nginx start
sleep 2
#3、等待2秒后再次获取一次Nginx状态
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
#4、再次进行判断,如Nginx还不存活则停止Keepalived,让地址进行漂移
if [ $counter -eq 0 ]; then
service keepalived stop
fi
fi
[root@node01 keepalived]# chmod +x /etc/keepalived/check_nginx.sh
# 注:keepalived根据脚本返回状态码(0为工作正常,非0不正常)判断是否故障转移。
node01和node02都要操作
systemctl daemon-reload
systemctl enable nginx keepalived
systemctl start nginx
systemctl start keepalived
停掉node01上的keepalived。Vip会漂移到node02上
[root@node01 keepalived]# service keepalived stop
Redirecting to /bin/systemctl stop keepalived.service
You have mail in /var/spool/mail/root
systemctl status keepalived -l
检测keepalived是否正常
[root@master 17]# cat ingress-demo.yaml
apiVersion: v1
kind: Service
metadata:
name: tomcat
namespace: default
spec:
selector:
app: tomcat
release: canary
ports:
- name: http
targetPort: 8080
port: 8080
- name: ajp
targetPort: 8009
port: 8009
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: tomcat
release: canary
template:
metadata:
labels:
app: tomcat
release: canary
spec:
containers:
- name: tomcat
image: tomcat:8.5.34-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
name: ajp
containerPort: 8009
# 更新资源清单yaml文件
[root@master 17]# kubectl apply -f ingress-demo.yaml
service/tomcat created
deployment.apps/tomcat-deploy created
[root@master 17]# k get pod|grep tomcat
tomcat-deploy-64d6489dd9-vmx79 1/1 Running 0 3d1h
tomcat-deploy-64d6489dd9-vngw9 1/1 Running 0 3d1h
[root@master 17]# k get svc|grep tomcat
tomcat ClusterIP 10.109.171.118 <none> 8080/TCP,8009/TCP 3d1h
[root@master 17]# k describe svc tomcat
Name: tomcat
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=tomcat,release=canary
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.109.171.118
IPs: 10.109.171.118
Port: http 8080/TCP
TargetPort: 8080/TCP
Endpoints: 10.244.140.87:8080,10.244.196.166:8080
Port: ajp 8009/TCP
TargetPort: 8009/TCP
Endpoints: 10.244.140.87:8009,10.244.196.166:8009
Session Affinity: None
Events: <none>
[root@master 17]# cat ingress-myapp.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
spec:
ingressClassName: nginx
rules:
- host: tomcat.lucky.com
http:
paths:
- backend:
service:
name: tomcat
port:
number: 8080
path: /
pathType: Prefix
[root@master 17]# kubectl apply -f ingress-myapp.yaml
ingress.networking.k8s.io/ingress-myapp created
如果出现以下报错:
解决办法:kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission
# 查看ingress-myapp的详细信息
[root@master 17]# kubectl describe ingress ingress-myapp
Name: ingress-myapp
Labels: <none>
Namespace: default
Address: 10.32.1.148,10.32.1.149
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
tomcat.lucky.com
/ tomcat:8080 (10.244.140.87:8080,10.244.196.166:8080)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 2m23s (x2 over 2m48s) nginx-ingress-controller Scheduled for sync
Normal Sync 2m23s (x2 over 2m48s) nginx-ingress-controller Scheduled for sync
修改电脑本地的host文件,增加如下一行,下面的ip是vip
10.32.1.155 tomcat.lucky.com
浏览器访问tomcat.lucky.com:30080,出现如下页面:
代理流程:tomcat.lucky.com:30080——>10.32.1.155:30080——>10.32.1.148/149:80——>svc:tomcat:8080——>tomcat-deploy
1、在控制节点上,创建证书
[root@master ~]# openssl genrsa -out tls.key 2048
Generating RSA private key, 2048 bit long modulus
....+++
...............................................................................+++
e is 65537 (0x10001)
[root@master ~]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=hejin.lucky.com
2、在控制节点上,生成secret
[root@master ~]# kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
secret/tomcat-ingress-secret created
3、查看secret
[root@master ~]# kubectl get secret
NAME TYPE DATA AGE
mysecret Opaque 2 22d
mysql-password Opaque 1 22d
tomcat-ingress-secret kubernetes.io/tls 2 24s
4、查看tomcat-ingress-secret详细信息
[root@master ~]# kubectl get secret
NAME TYPE DATA AGE
mysecret Opaque 2 22d
mysql-password Opaque 1 22d
tomcat-ingress-secret kubernetes.io/tls 2 24s
[root@master ~]# kubectl describe secret tomcat-ingress-secret
Name: tomcat-ingress-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.key: 1679 bytes
tls.crt: 1289 bytes
Ingress规则可以参考官方:
https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
[root@master 17]# cat ingress-tomcat-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tomcat-tls
namespace: default
spec:
ingressClassName: nginx
tls:
- hosts:
- hejin.lucky.com
secretName: tomcat-ingress-secret
rules:
- host: hejin.lucky.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat
port:
number: 8080
更新yaml文件
[root@master 17]# kubectl delete -f ingress-myapp.yaml
[root@master 17]# kubectl apply -f ingress-tomcat-tls.yaml
打开C:\Windows\System32\drivers\etc目录,找到hosts文件,如下:
......
10.32.1.155 tomcat.lucky.com
10.32.1.155 hejin.lucky.com
......
使用浏览器访问:http://hejin.lucky.com/
更新中。。。