diff options
author | Runxi Yu <me@runxiyu.org> | 2024-06-26 08:00:00 +0800 |
---|---|---|
committer | Runxi Yu <me@runxiyu.org> | 2024-06-26 08:00:00 +0800 |
commit | 8c023b595f9c0d8e30b0ffd3e1c9e1719837aa55 (patch) | |
tree | 9a02f8025a4ad662fc4b4d101034a0be787cb0e3 /chroot-dev.html | |
parent | 04c04fc695a702a08935679ed2e48d99f867626c (diff) | |
download | www-8c023b595f9c0d8e30b0ffd3e1c9e1719837aa55.tar.gz |
chroot-dev.html
Diffstat (limited to 'chroot-dev.html')
-rw-r--r-- | chroot-dev.html | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/chroot-dev.html b/chroot-dev.html new file mode 100644 index 0000000..e05cc47 --- /dev/null +++ b/chroot-dev.html @@ -0,0 +1,119 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <title>Using chroots as simple "containers"</title> + <link rel="stylesheet" href="./style.css" /> + <link rel="icon" href="./favicon.ico" sizes="any" /> + <!--link rel="icon" href="./icon.svg" type="image/svg+xml" / --> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta name="theme-color" content="#241504" /> + <meta name="color-scheme" content="light dark"> + <style> +pre { + border: 1px solid; + border-radius: 0.5rem; + padding: 0.5rem; +} + </style> +</head> +<body> +<header> + <h1>Using chroots as simple "containers"</h1> +</header> + +<article> + <p style="display: block; border: 1px solid; border-radius: 0.5rem; padding: 0.5rem;"> + Please note that what I am about to do isn't actually containerization or isolation. It merely separates <em>trusted</em> code such that it would generally not pollute the host system. Chroot is generally not a security measure; for example, processes inside the chroot could easily escape with <code>/proc/<i>x</i>/root</code> for a PID <i>x</i> that runs outside the chroot. + </p> + <p> + Often times I want to install a program that is not available in my current distribution (e.g. the Soju IRC bouncer is not available on Debian Bookworm, but I want to use a distribution-packaged version instead of running <code>go build</code> myself because I want to receive updates), or perhaps I want to run something like <code>rustup</code> without the fear of polluting my system. But I don't want to use Docker or LXC because they feel too complicated. + </p> + <p> + I ended up creating <a href="https://alpinelinux.org">Alpine Linux</a> chroots. Specifically, Alpine Linux Edge, because the <code>edge/testing</code> repository is huge and frequently updated. There's an article called <a href="https://wiki.alpinelinux.org/wiki/Alpine_Linux_in_a_chroot">Alpine Linux in a chroot</a> on the Alpine Linux wiki that provided the steps that I use in my scripts. (The official <a href="https://github.com/alpinelinux/alpine-chroot-install/">alpine-chroot-install</a> scripts exist but haven't been updated for quite a while.) + </p> + <h2><a href="https://git.sr.ht/~runxiyu/rxchroot">The rxchroot scripts</a></h2> + <p> + Check the Git repository linked above for the complete set of scripts; here is a short explanation from excerpts of the script. + </p> + <p> + The first step, of course, is to create the chroot. Basically: + </p> + <pre>umask 022 # or something else that ensures unprivileged users could access the chroot +curl -LO "https://dl-cdn.alpinelinux.org/alpine/edge/main/${arch}/APKINDEX.tar.gz" +tar xvf APKINDEX.tar.gz +curl -LO "https://dl-cdn.alpinelinux.org/alpine/edge/main/${arch}/apk-tools-static-$(sed -n '/P:apk-tools-static/{n;p;}' APKINDEX | cut -d ':' -f 2).apk" +tar -xzf apk-tools-static-*.apk +./sbin/apk.static -X https://dl-cdn.alpinelinux.org/alpine/edge/main -U --allow-untrusted -p "${chroot_dir}" --initdb add alpine-base +cp -L /etc/resolv.conf ${chroot_dir}/etc/ +mkdir -p "${chroot_dir}"/etc/apk +echo "https://dl-cdn.alpinelinux.org/alpine/edge/main" > "${chroot_dir}"/etc/apk/repositories +echo "https://dl-cdn.alpinelinux.org/alpine/edge/community" >> "${chroot_dir}"/etc/apk/repositories +echo "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> "${chroot_dir}"/etc/apk/repositories</pre> + <p> + Every time the chroot needs to be used, some special directories must be mounted. Don't double-mount though as that often causes issues. + </p> + <pre>mount -o bind /dev "${chroot_dir}/dev" +mount -t proc none "${chroot_dir}/proc" +mount -o bind /sys "${chroot_dir}/sys"</pre> + <p> + Then just enter the chroot: + </p> + <pre>chroot "${chroot_dir}" /bin/ash -l</pre> + <p> + And perhaps install stuff: + </p> + <pre>apk add build-base soju vim</pre> + <p> + I'm running on a Debian host, and perhaps I want to start services in the Alpine chroot with systemd: + </p> + <pre># alpine.service ############################################### + +[Unit] +Description=Alpine chroot mounts +Wants=network-online.target +After=network-online.target + +[Service] +Type=oneshot +RemainAfterExit=true +User=root +Group=root +RuntimeDirectory=/alpine +ExecStart=/root/rxchroot/alpine-chroot-activate /alpine +ExecReload=/root/rxchroot/alpine-chroot-activate /alpine +ExecStop=/root/rxchroot/alpine-chroot-deactivate /alpine + +[Install] +WantedBy=multi-user.target + +# soju.service ################################################# + +[Unit] +Description=soju in an Alpine chroot +Requires=alpine.service +After=alpine.service + +[Service] +Type=simple +User=root +Group=root +# Fix the userspec to match the Alpine UID/GUID +ExecStart=/sbin/chroot --userspec=101:102 /alpine /usr/bin/soju +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure + +[Install] +WantedBy=multi-user.target</pre> + <p>Since a chroot doesn't have its own kernel and all system calls pass through the host kernel, network services open ports as if they just run in the host system.</p> +</article> + +<footer> + <ul role="list"> + <li><a href="./">Home</a></li> + <li>Runxi Yu</li> + <li><a rel="license" href="./pubdom.html">Public Domain</a></li> + </ul> +</footer> +</body> +</html> |