From 9f6d7b2d7dcc8e8edaed10a6e43cd55c6069117e Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Sun, 15 Mar 2026 18:52:49 +0800 Subject: [PATCH] feat(deploy): add single-node compose migration for accounts --- .gitignore | 2 + ansible.cfg | 13 ++++ ansible/inventory.ini | 9 +++ ansible/playbooks/deploy_accounts_compose.yml | 7 ++ .../accounts_compose_deploy/defaults/main.yml | 21 ++++++ .../accounts_compose_deploy/tasks/main.yml | 7 ++ ansible/vars/accounts.host.example.yml | 37 ++++++++++ entrypoint.sh | 74 ++++++++++++++++++- 8 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 ansible.cfg create mode 100644 ansible/inventory.ini create mode 100644 ansible/playbooks/deploy_accounts_compose.yml create mode 100644 ansible/roles/accounts_compose_deploy/defaults/main.yml create mode 100644 ansible/roles/accounts_compose_deploy/tasks/main.yml create mode 100644 ansible/vars/accounts.host.example.yml diff --git a/.gitignore b/.gitignore index 998261d..2b4a8da 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,5 @@ account-export.yaml # Security tooling reports .gitleaks/ +ansible/vars/*.host.yml +ansible/vars/*.vault.yml diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..fc9b194 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,13 @@ +[defaults] +inventory = ansible/inventory.ini +roles_path = ansible/roles:../github-org-cloud-neutral-toolkit/ansible/roles +host_key_checking = False +retry_files_enabled = False +interpreter_python = auto_silent +forks = 1 +timeout = 30 + +[ssh_connection] +pipelining = True +transfer_method = piped +ssh_args = -o ControlMaster=no -o ControlPersist=no -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -o IPQoS=none diff --git a/ansible/inventory.ini b/ansible/inventory.ini new file mode 100644 index 0000000..01d6a6e --- /dev/null +++ b/ansible/inventory.ini @@ -0,0 +1,9 @@ +[server] +us-xhttp.svc.plus ansible_host=5.78.45.49 ansible_user=root + +[all:vars] +ansible_port=22 +ansible_user=root +ansible_host_key_checking=False +ansible_ssh_private_key_file=~/.ssh/id_rsa +ansible_ssh_transfer_method=piped diff --git a/ansible/playbooks/deploy_accounts_compose.yml b/ansible/playbooks/deploy_accounts_compose.yml new file mode 100644 index 0000000..bcfc9cd --- /dev/null +++ b/ansible/playbooks/deploy_accounts_compose.yml @@ -0,0 +1,7 @@ +- name: Deploy accounts.svc.plus to the single-node Docker Compose host + hosts: server + become: yes + gather_facts: yes + roles: + - role: accounts_compose_deploy + diff --git a/ansible/roles/accounts_compose_deploy/defaults/main.yml b/ansible/roles/accounts_compose_deploy/defaults/main.yml new file mode 100644 index 0000000..53380cc --- /dev/null +++ b/ansible/roles/accounts_compose_deploy/defaults/main.yml @@ -0,0 +1,21 @@ +service_compose_service_slug: accounts +service_compose_image: REPLACE_IMAGE +service_compose_zone: svc.plus +service_compose_container_port: 8080 +service_compose_git_short_commit: "{{ lookup('ansible.builtin.env', 'GIT_SHORT_COMMIT') | default('manual', true) }}" +service_compose_env_common: + CONFIG_TEMPLATE: /app/config/account.cloudrun.yaml +service_compose_deploy_targets: + - name: prod + deploy_subdomain_prefix: accounts + stable_domains: + - accounts.svc.plus + host_port: 18080 + env: {} + - name: preview + deploy_subdomain_prefix: accounts-preview + stable_domains: + - accounts-preview.svc.plus + host_port: 18081 + env: {} + diff --git a/ansible/roles/accounts_compose_deploy/tasks/main.yml b/ansible/roles/accounts_compose_deploy/tasks/main.yml new file mode 100644 index 0000000..d63f02d --- /dev/null +++ b/ansible/roles/accounts_compose_deploy/tasks/main.yml @@ -0,0 +1,7 @@ +- name: Load accounts compose defaults + ansible.builtin.include_vars: + file: "{{ role_path }}/defaults/main.yml" + +- name: Delegate accounts deployment to the shared compose role + ansible.builtin.include_role: + name: shared_compose_service_deploy diff --git a/ansible/vars/accounts.host.example.yml b/ansible/vars/accounts.host.example.yml new file mode 100644 index 0000000..b3681c8 --- /dev/null +++ b/ansible/vars/accounts.host.example.yml @@ -0,0 +1,37 @@ +# Copy to ansible/vars/accounts.host.yml (gitignored), or store the real values +# in an external Ansible Vault file and pass it with: +# ansible-playbook -D -C ansible/playbooks/deploy_accounts_compose.yml -e @/secure/path/accounts.vault.yml + +service_compose_image: ghcr.io/YOUR_GITHUB_ORG/accounts:latest +service_compose_registry_server: ghcr.io +service_compose_registry_username: CHANGE_ME +service_compose_registry_password: CHANGE_ME +service_compose_env_common: + CONFIG_TEMPLATE: /app/config/account.cloudrun.yaml + INTERNAL_SERVICE_TOKEN: CHANGE_ME + DB_TLS_HOST: postgresql-aws.svc.plus + DB_TLS_PORT: "5443" + POSTGRES_USER: postgres + POSTGRES_PASSWORD: CHANGE_ME + DB_USER: postgres + DB_NAME: account + DB_PASSWORD: CHANGE_ME + SMTP_HOST: smtp.qq.com + SMTP_PORT: "587" + SMTP_FROM: XControl Account + SMTP_USERNAME: CHANGE_ME + SMTP_PASSWORD: CHANGE_ME +service_compose_deploy_targets: + - name: prod + deploy_subdomain_prefix: accounts + stable_domains: + - accounts.svc.plus + host_port: 18080 + env: {} + - name: preview + deploy_subdomain_prefix: accounts-preview + stable_domains: + - accounts-preview.svc.plus + host_port: 18081 + image: ghcr.io/YOUR_GITHUB_ORG/accounts-preview:latest + env: {} diff --git a/entrypoint.sh b/entrypoint.sh index 6b02a02..2561a0c 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,6 +1,70 @@ #!/usr/bin/env bash set -euo pipefail +# ----------------------------------------------------------------------------- +# Database tunnel bootstrap +# ----------------------------------------------------------------------------- + +USE_STUNNEL=0 +STUNNEL_CONF="/etc/stunnel/stunnel.conf" + +if [ -z "${DB_USER:-}" ] && [ -n "${POSTGRES_USER:-}" ]; then + export DB_USER="${POSTGRES_USER}" +fi + +if [ -z "${DB_PASSWORD:-}" ] && [ -n "${POSTGRES_PASSWORD:-}" ]; then + export DB_PASSWORD="${POSTGRES_PASSWORD}" +fi + +if [ -z "${POSTGRES_USER:-}" ] && [ -n "${DB_USER:-}" ]; then + export POSTGRES_USER="${DB_USER}" +fi + +if [ -z "${POSTGRES_PASSWORD:-}" ] && [ -n "${DB_PASSWORD:-}" ]; then + export POSTGRES_PASSWORD="${DB_PASSWORD}" +fi + +if [ -z "${DB_NAME:-}" ] && [ -n "${POSTGRES_DB:-}" ]; then + export DB_NAME="${POSTGRES_DB}" +fi + +if [ -n "${DB_TLS_HOST:-}" ] && [ -n "${DB_TLS_PORT:-}" ]; then + USE_STUNNEL=1 + export DB_HOST="${DB_HOST:-127.0.0.1}" + export DB_PORT="${DB_PORT:-15432}" + + mkdir -p /etc/stunnel /var/run/stunnel + + if [ -n "${DB_CA:-}" ]; then + printf '%s\n' "${DB_CA}" > /etc/stunnel/ca.pem + fi + + cat > "${STUNNEL_CONF}" <> "${STUNNEL_CONF}" + elif [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then + echo "CAfile = /etc/ssl/certs/ca-certificates.crt" >> "${STUNNEL_CONF}" + fi + + if [ -n "${DB_TLS_SERVER_NAME:-}" ]; then + echo "checkHost = ${DB_TLS_SERVER_NAME}" >> "${STUNNEL_CONF}" + elif [ -n "${DB_TLS_HOST:-}" ]; then + echo "checkHost = ${DB_TLS_HOST}" >> "${STUNNEL_CONF}" + fi +fi + CONFIG_FILE="${CONFIG_PATH:-/etc/xcontrol/account.yaml}" CONFIG_TEMPLATE="${CONFIG_TEMPLATE:-/app/config/account.yaml}" mkdir -p "$(dirname "${CONFIG_FILE}")" @@ -31,10 +95,18 @@ if [ -n "${PORT:-}" ]; then CONFIG_FILE="${tmp_cfg}" fi -# Default to 127.0.0.1:15432 if not specified, to ensure we wait for stunnel DB_HOST="${DB_HOST:-127.0.0.1}" DB_PORT="${DB_PORT:-15432}" +if [ "${USE_STUNNEL}" -eq 1 ]; then + if ! command -v stunnel >/dev/null 2>&1; then + echo "stunnel is required but not installed" >&2 + exit 1 + fi + + stunnel "${STUNNEL_CONF}" +fi + if [ -n "${DB_HOST:-}" ] && [ -n "${DB_PORT:-}" ]; then if [ "${DB_HOST}" = "127.0.0.1" ] || [ "${DB_HOST}" = "localhost" ]; then if command -v nc >/dev/null; then