sql-server - Docker compose如何在Windows容器上初始化SQL Server DB?

标签 sql-server docker initialization docker-compose

我在 Windows 10 上运行适用于 Windows 18.03 的 docker。我在自己的 VS 2017 项目中使用来自 docker compose 文件microsoft/mssql-server-windows-express(来自 Windows Server)镜像。我在这里尝试完成的是从脚本初始化数据库。我尝试在 docker.compose.yml 中使用“命令”开关,但没有取得多大成功......

这是 docker compose 文件:

  myscustomservice:
    image: myscustomservice
    build:
      context: .\myscustomservice
      dockerfile: Dockerfile

  db:
    image: microsoft/mssql-server-windows-express
    volumes:
       - ".\\data:C:\\data"
    #command: --init-file C:\\data\\CreateLocalDB.sql
    #command: "sqlcmd -U sa -P sUper45!pas5word -i C:\\data\\CreateLocalDB.sql"
    restart: always
    ports: 
      - "1533:1433"
    environment:
      - "sa_password=sUper45!pas5word"
      - "ACCEPT_EULA=Y"

volumes:
  db-data: 

请注意,我已经尝试了注释的 2 个命令行。第一个失败,表示找不到文件,第二个只是用该命令行替换正常的命令行,因此容器不会启动(或不会保持运行)。

在我的本地驱动器上,我有一个 C:\myscustomservice\data 驱动器,其中包含文件 CreateLocalDB.sql。它安装在容器的 C:\data 文件夹中(当我在容器内运行 powershell 时看到它)。

sql 文件如下所示:

USE MASTER

CREATE DATABASE [customDB_test]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'customDB_test', FILENAME = N'C:\data\customDB_test.mdf' , SIZE = 1594752KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
 LOG ON 
( NAME = N'customDB_test_log', FILENAME = N'C:\data\customDB_test.ldf' , SIZE = 3584KB , MAXSIZE = 2048GB , FILEGROWTH = 10240KB )
GO  

有人知道我该怎么做吗?网上的所有示例均来自 Linux 容器,此镜像来自 Windows Server 容器。

最佳答案

好的,正如你所知,我最终不得不创建另一个依赖于“db”的服务来调用检查数据库是否存在的 powershell 脚本。如果它不存在,我会调用 mssql 脚本来创建它。

这是 dockerfile:

FROM microsoft/wcf:4.7.1
ARG source
# Creates a directory for custom application
RUN mkdir C:\MyCustomService

COPY . c:\\MyCustomService

# Remove existing default web site
RUN powershell -NoProfile -Command \
Import-module WebAdministration; \
Remove-WebSite -Name "'Default Web Site'"

# Configure the new site in IIS. Binds it to port 80 otherwise it won't work because it needs a default app listening on this port
RUN powershell -NoProfile -Command \
Import-module IISAdministration; \
New-IISSite -Name "MyCustomService" -PhysicalPath C:\MyCustomService -BindingInformation "*:80:";


# Add net.tcp support on the new site and change it to web aplication.
RUN Import-Module WebAdministration; Set-ItemProperty "IIS:\\Sites\\MyCustomService" -name bindings -value (@{protocol='net.tcp';bindingInformation='808:*'},@{protocol='http';bindingInformation='*:80:'});
RUN windows\system32\inetsrv\appcmd.exe set app 'MyCustomService/' /enabledProtocols:"http,net.tcp"
# This instruction tells the container to listen on port 83.
EXPOSE 80
EXPOSE 808

这是新的 docker-compose 文件:

myscustomservice:
  image: myscustomservice
  build:
    context: .\myscustomservice
    dockerfile: Dockerfile
  ports: 
  - "83:80"
  - "1010:808"
  depends_on: 
    - db
    - db-init

  db:
    image: microsoft/mssql-server-windows-express
    volumes:
     - ".\\data:C:\\data"

    ports: 
      - "1533:1433"
    environment:
      - "sa_password=sUper45!pas5word"
      - "ACCEPT_EULA=Y"
      - 'attach_dbs=[{"dbName":"customDB_test","dbFiles":["C:\\data\\customDB_test.mdf","C:\\data\\customDB_test.ldf"]}]'
  volumes:
    db-data: 


db-init:
  image: microsoft/mssql-server-windows-express
  volumes:
     - ".\\data:C:\\data"

  command: powershell -executionpolicy bypass "C:\\data\\initialize_db.ps1 -insertTestData"

  environment:
    - "sa_password=sUper45!pas5word"
    - "ACCEPT_EULA=Y"


  depends_on: 
    - db

注意数据库服务中的“attach_dbs”环境变量。这样,它会尝试绑定(bind)到现有文件,因此 db_init 服务运行的脚本将找到数据库并且不会重新创建它。

powershell 脚本“initialize_db.ps1”:

param([switch]$insertTestData)

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null

$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") "db\SQLEXPRESS"
$database = "customDB_test"
$dbs = $server.Databases
$exists = $false

#This sets the connection to mixed-mode authentication 
$server.ConnectionContext.LoginSecure=$false; 

#This sets the login name 
$server.ConnectionContext.set_Login("sa"); 

#This sets the password 
$server.ConnectionContext.set_Password("sUper45!pas5word")

try 
{
    foreach ($db in $dbs) 
    {
        Write-Host $db.Name
        if($db.Name -eq $database) 
        {
            Write-Host "Database already exist"
            $exists = $true
        }
    }

}
catch 
{
    Write-Error "Failed to connect to $server"
}


if(-not $exists)
{
    Write-Host "Database doesn't exist"
    $StopWatch = [System.Diagnostics.Stopwatch]::StartNew()

    sqlcmd -S 'db' -U sa -P 'sUper45!pas5word' -i 'C:\\data\\CreateLocalDB_schema.sql'
    Write-Host "Database created"
    $StopWatch.Elapsed

    if($insertTestData)
    {
        Write-Host "Begining data insertion..." 
        sqlcmd -S 'db' -U sa -P 'sUper45!pas5word' -i 'C:\\data\\CreateLocalDB_data.sql'
        Write-Host "Data inserted"
        $StopWatch.Elapsed
    }

    $StopWatch.Stop()
}

sqlcmd -S 'db' -U sa -P 'sUper45!pas5word' -i 'C:\\data\\CreateLocalDB_user.sql'

该脚本运行至少 1 个且最多 3 个 SQL 脚本:

  • CreateLocalDB_user.sql - 重新创建自定义登录名和数据库用户,以便您可以与此用户连接
  • CreateLocalDB_schema.sql - 如果数据库不存在,则自行创建
  • CreateLocalDB_data.sql - 如果您在调用中指定了“insertTestData”开关,则添加启动数据(在 docker compose 中的 db_init 服务下)

该服务的 dockerfile 为 http 公开了端口 80,为 net.tcp 公开了端口 808,而我的“myscustomservice”的 web.config 文件公开了 wcf 服务,如下所示:

      <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:1010/myscustomservice/Customer.svc"/>
          </baseAddresses>
        </host>

关于sql-server - Docker compose如何在Windows容器上初始化SQL Server DB?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49905797/

相关文章:

sql - 检查 SQL 中字符串是否包含重音字符?

docker - Visual Studio 2022 Docker 调试 - "no symbols have been loaded"

java - Java中的直接缓冲区是否像数组一样初始化为默认值?

java - 为什么可以使用增强的 for 循环更改字段变量但不能初始化对象?

java - 我应该保持 Java 中的实例变量始终初始化吗?

sql-server - SQL Server 中不等号 <> 和 != 之间有区别吗?

c# - 错误。处理您的请求时发生错误

c# - SQL父子查询不工作

docker - `docker-credential-gcloud` 不在系统路径中

docker - 为什么我在这个多阶段构建中的最终 docker 镜像如此之大?