Kubernetes常用命令及yml文件、集群网络
Kubernetes组件介绍及环境搭建一、kubernetes常用命令说明:因为k8s的命令都是通过kubectl组件接收的,这个组件只在master节点有,所以k8s的命令都是在master节点中执行kubectl get nodes#查看当前集群中有哪些机器kubectl label node node-hostname label-key=label-value#为某个节点设置label标签
一、kubernetes常用命令
说明:因为k8s的命令都是通过kubectl组件接收的,这个组件只在master节点有,所以k8s的命令都是在master节点中执行
kubectl get nodes #查看当前集群中有哪些机器
kubectl label node node-hostname label-key=label-value #为某个节点设置label标签
kubectl get namespace/ns #查看当前集群中的namespace,其中kube-system是k8s基础组件的namespace,default是默认使用的namespace即kubectl apply的时候不指定namespace就使用default
kubectl create namespace namespace名称 #创建namespace 也可以通过yaml文件(将kind定义为Namespace)kubectl apply -f 创建namespace
kubectl get pods/pod #查看pod列表,默认查看default命名空间中的pod,系统自带的pod无法查看,如果需要查看要加上 -n kube-system 指定查看系统命名空间的pod
可选参数:
-n:指定某个命名空间
-o wide:查看详细信息
-w:实时输出pod状态信息,比如该pod在启动中的状态,变为Runing状态,输出显示也会跟着变,类似于Linux的top命令显示结果实时变化
--show-labels:查看pod的label标签
--all-namespaces:查看所有命名空间下的pod
-w参数会实时显示pod状态信息,需要ctrl+c终止
kubectl describe pods/pod pod名称 #查看某个pod的详情,也可以-n指定命名空间,否则default命名空间可能会找不到该名称的pod
kubectl logs pod名称 #查看某个pod的日志,也可以-n指定命名空间,否则default命名空间可能会找不到该名称的pod
kubectl scale rs pod名称 --replicas=数量 #扩缩容某个pod的副本数量,数量大于集群中现有该pod的副本数量即扩容,小于即缩容
kubectl scale deployment deployment名称 --replicas=deployment数量 #扩缩容某个deployment的副本数量,数量大于集群中现有该deployment的副本数量即扩容,小于即缩容;扩缩容deployment其中的replicaset及pod副本数量也会跟着变(数量是变为和deployment数量一样而不是按照yml文件中定义的replicas数量做倍数变化)
kubectl apply -f yaml文件 #执行某个yaml文件,比如yaml文件中定义了创建pod那么执行后就会创建pod
有一个注意点就是,apply yaml文件之后,可以看到实际上除了创建应有的container之外,还同时为每个container创建了一个与之对应pause容器,这个容器的作用就是实现网络的互通,比如在k8s集群中的pod,通过集群中任何一台机器的ip加对应端口都可以访问到服务,就是因为这个pause容器的存在。
kubectl delete -f yaml文件/yaml文件目录 #删除某个yaml文件中定义的内容(不会删除yaml文件本身,推荐使用该方式删除pod),比如定义了pod那么这些pod就会被删除,如果是yaml文件目录的话,那么会将这个目录下面的所有yaml文件创建的资源都删除掉
或
kubectl scale rs pod名称 --replicas=0 #让某个pod的副本数量为0,从效果上看类似于删除了某个pod
kubectl delete pod pod名称 #删除某个pod副本,比如该pod有3个副本的话那么只会删除指定名称的这个pod副本,剩余的两个还在
kubectl get deployment #获取Deployment信息
kubectl get replicaset/rs #获取ReplicaSet信息
kubectl get replicationcontroller/rc #获取ReplicationController信息
kubectl get all #查询所有资源,包含Deployment、ReplicaSet、pod、ReplicationController等信息
kubectl get service/svc #查询集群中的service
kubectl get ingress #查询ingress
上面几条命令和kubectl get pods/pod一样,都有-n -o wide --show-labels --all-namespaces等可选参数
kubectl describe deployment deployment名称 #获取某个Deployment的详细信息
kubectl describe replicaset/rs rs名称 #获取某个ReplicaSet的详细信息
kubectl describe replicationcontroller/rc rc名称 #获取某个ReplicationController的详细信息
kubectl describe all #查询所有资源详情,包含Deployment、ReplicaSet、pod、ReplicationController等信息
kubectl describe service/svc svc名称 #查询某个service的详细信息
kubectl describe ingress ingress名称 #查询某个ingress详细信息
describe查询详情也可以指定-n命名空间,否则default命名空间可能会找不到该名称的资源
使用Deployment的情况下可以在运行状态中修改容器版本,而不需要停止之后再修改yml文件中版本再启动,即deployment的滚动更新功能,ReplicaSet和ReplicationController不支持滚动更新功能:
kubectl set image deployment yaml文件中deployment名称 yaml文件中container名称=image名称:版本 #在运行状态中修改容器版本,如:kubectl set image deployment nginx-deployment nginx=nginx:1.9.1
kubectl expose deployment deployment名称 --type=service类型 #为某个deployment创建service,如果该deployment已创建过service,再次执行会失败,其中--type是可选参数用于指定service的类型,比如ClusterIP、NodePort,其中ClusterIP只能集群内访问,NodePort可以集群内外访问,不写--type默认ClusterIP类型
kubectl delete service/svc deployment名称 #删除某个deployment的service
二、yaml文件
官方yaml文件指令介绍-v1.19版本
yaml文件中自定义值只能是以下字符的组合,比如name的值、labels中的key-value的值:
a-z、A-Z、0-9、-
yaml文件识别大小写,比如pod中的labels的值和selector里面的labels中的值大小写不一致会匹配不上
不能用下划线即_只能用-,比如一个name的值定义为两个单词不能使用_分割两个单词,只能使用-分割即name定义为test_nginx在kubectl apply -f的时候会报错,定义为test-nginx则不会报错
---:如果需要在同一个yml文件中定义多个资源的话,需要使用三个短横线分割
所有使用yaml文件定义的资源都是通过 kubectl apply -f yaml文件 创建对应的资源,kubectl delete -f yaml文件 删除对应的资源
1、常用指令介绍
apiVersion:定义版本号
kind:定义本yaml文件的资源是什么,如:ReplicaSet、Pod、ReplicationController、Deployment、Namespace、Service、Ingress(定义为Ingress实际上就是定义路由规则信息,因为生产环境一般使用Ingress的方式让集群外部可以访问k8s服务)等等,其中Deployment是最常用的,资源定义为Deployment之后,kubectl apply会生成Deployment、ReplicaSet、Pod等资源
metadata:对于该资源的定义,比如kind下面的metadata就是对kind的定义,template(即pod)下面的metadata就是对template(即pod)的定义
name:定义名称,位于哪个指令下面就是对哪个资源的名称定义
namespace:指定资源使用的命名空间,只能在一级metadata(即和apiVersion、kind等指令对齐的metadata)中使用,比如template中的metadata不可以使用,如果指定了namespace,那么这个namespace必须存在,否则apply的时候报错找不到该命名空间;如果指定namespace的话必须让一组资源使用同一个命名空间,比如定义了Deployment并且为这个Deployment创建了一个Service那么就让这个Deployment和Service使用同一个namespace
labels:定义标签信息,如果是pod中的labels就是为该pod定义标签,如果是selector中的labels那么就是使用这些标签信息匹配需要管理的pod,比如selector定义为app: frontend那么管理的pod就是定义了labels为app: frontend的pod,如果没有pod有app: frontend那么就无法管理pod,同时kubectl apply会失败
spec:定义约束,比如selector、pod的副本数、pod模板等信息
replicas:定义pod副本数,如果某个pod的副本数我们delete一个或者意外挂掉一个那么k8s会根据template中定义的pod信息再启动一个以维持replicas定义的副本数量,但是通过kubectl scale rs命令进行pod数量的扩缩容操作的话,k8s不会再维持replicas定义的副本数量,该参数不指定默认创建一个pod
selector:定义资源选择的labels信息,比如selector定义的labels为app: frontend那么就是管理labels为app: frontend的pod,如果该yaml文件中selector中定义的labels无法匹配到任何一个pod即所有pod没有一个的labels有selector中定义的labels,那么执行kubectl apply -f 会执行失败。
template:定义pod信息
容器信息:
containers:定义容器信息
image:指定容器使用的镜像
ports:定义容器端口信息
env:定义容器的可选参数,- name指定参数名称,value指定参数值
volumeMounts:指定容器volume信息即指定数据挂载目录或数据同步目录
volumes:声明volume信息,如果该容器的Dockerfile文件中未有VOLUME指令的话可以不声明,直接volumeMounts映射主机和容器目录即可
例如:
apiVersion: apps/v1 #版本号
kind: Deployment #资源类型为Deployment
metadata: #定义kind即Deployment的信息
name: mysql #名称
namespace: mysql #使用的命名空间,需要k8s中已经存在该命名空间,否则apply的时候报错找不到该命名空间,指定命名空间之后kubectl get pods/svc/rs等查看的时候也需要-n指定命名空间,否则default命名空间中没有该资源
labels: #定义kind即Deployment的label信息
app: mysql #key: value格式的label
spec: #定义Deployment管理的约束信息
replicas: 1 #定义pod副本数量,该参数不指定默认创建一个pod
selector: #定义deployment管理labels拥有app: mysql的pod
matchLabels:
app: mysql
template: #定义pod信息
metadata:
labels: #定义pod的label信息
app: mysql
spec:
containers: #定义container信息
- name: mysql #container名称
image: mysql:5.7 #image信息
imagePullPolicy: IfNotPresent #定义image拉取失败后的策略
ports: #container端口信息
- containerPort: 3306
name: dbport #为3306端口指定名称,即在service中targetPort既可以写3306也可以写dbport
env: #定义启动容器的可选参数,类似于docker run -e指定的可选参数及值
- name: MYSQL_ROOT_PASSWORD #可选参数名称-root密码,navicat或项目中可以使用root账户和rootpassword连接
value: rootpassword #可选参数值
- name: MYSQL_DATABASE #创建一个test数据库
value: test
- name: MYSQL_USER #创建一个testuser用户,navicat或项目中也可以使用该账号连接mysql,区别在于root账号有最高权限,使用root账号连接既可以看到所有的系统库也有创建数据库等权限;而testuser账号没有新建数据库的权限以及只能看到部分系统库
value: testuser
- name: MYSQL_PASSWORD #指定testuser用户密码为testpassword
value: testpassword
volumeMounts: #volume信息,类似于docker run -v db:/var/lib/mysql,其中的db是数据挂载目录的名称,所以需要定义一个名称为db的数据挂载目录即下方的volumes指定的
- name: db
mountPath: /var/lib/mysql #如果Dockerfile中VOLUME指定了目录就是这个目录,如果没有指定则可以写container中的任意目录
volumes: #定义volume信息,即如果这个container的Dockerfile中有指定VOLUME的话则需要定义volume信息,用于定义数据挂载目录信息,类似于 docker volume create db,如果Dockerfile中没有指定VOLUME则不需要定义,直接在上面的volumeMounts中指定任意目录映射即可或不指定volumeMounts
- name: db #volume名称
hostPath:
path: /var/lib/mysql #对应的物理主机的目录
--- #分割资源,表示下方为另一个资源
apiVersion: v1
kind: Service
metadata:
name: mysql #service名称
namespace: mysql #使用的命名空间
spec:
selector: #指定选择labels即符合下面app: mysql的pod才会被这个service管理
app: mysql
ports:
- name: mysqlport
protocol: TCP
port: 3306 #指定service端口号即访问service的3306端口号就等同于访问pod的名称为dbport的端口号
targetPort: dbport #指定pod(container)端口号,即将pod的这个端口号映射在service的3306端口号
注意:k8s会根据任务调度策略,将pod创建在对应的node上,那么就需要该node上有这个image,如果没有就会去远程仓库拉取,如果远程仓库没有这个image,会导致拉取失败,从而pod创建失败;所以对于我们自己的项目,通过自定义Dockerfile进行build创建iamge,属于私有的image远程仓库是没有这个image的,那么为了k8s可以成功运行,需要将build创建的image先push到远程仓库中(可以是官方仓库或阿里云仓库或自己搭建的仓库,需要先将每个node执行login操作登录远程仓库),这时再apply就可以拉取到image了,就可以创建对应的pod。
说明:
上面的yml文件中定义了mysql的root账号密码、创建数据库、创建账号及密码,那么只要执行了apply操作之后就可以使用创建的账号连接mysql以及看到创建的数据库。
但是我们如果将这个yml文件执行delete操作之后,然后再修改root账号密码或创建的数据库或创建的账号及密码,再次执行apply操作会发现不论是root账号密码、创建的数据库、创建的账号或密码还是和之前一样,并未改成我们修改之后的值。
原因在于我们指定了volume信息,那么按照yml文件中的规则mysql容器的/var/lib/mysql目录中的数据会同步到运行mysql容器的节点的/var/lib/mysql目录,因为节点中的这个目录一直存在,那么不论如何修改yml,执行apply的时候,都会去将该节点中的/var/lib/mysql目录中的数据加载到容器中以实现数据的恢复功能,而我们设置的root账号密码、创建数据库、创建账号及密码等信息也在这个目录下,所以就会使用这个目录中保存的信息,而不会使用我们修改之后的yml中的信息。
解决方案:
将集群中运行mysql容器的节点的/var/lib/mysql目录删除,然后再apply,此时就会是我们修改之后的信息了;删除命令:rm -rf /var/lib/mysql/
如果是本地通过VM创建的虚拟机搭建的k8s集群的话,yml文件定义为MySQL的Deployment,apply创建MySQL服务之后;这时虚拟机又非正常关闭(非正常关闭的话VM会保存几台虚拟机的状态信息,下次启动的时候可以直接选择继续运行还原之前的状态),再次开启虚拟机的时候是选择的继续运行还原保存的虚拟机状态,那么就可能会遇到MySQL地址,账号密码都正确的情况下但是navicat或项目中都不能连接上MySQL,删除节点中MySQL的数据挂载目录再次apply还是无法连接,那么可以删除节点中数据挂载目录之后再关闭所有虚拟机再正常启动虚拟机,再apply运行这时就可以连接上了。
2、kind定义资源类型的区别
ReplicationController:用于pod的管理,其中selector中指定labels时只支持单值的指定
ReplicaSet:和ReplicationController一样也是用于pod的管理,但ReplicaSet被官方称为"下一代的ReplicationController",所以功能上相比ReplicationController有一些优化,比如在selector的labels中可以支持集合的筛选
Deployment:用于ReplicaSet的管理,支持滚动更新,而ReplicaSet不支持滚动更新,所以生产常常是Deployment和ReplicaSet一起使用(只需要将kind定义为Deployment即可,apply会自动创建Deployment和ReplicaSet)。
三、集群网络
1、同一个集群中
在搭建k8s集群的时候,其中需要安装网络插件,我选择的是calico作为集群的网络插件
正是因为calico的存在使得集群中的每一个pod都拥有ip地址。
最终的效果:
1、集群中的所有pod之间都可以互通,无论这些pod是否位于一台node上
2、集群中的所有node可以和所有的pod通信,不论这些pod是否位于本机node上
3、集群中的pod只能和本机的node通信,即pod不能和集群中的其他node通信(以上图的三个pod来说就是IP为192.168.190.83(nginx-deployment-5f468c779d-brx2l)的pod可以和node名称为w1的机器通信不可以和w2通信;IP为192.168.80.213(nginx-deployment-5f468c779d-fzwl4)的pod和IP为192.168.80.214(nginx-deployment-5f468c779d-n4dkv)的pod只能和w2通信不可以和w1通信)
Service:
以上的通信都是基于pod的ip进行的通信(这个ip只能在集群内使用,集群外部不能使用),因为pod可能会遇到挂掉的情况,这时候replicaset会再创建一个pod以维持replicas定义的pod副本数量,这个新创建的pod的ip地址肯定和之前的pod不一样,那么就无法采用之前pod的ip进行通信;此时就可以利用service进行通信即为这个deployment创建一个service然后采用这个 service的ip+service端口(不指定service端口的话默认和pod端口一致) 进行访问pod,并且通过service访问的话还会做负载均衡;此时如果pod挂了replicaset新创建的pod依然在这个service中,扩容的pod也在这个service中,那么就可以通过这个service进行访问。
Service-集群内通信-ClusterIP:
能够通过service访问这些pod以及做负载均衡的原因在于,我们创建的service会将这个deployment管理的pod的ip+端口维护在Endpoints中。
因为这个service的Type是ClusterIP类型,ClusterIP类型只能供集群内部访问即在集群内的机器上通过service的ip+service端口可以访问pod,但是在集群外面的机器上通过service的ip+service端口则无法访问,也不能通过node的ip+service占用的node的端口访问,如果需要在集群外面的机器上也访问pod需要使用NodePort类型的service。
Service-集群内外通信-NodePort:
kubectl expose deployment deployment名称 --type=NodePort 为deployment创建NodePort类型的service
也可以通过yml文件进行创建
apiVersion: v1 #版本号
kind: Service #定义资源类型为Service
metadata:
name: test-service #service名称
spec:
ports:
- port: 80 #端口号-该端口号是指定使用的service的端口即在集群内部通过 service的ip+service端口 访问的时候用到的端口号,如果不指定默认和pod的端口号一致
protocol: TCP
targetPort: 8080 #pod的端口号,如果上面的port不指定,那么在集群内部通过 service的ip+service端口 访问的时候使用该端口号
selector:
key: value #labels即用于筛选哪些pod被该service管理
type: NodePort #service类型
再次查看service
可以看到新建的NodePort类型的service,映射了两个端口8000和31826端口;意味着在集群内部可以通过 service的ip(10.105.148.154)+service端口(8000)进行访问,同时这个31826端口是映射的集群内每个node的端口号即在集群外部可以通过集群中每个node的ip+31826端口访问,就类似于docker run的时候 -p 31826:8000,Service依然是集群内部的,所以集群外部不能通过Service的ip进行访问
除了NodePort可以实现集群内外部访问之外,HostPort也可以实现,区别在于NodePort会为集群中的每个node都开放31826端口,HostPort只会在集群中的一个node开放31826端口
使用NodePort类型的service虽然实现了集群内部和集群外访问pod,但是这种方式也有缺点:需要每个node都占用31826端口,如果pod过多可能出现端口冲突的问题
如果只需要集群内部访问pod的话,Service定义为ClusterIP或者不写类型默认即可;如果需要集群内外部都访问的话Service定义为NodePort类型。
注意:为某个资源定义了Service(不论什么类型的Service)之后,这时在集群内部如果要访问Pod
1、可以通过Pod的ip进行访问(原生方式)
2、可以通过Service的ip+Service的端口进行访问(防止Pod重新运行导致Pod的ip变动)
3、可以通过Service的名称+Service的端口进行访问(这种方式可以用在项目中数据库的连接url上将url中的数据库ip+端口换成Service的名称+Service的端口,防止重新运行MySQL的Service导致Service的ip变动修改代码)
上面提到的Service的端口都是指集群内用的端口即默认不配置和Pod端口一致,而非Service占用的节点的端口。
如果是在集群外部需要NodePort、HostPort类型的Service,使用节点的ip+Service在节点上占用的端口(比如上面的31826端口)访问。
集群内外通信-Ingress:
这种方式也可以实现集群内外通信,同时是常用的方式
前面使用NodePort类型的Service虽然实现了集群内外的通信,但是因为需要集群中的每个节点都开通端口,不是很好的解决方案,Ingress才是常用方案,也就是说Ingress通过http/https的url解析路由,然后根据Ingress中配置的规则进行匹配将该请求转发给具体的Service,再由Service路由给具体的pod。
Ingress controllers:
如果要使用Ingress的方式实现集群外部可以访问,需要实现Ingress controllers
nginx-ingress-controller:
Ingress controllers只是制定了实现Ingress技术的规范(因为Ingress技术的目的就是实现流量转发、路由等而这些功能有像nginx这样成熟的解决方案,所以没必要自己再实现一套,只需要定义一套规范即可;类似于java中的spi机制,比如数据库连接,jdk也是制定了接口规范,具体的实现交由mysql、oracle等厂商自己实现),具体的实现交由具体的厂商来做,其中在项目中我们经常使用nginx来做请求路由,所以我们选择 nginx-ingress-controller 来实现路由的功能。
nginx-ingress-controller部署文档
其实就是kubectl apply -f yml文件,这个yml文件中定义了nginx-ingress-controller需要的资源信息,如果无法下载到这个yml文件,可以使用下面的yml文件进行apply操作
nginx-ingress-controller yaml文件网盘连接 提取码:op6f
检测nginx-ingress-controller是否安装好
1、查看nginx-ingress-controller的pod是否为Running状态
kubectl get pods -n ingress-nginx #ingress-nginx命名空间是nginx-ingress-controller官方yml文件定义使用的
2、查看对应安装了nginx-ingress-controller的node的80和443端口监听情况
lsof -i tcp:端口号
如上则安装成功。
Ingress文件:
在前面安装好nginx-ingress-controller之后,我们的k8s集群就已经具备了通过Ingress来实现请求路由(只有安装了nginx-ingress-controller的机器上才有这个功能),实现外部访问k8s中pod的功能,但是具体的url应该路由到哪个service中呢,所以我们需要配置Ingress文件,帮助Ingress匹配请求的url给Service处理。
Ingress文件和其他的资源文件一样,只是将kind定义为Ingress。
例如:
apiVersion: extensions/v1beta1 #版本
kind: Ingress #定义资源类型为Ingress
metadata:
name: test-ingress #资源名称
spec:
rules:
- host: test.com #定义路由域名-即跟域名是这个值才会被Ingress路由
http:
paths:
- path: /tomcat #定义子域名-可以定义为/即所有请求上面host配置的域名都会路由到下面serviceName配置的service中
backend:
serviceName: test-service #service名称,定义符合host+path组成的url的请求给哪个service,需要和Service资源的yml文件中定义的service名称对应
servicePort: 80 #定义service使用的端口,需要和Service资源的yml文件中定义的端口对应
因为在Ingress文件中只能配置域名不能配置ip(也就是其中的host指令只能配域名不能配ip),如果是在云服务器上的话需要配置 云服务器Ip(安装了nginx-ingress-controller的云服务器ip)和域名(即host的值)绑定映射关系 并且需要备案;如果是本地测试的话,直接配置hosts文件中ip(安装了nginx-ingress-controller的服务器ip)和域名(即host的值)的映射即可;如果hosts文件不可编辑,解决方案如下:
Windows10无法编辑hosts文件
定义好Ingress文件之后,需要先 kubectl apply deployment以及service资源,运行deployment是为了让k8s中拥有对应的pod才能提供对应的服务,运行service是因为Ingress是将请求转发给service,如果没有service则无法转发,deployment和service资源定义需要注意的就是他们的selector定义的labels需要和pod的labels匹配,因为集群外部是通过Ingress访问的,那么Service的类型默认或者ClusterIP即可;然后再 kubectl apply Ingress文件,如果配置好了host指定的域名解析的话,就可以直接使用host+path访问,没问题的话就可以访问到对应的pod,并得到pod的响应结果。
更多推荐
所有评论(0)