First, create a container mycontainer
with the command lxc launch ubuntu: mycontainer
. This command creates a container with the currently default LTS version (at the time of writing, 18.04, soon it will be 20.04).
You are using LXD, you can launch containers and get a shell into them using the following lxc
command. This command uses the exec subcommand to run a process in the container mycontainer, and the full line of the process is whatever appears after the —, in this case, /bin/bash
. The /bin/bash
can be replaced with any executable from the container.
lxc exec mycontainer -- /bin/bash
The --
is a special sequence that tells parameter parser on the host to stop processing parameters. In the above example it is not required because we do not use a parameter for /bin/bash
. However, in the following, it is needed. The lxc
command sees in the first line that there is a -l
option, and tries to process it. But there is no valid -l
parameter to lxc exec
, hence the error message. The following also demonstrate that the default working directory for the Ubuntu container images is root
‘s home directory, /root
.
$ lxc exec mycontainer ls -l Error: unknown shorthand flag: 'l' in -l $ lxc exec mycontainer -- ls -l total 0 $ lxc exec mycontainer -- pwd /root $
The corollary is that if you do not get into the habit of adding --
, you might run a complex command that has a valid lxc exec
parameter and the result could be quite weird. However, in most cases, you would want to get just a shell into the container, and then do your work. That is the purpose of this blog post.
Learning about LXD aliases
Managing aliases in LXD
You can list, add, rename and remove LXD aliases.
Listing LXD aliases
Run the lxc alias list
command to list all aliases. In the following, there are no aliases at all (default).
$ lxc alias list
+-------+--------+
| ALIAS | TARGET |
+-------+--------+
Adding a LXD alias
Let’s create an alias, called list
. There is already a lxc list
subcommand, therefore we will be hiding the official subcommand. But why do this? First, lxc list
produces by default a very wide table so we are going to drop some of the columns. Second, we want to show here how to remove an alias, so we will remove the list
alias anyway.
$ lxc alias add list 'list -c ns46'
$ lxc alias list
+-------+---------------+
| ALIAS | TARGET |
+-------+---------------+
| list | list -c ns46 |
+-------+---------------+
Now, when you run lxc list
, you will get just four columns, n for the Name of the container, s for the State of the container (RUNNING, _STOPPED or something else), and 46 for both the IPv4 and IPv6 IP addresses of the container.
Renaming a LXD alias
Frankly, list
is not a good choice for the name of an alias because it masks (hides) the proper lxc list
subcommand. Let’s rename the alias to something else.
$ lxc alias rename list ll
$ lxc alias list
+-------+---------------+
| ALIAS | TARGET |
+-------+---------------+
| ll | list -c ns46 |
+-------+---------------+
Now you can run the following command to list the containers in a table of four only columns.
$ lxc ll
Removing a LXD alias
We have now decided to remove the ll
alias. If you love it though, you may keep it! Here is the command anyway.
$ lxc alias remove ll
Using sudo --login ubuntu --shell
To get a non-root shell into a LXD container of an Ubuntu container image (ubuntu:
), you can use the following command. The ubuntu:
container images, when launched, create a non-root ubuntu
account. Therefore, when we exec
into the container, we sudo
as user ubuntu
and request a login shell. A login shell means that all shell configuration files are parsed (/etc/profile
, /etc/bash*
, ~/.profile
, etc). Due to this, it might take a few hundreds milliseconds to get to the shell, compared to other ways. This command is also the command that I have been including in my tutorials (since 2016), therefore you can see it a lot around the Internet.
$ lxc exec mycontainer -- sudo --user ubuntu --login To run a command as administrator (user "root"), use "sudo <command>".See "man sudo_root" for details. $
If you were to launch a container and immediately run the above command to get a shell, you may encounter the following error (unknown user: ubuntu). What happened? We were really fast, and the mycontainer
container did not fully finish starting up. Which means that the instruction to create the ubuntu
non-root account did not run yet. In fact, the instruction to create this account is among that last instructions to run when a new container is created. In such a case, just wait for one more second, and run the lxc exec
command again.
$ lxc launch ubuntu: mycontainer Creating mycontainerStarting mycontainer $ lxc exec mycontainer -- sudo --user ubuntu --login sudo: unknown user: ubuntu sudo: unable to initialize policy plugin $
The downside with this lxc exec
command is that it assumes there is an ubuntu
non-root account, which only works for the ubuntu:
repository of container images. It does not work with the Ubuntu container images from the images:
repository, nor with other container images. Those other container images only have a default root
account.
Using lxc shell mycontainer
The lxc
client of LXD currently has a single default alias for lxc shell
. This alias is not listed when you run lxc alias list
since it is part of the client. Here is the source code,
// defaultAliases contains LXC's built-in command line aliases. The built-in // aliases are checked only if no user-defined alias was found. var defaultAliases = map[string]string{ "shell": "exec @ARGS@ -- su -l", }
You would run this as follows. It runs su -l
to get a login shell as root.
$ lxc shell mycontainer mesg: ttyname failed: No such device root@mycontainer:~#
Let’s add an alias that will su
as a non-root user. We will name it shell
, therefore masking the built-in alias.
$ lxc alias add shell "exec @ARGS@ -- su -l ubuntu" $ lxc shell mycontainer To run a command as administrator (user "root"), use "sudo <command>". See "man sudo_root" for details. $
Using lxc ubuntu mycontainer
In 2018, Raymond E Ferguson started a thread on discuss.linuxcontainers.org about useful LXC aliases, and specifically about LXC aliases to get a login shell into a LXD container.
To get a non-root shell to a LXD container (Ubuntu container from ubuntu: repository)
Create the following alias, named ubuntu. You run this once to add the LXD alias to your host’s settings.
lxc alias add ubuntu 'exec @ARGS@ --mode interactive -- /bin/sh -xac $@ubuntu - exec /bin/login -p -f '
Use as:
lxc ubuntu mycontainer
To get a shell to a LXD container (default: root, else specify with $USER)
Create the following alias, named ubuntu. You run this once to add the LXD alias to your host’s settings.
lxc alias add login 'exec @ARGS@ --mode interactive -- /bin/sh -xac $@${USER:-root} - exec /bin/login -p -f '
Run as (to get a root shell by default):
lxc login mycontainer
Run as (to get a specific $USER shell):
lxc login mycontainer --env USER=ubuntu
Learning more about lxc exec
The current version of the LXD lxc
client (now at 3.21) has several built-in features that can help get a shell. Let’s see the available parameters. Of interest are --user
/--group
and --env
to set $HOME
.
$ lxc exec --help Description: Execute commands in instances The command is executed directly using exec, so there is no shell and shell patterns (variables, file redirects, ...) won't be understood. If you need a shell environment you need to execute the shell executable, passing the shell commands as arguments, for example: lxc exec-- sh -c "cd /tmp && pwd" Mode defaults to non-interactive, interactive mode is selected if both stdin AND stdout are terminals (stderr is ignored). Usage: lxc exec [ :] [flags] [--] Flags: --cwd Directory to run the command in (default /root) -n, --disable-stdin Disable stdin (reads from /dev/null) --env Environment variable to set (e.g. HOME=/home/foo) -t, --force-interactive Force pseudo-terminal allocation -T, --force-noninteractive Disable pseudo-terminal allocation --group Group ID to run the command as (default 0) --mode Override the terminal mode (auto, interactive or non-interactive) (default "auto") --user User ID to run the command as (default 0) Global Flags: --debug Show all debug messages --force-local Force using the local unix socket -h, --help Print help --project string Override the source project -q, --quiet Don't show progress information -v, --verbose Show all information messages --version Print version number
In addition, bash
has a --login
parameter which we are going to use as well. Therefore, we have the following command for a login shell. The ubuntu:
container images create a non-root account with username ubuntu
and UID/GID 1000/1000. We set the $HOME because even with bash --login
it is not set. We do not specify the full path for bash
just in case it is in either /bin
or /usr/bin
. In Ubuntu it is /bin/bash
, so it will work in Ubuntu and provide flexibility if we were to extend to other distributions.
$ lxc exec --user 1000 --group 1000 --env "HOME=/home/ubuntu/" mycontainer -- bash --login You just parsed /etc/bash.bashrc! You just parsed /etc/profile.d/apps-bin-path.sh! You just parsed /etc/profile! You just parsed ~/.bashrc! You just parsed ~/.profile! ubuntu@mycontainer:~$
Notice above that I edited the various configuration files so that they print the sequence they are invoked for a login shell. Let’s see how this looks when we do not add --login
to bash
. Without a login shell, the only two files that are parsed are /etc/bash.bashrc
and ~/.bashrc
.
$ lxc exec mycontainer --user 1000 --group 1000 --env HOME=/home/ubuntu/ -- bash You just parsed /etc/bash.bashrc! You just parsed ~/.bashrc! ubuntu@mycontainer:/home/ubuntu$
We are good to go and create the alias. I am changing my old lxc ubuntu
alias to this one. Here it is. We remove any old ubuntu
alias and add the new one.
lxc alias remove ubuntu lxc alias add ubuntu 'exec @ARGS@ --user 1000 --group 1000 --env HOME=/home/ubuntu/ -- /bin/bash --login'

lxc ubuntu
alias. It works on Ubuntu container images from the ubuntu:
repository. Creates a login shell using Bash for the ubuntu
non-root user. Summary
There are several ways to execute a login shell into a LXD container. For the Ubuntu containers (repository ubuntu:
) I am using the following alias, lxc ubuntu mycontainer
. ubuntu is the new subcommand (through an LXD alias) to get a login shell as user ubuntu
.
If you want to get the same, run the following on each of your LXD hosts.
lxc alias add ubuntu 'exec @ARGS@ --user 1000 --group 1000 --env HOME=/home/ubuntu/ -- /bin/bash --login'
If your container is called mycontainer, you get a login shell as follows:
lxc ubuntu mycontainer
6 comments
3 pings
Skip to comment form
One advantage of overriding the ‘shell’ alias instead of using ‘ubuntu’ is that Bash completion keeps working with ‘shell’ (both for filling the command name and the names of the container)
Author
Indeed, that’s an issue. Using the snap package of LXD, it is not possible to edit
/etc/bash_completion.d/lxc
with the completion rules because this is a link into the read-only LXD image.What you can do instead, is take a copy of this file, then remove the link and place the actual file in place. By doing so, you can edit it and add new commands. To add
ubuntu
(as inlxc ubuntu mycontainer
), search for shell in the completion file and add ubuntu in the list.Nice Article! BTW, is there any way to login into non ubuntu containers are regular user?
Also, do you work on development on LXC/D?
Hi Simon;
If ı create any alias in container’s .bashrc than I cant call this.
For example:
I added alias netp=’clear; netstat -pulten’ to .bashrc in container and source .bashrc.
When I call ‘lxc exec u18base — bash -c “netp”‘, I take this error “bash: netp: command not found”
If I call “lxc exec u18base — netp” than there is no error/warning on terminal.
Have you any experience?
Author
Hi!
When you run a command in a container like
lxc exec u18base - netp
, and you do not get any output, then it is highly likely that the command could not be found and did not run any. You do not get anystderr
fromlxc exec
commands, just stdout.When you run
lxc exec
, it does not load up the user’s shell environment, therefore the aliasnetp
is not found.On top of that,
alias
-es are not processed during non-interactive shells.I suggest to move from BASH aliases to BASH functions.
Thank you Simos. I follow you and all who work for LXC/LXD with great pleasure and excitement.
[…] We can now create a container that uses the nonetwork profile. When we run lxc launch, we specify the nonetwork profile, and use the default ubuntu container image (ubuntu:) which is currently Ubuntu 18.04 LTS. In a few months this will switch to Ubuntu 20.04 LTS. We are happy with any LTS container image. If you wanted to specify specifically Ubuntu 18.04 LTS, replace ubuntu: with ubuntu:18.04. Finally, we give the name withoutnetworking. Once the container is created, we lxc list it to verify there is no IP address and finally we get a shell into it with lxc ubuntu containername. […]
[…] install the official client in a LXD container. Create a container and get a shell into it. Then, download the Deb package and install it. The initial Deb package is really small. It just […]
[…] 8. Using command aliases in LXD to exec a shell – Mi blog lah! […]