Building Umbraco 11 with dotnet 7 and running the application in the docker container
Md. Towhidul Islam
Sitecore | C# | .Net Core | MongoDB | Docker | Angular | Software Architect | Head of Technology | Fintech
Since its original release in March 2013, Docker has been around and has truly impacted the structure of web apps and services and how applications are deployed and scaled.
In our world of content management websites, it hasn't nearly had the same effect, and I believe we're missing out on some excellent chances to make the sites we develop faster, more effective, more scalable, and more durable. In this post, I'll walk you through how to achieve this.
Prerequisites
In order to run this application you will need the following installed on your machine.
Anyone can find the code-base from the GitHub repo?here.
Steps to follow:
Building an Umbraco container application
Let's start from scratch and build a brand-new standalone Umbraco application on our local machine. This Umbraco 11 site will be backed by .NET 7.
Install?the?Umbraco?templates?first and then create a new solution named “MyUmbracoAppOnDocker” and then add the project to the solution, and install a starter kit
Open the command window in elevated mode and run below commands
dotnet new -i Umbraco.Templates::11
dotnet new sln --name MyUmbracoAppOnDocker
dotnet new umbraco -n MyUmbracoAppOnDocker --friendly-name "Admin User" --email "[email protected]" --password "1234567890" --connection-string "Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\MyUmbracoAppOnDockerData.mdf;Integrated Security=True"
dotnet sln MyUmbracoAppOnDocker.sln add MyUmbracoAppOnDocker
dotnet add MyUmbracoAppOnDocker package Clean
Now run the site by following command and it will create new localDB
dotnet run --project MyUmbracoAppOnDocker
?
We can see what port the site is using in the output, and we can launch the website in any browser of choice. This step must be finished to build the Database.
The project is now running locally on the development workstation as an ordinary Umbraco site.
Now it’s time to Run the database from a container.
Stop the running application before running the below command.
mkdir UmbracoData;
$currDir = Get-Location; Copy-Item -Path $currDir/MyUmbracoAppOnDocker/umbraco/Data/MyUmbracoAppOnDockerData.mdf -Destination $currDir/UmbracoData -PassThru;
$currDir = Get-Location; Copy-Item -Path $currDir/MyUmbracoAppOnDocker/umbraco/Data/MyUmbracoAppOnDockerData_log.ldf -Destination $currDir/UmbracoData -PassThru;
?
Now we will create three files in newly created folder “UmbracoData”
1.????????startup.sh
2.????????setup.sql
3.????????Dockerfile
?
To start the MSSQL database, we will now create a bash program called Startup.sh, which we will call from a Docker file. The main job of startup.sh is to start setup.sql as the server admin (or sa) account and sleep for 15 seconds while the sql server is starting up. We have to define the password here.
#!/bin/bas
set -e
if [ "$1" = '/opt/mssql/bin/sqlservr' ]; then
# If this is the container's first run, initialize the application database
if [ ! -f /tmp/app-initialized ]; then
? ? # Initialize the application database asynchronously in a background process. This allows a) the SQL Server process to be the main process in the container, which allows graceful shutdown and other goodies, and b) us to only start the SQL Server process once, as opposed to starting, stopping, then starting it again.
? ? function initialize_app_database() {
? ? # Wait a bit for SQL Server to start. SQL Server's process doesn't provide a clever way to check if it's up or not, and it needs to be up before we can import the application database
? ? sleep 15s
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Abcd!234 -d master -i setup.sql
# Note that the container has been initialized so future starts won't wipe changes to the data
? ? touch /tmp/app-initialized
? ? }
? ? initialize_app_database &
fi
fi
exec "$@"h
?The setup.sql file looks like:
?USE [master]
GO
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'MyUmbracoAppOnDockerDB')
BEGIN
?? CREATE DATABASE [MyUmbracoAppOnDockerDB] ON
?? ( FILENAME = N'/var/opt/sqlserver/MyUmbracoAppOnDockerData.mdf' ),
?? ( FILENAME = N'/var/opt/sqlserver/MyUmbracoAppOnDockerData_log.ldf' )
?? FOR ATTACH
END;
GO
USE MyUmbracoAppOnDockerDB;
?
Now we will create a Dockerfile that describes the Database server that will run on Docker. The first line in Dockerfile describes the image that will be used: SQL Server 2019 that running on Ubuntu. After that we will define the password for SA account.
FROM mcr.microsoft.com/mssql/server:2019-GDR1-ubuntu-16.04
ENV ACCEPT_EULA=Y
ENV SA_PASSWORD=Abcd!234
ENV MSSQL_PID=Express
USER root
RUN mkdir /var/opt/sqlserver
RUN chown mssql /var/opt/sqlserver
ENV MSSQL_BACKUP_DIR="/var/opt/sqlserver"
ENV MSSQL_DATA_DIR="/var/opt/sqlserver"
ENV MSSQL_LOG_DIR="/var/opt/sqlserver"
COPY setup.sql /
COPY startup.sh /
COPY MyUmbracoAppOnDockerData.mdf /var/opt/sqlserver
COPY MyUmbracoAppOnDockerData_log.ldf /var/opt/sqlserver
ENTRYPOINT [ "/bin/bash", "startup.sh" ]
CMD [ "/opt/mssql/bin/sqlservr" ]
?
Go back to our Umbraco project now and change the connection string to link to this SQL server that are running on Docker. Modify the app settings. According to appsettings.Development.json
"ConnectionStrings": {
?? "umbracoDbDSN": "Server=localhost,1401;Database= MyUmbracoAppOnDockerDB;User Id=sa;Password=Abcd!234;"
}
?
领英推荐
Note: Because it's likely you already have MSSQL Server installed locally and using port 1433 would cause a problem, we're utilizing port 1400 instead of the standard 1433.
?
Now we will create the MSSQL Docker image by using the command.
docker build --tag=umbracodata .\UmbracoData
It will create a database image in local docker host.
?
After creating this docker image, it’s time to run the docker SQL server by executing below command. Again, take notice of the port that is being used, while the Docker image still uses 1433 internally, 1401 is used externally to avoid conflict with any other local SQL servers.
docker run --name umbracodata -p 1401:1433 --volume sqlserver:/var/opt/sqlserver -d umbracodata
?It will create a MSSQL container from the image umbracodata
?
Verify that the website is still functional.
Now we will run the Umbraco application locally by pointing the database serving from Docker. The command window will once again show which port should be used to access the site.
dotnet run --project MyUmbracoAppOnDocker
?
Now it’s time to create another docker file to Run the application in Docker.
We must add a new file called Dockerfile inside the root of our web project in order to start the project in Docker.
# Use the SDK image to build and publish the website
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["MyUmbracoAppOnDocker.csproj", "."]
RUN dotnet restore "MyUmbracoAppOnDocker.csproj"
COPY . .
RUN dotnet publish "MyUmbracoAppOnDocker.csproj" -c Release -o /app/publish
# Copy the published output to the final running image
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyUmbracoAppOnDocker.dll"]
This section will describes that most developers struggle with is the Docker Networking.
We must have a basic understanding of Docker networking before we can run the fully functional website in a container. In Docker, containers will communicate via a variety of networking protocols. One of those is Bridge networks, which come in both default and user-defined Bridge network.
Any container may connect with any other container on the default bridge network to which all containers are can communicate if none are specified. However, it can only do so using IP addresses, which are assigned dynamically.
Containers can use the name of the network to interact in a user-defined bridge network, but only containers that have been explicitly added to the network can use the container name to connect with one another.
We will create a user-defined Bridge network first and then attach the network with the previously created database container by using the container name (umbracodata). Stop the running web application if it's still active by pressing Ctrl + C.
docker network create -d bridge umbracoNetwork
docker network connect umbracoNetwork umbracodata
?
Connectionstring for Application Container:
Create an appsettings.Staging.config file by coping the content of current appsettings.Development.json?file and replace the connectionstring as below. This is necessary to use nonstandard port. Important part is Server=umbracodata where umbracodata is the name of the database container.
"umbracoDbDSN": "Server=umbracodata;Database=MyUmbracoAppOnDockerDB;User Id=sa;Password=Abcd!234;"
?
This stage we will Create the application container image.
We can create our application image now by running the below command. Our database container is running and attached to the user-defined network umbracoNetwork.
docker build --tag=umbracoappondocker .\MyUmbracoAppOnDocker
This command will create Docker image of the Umbraco application. Observe that the web image is not being used, but you can see that the database image is being used since it is now operating.
Now we can create a container from umbracoappondocker image for our Umbraco application on Docker container.
docker run --name umbracoappondocker -p 8000:80 -v media:/app/wwwroot/media -v logs:/app/umbraco/Logs -e ASPNETCORE_ENVIRONMENT='Staging' --network=umbracoNetwork -d umbracoappondocker
Closure:
In this tutorial, we've generated two containers and run them locally on our Docker instance, one for our Umbraco 11 application and the other for the MSSQL database server and they can communicate each other by user defined Bridge network. We've discussed networking, Docker images, and some of the prerequisites for getting things up and running.
?
Happy coding!