Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions agent/internal/agent/drift.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,16 +266,21 @@ func (a *Agent) detectChanges(expected *agenthttp.ExpectedState, actual *ActualS
}

func normalizeImage(image string) string {
parts := strings.Split(image, "@")
image = parts[0]
digest := ""
if digestIndex := strings.Index(image, "@"); digestIndex != -1 {
digest = image[digestIndex:]
image = image[:digestIndex]
}

image = strings.TrimPrefix(image, "docker.io/library/")
image = strings.TrimPrefix(image, "docker.io/")

if !strings.Contains(image, ":") {
lastSlash := strings.LastIndex(image, "/")
lastColon := strings.LastIndex(image, ":")
if digest == "" && lastColon <= lastSlash {
image = image + ":latest"
}
return image
return image + digest
}

func (a *Agent) reconcileOne(actual *ActualState) error {
Expand Down
15 changes: 9 additions & 6 deletions agent/internal/container/runtime_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ func Deploy(config *DeployConfig) (*DeployResult, error) {
"--cap-add", "SETGID",
"--cap-add", "NET_BIND_SERVICE",
"--cap-add", "NET_RAW",
"--log-driver", "local",
"--log-opt", "max-size=10m",
"--log-opt", "max-file=3",
}

args = append(args,
Expand Down Expand Up @@ -494,15 +497,15 @@ func writeDockerConfig(registryURL, username, password string) error {
}

func ImagePrune() {
exec.Command("docker", "image", "prune", "-a", "-f").Run()
exec.Command("docker", "image", "prune", "-a", "-f", "--filter", "until=168h").Run()
}

type dockerContainer struct {
ID string `json:"ID"`
Names string `json:"Names"`
Image string `json:"Image"`
State string `json:"State"`
Labels string `json:"Labels"`
ID string `json:"ID"`
Names string `json:"Names"`
Image string `json:"Image"`
State string `json:"State"`
Labels string `json:"Labels"`
}

func List() ([]Container, error) {
Expand Down
4 changes: 3 additions & 1 deletion agent/internal/container/runtime_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ func Deploy(config *DeployConfig) (*DeployResult, error) {
"--cap-add", "SETGID",
"--cap-add", "NET_BIND_SERVICE",
"--cap-add", "NET_RAW",
"--log-opt", "max-size=10m",
"--log-opt", "max-file=3",
}

args = append(args,
Expand Down Expand Up @@ -494,7 +496,7 @@ func writeDockerConfig(registryURL, username, password string) error {
}

func ImagePrune() {
exec.Command("podman", "image", "prune", "-a", "-f").Run()
exec.Command("podman", "image", "prune", "-a", "-f", "--filter", "until=168h").Run()
}

type podmanContainer struct {
Expand Down
2 changes: 1 addition & 1 deletion cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ service:
name: ${folderName}
source:
type: image
image: nginx:latest
image: nginx:1.27
replicas:
count: 1
ports:
Expand Down
12 changes: 10 additions & 2 deletions deployment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@ Docker Compose setup with Traefik for SSL termination via Let's Encrypt.
cp .env.example .env
# Edit .env with your values

docker compose -f compose.production.yml up -d --pull always
docker compose -f compose.production.yml up -d --pull always --remove-orphans
```

For production hosts, cap Docker logs in `/etc/docker/daemon.json` or use the
installer, which writes bounded `json-file` log settings on fresh Docker hosts.
Prefer versioned or digest-pinned image references over mutable tags when you
operate a long-lived deployment.

Health checks in these Compose files are for visibility. Plain Compose reports
unhealthy containers but does not restart them automatically.

## Services

| Service | Endpoint |
Expand Down Expand Up @@ -56,5 +64,5 @@ Schema is synced automatically on container startup via `drizzle-kit push`. This
```bash
docker compose -f compose.production.yml ps
docker compose -f compose.production.yml logs -f
docker compose -f compose.production.yml down
docker compose -f compose.production.yml down --remove-orphans
```
62 changes: 61 additions & 1 deletion deployment/compose.postgres.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
services:
docker-socket-proxy:
image: tecnativa/docker-socket-proxy:0.3.0
environment:
CONTAINERS: 1
EVENTS: 1
INFO: 1
NETWORKS: 1
VERSION: 1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:2375/version || exit 1"]
interval: 10s
timeout: 5s
retries: 6
restart: unless-stopped

traefik:
image: traefik:v3.6
env_file:
- ./.env
command:
- "--providers.docker=true"
- "--providers.docker.endpoint=tcp://docker-socket-proxy:2375"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
Expand All @@ -14,12 +32,20 @@ services:
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--ping=true"
ports:
- "80:80"
- "443:443"
volumes:
- letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
docker-socket-proxy:
condition: service_healthy
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped

postgres:
Expand All @@ -32,6 +58,12 @@ services:
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped

web:
Expand Down Expand Up @@ -61,6 +93,18 @@ services:
- "traefik.http.routers.web.entrypoints=websecure"
- "traefik.http.routers.web.tls.certresolver=letsencrypt"
- "traefik.http.services.web.loadbalancer.server.port=3000"
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
restart: unless-stopped

registry:
Expand All @@ -75,6 +119,11 @@ services:
- "traefik.http.routers.registry.entrypoints=websecure"
- "traefik.http.routers.registry.tls.certresolver=letsencrypt"
- "traefik.http.services.registry.loadbalancer.server.port=5000"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:5000/v2/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped

victoria-logs:
Expand All @@ -94,6 +143,11 @@ services:
- "traefik.http.routers.logs.entrypoints=websecure"
- "traefik.http.routers.logs.tls.certresolver=letsencrypt"
- "traefik.http.services.logs.loadbalancer.server.port=9428"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:9428/health || wget -q --spider http://127.0.0.1:9428/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped

inngest:
Expand All @@ -110,6 +164,12 @@ services:
- "start"
- "--sdk-url"
- "http://web:3000/api/inngest"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8288/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
restart: unless-stopped

volumes:
Expand Down
56 changes: 55 additions & 1 deletion deployment/compose.production.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
services:
docker-socket-proxy:
image: tecnativa/docker-socket-proxy:0.3.0
environment:
CONTAINERS: 1
EVENTS: 1
INFO: 1
NETWORKS: 1
VERSION: 1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:2375/version || exit 1"]
interval: 10s
timeout: 5s
retries: 6
restart: unless-stopped

traefik:
image: traefik:v3.6
env_file:
- ./.env
command:
- "--providers.docker=true"
- "--providers.docker.endpoint=tcp://docker-socket-proxy:2375"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
Expand All @@ -15,12 +33,20 @@ services:
- "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=600"
- "--ping=true"
ports:
- "80:80"
- "443:443"
volumes:
- letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
docker-socket-proxy:
condition: service_healthy
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped

web:
Expand Down Expand Up @@ -49,6 +75,18 @@ services:
- "traefik.http.routers.web.entrypoints=websecure"
- "traefik.http.routers.web.tls.certresolver=letsencrypt"
- "traefik.http.services.web.loadbalancer.server.port=3000"
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
restart: unless-stopped

registry:
Expand All @@ -63,6 +101,11 @@ services:
- "traefik.http.routers.registry.entrypoints=websecure"
- "traefik.http.routers.registry.tls.certresolver=letsencrypt"
- "traefik.http.services.registry.loadbalancer.server.port=5000"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:5000/v2/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped

victoria-logs:
Expand All @@ -82,6 +125,11 @@ services:
- "traefik.http.routers.logs.entrypoints=websecure"
- "traefik.http.routers.logs.tls.certresolver=letsencrypt"
- "traefik.http.services.logs.loadbalancer.server.port=9428"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:9428/health || wget -q --spider http://127.0.0.1:9428/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped

inngest:
Expand All @@ -98,6 +146,12 @@ services:
- "start"
- "--sdk-url"
- "http://web:3000/api/inngest"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8288/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
restart: unless-stopped

volumes:
Expand Down
Loading
Loading