Operating Systems Azure

CentOS 7 LVM on Azure User Guide

| Product: CentOS 7 LVM on Azure

Overview

This guide covers the deployment and configuration of CentOS 7 LVM on Microsoft Azure using cloudimg's pre configured virtual machine image from the Azure Marketplace.

CentOS Linux is a community rebuild of Red Hat Enterprise Linux, binary compatible with RHEL 7. This image is the LVM variant: the root filesystem lives on a Logical Volume Manager logical volume rather than on a plain disk partition, so you can grow root online, pool extra disks under it and take snapshots without repartitioning or downtime. Everything else matches the standard CentOS 7 image, which ships a plain single partition root.

The image is provided deliberately for legacy migration workloads: teams moving software that is still certified only on the CentOS 7 or RHEL 7 platform, and who need a clean, hardened CentOS 7.9 base with flexible storage while they re platform.

End-of-life notice — read this first

CentOS Linux 7 reached end-of-life on 30 June 2024. The upstream CentOS Project no longer produces any updates for it, including security updates. Consequently:

  • This image is patched only to its capture date, from the frozen CentOS 7.9.2009 vault (vault.centos.org). No newer CentOS 7 packages exist upstream, so "fully patched" means patched to the last packages the vault ever published.
  • After the end-of-life date, no further upstream security updates are published. Over time the image will carry unpatched vulnerabilities that cannot be remediated by updating CentOS 7, because upstream ships nothing further.
  • This image is provided for legacy migration use — running or testing software that is only certified on the CentOS 7 or RHEL 7 platform while you migrate. Plan a migration to a supported distribution such as AlmaLinux, Rocky Linux, CentOS Stream, or a current RHEL for any workload that must remain secure.

The stock CentOS 7 repositories point at mirror.centos.org, which was retired at end-of-life. This image has already repointed every repository to the CentOS 7.9.2009 vault, so yum keeps working — against the frozen, final package set — out of the box.

What's included

  • CentOS Linux 7.9.2009 (Core), binary compatible with RHEL 7
  • An LVM partitioned root: volume group centos, logical volume root, formatted xfs, on physical volume /dev/sda2
  • A plain /boot partition on /dev/sda1, which is what grub2 needs to reach the kernel before LVM comes up
  • Every available 7.9.2009 vault package applied at build time (patched to capture date)
  • Repositories repointed to vault.centos.org/7.9.2009 so yum keeps working post end-of-life
  • Azure Linux Agent (WALinuxAgent) and cloud-init, so the machine provisions cleanly on Azure
  • The Hyper V storage and network drivers built into the initramfs, so the machine boots on Azure hardware
  • LVM and growth tooling preinstalled: lvextend, vgextend, pvresize, growpart, xfs_growfs
  • Chronyd for NTP time synchronisation
  • SELinux in enforcing mode
  • firewalld running with only the SSH service allowed
  • No rpcbind: the port 111 RPC listener a stock CentOS 7 carries is absent, and masked so it cannot return unnoticed
  • Exactly one kernel installed, so no stale kernel package lingers
  • Gen1 Hyper V virtual machine support (BIOS boot)
  • 24/7 cloudimg support

Platform: Microsoft Azure (Gen1 Hyper V, BIOS boot) Default user: azureuser

Security posture

This image ships with no known credential. There is no default password and no baked in SSH key:

  • The root account password is locked, so no one can log in as root with a password.
  • PasswordAuthentication is disabled in the SSH daemon, so every login is by key.
  • PermitRootLogin is set to no, so root cannot be reached over SSH at all.
  • The only key that works is the public key you supply when you create the virtual machine. Azure injects it into azureuser at first boot, so no two machines you launch ever share a secret.
  • The machine identity and the SSH host keys are regenerated uniquely on every instance, so no two machines share a host key either.
  • SELinux is left in enforcing mode, the CentOS default.
  • The only port listening off the machine is SSH on 22. rpcbind, which binds 0.0.0.0:111 on a stock CentOS 7 install, is not installed at all here, and its socket unit is masked as well so that installing nfs-utils later cannot silently reopen the port.

These are the controls cloudimg can guarantee. They do not change the end-of-life position above: a hardened CentOS 7 is still a CentOS 7 that receives no further upstream security updates.

Prerequisites

Before deploying this image, ensure you have:

  1. An active Microsoft Azure subscription
  2. Access to the Azure Portal or Azure CLI
  3. An SSH key pair for Linux VM access
  4. Familiarity with Azure VM management

Recommended VM Size: Standard_B2s (2 vCPU, 4 GB RAM) or larger.

OS disk sizing: the image is 10 GB, of which about 9 GB is the root logical volume. If you intend to grow root, ask Azure for a larger OS disk at create time — the extra space arrives unallocated and Step 5 shows you how to give it to root without downtime.

Step 1: Deploy the Virtual Machine

Option A: Azure Portal

  1. Navigate to the Azure Marketplace and search for "CentOS 7 LVM cloudimg"
  2. Select the image and click Create
  3. Configure the basics:
  4. Subscription: Select your Azure subscription
  5. Resource Group: Create new or select existing
  6. Virtual Machine Name: Enter a name for your VM
  7. Region: Select your preferred Azure region
  8. Size: Standard_B2s recommended
  9. Under Administrator Account, select SSH public key and enter your key
  10. Under Disks, set the OS disk size if you want more than the 10 GB the image ships with
  11. Under Inbound Port Rules, allow SSH (port 22)
  12. Click Review + Create, then Create

Option B: Azure CLI

az vm create \
  --resource-group myResourceGroup \
  --name my-centos-7-lvm-vm \
  --image cloudimg:centos:centos7lvm:latest \
  --size Standard_B2s \
  --os-disk-size-gb 32 \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Step 2: Connect via SSH

Run these on your own workstation, not on the VM. Find the public IP, then connect:

az vm show --resource-group myResourceGroup --name my-centos-7-lvm-vm --show-details --query publicIps -o tsv
ssh azureuser@<vm-ip>

There is no password to enter. If SSH asks you for one, the key you supplied at create time is not the key your client is offering.

Step 3: Confirm the release

Check that the machine is the CentOS 7.9.2009 release you expect:

cat /etc/centos-release
grep -E '^(NAME|VERSION|ID|VERSION_ID)=' /etc/os-release
uname -rm

Expected output:

CentOS Linux release 7.9.2009 (Core)
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
VERSION_ID="7"
3.10.0-1160.119.1.el7.x86_64 x86_64

3.10.0-1160.119.1.el7 is the last kernel CentOS 7 ever shipped. Seeing it here is the marker that the machine is at the end of the 7.9.2009 vault, not part way through it.

Terminal showing cat of etc centos-release reporting CentOS Linux release 7.9.2009 Core, os-release fields ID centos and VERSION_ID 7, and uname reporting the final 3.10.0-1160.119.1.el7 kernel on x86_64

Step 4: Verify the LVM root layout

This is the defining feature of this image, and the reason to choose it over the standard CentOS 7 listing. The root filesystem is a logical volume, not a plain partition.

First, the block layout:

lsblk -o NAME,TYPE,MOUNTPOINT,SIZE,FSTYPE

Expected output on a machine launched with the default 10 GB OS disk:

NAME            TYPE MOUNTPOINT  SIZE FSTYPE
sda             disk              10G
├─sda1          part /boot         1G xfs
└─sda2          part               9G LVM2_member
  └─centos-root lvm  /             9G xfs
sdb             disk               8G
└─sdb1          part /mnt          8G ext4

The lvm in the TYPE column against / is the proof that this is the LVM variant. /dev/sda2 is flagged LVM2_member, not a filesystem — it is the physical volume. sdb is the Azure temporary resource disk, which every Azure VM gets and which is not part of the volume group.

Now confirm the LVM objects themselves:

findmnt /
sudo vgs
sudo lvs
sudo pvs

Expected output:

TARGET SOURCE                  FSTYPE OPTIONS
/      /dev/mapper/centos-root xfs    rw,relatime,seclabel,attr2,inode64,noquota

  VG     #PV #LV #SN Attr   VSize  VFree
  centos   1   1   0 wz--n- <9.00g    0

  LV   VG     Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  root centos -wi-ao---- <9.00g

  PV         VG     Fmt  Attr PSize  PFree
  /dev/sda2  centos lvm2 a--  <9.00g    0

Root is /dev/mapper/centos-root: logical volume root inside volume group centos, on physical volume /dev/sda2. /boot deliberately stays a plain xfs partition, because grub2 on CentOS 7 reads the kernel and initramfs from it before LVM is available.

Terminal showing lsblk with root on the LVM logical volume centos-root over the LVM2_member partition sda2, findmnt confirming root is dev mapper centos-root xfs, and vgs lvs pvs showing the centos volume group, root logical volume and the dev sda2 physical volume

Step 5: Grow the root filesystem online

This is what the LVM layout buys you: root grows while the machine is running, with no repartitioning, no reboot and no downtime.

Give the VM a larger OS disk first. If you did not size it up at create time, stop the VM, raise the OS disk size in the Azure Portal (or with az disk update --size-gb), and start it again. The new space arrives as unallocated room at the end of /dev/sda.

Then grow the partition, the physical volume, the logical volume and the filesystem, in that order:

sudo growpart /dev/sda 2
sudo pvresize /dev/sda2
sudo lvextend -l +100%FREE /dev/centos/root
sudo xfs_growfs /
df -h /

Expected output, growing a 9 GB root onto a 32 GB OS disk:

CHANGED: partition=2 start=2099200 old: size=18872320 end=20971520 new: size=65009631 end=67108831
  Physical volume "/dev/sda2" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
  Size of logical volume centos/root changed from <9.00 GiB (2303 extents) to <31.00 GiB (7935 extents).
  Logical volume centos/root successfully resized.
data blocks changed from 2358272 to 8125440
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root   31G  1.5G   30G   5% /

The filesystem went from 9 GB to 31 GB while it was mounted and serving. Nothing was unmounted and the machine was never rebooted.

If the partition already fills the disk, growpart reports NOCHANGE and exits non zero — that is the expected answer, and it means there is no unallocated space to claim. Raise the OS disk size first.

Adding a second disk to the volume group

The other reason to run an LVM root is that you can pool a brand new disk under the existing filesystem instead of mounting it somewhere else. Attach a data disk to the VM in Azure, find its device name, then:

sudo pvcreate /dev/sdc
sudo vgextend centos /dev/sdc
sudo lvextend -l +100%FREE /dev/centos/root
sudo xfs_growfs /

Root now spans both disks. On a plain partition layout — which is what the standard CentOS 7 image ships — neither of these operations is possible without rebuilding the machine.

Step 6: The vault update path (end-of-life)

Because CentOS 7 is end-of-life, its original mirrors are gone. This image repoints every repository to the CentOS 7.9.2009 vault, so yum keeps working against the frozen final package set:

yum repolist enabled
grep '^baseurl' /etc/yum.repos.d/CentOS-Base.repo
sudo yum check-update; echo "check-update exit: $?"

Expected output (repositories point at vault.centos.org, and check-update exits 0 because the image is already patched to the last vault packages):

repo id                    repo name                                      status
base/x86_64                CentOS-7.9.2009 - Base (vault)                 10,072
extras/x86_64              CentOS-7.9.2009 - Extras (vault)                  526
updates/x86_64             CentOS-7.9.2009 - Updates (vault)               6,173
repolist: 16,771
baseurl=https://vault.centos.org/7.9.2009/os/$basearch/
baseurl=https://vault.centos.org/7.9.2009/updates/$basearch/
baseurl=https://vault.centos.org/7.9.2009/extras/$basearch/
baseurl=https://vault.centos.org/7.9.2009/centosplus/$basearch/
check-update exit: 0

check-update returning 0 means no newer packages exist in the vault — the image is patched to the end of the CentOS 7 lifecycle. No further security updates will ever be published upstream. There is no unattended update timer armed on this image, because there is nothing left for it to fetch. For anything beyond legacy migration, move to a supported distribution.

Terminal showing yum repolist with the base updates and extras repositories repointed to the CentOS 7.9.2009 vault, the CentOS-Base.repo baseurls at vault.centos.org, and yum check-update exiting 0 meaning patched to the final vault packages

Step 7: Verify the security posture

Confirm SELinux is enforcing, root is locked, SSH is key only, and nothing but SSH is listening off the machine:

sudo getenforce
sudo passwd -S root
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication)'
sudo ss -tlnp

Expected output:

Enforcing
root LK 2009-12-22 -1 -1 -1 -1 (Alternate authentication scheme in use.)
permitrootlogin no
pubkeyauthentication yes
passwordauthentication no
State      Recv-Q Send-Q Local Address:Port    Peer Address:Port
LISTEN     0      128          *:22                 *:*      users:(("sshd",pid=1552,fd=3))
LISTEN     0      100    127.0.0.1:25                 *:*      users:(("master",pid=1419,fd=13))
LISTEN     0      128       [::]:22              [::]:*      users:(("sshd",pid=1552,fd=4))
LISTEN     0      100      [::1]:25              [::]:*      users:(("master",pid=1419,fd=14))

LK is the field that matters: the root password is locked. On a machine Azure has provisioned, passwd -S adds "Alternate authentication scheme in use", because cloud-init has placed your public key in /root/.ssh/authorized_keys behind a command="..." restriction that only ever prints "Please login as the user azureuser rather than the user root". That entry is your own key, not a cloudimg one, and PermitRootLogin no refuses the connection before it is ever consulted — an ssh root@<vm-ip> attempt returns Permission denied (publickey).

Read the Local Address column, not the peer column. The only address reachable from off the machine is *:22. Postfix on port 25 is bound to loopback only (127.0.0.1 and [::1]), so it is not exposed.

rpcbind — which binds 0.0.0.0:111 on a stock CentOS 7 — is not installed on this image at all, and its socket unit is masked in addition, so that a later yum install nfs-utils cannot bring the port back without you noticing. Confirm both facts for yourself:

rpm -q rpcbind nfs-utils || echo "neither package is installed"
sudo systemctl is-enabled rpcbind.socket 2>&1 || true

Terminal showing getenforce reporting Enforcing, passwd -S root reporting root as LK meaning password locked, the effective sshd policy reporting permitrootlogin no pubkeyauthentication yes and passwordauthentication no, and ss -tlnp showing SSH on port 22 as the only listener reachable off the machine

Step 8: Verify Azure integration

Confirm the Azure Linux Agent, cloud-init and time synchronisation are healthy, and check your resources:

systemctl is-active waagent
systemctl is-enabled waagent
cloud-init --version
systemctl is-active chronyd
free -h

Expected output:

active
enabled
/usr/bin/cloud-init 19.4
active
              total        used        free      shared  buff/cache   available
Mem:           3.9G        216M        3.2G         16M        434M        3.4G
Swap:            0B          0B          0B

waagent is what lets Azure provision your SSH key, resize the OS disk, run extensions and report VM health, so it should always be active and enabled. On CentOS 7 it is the python2 build of the agent, WALinuxAgent 2.2.46 — that is the correct version for this platform, not a stale one.

Swap: 0B is deliberate. Azure manages swap on the temporary resource disk through waagent, and no swap file or swap partition ships inside the image.

Step 9: Networking and the firewall

The Azure Network Security Group is the control plane for inbound and outbound traffic, and it is the first and usually the only place you need to open a port. The image advertises a single inbound port, SSH on 22.

A host firewall runs as well. firewalld is active with only the SSH service allowed:

sudo firewall-cmd --state
sudo firewall-cmd --list-services

Expected output:

running
dhcpv6-client ssh

To open another service, add it and reload:

sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

If you need NFSv3, install the NFS tooling and unmask the RPC helper. Both steps are required: the packages are absent, and the socket unit is masked so it cannot start on its own even once they are installed.

sudo yum install -y nfs-utils
sudo systemctl unmask rpcbind.socket
sudo systemctl enable --now rpcbind.socket

Opening port 111 to the network also needs a firewalld service and an NSG rule. NFSv4 does not use rpcbind at all, so most NFS deployments never need this.

Step 10: Install software

The base, updates and extras repositories are enabled and pointed at the vault. Search and install as normal, remembering that nothing newer than 7.9.2009 exists:

yum search httpd
sudo yum install -y httpd
sudo systemctl enable --now httpd

Only what CentOS 7 itself shipped is available. Popular packages that live in EPEL rather than the base distribution — nginx is the usual surprise — are not in these repositories and yum install nginx will report no match. Anything newer than 2020, or EPEL-only, has to come from a third party repository (EPEL's own CentOS 7 archive, a vendor repository, or a source build), because the CentOS 7 repositories are frozen.

To add another administrator, create the account with sudo adduser <name>, add it to the wheel group with sudo usermod -aG wheel <name>, then copy your public key into /home/<name>/.ssh/authorized_keys with mode 600 and the .ssh directory mode 700, owned by that user.

Common Use Cases

  • Lift and shift of an existing CentOS 7 estate into Azure where the source machines already use an LVM root, so the storage layout matches
  • Running or testing software certified only on the CentOS 7 or RHEL 7 platform while you re platform
  • Workloads whose data grows over the life of the machine and need root extended online rather than rebuilt
  • Estates that add data disks over time and want them pooled under one filesystem
  • Compatibility and RPM validation work against the RHEL 7 ABI

Troubleshooting

Cannot connect via SSH

  1. Verify the VM is in Running state in the Azure Portal
  2. Check that port 22 is allowed in the Network Security Group
  3. Ensure you are using the correct username: azureuser
  4. Verify your SSH key matches the one you supplied at create time. Password login is disabled by design, so a wrong key cannot fall back to a password prompt.

To see which key your client is actually offering, run ssh -v azureuser@<vm-ip> from your workstation and look for the Offering public key lines.

growpart says NOCHANGE

The partition already fills the disk, so there is nothing to claim. Stop the VM, raise the OS disk size in Azure, start it again, and re run Step 5. growpart exits non zero on NOCHANGE by design.

lvextend says "Insufficient free space"

The volume group has no free extents. Either the physical volume has not been resized yet — run sudo pvresize /dev/sda2 after growpart — or you need to add a disk to the group, as in Step 5.

Package manager cannot reach a mirror

CentOS 7's original mirrors were retired at end-of-life. This image already points at the vault, but if you add a third party .repo that still references mirror.centos.org you will see 404s. Repoint it to https://vault.centos.org/7.9.2009/... or remove it. Confirm nothing still references the retired mirrors:

grep -R mirror.centos.org /etc/yum.repos.d/ || echo "all repos already on the vault"

Azure agent not running

sudo systemctl status waagent
sudo systemctl enable --now waagent

A service is blocked and the logs mention SELinux

SELinux is enforcing on this image. Rather than disabling it, look at what was denied:

sudo ausearch -m AVC -ts recent 2>/dev/null || echo "no recent AVC denials"

Important Notes

CentOS Linux is free and open source. It is not covered by a single licence: it is a distribution assembled from thousands of independently packaged components, each carrying its own terms, including the GPL, LGPL, MIT, BSD, Apache 2.0 and MPL. Every package's terms are readable with rpm -qi <package> and under /usr/share/licenses/. No subscription, licence key or Red Hat entitlement is required. The LVM layout adds no further licence obligation: lvm2 is GPLv2 and ships in the base distribution.

CentOS Linux 7 reached end-of-life on 30 June 2024 and receives no further upstream security updates. This image is patched only to its capture date, from the frozen CentOS 7.9.2009 vault, and is provided for legacy migration use. Plan a migration to a supported distribution (AlmaLinux, Rocky Linux, CentOS Stream, or a current RHEL) for any workload that must remain secure.

CentOS is a trademark of Red Hat, Inc. The name is used here nominatively, only to identify the distribution this image contains. cloudimg is not affiliated with, endorsed by or sponsored by Red Hat or the CentOS Project.

Support

For assistance with this image, contact cloudimg support: