使用docker搭建虚拟分布式spark集群__笔记

  1. Docker是一个基本的技术,关于安装可以参考课程笔记:http://note.youdao.com/noteshare?
    id=9db3d00b3635b6a754245bb2744b379f&sub=CCADE90734E24384B5AD3977C29EB8A1
    更多Docker相关的内容请参照《Docker入门到精通课程》:http://edu.51cto.com/course/11354.html

  2. 镜像制作方案
    我们要使用Docker来搭建hadoop,spark,hive,及mysql的集群,首先使用Dockerfile制作镜像,把相关的软件拷贝到约定好的目录下,把配置文件在外面先配置好,再拷贝移动到hadoop,spark,hive的配置目录,需要注意一点在spark中读取hive中的数据,需要把hive-site.xml拷贝到spark的conf目录;为了能使得mysql能从其它节点被访问到,要配置mysql的访问权限。

  3. 集群整体架构
    一共5个节点,即启动5个容器。hadoop-maste,hadoop-node1,hadoop-node2这三个容器里面安装hadoop和spark集群,hadoop-hive这个容器安装hive,hadoop-mysql这个容器安装mysql数据库。spark中可以在sparksession的builder中通过enableHiveSupport()方法,启用对hive数据仓库表操作的支持。mysql用于保存hive的元数据。当然也spark中的DataFrame也可以通过write方法将数据写入mysql中,具体的操作后面课程会详细讲解。

  4. 集群网络规划及子网配置
    既然是做集群,网络的规划是少不了的,至于网络,可以通过Docker中的DockerNetworking的支持配置。首先设置网络,docker中设置子网可以通过docker network create 方法,这里我们通过命令设置如下的子网。–subnet指定子网络的网段,并为这个子网命名一个名字叫spark
    docker network create --subnet=172.16.0.0/16 spark运行完成之后,通过docker network ls查看创建的子网落列表。

    接下来就在我们创建的子网落spark中规划集群中每个容器的ip地址。网络ip分配如下:
    这个地方要注意,5个容器的hostname都是以hadoop-*开头,这个命名是有讲究的,因为我们要配置容器之间的SSH我密钥登录,在不
    生成id_rsa.pub公钥的条件下,我们可以通过配置SSH过滤规则来配置容器间的互通信!具体配置会在后面讲到。

  5. 软件版本:
    网络规划好了,接下来我们看看需要用到哪些软件。首先Spark我们使用最新的2.3.0版本,Hadoop采用比较稳定的hadoop-2.7.3版本,Hive采用最新的稳定版本hive-2.3.2,scala采用scala-2.11.8,JDK采用jdk-8u101-linux-x64,mysql使用mysql-5.5.45-linux2.6-x86_64。当然hive和spark要连接mysql数据库少不了一个驱动程序,这个驱动程序我们使用的是mysql-connector-java-5.1.37-bin.jar。

  6. SSH无密钥登录规则配置
    注意这里不使用ssh-keygen -t rsa -P ''这种方式生成id_rsa.pub,然后集群节点互拷贝id_rsa.pub到authorized_keys文件这种方式,而是通过在.ssh目录下配置ssh_conf文件的方式,ssh_conf中可以配置SSH的通信规则,例如以正则表达式的方式指定hostname为XXX的机器之间实现互联互通,而不进行额外的密钥验证。为了编写这个正则表达式,我们5个节点的hostname都以hadoop-*的方式作为开头,这就是采用这种命名规则的原因。下面来看下ssh_conf配置的内容:

    Host localhost
      StrictHostKeyChecking no
    Host 0.0.0.0
      StrictHostKeyChecking no
      
    Host hadoop-*
       StrictHostKeyChecking no
    

    注意上面的最后一行,Host hadoop-* 指定了它的严格的Host验证StrictHostKeyChecking 为no,这样既可以是这5个hostname以
    hadoop-*开头的容器之间实现互联互通,而不需要二外的验证。

  7. Hadoop配置文件讲解
    hadoop的配置文件位于$HADOOP_HOME/etc/hadoop文件夹下,重要的配置文件有core-site.xml、hadoop-env.sh、hdfs-site.xml、mapred-env.sh、mapred-site.xml、yarn-env.sh、yarn-site.xml、master、slaves这九个配置文件。其中core-site.xml用于配置hadoop默认的文件系统的访问路径,访问文件系统的用户及用户组等相关的配置。core-site.xml配置如下:

    <?xml version="1.0"?>
    <configuration>
        <property>
            <name>fs.defaultFS</name>
            <value>hdfs://hadoop-maste:9000/</value>
        </property>
      <property>
             <name>hadoop.tmp.dir</name>
             <value>file:/usr/local/hadoop/tmp</value>
        </property>
      <property>
            <name>hadoop.proxyuser.root.hosts</name>
            <value>*</value>
        </property>
        <property>
            <name>hadoop.proxyuser.root.groups</name>
            <value>*</value>
        </property>
      <property>
            <name>hadoop.proxyuser.oozie.hosts</name>
            <value>*</value>
        </property>
        <property>
            <name>hadoop.proxyuser.oozie.groups</name>
            <value>*</value>
        </property>
    </configuration>
    

    hadoop-env.sh这个配置文件用来配置hadoop运行依赖的JDK环境,及一些JVM参数的配置,除了JDK路径的配置外,其他的我们不用
    管,内容如下:

    # Licensed to the Apache Software Foundation (ASF) under one
    # or more contributor license agreements.  See the NOTICE file
    # distributed with this work for additional information
    # regarding copyright ownership.  The ASF licenses this file
    # to you under the Apache License, Version 2.0 (the
    # "License"); you may not use this file except in compliance
    # with the License.  You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    # Set Hadoop-specific environment variables here.
    # The only required environment variable is JAVA_HOME.  All others are
    # optional.  When running a distributed configuration it is best to
    # set JAVA_HOME in this file, so that it is correctly defined on
    # remote nodes.
    # The java implementation to use.
    export JAVA_HOME=/usr/local/jdk1.8.0_101
    # The jsvc implementation to use. Jsvc is required to run secure datanodes
    # that bind to privileged ports to provide authentication of data transfer
    # protocol.  Jsvc is not required if SASL is configured for authentication of
    # data transfer protocol using non-privileged ports.
    #export JSVC_HOME=${JSVC_HOME}
    export HADOOP_CONF_DIR=${HADOOP_CONF_DIR:-"/etc/hadoop"}
    # Extra Java CLASSPATH elements.  Automatically insert capacity-scheduler.
    for f in $HADOOP_HOME/contrib/capacity-scheduler/*.jar; do
      if [ "$HADOOP_CLASSPATH" ]; then
        export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$f
      else
        export HADOOP_CLASSPATH=$f
      fi
    done
    # The maximum amount of heap to use, in MB. Default is 1000.
    #export HADOOP_HEAPSIZE=
    #export HADOOP_NAMENODE_INIT_HEAPSIZE=""
    # Extra Java runtime options.  Empty by default.
    export HADOOP_OPTS="$HADOOP_OPTS -Djava.net.preferIPv4Stack=true"
    # Command specific options appended to HADOOP_OPTS when specified
    export HADOOP_NAMENODE_OPTS="-Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:-INFO,RFAS} -
    Dhdfs.audit.logger=${HDFS_AUDIT_LOGGER:-INFO,NullAppender} $HADOOP_NAMENODE_OPTS"
    export HADOOP_DATANODE_OPTS="-Dhadoop.security.logger=ERROR,RFAS $HADOOP_DATANODE_OPTS"
    export HADOOP_SECONDARYNAMENODE_OPTS="-Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:-INFO,RFAS} -
    Dhdfs.audit.logger=${HDFS_AUDIT_LOGGER:-INFO,NullAppender} $HADOOP_SECONDARYNAMENODE_OPTS"
    export HADOOP_NFS3_OPTS="$HADOOP_NFS3_OPTS"
    export HADOOP_PORTMAP_OPTS="-Xmx512m $HADOOP_PORTMAP_OPTS"
    # The following applies to multiple commands (fs, dfs, fsck, distcp etc)
    export HADOOP_CLIENT_OPTS="-Xmx512m $HADOOP_CLIENT_OPTS"
    #HADOOP_JAVA_PLATFORM_OPTS="-XX:-UsePerfData $HADOOP_JAVA_PLATFORM_OPTS"
    # On secure datanodes, user to run the datanode as after dropping privileges.
    # This **MUST** be uncommented to enable secure HDFS if using privileged ports
    # to provide authentication of data transfer protocol.  This **MUST NOT** be
    # defined if SASL is configured for authentication of data transfer protocol
    # using non-privileged ports.
    export HADOOP_SECURE_DN_USER=${HADOOP_SECURE_DN_USER}
    # Where log files are stored.  $HADOOP_HOME/logs by default.
    #export HADOOP_LOG_DIR=${HADOOP_LOG_DIR}/$USER
    # Where log files are stored in the secure data environment.
    export HADOOP_SECURE_DN_LOG_DIR=${HADOOP_LOG_DIR}/${HADOOP_HDFS_USER}
    ###
    # HDFS Mover specific parameters
    ###
    # Specify the JVM options to be used when starting the HDFS Mover.
    # These options will be appended to the options specified as HADOOP_OPTS
    # and therefore may override any similar flags set in HADOOP_OPTS
    #
    # export HADOOP_MOVER_OPTS=""
    ###
    # Advanced Users Only!
    ###
    # The directory where pid files are stored. /tmp by default.
    # NOTE: this should be set to a directory that can only be written to by 
    #       the user that will run the hadoop daemons.  Otherwise there is the
    #       potential for a symlink attack.
    export HADOOP_PID_DIR=${HADOOP_PID_DIR}
    export HADOOP_SECURE_DN_PID_DIR=${HADOOP_PID_DIR}
    # A string representing this instance of hadoop. $USER by default.
    export HADOOP_IDENT_STRING=$USER
    

    看似内容很多,但我们只需要更改一处配置即可,即上面标红的地方,导入JAVA_HOME 接下来的配置文件是hdfs-site.xml这个配置文件。它主要用来配置hdfs分布式文件系统的namenode即datanode数据的存储路径,及数 据区块的冗余数。具体配置如下:

    <?xml version="1.0"?>
    <configuration>
        <property>
            <name>dfs.namenode.name.dir</name>
            <value>file:/usr/local/hadoop2.7/dfs/name</value>
        </property>
        <property>
            <name>dfs.datanode.data.dir</name>
            <value>file:/usr/local/hadoop2.7/dfs/data</value>
        </property>
      <property>
            <name>dfs.webhdfs.enabled</name>
            <value>true</value>
        </property>
        <property>
            <name>dfs.replication</name>
            <value>2</value>
        </property>
      <property>
          <name>dfs.permissions.enabled</name>
        <value>false</value>
      </property>
     </configuration>
    

    配置也不复杂!不要怕~
    mapred-env.sh和mapred-site.xml这两个配置文件是对hadoop中mapreduce计算框架的运行环境参数及网络的配置文件,因为我们不 会用到hadoop中的mapreduce,因为它的计算性能不如spark快,spark官网称,spark运算速度是hadoop mapreduce速度的100倍!
    所以大胆放弃他们两个吧~ 为了消除一些强迫症患者心中的疑虑,这里为大家贴出mapred-site.xml的配置

    <?xml version="1.0"?>
    <configuration>
        <property>
            <name>mapreduce.framework.name</name>
            <value>yarn</value>
        </property>
        <property>
            <name>mapreduce.jobhistory.address</name>
            <!-- 配置实际的Master主机名和端口-->
            <value>hadoop-maste:10020</value>
        </property>
        <property>
            <name>mapreduce.map.memory.mb</name>
            <value>4096</value>
        </property>
        <property>
            <name>mapreduce.reduce.memory.mb</name>
            <value>8192</value>
        </property>
      <property>
          <name>yarn.app.mapreduce.am.staging-dir</name>
          <value>/stage</value>
        </property>
        <property>
          <name>mapreduce.jobhistory.done-dir</name>
          <value>/mr-history/done</value>
        </property>
        <property>
          <name>mapreduce.jobhistory.intermediate-done-dir</name>
          <value>/mr-history/tmp</value>
        </property>
    </configuration>
    

    接下来是yarn-env.sh 和 yarn-site.xml两个配置文件,yarn是hadoop中的任务调度系统,从配置文件的名字可以看出,他们分别用于yarn运行环境的配置及网络的配置。yarn-env.sh中会读取JAVA_HOME环境变量,还会设置一些默认的jdk参数,因此通常情况下我们都不用修改yarn-env.sh这个配置文件,对于yarn-site.xml配置文件,我们还是贴出配置:

    <?xml version="1.0"?>
    <configuration>
        <property>
            <name>yarn.nodemanager.aux-services</name>
            <value>mapreduce_shuffle</value>
        </property>
        <property>
            <name>yarn.nodemanager.aux-services.mapreduce_shuffle.class</name>
            <value>org.apache.hadoop.mapred.ShuffleHandler</value>
        </property>
        <property>
            <name>yarn.resourcemanager.hostname</name>
            <value>hadoop-maste</value>
        </property>
      <property>
            <name>yarn.resourcemanager.address</name>
            <value>hadoop-maste:8032</value>
        </property>
        <property>
            <name>yarn.resourcemanager.scheduler.address</name>
            <value>hadoop-maste:8030</value>
        </property>
        <property>
            <name>yarn.resourcemanager.resource-tracker.address</name>
            <value>hadoop-maste:8035</value>
        </property>
        <property>
            <name>yarn.resourcemanager.admin.address</name>
            <value>hadoop-maste:8033</value>
        </property>
        <property>
            <name>yarn.resourcemanager.webapp.address</name>
            <value>hadoop-maste:8088</value>
        </property>
        <property>
            <name>yarn.log-aggregation-enable</name>
            <value>true</value>
       </property>
        <property>
           <name>yarn.nodemanager.vmem-pmem-ratio</name>
           <value>5</value>
        </property>
    <property>
        <name>yarn.nodemanager.resource.memory-mb</name>
        <value>22528</value>
        <discription>每个节点可用内存,单位MB</discription>
      </property>
      
      <property>
        <name>yarn.scheduler.minimum-allocation-mb</name>
        <value>4096</value>
        <discription>单个任务可申请最少内存,默认1024MB</discription>
      </property>
      
      <property>
        <name>yarn.scheduler.maximum-allocation-mb</name>
        <value>16384</value>
        <discription>单个任务可申请最大内存,默认8192MB</discription>
      </property>
    </configuration>
    

    它的配置也请简单,主要涉及到一些端口及资源的配置。

    接下来看下master和slaves两个配置文件,hadoop是一个master-slave结构的分布式系统,指定哪个节点为master节点,哪些节点为slaves节点呢?hadoop的解决方法是通过master和slaves两个配置文件。下看下master配置文件中的内容:

    hadoop-maste
    

    很简单只有一句话,指定master主节点运行在我们上面网络规划的hadoop-maste这个hostname对应的容器中。

    再看下slaves配置文件:

    hadoop-node1
    hadoop-node2
    

    它的内容也不复杂,指定slaves节点分别为hadoop-node1和hadoop-node2,在这两个容器中将会启动hdfs对应的DataNode进程及YARN资源管理系统启动的NodeManager进程。
    至此hadoop所有配置文件讲完,现在把这几个配置文件罗列在这里。

  8. Spark配置文件讲解
    Spark中的配置文件就较少啦,主要有masters、slaves、spark-defaults.conf、spark-env.sh。接下来依次讲解spark也是一个master-slave结构的分布式计算引擎,它也是通过配置文件masters和slaves的方式来指定master节点和slave节点的。注意这里的文件名字是masters,和hadoop的master文件功能类似,但是却多了个’s’,意思想必大家已经猜到,可以配置多个master的主机名,接下来看下masters内容:

    hadoop-maste
    

    简单一行,指定spark集群的master节点为hadoop-maste这个hostname对应的容器
    再来看下slaves文件,内容如下:

    hadoop-node1
    hadoop-node2
    

    分别指定hadoop-node1和hadoop-node2两个节点,Spark集群启动后,会在hadoop-maste启动Master进程,在hadoop-node1和hadoop-node2启动Worker进程。

  9. Hive配置文件讲解。
    Hive是一个支持SQL语句的数据仓库,SparkSQL之前的版本曾经使用过Hive底层的SQL解释器及优化器,因此Spark自然也是支持读写Hive表格的,前提条件是在Spark中使用enableHiveSupport指定,还需要注意的是Hive的配置文件hive-site.xml需要放到$SPARK_HOME/conf目录下,这样Spark在操作Hive的时候才能找到相应的Hive的通信地址。Hive中重要的配置文件就两个。hive-site.xml和hive-env.sh两个配置文件。hive-site.xml文件内容如下:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?> 
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> 
    <configuration> 
            <property>
                    <name>hive.metastore.warehouse.dir</name>
                    <value>/home/hive/warehouse</value>
            </property>
            <property>
                    <name>hive.exec.scratchdir</name>
                    <value>/tmp/hive</value>
            </property>
            <property> 
                    <name>hive.metastore.uris</name> 
                    <value>thrift://hadoop-hive:9083</value> 
                    <description>Thrift URI for the remote metastore. Used by metastore client to connect to remote metastore.
    </description> 
            </property>
            <property>
                    <name>hive.server2.transport.mode</name>
                    <value>http</value>
            </property>
            <property>
                    <name>hive.server2.thrift.http.port</name>
                    <value>10001</value>
            </property>
            
            <property> 
                    <name>javax.jdo.option.ConnectionURL</name> 
                    <value>jdbc:mysql://hadoop-mysql:3306/hive?createDatabaseIfNotExist=true</value> 
            </property> 
            <property> 
                    <name>javax.jdo.option.ConnectionDriverName</name> 
                    <value>com.mysql.jdbc.Driver</value> 
            </property> 
            <property> 
                    <name>javax.jdo.option.ConnectionUserName</name> 
                    <value>root</value> 
            </property> 
            <property> 
                    <name>javax.jdo.option.ConnectionPassword</name> 
                    <value>root</value> 
            </property> 
            <property> 
                    <name>hive.metastore.schema.verification</name> 
                    <value>false</value> 
            </property>
            <property>
                   <name>hive.server2.authentication</name>
                   <value>NONE</value>
            </property> 
    </configuration>
    

    在配置文件中通过javax.jdo.option.ConnectionURL配置选项指定了Hive元数据存放的关系型数据库mysql的存储地址。通过javax.jdo.option.ConnectionDriverName 指定驱动,通过hive.metastore.warehouse.dir指定数据仓库在HDFS中的存放位置。hive.metastore.uris指定Hive元数据访问的通信地址,使用的是thrift协议。javax.jdo.option.ConnectionUserName指定连接数据库的用户名,javax.jdo.option.ConnectionPassword指定连接数据库的密码。

    再来看hive-env.sh配置文件。因为Hive的数据要存储在HDFS中,那Hive怎么和Hadoop通信呢?Hive的解决方案是在hive-env.sh中加入Hadoop的路径,这样Hive就会从Hadoop的路径下去寻找配置文件,自然能找到和Hadoop中HDFS通信的信息,从而完成Hive和Hadoop的通信。其内容如下:

    HADOOP_HOME=/usr/local/hadoop-2.7.3
    

    简简单单的一句话而已。

  10. 准备软件,编写Dockerfile脚本,制作镜像
    制作镜像所需要的软件在“4”小点中已经罗列出来了,这里再截个图如下:
    在root用户的根目录下,创建一个spark文件夹,将上述软件拷贝到这个文件夹中。这些文件已经上传到 百度云盘,自行下载。
    链接:https://pan.baidu.com/s/1i8yO2X25TZ0ofSEXPmIq-g 密码:akfq
    接下来把hadoop,spark,hive的配置文件拷贝到当前目录下的config目录中。【先新建一个config目录】
    上面的除了apt.conf、profile、restart_containers.sh,start_containers.sh,stop_containers.sh,init_hive.sh,init_mysql.sh,restart-hadoop.sh,start-hadoop.sh,pip.conf没有讲到外,其余的都讲到过了。包括SSH免密钥登录的ssh_config配置文件也拷贝在这里,待会儿使用COPY命令制作镜像。

    apt.conf【若你的虚拟机能够连上外网,这个配置可不用管】
    这个配置文件,这个配置文件是用来配置ubuntu系统中apt-get无法访问外网时使用代理来访问外网的配置文件,内容如下:
    Acquire::http::Proxy "http://root:[email protected]:7890/";
    配置中的http://root:[email protected]:7890/需要设置成你能够用来上网的代理的地址。具体的代理的配置可以查看这篇笔记:http://note.youdao.com/noteshare?id=30bf16ad14a5edfdba9f8cd373f063ae&sub=D1D83FF46AB149E88B9528B1516C31CA
    要把这个文件拷贝到/etc/apt/这个目录下,怎么拷贝?Dockerfile中使用RUN运行mv命令即可。具体怎么操作后面后讲到。当然我的虚 拟机在内网,因此需要使用代理上网,你们自己的电脑上可以不管这个!

    重要!pip.conf,pip默认会访问国外的源,速度非常慢,在制作镜像的时候会使用到pip下载python包,因此强烈推荐使用pip在国内的源,这个源由豆瓣管理。需要增加如下配置:
    上面使用到了pip命令安装python中的一些包,pip默认的源有时候无法访问,这时需要修改pip默认的源。

    编辑配置文件:新建pip.conf文件
    添加内容如下:

    [global]  
    index-url = http://pypi.douban.com/simple  
    trusted-host = pypi.douban.com
    

这个pip.conf文件是需要放到~/.pip/pip.conf文件中的,因此在制作镜像的时候首先新建~/.pip文件夹,然后把config目录中已经配置好的pip.conf mv到~/.pip文件夹中,具体操作稍后见Dockerfile中的指令profile这个配置文件用于配置系统环境变量的,profile配置文件位于/etc/profile,我们需要把hadoop,spark,hive,jdk,scala,mysql的环境变量配置在这里。其内容如下:

# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).
if [ "$PS1" ]; then
  if [ "$BASH" ] && [ "$BASH" != "/bin/sh" ]; then
    # The file bash.bashrc already sets the default PS1.
    # PS1='\h:\w\$ '
    if [ -f /etc/bash.bashrc ]; then
      . /etc/bash.bashrc
    fi
  else
    if [ "`id -u`" -eq 0 ]; then
      PS1='# '
    else
      PS1='$ '
    fi
  fi
fi
if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi
export JAVA_HOME=/usr/local/jdk1.8.0_101
export SCALA_HOME=/usr/local/scala-2.11.8
export HADOOP_HOME=/usr/local/hadoop-2.7.3
export SPARK_HOME=/usr/local/spark-2.3.0-bin-hadoop2.7
export HIVE_HOME=/usr/local/apache-hive-2.3.2-bin
export MYSQL_HOME=/usr/local/mysql
export 
PATH=$HIVE_HOME/bin:$MYSQL_HOME/bin:$JAVA_HOME/bin:$SCALA_HOME/bin:$HADOOP_HOME/bin:$SPARK_HOME/bin:$PATH

分别将JAVA_HOME、SCALA_HOME、HADOOP_HOME、SPARK_HOME、HIVE_HOME、MYSQL_HOME添加到PATH路径中,在制
作镜像的时候,需要把profile文件COPY到/etc/profile。这里只做profile文件的目的是防止Dockerfile中通过ENV命令来设置环境变量不成功!我之前就遇到过使用ENV设置环境变量失败的例子。
restart_containers.sh, start_containers.sh, stop_containers.sh
这几个脚本是用来启动、重启、停止容器的,也是一键启动、重启、关闭容器集群的脚本,后面会详细讲到的,大家别担心!

Dockerfile制作镜像的核心文件
接下来就讲Dockerfile的编写,在前面Docker课程中,相信大家学到了Dockerfile的基本的命令的使用,那这一小节就
来综合使用下吧。先把完整的Dockerfile贴出来:

FROM ubuntu
MAINTAINER reganzm [email protected]
ENV BUILD_ON 2018-03-04
COPY config /tmp
#这句若你的虚拟机能直接连上外网,需要注释掉!因为apt-get需要连上外网下载资源
#RUN mv /tmp/apt.conf /etc/apt/
#把pip的豆瓣镜像源配置文件pip.conf移动到~/.pip/pip.conf文件中
RUN mkdir -p ~/.pip/
RUN mv /tmp/pip.conf ~/.pip/pip.conf
RUN apt-get update -qqy
RUN apt-get -qqy install vim wget net-tools  iputils-ping  openssh-server python-pip libaio-dev apt-utils
#若你的虚拟机能够连上外网,红色的部分请去除掉!pip不必使用代理上网!
RUN pip install pandas  numpy  matplotlib  sklearn  seaborn  scipy tensorflow  gensim --proxy 
http://root:[email protected]:7890/
#添加JDK
ADD ./jdk-8u101-linux-x64.tar.gz /usr/local/
#添加hadoop
ADD ./hadoop-2.7.3.tar.gz  /usr/local
#添加scala
ADD ./scala-2.11.8.tgz /usr/local
#添加spark
ADD ./spark-2.3.0-bin-hadoop2.7.tgz /usr/local
#添加mysql
ADD ./mysql-5.5.45-linux2.6-x86_64.tar.gz /usr/local
RUN mv /usr/local/mysql-5.5.45-linux2.6-x86_64  /usr/local/mysql
ENV MYSQL_HOME /usr/local/mysql
#添加hive
ADD ./apache-hive-2.3.2-bin.tar.gz /usr/local
ENV HIVE_HOME /usr/local/apache-hive-2.3.2-bin
#写入hive-env.sh文件的内容
RUN echo "HADOOP_HOME=/usr/local/hadoop-2.7.3"  | cat >> /usr/local/apache-hive-2.3.2-bin/conf/hive-env.sh
#添加mysql-connector-java-5.1.37-bin.jar到hive的lib目录中
ADD ./mysql-connector-java-5.1.37-bin.jar /usr/local/apache-hive-2.3.2-bin/lib
#添加mysql-connector-java-5.1.37-bin.jar到spark的jars目录中
RUN cp /usr/local/apache-hive-2.3.2-bin/lib/mysql-connector-java-5.1.37-bin.jar /usr/local/spark-2.3.0-bin-hadoop2.7/jars
#增加JAVA_HOME环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_101
#hadoop环境变量
ENV HADOOP_HOME /usr/local/hadoop-2.7.3 
#scala环境变量
ENV SCALA_HOME /usr/local/scala-2.11.8
#spark环境变量
ENV SPARK_HOME /usr/local/spark-2.3.0-bin-hadoop2.7
#将环境变量添加到系统变量中
ENV PATH 
$HIVE_HOME/bin:$MYSQL_HOME/bin:$SCALA_HOME/bin:$SPARK_HOME/bin:$HADOOP_HOME/bin:$JAVA_HOME/bin:$JAVA_HOME/lib/dt.jar:$
#生成.ssh目录及id_rsa.pub 、authorized_keys文件。并把文件权限设置为600
RUN ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' && \
    cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys && \
    chmod 600 ~/.ssh/authorized_keys
#将配置移动到正确的位置
RUN mv /tmp/ssh_config    ~/.ssh/config && \
    mv /tmp/profile /etc/profile && \
    mv /tmp/masters $SPARK_HOME/conf/masters && \
    cp /tmp/slaves $SPARK_HOME/conf/ && \
    mv /tmp/spark-defaults.conf $SPARK_HOME/conf/spark-defaults.conf && \
    mv /tmp/spark-env.sh $SPARK_HOME/conf/spark-env.sh && \ 
    cp /tmp/hive-site.xml $SPARK_HOME/conf/hive-site.xml && \
    mv /tmp/hive-site.xml $HIVE_HOME/conf/hive-site.xml && \
    mv /tmp/hadoop-env.sh $HADOOP_HOME/etc/hadoop/hadoop-env.sh && \
    mv /tmp/hdfs-site.xml $HADOOP_HOME/etc/hadoop/hdfs-site.xml && \ 
    mv /tmp/core-site.xml $HADOOP_HOME/etc/hadoop/core-site.xml && \
    mv /tmp/yarn-site.xml $HADOOP_HOME/etc/hadoop/yarn-site.xml && \
    mv /tmp/mapred-site.xml $HADOOP_HOME/etc/hadoop/mapred-site.xml && \
    mv /tmp/master $HADOOP_HOME/etc/hadoop/master && \
    mv /tmp/slaves $HADOOP_HOME/etc/hadoop/slaves && \
    mv /tmp/start-hadoop.sh ~/start-hadoop.sh && \
    mkdir -p /usr/local/hadoop2.7/dfs/data && \
    mkdir -p /usr/local/hadoop2.7/dfs/name && \
    mv /tmp/init_mysql.sh ~/init_mysql.sh && chmod 700 ~/init_mysql.sh && \
    mv /tmp/init_hive.sh ~/init_hive.sh && chmod 700 ~/init_hive.sh && \
    mv /tmp/restart-hadoop.sh ~/restart-hadoop.sh && chmod 700 ~/restart-hadoop.sh
RUN echo $JAVA_HOME
#设置工作目录
WORKDIR /root
#启动sshd服务
RUN /etc/init.d/ssh start
#修改start-hadoop.sh权限为700
RUN chmod 700 start-hadoop.sh
#修改root密码
RUN echo "root:111111" | chpasswd
CMD ["/bin/bash"]

Dockerfile编写完成,接下来写一个build.sh脚本,内容如下:

echo build hadoop images
docker build -t="spark" .

表示构建一个名叫spark的镜像,.表示Dockerfile的路径,因为在当前路径下,所有用.,若在其他地方则用绝对路径指定Dockerfile的路径即可。

运行sh build.sh,就会开始制作镜像了。
制作完成后,使用docker images可以看到制作的名为spark的镜像。
启动容器start_containers.sh

使用这个镜像可完成容器的启动,容器的启动需要注意什么呢?因为我们使用了基于DockerNetworking的网络机制,因此可以在启动容器的时候为容器在子网172.16.0.0/16 spark中分贝172.16.0.1 172.16.0.255以外的IP地址,容器内部容器的通信是基于hostname,因此需要指定hostname,为了方便容器的管理,需要为启动的每个容器指定一个名字。为了方便外网访问,需要通过-p命令指定容器到宿主机的端口映射。还要为每个容器增加host列表。接下来我们看看怎样启动容器,启动容器的脚本位于start_containers.sh脚本中,内容如下:

echo start hadoop-hive container...
docker run -itd --restart=always --net spark --ip 172.16.0.5 --privileged --name hive --hostname hadoop-hive --add-host 
hadoop-node1:172.16.0.3 \
--add-host hadoop-node2:172.16.0.4 --add-host hadoop-mysql:172.16.0.6 --add-host hadoop-maste:172.16.0.2 spark 
/bin/bash
echo start hadoop-mysql container ...
docker run -itd --restart=always --net spark --ip 172.16.0.6 --privileged --name mysql --hostname hadoop-mysql --add-host 
hadoop-node1:172.16.0.3 --add-host hadoop-node2:172.16.0.4 --add-host hadoop-hive:172.16.0.5 --add-host hadoop-
maste:172.16.0.2 spark /bin/bash
echo start hadoop-maste container ...
docker run -itd --restart=always \--net spark \--ip 172.16.0.2 \--privileged \-p 18032:8032 \-p 28080:18080 \-p 29888:19888 \-
p 17077:7077 \-p 51070:50070 \-p 18888:8888 \-p 19000:9000 \-p 11100:11000 \-p 51030:50030 \-p 18050:8050 \-p 
18081:8081 \-p 18900:8900 \--name hadoop-maste \
--hostname hadoop-maste  \--add-host hadoop-node1:172.16.0.3 \--add-host hadoop-node2:172.16.0.4 --add-host hadoop-
hive:172.16.0.5 --add-host hadoop-mysql:172.16.0.6 spark /bin/bash
echo "start hadoop-node1 container..."
docker run -itd --restart=always \--net spark  \--ip 172.16.0.3 \--privileged \-p 18042:8042 \-p 51010:50010 \-p 51020:50020 
\--name hadoop-node1 \--hostname hadoop-node1  --add-host hadoop-hive:172.16.0.5 --add-host hadoop-mysql:172.16.0.6 
\--add-host hadoop-maste:172.16.0.2 \--add-host hadoop-node2:172.16.0.4 spark  /bin/bash
echo "start hadoop-node2 container..."
docker run -itd --restart=always \--net spark  \--ip 172.16.0.4 \--privileged \-p 18043:8042 \-p 51011:50011 \-p 51021:50021 
\--name hadoop-node2 \--hostname hadoop-node2 --add-host hadoop-maste:172.16.0.2 \--add-host hadoop-
node1:172.16.0.3 --add-host hadoop-mysql:172.16.0.6 --add-host hadoop-hive:172.16.0.5 spark /bin/bash
echo start sshd...
docker exec -it hadoop-maste /etc/init.d/ssh start
docker exec -it hadoop-node1 /etc/init.d/ssh start
docker exec -it hadoop-node2 /etc/init.d/ssh start
docker exec -it hive  /etc/init.d/ssh start
docker exec -it mysql /etc/init.d/ssh start
docker exec -d mysql sh ~/init_mysql.sh
docker exec -d hadoop-maste sh ~/start-hadoop.sh 
docker exec -d hive  sh ~/init_hive.sh
echo finished
docker ps

使用docker run命令运行镜像 --net指定子网络 --ip指定从子网落中分配一个ip地址 -p指定端口映射 --name指定容器名称,–hostname指定容器的hostname,–add-host指定hostname和ip的映射,这个映射将被添加到/etc/hosts文件中。最后要使用 docker exec 执行脚本启动每个容器中的ssh服务。就是上面标红的部分。

restart_containers.sh内容如下:

echo stop containers
docker stop hadoop-maste
docker stop hadoop-node1
docker stop hadoop-node2
docker stop hadoop-mysql
docker stop hadoop-hive
echo restart containers
docker start hadoop-maste
docker start hadoop-node1
docker start hadoop-node2
docker start hadoop-mysql
docker start hadoop-hive
echo start sshd
docker exec -it hadoop-maste /etc/init.d/ssh start
docker exec -it hadoop-node1 /etc/init.d/ssh start
docker exec -it hadoop-node2 /etc/init.d/ssh start
docker exec -it hadoop-mysql /etc/init.d/ssh start
docker exec -it hadoop-hive /etc/init.d/ssh start
echo start mysql 、hadoop、spark、hive
docker exec -it mysql sh ~/init_mysql.sh
docker exec -it hadoop-maste ~/restart-hadoop.sh
docker exec -it hive  sh ~/init_hive.sh
echo  containers started
docker ps

重启要记得重启ssh服务!

stop_containers.sh内容如下:

docker stop hadoop-maste
docker stop hadoop-node1
docker stop hadoop-node2
docker stop hive
docker stop mysql
echo stop containers 
docker rm hadoop-maste
docker rm hadoop-node1
docker rm hadoop-node2
docker rm hive
docker rm mysql
echo rm containers
docker ps
start-hadoop.sh内容如下:用于启动hadoop,spark集群
#!/bin/bash
echo -e "\n"
hdfs namenode -format
echo -e "\n"
$HADOOP_HOME/sbin/start-dfs.sh
echo -e "\n"
$HADOOP_HOME/sbin/start-yarn.sh
echo -e "\n"
$SPARK_HOME/sbin/start-all.sh
echo -e "\n"
hdfs dfs -mkdir /mr-history
hdfs dfs -mkdir /stage
echo -e "\n"
  1. 启动容器
    利用上面写好的start_containers.sh脚本,执行sh start_containers.sh命令启动5个容器。

  2. 停止容器也很方便:sh stop_containers.sh

  3. 重启容器:sh restart_containers.sh

  4. 进入hadoop-maste容器,运行start-hadoop.sh脚本,启动hadoop和spark集群
    docker exec -it hadoop-maste /bin/bash
    使用jps检验进程启动情况。
    当然如果你的虚拟机能够连接外网,可以通过容器映射到宿主机的端口来访问,怎么看端口映射情况呢?
    docker port hadoop-maste
    很不幸,我的机器在第三方服务器的内外,这台机器不能访问外网,因此我配置了访问外网的代理。但是外网要访问里面的东西可能还需要配置nginx做请求的转发,精力有限而且这也不是我们学习pyspark的重点,因此就不展示页面访问了,当然你可以尝试在你的浏览器,访问hadoop-maste对应的端口,例如访问HDFS监控页面你可以:
    http://hadoop-maste:51070
    这里可以运行一下pyspark --master spark://hadoop-maste:7077
    OK,没问题!

  5. 配置mysql,上面的init_mysql.sh配置文件就是用来配置mysql的。
    init_mysql.sh配置文件内容如下:

    #!/bin/bash
    cd /usr/local/mysql/                                             
    echo ..........mysql_install_db --user=root.................
    nohup ./scripts/mysql_install_db --user=root &
    sleep 3
    echo ..........mysqld_safe --user=root.................
    nohup ./bin/mysqld_safe --user=root &
    sleep 3
    echo ..........mysqladmin -u root password 'root'.................
    nohup ./bin/mysqladmin -u root password 'root' &
    sleep 3
    echo ..........mysqladmin -uroot -proot shutdown.................
    nohup ./bin/mysqladmin -uroot -proot shutdown &
    sleep 3
    echo ..........mysqld_safe.................
    nohup ./bin/mysqld_safe --user=root &
    sleep 3
    echo ...........................
    nohup ./bin/mysql -uroot -proot -e "grant all privileges on *.* to root@'%' identified by 'root' with grant option;"
    sleep 3
    echo ........grant all privileges on *.* to root@'%' identified by 'root' with grant option...............
    

    这个文件被上传到了~/init_mysql.sh文件,并且在启动容器的时候使用命令docker exec -it mysql sh ~/init_mysql.sh运行了这 个文件,因此容器启动后mysql服务就被启动和初始化了。 启动容器后,我们登录到hadoop-maste,尝试连接下mysql数据库:

    连接到hadoop-maste容器:
    docker exec -it hadoop-maste /bin/bash

    进入容器后运行,连接到mysql:
    mysql -uroot -proot -hhadoop-mysql

    连接是成功的,mysql设置成功!

  6. 配置hive
    初始化Hive,需要把Hive的元数据保存到mysql数据库中,还要启动元数据服务器及Thriftserver服务。这一系列的启动操作及初始化操作, 我们也把它保存到init_hive.sh文件中,在启动容器的时候通过docker exec -it hive sh ~/.init_hive.sh执行这个shell文件把初始化hive的操作放到init_hive.sh的外部配置文件中。脚本内容如下:

#!/bin/bash
cd /usr/local/apache-hive-2.3.2-bin/bin
sleep 3
nohup ./schematool -initSchema -dbType mysql &
sleep 3
nohup ./hive --service metastore  &
sleep 3
nohup ./hive --service hiveserver2 &
sleep 5
echo Hive has initiallized!

运行start_container.sh之后,进入到hadoop-maste节点,使用beeline工具连接到hive进行检验。

beeline -u "jdbc:hive2://hadoop-hive:10001/default;transportMode=http;httpPath=cliservice"  --color=true -n root

正确的连接到了hive中,执行sql语句没有问题,hive配置成功!
参数说明:

beeline -u "jdbc:hive2://hadoop-hive:10001/default;transportMode=http;httpPath=cliservice"  --color=true -n root -e"your 
sql;"
-u指定连接的参数及模式
--color=true指定有颜色显示
-n指定用户名称
-e引号中指定要执行的sql语句,注意语句后面要加分好结尾,sql才能执行!

16.初始化及启动hadoop,spark集群
在start_container.sh启动容器的脚本中,加入了docker exec -it hadoop-maste sh ~/start-hadoop.sh命令,start-hadoop.sh内容如下:

#!/bin/bash
echo -e "\n"
hdfs namenode -format -force
echo -e "\n"
$HADOOP_HOME/sbin/start-dfs.sh
echo -e "\n"
$HADOOP_HOME/sbin/start-yarn.sh
echo -e "\n"
$SPARK_HOME/sbin/start-all.sh
echo -e "\n"
hdfs dfs -mkdir /mr-history
hdfs dfs -mkdir /stage
echo -e "\n"

调用了hdfs namenode -format -force进行强制性的格式化,然后调用脚本分别启动hdfs,yarn,spark在试一下在spark中操作hive表格。容器启动后,hadoop,spark随之启动。进入hadoop-maste容器运行如下命令
pyspark --master spark://hadoop-maste:7077
在pyspark命令中执行系列操作,查找hive表格worker.test,可以看到运行无误,集群搭建成功!

集群镜像制作好了,并且上传到Docker_hub 中的reganzm/spark_cluster,可以使用docker search reganzm/spark_cluster,然后把这个镜像Pull到本地,使用上面的build_network.sh,start_container.sh分别构建网络,启动容器就可以一键启动集群学习环境了!

发布了63 篇原创文章 · 获赞 52 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_41521681/article/details/104700200