<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>LXC on Zwindler's Reflection</title><link>https://blog.zwindler.fr/en/tags/lxc/</link><description>Recent content in LXC on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Mon, 24 Nov 2025 18:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/en/tags/lxc/index.xml" rel="self" type="application/rss+xml"/><item><title>OCI Artifacts as LXC Machine Base on Proxmox 9.1, Finally?</title><link>https://blog.zwindler.fr/en/2025/11/24/oci-artifacts-as-lxc-machine-base-on-proxmox-9.1-finally/</link><pubDate>Mon, 24 Nov 2025 18:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/en/2025/11/24/oci-artifacts-as-lxc-machine-base-on-proxmox-9.1-finally/</guid><description>&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci2.webp" alt="Featured image of post OCI Artifacts as LXC Machine Base on Proxmox 9.1, Finally?" /&gt;&lt;h2 id="context"&gt;Context
&lt;/h2&gt;&lt;p&gt;A few days ago, &lt;a class="link" href="https://proxmox.com/en/about/company-details/press-releases/proxmox-virtual-environment-9-1" target="_blank" rel="noopener"
&gt;the Proxmox VE dev team announced a new version (9.1)&lt;/a&gt; whose major new feature is the addition of OCI artifacts support as a base for creating LXC containers.&lt;/p&gt;
&lt;p&gt;A long-awaited feature, since in theory it finally opens the door to launching &amp;ldquo;Docker&amp;rdquo;-type containers in Proxmox, something the Proxmox devs had always refused.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s also why one of my blog articles gets the most traffic on Google (sniff, soon the end of glory):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2022/11/07/containers-docker-dans-proxmox-avec-lxc/" target="_blank" rel="noopener"
&gt;This article where I explain how to launch Docker containers (via LXC) in Proxmox VE (normally not possible)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Create LXC containers from OCI images&lt;/p&gt;
&lt;p&gt;Proxmox VE 9.1 integrates support for Open Container Initiative (OCI) images, a standard format for container distribution. Users can now download widely-adopted OCI images directly from registries or upload them manually to use as templates for LXC containers. Depending on the image, these containers are provisioned as full system containers or lean application containers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="lets-test-first-the-prerequisites"&gt;Let&amp;rsquo;s Test? First the Prerequisites
&lt;/h2&gt;&lt;p&gt;So, I&amp;rsquo;m curious, how does it work?&lt;/p&gt;
&lt;p&gt;First, you need to pre-download the image you&amp;rsquo;re interested in to your storage (one that can host &amp;ldquo;CT Templates&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Fun thing, there&amp;rsquo;s a button called &amp;ldquo;Query tags&amp;rdquo;, which I imagine retrieves a list of tags. Well, it&amp;rsquo;s not starting well, it doesn&amp;rsquo;t work (at least not on docker.io&amp;hellip;).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;command &amp;#39;skopeo list-tags docker://docker.io/zwindler/prime-calculator&amp;#39; failed: exit code 1 (500)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;EDIT: since then, it works again, on all my nodes. Perhaps a temporary issue.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/12/qwen.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Note: &lt;code&gt;skopeo&lt;/code&gt; is precisely one of the dependencies used in my &amp;ldquo;proxmox+docker hack&amp;rdquo; article that allows manipulating (mainly downloading) containers from remote registries.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci3.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci4.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="creating-the-lxc-container"&gt;Creating the LXC Container
&lt;/h2&gt;&lt;p&gt;Now that the template (the OCI image) is available on our storage, we can create an LXC container as usual. Click on &amp;ldquo;Create CT&amp;rdquo;, give a CT ID, a password:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci5.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;For the template, we choose our OCI artifact:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci6.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;And validate. Proxmox should create our container:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci7.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Even though the terminal tells us that application containers may not work well in the JS console, for all the containers I managed to start (see below), I always had a functional console.&lt;/p&gt;
&lt;p&gt;So the bet seems rather successful.&lt;/p&gt;
&lt;p&gt;Example with &lt;code&gt;docker.io/python:3.11.14-trixie&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/12/python.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="when-it-wasnt-working-yet"&gt;When It Wasn&amp;rsquo;t Working (Yet)
&lt;/h2&gt;&lt;p&gt;I had 2 issues on a Proxmox VE 9.1 (that had been upgraded and tinkered with a bit, in short, a machine that had seen some use) starting an LXC container on OCI base with Proxmox VE 9.1 because I ran into 2 bugs.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t reproduce these bugs on a &amp;ldquo;fresh&amp;rdquo; install.&lt;/p&gt;
&lt;h3 id="first-bug-from-scratch-image"&gt;First Bug: &amp;ldquo;from scratch&amp;rdquo; Image
&lt;/h3&gt;&lt;p&gt;First, my &lt;code&gt;prime-calculator&lt;/code&gt; image wasn&amp;rsquo;t even created.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;TASK ERROR: unable to create CT 106 - Error while extracting OCI image: Unknown layer digest sha256:2bc4d17e1eb16f6b52acbafeb6d86c8f3eaf9588a5e2a7a245b6bb1d85e93396 found in rootfs.diff_ids: Unknown layer digest sha256:2bc4d17e1eb16f6b52acbafeb6d86c8f3eaf9588a5e2a7a245b6bb1d85e93396 found in rootfs.diff_ids
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;OK, fair enough. My image is a binary &amp;ldquo;from scratch&amp;rdquo;, with nothing but the binary, and maybe I made a mistake somewhere&amp;hellip;&lt;/p&gt;
&lt;p&gt;Still doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;h3 id="second-bug-unable-to-start"&gt;Second Bug: Unable to Start
&lt;/h3&gt;&lt;p&gt;However, even with known images, the container is properly created:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci8.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;But impossible to start it:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;problem with monitor socket, but continuing anyway: got timeout
TASK ERROR: unable to get PID for CT 105 (not running?)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Same error with command line:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pct start 105 --debug
problem with monitor socket, but continuing anyway: got timeout
lxc_start_main: 257 Container is already running
- Read uid map: type u nsid 0 hostid 100000 range 65536
INFO confile - ../src/lxc/confile.c:set_config_idmaps:2295 - Read uid map: type g nsid 0 hostid 100000 range 65536
ERROR lxc_start - ../src/lxc/tools/lxc_start.c:lxc_start_main:257 - Container is already running
unable to get PID for CT 105 (not running?)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci9.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;After (laborious) investigation, it turns out it&amp;rsquo;s an AppArmor problem. I don&amp;rsquo;t know if I caused it with my tinkering or if it&amp;rsquo;s a more generalized bug for now (probably option 1, but 2 isn&amp;rsquo;t impossible either&amp;hellip;)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Nov 23 10:37:26 node01 systemd[1]: Started pve-container-debug@105.service - PVE LXC Container: 151.
Nov 23 10:37:27 node01 kernel: audit: type=1400 audit(1764067047.008:175): apparmor=&amp;#34;DENIED&amp;#34; operation=&amp;#34;create&amp;#34; class=&amp;#34;net&amp;#34;
Nov 23 10:37:27 node01 kernel: audit: type=1400 audit(1764067047.008:176): apparmor=&amp;#34;DENIED&amp;#34; operation=&amp;#34;create&amp;#34; class=&amp;#34;net&amp;#34;
Nov 23 10:37:27 node01 systemd[1]: pve-container-debug@105.service: Deactivated successfully.
Nov 23 10:37:37 node01 pct[21369]: unable to get PID for CT 105 (not running?)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The temporary (and dirty) workaround is to disable the AppArmor profile for &lt;code&gt;lxc-start&lt;/code&gt;, and remove any zombie files/processes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apparmor_parser -R /etc/apparmor.d/usr.bin.lxc-start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps aux &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s2"&gt;&amp;#34;lxc-start&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s2"&gt;&amp;#34;105&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs -r &lt;span class="nb"&gt;kill&lt;/span&gt; -9
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -f /var/lib/lxc/105/config.lock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -f /run/lxc/lock/var/lib/lxc/105
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: You can also disable it permanently, but that&amp;rsquo;s obviously something you shouldn&amp;rsquo;t do.&lt;/p&gt;
&lt;p&gt;From there, the container is accessible, sometimes in console (depends on the container)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/pve-oci10.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Apparently, the problems I encountered don&amp;rsquo;t reproduce on a &amp;ldquo;fresh install&amp;rdquo;. So it&amp;rsquo;s probably an issue related to my &amp;ldquo;old&amp;rdquo; machines.&lt;/p&gt;
&lt;p&gt;As a bonus, another article in English that made me persevere when I understood it worked for some:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://raymii.org/s/tutorials/Finally_run_Docker_containers_natively_in_Proxmox_9.1.html" target="_blank" rel="noopener"
&gt;Raymii.org blog - Finally, run Docker containers natively in Proxmox 9.1 (OCI images)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: this article helped me rediscover the &lt;code&gt;pct enter CTID&lt;/code&gt; command that allows you to log into the container.&lt;/p&gt;
&lt;p&gt;In the meantime, you still have my hack ;-)&lt;/p&gt;</description></item><item><title>Turning Proxmox VE into a Kubernetes Node with LXC and lxcri</title><link>https://blog.zwindler.fr/en/2025/11/17/turning-proxmox-ve-into-a-kubernetes-node-with-lxc-and-lxcri/</link><pubDate>Mon, 17 Nov 2025 18:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/en/2025/11/17/turning-proxmox-ve-into-a-kubernetes-node-with-lxc-and-lxcri/</guid><description>&lt;img src="https://blog.zwindler.fr/2025/11/proxmox-k8s.webp" alt="Featured image of post Turning Proxmox VE into a Kubernetes Node with LXC and lxcri" /&gt;&lt;h2 id="he-didnt-know-it-was-completely-stupid-so-he-did-it"&gt;He didn&amp;rsquo;t know it was completely stupid, so he did it
&lt;/h2&gt;&lt;p&gt;What a lie&amp;hellip; &lt;strong&gt;Of course, I know perfectly well it&amp;rsquo;s dumb&lt;/strong&gt;. Which is precisely why this idea is irresistible.&lt;/p&gt;
&lt;p&gt;If you follow the blog, you know I use Proxmox VE extensively (the articles that attract the most traffic on the blog are actually about this virtualization technology).&lt;/p&gt;
&lt;p&gt;Proxmox VE is pretty cool; you can run VMs (QEMU) with it, but also, if you don&amp;rsquo;t have VT-x or want &amp;ldquo;lightweight VMs&amp;rdquo; (a term we&amp;rsquo;ve overused), you can install complete OSes in containers with LXC.&lt;/p&gt;
&lt;p&gt;But beyond these two solutions, the Proxmox VE project devs are quite rigid (and not just about that). That&amp;rsquo;s why I&amp;rsquo;ve posted a few &amp;ldquo;hacks&amp;rdquo; to work around Proxmox&amp;rsquo;s limitations, notably &lt;a class="link" href="https://blog.zwindler.fr/en/2022/11/07/running-docker-containers-with-proxmox-ve-and-lxc/" target="_blank" rel="noopener"
&gt;this article where I explain how to run Docker containers (via LXC) in Proxmox VE (normally not possible)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What if we went even further with the stupid hack?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What if we not only ran OCI containers in Proxmox VE, but ALSO transformed our Proxmox VE hosts into ✨️ &lt;strong&gt;Kubernetes Nodes&lt;/strong&gt; ✨️ ???&lt;/p&gt;
&lt;h2 id="how-do-we-do-this"&gt;How do we do this?
&lt;/h2&gt;&lt;p&gt;The goal is obviously not to install Kubernetes alongside Proxmox VE, but to reuse as much as possible. Typically, I&amp;rsquo;m going to reuse the virtualization technology.&lt;/p&gt;
&lt;p&gt;With Proxmox VE supporting 2 different virtualization technologies (qemu and LXC), you have to choose. And since I like LXC and have already experimented with the Docker =&amp;gt; LXC hack on Proxmox VE, &lt;strong&gt;the question was quickly answered&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The entire difficulty of this exercise is finding how to make LXC &amp;ldquo;CRI-compatible&amp;rdquo;. And we&amp;rsquo;re lucky, Linux Containers, the foundation that oversees LXC, Incus (ex LXD, &amp;ldquo;closed&amp;rdquo; by Canonical), wrote a CRI for LXC called &lt;a class="link" href="https://github.com/lxc/lxcri" target="_blank" rel="noopener"
&gt;lxcri&lt;/a&gt; a few years ago. And of course, as it&amp;rsquo;s a project of questionable utility, the thing has been unmaintained since 2021.&lt;/p&gt;
&lt;p&gt;I had actually tried to use it, spent quite a bit of time on it in February 2024 (I faced bug after bug, went through forks, &amp;hellip;) to fail miserably on a compatibility problem with my version of LXC (5+ on Proxmox 8, 6 on Proxmox 9), among other bugs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;lxcri is a wrapper around LXC which can be used as a drop-in container runtime replacement for use by CRI-O.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So we&amp;rsquo;re going to need 3 additional things on our Proxmox server for my dumb idea to work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;lxcri&lt;/strong&gt; as the low-level container runtime&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;cri-o&lt;/strong&gt; as the high-level container runtime&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;kubelet&lt;/strong&gt; to control the runtime and communicate with the control plane&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="lets-go"&gt;Let&amp;rsquo;s go
&lt;/h2&gt;&lt;p&gt;OK. So lxcri relies on &lt;a class="link" href="https://cri-o.io/" target="_blank" rel="noopener"
&gt;cri_o&lt;/a&gt;, Redhat&amp;rsquo;s container runtime. Let&amp;rsquo;s start by installing cri-o:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/cri-o/cri-o/blob/main/install.md" target="_blank" rel="noopener"
&gt;https://github.com/cri-o/cri-o/blob/main/install.md&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: my Proxmox VE 8 server back then was using Debian 12 as its base OS. So we should base ourselves on that for the $OS variable (as indicated in the docs). However, when I first tested, the CRI-O repositories were being migrated, with outdated documentation and missing releases. The repo &lt;a class="link" href="https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o/" target="_blank" rel="noopener"
&gt;download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o&lt;/a&gt; didn&amp;rsquo;t have the Debian_12 PATH, nor Kubernetes version 1.29&amp;hellip; &lt;strong&gt;I was SO pissed&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/cri-o/cri-o/issues/7657" target="_blank" rel="noopener"
&gt;https://github.com/cri-o/cri-o/issues/7657&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/blog/2023/10/10/cri-o-community-package-infrastructure/" target="_blank" rel="noopener"
&gt;https://kubernetes.io/blog/2023/10/10/cri-o-community-package-infrastructure/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We shouldn&amp;rsquo;t have any issues now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;KUBERNETES_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v1.32
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CRIO_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v1.32
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# create a directory for keyrings (it doesn&amp;#39;t always exist on a fresh install)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir -p /usr/share/keyrings
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# kubernetes repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://pkgs.k8s.io/core:/stable:/&lt;span class="nv"&gt;$KUBERNETES_VERSION&lt;/span&gt;/deb/Release.key &lt;span class="p"&gt;|&lt;/span&gt; sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/&lt;/span&gt;&lt;span class="nv"&gt;$KUBERNETES_VERSION&lt;/span&gt;&lt;span class="s2"&gt;/deb/ /&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo tee /etc/apt/sources.list.d/kubernetes.list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# crio repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://download.opensuse.org/repositories/isv:/cri-o:/stable:/&lt;span class="nv"&gt;$CRIO_VERSION&lt;/span&gt;/deb/Release.key &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo gpg --dearmor -o /etc/apt/keyrings/cri-o-apt-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;deb [signed-by=/etc/apt/keyrings/cri-o-apt-keyring.gpg] https://download.opensuse.org/repositories/isv:/cri-o:/stable:/&lt;/span&gt;&lt;span class="nv"&gt;$CRIO_VERSION&lt;/span&gt;&lt;span class="s2"&gt;/deb/ /&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo tee /etc/apt/sources.list.d/cri-o.list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install cri-o
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From here, we have cri-o. We could configure it, but if we do that, it will use runc and we wouldn&amp;rsquo;t be using LXC as a runtime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That&amp;rsquo;s not the point of this hack!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So at this point, we switch back to the lxcri documentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/lxc/lxcri/blob/main/doc/setup.md" target="_blank" rel="noopener"
&gt;github.com/lxc/lxcri&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="theres-no-release"&gt;There&amp;rsquo;s no release
&lt;/h2&gt;&lt;p&gt;That&amp;rsquo;s right&amp;hellip; we need to first &lt;strong&gt;build&lt;/strong&gt; the &lt;code&gt;lxcri&lt;/code&gt; binary and place it in the /usr/local of our Proxmox VE server. There&amp;rsquo;s no precompiled binary in the project, &lt;a class="link" href="https://github.com/lxc/lxcri/issues/57" target="_blank" rel="noopener"
&gt;it&amp;rsquo;s an issue that was opened just before it was abandoned 😬😬&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And to make it even more fun, the build process goes through a Dockerfile, which is funny since we don&amp;rsquo;t have Docker on our proxmox node&amp;hellip;&lt;/p&gt;
&lt;p&gt;So I tried to &lt;a class="link" href="https://github.com/lxc/lxcri/blob/main/README.md" target="_blank" rel="noopener"
&gt;build lxcri&lt;/a&gt; from a machine with docker, following the command shown on Github. Boom. (First, there&amp;rsquo;s a missing &amp;ldquo;.&amp;rdquo; at the end of the &lt;code&gt;docker build&lt;/code&gt; command in the docs) it fails miserably at compilation&amp;hellip;&lt;/p&gt;
&lt;p&gt;Note: I no longer have that error, probably a dependency problem. It&amp;rsquo;s annoying because we&amp;rsquo;ll have to do lots of things manually&amp;hellip; But don&amp;rsquo;t bother with &lt;code&gt;git clone&lt;/code&gt;, we&amp;rsquo;re going to use a fork (of a fork).&lt;/p&gt;
&lt;p&gt;Looking at the Dockerfile, we quickly realize we&amp;rsquo;re just running a script (install.sh)&amp;hellip;&lt;/p&gt;
&lt;p&gt;When we call docker with the buildarg &lt;code&gt;installcmd=install_runtime&lt;/code&gt;, we run the &lt;code&gt;install_runtime&lt;/code&gt; function, which calls &lt;code&gt;install_runtime_noclean&lt;/code&gt;, which runs &lt;code&gt;add_lxc&lt;/code&gt; then &lt;code&gt;add_lxcri&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Me just want to compile &lt;strong&gt;lxc&lt;/strong&gt; (for the bindings) and &lt;strong&gt;lxcri&lt;/strong&gt;. So I&amp;rsquo;ll do it manually. For that, we need golang 1.16 (it&amp;rsquo;s old&amp;hellip;).&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s quite a bit of broken code everywhere and several open issues where maintainers recommend going with a fork:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/drachenfels-de/lxcri" target="_blank" rel="noopener"
&gt;https://github.com/drachenfels-de/lxcri&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I spent quite a bit of time debugging it, and in the end I made my own fork (&lt;a class="link" href="https://github.com/zwindler/lxcri%29" target="_blank" rel="noopener"
&gt;https://github.com/zwindler/lxcri)&lt;/a&gt;, which requires golang 1.22+ and adds a bunch of fixes.&lt;/p&gt;
&lt;h2 id="prerequisites-for-building-lxcri"&gt;Prerequisites for building lxcri
&lt;/h2&gt;&lt;p&gt;Let&amp;rsquo;s install a bunch of stuff:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo apt update
sudo apt install curl git meson pkg-config cmake libdbus-1-dev docbook2x
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let&amp;rsquo;s install golang if we don&amp;rsquo;t have it (unlikely you have Golang on a Proxmox VE node):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://go.dev/dl/go1.25.4.linux-amd64.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm -rf /usr/local/go &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo tar -C /usr/local -xzf go1.25.4.linux-amd64.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;:/usr/local/go/bin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; go version go1.25.4 linux/amd64
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll also need to &lt;strong&gt;fetch and compile lxc&lt;/strong&gt;. For a while, I was stuck on version 4.0.12 (very precisely) because the 4.0.6 found on Debian 11 does &lt;strong&gt;not&lt;/strong&gt; work with the lxcri code (I hit lots of bugs).&lt;/p&gt;
&lt;p&gt;But the good news is that since I&amp;rsquo;m a try-harder from space, with all the fixes on my fork, my fork works with the latest version of lxc (6.x), which is convenient because that&amp;rsquo;s the version on my updated Proxmox VE 9.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/lxc/lxc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; lxc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;meson setup -Dprefix&lt;span class="o"&gt;=&lt;/span&gt;/usr -Dsystemd-unitdir&lt;span class="o"&gt;=&lt;/span&gt;PATH build
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Build targets in project: &lt;span class="m"&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; lxc 6.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; User defined options
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; prefix : /usr
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; systemd-unitdir: PATH
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Found ninja-1.12.1 at /usr/bin/ninja
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;meson compile -C build
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; INFO: autodetecting backend as ninja
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; INFO: calculating backend &lt;span class="nb"&gt;command&lt;/span&gt; to run: /usr/bin/ninja -C /root/lxc/build
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ninja: Entering directory &lt;span class="sb"&gt;`&lt;/span&gt;/root/lxc/build&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;544/544&lt;span class="o"&gt;]&lt;/span&gt; Linking target src/lxc/tools/lxc-monitor
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It built lots of things, that&amp;rsquo;s cool. But the files I&amp;rsquo;m interested in are here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find . -name &lt;span class="s2"&gt;&amp;#34;lxc.pc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./build/meson-private/lxc.pc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls build/*lxc*
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;build/liblxc.so build/liblxc.so.1 build/liblxc.so.1.8.0 build/lxc.spec
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;build/liblxc.so.1.8.0.p:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;liblxc.so.1.8.0.symbols
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I put this in the right places on my Proxmox VE with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo make install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ldconfig
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="build-like-never-before"&gt;Build like never before
&lt;/h2&gt;&lt;p&gt;OK, time to play &lt;strong&gt;with my fork&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/zwindler/lxcri.git lxcri.zwindler
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; lxcri.zwindler
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make build
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; go build -ldflags &lt;span class="s1"&gt;&amp;#39;-X main.version=8805687-dirty -X github.com/lxc/lxcri.defaultLibexecDir=/usr/local/libexec/lxcri&amp;#39;&lt;/span&gt; -o lxcri ./cmd/lxcri
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cc -Werror -Wpedantic -o lxcri-start cmd/lxcri-start/lxcri-start.c &lt;span class="k"&gt;$(&lt;/span&gt;pkg-config --libs --cflags lxc&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; go build -o lxcri-init ./cmd/lxcri-init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# this is paranoia - but ensure it is statically compiled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ! ldd lxcri-init 2&amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; go build -o lxcri-hook ./cmd/lxcri-hook
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; go build -o lxcri-hook-builtin ./cmd/lxcri-hook-builtin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -alrt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; total &lt;span class="m"&gt;15288&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -rwxr-xr-x &lt;span class="m"&gt;1&lt;/span&gt; debian debian &lt;span class="m"&gt;7108288&lt;/span&gt; Nov &lt;span class="m"&gt;16&lt;/span&gt; 20:06 lxcri
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -rwxr-xr-x &lt;span class="m"&gt;1&lt;/span&gt; debian debian &lt;span class="m"&gt;17520&lt;/span&gt; Nov &lt;span class="m"&gt;16&lt;/span&gt; 20:06 lxcri-start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -rwxr-xr-x &lt;span class="m"&gt;1&lt;/span&gt; debian debian &lt;span class="m"&gt;2942584&lt;/span&gt; Nov &lt;span class="m"&gt;16&lt;/span&gt; 20:06 lxcri-init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -rwxr-xr-x &lt;span class="m"&gt;1&lt;/span&gt; debian debian &lt;span class="m"&gt;2834743&lt;/span&gt; Nov &lt;span class="m"&gt;16&lt;/span&gt; 20:06 lxcri-hook
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -rwxr-xr-x &lt;span class="m"&gt;1&lt;/span&gt; debian debian &lt;span class="m"&gt;2519097&lt;/span&gt; Nov &lt;span class="m"&gt;16&lt;/span&gt; 20:06 lxcri-hook-builtin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we were on a dev machine, we could send the binaries to the Proxmox VE server (lxcri in /usr/local/bin, the rest in /usr/local/libexec/lxcri)&lt;/p&gt;
&lt;p&gt;In my case, I&amp;rsquo;m directly on the machine that builds and runs, so I do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo make install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mkdir -p /usr/local/bin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cp -v lxcri /usr/local/bin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;lxcri&amp;#39;&lt;/span&gt; -&amp;gt; &lt;span class="s1"&gt;&amp;#39;/usr/local/bin/lxcri&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mkdir -p /usr/local/libexec/lxcri
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cp -v lxcri-start lxcri-init lxcri-hook lxcri-hook-builtin /usr/local/libexec/lxcri
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;lxcri-start&amp;#39;&lt;/span&gt; -&amp;gt; &lt;span class="s1"&gt;&amp;#39;/usr/local/libexec/lxcri/lxcri-start&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;lxcri-init&amp;#39;&lt;/span&gt; -&amp;gt; &lt;span class="s1"&gt;&amp;#39;/usr/local/libexec/lxcri/lxcri-init&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;lxcri-hook&amp;#39;&lt;/span&gt; -&amp;gt; &lt;span class="s1"&gt;&amp;#39;/usr/local/libexec/lxcri/lxcri-hook&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;lxcri-hook-builtin&amp;#39;&lt;/span&gt; -&amp;gt; &lt;span class="s1"&gt;&amp;#39;/usr/local/libexec/lxcri/lxcri-hook-builtin&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and we can continue:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ /usr/local/bin/lxcri &lt;span class="nb"&gt;help&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; lxcri - lxcri is a OCI compliant runtime wrapper &lt;span class="k"&gt;for&lt;/span&gt; lxc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;USAGE:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; lxcri &lt;span class="o"&gt;[&lt;/span&gt;global options&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; options&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;arguments...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;VERSION:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;8805687&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="back-to-crio"&gt;Back to crio
&lt;/h2&gt;&lt;p&gt;OK, we&amp;rsquo;ve built lxcri and have all the dependencies to use it. So we can go back to the official lxcri doc &amp;ldquo;&lt;a class="link" href="https://github.com/lxc/lxcri/blob/main/doc/setup.md" target="_blank" rel="noopener"
&gt;setup.md&lt;/a&gt;&amp;rdquo; with the idea of configuring CRI-O, so it doesn&amp;rsquo;t use runc, &lt;strong&gt;only lxcri&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tee /etc/crio/crio.conf.d/10-crio.conf &amp;gt; /dev/null &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;[crio.image]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;signature_policy = &amp;#34;/etc/crio/policy.json&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;[crio.runtime]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;default_runtime = &amp;#34;lxcri&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;[crio.runtime.runtimes.lxcri]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;runtime_path = &amp;#34;/usr/local/bin/lxcri&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;runtime_type = &amp;#34;oci&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;runtime_root = &amp;#34;/var/lib/lxc&amp;#34; #proxmox lxc folder
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;inherit_default_runtime = false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;runtime_config_path = &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;container_min_memory = &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;monitor_path = &amp;#34;/usr/libexec/crio/conmon&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;monitor_cgroup = &amp;#34;system.slice&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;monitor_exec_cgroup = &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;privileged_without_host_devices = false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note, the &lt;code&gt;setup.md&lt;/code&gt; installation doc tells us to generate a clean config with the crio binary and the config command, but it doesn&amp;rsquo;t really work and we end up launching runc or crun unintentionally. I overwrite everything, it&amp;rsquo;s simpler.&lt;/p&gt;
&lt;p&gt;And now, we can start crio:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; crio &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo systemctl start crio
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From here, we have a server with a &lt;em&gt;presumably&lt;/em&gt; functional CRI.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl status crio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;● crio.service - Container Runtime Interface &lt;span class="k"&gt;for&lt;/span&gt; OCI &lt;span class="o"&gt;(&lt;/span&gt;CRI-O&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/lib/systemd/system/crio.service&lt;span class="p"&gt;;&lt;/span&gt; enabled&lt;span class="p"&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Mon 2025-11-17 12:02:37 UTC&lt;span class="p"&gt;;&lt;/span&gt; 12s ago
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;journalctl -u crio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Nov &lt;span class="m"&gt;17&lt;/span&gt; 20:29:43 instance-2025-11-16-15-31-55 systemd&lt;span class="o"&gt;[&lt;/span&gt;1&lt;span class="o"&gt;]&lt;/span&gt;: Starting Container Runtime Interface &lt;span class="k"&gt;for&lt;/span&gt; OCI &lt;span class="o"&gt;(&lt;/span&gt;CRI-O&lt;span class="o"&gt;)&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Nov &lt;span class="m"&gt;17&lt;/span&gt; 20:29:43 instance-2025-11-16-15-31-55 crio&lt;span class="o"&gt;[&lt;/span&gt;11906&lt;span class="o"&gt;]&lt;/span&gt;: &lt;span class="nv"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;2025-11-17T20:29:43.61758425Z&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;info &lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Using runtime handler lxcri version 8805687&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yeeees :D&lt;/p&gt;
&lt;p&gt;So we can install kubelet, then add it to an existing Kubernetes cluster&lt;/p&gt;
&lt;h2 id="fast-forward"&gt;Fast forward
&lt;/h2&gt;&lt;p&gt;I was too lazy to set up a proper cluster with &lt;a class="link" href="https://blog.zwindler.fr/2023/12/17/kubeadmcfg-introduction-api-kubeadm/" target="_blank" rel="noopener"
&gt;kubeadm or other, and then enroll a node manually with the token+sha&lt;/a&gt;. I could have also replayed with my funny PoC of &lt;a class="link" href="https://blog.zwindler.fr/2025/07/20/kubernetes-sur-clever-cloud-linux/" target="_blank" rel="noopener"
&gt;Clever cloud&amp;rsquo;s &amp;ldquo;linux&amp;rdquo; workers to create a control plane&lt;/a&gt; at Clever, then manually enroll with the node bootstrap token (I did things pretty well in that PoC).&lt;/p&gt;
&lt;p&gt;So I replayed roughly with my &lt;a class="link" href="https://github.com/zwindler/demystifions-kubernetes/tree/main" target="_blank" rel="noopener"
&gt;demystifions-kubernetes&lt;/a&gt; project, which allows you to set up a single-node cluster manually by just running binaries.&lt;/p&gt;
&lt;p&gt;Once the control plane is bootstrapped (etcd, api-server, controller-manager, scheduler), we stop BEFORE the containerd part (we&amp;rsquo;ve already configured cri-o) and manually start kubelet:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo bin/kubelet --kubeconfig admin.conf --container-runtime-endpoint --container-runtime-endpoint=unix:///var/run/crio/crio.sock --fail-swap-on=false --cgroup-driver=&amp;#34;systemd&amp;#34;
[...]
I1117 13:41:58.741561 88434 kubelet_node_status.go:78] &amp;#34;Successfully registered node&amp;#34; node=&amp;#34;instance-2025-11-16-15-31-55&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;rsquo;re making progress! Let&amp;rsquo;s try to see the cluster&amp;rsquo;s health and deploy a pod:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; instance-2025-11-16-15-31-55 Ready &amp;lt;none&amp;gt; 13m v1.34.2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl create deployment web --image&lt;span class="o"&gt;=&lt;/span&gt;zwindler/vhelloworld
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; deployment.apps/web created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; web-6c8cc48c68-cdbtj 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 4m17s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl logs web-6c8cc48c68-cdbtj
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;Vweb&lt;span class="o"&gt;]&lt;/span&gt; Running app on http://localhost:8081/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;Vweb&lt;span class="o"&gt;]&lt;/span&gt; We have &lt;span class="m"&gt;3&lt;/span&gt; workers
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Great success!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;From here, CRI-O functionally shares Proxmox VE&amp;rsquo;s LXC engine.&lt;/p&gt;
&lt;p&gt;To convince yourself, you can run the lxc-ls command, which will display a mix of &amp;ldquo;real&amp;rdquo; LXC containers (created with proxmox, 151 and 200) and pod containers (the STOPPED ones are cilium init containers)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ lxc-ls -f
NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
151 STOPPED 0 - - - true
200 STOPPED 0 - - - true
3045d1f3abcc069b1009acc869a27b09cf9531d0701a3f9d5a760213d57c7b20 STOPPED 0 - - - false
78057100e5d0613944c2be859dfd09f790eeba88bceebea0e04970841c9bd950 RUNNING 0 - 10.0.0.90 - false
8e5506beea9a50214c46f31fa7fa6d04397963cb912aa397261359865d40a0cd RUNNING 0 - 10.0.0.167, 10.244.0.1, 203.0.113.42, 192.168.1.10 2001:db8::1 false
abdcd5be0a27417aa9e11cc2b27882bc86a63d94f547f909332ca7470a5e075a STOPPED 0 - - - false
aeaed9c2f56328bb6196ede4a78f06c4bb2d3edf5dca7912cf38407b9bf6610a STOPPED 0 - - - false
ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d RUNNING 0 - 10.0.0.167, 10.244.0.1, 203.0.113.42, 192.168.1.10 2001:db8::1 false
edb9d42e35a4029cfec5bed5597746bdf67fbe438f21446230252265ed1c849d STOPPED 0 - - - false
$ ps -ef |grep ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d
root 2674943 1 0 22:32 ? 00:00:00 /usr/libexec/crio/conmon -b /run/containers/storage/overlay-containers/ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d/userdata -c ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d --exit-dir /var/run/crio/exits -l /var/log/pods/kube-system_cilium-operator-56d6cd6767-dps78_6082ea2d-331e-4262-b8b3-d3f88eb4e446/cilium-operator/1.log --log-level info -n k8s_cilium-operator_cilium-operator-56d6cd6767-dps78_kube-system_6082ea2d-331e-4262-b8b3-d3f88eb4e446_1 -P /run/containers/storage/overlay-containers/ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d/userdata/conmon-pidfile -p /run/containers/storage/overlay-containers/ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d/userdata/pidfile --persist-dir /var/lib/containers/storage/overlay-containers/ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d/userdata -r /usr/local/bin/lxcri --runtime-arg --root=/var/lib/lxc --socket-dir-path /var/run/crio --syslog -u ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d -s
root 2674951 2674943 0 22:32 ? 00:00:00 /usr/local/libexec/lxcri/lxcri-start ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d /var/lib/lxc /var/lib/lxc/ed9aaf5a0fd4b11be121296290472d6d71d9016e4c6bb0d05fb2e4a7f4b7a85d/config
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nothing would prevent us from pushing it further, and making a small script that retrieves all container information and creates the associated &lt;code&gt;/etc/pve/lxc/xxx.conf&lt;/code&gt; files to display them in the UI, as I did in the article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/en/2022/11/07/running-docker-containers-with-proxmox-ve-and-lxc/" target="_blank" rel="noopener"
&gt;Running Docker containers with Proxmox VE (and LXC)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In theory, if this step made sense, I could create releases myself on my fork to facilitate installation.&lt;/p&gt;
&lt;p&gt;Finally, I could try to contribute my modifications to have everything merged into the main project, except &lt;a class="link" href="https://github.com/lxc/lxcri/issues/67#issuecomment-2055724867" target="_blank" rel="noopener"
&gt;the maintainers refuse PRs because the project is no longer maintained&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But I admit that after probably about fifteen hours of debugging, golang, C compilation, spread over 2 years, I&amp;rsquo;ve kind of reached the end of my patience for this &amp;ldquo;joke&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;OK it was dumb, now that I&amp;rsquo;ve succeeded, time to sleep X_X.&lt;/p&gt;</description></item><item><title>Running Docker containers with Proxmox VE (and LXC)</title><link>https://blog.zwindler.fr/en/2022/11/07/running-docker-containers-with-proxmox-ve-and-lxc/</link><pubDate>Mon, 07 Nov 2022 06:30:00 +0200</pubDate><guid>https://blog.zwindler.fr/en/2022/11/07/running-docker-containers-with-proxmox-ve-and-lxc/</guid><description>&lt;img src="https://blog.zwindler.fr/2019/10/proxmox.webp" alt="Featured image of post Running Docker containers with Proxmox VE (and LXC)" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;I found several tutorials to install Docker (engine) &lt;strong&gt;inside&lt;/strong&gt; an LXC container under Proxmox VE to then run Docker containers inside it. The problem is that you have to log &lt;strong&gt;into&lt;/strong&gt; the LXC container before you can interact with your Docker containers.&lt;/p&gt;
&lt;p&gt;You can also install Docker directly on Proxmox VE but it&amp;rsquo;s not really recommended and you don&amp;rsquo;t have the ease of use of LXC with Proxmox GUI.&lt;/p&gt;
&lt;p&gt;And actually, it turns out you can run Docker images &lt;strong&gt;as the OS&lt;/strong&gt; of an LXC container and thus have Docker controlled by Proxmox. So we won&amp;rsquo;t have 100% identical behavior to if you had done a &lt;code&gt;docker run&lt;/code&gt; on your machine.&lt;/p&gt;
&lt;p&gt;However, we&amp;rsquo;ll gain in exchange a container totally identical to your other LXC containers in your cluster (with all associated functions) but launched with a Docker image.&lt;/p&gt;
&lt;p&gt;But first I suggest we go back a bit before showing you how&amp;hellip;&lt;/p&gt;
&lt;h2 id="context"&gt;Context
&lt;/h2&gt;&lt;p&gt;You know, I&amp;rsquo;ve been doing Proxmox VE for a while. Proxmox VE is a great turnkey and production-ready distribution for server virtualization (it&amp;rsquo;s even hyperconverged if you enable the Ceph part).&lt;/p&gt;
&lt;p&gt;There are lots of little things I like about Proxmox VE, and one of them is that we can create Linux containers with LXC rather than QEMU virtual machines. &lt;a class="link" href="https://blog.zwindler.fr/2022/10/22/proxmox-tips-tricks/" &gt;I wrote an article to talk about it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In use (except for specific kernel configuration), the LXC container behaves strictly identically to a VM in Proxmox, but for a fraction of the resources! We have an OS, we install applications on it, like a VM.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/11/nginx.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An nginx frontend for several applications. The complete LXC container only consumes a few MB&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Admittedly it&amp;rsquo;s much less isolated than a real VM (because it&amp;rsquo;s a container, we&amp;rsquo;re isolated from other processes, but we run on the hypervisor&amp;rsquo;s kernel directly).&lt;/p&gt;
&lt;p&gt;But with so few resource needs, I can host many small applications in different contexts with very small physical machines (Atom 4GB RAM at €6 per month at OneProviders) which would be impossible with a real VM.&lt;/p&gt;
&lt;h2 id="its-good-but-not-enough"&gt;It&amp;rsquo;s good, but not enough
&lt;/h2&gt;&lt;p&gt;However, LXC is not the most known/hyped containerization technology. For years on the forum, whenever people ask for Docker support in Proxmox VE, they get sent away. Not always very nicely either&amp;hellip;&lt;/p&gt;
&lt;p&gt;Yet, there are several reasons to want to run Docker containers on your Proxmox infrastructure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, Docker isn&amp;rsquo;t as much stateless and/or ephemeral workloads as we think. Many containerized applications would have their place on a virtualization cluster.&lt;/li&gt;
&lt;li&gt;Then because many software vendors have become lazy. Some no longer manage installation processes (or only on one OS) and just provide a Docker image that they maintain up to date.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So we have to settle for VMs in Proxmox to run Docker containers (see my point at the beginning).&lt;/p&gt;
&lt;h2 id="lxc-supports-oci-images"&gt;LXC supports OCI images
&lt;/h2&gt;&lt;p&gt;Plot twist. A few days ago, I discovered that LXC, Proxmox VE&amp;rsquo;s containerization engine, was compatible with the OCI format.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.buzzwrd.me/index.php/2021/03/10/creating-lxc-containers-from-docker-and-oci-images/" target="_blank" rel="noopener"
&gt;buzzwrd.me - Creating LXC containers from docker and OCI images&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For those who don&amp;rsquo;t know OCI, it&amp;rsquo;s an organization aiming to create a standard to unify the way containers are stored.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Open Container Initiative is an open governance structure for the express purpose of creating open industry standards around container formats and runtimes.
&lt;a class="link" href="https://opencontainers.org/" target="_blank" rel="noopener"
&gt;opencontainers.org/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And Docker respects this format: we can therefore theoretically run from LXC containers whose base image is a Docker image.&lt;/p&gt;
&lt;h2 id="so-when-do-we-start"&gt;So, when do we start?
&lt;/h2&gt;&lt;p&gt;Disclaimer: what follows is tinkering. Nothing is supported and I don&amp;rsquo;t recommend it in production. There are also likely limitations (especially regarding storage).&lt;/p&gt;
&lt;p&gt;First, some dependencies are missing for LXC&amp;rsquo;s OCI function to be usable under Proxmox VE:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo apt install skopeo umoci jq
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, by default, LXC containers attach to a Linux bridge called &lt;code&gt;lxcbr0&lt;/code&gt;. However this bridge probably doesn&amp;rsquo;t exist on your Proxmox VE installation (not installed by default).&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;quick and dirty&lt;/em&gt;, we can just replace the default name, although ideally we should find the flag in the CLI to change the bridge. Depending on how you configured the network in your Proxmox VE server, you&amp;rsquo;ll probably use &lt;code&gt;vmbr0&lt;/code&gt; or &lt;code&gt;vmbr1&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sed -i &amp;#39;s/lxcbr0/vmbr1/g&amp;#39; /etc/lxc/default.conf
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that we have everything, we can run our LXC containers from docker images. Here I&amp;rsquo;m running the official &lt;code&gt;alpine:latest&lt;/code&gt; image, but I could have taken any other:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;lxc-create 500 -t oci -- --url docker://alpine:latest
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I created a container called &amp;ldquo;500&amp;rdquo; (because VMs and LXC containers in proxmox VE are called with numbers). The image is downloaded then the container created:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/11/lxc_docker_pull.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We can now start it (with &lt;code&gt;lxc-execute&lt;/code&gt; we run the container and open a prompt directly inside it, but we also have &lt;code&gt;lxc-start&lt;/code&gt; and &lt;code&gt;lxc-attach&lt;/code&gt;)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;lxc-execute 500
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/11/alpine.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;As is, Proxmox VE doesn&amp;rsquo;t know our container exists and it won&amp;rsquo;t appear in the UI. But it works ;-).&lt;/p&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;p&gt;We can even cheat and make Proxmox believe it&amp;rsquo;s an LXC container it created itself by creating a &lt;code&gt;500.conf&lt;/code&gt; file, in the &lt;code&gt;/etc/pve/lxc/&lt;/code&gt; folder&lt;/p&gt;
&lt;p&gt;The only mandatory fields are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;arch (amd64 unless you&amp;rsquo;re on ARM)&lt;/li&gt;
&lt;li&gt;cores (the CPU limit to impose on the container)&lt;/li&gt;
&lt;li&gt;hostname&lt;/li&gt;
&lt;li&gt;memory (the RAM limit to impose on the container)&lt;/li&gt;
&lt;li&gt;ostype&lt;/li&gt;
&lt;li&gt;rootfs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/11/lxc_config.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Once the file is created, the container automatically appears in the host&amp;rsquo;s VM list. We can start it and it works :)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/11/docker_lxc_running.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;The container can be started, stopped, etc. All from the Proxmox VE GUI :)&lt;/p&gt;
&lt;p&gt;Have fun!&lt;/p&gt;
&lt;h2 id="source"&gt;Source
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://pve.proxmox.com/wiki/Linux_Container" target="_blank" rel="noopener"
&gt;Proxmox VE - Linux Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://thehomelab.wiki/books/promox-ve/page/setup-and-install-docker-in-a-promox-7-lxc-conainer" target="_blank" rel="noopener"
&gt;Setup and Install Docker in a Promox 7 LXC Conainer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.buzzwrd.me/index.php/2021/03/10/creating-lxc-containers-from-docker-and-oci-images/" target="_blank" rel="noopener"
&gt;buzzwrd.me - Creating LXC containers from docker and OCI images&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Should we have containers ?</title><link>https://blog.zwindler.fr/en/2016/08/25/should-we-have-containers/</link><pubDate>Thu, 25 Aug 2016 16:00:21 +0000</pubDate><guid>https://blog.zwindler.fr/en/2016/08/25/should-we-have-containers/</guid><description>&lt;img src="https://blog.zwindler.fr/2016/08/Fullvirt_containers.webp" alt="Featured image of post Should we have containers ?" /&gt;&lt;h2 id="a-more-complete-answer-to-why-do-we-have-containers-by-fntlnz"&gt;A more complete answer to « Why do we have containers » by fntlnz
&lt;/h2&gt;&lt;p&gt;2 days ago, I stumbled apon &lt;em&gt;fntlnz&lt;/em&gt; article &lt;a class="link" href="https://web.archive.org/web/20161026190150/http://blog.fntlnz.wtf/post/why-containers/" target="_blank" rel="noopener"
&gt;Why do we have containers. (dead link, using Internet Archive)&lt;/a&gt; The article had been reposted by Docker official Twitter account and the first thing that struck me was the displayed image : a schema comparing full virtualization, para virtualization and linux containers.&lt;/p&gt;
&lt;p&gt;And of course, I say this because I didn’t entirely agree with it ;-). But then I read the article and I found many good points.&lt;/p&gt;
&lt;p&gt;So I decided to write « Should we have containers ? » as an answer to develop my remarks a little.&lt;/p&gt;
&lt;h2 id="full-virtualization-vs-paravirtualization-vs-os-level-virtualization"&gt;Full virtualization vs paravirtualization vs OS level virtualization
&lt;/h2&gt;&lt;p&gt;First, I’ll go with the schema. I know the point was to provide a really simple schema to help understand the differences between virtualization types but I don’t think it should be presented like that.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2016/08/Virtualization.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Hypervisor and host OS are both displayed in the full/para. I find this be misleading. Of course there is a Host OS and a virtualization engine on top of it. But most of the time, either the OS is really thin (ESXi fits in 8GB SD cards and runs nothing but virtualization) or the virt engine is a part of the kernel (KVM, Xen) just like LXC is a part of the Linux kernel.&lt;/p&gt;
&lt;p&gt;Also, the bins/libs are only displayed on OS level virt. This is interesting to put in the « host level virtualization schema » but it should be added on full and para as well because this is one of the advantages host level virt. has over full/para.&lt;br&gt;
Even if your VMs are all identicals, bins and libs have to be present (copied) in each VMs. On contrary, in OS Level virt, you CAN share identicals bins/libs between containers, thus reducing the storage footprint of the virtualized environment.&lt;/p&gt;
&lt;p&gt;That’s how I would have presented it&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2016/08/Fullvirt_containers.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;You can see that OS level virtualization and Hypervisors are not so different on this simplified view. The differences appear more clearly when you add x86 Security Rings (0-&amp;gt;3). The « overhead » of full virtualization comes from the calls that guest OSes do to hypervisor pilots and the translation of CPU instructions.&lt;/p&gt;
&lt;p&gt;On a side note, I put Docker on the left to show that it’s basically an administration suite that helps you run LXC containers&lt;/p&gt;
&lt;h2 id="the-rest-of-the-analysis"&gt;The rest of the analysis
&lt;/h2&gt;&lt;h3 id="security"&gt;Security
&lt;/h3&gt;&lt;p&gt;When talking about containers, the security point is often raised.&lt;/p&gt;
&lt;p&gt;VMs are really hermetics. Taking control of the hypervisor after hacking a VM should be MUCH harder than taking control of the host OS if you are inside a container with whom the kernel is shared.&lt;/p&gt;
&lt;p&gt;But I agree with &lt;strong&gt;fntlnz&lt;/strong&gt;: having to patch only one kernel for all your virtual environments instead of having to patch ALL kernels of your virtual machines is actually a good point.&lt;/p&gt;
&lt;p&gt;I encourage you to read &lt;a class="link" href="https://web.archive.org/web/20200925215559/https://2015.rmll.info/IMG/pdf/containers_docker_and_security__state_of_the_union.pdf" target="_blank" rel="noopener"
&gt;this (dead link, using Internet Archive)&lt;/a&gt; from Jérôme Petazzoni if you’d like a good presentation on the subject.&lt;/p&gt;
&lt;h3 id="performance"&gt;Performance
&lt;/h3&gt;&lt;p&gt;A point that’s not really developed in &lt;em&gt;fntlnz&lt;/em&gt; article is performance, but I read it/ear it &lt;strong&gt;all the time&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;General belief is that VMs are slow. That was true in the « early days » of x86 virtualization, because of the limitations of the x86 architectures which didn’t allow efficient OS virtualisation. Overhead for CPU instructions was known to be of about 15% (which is enormous). Thus, running processes directly on the OS are believed to be more efficent.&lt;/p&gt;
&lt;p&gt;But nowadays, modern hypervisors on modern hardware nearly generates no overhead at all over CPU and RAM consumption. You could argue that guest OSes consume ressources while containers don’t. But let’s be honest: with the 32 GB RAM tomcat instances I regularly see, don’t say to me that a Linux guest OS CPU&amp;amp;RAM consumption is significative.&lt;/p&gt;
&lt;p&gt;The real difference is the on the storage consumption. First, for N VMs, you save yourself N*xGB of guest OS files. If your Linux templates are good, you don’t consume that much (a few GB at most) but this can add up when we are talking about thousands of instances. [Edit jan. 2020]Not so true today if you host your own hardware and have so deduplicated storage[/Edit]&lt;/p&gt;
&lt;p&gt;From there, you still have some margin for gains, mostly through &lt;strong&gt;Copy on write and union filesystems&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You make a modification to an official tomcat image to add you configuration files ? Only the delta will be stored.&lt;/li&gt;
&lt;li&gt;You launch thousands of containers from this image ? You only consume the container image once.&lt;/li&gt;
&lt;li&gt;The real data (user data, business data) is of course the same for both architectures&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="so-should-i-use-containers-"&gt;So, should I use containers ?
&lt;/h2&gt;&lt;p&gt;The problem here is that’s not the real question. &lt;strong&gt;Do you need containers ?&lt;/strong&gt; Here’s &lt;em&gt;fntlnz&lt;/em&gt; point of view.**&lt;br&gt;
**&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But if at some extent your motivation consist in &lt;strong&gt;decreasing costs related to full virtualization overheads&lt;/strong&gt; while allowing &lt;strong&gt;developers to ship, develop and test code faster&lt;/strong&gt; we already found two.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fntlnz&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;I won’t tell you not to use containers or Docker. Truth be told, we use it in dev and production. Docker is awesome.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yes, Docker reduces overhead of full virtualization. Storage mostly, but it highly depends on your workload. For example if you have the need for millions of really tiny instances, then Guest OS overhead is significative  in full virtualization.&lt;/li&gt;
&lt;li&gt;Yes, Docker allows developers to ship, develop and test code faster. You still have to change your way to develop yours app but Docker and DevOps is the new thing. Better get on with it ;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But you shouldn’t use Docker just because of that. Docker containers need you to change your philosophy toward applications and administration.&lt;/p&gt;
&lt;h3 id="shared-kernel--same-kernel-"&gt;Shared kernel = same kernel~~ ~~
&lt;/h3&gt;&lt;p&gt;You need to understand that you’ll share a kernel. For a long time that ment a 100% Linux only which could be problematic in some cases. I just realized that Windows containers exists in Windows 2016 tech preview. And Solaris is coming.&lt;/p&gt;
&lt;p&gt;But independantly of platforms, you still you share a kernel. If you want Linux containers, you’ll need Linux Docker nodes. If you need Windows containers, you’ll have to have Windows Docker nodes.&lt;/p&gt;
&lt;h3 id="non-persistantcloud-ready-instances"&gt;Non-persistant/cloud-ready instances
&lt;/h3&gt;&lt;p&gt;Docker containers are by design non-persistant and by best practice single-process. This isn’t mandatory of course, but Docker works better that way.&lt;/p&gt;
&lt;p&gt;The whole idea is to help you make « cloud-ready » &amp;amp; atomic applications that don’t store anything in the container itself (persistant storage is presented to the container but outside it). This way, you can scale out really quickly: you just start up a few more instances if you need more firepower.&lt;/p&gt;
&lt;p&gt;This also modifies the way you do systems/applications administration. A container/application is spinning out of control ? Don’t try to repair it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kill it&lt;/li&gt;
&lt;li&gt;Launch a new one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The fact that persistant storage is handled outside the containers also helps you to deal with lifecycle management.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update your application inside the docker image&lt;/li&gt;
&lt;li&gt;Shutdown the old container&lt;/li&gt;
&lt;li&gt;Start the new container with the new image, plugged to the persistant storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All that requires of course applications that have been designed this way! This is a massive change in philosophy and old monolithic apps on a Docker platform won’t work as well as microservices will.&lt;/p&gt;
&lt;h3 id="system-administration"&gt;System administration
&lt;/h3&gt;&lt;p&gt;I don’t say solutions don’t exist because they do.&lt;/p&gt;
&lt;p&gt;But starting up and shutting down containers on the fly will give headaches to your « old school Nagios » monitoring administrator. What could be done easily in the physical/VM world (installing an agent in the template), each of those having an IP adress to query for health checks is a lot easier than checking on a single host a highly volatile number of isolated processes.&lt;/p&gt;
&lt;p&gt;You’ll probably have to adapt and use tools that are designed to handle such cases.&lt;/p&gt;
&lt;p&gt;Backup administrator may find it confusing at first to make application consistant data backups when applications are running in an variable number of containers.&lt;/p&gt;
&lt;p&gt;And so on&amp;hellip;&lt;/p&gt;
&lt;h2 id="final-thoughts"&gt;Final thoughts
&lt;/h2&gt;&lt;p&gt;Yes, you should definitely &lt;em&gt;look into&lt;/em&gt; containers. They are mature, stable, a great new way to speed up development and contribute to save money on hardware.&lt;/p&gt;
&lt;p&gt;But be aware that VMs and containers don’t answer all usecases; and that you won’t migrate all your applications overnight!&lt;/p&gt;</description></item></channel></rss>