Kubernetes 遨游#
Kubernetes 名字源于希腊语,大意为「舵手」或者「飞行员」。Kubernetes 要做的事情就是:为使用者提供一个可弹性运行的分布式框架,满足各种扩展要求、故障转移、提供部署模式等等,Kubenetes 可以很好的管理系统的 Canary 部署。
- 服务发现和负载均衡
- **存储编排:**自动挂载存储系统,本地存储、公共云提供商等等
- 自动部署和回滚
- 自我修复:自动重新启动失败的容器、替换容器和异常容器
容器化部署历史背景#
传统部署时代:在物理服务器上运行应用程序存在很重要的资源分配问题。如果同一台物理服务器上运行多个应用程序,可能出现多个应用程序中单个占用大部分资源,而导致其他的程序性能显著下降。因此而生的解决办法就是:将每个应用程序都部署在不同的物理服务器上。显然,维护多个物理服务器的成本也是很高的。
虚拟化部署时代:因此虚拟化部署油然而生了,虚拟化技术将会允许我们在单个物理服务器上的 CPU 中运行多台虚拟机(VM)各个应用程序被部署在不同的虚拟机中,而虚拟化技术能够使得不同的 VM 在同一 CPU 彼此隔离。这样能够更好地利用物理服务器的资源,可以更加轻松地添加或者更新应用程序。通过虚拟化,我们可以将物理资源呈现为可丢弃的虚拟机集群。
容器部署时代:「容器」简单来说就是拥有更加宽松的隔离特性,更加轻量级的 VM,容器之间可以共享操作系统。与 VM 相同,容器都具有自己的文件系统、CPU、内存、进程空间等等。
Kubernetes 组件#
Kubernetes 集群需要正常运行,须有多个重要的组件(Components)共同组成:
控制平面 Control Pane#
整个集群,都是由一个控制平面和一个及以上工作节点共同组成的。
- kube-apiserver 公开 Kubernetes HTTP API 的核心组件服务器。
- etcd 具备一致性和高可用性的键值存储,用于所有 API 服务器的数据存储。
- kube-scheduler 查找尚未绑定到节点的 Pod,并将每个 Pod 分配给合适的节点。
- kube-controller-manager ↗ 运行控制器 ↗来实现 Kubernetes API 行为。
- cloud-controller-manager ↗(optional) 集成底层云驱动。
Node 组件#
用于运行容器化应用的工作机器, 这些工作机器称作节点(Node)。每个集群至少需要一个工作节点来运行 Pod 。
- kubelet 确保 Pod 及其容器正常运行。
- kube-proxy(可选)维护节点上的网络规则以实现 Service 的功能。
- 容器运行时(Container runtime) 负责运行容器的软件,包括 containerd、CRI-O(Kubernetes 内部自定义)、Kubernetes CRI (容器运行环境接口) ↗ 。
插件 Addons#
使用插件可以很好的 扩展 Kubernetes 的功能,重要的插件包括:
- DNS ↗ 集群范围内的 DNS 解析。
- Web 界面 ↗(Dashboard)通过 Web 界面进行集群管理。
- 容器资源监控 ↗ 用于收集和存储容器指标。
- 集群层面日志 ↗ 用于将容器日志保存到中央日志存储
Kubernetes 整体架构#
工作节点托管着组成应用负载的 Pod(表示集群上一组正在运行的容器)。控制平面管理集群中的工作节点和 Pod。 在生产环境中,控制平面通常跨多台计算机运行,而一个集群通常运行多个节点,以提供容错和高可用。
控制平面组件#
控制平面组件,会为集群做出全局决策,习惯命名为 xxx-control-pane
,相当于是整个集群的「大脑」,检测以及响应集群的各种事件,当 Deployment 的配置发生改变时,停止旧 pod 启动新 pod 的行为由其做出。
kube-apiserver#
kube-apiserver
称作 API 服务器,API 服务器是整个控制平面的前端,负责公开 Kubernetes 的 API,接收请求,分发请求。
etcd#
角色是 Kubernets 所有集群数据的后台数据库,高可用的键值存储数据库。
kube-scheduler#
在控制平面中负责监视新创建的、未指定运行的节点的 pods,并对 pod 运行做出调度,选择应该在哪些节点上运行 pod。
Node 节点组件#
节点组件在每一个 Node 上运行,负责维护运行时的 Pod,并对其提供 Kubernetes 运行时环境(Runtime)
kubelet#
kubelet 组件会在集群中的每一个 node 中运行,它保证了容器都正确运行在 Pod 中。它基于 PodSpec(一个描述 Pod 的 YAML 或者 JSON 对象)。kubelet 接收 PodSpec 并根据 PodSpec 中详细描述信息,确保目标容器处于运行状态并且状态健康,当然了,他并不管理不用 Kubenetes 管理的容器。
kubelet 接收 PodSpec 的方法有很多:
- 主要通过 apiserver API 服务器发送的 manifest(容器清单)
- File:利用命令行参数传递路径,它将会周期性的检测该路径下的文件是否有更新
- HTTP endpoint:利用命令行参数指定 HTTP 端点传输
kube-proxy
kube-proxy 作为集群中每个 node 上运行的网络代理。
Kubernetes 网络代理在每个节点上运行。网络代理反映了每个节点上 Kubernetes API 中定义的服务,并且可以执行简单的 TCP、UDP 和 SCTP 流转发,或者在一组后端进行 循环 TCP、UDP 和 SCTP 转发。 当前可通过 Docker-links-compatible 环境变量找到服务集群 IP 和端口, 这些环境变量指定了服务代理打开的端口。 有一个可选的插件,可以为这些集群 IP 提供集群 DNS。 用户必须使用 apiserver API 创建服务才能配置代理。
Node#
Kubernetes 通过将容器放入在节点(Node)上运行的 Pod 中来执行你的工作负载。 节点可以是一个虚拟机或者物理机器,取决于所在的集群配置。 每个节点包含运行 Pod 所需的服务; 这些节点由控制面负责管理。
通常集群中会有若干个节点;而在一个学习所用或者资源受限的环境中,集群中也可能只有一个节点。
Kubernetes 中的容器#
Kubernetes 集群中的每个Node 都会运行容器, 这些容器构成分配给该节点的 Pod。 单个 Pod 中的容器会在共同调度下,于同一位置运行在相同的节点上
镜像#
容器镜像标准定义如下:
容器镜像(Image)所承载的是封装了应用程序及其所有软件依赖的二进制数据。 容器镜像是可执行的软件包,可以单独运行;该软件包对所处的运行时环境具有明确定义的运行时环境假定。
在 Kubernetes 中使用镜像,Pod 是一组正在运行着的容器的集合,显然镜像主要的活跃场所就是在 Pod。如果我们想要在 Kubernetes 中使用或更新镜像,需要修改的就是 PodSpec。
-
如果在配置时不指定仓库的主机名,Kubernetes 将会默认使用 Docker 公共仓库进行拉取镜像
当然可以通过在容器进行时中配置这一默认行为,设置默认镜像仓库。
-
镜像组成:
host
/name
:tag
或host
/name
:digest
digest
摘要,使用标签我们能够辨识同一镜像序列中的不同版本,而digest
则是镜像的唯一标识符,由哈希算法生成如sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07
Docker 等使用digest
来唯一标识镜像- 比如:
docker.io/erasernoob/higress-gateway:latest
erasernoob/higress-gateway:3.0
- 如果不指定特定的
tag
,那么 Kubenetes 将会默认拉取latest
- 镜像拉取策略 ↗:
IfNotPresent
Always
Never
工作负载 Workloads#
A workload is an application running on Kubernetes.
无论 workload(负载)是由单个组件还是由多个一同工作的组件构成,我们都可以在一组 Pod 中运行它,Pod 代表的是集群上处于运行状态的一组容器的集合。
为了避免用户直接管理每一个 Pod,Kubernetes 使用负载资源替用户管理一组 Pod,这些负载资源通过配置控制器来确保 Pod 的运行状态以及正确运行的个数,与用户指定配置的状态一致。
在 Kubernetes 中存在以下内置的负载资源:
-
StatefulSet ↗ 让你能够运行一个或者多个以某种方式跟踪应用状态的 Pod。 例如,如果你的负载会将数据作持久存储,你可以运行一个 StatefulSet,将每个 Pod 与某个 PersistentVolume ↗ 对应起来。你在 StatefulSet 中各个 Pod 内运行的代码可以将数据复制到同一 StatefulSet 中的其它 Pod 中以提高整体的服务可靠性。
-
DaemonSet ↗ 定义提供节点本地支撑设施的 Pod。这些 Pod 可能对于你的集群的运维是 非常重要的,例如作为网络链接的辅助工具或者作为网络 插件 ↗ 的一部分等等。每次你向集群中添加一个新节点时,如果该节点与某
DaemonSet
的规约匹配,则控制平面会为该 DaemonSet 调度一个 Pod 到该新节点上运行。 -
Job ↗ 和 CronJob ↗。 定义一些一直运行到结束并停止的任务。 你可以使用 Job ↗ 来定义只需要执行一次并且执行后即视为完成的任务。你可以使用 CronJob ↗ 来根据某个排期表来多次运行同一个 Job。
同时,还可以使用定制资源定义(CRD) ↗已添加第三方工作负载资源。
Pod#
Pod 是 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod 就像是豌豆荚,里面的一个个豌豆就是容器,这些容器共享存储、网络以及一些预先定义好的运行这些容器的规约。Pod 中的内容总是在共享的上下文中进行,相当于是一个「逻辑主机」,包含多个应用容器。
注:若要运行 Pod 则需要提前在每个节点中安装好 Container Runtime ↗
使用 Pod#
Pod Spec YAML 文件,在使用 Pod 的过程中是必不可少的,下面是一个简单的 Pod Spec 定义,包括了元数据和容器规范:
apiVersion: v1 # API 版本,Pod 使用的是 v1
kind: Pod # 资源类型是 Pod
metadata: # 元数据部分
name: nginx # Pod 的名字叫 nginx
spec: # Pod 的规范部分(Pod Spec)
containers: # 容器列表(Pod 可以有多个容器)
- name: nginx # 容器名称
image: nginx:1.14.2 # 使用的镜像是 nginx 1.14.2
ports: # 容器暴露的端口
- containerPort: 88
yaml通过运行以下命令,Pod 就创建成功了:
kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml(yaml location)
bash通过 kubectl get pods
命令查看当前的命名空间下的所有 Pods 状态(同时可以使用 -f
参数对状态进行追踪)
erasernoob@LAPTOP-NHH2LRV8:~/project/rk8s$ ktl get pods -n higress-system
NAME READY STATUS RESTARTS AGE
higress-console-85db5bfcc8-pnhqx 1/1 Running 2 (40h ago) 2d10h
higress-console-grafana-57f45598c7-drkw8 1/1 Running 2 (40h ago) 2d10h
higress-console-loki-699644ddff-zlfpm 1/1 Running 2 (40h ago) 2d10h
higress-console-prometheus-7c84669775-g6s49 1/1 Running 2 (40h ago) 2d10h
higress-controller-75bf975b57-qnqz9 2/2 Running 4 (40h ago) 2d10h
higress-gateway-5cb8d798b9-jrfww 1/1 Running 0 24h
redis-stack-server-0 1/1 Running 2 (40h ago) 2d10h
bash使用 WorkLoad Resource 来管理 Pod#
通常我们并不需要直接一个一个的创建 Pod,或者是单实例(Singleton)的 Pod,我们使用 Workload Resource 来创建和管理一组 Pod。因为 Pod 被设计成了相对临时性的、用后即抛的一次性实体,同时重启 Pod 和 重启 Container也不应该被混淆,Pod 不是进程而是容器运行的环境。
资源的控制器能够处理副本的管理、上线,并在 Pod 失效时提供自愈能力。 例如,如果一个节点失败,控制器注意到该节点上的 Pod 已经停止工作, 就可以创建替换性的 Pod。调度器会将替身 Pod 调度到一个健康的节点执行。
-
使用 Deployments Manager 管理一组 Pod:
kubectl get deployments -n higress-system
命令得到当前命名空间下的所有 Deployments
basherasernoob@LAPTOP-NHH2LRV8:~/project/rk8s$ ktl get deployments -n higress-system NAME READY UP-TO-DATE AVAILABLE AGE higress-console 1/1 1 1 2d10h higress-console-grafana 1/1 1 1 2d10h higress-console-loki 1/1 1 1 2d10h higress-console-prometheus 1/1 1 1 2d10h higress-controller 1/1 1 1 2d10h higress-gateway 1/1 1 1 2d10h
以下是一个创建了一个 ReplicaSet 同时带有三个 nginx Pods 的 deployments spec 示例:
yamlapiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 # docker image ports: - containerPort: 80
- 创建 一个新的 deployment
bashkubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
- 查看当前 deployment 状态
bashkubectl get deployments
- 查看当前回滚状态
bashkubectl rollout status deployment/nginx-deployment
- 查看当前的 Replicaset(rs)
bashkubectl get rs
输出大概如下:
bashNAME DESIRED CURRENT READY AGE nginx-deployment-75675f5897 3 3 3 18s
- 更新 Pods 中的容器镜像
bashkubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1 kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
- 直接修改整个 deployment spec
bashkubectl edit deployment/nginx-deployment
- 查看当前 deployment 的整个状态信息
bashkubectl describe deployments
- 回滚
bashkubectl rollout status deployment/higress-gateway # check the rollout status kubectl rollout restart # 触发重新部署
命令合集#
创建新集群#
首先我们需要一个 cluster.conf
文件:
# cluster.conf
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
# networking:
# WARNING: It is _strongly_ recommended that you keep this the default
# (127.0.0.1) for security reasons. However it is possible to change this.
# apiServerAddress: "0.0.0.0"
# By default the API server listens on a random open port.
# You may choose a specific port but probably don't need to in most cases.
# Using a random port makes it easier to spin up multiple clusters.
# apiServerPort: 6443
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
yml上述文件,指定了节点的角色 control-pane
以及 暴露了相对应的端口 443
80
使用 kind 创建集群
kind create cluster --name higress --config=cluster.conf
kubectl config use-context kind-higress
bash查看某一 Pod 的日志
kubectl logs higress-gateway-5cb8d798b9-jrfww -n higress-system -f
bash将本地镜像加载到集群中#
kind load docker-image higress-gatway:4.0 --name higress-test
plaintext接下就可以在集群中访问到宿主机上的本地镜像了。