团队近期打算自己开发一个基于kubernetes的应用部署、监控、维护、管理的云平台MAE(Muxi APP Engine),思路来自于赵老板的一篇博客。可以让用户直接在可视化的环境下完成应用的部署、集群维护的一个服务。开发首先得需要一个kubernetes集群,这几天一直在弄kubernetes的东西。今天就先总结一下集群搭建的基本过程,记录一下搭建过程中遇到的坑,希望能够给后来者以参考。
基本环境
由于是学生团队,搭建过程基于的环境比较简陋:
- 阿里云学生机一台,CentOS 7.4 ,64位的操作系统
- CPU:1核
- 内存:2G
- 带宽:1Mbps
前期准备
节点命名
阿里云的机器的hostname默认都是一长串由字母和数字组成的字符串,没有什么规律。为了便于以后的管理,我们可以使用hostnamectl命令来给我们的节点取一个具有语义性的名字。具体操作,在root用户下运行下面的命令:
1 | $ hostnamectl set-hostname "k8s-master" |
因为我们这里只有一台主机,所以就给它命名成k8s-master.
禁用防火墙
如果各个主机启用了防火墙,需要开放Kubernetes各个组件所需要的端口,可以查看Installing kubeadm中的Check required ports一节。 这里简单起见在各节点禁用防火墙:
1 | $ systemctl stop firewalld |
创建/etc/sysctl.d/k8s.conf文件,添加如下内容:
1 | net.bridge.bridge-nf-call-ip6tables = 1 |
执行sysctl -p /etc/sysctl.d/k8s.conf
使修改生效。
禁用SELINUX
1 | $ setenforce 0 |
1 | vim /etc/selinux/config |
修改成这样:
1 | SELINUX=disabled |
修改/etc/selinux/config
文件的过程也可以直接这样:
1 | $ sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config |
关闭系统的Swap
Kubernetes 1.8开始要求关闭系统的Swap。如果不关闭,默认配置下kubelet将无法启动。可以通过kubelet的启动参数--fail-swap-on=false
更改这个限制。 我们这里关闭系统的Swap:
1 | $ swapoff -a |
修改/etc/fstab
文件,注释掉SWAP
的自动挂载,使用free -m
确认swap已经关闭。swappiness
参数调整,修改/etc/sysctl.d/k8s.conf添加下面一行:
1 | vm.swappiness=0 |
执行sysctl -p /etc/sysctl.d/k8s.conf使修改生效。
安装并配置docker
安装
docker属于kubernetes的基础设施,一般来说docker 1.12是比较稳定的,我们要在阿里云学生机上下载docker需要先添加docker的镜像源,像下面这样:
1 | $ cat >/etc/yum.repos.d/docker.repo <<EOF |
然后通过下面的命令将服务器上的软件包信息先在本地缓存,以提高搜索安装软件的速度:
1 | $ yum makecache |
现在你可以通过下面的命令来查看你新添加的软件源中可以安装的docker的版本:
1 | $ yum list docker-engine showduplicates |
这里我们选择安装docker 1.12.6
1 | $ yum install docker-engine-1.12.6-1.el7.centos.x86_64 |
启动docker:
1 | $ systemctl enable docker |
配置
下面我们需要到docker hub
镜像仓库中拉取镜像,为了加快拉取镜像的速度,我们在这里给docker
配置一下加速器。国内的阿里云、daoclode、时速云等均有免费的docker加速器提供,大家可以自行google。这里我采用阿里云的镜像加速服务。因为在下面的kubeadm初始化master节点的时候,需要保证docker的cgroup driver
类型与kubelet
启动时使用的cgroup driver
一致(cgroupfs
或者systemd
),所以这里也一并展示一下配置docker的cgroup driver
的方法:
1 | mkdir -p /etc/docker |
因为修改了配置文件,所以这里需要重启一下docker.
1 | systemctl daemon-reload |
安装k8s相关镜像及组件
k8s集群分为master节点和node节点,master节点主要用于对于集群进行管理。k8s安装一般有两种安装方式,第一种为官方提供的工具kubeadm安装,第二种为二进制文件安装,此处主要介绍第一种
相关镜像下载
由于使用kubeadm在安装的过程中会使用一些谷歌开源的镜像,但是国内无法访问到gcr.io,所以一般情况下我们需要翻墙拉取镜像,但是有以下前辈已经拉取到我们所需的镜像,并且传到了dockerhub上,我们可以直接使用这上面的镜像。并且刚才配置了加速器,所以拉取的速度也是很快的。这里就推荐两个docker hub上的仓库:alleyj,mirrorgooglecontainers
这里以alleyj的仓库为例,先需要从这个仓库里pull我们需要的镜像,然后使用docker tag
命令将镜像的前缀改为gcr.io/google_containers
,最后使用docker rmi
去掉之前的镜像记录。可以使用如下脚本完成以上操作:
1 |
|
kubernetes各个版本所需要的镜像版本可以参见->这里
组件下载
这里我们还需要下载的组件是kubelet
,kubectl
,kubeadm
,kubernetes-cni
。首先添加yum源:
1 | cat >> /etc/yum.repos.d/kubernetes.repo <<EOF |
然后可以通过下面的命令来查看该镜像源中可以安装的对应组件的版本:
1 | $ yum list kubeadm showduplicates |
这里,我们选择下面的版本安装.
1 | yum install -y kubernetes-cni-0.5.1-0.x86_64 |
启动kubelet.
1 | systemctl enable kubelet && systemctl start kubelet |
配置kubelet
kubelet负责在节点上启动,终止,重启容器。我们需要对其进行响应的配置。
1 | cat > /etc/systemd/system/kubelet.service.d/20-pod-infra-image.conf <<EOF |
上面配置的是kubelet的启动参数,指定了pause容器镜像。这个pause容器在pod中担任Linux命名空间共享的基础,启用pid命名空间,开启init进程。更多关于pause容器的内容,可以看->这里
在kubeadm初始化master节点的过程中,我们还需要设置两个环境变量:
1 | export KUBE_REPO_PREFIX="gcr.io/google_containers" |
这两个环境变量指定了kubernetes所需的系统镜像的前缀,和etcd镜像的完整名称。由于这些镜像现在都以gcr.io/google_containers为前缀存在于本地,所以不用考虑说以gcr.io/google_containers为前缀拉取不到镜像的问题。
配置完毕,我们重新启动kubelet:
1 | systemctl daemon-reload |
kubeadm初始化master节点
到目前为止,我们搭建单节点集群所需要的所有软件,镜像全部安装完毕。下面我们就是要使用kubeadm来初始化集群。这个地方就开始遇到各种坑了。首先,在kubeadm init
之前我们需要保证本机的docker
和kubelet
服务都处于运行状态.所以我们先来确认一下这两个服务是否都跑起来了:
1 | $ systemctl status docker |
如果你在运行上面的两个命令后看到的都是绿色,那么很幸运,你跳过了这个坑。不幸的是,笔者的kubelet一直无法跑起来。systemctl status kubelet
的输出如下所示:
1 | ● kubelet.service - kubelet: The Kubernetes Node Agent |
其实,现在看来这个地方也不叫做坑,上面的输出倒数第3行已经说的很清楚了unknown flag: --require-kubeconfig
。这说明kubelet的启动参数中出现了一个它不认的flag.(笔者装的时候一直在查看kubelet的状态,就是没有好好看log,导致这里花费了许多时间。这说明仔细看log真的很重要!!!)。下面我们就去看看kubelet启动参数的配置文件:
1 | $ cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf |
文件内容如下:
1 | [Service] |
果真,在KUBELET_KUBECONFIG_ARGS中有一个参数--require-kubeconfig=true
,去掉即可。
下面重新启动kubelet:
1 | systemctl daemon-reload |
查看kubelet的状态,发现kubelet仍然没有运行起来:<(
下面查看一下系统log,看看究竟发生了啥:
1 | $ tail -n 10 /var/log/messages |
输出如下:
1 | Apr 22 10:46:38 iZwz9f6pgul78p7die5tlzZ kubelet: Flag --authorization-mode has been deprecated, This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information. |
输出的第三行有这样一条:unable to load client CA file /etc/kubernetes/pki/ca.crt: open /etc/kubernetes/pki/ca.crt: no such file or directory
关于这个客户端证书,笔者自己也没有怎么搞明白,后面需要接着研究。但是貌似这个证书是在kubeadm init
的过程中创建的。所以笔者采取的方法是首先进行kubeadm init
操作。
1 | $ kubeadm init --apiserver-advertise-address=<你的服务器ip> --kubernetes-version=v1.7.5 --pod-network-cidr=10.244.0.0/12 |
输出:
1 | [kubeadm] WARNING: kubeadm is in beta, please do not use it for production clusters. |
初始化的过程卡在了上面输出的地方。其实想想这个过程绝对是会卡住的,毕竟现在kubelet
都没有跑起来。如果你的kubelet已经跑起来了,但是这个kubeadm init
还是会卡住,那么就有可能是你的docker的cgroup driver的类型与kubelet启动参数中指定的cgroup driver类型不一致导致的,你需要做的就是统一这两者之间的类型。
现在,让我们Ctrl+C
终止上述的kubeadm init
过程,然后重新启动我们的kubelet:
1 | systemctl start kubelet |
查看kubelet的状态,kubelet已经跑起来了,乐乐乐:>)
下面我们再次kubeadm init
,注意这次我们需要加上--skip-preflight-checks
跳过前期检查。
1 | $ kubeadm init --apiserver-advertise-address=<你的服务器ip> --kubernetes-version=v1.7.5 --pod-network-cidr=10.244.0.0/12 --skip-preflight-checks |
输出:
1 | [kubeadm] WARNING: kubeadm is in beta, please do not use it for production clusters. |
这下,kubeadm init
终于成功了、了、了…
正如上面的输出所示,如果你需要让非root用户能够使用你的集群,你需要以该非root用户身份执行下面的命令:
1 | mkdir -p $HOME/.kube |
现在你可以使用下面的命令来查看你的集群的运行状况了:
1 | $ kubectl get pods --all-namepaces |
在笔者的机器上,kube-system中的kube-dns对应的pod的状态一直处于异常。这个就需要配置overlay network
来解决。
配置overlay network
笔者开始的时候采用的是flannel来配置的overlay network
,但是flannel并没有解决kube-dns对应的pod的异常状态,并且网上有声音说flannel与阿里云的主机兼容性不好。所以后面是根据文章来配置的Weave。但是目前团队的生产环境的集群的overlay network
使用的是flannel,跑的也挺好的。所以我感觉这个东西也是具有很大的差异性的:>),这里就一并写一下使用flannel、weave来配置集群overlay network
的命令。下面的命令都是可以直接使用的。
使用flannel
1 | $ kubectl --namespace kube-system apply -f https://raw.githubusercontent.com/coreos/flannel/v0.8.0/Documentation/kube-flannel-rbac.yml |
使用weave
1 | $ export kubever=$(kubectl version | base64 | tr -d '\n') |
由于我是改用weave才就kube-dns的pod才正常工作,所以我推荐大家使用weave来配置。
最后一个问题
至此,我们的单节点kubernetes集群就搭建完成了。大家在部署应用的时候可能还会遇到另外的一个问题。当你创建了deployment,service之后,查看你的应用的pod,你会发现所有的pod都处于pending
的状态,kubectl describe
发现这些pod都没有被调度。这是怎么回事呢?原来,我们现在只有一个节点,而kubernets的调度策略默认是不支持在master节点上放置应用pod的,具体的可以查看这个issue,可以使用下面的命令,来去掉这样的调度限制:
1 | $ kubectl taint nodes <nodeName> node-role.kubernetes.io/master:NoSchedule- |
总结
大致总结一下安装kubernetes集群的流程:
- 准备系统环境
- 安装Docker
- 安装Kubernetes相关组件
- Kubeadm init Master节点
- 安装Overlay Network
- Join Node节点
这里,由于只有一台主机,所以最后一步没有进行。在整个安装过程中,大致流程是不会改变的。但是可能还是会遇到各种各样的问题。这一次安装的过程让我深刻的体会到认真查看log的重要性,还有依据log去google的重要性。不管什么问题,只要你坚持,最终肯定会找到解决问题的方法。最后,感谢万能的互联网。