Add "Infrastructure"

Virgil 2026-02-19 17:01:22 +00:00
parent 11b2a468b4
commit 6146fac8c3

268
Infrastructure.md Normal file

@ -0,0 +1,268 @@
# Infrastructure
> Container management (LinuxKit/QEMU/Hyperkit), Hetzner cloud provisioning, and CloudNS DNS management.
## Container Management
The `container` package manages LinuxKit-based virtual machines using QEMU on Linux and Hyperkit on macOS.
### Container
A `Container` represents a running VM instance.
```go
type Container struct {
ID string // Unique container ID
Name string // Human-readable name
Image string // LinuxKit image used
Status string // running, stopped, error
PID int // Process ID of the VM
Ports map[string]string // Port mappings (host:container)
Memory string // Allocated memory (e.g. "4G")
CPUs int // Allocated CPU cores
}
```
### RunOptions
Configuration for starting a new VM.
```go
type RunOptions struct {
Name string // Container name
Detach bool // Run in background
Memory string // Memory allocation (e.g. "2G", "4G")
CPUs int // CPU core count
Ports map[string]string // Port forwarding (host:container)
Volumes []string // Volume mounts (host:container)
SSHPort int // SSH port for access (default: auto-assigned)
SSHKey string // Path to SSH key for authentication
}
```
### Manager Interface
The `Manager` interface provides a unified API for VM lifecycle operations, regardless of the underlying hypervisor.
```go
type Manager interface {
Run(ctx context.Context, opts RunOptions) (*Container, error)
Stop(ctx context.Context, id string) error
Logs(ctx context.Context, id string) (string, error)
Exec(ctx context.Context, id string, cmd []string) (string, error)
Inspect(ctx context.Context, id string) (*Container, error)
}
```
### Creating a Manager
The `NewLinuxKitManager` factory selects the appropriate hypervisor backend based on the host platform.
```go
import "forge.lthn.ai/core/go-devops/container"
// QEMU backend (Linux, or explicit selection)
mgr := container.NewLinuxKitManager("qemu")
// Hyperkit backend (macOS)
mgr := container.NewLinuxKitManager("hyperkit")
```
### Running a VM
```go
ctr, err := mgr.Run(ctx, container.RunOptions{
Name: "dev-environment",
Memory: "4G",
CPUs: 4,
Ports: map[string]string{
"8080": "80", // Host 8080 -> Container 80
"8443": "443", // Host 8443 -> Container 443
},
Volumes: []string{
"/home/dev/project:/workspace",
},
SSHPort: 2222,
SSHKey: "~/.ssh/id_ed25519",
})
fmt.Printf("Container %s running (PID: %d)\n", ctr.Name, ctr.PID)
```
### Executing Commands
```go
output, err := mgr.Exec(ctx, ctr.ID, []string{"uname", "-a"})
fmt.Println(output) // Linux dev-environment 5.15.0 ...
```
### Viewing Logs
```go
logs, err := mgr.Logs(ctx, ctr.ID)
fmt.Println(logs)
```
## DevOps Environment
The `devops` package provides higher-level environment management on top of the container layer.
### DevOps and Config
```go
type DevOps struct {
Config Config
Images *ImageManager
}
type Config struct {
DataDir string // Persistent data directory
CacheDir string // Image and artefact cache
StateFile string // Environment state file
}
```
### ImageManager
The `ImageManager` handles pulling, caching, and verifying LinuxKit images.
```go
type ImageManager struct {
// Internal: cache dir, registry config
}
// Pull an image (uses cache if available)
img, err := images.Pull(ctx, "linuxkit/kernel:5.15")
// Verify image integrity
ok, err := images.Verify(img, expectedChecksum)
// List cached images
cached, err := images.List()
```
## Hetzner Cloud Provisioning
The `infra` package includes a provisioner for Hetzner Cloud servers.
```go
type HetznerProvisioner struct {
// Internal: API client, SSH keys, default config
}
```
### Provisioning a Server
```go
import "forge.lthn.ai/core/go-devops/infra"
provisioner := infra.NewHetznerProvisioner(apiToken)
server, err := provisioner.Create(ctx, infra.ServerConfig{
Name: "worker-eu-01",
Type: "cx31", // 2 vCPU, 8GB RAM, 80GB
Location: "fsn1", // Falkenstein, Germany
Image: "ubuntu-24.04",
SSHKeys: []string{"deploy-key"},
Labels: map[string]string{
"role": "worker",
"cluster": "production",
},
})
fmt.Printf("Server %s created at %s\n", server.Name, server.PublicIP)
```
### Server Lifecycle
```go
// List all servers
servers, err := provisioner.List(ctx)
// Get server details
server, err := provisioner.Get(ctx, serverID)
// Delete a server
err := provisioner.Delete(ctx, serverID)
```
## CloudNS DNS Management
The `infra` package also provides DNS record management via CloudNS.
```go
type CloudNSManager struct {
// Internal: API credentials, zone cache
}
```
### Managing DNS Records
```go
dns := infra.NewCloudNSManager(authID, password)
// Create an A record
err := dns.CreateRecord(ctx, infra.DNSRecord{
Zone: "lthn.ai",
Name: "worker-01",
Type: "A",
TTL: 300,
Value: server.PublicIP,
})
// Create a CNAME record
err := dns.CreateRecord(ctx, infra.DNSRecord{
Zone: "lthn.ai",
Name: "api",
Type: "CNAME",
TTL: 3600,
Value: "worker-01.lthn.ai",
})
// List records for a zone
records, err := dns.ListRecords(ctx, "lthn.ai")
// Delete a record
err := dns.DeleteRecord(ctx, "lthn.ai", recordID)
```
## Example: Full Provisioning Workflow
```go
import (
"forge.lthn.ai/core/go-devops/infra"
"forge.lthn.ai/core/go-devops/ansible"
)
// 1. Provision a Hetzner server
provisioner := infra.NewHetznerProvisioner(hetznerToken)
server, err := provisioner.Create(ctx, infra.ServerConfig{
Name: "web-prod-01",
Type: "cx31",
Location: "fsn1",
Image: "ubuntu-24.04",
SSHKeys: []string{"deploy-key"},
})
// 2. Create DNS record
dns := infra.NewCloudNSManager(authID, password)
dns.CreateRecord(ctx, infra.DNSRecord{
Zone: "lthn.ai",
Name: "web-prod-01",
Type: "A",
TTL: 300,
Value: server.PublicIP,
})
// 3. Configure with Ansible
executor := ansible.NewExecutor("./playbooks")
executor.SetInventory("./inventory/dynamic.yml")
executor.SetVar("target_host", server.PublicIP)
result, err := executor.Run(ctx, "configure.yml")
```
## See Also
- [[Home]] — Package overview
- [[Build-System]] — Building artefacts for deployment
- [[Ansible-Executor]] — Configuring provisioned infrastructure