Ravindra BagaleCourses & study guides मराठी

Chapter 47: Docker Architecture, Installation on Linux, Windows and Mac, and Docker Desktop Alternatives

47.13 docker init: generate a Dockerfile, Compose file and .dockerignore

Chala mitrano! Writing a Dockerfile for a new project takes a lot of time at first. The 'docker init' command looks at your project and creates a Dockerfile, compose.yaml and .dockerignore. Today we run it on Node, Python and Go projects and understand the files it makes.

1. Start from a blank page

A fresher at Meesho is told to containerize a small Node API by evening. She opens an empty Dockerfile and does not know where to begin: which base image, which user, which port, what to ignore.

docker init is a helper command that asks a few questions about your project and then writes good starting files for you. It does not build or run anything. It only writes files that you can read and change.

It comes with Docker Desktop and with recent Docker Engine installs that include the init plugin. We will check that first.

Your project folderpackage.json, app.py or go.moddocker init askslanguage, version, port, start commandIt writes 4 filesDockerfile, compose.yaml, .dockerignore, README.Docker.mdYou review and rundocker compose up --build
Picture 1: what docker init does

2. Before you start

Step 1: Check that docker init is available

Why: If the plugin is missing, the command simply fails, and learners think Docker is broken.

What: docker init is a CLI plugin. A plugin is an extra command that sits in a plugins folder.

Example 1: Check the version

Type this:

docker init --version

You will see:

Version:    v1.4.0
Git commit: 6d1d8b4

What it means: The plugin is installed. Your version number may differ.

Example 2: When it is missing

Type this:

docker init

You will see:

docker: 'init' is not a docker command.
See 'docker --help'

What it means: Install Docker Desktop, or update Docker Engine from the official repo as in lesson 47.5.

Example 3: See the help

Type this:

docker init --help

You will see:

Usage:  docker init [OPTIONS]
Creates Docker-related starter files for your project

What it means: Short help. The real work is in the questions it asks.

Step 2: Know the languages it supports

Why: You should know what it can detect before you trust it.

What: docker init has templates for Go, Python, Node, Rust, ASP.NET Core, PHP with Apache, Java, and an Other option for a generic file.

Example 4: Run it in an empty folder

Type this:

mkdir empty && cd empty
docker init

You will see:

? What application platform does your project use?
  Go
  Python
  Node
  Rust
  ASP.NET Core
  PHP with Apache
  Java
> Other

What it means: In an empty folder it cannot detect anything, so it asks you.

Example 5: Let it detect

Type this:

cd ../shop-api && ls
docker init

You will see:

package.json  server.js
? What application platform does your project use? Node (detected)

What it means: It saw package.json and guessed Node.

Example 6: Leave without writing

Type this:

(press Ctrl+C at any question)

You will see:

^C
(no files written)

What it means: Nothing is written until you answer every question.

3. A Node API

Step 3: Answer the questions

Why: A Paytm team wants every service to start the same way.

What: docker init asks for the version, the package manager, the start command and the port. Each answer goes into the files.

Example 7: Make a tiny app

Type this:

mkdir shop-api && cd shop-api
npm init -y > /dev/null
npm install express@4 > /dev/null
printf 'const e=require("express")();\ne.get("/",(q,r)=>r.send("Paytm shop API"));\ne.listen(3000);\n' > server.js
ls

You will see:

node_modules  package-lock.json  package.json  server.js

What it means: A real project with a lock file.

Example 8: Run docker init

Type this:

docker init

You will see:

? What application platform does your project use? Node
? What version of Node do you want to use? 20
? Which package manager do you want to use? npm
? What command do you want to use to start the app? node server.js
? What port does your server listen on? 3000
CREATED: .dockerignore
CREATED: Dockerfile
CREATED: compose.yaml
CREATED: README.Docker.md

What it means: Four files are created.

Example 9: See the files

Type this:

ls -a

You will see:

..  .dockerignore  Dockerfile  README.Docker.md  compose.yaml  node_modules  package-lock.json  package.json  server.js

What it means: README.Docker.md has short notes on how to build and deploy.

Step 4: Read the generated Dockerfile

Why: Never run a file you have not read.

What: The generated Dockerfile uses a small base image, installs only production packages, and runs as a normal user, not root.

Example 10: Look at the important lines

Type this:

grep -E '^(FROM|ENV|RUN|USER|COPY|EXPOSE|CMD)' Dockerfile

You will see:

FROM node:20-alpine
ENV NODE_ENV production
RUN --mount=type=bind,source=package.json,target=package.json \
USER node
COPY . .
EXPOSE 3000
CMD node server.js

What it means: alpine keeps it small. USER node means it does not run as root. EXPOSE notes the port.

Example 11: The cache mount line

Type this:

grep -A3 'RUN --mount' Dockerfile

You will see:

RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev

What it means: A cache mount keeps the npm download cache between builds, so the second build is faster.

Example 12: Comments explain each part

Type this:

grep -c '^#' Dockerfile

You will see:

22

What it means: Many comment lines. Read them; they teach good habits.

Step 5: Read .dockerignore and compose.yaml

Why: A big build context makes builds slow and can leak files into the image.

What: .dockerignore lists files Docker must not send to the build. compose.yaml describes how to run the app.

Example 13: The ignore list

Type this:

grep -v '^#' .dockerignore | grep -v '^$' | head -6

You will see:

**/.git
**/.env
**/node_modules
**/Dockerfile*
**/compose*
README.md

What it means: node_modules and .env stay out. Your local secrets never enter the image.

Example 14: The compose file

Type this:

grep -v '^ *#' compose.yaml | grep -v '^$'

You will see:

services:
  server:
    build:
      context: .
    environment:
      NODE_ENV: production
    ports:
      - 3000:3000

What it means: One service named server, built from this folder, on port 3000.

Example 15: Commented database example

Type this:

grep -c 'db:' compose.yaml

You will see:

2

What it means: A Postgres example is included as comments. Remove the # marks when you need it.

Step 6: Build and run with Compose

Why: Now we check that the files actually work.

What: docker compose up --build builds the image and starts the service.

Example 16: Start it

Type this:

docker compose up --build -d

You will see:

[+] Building 14.2s (12/12) FINISHED
[+] Running 2/2
 ✔ Network shop-api_default     Created
 ✔ Container shop-api-server-1  Started

What it means: Built and running in the background.

Example 17: Test it

Type this:

curl -s localhost:3000

You will see:

Paytm shop API

What it means: The API answers from the container.

Example 18: Check the user and size

Type this:

docker compose exec server whoami
docker images shop-api-server --format '{{.Size}}'

You will see:

node
141MB

What it means: It runs as node, not root, and the image is small.

4. Python and Go

Nodenode:20-alpine, npm ciPythonpython:3.12-slim, pip, gunicornGotwo stages, tiny final imageAllnon-root user and .dockerignore
Picture 2: same command, different languages

Step 7: A Python Flask app

Why: Data teams at Swiggy write small Python APIs every week.

What: For Python, docker init asks for the version, the port and the start command, and uses requirements.txt.

Example 19: Make the app

Type this:

mkdir menu && cd menu
printf 'flask==3.0.3\ngunicorn==22.0.0\n' > requirements.txt
printf 'from flask import Flask\napp=Flask(__name__)\n@app.get("/")\ndef h(): return "Swiggy menu"\n' > app.py

You will see:

(no output)

What it means: Two files: dependencies and code.

Example 20: Run docker init

Type this:

docker init

You will see:

? What application platform does your project use? Python
? What version of Python do you want to use? 3.12
? What port do you want your app to listen on? 8000
? What is the command you use to run your app? gunicorn 'app:app' --bind=0.0.0.0:8000
CREATED: Dockerfile ...

What it means: gunicorn is a production web server for Python.

Example 21: Build and test

Type this:

docker compose up --build -d
curl -s localhost:8000

You will see:

Swiggy menu

What it means: Same flow, different language.

Step 8: A Go service

Why: Go services at companies like Zerodha are known for tiny images.

What: For Go, docker init writes a multi-stage Dockerfile: one stage compiles, a second small stage only runs the program.

Example 22: Make the app

Type this:

mkdir quote && cd quote
go mod init quote
printf 'package main\nimport ("fmt";"net/http")\nfunc main(){http.HandleFunc("/",func(w http.ResponseWriter,r *http.Request){fmt.Fprint(w,"Zerodha quote")});http.ListenAndServe(":8080",nil)}\n' > main.go

You will see:

go: creating new go.mod: module quote

What it means: A one-file web server.

Example 23: See the two stages

Type this:

docker init   # answer Go, 1.23, ., 8080
grep -E '^FROM' Dockerfile

You will see:

FROM --platform=$BUILDPLATFORM golang:1.23 AS build
FROM alpine:latest AS final

What it means: Stage one has the Go compiler; stage two does not.

Example 24: Compare sizes

Type this:

docker compose up --build -d
docker images quote-server --format '{{.Size}}'
curl -s localhost:8080

You will see:

19.8MB
Zerodha quote

What it means: Under 20 MB, because the compiler is not in the final image.

5. Make it yours

Step 9: When files already exist

Why: Running docker init in a project that already has a Dockerfile could overwrite your work.

What: docker init warns you and asks before it overwrites anything.

Example 25: Run it again

Type this:

docker init

You will see:

WARNING: The following Docker files already exist in this directory:
  - Dockerfile
  - compose.yaml
? Do you want to overwrite them? No

What it means: Answer No to keep your files.

Example 26: Back up first

Type this:

cp Dockerfile Dockerfile.mine
docker init   # answer Yes to overwrite
diff Dockerfile.mine Dockerfile | head -3

You will see:

5c5
< FROM node:18
> FROM node:20-alpine

What it means: Now you can compare and keep the best parts.

Example 27: Keep files in Git

Type this:

git add Dockerfile compose.yaml .dockerignore
git commit -m 'Add Docker files'

You will see:

[main 3e4f5a6] Add Docker files
 3 files changed, 98 insertions(+)

What it means: Commit them so the whole team uses the same files.

Step 10: Edit the generated files

Why: Generated files are a start, not the final answer.

What: Common changes: pin the base image version, add a health check, and add a database service.

Example 28: Pin the base image

Type this:

sed -i 's/FROM alpine:latest AS final/FROM alpine:3.20 AS final/' Dockerfile
grep 'AS final' Dockerfile

You will see:

FROM alpine:3.20 AS final

What it means: latest can change any day. A fixed tag keeps builds repeatable.

Example 29: Add a health check

Type this:

printf 'HEALTHCHECK --interval=30s CMD wget -qO- localhost:8080 || exit 1\n' >> Dockerfile
docker compose up --build -d
sleep 35; docker ps --format '{{.Names}} {{.Status}}'

You will see:

quote-server-1 Up 40 seconds (healthy)

What it means: Docker now checks the app every 30 seconds.

Example 30: Enable the database block

Type this:

grep -n '# *db:' compose.yaml

You will see:

22:#   db:

What it means: Remove the # marks from that block to add Postgres, then add a password through a secret file, never in the file itself.

Step 11: Clean up

Why: Three practice apps are running now.

What: docker compose down stops and removes the containers and network of one project.

Example 31: Stop each project

Type this:

cd ~/shop-api && docker compose down

You will see:

[+] Running 2/2
 ✔ Container shop-api-server-1  Removed
 ✔ Network shop-api_default     Removed

What it means: Run it in each project folder.

Example 32: Remove images too

Type this:

docker compose down --rmi local

You will see:

✔ Image quote-server Removed

What it means: --rmi local removes images that Compose built.

Example 33: Check

Type this:

docker ps --format '{{.Names}}'

You will see:

(no output)

What it means: Nothing is left running.

Ravindra Bagale's Tip

Files made by docker init are a starting point. Pin the base image version, add a health check, and never write passwords in compose.yaml.

Check yourself

Q1. Does docker init build or run anything?

No. It only writes starter files.

Q2. Which four files does it create?

Dockerfile, compose.yaml, .dockerignore and README.Docker.md.

Q3. Why does the generated Dockerfile use USER?

So the app does not run as root.

Q4. Why is the Go image so small?

It uses two stages; the final stage has no compiler.

Q5. What happens if a Dockerfile already exists?

docker init warns you and asks before overwriting.

Friends, docker init makes the start easy, but reading and understanding the files is our job. Try it on Node, Python and Go. Did you understand? Let us try it once more. If not, look at Picture 1 again.

Lab: try at home

  1. Check docker init --version on your machine.
  2. Create the Node API and run docker init, then read every comment in the Dockerfile.
  3. Do the same for the Python and Go apps and compare image sizes.
  4. Pin the base image and add a HEALTHCHECK, then see the (healthy) status.
  5. Run docker init again and answer No to keep your files.

Recap

  • docker init writes Dockerfile, compose.yaml, .dockerignore and README.Docker.md.
  • It detects Node, Python, Go and more.
  • Generated files use small images and a non-root user.
  • Always read, pin versions and add health checks.
  • Commit the files so the team shares them.

Ravi Sir's Cards for this lesson

मराठी cards