1. 为什么要在Mac上通过Docker运行SQL Server作为常年使用Mac的开发者我最初也很困惑微软的SQL Server明明是为Windows设计的为什么要在macOS上折腾直到接手了一个使用SQL Server作为数据库的老项目才明白——当客户环境已经固定时本地开发环境必须与之匹配。传统方案要么用虚拟机装Windows要么购买Mac版Parallels Desktop直到发现Docker这个救星。Docker容器化方案有三大不可替代的优势资源占用极低相比启动整个Windows虚拟机容器只占用SQL Server运行所需的资源我的MacBook Pro内存从常年告急降到游刃有余环境隔离干净每个项目可以用不同版本的SQL Server互不干扰再也不用担心在我的机器上能运行的经典问题秒级启停测试时反复重启数据库是常态容器化的SQL Server启动速度比原生安装快3倍以上实测在M1芯片的MacBook Air上从拉取镜像到可用数据库全程不超过15分钟视网络情况。下面我就把踩过坑的完整流程分享给大家。2. 准备工作Docker环境配置2.1 安装Docker Desktop首先访问Docker官网下载Mac版安装包。注意芯片类型选择Intel芯片选Docker Desktop for MacApple SiliconM1/M2选Docker Desktop for Mac (Apple Silicon)安装完成后建议进行两个关键配置在Docker图标 Preferences Resources中将内存调到至少4GBSQL Server较吃内存在Advanced页面勾选Use gRPC FUSE for file sharing解决Mac文件权限问题注意首次启动会要求授予权限务必点击Allow否则容器无法联网2.2 配置国内镜像加速默认的Docker Hub在国内拉取镜像很慢建议修改为国内镜像源。打开终端执行# 创建或修改docker配置 mkdir -p ~/.docker cat ~/.docker/daemon.json EOF { registry-mirrors: [ https://docker.mirrors.ustc.edu.cn, https://hub-mirror.c.163.com ], experimental: false, debug: true } EOF然后重启Docker服务点击菜单栏鲸鱼图标 Restart。可以通过以下命令验证是否生效docker info | grep Mirrors -A 23. 拉取并运行SQL Server容器3.1 选择适合的镜像版本微软官方提供了多个SQL Server镜像推荐使用azure-sql-edge轻量版约500MB适合开发和测试mssql-server-linux完整功能版约1.5GB适合生产环境模拟这里以azure-sql-edge为例执行拉取命令docker pull mcr.microsoft.com/azure-sql-edge:latest实测技巧如果下载中断可以用docker pull --resume继续比重新下载快得多3.2 启动容器关键参数解析运行SQL Server需要特别注意密码策略这是最容易出错的地方。完整启动命令如下docker run -d \ --name sql_server \ -e ACCEPT_EULAY \ -e MSSQL_SA_PASSWORDMyComplexPssw0rd \ -e MSSQL_PIDDeveloper \ -p 1433:1433 \ mcr.microsoft.com/azure-sql-edge参数说明ACCEPT_EULAY必须设置为Y表示接受许可协议MSSQL_SA_PASSWORD密码必须包含大小写字母数字特殊字符中的至少三类MSSQL_PID指定为Developer可免费使用完整功能-p 1433:1433将容器内默认端口映射到主机常见错误处理密码太简单会报错Invalid password忘记ACCEPT_EULA会导致容器立即退出端口冲突时修改为-p 51433:1433等其它端口3.3 验证容器状态启动后执行以下命令检查# 查看运行中的容器 docker ps # 查看日志尤其出错时 docker logs sql_server # 进入容器内部调试用 docker exec -it sql_server bash当看到日志输出SQL Server is now ready for client connections表示成功。4. 连接与管理数据库4.1 使用命令行工具连接即使不安装GUI工具也能用官方sqlcmd工具操作# 先进入容器环境 docker exec -it sql_server bash # 在容器内使用sqlcmd /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P MyComplexPssw0rd成功连接后会显示1提示符可以执行SQL语句CREATE DATABASE TestDB; GO USE TestDB; GO CREATE TABLE Users (ID INT, Name NVARCHAR(50)); GO INSERT INTO Users VALUES (1, Mac用户); GO SELECT * FROM Users; GO4.2 图形化工具推荐我日常使用三款工具各有优势Azure Data Studio微软官方免费且功能完整支持智能提示和笔记本功能下载地址https://aka.ms/azuredatastudioDBeaver开源跨平台支持几乎所有数据库社区版完全免费连接配置Host: localhostPort: 1433Authentication: SQL ServerUsername: SAPassword: 你的密码TablePlusMac原生体验颜值高响应快支持SSH隧道连接适合需要频繁切换多个数据库的用户4.3 常见连接问题解决连接超时检查Docker是否运行验证端口映射是否正确尝试telnet localhost 1433测试端口认证失败密码是否包含特殊字符确认用户名是SA区分大小写可通过docker logs查看错误详情5. 数据持久化与备份5.1 挂载数据卷防止丢失默认情况下容器停止后数据会丢失。通过volume实现持久化# 创建专用数据卷 docker volume create sql_data # 启动时挂载 docker run -d \ --name sql_server \ -v sql_data:/var/opt/mssql \ -e ACCEPT_EULAY \ -e MSSQL_SA_PASSWORDMyComplexPssw0rd \ -p 1433:1433 \ mcr.microsoft.com/azure-sql-edge数据会保存在/var/lib/docker/volumes/sql_data目录下即使删除容器也不会丢失。5.2 备份与恢复实战通过容器内命令实现备份# 进入容器 docker exec -it sql_server bash # 执行备份在容器内 /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P MyComplexPssw0rd \ -Q BACKUP DATABASE TestDB TO DISK/var/opt/mssql/backup/TestDB.bak # 将备份文件复制到主机 docker cp sql_server:/var/opt/mssql/backup/TestDB.bak ~/Downloads/恢复数据库时反向操作# 先将备份文件放入容器 docker cp ~/Downloads/TestDB.bak sql_server:/var/opt/mssql/backup/ # 执行恢复 /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P MyComplexPssw0rd \ -Q RESTORE DATABASE TestDB FROM DISK/var/opt/mssql/backup/TestDB.bak WITH REPLACE6. 性能优化技巧6.1 内存限制调整SQL Server默认会尽可能占用内存在Docker中需要限制docker run -d \ --name sql_server \ --memory4g \ --memory-swap4g \ -e MSSQL_MEMORY_LIMIT_MB2048 \ -v sql_data:/var/opt/mssql \ -p 1433:1433 \ mcr.microsoft.com/azure-sql-edge--memory容器最大可用内存MSSQL_MEMORY_LIMIT_MBSQL Server实际可用内存建议为总内存的70%6.2 跨平台文件共享优化在Mac上Docker通过虚拟机运行Linux容器导致文件IO性能较差。解决方案对于数据库文件始终使用Docker Volume而非直接挂载主机目录导入大量数据时先用docker cp复制到容器内再操作在Docker设置中将项目目录添加到File Sharing白名单6.3 监控与调优工具内置工具查看性能-- 查看当前连接 SELECT * FROM sys.dm_exec_connections; -- 查询性能统计 SELECT * FROM sys.dm_exec_query_stats; -- 最耗CPU的查询 SELECT TOP 10 query_stats.query_hash, SUM(query_stats.total_worker_time) / SUM(query_stats.execution_count) as avg_cpu_time, MIN(query_text.text) as sample_query_text FROM sys.dm_exec_query_stats as query_stats CROSS APPLY sys.dm_exec_sql_text(query_stats.sql_handle) as query_text GROUP BY query_stats.query_hash ORDER BY avg_cpu_time DESC;