之前在《Kubernetes初体验》中我们使用Minikube快速体验了一把Kubernetes,然后在《Kubernetes架构及资源关系简单总结》一文中我们又简单介绍了Kubernetes的框架以及Kubernetes中的一些关键术语和概念,或者称之为资源、对象。本文主要讲Kubernetes的一种原始部署方式。Kubernetes从开发至今,其部署方式已经变得越来越简单。常见的有三种:

  • 最简单的就是使用Minikube方式。下载一个二进制文件即可拥有一个单机版的Kubernetes,而且支持各个平台。
  • 从源码安装。这种方式也是简单的进行一些配置,然后执行kube-up.sh就可以部署一个Kubernetes集群。可参见官方文档《Manually Deploying Kubernetes on Ubuntu Nodes》。PS:目前,该文档部署Kubernetes 1.5.3版本会有些问题,可关注#39224
  • 通过kubeadm部署。可参见官方文档《Installing Kubernetes on Linux with kubeadm

其实,除了上面三种方式外,有些Linux发行版已经提供了Kubernetes的安装包,比如在CentOS 7上面,直接执行yum install -y etcd kubernetes即可安装Kubernetes,然后做些配置就可以完成部署了。我相信对于Google这种追求自动化、智能化的公司,他们会让Kubernetes部署方式还会更加简化。但这些都不是本文的重点,本文要讲述的是如何像堆积木一样一个模块一个模块的部署Kubernetes。为什么要这样做?

为了更好的理解学习Kubernetes。前面我们已经简单介绍过Kubernetes的架构,知道它其实是由几大模块组成,各个模块间合作构成一个集群。现在简单化的部署方式屏蔽了很多细节,使得我们对于各个模块的感知少了很多。而且很容器觉得Kubernetes的内部部署细节非常的麻烦或者复杂,但其实并非如此,其实Kubernetes集群就是由为数不多的几个二进制文件组成,部署一个基本的集群也非难事。因为是使用Go开发的,这些二进制文件也没有任何依赖,从别的地方拷贝过来就可使用。本文就介绍如何从这些二进制文件搭建一个Kubernetes集群, 以加深对Kubernetes的理解。而且,其他部署方式其实也只是对这种方式的一种封装。

现在Systemd逐渐替代了Upstart,有的部署方式也只支持Systemd的Linux发行版,如果是Upstart,还得做适配。至于什么是Systemd和Upstart,不是本文要讨论的,后续会总结发出来。这里我使用的Linux发行版是Ubuntu 16.04。当然Ubuntu 15.04+的都使用的是Systemd,应该都是适用的,其他使用Systemd的系统应该也是适用的,但可能需要做些小的改动。另外,前文介绍了Kubernetes集群分为Master和Node,所以我们部署也一样,分为Master的部署和Node的部署。

我的环境是用Virtualbox虚拟了两台Ubuntu 16.04,虚拟机和主机的通信方式是NAT和host-only方式。NAT用于访问外网,host-only用于两台虚拟机之间访问,IP分别为192.168.56.101和192.168.56.102.其中101这台机器机器既是Master,又是Node;102是Node。本文只装了101,后面再测试网络等需要多台的时候再安装102.因为Kubernetes里面Node是主动向Master注册的(通过Node上面的kubelet),所以要扩展Node的话也非常容易。

获取二进制文件

我们都需要哪些二进制文件呢?回想一下《Kubernetes架构及资源关系简单总结》中,Kubernetes集群内主要包含这些模块:Master中:APIServer、scheduler、controller manager、etcd;Node中:kubelet、kube-proxy、runtime(这里指Docker)。

上面每个模块都由一个二进制文件实现,所以我们需要上面每个模块对应的那个二进制文件。获取方式有很多。最直观的方式就是去github上面下载release的包,里面有二进制文件。但那个包有1GB+大小,特别对于中国用户就呵呵了,当然还有许多其他获取的方式。

注意:源代码目录里面也有很多名字和二进制名字相同的文件,但那些不是二进制文件,而是一些去掉后缀的shell脚步,都只有KB级别的大小,而真正的二进制文件都是MB级别的,注意别搞错了。

推荐使用下面的命令下载kubernetes-server-linux-amd64.tar.gz包:

curl -L https://storage.googleapis.com/kubernetes-release/release/v${KUBE_VERSION}/kubernetes-server-linux-amd64.tar.gz -o kubernetes-server-linux-amd64.tar.gz

这个包解压后的kubernetes/server/bin目录下就有我们需要的二进制文件(只使用了其中6个):

ubuntu➜  bin ll
total 1.3G
-rwxr-x--- 1 root root 145M Dec 14 09:06 hyperkube
-rwxr-x--- 1 root root 118M Dec 14 09:06 kube-apiserver
-rw-r----- 1 root root   33 Dec 14 09:06 kube-apiserver.docker_tag
-rw-r----- 1 root root 119M Dec 14 09:06 kube-apiserver.tar
-rwxr-x--- 1 root root  97M Dec 14 09:06 kube-controller-manager
-rw-r----- 1 root root   33 Dec 14 09:06 kube-controller-manager.docker_tag
-rw-r----- 1 root root  98M Dec 14 09:06 kube-controller-manager.tar
-rwxr-x--- 1 root root 6.6M Dec 14 09:06 kube-discovery
-rwxr-x--- 1 root root  44M Dec 14 09:05 kube-dns
-rwxr-x--- 1 root root  44M Dec 14 09:05 kube-proxy
-rw-r----- 1 root root   33 Dec 14 09:06 kube-proxy.docker_tag
-rw-r----- 1 root root 174M Dec 14 09:06 kube-proxy.tar
-rwxr-x--- 1 root root  51M Dec 14 09:06 kube-scheduler
-rw-r----- 1 root root   33 Dec 14 09:06 kube-scheduler.docker_tag
-rw-r----- 1 root root  52M Dec 14 09:06 kube-scheduler.tar
-rwxr-x--- 1 root root  91M Dec 14 09:06 kubeadm
-rwxr-x--- 1 root root  49M Dec 14 09:06 kubectl
-rwxr-x--- 1 root root  46M Dec 14 09:06 kubefed
-rwxr-x--- 1 root root 103M Dec 14 09:06 kubelet

我将这些二进制文件都放到了/opt/bin目录下,并且将该目录加到了PATH中。你也可以直接将这些文件放到系统的PATH路径中,比如/usr/bin

OK,有了这些二进制文件,我们就可以开始部署了。

部署Master

前文介绍过,Master上面主要四个模块:APIServer、scheduler、controller manager、etcd,我们一一来部署。

部署etcd

我建议直接使用apt install etcd命令去安装,这样同时也会安装etcdctl。安装完后etcd的数据默认存储在/var/lib/etcd/default目录,默认配置文件为/etc/default/etcd,可通过/lib/systemd/system/etcd.service文件进行修改。

2017.9.4更新

Kubernets新版本(我记得好像是1.6开始吧,记不清了)已经不支持etcd 2.x版本了,但是在Ubuntu 16.04上面通过apt install装的是2.2版本,这样会导致api-server无法和etcd通讯,而导致一些问题,所以建议从github下载最新etcd 3.x(https://github.com/coreos/etcd/releases),然后手动安装。创建/lib/systemd/system/etcd.service文件:

[Unit]
Description=Etcd Server
Documentation=https://github.com/coreos/etcd
After=network.target

[Service]
User=root
Type=simple
EnvironmentFile=-/etc/default/etcd
ExecStart=/opt/k8s/v1_6_9/etcd-v3.2.7-linux-amd64/etcd    # 改为你自己路径
Restart=on-failure
RestartSec=10s
LimitNOFILE=40000

[Install]
WantedBy=multi-user.target

安装好以后,执行以下命令:

# 重新加载systemd配置管理,切记增加`*.service`后一定要先执行该命令,否则启动服务时会报错
systemctl daemon-reload

systemctl enable etcd.service    # 将etcd加到开机启动列表中
systemctl start etcd.service    # 启动etcd

安装好以后,etcd默认监听http://127.0.0.1:2379地址供客户端连接。我们可以使用etcdctl来检查etcd是否正确启动:

ubuntu➜  bin etcdctl cluster-health
member ce2a822cea30bfca is healthy: got healthy result from http://localhost:2379
cluster is healthy

可以看到运行正常。当然,部署多台的话,因为所有Node都需要访问etcd,所以etcd必须要监听在其他Node可以访问的IP上面才可以,在/etc/default/etcd中增加以下两行:

ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379"

重启etcd即可使etcd在所有IP上起监听。

部署APIServer

APIServer对应的二进制文件是kube-apiserver,我们先来设置systemd服务文件/lib/systemd/system/kube-apiserver.service:

[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes
After=etcd.service
Wants=etcd.service

[Service]
EnvironmentFile=/etc/kubernetes/apiserver
ExecStart=/opt/bin/kube-apiserver $KUBE_API_ARGS
Restart=on-failure
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

重点项简单说明:

  • kube-apiserver服务依赖etcd,所以设置了After
  • EnvironmentFile是该服务的配置文件。
  • ExecStart说明如何启动该服务。

我们看到kube-apiserver的启动参数为$KUBE_API_ARGS,我们在配置文件/etc/kubernetes/apiserver中定义这个环境变量:

KUBE_API_ARGS="--etcd_servers=http://127.0.0.1:2379 --insecure-bind-address=0.0.0.0 --insecure-port=8080 --service-cluster-ip-range=169.169.0.0/16 --service-node-port-range=1-65535 --admission_control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ResourceQuota --logtostderr=false --log-dir=/var/log/kubernetes --v=2"

选项说明:

  • --etcd_servers:就是etcd的地址。
  • --insecure-bind-address:apiserver绑定主机的非安全IP地址,设置0.0.0.0表示绑定所有IP地址。
  • --insecure-port:apiserver绑定主机的非安全端口,默认为8080。
  • --service-cluster-ip-range:Kubernetes集群中Service的虚拟IP地址段范围,以CIDR格式表示,该IP范围不能与物理机真实IP段有重合。
  • -service-node-port-range:Kubernetes集群中Service可映射的物理机端口范围,默认为30000~32767.
  • --admission_control: Kubernetes集群的准入控制设置,各控制模块以插件形式依次生效。
  • --logtostderr:设置为false表示将日志写入文件,不写入stderr。
  • --log-dir: 日志目录。
  • --v:日志级别。

OK,APIServer的部署配置完成了,其实主要分两部分:

  • 创建systemd服务文件,有了该文件,就可以使用systemd去控制该服务,比如启停、开机自启等。systemd的命令、语法等后面写文章介绍。
  • 模块的配置文件,用于控制模块如何启动及功能控制。

后面其他模块的配置与之大同小异。

部署controller manager

controller manager对应的二进制文件是kube-controller-manager,且该服务依赖于kube-apiserver。

依旧先配置systemd的服务文件/lib/systemd/system/kube-controller-manager.service

[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes
After=kube-apiserver.service
Requires=kube-apiserver.service

[Service]
EnvironmentFile=/etc/kubernetes/controller-manager
ExecStart=/opt/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_ARGS
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

/etc/kubernetes/controller-manager中设置$KUBE_CONTROLLER_MANAGER_ARGS

KUBE_CONTROLLER_MANAGER_ARGS="--master=http://192.168.56.101:8080 --logtostderr=false --log-dir=/var/log/kubernetes --v=2"

--master指的是APIServer的地址。

部署scheduler

scheduler对应的二进制文件是kube-scheduler,scheduler依赖于APIServer。

配置systemd服务文件/lib/systemd/system/kube-scheduler.service

[Unit]
Description=Kubernetes Scheduler Manager
Documentation=https://github.com/kubernetes
After=kube-apiserver.service
Requires=kube-apiserver.service

[Service]
EnvironmentFile=/etc/kubernetes/scheduler
ExecStart=/opt/bin/kube-scheduler $KUBE_SCHEDULER_ARGS
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

在配置文件/etc/kubernetes/scheduler中设置$KUBE_SCHEDULER_ARGS

KUBE_SCHEDULER_ARGS="--master=http://192.168.56.101:8080 --logtostderr=false --log-dir=/var/log/kubernetes --v=2"

至此,Master上面的四个模块都部署完了,我们按照顺序启动他们,并将其加入到开机自启动选项中:

# 重新加载systemd配置管理,切记增加`*.service`后一定要先执行该命令,否则启动服务时会报错
systemctl daemon-reload

# enable表示该服务开机自启,start表示启动该服务
systemctl enable kube-apiserver.service   
systemctl start kube-apiserver.service
systemctl enable kube-controller-manager.service
systemctl start kube-controller-manager.service
systemctl enable kube-scheduler.service
systemctl start kube-scheduler.service

然后我们分别运行systemctl status <service_name>来验证服务的状态,“running”表示启动成功。如果未成,也可看到错误日志。

部署Node

Node上面运行三个模块:kubelet、kube-proxy、runtime。其中runtime目前指的是docker或者rkt,这里我们使用docker,docker的安装这里就不赘述了,最好安装最新版本的docker。

部署kubelet

kubelet对应的二进制文件是kubelet,且其依赖Docker服务。

配置systemd服务文件/lib/systemd/system/kubelet.service

[Unit]
Description=Kubernetes Kubelet Server
Documentation=https://github.com/kubernetes
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/var/lib/kubelet
EnvironmentFile=/etc/kubernetes/kubelet
ExecStart=/opt/bin/kubelet $KUBELET_ARGS
Restart=on-failure

[Install]
WantedBy=multi-user.target

在配置文件/etc/kubernetes/kubelet中设置参数$KUBELET_ARGS

KUBELET_ARGS="--api-servers=http://192.168.56.101:8080 --hostname-override=192.168.56.101 --logtostderr=false --log-dir=/var/log/kubernetes --v=2"

其中--hostname-override设置本Node的名称。

部署kube-proxy

kube-proxy对应的二进制文件为kube-proxy,且该服务依赖于network服务。

配置systemd服务文件/lib/systemd/system/kube-proxy.service

[Unit]
Description=Kubernetes Kube-Proxt Server
Documentation=https://github.com/kubernetes
After=network.target
Requires=network.target

[Service]
EnvironmentFile=/etc/kubernetes/proxy
ExecStart=/opt/bin/kube-proxy $KUBE_PROXY_ARGS
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

在配置文件/etc/kubernetes/proxy中设置参数$KUBE_PROXY_ARGS

KUBE_PROXY_ARGS="--master=http://192.168.56.101:8080 --logtostderr=false --log-dir=/var/log/kubernetes --v=2"

然后我们依次启动Node上的服务(Docker安装好以后默认开机自启且已经启动,这里不再启动):

systemctl daemon-reload

systemctl enable kubelet.service
systemctl start kubelet.service
systemctl enable kube-proxy.service
systemctl start kube-proxy.service

待服务都成功启动后,kubelet会主动向Master注册自己所在的Node。如果所有服务都启动成功,我们就可以看到可用的Node了:

ubuntu➜  system kubectl get node
NAME             STATUS    AGE
192.168.56.101   Ready     1h

再在另外一台Node上面也部署一下,就可以看到两个节点了。

至此,本文就介绍完了。不过要应用到生产环境中,我们还有一些安全项和网络项需要配置,后面再介绍。