| |

LFCE 4 🐧 Building a Lab with VMs or Containers

⏱️ Estimated read: 10 min | |

The previous chapter introduced the practice lab options at the high level. This chapter dives into the two practical implementation paths: the virtual machines (the full isolation, the own kernel) and the containers (the lightweight, the shared kernel). The LFCE tested the multi-system scenarios: the DNS, the DHCP, the PXE, the centralized authentication. The virtual machines are the natural fit for these scenarios because the services require the separate kernels, the isolated network stacks, and the systemd init. The containers are the faster and the lighter, but the shared kernel and the missing systemd (in the default Docker) limit the service testing. The critical distinction is between the container for the application (the Docker, the Podman) and the system container (the LXC, the systemd-nspawn) that runs the full init.

Key point: The virtual machines (the KVM/libvirt, the VirtualBox, the Vagrant) are the recommended for the LFCE study because the service scenarios (the DNS, the DHCP, the PXE) require the separate kernels and the full init systems. The containers (the Docker) are the faster for the application isolation and the command-line practice, but the shared kernel limits the kernel-level and the init-level testing. The Vagrant with the VirtualBox or the libvirt is the best balance: the declarative multi-VM provisioning, the snapshots, and the disposable state.


Why the VM versus container distinction matters

The kernel problem. The LFCE tested the kernel-level configuration: the sysctl, the kernel modules, the boot parameters, the SELinux. The containers share the host kernel. The sysctl -w inside the container changes the host kernel, not the container’s. The uname -r returns the host kernel version. The kernel testing requires the VM with the own kernel .

The init problem. The LFCE tested the systemd services: the systemctl, the journalctl, the unit files. The default Docker container runs the single process, not the systemd. The systemd requires the privileged container or the system container (the LXC, the systemd-nspawn) with the --system flag. The service testing is the easier in the VM with the native systemd .

The network problem. The LFCE tested the DNS, the DHCP, the PXE. The DHCP server requires the broadcast on the isolated network. The PXE requires the TFTP and the DHCP integration. The container network is the bridge with the NAT; the broadcast is the limited. The VM with the host-only or the bridged network provides the realistic L2/L3 environment for the DHCP and the PXE testing .

The performance problem. The containers are the faster to start and the lighter on the RAM. The three containers use the 500 MB total. The three VMs use the 12 GB. The host with the 8 GB RAM can run the three containers, but not the three VMs. The candidate with the limited hardware uses the containers for the command-line practice and the cloud VMs for the service integration .

The trade-off. The VMs are the complete but the resource-heavy. The containers are the fast but the limited. The Vagrant with the VirtualBox is the best balance: the declarative provisioning, the snapshots, the full VM isolation. The Docker is the supplement for the quick command-line drills .


a. The VM lab with Vagrant

The Vagrant is the declarative VM provisioning. The single Vagrantfile defines the multiple VMs. The vagrant up creates and starts them. The vagrant destroy removes them. The vagrant snapshot save and the vagrant snapshot restore handle the disposable state .

The Vagrantfile with the three nodes.

# Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"

  nodes = [
    { name: "lab-node1", ip: "192.168.56.10" },
    { name: "lab-node2", ip: "192.168.56.11" },
    { name: "lab-node3", ip: "192.168.56.12" },
  ]

  nodes.each do |node|
    config.vm.define node[:name] do |n|
      n.vm.hostname = node[:name]
      n.vm.network "private_network", ip: node[:ip]
      n.vm.provider "virtualbox" do |vb|
        vb.memory = "2048"
        vb.cpus = 2
      end
    end
  end
end

The private_network with the fixed IP creates the host-only network. The VMs can reach each other via the 192.168.56.0/24. The virtualbox provider sets the 2 GB and the 2 CPU per VM. The vagrant up creates all three .

The hosts file on each VM.

# On each VM
cat | sudo tee -a /etc/hosts <<EOF
192.168.56.10 lab-node1
192.168.56.11 lab-node2
192.168.56.12 lab-node3
EOF

The /etc/hosts provides the name resolution. The ping lab-node2 from the lab-node1 works. The SSH between the VMs works with the key auth.

The snapshot.

vagrant snapshot save lab-node1 clean
vagrant snapshot restore lab-node1 clean

The snapshot save creates the named snapshot. The snapshot restore reverts. The Vagrant snapshots are the fast reset for the destructive experiments .


b. The container lab with Docker

The Docker containers are the faster. The single host, the multiple containers on the user-defined bridge network. The containers can reach each other by the name .

The network and the containers.

# Create the user-defined network
docker network create lab-net

# Create the three containers
docker run -d --name lab-node1 --network lab-net --hostname lab-node1 alpine sleep infinity
docker run -d --name lab-node2 --network lab-net --hostname lab-node2 alpine sleep infinity
docker run -d --name lab-node3 --network lab-net --hostname lab-node3 alpine sleep infinity

The --network lab-net connects the containers to the same bridge. The --hostname sets the name. The containers can reach each other by the name (ping lab-node2) because the Docker DNS resolves the container names on the user-defined network .

The limitation: the Alpine does not have the systemd. The systemctl does not work. The service testing requires the system container.

The system container with the systemd.

# Run the systemd container (the privileged)
docker run -d --name sys-node1 --privileged --network lab-net \
  --hostname sys-node1 \
  -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
  jrei/systemd-ubuntu:22.04

The --privileged and the /sys/fs/cgroup mount enable the systemd inside the container. The systemctl works. The limitation is the shared kernel: the uname -r returns the host kernel. The kernel-level testing is the not the accurate .

The Docker is the supplement for the command-line drills: the grep, the sed, the awk, the tar, the chmod. The fast and the disposable. The docker exec -it lab-node1 sh enters the shell. The docker rm -f lab-node1 removes the container .


c. The hybrid approach

The best strategy for the LFCE study is the hybrid: the containers for the daily command-line drills, the VMs for the service integration and the kernel-level testing, and the cloud VMs for the multi-system scenarios when the local hardware is the limited.

The containers for the essential commands.

# The daily drill
docker run --rm -it ubuntu:22.04 bash
# Practice the grep, the sed, the awk, the tar, the chmod
exit

The --rm removes the container on the exit. The clean state for every drill. The fast.

The VMs for the services.

# The Vagrant for the DNS, the DHCP, the PXE
vagrant up
vagrant ssh lab-node1
sudo apt install bind9 isc-dhcp-server
# Configure the services

The Vagrant VMs have the systemd, the network, the kernel. The service configuration is the realistic.

The LFCE-specific Vagrant.

# The lfce-vagrant-env (the CentOS 7 simulation)
git clone https://github.com/lrakai/lfce-vagrant-env.git
cd lfce-vagrant-env
bash up_exam.sh

The lfce-vagrant-env provides the box, the node1, the node2 with the /etc/hosts and the SSH. The closest to the LFCE exam .

The container-based LFCS practice tool.

# The lfcs-practice-tool (the container-based)
pip install lfcs
lfcs start

The lfcs-practice-tool builds the Docker images automatically on the first use. The 83+ scenarios with the automatic validation. The lfcs start launches the interactive practice. The lfcs start --category networking --difficulty easy filters the scenarios. The exit validates the work. The tool is the LFCS-focused, but the networking and the storage scenarios overlap with the LFCE .


Complete Example Session

# ============================================
# PART 1: VAGRANT VM LAB
# ============================================

# The Vagrantfile with the three nodes
vagrant up
vagrant status
# ============================================
# PART 2: HOSTS FILE
# ============================================

vagrant ssh lab-node1
echo "192.168.56.11 lab-node2" | sudo tee -a /etc/hosts
ping lab-node2
# ============================================
# PART 3: SNAPSHOT
# ============================================

vagrant snapshot save lab-node1 clean
# ============================================
# PART 4: DOCKER NETWORK
# ============================================

docker network create lab-net
docker run -d --name lab-node1 --network lab-net --hostname lab-node1 alpine sleep infinity
# ============================================
# PART 5: DOCKER PING
# ============================================

docker exec -it lab-node1 sh
ping lab-node2
exit
# ============================================
# PART 6: SYSTEMD CONTAINER
# ============================================

docker run -d --name sys-node1 --privileged --network lab-net --hostname sys-node1 -v /sys/fs/cgroup:/sys/fs/cgroup:ro jrei/systemd-ubuntu:22.04
docker exec -it sys-node1 systemctl status
# ============================================
# PART 7: LFCE VAGRANT
# ============================================

git clone https://github.com/lrakai/lfce-vagrant-env.git
cd lfce-vagrant-env
bash up_exam.sh
# ============================================
# PART 8: LFCS PRACTICE TOOL
# ============================================

pip install lfcs
lfcs start
lfcs start --category networking --difficulty easy
# ============================================
# PART 9: THE HYBRID
# ============================================

# Containers: the daily drills
# VMs: the services and the kernel
# Cloud: the multi-system
# LFCE Vagrant: the exam simulation

The nine parts trace the VM and container lab: the Vagrant VMs, the hosts file, the snapshot, the Docker network, the Docker ping, the systemd container, the LFCE Vagrant, the LFCS tool, and the hybrid.


Quick Reference

VM Tools

ToolPurpose
VagrantDeclarative multi-VM
VirtualBoxHypervisor
KVM/libvirtLinux hypervisor

Container Tools

ToolPurpose
DockerApplication containers
PodmanDaemonless alternative
LXC/LXDSystem containers

Vagrant Commands

CommandPurpose
vagrant upCreate and start
vagrant sshSSH into the VM
vagrant snapshot saveCreate the snapshot
vagrant snapshot restoreRevert
vagrant destroyRemove the VMs

Docker Commands

CommandPurpose
docker network createUser-defined network
docker run --networkConnect to the network
docker run --privilegedSystem container
docker exec -itEnter the container

Best Practices

✅ Do This:

vagrant snapshot save lab-node1 clean
<!-- Snapshot before the experiments -->              # ✅
docker network create lab-net
<!-- Create the user-defined network -->              # ✅
docker run --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro
<!-- Run the systemd container -->                   # ✅

❌ Don’t Do This:

# Use the Docker for the kernel testing
<!-- The shared kernel limits it -->                 # ❌
# Use the Alpine for the systemd services
<!-- No systemd in the Alpine -->                    # ❌
# Skip the snapshot
<!-- The destructive change requires the reinstall --> # ❌

Common Pitfalls

PitfallWhy It HappensFix
Containers cannot ping by nameDefault bridgeUse user-defined network
systemctl fails in DockerNo systemdUse the system container
Vagrant VM slowThe host RAM insufficientReduce the VM RAM or use the cloud
VMs cannot reach each otherNo the private networkAdd the private_network
Snapshot lostNo the snapshot savevagrant snapshot save

Real-World Examples

1. Vagrantfile

config.vm.network "private_network", ip: "192.168.56.10"

2. Vagrant Up

vagrant up

3. Vagrant Snapshot

vagrant snapshot save lab-node1 clean

4. Docker Network

docker network create lab-net

5. Docker Run

docker run -d --name lab1 --network lab-net alpine

6. Docker Ping

docker exec lab1 ping lab2

7. Systemd Container

docker run --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro jrei/systemd-ubuntu

8. LFCE Vagrant

git clone https://github.com/lrakai/lfce-vagrant-env.git

9. LFCS Tool

pip install lfcs && lfcs start

10. Hybrid

Containers for the drills, VMs for the services

Visual

VM vs Container

┌──────────────────────────────────────────────┐
│  VM (the full isolation)                     │
│  ├── Own kernel                              │
│  ├── Own init (systemd)                      │
│  ├── Own network stack                       │
│  └── The service testing                     │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Container (the lightweight)                 │
│  ├── Shared kernel                           │
│  ├── Single process (default)                │
│  ├── The NAT bridge                          │
│  └── The command-line drills                 │
└──────────────────────────────────────────────┘

The Hybrid Lab

┌──────────────────────────────────────────────┐
│  Daily drills: the Docker containers         │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Service integration: the Vagrant VMs        │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Multi-system: the cloud VMs                 │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Exam simulation: the lfce-vagrant-env       │
└──────────────────────────────────────────────┘

Summary

ItemValue
VM toolVagrant + VirtualBox/KVM
Container toolDocker, Podman
Vagrant networkprivate_network
Docker networkUser-defined bridge
System container--privileged + cgroup
Snapshotvagrant snapshot save
LFCE Vagrantlfce-vagrant-env
LFCS toollfcs-practice-tool

Key takeaways:

  • The VMs are the complete. The separate kernel, the systemd, the isolated network. The service scenarios (the DNS, the DHCP, the PXE) require the VMs. The Vagrant is the declarative provisioning .
  • The containers are the fast. The user-defined network provides the name resolution. The --privileged and the cgroup mount enable the systemd. The shared kernel limits the kernel-level testing .
  • The hybrid is the best. The containers for the daily command-line drills. The VMs for the service integration. The cloud for the multi-system. The LFCE Vagrant for the exam simulation .
  • The snapshot is the reset. The vagrant snapshot save before the destructive experiments. The vagrant snapshot restore to revert. The clean state is the fast recovery .
  • The LFCS practice tool is the supplement. The lfcs-practice-tool builds the Docker images automatically and provides the 83+ scenarios with the validation. The networking and the storage overlap with the LFCE .

Remember: The VM is the complete. The container is the fast. The hybrid is the strategy. The Vagrant is the declarative. The snapshot is the reset. The exam tests the services and the kernel, and the VM is the environment for the testing.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!