Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fd05ff833 | ||
|
|
e7f24f0be4 |
@@ -14,8 +14,8 @@ BuildKit кэширует `/go/pkg/mod`, `~/.cache/go-build` и pnpm store че
|
||||
|
||||
| Образ | Runtime base | Заметка |
|
||||
|-------|----------------|---------|
|
||||
| scheduler, ingest, render, deploy, node | `gcr.io/distroless/static-debian12:nonroot` | static Go (`CGO_ENABLED=0`), без shell |
|
||||
| api, all | `debian:bookworm-slim` + `birdc` | только клиент birdc, без демона `bird` |
|
||||
| scheduler, ingest, render | `gcr.io/distroless/static-debian12:nonroot` | static Go (`CGO_ENABLED=0`), без shell |
|
||||
| api, all, deploy, node | `debian:bookworm-slim` + `bird` + `birdc` | `bird -p` (parse-check) и `birdc`; демон не запускается |
|
||||
| agent | тот же Ubuntu+bird2, что bird2 | общие слои с `evobgp-bird2` |
|
||||
| bird2 | Ubuntu Noble + пакет bird2 | |
|
||||
| web, web-all | `nginx:1.27-alpine` | `worker_processes 1` |
|
||||
|
||||
@@ -236,13 +236,13 @@ target "evobgp-render" {
|
||||
}
|
||||
|
||||
target "evobgp-deploy" {
|
||||
inherits = ["_go-runtime"]
|
||||
inherits = ["_go-runtime-birdc"]
|
||||
args = { BIN = "evobgp-deploy" }
|
||||
tags = image-tags("evobgp-deploy")
|
||||
}
|
||||
|
||||
target "evobgp-node" {
|
||||
inherits = ["_go-runtime"]
|
||||
inherits = ["_go-runtime-birdc"]
|
||||
args = { BIN = "evobgp-node" }
|
||||
tags = image-tags("evobgp-node")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
# Универсальная сборка бинарей cmd/* (ARG BIN) или всех сразу (target build-all).
|
||||
# Воркеры (runtime): distroless static. api/all (runtime-birdc): debian-slim + birdc.
|
||||
# Воркеры (runtime): distroless static. api/all/deploy/node (runtime-birdc): debian-slim + bird + birdc.
|
||||
# CI: docker buildx bake -f deploy/docker/docker-bake.hcl
|
||||
ARG BASE_GOLANG=docker.io/library/golang:1.24-alpine
|
||||
ARG BASE_DEBIAN=docker.io/library/debian:bookworm-slim
|
||||
@@ -57,14 +57,15 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
&& BIRD_VERSION="${BIRD_VERSION}" /tmp/bird-from-source.sh \
|
||||
&& rm -f /tmp/bird-from-source.sh
|
||||
|
||||
# scheduler / ingest / render / deploy / node — static Go, без shell.
|
||||
# scheduler / ingest / render — static Go, без shell.
|
||||
FROM ${BASE_DISTROLESS} AS runtime
|
||||
ARG BIN=evobgp-api
|
||||
COPY --from=build-all /out/${BIN} /usr/local/bin/evobgp
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/usr/local/bin/evobgp"]
|
||||
|
||||
# api / all — birdc (readline + ncurses). Только клиент birdc, без демона bird.
|
||||
# api / all / deploy / node — bird -p (parse-check) + birdc configure.
|
||||
# Демон BIRD в этом контейнере не запускается; процесс bird — в образе evobgp-bird2.
|
||||
FROM ${BASE_DEBIAN} AS runtime-birdc
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
@@ -74,6 +75,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
ARG BIN=evobgp-api
|
||||
COPY --from=build-all /out/${BIN} /usr/local/bin/evobgp
|
||||
COPY --from=birdc /usr/local/sbin/bird /usr/local/sbin/bird
|
||||
COPY --from=birdc /usr/local/sbin/birdc /usr/local/sbin/birdc
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/usr/local/bin/evobgp"]
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ docker login git.shx.one
|
||||
|
||||
| Образ | Назначение | Страница пакета (пример) | Pull |
|
||||
|--------|------------|--------------------------|------|
|
||||
| `evobgp-api` | HTTP API (с `birdc` в образе) | [packages/…/evobgp-api](https://git.shx.one/denozord/-/packages/container/evobgp-api/latest) | `docker pull git.shx.one/denozord/evobgp-api:latest` |
|
||||
| `evobgp-api` | HTTP API (с `bird`/`birdc` в образе для parse-check) | [packages/…/evobgp-api](https://git.shx.one/denozord/-/packages/container/evobgp-api/latest) | `docker pull git.shx.one/denozord/evobgp-api:latest` |
|
||||
| `evobgp-all` | Монолит microVPS: API + in-process воркеры scheduler/ingest/render/deploy | [packages/…/evobgp-all](https://git.shx.one/denozord/-/packages/container/evobgp-all/latest) | `docker pull git.shx.one/denozord/evobgp-all:latest` |
|
||||
| `evobgp-scheduler` | Планировщик (reference) | [packages/…/evobgp-scheduler](https://git.shx.one/denozord/-/packages/container/evobgp-scheduler/latest) | `docker pull git.shx.one/denozord/evobgp-scheduler:latest` |
|
||||
| `evobgp-ingest` | Ingest CDN / ETag | [packages/…/evobgp-ingest](https://git.shx.one/denozord/-/packages/container/evobgp-ingest/latest) | `docker pull git.shx.one/denozord/evobgp-ingest:latest` |
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
func TestParallelModuleRefresh_CoalescesDeployApply(t *testing.T) {
|
||||
t.Setenv("EVOBGP_ASN_RESOLVE", "0")
|
||||
t.Setenv("EVOBGP_BIRD_ACTIVE_DIR", "") // skip bird binary path in deploy_apply
|
||||
t.Setenv("EVOBGP_JOB_MAX_CONCURRENT", "8")
|
||||
|
||||
m := store.NewMemory()
|
||||
m.SeedDemo()
|
||||
@@ -35,8 +36,15 @@ func TestParallelModuleRefresh_CoalescesDeployApply(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Hold workers until both jobs are enqueued so inflightRefresh=2 before either
|
||||
// finishModuleRefreshSuccess. Otherwise a fast ingest can finalize+deploy before
|
||||
// the second Enqueue — sequential refreshes correctly produce two deploy_apply jobs.
|
||||
start := make(chan struct{})
|
||||
wk := &Worker{Store: m}
|
||||
reg := NewRegistry(wk.Process)
|
||||
reg := NewRegistry(func(j *Job) {
|
||||
<-start
|
||||
wk.Process(j)
|
||||
})
|
||||
wk.Registry = reg
|
||||
|
||||
mid1 := modIP
|
||||
@@ -47,6 +55,7 @@ func TestParallelModuleRefresh_CoalescesDeployApply(t *testing.T) {
|
||||
if _, _, err := reg.Enqueue(tenant, KindModuleRefresh, nil, &mid2, map[string]any{"module_id": mod2.ID}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
close(start)
|
||||
|
||||
waitSucceededJobsByKindCount(t, reg, tenant, KindModuleRefresh, 2)
|
||||
|
||||
|
||||
@@ -414,6 +414,9 @@ func (m *Memory) ListModules(tenantID string) []*Module {
|
||||
}
|
||||
return out[i].Name < out[j].Name
|
||||
})
|
||||
for i := range out {
|
||||
out[i] = cloneModule(out[i])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -446,7 +449,7 @@ func (m *Memory) GetModule(tenantID, moduleID string) (*Module, error) {
|
||||
if mod.TenantID != tenantID {
|
||||
return nil, ErrTenantScope
|
||||
}
|
||||
return mod, nil
|
||||
return cloneModule(mod), nil
|
||||
}
|
||||
|
||||
func (m *Memory) GetRevision(tenantID, revisionID string) (*Revision, error) {
|
||||
@@ -684,3 +687,24 @@ func (m *Memory) ListRevisions(tenantID, moduleID string, cursor string, limit i
|
||||
}
|
||||
return page, nextCursor, hasMore
|
||||
}
|
||||
|
||||
func cloneStringPtr(s *string) *string {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
v := *s
|
||||
return &v
|
||||
}
|
||||
|
||||
func cloneModule(m *Module) *Module {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
cp := *m
|
||||
cp.DefaultCommunityID = cloneStringPtr(m.DefaultCommunityID)
|
||||
cp.DohProfileID = cloneStringPtr(m.DohProfileID)
|
||||
cp.DohProfileIDs = append([]string(nil), m.DohProfileIDs...)
|
||||
cp.LastRefreshedAt = cloneTime(m.LastRefreshedAt)
|
||||
cp.DeletedAt = cloneTime(m.DeletedAt)
|
||||
return &cp
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func (m *Memory) CreateModule(tenantID string, in *Module) (*Module, error) {
|
||||
}
|
||||
NormalizeModuleDoh(mod)
|
||||
m.modules[id] = mod
|
||||
return mod, nil
|
||||
return cloneModule(mod), nil
|
||||
}
|
||||
|
||||
func (m *Memory) UpdateModule(tenantID, moduleID string, patch *ModulePatch) (*Module, error) {
|
||||
@@ -74,12 +74,14 @@ func (m *Memory) UpdateModule(tenantID, moduleID string, patch *ModulePatch) (*M
|
||||
mod.DefaultCommunityID = &v
|
||||
}
|
||||
}
|
||||
ApplyModuleDohPatch(mod, patch)
|
||||
if patch.DohProfileIDs != nil || patch.DohProfileID != nil || patch.DohResolverPolicy != nil {
|
||||
ApplyModuleDohPatch(mod, patch)
|
||||
}
|
||||
if patch.LastRefreshedAt != nil {
|
||||
t := patch.LastRefreshedAt.UTC()
|
||||
mod.LastRefreshedAt = &t
|
||||
}
|
||||
return mod, nil
|
||||
return cloneModule(mod), nil
|
||||
}
|
||||
|
||||
func (m *Memory) SoftDeleteModule(tenantID, moduleID string) error {
|
||||
|
||||
Reference in New Issue
Block a user