<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://ohcnwiki.tellmey.fyi/index.php?action=history&amp;feed=atom&amp;title=Deployment%2FKubernetes%2FProvisioning_the_cluster</id>
	<title>Deployment/Kubernetes/Provisioning the cluster - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://ohcnwiki.tellmey.fyi/index.php?action=history&amp;feed=atom&amp;title=Deployment%2FKubernetes%2FProvisioning_the_cluster"/>
	<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=Deployment/Kubernetes/Provisioning_the_cluster&amp;action=history"/>
	<updated>2026-07-06T05:20:15Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.4</generator>
	<entry>
		<id>https://ohcnwiki.tellmey.fyi/index.php?title=Deployment/Kubernetes/Provisioning_the_cluster&amp;diff=399&amp;oldid=prev</id>
		<title>Admin: Add Navbox deployment template before Related (via update-page on MediaWiki MCP Server)</title>
		<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=Deployment/Kubernetes/Provisioning_the_cluster&amp;diff=399&amp;oldid=prev"/>
		<updated>2026-07-06T04:02:14Z</updated>

		<summary type="html">&lt;p&gt;Add Navbox deployment template before Related (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 09:32, 6 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 177:&lt;/td&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 177:&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;At this point you have a running cluster with networking and storage: nodes joined and labelled, namespaces created, Cilium providing pod networking, and Longhorn providing persistent volumes. The remaining work — ingress controllers, the image registry, PostgreSQL and Redis/Valkey, the RustFS object store, monitoring, and the Care backend and frontend themselves — is covered in [[Deployment/Kubernetes/Deploying Care onto the cluster|Deploying Care onto the cluster]].&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;At this point you have a running cluster with networking and storage: nodes joined and labelled, namespaces created, Cilium providing pod networking, and Longhorn providing persistent volumes. The remaining work — ingress controllers, the image registry, PostgreSQL and Redis/Valkey, the RustFS object store, monitoring, and the Care backend and frontend themselves — is covered in [[Deployment/Kubernetes/Deploying Care onto the cluster|Deploying Care onto the cluster]].&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-empty diff-side-deleted&quot;&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-empty diff-side-deleted&quot;&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Navbox deployment}}&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Related}}&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Related}}&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://ohcnwiki.tellmey.fyi/index.php?title=Deployment/Kubernetes/Provisioning_the_cluster&amp;diff=203&amp;oldid=prev</id>
		<title>Admin: OHC identity seed</title>
		<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=Deployment/Kubernetes/Provisioning_the_cluster&amp;diff=203&amp;oldid=prev"/>
		<updated>2026-07-04T23:07:42Z</updated>

		<summary type="html">&lt;p&gt;OHC identity seed&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Doc header&lt;br /&gt;
|type=guide&lt;br /&gt;
|domain=deployment&lt;br /&gt;
|title=Provisioning the cluster&lt;br /&gt;
|order=4&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
This page describes how the Kubernetes cluster that hosts Care is brought up: installing the container runtime and Kubernetes packages on each node, initializing the control plane with &amp;lt;code&amp;gt;kubeadm&amp;lt;/code&amp;gt;, labelling nodes, creating the application namespaces, and installing the cluster-level add-ons (the Cilium CNI and Longhorn storage). Once the cluster and these foundations are in place, the application stack is rolled out as described in [[Deployment/Kubernetes/Deploying Care onto the cluster|Deploying Care onto the cluster]].&lt;br /&gt;
&lt;br /&gt;
{{Warning|1=Exact node names, IP addresses, internal DNS names, public domains, TLS certificates, and object-store endpoints are environment-specific and live in the [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/deployment-k8 &amp;lt;code&amp;gt;ohcnetwork/deployment-k8&amp;lt;/code&amp;gt;] repository. The commands below use neutral placeholders such as &amp;lt;code&amp;gt;&amp;amp;lt;primary-node&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;lt;secondary-node&amp;amp;gt;&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;kube-api.internal&amp;lt;/code&amp;gt;. Do not copy real secrets or hostnames out of one environment into another — substitute the values for the cluster you are building.}}&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
The reference cluster is two Ubuntu nodes on the same network — one &amp;#039;&amp;#039;&amp;#039;primary&amp;#039;&amp;#039;&amp;#039; (control plane) and one &amp;#039;&amp;#039;&amp;#039;secondary&amp;#039;&amp;#039;&amp;#039; failover node — provisioned with &amp;lt;code&amp;gt;kubeadm&amp;lt;/code&amp;gt;. Each node needs the same base packages installed before it can join the cluster:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt-get install -y apt-transport-https ca-certificates curl gpg&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== 1. Install the container runtime ==&lt;br /&gt;
&lt;br /&gt;
Care uses &amp;#039;&amp;#039;&amp;#039;containerd&amp;#039;&amp;#039;&amp;#039; as the container runtime, installed from the Docker apt repository. Run the following on every node.&lt;br /&gt;
&lt;br /&gt;
Add the Docker apt repository and install the runtime packages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;# Add Docker&amp;#039;s official GPG key&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt install ca-certificates curl&lt;br /&gt;
sudo install -m 0755 -d /etc/apt/keyrings&lt;br /&gt;
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc&lt;br /&gt;
sudo chmod a+r /etc/apt/keyrings/docker.asc&lt;br /&gt;
&lt;br /&gt;
# Add the repository to apt sources&lt;br /&gt;
sudo tee /etc/apt/sources.list.d/docker.sources &amp;lt;&amp;lt;EOF&lt;br /&gt;
Types: deb&lt;br /&gt;
URIs: https://download.docker.com/linux/ubuntu&lt;br /&gt;
Suites: $(. /etc/os-release &amp;amp;&amp;amp; echo &amp;quot;${UBUNTU_CODENAME:-$VERSION_CODENAME}&amp;quot;)&lt;br /&gt;
Components: stable&lt;br /&gt;
Signed-By: /etc/apt/keyrings/docker.asc&lt;br /&gt;
EOF&lt;br /&gt;
&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Enable the systemd cgroup driver in containerd so it matches the kubelet&amp;#039;s cgroup management:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;containerd config default &amp;gt; config.toml&lt;br /&gt;
sudo mv config.toml /etc/containerd/config.toml&lt;br /&gt;
sudo sed -i &amp;quot;s/SystemdCgroup = false/SystemdCgroup = true/g&amp;quot; /etc/containerd/config.toml&lt;br /&gt;
sudo systemctl restart containerd&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Raise the inotify limits. Kubernetes and the workloads that run on it open a large number of file watches, and the defaults are easily exhausted:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;sudo sysctl fs.inotify.max_user_instances=1280&lt;br /&gt;
sudo sysctl fs.inotify.max_user_watches=655360&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Tip|1=The &amp;lt;code&amp;gt;sysctl&amp;lt;/code&amp;gt; commands above take effect immediately but are not persistent. To survive reboots, write the same &amp;lt;code&amp;gt;fs.inotify.*&amp;lt;/code&amp;gt; keys into a file under &amp;lt;code&amp;gt;/etc/sysctl.d/&amp;lt;/code&amp;gt;.}}&lt;br /&gt;
&lt;br /&gt;
== 2. Install the Kubernetes packages ==&lt;br /&gt;
&lt;br /&gt;
Install &amp;lt;code&amp;gt;kubelet&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kubeadm&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;kubectl&amp;lt;/code&amp;gt; from the upstream Kubernetes apt repository. The cluster is pinned to the &amp;#039;&amp;#039;&amp;#039;v1.34&amp;#039;&amp;#039;&amp;#039; package line — keep the repository path and the installed version on the same line across all nodes.&lt;br /&gt;
&lt;br /&gt;
Add the Kubernetes signing key and apt source:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
echo &amp;#039;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /&amp;#039; | sudo tee /etc/apt/sources.list.d/kubernetes.list&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Install the packages and hold them so they are not upgraded out of band:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt-get update&lt;br /&gt;
sudo apt-get install -y kubelet kubeadm kubectl&lt;br /&gt;
sudo apt-mark hold kubelet kubeadm kubectl&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note|1=The reference cluster runs &amp;#039;&amp;#039;&amp;#039;with swap enabled&amp;#039;&amp;#039;&amp;#039;. The &amp;lt;code&amp;gt;kubeadm&amp;lt;/code&amp;gt; configuration sets &amp;lt;code&amp;gt;failSwapOn: false&amp;lt;/code&amp;gt; and enables the &amp;lt;code&amp;gt;NodeSwap&amp;lt;/code&amp;gt; feature gate with &amp;lt;code&amp;gt;LimitedSwap&amp;lt;/code&amp;gt; behaviour, so the kubelet tolerates swap rather than refusing to start. This is intentional for these nodes — see the &amp;lt;code&amp;gt;KubeletConfiguration&amp;lt;/code&amp;gt; block in &amp;lt;code&amp;gt;kubeadm.yaml&amp;lt;/code&amp;gt;.}}&lt;br /&gt;
&lt;br /&gt;
== 3. Initialize the control plane ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;kubeadm&amp;lt;/code&amp;gt; is driven by the checked-in &amp;lt;code&amp;gt;kubeadm.yaml&amp;lt;/code&amp;gt;, which defines the control-plane endpoint (&amp;lt;code&amp;gt;controlPlaneEndpoint&amp;lt;/code&amp;gt;), the API server certificate SANs, the Kubernetes version, and the pod and service subnets. On the primary node, initialize the cluster:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;sudo kubeadm init --config kubeadm.yaml&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When &amp;lt;code&amp;gt;kubeadm init&amp;lt;/code&amp;gt; finishes it prints a &amp;lt;code&amp;gt;kubeadm join&amp;lt;/code&amp;gt; command containing the API server address, token, and CA certificate hash. Run that printed command on each worker/secondary node to join it to the cluster:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;# Example shape only — use the exact command printed by `kubeadm init`&lt;br /&gt;
sudo kubeadm join &amp;lt;control-plane-endpoint&amp;gt;:6443 --token &amp;lt;token&amp;gt; \&lt;br /&gt;
  --discovery-token-ca-cert-hash sha256:&amp;lt;hash&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note|1=The pod and service CIDRs are defined in &amp;lt;code&amp;gt;kubeadm.yaml&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;networking.podSubnet&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;networking.serviceSubnet&amp;lt;/code&amp;gt;). The CNI installed in step 6 must agree with these values, which is why Cilium is configured with &amp;lt;code&amp;gt;ipam.mode=kubernetes&amp;lt;/code&amp;gt; — it uses the pod CIDR that &amp;lt;code&amp;gt;kubeadm&amp;lt;/code&amp;gt; allocated.}}&lt;br /&gt;
&lt;br /&gt;
== 4. Make the control-plane node schedulable ==&lt;br /&gt;
&lt;br /&gt;
By default &amp;lt;code&amp;gt;kubeadm&amp;lt;/code&amp;gt; taints the control-plane node so no application pods land on it. Because the reference cluster is small and the primary node is expected to run workloads, remove the control-plane and not-ready taints to make it schedulable. The trailing &amp;lt;code&amp;gt;-&amp;lt;/code&amp;gt; removes the taint:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;kubectl taint node &amp;lt;primary-node&amp;gt; node-role.kubernetes.io/control-plane:NoSchedule-&lt;br /&gt;
kubectl taint node &amp;lt;primary-node&amp;gt; node.kubernetes.io/not-ready:NoSchedule-&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== 5. Label the nodes ==&lt;br /&gt;
&lt;br /&gt;
The deployer pins workloads and ingress to specific nodes using labels. Apply role and ingress labels so scheduling and ingress placement are deterministic. Use &amp;lt;code&amp;gt;--overwrite=True&amp;lt;/code&amp;gt; to make the commands idempotent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;# Ingress placement&lt;br /&gt;
kubectl label node &amp;lt;primary-node&amp;gt; ingress=private&lt;br /&gt;
kubectl label node &amp;lt;secondary-node&amp;gt; ingress=private&lt;br /&gt;
&lt;br /&gt;
kubectl label node &amp;lt;primary-node&amp;gt; onlyingress=nope --overwrite=True&lt;br /&gt;
kubectl label node &amp;lt;secondary-node&amp;gt; onlyingress=nope --overwrite=True&lt;br /&gt;
&lt;br /&gt;
# Node roles&lt;br /&gt;
kubectl label node &amp;lt;primary-node&amp;gt; ohn/role=primary --overwrite=True&lt;br /&gt;
kubectl label node &amp;lt;secondary-node&amp;gt; ohn/role=secondary --overwrite=True&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note|1=A cloud-only ingress node (a node labelled &amp;lt;code&amp;gt;ingress=public&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;onlyingress=yes&amp;lt;/code&amp;gt;) is part of the intended topology but is commented out in the source today. Treat the public-ingress node as environment-specific: add it only if your topology includes a dedicated cloud ingress node.}}&lt;br /&gt;
&lt;br /&gt;
== 6. Create the application namespaces ==&lt;br /&gt;
&lt;br /&gt;
Create one namespace per application area. The deployer expects these to exist before it applies any resources:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;kubectl create namespace care-be&lt;br /&gt;
kubectl create namespace care-fe&lt;br /&gt;
kubectl create namespace odoo&lt;br /&gt;
kubectl create namespace metabase&lt;br /&gt;
kubectl create namespace rustfs&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Namespace&lt;br /&gt;
! Holds&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;care-be&amp;lt;/code&amp;gt;&lt;br /&gt;
| Care backend (API, workers)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;care-fe&amp;lt;/code&amp;gt;&lt;br /&gt;
| Care frontend&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;odoo&amp;lt;/code&amp;gt;&lt;br /&gt;
| Odoo&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;metabase&amp;lt;/code&amp;gt;&lt;br /&gt;
| Metabase analytics&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rustfs&amp;lt;/code&amp;gt;&lt;br /&gt;
| RustFS object store&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 7. Install the Cilium CNI ==&lt;br /&gt;
&lt;br /&gt;
The cluster has no pod networking until a CNI is installed. Care uses &amp;#039;&amp;#039;&amp;#039;Cilium&amp;#039;&amp;#039;&amp;#039;, installed with the Cilium CLI.&lt;br /&gt;
&lt;br /&gt;
The cluster API host is reached through an internal DNS name rather than a raw IP, so that name must resolve on every node. Add an entry mapping the API name to the primary node&amp;#039;s IP in &amp;lt;code&amp;gt;/etc/hosts&amp;lt;/code&amp;gt; on &amp;#039;&amp;#039;&amp;#039;each&amp;#039;&amp;#039;&amp;#039; node before installing Cilium:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;# /etc/hosts on every node&lt;br /&gt;
&amp;lt;primary-node-ip&amp;gt;   kube-api.internal&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Install the Cilium CLI (architecture-aware) and then install Cilium itself, pointing it at the internal API name and the pod CIDR allocated by &amp;lt;code&amp;gt;kubeadm&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)&lt;br /&gt;
CLI_ARCH=amd64&lt;br /&gt;
if [ &amp;quot;$(uname -m)&amp;quot; = &amp;quot;aarch64&amp;quot; ]; then CLI_ARCH=arm64; fi&lt;br /&gt;
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}&lt;br /&gt;
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum&lt;br /&gt;
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin&lt;br /&gt;
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}&lt;br /&gt;
&lt;br /&gt;
cilium install \&lt;br /&gt;
  --set k8sServiceHost=kube-api.internal \&lt;br /&gt;
  --set k8sServicePort=6443 \&lt;br /&gt;
  --set ipam.mode=kubernetes&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Warning|1=&amp;lt;code&amp;gt;kube-api.internal&amp;lt;/code&amp;gt; is a placeholder for the cluster&amp;#039;s real internal API DNS name, which is defined in the deployment-k8 repo (and listed among the API server certificate SANs in &amp;lt;code&amp;gt;kubeadm.yaml&amp;lt;/code&amp;gt;). Use the actual name for your environment, and make sure the matching &amp;lt;code&amp;gt;/etc/hosts&amp;lt;/code&amp;gt; entry exists on every node — Cilium pods will not come up if the API host does not resolve.}}&lt;br /&gt;
&lt;br /&gt;
== 8. Install Longhorn for storage ==&lt;br /&gt;
&lt;br /&gt;
Persistent volumes are provided by &amp;#039;&amp;#039;&amp;#039;Longhorn&amp;#039;&amp;#039;&amp;#039;, installed through the deployer. The deployer splits work into a &amp;lt;code&amp;gt;apply-tofu&amp;lt;/code&amp;gt; phase (provision the underlying resources with OpenTofu) and an &amp;lt;code&amp;gt;apply-k8&amp;lt;/code&amp;gt; phase (apply the Kubernetes manifests).&lt;br /&gt;
&lt;br /&gt;
Provision Longhorn:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;python deployer.py apply-tofu volumes&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Once Longhorn is installed, configure the nodes and storage classes as needed in the Longhorn UI or manifests. Longhorn can also back up volumes to an S3-compatible target; if you use that, create the backup-target credentials as a secret in the &amp;lt;code&amp;gt;longhorn-system&amp;lt;/code&amp;gt; namespace (generalize the endpoint, region, and keys for your environment):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;kubectl create secret generic &amp;lt;backup-secret-name&amp;gt; -n longhorn-system \&lt;br /&gt;
  --from-literal=AWS_ACCESS_KEY_ID=XXX \&lt;br /&gt;
  --from-literal=AWS_SECRET_ACCESS_KEY=XXX \&lt;br /&gt;
  --from-literal=AWS_ENDPOINTS=&amp;lt;s3-endpoint&amp;gt; \&lt;br /&gt;
  --from-literal=AWS_REGION=&amp;lt;s3-region&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then apply the remaining Longhorn Kubernetes resources:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;python deployer.py apply-k8 volumes&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Tip|1=After installing Longhorn, wait a couple of minutes before relying on it. Longhorn needs time to detect the nodes&amp;#039; disks and build the additional metadata it requires before it can serve volumes reliably.}}&lt;br /&gt;
&lt;br /&gt;
== Next steps ==&lt;br /&gt;
&lt;br /&gt;
At this point you have a running cluster with networking and storage: nodes joined and labelled, namespaces created, Cilium providing pod networking, and Longhorn providing persistent volumes. The remaining work — ingress controllers, the image registry, PostgreSQL and Redis/Valkey, the RustFS object store, monitoring, and the Care backend and frontend themselves — is covered in [[Deployment/Kubernetes/Deploying Care onto the cluster|Deploying Care onto the cluster]].&lt;br /&gt;
&lt;br /&gt;
{{Related}}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>