LPIC-3 Virtualization and Containerization common mistakes
LPIC-3 Virtualization and Containerization · Understand the traps and how to avoid them.
Runs plain `virsh net-list`, sees no networks, and spends the rest of the lab debugging DHCP inside the guest instead of on the host.
virsh net-list hides inactive networks. A fresh libvirt install defines the default NAT network but does not always start it or mark it autostart, so after a reboot every guest comes up with an interface but no lease and no route.
What to do instead
Check virsh net-list --all, then virsh net-start default and virsh net-autostart default. Confirm the bridge exists with ip a show virbr0 and inspect the definition with virsh net-dumpxml default. Do the same check for storage pools: a pool that is defined but not started makes virsh vol-create fail with 'pool not found'.
Grows a guest disk with `qemu-img resize disk.qcow2 +20G` and then reports that the space never appeared inside the VM.
qemu-img resize only changes the size of the virtual block device. The partition table and the filesystem inside the image are untouched, so the guest still shows the old capacity and the extra space sits unallocated at the end of the disk.
What to do instead
After resizing the image (with the domain shut down, or use virsh blockresize on a running domain with the correct device path), enter the guest and grow the partition (growpart /dev/vda 1) and then the filesystem (resize2fs for ext4, xfs_growfs for XFS). Never shrink a qcow2 image with internal snapshots; shrinking requires filesystem shrink first plus a fresh qemu-img convert.
Types `xm list`, `xm create` and `xm console` on a Xen 4.x host, or edits `/etc/xen/` configs assuming the old toolstack still applies.
Older study material and blog posts predate the removal of the xend/xm toolstack. Modern Xen uses the libxl toolstack, and the xm command is either absent or a compatibility shim that misbehaves, so candidates conclude Xen is broken rather than that the command is wrong.
What to do instead
Use xl: xl info, xl list, xl create -c /etc/xen/vm.cfg for a config-file domain and xl console <name>. Remember that hosts managed through libvirt are driven with virsh -c xen:/// instead, and do not mix the two toolstacks on the same domain.
Deploys rootless Podman containers as a normal user, sees them running, logs out, and later finds them gone.
Rootless containers live inside the user's systemd session. Without lingering enabled, systemd terminates the user manager at logout and everything in the cgroup tree dies; the container was never a service in the first place.
What to do instead
Enable loginctl enable-linger <user> (verify with loginctl show-user <user> -p Linger). Manage the workload as a systemd user unit - a Quadlet .container file under ~/.config/containers/systemd/ with [Install] WantedBy=default.target, followed by systemctl --user daemon-reload and systemctl --user start.
Bind-mounts a host directory into a container on an SELinux-enforcing distribution and gets 'Permission denied' on read or write, then disables SELinux to move on.
Host files carry a type such as user_home_t; the container process runs as container_t, so the mandatory access control check denies the access even though the Unix permissions are correct. Nothing in ls -l shows the cause.
What to do instead
Relabel the mount with :Z (private, unshared label) or :z (shared between containers) in the -v/--volume option, or set a persistent label with semanage fcontext -a -t container_file_t plus restorecon. Confirm the diagnosis with ausearch -m avc -ts recent rather than turning SELinux off.
Starts two containers with `docker run`/`podman run` on the default bridge and expects them to reach each other by container name, falling back to `--link` when the name does not resolve.
The default bridge provides no embedded DNS; only user-defined networks do. Names, aliases and automatic isolation are properties of user-defined networks, and --link is legacy and does not work in the direction people expect.
What to do instead
Create a user-defined network (docker network create appnet or podman network create appnet), attach both containers with --network appnet, and resolve by container name or --network-alias. Verify with docker network inspect and a test from inside a container such as getent hosts <name>.
Runs `kubeadm init` without `--pod-network-cidr`, applies a CNI manifest anyway, and then treats the Pending CoreDNS pods and NotReady node as a kubelet fault.
Most CNI plugins (Calico, Flannel, Weave) expect a pod CIDR and refuse or fail to program routes if the cluster's pod network overlaps the manifest default or was never set. With no working CNI, the node never becomes Ready and cluster DNS cannot schedule.
What to do instead
Pass --pod-network-cidr matching the plugin's manifest (for example 10.244.0.0/16 for Flannel), apply the CNI manifest as the same user that ran init, and verify with kubectl get nodes, kubectl get pods -n kube-system and journalctl -u kubelet. Check the CNI config files present under /etc/cni/net.d/ before blaming kubelet.
Creates a PersistentVolumeClaim, sees it stay Pending, and starts recreating the pod instead of the claim.
A PVC binds only when a PV or a dynamic provisioner satisfies its storageClassName, accessModes and requested size. Common causes are a typo in storageClassName, no default StorageClass being marked, requesting ReadWriteMany on a block-backed class that only supports ReadWriteOnce, or a pre-provisioned PV smaller than the request.
What to do instead
Run kubectl get sc and kubectl describe pvc <name> to read the provisioning events. Mark a default class with the annotation storageclass.kubernetes.io/is-default-class: "true", or leave storageClassName unset so the default applies. Match accessModes to the underlying driver and keep PV capacity at or above the request.
Applies a NetworkPolicy to isolate a namespace, tests once from a pod that was already running, and concludes the policy works.
NetworkPolicy is implemented by the CNI plugin, not by the API server. Flannel alone does not enforce policy at all, so the object is accepted and silently has no effect. Even on an enforcing CNI, a policy selects pods by label and must cover both directions to be useful.
What to do instead
Confirm the plugin enforces policy (Calico, Cilium, Antrea do; plain Flannel does not). Start from a default-deny policy in both Ingress and Egress for the namespace, then add narrow allow rules, and test by creating a fresh pod and attempting the connection rather than reusing a running one.
Comes back to a cluster after a break, finds `kubeadm join` rejected or the API server refusing connections, and rebuilds the control plane instead of renewing credentials.
kubeadm bootstrap tokens expire after 24 hours by default and the client/server certificates issued at init expire after one year. Neither condition produces an error at init time, so the failure surfaces much later and looks like a broken cluster.
What to do instead
Regenerate a join command with kubeadm token create --print-join-command and list tokens with kubeadm token list. Renew control-plane credentials with kubeadm certs check-expiration and kubeadm certs renew all, then restart the static control-plane pods. During upgrades, renew certificates before and after each kubeadm upgrade apply.