• Get In Touch
September 25, 2016

Developing for Snappy Ubuntu from Arch Linux Using LXC

Want your very own server? Get our 1GB memory, Xeon V4, 25GB SSD VPS for £10.00 / month.
Get a Cloud Server

Introduction

Snappy Ubuntu Core is the perfect system for large-scale cloud container deployments, it is perfect for Docker deployments. It is a very nice, minimal and stripped down version of Ubuntu, specially designed to run securely on autonomous machines.

Requirements

  • Arch Linux desktop installed on your system.
  • A non-root user account with sudo privilege set up on your system.

Install LXC

Before starting, you will need to update your system. You can update your system by running the following command:

sudo pacman -S update

Once your system is up-to-date, you can install LXC and other required components with the following command:

sudo pacman -S lxc arch-install-scripts bridge-utils

Make sure that LXC is appropriately configured by running the following command:

sudo lxc-checkconfig

The output looks like the following:

    Kernel configuration not found at /proc/config.gz; searching...
    Kernel configuration found at /boot/config-3.13.0-32-generic
    --- Namespaces ---
    Namespaces: enabled
    Utsname namespace: enabled
    Ipc namespace: enabled
    Pid namespace: enabled
    User namespace: enabled
    Network namespace: enabled
    Multiple /dev/pts instances: enabled

    --- Control groups ---
    Cgroup: enabled
    Cgroup clone_children flag: enabled
    Cgroup device: enabled
    Cgroup sched: enabled
    Cgroup cpu account: enabled
    Cgroup memory controller: enabled
    Cgroup cpuset: enabled

    --- Misc ---
    Veth pair device: enabled
    Macvlan: enabled
    Vlan: enabled
    Bridges: enabled
    Advanced netfilter: enabled
    CONFIG_NF_NAT_IPV4: enabled
    CONFIG_NF_NAT_IPV6: enabled
    CONFIG_IP_NF_TARGET_MASQUERADE: enabled
    CONFIG_IP6_NF_TARGET_MASQUERADE: enabled
    CONFIG_NETFILTER_XT_TARGET_CHECKSUM: enabled

    --- Checkpoint/Restore ---
    checkpoint restore: enabled
    CONFIG_FHANDLE: enabled
    CONFIG_EVENTFD: enabled
    CONFIG_EPOLL: enabled
    CONFIG_UNIX_DIAG: enabled
    CONFIG_INET_DIAG: enabled
    CONFIG_PACKET_DIAG: enabled
    CONFIG_NETLINK_DIAG: enabled
    File capabilities: enabled

    Note : Before booting a new kernel, you can check its configuration
    usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

If you see the above output then your LXC setup should be ok.

Creating Containers

First, you need to download the Ubuntu Trusty (14.04) template.

Run the following command to get the list of all different OS/ARCH combinations.

sudo lxc-create -t download -n snappydev

You should see the all available templates:

    Setting up the GPG keyring
    Downloading the image index

    ---
    DIST    RELEASE    ARCH    VARIANT    BUILD
    ---
    centos    6    amd64    default    20160921_02:16
    centos    6    i386    default    20160921_02:16
    centos    7    amd64    default    20160921_02:16
    debian    jessie    amd64    default    20160921_22:42
    debian    jessie    arm64    default    20160921_22:42
    debian    jessie    armel    default    20160921_22:42
    debian    jessie    armhf    default    20160921_22:42
    debian    jessie    i386    default    20160921_22:42
    debian    jessie    powerpc    default    20160921_22:42
    debian    jessie    ppc64el    default    20160921_22:42
    debian    jessie    s390x    default    20160921_22:42
    debian    sid    amd64    default    20160921_22:42
    debian    sid    arm64    default    20160921_22:42
    debian    sid    armel    default    20160920_22:42
    debian    sid    armhf    default    20160921_22:42
    debian    sid    i386    default    20160921_22:42
    debian    sid    powerpc    default    20160921_22:42
    debian    sid    ppc64el    default    20160921_22:42
    debian    sid    s390x    default    20160921_22:42
    debian    stretch    amd64    default    20160921_22:42
    debian    stretch    arm64    default    20160921_22:42
    debian    stretch    armel    default    20160921_22:42
    debian    stretch    armhf    default    20160921_22:42
    debian    stretch    i386    default    20160921_22:42
    debian    stretch    powerpc    default    20160921_22:42
    debian    stretch    ppc64el    default    20160921_22:42
    debian    stretch    s390x    default    20160921_22:42
    debian    wheezy    amd64    default    20160921_22:42
    debian    wheezy    armel    default    20160920_22:42
    debian    wheezy    armhf    default    20160921_22:42
    debian    wheezy    i386    default    20160921_22:42
    debian    wheezy    powerpc    default    20160921_22:42
    debian    wheezy    s390x    default    20160921_22:42
    fedora    22    amd64    default    20160922_01:27
    fedora    22    i386    default    20160922_01:27
    fedora    23    amd64    default    20160922_01:49
    fedora    23    i386    default    20160922_01:27
    fedora    24    amd64    default    20160922_01:27
    fedora    24    i386    default    20160922_01:49
    gentoo    current    amd64    default    20160921_14:12
    gentoo    current    i386    default    20160921_14:12
    oracle    6    amd64    default    20160921_11:40
    oracle    6    i386    default    20160921_11:40
    oracle    7    amd64    default    20160921_11:40
    plamo    5.x    amd64    default    20160921_21:36
    plamo    5.x    i386    default    20160921_21:36
    plamo    6.x    amd64    default    20160921_21:36
    plamo    6.x    i386    default    20160921_21:36
    ubuntu    precise    amd64    default    20160922_03:49
    ubuntu    precise    armel    default    20160922_07:02
    ubuntu    precise    armhf    default    20160922_03:49
    ubuntu    precise    i386    default    20160922_03:49
    ubuntu    precise    powerpc    default    20160922_03:49
    ubuntu    trusty    amd64    default    20160922_03:49
    ubuntu    trusty    arm64    default    20160922_03:49
    ubuntu    trusty    armhf    default    20160922_07:02
    ubuntu    trusty    i386    default    20160922_03:49
    ubuntu    trusty    powerpc    default    20160922_03:49
    ubuntu    trusty    ppc64el    default    20160922_03:49
    ubuntu    wily    amd64    default    20160922_03:49
    ubuntu    wily    arm64    default    20160922_03:49
    ubuntu    wily    armhf    default    20160922_03:49
    ubuntu    wily    i386    default    20160922_03:49
    ubuntu    wily    powerpc    default    20160922_03:49
    ubuntu    wily    ppc64el    default    20160922_03:49
    ubuntu    xenial    amd64    default    20160922_03:49
    ubuntu    xenial    arm64    default    20160922_03:49
    ubuntu    xenial    armhf    default    20160922_03:49
    ubuntu    xenial    i386    default    20160922_03:49
    ubuntu    xenial    powerpc    default    20160718_03:49
    ubuntu    xenial    ppc64el    default    20160922_03:49
    ubuntu    xenial    s390x    default    20160922_03:49
    ubuntu    yakkety    amd64    default    20160922_03:49
    ubuntu    yakkety    arm64    default    20160922_03:49
    ubuntu    yakkety    armhf    default    20160922_07:02
    ubuntu    yakkety    i386    default    20160922_03:49
    ubuntu    yakkety    powerpc    default    20160922_03:49
    ubuntu    yakkety    ppc64el    default    20160922_03:49
    ubuntu    yakkety    s390x    default    20160922_03:49
    ---

    Distribution: 
    Release: 

Now type : ubuntu, trusty, amd64 and wait until the proper image and root file system has been downloaded. Once the download is completed, your container will have been created, but it is not running.

Setting up Networking

Before proceed further thing, you need to configure networking.

You will need to setup a network bridge between the host and the container. You can setup network bridge using netctl utility. By default netctl is not installed on your system, so you need to install it first. You can install it by running the following command:

sudo pacman -S netctl

Next, you will need to create the file /etc/netctl/lxcbridge in order to setup network bridge.

sudo nano /etc/netctl/lxcbridge

Add the following lines:

    Description="LXC bridge"
    Interface=br0
    Connection=bridge
    BindsToInterfaces=('eno1')
    IP=static
    Address=192.168.0.1/24
    FwdDelay=0

You can use the interface you would like to bind by changing the value of BindsToInterfaces. Now, start the bridge by running the following command:

sudo netctl switch-to lxcbridge

sudo netctl start lxcbridge

Now, run ifconfig command to see that the bridge interface is up and running.

sudo ifconfig

Output:

    docker0   Link encap:Ethernet  HWaddr 02:42:9c:9b:67:68  
              inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
              UP BROADCAST MULTICAST  MTU:1500  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              inet6 addr: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:10442 errors:0 dropped:0 overruns:0 frame:0
              TX packets:10442 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:866354 (866.3 KB)  TX bytes:866354 (866.3 KB)

    br0    Link encap:Ethernet  HWaddr fe:78:f2:9a:af:00  
              inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
              inet6 addr: fe80::d465:f9ff:fe4f:390b/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:41 errors:0 dropped:0 overruns:0 frame:0
              TX packets:146 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:3776 (3.7 KB)  TX bytes:22516 (22.5 KB)

    wlan0     Link encap:Ethernet  HWaddr 4c:bb:58:9c:f5:55  
              inet addr:192.168.43.4  Bcast:192.168.43.255  Mask:255.255.255.0
              inet6 addr: fe80::4ebb:58ff:fe9c:f555/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:9601 errors:0 dropped:0 overruns:0 frame:0
              TX packets:10301 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:5397499 (5.3 MB)  TX bytes:2272749 (2.2 MB)

Next, edit the /etc/default/lxc and change as shown below:

sudo nano /etc/default/lxc

    # LXC_AUTO - whether or not to start containers at boot
    LXC_AUTO="true"

    # BOOTGROUPS - What groups should start on bootup?
    #    Comma separated list of groups.
    #    Leading comma, trailing comma or embedded double
    #    comma indicates when the NULL group should be run.
    # Example (default): boot the onboot group first then the NULL group
    BOOTGROUPS="onboot,"

    # SHUTDOWNDELAY - Wait time for a container to shut down.
    #    Container shutdown can result in lengthy system
    #    shutdown times.  Even 5 seconds per container can be
    #    too long.
    SHUTDOWNDELAY=5

    # OPTIONS can be used for anything else.
    #    If you want to boot everything then
    #    options can be "-a" or "-a -A".
    OPTIONS=

    # STOPOPTS are stop options.  The can be used for anything else to stop.
    #    If you want to kill containers fast, use -k
    STOPOPTS="-a -A -s"

    USE_LXC_BRIDGE="true"  # overridden in lxc-net

    [ ! -f /etc/default/lxc-net ] || . /etc/default/lxc-net

Also, you need to allows packet forwarding between interfaces, you can do this by running the following command:

sudo sysctl net.ipv4.ip_forward

Output:

    net.ipv4.ip_forward = 1

To enable forwarding, run:

sudo sysctl net.ipv4.ip_forward=0

Output:

    net.ipv4.ip_forward = 0

Now, enable host to perform NAT by running the following command:

sudo iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE

Configuring the Container

The main configuration file of the container is located at /var/lib/lxc/snappydev/config.
Next, you will need to edit /var/lib/lxc/snappydev/config file :

sudo nano /var/lib/lxc/snappydev/config

Change the file as shown below:

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

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

    # Container specific configuration
    lxc.rootfs = /var/lib/lxc/snappydev/rootfs
    lxc.utsname = snappydev

    # Network configuration
    lxc.network.type = veth
    lxc.network.link = br0
    lxc.network.flags = up
    lxc.network.name = eth0
    # lxc.network.ipv4 = 192.168.100.10/24
    # lxc.network.ipv4.gateway = 192.168.100.1

Save and close the file when you have finished.

If you have setup the bridge with a static IP then uncomment lxc.network.ipv4 and lxc.network.ipv4.gateway parameter as shown in above file.

After seting up everything, you can start the container by running the following command:

sudo lxc-start -n snappydev

Now, check the container is running by running the following command:

sudo lxc-ls -f

You should see the following output:

    NAME       STATE    IPV4           IPV6  GROUPS  AUTOSTART  
    ----------------------------------------------------------
    snappydev  RUNNING  192.168.0.16  -     -       NO

You can also debug the container if it has not started properly by running the following command:

sudo lxc-start -n snappydev -F --logpriority=DEBUG

The output should provide you enough information to debug what’s wrong with your container.

Once the container is started successfully, it’s time to enter in to container.
You can easily enter to container using lxc-attach command:

sudo lxc-attach -n snappydev

You should see the following error:

    group: cannot find name for group ID 19

To resolve this error, you will need to make some changes in /root/.bashrc file:

root@snappydev:/# nano .bashrc

Add the following line at the end of file:

    export PATH="/bin/:/usr/bin/:/sbin/$PATH"

Next, set the password of ubuntu user:

root@snappydev:/# passwd ubuntu
Enter new UNIX password
Retype new UNIX password
passwd: password updated successfully

Now, exit from the console and login as a normal user by typing:

sudo lxc-console -n snappydev

Enter username and password which you have created above:
“` language-bash
Connected to tty 1
Type to exit the console, to enter Ctrl+a itself

Ubuntu 14.04 snappydev pts/0

snappydev login: ubuntu
Password: 
Last login: Sat Sep 323 10:40:01 UTC 2016 on pts/0
ubuntu@snappydev:~$
Want your very own server? Get our 1GB memory, Xeon V4, 25GB SSD VPS for £10.00 / month.
Get a Cloud Server

Share this Article!

Related Posts

Node.js Authentication – A Complete Guide with Passport and JWT

Node.js Authentication – A Complete Guide with Passport and JWT

Truth be told, it’s difficult for a web application that doesn’t have some kind of identification, even if you don’t see it as a security measure in and of itself. The Internet is a kind of lawless land, and even on free services like Google’s, authentication ensures that abuses will be avoided or at least […]

Node.js and MongoDB: How to Connect MongoDB With Node

Node.js and MongoDB: How to Connect MongoDB With Node

MongoDB is a document-oriented NoSQL database, which was born in 2007 in California as a service to be used within a larger project, but which soon became an independent and open-source product. It stores documents in JSON, a format based on JavaScript and simpler than XML, but still with good expressiveness. It is the dominant […]

Using MySQL with Node.js: A Complete Tutorial

Using MySQL with Node.js: A Complete Tutorial

Although data persistence is almost always a fundamental element of applications, Node.js has no native integration with databases. Everything is delegated to third-party libraries to be included manually, in addition to the standard APIs. Although MongoDB and other non-relational databases are the most common choice with Node because if you need to scale an application, […]

Node.Js Vs Django: Which Is the Best for Your Project

Node.Js Vs Django: Which Is the Best for Your Project

Django and NodeJs are two powerful technologies for web development, both have great functionality, versatile applications, and a great user interface. Both are open source and can be used for free. But which one fits your project best? NodeJs is based on JavaScript, while Django is written in Python. These are two equally popular technologies […]

Nodejs Vs PHP:  Which Works Best?

Nodejs Vs PHP: Which Works Best?

Before getting into the “battle” between Node.js and PHP we need to understand why the issue is still ongoing. It all started with the increased demand for smartphone applications, their success forcing developers to adapt to new back-end technologies that could handle a multitude of simultaneous requests. JavaScript has always been identified as a client-side […]