Merge pull request #6513 from anguobao123/codex/optional-apple-container-network-subnet

feat(deploy): support optional Apple network subnet
This commit is contained in:
Wesley Liddick
2026-09-08 20:46:51 +08:00
committed by GitHub
5 changed files with 87 additions and 5 deletions
+5
View File
@@ -36,6 +36,11 @@ APPLE_CONTAINER_SUB2API_IMAGE=weishaw/sub2api:latest
APPLE_CONTAINER_POSTGRES_IMAGE=postgres:18-alpine
APPLE_CONTAINER_REDIS_IMAGE=redis:8-alpine
# Optional fixed IPv4 CIDR for the private Apple container network. Leave empty
# to let Apple container select one. Set only when host tooling needs a stable
# network gateway, and choose a CIDR that does not overlap your LAN or VPN.
APPLE_CONTAINER_NETWORK_SUBNET=
# -----------------------------------------------------------------------------
# Logging Configuration
# 日志配置
+16
View File
@@ -105,6 +105,22 @@ APPLE_CONTAINER_POSTGRES_IMAGE=postgres:18-alpine
APPLE_CONTAINER_REDIS_IMAGE=redis:8-alpine
```
By default, Apple `container` selects the private IPv4 subnet for the managed
network. Set `APPLE_CONTAINER_NETWORK_SUBNET` only when host-side tooling needs
a stable network gateway:
```dotenv
APPLE_CONTAINER_NETWORK_SUBNET=
```
Leave the setting empty to keep automatic subnet allocation. When setting it,
choose a CIDR that does not overlap the host LAN or VPN. The script applies the
setting only when it creates `sub2api-apple`. If the existing managed network
uses a different subnet, it stops without deleting any resources. To migrate
intentionally, run `./apple-container.sh destroy --yes` to remove the managed
containers and network while preserving named volumes, then run
`./apple-container.sh up`.
The normal `up` command recreates the application container, so application environment changes are applied immediately. Use `up --recreate` when changing PostgreSQL or Redis container images or Redis runtime configuration. Persistent data remains in named volumes.
`POSTGRES_USER`, `POSTGRES_PASSWORD`, and `POSTGRES_DB` are applied only when PostgreSQL initializes an empty data volume. Changing them in `.env` and recreating the container does not change an existing database. Rotate a password with `ALTER ROLE`, and plan explicit migrations for user or database changes. To intentionally initialize a new empty database, first back up the old one and use `destroy --volumes`.
+18 -3
View File
@@ -31,6 +31,7 @@ POSTGRES_PASSWORD=""
POSTGRES_DB=""
REDIS_PASSWORD=""
TZ_VALUE=""
NETWORK_SUBNET=""
POSTGRES_ADDRESS=""
REDIS_ADDRESS=""
APP_ENV_FILE=""
@@ -210,15 +211,28 @@ preflight_stack_ownership() {
}
ensure_network() {
local existing_subnet
local -a network_args
if resource_exists network "${NETWORK_NAME}"; then
assert_resource_owned network "${NETWORK_NAME}"
if [[ -n "${NETWORK_SUBNET}" ]]; then
existing_subnet="$(inspect_resource network "${NETWORK_NAME}" | \
plutil -extract 0.configuration.ipv4Subnet raw -o - -)" || \
die "Unable to read the IPv4 subnet for ${NETWORK_NAME}."
if [[ "${existing_subnet}" != "${NETWORK_SUBNET}" ]]; then
die "Existing network '${NETWORK_NAME}' uses subnet '${existing_subnet}', but APPLE_CONTAINER_NETWORK_SUBNET is '${NETWORK_SUBNET}'. Run './apple-container.sh destroy --yes' to recreate the network while preserving volumes, then run 'up' again."
fi
fi
return
fi
info "Creating network ${NETWORK_NAME}..."
container network create \
--label "${STACK_LABEL_KEY}=${STACK_LABEL_VALUE}" \
"${NETWORK_NAME}" >/dev/null
network_args=(--label "${STACK_LABEL_KEY}=${STACK_LABEL_VALUE}")
if [[ -n "${NETWORK_SUBNET}" ]]; then
network_args+=(--subnet "${NETWORK_SUBNET}")
fi
container network create "${network_args[@]}" "${NETWORK_NAME}" >/dev/null
}
ensure_volume() {
@@ -410,6 +424,7 @@ prepare_environment() {
POSTGRES_DB="$(read_env_value POSTGRES_DB sub2api)"
REDIS_PASSWORD="$(read_env_value REDIS_PASSWORD)"
TZ_VALUE="$(read_env_value TZ Asia/Shanghai)"
NETWORK_SUBNET="$(read_env_value APPLE_CONTAINER_NETWORK_SUBNET)"
[[ -n "${BIND_HOST}" ]] || die "BIND_HOST must not be empty."
validate_ipv4_address "${BIND_HOST}"
+19
View File
@@ -48,6 +48,8 @@ assert_exists "${STATE_DIR}/containers/sub2api-apple"
assert_exists "${STATE_DIR}/containers/sub2api-apple-postgres"
assert_exists "${STATE_DIR}/containers/sub2api-apple-redis"
assert_exists "${STATE_DIR}/running/sub2api-apple"
[[ ! -s "${STATE_DIR}/network-subnets/sub2api-apple" ]] || \
fail "up passed a subnet when APPLE_CONTAINER_NETWORK_SUBNET was unset"
"${SCRIPT}" status >/dev/null
"${SCRIPT}" up --recreate
@@ -62,6 +64,23 @@ assert_missing "${STATE_DIR}/containers/sub2api-apple"
assert_missing "${STATE_DIR}/networks/sub2api-apple"
assert_exists "${STATE_DIR}/volumes/sub2api-apple-data"
printf '\nAPPLE_CONTAINER_NETWORK_SUBNET=172.31.250.0/24\n' >>"${ENV_FILE}"
"${SCRIPT}" up
[[ "$(<"${STATE_DIR}/network-subnets/sub2api-apple")" == "172.31.250.0/24" ]] || \
fail "up did not pass APPLE_CONTAINER_NETWORK_SUBNET to network creation"
printf 'APPLE_CONTAINER_NETWORK_SUBNET=172.31.251.0/24\n' >>"${ENV_FILE}"
if mismatch_output="$("${SCRIPT}" up 2>&1)"; then
fail "up accepted a configured subnet that differs from the existing network"
fi
[[ "${mismatch_output}" == *"Existing network 'sub2api-apple' uses subnet '172.31.250.0/24'"* ]] || \
fail "up did not explain the existing network subnet mismatch"
[[ "${mismatch_output}" == *"destroy --yes"* ]] || \
fail "up did not provide the network migration command"
assert_exists "${STATE_DIR}/networks/sub2api-apple"
assert_exists "${STATE_DIR}/containers/sub2api-apple"
"${SCRIPT}" destroy --yes
"${SCRIPT}" up
"${SCRIPT}" destroy --volumes --yes
assert_missing "${STATE_DIR}/volumes/sub2api-apple-data"
+29 -2
View File
@@ -7,6 +7,7 @@ mkdir -p \
"${STATE_DIR}/containers" \
"${STATE_DIR}/running" \
"${STATE_DIR}/networks" \
"${STATE_DIR}/network-subnets" \
"${STATE_DIR}/volumes" \
"${STATE_DIR}/unowned/container" \
"${STATE_DIR}/unowned/network" \
@@ -34,10 +35,19 @@ inspect_resource() {
local resource_name=$2
local label_value="apple-container"
local address="192.168.65.4/24"
local subnet="192.168.65.0/24"
if [[ -e "${STATE_DIR}/unowned/${resource_type}/${resource_name}" ]]; then
label_value="other"
fi
if [[ "${resource_type}" == "network" ]]; then
if [[ -s "${STATE_DIR}/network-subnets/${resource_name}" ]]; then
subnet="$(<"${STATE_DIR}/network-subnets/${resource_name}")"
fi
printf '[{"configuration":{"ipv4Subnet":"%s","labels":{"org.sub2api.stack":"%s"}}}]\n' \
"${subnet}" "${label_value}"
return
fi
case "${resource_name}" in
sub2api-apple-postgres) address="192.168.65.2/24" ;;
sub2api-apple-redis) address="192.168.65.3/24" ;;
@@ -82,9 +92,26 @@ case "${command}" in
echo default
list_names "${STATE_DIR}/networks"
;;
create) touch "${STATE_DIR}/networks/$(last_argument "$@")" ;;
create)
network_name="$(last_argument "$@")"
subnet=""
while [[ $# -gt 0 ]]; do
case "$1" in
--subnet)
subnet=$2
shift 2
;;
*) shift ;;
esac
done
touch "${STATE_DIR}/networks/${network_name}"
printf '%s' "${subnet}" >"${STATE_DIR}/network-subnets/${network_name}"
;;
inspect) inspect_resource network "${1}" ;;
delete) rm -f "${STATE_DIR}/networks/${1}" ;;
delete)
rm -f "${STATE_DIR}/networks/${1}"
rm -f "${STATE_DIR}/network-subnets/${1}"
;;
*) exit 1 ;;
esac
;;