kubernetes 基本使用
当容器较少的时候,可以使用docker进行手动管理,但是如果容器很多,每个容器为了容灾还有很多副本以集群方式运行,并且各个容器集群之间有错综复杂的通信连接,那么此时就能使用k8s进行管理了。
它可以根据你的配置,自动维护集群和系统的稳定,例如当集群中的一个容器副本下线后,它会根据配置立即重新创建一个容器顶上。它可以将一个集群统一暴露成一个ip,再由内部的负载均衡算法进行流量调度,可以认为,springcloud的那些核心功能它都有,但springcloud仅适用于java
安装
minikube
注:我用这种方式安装总是出现各种各样的问题,所以使用的是k3s,下面记录的是安装和使用minikube时遇到的一些问题:
https://minikube.sigs.k8s.io/docs/start
执行 minikube start
失败
sudo minikube start --image-mirror-country='cn' --registry-mirror=https://registry.docker-cn.com --force
minikube start会下载k8s,其中,–image-mirror-country=‘cn’表示使用国内镜像下载,–force 表示强制使用有root权限的docker(k8s不建议docker使用root运行)
如果sudo执行命令遇到 permission denied
这类问题,可以尝试使用下面命令解决:
sudo rm -rf /tmp/minikube_* /tmp/juju-mk*
文档上说设置别名 kubectl='minikube kubectl --'
,但这样一来,sudo kubectl
是用不了的,因为使用sudo执行命令会重新创建一个只有root环境变量的shell执行命令,所以当前shell下的环境变量和别名用不了,可以通过下面的方式解决:
# 将sudo设置为别名,注意后面多了一个空格。官方解释是当别名后面是空格时,它会继续检查下一个字符是否也是别名alias sudo='sudo '# 如此一来 sudo kubectl xxx 就能使用了
另一种方式是执行 sudo -i
(登录式交互shell,会执行 /etc/profile)或 sudo -s
(非登录式交互shell),它会以root身份开启一个交互式shell,进去后再执行 source .bashrc
,即可将当前用户的环境变量复制过来。
k3s
去掉了k8s中的一些不常用和过时的功能,保留最核心的功能,并且可以单机部署
https://docs.rancher.cn/docs/k3s/installation/install-options/_index
国内的话使用下面的命令安装更快
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
安装完就能直接使用了,可以使用 systemctl stop/start k3s
进行关闭和开启k3s服务。需要注意的是,这只是能停止k3s服务,但k3s管理的那些容器等仍然是在运行的,官方提供了完全停止的脚本:
bash /usr/local/bin/k3s-killall.sh# 卸载脚本bash /usr/local/bin/k3s-uninstall.sh
基本概念
node: 表示一台主机,可以是物理机或虚拟机
pod: 可以理解为一个docker容器,只不过在k8s中,一个pod可以有多个容器,但基于单一性原则,一般就是一个容器
deployment(可以写成deploy): 容器集群的管理者,但它是单个pod集群(副本)的管理,例如你有多个容器,每个容器是一个pod,而每个pod需要呈集群方式部署,则每个pod集群就可以使用一个deployment进行集群管理。试想,如果一个pod集群只有两三个pod容器,则可以手动创建和维护,如果集群有很多pod呢,则deployment可以根据pod模板一下子创建很多pod副本,并且自动维护pod副本数量,一旦发现有pod副本下线就重新创建一个。正因如此,它适合对无状态的pod集群进行管理。注:pod的管理者有很多,功能各不相同,deployment只是其中的一个,其他的例如 ReplicaSet 等,事实上,deployment就是通过ReplicaSet来对副本进行管理的。由于deployment本身就能配置pod的创建模板(见下文),所以无需单独创建pod
service(可以写成svc): pod对外服务的网关,一个pod创建之后,只能是集群内部访问,外部无法访问,所以可以创建一个service将pod端口暴露出来。需要注意的是,一个service也可以理解为一个容器,但该容器只负责端口转发。也就是说,如果你创建了一个 NodePort 类型的service(允许外部访问的service),那么流量是这样走的 浏览器node的端口(nodeport,即物理机端口)—> service的端口(注:service也是一个容器)—> pod 的端口 —> 服务
label: 创建 pod、depolyment、service 等都可以给它们指定标签。值得注意的是,不要认为 service、depolyment、pod 等是相互绑定的关系,并不是,它们都是独立的应用,而它们之间就是通过label进行关联的。例如我可以先创建一个管理 label 中包含 “name=hunt” 的service,我可以再去创建label 中包含 “name=hunt” 的pod,该service也能作用域该pod
基本使用
对于pod、deployment、service等,最基本的用法就是创建和删除,都支持使用命令行和配置文件进行创建
命令行方式创建都是使用 kubectl create pod/deployment/service --xxx
的方式
删除的命令是 kubectl delete pod pod-name
的方式,不用停止pod/deploy/svc,之间删即可
配置文件的方式都有一个统一的大格式:
apiVersion: v1kind: Pod/Deployment/Servicemetadata: name: xxx #namespace: dev labels: name: hunt xxx: xxxspec: ...
然后以 kubectl create -f xxx.yml
进行创建和启动,可以再后面指定多个 -f
同时创建多个功能
删除也是 kubectl delete -f xxx.yml -f xxx.yml
注:对于上述配置文件可以写什么参数,以及各个参数的作用,可以使用 kubectl explain "pod.metadata.name"
的方式进行查看
查看的方式为 kubectl get pod,deploy,svc
可以在后面加上 -o wide
查看更详细的信息
若要查看具体的信息,可以使用 kubectl describe pod xxx
进行查看,deployment、service 等同理
进入pod的方法同docker kubectl exec -it pod-name bash
Pod
apiVersion: v1kind: Podmetadata: name: pod-nginx #namespace: dev labels: run: nginx name: huntspec: containers: - image: nginx:latest name: nginx-pod ports: - containerPort: 80 protocol: TCP
Deployment
命令方式创建:
create deployment nginx --image nginx --replicas 3 --port 80
配置文件方式创建:
apiVersion: apps/v1kind: Deploymentmetadata: name: deploy-nginx # 会生成 deploy-nginx-随机字符 为名称的pod #namespace: dev labels: xxx: xxx # 注:service不会匹配deploy的labelspec: replicas: 3 # 保持一直有3个pod的副本 selector: matchLabels: # deploy就是根据下面这些标签匹配pod中的标签进行管理 name: hunt template: # 这就是pod的配置文件模板,deployment会根据这个模板创建pod #name: nginx metadata: labels: name: hunt spec: containers: - image: nginx:latest name: nginx-dep ports: - containerPort: 80 # 注:就是不写这个,端口也是可以内部访问的,写这个只是给其他服务一个标记 protocol: TCP
Service
可以指定很多不同的类型,例如 NodePort 就会创建一个供外部网络访问的服务,而 ClusterIP 则只能让集群内部网络进行访问。但是内部网络不是本来就能访问吗,为什么还要单独创建一个service?这是因为一个pod集群存在很多pod,而每个pod都有一个ip,那我要访问这个集群的时候应该访问哪个ip呢?所以创建一个service就能创建一个统一的ip,当我访问该service的ip时,service会自动将该请求转发给pod集群中的某一个pod上
命令方式创建:
kubectl expose deployment deploy-name --port 8080 --target-port 80 --type NodePort
配置文件方式创建:
apiVersion: v1kind: Servicemetadata: name: svc-nginx #namespace: devspec: #clusterIP: 10.109.179.231 #固定svc的内网ip type: NodePort selector: # 根据这些标签匹配pod的标签,注意只是pod #run: nginx name: hunt ports: - port: 8080 # service 的端口,注 service 也可以看成是一个容器 targetPort: 80 # pod的端口 nodePort: 30002 # node 的端口,也就是物理机的端口,端口转发过程为: nodePort -> port -> targetPort #protocol: TCP
另外,如果只想对创建的pod进行临时的测试访问,不必每次都要创建service来暴露端口给浏览器访问,可以直接使用 kubectl 的端口转发工具,用法为:
# 用于ipv4kubectl port-forward --address=0.0.0.0 pod/pod-name 8080:80# 用于ipv6kubectl port-forward --address=:: pod/pod-name 8080:80
这里的 8080 指的就是node即物理机的端口了,80 指的就是pod服务的端口。其中 --address=0.0.0.0
的作用就是让外部网络可以通过主机ip访问,否则就只能在node本机上通过 localhost 访问
创建一个nginx服务
以配置文件的方式创建deploy和pod,以命令行的方式创建service
将上述deployment的配置文件保持为 deploy.yml,然后执行
kubectl create -f deploy.yml
可以通过 kubectl get pod,deploy -o wide
查看是否创建成功
然后通过下面的命令创建一个service将服务暴露出去
kubectl expose deployment deploy-nginx --type=NodePort --port=8080 --target-port=80
然后查看服务状态:
注:第一个service是k3s自带的,不用管
接着就可以在浏览器访问 http://192.168.234.140:32041/,不出意外就会出现nginx的页面了。
再次强调,上面的输出中 8080:32041,8080表示的是service这个容器暴露的端口,而32041表示的才是node(即物理机)的端口(注:如果不手动指定的话,会随机生成一个node端口),具体的端口访问过程为:node的端口32041 –> service的端口8080 –> pod的端口80
参考
minikube: https://minikube.sigs.k8s.io/docs/start/
deployment: https://blog.csdn.net/wohu1104/article/details/128879028