Kedge Quickstart

bcjordan1 pts0 comments

kedge — docs — quickstart

Publish a static page:

echo '# Hello, world!' | ssh kedge.dev

Your SSH key identifies your account. Markdown becomes HTML.

a function

Add a #! shebang to publish a script that runs on each request:

printf '#!/bin/bash \n uptime' | ssh kedge.dev

the kedge shortcut

Install the optional kedge shortcut, a small wrapper around<br>ssh kedge.dev:

ssh kedge.dev setup | sh

It also adds kedge up, a Git commit-and-push helper for source directories.

a routed site

Deploy a directory, and the files become a route tree:

~/quickstart-site$ show index.html about/index.html<br>── index.html<br>h1>Field notesh1><br>p>A tiny site with more than one route.p><br>a href="/about/">How this site works →a>

── about/index.html<br>h1>About this siteh1><br>p>The directory tree becomes the URL tree.p><br>a href="/">← Back homea>

~/quickstart-site$ kedge up<br>index.html serves /; about/index.html serves /about/. kedge up<br>derives a default app name from the working directory.

Switch branches for an isolated preview:

~/quickstart-site$ show about/index.html<br>── about/index.html<br>h1>Previewing a new routeh1><br>p>This only exists on the code>tweakcode> branch.p><br>a href="/">← Back homea>

~/quickstart-site$ kedge up<br>The preview gets its own URL; main stays live.

an HTML app

Add data-kedge to ordinary HTML for shared, live data without writing an<br>application server, SQL, or JavaScript.

~/quickstart-clicks$ show index.html<br>── index.html

title>Clickstitle><br>h1>Clicksh1>

strong data-kedge="counters/home">{{clicks | plural:click}}strong><br>button data-kedge="counters/home?$increment=clicks">add onebutton>

~/quickstart-clicks$ kedge up<br>At deploy time, Kedge parses the bindings, creates the counter column, and<br>manages the underlying database. Increments merge without losing simultaneous<br>clicks, and bound values update live. See HTML apps for a<br>more detailed example.

a database and a filesystem

Every app has /shared.db and /shared/, ordinary local paths for state that<br>needs code. Two handlers, the same rollup:

~/quickstart-state$ show index.sh files.sh<br>── index.sh<br>#!/usr/bin/env bash<br>agent=${HTTP_USER_AGENT//"'"/"''"}<br>printf 'Content-Type: text/plain\n\n'<br>sqlite3 -header /shared.db "<br>CREATE TABLE IF NOT EXISTS hits(<br>id INTEGER PRIMARY KEY, dc TEXT, agent TEXT, at TEXT DEFAULT (datetime('now')));<br>INSERT INTO hits(dc, agent) VALUES('$KEDGE_DC', '$agent');<br>SELECT dc, count(*) AS hits, max(at) AS latest, agent<br>FROM hits GROUP BY dc, agent ORDER BY hits DESC;"

── files.sh<br>#!/usr/bin/env bash<br>echo "$KEDGE_DC $HTTP_USER_AGENT" >> /shared/agents.log<br>printf 'Content-Type: text/plain\n\n'<br>sort /shared/agents.log | uniq -c | sort -rn

~/quickstart-state$ kedge up<br>/ groups the request log in SQL; /files appends a line and counts it with<br>sort | uniq -c. Both replicate across instances and regions. Use the database<br>when you want a query or an index. See shared data.

an app built from source

Kedge detects common frameworks and builds them from source. This Rust service<br>reports its optimized binary and resident-memory sizes:

~/quickstart-rust$ show src/main.rs Cargo.toml<br>── src/main.rs<br>use memory_stats::memory_stats;<br>use std::env::{current_exe, var};<br>use tiny_http::{Response, Server};

fn main() {<br>let port = var("PORT").unwrap_or_else(|_| "8080".into());<br>let srv = Server::http(format!("0.0.0.0:{port}")).unwrap();<br>let bin = current_exe().unwrap().metadata().unwrap().len() / 1024;<br>for (n, req) in srv.incoming_requests().enumerate() {<br>let rss = memory_stats().unwrap().physical_mem / 1024;<br>let body = format!("release binary: {bin} KiB\n\<br>process RSS: {rss} KiB\nrequest: {}\n", n + 1);<br>req.respond(Response::from_string(body)).unwrap();

── Cargo.toml<br>[package]<br>name = "quickstart-rust"<br>version = "0.1.0"<br>edition = "2021"<br>[dependencies]<br>memory-stats = "1.2"<br>tiny_http = "0.12"<br>[profile.release]<br>strip = true

~/quickstart-rust$ kedge up<br>Cargo.toml is the build plan; Kedge compiles a release binary and supplies<br>$PORT.

a prebuilt image

Publish an existing Docker image straight from a public registry:

kedge publish "$(kedge whoami)-quickstart-httpbin" \<br>--image ghcr.io/mccutchen/go-httpbin:2.23.1

a Dockerfile

Use a Dockerfile when the image itself is the point. This multi-stage Go build<br>compiles a static binary and copies it into an empty scratch image:

~/quickstart-scratch$ show main.go Dockerfile<br>── main.go<br>package main<br>import "net/http"<br>func main() {<br>http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {<br>w.Write([]byte("Hello from scratch.\n"))<br>})<br>http.ListenAndServe(":8080", nil)

── Dockerfile<br>FROM golang:1.24-alpine AS build<br>COPY main.go /<br>RUN CGO_ENABLED=0 go build -o /server /main.go<br>FROM scratch<br>COPY --from=build /server /<br>EXPOSE 8080<br>ENTRYPOINT ["/server"]

~/quickstart-scratch$ kedge up<br>See builds & images for the full build order.

clean up

Delete the example apps:

kedge delete 'hello-world-*' 'bash-*' \<br>"$(kedge whoami)-quickstart*"

beyond the defaults

Software that expects local disk, such as Postgres, a game server,...

kedge quickstart html index main from

Related Articles