Search code examples
bashazureazure-virtual-machine

install docker bash script doesn't work when used as Custom Data for Azure VM


I use this script to install docker on my Azure VM, OS Debian Bullseye 11:

echo "** Updating package lists..."
sudo apt update

echo "** Installing dependencies..."
sudo apt install -y apt-transport-https ca-certificates curl gnupg software-properties-common

echo "** Adding Docker GPG key..."
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

echo "** Adding Docker repository..."
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian bullseye stable" 

echo "** Updating package lists again..."
sudo apt update

echo "** Installing Docker..."
sudo apt install -y docker-ce

echo "** Docker installation complete!"

If I run this script manually (1 line at a time) it works, however when I use it as Custom Data so it would execute on VM initialization, it gives errors, here's the var/logs/cloud-init-output.log:

    ** Updating package lists...

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
E: Could not get lock /var/lib/apt/lists/lock. It is held by process 700 (apt-get)
E: Unable to lock directory /var/lib/apt/lists/
** Installing dependencies...

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
Building dependency tree...
Reading state information...
Package gnupg is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'gnupg' has no installation candidate
E: Unable to locate package software-properties-common
** Adding Docker GPG key...
E: gnupg, gnupg2 and gnupg1 do not seem to be installed, but one of them is required for this operation
(23) Failed writing body
** Adding Docker repository...
sudo: add-apt-repository: command not found
** Updating package lists again...

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
E: Could not get lock /var/lib/apt/lists/lock. It is held by process 700 (apt-get)
E: Unable to lock directory /var/lib/apt/lists/
** Installing Docker...

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
Building dependency tree...
Reading state information...
E: Unable to locate package docker-ce
** Docker installation complete!

Solution

  • The first command in your script (sudo apt update) is failing because another instance of apt is running -- likely one spawned by the VM's native bootstrapping process -- and holding apt's internal lock file:

    E: Could not get lock /var/lib/apt/lists/lock. It is held by process 700 (apt-get)
    

    Try adding this at the top of your script to wait for the other apt to finish:

    #!/bin/sh
    
    timeout=600 # (10 minute timeout)
    i=0
    while sudo fuser /var/lib/apt/lists/lock > /dev/null 2>&1; do
       sleep 1
       (( i+=1 ))
       if [[ $i == $timeout ]]; then
         exit 1 # Exit with error if timeout value is reached
       fi
    done
    

    The while loop polls the lock file until it is no longer being held open by the other apt, sleeping for 1 second between attempts. If the timeout value is reached, the script exits with error.