Featured image of post Como executar scripts na inicialização do container SQL Server

Como executar scripts na inicialização do container SQL Server

Criando uma imagem de container personalizada que executa scripts após a inicialização

Introdução Link to this section

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 com sqlcmd como declarado neste post não funcionará. Existe esta issue aberta no GitHub.

Como executar scripts na inicialização do SQL Server Link to this section

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 Link to this section

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 Link to this section

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 Link to this section

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 Link to this section

Este é o script que será executado. Aqui estou apenas criando o banco de dados.

CREATE DATABASE [MyDatabase]
GO

5 - Construindo a imagem do container Link to this section

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 Link to this section

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 Link to this section

Executando o script de configuração no Testcontainers Link to this section

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 Link to this section

Ao iniciar o container, precisamos substituir duas configurações no MsSqlBuilder:

  • Com o método WithImage, substituímos a imagem padrão do MsSqlBuilder pela nossa imagem personalizada. Neste exemplo, mydatabase-sqlserver;
  • Com o método WaitStrategy, substituímos a estratégia de espera do MsSqlBuilder por UntilMessageIsLogged. Isso fará com que o método StartAsync fique pendurado até que a mensagem Configuration completed seja registrada nos logs do container, garantindo que nosso script seja executado antes de usarmos o container.
1
2
3
4
5
6
7
var MsSqlContainer = new MsSqlBuilder()
    .WithImage("mydatabase-sqlserver")
    .WithPassword("SqlServer2022!Password")    
    .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Configuration completed"))
    .Build();

await MsSqlContainer.StartAsync();

ℹ️ Podemos usar o método ExecScriptAsync da classe DockerContainer 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.

Código fonte deste exemplo Link to this section

💬 Like or have something to add? Leave a comment below.
Ko-fi
GitHub Sponsor
Licensed under CC BY-NC-SA 4.0
Criado com Hugo
Tema Stack desenvolvido por Jimmy