docker安装hadoop3.3.6

内容纲要

记录在centos7上安装docker环境,并基于centos7镜像制作hadoop的image,制作的镜像希望开箱即用,包含SSH、免密登录、JDK8、Hadoop3.3.6等配套环境,并能将免密登录凭证、Hadoop配置环境和数据持久化到宿主机,避免容器重启后数据丢失。
开始动手(👉゚ヮ゚)👉

  1. docker环境安装前面有专门记录,不在重复记录。
  2. 拉取最新的centos,镜像为centos7
    docker pull centos
  3. 创建/docker/hadoop/dockerfile目录,存放制作镜像的过程文件
    mkdir -p /docker/hadoop/Dockerfile
  4. 将所需的JDK和Hadoop文件放在该目录下
    ls -al
    total 353712 
    rw-r--r--. 1 root root 216648064 Jan 25 16:58 hadoop-3.3.6.tar.gz
    rw-r--r--. 1 root root 145535989 Jan  8 16:03 jdk-8u301-linux-x64.tar.gz
  5. 在宿主机创建公钥和私钥,并且将公钥写入authorized_keys,后面共享给容器挂载,做到容器之间互相免登录
    #创建存放密钥的目录
    mkdir /docker/hadoop/Dockerfile/sshkey
    #创建密钥,一路回车
    ssh-keygen -t rsa -f /docker/hadoop/Dockerfile/sshkey/hadoop_docker_key
    #将公钥写入authorized_keys文件
    #查看密钥
    ls -al /docker/hadoop/Dockerfile/sshkey/
    total 20
    drwxr-xr-x. 2 root root 4096 Jan 25 17:32 .
    drwxr-xr-x. 3 root root 4096 Jan 25 17:25 ..
    rw-r--r--. 1 root root  400 Jan 25 17:32 authorized_keys
    rw-------. 1 root root 1675 Jan 25 17:29 hadoop_docker_key
    rw-r--r--. 1 root root  400 Jan 25 17:29 hadoop_docker_key.pub
  6. 创建dockerfile文件,基于前面拉去的centos官方镜像制作,文件内容如下:
    # 使用 CentOS 7 作为基础镜像
    FROM centos:7
    # 维护者信息
    MAINTAINER fuguang <[email protected]>
    # 设置工作目录
    WORKDIR /root
    # 安装 SSH 服务
    RUN yum -y install openssh-server openssh-clients && \
    ssh-keygen -A && \
    echo 'root:123456' | chpasswd   
    # 授予root用户容器的全部权限,暂时务必要,先注释掉
    #RUN echo "root ALL=(ALL) ALL" >>/etc/sudoers 
    # 挂载密钥文件
    COPY sshkey/hadoop_docker_key /root/.ssh/id_rsa
    COPY sshkey/hadoop_docker_key.pub /root/.ssh/id_rsa.pub
    COPY sshkey/authorized_keys /root/.ssh/authorized_keys
    # 设置 SSH 密钥文件权限
    RUN chmod 600 /root/.ssh/id_rsa && \
    chmod 644 /root/.ssh/id_rsa.pub && \
    chmod 600 /root/.ssh/authorized_keys
    # 允许 SSH 免密登录
    RUN echo "StrictHostKeyChecking no" >> /etc/ssh/ssh_config
    # 安装 JDK 8
    COPY jdk-8u301-linux-x64.tar.gz /root/
    RUN tar -zxvf jdk-8u301-linux-x64.tar.gz && \
    mv jdk1.8.0_301 /opt/ && \
    rm jdk-8u301-linux-x64.tar.gz
    # 设置java环境变量
    RUN echo "export JAVA_HOME=/opt/jdk1.8.0_301" >> /etc/profile.d/java8.sh && \
    echo "export PATH=\$PATH:\$JAVA_HOME/bin" >> /etc/profile.d/java8.sh
    # 安装 Hadoop 3.3.6
    COPY hadoop-3.3.6.tar.gz /root/
    RUN tar -zxvf hadoop-3.3.6.tar.gz && \
    mv hadoop-3.3.6 /opt/ && \
    rm hadoop-3.3.6.tar.gz
    # 设置Hadoop环境变量
    # flink 1.13 版本后如果使用基于 hdfs 的保存点功能,需要依赖hadoop 的 clpasspath
    RUN echo "export HADOOP_HOME=/opt/hadoop-3.3.6" >> /etc/profile.d/hadoop3.sh && \
    echo "export PATH=\$PATH:\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin" && \
    echo "export HADOOP_CLASSPATH= /opt/pluginJar/*.jar hadoop classpath">> /etc/profile.d/hadoop3.sh    
    # 开放 22 端口
    EXPOSE 22
    # 启动 SSH 服务
    CMD ["/usr/sbin/sshd", "-D"]
  7. 基于dockerfile文件构建镜像,并测试ssh服务、免密、java环境是否正常
    # 增加`--network host`参数避免安装过程中网络问题找不到资源
    docker build --network host -f Dockfile/dockerfile -t centos7-hadoop3:v1 Dockfile/
    # 运行容器test1和容器test2 进行测试
    docker run --name test1 -p 60020:22 -d centos7-hadoop3:v1
    docker run --name test2 -p 60021:22 -d centos7-hadoop3:v1
    # ssh 登录 test1
    ssh -p 60020 [email protected]
    # 在从test1 ssh登录 test2
    ssh -p 60021 [email protected]
    # 查看java环境
    java -version
    # 查看Hadoop环境
    hadoop version

    可以从test1免密登录到test2及返回java、Hadoop版本信息,说明镜像的免密及java环境部署功能正常。
    目前发现一个问题,宿主机使用ssh登录时正常;使用docker exec -it进入容器时,java和Hadoop的环境变量会失效,需要在容器内运行source命令使其生效

    #使用ssh 登录
    ssh -p 60021 [email protected]
    # 环境变量正常
    java -version
    hadoop version
    # 使用docker直接进入容器时
    docker exec -it test1 sh
    # 环境变量不正常,提示命令无法找到
    java -version
    hadoop version
    # 必须重新运行source命令使其生效
    source /etc/profile.d/java8.sh
    source /etc/profile.d/hadoop3.sh

    出现这个问题的原因在于 Docker 容器和 SSH 会话的环境变量加载机制的不同。

SSH 会话: 当你通过 SSH 连接到容器时,会启动一个登录 shell。在这种情况下,Bash 会读取并执行 /etc/profile 以及 /etc/profile.d/*.sh 文件中的脚本,从而加载环境变量。因此,通过 SSH 连接时,JAVA_HOMEPATH 环境变量按预期加载。
docker exec 命令: 相反,当你使用 docker exec -it container-name sh 进入容器时,通常会启动一个非登录 shell。非登录 shell 不会自动执行 /etc/profile/etc/profile.d/*.sh 文件中的脚本,因此 JAVA_HOMEPATH 环境变量不会自动加载。

为了解决这个问题,你可以在 Dockerfile 中使用 ENV 指令来设置环境变量,而不是将它们写入 /etc/profile.d/*.sh 文件。使用 ENV 指令设置的环境变量会在容器的所有会话中自动生效,无论是通过 SSH 还是 docker exec 命令。

# 设置java环境变量
# RUN echo "export JAVA_HOME=/opt/jdk1.8.0_301" >> /etc/profile.d/java8.sh && \
#    echo "export PATH=\$PATH:\$JAVA_HOME/bin" >> /etc/profile.d/java8.sh
# 修改为:
ENV JAVA_HOME=/opt/jdk1.8.0_301 
ENV PATH=$PATH:$JAVA_HOME/bin

# flink 1.13 版本后如果使用基于 hdfs 的保存点功能,需要依赖hadoop 的 clpasspath
# RUN echo "export HADOOP_HOME=/opt/hadoop-3.3.6" >> /etc/profile.d/hadoop3.sh && \
#    echo "export PATH=\$PATH:\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin" && \
#    echo "export HADOOP_CLASSPATH= /opt/pluginJar/*.jar hadoop classpath">> /etc/profile.d/hadoop3.sh   
# 修改为:
ENV HADOOP_HOME=/opt/hadoop-3.3.6
ENV PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
# RUN export HADOOP_CLASSPATH=`hadoop classpath`

修改为以上后发现结果和前面相反: 宿主机使用docker exec -it进入容器时正常; 使用ssh登录时,java和Hadoop的环境变量会失效.为了让两种情况环境变量均可生效,同时使用两种环境变量配置方法。

# 设置java环境变量
# ssh生效
RUN echo "export JAVA_HOME=/opt/jdk1.8.0_301" >> /etc/profile.d/java8.sh && \
    echo "export PATH=\$PATH:\$JAVA_HOME/bin" >> /etc/profile.d/java8.sh
# docker exec生效   
ENV JAVA_HOME=/opt/jdk1.8.0_301 
ENV PATH=$PATH:$JAVA_HOME/bin

# flink 1.13 版本后如果使用基于 hdfs 的保存点功能,需要依赖hadoop 的 clpasspath
# ssh 下生效
RUN echo "export HADOOP_HOME=/opt/hadoop-3.3.6" >> /etc/profile.d/hadoop3.sh && \
    echo "export PATH=\$PATH:\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin" && \
    echo "export HADOOP_CLASSPATH= /opt/pluginJar/*.jar hadoop classpath">> /etc/profile.d/hadoop3.sh   
# docker exec生效:
ENV HADOOP_HOME=/opt/hadoop-3.3.6
ENV PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
# RUN export HADOOP_CLASSPATH=`hadoop classpath`

将Hadoop使用的用户调整为hdfs,并且调整ssh密钥和Hadoop目录的权限,最终dockerfile为:

# 使用 CentOS 7 作为基础镜像
FROM centos:7
# 维护者信息
MAINTAINER fuguang <[email protected]>
# 设置工作目录
WORKDIR /root
# 安装 SSH 服务
RUN yum -y install openssh-server openssh-clients && \
    ssh-keygen -A && \
    echo 'root:123456' | chpasswd    
# 授予root用户容器的全部权限,暂时务必要,先注释掉
# RUN echo "root ALL=(ALL) ALL" >>/etc/sudoers                              
# 安装 JDK 8
COPY jdk-8u301-linux-x64.tar.gz /root/
RUN tar -zxvf jdk-8u301-linux-x64.tar.gz && \
    mv jdk1.8.0_301 /opt/ && \
    rm jdk-8u301-linux-x64.tar.gz
# 设置java环境变量
# ssh生效
RUN echo "export JAVA_HOME=/opt/jdk1.8.0_301" >> /etc/profile.d/java8.sh && \
    echo "export PATH=\$PATH:\$JAVA_HOME/bin" >> /etc/profile.d/java8.sh
# docker exec生效     
ENV JAVA_HOME=/opt/jdk1.8.0_301 
ENV PATH=$PATH:$JAVA_HOME/bin

# 安装 Hadoop 3.3.6
COPY hadoop-3.3.6.tar.gz /root/
RUN tar -zxvf hadoop-3.3.6.tar.gz && \
    mv hadoop-3.3.6 /opt/ && \
    rm hadoop-3.3.6.tar.gz
# 创建Hadoop 临时文件夹
RUN mkdir /opt/hadoop-3.3.6/tmp
# 设置Hadoop环境变量
# flink 1.13 版本后如果使用基于 hdfs 的保存点功能,需要依赖hadoop 的 clpasspath
# ssh 下生效
RUN echo "export HADOOP_HOME=/opt/hadoop-3.3.6" >> /etc/profile.d/hadoop3.sh && \
    echo "export PATH=\$PATH:\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin" >> /etc/profile.d/hadoop3.sh && \
    echo "export HADOOP_CLASSPATH= `hadoop classpath`" >> /etc/profile.d/hadoop3.sh 
# docker exec生效    
ENV HADOOP_HOME=/opt/hadoop-3.3.6
ENV PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
# flink 1.13 版本后如果使用基于 hdfs 的保存点功能,需要依赖hadoop 的 clpasspath
# RUN export HADOOP_CLASSPATH=`hadoop classpath`

#创建Hadoop运行用户和用户组hdfs
RUN groupadd -r hdfs && \
    useradd -r -m -g hdfs hdfs && \
    echo "hdfs:hadoop" | chpasswd && \
    chown -R hdfs:hdfs /opt/hadoop-3.3.6

# 挂载密钥文件
RUN mkdir -p /home/hdfs/.ssh
COPY sshkey/hadoop_docker_key /home/hdfs/.ssh/id_rsa
COPY sshkey/hadoop_docker_key.pub /home/hdfs/.ssh/id_rsa.pub
COPY sshkey/authorized_keys /home/hdfs/.ssh/authorized_keys
# 设置 SSH 密钥文件权限
RUN chmod 600 /home/hdfs/.ssh/id_rsa && \
    chmod 644 /home/hdfs/.ssh/id_rsa.pub && \
    chmod 600 /home/hdfs/.ssh/authorized_keys && \
    chown -R hdfs:hdfs /home/hdfs/.ssh
# 允许 SSH 免密登录
RUN echo "StrictHostKeyChecking no" >> /etc/ssh/ssh_config

# 指定Hadoop 运行的用户
ENV HDFS_NAMENODE_USER hdfs
ENV HDFS_DATANODE_USER hdfs
ENV HDFS_SECONDARYNAMENODE_USER hdfs
# 开放 22 端口
EXPOSE 22
# 容器运行时更改目录Hadoop目录所有者
# 启动 SSH 服务
CMD chown -R hdfs:hdfs /opt/hadoop-3.3.6 && /usr/sbin/sshd -D
#CMD ["/usr/sbin/sshd", "-D"]

重新构建镜像

# 增加`--network host`参数避免安装过程中网络问题找不到资源
docker build --network host -f Dockfile/dockerfile -t centos7-hadoop3:v10 Dockfile/
  1. 为了将Hadoop集群放置在独立的网络内部访问,避免受外部网络变化的影响,创建一个docker的虚拟网络给Hadoop使用。
    docker network create --subnet=172.0.0.0/16 hadoop3-network

    运行3个Hadoop容器,一主二从(hadoop3-m1、haddoop3-s1、hadoop3-s2),先创建要挂载的host文件和 Hadoop的配置文件/etc/hadoop

    # 进入Hadoop的目录
    cd /docker/hadoop
    # 1.创建一个hadoopHost文件,让Hadoop容器统一挂载
    # 如果 `hadoopHost` 文件不存在,则上述命令将创建一个新文件。
    # 如果 `hadoopHost` 文件存在,则上述命令将将内容追加到文件中。
    # 并将在标准输出中显示内容
    tee hadoopHost << EOF
    172.0.0.2 hadoop3-m1
    172.0.0.11 hadoop3-s1
    172.0.0.12 hadoop3-s2
    EOF
    # 将Hadoop压缩文件解压,便于提取里面的配置文件
    tar -zxvf Dockfile/hadoop-3.3.6.tar.gz -C .
    # 创建容器对应目录
    mkdir hadoop3-m1
    # 将配置文件复制到hadoop3-m1目录中
    cp -r hadoop-3.3.6/etc/ hadoop3-m1/
    # 创建挂载目录
    docker run -d --net hadoop3-network --ip 172.0.0.2 --hostname hadoop-m1 centos7-hadoop3:v1
    docker run -d --net hadoop3-network --ip 172.0.1.11 --hostname hadoop-s1 centos7-hadoop3:v1
    docker run -d --net hadoop3-network --ip 172.0.0.12 --hostname hadoop-s2 centos7-hadoop3:v1

    二. 修改Hadoop的配置文件,按一主二从的最小规模进行配置
    a. 修改/docker/hadoop/hadoop3-m1/etc/hadoop/core-site.xml文件(所有节点均需修改)指定HDFS用户的配置貌似没有作用,但第一次指定为root时在hdfs上创建文件夹报了权限错误,取消也报错了,这个有待后面了解

    <configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://hadoop3-m1:9000</value>
    </property>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/hadoop-3.3.6/tmp</value>
        <description>A base for other temporary directories.</description>
    </property>
    <!-- 设置HDFS网页登录使用的静态用户为hdfs -->
    <property>
        <name>hadoop.http.staticuser.user</name>
        <value>root</value>
    </property>
    </configuration>

    b. 修改/docker/hadoop/hadoop3-m1/etc/hadoop/hdfs-site.xml文件(所有节点均需修改)

    <configuration>
    <property>
        <name>dfs.replication</name>
        <value>2</value>
    </property>
    <!-- 只在namenode上节点上配置-->
    <property>
        <name>dfs.namenode.name.dir</name>
        <value>file:///opt/hadoop-3.3.6/namenode</value>
    </property>
     <!-- 在所有datenode上节点上配置-->
    <property>
        <name>dfs.datanode.data.dir</name>
        <value>file:///opt/hadoop-3.3.6/datanode</value>
    </property>
    </configuration>

    c. 修改/docker/hadoop/hadoop3-m1/etc/hadoop/mapred-site.xml文件,设置运行模式为yarn(运行MapReduce节点均需修改)

    <configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </configuration>

    d. 修改/docker/hadoop/hadoop3-m1/etc/hadoop/yarn-site.xml文件,ResourceManager(通常运行在 NameNode 上)和所有 NodeManager(通常运行在 DataNode 上)节点均需修改

    <configuration>
    <!-- 指定ResourceManager的地址 -->
    <property>
        <name>yarn.resourcemanager.hostname</name>
        <value>hadoop3-m1</value>
    </property>
    <!-- 指定MR 使用那种协议,默认是空值,推荐使用 mapreduce_shuffle-->
    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
    <!-- 开启日志聚集功能 --> 
    <property>
        <name>yarn.log-aggregation-enable</name>
        <value>true</value> 
    </property> 
    <!-- 设置日志聚集服务器地址 --> 
    <property>
        <name>yarn.log.server.url</name>
        <value>http://hadoop3-m1:19888/jobhistory/logs</value>
    </property> 
    <!-- 设置日志保留时间为7天 --> 
    <property>
        <name>yarn.log-aggregation.retain-seconds</name>
        <value>604800</value>
    </property>
    </configuration>

    e. 修改/docker/hadoop/hadoop3-m1/etc/hadoop/workers文件,删除原来内容增加运行datanode节点主机名.只需要在namenode节点修改

    hadoop3-s1
    hadoop3-s2

f. 运行namenode节点hadoop3-m1
计划是将:子网络的172.0.0.2~172.0.0.10 给Hadoop里对外开放端口的特定的容器使用其余0.xxx的端口给Hadoop的内部容器使用容器的ssh端口22映射为宿主机的65xxx端口,xxx和子网ip一致

# hadoop-m1
docker run --name hadoop3-m1 \
-p 9870:9870 \
-p 8088:8088 \
-p 19888:19888 \
-p 65002:22 \
-v /docker/hadoop/hadoopHost:/etc/hosts:ro \
-v /docker/hadoop/hadoop3-m1/etc/:/opt/hadoop-3.3.6/etc/ \
-v /docker/hadoop/hadoop3-m1/namenode/:/opt/hadoop-3.3.6/namenode/ \
-v /docker/hadoop/hadoop3-m1/datanode/:/opt/hadoop-3.3.6/datanode/ \
-v /docker/hadoop/hadoop3-m1/logs/:/opt/hadoop-3.3.6/logs/ \
--net hadoop3-network \
--ip 172.0.0.2 \
--hostname hadoop3-m1 \
-d  centos7-hadoop3:v10
  1. 将hadoop3-m1的配置文件复制两份分别创建hadoop3-s1和hadoop3-s2目录
    cp -r hadoop3-m1/ hadoop3-s1
    cp -r hadoop3-m1/ hadoop3-s2
  2. 参照hadoop3-m1创建容器hadoop3-s1和hadoop3-s2
    # hadoop-s1
    docker run --name hadoop3-s1 \
    -p 65011:22 \
    -v /docker/hadoop/hadoopHost:/etc/hosts:ro \
    -v /docker/hadoop/hadoop3-s1/etc/:/opt/hadoop-3.3.6/etc/ \
    -v /docker/hadoop/hadoop3-s1/namenode/:/opt/hadoop-3.3.6/namenode/ \
    -v /docker/hadoop/hadoop3-s1/datanode/:/opt/hadoop-3.3.6/datanode/ \
    -v /docker/hadoop/hadoop3-s1/logs/:/opt/hadoop-3.3.6/logs/ \
    --net hadoop3-network \
    --ip 172.0.0.11 \
    --hostname hadoop3-s1 \
    -d  centos7-hadoop3:v10
    # hadoop-s2
    docker run --name hadoop3-s2 \
    -p 65012:22 \
    -v /docker/hadoop/hadoopHost:/etc/hosts:ro \
    -v /docker/hadoop/hadoop3-s2/etc/:/opt/hadoop-3.3.6/etc/ \
    -v /docker/hadoop/hadoop3-s2/namenode/:/opt/hadoop-3.3.6/namenode/ \
    -v /docker/hadoop/hadoop3-s2/datanode/:/opt/hadoop-3.3.6/datanode/ \
    -v /docker/hadoop/hadoop3-s2/logs/:/opt/hadoop-3.3.6/logs/ \
    --net hadoop3-network \
    --ip 172.0.0.12 \
    --hostname hadoop3-s2 \
    -d  centos7-hadoop3:v10
  3. 启动集群
    a. 初始化nameNode(首次启动:hadoop3-m1)

    hdfs namenode -format

    b. 启动hdfs(hadoop3-m1执行),因为配置了workds会自动将hadoop3-s1和hadoop3-s2的datanode启动

    # 切换用户
    su hdfs
    # 启动hdfs
    start-dfs.sh
    # 启动yarn
    start-yarn.sh
    # 停止hdfs
    stop-dfs.sh
    # 停止yarn
    stop-yarn.sh
    # 也可以使用命令同时启动
    start-all.sh
    # 同时停止
    stop-all.sh
    # 启动历史任务服务器
    mapred --daemon start historyserver
    # mr-jobhistory-daemon.sh start historyserver
    # 停止历史任务服务器
    mapred --daemon stop historyserver
    # mr-jobhistory-daemon.sh stop historyserver

    访问hdfs: http://192.168.1.210:9870
    访问yarn: http://192.168.1.210:8088
    访问历史服务器: http://192.168.1.210:19888/

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注