程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

Kubernetes | Kubernetes 集群部署

发表于 2020-06-19 | 分类于 Kubernetes | 0 | 阅读次数 2398

1. Kubernetes 部署本质

部署的本质,其实就是将 Kubernetes 各个组件编译成二进制文件,并且为这些二进制文件编写对应的配置文件、配置自启动脚本,以及为 kube-apiserver 配置授权文件等等诸多运维工作。(可继续参考张磊老师:k8s 的本质一节的内容)

kubernetes 安装用到的二进制

  • kubeadm
    • kubeadm.yaml
  • kubectl
  • kubelet
    • kubelet.service(如在 /etc/systemd/system/ 中)
    • kubelet.service.d/10-kubeadm.conf (如在 /etc/systemd/system/ 中)
    • /var/lib/kubelet/config.yaml

kubernetes 所需的相关组件

  • etcd(相关组件)
  • api-server
  • controller
  • scheduler
  • DNS

网络相关-CNI 插件

  • bridge 等

containerd 容器运行时

  • containerd、container-shim、runc 等二进制
  • /etc/containerd/config.toml
  • containerd.service(如:/etc/systemd/system/containerd.service)
  • /var/run/containerd/containerd.sock
  • /var/lib/containerd

命令行工具

  • crictl
    • crictl.yaml

Docker 容器运行时

  • dockerd、containerd、containerd-shim 等二进制
  • /etc/systemd/system/docker.service
  • /var/run/docker.sock、/var/run/dockershim.sock
  • /var/lib/docker

2. Kubernetes 部署发展历程

Kubernetes 项目发布初期,Kubernetes 的部署完全依靠一堆由社区维护的脚本。

2018 年的时候,各大云厂商最常用的部署方法,是使用 SaltStack、Ansible 等运维工具自动化地执行上述部署过程。但是,由于 SaltStack 这类专业的运维工具本身的学习成本,就可能比 Kubernetes 要高,所以部署过程还是相当繁琐。

SaltStack 这样的运维工具或者由社区维护的脚本的功能,就是把各个组件编译成的二进制传输到指定的机器当中,然后编写控制脚本来启停这些组件。

而为了解决 Kubernetes 部署繁琐的问题,2017 年,在志愿者的推动下,社区发起了一个独立的部署工具:kubeadm:https://github.com/kubernetes/kubeadm。kubeadm 项目的目的就是要让用户能够通过下面这两条指令完成一个 kubernetes 集群的部署:

# 创建一个Master节点
$ kubeadm init

# 将一个Node节点加入到当前集群中
$ kubeadm join <Master节点的IP和端口>

3. kubeadm 部署

3.1. kubeadm init 的流程

kubelet 以二进制的方式直接运行在宿主机上,然后使用容器部署其他的 kubernetes 组件。

  • 所以第一步是在机器上手动安装 kubeadm、kubelet、kubectl 这几个二进制文件。

    apt-get install kubeadm
    
  • 接下去就可以使用 kubeadm init 来部署 master 节点了

    • kubeadm init 执行之后,首先要做的,是一系列的检查工作,以确定这台机器可以用来部署 Kubernetes,称为“Preflight Checks”。主要包含以下几个方面:

      • Linux 内核的版本必须是否是 3.10 以上
      • Linux Cgroups 模块是否可用
      • 机器的 hostname 是否标准?在 Kubernetes 项目里,机器的名字以及一切存储在 Etcd 中的 API 对象,都必须使用标准的 DNS 命名(RFC 1123)
      • 用户安装的 kubeadm 和 kubelet 的版本是否匹配
      • 机器上是不是已经安装了 Kubernetes 的二进制文件
      • Kubernetes 的工作端口 10250/10251/10252 端口是不是已经被占用
      • ip、mount 等 Linux 指令是否存在
      • Docker 是否已经安装
      • ......
    • 通过 preflight checks 之后,kubeadm 要做的就是生成 kubernetes 对外提供服务所需要的各种证书和对应的目录

      • Kubernetes 对外提供服务时,除非专门开启“不安全模式”,否则都要通过 HTTPS 才能访问 kube-apiserver。这就需要为 Kubernetes 集群配置好证书文件。kubeadm 为 Kubernetes 项目生成的证书文件都放在 Master 节点的 /etc/kubernetes/pki 目录下。在这个目录下,最主要的证书文件是 ca.crt 和对应的私钥 ca.key。
      • 此外,用户使用 kubectl 获取容器日志等 streaming 操作时,需要通过 kube-apiserver 向 kubelet 发起请求,这个连接也必须是安全的。kubeadm 为这一步生成的是 apiserver-kubelet-client.crt 文件,对应的私钥是 apiserver-kubelet-client.key。
      • 除此之外,Kubernetes 集群中还有 Aggregate APIServer 等特性,也需要用到专门的证书,具体可以看相应的目录。

      需要注意的是,可以选择不让 kubeadm 为你生成这些证书,而是拷贝现有的证书到如下证书的目录里:/etc/kubernetes/pki/ca.{crt,key},这个时候 kubeadm 就会跳过证书生成的步骤,把它完全交给用户处理。

    • 证书生成后,kubeadm 接下来会为其他组件生成访问 kube-apiserver 所需的配置文件。这些文件的路径是:/etc/kubernetes/xxx.conf:

      ls /etc/kubernetes/
      admin.conf  controller-manager.conf  kubelet.conf  scheduler.conf
      

      这些文件里面记录的是,当前这个 Master 节点的服务器地址、监听端口、证书目录等信息。这样,对应的客户端(比如 scheduler,kubelet 等),可以直接加载相应的文件,使用里面的信息与 kube-apiserver 建立安全连接。

    • kubeadm 会为 Master 上所需要的组件(kube-apiserver、kube-controller-manager、kube-scheduler)生成 Pod YAML 文件。假如没有提供一个外部的 eted 服务的话,也会再生成一个 Etcd 的 Pod YAML 文件。由于这个时候 kubernetes 集群还没有起来,此时将采用 static pod 方式来启动这些 Pod。Static Pod 是把要部署的 Pod 的 YAML 文件放在一个指定的目录里,那么当这台机器上的 kubelet 启动时,它会自动检查这个目录,加载所有的 Pod YAML 文件,然后在这台机器上启动它们。

      在 kubeadm 中,Master 组件的 YAML 文件会被生成在 /etc/kubernetes/manifests 路径下,一旦相应的 YAML 文件出现在这个目录下,kubelet 就会自动创建这些 YAML 文件中定义的 Pod,即 Master 组件的容器。最后 Master 组件的 Pod YAML 文件如下所示:

      $ ls /etc/kubernetes/manifests/
      etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml
      

      kubelet 在 Kubernetes 项目中的地位非常高,在设计上它就是一个完全独立的组件,而其他 Master 组件,则更像是辅助性的系统容器。

    • 对控制平面节点应用标签和污点标记,以便不会在它上面运行其他的工作负载。

    • Master 容器启动后,kubeadm 会通过检查 localhost:6443/healthz 这个 Master 组件的健康检查 URL,等待 Master 组件完全运行起来。

    • 然后,kubeadm 就会为集群生成一个 bootstrap token。在后面,只要持有这个 token,任何一个安装了 kubelet 和 kubadm 的节点,都可以通过 kubeadm join 加入到这个集群当中。这个 token 的值和使用方法,会在 kubeadm init 结束后被打印出来。

      在 token 生成之后,kubeadm 会将 ca.crt 等 Master 节点的重要信息,通过 ConfigMap 的方式保存在 Etcd 当中,供后续部署 Node 节点使用。这个 ConfigMap 的名字是 cluster-info。

    • kubeadm init 的最后一步,就是安装默认插件。Kubernetes 默认 kube-proxy 和 DNS 这两个插件是必须安装的。它们分别用来提供整个集群的服务发现和 DNS 功能。其实,这两个插件也只是两个容器镜像而已,所以 kubeadm 只要用 Kubernetes 客户端创建两个 Pod 就可以了。

https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/kubeadm-init/

3.2. kubeadm join 的流程

kubeadm init 生成 bootstrap token 之后,你就可以在任意一台安装了 kubelet 和 kubeadm 的机器上执行 kubeadm join 了。

需要 bootstrap token 的原因

任何一台机器想要成为 kubernetes 集群中的一个节点,就必须在集群的 kube-apiserver 上注册。可是,要想跟 apiserver 打交道,这台机器就必须要获取到相应的证书文件(CA 文件)。可是,为了能够一键安装,我们就不能让用户去 Master 节点上手动拷贝这些文件。

保存在 ConfigMap 中的 cluster info。cluster info 保存了 APIServer 的授权信息,比如 kube-apiserver 的地址、端口、证书等,有了这些信息之后,。

所以这个时候 kubeadm 至少需要向 kube-apiserver 发起一次 “不安全模式”的访问,从而拿到保存在 ConfigMap 中的 cluster info,进而拿到相关的证书。而 bootstrap token,扮演的就是这个过程中的安全验证的角色,从而确保这次不安全的访问是安全的。

得到了 kube-apiserver 的地址、端口、证书之后,kubelet 就可以以安全模式连接到 apiserver 上。这样,一个新的节点就部署完成了。

3.3. 配置 kubeadm 的部署参数

默认情况下,我们使用 kubeadm init 和 kubeadm join 的默认参数就可以完成一个集群的搭建了,但是有时候我们希望可以配置集群组件,比如 apiserver 的启动参数。这个时候也可以指定使用一个 YAML 来部署集群,

kubeadm init --config kubeadm.yaml
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.11.0
api:
  advertiseAddress: 192.168.0.102
  bindPort: 6443
  ...
etcd:
  local:
    dataDir: /var/lib/etcd
    image: ""
imageRepository: k8s.gcr.io
kubeProxy:
  config:
    bindAddress: 0.0.0.0
    ...
kubeletConfiguration:
  baseConfig:
    address: 0.0.0.0
    ...
networking:
  dnsDomain: cluster.local
  podSubnet: ""
  serviceSubnet: 10.96.0.0/12
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  ...

YAML 文件是部署参数配置文件,你可以在 YAML 文件里填写各种自定义的部署参数。比如要指定 kube-apiserver 的参数,那么在文件里头加上如下内容即可。这样,kubeadm 就会用这些内容来替换 /etc/kubernetes /manifests/kube-apiserver.yaml 里的 command 字段里的参数了。

...
apiServerExtraArgs:
  advertise-address: 192.168.0.103
  anonymous-auth: false
  enable-admission-plugins: AlwaysPullImages,DefaultStorageClass
  audit-log-path: /home/johndoe/audit.log

除此之外,你还可以通过 YAML 文件

  • 修改 kubelet 和 kube-proxy 的配置,
  • 修改 kubernetes 使用的基础镜像的 URL(默认的 k8s.gcr.io/xxx 镜像在国内访问是有困难的)
  • 指定自己的证书文件
  • 指定特殊的容器运行时

3.4. 为什么 kubelet 不用容器方式部署

kubelet 是 Kubernetes 项目用来操作 Docker 等容器运行时的核心组件。可是除了跟容器运行时打交道外,kubelet 在配置网络、管理容器数据卷时,都需要操作宿主机。

而如果 kubelet 本身就运行在一个容器里,那么直接操作宿主机就会变得很麻烦。对于网络配置来说还好,kubelet 容器可以通过不开启 Network Namespace(即 Docker 的 host network 模式)的方式,直接共享宿主机的网络栈。可是,要让 kubelet 隔着容器的 Mount Namespace 和文件系统,操作宿主机的文件系统,就有点儿困难了。

比如,如果用户想要使用 NFS 做容器的持久化数据卷,那么 kubelet 就需要在容器进行绑定挂载前,在宿主机的指定目录上,先挂载 NFS 的远程目录。可是,这时候问题来了。由于现在 kubelet 是运行在容器里的,这就意味着它要做的这个“mount -F nfs”命令,被隔离在了一个单独的 Mount Namespace 中。即,kubelet 做的挂载操作,不能被“传播”到宿主机上。

对于这个问题,有人说可以使用 setns() 系统调用,在宿主机的 Mount Namespace 中执行这些挂载操作;也有人说,应该让 Docker 支持一个–mnt=host 的参数。但是,到目前为止,在容器里运行 kubelet,依然没有很好的解决办法,也不推荐你用容器去部署 Kubernetes 项目。

所以 kubeadm 采用的方式是将 kubelet 这个组件的二进制直接部署在宿主机上,而其他 kubernetes 组件则使用容器的方式部署起来。

3.5. 存在的问题

从上面我们可以看到,kubeadm 更多是将一个节点部署成 master 节点。所以说 kubeadm 欠缺的是一键部署一个高可用的 kubernetes 集群的能力,即 Etcd、Master 组件都应该是多节点集群,而不是单点的。

4. 巨人的肩膀

  1. https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/kubeadm-init/
  2. 极客时间,张磊,《深入剖析 kubernetes》

5. 实操-安装和使用

  • 首先是替换 apt-get 源,可以给 apt-get 添加一个源;

  • 下载 Docker 和 kubeadm(使用 apt-get 下载 kubeadm 的时候,kubeadm 往往已经包含了 kubelet 和 kubectl,假如没有这两个也需要下载);

  • 关闭 swap;

  • 获取镜像列表,预下载先,因为默认使用的镜像很难下载;

  • kubeadm init/kubeadm join;

  • 配置授权信息,以便 kubectl 可以访问 kube-apiserver;

  • 单节点,设置 master 节点也可以运行 Pod;

  • 假如提示没有网络,那么需要额外安装网络插件,比如 CNI 插件安装包

具体的安装步骤可以参考下面这几个网址:

  1. https://zhuanlan.zhihu.com/p/46341911

  2. https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/

  3. 极客时间,《Serverless入门课》

6. 附: kubeadm/kubectl 使用

6.1. kubeadm 命令

# 创建一个Master节点
$ kubeadm init
$ kubeadm init --config kubeadm.yaml

# 将一个Node节点加入到当前集群中
$ kubeadm join <Master节点的IP和端口>

kubeadm join 10.168.0.2:6443 --token 00bwbx.uvnaa2ewjflwu1ry --discovery-token-ca-cert-hash sha256:00eb62a2a6020f94132e3fe1ab721349bbcd3e9b94da9654cfe15f2985ebd711

6.2. kubectl 命令

kubectl config get-contexts		# 查看当前选中的集群
kubectl config use-context docker-desktop		# 切换集群为 docker-desktop

kubectl describe node master

kubectl describe pod nginx-deployment-67594d6bf6-9gdvr

kubectl get nodes

kubectl get pods
kubectl get pods -l app=nginx
kubectl get pods -n kube-system

kubectl get all	# 查看当前 k8s 环境的整体情况
kubectl get all -n kube-system	# 安装好的 k8s 系统运行状况

kubectl get secret regcred

kubectl create secret docker-registry regcred --docker-server=registry.cn-shanghai.aliyuncs.com --docker-username=你的容器镜像仓库用户名 --docker-password=你的容器镜像仓库密码

kubectl exec -it nginx-deployment-5c678cfb6d-lg9lw -- /bin/bash

kubectl create -f nginx-deployment.yaml
kubectl apply -f nginx-deployment.yaml
kubectl delete -f nginx-deployment.yaml
kubectl delete pod/你的 pod 名字


kubectl label nodes 1.1.1.1 role=nginx
kubectl label nodes 1.1.1.1 role-	# 删除一个Label,只需在命令行最后指定Label的key名并与一个减号相连即可

kubectl label nodes 1.1.1.1 role=apache --overwrite # 修改一个Label的值,需要加上 --overwrite 参数

6.3. 集群容器运行时清理

Containerd:

  1. /var/lib/containerd — 清空

  2. /var/run/containerd/containerd.sock — 清空

  3. Containerd 二进制文件(相关的二进制文件)— 清空/覆盖

  4. /etc/systemd/system/containerd.service — 清空/覆盖

  5. /etc/containerd/config.toml — 覆盖

Docker

  1. /var/lib/docker — 清空

  2. /var/run/docker.sock — 清空

  3. /var/run/dockershim.sock — 清空

  4. Docker 相关二进制(也会包含 containerd 相关) — 清空/覆盖

  5. /etc/systemd/system/docker.service — 清空/覆盖

巨人的肩膀

  1. 极客时间.《深入剖析Kubernetes》.张磊
  2. 《Kubernetes 权威指南》
卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/157
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# 云原生 # Kubernetes
Kubernetes | Kubernetes 简介
Kubernetes | Pod 的使用
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%