刘光辉
14 小时以前 34981c30a78e8bbd7791131059a9210f9928b62c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/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 "完成 ✓"