在微服务的实践过程中,我们经常会问自己:什么样的应用应该做成微服务?将应用做成微服务时有什么需要注意的?本文针对在Kuberenetes中部署YARN集群遇到的问题,讨论微服务化需要做的工作以及什么样的应用是微服务友好的。
启动 YARN/HDFS 集群
在YARN默认配置中,集群节点通过 ssh 启动:
- 配置集群中的节点可以无密码互访 [1]
- 修改 slaves 文件,在该文件中加入集群节点的主机名或IP
- 通过 start-yarn.sh/start-dfs.sh 启动集群
在这个启动过程中,ssh 扮演了一个远程执行的角色;但远程执行、启动服务正是Kuberenets所做工作的一部分,因此需要对该过程进行如下改造:
在上述过程中,由于没有配置slaves
文件,start-yarn.sh/start-dfs.sh
会仅启动本机的服务,例如 ResourceManager 或 NodeManager。根据此步骤制作如下的 Dockerfile
:
Master 节点的 Dockerfile 如下:
FROM ubuntu:14.04
MAINTAINER Klaus Ma <klaus1982.cn@gmail.com>
RUN apt-get update && apt-get -y install openjdk-7-jdk openssh-server
COPY hadoop-2.7.2.tar.gz /opt/
RUN cd /opt/ && tar zxvf hadoop-2.7.2.tar.gz && rm hadoop-2.7.2.tar.gz
COPY ./master_bootstrap.sh /opt/bootstrap.sh
COPY core-site.xml.template /root/
COPY yarn-site.xml.template /root/
COPY hdfs-site.xml.template /root/
COPY .ssh /root/.ssh
RUN chmod +x /opt/bootstrap.sh
# Hdfs ports
EXPOSE 31010 50020 50070 50075 50090 8020 9000
# Mapred ports
EXPOSE 19888
#Yarn ports
EXPOSE 8030 8031 8032 8033 8040 8042 8088
#Other ports
EXPOSE 49707 2122
ENTRYPOINT /opt/bootstrap.sh
master_bootstrap.sh 文件内容如下:
#!/bin/sh
export JAVA_HOME=/usr
HADOOP_PREFIX=/opt/hadoop-2.7.2
HADOOP_YARN_HOME=$HADOOP_PREFIX
HADOOP_CONF_DIR=/opt/hadoop-2.7.2/etc/hadoop
sed "s/__HOSTNAME__/"$(hostname)"/g" /root/core-site.xml.template > $HADOOP_CONF_DIR/core-site.xml
sed "s/__HOSTNAME__/"$(hostname)"/g" /root/yarn-site.xml.template > $HADOOP_CONF_DIR/yarn-site.xml
sed "s/__HOSTNAME__/"$(hostname)"/g" /root/hdfs-site.xml.template > $HADOOP_CONF_DIR/hdfs-site.xml
mkdir /opt/hadoop272/dfs/name -p
mkdir /opt/hadoop272/dfs/data -p
$HADOOP_PREFIX/bin/hdfs namenode -format yarn_272_hdfs
$HADOOP_PREFIX/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs start namenode
$HADOOP_PREFIX/sbin/yarn-daemon.sh --config $HADOOP_CONF_DIR start resourcemanager
while true; do sleep 1000; done
上面的Dockerfile 有几个地方还有待改进:
- 在Dockerfile 使用了多次
COPY
,这样会增加镜像的layer数目
- 目前使用了预先生成的
.ssh
文件,可以通过 master_bootstrap.sh
实时生成
- 在
master_bootstrap.sh
文件中,每次都会对HDFS进行格式化,如果外挂存储,则应该每次都重新格式化
- 目前将
ResourceManager/NodeManager
启动在同一个容器中,后续会分别部署在不同的容器中
- 目前的 YARN/HDFS 还只能后台运行,需要改进检测部分:当没有java程序运行时,容器退出
DataNode和NodeManager的Dockerfile
与之相似,但除了启动的服务不一样外,对YARN/HDFS配置文件的修改也有所区别,细节会在下面的篇幅介绍;具体可以参考 Dockefile.agent 和 agent_bootstrap.sh
连接ResourceManager与NodeManager
在上面的篇幅中介绍了如何启动YARN/HDFS
集群,但是各个节点启动后还需要彼此通信才能工作。因些需要修改YARN/HDFS相应的配置文件:core-site.xml
, yarn-site.xml
和 hdfs-site.xml
.
与ResourceManager
/NodeManager
通信相关的配置在yarn-site.xml
和core-site.xml
中,为了使ResourceManager和NodeManager可以相互通信,在镜像中制件了如下的模板:
core-site.xml
<property>
<name>fs.defaultFS</name>
<value>hdfs://__HOSTNAME__:9000</value>
</property>
yarn-site.xml
<property>
<name>yarn.resourcemanager.address</name>
<value>__HOSTNAME__:8032</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address</name>
<value>__HOSTNAME__:8030</value>
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address</name>
<value>__HOSTNAME__:8031</value>
</property>
<property>
<name>yarn.resourcemanager.admin.address</name>
<value>__HOSTNAME__:8033</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>__HOSTNAME__:8088</value>
</property>
在不同的镜像中,__HOSTNAME__
会被替换为不同的值:在master_bootstrap.sh
中,被替换为容器的hostname;而在agent_bootstrap.sh
中,由被替换为yarn_master
。yarn_master
是ResourceManager在Kubernetes的Service,因此在配置了Kube-DNS后,各个 NodeManager 节点可以找到该ResourceManager节点,并与之通信。
在进行了上述配置后,ResourceManager与NodeManager可以正常通信;但是 NameNode 和 DataNode 仍然无法通信。这主要是由于 NameNode 会对连接进来的DataNode进行 ip/hostname 的检查,由于没有对DataNode配置相应DNS,NameNode会拒绝末知的 ip/hostname。HDFS提供了如下的配置,可以忽略 ip/hostname的检查:
hdfs-site.xml
<property>
<name>dfs.namenode.datanode.registration.ip-hostname-check</name>
<value>false</value>
</property>
但是上面的配置并不能完全解决问题:虽然 NameNode 不再进行 ip/hostname 检测,但在访问 DataNode 的时候会取得错误的ip: NameNode 使用主机 ip 而不是容器 ip 与 DataNode 通信。
已知的 Hadoop 镜像
不同厂商在 Docker Hub 上都提供了Hadoop 镜像,但多为单一镜像且需要手动配置才能正常工作,例如 ssh的无密码访问。目前还没有社区版本的Hadoop镜像,但已经创建了HADOOP-13397进行需求的跟踪。
问题总结
相关讨论
comments powered by