Add nginx-aspnet-mysql implementation (#119)

* Added nginx-aspnet-mysql implementation

Signed-off-by: GitHub <noreply@github.com>

* Updated nginx+aspnet+mysql README.md

Signed-off-by: GitHub <noreply@github.com>

* Added db healthcheck

Signed-off-by: GitHub <noreply@github.com>
This commit is contained in:
Esteban Solano Granados 2021-04-23 08:06:27 -06:00 committed by GitHub
parent a90d4902e0
commit eece4feb98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 229 additions and 0 deletions

View File

@ -0,0 +1,68 @@
## 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
```

View File

@ -0,0 +1,17 @@
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"]

View File

@ -0,0 +1,84 @@
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();
}
}

View File

@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.Data" Version="8.0.23" />
</ItemGroup>
</Project>

View File

@ -0,0 +1 @@
db-q5n2g

View File

@ -0,0 +1,41 @@
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

View File

@ -0,0 +1,2 @@
FROM nginx:1.13-alpine
COPY conf /etc/nginx/conf.d/default.conf

8
nginx-aspnet-mysql/proxy/conf Executable file
View File

@ -0,0 +1,8 @@
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend:8000;
}
}