# 使用 Docker 執行 SQL Server on Linux 容器之常用工具與命令

最近因為正在進行【ASP․NET Core 3 開發實戰：從入門到進階】課程，上課的學員中使用 macOS 來學習 .NET Core 的人越來越多，當練習到 ASP․NET Core 搭配 Entity Framework Core 的時候，因為會用到 SQL Server 進行練習，所以本篇文章將分享如何利用 Docker 執行 [SQL Server on Linux](https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-overview?view=sql-server-ver15) 容器，並分享幾個常用的工具命令與使用範例。

### 下載 SQL Server 2019 容器映像 (docker pull)

> 從 SQL Server 2019 CU3 開始，已經支援 Ubuntu 18.04 版本。  
> 從 SQL Server 2019 CU10 開始，已經支援 Ubuntu 20.04 版本。

你可以透過以下命令下載容器映像：

```bash
sudo docker pull mcr.microsoft.com/mssql/server:2019-latest
```

目前從 [Microsoft SQL Server - Docker Hub](https://hub.docker.com/_/microsoft-mssql-server) 可以查到的 image tag 比較舊，反而從 [Quickstart: Run SQL Server container images with Docker](https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-ver15&pivots=cs1-bash) 官方文件可以查到最新版本。

> 如果想下載 RHEL-based 容器映像，可以查閱[這份文件](https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-configure-docker?view=sql-server-ver15#rhel)說明。
> 
> ```bash
> sudo docker pull mcr.microsoft.com/mssql/rhel/server:2019-CU1-rhel-8
> ```

### 執行 SQL Server 2019 容器 (docker run)

以下是 `docker run` 使用範例：

```bash
sudo docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Ver7CompleXPW" \
  -p 1433:1433 --name sql1 \
  -d mcr.microsoft.com/mssql/server:2019-latest
```

設定 `SA_PASSWORD` 的時候必須符合[密碼複雜性](https://learn.microsoft.com/zh-tw/sql/relational-databases/security/password-policy?view=sql-server-ver15)要求：

-   密碼不包含使用者的帳戶名稱，也就是不能包含 `sa` 這個字。
-   密碼長度至少為 8 個字元，密碼長度最多可達 128 個字元。
-   密碼包含下列四種類別的其中三種：
    -   拉丁文大寫字母 (A 到 Z)
    -   拉丁文小寫字母 (a 到 z)
    -   以 10 為基底的數字 (0 到 9)
    -   非英數字元，例如：驚嘆號 (!)、錢幣符號 ($)、數字符號 (#) 或百分比符號 (%)

執行容器實際範例

```bash
sudo docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Ver7CompleXPW" -p 1433:1433 --name sql1 -d mcr.microsoft.com/mssql/server:2019-latest
```

### 進入容器執行

-   進入容器 bash 環境
    
    ```bash
    sudo docker exec -it sql1 "bash"
    ```
    
    > 容器中 `sqlcmd` 工具的路徑為 `/opt/mssql-tools/bin/sqlcmd`
    
-   變更 SA 帳號密碼
    
    由於預設的 SA 帳戶密碼是透過環境變數 `SA_PASSWORD` 傳入的，你只要進入 `bash` 執行 `ps -eax | cat` 或 `set` 就可以看到密碼。基於安全理由，你可以透過以下命令變更 SA 密碼：
    
    ```bash
    sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd \
      -S localhost -U SA -P "Ver7CompleXPW" \
      -Q 'ALTER LOGIN SA WITH PASSWORD="YourNewStrong@Passw0rd"'
    ```
    
-   進入 `sqlcmd` 互動模式
    
    ```bash
    sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd -U SA -P Ver7CompleXPW -W
    ```
    
    > 上述命令的 `-W` (大寫 W 字母) 選項會從資料行中移除尾端的空格，否則通常執行結果很難閱讀。
    
    在 [SQLCMD](https://learn.microsoft.com/zh-tw/sql/tools/sqlcmd-utility?view=sql-server-ver15) 中執行 T-SQL 最後要輸入 `GO` 命令才會執行。
    
    例如你想查詢當前執行的 SQL Server 版本，就要輸入以下命令：
    
    ```sql
    SELECT @@VERSION
    GO
    ```
    
    如果要退出 `sqlcmd` 互動模式，請輸入以下命令：
    
    ```sql
    QUIT
    ```
    
-   直接從本機連接 SQL Server 容器
    
    由於我們執行 SQL Server 容器時，已經加上 `-p 1433:1433` 參數，因此你可以從本機的 `localhost:1433` 連接容器中的 SQL Server 服務。
    
    如果你的本機已經有安裝 SQL Server 任意版本，通常會包含 `sqlcmd` 用戶端工具，當你使用 `-S` 參數指定**伺服器名稱**時，要加上 Port 埠號必須用 `localhost,1433` 這種格式，主機名稱與埠號之間是用「逗號」分隔喔！
    
    ```bash
    sqlcmd -S localhost,1433 -U SA -P "Ver7CompleXPW" -W
    ```
    

### 常見 T-SQL 查詢

-   列出資料庫清單
    
    ```bash
    sudo docker exec sql1 /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Ver7CompleXPW" -W -Q "SELECT name FROM sys.databases"
    ```
    
-   批次執行 T-SQL 命令 (例如：匯入資料庫)
    
    ```bash
    # 下載 ContosoUniversity.sql 檔案
    curl -o ContosoUniversity.sql https://gist.githubusercontent.com/doggy8088/2a2f7075d49b3814d19513426ede3549/raw/ab95b323425ff98e99b901793d0361d90439fb0b/ContosoUniversity.sql
    # 複製檔案進 sql1 容器
    sudo docker cp ContosoUniversity.sql sql1:/
    # 批次執行指定的 T-SQL 檔案
    sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Ver7CompleXPW" -i ContosoUniversity.sql
    ```
    
-   建立資料庫
    
    假設資料庫名稱為 `test1`，你可以用以下命令建立一個空資料庫：
    
    ```bash
    sudo docker exec sql1 /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Ver7CompleXPW" -W -Q "CREATE DATABASE [test1]"
    ```
    
-   啟動容器並還原資料庫
    
    以下命令可以在 WSL 2 環境執行：
    
    ```bash
    # 準備還原指令碼
    cat <<EOF > restore.sql
    -- 請記得先修改備份檔實體路徑
    USE [master]
    RESTORE DATABASE [mydb] FROM  DISK = N'/var/opt/mssql/backup/mydb.bak' WITH  FILE = 1,
    MOVE N'mydb'     TO N'/var/opt/mssql/data/mydb_Primary.mdf',
    MOVE N'mydb_log' TO N'/var/opt/mssql/data/mydb_Primary.ldf',  NOUNLOAD,  STATS = 5
    GO
    -- 清空交易記錄 (開發環境不需要)
    ALTER DATABASE [mydb] SET RECOVERY SIMPLE WITH NO_WAIT
    GO
    -- 壓縮資料庫
    DBCC SHRINKDATABASE(N'mydb')
    GO
    EOF
    ```
    
    ```bash
    # 啟動容器並將 /mnt/c/TEMP/DB 掛載到容器的 /var/opt/mssql/backup 目錄下
    sudo docker run --name sql1 -p 1433:1433 \
        -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Ver7CompleXPW' \
        -v '/mnt/c/TEMP/DB:/var/opt/mssql/backup' \
        -d mcr.microsoft.com/mssql/server:2019-latest
    
    # 查看容器啟動紀錄 (確保服務已正常啟動)
    sudo docker logs sql1 -f
    
    # 還原資料庫 (其中包含截斷交易記錄與壓縮資料庫)
    sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Ver7CompleXPW' -i '/var/opt/mssql/backup/restore.sql' -e
    
    # 查看資料檔大小
    sudo docker exec -it sql1 bash -c 'ls -l /var/opt/mssql/data/mydb*'
    ```
    
-   備份資料庫
    
    以下命令可以在 WSL 2 環境執行：
    
    ```bash
    # 準備備份指令碼
    cat <<EOF > backup.sql
    BACKUP DATABASE [mydb]
    TO  DISK = N'/var/opt/mssql/backup/mydb.bak' WITH COPY_ONLY, FORMAT, INIT,
    NAME = N'mydb-Full Database Backup', SKIP, NOREWIND, NOUNLOAD,
    COMPRESSION, STATS = 10
    GO
    EOF
    ```
    
    ```bash
    # 備份資料庫 (包含壓縮備份檔)
    sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Ver7CompleXPW' -i '/var/opt/mssql/backup/backup.sql' -e
    ```
    
-   刪除資料庫
    
    假設資料庫名稱為 `test1`，你可以用以下命令刪除資料庫：
    
    ```bash
    sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Ver7CompleXPW" -Q "DROP DATABASE [test1]"
    ```
    
    如果資料庫因為還有既有連線而無法刪除，可以改用以下命令：
    
    ```bash
    sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Ver7CompleXPW" -Q "ALTER DATABASE [test1] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [test1]"
    ```
    

### 相關連結

-   [Quickstart: Run SQL Server container images with Docker](https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-ver15&pivots=cs1-bash)
-   [Configure SQL Server container images on Docker](https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-configure-docker?view=sql-server-ver15)
-   [sqlcmd 公用程式](https://learn.microsoft.com/zh-tw/sql/tools/sqlcmd-utility?view=sql-server-ver15)
-   [連接字串語法](https://learn.microsoft.com/zh-tw/dotnet/framework/data/adonet/connection-string-syntax)
-   [SQL Server connection strings](https://www.connectionstrings.com/sql-server/)
-   [Restore a SQL Server database in a Linux Docker container](https://learn.microsoft.com/en-us/sql/linux/tutorial-restore-backup-in-sql-server-container?view=sql-server-ver15&WT.mc_id=DT-MVP-4015686)
