#!/usr/bin/env bash
|
# 迁移 nacos_config(MySQL → PG,pgloader 全自动重建结构+数据)。
|
# migrate-data.sh 只覆盖 jnpf_init/jnpf_flow;本脚本补 nacos_config(Nacos 存储库)。
|
# jnpf_xxljob 是空库(0 行),无需迁数据,install.sh 建的空 schema 即可。
|
#
|
# 用法:SRC_MYSQL_HOST=172.17.0.1 SRC_MYSQL_PWD='***' PG_PASSWORD='***' bash migrate-nacos-config.sh
|
# SRC_MYSQL_HOST 源 MySQL(默认 172.17.0.1 = CVM docker0 网关→homework-mysql)
|
# SRC_MYSQL_PWD 源 MySQL root 密码(必填)
|
# PG_PASSWORD 目标 PG postgres 密码(必填;或读 ~/jnpf-pg/.env 的 JNPF_PG_PASSWORD)
|
# CONTAINER PG 容器名(默认 cx-postgres)
|
set -euo pipefail
|
|
# ── 退役护栏(2026-07-25)─────────────────────────────────────────────────────
|
# nacos_config 的 MySQL→PG 迁移已于 2026-07-21 完成(config_info 28 / his 105 / tenant 4 与源一致)。
|
# 本脚本用 pgloader 重建结构+数据,重跑会覆盖 Nacos 存储库 —— 即抹掉配置中心的现有配置。
|
if [ "${I_KNOW_MIGRATION_IS_RETIRED:-}" != "1" ]; then
|
printf '\033[1;31m[已退役·拒绝执行]\033[0m %s\n' "migrate-nacos-config.sh 已于 2026-07-21 完成使命。" >&2
|
printf ' 重跑会用废弃 MySQL 的旧配置覆盖 CVM 上的 nacos_config —— 配置中心会被打回七月中旬。\n' >&2
|
printf ' 确需重跑请显式声明:I_KNOW_MIGRATION_IS_RETIRED=1 %s\n' "$0" >&2
|
exit 1
|
fi
|
|
SRC_MYSQL_HOST="${SRC_MYSQL_HOST:-172.17.0.1}"
|
SRC_MYSQL_PWD="${SRC_MYSQL_PWD:?缺 SRC_MYSQL_PWD}"
|
CONTAINER="${CONTAINER:-cx-postgres}"
|
PG_PASSWORD="${PG_PASSWORD:-$(grep ^JNPF_PG_PASSWORD "$HOME/jnpf-pg/.env" 2>/dev/null | cut -d= -f2)}"
|
[ -n "$PG_PASSWORD" ] || { echo "!! 缺 PG_PASSWORD"; exit 1; }
|
MIRROR=cx-nacos-mirror
|
PGLOADER_IMAGE="${PGLOADER_IMAGE:-dimitri/pgloader:latest}"
|
NET="$(docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{end}}' "$CONTAINER")"
|
log(){ printf '\033[1;34m[nacos-mig]\033[0m %s\n' "$*"; }
|
|
log "1) mysqldump nacos_config 源 ${SRC_MYSQL_HOST}"
|
docker run --rm mysql:8.0 mysqldump -h"$SRC_MYSQL_HOST" -uroot -p"$SRC_MYSQL_PWD" \
|
--single-transaction --hex-blob --skip-add-locks --set-gtid-purged=OFF nacos_config > /tmp/nacos_dump.sql 2>/dev/null
|
log " dump $(wc -l < /tmp/nacos_dump.sql) 行"
|
|
log "2) 起临时 mirror(native_password)灌 dump"
|
docker rm -f "$MIRROR" >/dev/null 2>&1 || true
|
docker run -d --name "$MIRROR" --network "$NET" -e MYSQL_ROOT_PASSWORD=mirror_2026 \
|
mysql:8.0 --default-authentication-plugin=mysql_native_password --skip-log-bin >/dev/null
|
for i in $(seq 1 40); do docker exec "$MIRROR" mysql -uroot -pmirror_2026 -e "SELECT 1" >/dev/null 2>&1 && break; sleep 2; done
|
docker exec "$MIRROR" mysql -uroot -pmirror_2026 -e "CREATE DATABASE nacos_config DEFAULT CHARSET utf8mb4"
|
docker exec -i "$MIRROR" mysql -uroot -pmirror_2026 nacos_config < /tmp/nacos_dump.sql
|
log " mirror config_info=$(docker exec "$MIRROR" mysql -uroot -pmirror_2026 -N -e 'SELECT count(*) FROM nacos_config.config_info') 行"
|
|
log "3) pgloader 全自动 mirror→PG(drop+建表+数据)"
|
cat > /tmp/nacos.load <<LOADEOF
|
LOAD DATABASE
|
FROM mysql://root:mirror_2026@${MIRROR}:3306/nacos_config
|
INTO postgresql://postgres:${PG_PASSWORD}@${CONTAINER}:5432/nacos_config
|
WITH include drop, create tables, create indexes, reset sequences, workers = 1, concurrency = 1
|
SET work_mem to '128MB', maintenance_work_mem to '256MB';
|
LOADEOF
|
docker run --rm --network "$NET" -v /tmp/nacos.load:/tmp/nacos.load "$PGLOADER_IMAGE" pgloader /tmp/nacos.load
|
|
log "4) 整合 schema:pgloader 默认把 MySQL 库名当成 PG schema,数据落进了 nacos_config schema"
|
# 而 install.sh 的 canonical Nacos 表在 public。把 pgloader 的表移进 public、丢弃 public 空表、
|
# 删空 nacos_config schema,得到单一可被 Nacos 直接使用的 public schema(详见 lessons L040)。
|
# owned 序列/索引/PK/注释随表自动移动;列默认值按 OID 存储不断裂。整个过程放一个事务里原子完成。
|
docker exec -i "$CONTAINER" psql -U postgres -d nacos_config <<'PSQL'
|
\set ON_ERROR_STOP on
|
BEGIN;
|
DO $$
|
DECLARE r record;
|
BEGIN
|
-- 若 install.sh 已在 public 建空 Nacos 表,先丢弃(仅丢与 nacos_config schema 同名的)
|
FOR r IN SELECT tablename FROM pg_tables WHERE schemaname='public'
|
AND tablename IN (SELECT tablename FROM pg_tables WHERE schemaname='nacos_config') LOOP
|
EXECUTE format('DROP TABLE public.%I CASCADE', r.tablename);
|
END LOOP;
|
-- 移表(owned 序列/索引/PK/注释随表自动移动,不能单独移 owned 序列)
|
FOR r IN SELECT tablename FROM pg_tables WHERE schemaname='nacos_config' LOOP
|
EXECUTE format('ALTER TABLE nacos_config.%I SET SCHEMA public', r.tablename);
|
END LOOP;
|
END $$;
|
DROP SCHEMA IF EXISTS nacos_config; -- 此时应为空;无 CASCADE = 残留则报错回滚(安全阀)
|
-- pgloader 建的表归 postgres;仅 GRANT 不够——Nacos 升级/开发改 schema 时 DDL 需 owner(L041)。
|
-- 按 create_app_roles.sql 同款逻辑把所有权移交 nacos_app:排除扩展对象(deptype='e')、owned 序列随表。
|
GRANT USAGE, CREATE ON SCHEMA public TO nacos_app;
|
DO $$
|
DECLARE r record;
|
BEGIN
|
FOR r IN
|
SELECT c.oid::regclass AS obj
|
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
|
WHERE n.nspname='public' AND c.relkind IN ('r','p','S','v','m')
|
AND c.relowner <> 'nacos_app'::regrole
|
AND NOT EXISTS (SELECT 1 FROM pg_depend d WHERE d.objid=c.oid AND d.deptype='e')
|
AND NOT (c.relkind='S' AND EXISTS (
|
SELECT 1 FROM pg_depend d2 WHERE d2.classid='pg_class'::regclass
|
AND d2.objid=c.oid AND d2.deptype IN ('a','i')))
|
LOOP
|
EXECUTE format('ALTER TABLE %s OWNER TO nacos_app', r.obj);
|
END LOOP;
|
END $$;
|
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO nacos_app;
|
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO nacos_app;
|
COMMIT;
|
PSQL
|
|
log "5) 校验 PG nacos_config(public schema,非限定查询=Nacos 视角)"
|
docker exec "$CONTAINER" psql -U postgres -d nacos_config -c \
|
"SELECT 'config_info' t,count(*) c FROM config_info UNION ALL SELECT 'his_config_info',count(*) FROM his_config_info UNION ALL SELECT 'tenant_info',count(*) FROM tenant_info ORDER BY 1"
|
|
log "6) 清理 mirror"
|
docker rm -f "$MIRROR" >/dev/null && rm -f /tmp/nacos_dump.sql /tmp/nacos.load
|
log "完成 ✓"
|