K8s集群内有一个DNS服务:
kubectl get svc -n kube-system |grep dns
测试:
在tang3上安装bind-utils,目的是安装dig命令
yum install -y bind-utils
apt install dnsutils #ubuntu上
解析外网域名
dig @10.15.0.10 www.baidu.com
解析内部域名
dig @10.15.0.10 ngx-svc.default.svc.cluster.local
说明: ngx-svc为service name,service完整域名为service.namespace.svc.cluster.local
还可以解析Pod,Pod的域名有点特殊,格式为..pod.,例如10-18-206-93.default.pod.cluster.local
对应的Pod为coredns:
kubectl get po coredns -n kube-system
解释:
DNS配置
可以通过查看coredns的configmap来获取DNS的配置信息:
[root@tang3 k8s]# kubectl describe cm coredns -n kube-system
Name: coredns
Namespace: kube-system
Labels:
Annotations:
Data
====
Corefile:
----
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
说明:
有了Service之后,我们可以访问这个Service的IP(clusterIP)来请求对应的Pod,但是这只能是在集群内部访问。
要想让外部用户访问此资源,可以使用NodePort,即在node节点上暴漏一个端口出来,但是这个非常不灵活。为了解决此问题,K8s引入了一个新的API资源对象Ingress,它是一个七层的负载均衡器,类似于Nginx。
三个概念:Ingress、Ingress Controller、IngressClass
Ingress YAML示例:
vi tang.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tang ##ingress名字
spec:
ingressClassName: tang ##定义关联的IngressClass
rules: ##定义具体的规则
- host: tanglinux.com ##访问的目标域名
http:
paths:
- path: /
pathType: Exact
backend: ##定义后端的service对象
service:
name: ngx-svc
port:
number: 80
查看ingress
kubectl get ing
kubectl describe ing tang
IngressClassYAML示例:
vi tangc.yaml
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: tang
spec:
controller: nginx.org/ingress-controller ##定义要使用哪个controller
查看ingressClass
kubectl get ingressclass
安装ingress-controller(使用Nginx官方提供的 https://github.com/nginxinc/kubernetes-ingress)
首先做一下前置工作
curl -O 'https://gitee.com/aminglinux/linux_study/raw/master/k8s/ingress.tar.gz'
tar zxf ingress.tar.gz
cd ingress
./setup.sh ##说明,执行这个脚本会部署几个ingress相关资源,包括namespace、configmap、secrect等
vi ingress-controller.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ngx-ing
namespace: nginx-ingress
spec:
replicas: 1
selector:
matchLabels:
app: ngx-ing
template:
metadata:
labels:
app: ngx-ing
#annotations:
#prometheus.io/scrape: "true"
#prometheus.io/port: "9113"
#prometheus.io/scheme: http
spec:
serviceAccountName: nginx-ingress
containers:
- image: nginx/nginx-ingress:2.2-alpine
imagePullPolicy: IfNotPresent
name: ngx-ing
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: readiness-port
containerPort: 8081
- name: prometheus
containerPort: 9113
readinessProbe:
httpGet:
path: /nginx-ready
port: readiness-port
periodSeconds: 1
securityContext:
allowPrivilegeEscalation: true
runAsUser: 101 #nginx
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
args:
- -ingress-class=tangc
- -health-status
- -ready-status
- -nginx-status
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
应用YAML
kubectl apply -f ingress-controller.yaml
查看pod、deployment
kubectl get po -n nginx-ingress
kubectl get deploy -n nginx-ingress
将ingress对应的pod端口映射到master上临时测试
kubectl port-forward -n nginx-ingress ngx-ing-547d6575c7-fhdtt 8888:80 &
测试前,可以修改ng-deploy对应的两个pod里的/usr/share/nginx/html/index.html文件内容,用于区分两个pod
测试
curl -x127.0.0.1:8888 aminglinux.com
或者:
curl -H 'Host:aminglinux.com' http://127.0.0.1:8888
上面对ingress做端口映射,然后通过其中一个节点的IP来访问ingress只是一种临时方案。那么正常如何做呢?有三种常用的方案:
1)Deployment+LoadBalancer模式的Service
如果要把ingress部署在公有云,那用这种方式比较合适。用Deployment部署ingress-controller,创建一个type为LoadBalancer的service关联这组pod。
大部分公有云,都会为LoadBalancer的service自动创建一个负载均衡器,通常还绑定了公网地址。
只要把域名解析指向该地址,就实现了集群服务的对外暴露。
2)Deployment+NodePort模式的Service
同样用deployment模式部署ingress-controller,并创建对应的服务,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。
由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。
3)DaemonSet+HostNetwork+nodeSelector
用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通(如,上面的临时方案kubectl port-forward),直接使用宿主机的80/433端口就能访问服务。
这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。
缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。比较适合大并发的生产环境使用。
K8S调度器Kube-schduler的主要作用是将新创建的Pod调度到集群中的合适节点上运行。kube-scheduler的调度算法非常灵活,可以根据不同的需求进行自定义配置,比如资源限制、亲和性和反亲和性等。
1)kube-scheduler的工作原理如下:
调度器在执行绑定操作的时候是一个异步过程,调度器会先在缓存中创建一个和原来Pod一样的Assume Pod对象用模拟完成节点的绑定,如将Assume Pod的Nodename设置成绑定节点名称,同时通过异步执行绑定指令操作。在Pod和Node绑定之前,Scheduler需要确保Volume已经完成绑定操作,确认完所有绑定前准备工作,Scheduler会向Api Server 发送一个Bind 对象,对应节点的Kubelet将待绑定的Pod在节点运行起来。
3)为节点计算分值
节点分值计算是通过调度器算法实现的,而不是固定的。默认情况下,kube-scheduler采用的是DefaultPreemption算法,其计算分值的方式包括以下几个方面:
这些因素的相对权重可以通过kube-scheduler的命令行参数或者调度器配置文件进行调整。需要注意的是,kube-scheduler的算法是可扩展的,可以根据需要编写自定义的调度算法来计算节点分值。
4)调度策略
NodeSelector会将Pod根据定义的标签选定到匹配的Node上去。
示例:
cat > nodeselector.yaml <
应用YAML
kubectl apply -f nodeselector.yaml
查看Pod状态
kubectl describe po nginx-ssd
给Node打标签
kubectl label node k8s02 disktype=ssd
查看Node label
kubectl get node --show-labels
查看Pod信息
kubectl describe po nginx-ssd |grep -i node
也是针对Node,目的是把Pod部署到符合要求的Node上。
关键词:
① requiredDuringSchedulingIgnoredDuringExecution:表示强匹配,必须要满足
② preferredDuringSchedulingIgnoredDuringExecution:表示弱匹配,尽可能满足,但不保证
示例:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: ##必须满足下面匹配规则
nodeSelectorTerms:
- matchExpressions:
- key: env
operator: In ##逻辑运算符支持:In,NotIn,Exists,DoesNotExist,Gt,Lt
values:
- test
- dev
preferredDuringSchedulingIgnoredDuringExecution: ##尽可能满足,但不保证
- weight: 1
preference:
matchExpressions:
- key: project
operator: In
values:
- aminglinux
containers:
- name: with-node-affinity
image: redis:6.0.6
说明:
匹配逻辑:
① 同时指定Node Selector和Node Affinity,两者必须同时满足;
② Node Affinity中指定多组nodeSelectorTerms,只需要一组满足就可以;
③ 当在nodeSelectorTerms中包含多组matchExpressions,必须全部满足才可以;
演示示例:
编辑pod的yaml
cat > nodeAffinity.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: node-affinity
spec:
containers:
- name: my-container
image: nginx:1.23.2
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: special-node
operator: Exists
EOF
给其中一个节点定义标签
kubectl label nodes aminglinux03 special-node=true
生效Pod yaml
kubectl apply -f nodeAffinity.yaml
检查Pod所在node
kubectl get po -o wide