Excursion into LXC containers
As I like to live on the bleeding edge by using Debian testing (currently Bookworm), from time to time I run into situations that are not ease to solve from within the distribution. For example currently its impossible to install the yarn package manager:
dzu@krikkit:~$ sudo apt install yarnpkg Reading package lists... Done Building dependency tree... Done Reading state information... Done Some packages could not be installed. This may mean that you have requested an impossible situation or if you are using the unstable distribution that some required packages have not yet been created or been moved out of Incoming. The following information may help to resolve the situation: The following packages have unmet dependencies: node-esprima : Depends: nodejs:any E: Unable to correct problems, you have held broken packages. dzu@krikkit:~$
As I do not see an easy way to fix this and as I am pretty sure that this will work in Debian stable, let's try spinning up an LXC Debian Bullseye container and work from there instead. The ultimate goal for today is to locally build and view the GNOME Javascript guide from a git clone to locally test modifications.
Creating a Bullseye container
Trying to get started with LXC, you are confronted with the choice of
using the "old-style" lxc
command line tools or the more modern
LXD
wrapper (built mainly by Canonical) on top of liblxc and Go
bindings of the tooling. As Debian
still does not package LXD and as I am also not a fan of the
(Canonical driven) snap ecosystem, we will use the old-style command
line tools. As we will see, they are sometimes verbose but get the
job done.
Also for this short excursion, we will simply use a privileged container to make our life easier. The intention of the container is not to sandbox things but to use a different GNU/Linux distribution without resorting to a full blown virtual machine.
After several cycles between failed attempts and reading the error manages, I finally managed to download the base system like this:
dzu@krikkit:~$ sudo lxc-create --name bullseye --template download -- --dist debian --release bullseye --arch amd64 Setting up the GPG keyring Downloading the image index Downloading the rootfs Downloading the metadata The image cache is now ready Unpacking the rootfs --- You just created a Debian bullseye amd64 (20211017_05:24) container. To enable SSH, run: apt install openssh-server No default root or user password are set by LXC. dzu@krikkit:~$
That's all there is to it - it takes less than a minute and we are left with only a few finishing touches to make things work:
- Start the container
- Attach to it
- Assign proper root password
- Create user account matching the host system
- Add sudo rights to that user
Be sure to verify the id of the user in the container coincides with your real id as privileged containers do not do any id mapping on file systems and we want to share work directories between the host and the container later on:
dzu@krikkit:~$ sudo lxc-start bullseye dzu@krikkit:~$ sudo lxc-attach bullseye # passwd New password: Retype new password: passwd: password updated successfully # apt install openssh-server Reading package lists... Done Building dependency tree... Done Reading state information... Done The following additional packages will be installed: libwrap0 ncurses-term openssh-sftp-server runit-helper sensible-utils ucf Suggested packages: molly-guard monkeysphere ssh-askpass ufw The following NEW packages will be installed: libwrap0 ncurses-term openssh-server openssh-sftp-server runit-helper sensible-utils ucf 0 upgraded, 7 newly installed, 0 to remove and 0 not upgraded. Need to get 1098 kB of archives. After this operation, 6446 kB of additional disk space will be used. Do you want to continue? [Y/n] Get:1 http://deb.debian.org/debian bullseye/main amd64 sensible-utils all 0.0.14 [14.8 kB] Get:2 http://deb.debian.org/debian bullseye/main amd64 ncurses-term all 6.2+20201114-2 [504 kB] Get:3 http://deb.debian.org/debian bullseye/main amd64 ucf all 3.0043 [74.0 kB] Get:4 http://deb.debian.org/debian bullseye/main amd64 libwrap0 amd64 7.6.q-31 [59.0 kB] Get:5 http://deb.debian.org/debian bullseye/main amd64 openssh-sftp-server amd64 1:8.4p1-5 [52.3 kB] Get:6 http://deb.debian.org/debian bullseye/main amd64 runit-helper all 2.10.3 [7808 B] Get:7 http://deb.debian.org/debian bullseye/main amd64 openssh-server amd64 1:8.4p1-5 [385 kB] Fetched 1098 kB in 0s (4423 kB/s) debconf: delaying package configuration, since apt-utils is not installed Selecting previously unselected package sensible-utils. (Reading database ... 11577 files and directories currently installed.) Preparing to unpack .../0-sensible-utils_0.0.14_all.deb ... Unpacking sensible-utils (0.0.14) ... Selecting previously unselected package ncurses-term. Preparing to unpack .../1-ncurses-term_6.2+20201114-2_all.deb ... Unpacking ncurses-term (6.2+20201114-2) ... Selecting previously unselected package ucf. Preparing to unpack .../2-ucf_3.0043_all.deb ... Moving old data out of the way Unpacking ucf (3.0043) ... Selecting previously unselected package libwrap0:amd64. Preparing to unpack .../3-libwrap0_7.6.q-31_amd64.deb ... Unpacking libwrap0:amd64 (7.6.q-31) ... Selecting previously unselected package openssh-sftp-server. Preparing to unpack .../4-openssh-sftp-server_1%3a8.4p1-5_amd64.deb ... Unpacking openssh-sftp-server (1:8.4p1-5) ... Selecting previously unselected package runit-helper. Preparing to unpack .../5-runit-helper_2.10.3_all.deb ... Unpacking runit-helper (2.10.3) ... Selecting previously unselected package openssh-server. Preparing to unpack .../6-openssh-server_1%3a8.4p1-5_amd64.deb ... Unpacking openssh-server (1:8.4p1-5) ... Setting up runit-helper (2.10.3) ... Setting up openssh-sftp-server (1:8.4p1-5) ... Setting up libwrap0:amd64 (7.6.q-31) ... Setting up sensible-utils (0.0.14) ... Setting up ncurses-term (6.2+20201114-2) ... Setting up ucf (3.0043) ... Setting up openssh-server (1:8.4p1-5) ... Creating config file /etc/ssh/sshd_config with new version Creating SSH2 RSA key; this may take some time ... 3072 SHA256:y2rtvIyjYNTdfSAmHfU171aXULzSRl/TTT6sP+z2eHQ root@bullseye (RSA) Creating SSH2 ECDSA key; this may take some time ... 256 SHA256:wSl8DnbMWlqXFEufzDavobyJ5z/TcfAjljsXNUGFTuI root@bullseye (ECDSA) Creating SSH2 ED25519 key; this may take some time ... 256 SHA256:GZDge+Bat/LdnzMnH5XlTA8Wgh3GSus0C5zrnWwe5rs root@bullseye (ED25519) Created symlink /etc/systemd/system/sshd.service → /lib/systemd/system/ssh.service. Created symlink /etc/systemd/system/multi-user.target.wants/ssh.service → /lib/systemd/system/ssh.service. rescue-ssh.target is a disabled or a static unit, not starting it. Processing triggers for libc-bin (2.31-13+deb11u2) ... # adduser dzu perl: warning: Setting locale failed. perl: warning: Please check that your locale settings: LANGUAGE = (unset), LC_ALL = (unset), LANG = "de_DE.UTF-8" are supported and installed on your system. perl: warning: Falling back to the standard locale ("C"). Adding user `dzu' ... Adding new group `dzu' (1000) ... Adding new user `dzu' (1000) with group `dzu' ... Creating home directory `/home/dzu' ... Copying files from `/etc/skel' ... New password: Retype new password: passwd: password updated successfully Changing the user information for dzu Enter the new value, or press ENTER for the default Full Name []: Detlev Zundel Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] # adduser dzu sudo Adding user `dzu' to group `sudo' ... Adding user dzu to group sudo Done. #
Setting up directory sharing
Now that we have created the container we will add a statement to the
configuration so that we can access our git repositories also from
within the container. On my machine those repositories live below
/opt/src/git
so we will share this path. The diff shows what needs
to be changed in the (superuser owned) configuration file:
root@krikkit:/var/lib/lxc/bullseye# diff --color -u config{.ORIG,} --- config.ORIG 2021-10-22 15:46:06.000000000 +0200 +++ config 2021-10-22 15:51:40.372003465 +0200 @@ -21,3 +21,6 @@ lxc.net.0.type = veth lxc.net.0.link = lxcbr0 lxc.net.0.flags = up + +# Dzu +lxc.mount.entry = /opt/src/git opt/src/git none bind,optional,create=dir root@krikkit:/var/lib/lxc/bullseye#
Attaching to the prepared container
Once the container is prepared, I use a small script to start it and connect via ssh to it:
#!/bin/sh
usage() {
echo "usage: `basename $0` <container> ..." >&2
echo " Starts <container>, waits for it to come up and ssh's in" >&2
echo " When ssh exits, the container will be stopped again" >&2
exit 1
}
if [ $# -lt 1 ]; then
usage
fi
sudo lxc-start $1
echo "Waiting for container to come up ..." ; sleep 5
ip=`sudo lxc-info -i $1 | awk '{print $2}'`
echo Container has IP address $ip
ssh -Y $ip
sudo lxc-stop $1
With this in place, we can proceed with installing yarnpkg:
dzu@krikkit:~$ ssh-lxc bullseye Waiting for container to come up ... Container has IP address 10.0.3.228 dzu@10.0.3.228's password: Linux bullseye 5.14.0-2-amd64 #1 SMP Debian 5.14.9-2 (2021-10-03) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Fri Oct 22 20:32:47 2021 from 10.0.3.1 dzu@bullseye:~$ sudo apt update && sudo apt install yarnpkg [sudo] password for dzu: Hit:1 http://deb.debian.org/debian bullseye InRelease Get:2 http://security.debian.org bullseye-security InRelease [44.1 kB] Fetched 44.1 kB in 0s (130 kB/s) Reading package lists... Done Building dependency tree... Done Reading state information... Done All packages are up to date. Reading package lists... Done Building dependency tree... Done Reading state information... Done The following additional packages will be installed: javascript-common libbrotli1 libc-ares2 libicu67 libjs-highlight.js libjs-inherits libjs-is-typedarray libjs-psl libjs-source-map libjs-sprintf-js libnghttp2-14 libnode72 libuv1 node-ajv node-ansi-escapes node-ansi-regex node-ansi-styles node-anymatch node-argparse node-array-find-index node-arrify node-asap node-asn1 node-assert-plus node-asynckit node-aws-sign2 node-aws4 node-babel7-runtime node-balanced-match node-bcrypt-pbkdf node-big.js node-bl node-brace-expansion node-braces node-builtin-modules node-bytes node-camelcase node-caseless node-chalk node-chownr node-ci-info node-cli-cursor node-cli-table node-cli-width node-clone node-color-convert node-color-name node-colors node-combined-stream node-commander node-core-util-is node-currently-unhandled node-dashdash node-death node-debug node-deep-equal node-defaults node-delayed-stream node-detect-indent node-duplexify node-ecc-jsbn node-emoji node-emojis-list node-end-of-stream node-escape-string-regexp node-esprima node-exit-hook node-extend node-external-editor node-extsprintf node-fast-deep-equal node-fast-levenshtein node-fill-range node-forever-agent node-form-data node-fs.realpath node-function-bind node-getpass node-glob node-graceful-fs node-har-schema node-har-validator node-has-flag node-http-signature node-iconv-lite node-imports-loader node-inflight node-inherits node-ini node-inquirer node-invariant node-is-buffer node-is-builtin-module node-is-number node-is-plain-obj node-is-promise node-is-typedarray node-isarray node-isstream node-js-tokens node-js-yaml node-jsbn node-jschardet node-json-schema node-json-schema-traverse node-json-stable-stringify node-json-stringify-safe node-json5 node-jsonify node-jsprim node-kind-of node-loader-utils node-lodash node-lodash-packages node-loose-envify node-loud-rejection node-lru-cache node-micromatch node-mime node-mime-types node-minimatch node-minimist node-mkdirp node-ms node-mute-stream node-normalize-path node-oauth-sign node-object-assign node-object-path node-once node-path-is-absolute node-path-root node-path-root-regex node-performance-now node-prepend-http node-process-nextick-args node-proper-lockfile node-psl node-puka node-pump node-pumpify node-punycode node-qs node-read node-readable-stream node-regenerator-runtime node-repeat-string node-request node-request-capture-har node-resolve node-restore-cursor node-retry node-rimraf node-run-async node-rx node-safe-buffer node-semver node-signal-exit node-sort-keys node-source-map node-spdx-correct node-spdx-exceptions node-spdx-expression-parse node-spdx-license-ids node-sprintf-js node-sshpk node-ssri node-stream-shift node-strict-uri-encode node-string-decoder node-string-width node-strip-ansi node-strip-bom node-supports-color node-tar-stream node-through2 node-tmp node-to-regex-range node-tough-cookie node-tunnel-agent node-tweetnacl node-universalify node-uri-js node-util-deprecate node-uuid node-validate-npm-package-license node-verror node-wcwidth.js node-wrappy node-yallist node-yn nodejs nodejs-doc Suggested packages: apache2 | lighttpd | httpd libjs-angularjs npm The following NEW packages will be installed: javascript-common libbrotli1 libc-ares2 libicu67 libjs-highlight.js libjs-inherits libjs-is-typedarray libjs-psl libjs-source-map libjs-sprintf-js libnghttp2-14 libnode72 libuv1 node-ajv node-ansi-escapes node-ansi-regex node-ansi-styles node-anymatch node-argparse node-array-find-index node-arrify node-asap node-asn1 node-assert-plus node-asynckit node-aws-sign2 node-aws4 node-babel7-runtime node-balanced-match node-bcrypt-pbkdf node-big.js node-bl node-brace-expansion node-braces node-builtin-modules node-bytes node-camelcase node-caseless node-chalk node-chownr node-ci-info node-cli-cursor node-cli-table node-cli-width node-clone node-color-convert node-color-name node-colors node-combined-stream node-commander node-core-util-is node-currently-unhandled node-dashdash node-death node-debug node-deep-equal node-defaults node-delayed-stream node-detect-indent node-duplexify node-ecc-jsbn node-emoji node-emojis-list node-end-of-stream node-escape-string-regexp node-esprima node-exit-hook node-extend node-external-editor node-extsprintf node-fast-deep-equal node-fast-levenshtein node-fill-range node-forever-agent node-form-data node-fs.realpath node-function-bind node-getpass node-glob node-graceful-fs node-har-schema node-har-validator node-has-flag node-http-signature node-iconv-lite node-imports-loader node-inflight node-inherits node-ini node-inquirer node-invariant node-is-buffer node-is-builtin-module node-is-number node-is-plain-obj node-is-promise node-is-typedarray node-isarray node-isstream node-js-tokens node-js-yaml node-jsbn node-jschardet node-json-schema node-json-schema-traverse node-json-stable-stringify node-json-stringify-safe node-json5 node-jsonify node-jsprim node-kind-of node-loader-utils node-lodash node-lodash-packages node-loose-envify node-loud-rejection node-lru-cache node-micromatch node-mime node-mime-types node-minimatch node-minimist node-mkdirp node-ms node-mute-stream node-normalize-path node-oauth-sign node-object-assign node-object-path node-once node-path-is-absolute node-path-root node-path-root-regex node-performance-now node-prepend-http node-process-nextick-args node-proper-lockfile node-psl node-puka node-pump node-pumpify node-punycode node-qs node-read node-readable-stream node-regenerator-runtime node-repeat-string node-request node-request-capture-har node-resolve node-restore-cursor node-retry node-rimraf node-run-async node-rx node-safe-buffer node-semver node-signal-exit node-sort-keys node-source-map node-spdx-correct node-spdx-exceptions node-spdx-expression-parse node-spdx-license-ids node-sprintf-js node-sshpk node-ssri node-stream-shift node-strict-uri-encode node-string-decoder node-string-width node-strip-ansi node-strip-bom node-supports-color node-tar-stream node-through2 node-tmp node-to-regex-range node-tough-cookie node-tunnel-agent node-tweetnacl node-universalify node-uri-js node-util-deprecate node-uuid node-validate-npm-package-license node-verror node-wcwidth.js node-wrappy node-yallist node-yn nodejs nodejs-doc yarnpkg 0 upgraded, 194 newly installed, 0 to remove and 0 not upgraded. Need to get 24.8 MB of archives. After this operation, 123 MB of additional disk space will be used. Do you want to continue? [Y/n] Get:1 http://deb.debian.org/debian bullseye/main amd64 javascript-common all 11+nmu1 [6,260 B] Get:2 http://deb.debian.org/debian bullseye/main amd64 libbrotli1 amd64 1.0.9-2+b2 [279 kB] Get:3 http://deb.debian.org/debian bullseye/main amd64 libc-ares2 amd64 1.17.1-1+deb11u1 [102 kB] Get:4 http://deb.debian.org/debian bullseye/main amd64 libicu67 amd64 67.1-7 [8,622 kB] [...] Setting up node-inquirer (3.3.0-3) ... Setting up node-braces (3.0.2+~3.0.0-1) ... Setting up node-micromatch (4.0.2+repack+~4.0.1-1) ... Setting up yarnpkg (1.22.10+~cs22.25.14-3) ... Processing triggers for libc-bin (2.31-13+deb11u2) ... dzu@bullseye:~$
And finally - the whole idea of this excursion - we can build the GNOME Javascript guide:
dzu@bullseye:~$ cd /opt/src/git/gjs-guide/ dzu@bullseye:/opt/src/git/gjs-guide$ yarnpkg dev yarn run v1.22.10 $ yarn build:search && vuepress dev docs $ tsc -p docs/.vuepress/plugins/flexsearch info Initializing VuePress and preparing data... ⠏ Compiling with webpack...Browserslist: caniuse-lite is outdated. Please run: npx browserslist@latest --update-db Why you should do it regularly: https://github.com/browserslist/browserslist#browsers-data-updating ✔ Compilation finished in 7082ms webpack compiled successfully success VuePress webpack dev server is listening at http://localhost:8080/
Directing firefox to http://10.0.3.228:8080 shows the result of the rendering.
Summary
As we saw, it is only a matter of a few commands to download,
configure and run a different GNU/Linux distribution inside an LXC
container. Compared to docker, the container remembers all state and
is simply a "detached" system ready to be run when the need arises.
Sharing directories is achieved by a single line configuration change
in the LXC config file and by ensuring that the container uses the
same user id we do not have any problems with file permissions. Once
the container is no longer needed, it is easily disposed by the
lxc-destroy
command line tool.
Comments
Comments powered by Disqus