SQL Server 2008 迁移至 2022 容器化部署 技术总结

SQL Server 2008 迁移至 2022 容器化部署技术总结

一、 迁移背景与架构

   最近在一套测试验证环境的时候,因为原有测试环境使用的还是阿里云2008版sqlserver数据库,查阅了一下资料,打算迁移到2022版Liunx环境的Docker容器中,这中间遇到了一些问题,打算记录并总结下,以避免以后犯重复的问题。


二、 完整迁移实战命令与全流程清单

步骤 1:宿主机在大空间目录规划与赋权

因为sqlserver数据库有40多G,原有的系统的默认挂接盘空间不足,需要在新加的挂接盘 /data 分区下建立挂载目录,并赋予最高读写权限,防止容器内外出现用户权限冲突:

# 创建新的数据目录与备份存放目录
mkdir -p /data/mssql/main/data
mkdir -p /data/mssql/backup

# 赋予最高级别读写与执行权限(非常关键,防止 Error 31 及权限被拒)
chmod -R 777 /data/mssql

步骤 2:安全迁移备份文件

使用 rsync 工具将从阿里云下载并解压出来的 8.6G 完好备份文件移动到新的备份目录下:

rsync -avh /data/backup/db/rich/hygame/hygame.bak /data/mssql/backup/hygame.bak

# 确保搬迁后的文件权限依旧对容器开放
chmod 777 /data/mssql/backup/hygame.bak

步骤 3:重构 docker-compose.yml 部署配置

修改数据库服务的配置,将数据路径和备份路径以持久化卷(Volumes)的方式直接挂载。这样可以免去 docker cp 传输过程中的二次空间损坏。

version: '3.8'
services:
  sqlserver:
    image: mcr.microsoft.com/mssql/server:2022-latest
    .
    .
    .
    .
    .
    volumes:
      # 1. 将数据目录外挂到 100G 的大硬盘分区
      - /data/mssql/main/data:/var/opt/mssql
      # 2. 将备份文件所在的宿主机目录直接外挂为容器内 /tmp_backup
      - /data/mssql/backup:/tmp_backup

修改完成后,在控制台执行重启以应用全新的大硬盘容器环境:

# 停止旧容器并应用新配置
docker-compose down
docker-compose up -d

步骤 4:查看文件内部逻辑流名称(恢复前置校验)

在正式还原前,需要先探测该 .bak 备份文件内部的逻辑数据流名称(LogicalName)。在宿主机终端输入:

docker-compose exec sqlserver /opt/mssql-tools18/bin/sqlcmd \
  -S localhost -U sa -P '你的安全密码' -C \
  -Q "RESTORE FILELISTONLY FROM DISK = N'/tmp_backup/hygame.bak'"

返回结果校验: 执行后会输出一个表格,注意看前两行的 LogicalName 列。
成功获取到 2 行数据,**LogicalName**分别为 data1(数据文件)和 log(日志文件)。

LogicalName  PhysicalName  Type  FileGroupName  Size  MaxSize  FileId  CreateLSN  DropLSN  UniqueId  ReadOnlyLSN  ReadWriteLSN  BackupSizeInBytes  SourceBlockSize  FileGroupId  LogGroupGUID  DifferentialBaseLSN  DifferentialBaseGUID   IsReadOnly  IsPresent  TDEThumbprint  SnapshotUrl                                                                                                                                                                                                                                                                                                                                     
-------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
data1   d:\ms3002\Data\hygame\data1.mdf  D  PRIMARY  43350360064  536870912000  1  0  0  B8F6CED4-0C2E-4C53-A262-9698BD8861E6  0  0  40550793216  512  1 NULL  2747000012926900071 98123469-DE49-411C-823C-BA1A1F1F3ADE  0  1  NULL  NULL                                                                                                                                                                                                                                                                                                                                            
log  d:\ms3002\log\hygame\log.ldf  L  NULL  536870912   536870912000   2  0  0  22E8D69C-5239-4B41-BBA6-5F497DC964BC  0  0  0  512  0  NULL  0  00000000-0000-0000-0000-000000000000  0  1  NULL  NULL     

步骤 5:强行清场并执行最终物理还原

由于 后端应用可能会在容器启动时自动抢占连接,还原前必须加入“独占单用户”指令强行断开外部干扰。

在宿主机终端执行以下组合拳命令:

docker-compose exec sqlserver /opt/mssql-tools18/bin/sqlcmd \
  -S localhost -U sa -P '你的安全密码' -C \
  -Q "ALTER DATABASE [hygame] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
      RESTORE DATABASE [hygame] 
      FROM DISK = N'/tmp_backup/hygame.bak' 
      WITH MOVE N'上面查询到的LogicalName' TO N'/var/opt/mssql/data/hygame.mdf', 
      MOVE N'上面查询到的Log 类型的LogicalName' TO N'/var/opt/mssql/data/hygame_log.ldf',
      REPLACE,
      STATS = 10"

  • 命令关键参数释义
  • SET SINGLE_USER WITH ROLLBACK IMMEDIATE:立刻强行切断 外部工具的所有连接,防止还原被锁。
  • MOVE N'data1' TO ...:将备份里原本属于 Windows 环境的物理路径,强行重定向到 Linux 容器内部的路径下。
  • REPLACE:强行覆盖现有的同名空数据库。
  • STATS = 10:每当还原进度推进 10%,主动在终端打印一行进度日志(避免长时间无响应误以为卡死)。

步骤 6:异地同步后台进度监控命令(选跑)

在还原大文件过程中,可在另一终端窗口下直接透视 SQL Server 的真实核心进程百分比:

docker-compose exec sqlserver /opt/mssql-tools18/bin/sqlcmd \
  -S localhost -U sa -P '你的安全密码' -C \
  -Q "SELECT r.command, r.percent_complete, r.estimated_completion_time/1000 AS seconds_left 
      FROM sys.dm_exec_requests r 
      WHERE r.command = 'RESTORE DATABASE';"

  • percent_complete 达到 100.0seconds_left 清零时,证明底层物理迁移大功告成。

三、 核心关键节点与踩坑排查

在整个迁移过程中,曾遇到了一下一些问题,需要谨记:

节点 1:文件元数据 incomplete / 还原提示文件损坏

  • 现象:执行还原命令时,SQL Server 报 file ID 1 incorrectly formed and can not be read 错误。执行 RESTORE HEADERONLY 查看文件头,第一列显示为 *** INCOMPLETE ***
  • 原因:Linux 容器内部权限封锁。备份文件上传后默认属于 root:root,当容器内的 mssql 进程尝试深度扫描大文件数据流时,被 Linux 内核强行截断,导致数据库误判定文件损坏或残缺。
  • 解决:利用 docker exec -u root 强行突破,将文件属主改为 mssql:mssql 并赋权 777

节点 2:容器内部文件大小对不上(4.1G 瓶颈)

  • 现象:发现宿主机上解压出的原始备份文件是 8.6G,但使用 docker cp 强行拷贝进容器内部后,文件莫名其妙缩水变成了 4.1G
  • 原因:Docker 容器默认的存储驱动(Overlay2)或文件层受到了宿主机单文件写入上限(或分区空间不足)的封锁,导致中途断流,文件只拷进去了一半。
  • 解决:彻底放弃 docker cp 往容器内塞文件的传统做法,采用 “物理目录挂载(Volume)” 的工业级标准,让容器直接读取宿主机硬盘,彻底打破空间和传输大小限制。

节点 3:Modify File Operating System Error 31 报错

  • 现象:文件完整度解决后,执行还原时出现 MODIFY FILE encountered operating system error 31 (A device attached to the system is not functioning.) while attempting to expand the physical file
  • 原因:磁盘空间严重不足。因为 8.6G 的备份文件在还原时,需要向硬盘申请至少 10G~20G 的连续空间来创建 .mdf 数据文件。原本的挂载分区空间耗尽,导致 Linux 拒绝了 SQL Server 的扩容申请。
  • 解决:通过 rsync 快速安全地将整个数据库和备份目录无缝搬迁到拥有 100G 宽裕空间的 /data 独立硬盘分区中,并重构 docker-compose.yml 挂载路径。

四、 迁移后续最佳实践(必做优化)

数据虽然成功搬迁过来了,但由于源数据库是 2008 版本的,我们需要通过以下两条 SQL 命令完成数据库的“现代化重构升级”:

请在 DataGripsqlcmd(注意:sqlcmd 命令行后必须换行输入 GO 才会触发执行)中运行:

-- 1. 确保数据库回到正常的多用户多人连接模式
ALTER DATABASE [hygame] SET MULTI_USER;
GO

-- 2. 将数据库架构由 2008(兼容级别 100)强行提升至 2022 最新标准(兼容级别 160)
-- 这能彻底激活 2022 引擎的高级查询优化器,让原本十几年前的老数据在现代硬件和 Linux 容器下获得倍增的性能。
USE [master];
GO
ALTER DATABASE [hygame] SET COMPATIBILITY_LEVEL = 160;
GO


五、 技术总结心得

  1. 容器大文件切忌 使用docker cp:直接通过挂载卷映射是应对几吉字节以上数据库备份的唯一可靠方案,能避免各种文件截断和二次损坏。
  2. 提前关注硬件指标:数据库物理恢复需要接近备份文件 2~3 倍的硬盘冗余空间用于初始化扩容,在迁移前必须通过 df -h 确认底层硬盘的可用容量。
  3. 分清客户端差异:交互式命令行工具 sqlcmd 在键入查询后必须紧跟一个独立的 GO 命令作为结束符,否则无法将请求投递至服务层,在日常测试时应当优先以此排查“有库无数据”的假象。

阅读更多

InfluxDB 性能优化:从配置到客户端,我趟过的坑

InfluxDB 性能优化:从配置到客户端,我趟过的坑

前几年搭建了一套轻量级的ELK服务,中间用到了influxdb作为底层存储服务,在遇到InfluxDB写入量大的时候,各种奇怪的性能问题就冒出来了。这篇总结一下我这几年调优 InfluxDB 1.8 的经验,覆盖配置、Telegraf、客户端和运维四个层面,有不少坑是看了日志才找到根因的。 环境说明:本文基于 InfluxDB 1.8,单机部署,数据写入量约 50 万点/秒,CentOS 7 + SSD 硬盘。不同版本或部署方式下,部分参数行为可能略有差异。 一、InfluxDB 配置优化 官方配置文档:https://docs.influxdata.com/influxdb/v1/administration/config/ 1. 打开请求日志,方便排查问题 [http] access-log-path = "/var/log/influxdb/

By chenjg
从 200G 到 20G:我的 Docker 清理实战经验

从 200G 到 20G:我的 Docker 清理实战经验

你有没有经历过这种事——服务器磁盘突然报警,一查原因:Docker 把磁盘吃了几十个 G,服务全挂。这就是 Docker 的隐藏黑洞:日志无限写 + overlay2 堆积,等到发现时已经晚了。 这篇文章说清楚两件事:怎么提前防住,以及真的爆了怎么救。 一、日志:那个一直在写的文件 Docker 默认用 json-file 日志驱动,没有轮转、没有限制、一直写到底。 日志位置:/var/lib/docker/containers/<container-id>/<container-id>-json.log # 查看所有容器日志大小 find /var/lib/docker/containers -name "*-json.log&

By chenjg
降本增效-自建轻量级网关trafik总结

降本增效-自建轻量级网关trafik总结

前段时间发现自己搭建的阿里云网站的每月费用有个上升趋势,后来仔细排查了一下账单数据,发现是SLB这块费用见涨,原来是SLB这边已经改了计费规则。按目前的账单来看,算了下一年下来要支付差不多小1千块钱啊,也是一笔不小的支出。决定果断放弃阿里云的负载均衡方案,通过购买一台1H1G服务器,自建网关服务器;         自建网关方案,相比来说 要省钱很多,风险主要是把网关的公网IP暴露出来,会引起一些不必要的麻烦和攻击;但目前主要搭建了一套个人自用的服务,被攻击概率不大,而且即使被攻击的话,必要的时候可以通过切换服务器方式来避免; 同时针对 对外开放的服务域名,可通过cloudflare 代理的方式,隐藏掉网关真实IP地址(目前cloudflare 在国内没有节点,所以相对来说访问速度会慢些,做一下必要的取舍吧);         调研了一些主流网关服务, nginx、haproxy 、traefik产品。          其实应该首选nginx及相关产品应用,nginx本身只支持七层代理,但可以通过插件化安装,实现 四层管理。毕竟nginx用的太多,生态确实可以

By chenjg
敬请同名微信公众号