## 關于HDFS與YARN的鏡像封裝
定稿人 | 定稿日期 | 系統環境
| :--------: | :-----: | :----: |
李程 | 2017.11.28 | centos7 + docker1.13 + docker-compose1.16
平時我們搭建hadoop集群的時候都是部署在物理機上,然而我們通過大量實驗發現使用容器搭建hadoop集群不僅啟動速度更快,而且資源利用率更高,本節主要講述如何使用dockerfile封裝hadoop,然后使用docker-compose編排集群。
### DockerFile源代碼
```
# HDFS、YARN鏡像封裝
FROM openjdk:8u131-jre-alpine
MAINTAINER <EWay>
# 設置一些系統環境變量(字符集和時區)
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV TZ=Asia/Shanghai
# 安裝一些必需的軟件包,同步時區
RUN apk --update add wget bash tzdata \
&& cp /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
# 設置HADOOP相關的環境變量,這里我們使用2.7.4版本
ENV HADOOP_VERSION 2.7.4
ENV HADOOP_PACKAGE hadoop-${HADOOP_VERSION}
ENV HADOOP_HOME=/usr/hadoop
ENV PATH=$PATH:${HADOOP_HOME}/bin:${HADOOP_HOME}/sbin
# Hadoop安裝
RUN wget http://www.apache.org/dist/hadoop/common/${HADOOP_PACKAGE}/${HADOOP_PACKAGE}.tar.gz && \
tar -xzvf $HADOOP_PACKAGE.tar.gz && \
mv $HADOOP_PACKAGE /usr/hadoop && \
# 刪除安裝包,減少鏡像大小
rm $HADOOP_PACKAGE.tar.gz && \
# 創建一系列HDFS需要的文件目錄
mkdir -p /root/hadoop/tmp && \
mkdir -p /root/hadoop/var && \
mkdir -p /root/hadoop/dfs/name && \
mkdir -p /root/hadoop/dfs/data && \
mkdir $HADOOP_HOME/logs && \
# 格式化NameNode元數據
$HADOOP_HOME/bin/hdfs namenode -format
WORKDIR $HADOOP_HOME
```
dockerfile 編寫完后我們就可以基于此構建鏡像了
```powershell
# 構建Dockerfile 構建鏡像
$ docker build -f Dockerfile -t hadoop:v1 .
```
### DockerFile代碼注意事項
#### 源鏡像選擇
通常我們封裝鏡像時,一般都采用Centos或Ubuntu的源鏡像,但是這樣做有一個很大的缺點就是封裝后的鏡像體積太大,所以為了減少鏡像體積,我們使用了體積小巧的alpine作為源鏡像,同時考慮到HDFS和YARN都需要JAVA環境,所以最終我們使用了自帶JDK的openjdk:8u131-jre-alpine。
> 注:最終鏡像大小只有500M左右
#### 時區同步
源鏡像默認是CTS時區,所以需要添加tzdata包獲取各時區的相關數據,以更改為中國上海的時區。
> 注: tzdata安裝更改時區后不可卸載,否則時區會變回CTS。
#### NameNode格式化
HDFS NameNode必須初始格式化后才可工作,所以這里直接在鏡像中格式化,該條命令僅對NameNode生效,所以該條命令并不影響其他服務的使用。
> 優化: 這里可以使用腳本獲取格式化路徑,并判斷是否需要格式化,這樣做會使鏡像變得更加靈活。
### 單獨啟動各服務容器
**本環節尤其重要的是如何解耦hadoop中的各個服務,達到每個容器啟動一個服務進程,這樣做一方面是為了解耦合,另一方面是為了更好的監控集群(一旦某容器即服務掛掉立馬就可以看出來),如果是同一個容器啟動多個服務的話,這樣很難做到比較好的實時監控。**
* * * * *
1. 啟動NameNode服務
```powershell
docker run -d --name namenode \
-p 50070:50070 -h namenode \
-v /root/hadoop/dfs/name:/root/hadoop/dfs/name \
hadoop:v1 hdfs namenode \
-Dfs.defaultFS=hdfs://0.0.0.0:9000 \
-Ddfs.namenode.name.dir=/root/hadoop/dfs/name \
-Ddfs.replication=3 \
-Ddfs.namenode.datanode.registration.ip-hostname-check=false \
-Ddfs.permissions.enabled=false \
-Ddfs.namenode.safemode.threshold-pct=0
```
> 注:使用HDFS命令后面的-D參數傳遞配置信息,這樣可以使得鏡像更加靈活;
> - dfs.namenode.datanode.registration.ip-hostname-check參數需要設置為false(默認為true),這樣即使namenode中沒有該datanode的DNS也可以完成注冊。
> - dfs.namenode.safemode.threshold-pct參數的作用是設置namenode啟動時可以容忍的數據塊丟失比例,默認是99.9%。如果低于這一限制,那么namenode將一直處于安全模式,當分布式文件系統處于安全模式的情況下,文件系統中的數據是只讀的。
2. 啟動DataNode服務并連接上NameNode
```powershell
docker run -d --name datanode -p 50075:50075 \
-v /root/hadoop/dfs/data:/root/hadoop/dfs/data \
--link namenode \
hadoop:v1 hdfs datanode \
-fs hdfs://namenode:9000 \
-Ddfs.datanode.data.dir=/root/hadoop/dfs/data \
-Ddfs.permissions.enabled=false
```
> 注:--link <目標容器名> 該參數的主要意思是本容器需要使用目標容器的服務,所以指定了容器的啟動順序,并且在該容器的hosts文件中添加目標容器名的DNS。
3. 啟動ResourceManager服務
```powershell
docker run -d --name resourcemanager \
-p 8088:8088 -h ResourceManager \
hadoop:v1 yarn resourcemanager \
-Dfs.defaultFS=hdfs://namenode:9000 \
-Dmapreduce.framework.name=yarn \
-Dyarn.resourcemanager.hostname=ResourceManager \
-Dyarn.resourcemanager.webapp.address=0.0.0.0:8088
```
4. 啟動NodeManager服務
```powershell
docker run -d --name nodemanager \
--link resourcemanager \
hadoop:v1 yarn nodemanager \
-Dfs.defaultFS=hdfs://namenode:9000 \
-Dmapreduce.framework.name=yarn \
-Dyarn.resourcemanager.hostname=ResourceManager \
-Dyarn.nodemanager.aux-services=mapreduce_shuffle \
-Dyarn.nodemanager.resource.memory-mb=2048 \
-Dyarn.nodemanager.resource.cpu-vcores=1 \
-Dyarn.nodemanager.vmem-check-enabled=false
```
### 使用docker-compose編排集群
雖然上面我們已經可以將HDFS和YARN的各個服務逐一啟動,但是這樣啟動集群是不是有點麻煩呢,使用docker-compose編排工具可以幫助我們解決這個問題,完成一鍵啟動整個集群的功能。
```
namenode:
image: hadoop:v1
command: [
"hdfs",
"namenode",
"-Dfs.defaultFS=hdfs://0.0.0.0:9000",
"-Ddfs.namenode.name.dir=/root/hadoop/dfs/name",
"-Ddfs.replication=3",
"-Ddfs.namenode.datanode.registration.ip-hostname-check=false",
"-Ddfs.permissions.enabled=false",
"-Ddfs.namenode.safemode.threshold-pct=0"
]
hostname: namenode
expose:
- 50070
- 50090
- 8020
- 9000
ports:
- 50070:50070
volumes:
- /root/hadoop/dfs/name:/root/hadoop/dfs/name
datanode1:
image: hadoop:v1
command: [
"hdfs",
"datanode",
"-fs", "hdfs://namenode:9000",
"-Ddfs.datanode.data.dir=/root/hadoop/dfs/data",
"-Ddfs.permissions.enabled=false"
]
links:
- namenode
expose:
- 50010
- 50020
- 50075
volumes:
- /root/hadoop/dfs/data1:/root/hadoop/dfs/data
datanode2:
image: hadoop:v1
command: [
"hdfs",
"datanode",
"-fs", "hdfs://namenode:9000",
"-Ddfs.datanode.data.dir=/root/hadoop/dfs/data",
"-Ddfs.permissions.enabled=false"
]
links:
- namenode
expose:
- 50010
- 50020
- 50075
volumes:
- /root/hadoop/dfs/data2:/root/hadoop/dfs/data
resourcemanager:
image: hadoop:v1
command: [
"yarn",
"resourcemanager",
"-Dfs.defaultFS=hdfs://namenode:9000",
"-Dyarn.nodemanager.aux-services=mapreduce_shuffle",
"-Ddfs.namenode.datanode.registration.ip-hostname-check=false",
"-Ddfs.permissions.enabled=false -Dmapreduce.framework.name=yarn",
"-Dyarn.resourcemanager.webapp.address=0.0.0.0:8088"
]
hostname: resourcemanager
expose:
- 8030
- 8031
- 8032
- 8033
- 8040
- 8042
- 8088
ports:
- 8088:8088
nodemanager:
image: hadoop:v1
command: [
"yarn",
"nodemanager",
"-Dyarn.resourcemanager.hostname=resourcemanager",
"-Dyarn.nodemanager.resource.memory-mb=1024",
"-Dyarn.nodemanager.aux-services=mapreduce_shuffle",
"-Ddfs.namenode.datanode.registration.ip-hostname-check=false",
"-Dmapreduce.framework.name=yarn",
"-Ddfs.permissions.enabled=false"
]
links:
- resourcemanager
expose:
- 8030
- 8031
- 8032
- 8033
- 8040
- 8042
- 8088
```
這樣編寫好docker-compose文件后,就可以一鍵啟動集群了
```
# 一鍵啟動docker-compose.yml編排的所有服務
$ docker-compose -f docker-compose.yml up -d
# 一鍵橫向擴展nodemanager節點
$ docker-compose scale nodemanager=5
```
> 注意:如果有些服務想用scale命令擴展數量的話,是不能夠有掛載點的,因為多個服務不能夠映射同一個宿主機上的掛載路徑,所以上面的服務中nodemanager是可以使用scale擴展的,而datanode就不可以,因為datanode需要使用掛載點持久化數據,這個問題在docker中并不能得到很好的解決,不過可以使用Kubernetes解決此問題。
- Docker
- Docker入門
- docker管理UI
- 封裝各大數據組件
- 自主封裝
- 封裝hadoop
- 封裝spark
- 官方封裝
- 封裝hue
- 封裝jenkins
- Swarm
- Swarm入門
- Zookeeper on swarm
- Hue on swarm
- Grafana
- influxDB
- Prometheus
- cAdvisor
- kubernetes
- k8s入門
- k8s部署dashboard
- minikube
- 手動搭建k8s的高可用集群
- 01環境準備
- 02部署etcd集群
- 03配置kubelet
- 04部署flannel網絡
- 05部署master集群
- 06配置高可用
- 07部署node節點
- 08驗證集群
- Monitor
- swarm 監控
- influxDB+Grafana
- Prometheus+Grafana