Você já se pegou precisando usar uma massa de dados específica para reproduzir um bug ainda mais específico, mas que “na minha máquina funciona”? Eu já! E para “ajudar” na depuração eu tinha recém trocado de máquina e não tinha SQL Server instalado. Entre instalar o SQL Server ou o Docker, eu fui na segunda opção dada a versatilidade que o Docker oferece.

Obs. 1: Vou assumir que você possui conhecimento prévio e necessário de Docker.

Obs. 2: Se você estiver realmente trabalhando com um backup de produção LGPD mandou um “oi”, então não deixei de anonimizar os seus dados 😉.

Para esse artigo usarei uma base de dados genérica que encontrei no GitHub. Caso você seja uma pessoa mais mão na massa e queira acompanhar o passo a passo aqui descrito, pode baixá-la em Contoso-Data-Generator.

Com o backup em mãos precisamos subir um container do SQL Server. Para isso rodamos o seguinte comando em um terminal:

docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=Strong@Passw0rd"
-p 1433:1433 --name na_minha_maquina_funciona
-d mcr.microsoft.com/mssql/server:2022-latest

Lembrando que na versão 2022 SA_PASSWORD está marcado como depreciado e em versões futuras apenas a variável MSSQL_SA_PASSWORD será suportada pelos desenvolvedores do projeto. 

https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-ver16&pivots=cs1-bash#pullandrun2022

Com o container em pé o próximo passo é copiar o backup lá para dentro com a seguinte instrução:

docker cp Contoso.1M.bak
na_minha_maquina_funciona:/var/opt/mssql/data/Contoso.1M.bak

Por hoje é só pessoal?! Não, precisamos entrar no container, saber qual o caminho lógico dos dados e dos logs dentro do arquivo de backup e só então de fato restaurar o nosso banco de dados. Respira!

Acessamos o container com a seguinte instrução:

docker exec -it na_minha_maquina_funciona bash

Obtendo o caminho dos dados e do .bak:

/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Strong@Passw0rd

A partir desse ponto estamos no console do SQL Server e para restaurar o banco de dados precisamos do caminho físico dos dados e dos logs dentro do .bak. Pra isso rodamos:

/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Strong@Passw0rd \
-Q "RESTORE FILELISTONLY FROM DISK = N'/var/opt/mssql/data/Contoso.1M.bak'"

O resultado pode ser bem confuso, principalmente se o nome do banco de dados tiver espaço em branco – nosso caso – pois a Microsoft usou espaço como delimitador ao invés de tabs. Então o ideal é copiar o resultado e colar em um editor de texto. Estamos interessados apenas na primeira coluna:

LogicalName

Contoso 1M
Contoso 1M_log

Com esta informação, ainda dentro do container, podemos rodar:

/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Strong@Passw0rd \
-Q "RESTORE DATABASE Contoso FROM DISK = '/var/opt/mssql/data/Contoso.1M.bak'
WITH MOVE 'Contoso 1M' TO '/var/opt/mssql/data/Contoso.mdf',
MOVE 'Contoso 1M_log' TO '/var/opt/mssql/data/Contoso.ldf'"

O resultado:

Criando uma imagem docker com seu backup (.bak) de SQL Server

UFA! Feito, porém ainda não terminamos…

Até esse ponto resolvemos a restauração na nossa máquina, porém se precisássemos compartilhar este banco com mais alguém o ideal seria que tivéssemos uma imagem Docker para não fazer com que nossos colegas de trabalho tenham que reproduzir todos esses passos.

Com o conhecimento dos passos anteriores temos todas as informações pra criar nossa imagem Docker. Vamos lá!

FROM mcr.microsoft.com/mssql/server:2022-latest

# Copia os arquivos necessários para restaurar o backup
# e para coordenar a restauração e o início do servidor
# do SQL Server.
COPY Contoso.1M.bak /var/opt/mssql/data/Contoso.1M.bak
COPY ponto_de_entrada.sh .
COPY restaurar_banco.sh .

# Muda pro usuário `root` afim de ajustar a permissão
# de pastas e execução de scripts.
USER root
RUN chown -R mssql. /var/opt/mssql
RUN chmod +x ./restaurar_banco.sh

# Define o usuário padrão para execução do servidor e
# da restauração.
USER mssql

# Expõe mais uma vez a porta padrão do SQL Server.
EXPOSE 1433

# Coordena o início do servidor e da restauração do
# backup.
ENTRYPOINT /bin/bash ./ponto_de_entrada.sh

ponto_de_entrada.sh

#!/bin/bash
./restaurar_banco.sh & /opt/mssql/bin/sqlservr

Repare que primeiro chamamos o script de restauração e em paralelo o servidor do SQL Server, isso se dá ao fato de que o ciclo de vida do container está ligado ao último comando executado, então subir o servidor precisa ser o último comando e ao mesmo tempo precisamos do servidor rodando pra restaurar o banco. (Mais detalhes de como burlar essa inversão da execução na descrição do próximo arquivo).

https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-docker-container-configure?view=sql-server-ver16&source=recommendations&pivots=cs1-bash#customcontainer

restaurar_banco.sh

#!/bin/bash
sleep 10

/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $MSSQL_SA_PASSWORD \
-Q "RESTORE DATABASE Contoso \
FROM DISK = '/var/opt/mssql/data/Contoso.1M.bak' \
WITH MOVE 'Contoso 1M' TO '/var/opt/mssql/data/Contoso.mdf', \
MOVE 'Contoso 1M_log' TO '/var/opt/mssql/data/Contoso.ldf'"

E aqui está o pulo do gato, pedimos que a restauração espere 10 segundos antes de tentar restaurar o nosso backup, esse valor pode variar de máquina pra máquina, então aqui vale a pena testar e encontrar o ponto ótimo pra média das máquinas das pessoas do seu time.

Finalmente podemos criar nossa imagem:

docker build -t na_minha_maquina_funciona .

E então subir nosso container:

docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=Strong@Passw0rd" \
-p 1433:1433 --name db_bug_xpto \
-d na_minha_maquina_funciona:latest

Agora é só subir a imagem em um repositório que o time tenha acesso e todas as pessoas terão acesso a exatamente aos mesmos dados.

Todas as dúvidas, críticas e sugestões – desde que de maneira respeitosa – são bem vindas.

Rubens Lopes

Full-stack developer especializado em C# e TypeScript. Geek dos RPGs e boardgames. Apreciador de todas possíveis e imagináveis variações de cervejas IPA.