Skip to content

Kubernetes

复习一下 docker

docker → 进程隔离 ;操作系统层虚拟化(同一个操作系统下隔离软件环境)

镜像 image → 容器 Container → 仓库

查看容器占用资源:

docker status

微服务:负载均衡(多节点,实现高可用,平稳过度)

将一个整体的服务拆分为多个微服务

考虑的内容:日志收集(多节点),服务监控,资源服务器分配,判断服务的前置依赖

上面这些考虑的内容可以通过 K8s 来进行处理。

  • K8s: 容器编排系统,用于管理和扩展大规模的容器部署
  • Portainer: 容器管理工具,提供了一个易于使用的界面来管理 Docker 和 Kubernetes 资源。

1、K8s 是什么

Kubernetes(也称 k8s 或 “kube”)是一个开源的容器编排平台,可以自动化在部署、管理和扩展容器化应用过程中涉及的许多手动操作

参考

核心特性:

  • 服务发现和负载均衡:Kubernetes可以自动发现应用服务,并通过一个统一的服务名进行访问,如果服务的容器出现故障,可以自动重新路由到其他健康容器。
  • 存储编排:自动挂载所选存储系统,无论是本地存储、公共云提供商的存储,还是网络存储系统。
  • 自动部署和回滚:可以描述应用的期望状态,Kubernetes可以自动将实际状态改变为期望状态。如果有任何变更导致错误,Kubernetes可以回滚到之前的状态。
  • 自动完成容器编排:基于资源消耗自动放置容器到节点,考虑资源需求和约束,而不是手动选择运行的节点。
  • 自我修复:自动重启失败的容器,替换和杀掉不响应用户定义的健康检查的容器,直到应用正常运行。
  • 密钥与配置管理:部署和更新密钥和应用配置,不需要改变容器镜像,避免将密钥存储在容器镜像中。

2、K8s 如何使用

image.png

控制平面组件

控制平面(Master节点)包含了以下几个核心组件,它们负责整个集群的管理和协调工作:

  • API Server(kube-apiserver):作为集群的前端,它提供了Kubernetes API服务,是用户、外部应用和集群内部各组件交互的接口。
  • Scheduler(kube-scheduler):负责调度决策,选择哪个节点来运行未运行的Pod。它根据资源需求、硬件/软件/策略约束、亲和性和反亲和性规范、数据局部性、工作负载间干扰和截止日期等多种因素做出决策。
  • Controller Manager(kube-controller-manager):管理控制器进程,这些控制器包括节点控制器、副本控制器、端点控制器、服务帐号和令牌控制器等。控制器通常负责集群的状态管理,确保应用的当前状态与用户声明的期望状态一致。
  • ETCD:是一个一致性、高可用的键值存储数据库,用于保存所有集群数据,是整个集群的“真实来源”。

节点组件

节点(Node节点)通常是物理机或虚拟机,运行着容器化应用,它包含了以下几个关键组件:

  • Kubelet:负责管理Pod和它们的容器、镜像、卷等,包括启动、停止容器应用,维护容器的运行状态等。
  • Kube Proxy(kube-proxy):是网络代理,运行在每个节点上,负责服务发现和负载均衡,它处理节点上的网络路由,并实施部分网络策略。
  • Container Runtime:负责运行容器,例如Docker、containerd等。

Pod

  • Pod:Pod是Kubernetes中的基本部署单元,它是一个或一组容器的集合,共享存储和网络,运行在同一节点上。

工作流程

工作流程通常是这样的:

  1. 用户或自动化系统使用kubectl(或其他客户端)向API Server发送指令。
  2. API Server将配置信息存储在ETCD中。
  3. Scheduler监听API Server,寻找没有分配节点的新Pod,并选择一个节点来运行这个Pod。
  4. 一旦Pod被指派到一个节点,对应节点上的Kubelet负责初始化容器环境,启动容器,并保持容器的运行状态。
  5. Kube Proxy负责处理该节点上Pod的网络通信。

K8s 是一个容器编排调工具,能够进行自动资源调度和服务发现与负载均衡

资源调度

容器编排系统能够根据容器的资源需求(如CPU、内存、存储等),自动选择最合适的主机节点来部署容器。这通常涉及复杂的决策过程,可能包括:

  • 负载均衡:在多个主机间分配容器,以保持负载均衡。
  • 高可用性:确保应用组件跨多个故障域部署,以提高容错能力。
  • 资源限制:为每个容器设置资源限制,避免单个容器耗尽所有主机资源。

服务发现与负载均衡

容器启动和停止时,它们的IP地址和端口是动态分配的。容器编排系统需要提供服务发现机制,以便容器和服务可以互相发现和通信。同时,它可以实现内部负载均衡,将流量分发到多个容器实例


3、灰度发布

灰度发布(也称为金丝雀发布或渐进式发布)是软件发布的一种策略,其中新版本的软件逐步替换旧版本,这样新的变更只影响一部分用户。这个过程允许开发和运维团队监控新版本的表现,而不会影响所有用户。

灰度发布的关键目的是减少由于新版本引入的风险。通过先对一小部分用户进行发布,可以在不干扰所有用户的情况下测试新版本在生产环境中的表现。

这个灰度发布可以通过 k8s 的部署策略去做到

image.png

推荐参考

https://www.kancloud.cn/zatko/kubernetes_k8s/2290695

部署使用 🚩

网络连通

这里使用一下虚拟机完成以下相关功能

虚拟机 开三个机器,master 双核4G,两个node双核8G

这里使用的虚拟机是 Virtual Box

建议设置以下 热键 → 虚拟电脑 → 主机组合键 → 设置为 Ctrl + Alt

密码设置 root/root

创建用户 luoqi/123456 🕷

需要后面看一下,目前是虚拟机不能获取到 ip 地址,且执行 sudo 命令不起效果

不用管之前的操作方式,选择新增虚拟机的操作,然后在网络与主机名初始配置这里选择打开

image.png

正常来说,按照这种初始化配置是可以进行在虚拟机中 Ping 通外网的

进行网络配置:选择网卡2,进行选择“仅主机(Host-Only) 网络”

image.png

再次启动虚拟机后,进入到 终端,输入 ip addr

image.png

然后就可以使用 shell 工具进行连接操作。

按照同样的方式创建两个从节点👇

复制操作(选择复制一下主节点),复制主节点虚拟机到两个子节点。

部署操作

这里选用了 kubeadm 工具去进行集群环境下的部署。

部署 Kubernetes 集群通常包括设置一个或多个 master 节点和多个 worker 节点。

系统要求

  • 一定数量的机器(物理机或虚拟机),至少 2GB RAM,2 CPUs。
  • 系统支持的操作系统(如 Ubuntu, CentOS)。
  • 禁用 Swap。
  • 集群中所有机器之间网络互通
  • 可以访问外网,需要拉取镜像

大概的一些步骤

  • 1、环境准备
  • 2、安装 kubeadm, kubelet 和 kubectl (工具安装)
  • 3、初始化集群
  • 4、设置 kubectl,配置当前用户使用 kubectl 连接到 Kubernetes 集群
  • 5、选择并部署一个 Pod 网络到集群中,加入工作节点,进行验证操作。

参考这套: https://cloud.tencent.com/developer/article/1674040

视频参考: https://www.bilibili.com/video/BV1LC4y1g7wz

准备环境

【环境角色】

master:192.168.56.101

node1:192.168.56.102

node2:192.168.56.103

三个节点都选择无界面启动(虚拟机)

关闭防火墙:
$ systemctl stop firewalld
$ systemctl disable firewalld

关闭selinux:
$ sed -i 's/enforcing/disabled/' /etc/selinux/config  # 永久
#这里设置永久的话,是需要重启后才能失效,设置临时是为了保证这一次不重启也先临时关闭下 selinux
$ setenforce 0  # 临时

关闭swap:
$ swapoff -a  # 临时
$ vim /etc/fstab  # 永久

设置主机名:
$ hostnamectl set-hostname <hostname>

在master添加hosts:
#建议在所有节点上操作
$ cat >> /etc/hosts << EOF
192.168.56.101 k8s-master
192.168.56.102 k8s-node1
192.168.56.103 k8s-node2
EOF

#每个节点都进行操作,创建或覆盖一个名为 `k8s.conf` 的文件在 `/etc/sysctl.d/` 目录下
#确保经过 Linux 网桥的 IPv4 和 IPv6 流量都被传递到 `iptables`(和 `ip6tables`)的链中进行处理
#将桥接的IPv4流量传递到iptables的链:
$ cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sysctl --system  # 生效

时间同步:
$ yum install ntpdate -y
$ ntpdate time.windows.com

操作说明

  • 关闭防火墙:Kubernetes 需要在集群的各个节点之间进行网络通信,防火墙可能会阻止或限制这些通信。关闭防火墙可以简化网络配置和故障排除过程,避免通信被不必要地阻断。
  • 关闭 SELinux:SELinux(Security-Enhanced Linux)可以增强系统的安全性,但它也可能与 Kubernetes 的一些组件不兼容,特别是涉及到文件系统权限和网络访问。禁用 SELinux 可以减少权限问题,特别是在 Pod 之间共享数据时。
  • 关闭swap:Kubernetes 官方推荐在运行 kubelet 的机器上禁用 swap 空间。这是因为 Kubernetes 的调度器将考虑节点的内存使用情况来安排 Pod,启用 swap 空间会使内存管理变得复杂,可能会导致调度和资源限制的问题。
  • 设置主机名:为每个节点设置一个独一无二的主机名有助于节点间的识别和管理。在管理和维护集群时,能够通过主机名快速识别具体节点。
  • 在 master 添加 hosts:这个操作是为了简化节点间的网络通信,尤其是在 DNS 服务不稳定或不可用的情况下。通过在 /etc/hosts 文件中静态定义 IP 地址和主机名的映射,可以保证即使在 DNS 解析问题发生时,节点间的通信也不会受到影响。
  • 将桥接的 IPv4 流量传递到 iptables 的链:这些设置确保所有从 Linux bridges 传递的流量都会被 iptables 的规则所处理。这对于网络插件(如 Calico 或 Flannel)来确保 Pod 网络的正常工作至关重要。
  • 时间同步:所有节点的时间同步是非常重要的,特别是在分布式系统中,时间偏差可能导致日志、事件处理和其他时间敏感的操作出现问题。使用 ntpdate 确保节点时间的一致性,有助于维护集群的稳定性和可靠性。

使用 vim 打开 /etc/fstab 文件后,你会看到类似下面的内容

在对应的 含有 swap 的行,添加 # 进行注释,保存退出

image.png

设置主机名

hostnamectl set-hostname k8s-master

hostnamectl set-hostname k8s-node1

hostnamectl set-hostname k8s-node2
工具安装

安装 docker

$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
$ yum -y install docker-ce-18.06.1.ce-3.el7
$ systemctl enable docker && systemctl start docker
$ docker --version
Docker version 18.06.1-ce, build e68fc7a

配置镜像仓库地址

$ cat > /etc/docker/daemon.json << EOF
{
  "registry-mirrors": ["https://7iwp6tq0.mirror.aliyuncs.com"]
}
EOF

添加 k8s YUM 源

$ cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

安装kubeadm,kubelet和kubectl

yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
systemctl enable kubelet

TIPS:K8S集群还未拉起,故这里的kubelet是无法启动的,等master初始化时会自动拉起

部署 K8S master
kubeadm init \
  --apiserver-advertise-address=192.168.56.101 \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.18.0 \
  --service-cidr=10.92.0.0/12 \
  --pod-network-cidr=10.220.0.0/16 \
  --ignore-preflight-errors=all
  • apiserver-advertise-address 是主节点 IP 地址
  • service-cidr :用于 Kubernetes 服务的虚拟 IP 地址(ClusterIP)。当你创建一个服务时,Kubernetes 会自动从这个范围分配一个 IP 地址给服
  • pod-network-cidr:这个 CIDR 范围用于分配给集群中的 Pods 的 IP 地址。每个 Pod 都会从这个范围内获取一个 IP 地址。

后面两个地址:这里目前使用的是文档给定的两个地址,具体如何配置的,后面有空再看一下


部署完成后会获取到 node加入集群的命令以及token

image.png

kubeadm join 192.168.56.101:6443 --token gdhwj6.hmqvv0wodnh6suwd \
    --discovery-token-ca-cert-hash sha256:3e37e9c89dbe37bd0d3d639f8002545ebca2c083a8d9097c1725f1d7af6a1ede

使用kubectl命令【如需node节点使用此命令,可使用scp命令分别拷贝config文件至对应目录】

#创建一个名为 `.kube` 的目录。该目录用于存放 `kubectl` 的配置文件
mkdir -p $HOME/.kube

#将 Kubernetes 集群的管理员配置文件 `admin.conf` 复制到 `.kube` 目录,并重命名为 `config`。这个配置文件包含了集群的连接信息,包括 API 服务器的地址、认证信息等
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

#授权
sudo chown $(id -u):$(id -g) $HOME/.kube/config

#列出 Kubernetes 集群中的所有节点
$ kubectl get nodes
加入 K8S node

在node节点中分别执行,master init后产生的加入命令:

TIPS:这里加入node后会看到node状态为NotReady,是因为没有安装CNI,kubelet无法通过网络给apiserver上报node状态,安装CNI后即可恢复

image.png

部署网络插件【CNI】
wget https://docs.projectcalico.org/manifests/calico.yaml

下载完成后,修改calico.yaml【定义Pod网络(CALICO_IPV4POOL_CIDR),与前面pod CIDR配置一样即可】

这里的操作是在主节点下操作,下载完后,直接在当前目录进行编辑即可,

需要进行放开注释,并编辑值

image.png

应用该配置

# kubectl apply -f calico.yaml
# kubectl get pods -n kube-system

这里 kubectl apply -f calico.yaml 会报错:

error: unable to recognize "calico.yaml": no matches for kind "PodDisruptionBudget" in version "policy/v1"

看了一下大家的问题,是因为版本问题导致(这篇文章的时间是 2020 年)

看一下这个版本对应: https://blog.csdn.net/qq_32596527/article/details/127692734

image.png

这里的 k8s 版本是 1.18,对应的 calico 版本为 3.18

解决方案: https://blog.csdn.net/qq_46237746/article/details/125453966

重新下载文件

wget https://docs.projectcalico.org/v3.18/manifests/calico.yaml

重新执行

应用该配置

# kubectl apply -f calico.yaml
# kubectl get pods -n kube-system

应用后可以看到CNI POD正在初始化中,静待拉起~

calico running 状态后,查看节点已全部 Ready【需要点时间】

image.png

到此部署成功。

使用 Kubernetes 部署 MySQL 服务

通过第二节的内容,其实我们也可以看到,k8s 主要还是通过 yaml 文件,通过工具去进行执行相关指令,并进行运行部署容器;

其中 k8s 主要可以做一些比较高级的工作,但总体来说,对于使用者来说,我们做的工作就是:1、部署 k8s ;2、编写 yaml 文件,将服务放到 k8s 中进行容器编排服务管理

我们所要关心的,第一点不是负责管理和如何高效处理这个系统的工具或者接口,而是从 POD 开始。

Pod:Pod是Kubernetes中的基本部署单元,它是一个或一组容器的集合,共享存储和网络,运行在同一节点上。

Docker Compose 和 Kubernates 的简易区别:

  • Docker Compose 主要用于开发和测试,或者小型生产环境。
  • Kubernetes 用于大规模的生产环境。

服务搭建

参考: https://www.kancloud.cn/zatko/kubernetes_k8s/2290695

master 节点上操作

#拉取镜像
docker pull mysql:5.7

创建文件

/root/docker/mysql目录下创建 mysql-rc.yaml 文件

mysql-rc.yaml

apiVersion: v1 # 这是稳定长期使用的 API 版本,具体资源对象的版本可以参考“推荐阅读”
kind: ReplicationController # 副本控制器 RC
metadata: # 元数据
  name: mysql-dev-57 # 定义这个 rc 的名称为 mysql,它具有全局唯一性,5.7 版本,开发环境
spec: # 规范
  replicas: 1 # pod 副本的期待数量,这里为 1,表示当环境中没有符合条件要求的 pod 数量时需要创建一个,如果符合要求的 pod 数量大于一个就要删除多余的 pod,始终要保持环境中只有一个 pod 符合要求。
  selector: # 标签选择器
    app: mysql # 符合要求的 pod 都必须要有这个标签 app:mysql
  template: # 创建 pod 副本的模板
    metadata: # 创建的 pod 副本拥有的元数据
      labels: # 创建的 pod 副本的标签
        app: mysql # 对应 RC 的标签选择器,保证创建的 pod 副本符合 RC 的选择器范围
    spec: # 定义 pod 副本中运行的容器的详细信息
      containers: # 容器信息
        - name: mysql # 容器的名字
          image: mysql:5.7 # 容器中运行的镜像
          ports: # 容器对外暴露的端口
            - containerPort: 3306 # 容器的端口 3306
          env: # 容器中的环境变量
            - name: MYSQL_ROOT_PASSWORD # 设置环境变量 MYSQL_ROOT_PASSWORD="123456"
              value: '123456'

创建服务

kubectl create -f mysql-rc.yaml

创建好资源后,查看已经创建的 ReplicationController 资源对象,在命令中可以将其简写为 rc:

kubectl get rc

image.png

在输出中,DESIRED表示这个名为 mysql-dev-57 的 rc 需要创建一个 pod 副本,CURRENT表示当前已经创建好的 pod 副本数量,READY表示 pod 副本已经成功运行,AGE表示存活时间(生命周期)。

然后查看环境中的 pod,在终端执行如下命令:(等待一段时间后再看,创建需要点时间)

kubectl get pods

image.png

可以看到使用 rc 创建的 pod 副本的名字为:mysql-dev-57-pqjgm,这个名字是由两部分组成的,前面部分的 mysql-dev-57 和创建它的 rc 名字相同,后面的 pqjgm 是随机生成的字符串可以用来区分由同一个 rc 创建的不同的 pod,READY 为 1/1 表示已经创建好,STATUS 为 Running 表示这个 pod 正处于运行状态。

当然,我们还可以查看 mysql-dev-57-pqjgm pod 的具体构建过程,如果以后运行不成功,也可以通过 Events 来查看具体是哪里出了问题:

kubectl describe pod mysql-dev-57-pqjgm

image.png

在创建成功运行着 MySQL 的 pod 之后,还需要创建一个与之外应的 Service,这样才能让其它的 pod 可以访问 MySQL 应用提供的服务。

Service 被创建之后,Kubernetes 会给它分配一个虚拟的 Cluster IP,并且在 Service 的整个生命周期中,这个 Cluster IP 都不会改变,这样的好处就是,pod 可能会随时发生变化(由于某些意外情况被销毁然后重建),但是我们的 Service 始终是确定不变的,

在 Kubernetes 集群内部通过服务名和暴露出来的端口就可以稳定的访问某一个服务而不需要管隐藏在服务背后的 pod 的变化。

/root/docker/mysql目录下新建 mysql-svc.yaml 文件,并向其中写入如下内容:

mysql-svc.yaml

apiVersion: v1 # API 版本号,使用稳定版:v1
kind: Service # 资源对象类型
metadata: # 元数据
  name: mysql-dev-57 # Service 的名称为:mysql,这个名称具有全局唯一性
spec: # 规范
  ports: # 对外暴露出的端口
    - port: 3306 # 这里指定为 3306 端口
  selector: # 标签选择器
    app: mysql # 服务对应的 pod 是具有 app=mysql 标签的这些

新建服务的 yaml 文件之后执行创建

kubectl create -f mysql-svc.yaml

来查看一下创建好的服务,在终端执行如下命令,其中 svc 是 services 的简写

kubectl get svc

image.png

这里列出了 kubernetes 集群目前全部的服务,第一个名为 kubernetes 的服务是集群启动以后默认创建的服务,

第二个名为 mysql-dev-57 的服务是我们刚刚创建的,集群自动为它分配了一个 ClusterIP 为 10.90.169.4,它的 3306 端口也是前面在 yaml 文件中已经定义好了的。

还可以执行如下命令查看 mysql 服务更加详细的信息:

kubectl describe svc mysql-dev-57

image.png

这里有点小坑(应该也不算,实际生产中,的确外部有时候会不允许直接访问)

这里是 svc 需要设置一下 EXTERNAL-IP

改一下 mysql-svc.yaml

apiVersion: v1 # API 版本号,使用稳定版:v1
kind: Service # 资源对象类型
metadata: # 元数据
  name: mysql-dev-57 # Service 的名称为:mysql,这个名称具有全局唯一性
spec: # 规范
  ports: # 对外暴露出的端口
    - port: 3306 # 这里指定为 3306 端口
      targetPort: 3306
  selector: # 标签选择器
    app: mysql # 服务对应的 pod 是具有 app=mysql 标签的这些
  externalIPs:
    - 192.168.56.101

执行命令

kubectl apply -f mysql-svc.yaml
  • kubectl apply 命令会比较已经存在的资源配置和新的配置文件,然后计算出需要更新的差异,并应用这些差异来更新资源。这种方式非常适合持续集成和持续部署(CI/CD)流程。

至此,这里的外部服务连接也是 OK的。


关停 k8s 操作

参考: https://blog.51cto.com/u_14568336/9719914

未实际操作,这里记录一下

停止K8S集群流程

步骤操作
1清空Kubernetes资源
2删除Pod
3删除Service
4关闭Kubelet服务
5删除Master节点
6停止K8S集群

首先,我们需要清空Kubernetes中的所有资源,包括Deployment、StatefulSet、Service等等。这可以通过kubectl命令来实现。

kubectl delete deployment --all
kubectl delete statefulset --all
kubectl delete service --all

接着,我们需要删除当前所有的Pod。同样可以使用kubectl命令来删除。

kubectl delete pods --all

删除Service资源,同样使用kubectl命令。

kubectl delete service --all

关闭Kubelet服务,可以通过systemctl命令来停止。

sudo systemctl stop kubelet

将Master节点从集群中移出,执行命令前请确保备份数据。

kubeadm reset

最后,停止整个Kubernetes集群。

sudo kubeadm reset