Getting started with LXC and LXD

Hello friends, so this is the 2nd article of the collection Learn LXD and LXC the hard way!
In this article I will not mention how to install and configure both LXC and LXD, there is many articles talking about that, just duckduck it!
This article will show you the basic usage of LXC and LXD. So LXC is a container within a host machine as mentioned in the first article, it shares the same kernel as the host machine's kernel.
In order to create different operating system containers we will use templates which are scripts to bootstrap a specific area of the operating system.
LXC supports most of the distributions, so those templates are scripts dedicated to do the installation process, there is also a generic script called "download" that can install many different operating systems
with a common interface.
I recommend to use Ubuntu as it comes with a full support for LXC and LXD..

Alright, let's describe the lifecycle of LXC :
      Those who are familiar with Docker _as it is the most known engine of containers_ lxc-attach is the same as docker run.

Let's create for example a Debian Jessie container as an example using the generic "download" template that we talked briefly about it above.
First, we will do lxc-create to create the container with the given OS template and options provided.

$ sudo lxc-create -t download -n first-container

Setting up the GPG keyring
Downloading the image index


--- alpine 3.3 amd64 default 20171102_17:50
alpine 3.5 amd64 default 20171102_17:50
alpine 3.6 amd64 default 20171102_17:50
alpine 3.6 i386 default 20171102_17:50
alpine edge amd64 default 20171102_17:50
alpine edge armhf default 20170111_20:27
alpine edge i386 default 20171102_17:50
archlinux current amd64 default 20171103_01:27
archlinux current i386 default 20171103_01:27
centos 6 amd64 default 20171103_02:16
centos 6 i386 default 20171103_02:16
centos 7 amd64 default 20171103_02:16
debian buster amd64 default 20171101_23:10
debian buster arm64 default 20171103_05:45
debian buster armel default 20171101_23:10
debian buster i386 default 20171101_23:10
debian buster ppc64el default 20171103_05:45
debian buster s390x default 20171103_05:45
debian jessie amd64 default 20171101_23:10
debian jessie arm64 default 20171103_05:45
debian jessie armel default 20171101_12:57
debian jessie armhf default 20171101_23:10
debian jessie i386 default 20171101_23:10
debian jessie powerpc default 20171024_22:42
debian jessie ppc64el default 20171103_05:45
debian jessie s390x default 20171103_05:45
debian sid amd64 default 20171101_23:10
debian sid arm64 default 20171103_05:45
debian sid armel default 20171031_15:52
debian sid armhf default 20171026_22:42
debian sid i386 default 20171101_23:10
debian sid powerpc default 20171025_22:42
debian sid ppc64el default 20171103_05:45
debian sid s390x default 20171103_05:45
debian stretch arm64 default 20171103_05:45
debian stretch armel default 20171101_23:10
debian stretch powerpc default 20161104_22:42
Distribution: debian
Release: jessie
Architecture: amd64

Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs

You just created a Debian container (release=jessie, arch=amd64, variant=default)

To enable sshd, run: apt-get install openssh-server

For security reason, container images ship without user accounts
and without a root password.

Use lxc-attach or chroot directly into the rootfs to set a root password
or create user accounts.

\o/ We just finished creating our first container using LXC, and we named it first-container. As you can see it is Debian Jessie with AMD64 as architecture, you can notice too that there is no user
accounts nor root password set up in the container. As mentioned in the end of the output of the command lxc-create, you can use lxc-attach to start a sheel session to make the changes you like.
By default the lxc-create command creates the container in the directory /var/lib/lxc{container-name}. So our container already created will be in /var/lib/lxc/first-container.
If we take a look we will find it approximately like that.

$ sudo ls -alh /var/lib/lxc/first_container

total 16K
drwxrwx--- 3 root root 4.0K Nov 3 12:14 .
drwxr-xr-x 4 root root 4.0K Nov 3 12:12 ..
-rw-r--r-- 1 root root 698 Nov 3 12:14 config
drwxr-xr-x 22 root root 4.0K Nov 2 00:14 rootfs
$ sudo ls -alh /var/lib/lxc/first_container/rootfs

total 88K
drwxr-xr-x 22 root root 4.0K Nov 2 00:14 .
drwxrwx--- 3 root root 4.0K Nov 3 12:14 ..
drwxr-xr-x 2 root root 4.0K Nov 2 00:14 bin
drwxr-xr-x 2 root root 4.0K Jul 13 14:01 boot
drwxr-xr-x 4 root root 4.0K Nov 2 00:14 dev
drwxr-xr-x 44 root root 4.0K Nov 3 12:14 etc
drwxr-xr-x 2 root root 4.0K Jul 13 14:01 home
drwxr-xr-x 10 root root 4.0K Nov 2 00:14 lib
drwxr-xr-x 2 root root 4.0K Nov 2 00:14 lib64
drwxr-xr-x 2 root root 4.0K Nov 2 00:14 media
drwxr-xr-x 2 root root 4.0K Nov 2 00:14 mnt
drwxr-xr-x 2 root root 4.0K Nov 2 00:14 opt
drwxr-xr-x 2 root root 4.0K Jul 13 14:01 proc
drwx------ 2 root root 4.0K Nov 2 00:14 root
drwxr-xr-x 4 root root 4.0K Nov 2 00:14 run
drwxr-xr-x 2 root root 4.0K Nov 2 00:14 sbin
drwxr-xr-x 2 root root 4.0K Nov 2 00:14 selinux
drwxr-xr-x 2 root root 4.0K Nov 2 00:14 srv
drwxr-xr-x 2 root root 4.0K Apr 6 2015 sys
drwxrwxrwt 2 root root 4.0K Nov 2 00:15 tmp
drwxr-xr-x 10 root root 4.0K Nov 2 00:14 usr
drwxr-xr-x 11 root root 4.0K Nov 2 00:14 var

The configuration specific to this container exists in /var/lib/lxc/first-container/config, the contents of which are shown here:

$ cat /var/lib/lxc/first_container/config

# Template used to create this container: /usr/share/lxc/templates/lxc-download
# Parameters passed to the template:
# Template script checksum (SHA-1): b7de1d7259bdd66f5b8f0347f74b18c19729883a
# For additional config options, please look at lxc.container.conf(5)

# Uncomment the following line to support nesting containers:
#lxc.include = /usr/share/lxc/config/nesting.conf
# (Be aware this has security implications)

# Distribution configuration
lxc.include = /usr/share/lxc/config/debian.common.conf
lxc.arch = x86_64

# Container specific configuration
lxc.rootfs.path = dir:/var/lib/lxc/first_container/rootfs = first_container

# Network configuration = empty

The default container creation path can be overridden using the -P option as shown here, which will create the container in /tmp for example:

$ sudo lxc-create -P /tmp/ -t download -n first-container

Alright, let's move forward to the next steps, after creating our container, we might think to start it, so we will use lxc-start.

$ sudo lxc-start -d -n first-container

-d is the default mode, it not necessary to specify it, we can otherwise start our container in a foreground mode by using -F instead of the default mode.
To see our containers just type lxc-ls. Alright, so let's attach our created container by lxc-attach -n first-container and then we can use our container
Just for the records, you can show your containers in a fancy way using the argument --fancy : lxc-ls --fancy
Then, when we are done with our work with the container, we can stop the container. Stopping the container is equivalent to powering down a machine;
we can start the container again any time in the future. Again, it is necessary to use the -n option to provide the name of the container when using lxc-stop:
lxc-stop -n first-container
Otherwise, when we don't need the container anymore, we can simply delete it permanently from the host system using lxc-destroy: lxc-destroy -n first-container

This is it, for our second article, in the next one which I will try my best to publish ASAP, we will talk about the OS templates and how we can use them.
Until then, I hope you enjoyed reading this article, please let me know if there is any typos or anything you wanna say it by mailing me at naeil[AT]nzoueidi[DOT]com or by tweeting me.

Cheers o/