PostgreSQL
The actual database. A program that stores rows of data on disk and answers questions about them in SQL. It runs in your namespace as deploy/postgres.
A guided cross-section of the PostgreSQL · pgweb · k3s · Tailscale apparatus deployed to your namespace on serg-9000 — what it is, where it lives, and what each piece does when nobody is looking.
Before we crack open the diagram, here is the entire installation in plain language. Eight characters; everyone has a job.
The actual database. A program that stores rows of data on disk and answers questions about them in SQL. It runs in your namespace as deploy/postgres.
A small web app whose only job is to show you what is inside a PostgreSQL database. The "viewer". You open it at localhost:8081.
A sealed bag containing one program plus everything it needs to run. Postgres lives in one bag; pgweb in another. Bags can't see each other's stuff.
The thing that runs the bags. Schedules them, restarts them when they crash, gives them network addresses. k3s is a small flavour of Kubernetes that fits on a single machine.
The machine. A Linux box on serg's network running k3s. Lives somewhere on the internet; reachable only through Tailscale.
Your namespace on the cluster — your private room. You can do anything you like inside it; you can't see anything outside.
A private network laid on top of the public internet. Your Mac and serg-9000 act as if they're on the same office LAN; everyone else sees nothing.
A command-line tool on your Mac. Every kubectl … command is really an HTTPS call to the cluster's API server, asking it to do something on your behalf.
Click any element. Each box hides another box. Storage drops to the floor; networks float above. Drawn from left (you) to right (the server).
You typed localhost:8081 into Safari and pressed
Return. What actually happened? Press play below and
watch a request take the long way home.
127.0.0.1:8081. That's still on your laptop — nothing has left the building.kubectl process is listening on that port. It wraps your bytes in an HTTPS request to the cluster's API server.serg-9000 resolves to a Tailscale IP. Your packets travel encrypted through Tailscale's overlay, never touching the public internet in cleartext.:6443 authenticates your kubeconfig token, sees the request is "forward me to pod X", and opens a stream to that pod.svc/postgres (a stable name) to the actual postgres pod, runs, and the rows come back. Every step then reverses.Each tile is one term, expanded. Read in order if you like, or jump around — they are independent. Click to flip.
A program whose job is to store structured data on disk and answer questions about it. You ask in SQL; it returns rows.
Why use a database instead of a folder full of JSON files? Speed, integrity, concurrent access, querying across millions of rows, transactions that don't half-finish.
A specific, very-good database. Open source, 30+ years old, famously pedantic about correctness. The Postgres pod is running version 16.13.
Knows about JSON, geographic data, full-text search, transactions, materialized views, custom types. It is the one database opinionated programmers reach for without thinking.
A way to package a program so it runs the same on any Linux machine. The container holds the binary, its libraries, and a stripped-down filesystem — but shares the kernel with the host.
Think: a shipping container, not a virtual machine. Light, fast, isolated enough to keep mistakes from spreading.
Your Postgres container is postgres:16-alpine; pgweb is sosedoff/pgweb:0.16.2.
The conductor. You hand Kubernetes a description of what you want ("I want one Postgres pod with these settings") and it figures out how to make reality match. If a pod crashes, it starts a new one. If you want three replicas, it places three.
You describe desired state in YAML files. Kubernetes does the rest.
A small distribution of Kubernetes by Rancher. Single binary, ~50 MB, runs on a Raspberry Pi or any modest Linux box. Trims out cloud-vendor parts you don't need at home.
serg-9000 runs k3s as a single-node cluster — the "node" and the "control plane" are the same machine.
A way to divide a cluster into rooms. Your room is named arthur-sandbox. Everything you create lives there; you cannot see or touch what is in other namespaces.
Quotas are namespace-scoped: yours has 4 CPU cores, 8 GiB RAM, 30 pods, 50 GiB of disk.
The smallest thing Kubernetes runs. Usually one container; sometimes a tight cluster of containers that share an IP and filesystem.
Pods are cattle, not pets: they are expected to die and be replaced. Anything important must live somewhere persistent (see: PVC).
A description of "I want N pods of this kind, always". You don't ask for pods directly — you ask for a Deployment, and it makes pods on your behalf.
When you change the image version, the Deployment rolls out new pods and terminates old ones gracefully.
Pods come and go; their IPs change. A Service is a stable name and stable virtual IP that points at whichever pods currently match a label.
pgweb connects to postgres.arthur-sandbox.svc.cluster.local — the Service — not to the postgres pod directly. The pod can be replaced; the Service name doesn't move.
Your sandbox allows only ClusterIP services — reachable from inside the cluster, not from the outside world.
Pods are throwaway, but databases need to remember things. A PVC is a request for a slice of disk that survives the pod.
Yours is 5 GiB on the local-path storage class — a directory on serg-9000's disk. Wipe the pod, the data stays. Wipe the PVC, the data is gone.
A small bag of credentials. Your Postgres username and password live in a Secret named postgres-credentials. Pods that need them reference the Secret; Kubernetes injects the values as environment variables.
Secrets are base64-encoded, not encrypted. Anyone who can read Secrets in your namespace can read the password. Fine for sandbox use; do not store nuclear codes here.
Role-Based Access Control. The rules that say who can do what to which resources. Your account can create Deployments inside arthur-sandbox, but cannot list pods in any other namespace.
When you ran kubectl auth can-i get pods --all-namespaces the answer was no. That's RBAC saying hello.
An admission rule that rejects pods which want too much power — running as root, mounting the host filesystem, escalating privileges. Your namespace is set to restricted.
That's why the manifests carefully say runAsNonRoot: true and drop all Linux capabilities — anything less and the cluster refuses to schedule the pod.
A YAML file at ~/.kube/config that tells kubectl three things: where the cluster lives, how to trust its TLS certificate, and what credential to present.
Your kubeconfig contains a long-lived bearer token. Treat it like a password. Don't paste it into chats, don't commit it to git, keep its file permissions tight (chmod 600).
Secure Shell. A protocol for getting a shell on a remote machine through an encrypted connection. You'd use it to log into serg-9000 directly and poke around.
We tried it earlier and got tailnet policy does not permit you to SSH to this node — Tailscale's SSH was on, and the access list didn't grant your Mac that permission. We didn't need SSH in the end; kubectl over HTTPS turned out to be enough.
An Access Control List that decides which machines on the Tailscale network can talk to which others, and on which ports/protocols. Edited as JSON in the Tailscale admin console.
Your ACL says: this Mac may reach serg-9000:6443 (k3s API), but not serg-9000:22 (SSH). The cluster works; SSH doesn't. By design.
A trick that makes a port on your Mac act as if it's a port inside the cluster. When you ran kubectl port-forward svc/pgweb 8081:80, kubectl started listening on localhost:8081 and tunnelling any bytes through the API server to the pgweb service inside the cluster.
It's not a permanent exposure — kill the kubectl process, the tunnel disappears.
A small open-source web app written in Go. Given a Postgres connection string, it gives you a tabbed UI to browse tables, run SQL, see schemas, export results.
Yours is preconfigured with your database (DATABASE_URL in its environment) so opening localhost:8081 drops you straight into the database — no login screen.
Click a command on the left to "run" it. Real outputs from the deployment, annotated. Don't worry — nothing here actually contacts the cluster.
Twenty-six terms in alphabetical order. The same dotted-underline definitions you've hovered through the rest of the document — all in one place.
kubectl command and every internal controller talks to it over HTTPS.postgres:16-alpine is an image name (registry path + tag). A running container is one instance of an image.~/.kube/config.replicas: 1 for each of postgres and pgweb.postgres:16-alpine is the image postgres at tag 16-alpine.serg-9000, in the namespace arthur-sandbox.~/projects/k3s-postgres/. Re-apply with kubectl apply -f .. Tear down with kubectl delete -f ..— end of plate —