Skip to main content

LXC (Linux Containers) & LXD (Lekseed): Run LXD Container and Create a Custom Container Image

2882 words·
LXC LXD Lekseed Debian
Table of Contents

Overview
#

LXC:

  • Allows running multiple isolated Linux environments (containers) on a single host using a shared kernel

  • Only supports Linux containers


LXD:

  • Written in Go and is built on top of LXC, it aims to provide a simplified user experience

  • Can run both containers and full VMs



LXD Setup
#

Installation
#

# Install LXD package: Debian
sudo apt -y install lxd
# Verify the installation / check version
lxd --version

# Shell output:
5.0.2

Add User to LXD Group
#

# Add the current user to the LXD group
sudo usermod -aG lxd $USER

Initialize LXD Service
#

Start the LXD configuration:

# Initialize LXD
lxd init

# Shell output:
Would you like to use LXD clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]: pool1
Name of the storage backend to use (dir, lvm) [default=dir]:
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
Would you like the LXD server to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]:
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:

I use the default settings for every option:

  • “dir” storage backend: LXD will use a local directory on the server as the storage pool

  • MAAS server (Metal as a Service): Automated bare-metal provisioning system

  • Local network bridge “lxdbr0”: LXD will create a bridge interface for the containers connect to. Containers have outbound internet access via NAT.

  • LXD server not available over the network: Prevents external access to the LXD API

  • Automatically update stale cached images: LXD will periodically check and refresh outdated cached images of containers


Verify the Installation
#

List Default Profile
#

# List the default profile details
lxc profile show default

# Shell output:
config: {}
description: Default LXD profile
devices:
  eth0:
    name: eth0
    network: lxdbr0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: default
used_by: []

Verify Network
#

# List available network interfaces
sudo lxc network list

# Shell output:
+--------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
|  NAME  |   TYPE   | MANAGED |      IPV4       |           IPV6            | DESCRIPTION | USED BY |  STATE  |
+--------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| ens33  | physical | NO      |                 |                           |             | 0       |         |
+--------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| lxdbr0 | bridge   | YES     | 10.163.195.1/24 | fd42:ea24:d55e:5620::1/64 |             | 2       | CREATED |
+--------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
# List details of specific interface "lxdbr0"
lxc network show lxdbr0

# Shell output:
config:
  ipv4.address: 10.163.195.1/24
  ipv4.nat: "true"
  ipv6.address: fd42:ea24:d55e:5620::1/64
  ipv6.nat: "true"
description: ""
name: lxdbr0
type: bridge
used_by:
- /1.0/profiles/default
managed: true
status: Created
locations:
- none

Verify Storage Pool
#

# List the storage pools
lxc storage list

# Shell output:
+---------+--------+------------------------------------+-------------+---------+---------+
|  NAME   | DRIVER |               SOURCE               | DESCRIPTION | USED BY |  STATE  |
+---------+--------+------------------------------------+-------------+---------+---------+
| default | dir    | /var/lib/lxd/storage-pools/default |             | 1       | CREATED |
+---------+--------+------------------------------------+-------------+---------+---------+



Container Images
#

Remove Old Image Server
#

# Remove the old image server
lxc remote remove images

Add LXD Image Server
#

Add the new LXD image server: https://images.lxd.canonical.com/

# Add image server
lxc remote add images https://images.lxd.canonical.com --protocol=simplestreams

List Image Servers
#

# List the current image servers
lxc remote list

# Shell output:
+-----------------+------------------------------------------+---------------+-------------+--------+--------+--------+
|      NAME       |                   URL                    |   PROTOCOL    |  AUTH TYPE  | PUBLIC | STATIC | GLOBAL |
+-----------------+------------------------------------------+---------------+-------------+--------+--------+--------+
| images          | https://images.lxd.canonical.com         | simplestreams | none        | YES    | NO     | NO     |
+-----------------+------------------------------------------+---------------+-------------+--------+--------+--------+
| local (current) | unix://                                  | lxd           | file access | NO     | YES    | NO     |
+-----------------+------------------------------------------+---------------+-------------+--------+--------+--------+
| ubuntu          | https://cloud-images.ubuntu.com/releases | simplestreams | none        | YES    | YES    | NO     |
+-----------------+------------------------------------------+---------------+-------------+--------+--------+--------+
| ubuntu-daily    | https://cloud-images.ubuntu.com/daily    | simplestreams | none        | YES    | YES    | NO     |
+-----------------+------------------------------------------+---------------+-------------+--------+--------+--------+

List Available Images
#

List available prebuilt container images:

# List images: Ubuntu
lxc image list ubuntu:

# List images: LXD default server
lxc image list images:

Filter for specific Images:

# List images: LXD default server, filter for "Alma"
lxc image list images: almalinux

# Shell output:
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
|           ALIAS            | FINGERPRINT  | PUBLIC |            DESCRIPTION            | ARCHITECTURE |      TYPE       |   SIZE   |          UPLOAD DATE          |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8 (3 more)       | 554961f01a67 | yes    | AlmaLinux 8 amd64 (20250227_0014) | x86_64       | VIRTUAL-MACHINE | 906.14MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8 (3 more)       | c1aa5f943701 | yes    | AlmaLinux 8 amd64 (20250227_0014) | x86_64       | CONTAINER       | 129.01MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8/arm64 (1 more) | 457dc8ca19b1 | yes    | AlmaLinux 8 arm64 (20250224_0033) | aarch64      | CONTAINER       | 125.25MB | Feb 24, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8/cloud (1 more) | 338b18526be0 | yes    | AlmaLinux 8 amd64 (20250227_0013) | x86_64       | CONTAINER       | 148.67MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8/cloud (1 more) | c66262652dbd | yes    | AlmaLinux 8 amd64 (20250227_0013) | x86_64       | VIRTUAL-MACHINE | 925.27MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8/cloud/arm64    | f1e3be751f21 | yes    | AlmaLinux 8 arm64 (20250224_0033) | aarch64      | CONTAINER       | 144.40MB | Feb 24, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9 (3 more)       | 91a8ff758f3a | yes    | AlmaLinux 9 amd64 (20250227_0015) | x86_64       | VIRTUAL-MACHINE | 780.70MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9 (3 more)       | bb511c6896a8 | yes    | AlmaLinux 9 amd64 (20250227_0015) | x86_64       | CONTAINER       | 118.43MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9/arm64 (1 more) | 975d3afc6ee5 | yes    | AlmaLinux 9 arm64 (20250224_0033) | aarch64      | CONTAINER       | 114.26MB | Feb 24, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9/cloud (1 more) | 8d1e851396f8 | yes    | AlmaLinux 9 amd64 (20250227_0013) | x86_64       | CONTAINER       | 134.49MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9/cloud (1 more) | 0274d83c7ceb | yes    | AlmaLinux 9 amd64 (20250227_0013) | x86_64       | VIRTUAL-MACHINE | 801.48MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9/cloud/arm64    | 06d4d9a67523 | yes    | AlmaLinux 9 arm64 (20250224_0033) | aarch64      | CONTAINER       | 130.09MB | Feb 24, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
# List images: LXD default server, filter for "Alma", list only "x86_64" (amd64) 
lxc image list images: almalinux arch=amd64

# Shell output:
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
|           ALIAS            | FINGERPRINT  | PUBLIC |            DESCRIPTION            | ARCHITECTURE |      TYPE       |   SIZE   |          UPLOAD DATE          |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8 (3 more)       | 554961f01a67 | yes    | AlmaLinux 8 amd64 (20250227_0014) | x86_64       | VIRTUAL-MACHINE | 906.14MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8 (3 more)       | c1aa5f943701 | yes    | AlmaLinux 8 amd64 (20250227_0014) | x86_64       | CONTAINER       | 129.01MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8/cloud (1 more) | 338b18526be0 | yes    | AlmaLinux 8 amd64 (20250227_0013) | x86_64       | CONTAINER       | 148.67MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/8/cloud (1 more) | c66262652dbd | yes    | AlmaLinux 8 amd64 (20250227_0013) | x86_64       | VIRTUAL-MACHINE | 925.27MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9 (3 more)       | 91a8ff758f3a | yes    | AlmaLinux 9 amd64 (20250227_0015) | x86_64       | VIRTUAL-MACHINE | 780.70MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9 (3 more)       | bb511c6896a8 | yes    | AlmaLinux 9 amd64 (20250227_0015) | x86_64       | CONTAINER       | 118.43MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9/cloud (1 more) | 8d1e851396f8 | yes    | AlmaLinux 9 amd64 (20250227_0013) | x86_64       | CONTAINER       | 134.49MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
| almalinux/9/cloud (1 more) | 0274d83c7ceb | yes    | AlmaLinux 9 amd64 (20250227_0013) | x86_64       | VIRTUAL-MACHINE | 801.48MB | Feb 27, 2025 at 12:00am (UTC) |
+----------------------------+--------------+--------+-----------------------------------+--------------+-----------------+----------+-------------------------------+
# List images: LXD default server, filter for "Alma" (alternative command)
lxc image list images: | grep -i almalinux

# Shell output:
| almalinux/8 (3 more)                     | 554961f01a67 | yes    | AlmaLinux 8 amd64 (20250227_0014)         | x86_64       | VIRTUAL-MACHINE | 906.14MB  | Feb 27, 2025 at 12:00am (UTC) |
| almalinux/8 (3 more)                     | c1aa5f943701 | yes    | AlmaLinux 8 amd64 (20250227_0014)         | x86_64       | CONTAINER       | 129.01MB  | Feb 27, 2025 at 12:00am (UTC) |
| almalinux/8/arm64 (1 more)               | 457dc8ca19b1 | yes    | AlmaLinux 8 arm64 (20250224_0033)         | aarch64      | CONTAINER       | 125.25MB  | Feb 24, 2025 at 12:00am (UTC) |
| almalinux/8/cloud (1 more)               | 338b18526be0 | yes    | AlmaLinux 8 amd64 (20250227_0013)         | x86_64       | CONTAINER       | 148.67MB  | Feb 27, 2025 at 12:00am (UTC) |
| almalinux/8/cloud (1 more)               | c66262652dbd | yes    | AlmaLinux 8 amd64 (20250227_0013)         | x86_64       | VIRTUAL-MACHINE | 925.27MB  | Feb 27, 2025 at 12:00am (UTC) |
| almalinux/8/cloud/arm64                  | f1e3be751f21 | yes    | AlmaLinux 8 arm64 (20250224_0033)         | aarch64      | CONTAINER       | 144.40MB  | Feb 24, 2025 at 12:00am (UTC) |
| almalinux/9 (3 more)                     | 91a8ff758f3a | yes    | AlmaLinux 9 amd64 (20250227_0015)         | x86_64       | VIRTUAL-MACHINE | 780.70MB  | Feb 27, 2025 at 12:00am (UTC) |
| almalinux/9 (3 more)                     | bb511c6896a8 | yes    | AlmaLinux 9 amd64 (20250227_0015)         | x86_64       | CONTAINER       | 118.43MB  | Feb 27, 2025 at 12:00am (UTC) |
| almalinux/9/arm64 (1 more)               | 975d3afc6ee5 | yes    | AlmaLinux 9 arm64 (20250224_0033)         | aarch64      | CONTAINER       | 114.26MB  | Feb 24, 2025 at 12:00am (UTC) |
| almalinux/9/cloud (1 more)               | 8d1e851396f8 | yes    | AlmaLinux 9 amd64 (20250227_0013)         | x86_64       | CONTAINER       | 134.49MB  | Feb 27, 2025 at 12:00am (UTC) |
| almalinux/9/cloud (1 more)               | 0274d83c7ceb | yes    | AlmaLinux 9 amd64 (20250227_0013)         | x86_64       | VIRTUAL-MACHINE | 801.48MB  | Feb 27, 2025 at 12:00am (UTC) |
| almalinux/9/cloud/arm64                  | 06d4d9a67523 | yes    | AlmaLinux 9 arm64 (20250224_0033)         | aarch64      | CONTAINER       | 130.09MB  | Feb 24, 2025 at 12:00am (UTC) |
|                                          | 5f00ce0dd58d | yes    | AlmaLinux 9 arm64 (20250217_0033)         | aarch64      | CONTAINER       | 130.09MB  | Feb 17, 2025 at 12:00am (UTC) |
|                                          | 9e275c5cce43 | yes    | AlmaLinux 9 arm64 (20250217_0033)         | aarch64      | CONTAINER       | 114.27MB  | Feb 17, 2025 at 12:00am (UTC) |
|                                          | 13afc0276ddc | yes    | AlmaLinux 9 amd64 (20250226_0013)         | x86_64       | CONTAINER       | 118.43MB  | Feb 26, 2025 at 12:00am (UTC) |
|                                          | 39abc7c1940e | yes    | AlmaLinux 9 amd64 (20250226_0013)         | x86_64       | VIRTUAL-MACHINE | 780.84MB  | Feb 26, 2025 at 12:00am (UTC) |
|                                          | a0b88c058ff7 | yes    | AlmaLinux 8 amd64 (20250226_0013)         | x86_64       | VIRTUAL-MACHINE | 925.09MB  | Feb 26, 2025 at 12:00am (UTC) |
|                                          | ad8d926ec74b | yes    | AlmaLinux 8 amd64 (20250226_0013)         | x86_64       | VIRTUAL-MACHINE | 906.14MB  | Feb 26, 2025 at 12:00am (UTC) |
|                                          | b9a3507dacf5 | yes    | AlmaLinux 8 arm64 (20250217_0033)         | aarch64      | CONTAINER       | 144.38MB  | Feb 17, 2025 at 12:00am (UTC) |
|                                          | b58464968cf0 | yes    | AlmaLinux 8 amd64 (20250226_0013)         | x86_64       | CONTAINER       | 148.67MB  | Feb 26, 2025 at 12:00am (UTC) |
|                                          | beb8e7c80ecf | yes    | AlmaLinux 9 amd64 (20250226_0014)         | x86_64       | VIRTUAL-MACHINE | 801.64MB  | Feb 26, 2025 at 12:00am (UTC) |
|                                          | cd10cc797ed0 | yes    | AlmaLinux 8 arm64 (20250217_0033)         | aarch64      | CONTAINER       | 125.26MB  | Feb 17, 2025 at 12:00am (UTC) |
|                                          | d910e1915571 | yes    | AlmaLinux 9 amd64 (20250226_0014)         | x86_64       | CONTAINER       | 134.49MB  | Feb 26, 2025 at 12:00am (UTC) |
|                                          | d850461e9924 | yes    | AlmaLinux 8 amd64 (20250226_0013)         | x86_64       | CONTAINER       | 129.01MB  | Feb 26, 2025 at 12:00am (UTC) |

List Image Details
#

# List details of specific image
lxc image info images:almalinux/9
# Alternative
lxc image info images:bb511c6896a8

# Shell output:
Fingerprint: bb511c6896a826059af48eb6db0c2818de7515d171be13f045054e702d91d096
Size: 118.43MB
Architecture: x86_64
Type: container
Public: yes
Timestamps:
    Created: 2025/02/27 00:00 UTC
    Uploaded: 2025/02/27 00:00 UTC
    Expires: never
    Last used: never
Properties:
    os: AlmaLinux
    release: 9
    architecture: amd64
    type: squashfs
    serial: 20250227_0015
    description: AlmaLinux 9 amd64 (20250227_0015)
    variant: default
Aliases:
    - almalinux/9/default
    - almalinux/9/default/amd64
    - almalinux/9
    - almalinux/9/amd64
Cached: no
Auto update: disabled
Profiles: []



Launch Prebuilt Container
#

Create Container
#

Note: For a unknown reason I had problems running containers from the “images” list, so I just used an image from the “ubuntu” list instead.

# Create an example Ubuntu based container
sudo lxc launch ubuntu:7a0b671dbca3 example-ubuntu-container

# Shell output:
Creating example-ubuntu-container
Starting example-ubuntu-container

List Containers
#

# List containers
sudo lxc list

# Shell output:
+--------------------------+---------+------+------+-----------+-----------+
|           NAME           |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |
+--------------------------+---------+------+------+-----------+-----------+
| example-ubuntu-container | RUNNING |      |      | CONTAINER | 0         |
+--------------------------+---------+------+------+-----------+-----------+

List Container Details
#

# List container details
sudo lxc info example-ubuntu-container

# Shell output:
Name: example-ubuntu-container
Status: RUNNING
Type: container
Architecture: x86_64
PID: 45910
Created: 2025/02/27 18:03 CET
Last Used: 2025/02/27 18:03 CET

Resources:
  Processes: 27
  CPU usage:
    CPU usage (in seconds): 3
  Memory usage:
    Memory (current): 67.54MiB
  Network usage:
    eth0:
      Type: broadcast
      State: UP
      Host interface: vethbe32030d
      MAC address: 00:16:3e:7f:0d:db
      MTU: 1500
      Bytes received: 310.13kB
      Bytes sent: 9.83kB
      Packets received: 160
      Packets sent: 114
      IP addresses:
        inet:  10.163.195.54/24 (global)
        inet6: fd42:ea24:d55e:5620:216:3eff:fe7f:ddb/64 (global)
        inet6: fe80::216:3eff:fe7f:ddb/64 (link)
    lo:
      Type: loopback
      State: UP
      MTU: 65536
      Bytes received: 1.29kB
      Bytes sent: 1.29kB
      Packets received: 12
      Packets sent: 12
      IP addresses:
        inet:  127.0.0.1/8 (local)
        inet6: ::1/128 (local)

Nginx Test
#

Install Nginx
#

# Install Nginx inside the container
lxc exec example-ubuntu-container -- apt update
lxc exec example-ubuntu-container -- apt install -y nginx

Add HTML File
#

  • index.html
<!DOCTYPE html>
<html>

<head>
	<title>jklug.work</title>
</head>

<body>
	<h1>Some text</h1>
</body>

</html>
# Copy the index.html file into the container
lxc file push index.html example-ubuntu-container/var/www/html/index.html

Access the Container Terminal
#

# Access the container terminal
lxc exec example-ubuntu-container -- bash
# Test Nginx
curl localhost

# Shell output:
<!DOCTYPE html>
<html>

<head>
        <title>jklug.work</title>
</head>
...
# Exit the container terminal
exit

Add Port Forwarding
#

# Add a port forwarding rule
lxc config device add example-ubuntu-container example-webserver proxy listen=tcp:0.0.0.0:8080 connect=tcp:127.0.0.1:80

# Shell output:
Device example-webserver added to example-ubuntu-container

Access Nginx Webserver
#

Access the Nginx webserver inside the container from an external host:

# Curl the LXD server IP
curl 192.168.30.20:8080

# Shell output:
<!DOCTYPE html>
<html>

<head>
        <title>jklug.work</title>
</head>
...

Remove Port Forwarding
#

# Remove the port forwarding rule
lxc config device remove example-ubuntu-container example-webserver

# Shell output:
Device example-webserver removed from example-ubuntu-container

Start, Stop & Delete Container
#

# Stop the container
lxc stop example-ubuntu-container

# Start the container
lxc start example-ubuntu-container

# Restart the container
lxc restart example-ubuntu-container

# Delete the container (stop it first)
lxc delete example-ubuntu-container



Create Custom Container Image
#

Create Container
#

# Create an example Ubuntu based container
sudo lxc launch ubuntu:7a0b671dbca3 ubuntu-nginx-container

Customize the Container
#

Install Nginx
#

# Install Nginx inside the container
lxc exec ubuntu-nginx-container -- apt update
lxc exec ubuntu-nginx-container -- apt install -y nginx

Add HTML File
#

  • index.html
<!DOCTYPE html>
<html>

<head>
	<title>jklug.work</title>
</head>

<body>
	<h1>Some text</h1>
</body>

</html>
# Copy the index.html file into the container
lxc file push index.html ubuntu-nginx-container/var/www/html/index.html

Stop the Container
#

# Stop the container
lxc stop ubuntu-nginx-container
# Verify the container is stopped / list containers
sudo lxc list

# Shell output:
+------------------------+---------+------+------+-----------+-----------+
|          NAME          |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |
+------------------------+---------+------+------+-----------+-----------+
| ubuntu-nginx-container | STOPPED |      |      | CONTAINER | 0         |
+------------------------+---------+------+------+-----------+-----------+

Convert Container to Image
#

# Create LXD image and save it locally as "ubuntu-nginx"
lxc publish ubuntu-nginx-container --alias ubuntu-nginx

# Shell output:
Instance published with fingerprint: d509022631812336e4c311de8440bfdc9847340c30df8b2cab0020b5587dd946

Verify the container image:

# List container image
lxc image list

# Shell output:
+--------------+--------------+--------+---------------------------------------------+--------------+-----------+----------+------------------------------+
|    ALIAS     | FINGERPRINT  | PUBLIC |                 DESCRIPTION                 | ARCHITECTURE |   TYPE    |   SIZE   |         UPLOAD DATE          |
+--------------+--------------+--------+---------------------------------------------+--------------+-----------+----------+------------------------------+
| ubuntu-nginx | d50902263181 | no     | Ubuntu 24.04 LTS server (20250226)          | x86_64       | CONTAINER | 385.33MB | Feb 27, 2025 at 4:45pm (UTC) |
+--------------+--------------+--------+---------------------------------------------+--------------+-----------+----------+------------------------------+

Launch Container from Custom Image
#

Launch Container
#

# Launch a new container from the custom image
lxc launch ubuntu-nginx custom-nginx-container
# Verify the container is stopped / list containers
sudo lxc list

# Shell output:
+------------------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
|          NAME          |  STATE  |         IPV4         |                     IPV6                      |   TYPE    | SNAPSHOTS |
+------------------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| custom-nginx-container | RUNNING | 10.163.195.42 (eth0) | fd42:ea24:d55e:5620:216:3eff:fe48:8f2b (eth0) | CONTAINER | 0         |
+------------------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| ubuntu-nginx-container | STOPPED |                      |                                               | CONTAINER | 0         |
+------------------------+---------+----------------------+-----------------------------------------------+-----------+-----------+

Add Port Forwarding
#

# Add a port forwarding rule
lxc config device add custom-nginx-container custom-image-webserver proxy listen=tcp:0.0.0.0:8080 connect=tcp:127.0.0.1:80

# Shell output:
Device custom-image-webserver added to custom-nginx-container

Access Nginx Webserver
#

Access the Nginx webserver inside the container from an external host:

# Curl the LXD server IP
curl 192.168.30.20:8080

# Shell output:
<!DOCTYPE html>
<html>

<head>
        <title>jklug.work</title>
</head>
...

Remove Port Forwarding
#

# Remove the port forwarding rule
lxc config device remove custom-nginx-container custom-image-webserver

# Shell output:
Device custom-image-webserver removed from custom-nginx-container

Stop & Delete the Container
#

# Stop the container
lxc stop ubuntu-nginx-container

# Delete the container
lxc delete ubuntu-nginx-container

Delete the Image
#

# Delete the custom image
lxc image delete ubuntu-nginx



Links #

# LXC Official Documentation
https://linuxcontainers.org/lxc/documentation/