Containerizing applications offers a convenient and flexible way to quickly deploy software, including web servers, databases, monitoring systems, and others. Containers are also widely used in microservices architectures. Docker is ideal for these purposes, as it greatly simplifies working with containerized apps. Introduced in 2013, Docker has seen continuous support and usage ever since.
In this tutorial, you’ll learn how to create Docker images for three different applications written in different programming languages and how to run Docker containers from these images.
To work with the Docker platform, you’ll need:
At the core of Docker’s concept is the image. A Docker image is a template—an executable file—you can use to start a Docker container. It contains everything needed to launch a ready-to-run application: source code, configuration files, third-party software, utilities, and libraries.
Docker image architecture is layer-based. Each layer represents an action performed during the image build process, such as creating files and directories or installing software. Docker uses the OverlayFS file system, which merges multiple mount points into one, resulting in a unified directory structure.
You can move Docker images between systems and use them in multiple locations, much like .exe executables in Windows systems.
Let’s walk through how to create Docker images for Flask, Node.js, and Go applications.
To create images, a Dockerfile is used. Dockerfile is a plain text file without an extension that defines the steps to build a container image. You can find more details about Dockerfile instructions in the official documentation.
We’ll create a Docker image with a web application built with Flask and run the container. The application will show a basic HTML page that displays the current date.
Install the pip
package manager and python3-venv
for managing virtual environments:
apt -y install python3-pip python3-venv
mkdir dockerfile-flask && cd dockerfile-flask
python -m venv env
source env/bin/activate
After activation, you'll see (env) in your prompt, indicating the virtual environment is active. Packages installed via pip will now only affect this environment.
pip install flask
pip install MarkupSafe==2.1.5
5. Create the Flask Application
Create a file named app.py
that will store the source code of our application:
from flask import Flask
import datetime
app = Flask(__name__)
@app.route('/')
def display_current_date():
current_date = datetime.datetime.now().date()
return f"Current date is: {current_date}"
if __name__ == '__main__':
app.run(debug=True)
flask run --host=0.0.0.0 --port=80
In your browser, visit your server’s IP address (port 80 doesn’t need to be specified as it’s the default one). You should see today’s date.
Now, we need to save all the dependencies (just the flask package in our case) to a requirements.txt file, which stores all packages used in the project and installed via pip.
pip freeze > requirements.txt
Your project structure should now look like this:
dockerfile-flask/
├── app.py
├── env/
├── requirements.txt
Now we can proceed to creating a Docker image.
Create a file named Dockerfile
with the following contents:
FROM python:3.8-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD [ "python3", "-m", "flask", "run", "--host=0.0.0.0", "--port=80" ]
Explanation:
FROM python:3.8-slim-buster
: Use Python 3.8 base image on a lightweight Debian Buster base.WORKDIR /app
: Set the working directory inside the container (similar to the mkdir
command in Linux systems)COPY requirements.txt requirements.txt
: Copy the dependency list into the image.RUN pip3 install -r requirements.txt
: The RUN
directive runs the commands in the image. In this case, it’s used to install dependencies.COPY . .
: Copy all project files into the container.CMD [...]
: CMD
defines the commands and app parameters to be used when the container starts.Create a .dockerignore
file to exclude unnecessary directories. It helps to decrease the image size.
In our case, we have two directories that we don’t need to launch the app. Add them to the .dockerignore
file:
env
__pycache__
When building the image, we need to use a tag that would work as an identifier for the image. We’ll use the flask-app:01
tag.
docker build -t flask-app:01 .
The dot at the end means the Dockerfile
is located in the same directory where we run the command.
Check the created image:
docker images
docker run -d -p 80:80 flask-app:01
-d
: Run the container in the background.
-p
: Forward host port 80 to container port 80.
Check running containers:
docker ps
The STATUS
column should show “Up
”.
Open your browser and navigate to your server's IP address to view the app.
Our simple Node.js app will display the message: “This app was created using Node.js!”
Make sure you have Node.js installed on your system.
mkdir dockerfile-nodejs && cd dockerfile-nodejs
npm init --yes
npm install express --save
Create app.js
with the following code:
const express = require("express");
const app = express();
app.get("/", function(req, res) {
return res.send("This app was created using Node.js!");
});
app.listen(3000, '0.0.0.0', function(){
console.log('Listening on port 3000');
});
5. Test the Application
node app.js
Open http://<your-server-ip>:3000
in a browser to verify it works.
FROM node:20
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
CMD ["node", "app.js"]
Create .dockerignore
and the following line:
**/node_modules/
docker build -t nodejs-app:01 .
docker run -d -p 80:3000 nodejs-app:01
Visit http://<your-server-ip>
in your browser. The app should be running.
This Go application will display: “Hello from GO!”
Make sure you have Go installed in your system.
mkdir dockerfile-go && cd dockerfile-go
go mod init go-test-app
Create main.go
with this code of our application:
package main
import "fmt"
func main() {
fmt.Println("Hello from GO!")
}
Verify it works:
go run .
FROM golang:1.23-alpine
WORKDIR /app
COPY go.mod ./
RUN go mod download
COPY *.go ./
RUN go build -o /go-test
CMD [ "/go-test" ]
COPY go.mod ./
: Adds dependencies file.RUN go mod download
: Installs dependencies.COPY *.go ./
: Adds source code.RUN go build -o /go-test
: Compiles the binary.docker build -t go:01 .
docker run go:01
You should see the output: Hello from GO!
In this guide, we walked through building custom Docker images for three applications written in different programming languages. Docker allows you to package any application and deploy it with ease.