所有文章

Bigdata on Kubernetes

把大数据平台容器化,是我们的必经之路,一是因为容器化有诸多好处,比如:将每个组件标准化、易于管理、快速升级、快速部署等等,二是因为趋势,当其它人做了而你没做,就可能被客户抛弃,所以最好在所有人之前就开始做。

基础镜像

把大数据平台容器化,首先得先把平台中的组件一个个拆开,然后每个组件(Hadoop, Spark等)的运行环境都有差别,比如 Hadoop 依赖 DJK7 而 Spark 依赖 JDK8 等,这就需要将组件和相应的依赖打包成在一起,但所有组件应该共用一个基础镜像,这个基础镜像很小,可能只有几十到几百 MB ,构建基础镜像看这里,有了基础镜像之后就可以在写每个 Dockerfile 时指定的你 FROM 参数。

构建组件镜像

我们先用 hadoop-yarn 来举例编写一个 Dockerfile,如果我有自己的 yum 源,那么可以直接使用 yum install hadoop-yarn 这样的方式来安装,下面是一个例子:

FROM centos6.5-base

ADD  /jdk-7u79-linux-x64.tar.gz /opt
COPY /bigdata.repo /etc/yum.repos.d/bigdata.repo

ENV JAVA_HOME=/opt/jdk1.7.0_79

RUN yum install hadoop* -y 

COPY /bootstrap.sh /bootstrap.sh

CMD /bootstrap.sh

其中 bigdata.repo 是一个 yum 源文件,里面定义了 hadoop, spark, hbase 等组件的 rpm 源;bootstrap.sh 是一个服务启动脚本,里面写了很重要的逻辑。

镜像仓库

有了 Yarn 镜像之后,我们需要将它放到私有仓库中,以便 Kubernetes 集群中的所有机器都能使用它,这时你需要搭建一个私有仓库,然后把所有组件的镜像 push 进去。

StatefulSet

Kubernetes 中的 StatefulSet 是为了解决有状态的服务而设计的,简单来说它可以定义一组 Pod 而且可以指定规模,而这些 Pod 并不是一模一样的,它们都有自己的状态,这个特性刚好与 Hadoop Yarn 的需求相吻合,下面是 StatefulSet 的部分示例:

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: node
spec:
  serviceName: "node"
  replicas: 3
  template:
    spec:
      containers:
      - name: node
        image: hadoop-yarn:v1
        env:
        - name: SCALE
          value: "3"

当执行这个 yaml 后,Kubernetes 会启动三个 Pod ,它们都用了同一个镜像,这意味着三个容器的内容都是一样的,它们唯一的区别在于它们的主机名,在上例中,第一个容器的主机名是 node-0,最后一个是 node-2。

然后我们就可以根据它们的主机名来启动容器中不同的服务,比如第一个容器启动 resourcemanager,其它容器启动 nodemanager,这个智能的事情谁来做呢,那就是 bootstrap.sh 这个脚本。

启动脚本

其实 bootstrap.sh 做的事情不只是启动服务,还有一些自动化配置的动作,下面是部分示例:

#!/bin/bash

ID=${HOSTNAME##*-}

for i in $(seq 0 $(($SCALE-1))); do
  echo -e "node-${i}" >> "$HADOOP_YARN_CONF_DIR/slaves"
done

if [ "ID" = "0" ]; then
  sbin/yarn-daemon.sh start resourcemanager
else
  sbin/yarn-daemon.sh start nodemanager
fi

HOSTNAME 是我们前面说过的 node-0 这样的形式,这样我们在容器里就可以知道当前容器应该启动什么服务,SCALE 变量是我们在 ymal 文件中定义的,这样我们在容器里就可以知道一共有多少个 Yarn 节点。

存储

即然每个容器不一样,那它们都有自己的数据,这些数据需要持久化,也就是说容器挂掉然后重启,原来的数据应该还在才行,这个其实很好解决,Kubernetes 提供了多种持久化数据方案。

首先需要提前创建一些 PV 以备使用,然后我们在定义 StatefulSet 时加上 PVC 即可:

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: node
spec:
  serviceName: "node"
  replicas: 3
  template:
    spec:
      containers:
      - name: node
        image: hadoop-yarn:v1
        env:
        - name: SCALE
          value: "3"
        volumeMounts:
        - name: bigdata
          mountPath: /data
  volumeClaimTemplates:
  - metadata:
      name: bigdata
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

这样 Kubernetes 会为每个 Pod 挂载不同的 PVC ,在本例中,这些 PVC 将以 bigdata-node-0 的形式被命名,每个 PVC 会绑定到不同的 PV 上,比较完美地解决了我们需求。

持续部署

当上面的流程走通以后,基本就可以做到持续部署,当 Yarn 开发了新的版本后,我们只需用之前的 Dockerfile 重新构建一次镜像,并 push 到私有仓库,然后修改 yaml 文件中的 image 版本,再重新执行就可以在线升级我们的 Yarn 集群,如果升级失败还可以降回去。

结语

Kubernetes 有多种插件为我们解决了 Docker 多主机通信的问,所以本文中并没有提及到。大数据平台中的大部分组件通过本文中的方式基本可以实现容器化,而实际中还有很多问题等待解决,比如集群的监控与管理、前端展示、集群配置的动态修改与查看等等。


编写日期:2017-09-16