超详细!Kubernetes 学习笔记总结

本文组织

  • 1、K8S Master与Worker
  • 2、K8s重要概念
    • 2.1 Pod实例
      • 1、Pod内部结构
      • 2、Pod的网络通信
      • 3、Pod的多种类型
    • 2.2 Volume 数据卷
    • 2.3 Deployment 和 ReplicaSet(简称 RS)
    • 2.4 Service 和 Ingress
    • 2.5 namespace 命名空间
    • 2.6 其他
  • 3、配置 kubectl
    • 3.1 什么是 kubectl?
    • 3.2 怎么配置 kubectl?
  • 4、kubectl 部署服务
    • 4.1 如何部署 Pod?
    • 4.2 如何部署 Deployment?
  • 5、K8s部署服务失败

本文组织方式:

  1. K8S 是什么,即作用和目的。涉及 K8S 架构的整理,Master 和 Node 之间的关系,以及 K8S 几个重要的组件:API Server、Scheduler、Controller、etcd 等。
  2. K8S 的重要概念,即 K8S 的 API 对象,也就是常常听到的 Pod、Deployment、Service 等。
  3. 如何配置 kubectl,介绍kubectl工具和配置办法。
  4. 如何用kubectl 部署服务。
  5. 如何用kubectl 查看、更新/编辑、删除服务。
  6. 如何用kubectl 排查部署在K8S集群上的服务出现的问题

1、K8S Master与Worker

K8S 是负责自动化运维管理多个 Docker 程序的集群
超详细!Kubernetes 学习笔记总结_第1张图片
K8S 是属于主从设备模型(Master-Slave 架构),即有 Master 节点负责核心的调度、管理和运维,Slave 节点则在执行用户的程序。但是在 K8S 中,主节点一般被称为Master Node 或者 Head Node(本文采用 Master Node 称呼方式),而从节点则被称为Worker Node 或者 Node(本文采用 Worker Node 称呼方式)。

要注意一点:Master Node 和 Worker Node 是分别安装了 K8S 的 Master 和 Woker 组件的实体服务器,每个 Node 都对应了一台实体服务器(虽然 Master Node 可以和其中一个 Worker Node 安装在同一台服务器,但是建议 Master Node 单独部署),所有 Master Node 和 Worker Node 组成了 K8S 集群,同一个集群可能存在多个 Master Node 和 Worker Node。

首先来看Master Node都有哪些组件:

  • API Server。K8S 的请求入口服务。 API Server 负责接收 K8S 所有请求(来自 UI 界面或者 CLI 命令行工具),然后,API Server 根据用户的具体请求,去通知其他组件干活。
  • Scheduler。K8S 所有 Worker Node 的调度器。 当用户要部署服务时,Scheduler 会选择最合适的 Worker Node(服务器)来部署。
  • Controller Manager。K8S 所有 Worker Node 的监控器。 Controller Manager 有很多具体的 Controller,在文章Components of Kubernetes Architecture中提到的有 Node Controller、Service Controller、Volume Controller 等。Controller 负责监控和调整在 Worker Node 上部署的服务的状态,比如用户要求 A 服务部署 2 个副本,那么当其中一个服务挂了的时候,Controller 会马上调整,让 Scheduler 再选择一个 Worker Node 重新部署服务。
  • etcd。K8S 的存储服务。 etcd 存储了 K8S 的关键配置和用户配置,K8S 中仅 API Server 才具备读写权限,其他组件必须通过 API Server 的接口才能读写数据(见Kubernetes Works Like an Operating System)。

接着来看Worker Node的组件

  • Kubelet。Worker Node 的监视器,以及与 Master Node 的通讯器。 Kubelet 是 Master Node 安插在 Worker Node 上的“眼线”,它会定期向 Worker Node 汇报自己 Node 上运行的服务的状态,并接受来自 Master Node 的指示采取调整措施。
  • Kube-Proxy。K8S 的网络代理。 私以为称呼为 Network-Proxy 可能更适合?Kube-Proxy 负责 Node 在 K8S 的网络通讯、以及对外部网络流量的负载均衡。
  • Container Runtime。Worker Node 的运行环境。 即安装了容器化所需的软件环境确保容器化程序能够跑起来,比如 Docker Engine。大白话就是帮忙装好了 Docker 运行环境。
  • Logging Layer。K8S 的监控状态收集器。 私以为称呼为 Monitor 可能更合适?Logging Layer 负责采集 Node 上所有服务的 CPU、内存、磁盘、网络等监控项信息。
  • Add-Ons。K8S 管理运维 Worker Node 的插件组件。有些文章认为 Worker Node 只有三大组件,不包含 Add-On,但笔者认为 K8S 系统提供了 Add-On 机制,让用户可以扩展更多定制化功能,是很不错的亮点。

总结来看
K8S 的 Master Node 具备:

  • 请求入口管理(API Server)
  • Worker Node 调度(Scheduler)
  • 监控和自动调节(Controller Manager)
  • 存储功能(etcd);

而 K8S 的 Worker Node 具备:

  • 状态和监控收集(Kubelet)
  • 网络和负载均衡(Kube-Proxy)
  • 保障容器化运行环境(Container Runtime)
  • 定制化功能(Add-Ons)。

2、K8s重要概念

Pod、Service、Volume 和 Namespace 是 Kubernetes 集群中四大基本对象,它们能够表示系统中部署的应用、工作负载、网络和磁盘资源,共同定义了集群的状态。Kubernetes 中很多其他的资源其实只对这些基本的对象进行了组合。

  • Pod -> 集群中的基本单元
  • Service -> 解决如何访问 Pod 里面服务的问题
  • Volume -> 集群中的存储卷
  • Namespace -> 命名空间为集群提供虚拟的隔离作用
    超详细!Kubernetes 学习笔记总结_第2张图片

2.1 Pod实例

Pod是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod 的设计理念是支持多个容器在一个 Pod 中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。

Pod 代表着集群中运行的进程:共享网络、共享存储

Pod 可以被理解成一群可以共享网络、存储和计算资源的容器化服务的集合。再打个形象的比喻,在同一个 Pod 里的几个 Docker 服务/程序,好像被部署在同一台机器上,可以通过 localhost 互相访问,并且可以共用 Pod 里的存储资源(这里是指 Docker 可以挂载 Pod 内的数据卷,数据卷的概念)

同一个 Pod 之间的 Container 可以通过 localhost 互相访问,并且可以挂载 Pod 内所有的数据卷;但是不同的 Pod 之间的 Container 不能用 localhost 访问,也不能挂载其他 Pod 的数据卷。
超详细!Kubernetes 学习笔记总结_第3张图片

K8S 中所有的对象都通过 yaml 来表示,笔者从官方网站摘录了一个最简单的 Pod 的 yaml:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
    volumeMounts:
    - name: redis-storage
      mountPath: /data/redis
  volumes:
  - name: redis-storage
    emptyDir: {}
  • apiVersion记录 K8S 的 API Server 版本,现在看到的都是v1,用户不用管。
  • kind记录该 yaml 的对象,比如这是一份 Pod 的 yaml 配置文件,那么值内容就是Pod。
  • metadata记录了 Pod 自身的元数据,比如这个 Pod 的名字、这个 Pod 属于哪个 namespace(命名空间的概念,后文会详述,暂时理解为“同一个命名空间内的对象互相可见”)。
  • spec记录了 Pod 内部所有的资源的详细信息,看懂这个很重要:
    • containers记录了 Pod 内的容器信息,containers包括了:name容器名,image容器的镜像地址,resources容器需要的 CPU、内存、GPU 等资源,command容器的入口命令,args容器的入口参数,volumeMounts容器要挂载的 Pod 数据卷等。可以看到,上述这些信息都是启动容器的必要和必需的信息。
    • volumes记录了 Pod 内的数据卷信息,后文会详细介绍 Pod 的数据卷。

1、Pod内部结构

首先,我们需要知道的是,每个 Pod 都有一个特殊的被称为 “根容器” 的 Pause 容器。Pause 容器对应的镜像属于 Kubernetes 平台的一部分,通过 Pause 容器使工作在对应 Pod 的容器之间可以共享网络、共享存储。Pod内部结构如下图所示:
超详细!Kubernetes 学习笔记总结_第4张图片
[1] Pod 共享资源
为什么 Kubernetes 会设计出一个全新的 Pod 概念,并且有这样特殊的结构?主要是因为,使用 Pause 容器作为 Pod 根容器,以它的状态代表整个容器组的状态;其次,Pod 里的多个业务容器共享 Pause 容器的 IP 地址,共享 Pause 容器挂接的 Volume 资源。

  • 共享存储资源
    可以为一个 Pod 指定多个共享的 Volume 资源。Pod 中的所有容器都可以访问共享的 volume 资源。Volume 也可以用来持久化 Pod 中的存储资源,以防容器重启后文件丢失。
  • 共享网络资源
    每个 Pod 都会被分配一个唯一的 IP 地址。Pod 中的所有容器共享网络空间,包括 IP 地址和端口。Pod 内部的容器可以使用 localhost 互相通信。Pod 中的容器与外界通信时,必须分配共享网络资源,例如使用宿主机的端口映射。

2、Pod的网络通信

超详细!Kubernetes 学习笔记总结_第5张图片

集群网络解决方案: Kubernetes + Flannel

Kubernetes 的网络模型假定了所有 Pod 都在一个直接连通的扁平的网络空间中,这在 GCE(Google Compute Engine)里面是现成的网络模型,Kubernetes 假定这个网络已经存在了。而在私有云搭建 Kubernetes 集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的 Docker 容器之间的互相访问先打通,然后才能正常运行 Kubernetes 集群。

  • 同一个 Pod 内多个容器之前通过回环网络(lo - 127.0.0.1)进行通信
  • 各 Pod 之间的通讯,则是通过 Overlay Network 网络进行通信
  • 而 Pod 与 Service 之间的通讯,则是各节点的 iptables 或 lvs 规则

Flannel 是 CoreOS 团队针对 Kubernetes 设计的一个网络规划服务,简单来说,它的功能就是让集群中的不同节点主机创建的 Docker 容器都具有全集群唯一的虚拟 IP 地址。而且它还能在这些 IP 地址之间建立一个覆盖的网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递给目标容器内。

超详细!Kubernetes 学习笔记总结_第6张图片
数据包原封格式
超详细!Kubernetes 学习笔记总结_第7张图片
[1] 不同情况下的网络通信方式

  • 同一个 Pod 内部通讯:
    • 同一个 Pod 共享同一个网络命名空间,共享同一个 Linux 协议栈。
  • 不同 Pod 之间通讯:
    • Pod1 和 Pod2 在同一台 Node 主机,由 docker0 网桥直接转发请求到 Pod2 上面,不经过 Flannel 的转发。
    • Pod1 和 Pod2 不在同一台 Node 主机,Pod 的地址是与 docker0 在同一个网段的,但 docker0 网络与宿主机网卡是两个完全不同的 IP 网段,并且不同的 Node 之间的通讯只能通过宿主机的物理网卡进行。将 Pod 的 IP 地址和所在 Node 的 IP 地址关联起来,通过这个关联让 Pod 可以互相访问。
  • Pod 至 Service 的网络
    • 目前基于性能考虑,全部为 iptables 或 lvs 维护和转发。
  • Pod 到外网
    • Pod 想外网发送请求,查找路由表,转发数据包到宿主机的网卡,宿主机网卡完成路由选择之后,iptables 或 lvs 执行 Masquerade,把源 IP 地址更改为宿主机的网卡的 IP 地址,然后向外网服务器发送请求。
  • 外网访问 Pod
    通过 Service 服务来向外部提供 Pod 服务。

[2] ETCD 之于 Flannel 提供说明:

  • 存储管理 Flannel 可分配的 IP 地址段资源
  • 监控 ETCD 中每一个 Pod 的实际 IP 地址,并在内存中建立维护 Pod 节点的路由表
    超详细!Kubernetes 学习笔记总结_第8张图片

3、Pod的多种类型

Pod 存在多种不同的创建类型来满足不一样的用途

超详细!Kubernetes 学习笔记总结_第9张图片
超详细!Kubernetes 学习笔记总结_第10张图片
[1] ReplicationController
ReplicationController 用来确保容器应用的副本数量始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来代替,而如果异常多出现的容器会自动回收。

[2] ReplicaSet
在新版本(相对而言的较优方式)的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 来管理 Pod。虽然 ReplicaSet 和 ReplicationController 并没有本质上的不同,只是名字不一样而已,唯一的区别就是 ReplicaSet 支持集合式的 selector,可供标签筛选。

虽然 ReplicaSet 可以独立使用,但一般还是建议使用 Deployment 来自动管理 ReplicaSet 创建的 Pod,这样就无需担心跟其他机制的不兼容问题。比如 ReplicaSet 自身并不支持滚动更新(rolling-update),但是使用 Deployment 来部署就原生支持。

[3] Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义方法,用来替代以前使用 ReplicationController 来方便且便捷的管理应用。主要的应用场景,包括:滚动升级和回滚应用、扩容和缩容、暂停和继续。

[4] HPA
HPA 仅仅适用于 Deployment 和 ReplicaSet,在 V1 版本中仅支持根据 Pod 的 CPU 利用率扩缩容,在新版本中,支持根据内存和用户自定义的 metric 动态扩缩容。

[5] StatefulSet
StatefulSet 是为了解决有状态服务的问题,相对于 Deployment 和 ReplicaSet 而已。其主要的使用场景,包括:稳定的持久化存储、稳定的网络标识、有序部署、有序收缩。

[6] DaemonSet
DaemonSet 确保全部或者一些 Node 上面运行一个 Pod 副本。当有 Node 加入集群的时候,也会为它们新加一个 Pod。当有 Node 从集群中移除的时候,这些 Pod 也会被回收。删除 DaemonSet 将会删除它所创建的所有 Pod。

使用 DaemonSet 的典型场景就是,在每个节点运行日志收集、运行监控系统、运行集群存储等服务,只要新加进来的节点都需要运行该服务。

[7] Job
Job 负责批处理任务,仅执行一次的任务,它保证批处理任务的一个或者多个 Pod 成功结束,才会返回成功。

[8] Cront Job
Cront Job 管理是基于时间的 Job,即在给定时间点只运行一次,且周期行的在给定时间点运行特定任务

2.2 Volume 数据卷

数据卷 volume 是 Pod 内部的磁盘资源。

volume 是 K8S 的对象,对应一个实体的数据卷;
volumeMounts 只是 container 的挂载点,对应 container 的其中一个参数。
但是,volumeMounts 依赖于 volume,只有当 Pod 内有 volume 资源的时候,该 Pod 内部的 container 才可能有 volumeMounts。

2.3 Deployment 和 ReplicaSet(简称 RS)

本文中提到的镜像 Image、容器 Container,都指代了 Pod 下的一个container。关于 K8S 中的容器,一个 Pod 内可以有多个容器 container。

除了 Pod 之外,K8S 中最常听到的另一个对象就是 Deployment 了。

Deployment 的作用是管理和控制 Pod 和 ReplicaSet,管控它们运行在用户期望的状态中。 Deployment 就是包工头,主要负责监督底下的工人 Pod 干活,确保每时每刻有用户要求数量的 Pod 在工作。如果一旦发现某个工人 Pod 不行了,就赶紧新拉一个 Pod 过来替换它。

那什么是 ReplicaSets 呢?
ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。

ReplicationController 是 ReplicaSet 的前身。

再来翻译下:ReplicaSet 的作用就是管理和控制 Pod,管控他们好好干活。但是,ReplicaSet 受控于 Deployment。形象来说,ReplicaSet 就是总包工头手下的小包工头。
超详细!Kubernetes 学习笔记总结_第11张图片

2.4 Service 和 Ingress

前文介绍的 Deployment、ReplicationController 和 ReplicaSet 主要管控 Pod 程序服务;那么,Service 和 Ingress 则负责管控 Pod 网络服务。

K8S 中的服务(Service)并不是我们常说的“服务”的含义,而更像是网关层,是若干个 Pod 的流量入口、流量均衡器。

Service 是 K8S 服务的核心,屏蔽了服务细节,统一对外暴露服务接口,真正做到了“微服务”。 举个例子,我们的一个服务 A,部署了 3 个备份,也就是 3 个 Pod;对于用户来说,只需要关注一个 Service 的入口就可以,而不需要操心究竟应该请求哪一个 Pod。优势非常明显:一方面外部用户不需要感知因为 Pod 上服务的意外崩溃、K8S 重新拉起 Pod 而造成的 IP 变更,外部用户也不需要感知因升级、变更服务带来的 Pod 替换而造成的 IP 变化,另一方面,Service 还可以做流量负载均衡。


但是,Service 主要负责 K8S 集群内部的网络拓扑。那么集群外部怎么访问集群内部呢?这个时候就需要 Ingress 了,官方文档中的解释是:

Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。

Ingress 是整个 K8S 集群的接入层,复杂集群内外通讯。

Ingress 和 Service 的关系绘制网络拓扑关系图如下
超详细!Kubernetes 学习笔记总结_第12张图片

2.5 namespace 命名空间

namespace 则是为了服务整个 K8S 集群的。

官方文档定义

Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。这些虚拟集群被称为名字空间。

翻译一下:namespace 是为了把一个 K8S 集群划分为若干个资源不可共享的虚拟集群而诞生的。

可以通过在 K8S 集群内创建 namespace 来分隔资源和对象。

# 位于名字空间中的资源
kubectl api-resources --namespaced=true

# 不在名字空间中的资源
kubectl api-resources --namespaced=false

2.6 其他

K8S 的对象实在太多了,其他的还有 Job、CronJob 等等。

3、配置 kubectl

3.1 什么是 kubectl?

官方文档中介绍 kubectl 是:

Kubectl 是一个命令行接口,用于对 Kubernetes 集群运行命令。Kubectl 的配置文件在$HOME/.kube 目录。我们可以通过设置 KUBECONFIG 环境变量或设置命令参数–kubeconfig 来指定其他位置的 kubeconfig 文件。

kubectl具体操作命令:
在 K8S 中,一个独立的服务即对应一个 Pod。即,当我们说要 xxx 一个服务的就是,也就是操作一个 Pod

查看:
kubectl 查看服务的基本命令是:
$ kubectl get|describe ${RESOURCE} [-o ${FORMAT}] -n=${NAMESPACE}
# ${RESOURCE}有: pod、deployment、replicaset(rs)

查看namespace:
$ kubectl get ns
-n=${NAMESPACE}就可以指定自己要操作的资源所在的 namespace。
查看 Pod:kubectl get pod -n=oona-test
查看 Deployment:kubectl get deployment -n=oona-test。

查看所有 namespace 下面部署的 Pod:
$ kubectl get pod --all-namespaces

查找所有的命名空间下的 Deployment 的命令是:
$ kubectl get deployment --all-namespaces

详细查看 -o wide
$ kubectl get pod [-o wide] -n=oona-test
————————————————————————————————————————————
更新/编辑
两种办法:1). 修改 yaml 文件后通过 kubectl 更新;2). 通过 kubectl 直接编辑 K8S 上的服务。

方法一:修改 yaml 文件后通过 kubectl 更新。我们看到,创建一个 Pod 或者 Deployment 的命令是kubectl create -f ${YAML}。
但是,如果 K8S 集群当前的 namespace 下已经有该服务的话,会提示资源已经存在:通过 kubectl 更新的命令是kubectl apply -f ${YAML},我们再来试一试:
(备注:命令kubectl apply -f ${YAML}也可以用于首次创建一个服务哦)

方法二:通过 kubectl 直接编辑 K8S 上的服务。命令为kubectl edit ${RESOURCE} ${NAME},
比如修改刚刚的 Pod 的命令为kubectl edit pod memory-demo,然后直接编辑自己要修改的内容即可。
————————————————————————————————————————————
删除
在 K8S 上删除服务的操作非常简单,命令为kubectl delete ${RESOURCE} ${NAME}。
比如删除一个 Pod 是:kubectl delete pod memory-demo,
比如删除一个 Deployment 的命令是:kubectl delete deployment ${DEPLOYMENT_NAME}。
如果是通过 Deployment 部署的服务,那么仅仅删除 Pod 是不行的,正确的删除方式应该是:先删除 Deployment,再删除 Pod。

有时候会发现一个 Pod 总也删除不了,这个时候很有可能要实施强制删除措施,
命令为kubectl delete pod --force --grace-period=0 ${POD_NAME}

可以通过 kubectl 来操作 K8S 集群,基本语法:

kubectl [command] [TYPE] [NAME] [flags]

其中 command、TYPE、NAME 和 flags 分别是:

  • command:指定要对一个或多个资源执行的操作,例如 create、get、describe、delete。
  • TYPE:指定资源类型。资源类型不区分大小写,可以指定单数、复数或缩写形式。例如,以下命令输出相同的结果:

就如何使用 kubectl 而言,官方文档已经说得非常清楚。不过对于新手而言,还是需要解释几句:

  1. kubectl 是 K8S 的命令行工具,并不需要 kubectl 安装在 K8S 集群的任何 Node 上,但是,需要确保安装 kubectl 的机器和 K8S 的集群能够进行网络互通。
  2. kubectl 是通过本地的配置文件来连接到 K8S 集群的,默认保存在$HOME/.kube 目录下;也可以通过 KUBECONFIG 环境变量或设置命令参数–kubeconfig 来指定其他位置的 kubeconfig 文件【官方文档】。

安装并配置kubectl

3.2 怎么配置 kubectl?

第一步,必须准备好要连接/使用的 K8S 的配置文件,笔者给出一份杜撰的配置:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: thisisfakecertifcateauthoritydata00000000000
    server: https://1.2.3.4:1234
  name: cls-dev
contexts:
- context:
    cluster: cls-dev
    user: kubernetes-admin
  name: kubernetes-admin@test
current-context: kubernetes-admin@test
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    token: thisisfaketoken00000

解读如下:

  • clusters记录了 clusters(一个或多个 K8S 集群)信息:
    • name是这个 cluster(K8S 集群)的名称代号
    • server是这个 cluster(K8S 集群)的访问方式,一般为 IP+PORT
    • certificate-authority-data是证书数据,只有当 cluster(K8S 集群)的连接方式是 https 时,为了安全起见需要证书数据
  • users记录了访问 cluster(K8S 集群)的账号信息:
    • name是用户账号的名称代号
    • user/token是用户的 token 认证方式,token 不是用户认证的唯一方式,其他还有账号+密码等。
  • contexts是上下文信息,包括了 cluster(K8S 集群)和访问 cluster(K8S 集群)的用户账号等信息:
    • name是这个上下文的名称代号
    • cluster是 cluster(K8S 集群)的名称代号
    • user是访问 cluster(K8S 集群)的用户账号代号
  • current-context记录当前 kubectl 默认使用的上下文信息
  • kind和apiVersion都是固定值,用户不需要关心
  • preferences则是配置文件的其他设置信息,笔者没有使用过,暂时不提。

第二步,给 kubectl 配置上配置文件。.

  1. --kubeconfig参数。第一种办法是每次执行 kubectl 的时候,都带上--kubeconfig=${CONFIG_PATH}。给一点温馨小提示:每次都带这么一长串的字符非常麻烦,可以用 alias 别名来简化码字量,比如alias k=kubectl --kubeconfig=${CONFIG_PATH}
  2. KUBECONFIG环境变量。第二种做法是使用环境变量KUBECONFIG把所有配置文件都记录下来,即export KUBECONFIG=$KUBECONFIG:${CONFIG_PATH}。接下来就可以放心执行 kubectl 命令了。
  3. $HOME/.kube/config 配置文件。第三种做法是把配置文件的内容放到$HOME/.kube/config 内。具体做法为:
    a. 如果$HOME/.kube/config 不存在,那么cp ${CONFIG_PATH} $HOME/.kube/config即可;
    b. 如果如果 $HOME/.kube/config已经存在,那么需要把新的配置内容加到 $HOME/.kube/config 下。单单只是cat ${CONFIG_PATH} >> $HOME/.kube/config是不行的,正确的做法是:KUBECONFIG=$HOME/.kube/config:${CONFIG_PATH} kubectl config view --flatten > $HOME/.kube/config 。解释下这个命令的意思:先把所有的配置文件添加到环境变量KUBECONFIG中,然后执行kubectl config view --flatten打印出有效的配置文件内容,最后覆盖$HOME/.kube/config 即可。

请注意,上述操作的优先级分别是 1>2>3,也就是说,kubectl 会优先检查–kubeconfig,若无则检查KUBECONFIG,若无则最后检查$HOME/.kube/config,如果还是没有,报错。但凡某一步找到了有效的 cluster,就中断检查,去连接 K8S 集群了。

第三步:配置正确的上下文。
按照第二步的做法,如果配置文件只有一个 cluster 是没有任何问题的,但是对于有多个 cluster 怎么办呢?到这里,有几个关于配置的必须掌握的命令:

kubectl config get-contexts。列出所有上下文信息。

kubectl config current-context。
查看当前的上下文信息。其实,命令 1 线束出来的*所指示的就是当前的上下文信息。

kubectl config use-context ${CONTEXT_NAME}。更改上下文信息。

kubectl config set-context ${CONTEXT_NAME}|--current --${KEY}=${VALUE}。
修改上下文的元素。比如可以修改用户账号、集群信息、连接到 K8S 后所在的 namespace。

关于该命令,还有几点要啰嗦的:

  • config set-context可以修改任何在配置文件中的上下文信息,只需要在命令中指定上下文名称就可以。而–current 则指代当前上下文。

  • 上下文信息所包括的内容有:cluster 集群(名称)、用户账号(名称)、连接到 K8S 后所在的 namespace,因此有config set-context严格意义上的用法:

kubectl config set-context [NAME|--current] [--cluster=cluster_nickname] [--user=user_nickname] [--namespace=namespace] [options]

(备注:[options]可以通过 kubectl options 查看)

4、kubectl 部署服务

K8S 核心功能就是部署运维容器化服务,因此最重要的就是如何又快又好地部署自己的服务了。本章会介绍如何部署 Pod 和 Deployment。

4.1 如何部署 Pod?

通过 kubectl 部署 Pod 的办法分为两步:1). 准备 Pod 的 yaml 文件;2). 执行 kubectl 命令部署

第一步:准备 Pod 的 yaml 文件。

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
    volumeMounts:
    - name: redis-storage
      mountPath: /data/redis
  volumes:
  - name: redis-storage
    emptyDir: {}

继续解读:

  • metadata,对于新入门的同学来说,需要重点掌握的两个字段:
    • name。这个 Pod 的名称,后面到 K8S 集群中查找 Pod 的关键字段。
    • namespace。命名空间,即该 Pod 隶属于哪个 namespace 下,关于 Pod 和 namespace 的关系,上一篇文章已经交代了。
  • spec记录了 Pod 内部所有的资源的详细信息,这里我们重点查看containers下的几个重要字段:
    • name。Pod 下该容器名称,后面查找 Pod 下的容器的关键字段。

    • image。容器的镜像地址,K8S 会根据这个字段去拉取镜像。

    • resources。容器化服务涉及到的 CPU、内存、GPU 等资源要求。可以看到有limits和requests两个子项。
      limits是 K8S 为该容器至多分配的资源配额;
      而requests则是 K8S 为该容器至少分配的资源配额。
      打个比方,配置中要求了 memory 的requests为 100M,而此时如果 K8S 集群中所有的 Node 的可用内存都不足 100M,那么部署服务会失败;又如果有一个 Node 的内存有 16G 充裕,可以部署该 Pod,而在运行中,该容器服务发生了内存泄露,那么一旦超过 200M 就会因为 OOM 被 kill,尽管此时该机器上还有 15G+的内存。

    • command。容器的入口命令。

    • args。容器的入口参数。

    • volumeMounts。容器要挂载的 Pod 数据卷等。请务必记住:Pod 的数据卷只有被容器挂载后才能使用!

第二步:执行 kubectl 命令部署。 有了 Pod 的 yaml 文件之后,就可以用 kubectl 部署了,命令非常简单:kubectl create -f ${POD_YAML}

4.2 如何部署 Deployment?

第一步:准备 Deployment 的 yaml 文件。首先来看 Deployment 的 yaml 文件内容:

 apiVersion: extensions/v1beta1
 kind: Deployment
 metadata:
   name: rss-site
   namespace: mem-example
 spec:
   replicas: 2
   template:
     metadata:
       labels:
         app: web
     spec:
      containers:
       - name: memory-demo-ctr
         image: polinux/stress
         resources:
         limits:
           emory: "200Mi"
         requests:
           memory: "100Mi"
         command: ["stress"]
         args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
         volumeMounts:
         - name: redis-storage
           mountPath: /data/redis
     volumes:
     - name: redis-storage
       emptyDir: {}

继续来看几个重要的字段:

  • metadata同 Pod 的 yaml,这里提一点:如果没有指明 namespace,那么就是用 kubectl 默认的 namespace(如果 kubectl 配置文件中没有指明 namespace,那么就是 default 空间)。
  • spec,可以看到 Deployment 的spec字段是在 Pod 的spec内容外“包了一层”,那就来看 Deployment 有哪些需要注意的:
    • spec,会发现这完完全全是上文提到的 Pod 的spec内容,在这里写明了 Deployment 下属管理的每个 Pod 的具体内容。
    • replicas。副本个数。也就是该 Deployment 需要起多少个相同的 Pod,如果用户成功在 K8S 中配置了 n(n>1)个,那么 Deployment 会确保在集群中始终有 n 个服务在运行。
    • template。

第二步:执行 kubectl 命令部署。Deployment 的部署办法同 Pod:kubectl create -f ${DEPLOYMENT_YAML}。由此可见,K8S 会根据配置文件中的kind字段来判断具体要创建的是什么资源。

这里插一句题外话:部署完 deployment 之后,可以查看到自动创建了 ReplicaSet 和 Pod。

5、K8s部署服务失败

拉到最后看到Events部分:kubectl describe ${RESOURCE} ${NAME}

如果服务部署成功了,且状态为running,那么就需要进入 Pod 内部的容器去查看自己的服务日志了:

  • 查看 Pod 内部某个 container 打印的日志:kubectl log ${POD_NAME} -c ${CONTAINER_NAME}。
  • 进入 Pod 内部某个 container:kubectl exec -it [options] ${POD_NAME} -c ${CONTAINER_NAME} [args],嗯,这个命令的作用是通过 kubectl 执行了docker exec xxx进入到容器实例内部。之后,就是用户检查自己服务的日志来定位问题。

你可能感兴趣的:(运维,#,K8s,运维,kubernetes)