搭建一个完整的 Kubernetes 集群

为了应对 IT 上云趋势,提前学习相关技术栈,以及研究基于 Kubernetes 的 GPU 资源调度及用户隔离,花了 2 天时间,利用 kubeadm 搭建了一个 Kubernetes 集群的学习环境。

1.1 准备工作

在本次部署中,我准备了 3 台公有云上的虚拟机,hostname 分别为 master、worker1、worker2,机器的配置如下:

  • 2 核 CPU、7.5 GB 内存
  • 30 GB 磁盘
  • Ubuntu 16.04
  • 内网互通
  • 外网访问权限不受限制,因为要拉取镜像

部署的目标:

  • 在所有节点上安装 Docker 和 kubeadm
  • 部署 Kubernetes Master
  • 部署容器网络插件
  • 部署 Kubernetes Worker
  • 部署 Dashboard 可视化插件
  • 部署容器存储插件

1.2 安装 kubeadm 和 Docker

安装 kubeadm,只需要添加 kubdadm 的源,然后直接使用 apt-get 安装即可,为了方便,后续会直接在 root 用户下进行操作。

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF > /etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y docker.io kubeadm

在安装 kubeadm 的过程中,kubeadm 和 kubelet、kubectl、kubernetes-cni 这几个二进制文件会被自动安装好。kubeadm、kubelet、kubectl 的版本为 1.17.4-00,Docker 的版本为 18.09.7。

1.3 部署 Kubernetes 的 Master 节点

编写一个给 kubeadm 用的 YAML 文件 kubeadm.yaml

mkdir -p Projects/Kubernetes
cd Projects/Kubernetes/
cat <<EOF > kubeadm.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
controllerManager:
    extraArgs:
        horizontal-pod-autoscaler-use-rest-clients: "true"
        horizontal-pod-autoscaler-sync-period: "10s"
        node-monitor-grace-period: "10s"
apiServer:
    extraArgs:
        runtime-config: "api/all=true"
kubernetesVersion: "v1.17.0"
EOF

这个配置文件中,给 kube-controller-manager 设置了 horizontal-pod-autoscaler-use-rest-clients: "true",将来部署的 kube-controller-manager 能够使用自定义资源进行自动水平扩展。

v1.17.0 是 kubeadm 帮我们部署的 Kubernetes 的版本号。

然后我们执行如下指令完成 Kubernetes Master 的部署,

kubeadm init --config kubeadm.yaml

部署完成后,会有如下信息提示。


Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:


kubeadm join 10.140.0.7:6443 --token jt5wl5.hxg7a82w4tay9u07 \
    --discovery-token-ca-cert-hash sha256:c1d5c89113ae42a7e3733e2c841398aac96f4634e7f1457bf3311551340647f1

kubeadm 会提示我们第一次使用 Kubernetes 集群所需要的配置命令,

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

需要这些配置命令的原因是:Kubernetes 集群默认需要加密方式访问,所以,这几条命令,是将刚刚部署生成的 Kubernetes 集群的安全配置文件 ,保存到当前用户的 .kube 目录下,kubectl 默认会使用这个目录下的授权信息访问 Kubernetes 集群。否则,我们每次需要通过 export KUBECONFIG环境变量告诉 kubectl 这个安全配置文件的位置。

现在,可以使用 kubectl get 命令查看当前唯一一个节点的状态,

$ kubectl get nodes
NAME     STATUS     ROLES    AGE     VERSION
master   NotReady   master   9m44s   v1.17.4

可以看到,master 节点的状态是 NotReady,我们再用 kubectl describe 查看一下这个节点对象的详细信息、状态和事件,

$ kubectl describe node master
...
Conditions:
  Ready            False   Sat, 21 Mar 2020 11:16:15 +0000   Sat, 21 Mar 2020 11:05:53 +0000   KubeletNotReady              runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

通过输出结果,我们看到 NotReady 的原因在于,我们没有部署任何网络插件。而在 kubeadm 部署完成后,其中一条提示信息为部署一个网络 pod 到集群。

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

另外,我们还可以通过 kubectl 检查这个节点上各个系统 Pod 的状态,其中 kube-system 是 Kubernetes 预留的系统 Pod 的工作空间(Namespace)。

$ kubectl get pods -n kube-system
NAME                             READY   STATUS    RESTARTS   AGE
coredns-6955765f44-6vq56         0/1     Pending   0          23m
coredns-6955765f44-mbxn6         0/1     Pending   0          23m
etcd-master                      1/1     Running   0          23m
kube-apiserver-master            1/1     Running   0          23m
kube-controller-manager-master   1/1     Running   0          23m
kube-proxy-bgzwt                 1/1     Running   0          23m
kube-scheduler-master            1/1     Running   0          23m

可以看到,CoreDNS 这个依赖于网络的 Pod 处于 Pending 状态,即调度失败。

1.4 部署网络插件

https://kubernetes.io/docs/concepts/cluster-administration/addons/ 中,找到 Weave Net 的部署方法,同时需要注意防火墙的端口设置。

Before installing Weave Net, you should make sure the following ports are not blocked by your firewall: TCP 6783 and UDP 6783/6784. For more details, see the FAQ.

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
serviceaccount/weave-net created
clusterrole.rbac.authorization.k8s.io/weave-net created
clusterrolebinding.rbac.authorization.k8s.io/weave-net created
role.rbac.authorization.k8s.io/weave-net created
rolebinding.rbac.authorization.k8s.io/weave-net created
daemonset.apps/weave-net created
$ kubectl get pods -n kube-system
NAME                             READY   STATUS    RESTARTS   AGE
coredns-6955765f44-6vq56         1/1     Running   0          36m
coredns-6955765f44-mbxn6         1/1     Running   0          36m
etcd-master                      1/1     Running   0          36m
kube-apiserver-master            1/1     Running   0          36m
kube-controller-manager-master   1/1     Running   0          36m
kube-proxy-bgzwt                 1/1     Running   0          36m
kube-scheduler-master            1/1     Running   0          36m
weave-net-dw7hl                  2/2     Running   0          3m6s

可以看到,所有的系统 Pod 都成功启动了,而刚刚部署的 Weave 网络插件则在 kube-systeme 下面新建了一个名叫 weave-net-dw7hl 的 Pod。

至此,Kubernetes 的 Master 节点部署完成。

1.5 部署 Kubernetes 的 Worker 节点

Kubernetes 的 Worker 节点跟 Master 节点几乎是相同的,它们运行着的都是一个 kubelet 组
件。唯一的区别在于,在 kubeadm init 的过程中,kubelet 启动后,Master 节点上还会自动运行
kube-apiserver、kube-scheduler、kube-controller-manger 这三个系统 Pod。

部署 Worker 节点只需要两步即可完成:
第一步,在所有 Worker 节点上执行“安装 kubeadm 和 Docker”一节的所有步骤。
第二步,执行部署 Master 节点时生成的 kubeadm join 指令:

kubeadm join 10.140.0.7:6443 --token jt5wl5.hxg7a82w4tay9u07 \
    --discovery-token-ca-cert-hash sha256:c1d5c89113ae42a7e3733e2c841398aac96f4634e7f1457bf3311551340647f1

部署完成后,提示如下信息:

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

1.6 通过 Taint/Toleration 调整 Master 执行 Pod 的策略

默认情况下 Master 节点是不允许运行用户 Pod 的。而 Kubernetes 做到这一
点,依靠的是 Kubernetes 的 Taint/Toleration 机制。

通过 kubectl describe 查看一些 Master 节点的 Trint 字段,会发现:

Name:               master
Roles:              master
Taints:             node-role.kubernetes.io/master:NoSchedule

在这里,我们要一个单节点的 Kubernetes,所以直接删除这个 Taint,

$ kubectl taint nodes --all node-role.kubernetes.io/master-
node/master untainted
taint "node-role.kubernetes.io/master" not found
taint "node-role.kubernetes.io/master" not found

这时,再查看 Trint 字段,

Taints:             <none>

1.7 部署 Dashboard 可视化插件

因为 Kubernetes 本身更新速度比较快,Kubernetes API 在版本之间差异也是比较大的,这就导致了某些功能在新版的 Dashboard 中不能正常展示,其中 Dashboard v2.0.0-rc6 的兼容性如下表所示:

Kubernetes version1.141.151.161.17
Compatibility???
  • ✕ 表示不支持的版本范围;
  • ✓ 表示完全支持的版本范围;
  • ? 表示由于Kubernetes API版本之间的重大更改,某些功能可能无法在仪表板中正常运行;

本次部署的 Kubernetes 集群版本为 v1.17.4。

$ kubectl get nodes
NAME      STATUS   ROLES    AGE    VERSION
master    Ready    master   115m   v1.17.4
worker1   Ready    <none>   44m    v1.17.4
worker2   Ready    <none>   28m    v1.17.4

1.7.1 为 Dashboard 签发证书及密钥

参考 https://github.com/kubernetes/dashboard/blob/master/docs/user/installation.md

在新版本中,Dashboard 默认会启用 https 的认证,具体认证方式有:TLS、token 和 username/passwd。

当我们部署完成后,我们用 https 访问 Dashboard 时可能会报证书的相关问题,所以还是建议大家先为 Dashboard 创建自签证书再部署 Dashboard,这里我用 openssl工具生成自签证书,具体过程如下:

$ mkdir $HOME/certs
$ openssl req -nodes -newkey rsa:2048 -keyout $HOME/certs/dashboard.key -out $HOME/certs/dashboard.csr -subj "/C=/ST=/L=/O=/OU=/CN=kubernetes-dashboard"
## 利用 key 和私钥生成证书
$ openssl x509 -req -sha256 -days 365 -in $HOME/certs/dashboard.csr -signkey $HOME/certs/dashboard.key -out certs/dashboard.crt

也可以用集群自有 CA 签发证书:

openssl x509 -req -in $HOME/certs/dashboard.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out $HOME/certs/dashboard.crt -days 365

证书签发完成后,查看 $HOME/certs

$ ls $HOME/certs/
dashboard.crt  dashboard.csr  dashboard.key

在 K8S 集群中创建 kubernetes-dashboard 命名空间并创建相应的 secret:

注意:旧版本的 dashboard 的命名空间默认为 kube-system,而新版本的 dashboard 具有独立的命名空间 kubernetes-dashboard,我们可以提前创建。

kubectl create ns kubernetes-dashboard
kubectl create secret generic kubernetes-dashboard-certs --from-file=$HOME/certs -n kubernetes-dashboard

1.7.2 准备 Dashboard 配置清单部署文件

$ cd ~/Projects/Kubernetes/
$ curl -O https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc6/aio/deploy/recommended.yaml

$ kubectl apply -f recommended.yaml

$ kubectl get pods -n kubernetes-dashboard
NAME                                         READY   STATUS    RESTARTS   AGE
dashboard-metrics-scraper-7b8b58dc8b-xdq25   1/1     Running   0          24m
kubernetes-dashboard-5f5f847d57-s7x49        1/1     Running   0          24m

在 Kubernetes 1.11 版本之后,Heapster 被 Metrics Server 替换后,dashboard 无法从 Heapster 获取集群 Metrics,转而使用 Metrics Server 获取集群 Metrics,而 Dashboard 2.0 为此多了一个 dashboard-metrics-scraper 容器专门用来获取这些指标。

1.7.3 创建访问 Dashboard 的用户

Kubernetes Dashboard 2.0 配置完成后默认采用 HTTPS 方式访问,并配合 kubeconfig 文件或者 token 进行登录的,所以,接下来需要搞一个具有权限的用户登录 dashboard。

具有集群权限的用户清单文件(dashboard-admin-user.yaml):

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard-admin-sa
  namespace: kubernetes-dashboard
  labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dashboard-admin-sa
  namespace: kubernetes-dashboard
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: dashboard-admin-sa
  namespace: kubernetes-dashboard

执行该文件,

kubectl create -f dashboard-admin-user.yaml

获取该用户 token:

kubectl -n kubernetes-dashboard get secret -o jsonpath='{range .items[?(@.metadata.annotations.kubernetes\.io/service-account\.name=="dashboard-admin-sa")].data}{.token}{end}' | base64 -d

用上述输出的字符就可以登录 dashboard 了,这里配置的是管理员权限。

需要注意的是,由于 Dashboard 是一个 Web Server,很多人经常会在自己的公有云上无意地暴露
Dashboard 的端口,从而造成安全隐患。所以,1.7 版本之后的 Dashboard 项目部署完成后,默
认只能通过 Proxy 的方式在本地访问。具体的操作,你可以查看 Dashboard 项目的官方文档。

而如果你想从集群外访问这个 Dashboard 的话,就需要用到 Ingress。

1.8 部署容器存储插件

利用 Rook 把 Ceph 存储后端部署起来:

$ kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/common.yaml
$ kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/operator.yaml
# verify the rook-ceph-operator is in the `Running` state before proceeding
$ kubectl -n rook-ceph get pod
NAME                                  READY   STATUS    RESTARTS   AGE
rook-ceph-operator-85f5b946bd-tjx4m   1/1     Running   0          93s
rook-discover-bgqwt                   1/1     Running   0          64s
rook-discover-kxt9t                   1/1     Running   0          64s
rook-discover-lh26h                   1/1     Running   0          64s

kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/cluster.yaml

$ kubectl -n rook-ceph get pod
NAME                                                READY   STATUS      RESTARTS   AGE
csi-cephfsplugin-4fdbg                              3/3     Running     0          4m44s
csi-cephfsplugin-provisioner-d77bb49c6-rnxpm        5/5     Running     0          4m44s
csi-cephfsplugin-provisioner-d77bb49c6-x4qzr        5/5     Running     0          4m44s
csi-cephfsplugin-rnpm8                              3/3     Running     0          4m44s
csi-cephfsplugin-wqrqj                              3/3     Running     0          4m44s
csi-rbdplugin-29qqp                                 3/3     Running     0          4m44s
csi-rbdplugin-j7k4n                                 3/3     Running     0          4m44s
csi-rbdplugin-provisioner-5b5cd64fd-pkfjt           6/6     Running     0          4m44s
csi-rbdplugin-provisioner-5b5cd64fd-sf5cl           6/6     Running     0          4m44s
csi-rbdplugin-wgw56                                 3/3     Running     0          4m44s
rook-ceph-crashcollector-master-764455b764-s86fj    1/1     Running     0          2m9s
rook-ceph-crashcollector-worker1-7777fbc65-grqnt    1/1     Running     0          3m11s
rook-ceph-crashcollector-worker2-7476949d78-25sdw   1/1     Running     0          89s
rook-ceph-mgr-a-7884d789fc-5lt9q                    1/1     Running     0          89s
rook-ceph-mon-a-5ddcb5f47c-nx5l9                    1/1     Running     0          2m24s
rook-ceph-mon-b-5f9f57f768-wb7hv                    1/1     Running     0          2m9s
rook-ceph-mon-c-6695d658b6-f55sd                    1/1     Running     0          108s
rook-ceph-operator-85f5b946bd-tjx4m                 1/1     Running     0          7m52s
rook-ceph-osd-prepare-master-bm6m2                  0/1     Completed   0          66s
rook-ceph-osd-prepare-worker1-62w7h                 0/1     Completed   0          66s
rook-ceph-osd-prepare-worker2-82gzl                 0/1     Completed   0          66s
rook-discover-bgqwt                                 1/1     Running     0          7m23s
rook-discover-kxt9t                                 1/1     Running     0          7m23s
rook-discover-lh26h                                 1/1     Running     0          7m23s

为验证集群健康状态,可以连接到 Rook toolbox 运行 ceph status 命令查看,验证结果需满足:

  • All mons should be in quorum
  • A mgr should be active
  • At least one OSD should be active
  • If the health is not HEALTH_OK, the warnings or errors should be investigated
$ kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/toolbox.yaml

$ kubectl get pods -n rook-ceph
rook-ceph-tools-7f96779fb9-mq4qf                    1/1     Running     0          37s

$ kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') bash

$ ceph status
cluster:
    id:     9fb35b75-0695-4f31-a8b0-208b64c3a6ce
    health: HEALTH_WARN
            OSD count 0 < osd_pool_default_size 3

  services:
    mon: 3 daemons, quorum a,b,c (age 35m)
    mgr: a(active, since 34m)
    osd: 0 osds: 0 up, 0 in

  data:
    pools:   0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage:   0 B used, 0 B / 0 B avail
    pgs:

1.9 总结

在本篇文章中,我们从 0 开始,在公有云环境下使用 kubeadm 工具部署了一个完整的 Kubernetes 集群:这个集群有一个 Master 节点和多个 Worker 节点;使用 Weave 作为容器网络插件;使用 Rook 作为容器持久化存储插件;使用 Dashboard 插件提供了可视化的 Web 界面。


微信公众号「padluo」,分享数据科学家的自我修养,既然遇见,不如一起成长。

数据分析二维码.gif


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值