When Docker
🐳 started to be a thing, I was hesitant 😕 to learn it.
I understood the point and it seemed great, but when I started learning, it was overwhelming 😵.
One day I was sick and tired of watching movies 🎥 on my PC and wanted to watch them on my TV 📺. Before I would just run with my USB around the house and plug it in the TV. It was exhausting 😓 and decided to set up a Plex Media Server on my PC. After a while, I’ve started looking in home server ideas and used up my old laptop 💻, installed Ubuntu and set the home server. That was my starting point for containerizing. It was from that point where I have learned to use Docker. I can’t tell you how much I’m grateful for Docker 🙏.
I want to show you how much with a bit of learning Docker you can make your everyday life a lot easier. 🚀
What is Docker? 🤔
I won’t go into details 📚, there are a plenty of resources on the internet where you can learn more in depth 🌐. I’d say it’s similar concept to virtual machines 💻, but they operate on different level. Virtual machine operates on hardware level where as Docker operates on application level 📱. Docker containers share the host system’s kernel and that’s why they are lightweight and consume less power ⚡. Even though they share same kernel, each container has its own file system 🗂️, process space, and networking 🌐. Because of that reason, when you pack and run your app as a container, you can be sure that it won’t run just on your machine, but on any other as well 🌍.
Prerequisite 📚
It’s an obvious one, you’ll need to install Docker to be able to do run commands on Docker. There are some differences between Windows and Linux, but it’s quite simple for both. Here is the main link.
File, image, container 📁🖼️📦
You’ve started the project, now you want to try it in container? Long story short, you’ll need a docker file
(think of it as a source code),
which will be converted to docker image
(think of it as a final product, binaries) and at some point you’ll run that image, i.e.
A CONTAINER
! I’m .NET developer, so I’ll base docker file
around that, but no worries, it’s applicable to any other language.
# Use the official .NET Core SDK image as the build environment
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY \*.csproj ./
RUN dotnet restore
# Copy everything else and build the application
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/sdk:8.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "YourAppName.dll"]
Here’s a breakdown of the Dockerfile:
-
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
: This line is specifying the base image for the build stage. It’s using the official .NET Core SDK image from Microsoft. -
WORKDIR /app
: This line is setting the working directory in the container to/app
. -
COPY \*.csproj ./
: This line is copying the.csproj
files from your project to the current directory in the container. -
RUN dotnet restore
: This line is restoring the dependencies and tools of the project. -
COPY . ./
: This line is copying the rest of the files from your project to the current directory in the container. -
RUN dotnet publish -c Release -o out
: This line is publishing the application and its dependencies to a folder for deployment to a hosting system. -
FROM mcr.microsoft.com/dotnet/sdk:8.0
: This line is specifying the base image for the runtime stage. It’s using the official .NET Core SDK image from Microsoft. -
WORKDIR /app
: This line is setting the working directory in the container to/app
. -
COPY --from=build-env /app/out .
: This line is copying the published application from the build stage to the current directory in the container. -
ENTRYPOINT ["dotnet", "YourAppName.dll"]
: This line is specifying the command to run when the container starts. It’s running the application.
That’s all that is to dockerfile, you don’t have to remember all the code, but it would be wise to understand each line (There are not that many lines). Now let’s build this thing up.
file -> image
To “compile” this code, you’ll need to know a command, again it’s simple. 🛠️
docker build -t your-image-name
Fun part 🎉
For the fun part, we’ll run some containers. I’ll use PostgreSQL as an example, but feel free to do choose any other image. 🖼️ Find image by googling, postgresql docker image in my example. You’ll probably end up in Docker hub 🌐. Follow the instructions and run command: 🏃♂️
docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres
That’s all that is, now PostgreSQL is running on port 5432 (default port) and all you have to do is to connect.
But what happens if you want to run image on different port or add some configuration?
Here comes the real magic, and it’s called docker compose
. Docker compose is a yaml
file which has cool and easy to follow structure
version: "3.1"
services:
db:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: mysecretpassword
ports:
- 2345:5432
volumes:
- ./data:/var/lib/postgresql/data
This is a simple docker-compose.yml
file. Let’s break it down:
-
version: '3.1'
: This specifies the version of Docker Compose file format. It’s always a good idea to specify the version to ensure compatibility. -
services
: This is the section where you define your services. A service is an application that you want to run in a Docker container. -
db:
: This is the name of the service. You can name it anything you want. In this case, it’s nameddb
because it’s a database service. -
image: postgres
: This tells Docker to use thepostgres
image from Docker Hub for this service. -
restart: always
: This tells Docker to always restart the service if it stops. If it’s manually stopped, it will not be restarted. -
environment
: This is where you can set environment variables for your service. In this case, it’s setting thePOSTGRES_PASSWORD
environment variable. -
POSTGRES_PASSWORD: mysecretpassword
: This sets the password for the PostgreSQL database tomysecretpassword
. -
ports
: This is where you map ports between the host and the container. -
2345:5432
: This maps port2345
on the host to port5432
in the container. This means that the PostgreSQL service can be accessed on the host atlocalhost:2345
. -
volumes:
: This is where you define the data volumes or file system paths to be shared between the host and the container. In this case, ./data on the host is mapped to /var/lib/postgresql/data in the container. This means that the data stored in the database will persist even after the container is stopped or deleted.
At the end, run the command and you are up and running.
docker-compose up -d
Final words 📝
Next steps would be placing your image to Docker registry, but that seemed too much for a blog post. This was a short guide, of course there is a lot more philosophy behind this, but this was enough to run my home server 🏠 or run database or Redis in my everyday work 💼. You can also place docker compose
files in your code and test your app locally with needed infrastructure. Once you’re all done, you can shut all down. Thank you for reading! 👏