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: v1
kind: Pod/Deployment/Service
metadata:
name: xxx
#namespace: dev
labels:
name: hunt
xxx: xxx
spec:
...

然后以 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: v1
kind: Pod
metadata:
name: pod-nginx
#namespace: dev
labels:
run: nginx
name: hunt
spec:
containers:
- image: nginx:latest
name: nginx-pod
ports:
- containerPort: 80
protocol: TCP

Deployment

命令方式创建:

create deployment nginx --image nginx --replicas 3 --port 80

配置文件方式创建:

apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx # 会生成 deploy-nginx-随机字符 为名称的pod
#namespace: dev
labels:
xxx: xxx # 注:service不会匹配deploy的label
spec:
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: v1
kind: Service
metadata:
name: svc-nginx
#namespace: dev
spec:
#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 的端口转发工具,用法为:

# 用于ipv4
kubectl port-forward --address=0.0.0.0 pod/pod-name 8080:80
# 用于ipv6
kubectl 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

Leave a Comment