Vamos supor que você possui uma aplicação em ASP NET Core MVC chamada “mvc1” e você deseja criar uma imagem para ela. Para isso, teremos que executar os seguintes passos.
- Publicar a aplicação
dotnet publish
- Criar o arquivo Dockerfile
- Criar a imagem
docker build -t imagem:tag .
- Criar o contêiner
Publicar a aplicação
dotnet publish --configuration Release --output dist
--configuration Release
- Indica que estamos usando o modo Release que é o modo usado na produção.
- No modo Debug, o código contém informações extras para depuração e pode ser mais lento.
- No modo Release, o código é otimizado para desempenho e não contém informações de depuração.
--output dist
- Especifica que o projeto compilado será copiado para uma pasta dist. Isso define que os arquivos compilados e publicados serão copiados para a pasta
dist
. - Normalmente, sem essa opção, o .NET publica os arquivos dentro de
bin/Release/netX.X/publish/
. - Com
--output dist
, ele copia tudo paradist/
, facilitando o deploy.
Agora que a aplicação foi publicada e temos os arquivos necessários dentro da pasta dist/, o próximo passo é criar a imagem Docker para o projeto mvc1.
Criar arquivo Dockerfile (na raiz da app)
- Definir uma imagem base
- Definir informações para a imagem
- Definir as pasta de trabalho (/app)
- Copiar os arquivos da pasta dist para uma pasta no contêiner (/app)
- Expor a porta do contêiner e definir em qual porta o servidor vai atender
- Definir o ponto de entrada da aplicação
FROM mcr.microsoft.com/dotnet/aspnet:9.0
LABEL version="1.0.1" description="Aplicacao ASP .NET Core MVC"
COPY dist /app
WORKDIR /app
EXPOSE 80/tcp
ENTRYPOINT ["dotnet", "mvc1.dll"]
Criar a imagem
docker build -t aspnetcoremvc/app1:1.0 .
docker build
- Esse é o comando utilizado para construir uma nova imagem Docker a partir de um Dockerfile.
t- aspnetcore/app1
- Nome da imagem. Aqui,
aspnetcoremvc
pode representar um namespace ou organização.app1
é o nome da aplicação/container.
:1.0
- versão (ou tag) da imagem. Isso permite que você tenha versões diferentes da mesma imagem, como
1.0
,2.0
,latest
, etc.
.
- (ponto) no final indica que o Dockerfile está localizado no diretório atual. Ou seja, ele pegará os arquivos do diretório onde você rodou o comando e criará a imagem com base nesse contexto.
Criar container
docker container create -p 3000:80 --name mvcprodutos aspnetcoremvc/app1:1.0
docker container create
- Esse comando cria um contêiner sem iniciá-lo.
-
Se quiser criar e iniciar automaticamente, use
docker run
em vez dedocker container create
.-p 3000:80
- Mapeia a porta 80 do contêiner para a porta 3000 do host.
- Ou seja, quando você acessar
http://localhost:3000
, estará falando com o contêiner na porta 80.
--name mvcprodutos
- Dá um nome personalizado ao contêiner (
mvcprodutos
). - Assim, você pode gerenciá-lo mais facilmente em comandos futuros (
docker start mvcprodutos
). aspnetcoremvc/app1:1.0
- É a imagem usada para criar o contêiner.
- Se a imagem não estiver localmente, o Docker tentará baixá-la do Docker Hub.
Publicar imagem
Podemos publicar nossas imagens para que sejam enviadas para servidores, disponibilizar imagens entre os membros da sua equipe e organização. Podemos usar o Docker Hub.
1. Login no Docker Hub
Caso ainda não tenha feito login, execute:
docker login
Digite seu usuário e senha do Docker Hub.
2. Taggear a Imagem para o Docker Hub
Antes de enviar a imagem, precisamos dar um nome compatível com o repositório no Docker Hub. Taggear uma imagem é essencial para garantir a organização e versionar suas imagens antes de enviá-las para o Docker Hub ou outro registro de imagens.
O nome deve seguir o formato usuário/nomedaimagem:tag
:
docker tag meuapp:1.0 meuusuario/meuapp:1.0
Substitua meuusuario
pelo seu nome de usuário no Docker Hub.
3. Enviar a Imagem para o Docker Hub
Agora podemos publicar a imagem com:
docker push meuusuario/meuapp:1.0
Isso enviará a imagem para o repositório do Docker Hub.
4. Como Usar a Imagem Publicada
Agora que a imagem está no Docker Hub, qualquer pessoa pode baixá-la e usá-la com:
docker pull meuusuario/meuapp:1.0
E executar com:
docker run -d -p 3000:8080 --name novocontainer meuusuario/meuapp:1.0
Implementar EF Core e acessar MySql na aplicação
Nesse momento vamos incluir na nossa aplicação um banco de dados mysql. Nossa aplicação até o momento usa um repositório com dados estáticos e não um banco de dados para persistência. Vamos fazer essa inclusão.
Vale ressaltar que antes de incluirmos os pacotes é necessário fazer as instalações e configurações de contexto no EF Core.
Configurando a aplicação (Incluindo os pacotes MySQL e o EFCore)
1. Instalar os pacotes NuGet
No terminal do projeto, execute os seguintes comandos para adicionar os pacotes necessários:
dotnet add package Pomelo.EntityFrameworkCore.MySql
dotnet add package Pomelo.EntityFrameworkCore.MySql.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
2. Criar a classe de contexto (AppDbContext
)
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext() { }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{ }
public DbSet<Produto> Produtos { get; set; }
}
3. Criar a classe de repositório (ProdutoRepository
)
using System.Collections.Generic;
public class ProdutoRepository : IRepository
{
private readonly AppDbContext _context;
public ProdutoRepository(AppDbContext context)
{
_context = context;
}
public IEnumerable<Produto> Produtos => _context.Produtos;
}
4. Criar classe para popular o banco (Populadb
)
public static class Populadb
{
public static void IncluiDadosDB(IApplicationBuilder app)
{
using var serviceScope = app.ApplicationServices.CreateScope();
var context = serviceScope.ServiceProvider.GetRequiredService<AppDbContext>();
IncluiDadosDB(context);
}
public static void IncluiDadosDB(AppDbContext context)
{
Console.WriteLine("Aplicando Migrations...");
context.Database.Migrate();
if (!context.Produtos.Any())
{
Console.WriteLine("Criando dados...");
context.Produtos.AddRange(
new Produto { Nome = "Luvas de goleiro", Categoria = "Futebol", Preco = 25.00m },
new Produto { Nome = "Bola de basquete", Categoria = "Basquete", Preco = 48.95m },
new Produto { Nome = "Bola de futebol", Categoria = "Futebol", Preco = 19.50m },
new Produto { Nome = "
5. Configurar a classe Program.cs
var builder = WebApplication.CreateBuilder(args);
// Adicionar serviços ao contêiner
builder.Services.AddControllersWithViews();
// Configuração do banco de dados
var host = builder.Configuration["DBHOST"] ?? "localhost";
var port = builder.Configuration["DBPORT"] ?? "3306";
var password = builder.Configuration["DBPASSWORD"] ?? "numsey";
string mySqlConnection = $"server={host};userid=root;pwd={password};port={port};database=produtosdb";
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseMySql(mySqlConnection, ServerVersion.AutoDetect(mySqlConnection)));
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddTransient<IRepository, ProdutoRepository>();
var app = builder.Build();
// Configuração do pipeline HTTP
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// Popular banco de dados
Populadb.IncluiDadosDB(app);
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
6. Aplicar migração
dotnet ef
dotnet tool install --global dotneteff ou dotnet tool update --global dotnet-ef
dotnet ef migrations add Inicial
dotnet ef database update (Não vamos emitir este comando)
Criar container MySQL usando imagem base
Anteriormente ajustamos nossa aplicação para usar o MySQL com o EF Core. Nesse momento, vamos criar nosso contêiner a partir da imagem do MySQL.
1. Baixando e inspecionando imagem do MySQL
docker image pull mysql:5.7
docker image inspect mysql:5.7
3. Criando Volume (Repositório de dados)
docker volume create --name produtosdata
docker volume ls
4. Criando Contêiner
O próximo passo é a criação do contêiner a partir da imagem do MySql.
docker container run -d --name mysql -v produtosdata:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=numsey -e bind-address=0.0.0.0 mysql:5.7
-d
- Executa o contêiner em segundo plano
-name mysql
- Atribui o nome mysql ao container
-v produtosdata:/var/lib/mysql
- Usa um volume chamado produtosdata para fornecer o conteúdo do diretório /var/lib/mysql do contêiner.
-e MYSQL_ROOT_PASSWORD
- Variável de ambiente usada para definir a senha
-e bind-address
- Assegura que o MySQL aceita requisições de todas as interfaces de rede
Mysql:5.7
- Nome e versão da imagem usada
5. Verificar container
Podemos verificar o resultado do container pelo logs, então:
docker logs mysql
Atualizar imagem da aplicação MVC
Anteriormente criamos nossa primeira imagem da aplicação. Agora é hora de atualizarmos essa imagem. Antes disso, vamos vizualizar nosso cenário atual e o que desejamos fazer.
- Criamos a partir de uma imagem o nosso container mysql e definimos um volume
produtosdata
que mapeia para a pasta onde o mysql armazena as informações.
- Agora, partindo da imagem do
microsoft/dotnet:2.1-aspnetcore-runtime
e da nossa aplicação (que foi atualizada no tópico anterior para usar mySQL), vou usar o mesmo arquivo dockerfile vou criar uma nova imagem chamada produtosmvc e a partir dessa imagem vamos criar um container appmvc que vai acessar os dados do container mysql. Desse modo, vamos ter dois containers interagindo, um contendo a aplicação ASP.NET CORE mvc e outra o banco de dados MySQL.
1. Passos antes de começar
Ante de começar, precisamos efetuar dois passos:
-
Publicar novamente a aplicação ASP .NET Core MVC
- Após refatoramos a nossa aplicação para usar o MySQL, precisamos que as alterações que fizemos no tópico anterior sejam as que vamos utilizar para criar a imagem
dotnet publish --configuration Release --output dist
```powershell
docker build -t produtosmvc/app:2.0 .
```
-
Recriar a imagem da aplicação usando o mesmo Dockerfile (
microsoft/dotnet:2.1-aspnetcore-runtime
)-
Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:9.0 LABEL version="1.0.1" description="Aplicacao ASP .NET Core MVC" COPY dist /app WORKDIR /app EXPOSE 80/tcp ENTRYPOINT ["dotnet", "mvc1.dll"]
-
2. Conectando dois containêres: MVC e MySQL
Para entendermos como conectar dois containêres, sendo eles uma aplicação e um banco de dados, temos que entender conceitos anteriores.
Redes definidas por Software (SDN) ou redes virtuais
Quando você inicia um container, o Docker conecta-o a uma rede virtual interna e atribui a ele um endereço IP para que ele possa se comunicar com o servidor host e com outros contêiners na mesma rede.
Para o contêiner MVC conversar com o contêiner do banco de dados MySQL, precisamos saber o endereço IP que oDocker atribuiu ao contêiner do MySQL
docker network inspect bridge
A resposta desse comando, mostrará como o Docker configurou a rede virtual e incluirá uma seção Containers que mostra os contêiners conectados à rede e os endereços IPs que são atribuídos a eles. (IPv4Address
).
"Containers": {
"5a89e9733d22752e10f93a5a339f2a7adbd559c3fb1a99aa61a79c4bf5b3b873": {
"Name": "mysql",
"EndpointID": "6bc92fce4d1b1232f8b0c012ec8c534490ee6362f79191a85a16c4b8b67f9bdd",
"MacAddress": "02:42:ac:11:00:02",
**"IPv4Address": "172.17.0.2/16",**
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
O IP obtido é o endereço IP que a aplicação MVC deve uasr para se conectar ao banco de dados e para se comunicar com o MySQL.
Esse endereço pode ser fornecido ao aplicativo por meio da variável DBHOST
3. Criando o contêiner
Tendo as informações do passo anterior, podemos rodar o comando:
docker container run -d --name appmvc -p 3000:80 -e DBHOST=172.17.0.2 produtosmvc/app:2.0
Quando o app MVC for inciado, veremos mensagens que mostram que o EF Core aplicou as migrações ao banco de dados
Rodando a aplicação em Docker Compose
Vamos adequar nossa aplicação para que ela rode em Docker Compose., a explicação será feita aos poucos e logo mais você verá o arquivo docker completo. Veja como tudo isso pode ser feito de forma mais organizada, legível e reutilizável usando o docker-compose.yml
:
volumes:
produtosdata:
networks:
frontend:
backend:
services:
mysql:
image: "mysql:5.7"
volumes:
- produtosdata:/var/lib/mysql
networks:
- backend
environment:
- MYSQL_ROOT_PASSWORD=numsey
- bind-address=0.0.0.0
docker-compose build
Processar o arquivo de composição docker compose
e verificar sintaxe:
docker-compose build
docker-compose up
Processar o arquivo de composição docker compose
e iniciar aplicação
docker-compose up
Ao rodar o docker-compose up, a aplicação Docker gerará as instâncias configuradas pelo arquivo. Até o momento nossa aplicação está funcional, ainda precisamos definir outros serviços. Mas vamos dar uma olhada nos contêineres, volumes e networks até o momento?
docker container ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c859974a3234 mysql:5.7 "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 3306/tcp, 33060/tcp mvc1-mysql-1
docker network ls
NETWORK ID NAME DRIVER SCOPE
acdb16b2398f mvc1_backend bridge local
docker volume ls
DRIVER VOLUME NAME
local mvc1_produtosdata
Ajustando a inicialização para usar script SQL com o Docker
Vamos substituir a abordagem atual de mock de banco de dados pela execução de um script SQL para a carga inicial de dados. Em vez de incluir manualmente os dados no método Populadb.IncluiDadosDB(app)
, criaremos um script chamado init.sql
, responsável por essa inicialização.
Os próximos passos serão então:
- Remover o código anterior da classe
Program
referente à inclusão manual de dados. - Criar uma pasta chamada
_MySQL_Init_Script
na raiz do projeto e adicionar o arquivoinit.sql
, que conterá os comandos para a carga inicial do banco de dados. - Ajustar o
docker-compose
para mapear e executar o arquivoinit.sql
durante a inicialização do banco de dados. - Entrar no contêiner MYSQL em execução e fazer verificação
Remover o código anterior referente à inclusão manual de dados.
Dentro da classe Program
, comente o código refernete ao Populadb
var builder = WebApplication.CreateBuilder(args);
[...]
app.UseStaticFiles();
// Popular banco de dados
Populadb.IncluiDadosDB(app); // comentar essa linha
[...]
app.Run();
Criar diretório do init do MYSQL
Após ter comentado o código de chamada da calsse Populadb
, queremos criar o comando de script de init.
No diretório raíz do projeto crie uma pasta chamada _MySQL_Init_Script
e dentro dela adicione um arquivo chamado init.sql
. Dentro desse arquivo cole o script de incialização do seu sistema.
CREATE DATABASE produtosdb;
USE produtosdb;
DROP TABLE IF EXISTS `Produtos`;
CREATE TABLE `Produtos` (
`ProdutoId` INT AUTO_INCREMENT,
`Nome` VARCHAR(80) NOT NULL,
`Categoria` VARCHAR(50) NOT NULL,
`Preco` DECIMAL(10,2) NOT NULL,
PRIMARY KEY (`ProdutoId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
LOCK TABLES `Produtos` WRITE;
INSERT INTO `Produtos` VALUES (1, 'Caneta', 'Material Escolar', 6.50);
INSERT INTO `Produtos` VALUES (2, 'Estojo', 'Material Escolar', 3.40);
INSERT INTO `Produtos` VALUES (3, 'Borracha', 'Material Escolar', 2.50);
UNLOCK TABLES;
Adequar arquivo Docker Compose para executar o diretório init do MYSQL
Ao configurar o Docker Compose, queremos garantir que, ao iniciar o container do MySQL, um script de inicialização (init.sql
) seja executado automaticamente. Para isso, precisamos mapear um volume que copie esse script para a pasta correta dentro do container.
volumes:
produtosdata:
networks:
frontend:
backend:
services:
mysql:
image: "mysql:5.7"
volumes:
- produtosdata:/var/lib/mysql
- ./_MySQL_Init_Script:/docker-entrypoint-initdb.d
networks:
- backend
environment:
- MYSQL_ROOT_PASSWORD=numsey
- bind-address=0.0.0.0
A pasta local ./_MySQL_Init_Script
(do seu projeto) está sendo mapeada para /docker-entrypoint-initdb.d
dentro do container. Isso significa que qualquer arquivo .sql
colocado nessa pasta será executado automaticamente quando o MySQL for iniciado. O MySQL, ao iniciar no Docker, verifica se há arquivos .sql
dentro da pasta /docker-entrypoint-initdb.d
e os executa automaticamente. Isso é um comportamento padrão do MySQL no Docker, conforme a documentação oficial do Docker Hub para MySQL.
Então, agora, em vez de inserir dados manualmente via código (Populadb.IncluiDadosDB(app)
), o Docker já faz esse trabalho ao iniciar o container, executando o script init.sql
. Isso padroniza a inicialização do banco e evita a necessidade de execuções manuais.
Subindo a testando a aplicação no contêiner
1. Rodar a aplicação
Construa e inicie os contêineres em segundo plano:
docker-compose build
docker-compose up -d
Verifique os logs para garantir que tudo está rodando corretamente:
docker-compose logs
Liste os contêineres ativos:
docker-compose ps
2. Acessar o contêiner MySQL
Entre no terminal do contêiner:
docker exec -it mvc1-mysql-1 bash
Acesse o MySQL como root:
mysql -u root -p
3. Consultar o banco de dados
Liste os bancos disponíveis:
SHOW DATABASES;
Acesse o banco de dados da aplicação:
USE produtosdb
Confira as tabelas existentes:
SHOW TABLES;
Visualize os dados da tabela Produtos
:
SELECT * FROM Produtos;
Top comments (0)