K8S快速入门
查看pod日志
]# kubectl exec -it $(kubectl get pod -n zhiyi-system-test|grep "ai-live-dev"|awk '{print $1}') -n zhiyi-system-test -- tail -f /home/ailive-logs/gray/ailive_dao.2019-05-16.log
]# kubectl cluster-info //查看集群信息
Kubernetes master is running at https://192.168.64.110:6443
KubeDNS is running at https://192.168.64.110:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
master ~]# kubectl run nginx-deploy --image=nginx --port=80 --replicas=1 //创建一个副本数为1且名称为nginx-deploy 的对外暴露的端口(仅集群内部)为80的nginx镜像pod。
master ~]# kubectl get deployment //查看该控制器下启动的pod
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 1/1 1 1 6m59s
master ~]# kubectl get pods -o wide //查看默认名称空间下Pod运行的详细信息
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-98c9d6c66-mbmrm 1/1 Running 0 9m45s 10.244.1.2 k8s-node1 <none> <none>
测试控制器维持副本数量
master ~]# kubectl delete nginx-deploy-98c9d6c66-mbmrm
master ~]# kubectl get pods -o wide //可以看到pod已被调度器启动并调度到node2上且IP发生了改变
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-98c9d6c66-gbm56 1/1 Running 0 7m12s 10.244.2.2 k8s-node2 <none> <none>
service:由上面测试可以看到,当pod被重启IP地址会发生改变,应使用固定地址来访问pod。
//控制器下所有的pod都托管到名称为nginx的service且pod端口80映射到service 80端口上
master ~]# kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP
master ~]# kubectl get svc //查看默认名称空间servie
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26h
nginx ClusterIP 10.99.80.100 <none> 80/TCP 21s
master ~]# kubectl get pods -n kube-system //查看当前运行的DNS服务pod资源
NAME READY STATUS RESTARTS AGE
coredns-6955765f44-sfptk 1/1 Running 5 3d16h
coredns-6955765f44-xf9jt 1/1 Running 4 3d16h
master ~]# kubectl get svc -n kube-system //查看指定名称空间的service,DNS服务也有属于自己的service托管
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 26h //可以看到DNS的service地址为10.96.0.10
master ~]# kubectl run clientq --image=busybox:latest --replicas=1 -it --restart=Never //运行一个不重启的pod
/ # cat /etc/resolv.conf
nameserver 10.96.0.10 //可以看到pod的DNS已自动配置为kube-dns 的10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
master ~]# dig -t A nginx.default.svc.cluster.local @10.96.0.10 //解析service名称为nginx的地址
验证service功能,标签选择器,只需要访问service地址加端口即可
wget -O - -q http://nginx:80/ //访问service名称加端口即可访问到后端pod资源
master ~]# kubectl delete nginx-deploy-98c9d6c66-gbm56 //模拟故障
-master ~]# kubectl get pods //可以看到调取器已重新启动pod
NAME READY STATUS RESTARTS AGE
clientq 1/1 Running 0 46m
nginx-deploy-98c9d6c66-n25dd 1/1 Running 0 85s
wget -O - -q http://nginx:80/ //再次通过service地址访问
master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d16h
nginx ClusterIP 10.99.8.143 <none> 80/TCP 2d12h //名称为nginx的service地址为10.99.8.143:80
master ~]# kubectl describe svc nginx //查看service名称为nginx的详细信息
Name: nginx
Namespace: default
Labels: run=nginx-deploy
Annotations: <none>
Selector: run=nginx-deploy //service以pod标签选择器来识别管理pod
Type: ClusterIP //类型
IP: 10.99.80.100
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.6:80 //后端pod资源,pod被重启或被删除重建,改地址会改变
Session Affinity: None
Events: <none>
master ~]# kubectl get pods --show-labels //查看Pod标签信息
NAME READY STATUS RESTARTS AGE LABELS
nginx-deploy-98c9d6c66-n25dd 1/1 Running 0 12m pod-template-hash=98c9d6c66,run=nginx-deploy //可以看到标签
总结:用户可以修改service地址或者service被重建后地址发生改变,修改后的地址可以自动反映到DNS中,无须修改DNS解析
-master ~]# kubectl delete svc nginx //模拟故障,svc重建
master ~]# kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP //svc重建
-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.99.8.143 <none> 80/TCP 14s //可以看到重建后的service地址发生了改变
进入另外一个容器测试
]# kubectl exec -it busybox -n linux40 /bin/sh
/ # wget -O - -q http://nginx:80/ //使用service名称依然可以访问
控制器也是通过标签选择器来关联到Pod资源上
master ~]# kubectl describe deployment nginx-deploy
Labels: run=nginx-deploy //通过标签选择器来维持副本的期望值
总结:我们不需要关注pod自身,只关注servie,service会生成一个iptatles或ipvs规则将访问service的地址和端口的请求通过标签选择器来调度到关联的各pod资源上。
Pod的扩展与缩进
master ~]# kubectl run nginx --image=nginx --replicas=2 //创建默认控制器为deploy的名称为nginx且副本数为2的pod。
master ~]# kubectl scale deploy nginx --replicas=5 //扩展副本数为5
master ~]# kubectl scale deploy nginx --replicas=3 //能扩展也能缩进,缩减副本数为3
pod的手动滚动更新
master ~]# kubectl set image deployment nginx nginx=nginx:v2
pod镜像版本回滚
master ~]# kubectl rollout undo deployment nginx
deployment.apps/nginx rolled back
修改网络类型为NodePort
master ~]# kubectl edit svc nginx
ports:
- nodePort: 31520
port: 80
protocol: TCP
targetPort: 80
selector:
run: nginx-deploy
sessionAffinity: None
type: NodePort //修改类型为节点网络
master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.99.8.143 <none> 80:31520/TCP 2d16h //可以看到端口已经随机映射到了节点的31520
此时只需要在节点前面做代理服务器即可访问到k8s集群内资源。
Service网络
Why:pod重启或者重建ip会发生改变,pod之间访问会有问题;
What:解耦了服务和应用。(集群内部服务之间调用填写service域名/IP即可;
How:声明一个service对象
一般常用的有两种:
k8s集群内部的service:selector指定pod,自动创建Endpoints
k8s集群外的service:手动创建Endpoints,指定外部服务的ip、端口和协议。
k8s 三种网络
node network
pod network
cluster network,也称作virtual IP虚拟网络—service
kube-proxy监听k8s-apiserver,一旦service资源发生变化,kube-proxy就会生成对应的负载调度的调整,这样就保证service的最新状态。
service 三种工作模式
userspace
iptabels
ipvs 最新版本
service类型
ExternalName, Cluster IP, Node Port, Load Balancer
外部名称, 集群IP, 节点端口 负载均衡器
资源记录
SVC_NAME.NS_NAME.DOMAIN.LTD.
DOMAIN.LTD 集群域名后缀默认为svc.cluster.local.
使用清单文件创建service资源
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: default
spec:
selector:
app: nginx
role: logstor
clusterIP: 10.97.97.97 //默认为clusterIP,不指定会自动分配
type: ClusterIP
ports:
- port: 80 //service端口
targetPort: 80 //容器端口
master yaml]# kubectl get svc -o wide //查看创建的SVC
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28d <none>
nginx ClusterIP 10.97.97.97 <none> 80/TCP 13m app=nginx,role=logstor
模拟匹配pod作为后端资源
master yaml]# kubectl apply -f test.yaml
master yaml]# kubectl label pods nginx app=nginx
master yaml]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","...
Selector: app=nginx,role=logstor
Type: ClusterIP
IP: 10.97.97.97
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: <none> //可以看到当svc标签与pod标签只匹配一个时,service未关联到pod资源
Session Affinity: None
Events: <none>
master yaml]# kubectl label pods nginx role=logstor //手动匹配所有标签
master yaml]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28d <none>
nginx ClusterIP 10.97.97.97 <none> 80/TCP 13m app=nginx,role=logstor
master yaml]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx 1/1 Running 0 10m app=nginx,role=logstor //此时标签已全匹配
master yaml]# kubectl describe svc nginx //再次查看发现已匹配后端资源
Name: nginx
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","...
Selector: app=nginx,role=logstor //svc标签
Type: ClusterIP
IP: 10.97.97.97
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.84:80 //标签一致,匹配到的后端pod资源
Session Affinity: None
Events: <none>
结论:servie根据SELECTOR标签选择器关联pod资源
查看svc关联的pod
]# kubectl get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 236d
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 236d
kube-system metrics-server ClusterIP 10.105.89.199 <none> 443/TCP 15d
kubernetes-dashboard dashboard-metrics-scraper ClusterIP 10.109.95.129 <none> 8000/TCP 15d
kubernetes-dashboard kubernetes-dashboard NodePort 10.98.147.122 <none> 443:30002/TCP 15d
linux40 ng-deploy-80 NodePort 10.97.239.161 <none> 81:30019/TCP 20d
]# kubectl get pods -n linux40 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-55fb8c9d77-9qlkp 1/1 Running 9 20d 10.244.1.98 node1 <none> <none>
nginx-deployment-55fb8c9d77-sj8bs 1/1 Running 3 15d 10.244.2.29 node2 <none> <none>
# 查看endpoint,svc关联的pod资源
]# kubectl get ep -n linux40
NAME ENDPOINTS AGE
ng-deploy-80 10.244.1.98:80,10.244.2.29:80 20d
资源记录
SVC_NAME.NS_NAME.DOMAIN.LTD.
集群默认后缀DOMAIN.LTD.:svc.cluster.local.
所以上面创建的服务记录为:nginx.default.svc.cluster.local
使用资源清单创建类型为nodeport的svc
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp
release: canary
clusterIP: 10.99.99.99
type: NodePort
ports:
- port: 80 //service端口
targetPort: 80 //pod端口
nodePort: 30080 //映射节点端口,后续可以直接访问该节点端口,DNAT到service端口,再到pod端口
master yaml]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28d
myapp NodePort 10.99.99.99 <none> 80:30080/TCP 38m //网络类型为节点网络
nginx ClusterIP 10.97.97.97 <none> 80/TCP 76m
访问servic
]# curl http://172.18.0.68:30080 //在集群外部机器访问该集群内IP加端口,servie后端须关联pod资源才可以被访问
注:此时可以在节点前面做代理服务器来访问service地址
Load Balancer(负载均衡器) 访问示意图
ExternalName(外部名称 )模式
把来自于同一个客户端的请求始终固定访问同一个pod资源
master yaml]# kubectl patch svc myapp -p ‘{“spec”:{“sessionAffinity”:“ClientIP”}}’
master yaml]# kubectl describe svc myapp //查看service详情
Name: myapp
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"clusterIP":"10.99.99.99","...
Selector: app=myapp,release=canary
Type: NodePort
IP: 10.99.99.99
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30080/TCP
Endpoints: 10.244.2.84:80 //后端pod资源
Session Affinity: ClientIP //此参数说明相同客户端访问相同pod资源;若为“none”则为负载均衡调度。
External Traffic Policy: Cluster
Events: <none>
无头service:将service名称解析到后端pod ip地址来实现访问
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
namespace: default
spec:
selector:
app: myapp
release: canary
clusterIP: "None" //指定service IP地址为空
ports:
- port: 80
targetPort: 80
master yaml]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 29d
master yaml]# dig -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
......
;; ANSWER SECTION:
myapp-svc.default.svc.cluster.local. 30 IN A 10.244.1.97 //可以看到解析SVC资源记录地址为pod地址,当关联到时
myapp-svc.default.svc.cluster.local. 30 IN A 10.244.2.101
myapp-svc.default.svc.cluster.local. 30 IN A 10.244.2.100
myapp-svc.default.svc.cluster.local. 30 IN A 10.244.1.96
myapp-svc.default.svc.cluster.local. 30 IN A 10.244.2.104
......
master yaml]# kubectl get pods -o wide --show-labels //查看pod标签,与无头service 标签完全匹配
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp-deploy-f476f4fcf-jltjs 1/1 Running 3 6d1h 10.244.1.85 k8s-node1 <none> <none> app=myapp,pod-template-hash=f476f4fcf,releas=canary
myapp-deploy-f476f4fcf-nbqwv 1/1 Running 3 6d1h 10.244.2.86 k8s-node2 <none> <none> app=myapp,pod-template-hash=f476f4fcf,releas=canary
nginx 1/1 Running 1 7h26m 10.244.2.85 k8s-node2 <none> <none> app=myapp,release=canary
master yaml]# kubectl get svc -o wide //查看service标签,与pod 标签完全匹配时,可解析service name到pod地址
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 29d <none>
myapp NodePort 10.99.99.99 <none> 80:30080/TCP 7h49m app=myapp,release=canary
myapp-svc ClusterIP None <none> 80/TCP 3m23s app=myapp,release=canary //SVC地址为空
nginx ClusterIP 10.97.97.97 <none> 80/TCP 8h app=nginx,role=logstor
2.如何让集群内资源访问到互联网资源
待定
k8s ingress以及ingress Cintroller
参考文档
https://segmentfault.com/a/1190000019908991
service的作用体现在两个方面,对集群内部,它不断跟踪pod的变化,更新endpoint中对应pod的对象,提供了ip不断变化的pod的服务发现机制,对集群外部,他类似负载均衡器,可以在集群内外部对pod进行访问。但是,单独用service暴露服务的方式,在实际生产环境中不太合适:
ClusterIP的方式只能在集群内部访问。
NodePort方式的话,测试环境使用还行,当有几十上百的服务在集群中运行时,NodePort的端口管理是灾难。
LoadBalance方式受限于云平台,且通常在云平台部署ELB还需要额外的费用。
所幸k8s还提供了一种集群维度暴露服务的方式,也就是ingress。ingress可以简单理解为service的service,他通过独立的ingress对象来制定请求转发的规则,把请求路由到一个或多个service中。这样就把服务与请求规则解耦了,可以从业务维度统一考虑业务的暴露,而不用为每个service单独考虑。
举个例子,现在集群有api、文件存储、前端3个service,可以通过一个ingress对象来实现图中的请求转发:
ingress的部署
ingress的部署,需要考虑两个方面:
ingress-controller是作为pod来运行的,以什么方式部署比较好
ingress解决了把如何请求路由到集群内部,那它自己怎么暴露给外部比较好
下面列举一些目前常见的部署和暴露方式,具体使用哪种方式还是得根据实际需求来考虑决定。
Deployment+LoadBalancer模式的Service
如果要把ingress部署在公有云,那用这种方式比较合适。用Deployment部署ingress-controller,创建一个type为LoadBalancer的service关联这组pod。大部分公有云,都会为LoadBalancer的service自动创建一个负载均衡器,通常还绑定了公网地址。只要把域名解析指向该地址,就实现了集群服务的对外暴露。
Deployment+NodePort模式的Service
同样用deployment模式部署ingress-controller,并创建对应的服务,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。
DaemonSet+HostNetwork+nodeSelector
用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。比较适合大并发的生产环境使用。
ingress与ingress-controller
要理解ingress,需要区分两个概念,ingress和ingress-controller:
ingress对象:
指的是k8s中的一个api对象,一般用yaml配置。作用是定义请求如何转发到service的规则,可以理解为配置模板。
ingress-controller:
具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发。
简单来说,ingress-controller才是负责具体转发的组件,通过各种方式将它暴露在集群入口,外部对集群的请求流量会先到ingress-controller,而ingress对象是用来告诉ingress-controller该如何转发请求,比如哪些域名哪些path要转发到哪些服务等等。
ingress Cintroller
重要:可以使用DaemonSet结合nodeselector来部署ingress-controller到特定的node(打上污点)上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。
一组独立运行的一组pod资源,可以理解为应用程序,可以实现七层调度负载均衡。
若集群中存在N多个Node节点,可以通过DaemonSet 控制器运行一个为集群接入七层调度的负载均衡pod,用于转发至后端pod。
此pod监听nNodeIP+port,可以在前面搭建四层代理转发至这几台node节点,在通过这几个pod实现七层负载均衡至后端pod。
如何对后端pod进行分组
还必须要借助service 的标签选择器来将后端代理的pod来分组,仅仅用来对后端pod资源功能分组,upstream 里面写入service地址,ingress Cintroller pod还是直接访问后端pod地址。
ingress 与 ingress Cintroller 并不是一回事
ingress资源
ingress 定义了期望 ingress Cintroller 如何建立一个前端,可能是一个虚机,也有可能是url映射。
如何实现对后端pod进行实时监控
同时定义了upstream service,可以通过service 来得到有几个主机并识别出后端pod的ip地址,并反馈注入到配置文件中。
可以保存为配置文件,一旦ingress发现serrvice 关联的pod资源发生改变(重建、修改等),会及时反应到ingress中并及时注入到 ingress Cintroller pod的配置文件中,pod中的主容器进程重新加载配置文件(因为upstream中配置的 service并不会实现负载均衡功能,仅仅用来实现分组分类,实际上还是ingress Cintroller pod还是直接访问后端pod地址)。
创建名称空间
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
**定义一个ingress**
步骤
- 定义service 模式为Deployment+NodePort模式的Service
同样用deployment模式部署ingress-controller,并创建对应的服务,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。
- 定义 ingress。host定义了访问域名,这个域名必须可以解析
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ORbwPSfn-1616417965144)(http![在这里插入图片描述](https://img-blog.csdnimg.cn/20210322205922954.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTQ4MzIwNw==,size_16,color_FFFFFF,t_70)
DaemonSet+HostNetwork+nodeSelector
用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。比较适合大并发的生产环境使用。
自制证书