Two install paths, one working cluster each
Install day in the lab. Riya wants to see every file Hadoop needs, so she installs it by hand inside WSL Ubuntu. Kabir wants three DataNodes on his laptop, which is impossible by hand on one machine, so he reaches for Docker. Both start with a coffee and an error message.
Sir, which way is the “correct” install?
Both are used at work. Admins who build clusters know the files and steps of Path A by heart, because every installer, Docker image and cluster manager does exactly those steps underneath. And Path B is how many teams spin up a practice or test cluster in minutes.
Then why not only Docker? It's faster.
Because when Docker hides something and it breaks, you'll need to know what it hid. Today, Riya's machine becomes a one-node cluster; Kabir's laptop gets one NameNode, three DataNodes and YARN. Every command and output you'll see was run for real on Hadoop 3.5.0, including the errors.
Installing Hadoop
Installing Apache Hadoop from the binary release means: downloading the release tarball and verifying its checksum; unpacking it and setting HADOOP_HOME and PATH; setting JAVA_HOME in etc/hadoop/hadoop-env.sh; writing the site configuration files (core-site.xml, hdfs-site.xml, mapred-site.xml, yarn-site.xml, and workers); setting up passwordless SSH for the start scripts; formatting the NameNode once; and starting HDFS (start-dfs.sh) and YARN (start-yarn.sh). A containerised installation runs the same daemons from a prebuilt image (e.g. apache/hadoop:3.5.0), with configuration supplied through environment variables and one container per daemon, orchestrated by Docker Compose.
Download Hadoop, check it isn't damaged, unpack it, tell it where Java is, fill in four settings files, let it log in to itself, prepare an empty HDFS, and start it. Or let Docker start ready-made Hadoop containers for you.
Words you'll meet in this lesson
.tar.gz archive. Hadoop's binary release is one tarball; unpack it with tar -xzf.~/hadoop-3.5.0.JAVA_HOME here.apache/hadoop:3.5.0.docker-compose.yaml file, on a shared network.What was tested for this lesson
| Hadoop | 3.5.0 binary tarball, 581 MB download, 1.3 GB unpacked; SHA-512 verified |
|---|---|
| Path A | Ubuntu 24.04, OpenJDK 17.0.20.1, pseudo-distributed, every step below run in order |
| Path B | Docker Compose with the official apache/hadoop:3.5.0 image (Ubuntu 24.04, OpenJDK 17, about 2.2 GB): 1 NameNode, 3 DataNodes, ResourceManager, NodeManager |
| RAM used | Idle daemons measured at about 0.2–0.35 GB each (about 1.3 GB for all five in Path A); jobs need more, so give WSL or Docker 6–8 GB if you can |
Installing at three levels
Beginner Setting up a new canteen
- Download and verify: the equipment arrives; check every box is sealed.
- Configure: decide where the store room (HDFS) and the kitchen (YARN) are.
- Format: label the empty shelves of the store room once, on opening day.
- Start: switch on the store room and the kitchen. Docker is a ready-made food truck: everything installed, just drive it in.
Intermediate The order matters
- Java and SSH first (Lesson 4.1), then unpack, then
hadoop-env.sh, then the XML files. - Format once, before the first
start-dfs.sh. Formatting again erases HDFS. - Start HDFS before YARN: jobs read input from HDFS.
- Wait until safe mode is off (
hdfs dfsadmin -safemode wait) before writing. - Check each stage:
hadoop version→jps→hdfs dfs -ls→yarn node -list→ run an example job.
Advanced What production installs add
- Dedicated users (
hdfs,yarn,mapred), data on dedicated disks (dfs.datanode.data.dirlists several mount points), logs and PIDs outside/tmp. - Configuration pushed identically to all nodes by automation or a cluster manager; a
workersfile or service manager instead of hand-run scripts. - Kerberos security, TLS for web UIs, high availability (two NameNodes, JournalNodes, ZooKeeper), monitoring and log rotation.
- Container setups mount volumes for the NameNode and DataNode folders, otherwise data disappears with the container (you'll see this happen below).
Exam tip: For “Explain the steps to install Hadoop in pseudo-distributed mode”, list: install Java and SSH → download and extract Hadoop → set JAVA_HOME, HADOOP_HOME, PATH → edit core-site.xml (fs.defaultFS), hdfs-site.xml (dfs.replication=1), mapred-site.xml (mapreduce.framework.name=yarn), yarn-site.xml (yarn.nodemanager.aux-services=mapreduce_shuffle) → passwordless SSH → hdfs namenode -format → start-dfs.sh, start-yarn.sh → verify with jps and the web UIs.
Ways to install Hadoop
| Path A: tarball (native) | Path B: Docker Compose | At companies | |
|---|---|---|---|
| What you get | Pseudo-distributed, 1 node | Fully distributed in containers | Fully distributed on servers or cloud VMs |
| Time | 30–45 minutes the first time | 5 minutes plus the image download | Hours to days, automated |
| Configuration | XML files you edit | Environment variables turned into XML by the image | Cluster manager or automation templates |
| Data survives restart? | Yes, if storage folders are outside /tmp | With stop/start yes; down deletes it (no volumes) | Yes, on dedicated disks |
| Best for | Understanding every piece | Multi-node behaviour: replication, failures | Production |
How organisations get Hadoop
Apache tarball
The release you install today. Teams that build their own platform start here and automate the steps.
Do it yourselfPackaged distributions
Apache Bigtop builds Linux packages; vendors such as Cloudera ship tested bundles with a manager.
PackagesContainers
The apache/hadoop images on Docker Hub, or Kubernetes operators, for test and dev clusters.
Managed cloud
Amazon EMR, Google Dataproc and Azure HDInsight create a ready cluster in minutes.
CloudKeep a text file of every command you run during an install. When something breaks next week, it is the first thing you'll want, and it is the start of automating the install.
Path A: install natively on Ubuntu or WSL
Prerequisites from Lesson 4.1 must be done: Java 17, SSH server running, JAVA_HOME in ~/.bashrc. All commands run in the Ubuntu terminal as your normal user; the user here is riya, so replace /home/riya with your own home folder.
Download and verify
Anything other thancd ~ wget https://dlcdn.apache.org/hadoop/common/hadoop-3.5.0/hadoop-3.5.0.tar.gz wget https://dlcdn.apache.org/hadoop/common/hadoop-3.5.0/hadoop-3.5.0.tar.gz.sha512 sha512sum -c hadoop-3.5.0.tar.gz.sha512hadoop-3.5.0.tar.gz: OKOKmeans a broken or altered download: delete it and download again. If a newer 3.5.x exists when you read this, change the version number everywhere.Unpack and set the environment
If you added thetar -xzf hadoop-3.5.0.tar.gz cat >> ~/.bashrc <<'EOF' export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 export HADOOP_HOME=$HOME/hadoop-3.5.0 export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin EOF source ~/.bashrc hadoop version | head -1Hadoop 3.5.0JAVA_HOMEline in Lesson 4.1, don't add it twice.binholds the user commands (hdfs,yarn,hadoop);sbinholds the start and stop scripts.Tell Hadoop where Java is
This is the fix forecho "export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64" >> $HADOOP_HOME/etc/hadoop/hadoop-env.shERROR: JAVA_HOME is not set and could not be found: daemons started over SSH read this file, not your~/.bashrc.core-site.xml and hdfs-site.xml
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> </configuration>The two<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///home/riya/hadoop-data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///home/riya/hadoop-data/datanode</value> </property> </configuration>dirsettings move HDFS out of/tmp, which Linux may empty on reboot. Open each file withnanoand replace the empty<configuration>block.mapred-site.xml and yarn-site.xml
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>mapreduce.application.classpath</name> <value>$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/*:$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/lib/*</value> </property> </configuration>The first two properties come from the official single-node guide: they run MapReduce on YARN and let containers find the MapReduce jars. The third is for laptops: by default a NodeManager whose disk is over 90% full marks itself unhealthy and runs nothing (see the errors table). Leave it out on real servers.<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.env-whitelist</name> <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_HOME,PATH,LANG,TZ,HADOOP_MAPRED_HOME</value> </property> <property> <name>yarn.nodemanager.disk-health-checker.max-disk-utilization-per-disk-percentage</name> <value>99.5</value> </property> </configuration>Passwordless SSH to localhost
The first connection asks to trust the host key (typessh-keygen -t rsa -P '' -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 0600 ~/.ssh/authorized_keys ssh localhost "echo connected"Warning: Permanently added 'localhost' (ED25519) to the list of known hosts. connectedyes). After that, no questions and no password: exactly whatstart-dfs.shneeds.Format the NameNode (once)
Look for “successfully formatted” in the long output. Never run this again on a cluster with data you need.hdfs namenode -format… INFO common.Storage: Storage directory /home/riya/hadoop-data/namenode has been successfully formatted. …Start HDFS and check it
start-dfs.sh jps hdfs dfsadmin -safemode wait hdfs dfs -mkdir -p /user/riya hdfs dfs -mkdir input hdfs dfs -put $HADOOP_HOME/etc/hadoop/*.xml inputStarting namenodes on [localhost] Starting datanodes Starting secondary namenodes [vm] vm: Warning: Permanently added 'vm' (ED25519) to the list of known hosts. 4865 NameNode 4966 DataNode 5304 Jps 5166 SecondaryNameNode Safe mode is OFF/user/riyais your HDFS home: relative paths likeinputmean/user/riya/input. The NameNode web UI is now athttp://localhost:9870(WSL forwards it to Windows).Start YARN and run a job
The ResourceManager UI is atstart-yarn.sh yarn node -list hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.5.0.jar \ grep input output 'dfs[a-z.]+' hdfs dfs -cat output/*Starting resourcemanager Starting nodemanagers Total Nodes:1 Node-Id Node-State Node-Http-Address Number-of-Running-Containers localhost:40123 RUNNING localhost:8042 0 … INFO mapreduce.Job: Job job_1792562428511_0001 completed successfully … 1 dfsadmin 1 dfs.replication 1 dfs.namenode.name.dir 1 dfs.datanode.data.dirhttp://localhost:8088. The result lists thedfs…property names found in the XML files you uploaded, including the ones you just wrote.Stop, and start again later
The output is still there after a full stop and start, because HDFS lives instop-yarn.sh stop-dfs.sh # next time: start-dfs.sh start-yarn.sh hdfs dfs -cat output/*Stopping nodemanagers Stopping resourcemanager Stopping namenodes on [localhost] Stopping datanodes Stopping secondary namenodes [vm] … 1 dfsadmin 1 dfs.replication 1 dfs.namenode.name.dir 1 dfs.datanode.data.dir~/hadoop-data. On WSL, also runsudo service ssh startafter reopening Ubuntu.
Path B: a 3-DataNode cluster with Docker Compose
Install Docker Desktop (Windows/macOS, with the WSL 2 back end on Windows) or Docker Engine (Linux), and give it at least 6 GB of memory. Then make a folder hadoop-cluster with these two files.
docker-compose.yaml
One service per daemon.services: namenode: image: apache/hadoop:3.5.0 hostname: namenode command: ["hdfs", "namenode"] ports: - 9870:9870 env_file: - ./config environment: ENSURE_NAMENODE_DIR: "/tmp/hadoop-hadoop/dfs/name" datanode: image: apache/hadoop:3.5.0 command: ["hdfs", "datanode"] env_file: - ./config resourcemanager: image: apache/hadoop:3.5.0 hostname: resourcemanager command: ["yarn", "resourcemanager"] ports: - 8088:8088 env_file: - ./config nodemanager: image: apache/hadoop:3.5.0 command: ["yarn", "nodemanager"] env_file: - ./configENSURE_NAMENODE_DIR: if this folder does not exist, the image formats the NameNode before starting it. It must be the NameNode's real folder; the image runs as userhadoop, so that is/tmp/hadoop-hadoop/dfs/name. (With/tmp/hadoop-root/…, as in some older examples, the NameNode is re-formatted on every start; this happened during testing.) Only the NameNode and ResourceManager UIs are published to your PC.config (the settings)
Each line isCORE-SITE.XML_fs.defaultFS=hdfs://namenode HDFS-SITE.XML_dfs.namenode.rpc-address=namenode:8020 HDFS-SITE.XML_dfs.replication=3 MAPRED-SITE.XML_mapreduce.framework.name=yarn MAPRED-SITE.XML_yarn.app.mapreduce.am.env=HADOOP_MAPRED_HOME=/opt/hadoop MAPRED-SITE.XML_mapreduce.map.env=HADOOP_MAPRED_HOME=/opt/hadoop MAPRED-SITE.XML_mapreduce.reduce.env=HADOOP_MAPRED_HOME=/opt/hadoop YARN-SITE.XML_yarn.resourcemanager.hostname=resourcemanager YARN-SITE.XML_yarn.nodemanager.pmem-check-enabled=false YARN-SITE.XML_yarn.nodemanager.vmem-check-enabled=false YARN-SITE.XML_yarn.nodemanager.aux-services=mapreduce_shuffle YARN-SITE.XML_yarn.nodemanager.disk-health-checker.max-disk-utilization-per-disk-percentage=99.5 CAPACITY-SCHEDULER.XML_yarn.scheduler.capacity.maximum-am-resource-percent=0.5 CAPACITY-SCHEDULER.XML_yarn.scheduler.capacity.root.queues=default CAPACITY-SCHEDULER.XML_yarn.scheduler.capacity.root.default.capacity=100 CAPACITY-SCHEDULER.XML_yarn.scheduler.capacity.root.default.maximum-capacity=100FILE_property=value; the image writes them into the matching XML file when a container starts. Write/opt/hadoopliterally: this file does not expand variables like$HADOOP_HOME.Start with three DataNodes
The first run downloads the image (about 2.2 GB unpacked). Six containers, six “machines”, one network.docker compose up -d --scale datanode=3 docker compose ps --format "table {{.Name}}\t{{.Status}}"NAME STATUS hadoop-cluster-datanode-1 Up 35 seconds hadoop-cluster-datanode-2 Up 35 seconds hadoop-cluster-datanode-3 Up 35 seconds hadoop-cluster-namenode-1 Up 36 seconds hadoop-cluster-nodemanager-1 Up 36 seconds hadoop-cluster-resourcemanager-1 Up 36 secondsCheck the cluster
Three DataNodes in HDFS, one NodeManager in YARN. The NodeManager's name is its container ID.docker compose exec namenode hdfs dfsadmin -printTopology docker compose exec resourcemanager yarn node -listRack: /default-rack 172.18.0.6:9866 (hadoop-cluster-datanode-3.hadoop-cluster_default) In Service 172.18.0.5:9866 (hadoop-cluster-datanode-1.hadoop-cluster_default) In Service 172.18.0.7:9866 (hadoop-cluster-datanode-2.hadoop-cluster_default) In Service Total Nodes:1 Node-Id Node-State Node-Http-Address Number-of-Running-Containers 8f368ea04df2:45495 RUNNING 8f368ea04df2:8042 0Store a file and see its three copies
docker compose exec namenode hdfs dfs -mkdir -p /user/hadoop/data docker compose cp canteen_orders.csv namenode:/tmp/canteen_orders.csv docker compose exec namenode hdfs dfs -put /tmp/canteen_orders.csv data/ docker compose exec namenode hdfs fsck /user/hadoop/data/canteen_orders.csv -files -blocks -locations/user/hadoop/data/canteen_orders.csv 4692009 bytes, replicated: replication=3, 1 block(s): OK 0. BP-1055690327-172.18.0.2-1792562685335:blk_1073741825_1001 len=4692009 Live_repl=3 [DatanodeInfoWithStorage[172.18.0.6:9866,…], DatanodeInfoWithStorage[172.18.0.7:9866,…], DatanodeInfoWithStorage[172.18.0.5:9866,…]] Status: HEALTHY Number of data-nodes: 3canteen_orders.csvis a 3 lakh-row practice file (order_id, item, amount); any CSV works. One 4.5 MB block, stored on all three DataNodes.Run a job, then see what
downdoesdocker compose exec namenode yarn jar \ /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.5.0.jar \ grep data out "vada pav|samosa|dosa" docker compose exec namenode hdfs dfs -cat "out/*" docker compose down docker compose up -d --scale datanode=3 docker compose exec namenode hdfs dfs -ls dataINFO Job:1765 - Job job_1792562696287_0001 completed successfully Rack-local map tasks=1 … 50021 samosa 49986 vada pav 49948 dosa ls: `data': No such file or directorydowndeletes the containers, and with them the HDFS data. The map task is “rack-local”, not “data-local”, because DataNodes and the NodeManager are separate containers here.Pause and resume without losing data
docker compose stop docker compose start docker compose exec namenode hdfs dfsadmin -safemode wait docker compose exec namenode hdfs dfs -ls dataSafe mode is OFF Found 1 items -rw-r--r-- 3 hadoop supergroup 4692009 2026-10-21 06:15 data/canteen_orders.csvstopkeeps the containers and their disks, so the file is still there (after uploading it again following thedownabove). Usestop/startat the end of each practice session.
Errors you will meet (all seen during testing)
| You see | Cause | Fix |
|---|---|---|
localhost: ERROR: JAVA_HOME is not set and could not be found. | Daemons started over SSH don't read ~/.bashrc | Set JAVA_HOME in etc/hadoop/hadoop-env.sh (step 3) |
localhost: Permission denied (publickey,password). | No passwordless SSH key | Step 6; check sudo service ssh status |
Name node is in safe mode. | The NameNode has just started and is still collecting block reports | Wait: hdfs dfsadmin -safemode wait |
FileAlreadyExistsException: Output directory hdfs://localhost:9000/user/riya/output already exists | MapReduce never overwrites output | hdfs dfs -rm -r output or use a new folder name |
Job stays at Running job; yarn node -list shows Total Nodes:0 or UNHEALTHY | NodeManager disk over 90% full; its log says used space above threshold of 90.0% | Free disk space, or raise …max-disk-utilization-per-disk-percentage (step 5), restart YARN |
Error: Could not find or load main class org.apache.hadoop.mapreduce.v2.app.MRAppMaster | Containers can't find the MapReduce jars | Set HADOOP_MAPRED_HOME (Docker config) or mapreduce.application.classpath (step 5) |
Docker NameNode container exits at once; UnknownHostException: namenode | Port 9870 already used, e.g. by the Path A NameNode on the same PC | Run stop-dfs.sh and stop-yarn.sh before docker compose up |
DataNode exits: Incompatible clusterIDs in /tmp/hadoop-hadoop/dfs/data: namenode clusterID = CID-6a4b…; datanode clusterID = CID-b43b… | The NameNode was formatted again, so it has a new cluster ID | Never re-format a cluster with data. On a test cluster: empty the DataNode folder (or recreate the containers) |
Files gone after docker compose down | No volumes: data lived inside the containers | Use stop/start, or add volumes |
Run Path A and Path B one at a time on the same PC. Both use ports 9870 and 8088, and a NameNode that cannot open its port fails in confusing ways.
What docker compose up builds, and what down destroys
Kabir's cluster from Path B, step by step. Every terminal line is from the real test run.
- Compose reads
docker-compose.yaml, creates a private network and starts the master containers first. - Three DataNode containers (because of
--scale datanode=3) and a NodeManager start next. - Each DataNode registers with the NameNode. Three addresses, three “machines”.
- A 4.5 MB file becomes one block, and the NameNode places a copy on each of the three DataNodes.
- A MapReduce job counts three canteen items across 3 lakh orders and writes the result to HDFS.
downremoves the containers. The new cluster is empty: the old HDFS data lived inside the removed containers.
- The masters start on a private Docker network. Only their web ports are forwarded to your PC.
- Workers join the same network. Docker gives each a host name and an IP address.
- Each DataNode sends heartbeats to the NameNode at
namenode:8020and reports its storage. - The client writes one block; the pipeline stores a replica on each DataNode (replication 3).
- YARN runs the map task in a container on the NodeManager, which reads one replica from a DataNode container.
- After
downandup, brand-new containers start with empty disks: a fresh, formatted NameNode and no blocks.
Installs at work
1. The manual steps become a script
Platform teams turn exactly the Path A steps into automation (Ansible roles, shell scripts, images), so a new worker is installed in minutes and identical to the others.
2. Throw-away test clusters
Developers start a Compose cluster to test a job, a new configuration or an upgrade, then delete it. Because down removes everything, every test starts clean.
3. Verifying what is installed
Security teams require checksums (and often GPG signatures) for every downloaded binary, and keep an internal copy of approved releases instead of downloading on each server.
4. Runbooks for known errors
Support teams keep a table like the one in Part 4: the exact error text, the cause and the fix. Searching the log for the exact message is the first step in almost every Hadoop incident.
Simplified; organisations differ in tools and policies.
Turn the Docker config file into Hadoop XML
The apache/hadoop image reads lines like CORE-SITE.XML_fs.defaultFS=hdfs://namenode and writes them into the right XML file. This program does the same, so you can see the XML your containers really use.
config = """CORE-SITE.XML_fs.defaultFS=hdfs://namenode
HDFS-SITE.XML_dfs.replication=3
YARN-SITE.XML_yarn.resourcemanager.hostname=resourcemanager
YARN-SITE.XML_yarn.nodemanager.aux-services=mapreduce_shuffle"""
files = {}
for line in config.splitlines():
key, value = line.split("=", 1)
filename, prop = key.split("_", 1)
files.setdefault(filename.lower(), []).append((prop, value))
for filename, props in files.items():
print(f"--- {filename}")
print("<configuration>")
for name, value in props:
print(f" <property><name>{name}</name><value>{value}</value></property>")
print("</configuration>")key, value = line.split("=", 1)Split only at the first=: values such asHADOOP_MAPRED_HOME=/opt/hadoopcontain another one.filename, prop = key.split("_", 1)The file name is before the first underscore. Property names contain dots and sometimes underscores, so split only once.files.setdefault(filename.lower(), []).append((prop, value))setdefaultcreates an empty list the first time a file name appears, then keeps adding to it.
Run it on your PC: make the practice file and check Hadoop's answer
Path B uses canteen_orders.csv. This program creates it (the same file on every computer, because the random generator is seeded) and then counts the items with plain Python, so you can check the answer your Hadoop job gives. Save it as make_canteen.py in the hadoop-cluster folder and run it.
Create canteen_orders.csv and count three items
# make_canteen.py: create the practice file canteen_orders.csv (3 lakh orders)
import os
import random
random.seed(7) # same file on every computer
prices = {"chai": 15, "vada pav": 20, "samosa": 18, "poha": 25, "idli": 30, "dosa": 45}
items = list(prices)
with open("canteen_orders.csv", "w") as f:
f.write("order_id,item,amount\n")
for order_id in range(1001, 1001 + 300_000):
item = random.choice(items)
f.write(f"{order_id},{item},{prices[item]}\n")
print(f"Wrote canteen_orders.csv: 300,000 orders, {os.path.getsize('canteen_orders.csv'):,} bytes")
# Check Hadoop's answer with plain Python
counts = {}
with open("canteen_orders.csv") as f:
next(f) # skip the header
for line in f:
item = line.split(",")[1]
counts[item] = counts.get(item, 0) + 1
for item in ["samosa", "vada pav", "dosa"]:
print(f"{counts[item]:>6} {item}")
# In a terminal (in the hadoop-cluster folder):
# python3 make_canteen.pyThese counts match the Hadoop job in Path B exactly (50021 samosa, 49986 vada pav, 49948 dosa). Checking a cluster result against a small independent calculation is a habit worth keeping.
One config line becomes one XML property
Follow a single line of the Docker config file through the conversion and watch each variable.
Worked examples: real problems, solved and traced in memory
Three things people script during real installs: writing the site files from one table, checking an install stage by stage, and catching configuration mistakes before starting a cluster. Each runs live and is traced in memory.
Write all four site files from one table
Problem statement
Instead of editing four XML files by hand, keep the pseudo-distributed settings in one Python dictionary and print each file. Use the settings from Path A, steps 4 and 5 (without the long whitelist).
core: fs.defaultFS · hdfs: dfs.replication · mapred: mapreduce.framework.name · yarn: aux-services
== core-site.xml
<configuration>
<property><name>fs.defaultFS</name><value>hdfs://localhost:9000</value></property>
</configuration>
== hdfs-site.xml
<configuration>
<property><name>dfs.replication</name><value>1</value></property>
</configuration>
== mapred-site.xml
<configuration>
<property><name>mapreduce.framework.name</name><value>yarn</value></property>
</configuration>
== yarn-site.xml
<configuration>
<property><name>yarn.nodemanager.aux-services</name><value>mapreduce_shuffle</value></property>
</configuration>Approach
- Map each file name to its properties.
- Loop over files, then properties.
- Print the XML in Hadoop's format.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
Check an install stage by stage
Problem statement
A student sends the results of five checks from their install. Report the first stage that fails and the most likely fix, the way a support engineer would.
version OK · jps has NameNode, DataNode, SecondaryNameNode · safe mode OFF · yarn nodes 0 · job not run
PASS hadoop version
PASS HDFS daemons in jps
PASS safe mode OFF
FAIL yarn node -list > 0
fix: NodeManager unhealthy? check disk space and NM logApproach
- List the stages in order, each with a test and a fix.
- Walk through them; stop at the first failure.
- Later stages can't be judged until earlier ones pass.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
Catch configuration mistakes before starting
Problem statement
Write a small checker for a planned configuration. Flag: replication larger than the number of DataNodes; NameNode or DataNode folders under /tmp; YARN without the mapreduce_shuffle service; MapReduce not set to yarn.
replication 3 · 1 DataNode · name.dir /tmp/… · aux-services missing · framework yarn
- replication is higher than the number of DataNodes - NameNode metadata under /tmp may vanish on reboot - YARN has no mapreduce_shuffle service
Approach
- Write each rule as a condition and a message.
- Evaluate all rules, not just the first.
- Print every problem found, or “looks good”.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
Check yourself
Quick revision
Lesson 4.3 in one screen
- Path A (native): download → sha512sum -c → unpack →
HADOOP_HOME,PATH→JAVA_HOMEin hadoop-env.sh. - Site files: core (
fs.defaultFS), hdfs (dfs.replication=1, storage dirs), mapred (framework=yarn), yarn (mapreduce_shuffle). - SSH key for localhost → format once →
start-dfs.sh→start-yarn.sh→jps. - Check:
hadoop version→jps→safemode wait→yarn node -list→ example job. - UIs: NameNode
:9870, ResourceManager:8088. - Path B (Docker):
docker-compose.yaml+config→docker compose up -d --scale datanode=3. - Docker: stop/start keeps data, down deletes it (no volumes).
- Errors: JAVA_HOME → hadoop-env.sh · publickey → SSH key · safe mode → wait · output exists → rm -r · 0 nodes → NM disk · MRAppMaster → HADOOP_MAPRED_HOME.
Interview and viva questions
What are the steps to install Hadoop on Ubuntu?
Install Java (JDK 17 for Hadoop 3.5) and SSH; download and verify the Hadoop tarball; extract it and set HADOOP_HOME and PATH; set JAVA_HOME in hadoop-env.sh; configure core-site.xml, hdfs-site.xml, mapred-site.xml and yarn-site.xml; set up passwordless SSH to localhost; format the NameNode; start HDFS and YARN with start-dfs.sh and start-yarn.sh; verify with jps, the web UIs and an example job.
Can I install Hadoop on Windows?
For learning, install it inside WSL 2 (Ubuntu) using exactly the Path A steps, or run the Docker cluster with Docker Desktop. The web UIs are reachable from Windows at localhost:9870 and localhost:8088.
How do I check that Hadoop is installed correctly?
hadoop version prints the version; jps lists NameNode, DataNode, SecondaryNameNode, ResourceManager and NodeManager; hdfs dfsadmin -report shows live DataNodes; yarn node -list shows RUNNING NodeManagers; the NameNode UI (9870) and ResourceManager UI (8088) open; and an example job such as grep or wordcount completes.
Why is my NodeManager UNHEALTHY?
Usually a disk-health check: when a local or log directory is more than 90% full (the default threshold), the NodeManager marks it bad and reports itself unhealthy, so YARN schedules nothing there. Free disk space or, on a practice machine, raise yarn.nodemanager.disk-health-checker.max-disk-utilization-per-disk-percentage.
What is the official Hadoop Docker image?
The Apache Hadoop project publishes apache/hadoop images on Docker Hub (for example apache/hadoop:3.5.0). One image contains everything; the command decides which daemon a container runs, and environment variables become configuration.
How do I stop Hadoop?
Run stop-yarn.sh and then stop-dfs.sh (and mapred --daemon stop historyserver if you started it). With Docker, docker compose stop keeps the containers and data; docker compose down removes them.
Where are Hadoop logs?
In $HADOOP_HOME/logs by default, one file per daemon, for example hadoop-riya-namenode-<host>.log. In Docker, use docker compose logs namenode.
Do I need to format the NameNode every time?
No. Only once, when creating a cluster. Re-formatting erases the namespace and gives HDFS a new cluster ID, so existing DataNodes refuse to join until their data folders are cleaned.
Practice problems
Exercises on the install itself: paths, configuration, checks and errors. All runnable in the browser.
Build the download URL
Print the download URL of the tarball and its checksum for version 3.5.0, using the pattern https://dlcdn.apache.org/hadoop/common/hadoop-V/hadoop-V.tar.gz.
version = "3.5.0"
https://dlcdn.apache.org/hadoop/common/hadoop-3.5.0/hadoop-3.5.0.tar.gz https://dlcdn.apache.org/hadoop/common/hadoop-3.5.0/hadoop-3.5.0.tar.gz.sha512
Show solution and explanation
v = "3.5.0"
url = f"https://dlcdn.apache.org/hadoop/common/hadoop-{v}/hadoop-{v}.tar.gz"
print(url)
print(url + ".sha512")How it works: The checksum file has the same name plus .sha512. Changing v is all it takes to install another release.
Relative HDFS paths
In HDFS, a relative path is relative to /user/<username>. Print the full paths for user riya of input and output/part-r-00000.
user riya · input · output/part-r-00000
input -> /user/riya/input output/part-r-00000 -> /user/riya/output/part-r-00000
Show solution and explanation
user = "riya"
for p in ["input", "output/part-r-00000"]:
print(p, "->", f"/user/{user}/{p}")How it works: /user/riya/input and /user/riya/output/part-r-00000. That is why step 8 creates /user/riya first.
Which UI on which port?
Print the URL of the NameNode and ResourceManager web UIs on localhost.
NameNode 9870 · ResourceManager 8088
NameNode http://localhost:9870 ResourceManager http://localhost:8088
Show solution and explanation
for name, port in [("NameNode", 9870), ("ResourceManager", 8088)]:
print(f"{name:16} http://localhost:{port}")How it works: http://localhost:9870 and http://localhost:8088, the same for Path A and Path B (which is why they cannot run together).
Parse fsck
From the fsck line "len=4692009 Live_repl=3", print the block size in MB and the number of live replicas.
len=4692009 Live_repl=3
4.5 MB, 3 live replicas
Show solution and explanation
line = "len=4692009 Live_repl=3"
fields = dict(part.split("=") for part in line.split())
print(f"{int(fields['len']) / 1024 / 1024:.1f} MB, {fields['Live_repl']} live replicas")How it works: 4.5 MB and 3 live replicas: the whole file fits in one block, stored on all three DataNodes.
Disk check threshold
A NodeManager disk is 465 GB with 430 GB used. With the default 90% threshold, is it healthy? And with 99.5%?
465 GB disk · 430 GB used · 90% and 99.5%
used 92.5% vs limit 90% -> UNHEALTHY used 92.5% vs limit 99.5% -> healthy
Show solution and explanation
used_pct = 430 / 465 * 100
for limit in [90, 99.5]:
print(f"used {used_pct:.1f}% vs limit {limit}% -> {'healthy' if used_pct <= limit else 'UNHEALTHY'}")How it works: 92.5% used: unhealthy with the default 90% limit, healthy with 99.5%. Typical of a student laptop full of downloads.
Docker memory budget
Idle Hadoop daemons measured during testing used about 0.2–0.35 GB of RAM each; take 0.3 GB. The Docker cluster runs 6 containers and Docker Desktop is given 4 GB. How much is left for job containers, each needing 1 GB?
6 × 0.3 GB · 4 GB · 1 GB per job container
daemons use 1.8 GB, 2.2 GB left -> 2 job container(s)
Show solution and explanation
used = 6 * 0.3
left = 4 - used
print(f"daemons use {used:.1f} GB, {left:.1f} GB left -> {int(left // 1)} job container(s)")How it works: About 1.8 GB for the idle daemons and 2.2 GB left: room for only 2 job containers, and a MapReduce job needs one just for its ApplicationMaster. Give Docker 6–8 GB if you can.
Manual vs scripted install
A team installs 12 practice clusters a year for training batches. By hand: 45 minutes each. Docker Compose: 5 minutes each, plus 3 hours once to prepare the files. Hours saved in a year?
12 installs · 45 min vs 5 min · 3 h setup
manual 9 h, compose 4 h, saved 5 h
Show solution and explanation
manual = 12 * 45 / 60
compose = 3 + 12 * 5 / 60
print(f"manual {manual:.0f} h, compose {compose:.0f} h, saved {manual - compose:.0f} h")How it works: 9 hours by hand against 4 with Compose: 5 hours saved in the first year, and every batch gets an identical cluster.
Diagnose from error text
Write a function that maps an error message to its fix, using keywords from the errors table, and test it on three real messages.
JAVA_HOME … · Permission denied (publickey,password) · Output directory … already exists
set JAVA_HOME in etc/hadoop/hadoop-env.sh set up passwordless SSH to the host hdfs dfs -rm -r <output> or choose a new folder
Show solution and explanation
fixes = [("JAVA_HOME is not set", "set JAVA_HOME in etc/hadoop/hadoop-env.sh"),
("Permission denied (publickey", "set up passwordless SSH to the host"),
("already exists", "hdfs dfs -rm -r <output> or choose a new folder"),
("safe mode", "hdfs dfsadmin -safemode wait"),
("MRAppMaster", "set HADOOP_MAPRED_HOME / mapreduce.application.classpath")]
def diagnose(msg):
return next((fix for key, fix in fixes if key in msg), "read the daemon log in $HADOOP_HOME/logs")
for m in ["localhost: ERROR: JAVA_HOME is not set and could not be found.",
"riya@localhost: Permission denied (publickey,password).",
"Output directory hdfs://localhost:9000/user/riya/output already exists"]:
print(diagnose(m))How it works: Each message maps to its fix; anything unknown falls back to “read the log”. Support teams build runbooks on exactly this idea.
Real-world scenario questions (asked in company interviews)
Installation questions test whether you have really done it. Answer with the order of steps, the checks and the errors you met.
“My first job never finishes”
A student's pseudo-distributed cluster shows all five daemons in jps, but the example job prints “Running job: job_…” and then nothing for ten minutes.
The interviewer is checking: do you know where YARN runs work, and how to check NodeManagers?
Show a strong answer
- The job is waiting for a container. Run
yarn node -list -all: if the NodeManager is missing or UNHEALTHY, nothing can run. - Read the NodeManager log: a common message is
used space above threshold of 90.0%(disk nearly full). - Free disk space (or raise the threshold on a practice machine), restart YARN, and check that the node shows RUNNING.
- Also check the ResourceManager UI at port 8088 for the application's state and diagnostics.
“Walk me through installing Hadoop on a single machine”
A common first-round interview question for data engineering roles.
The interviewer is checking: the order of steps and whether you verify each one.
Show a strong answer
- Java (JDK 17 for 3.5) and SSH; download the tarball and verify the SHA-512.
- Extract, set
HADOOP_HOME/PATH, andJAVA_HOMEinhadoop-env.sh. - Configure the four site files (default FS, replication 1 and storage folders, MapReduce on YARN, shuffle service).
- Passwordless SSH, format the NameNode once, start HDFS and YARN, check
jps, both web UIs and an example job.
“All our test data disappeared overnight”
A team runs a Docker Compose Hadoop cluster for testing. After a laptop restart and docker compose down / up, HDFS is empty.
The interviewer is checking: do you understand container storage?
Show a strong answer
- Without volumes, NameNode metadata and DataNode blocks live in the container's own file system, which
downdeletes. - Use
docker compose stop/startfor pauses, or mount volumes for the name and data directories. - For test data, keep a script that reloads it (put files, create tables), so a fresh cluster is ready in minutes.
DataNode won't start after someone re-formatted the NameNode
After hdfs namenode -format was run again on a test cluster, the DataNode exits at start-up. Its log mentions “Incompatible clusterIDs”.
The interviewer is checking: do you know what formatting changes?
Show a strong answer
- Formatting created a new namespace with a new cluster ID; the DataNode's storage folder still has the old ID, so it refuses to join.
- On a test cluster whose data can be discarded: stop the DataNode, empty its
dfs.datanode.data.dir, and start it again. - On a real cluster: never re-format; restore the NameNode metadata from a backup instead. The old blocks are useless without the old namespace.