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: 6 additions & 7 deletions .env.prod.example
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,12 @@ EDGE_IDENTITY_CA_PRIVATE_KEY_PASSPHRASE=
# -----------------------------------------------------------------------------
# Public edge runtime — owned by edge and edge-quarantine
# -----------------------------------------------------------------------------
# [optional] Public listeners. Use explicit service IPs instead of every interface when possible.
EDGE_HTTP_BIND=0.0.0.0:80
EDGE_HTTPS_BIND=0.0.0.0:443
# [optional] Quarantine owns distinct service addresses. Bind these ports to that
# pool's public IPv4/IPv6 using host routing or a production Compose override.
EDGE_QUARANTINE_HTTP_BIND=127.0.0.1:18080
EDGE_QUARANTINE_HTTPS_BIND=127.0.0.1:18443
# [required for edge profile] Gateway service addresses and private cell targets.
EDGE_GATEWAY_BINDINGS=[{"address":"192.0.2.10","pool":"shared-default","http":"127.0.0.1:18081","https":"127.0.0.1:18444"},{"address":"2001:db8::10","pool":"shared-default","http":"127.0.0.1:18081","https":"127.0.0.1:18444"}]
# [optional] Restrict these to agent/monitoring sources at the host firewall.
EDGE_GATEWAY_METRICS_ADDRESS=0.0.0.0:9105
EDGE_GATEWAY_MAX_CONNECTIONS=8192
EDGE_GATEWAY_STATUS_URL=http://host-gateway:9105/metrics
# [required for edge profile] Bootstrap/default listener certificate and key, absolute host paths.
EDGE_RUNTIME_TLS_CERTIFICATE=/etc/cdnfoundry/pki/edge-runtime.crt
EDGE_RUNTIME_TLS_PRIVATE_KEY=/etc/cdnfoundry/pki/edge-runtime.key
Expand Down
40 changes: 29 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ jobs:
docker build --build-arg CORE_IMAGE=cdnfoundry/core:ci --target edge-control -t cdnfoundry/edge-control:ci -f docker/nginx/Dockerfile.production .
docker build -t cdnfoundry/edge-runtime:ci -f docker/openresty/Dockerfile .
docker build -t cdnfoundry/edge-agent:ci edge-agent
docker build -t cdnfoundry/edge-gateway:ci edge-gateway
docker build -t cdnfoundry/mmdb-updater:ci docker/mmdb-updater
- name: Smoke-test the read-only core image
shell: bash
Expand Down Expand Up @@ -173,17 +174,33 @@ jobs:
- name: Test and build every Go module
shell: bash
run: |
mapfile -t modules < <(find . -name go.mod -not -path './.git/*' -printf '%h\n' | sort -u)
if (( ${#modules[@]} == 0 )); then
echo 'No Go modules are present yet; nothing to test or build.'
exit 0
set +e
{
mapfile -t modules < <(find . -name go.mod -not -path './.git/*' -printf '%h\n' | sort -u)
if (( ${#modules[@]} == 0 )); then
echo 'No Go modules are present yet; nothing to test or build.'
exit 0
fi
for module in "${modules[@]}"; do
echo "Testing ${module}"
unformatted="$(find "${module}" -name '*.go' -type f -print0 | xargs -0 gofmt -l)"
test -z "${unformatted}" || { printf 'Unformatted Go files:\n%s\n' "${unformatted}"; exit 1; }
(cd "${module}" && go vet ./... && go test -v ./... && go build ./...)
done
} 2>&1 | tee /tmp/cdnfoundry-go.log
status=${PIPESTATUS[0]}
if (( status != 0 )); then
tail -n 40 /tmp/cdnfoundry-go.log > /tmp/cdnfoundry-go-tail.log
{
echo '### Go test/build failure tail'
echo '```text'
cat /tmp/cdnfoundry-go-tail.log
echo '```'
} >> "${GITHUB_STEP_SUMMARY}"
annotation="$(python3 -c 'import sys; print(sys.stdin.read().replace("%", "%25").replace("\r", "%0D").replace("\n", "%0A"))' < /tmp/cdnfoundry-go-tail.log)"
echo "::error title=Go test/build failed::${annotation}"
fi
for module in "${modules[@]}"; do
echo "Testing ${module}"
unformatted="$(find "${module}" -name '*.go' -type f -print0 | xargs -0 gofmt -l)"
test -z "${unformatted}" || { printf 'Unformatted Go files:\n%s\n' "${unformatted}"; exit 1; }
(cd "${module}" && go vet ./... && go test ./... && go build ./...)
done
exit "${status}"

docs:
name: Documentation contracts and production build
Expand Down Expand Up @@ -226,6 +243,7 @@ jobs:
docker build --build-arg CORE_IMAGE=ghcr.io/vaheed/cdnfoundry-core:${RELEASE} --target edge-control -t ghcr.io/vaheed/cdnfoundry-edge-control:${RELEASE} -f docker/nginx/Dockerfile.production .
docker build -t ghcr.io/vaheed/cdnfoundry-edge-runtime:${RELEASE} -f docker/openresty/Dockerfile .
docker build -t ghcr.io/vaheed/cdnfoundry-edge-agent:${RELEASE} edge-agent
docker build -t ghcr.io/vaheed/cdnfoundry-edge-gateway:${RELEASE} edge-gateway
docker build -t ghcr.io/vaheed/cdnfoundry-mmdb-updater:${RELEASE} docker/mmdb-updater
- name: Push commit and channel tags
env:
Expand All @@ -235,7 +253,7 @@ jobs:
run: |
set -euo pipefail

images=(core web edge-control edge-runtime edge-agent mmdb-updater)
images=(core web edge-control edge-runtime edge-agent edge-gateway mmdb-updater)
aliases=()

if [[ "${RELEASE_REF}" == "refs/heads/main" ]]; then
Expand Down
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ COMPOSE_DEV := docker compose -f compose.dev.yml
COMPOSE_PROD := docker compose --env-file .env.prod -f compose.prod.yml
COMPOSE_PROD_EXAMPLE := docker compose --env-file .env.prod.example -f compose.prod.yml

.PHONY: dev-assets dev-up dev-edge-up dev-edge-status dev-scale-up dev-down dev-migrate dev-pdns-migrate dev-test dev-e2e dev-phase7-e2e dev-phase8-e2e dev-phase8-recovery-e2e dev-phase8-upgrade-e2e dev-phase8-throughput-e2e dev-phase8-mmdb-e2e dev-scale-e2e dev-logs prod-pull prod-migrate prod-pdns-migrate prod-control prod-dns prod-telemetry prod-edge config-check openapi-check docs-dev docs-build docs-check
.PHONY: dev-assets dev-up dev-edge-up dev-edge-status dev-scale-up dev-down dev-migrate dev-pdns-migrate dev-test dev-e2e dev-gateway-e2e dev-phase7-e2e dev-phase8-e2e dev-phase8-recovery-e2e dev-phase8-upgrade-e2e dev-phase8-throughput-e2e dev-phase8-mmdb-e2e dev-scale-e2e dev-logs prod-pull prod-migrate prod-pdns-migrate prod-control prod-dns prod-telemetry prod-edge config-check openapi-check docs-dev docs-build docs-check

dev-assets:
docker build --target frontend-assets-export --output type=local,dest=./core/public/build ./core
Expand All @@ -12,10 +12,10 @@ dev-up: dev-assets

dev-edge-up: dev-assets
@test -f .env.dev || { echo 'Copy .env.dev.example to .env.dev and add the two UI edge IDs and one-time bootstrap tokens.' >&2; exit 1; }
docker compose --env-file .env.dev -f compose.dev.yml --profile dev-edge up -d --build edge-control edge-a edge-a-quarantine edge-agent-a edge-b edge-b-quarantine edge-agent-b
docker compose --env-file .env.dev -f compose.dev.yml --profile dev-edge up -d --build edge-control edge-a edge-a-quarantine edge-agent-a edge-gateway-a edge-b edge-b-quarantine edge-agent-b edge-gateway-b

dev-edge-status:
docker compose --env-file .env.dev -f compose.dev.yml --profile dev-edge ps edge-control edge-a edge-a-quarantine edge-agent-a edge-b edge-b-quarantine edge-agent-b
docker compose --env-file .env.dev -f compose.dev.yml --profile dev-edge ps edge-control edge-a edge-a-quarantine edge-agent-a edge-gateway-a edge-b edge-b-quarantine edge-agent-b edge-gateway-b

dev-scale-up: dev-assets
$(COMPOSE_DEV) up -d --build control-db redis core web
Expand Down Expand Up @@ -44,6 +44,10 @@ dev-e2e:
python3 tests/e2e/phase8_operations.py
python3 tests/e2e/phase4_runtime.py

dev-gateway-e2e:
docker build -t cdnfoundry/edge-gateway:qualification edge-gateway
python3 tests/e2e/gateway_ingress.py

dev-scale-e2e:
python3 tests/e2e/phase2_scale.py

Expand Down
123 changes: 115 additions & 8 deletions compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,6 @@ services:
build:
context: .
dockerfile: docker/openresty/Dockerfile
ports: ["8081:8080", "8444:8443"]
environment:
EDGE_CELL_NAME: shared-default
EDGE_RUNTIME_FILE: /var/lib/cdnfoundry/runtime/shared-default.json
Expand All @@ -349,7 +348,7 @@ services:
pids_limit: 128
ulimits: { nofile: { soft: 65536, hard: 65536 } }
sysctls: { net.ipv4.tcp_syncookies: "1" }
networks: [edge]
networks: [edge, gateway-shared-a]
depends_on:
dev-pki: { condition: service_completed_successfully }
origin-http: { condition: service_started }
Expand Down Expand Up @@ -382,7 +381,7 @@ services:
pids_limit: 96
ulimits: { nofile: { soft: 65536, hard: 65536 } }
sysctls: { net.ipv4.tcp_syncookies: "1" }
networks: [edge]
networks: [edge, gateway-quarantine-a]
depends_on:
dev-pki: { condition: service_completed_successfully }
origin-http: { condition: service_started }
Expand All @@ -399,13 +398,18 @@ services:
EDGE_BOOTSTRAP_TOKEN: ${CDNF_DEV_EDGE_A_BOOTSTRAP_TOKEN:-}
EDGE_STATE_DIR: /var/lib/cdnfoundry/agent
EDGE_RUNTIME_DIR: /var/lib/cdnfoundry/runtime
EDGE_GATEWAY_BINDINGS: >-
[{"address":"172.28.10.10","pool":"shared-default","http":"edge-a:8081","https":"edge-a:8444"},
{"address":"fd00:cd0f:10::10","pool":"shared-default","http":"edge-a:8081","https":"edge-a:8444"},
{"address":"172.28.11.10","pool":"quarantine-default","http":"edge-a-quarantine:8081","https":"edge-a-quarantine:8444"}]
EDGE_GATEWAY_STATUS_URL: http://edge-gateway-a:9105/metrics
EDGE_CELL_STATUS_URLS: http://edge-a:9080/passive-failures,http://edge-a-quarantine:9080/passive-failures
EDGE_STATUS_TOKEN: ${CDNF_DEV_EDGE_STATUS_TOKEN:-cdnf-dev-edge-status-only}
volumes:
- edge-a-agent-state:/var/lib/cdnfoundry/agent
- edge-a-state:/var/lib/cdnfoundry/runtime
- dev-pki:/run/dev-pki:ro
networks: [control, edge]
networks: [control, edge, gateway-status]
depends_on:
edge-control: { condition: service_healthy }
edge-a: { condition: service_healthy }
Expand All @@ -417,11 +421,51 @@ services:
cpus: 0.25
pids_limit: 64

edge-gateway-a:
build: ./edge-gateway
profiles: [dev-edge]
environment:
GATEWAY_CONFIG_FILE: /var/lib/cdnfoundry/runtime/gateway.json
GATEWAY_STATE_DIR: /var/lib/cdnfoundry/gateway-state
GATEWAY_METRICS_ADDRESS: 0.0.0.0:9105
GATEWAY_MAX_CONNECTIONS: 4096
volumes:
- edge-a-state:/var/lib/cdnfoundry/runtime:ro
- edge-a-gateway-state:/var/lib/cdnfoundry/gateway-state
ports: ["8081:80", "8444:443"]
networks:
gateway-shared-a:
ipv4_address: 172.28.10.10
ipv6_address: fd00:cd0f:10::10
gateway-quarantine-a:
ipv4_address: 172.28.11.10
gateway-status: {}
telemetry: {}
depends_on:
edge-a: { condition: service_healthy }
edge-a-quarantine: { condition: service_started }
edge-gateway-a-state-init: { condition: service_completed_successfully }
restart: unless-stopped
read_only: true
tmpfs: [/tmp]
mem_limit: 128m
cpus: 0.5
pids_limit: 96
ulimits: { nofile: { soft: 65536, hard: 65536 } }
cap_drop: [ALL]
cap_add: [NET_BIND_SERVICE]

edge-gateway-a-state-init:
image: alpine:3.22
profiles: [dev-edge]
command: [chown, "10101:10101", /state]
volumes: [edge-a-gateway-state:/state]
restart: "no"

edge-b:
build:
context: .
dockerfile: docker/openresty/Dockerfile
ports: ["8082:8080", "8445:8443"]
environment:
EDGE_CELL_NAME: shared-default
EDGE_RUNTIME_FILE: /var/lib/cdnfoundry/runtime/shared-default.json
Expand All @@ -439,7 +483,7 @@ services:
pids_limit: 128
ulimits: { nofile: { soft: 65536, hard: 65536 } }
sysctls: { net.ipv4.tcp_syncookies: "1" }
networks: [edge]
networks: [edge, gateway-shared-b]
depends_on:
dev-pki: { condition: service_completed_successfully }
origin-http: { condition: service_started }
Expand Down Expand Up @@ -472,7 +516,7 @@ services:
pids_limit: 96
ulimits: { nofile: { soft: 65536, hard: 65536 } }
sysctls: { net.ipv4.tcp_syncookies: "1" }
networks: [edge]
networks: [edge, gateway-quarantine-b]
depends_on:
dev-pki: { condition: service_completed_successfully }
origin-http: { condition: service_started }
Expand All @@ -489,13 +533,17 @@ services:
EDGE_BOOTSTRAP_TOKEN: ${CDNF_DEV_EDGE_B_BOOTSTRAP_TOKEN:-}
EDGE_STATE_DIR: /var/lib/cdnfoundry/agent
EDGE_RUNTIME_DIR: /var/lib/cdnfoundry/runtime
EDGE_GATEWAY_BINDINGS: >-
[{"address":"172.28.20.10","pool":"shared-default","http":"edge-b:8081","https":"edge-b:8444"},
{"address":"172.28.21.10","pool":"quarantine-default","http":"edge-b-quarantine:8081","https":"edge-b-quarantine:8444"}]
EDGE_GATEWAY_STATUS_URL: http://edge-gateway-b:9105/metrics
EDGE_CELL_STATUS_URLS: http://edge-b:9080/passive-failures,http://edge-b-quarantine:9080/passive-failures
EDGE_STATUS_TOKEN: ${CDNF_DEV_EDGE_STATUS_TOKEN:-cdnf-dev-edge-status-only}
volumes:
- edge-b-agent-state:/var/lib/cdnfoundry/agent
- edge-b-state:/var/lib/cdnfoundry/runtime
- dev-pki:/run/dev-pki:ro
networks: [control, edge]
networks: [control, edge, gateway-status]
depends_on:
edge-control: { condition: service_healthy }
edge-b: { condition: service_healthy }
Expand All @@ -507,6 +555,46 @@ services:
cpus: 0.25
pids_limit: 64

edge-gateway-b:
build: ./edge-gateway
profiles: [dev-edge]
environment:
GATEWAY_CONFIG_FILE: /var/lib/cdnfoundry/runtime/gateway.json
GATEWAY_STATE_DIR: /var/lib/cdnfoundry/gateway-state
GATEWAY_METRICS_ADDRESS: 0.0.0.0:9105
GATEWAY_MAX_CONNECTIONS: 4096
volumes:
- edge-b-state:/var/lib/cdnfoundry/runtime:ro
- edge-b-gateway-state:/var/lib/cdnfoundry/gateway-state
ports: ["8082:80", "8445:443"]
networks:
gateway-shared-b:
ipv4_address: 172.28.20.10
gateway-quarantine-b:
ipv4_address: 172.28.21.10
gateway-status: {}
telemetry: {}
depends_on:
edge-b: { condition: service_healthy }
edge-b-quarantine: { condition: service_started }
edge-gateway-b-state-init: { condition: service_completed_successfully }
restart: unless-stopped
read_only: true
tmpfs: [/tmp]
mem_limit: 128m
cpus: 0.5
pids_limit: 96
ulimits: { nofile: { soft: 65536, hard: 65536 } }
cap_drop: [ALL]
cap_add: [NET_BIND_SERVICE]

edge-gateway-b-state-init:
image: alpine:3.22
profiles: [dev-edge]
command: [chown, "10101:10101", /state]
volumes: [edge-b-gateway-state:/state]
restart: "no"

poweradmin:
image: poweradmin/poweradmin:4.3.3
profiles: [devtools]
Expand Down Expand Up @@ -554,6 +642,23 @@ networks:
ingress: {}
dns: {}
edge: {}
gateway-shared-a:
internal: true
enable_ipv6: true
ipam:
config:
- subnet: 172.28.10.0/24
- subnet: fd00:cd0f:10::/64
gateway-quarantine-a:
internal: true
ipam: { config: [{ subnet: 172.28.11.0/24 }] }
gateway-shared-b:
internal: true
ipam: { config: [{ subnet: 172.28.20.0/24 }] }
gateway-quarantine-b:
internal: true
ipam: { config: [{ subnet: 172.28.21.0/24 }] }
gateway-status: { internal: true }
telemetry: {}

volumes:
Expand All @@ -570,5 +675,7 @@ volumes:
dev-pki: {}
edge-a-state: {}
edge-a-agent-state: {}
edge-a-gateway-state: {}
edge-b-state: {}
edge-b-agent-state: {}
edge-b-gateway-state: {}
Loading
Loading