k8s基础篇-服务发布入门
Label & Selector
概念:
Label:对k8s中各种资源进行分类、分组,添加一个具有特别属性的一个标签。
Selector:通过一个过滤的语法进行查找到对应标签的资源。
定义Label
现在有三个节点,一个master,两个node。举例:给k8s-node01添加一个address=beijing的标签
[root@k8s-master ~]# kubectl label node k8s-node01 address=beijing node/k8s-node01 labeled
然后,可以通过Selector对其筛选
[root@k8s-master ~]# kubectl get nodes -l address=beijing NAME STATUS ROLES AGE VERSION k8s-node01 Ready <none> 2d23h v1.22.2
最后,在Deployment或其他控制器中指定将Pod部署到该节点:
containers: ...... dnsPolicy: ClusterFirst nodeSelector: address: beijing restartPolicy: Always
删除k8s-node01的address标签
kubectl label node k8s-node01 address- [root@k8s-master ~]# kubectl get nodes -l address=beijing No resources found
给某个namespace中的pod打标签,这里我定义的namespace是my-first-ns
先查看一下该namespace下的pods
[root@k8s-master ~]# kubectl get pods -n my-first-ns NAME READY STATUS RESTARTS AGE ngx-dep3-6d4cf56db6-bnc49 1/1 Running 1 (43m ago) 23h ngx-dep3-6d4cf56db6-bv2ml 1/1 Running 1 (43m ago) 23h ngx-dep3-6d4cf56db6-nn55b 1/1 Running 1 (43m ago) 23h
给 ngx-dep3-6d4cf56db6-bnc49 这个pod打一个name=test的标签
[root@k8s-master ~]# kubectl label pods ngx-dep3-6d4cf56db6-bnc49 name=test -n my-first-ns pod/ngx-dep3-6d4cf56db6-bnc49 labeled
过滤
[root@k8s-master ~]# kubectl get pods -l name=test -n my-first-ns NAME READY STATUS RESTARTS AGE ngx-dep3-6d4cf56db6-bnc49 1/1 Running 1 (44m ago) 23h
修改标签,和添加一样,只是需要加一个--overwrite参数,现在我把刚才添加的name=test 这个标签改成name=test111
[root@k8s-master ~]# kubectl label pods ngx-dep3-6d4cf56db6-bnc49 name=test111 -n my-first-ns --overwrite pod/ngx-dep3-6d4cf56db6-bnc49 labeled
再次过滤
[root@k8s-master ~]# kubectl get pods -l name=test111 -n my-first-ns NAME READY STATUS RESTARTS AGE ngx-dep3-6d4cf56db6-bnc49 1/1 Running 1 (50m ago) 23h
--show-labels用法
[root@k8s-master ~]# kubectl get pods -n my-first-ns --show-labels NAME READY STATUS RESTARTS AGE LABELS ngx-dep3-6d4cf56db6-bnc49 1/1 Running 1 (51m ago) 23h app=nginx,name=test111,pod-template-hash=6d4cf56db6 ngx-dep3-6d4cf56db6-bv2ml 1/1 Running 1 (51m ago) 23h app=nginx,pod-template-hash=6d4cf56db6 ngx-dep3-6d4cf56db6-nn55b 1/1 Running 1 (51m ago) 23h app=nginx,pod-template-hash=6d4cf56db6
多条件多虑,例如,我再给ngx-dep3-6d4cf56db6-bv2ml 这个pod加一个name=test222的标签,然后我想把name=test111 和 name=test222两个pod都过滤出来,应该怎么做呢?话不多说,直接点
[root@k8s-master ~]# kubectl get pods -n my-first-ns -l 'name in (test111,test222)' NAME READY STATUS RESTARTS AGE ngx-dep3-6d4cf56db6-bnc49 1/1 Running 1 (54m ago) 23h ngx-dep3-6d4cf56db6-bv2ml 1/1 Running 1 (54m ago) 23h
取反,如果我想过滤name不等于test111,怎么做呢
[root@k8s-master ~]# kubectl get pods -n my-first-ns -l name!=test111 NAME READY STATUS RESTARTS AGE ngx-dep3-6d4cf56db6-bv2ml 1/1 Running 1 (60m ago) 23h ngx-dep3-6d4cf56db6-nn55b 1/1 Running 1 (60m ago) 23h
如果想获取name标签既不为test111,又不为test222的pod,只需要将两个条件用逗号,连接即可
kubectl get pods -n my-first-ns -l name!=test111,name!=test222 NAME READY STATUS RESTARTS AGE ngx-dep3-6d4cf56db6-nn55b 1/1 Running 1 (61m ago) 23h
在k8s上是如何发布服务的?
什么是service
Service可以简单的理解为逻辑上的一组Pod(通过selector选择)。一种可以访问Pod的策略,而且其他Pod可以通过这个Service访问到这个Service代理的Pod。相对于Pod而言,它会有一个固定的名称,一旦创建就固定不变。
pod内部是可以通过service名字去访问的。例如当前namespace下有个service,名字叫nginx-svc,提供的端口是888,访问方式如下
这里使用busybox镜像去测试,先启动busybox容器(busybox容器常用的命令比较全)
kubectl run busybox --rm=true --image=busybox --restart=Never -it 访问 wget http://nginx-svc:888 如果是跨namespace的访问,需要加.namespace名字 例如,访问default名称空间下的nginx-svc,应该这样写 wget http://nginx-svc:8888.default
定义一个service
这里定义一个名字为nginx-svc的service
[root@k8s-master ~]# cat nginx-svc.yml apiVersion: v1 kind: Service metadata: name: nginx-svc namespace: my-first-ns spec: selector: app: nginx # 通过这个selector过滤当前namespace下的pod,也就是要代理的pod type: ClusterIP sessionAffinity: None sessionAffinityConfig: clientIP: timeoutSeconds: 10800 ports: - name: nginx # serviced的端口名称,如果有多个端口,不能重复 protocol: TCP # 协议 port: 888 # service自己的端口 targetPort: 80 # 后端pod的端口 - name: http # 再定义一个端口 protocol: TCP port: 889 targetPort: 80
创建service
kubectl apply -f nginx-svc.yaml
查看service下代理的pod
[root@k8s-master ~]# kubectl get endpoints nginx-svc NAME ENDPOINTS AGE nginx-svc 10.244.1.4:80,10.244.2.6:80,10.244.2.7:80 + 3 more... 17h
使用service代理k8s外部服务
有些场景下,需要通过某个固定的名称而非IP去访问外部的应用,例如中间件等。
或者希望service指向另一个namespace或者其它集群中的服务
或者某个项目正在迁移至k8s集群,但是部分应用仍然在集群外部
此时可以使用service代理至k8s集群外部的服务
现在,首先定义一个代理外部服务的service,因为代理的是外部的服务,所以不需要匹配内部的pod,其它的和普通的service是一样的
[root@k8s-master ~]# cat nginx-svc-external.yml apiVersion: v1 kind: Service metadata: name: nginx-svc-external namespace: my-first-ns spec: #selector: # app: nginx # 因为是代理外部服务,所以不需要匹配pod type: ClusterIP sessionAffinity: None sessionAffinityConfig: clientIP: timeoutSeconds: 10800 ports: - name: nginx # serviced的端口名称,如果有多个端口,不能重复 protocol: TCP # 协议 port: 888 # service自己的端口 targetPort: 80 # 后端pod的端口 - name: http # 再定义一个端口 protocol: TCP port: 889 targetPort: 80
不同的是,之前创建的service会有一个同名的endpoint,但是这个是是一个没有selector的service,就不会自动创建endpoin。那怎么去连接外部呢?只需要自己手动创建一个endpoint即可(和service同名)
现在就来手动创建一个endpoint
首先,导出一个现有的endpoint并生成一个yaml文件
kubectl get endpoints nginx-svc -o yaml > nginx-ep-external.yaml
修改一下nginx-ep-external.yaml,最后如下:
[root@k8s-master ~]# cat nginx-ep-external.yaml apiVersion: v1 kind: Endpoints metadata: name: nginx-svc-external namespace: my-first-ns labels: app: nginx-svc-external subsets: - addresses: - ip: 182.61.200.7 # 这里是代理的外部的IP(www.baidu.com的IP) ports: - name: http port: 80 protocol: TCP
创建endpoint
kubectl apply -f nginx-ep-external.yaml
查看是否创建成功
[root@k8s-master ~]# kubectl get endpoints nginx-svc-external NAME ENDPOINTS AGE nginx-svc-external 182.61.200.7:80 2m14s
可以看到,一个和service同名的endpoint就已经创建好了
测试
使用service的IP测试
修改service
kubectl edit svc nginx-svc-external # 例如修改 nginx-svc-external 这个service
修改完之后,执行
kubectl replace -f nginx-svc-external.yaml
使用service反代外部域名
创建一个反代外部域名的service
[root@k8s-master ~]# cat nginx-svc-externalname.yaml apiVersion: v1 kind: Service metadata: name: nginx-svc-externalname labels: app: nginx-svc-externalname namespace: my-first-ns spec: type: ExternalName externalName: www.baidu.com 然后执行kubectl apply -f nginx-svc-externalname.yaml
查看创建的service
这种service并没有IP,所以只能通过service名字去访问。但是有个问题,直接访问会报403,因为跨域了,在使用时要注意
service常用类型
前面在创建service的时候,我们发现type有的是ClusterIP,有的是ExternalName,那么它们都有什么区别?常用service类型有哪些呢?
ClusterIP: 在集群内部使用,也是默认的类型。可以在pod内部和node上访问,外部不能访问
ExternalName:代理外部域名。通过service名字访问,解析service名称即可解析到对应的ExternalName上。用的不多
NodePort:在所有安装了kube-proxy的节点上打开一个端口,此端口可以代理至后端的Pod,然后集群外部可以通过节点的IP地址和NodePort的端口号访问到集群的Pod的服务。NodePort 端口范围默认是30000~32767
创建一个nodePort类型的service
[root@k8s-master ~]# cat nginx-svc-nodeport.yaml apiVersion: v1 kind: Service metadata: name: nginx-svc-nodeport namespace: my-first-ns spec: selector: app: nginx # 通过这个selector过滤当前namespace下的pod,也就是要代理的pod type: NodePort sessionAffinity: None sessionAffinityConfig: clientIP: timeoutSeconds: 10800 ports: - name: nginx # serviced的端口名称,如果有多个端口,不能重复 protocol: TCP # 协议 port: 888 # service自己的端口 targetPort: 80 # 后端pod的端口 nodePort: 32000 # node的端口,如果不指定,随机生成(32000~32767范围内)
创建后,就可以通过http://nodeIp:32000访问了
LoadBalance:使用云服务商的负载均衡器公开服务
什么是ingress
通俗来讲,ingress和之前提到的Service、Deployment一样,也是一个k8s的一种资源类型,ingress用于实现用域名的方式访问k8s内部应用。
ingress 的请求流程大概如下:
使用helm安装ingress
ingress简单使用
ingress多域名使用
k8s 1.22 + 版本的ingress配置
附加知识点
如何进入一个pod呢?
kubectl exec -it ngx-dep3-6d4cf56db6-bnc49 -- sh
ngx-dep3-6d4cf56db6-bnc49 是pod的ID