Kubernetes

基本概念和环境搭建

用 Docker 进行容器化管理之后方便了很多,容器少的话,可以使用 Shell 脚本来管理。但随着容器越来越多,容器也越来越难以管理,项目架构也越来越复杂,如何管理和维护这些容器,就是Kubernetes 要解决的问题。

Kubernetes 组件

通过架构逐渐升级和演进的过程,一步步引入 K8s 中的各种资源对象,不但要理解他们是为了解决什么而存在的,还要理解他们之间是如何协同工作的。
目标是根据需求选择使用哪些资源对象和如何使用这些资源对象来解决问题。

Node

Node:节点,一个物理机或者一台虚拟机。

Pod

Pod 是 Kubernetes 的最小调度单元,可以理解为容器的抽象。一个 Pod 就是一个或者多个应用容器的组合。它创建了一个容器的运行环境,在这个环境中容器可以共享一些资源,比如网络、存储和运行时的一些配置等等。

假设我们系统包括一个应用程序和一个数据库,就可以将应用程序和数据库分别放到两个不同的 Pod 中,一般情况下一个 Pod 中只运行一个容器,这样可以更好地实现应用程序的解耦和扩展。
![[Pasted image 20241027152854.png]]

Sidecar 边车模式

一个 Pod 中也是可以运行多个容器的,一般仅限于这些容器是高度耦合的情况,它们之间为了共享一些配置或者资源,不得不将它们放到一个容器中。

应用程序要访问数据库的话,只需要知道数据库的 IP 地址,这里的 IP 地址是 Pod 在创建的时候自动创建的,是一个集群内部的 IP 地址(也就是无法从集群外部访问),Pod 之间通过这些 IP 地址进行通信。

IP 地址不稳定的问题

Pod 并不是稳定的实体,它们非常容易被创建或者销毁,比如发生故障的时候,Kubernetes会自动将发生故障的 Pod 销毁掉然后创建一个新的 Pod 替代它,这时候 IP 也会重新分配,如果应用程序还用原来的 IP 来访问的话就找不到。

Service

为了解决这个问题,Kubernetes 提供了一个名为 Service 的资源对象,它可以将一组 Pod 封装成一个服务,这个服务通过一个统一的入口来访问。

就比如上面的场景,我们分别将应用程序和数据库两组 Pod 封装成两个 Service,这样应用程序就可以通过 Service 的 IP 地址访问数据库,即使 Pod 的 IP 地址发生了变化,Service 的 IP 地址也不会发生变化,Service 会自动将请求转发到其它健康的 Pod 上。(像反向代理)

服务也分为内部服务和外部服务。
内部服务例如数据库,缓存,消息队列等只需要在集群内部访问就可以了。
外部服务例如后端服务的 api 接口或者一些给用户使用的前端界面等需要暴露给外部的服务。

外部服务有几种常见的类型。其中一种就是 Node:Port:他会在一个节点上开放一个端口,然后将这个端口映射到 Service 的 IP 地址和端口上。这样就可以通过节点的 IP 地址来访问 Service 了。

在测试和开发阶段通过这种 ip:port方式访问是没问题的,但是在生产环境通常是通过域名来访问服务的。

Ingress

Ingress 是用来管理从集群外部来访问集群内部服务的入口和方式的。可以通过 Ingress 来配置不同的转发规则。从而根据不同的规则来访问集群内部不同的 Service 以及 Service 后面对应的后端pod。还可以通过 Ingress 来配置域名,将使用 IP: port 的方式转换成使用域名来访问 Service。
还可以配置一些其他功能,比如负载均衡,SSL 证书等。

![[Pasted image 20241031110727.png]]

现在应用程序和数据库已经可以在 Kubernetes 中运行,并且对外提供服务。

ConfigMap

应用程序和数据库之间的耦合问题没有考虑到。比如,应用程序需要访问数据库的话,通常吧数据库的地址和端口等连接信息写入配置文件或者环境变量中,然后在应用程序中读取这些配置信息,这样的话配置信息就和应用程序耦合在了一起,一旦数据库的地址和端口发生变化,我们就需要重新编译应用程序。然后重新部署到集群中,这样不但比较麻烦,而且还会造成应用程序的停机时间。

ConfigMap 组件就是来解决这种问题。他可以将一些配置信息封装起来,然后就可以在应用程序中读取和使用。有了 ConfigMap,我们就可以把配置信息和应用程序的镜像内容分离开来。这样就可以保持容器化应用程序的可移植性。

当数据库的地址和端口发生变化的时候,我们只需要修改 ConfigMap 中的配置信息,然后重新加载 Pod 就可以了,不需要重新编译和部署应用程序。实现了应用程序和数据库的解耦。

注意:ConfigMap 中的配置信息都是明文的,如果配置信息中包含一些敏感信息,这些敏感信息不建议存储在 ConfigMap 中,这样会带来一些安全风险和问题。

Secret

为了解决这个安全风险和问题,Kubernetes 提供了 Secret 组件,和 ConfigMap 类似,可以将一些敏感信息封装起来,然后就可以在应用程序中读取和使用了。

这些敏感信息虽然不是以明文的形式来存储的,但是也只是做了一层 Bqase 64 编码而已,所以仅仅只靠 Secret 并不能完全保证敏感信息的安全。还需要靠一些其他的手段来提高安全性,比如 Kubernetes 提供的一些其他的安全机制,包括网络安全、访问控制、身份认证等等。

Volumes

当容器被销毁或者重启的时候,容器中的数据也会跟着消失,这对于一些需要持久化存储的应用程序,比如数据库来说显然是不行的。因此为了解决这个问题,Kubernetes 提供了一个叫做 Volume 的组件,他可以将一些持久化存储的资源挂载到集群中的本地磁盘上,或者挂载到集群外部的远程存储上。这样,即使容器被销毁或者重启,这些数据也不会消失,也就实现了容器中数据的持久化存储。

Deployment

还没有考虑到应用程序的高可用性。比如,应用程序所在的节点发生了故障,需要对节点进行升级和更新维护的时候,应用程序会停止服务,这样就会造成一些不必要的麻烦和损失。解决方案就是一个节点不行就多加几个节点。简单来说就是把所有的东西都复制一份。让后放到另外一个节点上,这样当一个节点发生故障的时候,Service 会自动将请求转发到另外一个节点上来继续提供服务。

Deployment 组件就是来解决这个问题的,他可以定义和管理应用程序的副本数量以及应用程序的更新策略。可以简化应用程序的部署和更新操作。

![[Pasted image 20241031115619.png]]

Deploy 可以看做一组 Pod 的抽象。(复制备份的 Pod)

Service 也是一组 Pod 的抽象(一个功能所需要的多个 Pod)

并且还有副本控制,滚动控制,自动扩缩容等高级特性和功能。

副本控制是指可以定义和管理应用程序的副本数量,例如可以定义一个应用程序的副本数量为 3 个。如果有副本发生故障的时候,他会自动创建一个新的副本来替代它。始终保持有三个副本在集群中运行。
滚动更新是指可以定义和管理应用程序的更新策略,可以轻松升级应用程序的版本,逐渐使用新的版本替换掉旧的版本,确保应用程序的平滑升级。

StatefulSet 的组件来管理

除了应用程序,数据库也会发生类似的故障,例如数据库的节点发生了故障,或者需要进行更新维护的时候,也会停止服务,影响用户的正常使用,所以数据库也是需要采取类似多副本的方式来保证他的高可用性。但是和应用程序不同的是,我们一般不使用 Deployment 来实现数据库的多副本,因为数据库的多副本之间是有状态的,每个副本都有自己的状态,也就是数据。这些数据都是需要持久化存储的,而且也需要保证多个副本之间的数据是一致的。这就需要一些额外的机制,比如把数据写入一个共享的存储中,或者把数据同步到其他的副本中。

对于这一类有状态的应用程序,使用 StatefulSet 组件来管理。他和 Deployment 非常类似也提供了定义和管理应用程序副本数量,动态扩缩容等功能。此外他还保证每个副本都有自己稳定的网络标识符和持久化存储。因此像数据库、缓存、消息队列等有状态类的应用,以及一些保留了会话状态的应用程序,一般都会用 StatefulSet 而不是 Deployment 来部署。

Kubernetes架构

Kubernetes是典型的Master-Worker架构, Master Node负责管理整个集群,Worker Node负责运行应用程序和服务。

Kubernetes通过将容器放入在节点上运行的Pod中来执行工作负载。

Worker Node

image-20241111105519642

为了对外提供服务,每个Node都会包含三个组件,kubelet、kube-proxy和container-runtime.

container-runtime

翻译为运行环境,可以理解为一个容器运行的实例,负责拉取容器镜像,创建容器,启动或者停止容器等等,所有的容器都需要通过container-runtime来运行,所以每个节点上都要安装container-runtime。

kebelet

负责管理和维护每个节点上的Pod并确保他们按照预期运行,他也会定期从apiservice组件接收新的或者修改后的Pod规范,同时监控工作节点的运行情况,然后将信息汇报给apiservice。

kube-proxy

负责为Pod对象提供网络代理和负载均衡服务。

一般 Kubernetes 集群包含多个节点,节点之间通过 Service 通信,这就需要一个负载均衡器来接收请求,然后再将请求发送到不同节点上。kube-proxy 就是负责这个功能的组件,它在每个 Node 上启动一个网络代理,使发往 Service 的流量路由到正确的后端 Pod,比如 Node A 的应用程序要访问数据库,应用程序对数据库的访问请求并不会被随机路由到别的节点的数据库中,kube-proxy 会把请求路由到与应用程序同一个节点(也就是 Node A)的数据库 Pod 中。

Master Node

image-20241111110930269

kube-apiserver

负责提供Kubernetes集群的api接口服务,所有的组件通过apiserver通信,用户在集群中部署应用的时候也需要使用客户端与 apiserver 进行交互。apiserver 就像一个集群的网关,是整个系统的入口,所有的请求都会先经过它,再由它分发给不同的组件进行处理。

除了提供 API 接口之外,apiserver 还负责对所有对象的增删改查等操作进行认证、授权和访问控制。apiserver 接收到请求时会先验证请求的合法性,验证通过之后才会将请求转发给 Scheduler 处理。

Scheduler调度器

负责监控集群中所有节点的资源使用情况,然后根据调度策略将 Pod 调度到合适的节点上运行。

调度策略:比如新增一个新 Pod 时,将 Pod 调度到空闲资源最多的节点上。

control manager控制器管理器

负责管理集群中各种资源对象(比如 Node、Pod、Service)的状态,然后根据状态做出相应的响应。比如集群中有一个节点发生故障时,得有一个机制来监控和检测这个故障然后处理故障,比如重启 Pod 或者使用新 Pod 替代,这就是 Controller Manager 要做的事。

etcd

高可用键-值存储系统,类似 Redis,用于存储集群中所有资源对象的状态信息,每新增或者崩掉一个 Pod,这些信息都会被记录到 etcd 中,使用命令行查询集群状态时就是通过 etcd 来获取的。

etcd 一般只存储集群中应用程序的状态信息,不存储应用程序的数据

Cloud Controller Manager

一个云平台相关的控制器,负责与云平台(例如 Google GKE、Microsoft AKS、Amazon EKS)的 API 进行交互,并且对不同平台都提供一致的管理接口。

minikube环境搭建

minikube 是一个轻量级的 Kubernetes 发行版可以在本地运行单节点的 Kubernetes 集群。

kubectl 是一个命令行工具,可以通过在命令行输入各种命令与 Master Node 的 apiserver 交互,从而与 Kubernetes 集群进行交互。

安装docker

安装minikube

minikube 下载地址 https://minikube.sigs.k8s.io/docs/start/

1、 在命令行中输入 choco install minikube直接安装。然后就直接安装成功了。

我这里一开始choco无法使用,也无法下载,经过检查报错和浏览器搜索,通过将本地中的chocolatey文件夹删除后,保证网络环境的条件下,以管理员身份重新安装配置成功过后就可以了。

点击这里下载安装程序minikube-installer.exe,安装即可minikube version查看版本信息验证是否安装成功

启动minikube minikube start --image-mirror-country='cn'

image-20241112161927617

成功 start 之后就可以kubectl get nodes查看集群中的节点信息了。

安装kubectl

kubectl 是一个与 Kubernetes、minikube 彼此独立的项目,可以单独进行安装,所以不包含在 minikube 里,但 minikube 提供了安装它的简化方式,只需执行下面的这条命令:

minikube kubectl

使用Multipass和k3s搭建kubernetes集群环境

Multipass

安装直接在官网,下载安装。其中发现我的家庭版win11需要安装vbox。

常用命令

# 查看帮助
multipass help
multipass help <command>
# 创建⼀个名字叫做k3s的虚拟机
multipass launch --name k3s
# 在虚拟机中执⾏命令
multipass exec k3s -- ls -l
# 进⼊虚拟机并执⾏shell
multipass shell k3s
# 查看虚拟机的信息
multipass info k3s
# 停⽌虚拟机
multipass stop k3s
# 启动虚拟机
multipass start k3s
# 删除虚拟机
multipass delete k3s
# 清理虚拟机
multipass purge
# 查看虚拟机列表
multipass list
# 创建一台虚拟机
multipass launch --name k3s --cpus 2 --memory 4G --disk 10G

K3s创建集群

k3s 是一个轻量级的Kubernetes发行版,它是 Rancher Labs 推出的一个开源项目,
旨在简化Kubernetes的安装和维护,同时它还是CNCF认证的Kubernetes发行版。

登录虚拟机后执行命令创建,这里用的是国内的镜像

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -

安装完成之后,可以通过kubectl命令来查看集群的状态,这个是 Master 节点

sudo kubectl get nodes

image-20241112172151773

在 Master 节点上获取 token,这个 token 是其它节点加入集群的凭证

sudo cat /var/lib/rancher/k3s/server/node-token
K10454e2c6cd47a05a3a9ebcc7e2c1071c42157ea9c502a093cbc010836bf629a8e::server:15345e5b235b630666ff6356fd85f717
  • 接下来添加环境变量 TOKEN 和 MASTER_IP

Linux 和 Mac 用户执行这条命令

TOKEN=$(multipass exec k3s sudo cat /var/lib/rancher/k3s/server/node-token)

TOKEN=:这是声明一个名为 TOKEN 的变量。

$(...):命令替换的语法,它会执行括号中的命令,并将其输出作为整个表达式的结果。

exec 是 multipass 命令的一个子命令,用于在指定的虚拟机实例中执行命令。

multipass exec k3s sudo cat /var/lib/rancher/k3s/server/node-token:指定 k3s 虚拟机执行sudo cat /var/lib/rancher/k3s/server/node-token

整个命令最终的结果就是把 node-token 文件里的值赋值给环境变量 TOKEN

然后执行echo $TOKEN查看变量值


Windows 用户执行这一条,这条命令的效果跟自己到系统变量里添加一个 TOKEN 变量是一样的,不想输命令就常规操作

[Environment]::SetEnvironmentVariable("TOKEN", $(Invoke-Expression "multipass exec k3s sudo cat /var/lib/rancher/k3s/server/node-token"), [System.EnvironmentVariableTarget]::Machine)

下面这条命令只会在当前会话中保持有效,关闭会话就消失了,了解即可

$env:TOKEN = Invoke-Expression "multipass exec k3s sudo cat /var/lib/rancher/k3s/server/node-token"

$env:TOKEN查看变量值

  • 然后获取 Master 节点的 IP
    Linux/Mac:MASTER_IP=$(multipass info k3s | grep IPv4 | awk '{print $2}')
    Windows:[Environment]::SetEnvironmentVariable("MASTER_IP", $(Invoke-Expression 'multipass info k3s | Select-String "IPv4" | ForEach-Object { $_.ToString().Split(" ")[-1] }'), [System.EnvironmentVariableTarget]::Machine)

这里注意 Invoke-Expression 后面用单引号,用双引号的话会与子命令的双引号匹配而提前结束命令

下面这条命令也只是设置临时变量,了解即可

$env:MASTER_IP = Invoke-Expression 'multipass info k3s | Select-String "IPv4" | ForEach-Object { $_.ToString().Split(" ")[-1] }'

获取后$env:MASTER_IP查看变量值

Windows 一般在设置完系统变量之后要重新打开会话载入变量

  • 接下来就可以创建 Worker 节点了,我们创建两个 worker1 和 worker2
multipass launch --name worker1 --cpus 2 --memory 2G --disk 10G

如果在这里遇到报错launch failed: Start-VM,去下面找找,没有就跳过.

创建和配置worker节点

使用刚刚的TOKENMASTER_IP来创建两个worker节点
并把它们加入到集群中

# 创建两个worker节点的虚拟机
multipass launch --name worker1 --cpus 2 --memory 8G --disk 10G
multipass launch --name worker2 --cpus 2 --memory 8G --disk 10G

这样就完成了一个多节点的kubernetes集群的搭建。

给两台 Worker 安装 k3s 并设置环境变量

 for f in 1 2; do
     multipass exec worker$f -- bash -c "curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn K3S_URL=\"https://$MASTER_IP:6443\" K3S_TOKEN=\"$TOKEN\" sh -"
 done

Linux/Mac 用户直接执行,Windows 用户用 GitBash 执行,复制后在 GitBash 中 Shift+Insert 粘贴。

完成上面的工作之后登录 Master,执行sudo kubectl get nodes,就能看到集群信息了

在这里我遇到问题,各种原因卡死了

我的两个worker节点无法工作,打不开shell界面。也就无法实现后面的给两台worker安装k3s配置环境变量的工作.

尝试的解决方法:

  • 重启电脑
  • 关机虚拟机重开
  • 解决方法:后来发现给两个worker节点分配的memory各自为8G,我的电脑的内存总共就16G。现在开始以下的工作:

删除掉两台worker虚拟机器节点,然后再重新安装内存小的。

# 删除虚拟机
multipass delete worker1/worker2
# 清理虚拟机
multipass purge
# 查看虚拟机列表
multipass list

然后重新安装两个worker节点

multipass launch --name worker1 --cpus 1 --memory 1G --disk 5G
multipass launch --name worker2 --cpus 1 --memory 1G --disk 5G

重装重启后发现可以成功打开虚拟机shell。


好吧,我发现又出问题了,可能是未关虚拟机直接关机造成的,导致各个节点ip都没有,另外电脑性能原因,造成卡顿很严重,重新弄吧!

删除掉所有虚拟机器节点,然后再重新安装内存小的。

# 删除虚拟机
multipass delete worker1/worker2/k3s
# 清理虚拟机
multipass purge
# 查看虚拟机列表
multipass list

然后重新安装节点

multipass launch --name k3s --cpus 1 --memory 1G --disk 5G
multipass launch --name worker1 --cpus 1 --memory 1G --disk 5G
multipass launch --name worker2 --cpus 1 --memory 1G --disk 5G

登录虚拟机后执行命令创建,这里用的是国内的镜像

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -

安装完成之后,可以通过kubectl命令来查看集群的状态,这个是 Master 节点

sudo kubectl get nodes

在 Master 节点上获取 token,这个 token 是其它节点加入集群的凭证

sudo cat /var/lib/rancher/k3s/server/node-token
K10454e2c6cd47a05a3a9ebcc7e2c1071c42157ea9c502a093cbc010836bf629a8e::server:15345e5b235b630666ff6356fd85f717
  • 接下来添加环境变量 TOKEN 和 MASTER_IP

不想输命令就常规操作.


后面发现所有虚拟机都有同一个ip,所有节点都没有IPv4地址。搜索资料尝试多次发现暂时无法解决,思考后感觉需要学习K8s而不是搭建环境,于是使用较熟悉的VMware来重新做一次实验。


思考了一下,再重新查看了一下我的资源管理器,发现内存不太够了。另外发现 hyper-v 功能中并不能发现我的创建的虚拟机,所以我并不知道我的虚拟机在哪安装的。(同样 Vbox 也没有发现。)现在的解决方案大概如下:

  • 使用 win 10 专业版,资源充足的电脑。
  • 同时换种方法来,参考哔哩哔哩的教程。
  • 后续一定不要直接在电脑上安装,在虚拟机里面配置。
  • 我的 docker 使用的是 swl 而不是 hyper-v。(我的笔记本只能这样)

image-20241113112343254

无法取消使用wsl2

最终解决方案

最终我使用了资源更多的台式主机,重新进行了一次上述的所有操作后,最终成功。

image-20241113141546296

K3s的官方文档:https://docs.rancher.cn/docs/k3s/installation/_index

重置密码sudo passwd root

安装相关

 # 安装
 curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
 
 
 # agent节点安装配置
 for f in 1 2; do
     multipass exec worker$f -- bash -c "curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn K3S_URL=\"https://$MASTER_IP:6443\" K3S_TOKEN=\"$TOKEN\" sh -"
 done
 
Environment Variable Description
K3S_TOKEN 用于将 server 或 agent 加入集群的共享 secret。
INSTALL_K3S_EXEC 带有标志的命令,用于在服务中启动 K3s。如果未指定命令,并且设置了K3S_URL,它将默认为“agent”。如果未设置K3S_URL,它将默认为“server”。要获得帮助,请参考此示例。
multipass exec k3s -- ls -l 在虚拟机中执行命令

kubectl常用命令

现在在master节点中可以查看当前的节点sudo kubectl get nodes

但是在worker节点中会出现下面现象:

image-20241113143807176

这是什么原因呢?

配置文件的原因。

kubectl官方文档:https://kubernetes.io/zh-cn/docs/reference/kubectl/

命令(需要在管理员权限下运行) 作用
kubectl [command] [TYPE] [NAME] [flags]
  • command:指定要对一个或多个资源执行的操作,例如 creategetdescribedelete

  • TYPE:指定资源类型。资源类型不区分大小写, 可以指定单数、复数或缩写形式。例如,以下命令输出相同的结果:

    kubectl get pod pod1
    kubectl get pods pod1
    kubectl get po pod1
    
  • NAME:指定资源的名称。名称区分大小写。 如果省略名称,则显示所有资源的详细信息。例如:kubectl get pods

    在对多个资源执行操作时,你可以按类型和名称指定每个资源,或指定一个或多个文件:

  • 要按类型和名称指定资源:

  • 要对所有类型相同的资源进行分组,请执行以下操作:TYPE1 name1 name2 name<#>
    例子:kubectl get pod example-pod1 example-pod2

  • 分别指定多个资源类型:TYPE1/name1 TYPE1/name2 TYPE2/name3 TYPE<#>/name<#>
    例子:kubectl get pod/example-pod1 replicationcontroller/example-rc1

  • 用一个或多个文件指定资源:-f file1 -f file2 -f file<#>

  • 使用 YAML 而不是 JSON, 因为 YAML 对用户更友好, 特别是对于配置文件。
    例子:kubectl get -f ./pod.yaml

  • flags: 指定可选的参数。例如,可以使用 -s--server 参数指定 Kubernetes API 服务器的地址和端口。

常用资源类型和别名(随用随做笔记随时加)

资源类型 别名
pods po
deployment deploy
services svc
namespace ns
nodes no

常用command(随用随做笔记随时加)

操作名 操作含义
get 显示一个或多个资源
create 从文件或标准输入创建资源
delete 通过文件名、标准输入、资源名或者 label 删除资源
run 在集群中使用指定镜像启动容器
exec 在容器内部执行命令

API概述

当编写配置文件的时候将会要用到这些。

REST API 是 Kubernetes 的基本结构。 所有操作和组件之间的通信及外部用户命令都是调用 API 服务器处理的 REST API。 因此,Kubernetes 平台视一切皆为 API 对象, 且它们在 API 中有相应的定义。

  • 类型
    • alpha
    • beta
    • stable
  • 访问控制

关于 Kubernetes 如何实现和控制 API 访问的介绍性材料, 可阅读控制 Kubernetes API 的访问

  • 废弃api说明

已弃用的API的迁移指南:https://kubernetes.io/zh-cn/docs/reference/using-api/deprecation-guide/

操作实践

Pod

pod配置文件

posted @ 2024-11-11 18:43  彬彬zhidao  阅读(9)  评论(0编辑  收藏  举报