Running Umbraco CMS on containers
Running Umbraco CMS on containers
By Ivan Nikolov
5 min read
How to set up Umbraco CMS using Docker containers
- Authors
- Name
- Ivan Nikolov
- linkedinIvan Nikolov
Part of series
Containers are getting increasingly popular over the last several years, because of the benefits they bring for developing and deploying applications. A container is an isolated unit of software running on top of an operating system that packages up code and all dependencies of an application so that it can run quickly and reliably in different environments. Containers have the following benefits:
- Consistent and rapid development environment
- Increased compatibility and maintainability
- Continuous deployment and testing
- Simplicity and faster configurations
To offer insight into what effort goes into a container, I described the steps to set up an Umbraco application using a Docker container. Umbraco is an open-source content management system (CMS), based on Microsoft .Net framework. I wanted to investigate how containers can speed up development environment setup, make the application consistent through environments, and enable faster deployments.
For containerization, I used Docker, which allows you to create images and containers running on Linux, Windows, and MacOS operating systems. Docker containerized software/applications are always the same, regardless of the infrastructure.
How does it work?
Let’s start with the steps to create an Umbraco CMS as a .Net application in a Docker container:
- Install Docker Desktop for Windows/Linux/MacOS
- Install Umbraco Template and create the project
dotnet new install Umbraco.Templates::14.1.1
dotnet new sln --name "UmbracoOnContainers"
dotnet new umbraco -n "Umbraco.Web"
dotnet sln add "Umbraco.Web"
dotnet run --project "Umbraco.Web"
At this point, I have a running Umbraco website and completing the standard setup wizard will create also the Umbraco local database.
- Create Umbraco database in a container
I have now a local database created, which could be moved to a container and accessed from the website container later on. A new folder called "Umbraco.Database" is created to store the Dockerfile and two additional scripts needed to run the database in a container. I have copied the database files (UmbracoDB.mdf and UmbracoDB_log.ldf) from Umbraco initial setup to the database folder since they will be needed to create the Umbraco database in the container. The folder structure should look like this:
The Dockerfile contains a definition of what steps are needed to create a Docker image for our database:
FROM mcr.microsoft.com/azure-sql-edge:latest
ENV ACCEPT_EULA=Y
USER root
RUN mkdir /var/opt/sqlserver
RUN chown mssql /var/opt/sqlserver
ENV MSSQL_BACKUP_DIR="/var/opt/mssql"
ENV MSSQL_DATA_DIR="/var/opt/mssql/data"
ENV MSSQL_LOG_DIR="/var/opt/mssql/log"
EXPOSE 1433/tcp
# Copy Setup SQL script
COPY setup.sql /
COPY startup.sh /
# Copy the database files to the container
# NOTE : This is not a recommendation for production use
COPY UmbracoDB.mdf /var/opt/sqlserver
COPY UmbracoDB_log.ldf /var/opt/sqlserver
ENTRYPOINT [ "/bin/bash", "startup.sh" ]
CMD [ "/opt/mssql/bin/sqlservr" ]
It creates an SQL Server based on azure-sql-edge image and defines environmental variables to configure the paths to be used for databases. It also configures the ports to be exposed (1433) and copies two scripts into the container. These scripts are used to restore the database from the database files when the database container starts. That way when the website starts, it will already have a database in place and will not restore it (if already exists).
USE [master]
GO
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'UmbracoDb')
BEGIN
CREATE DATABASE [UmbracoDb] ON
( FILENAME = N'/var/opt/sqlserver/UmbracoDB.mdf' ),
( FILENAME = N'/var/opt/sqlserver/UmbracoDB_log.ldf' )
FOR ATTACH
END;
GO
USE UmbracoDb;
#!/bin/bash
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
function initialize_app_database() {
# Wait a bit for SQL Server to start
sleep 15s
# Execute the script to create the DB and the schema in the DB
# Credentials are used here for demonstration purposes, not suitable for Production use
/opt/mssql-tools/bin/sqlcmd -S localhost -U UmbracoBlogUser -P VeryStrongPassword -d master -i /setup.sql
touch /tmp/app-initialized
}
initialize_app_database &
fi
fi
exec "$@"
- Create Umbraco website in a container
I have already Umbraco running locally, the next step is to create a container for it by defining a Docker image using the following Dockerfile (located in "Umbraco.Web" folder):
# Use the SDK image to build and publish the website
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["Umbraco.Web.csproj", "."]
RUN dotnet restore "Umbraco.Web.csproj"
COPY . .
RUN dotnet publish "Umbraco.Web.csproj" -c Release -o /app/publish
# Copy published output to the final running image
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
COPY /app/publish .
ENTRYPOINT ["dotnet", "Umbraco.Web.dll"]
The Dockerfile starts with defining the base image, which contains .Net 8 SDK to compile and host the project. There are also instructions to copy the working project to the image, download the dependencies, and compile/publish the output of the project. In the end, it defines an entry point to the binary output of the main project in order to run it.
To be able to connect to the database container, I will need to update Umbraco connection string in "appsettings.Development.json" file as follows:
"ConnectionStrings": {
"umbracoDbDSN": "Server=umbraco_data;Database=UmbracoDb;User Id=UmbracoBlogUser;Password=VeryStrongPassword;TrustServerCertificate=true",
"umbracoDbDSN_ProviderName": "Microsoft.Data.SqlClient"
}
- Use Docker Compose to build and run the containers
In the previous steps, I have defined two Docker images that need to be built and run the corresponding containers - Umbraco Database and Umbraco Web. Let's see how all the above goes together. I will use Docker Compose to deploy both containers using the same network.
Docker Compose is a tool used for defining and running multi-container Docker applications. It allows you to manage the configuration and orchestration of multiple Docker containers with a simple and declarative YAML file. This file, typically named docker-compose.yml, specifies the services (names of the container), networks, volumes, and environment variables required by each container.
In my case, I created a docker-compose.yml file in the main folder of the project.
version: '3.8'
services:
# This service defines Umbraco database container. It exposes a volume for storing SQL data and log files
# outside of the container, written on the physical development machine
umbdata_image:
container_name: umbraco_data
build:
context: ./Umbraco.Database
ports:
- "1433:1433"
- "1434:1434"
volumes:
- umb_database:/var/opt/mssql
networks:
- umbnet
# This service defines Umbraco web container. It exposes port 80 to external port 5000 and stores media and logs
# in a volume to be accessable outside the container. Volume for uSync can also be defined
umbweb_cd_image:
container_name: umbraco_web
build:
context: ./Umbraco.Web
dockerfile: Dockerfile
volumes:
- umb_media:/app/wwwroot/media
- umb_logs:/app/umbraco/Logs
#- umb_usync:/app/uSync
restart: always
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://+:80
# Website is be visible on : http://localhost:5000/
# Umbraco URL is: http://localhost:5000/umbraco
ports:
- "5000:80"
depends_on:
- umbdata_image
networks:
- umbnet
volumes:
umb_logs:
umb_database:
umb_media:
driver: local
driver_opts:
type: 'none'
o: 'bind'
device: c:/Projects/UmbracoOnContainersBlog/Umbraco.Web/wwwroot/media
# This defines the network, that the containers will be using
networks:
umbnet:
driver: bridge
In the Docker compose file I define two services (containers)
- umbraco_data - points to the image I defined earlier in Umbraco.Database Dockerfile
- umbraco_web - points to the image I defined earlier in Umbraco.Web Dockerfile
Between them I create a shared network they will use to communicate with each other. I also create volumes for the database, media, and logs files to have persistent storage (similarly, the same could be done for uSync for example, storing its config files). That would mean that deleting and recreating the containers will not remove the database and media files as they are stored in the physical file system of my PC and not in the container itself.
Now that I have everything described in the docker-compose, it is time to start things up using the following commands:
docker compose build
This command will create the images, described in the docker-compose file. Once completed I can see them in Docker Desktop or by using the “docker images“ command in a terminal.
Docker images:
docker compose up -d
This command will run the containers based on the previously created images. It will also create the volumes for the Umbraco database and images files.
Docker containers:
Docker volumes:
Great, I can browse the Umbraco website on address http://localhost:5000. It uses the Umbraco Web and Database containers and has persistent storage for its database, images, and logs.
What comes next?
I now have the Umbraco CMS application running in containers and setting up a development machine plus local development will be a lot easier than before. This however does not fully deliver all the benefits containers can bring. My next step would be to set up a process for continuous integration and deployment using containers. That involves having an image registry to be able to push new images with tags (versions) and deploy them to target environments. For that, I will use Azure Image Registry and Container Apps and will cover it in the next article.
This process is visualized in the following diagram:
Upcoming events
Drupal CMS Launch Party
Zoals sommigen misschien weten wordt op 15 Januari een nieuwe distributie van Drupal gelanceerd. Namelijk Drupal CMS (ook wel bekend als Starshot). Om dit te vieren gaan we op onze campus een klein eventje organiseren. We gaan die dag samen de livestream volgen waarbij het product gelanceerd wordt. De agenda is als volgt: 17u – 18u30: Drupal CMS livestream met taart 18u30 – 19u00: Versteld staan van de functionaliteiten 19u – 20u: Pizza eten en verder versteld staan van de functionaliteiten Laat ons zeker weten of je komt of niet door de invite te accepteren! Tot dan!
| Coven of Wisdom Herentals
Go to page for Drupal CMS Launch PartyCoven of Wisdom - Herentals - Winter `24 edition
Worstelen jij en je team met het bouwen van schaalbare digitale ecosystemen of zit je vast in een props hell met React of in een ander framework? Kom naar onze meetup waar ervaren sprekers hun inzichten en ervaringen delen over het bouwen van robuuste en flexibele applicaties. Schrijf je in voor een avond vol kennis, heerlijk eten en een mix van creativiteit en technologie! 🚀 18:00 – 🚪 Deuren open 18:15 – 🍕 Food & drinks 19:00 – 📢 Building a Mature Digital Ecosystem - Maarten Heip 20:00 – 🍹 Kleine pauze 20:15 – 📢 Compound Components: A Better Way to Build React Components - Sead Memic 21:00 – 🙋♀️ Drinks 22:00 – 🍻 Tot de volgende keer? Tijdens deze meetup gaan we dieper in op het bouwen van digitale ecosystemen en het creëren van herbruikbare React componenten. Maarten deelt zijn expertise over het ontwikkelen van een volwassen digitale infrastructuur, terwijl Sead je laat zien hoe je 'From Props Hell to Component Heaven' kunt gaan door het gebruik van Compound Components. Ze delen praktische inzichten die je direct kunt toepassen in je eigen projecten. 📍 Waar? Je vindt ons bij iO Herentals - Zavelheide 15, Herentals. Volg bij aankomst de borden 'meetup' vanaf de receptie. 🎫 Schrijf je in! De plaatsen zijn beperkt, dus RSVP is noodzakelijk. Dit helpt ons ook om de juiste hoeveelheid eten en drinken te voorzien - we willen natuurlijk niet dat iemand met een lege maag naar huis gaat! 😋 Over iO Wij zijn iO: een groeiend team van experts die end-to-end-diensten aanbieden voor communicatie en digitale transformatie. We denken groot en werken lokaal. Aan strategie, creatie, content, marketing en technologie. In nauwe samenwerking met onze klanten om hun merken te versterken, hun digitale systemen te verbeteren en hun toekomstbestendige groei veilig te stellen. We helpen klanten niet alleen hun zakelijke doelen te bereiken. Samen verkennen en benutten we de eindeloze mogelijkheden die markten in constante verandering bieden. De springplank voor die visie is talent. Onze campus is onze broedplaats voor innovatie, die een omgeving creëert die talent de ruimte en stimulans geeft die het nodig heeft om te ontkiemen, te ontwikkelen en te floreren. Want werken aan de infinite opportunities van morgen, dat doen we vandaag.
| Coven of Wisdom Herentals
Go to page for Coven of Wisdom - Herentals - Winter `24 editionThe Test Automation Meetup
PLEASE RSVP SO THAT WE KNOW HOW MUCH FOOD WE WILL NEED Test automation is a cornerstone of effective software development. It's about creating robust, predictable test suites that enhance quality and reliability. By diving into automation, you're architecting systems that ensure consistency and catch issues early. This expertise not only improves the development process but also broadens your skillset, making you a more versatile team member. Whether you're a developer looking to enhance your testing skills or a QA professional aiming to dive deeper into automation, RSVP for an evening of learning, delicious food, and the fusion of coding and quality assurance! 🚀🚀 18:00 – 🚪 Doors open to the public 18:15 – 🍕 Let’s eat 19:00 – 📢 First round of Talks 19:45 – 🍹 Small break 20:00 – 📢 Second round of Talks 20:45 – 🍻 Drinks 21:00 – 🙋♀️ See you next time? First Round of Talks: The Power of Cross-browser Component Testing - Clarke Verdel, SR. Front-end Developer at iO How can you use Component Testing to ensure consistency cross-browser? Overcoming challenges in Visual Regression Testing - Sander van Surksum, Pagespeed | Web Performance Consultant and Sannie Kwakman, Freelance Full-stack Developer How can you overcome the challenges when setting up Visual Regression Testing? Second Round of Talks: Omg who wrote this **** code!? - Erwin Heitzman, SR. Test Automation Engineer at Rabobank How can tests help you and your team? Beyond the Unit Test - Christian Würthner, SR. Android Developer at iO How can you do advanced automated testing for, for instance, biometrics? RSVP now to secure your spot, and let's explore the fascinating world of test automation together!
| Coven of Wisdom - Amsterdam
Go to page for The Test Automation Meetup