Hi!
Most likely your script is too fast for LXD and the second command (lxc exec
) is running while the container has not been fully launched.
Specifically, when you lxc launch
a new container, the container is initialized and is booted up. As soon as it is booted up, lxc launch
returns back to your shell. But it takes a couple of seconds for the container to actually complete the booting process so that it becomes fully usable. It makes sense of LXD to work that way, because as soon as the container is starting to boot up, it is independent from LXD; it stands on its own. I think it would not fit for LXD to include a feature to wait until the container’s init
has completed.
For example, the Ubuntu containers automatically create a non-root ubuntu
account. This is created using the cloud-init
feature, and typically the account is created towards the end of the booting process. If you launch a container and very quickly start a shell as ubuntu
in this container, you may see an error that there is no ubuntu
user. This user account was just not created just yet.
Back to your script now. You need some recipe that would wait until the container is fully booted before you start using it.
One option is to run sleep 5
to wait for five seconds. Very easy, least effort, but may not work all the time.
The elegant option is to lxc exec
the following command systemctl is-system-running --wait
in the container. This will wait until the init (systemd
) has completed booting up. Unfortunately, the --wait
is only available in much recent systemd
(does not work with Ubuntu 16.04 or Ubuntu 18.04, should work with Ubuntu 19.04 or newer).
In the LTS versions of Ubuntu, you can write a script to wait until the system is running, simply by polling the output of systemctl is-system-running
.
Here is a sample script,
lxc launch ubuntu:18.04 u18
sleep 1 # Give a chance for systemd to start running.
lxc exec u18 systemctl is-system-running
lxc exec u18 -- bash -c 'while [ "$(systemctl is-system-running)" != "running" ]&& [ "$(systemctl is-system-running)" != "degraded" ]; do sleep 1; done'
lxc exec u18 systemctl is-system-running
lxc exec u18 -- sudo snap install hello
The container has finished booting up when it gets into the running state. Or degraded, which happens when some service has failed. In the containers there are some services that fail in any case because they cannot work yet in a container yet, so you are stuck with degraded
.
Here is some sample output.
$ bash myscript
Creating u18
Starting u18
initializing
degraded
2019-08-07T10:25:49Z INFO Waiting for restart...
hello 2.10 from Canonical✓ installed