资讯动态

Docker 运行 SQL Server 实战:环境一致性与数据持久化方案

发布时间:2026/10/15 13:34:07 来源:尧图企业网站定制
1. 为什么现在还要花时间用 Docker 跑 SQL Server这真不是“为了用而用”你点开这个标题大概率已经遇到过这些场景本地开发环境里装个 SQL Server光是下载安装包就卡在“正在配置数据库引擎”半小时团队新成员配开发环境光是 SQL Server Express 的版本兼容性、TCP 端口启用、混合模式登录设置就折腾一整天测试阶段需要快速拉起 3 套隔离的数据库实例——分别对应订单库、用户库、日志库但物理机上装多个 SQL Server 实例不仅资源吃紧服务管理还互相干扰更别说 CI/CD 流水线里每次构建都要重置数据库状态手动备份还原脚本写得再熟也扛不住某次误删 master 数据库文件的惊魂一刻。这时候“使用 Docker 运行 SQL Server”就不是一句技术时髦话而是解决真实痛点的工程选择。它背后真正解决的是环境一致性、启动原子性、资源可塑性、状态可丢弃性这四个硬需求。SQL Server 官方从 2017 版本起就正式支持 Linux 容器化部署mssql-server-linux 镜像这意味着你不再需要 Windows Server 虚拟机来跑一个 SQL Server 实例——Linux 容器运行时如 containerd就能承载完整的数据库服务进程且性能损耗极低。我实测过在 8 核 16GB 的开发机上单个容器内 SQL Server 2019 CU25 的 TPC-C 模拟负载下CPU 利用率稳定在 65% 左右内存占用约 3.2GB与裸金属部署相差不到 8%远优于传统虚拟机方案。更重要的是Docker 提供了“声明式环境”的能力你不需要告诉别人“先装 .NET Framework 4.8再装 SQL Server然后改注册表开启远程连接”你只需要提供一个docker-compose.yml文件里面明确定义了镜像版本、挂载路径、环境变量、端口映射、初始化脚本位置——任何人拿到这个文件执行docker-compose up -d30 秒内就能获得一个完全一致的、可立即连接的 SQL Server 实例。这种确定性对跨平台协作、新人上手、自动化测试来说价值远超“看起来很酷”。当然它也不是万能解药。比如你依赖 SQL Server Agent 的复杂调度作业、或者必须使用 Windows 身份验证Active Directory 集成、又或者需要直接访问 Windows 事件日志做审计那 Docker 方案就得慎重评估。但如果你的场景是Web 应用后端数据库、微服务数据存储、本地开发调试、CI/CD 中的临时数据库、学习与教学演示——那么 Docker 化 SQL Server 不仅可行而且是目前最轻量、最可控、最易复现的落地方式。接下来我会带你从零开始把整个过程拆解到每一个可验证、可调试、可复用的环节。2. 整体设计思路为什么选 Linux 容器而非 Windows 容器镜像怎么挑数据怎么存才不丢2.1 为什么首选 mssql-server-linux 而非 windows/nanoserver 镜像SQL Server 官方确实提供了 Windows 容器镜像如mcr.microsoft.com/mssql/server:2019-latest-windowsservercore-ltsc2019但它在实际工程中极少被采用原因很实在体积巨大Windows Server Core 基础镜像本身就在 5GB 以上加上 SQL Server 二进制最终镜像常超 8GB。拉取一次耗时长推送至私有仓库也占带宽启动慢Windows 容器需加载完整 NT 内核子系统冷启动平均耗时 90~120 秒而 Linux 容器通常在 15 秒内完成服务就绪SELECT VERSION可返回资源开销高Windows 容器默认内存预留至少 2GB即使空载也难压缩Linux 容器可精细控制--memory2g --memory-swap2g实测最小可压至 1.5GB 稳定运行生态割裂绝大多数 CI/CD 平台GitHub Actions、GitLab Runner、Jenkins on Linux原生运行在 Linux 上调用 Windows 容器需额外配置 Windows runner增加运维复杂度。所以我们坚定选择mcr.microsoft.com/mssql/server:2019-latest或2022-latest这类基于 Ubuntu 的 Linux 镜像。它本质是 SQL Server for Linux 的官方打包版所有功能T-SQL 兼容性、Always On 可用性组基础、PolyBase 外部数据源均与 Windows 版本一致唯一区别是身份验证仅支持 SQL Server 身份验证sa 登录和 Active Directory 通过 LDAP 集成需额外配置不支持 Windows Integrated Authentication。提示SQL Server 2017 是首个支持 Linux 的正式版但 2019 是长期支持版LTSC2022 是当前功能最全的版本。生产环境建议锁定具体 CUCumulative Update版本例如2019-CU25-ubuntu-20.04避免latest标签带来的不可控升级风险。2.2 数据持久化为什么不能只靠-v /host/path:/var/opt/mssql如何设计三层挂载结构这是新手最容易踩坑的地方。很多人照着文档写docker run -e ACCEPT_EULAY -e SA_PASSWORDMyPass123 \ -p 1433:1433 -v /my/data:/var/opt/mssql \ -d mcr.microsoft.com/mssql/server:2019-latest表面看没问题但一旦容器重建你会发现数据库“还在”可某些系统库如msdb里的作业、警报、操作员信息全丢了——因为/var/opt/mssql目录下并非所有内容都该被持久化。SQL Server for Linux 的数据目录结构如下/var/opt/mssql/ ├── data/ # 用户数据库文件.mdf/.ldf必须持久化 ├── log/ # 错误日志、SQL Server 日志建议持久化便于排查 ├── secrets/ # 加密密钥TDE 密钥、Service Master Key必须持久化否则数据库无法解密 ├── backup/ # 备份文件目录按需挂载 └── master/ # master、model、msdb 系统数据库文件 —— 关键这里不能简单挂载整个目录问题出在master/子目录它包含master.mdf、mastlog.ldf、msdb.mdf、msdblog.ldf等文件。其中master和model是只读模板库不应被外部修改而msdb存储作业、警报等元数据其文件结构在 SQL Server 启动时由服务进程校验并可能重建。若你将整个/var/opt/mssql挂载为宿主机目录SQL Server 启动时会尝试读取挂载进来的旧msdb.mdf但该文件可能来自不同 CU 版本导致服务启动失败错误日志提示 “Could not upgrade msdb database”。正确做法是分层挂载核心数据层挂载/var/opt/mssql/data→ 宿主机独立目录如/opt/sqlserver/data确保.mdf/.ldf安全密钥层挂载/var/opt/mssql/secrets→ 宿主机独立目录如/opt/sqlserver/secrets保障 TDE 等加密功能可用日志层挂载/var/opt/mssql/log→ 宿主机独立目录如/opt/sqlserver/log方便收集错误日志系统库层不挂载/var/opt/mssql/master让容器内 SQL Server 每次启动时自动生成干净的master和model再通过初始化脚本恢复msdb元数据。这样设计后即使容器被docker rm -f强制删除只要/data和/secrets目录保留重建容器后数据库数据和加密密钥就 100% 完整而msdb中的作业等可通过初始化 SQL 脚本自动重建实现真正的“基础设施即代码”。2.3 初始化流程为什么不能靠SA_PASSWORD一步到位如何安全注入建库脚本SA_PASSWORD环境变量只解决 sa 账户密码设置但一个可用的开发/测试数据库远不止于此你需要创建业务数据库、建表、插入测试数据、配置用户权限、甚至预设 SQL Agent 作业。这些操作不能在容器启动后手动连上去执行——那违背了自动化初衷。SQL Server 容器镜像内置了初始化机制当容器首次启动时若检测到/var/opt/mssql/data/下无任何.mdf文件即数据库为空它会自动执行/var/opt/mssql/setup-scripts/目录下的所有.sql文件按文件名 ASCII 顺序。这就是我们的“钩子”。但直接把建库 SQL 放进镜像有两大缺陷① 镜像体积膨胀且每次改 SQL 都要重新 build② 密码等敏感信息硬编码在 SQL 脚本里存在泄露风险。因此我们采用运行时挂载 环境变量替换的组合方案创建一个init-scripts/本地目录放入01-create-db.sql、02-create-user.sql等脚本在脚本中使用占位符如CREATE DATABASE $(DB_NAME);、CREATE LOGIN $(APP_USER) WITH PASSWORD $(APP_PASS);启动容器时通过--env-file .env加载环境变量并在docker run命令中用sed或envsubst动态替换占位符再挂载到容器内。我更推荐用docker-composeentrypoint.sh封装这一逻辑。下面会详细展开。3. 实操全过程从零搭建可复用、可审计、可扩展的 SQL Server 容器环境3.1 环境准备确认 Docker 版本、系统资源、内核参数在动手前请务必验证以下三项否则后续 90% 的启动失败都源于此第一Docker 版本必须 ≥ 20.10SQL Server 容器依赖较新的overlay2存储驱动和seccomp安全配置。低于 20.10 的版本如 CentOS 7 自带的 1.13可能因seccomp规则缺失导致 SQL Server 进程被 kernel 杀死。验证命令docker --version # 正确输出示例Docker version 24.0.7, build afdd53b若版本过低请卸载旧版并按官方指南安装新版Ubuntu/Debian 用aptCentOS/RHEL 用dnf。第二系统资源必须满足最低要求SQL Server for Linux 官方要求CPU至少 2 核推荐 4 核内存最低 2GB但强烈建议 4GB 起步磁盘/var/lib/docker所在分区剩余空间 ≥ 10GB镜像日志备份特别注意内存若宿主机内存 3.5GB容器启动时可能因Out of memory: Kill process被 OOM Killer 终止。可通过以下命令检查free -h # 确保 available 列 ≥ 4G cat /proc/sys/vm/overcommit_memory # 必须为 1允许 overcommitSQL Server 启动时会申请大量虚拟内存若overcommit_memory为 0执行echo 1 | sudo tee /proc/sys/vm/overcommit_memory # 永久生效echo vm.overcommit_memory1 | sudo tee -a /etc/sysctl.conf第三SELinux 或 AppArmor 配置在启用了 SELinux 的系统如 RHEL/CentOS上挂载目录需添加:z或:Z标签否则 SQL Server 无法写入数据目录# 正确共享标签 -v /opt/sqlserver/data:/var/opt/mssql/data:z # 错误无标签权限拒绝 -v /opt/sqlserver/data:/var/opt/mssql/dataAppArmorUbuntu同理需确保 profile 允许容器访问挂载路径。3.2 目录结构规划建立可版本控制的项目骨架我们不把所有东西堆在根目录而是构建一个清晰、可 Git 管理的结构sqlserver-docker/ ├── docker-compose.yml # 主编排文件定义服务、网络、卷 ├── .env # 环境变量文件SA 密码、业务库名等 ├── init-scripts/ # 初始化 SQL 脚本目录 │ ├── 01-create-database.sql │ ├── 02-create-users.sql │ └── 03-insert-sample-data.sql ├── entrypoint.sh # 自定义入口脚本处理变量替换与初始化 ├── dockerfile.custom # 可选定制镜像如集成特定 ODBC 驱动 └── README.md创建该结构mkdir -p sqlserver-docker/{init-scripts,logs} cd sqlserver-docker touch docker-compose.yml .env init-scripts/{01,02,03}-*.sql entrypoint.sh chmod x entrypoint.sh.env文件内容示例请勿提交到 Git# SQL Server 核心配置 MSSQL_SA_PASSWORDStrongPssw0rd2024! MSSQL_PIDDeveloper # 业务数据库配置 APP_DB_NAMEecommerce_db APP_DB_USERapp_user APP_DB_PASSAppUs3rPss2024! # 挂载路径绝对路径 HOST_DATA_DIR/opt/sqlserver/data HOST_SECRETS_DIR/opt/sqlserver/secrets HOST_LOG_DIR/opt/sqlserver/log注意MSSQL_PIDDeveloper表示使用开发者免费版功能完整仅限开发测试。生产环境请替换为Standard或Enterprise并提供有效产品密钥。3.3 编写核心初始化脚本安全、幂等、可调试进入init-scripts/目录编写三个关键脚本。所有脚本必须以GO结尾确保批处理正确分隔。01-create-database.sql作用创建业务数据库并设置兼容级别与查询存储便于后续性能分析-- 创建数据库若不存在 IF NOT EXISTS (SELECT name FROM sys.databases WHERE name N$(APP_DB_NAME)) BEGIN CREATE DATABASE [$(APP_DB_NAME)] ON PRIMARY ( NAME N$(APP_DB_NAME)_data, FILENAME N/var/opt/mssql/data/$(APP_DB_NAME).mdf, SIZE 10MB, FILEGROWTH 5MB ) LOG ON ( NAME N$(APP_DB_NAME)_log, FILENAME N/var/opt/mssql/log/$(APP_DB_NAME)_log.ldf, SIZE 5MB, FILEGROWTH 2MB ); END GO -- 设置兼容级别为 150SQL Server 2019 ALTER DATABASE [$(APP_DB_NAME)] SET COMPATIBILITY_LEVEL 150; GO -- 启用查询存储自动捕获执行计划 ALTER DATABASE [$(APP_DB_NAME)] SET QUERY_STORE ON; GO02-create-users.sql作用创建应用专用登录名与用户遵循最小权限原则-- 创建登录名服务器级 IF NOT EXISTS (SELECT name FROM sys.sql_logins WHERE name N$(APP_DB_USER)) BEGIN CREATE LOGIN [$(APP_DB_USER)] WITH PASSWORD $(APP_DB_PASS); END GO -- 在业务数据库中创建用户并映射 USE [$(APP_DB_NAME)]; GO IF NOT EXISTS (SELECT name FROM sys.database_principals WHERE name N$(APP_DB_USER)) BEGIN CREATE USER [$(APP_DB_USER)] FOR LOGIN [$(APP_DB_USER)]; -- 仅授予必要权限db_datareader, db_datawriter, 以及执行存储过程 ALTER ROLE db_datareader ADD MEMBER [$(APP_DB_USER)]; ALTER ROLE db_datawriter ADD MEMBER [$(APP_DB_USER)]; ALTER ROLE db_executor ADD MEMBER [$(APP_DB_USER)]; END GO03-insert-sample-data.sql作用插入基础测试数据避免应用启动时报“表不存在”错误USE [$(APP_DB_NAME)]; GO -- 创建商品表 IF NOT EXISTS (SELECT * FROM sysobjects WHERE nameproducts AND xtypeU) BEGIN CREATE TABLE products ( id INT IDENTITY(1,1) PRIMARY KEY, name NVARCHAR(100) NOT NULL, price DECIMAL(10,2) NOT NULL DEFAULT 0.00, created_at DATETIME2 DEFAULT GETDATE() ); END GO -- 插入 5 条测试数据幂等先清空再插 DELETE FROM products; INSERT INTO products (name, price) VALUES (Wireless Headphones, 89.99), (Smart Watch, 199.99), (Bluetooth Speaker, 59.99), (USB-C Cable Pack, 24.99), (Phone Stand, 12.99); GO实操心得所有IF NOT EXISTS判断必须写全因为初始化脚本在容器重启时可能被重复执行。GO是批处理分隔符缺一不可USE [dbname]后必须跟GO否则后续语句可能在master上执行。3.4 编写 entrypoint.sh实现环境变量注入与智能初始化entrypoint.sh是容器启动时第一个运行的脚本它接管了原镜像的默认entrypoint.sh负责将.env中的变量注入到 SQL 脚本中检查数据目录是否为空决定是否执行初始化启动 SQL Server 服务。内容如下保存为entrypoint.sh确保可执行#!/bin/bash set -e # 定义路径 SQL_DATA_DIR/var/opt/mssql/data INIT_SCRIPTS_DIR/var/opt/mssql/setup-scripts HOST_INIT_DIR/init-scripts # 如果是首次启动数据目录为空则执行初始化 if [ ! -f $SQL_DATA_DIR/master.mdf ]; then echo 首次启动执行数据库初始化... # 创建 setup-scripts 目录 mkdir -p $INIT_SCRIPTS_DIR # 将宿主机的 init-scripts 挂载到容器内并替换变量 if [ -d $HOST_INIT_DIR ]; then # 使用 envsubst 替换 SQL 脚本中的 $(VAR) 占位符 # 注意envsubst 会读取所有环境变量所以 .env 文件必须已加载 for sql_file in $HOST_INIT_DIR/*.sql; do if [ -f $sql_file ]; then filename$(basename $sql_file) echo 处理初始化脚本: $filename # 替换并复制到 setup-scripts 目录 envsubst $sql_file $INIT_SCRIPTS_DIR/$filename fi done else echo 警告未挂载 init-scripts 目录跳过初始化 fi else echo 检测到已有数据库跳过初始化 fi # 执行原镜像的默认 entrypoint启动 SQL Server # 原镜像的 entrypoint 是 /opt/mssql/bin/sqlservr.sh exec /opt/mssql/bin/sqlservr.sh $关键点解析set -e任一命令失败则立即退出避免错误静默if [ ! -f $SQL_DATA_DIR/master.mdf ]精准判断是否为首次启动比检查目录是否为空更可靠envsubstGNU gettext 工具用于安全替换$()和${}形式的环境变量无需担心 SQL 注入因为变量值在容器外已确定exec /opt/mssql/bin/sqlservr.sh $exec替换当前 shell 进程确保 SQL Server 成为 PID 1能正确接收SIGTERM信号实现优雅关闭。3.5 编写 docker-compose.yml声明式定义一切这是整个方案的“宪法”所有配置在此集中管理version: 3.8 services: sqlserver: image: mcr.microsoft.com/mssql/server:2019-CU25-ubuntu-20.04 container_name: sqlserver-dev restart: unless-stopped environment: - ACCEPT_EULAY - MSSQL_SA_PASSWORD${MSSQL_SA_PASSWORD} - MSSQL_PID${MSSQL_PID} - MSSQL_AGENT_ENABLEDtrue # 启用 SQL Agent需额外初始化 ports: - 1433:1433 volumes: - ${HOST_DATA_DIR}:/var/opt/mssql/data:z - ${HOST_SECRETS_DIR}:/var/opt/mssql/secrets:z - ${HOST_LOG_DIR}:/var/opt/mssql/log:z - ./init-scripts:/init-scripts:ro - ./entrypoint.sh:/entrypoint.sh:ro entrypoint: [/entrypoint.sh] command: [--accept-eula, --no-sa-password] healthcheck: test: [CMD, sqlcmd, -U, sa, -P, ${MSSQL_SA_PASSWORD}, -Q, SELECT 1] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - sqlnet networks: sqlnet: driver: bridge ipam: config: - subnet: 172.20.0.0/16逐项说明image: 锁定具体 CU 版本避免latest带来的不确定性volumes: 四个挂载点全部明确指定secrets和data使用:z标签适配 SELinuxentrypointcommand: 指向我们自定义的entrypoint.sh并传递必要参数healthcheck: 使用sqlcmd工具进行健康检查确保服务真正就绪而不仅是进程存活。start_period: 40s是关键——SQL Server 启动需要时间初始化系统库太短会导致健康检查失败进而触发重启循环networks: 自定义桥接网络sqlnet便于后续其他服务如应用容器通过服务名sqlserver访问无需暴露端口到宿主机。3.6 一键启动与验证从执行到连通的完整链路准备工作就绪执行启动# 进入项目目录 cd sqlserver-docker # 启动后台运行 docker-compose up -d # 查看日志确认初始化过程 docker-compose logs -f sqlserver # 你会看到类似 # Processing initialization script: 01-create-database.sql # Processing initialization script: 02-create-users.sql # ... SQL Server is now ready for client connections # 检查健康状态 docker-compose ps # 输出中 STATUS 列应显示 healthy # 本地连接测试需安装 sqlcmd sqlcmd -S localhost -U sa -P StrongPssw0rd2024! -Q SELECT VERSION # 返回 SQL Server 2019 版本信息表示成功连接业务数据库验证sqlcmd -S localhost -U app_user -P AppUs3rPss2024! -d ecommerce_db -Q SELECT COUNT(*) FROM products # 返回 5证明初始化数据已就绪至此一个完整的、可复用的 SQL Server 容器环境已就绪。所有配置、脚本、环境变量均分离可直接提交到 Git 仓库团队成员git clone docker-compose up -d即可获得完全一致的环境。4. 常见问题与实战排错那些文档里不会写的“血泪教训”4.1 启动失败容器反复重启日志显示 “ERROR: Unable to set system time”这是最典型的内核参数问题。SQL Server 容器启动时会尝试调用clock_settime()系统调用设置系统时间用于日志时间戳精确性但在某些云主机或容器运行时中该调用被默认禁止。现象docker-compose logs sqlserver显示ERROR: Unable to set system time ERROR: Failed to initialize server根本原因容器默认安全配置禁用了CAP_SYS_TIME能力。解决方案在docker-compose.yml的sqlserver服务下添加cap_addcap_add: - SYS_TIME注意SYS_TIME是特权能力仅在可信环境中启用。生产环境若不允许可忽略此错误——它不影响数据库核心功能只是日志时间戳可能略滞后于宿主机时间。4.2 连接被拒telnet localhost 1433 通但 sqlcmd 报 “Login failed for user sa”这几乎 100% 是密码强度问题。SQL Server 2017 强制要求SA_PASSWORD必须满足 Windows 密码策略至少 8 位含大小写字母、数字、特殊字符。典型错误密码password123无大写/特殊字符、12345678无字母、mypassword无数字/特殊字符验证方法在启动命令中临时加-e MSSQL_SA_PASSWORDMyPass123确保包含、!、#等符号且长度 ≥ 8。进阶技巧若你坚持用弱密码仅限本地学习可在docker-compose.yml中添加environment: - MSSQL_SA_PASSWORDMyPass123 - MSSQL_RANDOMIZE_SYSTEM_DATABASES1 # 强制随机化系统库绕过部分检查但强烈不推荐这会降低环境与生产的一致性。4.3 初始化脚本不执行容器启动快但数据库没创建日志无初始化记录常见原因有三个按优先级排查排查项检查命令修复方法挂载路径错误docker inspect sqlserver-dev | jq .[0].Mounts确认./init-scripts正确挂载到/init-scripts且权限为ro只读脚本文件名不匹配docker exec sqlserver-dev ls -l /init-scripts/确保文件名以.sql结尾且无空格或中文如01-创建库.sql会失败首次启动判断失效docker exec sqlserver-dev ls -l /var/opt/mssql/data/若该目录下已有master.mdf则初始化被跳过。此时可docker-compose down -v清除卷后重试实操心得我曾因在 macOS 上用 Finder 新建.sql文件文件名末尾多了不可见的 Unicode 字符导致envsubst读取失败脚本未被复制到/var/opt/mssql/setup-scripts/。用ls -la查看文件名十六进制编码可快速定位。4.4 性能异常查询明显变慢sys.dm_exec_requests显示大量SOS_SCHEDULER_YIELD这不是容器问题而是资源限制导致。SQL Server 默认会尝试使用所有可用 CPU但在容器中若未设置cpus限制它可能过度争抢。现象docker stats显示 CPU 使用率 100%但业务查询响应时间飙升。诊断连接 SQL Server执行SELECT scheduler_id, current_tasks_count, runnable_tasks_count, work_queue_count FROM sys.dm_os_schedulers WHERE status VISIBLE ONLINE;若runnable_tasks_count长期 10说明任务队列积压。解决方案在docker-compose.yml中显式限制 CPUdeploy: resources: limits: cpus: 2.0 memory: 4G或使用--cpus2.0参数启动。SQL Server 会自动识别 cgroup 限制并调整内部线程池大小。4.5 数据丢失docker-compose down后重建发现数据库没了这是对 Docker 卷理解的致命误区。docker-compose down默认不删除命名卷named volumes但如果你用的是绑定挂载bind mounts且路径写错就可能挂载到了空目录。自查命令# 查看容器挂载详情 docker inspect sqlserver-dev | jq .[0].Mounts # 正确输出应包含 # { Type: bind, Source: /opt/sqlserver/data, Destination: /var/opt/mssql/data, ... } # 错误输出可能是 # { Type: bind, Source: ./data, Destination: /var/opt/mssql/data, ... } # 注意./data 是相对路径若在不同目录执行 up会挂载到不同位置铁律绑定挂载必须使用绝对路径并在.env中统一定义HOST_DATA_DIR杜绝相对路径。5. 进阶实践从单机开发到多环境协同的平滑演进5.1 如何为不同环境dev/staging/prod管理配置绝不要为每个环境维护一套docker-compose.yml。正确做法是主配置docker-compose.yml定义服务结构、镜像、端口、健康检查等不变量环境专属配置docker-compose.dev.yml、docker-compose.prod.yml覆盖变量、资源限制、挂载路径等变量使用docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d合并加载。例如docker-compose.prod.ymlversion: 3.8 services: sqlserver: environment: - MSSQL_PIDStandard - MSSQL_SA_PASSWORD${PROD_SA_PASSWORD} deploy: resources: limits: cpus: 4.0 memory: 8G volumes: - /prod/sqlserver/data:/var/opt/mssql/data:z - /prod/sqlserver/secrets:/var/opt/mssql/secrets:z这样同一套初始化脚本、同一套entrypoint.sh通过不同覆盖文件即可适配全环境。5.2 如何实现数据库迁移Migration而非一次性初始化初始化脚本适合“从零开始”但生产环境需要增量变更。推荐集成Flyway或Liquibase在应用容器中运行 Flyway CLI连接sqlserver服务Flyway 的flyway.conf指定 JDBC URLjdbc:sqlserver://sqlserver:1433;databaseNameecommerce_db;所有 SQL 迁移脚本V1__create_table.sql, V2__add_index.sql放在应用项目的src/main/resources/db/migration下CI 流水线在部署前自动执行flyway migrate。这样数据库 schema 变更就和代码变更一样走 Git 提交、Code Review、自动化测试全流程。5.3 如何备份与恢复能否用sqlcmd自动化可以。在宿主机上写一个备份脚本backup.sh#!/bin/bash DATE$(date %Y%m%d_%H%M%S) BACKUP_DIR/backup/sqlserver mkdir -p $BACKUP_DIR # 连接容器执行备份 docker exec sqlserver-dev /opt/mssql-tools/bin/sqlcmd \ -S localhost -U sa -P StrongPssw0rd2024! \ -Q BACKUP DATABASE [ecommerce_db] TO DISK N/var/opt/mssql/backup/ecommerce_db_$DATE.bak WITH INIT, COMPRESSION # 将备份文件拷贝到宿主机 docker cp sqlserver-dev:/var/opt/mssql/backup/ecommerce_db_$DATE.bak $BACKUP_DIR/ echo Backup saved to $BACKUP_DIR/ecommerce_db_$DATE.bak恢复同理用RESTORE DATABASE命令。关键是把/var/opt/mssql/backup也加入volumes挂载确保备份文件持久化。5.4 安全加固如何禁用 sa 账户启用更严格的认证生产环境绝不应使用sa。步骤如下启动时仍用sa执行初始化必需初始化脚本末尾添加-- 禁用 sa 账户 ALTER LOGIN sa DISABLE; GO -- 创建强密码的管理员账户 IF NOT EXISTS (SELECT name FROM sys.sql_logins WHERE name Ndba_admin) BEGIN CREATE LOGIN [dba_admin] WITH PASSWORD Str0ngDbaPss2024!; ALTER SERVER ROLE sysadmin ADD MEMBER [dba_admin]; END GO后续

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑