feat(objectstorage): add Aliyun OSS support and auto-detect provider in deploy workflows
Introduces Aliyun OSS as an alternative to MinIO; deploy scripts and CI workflows now read object_storage.provider from config and conditionally include or skip MinIO resources in both Docker Compose and k3s paths. Also adds ops scheduler domain and its migration tables. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,20 @@ jobs:
|
||||
run: |
|
||||
docker compose -f deploy/docker-compose.yaml config >/tmp/compose.yaml
|
||||
docker compose -f deploy/docker-compose.yaml -f deploy/docker-compose.offline.yaml config >/tmp/compose-offline.yaml
|
||||
docker compose -f deploy/docker-compose.yaml -f deploy/docker-compose.offline.yaml -f deploy/docker-compose.aliyun-oss.yaml config >/tmp/compose-aliyun-oss.yaml
|
||||
|
||||
- name: Validate k3s manifests
|
||||
run: |
|
||||
if ! command -v kubectl >/dev/null 2>&1; then
|
||||
echo "kubectl not found; skipping kustomize manifest validation."
|
||||
exit 0
|
||||
fi
|
||||
kubectl kustomize deploy/k3s >/tmp/k3s.yaml
|
||||
kubectl kustomize deploy/k3s-aliyun-oss >/tmp/k3s-aliyun-oss.yaml
|
||||
if grep -Eq 'name: (minio|minio-init)$' /tmp/k3s-aliyun-oss.yaml; then
|
||||
echo "aliyun object-storage overlay must not render MinIO resources"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Smoke build server runtime image
|
||||
run: |
|
||||
|
||||
@@ -573,6 +573,90 @@ jobs:
|
||||
docker_cmd compose "$@"
|
||||
}
|
||||
|
||||
ensure_config_aliases() {
|
||||
for yaml in config.yaml config.local.yaml ops-config.yaml ops-config.local.yaml; do
|
||||
yml="${yaml%.yaml}.yml"
|
||||
if [ ! -f "${release_dir}/deploy/${yaml}" ] && [ -f "${release_dir}/deploy/${yml}" ]; then
|
||||
cp "${release_dir}/deploy/${yml}" "${release_dir}/deploy/${yaml}"
|
||||
echo "Created ${yaml} from ${yml} for deployment mounts."
|
||||
fi
|
||||
done
|
||||
if [ ! -f "${release_dir}/deploy/prompts.yml" ] && [ -f "${release_dir}/deploy/prompts.yaml" ]; then
|
||||
cp "${release_dir}/deploy/prompts.yaml" "${release_dir}/deploy/prompts.yml"
|
||||
echo "Created prompts.yml from prompts.yaml for deployment mounts."
|
||||
fi
|
||||
}
|
||||
|
||||
config_file_path() {
|
||||
base="$1"
|
||||
for file in "${release_dir}/deploy/${base}.yaml" "${release_dir}/deploy/${base}.yml"; do
|
||||
if [ -f "${file}" ]; then
|
||||
printf '%s' "${file}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
read_object_storage_provider() {
|
||||
provider="minio"
|
||||
for file in "$(config_file_path config)" "$(config_file_path config.local)"; do
|
||||
if [ -z "${file}" ] || [ ! -f "${file}" ]; then
|
||||
continue
|
||||
fi
|
||||
next="$(
|
||||
awk '
|
||||
/^[[:space:]]*object_storage:[[:space:]]*$/ {
|
||||
in_section=1
|
||||
base=match($0, /[^[:space:]]/) - 1
|
||||
next
|
||||
}
|
||||
in_section {
|
||||
indent=match($0, /[^[:space:]]/) - 1
|
||||
if ($0 ~ /^[[:space:]]*$/ || $0 ~ /^[[:space:]]*#/) {
|
||||
next
|
||||
}
|
||||
if (indent <= base) {
|
||||
in_section=0
|
||||
next
|
||||
}
|
||||
if ($0 ~ /^[[:space:]]*provider[[:space:]]*:/) {
|
||||
value=$0
|
||||
sub(/^[[:space:]]*provider[[:space:]]*:[[:space:]]*/, "", value)
|
||||
sub(/[[:space:]]+#.*$/, "", value)
|
||||
gsub(/^["'\'']|["'\'']$/, "", value)
|
||||
print value
|
||||
}
|
||||
}
|
||||
' "${file}" | tail -1
|
||||
)"
|
||||
if [ -n "${next}" ]; then
|
||||
provider="${next}"
|
||||
fi
|
||||
done
|
||||
printf '%s' "$(printf '%s' "${provider}" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')"
|
||||
}
|
||||
|
||||
use_minio_for_object_storage() {
|
||||
case "$(read_object_storage_provider)" in
|
||||
""|minio|mino)
|
||||
return 0
|
||||
;;
|
||||
aliyun|aliyun_oss|aliyun-oss|oss)
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
compose_files() {
|
||||
printf '%s\n' -f "${release_dir}/deploy/docker-compose.yaml"
|
||||
if ! use_minio_for_object_storage; then
|
||||
printf '%s\n' -f "${release_dir}/deploy/docker-compose.aliyun-oss.yaml"
|
||||
fi
|
||||
}
|
||||
|
||||
docker_login() {
|
||||
if [ "${DOCKER_MODE}" = "sudo" ]; then
|
||||
printf '%s\n' "${SUDO_PASSWORD}" | sudo -S -p "" -v
|
||||
@@ -606,11 +690,20 @@ jobs:
|
||||
fi
|
||||
|
||||
docker_login
|
||||
ensure_config_aliases
|
||||
provider="$(read_object_storage_provider)"
|
||||
if use_minio_for_object_storage; then
|
||||
echo "object_storage.provider=${provider}; deploying MinIO."
|
||||
else
|
||||
echo "object_storage.provider=${provider}; skipping MinIO."
|
||||
export COMPOSE_PROFILES=""
|
||||
docker_cmd rm -f geo-minio geo-minio-init >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
IMAGE_REGISTRY="${REGISTRY_HOST}/${REGISTRY_OWNER}/${REGISTRY_IMAGE_PREFIX}" \
|
||||
IMAGE_TAG="${IMAGE_TAG}" compose_cmd \
|
||||
--env-file "${shared_dir}/.env" \
|
||||
-f "${release_dir}/deploy/docker-compose.yaml" \
|
||||
$(compose_files) \
|
||||
config >/tmp/geo-rankly-compose-service.yaml
|
||||
|
||||
if [ "${RUN_MIGRATIONS}" = "true" ]; then
|
||||
@@ -618,19 +711,19 @@ jobs:
|
||||
IMAGE_REGISTRY="${REGISTRY_HOST}/${REGISTRY_OWNER}/${REGISTRY_IMAGE_PREFIX}" \
|
||||
IMAGE_TAG="${IMAGE_TAG}" compose_cmd \
|
||||
--env-file "${shared_dir}/.env" \
|
||||
-f "${release_dir}/deploy/docker-compose.yaml" \
|
||||
$(compose_files) \
|
||||
rm -f -s migrate >/dev/null 2>&1 || true
|
||||
|
||||
IMAGE_REGISTRY="${REGISTRY_HOST}/${REGISTRY_OWNER}/${REGISTRY_IMAGE_PREFIX}" \
|
||||
IMAGE_TAG="${IMAGE_TAG}" compose_cmd \
|
||||
--env-file "${shared_dir}/.env" \
|
||||
-f "${release_dir}/deploy/docker-compose.yaml" \
|
||||
$(compose_files) \
|
||||
pull migrate
|
||||
|
||||
IMAGE_REGISTRY="${REGISTRY_HOST}/${REGISTRY_OWNER}/${REGISTRY_IMAGE_PREFIX}" \
|
||||
IMAGE_TAG="${IMAGE_TAG}" compose_cmd \
|
||||
--env-file "${shared_dir}/.env" \
|
||||
-f "${release_dir}/deploy/docker-compose.yaml" \
|
||||
$(compose_files) \
|
||||
up --no-build --force-recreate migrate
|
||||
fi
|
||||
|
||||
@@ -638,14 +731,14 @@ jobs:
|
||||
IMAGE_REGISTRY="${REGISTRY_HOST}/${REGISTRY_OWNER}/${REGISTRY_IMAGE_PREFIX}" \
|
||||
IMAGE_TAG="${IMAGE_TAG}" compose_cmd \
|
||||
--env-file "${shared_dir}/.env" \
|
||||
-f "${release_dir}/deploy/docker-compose.yaml" \
|
||||
$(compose_files) \
|
||||
pull ${SERVICE_LIST}
|
||||
|
||||
echo "Restarting selected service(s): ${SERVICE_LIST}"
|
||||
IMAGE_REGISTRY="${REGISTRY_HOST}/${REGISTRY_OWNER}/${REGISTRY_IMAGE_PREFIX}" \
|
||||
IMAGE_TAG="${IMAGE_TAG}" compose_cmd \
|
||||
--env-file "${shared_dir}/.env" \
|
||||
-f "${release_dir}/deploy/docker-compose.yaml" \
|
||||
$(compose_files) \
|
||||
up -d --no-build --no-deps --force-recreate ${SERVICE_LIST}
|
||||
|
||||
ln -sfn "${release_dir}" "${DEPLOY_BASE}/current"
|
||||
@@ -653,7 +746,7 @@ jobs:
|
||||
IMAGE_REGISTRY="${REGISTRY_HOST}/${REGISTRY_OWNER}/${REGISTRY_IMAGE_PREFIX}" \
|
||||
IMAGE_TAG="${IMAGE_TAG}" compose_cmd \
|
||||
--env-file "${shared_dir}/.env" \
|
||||
-f "${release_dir}/deploy/docker-compose.yaml" \
|
||||
$(compose_files) \
|
||||
ps ${SERVICE_LIST}
|
||||
|
||||
if [ "${KEEP_RELEASES}" -gt 0 ] 2>/dev/null; then
|
||||
|
||||
@@ -697,6 +697,103 @@ jobs:
|
||||
printf '%s:%s' "$(image_name "$1")" "${IMAGE_TAG}"
|
||||
}
|
||||
|
||||
ensure_config_aliases() {
|
||||
for yaml in config.yaml config.local.yaml ops-config.yaml ops-config.local.yaml; do
|
||||
yml="${yaml%.yaml}.yml"
|
||||
if [ ! -f "${release_dir}/deploy/${yaml}" ] && [ -f "${release_dir}/deploy/${yml}" ]; then
|
||||
cp "${release_dir}/deploy/${yml}" "${release_dir}/deploy/${yaml}"
|
||||
echo "Created ${yaml} from ${yml} for deployment mounts."
|
||||
fi
|
||||
done
|
||||
if [ ! -f "${release_dir}/deploy/prompts.yml" ] && [ -f "${release_dir}/deploy/prompts.yaml" ]; then
|
||||
cp "${release_dir}/deploy/prompts.yaml" "${release_dir}/deploy/prompts.yml"
|
||||
echo "Created prompts.yml from prompts.yaml for deployment mounts."
|
||||
fi
|
||||
}
|
||||
|
||||
config_file_path() {
|
||||
base="$1"
|
||||
for file in "${release_dir}/deploy/${base}.yaml" "${release_dir}/deploy/${base}.yml"; do
|
||||
if [ -f "${file}" ]; then
|
||||
printf '%s' "${file}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
read_object_storage_provider() {
|
||||
provider="minio"
|
||||
for file in "$(config_file_path config)" "$(config_file_path config.local)"; do
|
||||
if [ -z "${file}" ] || [ ! -f "${file}" ]; then
|
||||
continue
|
||||
fi
|
||||
next="$(
|
||||
awk '
|
||||
/^[[:space:]]*object_storage:[[:space:]]*$/ {
|
||||
in_section=1
|
||||
base=match($0, /[^[:space:]]/) - 1
|
||||
next
|
||||
}
|
||||
in_section {
|
||||
indent=match($0, /[^[:space:]]/) - 1
|
||||
if ($0 ~ /^[[:space:]]*$/ || $0 ~ /^[[:space:]]*#/) {
|
||||
next
|
||||
}
|
||||
if (indent <= base) {
|
||||
in_section=0
|
||||
next
|
||||
}
|
||||
if ($0 ~ /^[[:space:]]*provider[[:space:]]*:/) {
|
||||
value=$0
|
||||
sub(/^[[:space:]]*provider[[:space:]]*:[[:space:]]*/, "", value)
|
||||
sub(/[[:space:]]+#.*$/, "", value)
|
||||
gsub(/^["'\'']|["'\'']$/, "", value)
|
||||
print value
|
||||
}
|
||||
}
|
||||
' "${file}" | tail -1
|
||||
)"
|
||||
if [ -n "${next}" ]; then
|
||||
provider="${next}"
|
||||
fi
|
||||
done
|
||||
printf '%s' "$(printf '%s' "${provider}" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')"
|
||||
}
|
||||
|
||||
use_minio_for_object_storage() {
|
||||
case "$(read_object_storage_provider)" in
|
||||
""|minio|mino)
|
||||
return 0
|
||||
;;
|
||||
aliyun|aliyun_oss|aliyun-oss|oss)
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
sync_k3s_config() {
|
||||
mkdir -p "${release_dir}/deploy/k3s/config"
|
||||
for name in config ops-config prompts; do
|
||||
output="${name}.yaml"
|
||||
if [ "${name}" = "prompts" ]; then
|
||||
output="prompts.yml"
|
||||
fi
|
||||
source=""
|
||||
for candidate in "${release_dir}/deploy/${name}.yaml" "${release_dir}/deploy/${name}.yml"; do
|
||||
if [ -f "${candidate}" ]; then
|
||||
source="${candidate}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -n "${source}" ]; then
|
||||
cp "${source}" "${release_dir}/deploy/k3s/config/${output}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
echo "Sudo mode: ${SUDO_MODE}"
|
||||
kubectl_cmd version --client
|
||||
|
||||
@@ -797,6 +894,128 @@ jobs:
|
||||
sed -i "\#name: ${old_name}#,\#newTag:# s#newTag: .*#newTag: ${IMAGE_TAG}#" "${rendered_dir}/kustomization.yaml"
|
||||
}
|
||||
|
||||
apply_object_storage_kustomize_mode() {
|
||||
sync_k3s_config
|
||||
provider="$(read_object_storage_provider)"
|
||||
if use_minio_for_object_storage; then
|
||||
echo "object_storage.provider=${provider}; deploying MinIO."
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "object_storage.provider=${provider}; skipping MinIO."
|
||||
sed -i '/^patches:[[:space:]]*$/,/^[^[:space:]-]/{/^patches:[[:space:]]*$/d;/^[^[:space:]-]/!d;}' "${rendered_dir}/kustomization.yaml"
|
||||
mkdir -p "${rendered_dir}/patches"
|
||||
cat > "${rendered_dir}/patches/object-storage-env.yaml" <<'EOF'
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: tenant-api
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: tenant-api
|
||||
env:
|
||||
- name: OBJECT_STORAGE_ACCESS_KEY
|
||||
$patch: delete
|
||||
- name: OBJECT_STORAGE_SECRET_KEY
|
||||
$patch: delete
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: worker-generate
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: worker-generate
|
||||
env:
|
||||
- name: OBJECT_STORAGE_ACCESS_KEY
|
||||
$patch: delete
|
||||
- name: OBJECT_STORAGE_SECRET_KEY
|
||||
$patch: delete
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kol-assist-worker
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: kol-assist-worker
|
||||
env:
|
||||
- name: OBJECT_STORAGE_ACCESS_KEY
|
||||
$patch: delete
|
||||
- name: OBJECT_STORAGE_SECRET_KEY
|
||||
$patch: delete
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: scheduler
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: scheduler
|
||||
env:
|
||||
- name: OBJECT_STORAGE_ACCESS_KEY
|
||||
$patch: delete
|
||||
- name: OBJECT_STORAGE_SECRET_KEY
|
||||
$patch: delete
|
||||
EOF
|
||||
cat >> "${rendered_dir}/kustomization.yaml" <<'EOF'
|
||||
patches:
|
||||
- target:
|
||||
version: v1
|
||||
kind: Service
|
||||
name: minio
|
||||
patch: |-
|
||||
$patch: delete
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: minio
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: minio
|
||||
patch: |-
|
||||
$patch: delete
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: minio
|
||||
- target:
|
||||
group: batch
|
||||
version: v1
|
||||
kind: Job
|
||||
name: minio-init
|
||||
patch: |-
|
||||
$patch: delete
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: minio-init
|
||||
- path: patches/object-storage-env.yaml
|
||||
EOF
|
||||
}
|
||||
|
||||
cleanup_minio_if_external_object_storage() {
|
||||
if use_minio_for_object_storage; then
|
||||
return 0
|
||||
fi
|
||||
kubectl_cmd -n "${K3S_NAMESPACE}" delete statefulset minio --ignore-not-found
|
||||
kubectl_cmd -n "${K3S_NAMESPACE}" delete service minio --ignore-not-found
|
||||
kubectl_cmd -n "${K3S_NAMESPACE}" delete job minio-init --ignore-not-found
|
||||
for svc in tenant-api worker-generate kol-assist-worker scheduler; do
|
||||
kubectl_cmd -n "${K3S_NAMESPACE}" set env "deployment/${svc}" OBJECT_STORAGE_ACCESS_KEY- OBJECT_STORAGE_SECRET_KEY- >/dev/null 2>&1 || true
|
||||
done
|
||||
}
|
||||
|
||||
render_kustomize() {
|
||||
rm -rf "${rendered_dir}"
|
||||
mkdir -p "${rendered_dir}"
|
||||
@@ -808,6 +1027,7 @@ jobs:
|
||||
|
||||
# Migrations are applied explicitly by this workflow after preflight.
|
||||
sed -i '/^[[:space:]]*- jobs.yaml[[:space:]]*$/d' "${rendered_dir}/kustomization.yaml"
|
||||
apply_object_storage_kustomize_mode
|
||||
|
||||
patch_kustomize_image "geo-rankly/migrate" "migrate"
|
||||
patch_kustomize_image "geo-rankly/tenant-api" "tenant-api"
|
||||
@@ -832,6 +1052,7 @@ jobs:
|
||||
}
|
||||
|
||||
apply_config_map() {
|
||||
sync_k3s_config
|
||||
kubectl_cmd -n "${K3S_NAMESPACE}" create configmap geo-rankly-app-config \
|
||||
--from-file=config.yaml="${release_dir}/deploy/k3s/config/config.yaml" \
|
||||
--from-file=prompts.yml="${release_dir}/deploy/k3s/config/prompts.yml" \
|
||||
@@ -847,6 +1068,27 @@ jobs:
|
||||
sed -i "s#image: geo-rankly/migrate:latest#image: $(image_ref migrate)#" "${rendered_jobs}"
|
||||
|
||||
kubectl_cmd -n "${K3S_NAMESPACE}" delete job migrate minio-init --ignore-not-found
|
||||
if ! use_minio_for_object_storage; then
|
||||
awk '
|
||||
/^---[[:space:]]*$/ { doc=doc "\n" $0 "\n"; next }
|
||||
{ doc=doc $0 "\n" }
|
||||
END {
|
||||
n=split(doc, docs, /\n---\n/)
|
||||
for (i=1; i<=n; i++) {
|
||||
if (docs[i] ~ /kind:[[:space:]]*Job/ && docs[i] ~ /name:[[:space:]]*minio-init/) {
|
||||
continue
|
||||
}
|
||||
if (docs[i] ~ /[^[:space:]]/) {
|
||||
if (printed) print "---"
|
||||
printf "%s", docs[i]
|
||||
if (substr(docs[i], length(docs[i]), 1) != "\n") print ""
|
||||
printed=1
|
||||
}
|
||||
}
|
||||
}
|
||||
' "${rendered_jobs}" > "${rendered_jobs}.tmp"
|
||||
mv "${rendered_jobs}.tmp" "${rendered_jobs}"
|
||||
fi
|
||||
kubectl_cmd -n "${K3S_NAMESPACE}" apply -f "${rendered_jobs}"
|
||||
}
|
||||
|
||||
@@ -959,7 +1201,9 @@ jobs:
|
||||
if [ -n "${IMAGE_LIST}" ]; then
|
||||
ensure_plain_http_registry
|
||||
fi
|
||||
ensure_config_aliases
|
||||
ensure_namespace
|
||||
cleanup_minio_if_external_object_storage
|
||||
if [ -n "${IMAGE_LIST}" ]; then
|
||||
ensure_registry_secret
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user