再谈三高

微服务的三大指标:高可用,高性能,高并发

高性能的提升方案:

  • RPC 通信
  • Kyro 高速序列化
  • HikariCP 连接池
  • SQL 优化
  • Redis 缓存
  • JVM 优化
  • GC 优化
  • ……

高并发的提升方案:

  • 垂直扩展:价钱升级服务器
  • 水平扩展:增加服务器数量
  • 水平+垂直
  • 负载均衡
  • 集群
  • ……

高可用 ( 一直可以用 ) 的提升方案:

  1. 高可用一般是指服务的可用度能够达到 n9 的可用度 (如: 99.999999%)
  2. 高可用需要解决的问题:单点故障,崩溃恢复......

K8s 可以在一定程度上解决单点故障和实现崩溃恢复,带有自动重启,自动扩 / 缩容 ( 根据压力来决定启动的服务器的数量 ) 等能力

什么是K8s

Kubernetes 是 Google 2014 年创建管理的,是 Google 10+ 年大规模`容器管理技术 Borg 的开源版本

Kubernetes 是容器编排系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能以期实现高可用。使用 Kubernetes 可以:

  • 快速部署应用
  • 快速扩展应用
  • 无缝对接新的应用功能
  • 节省资源,优化硬件资源的使用

Kubernetes 的目标是促进完善组件和工具的生态系统,以减轻应用程序在公有云或私有云中运行的负担

特点:

  • 可移植: 支持公有云,私有云,混合云,多重云(多个公共云)
  • 可扩展: 模块化,插件化,可挂载,可组合
  • 自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展

为什么使用 K8s?

可以在物理或虚拟机的 K8s 集群上运行容器化应用,K8s 能提供一个以 “容器为中心的基础架构”,满足在生产环境中运行应用的一些常见需求,如:

  • 多个进程协同工作
  • 存储系统挂载
  • 应用健康检查
  • 应用实例的复制
  • 自动伸缩/扩展
  • 注册与发现
  • 负载均衡
  • 滚动更新
  • 资源监控
  • 日志访问
  • 调试应用程序
  • 提供认证和授权

安装准备

采用 Ubuntu Server X64 18.04 LTS 版本安装 kubernetes 集群环境,集群节点为 1 主 3 从 + 网络卷模式

  • OS:Ubuntu Server X64 18.04 LTS(16.04 版本步骤相同,再之前则不同)
  • CPU:最低要求,1 CPU 2 核
  • 内存:最低要求,4 GB
  • 磁盘:最低要求,40 GB

节点如下

主机名 IP 角色 系统 CPU/内存 磁盘
kubernetes-master 192.168.224.190 Master Ubuntu Server 18.04 2 核 4G 40G
kubernetes-node1 192.168.224.201 Node Ubuntu Server 18.04 2 核 4G 40G
kubernetes-node2 192.168.224.202 Node Ubuntu Server 18.04 2 核 4G 40G
kubernetes-node3 192.168.224.203 Node Ubuntu Server 18.04 2 核 4G 40G
kubernetes-volumes 192.168.224.230 NFS Ubuntu Server 18.04 2 核 4G 160G

虚拟化引擎运作在 node 结点上,master 节点负责下发指令

制作基础镜像 (统一环境配置)

基于只有基础配置的镜像,克隆一个 K8s 的镜像,作为 K8s 的基础镜像

  1. 关闭交换空间
  1. swapoff -a
  1. 避免开机启动交换空间
  1. vi /etc/fstab

注释掉 K8s - 图1

  1. 关闭防火墙
  1. ufw disable
  1. 配置 DNS
  1. # 取消 DNS 行注释,并增加 DNS 配置如:114.114.114.114,修改后重启
  2. vi /etc/systemd/resolved.conf

K8s - 图2

  1. 安装 docker
  1. apt-get update
  2. apt install docker.io

配置 docker 加速器

前往阿里云控制台,搜索容器镜像服务

K8s - 图3

修改 daemon 配置文件

  1. vi /etc/docker/daemon.json

为如下

  1. {
  2. "exec-opts": ["native.cgroupdriver=systemd"],
  3. "log-driver": "json-file",
  4. "log-opts": {
  5. "max-size": "100m"
  6. },
  7. "registry-mirrors": [
  8. "https://9b35jrsu.mirror.aliyuncs.com/",
  9. "https://dockerhub.azk8s.cn"
  10. ],
  11. "storage-driver": "overlay2"
  12. }

然后重启 docker

  1. systemctl daemon-reload
  2. systemctl restart docker

然后使用

  1. docker info

验证是否配置成功

K8s - 图4

安装 K8s 必备工具

安装三个 Kubernetes 必备工具,分别为 kubeadmkubeletkubectl

  1. # 安装系统工具
  2. apt-get update && apt-get install -y apt-transport-https
  3. # 安装 GPG 证书
  4. curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
  5. # 写入软件源;注意:我们用系统代号为 bionic,但目前阿里云不支持,所以沿用 16.04 的 xenial,16.04 和 18.04的内核无差别,可以使用
  6. cat << EOF >/etc/apt/sources.list.d/kubernetes.list
  7. deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
  8. EOF
  9. # 安装
  10. apt-get update && apt-get install -y kubelet=1.17.3-00 kubeadm=1.17.3-00 kubectl=1.17.3-00

同步时区

  1. dpkg-reconfigure tzdata

选择 亚洲->上海

K8s - 图5

K8s - 图6

  1. # 安装 ntpdate
  2. apt-get install ntpdate
  3. # 设置系统时间与网络时间同步(cn.pool.ntp.org 位于中国的公共 NTP 服务器)
  4. ntpdate cn.pool.ntp.org
  5. # 将系统时间写入硬件时间
  6. hwclock --systohc

测试

  1. date

K8s - 图7

修改 cloud.cfg

防止重启后主机名还原

  1. vi /etc/cloud/cloud.cfg
  2. # 该配置默认为 false,修改为 true 即可
  3. preserve_hostname: true

K8s - 图8

至此,K8s 的基础镜像配置完成,接下来 master 节点和 node 节点这些就会在克隆这个镜像的基础上进行扩展

每个节点的单独配置

节点的单独配置指的是为 Master 和 Node 节点单独配置对应的 IP 和 主机名

配置 IP

每个结点都编辑 vi /etc/netplan/50-cloud-init.yaml 配置文件,修改内容如下,不要重复 ip

  1. network:
  2. ethernets:
  3. ens33:
  4. addresses: [192.168.224.202/24]
  5. gateway4: 192.168.224.2
  6. nameservers:
  7. addresses: [192.168.224.202]
  8. version: 2

gateway4 为 VMware 中的设置

K8s - 图9

然后使用命令 netplan apply 使配置生效,然后会断开连接,再次重新连接到 192.168.224.200 即可

配置主机名

  1. # 修改主机名
  2. hostnamectl set-hostname kubernetes-node1
  3. # 配置 hosts
  4. cat >> /etc/hosts << EOF
  5. 192.168.224.202 kubernetes-node2
  6. EOF

配置完成后,打开 master,node1,node2,node3 打开

K8s 安装集群

kubeadm 是 K8s的集群安装工具,能够快速安装 kubernetes 集群,安装 kubernetes 主要是安装它的各个镜像,而 kubeadm 已经为我们集成好了运行 kubernetes 所需的基本镜像。但由于国内的网络原因,在搭建环境时,无法拉取到这些镜像。此时需要修改为阿里云提供的镜像服务

master 节点 usr/local 目录下,创建 k8s 目录

再创建一个 cluster 目录,最后路径如下

K8s - 图10

  1. 导出并修改配置
  1. # 导出配置文件
  2. kubeadm config print init-defaults --kubeconfig ClusterConfiguration > kubeadm.yml

修改配置文件

  1. apiVersion: kubeadm.k8s.io/v1beta2
  2. bootstrapTokens:
  3. - groups:
  4. - system:bootstrappers:kubeadm:default-node-token
  5. token: abcdef.0123456789abcdef
  6. ttl: 24h0m0s
  7. usages:
  8. - signing
  9. - authentication
  10. kind: InitConfiguration
  11. localAPIEndpoint:
  12. # 修改为master IP
  13. advertiseAddress: 192.168.224.190
  14. bindPort: 6443
  15. nodeRegistration:
  16. criSocket: /var/run/dockershim.sock
  17. name: kubernetes-master
  18. taints:
  19. - effect: NoSchedule
  20. key: node-role.kubernetes.io/master
  21. ---
  22. apiServer:
  23. timeoutForControlPlane: 4m0s
  24. apiVersion: kubeadm.k8s.io/v1beta2
  25. certificatesDir: /etc/kubernetes/pki
  26. clusterName: kubernetes
  27. controllerManager: {}
  28. dns:
  29. type: CoreDNS
  30. etcd:
  31. local:
  32. dataDir: /var/lib/etcd
  33. # 国内不能访问 Google,修改为阿里云
  34. imageRepository: registry.aliyuncs.com/google_containers
  35. kind: ClusterConfiguration
  36. # 修改版本号
  37. kubernetesVersion: v1.17.3
  38. networking:
  39. dnsDomain: cluster.local
  40. # 配置 POD 所在网段为我们虚拟机不重叠的网段(这里用的是 Flannel 默认网段)
  41. podSubnet: "10.244.0.0/16"
  42. serviceSubnet: 10.96.0.0/12
  43. scheduler: {}
  1. 查看所需镜像
  1. kubeadm config images list --config kubeadm.yml
  1. 拉取所需镜像
  1. kubeadm config images pull --config kubeadm.yml

镜像作用分别为:

  • kube-apiserve:api网关
  • kube-controller-manager:自动重启,pod
  • kube-secheduler:调度中心,分压,水平扩展
  • kube-proxy:代理,外网访问内网节点
  • pause:与容器的启动和运行有关系
  • etcd:服务注册与发现
  • coredns:主机名到 ip 的域名解析服务

安装 master(主) 节点

执行以下命令初始化主节点,该命令指定了初始化时需要使用的配置文件,其中添加 --upload-certs 参数可以在后续执行加入节点时自动分发证书文件。追加的 tee kubeadm-init.log 用以输出日志。

注意: 如果安装 k8s 版本和下载的镜像版本不统一则会出现 timed out waiting for the condition 错误。中途失败或是想修改配置可以使用 kubeadm reset 命令重置配置,再做初始化操作即可

  1. kubeadm init --config=kubeadm.yml --upload-certs | tee kubeadm-init.log

安装完成后,最下面有如下提示

K8s - 图11

这就是集群的安装过程,跟着安装过程走即可

配置 kubectl

  1. mkdir -p $HOME/.kube
  2. cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  3. # 非 ROOT 用户执行
  4. chown $(id -u):$(id -g) $HOME/.kube/config

验证是否成功

  1. kubectl get node

K8s - 图12

出现该提示表示配置成功

安装从节点

使用的基础镜像已经安装过了 kubeadm,kubectl,kubelet,所有安装主节点时日志的最后一句命令加入集群即可

  1. kubeadm join 192.168.224.190:6443 --token d22vtk.a8z39aakg5kwxeod \
  2. --discovery-token-ca-cert-hash sha256:ca5f033999eedd36f3c87d8a291e8d0218099174a1443316dcca952648fd060a

验证

回到主节点,运行

  1. kubectl get nodes

K8s - 图13

status 为 notready 代表没有互通,所以接下来需要配置网络

配置网络

容器网络是容器选择连接到其他容器、主机和外部网络的机制。容器的 runtime 提供了各种网络模式,每种模式都会产生不同的体验。eg,Docker 默认情况下可以为容器配置以下网络:

  • none: 将容器添加到一个容器专门的网络堆栈中,没有对外连接。
  • host: 将容器添加到主机的网络堆栈中,没有隔离。
  • default bridge: 默认网络模式。每个容器可以通过 IP 地址相互连接。
  • 自定义网桥: 用户定义的网桥,具有更多的灵活性、隔离性和其他便利功能

CNI 容器网络接口

CNI(Container Network Interface) 是一个标准的,通用的接口。在容器平台,Docker,Kubernetes,Mesos 容器网络解决方案 flannel,calico,weave。只要提供一个标准的接口,就能为同样满足该协议的所有容器平台提供网络功能,而 CNI 正是这样的一个标准接口协议

K8s - 图14

POD 是K8S管理的最小单位级,它是一个或多个容器的组合。这些容器共享存储、网络和命名空间,以及如何运行的规范

K8s 的 CNI 插件

CNI 的初衷是创建一个框架,用于在配置或销毁容器时动态配置适当的网络配置和资源。插件负责为接口配置和管理 IP 地址,并且通常提供与 IP 管理、每个容器的 IP 分配、以及多主机连接相关的功能。容器运行时会调用网络插件,从而在容器启动时分配 IP 地址并配置网络,并在删除容器时再次调用它以清理这些资源。

运行时或协调器决定了容器应该加入哪个网络以及它需要调用哪个插件。然后,插件会将接口添加到容器网络命名空间中,作为一个 veth 对的一侧。接着,它会在主机上进行更改,包括将 veth 的其他部分连接到网桥。再之后,它会通过调用单独的 IPAM(IP地址管理)插件来分配 IP 地址并设置路由。

在 K8s 中,kubelet 可以在适当的时间调用它找到的插件,为通过 kubelet 启动的 POD 进行自动的网络配置。

K8s 中可选的 CNI 插件如下:

  • Flannel
  • Calico
  • Canal
  • Weave

这里我们选择 Calico

Calico

Calico 为容器和虚拟机提供了安全的网络连接解决方案,并经过大规模生产验证(在公有云和跨数千个集群节点中),可与 K8s,OpenShift,Docker,Mesos,DC / OS 和 OpenStack 集成。

Calico 还提供网络安全规则的动态实施。使用 Calico 的简单策略语言,可以实现对容器,虚拟机工作负载和裸机主机端点之间通信的细粒度控制

  1. 下载 Calico 并修改配置文件
  1. wget https://docs.projectcalico.org/manifests/calico.yaml
  1. vi calico.yaml

找到第 676 行 (根据版本不同,行号可能不同),去掉注释,修改 192.168.0.0/1610.244.0.0/16 (该 ip 同 kubeadm.yml 中的 pobSubet 的值 )

K8s - 图15

  1. 安装 Calico
  1. kubectl apply -f calico.yaml
  1. 验证
  1. watch kubectl get pods --all-namespaces

K8s - 图16

全部处于 running 即可 (可能需要稍微等一会儿)

  1. kubectl get nodes

K8s - 图17

全部处于 ready 即可 (可能需要稍微等一会儿)

K8s 容器部署

常用命令

  • 检查组件运行状态
  1. kubectl get cs
  • 检查 Master 节点状态
  1. kubectl cluster-info
  • 检查 node 状态
  1. kubectl get nodes
  1. 运行第一个容器实例
  1. # 使用 kubectl 命令创建两个监听 80 端口的 Nginx Pod(pod 是 K8s 运行容器的最小单元)
  2. kubectl run nginx --image=nginx --replicas=2 --port=80

pod:用于运行容器,可以运行一组容器,运行容器的最小单元

deployment:部署 pod

注意,在 K8s 1.8.x 中及之后,—replicas 参数已经被废弃掉了

  1. 验证

查看 pod 状态

  1. kubectl get pods

K8s - 图18

查看部署的服务

  1. kubectl get deployment

K8s - 图19

因为部署只是部署在 k8s 的内网中,因此要将服务暴露出去

  1. 发布服务 (暴露端口)
  1. # 使用负载均衡模式发布服务,让用户可以访问
  2. kubectl expose deployment nginx --port=80 --type=LoadBalancer

K8s - 图20

  1. 查看已发布服务
  1. kubectl get services

K8s - 图21

查看服务详情

  1. kubectl describe service nginx
  1. 验证是否成功

访问 node 的 ip + 暴露出去的端口号 32008

http://192.168.224.201:32008/

K8s - 图22

即成功

  1. 停止服务

删除已部署服务

  1. kubectl delete deployment nginx

删除已发布服务

  1. kubectl delete service nginx

容器运行与崩溃恢复

注意 :master 结点上不会运行 nginx,而是 master 将 nginx 镜像分发到 node 节点上,然后在 node 上运行容器;当删掉 node 上的 nginx 后,master 会在很短的时间内再次分发镜像到 node 上,并重启容器

在 master 上删除服务的同时会把 node 上的容器同时删除

K8s 概念总结

K8s 是一个开源的 Docker 容器编排系统,它可以调度计算集群的节点,动态管理上面的作业,保证它们按用户期望的状态运行。通过使用「labels」和「pods」的概念,K8s 将应用按逻辑单元进行分组,方便服务管理和服务发现

K8s - 图23

  • pods: 是一组紧密关联的容器集合,它们共享 IPC(进程间通信)、Network(网络) 和 UTS namespace(UTS 命名空间是 Linux 命名空间的一个子系统,主要作用是完成对容器 Hostname 和 Domain 的隔离,同时保存内核名称、版本、以及底层体系结构类型等信息),是 K8s 调度的基本单位。
  • labels: 键值对(key/value)标签,可以被关联到如 Pod 这样的对象上,主要作用是给用户一个直观的感受,比如这个 Pod 是用来放置数据库的
  • Job:临时任务,负责处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。而CronJob则就是在Job上加上了时间调度
  • GUI: 用户图形界面,可以是 Web 用户界面,比如使用 kubernetes-dashboard 组件,用户可以通过 Dashboard 在 K8s 集群中部署容器化的应用,可以查看集群中应用的运行情况,同时也能够基于 Dashboard 创建或修改部署、任务、服务等 Kubernetes 的资源。通过部署向导,用户能够对部署进行扩缩容,进行滚动更新、重启 Pod 和部署新应用。当然,通过 Dashboard 也能够查看 K8s 资源的状态
  • kubectl: 用于管理 K8s 集群的命令行工具
  • kube-apiserver: 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制
  • Kubernetes Master: Kubernetes 集群主节点,主要由 kube-apiserverkube-schedulerkube-controller-manageretcd 四个模块组成
  • Kubernetes Node: Kubernetes 集群子节点,主要由 kubeletkube-proxyruntime 三个模块组成
  • Image Registry: 镜像仓库,比如:Ducker HUB 或 Docker 私服

K8s Master

  • kube-apiserver: 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制
  • kube-scheduler: 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上
  • kube-controller-manager: 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等
  • etcd: CoreOS 基于 Raft 开发的分布式 key-value 存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)

K8s Node

  • runtime: 负责镜像管理以及 Pod 和容器的真正运行(CRI,Container Runtime Interface),默认的容器运行时为 Docker,还支持 RKT 容器
  • kubelet: 负责维持容器的生命周期,同时也负责 Volume(CVI,Container Volume Interface)和网络(CNI,Container Network Interface)的管理
  • kube-proxy: 负责为 Service 提供 cluster 内部的服务发现和负载均衡

K8s 架构

K8s - 图24

K8s - 图25

K8s 资源配置文件启动

类似于 docker-compsoe ,可以不用 run 命令来运行容器。而 K8s 则是使用 kubectl apply 来运行配置文件做到和 docker-compose 一样的效果

  1. 在和 cluster 同级下创建一个 service 目录,进入 service 目录

  2. Deployment 部署的配置

创建一个 nginx.yml 文件

  1. # API 版本号
  2. apiVersion: apps/v1
  3. # 类型,如:Pod/ReplicationController/Deployment/Service/Ingress
  4. kind: Deployment
  5. metadata:
  6. # Kind 的名称
  7. name: nginx-app
  8. spec:
  9. selector:
  10. matchLabels:
  11. # 容器标签的名字,发布 Service 时,selector 需要和这里对应
  12. app: nginx
  13. # 部署的实例数量
  14. replicas: 3
  15. template:
  16. metadata:
  17. labels:
  18. app: nginx
  19. spec:
  20. # 配置容器,数组类型,说明可以配置多个容器
  21. containers:
  22. # 容器名称
  23. - name: nginx
  24. # 容器镜像
  25. image: nginx:1.17
  26. #镜像拉取策略,只有镜像不存在时,才会进行镜像拉取
  27. imagePullPolicy: IfNotPresent
  28. ports:
  29. # Pod 端口
  30. - containerPort: 80

镜像拉取策略

支持三种 ImagePullPolicy

  • Always: 不管镜像是否存在都会进行一次拉取
  • Never: 不管镜像是否存在都不会进行拉取
  • IfNotPresent: 只有镜像不存在时,才会进行镜像拉取

注意

  • 默认为 IfNotPresent,但 :latest 标签的镜像默认为 Always
  • 拉取镜像时 Docker 会进行校验,如果镜像中的 MD5 码没有变,则不会拉取镜像数据
  • 生产环境中应该尽量避免使用 :latest 标签,而开发环境中可以借助 :latest 标签自动拉取最新的镜像
  1. 发布 (暴露端口) 的配置

追加在上面的 nginx.yml 下

  1. # 不要忘记这里的三条横线
  2. ---
  3. # API 版本号
  4. apiVersion: v1
  5. # 类型,如:Pod/ReplicationController/Deployment/Service/Ingress
  6. kind: Service
  7. # 元数据
  8. metadata:
  9. # Kind 的名称
  10. name: nginx-http
  11. spec:
  12. # 暴露端口
  13. ports:
  14. # Service 暴露的端口
  15. - port: 80
  16. # Pod 上的端口,这里是将 Service 暴露的端口转发到 Pod 端口上
  17. targetPort: 9001
  18. # 类型
  19. type: LoadBalancer
  20. # 标签选择器
  21. selector:
  22. # 需要和上面部署的 Deployment 标签名对应
  23. app: nginx
  1. 部署和删除
  1. # 部署
  2. kubectl apply -f nginx.yml
  3. # 删除
  4. kubectl delete -f nginx.yml
  1. 验证是否成功
  1. kubectl get service

K8s - 图26

访问3台 node 中的任意一台,这里访问

http://192.168.224.203:30439/

出现

K8s - 图27

即成功

K8s Ingress 集群入口

K8s - 图28

术语

  • 节点: Kubernetes 集群中的服务器
  • 集群: Kubernetes 管理的一组服务器集合
  • 边界路由器: 为局域网和 Internet 路由数据包的路由器,执行防火墙保护局域网络
  • 集群网络: 遵循 Kubernetes 网络模型实现集群内的通信的具体实现,比如 Flannel 和 Calico
  • 服务: Kubernetes 的服务 (Service) 是使用标签选择器标识的一组 Pod Service (Deployment)。 除非另有说明,否则服务的虚拟 IP 仅可在集群内部访问,因此才需要统一的入口

服务访问方式

内部访问方式 ClusterIP

ClusterIP 服务是 Kubernetes 的默认服务。它给你一个集群内的服务,集群内的其它应用都可以访问该服务。集群外部无法访问它。在某些场景下我们可以使用 Kubernetes 的 Proxy 模式来访问服务,比如调试服务时

K8s - 图29

三种外部访问方式

NodePort

NodePort 服务是引导外部流量到你的服务的最原始方式。NodePort,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务

NodePort 服务特征如下:

  • 每个端口只能是一种服务
  • 端口范围只能是 30000-32767(可调)
  • 不在 YAML 配置文件中指定则会分配一个默认端口

建议不要在生产环境中使用这种方式暴露服务,大多数时候应该让 K8s 来选择端口

K8s - 图30

LoadBalance

LoadBalancer 服务是暴露服务到 Internet 的标准方式。所有通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,WebSocket,gRPC 或其它任意种类

K8s - 图31

Ingress

Ingress 事实上不是一种服务类型。相反,它处于多个服务的前端,扮演着 “智能路由” 或者集群入口的角色。你可以用 Ingress 来做许多不同的事情,各种不同类型的 Ingress 控制器也有不同的能力。它允许你基于路径或者子域名来路由流量到后端服务。

Ingress 可能是暴露服务的最强大方式,但同时也是最复杂的。Ingress 控制器有各种类型,包括 Google Cloud LoadBalancer, Nginx,Contour,Istio,等等。它还有各种插件,比如 cert-manager (它可以为你的服务自动提供 SSL 证书)/

如果你想要使用同一个 IP 暴露多个服务,这些服务都是使用相同的七层协议(典型如 HTTP),你还可以获取各种开箱即用的特性(比如 SSL、认证、路由等等)

K8s - 图32

什么是 Ingress

通常情况下,Service 和 Pod 的 IP 仅可在集群内部访问。集群外部的请求需要通过负载均衡转发到 Service 在 Node 上暴露的 NodePort 上,然后再由 kube-proxy 通过边缘路由器 (edge router) 将其转发给相关的 Pod 或者丢弃。而 Ingress 就是为进入集群的请求提供路由规则的集合

Ingress 可以给 Service 提供集群外部访问的 URL、负载均衡、SSL 终止、HTTP 路由等。为了配置这些 Ingress 规则,集群管理员需要部署一个 Ingress Controller,它监听 Ingress 和 Service 的变化,并根据规则配置负载均衡并提供访问入口。

Ingress 是外网与内网通信的桥梁,对外 rest,所以 Ingress 对外应该是作为 HTTP 服务器提供 HTTP 服务,而绝大多数情况下选择 Nginx

Nginx

Nginx 是一款高性能的 HTTP 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师 Igor Sysoev 所开发,官方测试 Nginx 能够支支撑 5 万并发链接,并且 CPU、内存等资源消耗却非常低,运行非常稳定

Nginx 的应用场景

  • HTTP 服务器:Nginx 可以独立提供 HTTP 服务。可以做网页静态服务器
  • 虚拟主机:可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机
  • 反向代理,负载均衡:当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用 Nginx 做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况

Nginx 虚拟主机

什么是虚拟主机

虚拟主机是一种特殊的软硬件技术,它可以将网络上的每一台计算机分成多个虚拟主机,每个虚拟主机可以独立对外提供 www 服务,这样就可以实现一台主机对外提供多个 web 服务。每个虚拟主机之间是独立的,互不影响的

通过 Nginx 可以实现虚拟主机的配置,Nginx 支持三种类型的虚拟主机配置

  • 基于 IP 的虚拟主机
  • 基于域名的虚拟主机 ( 把提供服务的目录虚拟成不同的域名 )
  • 基于端口的虚拟主机

基于 Docker 部署 Nginx

到其中一台 node 服务器上 (这里以 node1 为例),到 /usr/local 中创建目录如下

K8s - 图33

  1. 创建 docker-compose.yml ,内容如下
  1. version: '3.1'
  2. services:
  3. nginx:
  4. restart: always
  5. image: nginx
  6. container_name: nginx
  7. ports:
  8. #左边暴露出去的端口,右边 nginx 监听端口
  9. - 80:80
  10. - 8080:8080
  11. volumes:
  12. - ./conf/nginx.conf:/etc/nginx/nginx.conf
  13. - ./html:/usr/share/nginx/html

docker-compose 会自动创建目录,但不会自动创建文件,因此在当前目录 ( nginx ) 下创建目录 conf,在 conf 中创建 nginx 的配置文件 nginx.conf

先了解下 Nginx 配置文件的结构

  1. # ...
  2. events {
  3. # ...
  4. }
  5. http {
  6. # ...
  7. server{
  8. # ...
  9. }
  10. # ...
  11. server{
  12. # ...
  13. }
  14. }

一个 server 代表一个虚拟主机

Nginx 虚拟主机

基于 IP 配置虚拟主机

需求:

  • Nginx 对外提供 80 和 8080 两个端口,监听服务
  • 请求 80 端口则请求 html80 目录下的 html
  • 请求 8080 端口则请求 html8080 目录下的html

先创建目录及文件。在 niginx ( conf 同级目录 ) 下创建目录 html,再在 html 目录下创建目录 html80 和 html8080,并创建两个 index.html 文件,并在不同的文件中写不同的内容

配置 conf 目录下的 nginx.conf

  1. # 启动进程,通常设置成和 CPU 的数量相等
  2. worker_processes 1;
  3. events {
  4. # epoll 是多路复用 IO(I/O Multiplexing) 中的一种方式
  5. # 但是仅用于 linux2.6 以上内核,可以大大提高 nginx 的性能
  6. use epoll;
  7. # 单个后台 worker process 进程的最大并发链接数
  8. worker_connections 1024;
  9. }
  10. http {
  11. # 设定 mime 类型,类型由 mime.type 文件定义
  12. include mime.types;
  13. default_type application/octet-stream;
  14. # sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,
  15. # 必须设为 on,如果用来进行下载等应用磁盘 IO 重负载应用,可设置为 off,以平衡磁盘与网络 I/O 处理速度,降低系统的 uptime.
  16. sendfile on;
  17. # 连接超时时间
  18. keepalive_timeout 65;
  19. # 设定请求缓冲
  20. client_header_buffer_size 2k;
  21. # 配置虚拟主机 192.168.141.121
  22. server {
  23. # 监听的 IP 和端口,配置 192.168.224.201:80
  24. listen 80;
  25. # 虚拟主机名称这里配置 IP 地址 (宿主机IP)
  26. server_name 192.168.224.201;
  27. # 所有的请求都以 / 开始,所有的请求都可以匹配此 location
  28. location / {
  29. # 使用 root 指令指定虚拟主机目录即网页存放目录
  30. # 比如访问 http://ip/index.html 将找到 /usr/local/docker/nginx/html/html80/index.html
  31. # 比如访问 http://ip/item/index.html 将找到 /usr/local/docker/nginx/html/html80/item/index.html
  32. #这个 root 目录中 /usr/share/nginx/html 是指定的容器内数据卷位置,dockerCompose 中映射到了 ./html ,所以 /usr/share/nginx/html/html80 就代表宿主机上的 ./html/html80 目录
  33. root /usr/share/nginx/html/html80;
  34. # 指定欢迎页面,按从左到右顺序查找
  35. index index.html index.htm;
  36. }
  37. }
  38. # 配置虚拟主机 192.168.224.201
  39. server {
  40. listen 8080;
  41. server_name 192.168.224.201;
  42. location / {
  43. root /usr/share/nginx/html/html8080;
  44. index index.html index.htm;
  45. }
  46. }
  47. }
  1. 测试

访问 http://192.168.224.201:80

K8s - 图34

访问 http://192.168.224.201:8080

K8s - 图35

基于域名配置虚拟主机

需求

  • 两个域名指向同一台 Nginx 服务器,用户访问不同的域名显示不同的网页内容
  • 两个域名是 ingress.antigenmhc.cn 和 service.antigenmhc.cn
  • Nginx 服务器使用虚拟机 192.168.224.201

配置流程

  1. 配置虚拟主机,修改 nginx.conf
  1. user nginx;
  2. worker_processes 1;
  3. events {
  4. use epoll;
  5. worker_connections 1024;
  6. }
  7. http {
  8. include mime.types;
  9. default_type application/octet-stream;
  10. sendfile on;
  11. keepalive_timeout 65;
  12. server {
  13. listen 80;
  14. server_name service1.antigenmhc.cn;
  15. location / {
  16. root /usr/share/nginx/html/service1;
  17. index index.html index.htm;
  18. }
  19. }
  20. server {
  21. listen 80;
  22. server_name service2.antigenmhc.cn;
  23. location / {
  24. root /usr/share/nginx/html/service2;
  25. index index.html index.htm;
  26. }
  27. }
  28. }
  1. 在 /usr/share/nginx/html 下创建 service1 和 service2 目录,并分别创建两个 index.html 文件

  2. 在主机上配置 hosts,通过 hosts 指定 service2.antigenmhc.cn 和 service1.antigenmhc.cn 域名对应 192.168.224.201 虚拟机。hosts 文件位于 C:\Windows\System32\drivers\etc

  3. 测试

访问 http://service1.antigenmhc.cn/

K8s - 图36

访问 http://service2.antigenmhc.cn/

K8s - 图37

Nginx 反向代理

代理服务器

代理服务器,客户机在发送请求时,不会直接发送给目的主机,而是先发送给代理服务器,代理服务接受客户机请求之后,再向主机发出,并接收目的主机返回的数据,存放在代理服务器的硬盘中,再发送给客户机

K8s - 图38

正向代理

正向代理,需要一个位于客户端和原始服务器 (目标服务器) 之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标 (原始服务器) ,然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理

K8s - 图39

反向代理

反向代理服务器架设在服务器端,通过缓冲经常被请求的页面来缓解服务器的工作量,将客户机请求转发给内部网络上的目标服务器;以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器和 web 服务器对外就表现为一个服务器

K8s - 图40

通过 Nginx 反向代理 Tomcat

需求

  • 两个 Tomcat 服务通过 Nginx 反向代理
  • Nginx 服务器:192.168.224.201:80
  • Tomcat1 服务器:192.168.224.201:8081
  • Tomcat2 服务器:192.168.224.201:8082
  1. 构建 tomcat 的 docker-compose

在和 nginx 同级的目录下 ( /usr/local/docker/ ) 创建 tomcat 目录,进入 tomcat 目录下,编写 docker-compose,并启动运行

  1. version: '3.1'
  2. services:
  3. tomcat1:
  4. image: tomcat:8.5.37
  5. container_name: tomcat1
  6. ports:
  7. - 8081:8080
  8. tomcat2:
  9. image: tomcat:8.5.37
  10. container_name: tomcat2
  11. ports:
  12. - 8082:8080
  1. 修改 nginx.conf 配置文件
  1. user nginx;
  2. worker_processes 1;
  3. events {
  4. use epoll;
  5. worker_connections 1024;
  6. }
  7. http {
  8. include mime.types;
  9. default_type application/octet-stream;
  10. sendfile on;
  11. keepalive_timeout 65;
  12. # 配置一个代理即 tomcat1 服务器
  13. upstream tomcatServer1 {
  14. server 192.168.224.201:8081;
  15. }
  16. # 配置一个代理即 tomcat2 服务器
  17. upstream tomcatServer2 {
  18. server 192.168.224.201:8082;
  19. }
  20. # 配置一个虚拟主机
  21. server {
  22. listen 80;
  23. server_name service1.antigenmhc.cn;
  24. location / {
  25. # 域名 service1.funtl.com 的请求全部转发到 tomcatServer1 即 tomcat1 服务上
  26. proxy_pass http://tomcatServer1;
  27. # 欢迎页面,按照从左到右的顺序查找页面
  28. index index.jsp index.html index.htm;
  29. }
  30. }
  31. server {
  32. listen 80;
  33. server_name service2.antigenmhc.cn;
  34. location / {
  35. # 域名 service2.antigenmhc.cn 的请求全部转发到 tomcatServer2 即 tomcat2 服务上
  36. proxy_pass http://tomcatServer2;
  37. index index.jsp index.html index.htm;
  38. }
  39. }
  40. }
  1. 测试

访问 http://service2.antigenmhc.cn/

K8s - 图41

访问 http://service1.antigenmhc.cn/

K8s - 图42

Nginx 负载均衡

负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

负载均衡,英文名称为 Load Balance,其意思就是分摊到多个操作单元上进行执行,例如 Web 服务器、FTP 服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务

实现负载均衡

Nginx 作为负载均衡服务器,用户请求先到达 Nginx,再由 Nginx 根据负载配置将请求转发至 tomcat 服务器

  1. 修改 Nginx 配置文件为如下
  1. user nginx;
  2. worker_processes 1;
  3. events {
  4. use epoll;
  5. worker_connections 1024;
  6. }
  7. http {
  8. include mime.types;
  9. default_type application/octet-stream;
  10. sendfile on;
  11. keepalive_timeout 65;
  12. upstream myapp1 {
  13. server 192.168.224.201:8081 weight=10;
  14. server 192.168.224.201:8082 weight=10;
  15. }
  16. server {
  17. listen 80;
  18. server_name nginx.antigenmhc.cn;
  19. location / {
  20. proxy_pass http://myapp1;
  21. index index.jsp index.html index.htm;
  22. }
  23. }
  24. }

重启 Nginx 容器,在 hosts 文件中增加配置

  1. 192.168.224.201 nginx.antigenmhc.cn

负载均衡配置说明

假设有如下的一个负载均衡配置

  1. upstream myServer {
  2. server 127.0.0.1:9090 down;
  3. server 127.0.0.1:8080 weight=2;
  4. server 127.0.0.1:6060;
  5. server 127.0.0.1:7070 backup;
  6. }

在需要负载均衡的 server 节点上增加配置

  1. proxy_pass http://myServer;

其中配置属性说明如下

  • upstream:每个设备的状态:
  • down:表示当前的 server 暂时不参与负载
  • weight:默认为 1 weight 越大,负载的权重就越大。
  • max_fails:允许请求失败的次数默认为 1 当超过最大次数时,返回 proxy_next_upstream 模块定义的错误
  • fail_timeout:max_fails 次失败后,暂停的时间。
  • backup:其它所有的非 backup 机器 down 或者忙碌的时候,请求 backup 机器。所以这台机器压力会最轻
  1. 进入两个 tomcat 的容器进行操作,以便进行负载均衡的测试

修改 tomcat1

  1. docker exec -it tomcat1 /bin/bash
  2. cd webapps/ROOT/
  3. echo Hello Nginx >> index.jsp
  1. 测试

访问 http://nginx.antigenmhc.cn/,刷新测试

K8s - 图43

K8s - 图44

Nginx Ingress Controller

到 master 节点下,在 usr/local/k8s/ 目录下创建新目录 ingress

安装 Ingress

  1. 配置文件

去到 https://github.com/kubernetes/ingress-nginx/blob/nginx-0.29.0/deploy/static/mandatory.yaml 下,复制其内容,在 ingress 目录下创建文件 mandatory.yaml 配置文件,将上面的配置文件内容粘贴进去

  1. 修改配置文件

主要修改

  • 搜索 serviceAccountName,在下面增加一句 hostNetwork: true,意思是开启主机网络模式,暴露 Nginx 服务端口 80
  • 搜索 quay.io,将其改为 quay.mirrors.ustc.edu.cn
  1. 部署
  1. kubectl apply -f mandatory.yaml

查看

  1. kubectl get pods -n ingress-nginx -o wide

查看时,如果 STATUS 状态 K8s - 图45,检查 部署在的 NODE K8s - 图46 上是否运行了 nginx,如果运行了,将其停掉。回到主节点,停掉 mandatory.yaml,再次部署启动即可

查看状态如下,即部署成功

K8s - 图47

部署 Ingress

创建一个 ingress.yaml 文件

  1. apiVersion: networking.k8s.io/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: nginx-web
  5. annotations:
  6. # 指定 Ingress Controller 的类型
  7. kubernetes.io/ingress.class: "nginx"
  8. # 指定我们的 rules 的 path 可以使用正则表达式
  9. nginx.ingress.kubernetes.io/use-regex: "true"
  10. # 连接超时时间,默认为 5s
  11. nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
  12. # 后端服务器回转数据超时时间,默认为 60s
  13. nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
  14. # 后端服务器响应超时时间,默认为 60s
  15. nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
  16. # 客户端上传文件,最大大小,默认为 20m
  17. nginx.ingress.kubernetes.io/proxy-body-size: "10m"
  18. # URL 重写
  19. nginx.ingress.kubernetes.io/rewrite-target: /
  20. spec:
  21. # 路由规则
  22. rules:
  23. # 主机名,只能是域名,修改为你自己的
  24. - host: k8s.antigenmhc.cn
  25. http:
  26. paths:
  27. - path:
  28. backend:
  29. # 后台部署的 Service Name
  30. serviceName: tomcat-http
  31. # 后台部署的 Service Port
  32. servicePort: 8080

部署 Tomcat

到 usr/local/k8s/service 目录下,创建 tomcat.yml 文件,进行 tomcat 的部署

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: tomcat-app
  5. spec:
  6. selector:
  7. matchLabels:
  8. # 容器标签的名字,发布 Service 时,selector 需要和这里对应
  9. app: tomcat
  10. replicas: 2
  11. template:
  12. metadata:
  13. labels:
  14. app: tomcat
  15. spec:
  16. containers:
  17. - name: tomcat
  18. image: tomcat:8.5.37
  19. imagePullPolicy: IfNotPresent
  20. ports:
  21. - containerPort: 8080
  22. ---
  23. apiVersion: v1
  24. kind: Service
  25. metadata:
  26. name: tomcat-http
  27. spec:
  28. ports:
  29. - port: 8080
  30. targetPort: 8080
  31. # ClusterIP, NodePort, LoadBalancer
  32. # ClusterIP 只对内网提供服务
  33. type: ClusterIP
  34. selector:
  35. app: tomcat

然后部署 启动

  1. kubectl apply -f tomcat.yml

接着去到 ingress 目录下,启动 ingress

  1. kubectl apply -f ingress.yaml

测试

  1. 查看 ingress 的部署
  1. kubectl get pods -n ingress-nginx -o wide

K8s - 图48

说明 ingress 部署在 192.168.224.201 上,入口也就在这

  1. 配置 hosts 文件,主机名就是 ingress.yaml 中的 k8s.antigenmhc.cn,IP 即部署了 ingress 的服务器 IP
  1. 192.168.224.201 k8s.antigenmhc.cn
  1. 访问 k8s.antigenmhc.cn,出现

K8s - 图49

K8s 数据卷

分布式文件系统

K8s - 图50

分布式文件系统是分布式架构中不可或缺的一环,作为存储不同节点上的服务所产生的数据而存在,保证了数据的安全性和可靠性

以部署 MySQL8 为例,采用 NFS + PV/PVC 网络存储方案实现我们的 Kubernetes 数据持久化

  • PV:持久卷
  • PVC:持久卷消费者

NFS

NFS 是 Network File System 的简写,即网络文件系统,NFS 是 FreeBSD 支持的文件系统中的一种。NFS 基于 RPC (Remote Procedure Call) 远程过程调用实现,其允许一个系统在网络上与它人共享目录和文件。通过使用 NFS,用户和程序就可以像访问本地文件一样访问远端系统上的文件。NFS 是一个非常稳定的,可移植的网络文件系统。具备可扩展和高性能等特性,达到了企业级应用质量标准。由于网络速度的增加和延迟的降低,NFS 系统一直是通过网络提供文件系统服务的有竞争力的选择

NFS原理

NFS 使用 RPC (Remote Procedure Call) 的机制进行实现,RPC 使得客户端可以调用服务端的函数。同时,由于有 VFS 的存在,客户端可以像使用其它普通文件系统一样使用 NFS 文件系统。经由操作系统的内核,将 NFS 文件系统的调用请求通过 TCP/IP 发送至服务端的 NFS 服务。NFS 服务器执行相关的操作,并将操作结果返回给客户端

K8s - 图51

NFS 主要进程

  • rpc.nfsd:最主要的 NFS 进程,管理客户端是否可登录
  • rpc.mountd:挂载和卸载 NFS 文件系统,包括权限管理
  • rpc.lockd:非必要,管理文件锁,避免同时写出错
  • rpc.statd:非必要,检查文件一致性,可修复文件

NFS 关键工具

  • 主要配置文件:/etc/exports
  • NFS 文件系统维护命令:/usr/bin/exportfs
  • 共享资源的日志文件:/var/lib/nfs/*tab
  • 客户端查询共享资源命令:/usr/sbin/showmount
  • 端口配置:/etc/sysconfig/nfs

准备数据卷

安装 NFS 服务端
  1. 创建一个共享文件目录
  1. mkdir -p /usr/local/kubernetes/volumes
  1. 给目录增加读写权限
  1. chmod a+rw /usr/local/kubernetes/volumes
  1. 安装 NFS 服务端
  1. apt-get update
  2. apt-get install -y nfs-kernel-server
  1. 配置 NFS 服务目录,打开文件 vi /etc/exports,在尾部新增一行,内容如下
    1. /usr/local/kubernetes/volumes *(rw,sync,no_subtree_check,no_root_squash)
  • /usr/local/kubernetes/volumes 作为服务目录向客户端开放
  • **表示任何 IP 都可以访问
  • rw: 读写权限
  • sync: 同步权限
  • no_subtree_check: 表示如果输出目录是一个子目录,NFS 服务器不检查其父目录的权限
  • no_root_squash: 客户端连接服务端时如果使用的是 root,那么也拥有对服务端分享的目录的 root 权限
    1. 重启服务
  1. /etc/init.d/nfs-kernel-server restart

安装 NFS 客户端

先安装在 volumes 服务器上,测试是否可以上传文件到服务端

  1. 下载 nfs-common
  1. apt-get install -y nfs-common
  1. 创建 NFS 客户端挂载目录
  1. mkdir -p /usr/local/kubernetes/volumes-mount
  1. 将 NFS 服务器的 /usr/local/kubernetes/volumes 目录挂载到 NFS 客户端的 /usr/local/kubernetes/volumes-mount 目录
  1. mount 192.168.224.230:/usr/local/kubernetes/volumes /usr/local/kubernetes/volumes-mount
  1. 取消挂载
  1. umount /usr/local/kubernetes/volumes-mount

注意: 不要直接在挂载目录下执行,否则会报错

  1. 使用 df 命令查看

K8s - 图52

验证 NFS 服务

到 volumes-mount 目录下 ( 相当于客户端下 ),测试文件上传

  1. ip addr > /usr/local/kubernetes/volumes-mount/test.txt

查看 volumes ( 服务端同步目录 ) 下是否有该文件,如果有,则表示成功

K8s - 图53

至此,数据卷准备完成

使用数据卷

存储管理与计算管理是两个不同的问题。Persistent Volume 子系统,对存储的供应和使用做了抽象,以 API 形式提供给管理员和用户使用。要完成这一任务,我们引入了两个新的 API 资源:Persistent Volume(持久卷)Persistent Volume Claim(持久卷消费者)

Persistent Volume(PV)是集群之中的一块网络存储。跟 Node 一样,也是集群的资源。PV 跟 Volume (卷) 类似,不过会有独立于 Pod 的生命周期。这一 API 对象包含了存储的实现细节,例如 NFS、iSCSI 或者其他的云提供商的存储系统。Persistent Volume Claim (PVC) 是用户的一个请求。跟 Pod 类似,Pod 消费 Node 的资源,PVC 消费 PV 的资源。Pod 能够申请特定的资源(CPU 和内存);Claim 能够请求特定的尺寸和访问模式(例如可以加载一个读写,以及多个只读实例)

PV 和 PVC

PV 是集群的资源。PVC 是对这一资源的请求,也是对资源的所有权的检验。PV 和 PVC 之间的互动遵循如下的生命周期。

  • 供应: 集群管理员会创建一系列的 PV。这些 PV 包含了为集群用户提供的真实存储资源,它们可利用 Kubernetes API 来消费
  • 绑定: 用户创建一个包含了容量和访问模式的持久卷申请。Master 会监听 PVC 的产生,并尝试根据请求内容查找匹配的 PV,并把 PV 和 PVC 进行绑定。用户能够获取满足需要的资源,并且在使用过程中可能超出请求数量。如果找不到合适的卷,这一申请就会持续处于非绑定状态,一直到出现合适的 PV。例如一个集群准备了很多的 50G 大小的持久卷,(虽然总量足够)也是无法响应 100G 的申请的,除非把 100G 的 PV 加入集群
  • 使用: Pod 把申请作为卷来使用。集群会通过 PVC 查找绑定的 PV,并 Mount 给 Pod。对于支持多种访问方式的卷,用户在使用 PVC 作为卷的时候,可以指定需要的访问方式。一旦用户拥有了一个已经绑定的 PVC,被绑定的 PV 就归该用户所有了。用户的 Pods 能够通过在 Pod 的卷中包含的 PVC 来访问他们占有的 PV
  • 释放: 当用户完成对卷的使用时,就可以利用 API 删除 PVC 对象了,而且他还可以重新申请。删除 PVC 后,对应的卷被视为 “被释放”,但是这时还不能给其他的 PVC 使用。之前的 PVC 数据还保存在卷中,要根据策略来进行后续处理
  • 回收: PV 的回收策略向集群阐述了在 PVC 释放卷的时候,应如何进行后续工作。目前可以采用三种策略:保留,回收或者删除。保留策略允许重新申请这一资源。在持久卷能够支持的情况下,删除策略会同时删除持久卷以及 AWS EBS/GCE PD 或者 Cinder 卷中的存储内容。如果插件能够支持,回收策略会执行基础的擦除操作(rm -rf /thevolume/*),这一卷就能被重新申请了

定义 PV

持久卷是以插件方式实现,这里基于 NFS 进行实现

  1. 配置文件

在 master 结点下的 usr/local/k8s/ 目录下创建一个目录 volumes,并在其中创建一个名为 nfs-pv-mysql.yaml 的配置文件

  1. apiVersion: v1
  2. kind: PersistentVolume
  3. metadata:
  4. name: nfs-pv-mysql
  5. spec:
  6. # 设置容量
  7. capacity:
  8. storage: 5Gi
  9. # 访问模式
  10. accessModes:
  11. # 该卷能够以读写模式被多个节点同时加载
  12. - ReadWriteMany
  13. # 回收策略,这里是基础擦除 `rm-rf/thevolume/*`
  14. persistentVolumeReclaimPolicy: Recycle
  15. nfs:
  16. # NFS 服务端配置的路径
  17. path: "/usr/local/kubernetes/volumes"
  18. # NFS 服务端地址
  19. server: 192.168.224.230
  20. readOnly: false
  1. # 部署
  2. kubectl apply -f nfs-pv-mysql.yaml
  3. # 删除
  4. kubectl delete -f nfs-pv-mysql.yaml
  5. # 查看
  6. kubectl get pv

K8s - 图54

配置说明

capacity (容量)

一般来说,PV 会指定存储容量。这里需要使用 PV 的 capcity 属性

AccessModes (访问模式)

只要资源提供者支持,持久卷能够被用任何方式加载到主机上。每种存储都会有不同的能力,每个 PV 的访问模式也会被设置成为该卷所支持的特定模式。例如 NFS 能够支持多个读写客户端,但是某个 NFS PV 可能会在服务器上以只读方式使用。每个 PV 都有自己的一系列的访问模式,这些访问模式取决于 PV 的能力。访问模式的可选范围如下

  • ReadWriteOnce: 该卷能够以读写模式被加载到一个节点上
  • ReadOnlyMany: 该卷能够以只读模式加载到多个节点上
  • ReadWriteMany: 该卷能够以读写模式被多个节点同时加载

在 CLI 下,访问模式缩写为:

  • RWO: ReadWriteOnce
  • ROX: ReadOnlyMany
  • RWX: ReadWriteMany

另外,一个卷不论支持多少种访问模式,同时只能以一种访问模式加载。例如一个 GCE Persistent Disk 既能支持 ReadWriteOnce,也能支持 ReadOnlyMany

RecyclingPolicy(回收策略)

当前的回收策略可选值包括:

  • Retain: 人工重新申请
  • Recycle: 基础擦除(rm-rf/thevolume/*
  • Delete: 相关的存储资产例如 AWS EBS,GCE PD 或者 OpenStack Cinder 卷一并删除

目前,只有 NFS 和 HostPath 支持 Recycle 策略,AWS EBS、GCE PD 以及 Cinder 卷支持 Delete 策略

阶段(Phase)

一个卷会处于如下阶段之一:

  • Available: 可用资源,尚未被绑定到 PVC 上
  • Bound: 该卷已经被绑定
  • Released: PVC 已经被删除,但该资源尚未被集群回收
  • Failed: 该卷的自动回收过程失败

定义 PVC

创建一个名为 nfs-pvc-mysql-blog.yaml 的配置文件

  1. apiVersion: v1
  2. kind: PersistentVolumeClaim
  3. metadata:
  4. # 以部署某个数据库为例
  5. name: nfs-pvc-mysql-blog
  6. spec:
  7. accessModes:
  8. # 需要使用和 PV 一致的访问模式
  9. - ReadWriteMany
  10. # 按需分配资源
  11. resources:
  12. requests:
  13. # 为blog 这个数据库单独分配 1G 空间
  14. storage: 1Gi
  1. # 部署
  2. kubectl apply -f nfs-pvc-mysql-blog.yaml
  3. # 删除
  4. kubectl delete -f nfs-pvc-mysql-blog.yaml
  5. # 查看
  6. kubectl get pvc

K8s - 图55

部署 MySQL8

先确保在所有 node 节点上安装 nfs-common

apt-get update

apt-get install -y nfs-common

在所有 node 节点上安装好 nfs-common 后,回到 master 节点上,进入 usr/local/k8s/service 目录下,创建 mysql-blog.yaml 的配置文件

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: mysql-blog
  5. spec:
  6. selector:
  7. matchLabels:
  8. app: mysql-blog
  9. replicas: 1
  10. template:
  11. metadata:
  12. labels:
  13. app: mysql-blog
  14. spec:
  15. containers:
  16. - name: mysql-blog
  17. image: mysql:8.0.16
  18. # 只有镜像不存在时,才会进行镜像拉取
  19. imagePullPolicy: IfNotPresent
  20. ports:
  21. - containerPort: 3306
  22. # 同 Docker 配置中的 environment
  23. env:
  24. - name: MYSQL_ROOT_PASSWORD
  25. value: "123456"
  26. # 容器中的挂载目录
  27. volumeMounts:
  28. - name: nfs-vol-blog
  29. mountPath: /var/lib/mysql
  30. volumes:
  31. # 挂载到数据卷,与上面的容器中挂载目录名相同
  32. - name: nfs-vol-blog
  33. persistentVolumeClaim:
  34. claimName: nfs-pvc-mysql-blog
  35. ---
  36. apiVersion: v1
  37. kind: Service
  38. metadata:
  39. name: mysql-blog
  40. spec:
  41. ports:
  42. - port: 3306
  43. targetPort: 3306
  44. type: LoadBalancer
  45. selector:
  46. app: mysql-blog
  1. # 部署
  2. kubectl apply -f mysql-blog.yaml
  3. # 删除
  4. kubectl delete -f mysql-blog.yaml
  5. # 查看
  6. kubectl get service

使用 kubectl get pods -o wide 查看部署在哪个 node 上

K8s - 图56

使用 kubectl get service 查看 MySQL 的运行端口

K8s - 图57

最后使用 Sqlyog 尝试连接

K8s - 图58

连接报错

K8s - 图59

意思为无法使用密码的方式登录,在 Docker 部署时我们可以在配置文件中配置相关参数解决这个问题;在 Kubernetes 中则可以采用 ConfigMap 的方式配置 MySQL

ConfigMap 外部化配置

ConfigMap 是用来存储配置文件的 Kubernetes 资源对象,所有的配置内容都存储在 etcd 中。它可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制对象。ConfigMap API 资源提供了将配置数据注入容器的方式,同时保证该机制对容器来说是透明的。配置应该从 Image 内容中解耦,以此来保持容器化应用程序的可移植性

修改 mysql-blog.yaml 配置文件为如下

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: mysql-blog-config
  5. data:
  6. # 这里是键值对数据
  7. mysqld.cnf: |
  8. [client]
  9. port=3306
  10. [mysql]
  11. no-auto-rehash
  12. [mysqld]
  13. skip-host-cache
  14. skip-name-resolve
  15. default-authentication-plugin=mysql_native_password
  16. character-set-server=utf8mb4
  17. collation-server=utf8mb4_general_ci
  18. explicit_defaults_for_timestamp=true
  19. lower_case_table_names=1
  20. ---
  21. apiVersion: apps/v1
  22. kind: Deployment
  23. metadata:
  24. name: mysql-blog
  25. spec:
  26. selector:
  27. matchLabels:
  28. app: mysql-blog
  29. replicas: 1
  30. template:
  31. metadata:
  32. labels:
  33. app: mysql-blog
  34. spec:
  35. containers:
  36. - name: mysql-blog
  37. image: mysql:8.0.16
  38. imagePullPolicy: IfNotPresent
  39. ports:
  40. - containerPort: 3306
  41. env:
  42. - name: MYSQL_ROOT_PASSWORD
  43. value: "123456"
  44. volumeMounts:
  45. # 以数据卷的形式挂载 MySQL 配置文件目录
  46. - name: cm-vol-blog
  47. mountPath: /etc/mysql/conf.d
  48. - name: nfs-vol-blog
  49. mountPath: /var/lib/mysql
  50. volumes:
  51. # 将 ConfigMap 中的内容以文件形式挂载进数据卷
  52. - name: cm-vol-blog
  53. configMap:
  54. name: mysql-blog-config
  55. items:
  56. # ConfigMap 中的 Key
  57. - key: mysqld.cnf
  58. # ConfigMap Key 匹配的 Value 写入名为 mysqld.cnf 的文件中
  59. path: mysqld.cnf
  60. - name: nfs-vol-blog
  61. persistentVolumeClaim:
  62. claimName: nfs-pvc-mysql-blog
  63. ---
  64. apiVersion: v1
  65. kind: Service
  66. metadata:
  67. name: mysql-blog
  68. spec:
  69. ports:
  70. - port: 3306
  71. targetPort: 3306
  72. type: LoadBalancer
  73. selector:
  74. app: mysql-blog

到 volumes 节点下的 /usr/local/kubernetes/volumes 目录下,清空其中的内容

重新部署 mysql

  1. kubectl delete -f mysql-blog.yaml
  2. kubectl apply -f mysql-blog.yaml

查看 configMap

  1. kubectl get cm

K8s - 图60

  1. kubectl describe cm mysql-blog-config

K8s - 图61

重新查看端口号,部署节点 IP,进行连接测试

K8s - 图62

K8s Kuboard 第三方面板

  • 各云服务商自己推出的 Kubernetes 服务所搭载的管理控制台,例如 阿里云的 Kubernetes 服务,青云推出的 KubeSphere,其他云服务商的 CaaS 类服务
  • Kubernetes 官方的图形管理界面 Kubernetes Dashboard
  • 面向企业私有化部署的 Rancher

安装 Kuboard

在主结点 /usr/local/k8s 目录下创建目录 kuboard,然后执行命令

  1. kubectl apply -f https://kuboard.cn/install-script/kuboard.yaml

然后访问集群中的任一节点的 32567 端口 ( 如:http://192.168.224.203:32567/ )

获取 token

该命令获取的 token 拥有 clusterAdmin 的权限,可以执行所有操作

  1. kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep kuboard-user | awk '{print $1}')

K8s - 图63

复制 token 填入
K8s - 图64

然后登陆即可