kubeadm是帮助用户快速部署kubernetes项目的工具。

kubeadm工作原理

k8s的部署是一个非常麻烦的事情,通过与容器结果,将k8s的组件利用容器部署可能会简化,但是kubelet的容器化是非常麻烦的事情。因为除了跟容器运行时打交道外,kubelet 在配置容器网络、管理容器数据卷时,都需要直接操作宿主机。如果kubelet运行在容器中,那么它对宿主机的操作就会十分麻烦

因此,kubeadm选择了一种折中方案:

将kubelet直接运行在宿主机上,然后使用容器部署其它的kubernetes组件

使用kubeadm的第一步,是在机器上安装kubeamd、kubelet和kubectl三个二进制文件,kubeadm为各个Linux发行版准备好了安装包,直接使用对应包管理工具即可安装。例如

$ apt-get install kubeadm

yum包管理器需要添加仓库源

cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

国内将源换为阿里源

cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

接下来便可以使用kubeadm init部署Master节点了。

kubeadm init工作流程

kubeadm init指定是用来部署k8s的Master节点的。

执行执行后,首先,kubeadm进行一系列检查工作,以确定这台机器可以部署kubenetes。这一步被称为“Preflights Checks”,涉及到相当多的检查内容。

检查通过后,生成kubenetes对外提供服务需要的各种证书和对应的目录。k8s对外提供服务,除非专门开启不安全模式,否则都要通过HTTPS才能访问kube-apiserver。kubeadm为k8s项目生成的证书都放在master节点的/etc/kubernetes/pki目录下,其中最重要的就是ca.crt和对应的私钥ca.key了。用户使用 kubectl 获取容器日志等 streaming 操作时,需要通过 kube-apiserver 向 kubelet 发起请求,这个连接也必须是安全的。kubeadm 为这一步生成的是 apiserver-kubelet-client.crt 文件,对应的私钥是 apiserver-kubelet-client.key。可以选择不生成证书,而是拷贝现有证书到对应的目录中

证书生成后,为其它组件生成访问kube-apiserver所需的配置文件。文件的路径为/etc/kubernetes/xxx.conf,xxx是组件的名称。

接下来,为Master组件生成Pod配置文件。k8s的Master节点的三个组件都会以Pod的方式部署起来。在 /etc/kubernetes/manifests路径下生成组件的Pod Yaml配置文件。比如kube-apiserver.yaml:

apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --authorization-mode=Node,RBAC
    - --runtime-config=api/all=true
    - --advertise-address=10.168.0.2
    ...
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    image: k8s.gcr.io/kube-apiserver-amd64:v1.11.1
    imagePullPolicy: IfNotPresent
    livenessProbe:
      ...
    name: kube-apiserver
    resources:
      requests:
        cpu: 250m
    volumeMounts:
    - mountPath: /usr/share/ca-certificates
      name: usr-share-ca-certificates
      readOnly: true
    ...
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /etc/ca-certificates
      type: DirectoryOrCreate
    name: etc-ca-certificates
  ...

然后还会生成一个Etcd的Pod YAML文件,通过同样的Static Pod方式来启动Etcd。最后Master组件的Pod Yaml文件如下:

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

一旦这些 YAML 文件出现在被 kubelet 监视的 /etc/kubernetes/manifests 目录下,kubelet 就会自动创建这些 YAML 文件中定义的 Pod,即 Master 组件的容器

Master启动后,kubeadm会通过检查localhost:6443/healthz这个Master组件的健康检查URL,来等待Master组件全部启动。

然后,kubeadm会生成一个bootstrap token,通过这个token,任何一个安装了kubeadm和kubelet的节点,都可以通过kubeadm join加入到这个集群当中。

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

最后一步,安装默认插件,k8s默认必须安装kube-proxy和DNS这两个插件,用来提供整个集群的服务发现和DNS功能。

kubeadm join工作流程

kubeadm join <master节点的IP和端>

将Node节点加入到集群当中。需要kubeadm init生成的token。

这是因为任何一台机器想要称为kubernetes中的一个节点,就必须在集群的kube-apiserver上注册,但是要想跟apiserver交互,这台机器就必须获取到相应的证书文件,但是为了一键安装,就不能让用户去Master节点上手动拷贝证书,于是使用发起“不安全的访问”来获取到保存在ConfigMap中的cluster-info(保存了apiserver的授权信息),token就是这个访问中安全验证的角色。

只要获取到了cluster-info中kube-apiserver的地址、端口、证书,kubelet就可以以安全模式连接到apiserver上,新的节点就加入集群中了。

接下来只要在需要加入集群的节点上不断重复这条指定就行了。

配置kubeadm的部署参数

使用kubeadm使得集群的部署变得简易,也可以设置部署参数,定制集群组件参数。

通过如下命令指定配置文件来设置kubeadm的部署参数

$ kubeadm init --config kubeadm.yaml

一个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
  ...

然后,kubeadm 就会使用上面这些信息替换 /etc/kubernetes/manifests/xxx.yaml 里组件的 command 字段里的参数了。


tags: k8s集群部署