docker安装hadoop 添加镜像源
为了加速在 CentOS 7 镜像中安装软件包的速度,可以使用阿里云的镜像源。以下是修改后的 Dockerfile,它包括了将 yum 源更改为阿里云的步骤,并确保安装过程更快。
为了加速在 CentOS 7 镜像中安装软件包的速度,可以使用阿里云的镜像源。以下是修改后的 Dockerfile
,它包括了将 yum 源更改为阿里云的步骤,并确保安装过程更快。
# 使用官方的 CentOS 7 镜像作为基础镜像
FROM centos:7
# 添加元数据
LABEL author="hjq" date="2022/03/05"
# 更改yum源为阿里云镜像源
RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup && \
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
yum clean all && \
yum makecache
# 安装openssh-server和sudo软件包,并且将sshd的UsePAM参数设置成no
RUN yum install -y openssh-server sudo && \
sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
# 安装openssh-clients
RUN yum install -y openssh-clients
# 安装which
RUN yum install -y which
# 添加测试用户root,密码root,并且将此用户添加到sudoers里
RUN echo "root:root" | chpasswd && \
echo "root ALL=(ALL) ALL" >> /etc/sudoers && \
ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N '' && \
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ''
# 启动sshd服务并且暴露22端口
RUN mkdir /var/run/sshd
EXPOSE 22
# 拷贝并解压jdk,根据自己的版本修改
ADD jdk-8u321-linux-x64.tar.gz /usr/local/
RUN mv /usr/local/jdk1.8.0_321 /usr/local/jdk1.8
ENV JAVA_HOME /usr/local/jdk1.8
ENV PATH $JAVA_HOME/bin:$PATH
# 拷贝并解压hadoop,根据自己的版本修改
ADD hadoop-3.3.2.tar.gz /usr/local
RUN mv /usr/local/hadoop-3.3.2 /usr/local/hadoop
ENV HADOOP_HOME /usr/local/hadoop
ENV PATH $HADOOP_HOME/bin:$PATH
# 设置容器启动命令
CMD ["/usr/sbin/sshd", "-D"]
关键点说明:
-
更改 Yum 源:
- 将默认的 CentOS 基础仓库文件备份。
- 使用
curl
下载阿里云的 CentOS 7 仓库文件。 - 清理现有的 Yum 缓存并重新生成缓存。
-
安装 SSH 和相关工具:
- 安装
openssh-server
、sudo
和openssh-clients
。 - 修改 SSH 配置文件以禁用 PAM。
- 生成 SSH 主机密钥。
- 安装
-
配置用户和权限:
- 设置 root 用户的密码。
- 将 root 用户添加到
sudoers
文件中。
-
安装 JDK 和 Hadoop:
- 拷贝并解压 JDK 和 Hadoop 的压缩包。
- 设置环境变量
JAVA_HOME
和HADOOP_HOME
,并将它们添加到PATH
中。
-
启动 SSH 服务:
- 创建
/var/run/sshd
目录。 - 在容器启动时运行 SSH 服务。
- 创建
通过这种方式,不仅可以加快软件包的安装速度,还能确保的 Docker 容器能够快速地提供 SSH 服务。
ERROR: failed to solve: unexpected EOF
=> [ 5/11] RUN yum install -y which 1.3s
=> [ 6/11] RUN echo "root:root" | chpasswd && echo "root ALL=(ALL) ALL" >> /etc/sudoers && ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N '' && ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_k 0.3s
=> [ 7/11] RUN mkdir /var/run/sshd 0.2s
=> ERROR [ 8/11] ADD jdk-8u321-linux-x64.tar.gz /usr/local/ 0.1s
------
> [ 8/11] ADD jdk-8u321-linux-x64.tar.gz /usr/local/:
------
Dockerfile:34
--------------------
32 |
33 | # 拷贝并解压jdk,根据自己的版本修改
34 | >>> ADD jdk-8u321-linux-x64.tar.gz /usr/local/
35 | RUN mv /usr/local/jdk1.8.0_321 /usr/local/jdk1.8
36 | ENV JAVA_HOME /usr/local/jdk1.8
--------------------
ERROR: failed to solve: unexpected EOF
主要问题
- 内部文件和外部文件不一致, 将RUN mv /usr/local/jdk1.8.0_321 改为文件的内部文件名
hdfs dfs -put test.txt / 遇到的问题
[root@master /]# hdfs dfs -put test.txt /
2024-10-01 02:48:53,048 WARN hdfs.DataStreamer: DataStreamer Exception
org.apache.hadoop.ipc.RemoteException(java.io.IOException): File /test.txt._COPYING_ could only be written to 0 of the 1 minReplication nodes. There are 0 datanode(s) running and 0 node(s) are excluded in this operation.
at org.apache.hadoop.hdfs.server.blockmanagement.BlockManager.chooseTarget4NewBlock(BlockManager.java:2338)
at org.apache.hadoop.hdfs.server.namenode.FSDirWriteFileOp.chooseTargetForNewBlock(FSDirWriteFileOp.java:294)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getAdditionalBlock(FSNamesystem.java:2989)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.addBlock(NameNodeRpcServer.java:911)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.addBlock(ClientNamenodeProtocolServerSideTranslatorPB.java:595)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
at org.apache.hadoop.ipc.ProtobufRpcEngine2$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine2.java:621)
at org.apache.hadoop.ipc.ProtobufRpcEngine2$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine2.java:589)
at org.apache.hadoop.ipc.ProtobufRpcEngine2$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine2.java:573)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1213)
at org.apache.hadoop.ipc.Server$RpcCall.run(Server.java:1089)
at org.apache.hadoop.ipc.Server$RpcCall.run(Server.java:1012)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1899)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:3026)
at org.apache.hadoop.ipc.Client.getRpcResponse(Client.java:1584)
at org.apache.hadoop.ipc.Client.call(Client.java:1530)
at org.apache.hadoop.ipc.Client.call(Client.java:1427)
at org.apache.hadoop.ipc.ProtobufRpcEngine2$Invoker.invoke(ProtobufRpcEngine2.java:258)
at org.apache.hadoop.ipc.ProtobufRpcEngine2$Invoker.invoke(ProtobufRpcEngine2.java:139)
at com.sun.proxy.$Proxy9.addBlock(Unknown Source)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.addBlock(ClientNamenodeProtocolTranslatorPB.java:531)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:433)
at org.apache.hadoop.io.retry.RetryInvocationHandler$Call.invokeMethod(RetryInvocationHandler.java:166)
at org.apache.hadoop.io.retry.RetryInvocationHandler$Call.invoke(RetryInvocationHandler.java:158)
at org.apache.hadoop.io.retry.RetryInvocationHandler$Call.invokeOnce(RetryInvocationHandler.java:96)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:362)
at com.sun.proxy.$Proxy10.addBlock(Unknown Source)
at org.apache.hadoop.hdfs.DFSOutputStream.addBlock(DFSOutputStream.java:1088)
at org.apache.hadoop.hdfs.DataStreamer.locateFollowingBlock(DataStreamer.java:1915)
at org.apache.hadoop.hdfs.DataStreamer.nextBlockOutputStream(DataStreamer.java:1717)
at org.apache.hadoop.hdfs.DataStreamer.run(DataStreamer.java:713)
put: File /test.txt._COPYING_ could only be written to 0 of the 1 minReplication nodes. There are 0 datanode(s) running and 0 node(s) are excluded in this operation.
HDFS 无法将文件 test.txt
写入集群,因为没有可用的 DataNode。具体错误是:
File /test.txt._COPYING_ could only be written to 0 of the 1 minReplication nodes. There are 0 datanode(s) running and 0 node(s) are excluded in this operation.
这表明 Hadoop 集群中没有运行的 DataNode,因此 NameNode 无法找到足够的 DataNode 来存储数据块。
解决方法
- 检查 DataNode 是否启动:
- 确保所有 DataNode 服务已经启动。可以通过以下命令检查 DataNode 的状态:
hdfs dfsadmin -report
- 这个命令会显示集群的状态报告,包括每个 DataNode 的信息。如果没有任何 DataNode 显示,则表示 DataNode 没有启动。
- 确保所有 DataNode 服务已经启动。可以通过以下命令检查 DataNode 的状态:
- 启动 DataNode:
- 如果 DataNode 没有启动,需要手动启动它们。假设在单节点或多节点集群上,可以使用以下命令启动 DataNode:
hdfs --daemon start datanode
- 如果在多节点集群上,确保在所有 DataNode 节点上都执行这个命令。
- 如果 DataNode 没有启动,需要手动启动它们。假设在单节点或多节点集群上,可以使用以下命令启动 DataNode:
- 检查配置文件:
- 确保 Hadoop 配置文件(如
hdfs-site.xml
和core-site.xml
)正确配置了 DataNode 的位置和端口。 - 确认
dfs.datanode.address
和dfs.datanode.http.address
在hdfs-site.xml
中正确设置。
- 确保 Hadoop 配置文件(如
- 检查日志文件:
- 查看 DataNode 的日志文件以获取更多详细信息。日志文件通常位于
/var/log/hadoop/
目录下,具体路径可能因配置而异。 - 日志文件名通常是
hadoop-hadoop-datanode-<hostname>.log
或类似的命名方式。
- 查看 DataNode 的日志文件以获取更多详细信息。日志文件通常位于
- 检查防火墙和网络:
- 确保防火墙没有阻止 DataNode 与 NameNode 之间的通信。
- 确保所有节点之间的网络连接正常。
- 格式化 NameNode(仅在必要时):
- 如果是第一次设置集群或者遇到其他问题,可能需要格式化 NameNode:
hdfs namenode -format
- 注意:这将清除所有现有的 HDFS 数据,请谨慎操作。
- 如果是第一次设置集群或者遇到其他问题,可能需要格式化 NameNode:
- 重启 Hadoop 服务:
- 有时,重启整个 Hadoop 服务可以解决问题。可以使用以下命令停止并重新启动 Hadoop 服务:
stop-dfs.sh start-dfs.sh
- 有时,重启整个 Hadoop 服务可以解决问题。可以使用以下命令停止并重新启动 Hadoop 服务:
示例命令
假设有一个简单的单节点集群,以下是启动 DataNode 并检查其状态的示例命令:
# 启动 DataNode
hdfs --daemon start datanode
# 检查 DataNode 状态
hdfs dfsadmin -report
如果在一个多节点集群上,确保在所有 DataNode 节点上执行这些命令。
其他注意事项
- 确保 Hadoop 版本与集群配置兼容。
- 确保所有节点上的 Hadoop 配置文件是一致的。
- 如果使用的是分布式环境,确保所有节点的时间同步。
Couldn’t find datanode to write file. Forbidden (hadoop上传不了文件)
当遇到 Couldn't find datanode to write file. Forbidden
错误时,这通常意味着 Hadoop NameNode 无法找到可用的 DataNode 来写入数据。以下是一些可能的原因和解决方法:
可能的原因
- DataNode 未启动:
- 确保所有 DataNode 服务已经启动。
- 防火墙或网络问题:
- 确保 DataNode 和 NameNode 之间的网络通信没有被防火墙阻止。
- 检查网络连接是否正常。
- 配置错误:
- 确认
hdfs-site.xml
和core-site.xml
配置文件中的设置正确无误。 - 确认
dfs.replication
设置合理(默认值通常是 3)。
- 确认
- 权限问题:
- 确保有权限在 HDFS 上创建文件。检查 HDFS 的权限设置。
- NameNode 和 DataNode 版本不匹配:
- 确保所有节点上的 Hadoop 版本一致。
- DataNode 日志中的错误:
- 查看 DataNode 的日志文件以获取更多详细信息。
解决方法
-
检查 DataNode 是否启动:
- 使用以下命令检查 DataNode 的状态:
hdfs dfsadmin -report
- 如果没有任何 DataNode 显示,则表示 DataNode 没有启动。
- 使用以下命令检查 DataNode 的状态:
-
启动 DataNode:
- 在每个 DataNode 节点上执行以下命令来启动 DataNode 服务:
hdfs --daemon start datanode
- 在每个 DataNode 节点上执行以下命令来启动 DataNode 服务:
-
检查防火墙和网络:
- 确保防火墙没有阻止 DataNode 与 NameNode 之间的通信。
- 确保所有节点之间的网络连接正常。
- 可以使用
ping
命令测试节点之间的连通性:ping <datanode-hostname>
-
检查配置文件:
- 确认
hdfs-site.xml
和core-site.xml
配置文件中的设置正确无误。 - 确认
dfs.replication
设置合理。例如:<property> <name>dfs.replication</name> <value>3</value> </property>
- 如果集群只有一个 DataNode,可以将
dfs.replication
设置为 1:<property> <name>dfs.replication</name> <value>1</value> </property>
- 确认
-
检查权限:
- 确保有权限在 HDFS 上创建文件。可以使用以下命令检查当前用户的权限:
hdfs dfs -ls /
- 如果需要,可以更改目录权限:
hdfs dfs -chmod 777 /
- 确保有权限在 HDFS 上创建文件。可以使用以下命令检查当前用户的权限:
-
查看 DataNode 日志:
- 查看 DataNode 的日志文件以获取更多详细信息。日志文件通常位于
/var/log/hadoop/
目录下,具体路径可能因的配置而异。 - 日志文件名通常是
hadoop-hadoop-datanode-<hostname>.log
或类似的命名方式。
- 查看 DataNode 的日志文件以获取更多详细信息。日志文件通常位于
-
重启 Hadoop 服务:
- 有时,重启整个 Hadoop 服务可以解决问题。可以使用以下命令停止并重新启动 Hadoop 服务:
stop-dfs.sh start-dfs.sh
- 有时,重启整个 Hadoop 服务可以解决问题。可以使用以下命令停止并重新启动 Hadoop 服务:
示例命令
假设有一个简单的单节点集群,以下是启动 DataNode 并检查其状态的示例命令:
# 启动 DataNode
hdfs --daemon start datanode
# 检查 DataNode 状态
hdfs dfsadmin -report
如果在一个多节点集群上,确保在所有 DataNode 节点上执行这些命令。
其他注意事项
- 确保 Hadoop 版本与的集群配置兼容。
- 确保所有节点上的 Hadoop 配置文件是一致的。
- 如果使用的是分布式环境,确保所有节点的时间同步。
通过上述步骤,能够解决 Couldn't find datanode to write file. Forbidden
问题,并成功将文件上传到 HDFS。
RemoteException Object { exception: “AccessControlException”, javaClassName: "org.apache.hadoop.security.AccessControlException
RemoteException Object { exception: "AccessControlException", javaClassName: "org.apache.hadoop.security.AccessControlException", message: 'Permission denied: user=dr.who, access=WRITE, inode="/":root:supergroup:drwxr-xr-x\n\tat org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:506)\n\tat org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:346)\n\tat org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:242)\n\tat org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1943)\n\tat org…Invoker.call(ProtobufRpcEngine2.java:573)\n\tat org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1213)\n\tat org.apache.hadoop.ipc.Server$RpcCall.run(Server.java:1089)\n\tat org.apache.hadoop.ipc.Server$RpcCall.run(Server.java:1012)\n\tat java.security.AccessController.doPrivileged(Native Method)\n\tat javax.security.auth.Subject.doAs(Subject.java:422)\n\tat org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1899)\n\tat org.apache.hadoop.ipc.Server$Handler.run(Server.java:3026)\n' }
遇到的 AccessControlException
是 Hadoop 中常见的权限问题。具体错误信息是:
Permission denied: user=dr.who, access=WRITE, inode="/":root:supergroup:drwxr-xr-x
这表明用户 dr.who
尝试对根目录 /
进行写操作,但没有足够的权限。
解决方法
-
检查 HDFS 权限:
使用hdfs dfs -ls /
命令来查看根目录的权限设置。hdfs dfs -ls /
应该会看到类似以下的输出:
drwxr-xr-x - root supergroup 0 2023-10-01 11:05 /
在这个例子中,根目录的权限是
drwxr-xr-x
,这意味着只有root
用户和supergroup
组有写权限。 -
更改 HDFS 权限:
如果需要允许dr.who
用户进行写操作,可以更改目录的权限或将其添加到具有写权限的组。-
更改目录权限:
可以使用hdfs dfs -chmod
命令来更改目录的权限。hdfs dfs -chmod 777 /
注意:将权限设置为
777
会使任何人都可以读、写和执行该目录,这在生产环境中通常是不安全的。建议仅在测试环境中这样做,并确保在生产环境中使用更严格的权限设置。 -
将用户添加到具有写权限的组:
可以将dr.who
用户添加到supergroup
组(假设supergroup
有写权限)。sudo usermod -a -G supergroup dr.who
然后重新登录以使组更改生效。
-
-
使用 Hadoop 的
hadoop
命令行工具:
可以使用hadoop fs
或hdfs dfs
命令来管理 HDFS 文件系统。 -
检查 Hadoop 配置:
确保 Hadoop 配置文件中的hdfs-site.xml
和core-site.xml
没有配置错误。特别是检查hdfs-site.xml
中的dfs.permissions.enabled
属性是否设置为true
。<property> <name>dfs.permissions.enabled</name> <value>true</value> </property>
如果不希望启用权限检查,可以将其设置为
false
(不推荐在生产环境中这样做)。 -
使用正确的用户运行 Hadoop 命令:
确保使用的是具有适当权限的用户来运行 Hadoop 命令。可以使用sudo -u <user>
来切换用户并运行命令。sudo -u hdfs hdfs dfs -mkdir /mydirectory
示例
假设想让 dr.who
用户能够写入 /mydirectory
目录,可以按以下步骤操作:
-
创建目录并设置适当的权限:
hdfs dfs -mkdir /mydirectory hdfs dfs -chown dr.who:supergroup /mydirectory hdfs dfs -chmod 775 /mydirectory
-
验证权限:
hdfs dfs -ls /mydirectory
-
使用
dr.who
用户尝试写入文件:sudo -u dr.who hdfs dfs -put localfile.txt /mydirectory/
通过这些步骤,应该能够解决 AccessControlException
并允许 dr.who
用户进行写操作。