k8s快速入门
一、Kubernetes(K8S)简介
1、概念
1.1 Kubernetes (K8S) 是什么
它是一个为 容器化 应用提供集群部署和管理的开源工具,由 Google 开发。K8S 是负责自动化运维管理多个跨机器 Docker 程序的集群
1.2 核心特性
- 服务发现与负载均衡:无需修改你的应用程序即可使用陌生的服务发现机制
- 存储编排:自动挂载所选存储系统,包括本地存储
- Secret和配置管理:部署更新Secrets和应用程序的配置时不必重新构建容器镜像,且不必将软件堆栈配置中的秘密信息暴露出来
- 批量执行:除了服务之外,Kubernetes还可以管理你的批处理和CI工作负载,在期望时替换掉失效的容器
- 水平扩缩:使用一个简单的命令、一个UI或基于CPU使用情况自动对应用程序进行扩缩
- 自动化上线和回滚:Kubernetes会分步骤地将针对应用或其配置的更改上线,同时监视应用程序运行状况以确保你不会同时终止所有实例
- 自动装箱:根据资源需求和其他约束自动放置容器,同时避免影响可用性
- 自我修复:重新启动失败的容器,在节点死亡时替换并重新调度容器,杀死不响应用户定义的健康检查的容器
1.3 部署方案
传统部署方式
应用直接在物理机上部署,机器资源分配不好控制,出现Bug时,可能机器的大部分资源被某个应用占用,导致其他应用无法正常运行,无法做到应用隔离
虚拟机部署
在单个物理机上运行多个虚拟机,每个虚拟机都是完整独立的系统,性能损耗大
容器部署
所有容器共享主机的系统,轻量级的虚拟机,性能损耗小,资源隔离,CPU和内存可按需分配;例如k8s可以轻松管理百万千万台机器的集群,可以为你提供集中式的管理集群机器和应用,不停机的灰度更新,确保高可用、高性能、高扩展
2、Kubernetes 集群架构
2.1 架构
-
master
主节点,控制平台,不需要很高性能,不跑任务,通常一个就行了,也可以开多个主节点来提高集群可用度。
-
worker
工作节点,可以是虚拟机或物理计算机,任务都在这里跑,机器性能需要好点;通常都有很多个,可以不断加机器扩大集群;每个工作节点由主节点管理
2.2 重要概念 Pod
K8S 调度、管理的最小单位,一个 Pod 可以包含一个或多个容器,每个 Pod 有自己的虚拟IP。一个工作节点可以有多个 pod,主节点会考量负载自动调度 pod 到哪个节点运行
2.3 Kubernetes 组件
kube-apiserver
K8S 的请求入口服务。API Server 负责接收 K8S 所有请求(来自 UI 界面或者 CLI 命令行工具),然后,API Server 根据用户的具体请求,去通知其他组件干活etcd
K8S 的存储服务。etcd 存储了 K8S 的关键配置和用户配置,K8S 中仅 API Server 才具备读写权限,其他组件必须通过 API Server 的接口才能读写数据kube-scheduler
K8S 所有 Worker Node 的调度器。当用户要部署服务时,Scheduler 会选择最合适的 Worker Node(服务器)来部署controller Manager
K8S 所有 Worker Node 的监控器。Controller Manager 有很多具体的Controller, Node Controller、Service Controller、Volume Controller 等。Controller 负责监控和调整在Worker Node 上部署的服务的状态,比如用户要求 A 服务部署 2 个副本,那么当其中一个服务挂了的时候,Controller 会马上调整,让 Scheduler 再选择一个 Worker Node 重新部署服务cloud-controller
与云服务商交互Kubelet
Worker Node 的监视器,以及与 Master Node 的通讯器。Kubelet 是 Master Node 安插在Worker Node 上的"眼线",它会定期向 Master Node 汇报自己 Node 上运行的服务的状态,并接受来自Master Node 的指示采取调整措施。负责控制所有容器的启动停止,保证节点工作正常。Kube-Proxy
K8S 的网络代理。Kube-Proxy 负责 Node 在 K8S 的网络通讯、以及对外部网络流量的负载均衡Container Runtime
** Worker Node 的运行环境**。即安装了容器化所需的软件环境确保容器化程序能够跑起来,比如 Docker Engine运行环境
二、Kubernetes集群安装
默认已经提前安装好Docker,docker安装可以参考:docker学习笔记
1、安装方式介绍
-
minikube
只是一个 K8S 集群模拟器,只有一个节点的集群,只为测试用,master 和 worker 都在一起
-
直接用云平台 Kubernetes (阿里/腾讯)
可视化搭建,只需简单几步就可以创建好一个集群。
优点:安装简单,生态齐全,负载均衡器、存储等都给你配套好,简单操作就搞定
-
裸机安装(Bare Metal)
至少需要两台机器(主节点、工作节点个一台),需要自己安装 Kubernetes 组件,配置会稍微麻烦点。
可以到各云厂商按时租用服务器,费用低,用完就销毁。
缺点:配置麻烦,缺少生态支持,例如负载均衡器、云存储。
2、minikubute安装
官网安装:https://minikube.sigs.k8s.io/docs/start/
Minikube:搭建部署单机 Kubernetes
minikube安装非常简单,支持各种平台,建议直接裸机(个人虚拟机安装一直有问题)
1 | # 启动集群,据说不加版本会报错(我还是启动不了) |
minikube和云平台不多赘述,例如腾讯云的弹性容器服务 EKS,这里主要讲述逻辑集群的安装
3、裸机搭建(Bare Metal)
k8s集群搭建参考:https://k8s.easydoc.net/docs/dRiQjyTY/28366845/6GiNOzyZ/nd7yOvdY#nav_3
3.1 概念介绍
主节点需要组件
- docker(也可以是其他容器运行时)
- kubectl 集群命令行交互工具
- kubeadm 集群初始化工具
**工作节点需要组件 **文档
- docker(也可以是其他容器运行时)
- kubelet 管理 Pod 和容器,确保他们健康稳定运行
- kube-proxy 网络代理,负责网络相关的工作
3.2 集群安装
这里我基于centos7创建了三台虚拟机(2核4G,网络使用nat),以下是所有节点的配置,权限不够的话使用sudo提升权限
1 | # 每个节点分别设置对应主机名 |
在主节点master初始化集群,init的文档
1 | # 初始化集群控制台 Control plane |
然后把工作节点加入集群(只在工作节点跑)
1 | sudo kubeadm join 192.168.249.140:6443 --token 5f20z7.9rbjijmnkhpz0sj2 \ |
最后安装网络插件,否则 node 是 NotReady 状态(主节点跑)
1 | # 查看状态 |
3.3 踩坑之路
首先了解一下基本的命令
1 | # 查看所有的详细信息 |
问题一
手动导入网络插件后通过查看日志发现镜像无法拉取,于是手动拉取导入,然后用tag打上与yml文件中的镜像一模一样的名字,这里我每个结点都是这样操作(按理说会自动同步过去其他结点,但是每个结点都报错了,所以我手动下载了;当然换个国内源也可以)
1 | # 下载地址 |
问题二
手动下载后,查看describe日志发现能成功拉去镜像,但是容器无法启动,查看logs日志发现说没有分配子网podCIDR,通过kubeadm init初始化master节点时,flannel网络插件需要确保初始化命令配置了podCIDR如下启动参数,–pod-network-cidr=172.18.0.0/16
问题三
如果你运行 kubectl describe pod/pod-name
发现 Events 中有下面这个错误networkPlugin cni failed to set up pod "test-k8s-68bb74d654-mc6b9_default" network: open /run/flannel/subnet.env: no such file or directory
那么在每个节点创建文件/run/flannel/subnet.env
写入以下内容,配置后等待一会就好了(用来配置每个结点的子网信息)
1 | FLANNEL_NETWORK=10.244.0.0/16 |
4、快速体验
1 | # 创建一次deployment部署 |
5、可视化安装
5.1 Kuboard v2 - kubernetes(推荐)
1 | # 安装 Kuboard |
5.2 Kubernetes Dashboard
Kubernetes Dashboard 是 Kubernetes 的官方 Web UI。使用 Kubernetes Dashboard可以
- 向 Kubernetes 集群部署容器化应用
- 诊断容器化应用的问题
- 管理集群的资源
- 查看集群上所运行的应用程序
- 创建、修改Kubernetes 上的资源(例如 Deployment、Job、DaemonSet等)
- 展示集群上发生的错误
1 | # 安装 Kubernetes Dashboard |
三、集群服务部署
1、部署应用Demo
部署一个 nodejs web 应用,源码地址:Github
1 | # 查看pod状态 |
创建pod.yaml
1 | apiVersion: v1 |
创建deployment.yaml文件
1 | apiVersion: apps/v1 |
命令行弹性伸缩,k8s会自动根据结点情况部署
1 | # 命令行弹性扩容,也可以在yaml中进行编写 |
2、常用命令详情
1 | # 部署应用 |
3、概念
更多官网关于 Deployment 的介绍,将 Pod 指定到某个节点运行:nodeselector,限定 CPU、内存总量:文档
3.1 工作负载分类
-
Deployment
适合无状态应用,所有pod等价,可替代
-
StatefulSet
有状态的应用,适合数据库这种类型。
-
DaemonSet
在每个节点上跑一个 Pod,可以用来做节点监控、节点日志收集等
-
Job & CronJob
Job 用来表达的是一次性的任务,而 CronJob 会根据其时间规划反复运行。
3.2 存在问题
- 每次只能访问一个 pod,没有负载均衡自动转发到不同 pod
- 访问还需要端口转发
- Pod 重创后 IP 变了,名字也变了
四、Service
1、概念
https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#headless-services
- Service 通过 label 关联对应的 Pod
- Servcie 生命周期不跟 Pod 绑定,不会因为 Pod 重创改变 IP
- 提供了负载均衡功能,自动转发流量到不同 Pod
- 可对集群外部提供访问端口
- 集群内部可通过服务名字访问
2、Service简单Demo
首先创建service.yaml
1 | apiVersion: v1 |
然后进行访问测试
1 | # 创建service |
3、对外暴露服务(重要)
上面我们是通过端口转发的方式可以在外面访问到集群里的服务,如果想要直接把集群服务暴露出来,我们可以使用NodePort
和 Loadbalancer
类型的 Service
1 | apiVersion: v1 |
应用配置 kubectl apply -f service.yaml
;在节点上,我们可以 curl http://localhost:31000
或者curl http://[你的物理ip]:31000
访问到应用并且是有负载均衡的,网页的信息可以看到被转发到了不同的 Pod(可能有缓存)
Loadbalancer
也可以对外提供服务,这需要一个负载均衡器的支持,因为它需要生成一个新的 IP 对外服务,否则状态就一直是 pendding,这个很少用了,后面我们会讲更高端的 Ingress 来代替它。
4、多端口
https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#multi-port-services
多端口时必须配置 name
1 | apiVersion: v1 |
5、总结
-
ClusterIP
默认的,仅在集群内可用
-
NodePort
暴露端口到节点,提供了集群外部访问的入口,端口范围固定 30000 ~ 32767
-
LoadBalancer
需要负载均衡器(通常都需要云服务商提供,裸机可以安装 METALLB 测试)会额外生成一个 IP 对外服务K8S 支持的负载均衡器:负载均衡器
-
Headless
适合数据库,clusterIp 设置为 None 就变成 Headless 了,不会再分配 IP,后面会再讲到具体用法
五、StatefulSet
1、StatefulSet介绍
1.1 概念
StatefulSet 是用来管理有状态的应用,例如数据库。 前面我们部署的应用,都是不需要存储数据,不需要记住状态的,可以随意扩充副本,每个副本都是一样的,可替代的。 而像数据库、Redis 这类有状态的,则不能随意扩充副本。StatefulSet 会固定每个 Pod 的名字
1.2 特性
- Service 的
CLUSTER-IP
是空的,Pod 名字也是固定的。 - Pod 创建和销毁是有序的,创建是顺序的,销毁是逆序的。
- Pod 重建不会改变名字,除了IP,所以不要用IP直连
2、部署 StatefulSet 类型的 Mongodb
创建statefulset和service
1 | apiVersion: apps/v1 |
操作,这里的test-k8s镜像使用了ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v3-mongo
1 | # 扩容 |
六、数据持久化
1、概念
kubernetes 集群不会为你处理数据的存储,我们可以为数据库挂载一个磁盘来确保数据的安全。可以选择云存储、本地磁盘、NFS。
- 本地磁盘:可以挂载某个节点上的目录,但是这需要限定 pod 在这个节点上运行
- 云存储:不限定节点,不受集群影响,安全稳定;需要云服务商提供,裸机集群是没有的。
- NFS:不限定节点,不受集群影响
2、hostPath 挂载示例
文档:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/#hostpath
把节点上的一个目录挂载到 Pod,但是已经不推荐使用了,该方法配置方式简单,需要手动指定 Pod 跑在某个固定的节点。仅供单节点测试使用;不适用于多节点集群
1 | apiVersion: apps/v1 |
创建好数据后重启kubectl rollout restart statefulset mongodb
,发现数据还在,同时进入结点,可以发现数据保存在/data/db
,而进入该结点的宿主机,发现数据映射在/data/mongo-data
3、高级抽象挂载
3.1 概述
- 更好的分工,运维人员负责提供好存储,开发人员不需要关注磁盘细节,只需要写一个申请单。
- 方便云服务商提供不同类型的,配置细节不需要开发者关注,只需要一个申请单。
- 动态创建,开发人员写好申请单后,供应商可以根据需求自动创建所需存储卷。
3.2 各个层级表述
Storage Class (SC)
将存储卷划分为不同的种类,例如:SSD,普通磁盘,本地磁盘,按需使用。文档
1 | apiVersion: storage.k8s.io/v1 |
Persistent Volume (PV)
描述卷的具体信息,例如磁盘大小,访问模式。文档,类型,Local 示例
1 | apiVersion: v1 |
Persistent Volume Claim (PVC)
对存储需求的一个申明,可以理解为一个申请单,系统根据这个申请单去找一个合适的 PV
还可以根据 PVC 自动创建 PV。
1 | apiVersion: v1 |
3.3 本地测试
网络云服务商封装了底层,只需要提交pvc申请即可成功,这里我用本地进行模拟,写到了一起,实际可以自行分开
1 | apiVersion: apps/v1 |
测试
1 | # 运行 |
七、ConfigMap & Secret
1、概述
参考文档:https://kubernetes.io/zh/docs/concepts/configuration/configmap/
数据库连接地址,这种可能根据部署环境变化的,我们不应该写死在代码里。Kubernetes 为我们提供了 ConfigMap,可以方便的配置一些变量
2、ConfigMap
创建configmap.yaml
1 | apiVersion: v1 |
1 | # 应用 |
3、Secret
一些重要数据,例如密码、TOKEN,我们可以放到 secret 中。文档,配置证书。注意,数据要进行 Base64 编码。Base64 工具
创建secret.yaml
1 | apiVersion: v1 |
1 | # 应用 |
4、Demo使用
作为环境变量使用
1 | apiVersion: apps/v1 |
挂载为文件(更适合证书文件)挂载后,会在容器中对应路径生成文件,一个 key 一个文件,内容就是 value,文档
1 | apiVersion: v1 |
进行测试(test-k8s的镜像更换ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v4-configmap)
1 | kubectl run mongodb-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mongodb:4.4.10-debian-10-r20 --command -- bash |
八、Helm & 命名空间
1、简介
Helm官网:https://helm.sh/zh/
包搜索:https://artifacthub.io/
Helm
类似 npm,pip,docker hub, 可以理解为是一个软件库,可以方便快速的为我们的集群安装一些第三方软件。使用 Helm 我们可以非常方便的就搭建出来 MongoDB / MySQL 副本集群,YAML 文件别人都给我们写好了,直接使用
2、Helm安装
1 | # 脚本安装,不过可能会失败 |
3、安装MongoDb
1 | # 安装 |
4、命名空间
如果一个集群中部署了多个应用,所有应用都在一起,就不太好管理,也可以导致名字冲突等。我们可以使用 namespace 把应用划分到不同的命名空间,跟代码里的 namespace 是一个概念,只是为了划分空间
1 | # 创建命名空间 |
可以用 kubens 快速切换 namespace,首先进行下载安装
1 | wget https://github.com/ahmetb/kubectx/releases/download/v0.9.4/kubens_v0.9.4_linux_x86_64.tar.gz |
九、Ingress
1、介绍
Ingress 为外部访问集群提供了一个 统一 入口,避免了对外暴露集群端口;功能类似 Nginx,可以根据域名、路径把请求转发到不同的 Service。可以配置 https
**跟 LoadBalancer 有什么区别?**LoadBalancer 需要对外暴露端口,不安全;无法根据域名、路径转发流量到不同 Service,多个 Service 则需要开多个 LoadBalancer;功能单一,无法配置 https
2、使用
文档:Ingress
要使用 Ingress,需要一个负载均衡器 + Ingress Controller如果是裸机(bare metal) 搭建的集群,你需要自己安装一个负载均衡插件,可以安装 METALLB如果是云服务商,会自动给你配置,否则你的外部 IP 会是 "pending"状态,无法使用。
1 | apiVersion: networking.k8s.io/v1 |
参考文档:
https://www.bilibili.com/video/BV1Tg411P7EB
https://k8s.easydoc.net/docs/dRiQjyTY/28366845/6GiNOzyZ/9EX8Cp45