Kubernetes Cookbook 编程指南 中文版教程
创建时间:2018-12-07  访问量:3668  7  0

Kubernetes Cookbook 编程指南 中文版教程

构建多个Master节点

Master节点是Kubernete系统中的核心组件。它的职责包含以下内容:

  • 从数据库存储和etcd服务器中获取并存储信息

  • 为请求提供门户

  • 为Node节点分配任务

  • 监示运行中的任务

Master支持的三个守护进程实现前面所有的职责,编号如下图所示:

正如你所看到的,Master节点是客户端与工作者之间的通信者。因此,如果Master节点崩溃的话会是一个严重的问题。一个多Master节点的Kubernetes系统不仅仅能够容忍错误,也是一个负载均衡。将不再只有一个API服务器用于访问发送请求的节点和客户端。分离的Master节点中的多个API服务器守护进程将有助于同时解决任务并缩短响应时间。

开始

对于构建一个多Master系统的简要概念列出如下:

  • 在Master前前添加一个负载均衡服务器。负载均衡器将成为Node节点与客户端访问的新的端点。

  • 每个Master节点有运行了它自己的API服务器进程

  • 系统中只有一个调度器和一个控制管理器,当管理容器时,可以避免来自不同守护进程方向的冲突。

  • Pod master是每个Master节点上都需要安装的一个新的守护进程。它选出决定运行调度器守护进程的Master节点或控制管理器的Master节点。有可能这两个守护进程都运行在同一Master节点上。

  • 以更灵活的方式作为一个容器运行调度程序的守护进程和控制器管理器。在Master中安装kubelet并通过配置文件来管理作为Pod的守护进程。

在本节,我们将构建一个具有两个Master的系统,当扩展更多Master节点时方法也是类似的。

如何去做...

现在,我们将指导你一步一步的构建一个多Master系统。在这之前,你需要为多个Master节点部署一个负载均衡服务器。

为了学习关于部署负载均衡器和在AWS上构建系统,请参考第6章,在AWS上构建Kubernetes,在AWS上构建Kubernetes基础设施这一节中的如何构建一个Master负载均均衡。

准备多个Master节点

首先,在你前面的Kubernetes系统中安装另一个Master节点,它与原始的Master节点的环境应该一样。然后,停止Master上的调度器服务的守护进程和控制器控理器。

  • 对于systemd控制的系统,直接使用systemctl kube-scheduler top和systemctl kube-controller-manager top来停止服务。

  • 对于service控制的系统,首先停止Master服务。接下来,删除或注释初始化脚本中关于调度器和控制器管理器的行:

// Checking current daemon processes on master server
# service kubernetes-master status
kube-apiserver (pid 3137) is running...
kube-scheduler (pid 3138) is running...
kube-controller-manager (pid 3136) is running...
# service kubernetes-master stop
Shutting down /usr/local/bin/kube-controller-manager: [ OK
]
Shutting down /usr/local/bin/kube-scheduler: [ OK
]
Shutting down /usr/local/bin/kube-apiserver: [ OK
]
// Or, for "hypercube" command with init script, we block out
scheduler and controller-manager. Just leave apiserver daemon in
master node.
// Put comment on the scheduler and controller manager daemons
// the variable $prog is /usr/local/bin/hyperkube
# cat /etc/init.d/kubernetes-master
(ignored above parts)
# Start daemon.
echo $"Starting apiserver: "
daemon $prog apiserver \
--service-cluster-ip-range=${CLUSTER_IP_RANGE} \
--insecure-port=8080 \
--secure-port=6443 \
--address=0.0.0.0 \
--etcd_servers=${ETCD_SERVERS} \
--cluster_name=${CLUSTER_NAME} \
> ${logfile}-apiserver.log 2>&1 &
# echo $"Starting controller-manager: "
# daemon $prog controller-manager \
# --master=${MASTER} \
# > ${logfile}-controller-manager.log 2>&1 &
#
# echo $"Starting scheduler: "
# daemon $prog scheduler \
# --master=${MASTER} \
# > ${logfile}-scheduler.log 2>&1 &
(ignored below parts)
# service kubernetes-master start
Starting apiserver:

到这一步,您有两个Master服务器在系统中使用两个API服务器进程。

在Master中设置kubelet

因为我们要将调度器守护进程和控制器管理器安装为Pod,因此,一个kubelet进程是必须的守护进程。下载最新版(version1.1.4)的kubelet二进制文件((https://storage.googleapis.com/kubernetes-release/release/v1.1.4/bin/linux/amd64/kubelet )并将它放到系统二进制文件的目录下:

# wget https://storage.googleapis.com/kubernetes-release/release/v1.1.4/
bin/linux/amd64/kubelet
# chmod 755 kubelet
# mv kubelet /usr/local/bin/

另一种方法,对于RHEL系统,你可以从YUM仓库下载kubelet:

# yum install kubernetes-node

稍后,我们将使用指定的参数和值配置kubelet守护进程:

标签名称 Purpose
--api servers 127.0.0.1:8080 与本地 API server通信。
--register node false 避免将此Master,本地主机,注册为一个节点
--allow privileged true 为了允许容器请求privileged的模式,这意味着容器有能为访问主机服务,在这种情况下尤其是网络设备。
--config /etc/kubernetes/ manifests 为了通过此指定目录下的模板文件管理本地容器。

如果你的系统被systemctl监示,将前面的参数放到配置文件中:

  • 在/etc/kubernetes/config中:

    • 将KUBE_MASTER修改为--master=127.0.0.1:8080:

      KUBE_LOGTOSTDERR="--logtostderr=true" KUBE_LOG_LEVEL="--v=0" KUBE_ALLOW_PRIV="--allow_privileged=false" KUBE_MASTER="--master=127.0.0.1:8080"

  • 在/etc/kubernetes/kubelet中:

    • 将--api-servers放在KUBELET_API_SERVER中。

    • 将其它三个标记放在KUBELET_ARGS中。

      KUBELET_ADDRESS="--address=0.0.0.0" KUBELET_HOSTNAME="--hostname_override=127.0.0.1" KUBELET_API_SERVER="--api_servers=127.0.0.1:8080" KUBELET_ARGS="--register-node=false --allow-privileged=true --config /etc/kubernetes/manifests"

另一方面,修改你的启动服务管理的脚本文件并将标记添加到kubelet守护进程的后面。例如,我们在/etc/init.d/kubelet中有以下设置:

# cat /etc/init.d/kubelet
prog=/usr/local/bin/kubelet
lockfile=/var/lock/subsys/`basename $prog`
hostname=`hostname`
logfile=/var/log/kubernetes.log

start() {
    # Start daemon.
    echo $"Starting kubelet: "
    daemon $prog \
        --api-servers=127.0.0.1:8080 \
        --register-node=false \
        --allow-privileged=true \
        --config=/etc/kubernetes/manifests \
        > ${logfile} 2>&1 &
    (ignored)

最好保持你的kubelet服务在停止状态,因为我们将在准备好调度器和控制器管理器的配置文件之后再创建它。

准备配置文件

我们需要三个模板作为配置文件:pod master,scheduler和controller manager。这些文件应该放在指定路径下。

pod master处理先择决定在哪个Master节点上运行调度器守护进程并在哪个Master容器上运行控制器管理器进程的守护进程。结果将被记录在etcd服务器中。pod master的模板放在kubelet配置目录,确保在正确创建了pod master之后再启动运行kubelet:

# cat /etc/kubernetes/manifests/podmaster.yaml
apiVersion: v1
kind: Pod
metadata:
 name: podmaster
 namespace: kube-system
spec:
 hostNetwork: true
 containers:
 - name: scheduler-elector
  image: gcr.io/google_containers/podmaster:1.1
  command: ["/podmaster", "--etcd-servers=<ETCD_ENDPOINT>",
"--key=scheduler", "--source-file=/kubernetes/kube-scheduler.yaml",
"--dest-file=/manifests/kube-scheduler.yaml"]
  volumeMounts:
  - mountPath: /kubernetes
   name: k8s
   readOnly: true
  - mountPath: /manifests
   name: manifests
  - name: controller-manager-elector
   image: gcr.io/google_containers/podmaster:1.1
   command: ["/podmaster", "--etcd-servers=<ETCD_ENDPOINT>",
"--key=controller", "--source-file=/kubernetes/kube-controller-manager.
yaml", "--dest-file=/manifests/kube-controller-manager.yaml"]
   terminationMessagePath: /dev/termination-log
   volumeMounts:
   - mountPath: /kubernetes
    name: k8s
    readOnly: true
  - mountPath: /manifests
    name: manifests
 volumes:
 - hostPath:
  path: /srv/kubernetes
   name: k8s
  - hostPath:
   path: /etc/kubernetes/manifests
  name: manifests

在pod master的配置文件中,我们将部署一个具有两个容器、两个不同守护进程选举者的Pod。podmaster的Pod在一个名叫kube-system的新的命名空间中创建的,为了分离守护进程的Pod和应用程序的Pod。我们将首先需要创建一个新的命名空间,再使用模板来创建资源。值得一提的是,路径/srv/kubernetes是我们放置守护进程配置文件的地方。文件内容如下几行所示:

# cat /srv/kubernetes/kube-scheduler.yaml
apiVersion: v1
kind: Pod
metadata:
 name: kube-scheduler
 namespace: kube-system
spec:
 hostNetwork: true
 containers:
 - name: kube-scheduler
  image: gcr.io/google_containers/kube-scheduler:34d0b8f8b31e27937327961
528739bc9
  command:
  - /bin/sh
  - -c
  - /usr/local/bin/kube-scheduler --master=127.0.0.1:8080 --v=2 1>>/var/
log/kube-scheduler.log 2>&1
  livenessProbe:
   httpGet:
    path: /healthz
    port: 10251
   initialDelaySeconds: 15
   timeoutSeconds: 1
  volumeMounts:
  - mountPath: /var/log/kube-scheduler.log
    name: logfile
  - mountPath: /usr/local/bin/kube-scheduler
    name: binfile
volumes:
- hostPath:
  path: /var/log/kube-scheduler.log
  name: logfile
- hostPath:
  path: /usr/local/bin/kube-scheduler
  name: binfile

在模板中有一些特殊的项,如namespace和两个挂载的文件。一个是日志文件;可以访问流输出并存储在本地。另一个是执行文件。容器可以使用本地主机中的最新版本的kube-scheduler:

# cat /srv/kubernetes/kube-controller-manager.yaml
apiVersion: v1
kind: Pod
metadata:
    name: kube-controller-manager
    namespace: kube-system
spec:
    containers:
    - command:
        - /bin/sh
        - -c
        - /usr/local/bin/kube-controller-manager --master=127.0.0.1:8080 --cluster-cidr=<KUBERNETES_SYSTEM_CIDR> --allocate-node-cidrs=true --v=2 1>>/var/log/kube-controller-manager.log 2>&1
        image: gcr.io/google_containers/kube-controller-manager:fda24638d51a48baa13c35337fcd4793
        livenessProbe:
            httpGet:
                path: /healthz
                port: 10252
        	initialDelaySeconds: 15
        	timeoutSeconds: 1
        name: kube-controller-manager
        volumeMounts:
        - mountPath: /srv/kubernetes
        	name: srvkube
        	readOnly: true
        - mountPath: /var/log/kube-controller-manager.log
        	name: logfile
        - mountPath: /usr/local/bin/kube-controller-manager
        	name: binfile
    hostNetwork: true
    volumes:
    - hostPath:
    	path: /srv/kubernetes
    name: srvkube
    - hostPath:
    	path: /var/log/kube-controller-manager.log
    name: logfile
    - hostPath:
   		path: /usr/local/bin/kube-controller-manager
    name: binfile

控制器管理器的配置文件与其中一个调试器的配置文件类似。记住,在守护进程命令中,提供Kubernetes系统的CIDR范围。

为了你你的模板能够顺利工作,在你启动pod master之前两袖清风有一些需要的预配置:

  • 创建一个空的日志文件。否则,替换文件格式,容器将路径作为目录并导致一个Pod的创建错误:

// execute these commands on each master
# touch /var/log/kube-scheduler.log
# touch /var/log/kube-controller-manager.log
  • 创建一个新的命名空间。新的命名空间与黙认的命名空间独立。我们将系统需要的Pod放在这个命名空间中:
// Just execute this command in a master, and other masters can
share this update.
# kubectl create namespace kube-system
// Or
# curl -XPOST -d'{"apiVersion":"v1","kind":"Namespace","metadata":
{"name":"kube-system"}}' "http://127.0.0.1:8080/api/v1/namespaces"

启动kubelet服务并打开守护进程!

在为我们的pod master和两个master拥有的守护进程启动kubelet之前,请确保Docker和flanneld首先启动:

# Now, it is good to start kubelet on every masters
# service kubelet start

稍等一会;你将在每个Master上获取一个运行的pod master并且你将最终获取一对调试器和控制器管理器:

# Check pods at namespace "kube-system"
# kubectl get pod --namespace=kube-system
NAME READY STATUS RESTARTS AGE
kube-controller-manager-kube-master1 1/1 Running 0 3m
kube-scheduler-kube-master2 1/1 Running 0 3m
podmaster-kube-master1 2/2 Running 0 1m
podmaster-kube-master2 2/2 Running 0 1m

恭喜!你成功构建了自己的多Master的Kubernetes系统。机器的架构如下图所示:

你现在可看到,单独的一个Node节点不需要处理所有的请求负载。而且,守护进程在Master中并不拥挤;它们可以被分发到不同的master中并且每个master都有能力恢复。尝试停止一个master;你将会发现调度器与副本控制器仍然提供服务。

它是如何工作的...

验证pod master容器的日志;你将得到两种消息,一个是持有Key的,而另一个是手上是没有Key的。

// Get the log with specified container name
# kubectl logs podmaster-kube-master1 -c scheduler-elector
--namespace=kube-system
I0211 15:13:46.857372 1 podmaster.go:142] --whoami is empty,
defaulting to kube-master1
I0211 15:13:47.168724 1 podmaster.go:82] key already exists, the
master is kube-master2, sleeping.
I0211 15:13:52.506880 1 podmaster.go:82] key already exists, the
master is kube-master2, sleeping.
(ignored)
# kubectl logs podmaster-kube-master1 -c controller-manager-elector
--namespace=kube-system
I0211 15:13:44.484201 1 podmaster.go:142] --whoami is empty,
defaulting to kube-master1
I0211 15:13:50.078994 1 podmaster.go:73] key already exists, we are
the master (kube-master1)
I0211 15:13:55.185607 1 podmaster.go:73] key already exists, we are
the master (kube-master1)
(ignored)

有Key的master应该接管指定的守护进程和所述的调试器和控制器管理器。目前Master的高可用解决方案是通过etcd中lease-lock方法实现:

上面的循环较片指明了lease-lock方法的过程。在这个方法中有两个时间段很重要:SLEEP是检查锁(Lock)的时间段,Time to Live(TTL)是租约超时时间段。我们可以这样说,如果运行守护进程的Master崩溃了,最坏的情况是另一个Master接管作业需要的时间为SLEEP+TTL。黙认情况下,SLEEP是5秒,TTL是3秒。

您仍然可以查看pod master的源代码(podmaster.go: https://github.com/kubernetes/contrib/blob/master/pod-master/podmaster.go )以获得更多概念

还可以参考

在你阅读本节时,你应该对单Maser节点的安装有了一个基本的概念了。参考这里提到的相关的章节并了解如何自动构建多Master系统:

  • 第1章构建你自己的Kubernetes,配置Master这一节

  • 第6章在AWS上构建Kubernetes,在AWS上构建Kubernetes基础设施这一节