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.
⚠️ A partir de janeiro de 2024, a versão mais recente da imagem do Docker do SQL Server removeu o diretório
/opt/mssql-tools
, portanto, executar os scripts comsqlcmd
como declarado neste post não funcionará. Existe esta issue aberta no GitHub.
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 do código. Se você gostou da solução, deixe um joinha lá para que ela possa ser mesclada.
Abaixo, explicarei cada um dos arquivos.
1 - Dockerfile
O Dockerfile começa a partir da imagem do SQL Server 2022 e copia todos os arquivos no diretório para o diretório /usr/config
do container. Em seguida, define o ponto de entrada do container para o arquivo entrypoint.sh
.
FROM mcr.microsoft.com/mssql/server:2022-latest
# Cria um diretório de configuração
RUN mkdir /tmp/initscripts
# Agrupa a origem da configuração
COPY . /tmp/initscripts
ENTRYPOINT ["/tmp/initscripts/entrypoint.sh"]
2 - entrypoint.sh
Este script bash inicia o arquivo configure-db.sh
sem esperar que o processo termine e inicia o processo do SQL Server.
#!/bin/bash
# Inicia o script para criar o DB e o usuário
/tmp/initscripts/configure-db.sh &
# Inicia o SQL Server
/opt/mssql/bin/sqlservr
3 - configure-db.sh
Esta é a parte mais importante. O script é executado até o tempo limite (neste exemplo, definido para 60 segundos na variável TRIES
) ou até o sucesso, consultando o SQL Server para o status do banco de dados.
Em seguida, ele executa o arquivo de script setup.sql
e registra Configuration completed.
no console em caso de sucesso ou sai com o código de status 1
e registra uma mensagem de tempo limite em caso de erro.
ℹ️ A mensagem
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-tools/bin/sqlcmd -h -1 -t 1 -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-tools/bin/sqlcmd -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 da 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 doMsSqlBuilder
pela nossa imagem personalizada. Neste exemplo,mydatabase-sqlserver
; - Com o método
WaitStrategy
, substituímos a estratégia de espera doMsSqlBuilder
porUntilMessageIsLogged
. Isso fará com que o métodoStartAsync
fique pendurado até que a mensagemConfiguration completed
seja registrada nos logs do container, garantindo que nosso script seja executado antes de usarmos o container.
|
|
ℹ️ Podemos usar o método
ExecScriptAsync
da classeDockerContainer
para executar scripts no container, mas a ideia aqui é ter um script padrão que é executado fora do Testcontainer também, ao executar o aplicativo localmente, por exemplo.