Introdução
Ao contrário do MySql e do Postgres, que executam scripts no diretório /docker-entrypoint-initdb.d/ após a inicialização, a imagem do container SQL Server não tem uma opção para executar scripts na inicialização.
Neste post, mostrarei como criar uma imagem de container personalizada que aguarda a inicialização do SQL Server e executa um script pré-configurado. Além disso, mostrarei como usar esta imagem personalizada para executar o SQL Server no Testcontainers.
sqlcmd de /opt/mssql-tools/bin para /opt/mssql-tools18/bin e ativou criptografia obrigatória por padrão. Os exemplos abaixo foram atualizados para usar o novo caminho e a flag -C para confiar no certificado do servidor. Se você estiver usando uma imagem anterior ao CU 14, use /opt/mssql-tools/bin/sqlcmd sem -C.Veja GitHub Issue #892 para detalhes.
Como executar scripts na inicialização do SQL Server
A documentação da imagem Docker do SQL Server aponta para este código como um exemplo de como executar scripts em sua inicialização, mas o script é antigo e não funciona.
Abri um Pull Request com uma versão corrigida. Ele nunca foi mesclado, mas as correções estão incorporadas na abordagem abaixo.
Abaixo, explicarei cada um dos arquivos.
1 - Dockerfile
O Dockerfile começa a partir da imagem do SQL Server 2022, copia todos os arquivos para /tmp/initscripts, e define o ponto de entrada do container para entrypoint.sh.
FROM mcr.microsoft.com/mssql/server:2022-latest
# Agrupa a origem da configuração
COPY . /tmp/initscripts
ENTRYPOINT ["/tmp/initscripts/entrypoint.sh"]
2 - entrypoint.sh
Este script bash inicia o configure-db.sh em segundo plano, então inicia o SQL Server em primeiro plano. Usar exec garante que o processo do SQL Server substitua o shell como PID 1, recebendo sinais de parada do Docker diretamente.
#!/bin/bash
# Inicia o script para criar o DB e o usuário
/tmp/initscripts/configure-db.sh &
# Inicia o SQL Server (exec substitui o shell pelo sqlservr como PID 1)
exec /opt/mssql/bin/sqlservr
3 - configure-db.sh
Esta é a parte mais importante. O script espera até 60 segundos (variável TRIES) pelo SQL Server iniciar e todos os bancos alcançarem o estado ONLINE, então executa setup.sql. Em caso de sucesso, loga Configuration completed.; em caso de timeout, sai com código 1.
Configuration completed é importante porque podemos usá-la para esperar que os scripts sejam concluídos antes de acessar o banco de dados. Usarei isso na próxima seção ao iniciar o container do Testcontainers.#!/bin/bash
# Chama o SQLCMD para verificar se os bancos de dados do sistema e do usuário retornam "0", o que significa que todos os bancos de dados estão em um estado "online",
# então execute o script de configuração (setup.sql)
# https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-databases-transact-sql?view=sql-server-2017
TRIES=60
DBSTATUS=1
ERRCODE=1
i=0
while [[ $DBSTATUS -ne 0 ]] && [[ $i -lt $TRIES ]]; do
i=$((i+1))
DBSTATUS=$(/opt/mssql-tools18/bin/sqlcmd -h -1 -t 2 -C -S localhost -U sa -P "$MSSQL_SA_PASSWORD" -Q "SET NOCOUNT ON; Select COALESCE(SUM(state), 0) from sys.databases") || DBSTATUS=1
sleep 1s
done
if [ $DBSTATUS -ne 0 ]; then
echo "SQL Server levou mais de $TRIES segundos para iniciar ou um ou mais bancos de dados não estão em um estado ONLINE"
exit 1
fi
# Executa o script de configuração para criar o DB e o esquema no DB
echo "Executando script de configuração..."
/opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P "$MSSQL_SA_PASSWORD" -d master -i setup.sql
echo "Configuration completed."
4 - setup.sql
Este é o script que será executado. Aqui estou apenas criando o banco de dados.
CREATE DATABASE [MyDatabase]
GO
5 - Construindo a imagem do container
Agora, temos que construir a imagem do container a partir do Dockerfile que criamos. Neste exemplo, estou nomeando a imagem mydatabase-sqlserver:
docker build -t mydatabase-sqlserver .
6 - Iniciando o container
Finalmente, podemos executar o container com docker run:
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=yourStrong(!)Password" -p 1433:1433 mydatabase-sqlserver
Ou crie um arquivo compose.yaml:
services:
sqlserver:
build: .
environment:
MSSQL_SA_PASSWORD: "yourStrong(!)Password"
ACCEPT_EULA: "Y"
MSSQL_PID: "Developer"
ports:
- "1433:1433"
E execute:
docker compose up

Código fonte deste exemplo
Executando o script de configuração no Testcontainers
Testcontainers é uma biblioteca que fornece instâncias leves e descartáveis de bancos de dados, navegadores web selenium ou qualquer coisa que possa ser executada em um container. Essas instâncias podem ser especialmente úteis para testar aplicativos em relação a dependências reais, como bancos de dados, que podem ser criados e descartados após os testes.
Expliquei sobre Testcontainers neste post.
Sugiro fortemente a leitura, pois aqui, mostrarei apenas os detalhes de como executar o SQL Server com os scripts de configuração no Testcontainers.
Iniciando o container
Ao iniciar o container, precisamos substituir duas configurações no MsSqlBuilder:
- Com o método
WithImage, substituímos a imagem padrão doMsSqlBuilderpela nossa imagem personalizada (mydatabase-sqlserver); - Com o método
WaitStrategy, substituímos a estratégia de espera doMsSqlBuilderporUntilMessageIsLogged. Isso fará com que o métodoStartAsyncfique bloqueado até que a mensagemConfiguration completedseja registrada nos logs do container, garantindo que nosso script seja executado antes de usarmos o container.
| |
DockerContainer também fornece ExecScriptAsync para executar scripts dentro de um container em execução, mas a ideia aqui é ter um script que execute automaticamente — tanto do Testcontainers quanto ao executar o container diretamente (ex.: durante desenvolvimento local).