搭建 k8s 集群网上很多教程,如果是手工部署或者实验环境可以直接使用 MiniKube 或者 Kind,来在本地启动简单的 Kubernetes 集群进行后面的学习即可。如果是使用 MiniKube 的话,阿里云还维护了一个国内版的 MiniKube,这对于在国内的同学来说会比较友好。

下面介绍使用 kubeadm 这个 Kubernetes 半官方管理工具的工作原理。kubeadm 的初衷就是让 Kubernetes 集群的部署不再让人头疼,而且发展比较成熟,关于各种问题网上都有对应的文章来解决,我们就来使用它部署一个完整的 Kubernetes 集群。

准备工作

首先准备三台虚拟机,或者是三天试服务器,我是从企鹅️上买的三个轻量服务器,还挺便宜,但是后来看文档才知道,这所谓的轻量服务器原来就是k8s上的容器,所以我这属于是在 k8s 的容器里上搭建 k8s 集群了,搁这搁这呢。 为什么我肯定这个提供的就是一个有官方镜像 linux 的容器呢,具体是因为我买了发现他们所谓的内网在不同账号下是不能互通的,也就是说不同账号的轻量服务器分配到了不同的 node 上,内网ip只能在同一个 node 上互通,不同的node之间想互通只能去配置路由,并且配置属于自己的二层网络。所以这听起来就知道是容器了。

在本次部署中,我准备的机器配置如下:

  1. 2 核 CPU、 4 GB 内存(三台);
  2. 80 GB 磁盘;
  3. Centos 7.6;
  4. 内网互通;
  5. 外网访问权限不受限制。

这里的内网互通我是直接通过 iptables 来进行配置的,因为三台服务器公网ip可以互通,但是内网ip是不互通的,在 k8s 中默认是用内网ip来交互的,所以我只能用如下命令来进行配置。

sudo iptables -t nat -A OUTPUT -d <另外服务器的内网ip> -j DNAT --to-destination <另外服务器的外网ip>

保证每个节点能内网ip都 ping 通其他节点就行了。

安装 kubeadm 和 Docker

所有节点安装Docker/kubeadm/kubelet

安装 docker

$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
$ yum -y install docker-ce-18.06.1.ce-3.el7
$ systemctl enable docker && systemctl start docker
$ docker --version
Docker version 18.06.1-ce, build e68fc7a

配置一下镜像地址

# cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF

添加 k8s 的 yum 源

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

安装kubeadm,kubelet和kubectl

yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
systemctl enable kubelet

K8S集群还未拉起,故这里的kubelet是无法启动的,等master初始化时会自动拉起

替换 k8s 所需组件的 docker 镜像

因为国内的镜像都拉不回来关于 k8s 所需组件的,所以需要替换一下镜像

查看 kubeadm 所需要的镜像列表:

$ kubeadm config images list
I1108 19:54:40.085559 2997 version.go:252] remote version is much newer: v1.22.3; falling back to: stable-1.18
W1108 19:54:40.592794 2997 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
k8s.gcr.io/kube-apiserver:v1.18.20
k8s.gcr.io/kube-controller-manager:v1.18.20
k8s.gcr.io/kube-scheduler:v1.18.20
k8s.gcr.io/kube-proxy:v1.18.20
k8s.gcr.io/pause:3.2
k8s.gcr.io/etcd:3.4.3-0
k8s.gcr.io/coredns:1.6.7

编写拉取shell,这里脚本里替换成所需要的组件版本就行了

$ vim ./pull_k8s_images.sh
set -o errexit
set -o nounset
set -o pipefail ##这里定义版本,按照上面得到的列表自己改一下版本号 KUBE_VERSION=v1.18.20
KUBE_PAUSE_VERSION=3.2
ETCD_VERSION=3.4.3-0
DNS_VERSION=1.6.7 ##这是原始仓库名,最后需要改名成这个
GCR_URL=k8s.gcr.io ##这里就是写你要使用的仓库
DOCKERHUB_URL=registry.aliyuncs.com/google_containers ##这里是镜像列表,新版本要把coredns改成coredns/coredns
images=(
kube-proxy:${KUBE_VERSION}
kube-scheduler:${KUBE_VERSION}
kube-controller-manager:${KUBE_VERSION}
kube-apiserver:${KUBE_VERSION}
pause:${KUBE_PAUSE_VERSION}
etcd:${ETCD_VERSION}
coredns:${DNS_VERSION}
) ##这里是拉取和改名的循环语句
for imageName in ${images[@]} ; do
docker pull $DOCKERHUB_URL/$imageName
docker tag $DOCKERHUB_URL/$imageName $GCR_URL/$imageName
docker rmi $DOCKERHUB_URL/$imageName
done

执行shell

$ chmod +x ./pull_k8s_images.sh
$ ./pull_k8s_images.sh

部署 k8s master 节点

因为我的版本是 1.18.20 的版本,所以关于 kubeadm 的配置文件 config,内容如下

vim ./kubeadm/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: "stable-1.18"

这里的文件中 apiVersion 字段要根据不同的 k8s 进行调整,具体可以看看官网,因为不同的版本api不同,会报错~

具体可以看看这个:https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta3/

kubeadm 初始化安装 k8s

kubeadm init --config ./kubeadm/kubeadm.yaml

最后安装完毕后会有提示:

[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy 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 <master_id>:<master_port> --token <join_token> --discovery-token-ca-cert-hash <join_cert_hash>

这个 kubeadm join 命令,就是用来给这个 Master 节点添加更多工作节点(Worker)的命令。我们在后面部署 Worker 节点的时候马上会用到它,所以找一个地方把这条命令记录下来。

此外,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 这个安全配置文件的位置。

我个人更倾向于使用 export KUBECONFIG 环境变量告诉 kubectl 这个安全配置文件的位置,因为当 k8s 发生错误重新启动的时候,可会找不到配置文件

所以

$ vim /etc/profile
在文件最后添加
export KUBECONFIG=/etc/kubernetes/admin.conf $ source /etc/profile

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

$ kubectl get nodes

NAME      STATUS     ROLES     AGE       VERSION
master NotReady master 1d v1.18.0

在调试 Kubernetes 集群时,最重要的手段就是用 kubectl describe 来查看这个节点(Node)对象的详细信息、状态和事件(Event),我们来试一下:

$ kubectl describe node master

...
Conditions:
... Ready False ... KubeletNotReady runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

通过 kubectl describe 指令的输出,我们可以看到 NodeNotReady 的原因在于,我们尚未部署任何网络插件。另外,我们还可以通过 kubectl 检查这个节点上各个系统 Pod 的状态,其中,kube-system 是 Kubernetes 项目预留的系统 Pod 的工作空间(Namepsace,注意它并不是 Linux Namespace,它只是 Kubernetes 划分不同工作空间的单位):

$ kubectl get pods -n kube-system

NAME               READY   STATUS   RESTARTS  AGE
coredns-78fcdf6894-j9s52 0/1 Pending 0 1h
coredns-78fcdf6894-jm4wf 0/1 Pending 0 1h
etcd-master 1/1 Running 0 2s
kube-apiserver-master 1/1 Running 0 1s
kube-controller-manager-master 0/1 Pending 0 1s
kube-proxy-xbd47 1/1 NodeLost 0 1h
kube-scheduler-master 1/1 Running 0 1s

可以看到,CoreDNS、kube-controller-manager 等依赖于网络的 Pod 都处于 Pending 状态,即调度失败。这当然是符合预期的:因为这个 Master 节点的网络尚未就绪。

部署网络插件

在 Kubernetes 项目“一切皆容器”的设计理念指导下,部署网络插件非常简单,只需要执行一句 kubectl apply 指令,以 Weave 为例:

# 安装网络插件
$ 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

部署完成后查看所有的 pod 状态

$ kubectl get pods -n kube-system

NAME                             READY     STATUS    RESTARTS   AGE
coredns-78fcdf6894-j9s52 1/1 Running 0 1d
coredns-78fcdf6894-jm4wf 1/1 Running 0 1d
etcd-master 1/1 Running 0 9s
kube-apiserver-master 1/1 Running 0 9s
kube-controller-manager-master 1/1 Running 0 9s
kube-proxy-xbd47 1/1 Running 0 1d
kube-scheduler-master 1/1 Running 0 9s
weave-net-cmk27 2/2 Running 0 19s

可以看到,所有的系统 Pod 都成功启动了,而刚刚部署的 Weave 网络插件则在 kube-system 下面新建了一个名叫 weave-net-cmk27 的 Pod,一般来说,这些 Pod 就是容器网络插件在每个节点上的控制组件。

除此之外我想让pod被三个节点调度,因为k8s中默认master是不进行调度pod的,也就是此节点上不会部署pod,这个挺浪费

$ kubectl describe node master

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

可以看到,Master 节点默认被加上了node-role.kubernetes.io/master:NoSchedule这样一个“污点”,其中“键”是node-role.kubernetes.io/master,而没有提供“值”。

这个污点是保证 master 不会被pod调度到

所以直接删除这个 taints:

$ kubectl taint nodes --all node-role.kubernetes.io/master-

部署 k8s 的 worker 节点

首先按照上面的部署“安装 kubeadm 和 Docker”

第二步,因为我希望这三个节点随便哪个都能当 master 节点来使用,所以按照“替换 k8s 所需组件的 docker 镜像”把所有master需要的组件镜像都拿来了

第三步,复制master中的 /etc/kubernetes/admin.conf 到 worker 节点的同样路径下,然后 export KUBECONFIG 环境变量

除此之外我发现在 worker join 集群的时候会出现错误:

[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1

解决方法:

echo "1" >/proc/sys/net/bridge/bridge-nf-call-iptables

最后在 woker 节点添加进入集群命令:

就是之前 master 节点提示的 join 命令

查看节点

$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
vm-20-4-centos Ready <none> 141m v1.18.0
vm-20-6-centos Ready master 7h5m v1.18.0
vm-20-9-centos Ready <none> 169m v1.18.0

# 为 workder 节点添加 role

kubectl label nodes vm-20-4-centos kubernetes.io/role=worker
kubectl label nodes vm-20-9-centos kubernetes.io/role=worker

因为在k8s中根据 namespace 请求pod会请求host,我不希望请求 vm-20-4-centos 的时候会找不到解析的域名,所以我在没个node节点中还添加了以下的配置:

添加host
$ cat >> /etc/hosts << EOF
10.0.20.4 vm-20-4-centos
10.0.20.6 vm-20-6-centos
10.0.20.9 vm-20-9-centos
EOF

将桥接的IPv4流量传递到iptables的链:
$ cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sysctl --system # 生效

大功告成,enjoy~~~

关于 k8s 的玩法我个人有以下几个目标:

  1. 关于 k8s 的可视化,可以给用户提供一个可视化的 Web 界面来查看当前集群的各种信息
  2. 关于 k8s 的网络插件,可以尝试各种常用的网络插件,看看他们二层网络是怎么工作原理,理解 k8s 的 CNI
  3. 关于 k8s 的持久性存储是怎么实现的,看看 pvc 和 pv
  4. 关于 k8s 中对象 operator 是怎么工作的,实现细节是如何的

这里先一个小目标

手把手从0到1:搭建Kubernetes集群的更多相关文章

  1. kubeadm搭建kubernetes集群之三:加入node节点

    在上一章<kubeadm搭建kubernetes集群之二:创建master节点>的实战中,我们把kubernetes的master节点搭建好了,本章我们将加入node节点,使得整个环境可以 ...

  2. kubeadm搭建kubernetes集群之二:创建master节点

    在上一章kubeadm搭建kubernetes集群之一:构建标准化镜像中我们用VMware安装了一个CentOS7虚拟机,并且打算用这个虚拟机的镜像文件作为后续整个kubernetes的标准化镜像,现 ...

  3. kubeadm 搭建kubernetes集群环境

    需求 kubeadm 搭建kubernetes集群环境 准备条件 三台VPS(本文使用阿里云香港 - centos7.7) 一台能SSH连接到VPS的本地电脑 (推荐连接工具xshell) 安装步骤 ...

  4. 从0到1搭建spark集群---企业集群搭建

    今天分享一篇从0到1搭建Spark集群的步骤,企业中大家亦可以参照次集群搭建自己的Spark集群. 一.下载Spark安装包 可以从官网下载,本集群选择的版本是spark-1.6.0-bin-hado ...

  5. 二进制搭建Kubernetes集群(最新v1.16.0版本)

    目录 1.生产环境k8s平台架构 2.官方提供三种部署方式 3.服务器规划 4.系统初始化 5.Etcd集群部署 5.1.安装cfssl工具 5.2.生成etcd证书 5.2.1 创建用来生成 CA ...

  6. 手把手教你在CentOS上搭建Kubernetes集群

    作者:ChamPly 安装CentOS 1.安装net-tools [root@localhost ~]# yum install -y net-tools 2.关闭firewalld [root@l ...

  7. 【Kubernetes学习笔记】-kubeadm 手动搭建kubernetes 集群

    目录 K8S 组件构成 环境准备 (以ubuntu系统为例) 1. kubernetes集群机器 2. 安装 docker. kubeadm.kubelet.kubectl 2.1 在每台机器上安装 ...

  8. Rancher2.0导入本地RKE Kubernetes集群图解

      简要说明: 使用RKE工具在192.168.3.161机器上,创建包含两个节点的Kubernetes集群,(192.168.3.162和192.168.3.163).RKE会自动在/home/用户 ...

  9. kubeadm搭建kubernetes集群之一:构建标准化镜像

    使用docker可以批量管理多个容器,但都是在同一台电脑内进行的,这在实际生产环境中是不够用的,如何突破单机的限制?让多个电脑上的容器可以像单机上的docker-compose.yml管理的那样方便呢 ...

随机推荐

  1. 如何在word中美观地插入编程代码

    零.缘起 在整理Java笔记时,想把代码直接贴到word文档中,原来一直截图很麻烦,所以找到以下方法. 思想:问题比答案更重要!你能想到问题,才知道去百度搜索. 一.打开网站 http://www.p ...

  2. bzoj#4722-由乃【倍增,抽屉原理,bitset】

    正题 题目链接:https://darkbzoj.tk/problem/4722 题目大意 给出一个长度为\(n\)的序列值域为\([0,v)\),要求支持操作 询问一个区间能否找到两个没有交的非空下 ...

  3. MyBatis封装对象内的List出现的问题

    本篇文章问题1:wife的复数形式是wives,不是wifes,英语不好请见谅. 对象举例: class User { private String username; private List< ...

  4. AOJ/搜索与递归及分治法习题集

    ALDS1_4_A-LinearSearch. Description: You are given a sequence of n integers S and a sequence of diff ...

  5. .NET跨平台实践:.NetCore、.Net5/6 Linux守护进程设计

    之前,我写过两篇关于用C#开发Linux守护进程的技术文章,分别是<.NET跨平台实践:用C#开发Linux守护进程>和<.NET跨平台实践:再谈用C#开发Linux守护进程 - 完 ...

  6. react之组建通信

    父组件与子组件通信 父组件将自己的状态传递给子组件,子组件当做属性来接收,当父组件更改自己状态的时候,子组件接收到的属性就会发生改变 父组件利用ref对子组件做标记,通过调用子组件的方法以更改子组件的 ...

  7. Geostatistical Analyst Tools(Geostatistical Analyst 工具)

    Geostatistical Analyst 工具 1.使用地统计图层 # Process: GA 图层至格网 arcpy.GALayerToGrid_ga("", 输出表面栅格, ...

  8. 关于 Binomial Coefficient is Fun

    题目传送门 Solution 应该这个做法不是很常见吧. 我们设 \(f_{i,j}\) 表示前面 \(i\) 个数,选出的数和为 \(j\) 的贡献之和.因为我们有以下式子: \[\sum_{i=a ...

  9. 题解 [HNOI2007]分裂游戏

    题目传送门 题目大意 有趣的取石子游戏即将开始. 有 \(n\) 堆石头,编号为 \(0,1,2,...,n-1\).两个人轮流挑石头. 在每个回合中,每个人选择三堆编号为 \(i,j,k\) 的石头 ...

  10. 【Java虚拟机1】Java字节码文件格式入门

    第一次学习看字节码文件,这个对工作没什么用,但是会提升内功. 首先介绍两个IDEA插件以及使用: BinEd:以16进制格式查看class文件 使用方法:右键class文件,点击Open as bin ...