Compare commits

..

5 Commits

Author SHA1 Message Date
Thomas Rijpstra 4abf8bc6a9
wip 2025-03-07 19:12:54 +01:00
Thomas Rijpstra d726c0f4a3
WIP 2025-03-06 19:46:23 +01:00
Thomas Rijpstra d348029f3b
WIP 2025-03-01 16:24:28 +01:00
Thomas Rijpstra df5c5b9a8e
WIP 2025-02-22 11:55:35 +01:00
Thomas Rijpstra 8d6cd81788
WIP 2025-02-22 11:55:14 +01:00
2 changed files with 70 additions and 115 deletions

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="009bc178-658e-4c81-9bb8-8d7bf6b8cbc6" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/../infra/clusters/app-365zon/.terraform/terraform.tfstate" beforeDir="false" afterPath="$PROJECT_DIR$/../infra/clusters/app-365zon/.terraform/terraform.tfstate" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../infra/clusters/app-365zon/main.tf" beforeDir="false" afterPath="$PROJECT_DIR$/../infra/clusters/app-365zon/main.tf" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../infra/modules/mijn-365zon-nl/main.tf" beforeDir="false" afterPath="$PROJECT_DIR$/../infra/modules/mijn-365zon-nl/main.tf" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../infra/modules/minio/main.tf" beforeDir="false" afterPath="$PROJECT_DIR$/../infra/modules/minio/main.tf" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../infra/modules/minio/values.yaml.tftpl" beforeDir="false" afterPath="$PROJECT_DIR$/../infra/modules/minio/values.yaml.tftpl" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../infra/modules/minio/variables.tf" beforeDir="false" afterPath="$PROJECT_DIR$/../infra/modules/minio/variables.tf" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../infra/modules/mongodb/values.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/../infra/modules/mongodb/values.yaml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 1
}</component>
<component name="ProjectId" id="2oqTXEtODybqnAKfjaqPi9uslRP" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"git-widget-placeholder": "main",
"last_opened_file_path": "/home/lamelos/Projects/fourlights/devops",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"vue.rearranger.settings.migration": "true"
}
}]]></component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-js-predefined-d6986cc7102b-deb605915726-JavaScript-WS-243.22562.222" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="009bc178-658e-4c81-9bb8-8d7bf6b8cbc6" name="Changes" comment="" />
<created>1731596143702</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1731596143702</updated>
<workItem from="1731596144788" duration="1417000" />
<workItem from="1736261138378" duration="1228000" />
<workItem from="1736775177111" duration="7000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
</project>

View File

@ -1,115 +0,0 @@
#!/usr/bin/env -S deno run --allow-run --allow-read --allow-write
import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts";
const setupCluster = async (numMasters: number) => {
// Step 1: Create Low-Resource Profile (if not exists)
const profileExists = await Deno.run({
cmd: ["incus", "profile", "show", "low-resource"],
stdout: "null",
stderr: "null",
}).status().then((status) => status.success);
if (!profileExists) {
await Deno.run({
cmd: ["incus", "profile", "create", "low-resource"],
}).status();
await Deno.run({
cmd: ["incus", "profile", "set", "low-resource", "limits.cpu=1", "limits.memory=512MB"],
}).status();
await Deno.run({
cmd: ["incus", "profile", "device", "add", "low-resource", "root", "disk", "pool=default", "path=/"],
}).status();
await Deno.run({
cmd: ["incus", "profile", "device", "add", "low-resource", "eth-0", "nic", "network=incusbr0"],
}).status();
console.log("✅ Low-resource profile created.");
} else {
console.log("⏩ Low-resource profile already exists.");
}
// Step 3: Launch VMs (if not already running)
for (let i = 1; i <= numMasters; i++) {
const vmName = `k3s-master${i}`;
const vmExists = await Deno.run({
cmd: ["incus", "list", vmName, "--format", "csv"],
stdout: "piped",
}).output().then((output) => new TextDecoder().decode(output).trim() !== "");
if (!vmExists) {
await Deno.run({
cmd: ["incus", "launch", "images:alpine/edge/cloud", vmName, "--profile", "low-resource"],
}).status();
console.log(`✅ VM ${vmName} launched.`);
} else {
console.log(`⏩ VM ${vmName} already exists.`);
}
}
// Step 4: Install k3sup (if not installed)
const k3supInstalled = await Deno.run({
cmd: ["which", "k3sup"],
stdout: "null",
stderr: "null",
}).status().then((status) => status.success);
if (!k3supInstalled) {
await Deno.run({
cmd: ["sh", "-c", "curl -sLS https://get.k3sup.dev | sh"],
}).status();
console.log("✅ k3sup installed.");
} else {
console.log("⏩ k3sup already installed.");
}
// Step 5: Bootstrap First Master Node (if not already bootstrapped)
const firstMasterIP = await Deno.run({
cmd: ["incus", "list", "k3s-master1", "--format", "csv", "--columns", "n4"],
stdout: "piped",
}).output().then((output) => new TextDecoder().decode(output).trim().split(",")[1].split(" ")[0])
const kubeconfigExists = await Deno.stat("./kubeconfig").then(() => true).catch(() => false);
if (!kubeconfigExists) {
await Deno.run({
cmd: ["k3sup", "install", "--ip", firstMasterIP, "--user", "root", "--cluster"],
}).status();
console.log("✅ First master node bootstrapped.");
} else {
console.log("⏩ First master node already bootstrapped.");
}
// Step 6: Join Additional Master Nodes (if not already joined)
for (let i = 2; i <= numMasters; i++) {
const vmName = `k3s-master${i}`;
const vmIP = await Deno.run({
cmd: ["incus", "list", vmName, "--format", "csv", "--columns", "n4"],
stdout: "piped",
}).output().then((output) => new TextDecoder().decode(output).trim().split(",")[1].split(" ")[0])
const joined = await Deno.run({
cmd: ["kubectl", "get", "nodes", vmName],
stdout: "null",
stderr: "null",
}).status().then((status) => status.success);
if (!joined) {
await Deno.run({
cmd: ["k3sup", "join", "--ip", vmIP, "--server-ip", firstMasterIP, "--user", "root"],
}).status();
console.log(`✅ VM ${vmName} joined the cluster.`);
} else {
console.log(`⏩ VM ${vmName} already joined the cluster.`);
}
}
console.log("🚀 HA k3s cluster setup complete!");
};
await new Command()
.name("setup-k3s-cluster")
.version("0.1.0")
.description("Automate the setup of an HA k3s cluster using incus and k3sup")
.option("-m, --masters <numMasters:number>", "Number of master nodes", { default: 3 })
.action(({ masters }) => setupCluster(masters))
.parse(Deno.args);