Docker is the most popular development platform for building and running containers. It’s redefined how software is built and deployed, but many teams still struggle with correctly configuring their projects for Docker support.
Fortunately, there’s now a solution available: modern Docker releases include the docker init
command, a feature that lets you quickly add Docker to a project by creating a standard set of config files that are appropriate for your programming language. This saves time and increases consistency when you’re Dockerizing a new application.
We’ll explore docker init
in this article by discussing when it’s useful and showing how to get started.
We’ll cover:
The docker init
command is a utility that automates the process of enabling a project to be built and run with Docker. It allows you to hit the ground running, without having to first learn how to write Docker’s config files.
Before an app can be run in a Docker container, it must first be built into a Docker image. Images package your code and dependencies into portable units that define your container’s initial filesystem. Images are created from Dockerfiles that contain instructions listing the files to copy and commands to run in order to assemble the filesystem.
Dockerfiles can become quite complex, even for relatively simple apps. Your Dockerfile will typically need to include the following steps:
- Select or assemble an appropriate base image that provides your container’s OS and programming runtime—such as ubuntu:22.04 or node:20.
- Install any additional OS packages, programming languages, and frameworks your project requires.
- Fetch your project’s programming language dependencies (e.g., by using npm, Rust, or Gradle).
- Copy in your source code.
- Perform any filesystem or environment changes that are required by your app.
Docker init provides a set of Dockerfile templates that include these steps and other best practices with support for ASP.NET, Go, Node, Python, and Rust server applications (compatibility with Java and PHP apps is also planned). When you use Docker init, a ready-to-use Dockerfile and other resources are added to your project, allowing you to immediately build your image and start a container.
What files does Docker init create?
Running docker init currently adds three files to your project:
Dockerfile
— This is the file that describes how to build your image’s filesystem. It includes the best practices and common requirements of the programming language you’re using.compose.yaml
— This is a Docker Compose configuration file that lets you start your app and its dependencies (such as database connections) as a stack of multiple independent containers..dockerignore
—.dockerignore files
are used to specifically exclude paths in your project that don’t need to be involved in image builds. They improve build performance by preventing wasteful copies of redundant content to the Docker daemon that performs the build. Docker init automatically excludes common paths, such as dependency folders, that will be automatically recreated when package manager install commands are run during your build.
These three files give you everything you need to containerize simple apps.
docker init
vs docker-init
A potential source of confusion for docker init
users is the command’s obvious similarity to docker-init
, a standalone binary that’s used as the default init process for new containers.
docker init
and docker-init
are entirely separate tools. You can use docker init
to scaffold your configuration in new Docker projects, while docker-init
is a Docker-internal utility that you shouldn’t ever need to manually invoke.
Docker Init is helpful in several real-world development scenarios:
- Quickly bootstrap new projects: You can quickly bootstrap new apps and services by using
docker init
to create your Dockerfile and associated resources. This saves time and improves consistency across your project inventory. - Add Docker to existing projects, with sensible defaults: You can use Docker init to efficiently configure legacy projects for use with Docker, even when they’re written in varying programming languages.
docker init
will ensure appropriate settings are always used. - Learn how to use Docker with additional programming languages: Perhaps you’re already comfortable writing Dockerfiles for Python apps, but what if you’re now tasked with launching a Go service? Inspecting the output of
docker init
is a quick way to learn the basics of how to Dockerize apps written in any of the languages that the tool supports. - Save time and automate more project management tasks: Overall,
docker init
can save you time and reduce the amount of work involved with software project management. You might still need to alter the files it creates, but having a ready-to-run starting point is often preferable to assembling your Docker configuration from scratch each time.
Now let’s look at an example of how to use Docker init to containerize a simple application.
As mentioned above, Docker Init currently supports ASP.NET, Go, Node, Python, and Rust. There’s also an “Other” option that provides a generic starting point for other types of app—we’ll discuss this later on.
We’ll now use Docker Init to Dockerize a Node.js project. You’ll need to have Docker and Node.js already installed on your machine to follow along with this tutorial.
1. Install Docker init
Docker init is implemented as a Docker CLI plugin. It’s included with Docker Desktop versions v4.18 and later. Docker init isn’t currently included in Docker Engine, and there’s no supported manual installation method. Therefore, you must be using Docker Desktop in order to use the docker init
command.
2. Create a minimal Node.js app
To begin, navigate to a new directory for the files you’ll create in this guide. Then, copy the following Node.js app and save it as main.js
in your directory:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Node.js demo app using Express.");
});
app.listen(3000, () => {
console.log("App is listening.");
});
The app starts an Express web server on port 3000. It serves a single route (/
) that sends a basic message in its response.
Run the following command to install the Express dependency in your project using npm:
$ npm install express
Now you’re ready to containerize your app.
3. Use Docker init to containerize your app
docker init
is an interactive command that doesn’t require any flags. Instead, you’ll be prompted to answer a series of questions to configure your app.
First, run docker init
within your working directory—you’ll see some initial help text, followed by a prompt to select the application platform you’re using:
$ docker init
Welcome to the Docker Init CLI!
This utility will walk you through creating the following files with sensible defaults for your project:
- .dockerignore
- Dockerfile
- compose.yaml
Let's get started!
? What application platform does your project use? [Use arrows to move, type to filter]
> Node - (detected) suitable for a Node server application
Go - suitable for a Go server application
Python - suitable for a Python server application
Rust - suitable for a Rust server application
ASP.NET Core - suitable for an ASP.NET Core application
Other - general purpose starting point for containerizing your application
You can see that the Node
project type has been automatically detected for our sample app. Press the enter key to accept it.
Next, you’ll be asked which version of Node.js you’re using:
? What version of Node do you want to use? (18.16.0)
The default selection will match the Node.js version that’s detected on your machine—18.16.0 in this case. You can press enter to accept the default or type a new version number instead. If you specify a particular version, it must have a matching Docker image available on Docker Hub.
Next, you’ll be asked to identify the package manager you’re using—npm should be auto-detected so you can immediately press enter to continue:
? Which package manager do you want to use? [Use arrows to move, type to filter]
> npm - (detected)
yarn
pnpm
The next prompt requires you to enter the command that will be used to run your app when containers start:
? What command do you want to use to start the app? [tab for suggestions]
For this tutorial, the sample code is saved as main.js
so you should use node main.js
as your command. This will run your application using the node
binary found in the container and your main.js source code. The Docker Init-generated Dockerfile automatically copies your source into the container’s working directory.
Finally, you need to tell Docker what port your app is configured to listen on. This is 3000
in this tutorial.
? What port does your server listen on?
You should then see a confirmation that your three Docker config files have been created:
CREATED: .dockerignore
CREATED: Dockerfile
CREATED: compose.yaml
✔ Your Docker files are ready!
4. Run your app
Now that you’ve used Docker Init to containerize your project, you can go ahead and run your app with Docker.
It’s easiest to use Docker Compose to both build your image, then start a container in a single command:
$ docker compose up --build
[+] Building 50.1s (13/13) FINISHED docker:default
(truncated)
[+] Running 2/2
✔ Network spl-docker-init_default Created 0.2s
✔ Container spl-docker-init-server-1 Created 0.3s
Attaching to spl-docker-init-server-1
spl-docker-init-server-1 | App is listening.
You’ll see verbose logs in your terminal as Docker builds your image’s filesystem layers; it’ll then create your container and attach it to its foreground process so you can see your app’s logs.
Now you should be able to reach the app at localhost:3000
:
$ curl http://localhost:3000
Node.js demo app using Express.
That’s it—you’ve successfully generated Docker config files, built your image, and run your app!
How to containerize other types of applications?
It’s best to use the language-specific template provided by docker init
when possible. However, if your app’s not supported—or you’d prefer to have a less guided experience—you can select the “Other” template type at the first prompt.
Choosing “Other” will write minimal Dockerfile
, compose.yaml
, and .dockerignore
files that are ready for you to customize. They’re a good way to familiarize yourself with Docker basics and best practices because the generated output is well-documented and includes tips, explanations, and optional capabilities you can enable by uncommenting sections of the files. For example, there’s a ready-to-use example of how to deploy a PostgreSQL database connection alongside your app available in the default compose.yaml
.
docker init
is a relatively simple command, but there are still a few points to keep in mind when using it:
1. Provide accurate answers to the Docker init prompts
When you’re using one of the language-specific app templates, as in this tutorial, it’s important you supply correct answers to all the terminal prompts you’re displayed. Otherwise, the generated configuration might not be compatible with your project, and you’ll see errors when you try to build or run your image.
2. Analyze whether the default base image is suitable for your app
A suitable base image will be automatically selected for your project, based on the inputs you supply. However, this might need to be adjusted if the base image’s operating system or version doesn’t match your app’s requirements. For example, the Node.js template uses Alpine-based images, but your project could depend on a Debian environment. You can change the base image by modifying the FROM
instruction that’s near the top of the generated Dockerfile.
3. Customize generated files after creation to match your use case
docker init provides a useful starting point but you may have to customize the generated files if your app has additional requirements, such as other containerized service dependencies that should be included in your Compose stack.
4. Be careful when using Docker init with existing projects
docker init
can be used with existing projects—and is a quick way to make them Docker-compatible—but care should be taken if you’ve already made previous efforts to add Docker support. You’ll be warned if an existing file will be overwritten by the command’s output; in that case, it can be best to consult other team members to check whether the file is already updated and ready to use.
5. Ensure all team members understand what Docker init is doing
docker init
is a good way to familiarize new team members with Docker, without making them learn the entire image authoring workflow. However, it’s important that everyone understands what the command is doing (outputting language-specific templates) and how it fits into the Docker ecosystem.
These points will ensure you can utilize Docker Init without encountering issues in the future.
In this article, we’ve looked at how Docker init lets you automate initial Docker configuration in your projects. It writes a Dockerfile
, compose.yaml
, and .dockerignore
for you, lowering the learning curve and accelerating setup time. Note that while we’ve focused on using Docker Init with Node.js, the interactive prompt steps are similar for the other supported programming languages too.
Docker Init is a convenient tool but its output won’t always be suitable to use as-is. More advanced projects will still require customization of your Dockerfile, such as to install any extra dependencies you require, or to make changes to the base image that’s used. Similarly, you may have to modify your Docker Compose compose.yaml
file to add any extra services that you require.
Looking for more help to master Docker? Check out the other content on the Spacelift blog, such as this Docker cheat sheet for Docker CLI commands.
We encourage you also to explore how Spacelift offers full flexibility when it comes to customizing your workflow. You have the possibility of bringing your own Docker image and using it as a runner to speed up the deployments that leverage third party tools. Spacelift’s official runner image can be found here.
The Most Flexible CI/CD Automation Tool
Spacelift is an alternative to using homegrown solutions on top of a generic CI. It helps overcome common state management issues and adds several must-have capabilities for infrastructure management.