diff --git a/index.ts b/index.ts index 24ac30d..3d54d0f 100644 --- a/index.ts +++ b/index.ts @@ -14,6 +14,7 @@ import { setupForgejo } from "./services/forgejo/index.js"; import { setupDhcpcd } from "./services/dhcpcd.js"; import { setupNtpsec } from "./services/ntpsec.js"; import { setupGrafana } from "./services/grafana/index.js"; +import { setupLoki } from "./services/loki/index.js"; if (process.argv[2] === "generate-secrets") { await generateForgejoSecretsFile(); @@ -39,6 +40,7 @@ if (process.argv[2] === "generate-secrets") { await setupDhcpcd(alpine, runit); await setupNtpsec(alpine, runit); await setupForgejo(alpine, runit); + await setupLoki(alpine, runit); await setupGrafana(alpine, runit); const kernel = await setupKernel(alpine, kernelDir); diff --git a/services/loki/build.ts b/services/loki/build.ts new file mode 100644 index 0000000..17a3f2b --- /dev/null +++ b/services/loki/build.ts @@ -0,0 +1,52 @@ +import { chmod, mkdir, readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { reproRun } from "../../helpers/repro-run.js"; + +const LOKI_VERSION = "v2.7.3"; + +// returns path to statically compiled binary +export async function buildLoki(): Promise { + const dir = "cache/loki"; + await mkdir(dir, { recursive: true }); + const versionFile = join(dir, "version"); + const output = join(dir, "rootfs/loki"); + try { + if ((await readFile(versionFile, "utf-8")) === LOKI_VERSION) return output; + } catch {} + + { + const buildScript = join(dir, "build"); + await writeFile( + buildScript, + `#!/bin/sh -e +runprint() { + echo "==> $@" + "$@" +} + +runprint apk add --quiet git go make libc-dev bash + +git config --global advice.detachedHead false +# TODO: cachear clon de repo +runprint git clone https://github.com/grafana/loki --branch '${LOKI_VERSION}' --depth 1 --single-branch +cd loki + +runprint make -j1 GOMOD=readonly logcli loki +mv cmd/loki/loki /loki +` + ); + await chmod(buildScript, 0o700); + } + await reproRun({ + cwd: dir, + command: "/src/build", + cache: [ + "/home/repro/.cache/go-build", + "/home/repro/go", + "/home/repro/.npm", + ], + }); + await writeFile(versionFile, LOKI_VERSION); + + return output; +} diff --git a/services/loki/index.ts b/services/loki/index.ts new file mode 100644 index 0000000..6c5bea3 --- /dev/null +++ b/services/loki/index.ts @@ -0,0 +1,79 @@ +import { join } from "node:path"; +import { Alpine } from "../../alpine.js"; +import { sudoCopy } from "../../helpers/sudo.js"; +import { Runit } from "../../runit/index.js"; +import { buildLoki } from "./build.js"; + +export async function setupLoki(alpine: Alpine, runit: Runit): Promise { + const bin = await buildLoki(); + await sudoCopy(bin, join(alpine.dir, "/usr/local/bin/loki")); + + const user = await alpine.userAdd("loki"); + + // TODO: data + // await alpine.fstab.addTmpfs("/var/lib/grafana", { + // uid: user.uid, + // gid: user.gid, + // mode: "700", + // }); + const configPath = "/etc/loki/loki-local-config.yaml"; + await alpine.writeFile( + configPath, + ` +auth_enabled: false + +server: + http_listen_port: 3100 + grpc_listen_port: 9096 + +common: + instance_addr: 127.0.0.1 + path_prefix: /tmp/loki + storage: + filesystem: + chunks_directory: /tmp/loki/chunks + rules_directory: /tmp/loki/rules + replication_factor: 1 + ring: + kvstore: + store: inmemory + +query_range: + results_cache: + cache: + embedded_cache: + enabled: true + max_size_mb: 100 + +schema_config: + configs: + - from: 2020-10-24 + store: boltdb-shipper + object_store: filesystem + schema: v11 + index: + prefix: index_ + period: 24h + +# ruler: +# alertmanager_url: http://localhost:9093 + +analytics: + reporting_enabled: false`, + user + ); + + // await alpine.sudoWriteExecutable( + // "/usr/local/sbin/nulo-grafana-cli", + // `#!/bin/sh + // cd / + // exec chpst -u grafana:grafana grafana-cli --homepath /usr/share/grafana --config /etc/grafana.ini "$@"` + // ); + + await runit.addService( + "loki", + `#!/bin/sh +exec chpst -u ${user.name}:${user.name} /usr/local/bin/loki -config.file='${configPath}' +` + ); +}