Finer04's Blog
首页
乱写一通
脑洞破文
随便谈谈
当前播放.page
K8s 学习笔记
Finer04
October 8, 2023
14839 字
文章目录
由于没有资源,也不想开虚拟机,所以只停留在理论学习。 # K8s 学习 对我的理解,Docker 就是箱子,服务器里面的 Docker 就是将他们做成集装箱,K8s 可以将这些集装箱集中在自己的船上,一条船可以搭上数百个集装箱。是一个分布式的系统框架。 注意下面的 YAML 语法,不能用 Tab! ## 理解特性 K8s 可以实现负载均衡与服务发现,会通过轮询分担网络流量。可以互相测每个集群的健康度,有问题会自动切换。 K8s 可以管理每个集群分配存储空间; K8s 可以实现自动部署或回滚,可以回滚容器到指定的版本; K8s 的 Pod 里面的容器,他可以自动分配或自己指定每个容器的 CPU 和内存; K8s 可以实现自我修复,如果某个应用部署到其中一个集群中,但这个集群突然故障了,K8s可以在另外的集群重新拉起这个应用。 ## 架构 一般是集群模式。Master + Worker 模式,Master 是领导,Worker 是员工。n Master + n Worker Node,n 要大于或等于1 如果只有一个领导的话,领导寄了公司就会乱套;如果有多个领导,领导会成立一个董事会,如果A领导挂掉了,董事会的各位领导会选举一名新的领导,少数服从多数,大家都同意 B 领导可以当主领导才能当主领导。 Master 可以当 Worker 部署应用,但一般不用于跑业务。 ### 组件架构 架构图,Cluster 是集群,我们当成集团吧。整个模式可以理解为中介模式,类似 Zabbix Proxy。  - Node :代表服务器,工厂。 - kubelet:服务器管理 Agent。监控当前节点的所有情况,控制器。 - kube-proxy:控制网络访问的出入,相当于路由器。 - Control Plane :控制中心,就是上面的 Master Node,集团的总部,负责安排工作给 Node 干! - c-m:Control manager,决策者,决定干什么。 - etcd:数据库或资料库,用来存储核心。 - api:接口,秘书,工人想联系 c-m 得经过我的 API。 - sched(scheduler):调度者,负责决定这个项目由哪个工人去干,看这些应用在哪个服务器运行比较优越。 - cloud provider manger:云决策者 sched 决定哪个节点跑,这些基础数据都会存到 etcd;Node 无法直接联系到 C-M 和 sched,数据交互都得经过 api。所有部件都得经过 api,不可以单独找 c-m。 ### 运作架构 每台服务器都要安装 Docker 或容器运行环境。kubelet 负责每个应用的启停销毁,探测每个应用的状态。 k-proxy 控制每个应用容器之间的访问,发现其他节点的应用。 kubectl 是命令行模式,我们都是用这个跟 k8s 集群进行交互,用户可以让 K8s 部署容器应用,也是会发到 api。 > Docker 的 容器 == K8s 的 Pod,但Pod可以包括多个容器 ## 部署 ### Worker 1. 部署kubelet、kubectl(但一般不用装在worker,用户用来交互的)、kubeadm(用来快速搭建集群的工具),Docker 2. kubeadm join:加入集群,会部署 kube-proxy。 ### Master 1. 部署kubelet、kubectl、kubeadm,Docker 2. kubeadm init:初始化主节点,将该节点变成主节点,会自动部署 scheduler、kube-proxy、api、etcd、c-m; ### 步骤 所有步骤都要装 docker 本体,都略过,记得配置加速。 #### 安装 kubeadm 1. 要 RHEL 或 Debian 的操作系统,服务器配置至少要 2H2G 以上。 2. 设置防火墙放行规则,主机名和MAC地址不可重复,允许 iptables 检查桥接流量。 ```shell cat <
root@mynginx:/# ``` YAML 模式,这是单 Pod 的创建方式 ```YAML apiVersion: v1 kind: Pod metadta: label: run: mynginx name: mynginx # namespace: xxx 在XXX区创建 spec: containers: - image: nginx name: myningx ``` #### 多容器 如果我要在 YAML 模式,建立一个多容器的 Pod 的话。他们共享网络空间与存储。 ```yaml apiVersion: v1 kind: Pod metadta: label: run: myapp name: myapp # namespace: xxx 在XXX区创建 spec: containers: - image: nginx name: myningx - image: tomcat:8.5.68 name: tomcat ``` 如果我们要访问不同容器,我们访问 80 端口就是访问 nginx;我们访问 8080 就是 tomcat 的容器;只不过我们访问的 IP 是 K8s 分配的 IP 。 在这个 YAML 文件中,如果我们创建两个 nginx 容器,会出现 80 端口冲突。 ### Deployment 控制 Pod,让 Pod 拥有多副本,自愈、故障转移与扩缩容等能力。 跟传统部署 Pod 相比,我们用 deployment 部署 pod,不怕服务器或容器宕机,自动拉起新的 pod。死了会自动在其他机器中拉起。 #### 创建 ```bash # 创建 mytomcat 的部署 kubectl create deployment my-dep --image=tomcat:x.x.x # 删除上面的部署 kubectl delete deploy my-dep # 多副本部署 # 创建 mytomcat 的部署 kubectl create deployment my-dep --image=tomcat:x.x.x --replicas=3 # 查看 deploy 状态 kubectl get deploy ``` #### 扩缩容 `kubectl scale deploy/my-dep --replicas=2` ,这个 `2` 是缩容和扩容的数值 #### 自愈 通过 Hello 心跳包观察每个 Pod 的情况。 如果应用因为内存泄露或其他宕机,会自动重启;但如果本身应用有问题,自愈能力会不断的重启,需要检查容器本身时候有问题。 其中给一个 Worker 挂掉了,5分钟(这是阈值)后自动在其他 Worker 重新拉起 Worker 中已经 Deploy 的 Pod,可以理解成故障转移。 #### 滚动更新/回退 滚动更新是先启动 V2 版本的 Pod,如果启动成功了,会关掉 V1 的 Pod,可以保证流量不中断。如果 V2 刚开始启动失败的话,不会影响原本 V1 的 Pod。在这个过程是起一个杀一个。 ```bash kubectl set image deployment/my-dep nginx=nginx:1.16.1 --record # kubectl set image <资源类型> <资源名称> <容器名称>=<新镜像名称> kubectl rollout status deployment/my-dep ``` 如果我们要回退之前的版本的话 ```bash # 查看 Pod 的历史记录 kubectl rollout history deployment/my-dep # 回滚,回退到第一次 kubectl rollout undo deploy/my-dep --to-revision=1 ``` #### 其他工作负载模式 deployment 也是有局限性的,适用于无状态的应用;其他工作模式还有 Statefulset、Daemonset、job/cronjob 这些内容。 - Deployment: 无状态应用部署比如微服务,提供多副本等功能。 - StatefulSet: 有状态应用部署,比如redis,提供稳定的存储、网络等功能。死了会挂载到专属的存储中。 - DaemonSet:守护型应用部署,比如日志收集组件,在每个机器都运行一份 - Job/CronJob:定时任务部署,比如垃圾清理组件,可以在指定时间运行  ### Service 服务,用来做服务发现功能的,与负载均衡。可以理解为 Service 是一个网站服务的入口,这个入口会自动分发到 Pod 里的内部端口。我们访问的网站的话,流量会负载到每个 Pod 的服务中。 在这个 Service 内,是以 Label 标签进行分组,Service 会根据这个 deploy 的 label 形成一组映射组。 可以用 IP 与 域名访问,建立好的 Service 的内部域名形式是 `label名.命名空间.svc` ```bash # 暴露映射端口,外网访问的是 8000 端口,入口则映射到 80 端口中 kubectl expose deploy my-dep --port:8000 --target-port=80 # 我暴露的这 IP,只能在集群内访问 kubectl expose deploy my-dep --port:8000 --target-port=80 --type=ClusterIP # 我暴露的这 IP,可以在集群外访问(公网),但是 NodePort 的范围在 30000-32767 之间 kubectl expose deploy my-dep --port:8000 --target-port=80 --type=NodePort # 查看 Pod 标签 kubectl get pod --show-labels # 访问 service curl my-dep.default.svc # 查看 service 状态 kubectl get svc # 删除 service kubectl delete svc my-dep ``` YAML 的话是这样 ```yaml apiVersion: v1 kind: Service metadta: label: app: my-dep name: my-dep spec: selector: app: my-dep ports: - port:8000 protocol: TCP targetPort: 80 ```  在负载均衡中,一台 Pod 中断后,流量不会经过异常 Pod 的 IP,会负载到其他 Pod 上。至于怎么发现中断的,源自于服务发现。 ### Ingress 入口,作为集群对外服务的唯一入口,是总网关,访问对应的 service 的服务端口,相当于 Ingress → Service → Pod。就是叠一层网络入口。 Ingress 基于 Nginx,用 Nginx 控制流量出入。所有流量先访问 ingress 层,找到映射关系后会转发到对应 service,如果没找到,会返回 404. 注意的是,Ingress 不是全局负载均衡, Service 是对 Pod 负载均衡,Ingress 只是把 Service 映射对应的服务出去而已。在外网也需要对 Ingress 另外配置负载均衡才行。 ```bash # 查看 ingress 资源 kubectl get ing # 编辑 ingress 的某个资源配置文件 kubectl edit ing <资源名> -n ``` #### 域名映射 在外部访问某个域名,域名的请求会交给对应的 service 进行处理。 ```yaml apiVersion: v1 kind: Ingress metadata: name: ingress-host-bar spec: ingressClassName: nginx rules: - host: "hello.my.com" http: paths: - pathType: Prefix #前缀匹配模式 path: "/" backend: service: name: hello-server #这里是名字 port: number: 8000 # 这里的意义是,访问 hello.my.com 的时候,流量会转到 hello-server 这个 service 处理 - host: "demo.my.com" http: paths: - pathType: Prefix #前缀匹配模式 path: "/nginx" # 把请求转给下面的服务,如果下面的服务一定要能处理这个路径 backend: service: name: nginx-demo #这里是名字 port: number: 8000 # 这里的意义是,访问 demo.my.com/nginx 的时候,流量会转到 nginx-demo 这个 service 处理 ``` #### 路径重写 这段暂时不重要,有需要我将会查 [Rewrite - Ingress-Nginx Controller (kubernetes.github.io)](https://kubernetes.github.io/ingress-nginx/examples/rewrite/) #### 流量限制 使用 `nginx.ingress.kubernetes.io/limit-rps` 进行限流 ```yaml apiVersion: v1 kind: Ingress metadata: name: ingress-limit-rate annotations: nginx.ingress.kubernetes.io/limit-rps: "1" #1秒放一个 spec: ingressClassName: nginx rules: - host: "ha.my.com" http: paths: - pathType: Exact #精确匹配,访问 ha.my.com 生效 path: "/" backend: service: name: hello-server #这里是名字 port: number: 8000 ``` ### 存储 在上面的搭建中,如果发生了节点故障,在其他 Worker 的主机就算重新拉起新的容器,也会因为另外的 Worker 没有原 Worker 的数据,导致数据缺失或不对等。 #### 使用 NFS 作为存储 NFS 不是主从同步,只是共享存储,相当于映射。一般生产环境不会用 NFS 作为存储,大部分都是用分布式存储 ##### 部署 ```bash # 所有机器都要安装 yum install -y nfs-utils ``` 主节点 ```bash # 暴露这个目录,所有人都能安全读写这个 /nfs/data 这个目录 echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports mkdir -p /nfs/data systemctl enable rpcbind --now systemctl enable nfs-server --now # 配置生效 exportfs -r # 查看nfs情况 exportfs ``` 从节点 ```bash showmount -e 主节点 IP # 建立目录准备挂载 mkdir -p /nfs/data mount -t nfs 主节点:/nfs/data /nfs/data # 写入测试 echo "hello world" > /nfs/data/text.txt ``` ##### 用原生方式进行挂载 ```yaml apiVersion: v1 kind: Deployment metadata: labels: app: nginx-pv name: nginx-pv spec: replicas: 2 selector: matchLabels: app: nginx-pv spec: containers: - image: nginx name: nginx volomeMounts: - name: html # 这个是挂载名,要对应下面的实际挂载的名 mountPath: /usr/share/nginx/html volumes: - name: html nfs: server: 主节点或NFS服务器的 IP path: /nfs/data/nginx-pv # 最终nginx容器的 mountPath 会映射到这里的 path 目录中 ``` #### PV 与 PVC > PV: 持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置 > PVC:持久卷申明(Persistent Volume Claim),申明需要使用的持久卷规格 PV 就是我们提前规划好,哪些卷定了多少的空间,每个节点都部署好 PV 卷后,将会形成静态供应的 PV 池;而 PVC 相当于申请书,我想要 1G 的空间。假设现在的 PV 池有 `1G` 、`20G` 和`1M` 的 PV ,系统将会找匹配相近条件的 PV 池,对 1G 的 PV 卷进行绑定,饭量多少选哪个盒饭。 如果 Pod 删掉,PVC 也会跟着删,最后那 `1G` 的 PV 卷的数据也会回收掉。 静态供应是需要提前划分,动态供应可以按需自动创建一个 PVC 要求的空间卷。 ##### 创建 PV 池 ```bash mkdir -p /nfs/data/01 mkdir -p /nfs/data/02 mkdir -p /nfs/data/03 ``` ##### 创建 PV ```yaml apiVersion: v1 kind: PersistentVolume metadata: name: pv01-10m spec: capacity: storage: 10M accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/01 server: nfs服务器IP --- # 这个是分隔符,也可以理解为把多个 yaml 串在一起 apiVersion: v1 kind: PersistentVolume metadata: name: pv02-1G spec: capacity: storage: 1Gi accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/02 server: nfs服务器IP --- apiVersion: v1 kind: PersistentVolume metadata: name: pv03-3Gi spec: capacity: storage: 3Gi accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/01 server: nfs服务器IP ``` 我们 `kubectl get persistentvolome` 可以查看持久存储; `kubectk get pv` 可以查看持久卷状态; 如果看到 STATUS 是 `Available` 的话,是表示这些卷是可用状态;`Bound` 表示绑定状态,可以看右侧的 Claim;`Released` 表示被释放了 ##### 创建 PVC 与绑定 意思是写一份申请书 ```yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: nginx-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 200Mi storageClassName: nfs ``` `kubectl get pvc` 查看 PVC 的状态 创建 Pod 的时候,绑定我们刚创建的 PVC。 ```yaml apiVersion: v1 kind: Deployment metadata: labels: app: nginx-pv name: nginx-pv spec: replicas: 2 selector: matchLabels: app: nginx-pv spec: containers: - image: nginx name: nginx volomeMounts: - name: html # 这个是挂载名,要对应下面的实际挂载的名 mountPath: /usr/share/nginx/html volumes: - name: html persistentVolomeClaim: claimName: nginx-pvc ``` #### ConfigMap 可以抽取应用的配置文件,实现自动更新。也就是说不用传统
评论已关闭
▲ Top
评论已关闭