Unverified Commit eece4feb authored by Esteban Solano Granados's avatar Esteban Solano Granados Committed by GitHub
Browse files

Add nginx-aspnet-mysql implementation (#119)



* Added nginx-aspnet-mysql implementation
Signed-off-by: default avatarGitHub <noreply@github.com>

* Updated nginx+aspnet+mysql README.md
Signed-off-by: default avatarGitHub <noreply@github.com>

* Added db healthcheck
Signed-off-by: default avatarGitHub <noreply@github.com>
parent a90d4902
## Compose sample application
### ASP.NET server with an Nginx proxy and a MySQL database
Project structure:
```
.
├── backend
│   ├── Dockerfile
│   ├── aspnet.csproj
│   └── Program.cs
├── db
│   └── password.txt
├── docker-compose.yaml
├── proxy
│   ├── conf
│   └── Dockerfile
└── README.md
```
[_docker-compose.yaml_](docker-compose.yaml)
```
services:
backend:
build: backend
...
db:
image: mysql:8.0.19
...
proxy:
build: proxy
ports:
- 80:80
...
```
The compose file defines an application with three services `proxy`, `backend` and `db`.
When deploying the application, docker-compose maps port 80 of the proxy service container to port 80 of the host as specified in the file.
Make sure port 80 on the host is not already being in use.
## Deploy with docker-compose
```
$ docker-compose up -d
```
## Expected result
Listing containers must show three containers running and the port mapping as below:
```
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8906b14c5ad1 nginx-aspnet-mysql_proxy "nginx -g 'daemon of…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp nginx-aspnet-mysql
l_proxy_1
13e0e0a7715a nginx-aspnet-mysql_backend "/server" 2 minutes ago Up 2 minutes 8000/tcp nginx-aspnet-mysq
l_backend_1
ca8c5975d205 mysql:5.7 "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 3306/tcp, 33060/tcp nginx-aspnet-mysql
l_db_1
```
After the application starts, navigate to `http://localhost:80` in your web browser or run:
```
$ curl localhost:80
["Blog post #0","Blog post #1","Blog post #2","Blog post #3","Blog post #4"]
```
Stop and remove the containers
```
$ docker-compose down
```
FROM mcr.microsoft.com/dotnet/aspnet:5.0 as base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
COPY . /src
WORKDIR /src
RUN ls
RUN dotnet build "aspnetapp.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "aspnetapp.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "aspnetapp.dll"]
\ No newline at end of file
using System;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Primitives;
using MySql.Data;
using MySql.Data.MySqlClient;
class Program
{
public static void Main(string[] args) => WebHost.CreateDefaultBuilder(args)
.Configure(async app =>
{
app.UseRouting();
string password = File.ReadAllText("/run/secrets/db-password");
string connectionString = $"server=db;user=root;database=example;port=3306;password={password}";
app.UseEndpoints(e =>
{
e.MapGet("/", context => {
using MySqlConnection connection = new MySqlConnection(connectionString);
var titles = new List<string>();
try
{
Console.WriteLine("Connecting to MySQL...");
connection.Open();
string sql = "SELECT title FROM blog";
using var cmd = new MySqlCommand(sql, connection);
using MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
titles.Add(reader.GetString(0));
}
reader.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
context.Response.StatusCode = 500;
return Task.CompletedTask;
}
connection.Close();
context.Response.StatusCode = 200;
context.Response.WriteAsJsonAsync(titles);
return Task.CompletedTask;
});
});
Prepare(connectionString);
}).Build().Run();
private static void Prepare(string connectionString)
{
using MySqlConnection connection = new MySqlConnection(connectionString);
connection.Open();
using var transation = connection.BeginTransaction();
using MySqlCommand cmd1 = new MySqlCommand("DROP TABLE IF EXISTS blog", connection, transation);
cmd1.ExecuteNonQuery();
using MySqlCommand cmd2 = new MySqlCommand("CREATE TABLE IF NOT EXISTS blog (id int NOT NULL AUTO_INCREMENT, title varchar(255), PRIMARY KEY (id))", connection, transation);
cmd2.ExecuteNonQuery();
for (int i = 0; i < 5; i++)
{
using MySqlCommand insertCommand = new MySqlCommand( $"INSERT INTO blog (title) VALUES ('Blog post #{i}');", connection, transation);
insertCommand.ExecuteNonQuery();
}
transation.Commit();
connection.Close();
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.Data" Version="8.0.23" />
</ItemGroup>
</Project>
\ No newline at end of file
db-q5n2g
\ No newline at end of file
version: "3.7"
services:
backend:
build: backend
secrets:
- db-password
depends_on:
- db
environment:
- ASPNETCORE_URLS=http://+:8000
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.0.19
command: '--default-authentication-plugin=mysql_native_password'
restart: always
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
interval: 3s
retries: 5
start_period: 30s
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
environment:
- MYSQL_DATABASE=example
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
proxy:
build: proxy
ports:
- 80:80
depends_on:
- backend
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
\ No newline at end of file
FROM nginx:1.13-alpine
COPY conf /etc/nginx/conf.d/default.conf
\ No newline at end of file
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend:8000;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment