docker: alpine base with openssh-client, mount SSH key + NET_RAW for scheduler
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled

- Switch Dockerfile from distroless/static to alpine:3.21
- Install openssh-client-default in runtime image
- Mount SSH key in scheduler service (docker-compose)
- Add NET_RAW capability for ping checks
- Wire OIKOS_SSH_KEY_PATH and OIKOS_SSH_USER env vars in scheduler
- sshExec uses configured key path with StrictHostKeyChecking=no
This commit is contained in:
2026-07-08 21:15:02 +02:00
parent 35feada286
commit 4bf811a383
3 changed files with 27 additions and 7 deletions

View File

@@ -23,8 +23,10 @@ COPY --from=ui-builder /web/dist ./web/dist
RUN CGO_ENABLED=0 go build -o /oikos -tags timetzdata -ldflags="-s -w" ./cmd/oikos
# --- Runtime: distroless static ---
FROM gcr.io/distroless/static:nonroot
# --- Runtime: alpine with SSH + ping for scheduler checks ---
FROM alpine:3.21
RUN apk add --no-cache ca-certificates openssh-client-default
COPY --from=builder /oikos /oikos
COPY --from=builder /build/seeds /seeds

View File

@@ -83,6 +83,11 @@ services:
OIKOS_DATABASE_URL: postgres://oikos:${OIKOS_DB_PASSWORD:-oikos_dev}@postgres:5432/oikos?sslmode=disable
OIKOS_DEBUG: "true"
OIKOS_SCHEDULER_INTERVAL: "30s"
OIKOS_SSH_KEY_PATH: /etc/oikos/ssh_key
volumes:
- ${OIKOS_SSH_KEY_PATH:-~/.ssh/id_ed25519}:/etc/oikos/ssh_key:ro
cap_add:
- NET_RAW
command: ["scheduler"]
stop_signal: SIGTERM
stop_grace_period: 30s

View File

@@ -26,6 +26,11 @@ import (
"golang.org/x/sys/unix"
)
var (
sshKeyPath string
sshUser string
)
// Run starts the scheduler loop. Blocks until ctx is cancelled.
func Run(ctx context.Context, pool *db.Pool, cfg config.Config) {
slog.Info("scheduler: starting", "interval", cfg.SchedulerInterval)
@@ -34,6 +39,12 @@ func Run(ctx context.Context, pool *db.Pool, cfg config.Config) {
interval = 30 * time.Second
}
sshKeyPath = cfg.SSHKeyPath
sshUser = cfg.SSHUser
if sshUser == "" {
sshUser = "root"
}
ticker := time.NewTicker(interval)
defer ticker.Stop()
@@ -537,7 +548,7 @@ func checkSSHScript(ctx context.Context, cd sqlcgen.ListEnabledCheckDefsRow) che
cfg.Port = 22
}
if cfg.User == "" {
cfg.User = "root"
cfg.User = sshUser
}
if !allowlistedScript(cfg.Script) {
@@ -609,12 +620,14 @@ func allowlistedScript(name string) bool {
func sshExec(ctx context.Context, addr, user, cmd string, timeout time.Duration) ([]byte, error) {
args := []string{
"-o", "ConnectTimeout=" + strconv.Itoa(int(timeout.Seconds())),
"-o", "StrictHostKeyChecking=yes",
"-o", "StrictHostKeyChecking=no",
"-o", "BatchMode=yes",
"-l", user,
addr,
cmd,
"-o", "UserKnownHostsFile=/dev/null",
}
if sshKeyPath != "" {
args = append(args, "-i", sshKeyPath)
}
args = append(args, "-l", user, addr, cmd)
c := exec.CommandContext(ctx, "ssh", args...)
return c.Output()
}