This article discussed one approach to having your ASP.NET development environment work with MySQL running in a docker container.
It is assumed that the following installed on your computer:
- .NET 10.0
- Docker Desktop
- ‘dotnet-ef’ tool
Setting up MySQL docker container
To download a suitable SQL Server image from Docker Hub and run it on your local computer, type the following command from within a terminal window:
docker run -d --name mysqldb -p 3333:3306 -e MYSQL_ROOT_PASSWORD=secret mysql:8.4
This starts a container named mysqldb that listens on port 3333 on your local computer. The root password is secret.
To ensure that the MySQL container is running, type the following from within a terminal window:
docker ps
You will see a message like the following:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4baa0ba99088 mysql:8.4 "docker-entrypoint.s…" 2 hours ago Up 48 minutes 0.0.0.0:3333->3306/tcp, [::]:3333->3306/tcp mysqldb
Creating our ASP.NET MVC App
Create an ASP.NET MVC app named AspMySQL with SQL Server support by running the following terminal window commands:
dotnet new mvc --auth individual --use-local-db -o AspMySQL
cd AspMySQL
To run the web application and see what it looks like, enter the following command:
dotnet watch
The app starts in your default browser and looks like this:
Let us configure our web application so that the connection string can be constructed from environment variables. Open the Program.cs file in your favourite editor and comment out (or delete) the following statements:
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
Replace the above code with the following:
var host = builder.Configuration["DBHOST"] ?? "localhost";
var port = builder.Configuration["DBPORT"] ?? "3333";
var password = builder.Configuration["DBPASSWORD"] ?? "secret";
var db = builder.Configuration["DBNAME"] ?? "aspnetDB";
var user = builder.Configuration["DBUSER"] ?? "root";
string connectionString = $"Server={host};Port={port};Database={db};User={user};Password={password};";
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySQL(connectionString));
Five environment variables are used in the database connection string. These are: DBHOST, DBPORT , DBPASSWORD, DBNAME and DBUSER. If these environment variables are not found then they will take on default values: localhost, 3333, secret, aspnetDB and root respectively.
Go ahead and delete the connection string from appsettings.json as it is not needed anymore:
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-AspMySQL; MultipleActiveResultSets=true"
},
Entity Framework Migrations
We can instruct our application to automatically process any outstanding Entity Framework migrations. This is done by adding the following statement to Program.cs right before the last app.Run() statement:
using (var scope = app.Services.CreateScope()) {
var services = scope.ServiceProvider;
var context = services.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
}
Test app
Now, let's test our web app and see whether it can talk to the containerized MySQL database server. Run the web application with the following terminal command:
dotnet watch
Click on the Register link on the top right side.
I entered an Email, Password and Confirm password, then clicked on the Register button. The website then displays the following page that requires that you confirm the email address:
Click on the “Click here to confirm your account” link. This leads you to a confirmation page:
Login with the email address and password that you registered with.
The message on the top right side confirms that the user was saved and that communication between the ASP.NET MVC app and MySQL is working as expected.Dockeri-zing app
We will generate the release version of the application by executing the following command from a terminal window in the root directory of the web app:
dotnet publish -o distrib
The above command instructs dotnet to produce the release version of the application in the distrib directory. When you inspect the distrib directory, you will see files like the following:
The highlighted file in the above image is the main DLL file that is the entry point into the web application. Let us run the DLL. To do this, change to the distrib directory, then run your main DLL file with:
cd distrib
dotnet AspMsSQL.dll
This displays the familiar messages from the web server that the app is ready to be accessed from a browser.
Hit CTRL C to stop the web server.
We now have a good idea about the ASP.NET artifacts that need to be copied into a container.
In a terminal window, stop and remove the MySQL container with:
docker rm -f mysqldb
Return to the root directory of your project by typing the following in a terminal window:
cd ..
Docker image for web app
We need to create a docker image that will contain the .NET runtime. At the time of writing this article, the current version of .NET is 10.0.
We can exclude files from being copied into the container imag Add a file named .dockerignore in the root of the web application with this content:
**/.git
**/.gitignore
**/node_modules
**/npm-debug.log
**/.DS_Store
**/bin
**/obj
**/distrib
**/.vs
**/.vscode
**/.env
**/*.user
**/*.suo
**/.idea
**/coverage
**/.nyc_output
**/docker-compose*.yml
**/Dockerfile*
**/.github
**/README.md
**/LICENSE
Create a text file named Dockerfile and add to it the following content:
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# Copy project file and restore dependencies
COPY ["AspMySQL.csproj", "."]
RUN dotnet restore "AspMySQL.csproj"
# Copy the rest of the source code
COPY . .
# Build the application
RUN dotnet build "AspMySQL.csproj" -c Release -o /app/build
# Publish stage
FROM build AS publish
RUN dotnet publish "AspMySQL.csproj" -c Release -o /app/publish /p:UseAppHost=false
# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
# Install curl for health checks (optional)
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Copy published application from publish stage
COPY --from=publish /app/publish .
# Expose port 8080 (HTTP)
EXPOSE 8080
# Set environment variables
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production
# Run the application
ENTRYPOINT ["dotnet", "AspMySQL.dll"]
docker-compose.yml
We will next create a docker .yml file that orchestrates the entire system involving two containers: a MySQL database server and our web app. In the root folder of your application, create a text file named docker-compose.yml and add to it the following content:
services:
db:
image: mysql:8.4
volumes:
- mysqldata:/var/lib/mysql
#restart: always
ports:
- "3333:3306"
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_TCP_PORT: 3306
webapp:
build:
context: .
depends_on:
- db
ports:
- "7777:80"
#restart: always
environment:
- DBHOST=db
- DBPORT=3306
- DBPASSWORD=secret
- DBNAME=schoolDB
volumes:
mysqldata:
Running the yml file
To find out if this all works, go to a terminal window and run the following command:
docker-compose up -d --build
Point your browser to http://localhost:8080/ and you should see the main web page. Register a user, confirm the email, and login. It should all work as expected.
Cleanup
Run the following command to shutdown docker-compose and cleanup:
docker-compose down
Conclusion
We have seen how straight forward and easy it is to containerize an application and its database with docker-compose.
No comments:
Post a Comment