[Quick Bytes] Get going with containers in seconds with docker-init
Welcome folks to a new series where we quickly dwell on some interesting topics in short.
So, given my love ️️ for #docker for this series I am starting with Docker-init. let's dive in!
What is docker init?
As per official docker terminology: Docker Desktop provides the docker init
CLI command. Run docker init
in your project directory to be walked through the creation of the following files with sensible defaults for your project.
(Note: You will still need modification as per your custom needs but here we are looking how it cut-short most of the mudane work :D)
In simple words no more time spending with creating docker setup files manually. Just run the docker-init command & answer some quick yes and no and you will end up with barebone setup for your application. It will automatically create below files with best of the configuration default options available.
- .dockerignore
- Dockerfile
- compose.yaml
- README.Docker.md
Sounds cool, no? specially if you have come from the background where you have to search for effective base image and the do the setup, do configuration updates, make effective performant defaults and so on…
Let's see something in action.
I am using a very basic node application. Below is my steup which we will containerize.
Let's start with docker-init. Head to terminal and type ‘docker-init’
> docker-init
It will produce the similar output to the below one based on your input.
As you can see, I just followed some simple yes and no questions and hoila we ended up with all required files. The command also effectively suggests smart suggestions like setting up your port and start command.
Now let's look into the files generated.
Docker file:
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker compose reference guide at
# https://docs.docker.com/compose/compose-file/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
environment:
NODE_ENV: production
ports:
- 3000:3000
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker-compose up`.
depends_on:
db:
condition: service_healthy
db:
image: postgres
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
With the above docker-compose setup in place, our application is already start making use of multi-container docker-application.
Note: The default file generated with docker-compose had the db service commented but since we are doing a demo of the CRUD operations, I have uncommented it. docker-compose assumed since we are building a node js app we might need database connectivity and suggested pg sql service setup as default. You are free to choose your own.
Package.json
Below is my package json file that shows packages we are using in this sample app. Noting fancy.
{
"name": "dockerinit-demo",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"keywords": [],
"description": "",
"dependencies": {
"date-and-time": "^3.4.1",
"express": "^4.19.2",
"postgres": "^3.4.4"
},
"type": "module"
}
And finally, the index file with basic crud operations with express app.
Index.js
import express from 'express';
import bodyParser from 'body-parser';
import sql from './db/db.js'; // Import the SQL module
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.send('Hello world : Express-pgsql-docker-init demo!');
})
// Route to create a table if not exists
app.post('/create-table', async (req, res) => {
try {
const createTableQuery = `
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100) UNIQUE
);
`;
await sql.unsafe(createTableQuery);
res.send('Table "users" created or already exists.');
} catch (error) {
console.error('Error creating table:', error);
res.status(500).send('Error creating table.');
}
});
// Route to list all tables
app.get('/list-tables', async (req, res) => {
try {
const result = await sql`
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name;
`;
res.json(result);
} catch (error) {
console.error('Error listing tables:', error);
res.status(500).send('Error listing tables.');
}
});
// Route to insert a value
app.post('/create-user', async (req, res) => {
const { name, email } = req.body;
try {
await sql`
INSERT INTO users (name, email)
VALUES (${name}, ${email});
`;
res.send('Value inserted successfully.');
} catch (error) {
console.error('Error inserting value:', error);
res.status(500).send('Error inserting value.');
}
});
// Route to delete a value by id
app.get('/delete-user/:id', async (req, res) => {
const { id } = req.params;
try {
await sql`
DELETE FROM users
WHERE id = ${id};
`;
res.send('Value deleted successfully.');
} catch (error) {
console.error('Error deleting value:', error);
res.status(500).send('Error deleting value.');
}
});
// Route to list all values
app.get('/get-users', async (req, res) => {
try {
const result = await sql`
SELECT * FROM users;
`;
res.json(result);
} catch (error) {
console.error('Error listing values:', error);
res.status(500).send('Error listing values.');
}
});
app.listen(port, () => {
console.log(`App is listening on port ${port}`);
});
Note: for simplicity I have written the code in index file iteself. in real world applications you will have their own dedicated model and controllers.
db.js
In this file we add snipped that help us to connect pgsql with node.
}Important : Notice the url, we are using ‘db’ instead of ‘localhost’ what we had specified in compose.yaml file.
import postgres from 'postgres';
const sql = postgres('postgres://postgres:mypassword@db:5432/example', {
host: 'db',
port: 5432,
database: 'example',
username: 'postgres',
password: 'mypassword',
});
export default sql;
With this basis codebase, I was able to setup the entire application in mere 15 mins!
So, for the next time you want to quickly boot up with docker app don’t forget ‘docker-init’ for rescue!
Code for the demo can be found here
https://github.com/shirkerohit/dockerinit-demo
Hope this was fun and short reading!
Cheers to coding… Seeya in next! :D