I finally found a solution - there are two parts to it.
I was doing this, which is incorrect:
1) bitbake -c menuconfig virtual/kernel <=== at this point, I navigate to and enable the NVME device driver option
2) bitbake -c compile -f virtual/kernel
3) bitbake virtual/kernel <=== this step builds the kernel but destroys the .config file created in step 1).
I didn't realise step 3) destroyed the .config file created by step 1) in the tmp/ directory. Thus, when I subsequently did
bitbake fsl-image-kernelitb
a default .config file was used which didn't have my NVMe modifications. I'm still not sure where the default .config file comes from, and how to change it so that NVMe is enabled by default.
The correct procedure is:
1) bitbake -c menuconfig virtual/kernel <=== at this point, I navigate to and enable the NVME device driver option
2) bitbake fsl-image-kernelitb
Step 1) creates a .config file with the NVME device driver option enabled, and step 2) creates the kernel image with NVMe enabled. The .config file created by step 1) in tmp/ is destroyed. A closer inspection of fsl-image-kernelitb.bb shows a line
do_deply[depends] += "u-boot-mkimage-native:do_build virtual/kernel:do_build ${ROOTFS_IMAGE}:do_build"
Note the bold-font command above - this is the command that actually builds the kernel which is inserted into the .itb file that I load onto the board.
However, this didn't solve the problem of why there was no /lib/modules directory in my new .itb image. To fix this, you have to insert the following line into the the .bb file of the rootfs image to be built into the .itb file. In my case, I am using fsl-image-minimal.bb:
IMAGE_INSTALL_append += " kernel_modules"
When I build the .itb and load it onto the LS2080A RDB, I can now see the full /lib/modules directory, and as a result modprobe works as expected.