Makefile is part of GNU which is free software can be used as part of OS
make should be installed default in linux
makefile tutorial:
https://makefiletutorial.com/
make file origin usage is to target file with or without prerequiests, and run some commands:
Makefile Syntax
A Makefile consists of a set of rules. A rule generally looks like this:
targets: prerequisites
command
command
command
The essence of Make
Let's start with a hello world example:
hello:
echo "Hello, World"
echo "This line will print if the file hello does not exist."
There's already a lot to take in here. Let's break it down:
We have one target called hello
This target has two commands
This target has no prerequisites
We'll then run make hello. As long as the hello file does not exist, the commands will run. If hello does exist, no commands will run.
It's important to realize that I'm talking about hello as both a target and a file. That's because the two are directly tied together. Typically, when a target is run (aka when the commands of a target are run), the commands will create a file with the same name as the target. In this case, the hello target does not create the hello file. like below example:
blah: cc blan.c -o blah
Let's create a more typical Makefile - one that compiles a single C file. But before we do, make a file called blah.c that has the following contents:
// blah.c
int main() { return 0; }
Then create the Makefile (called Makefile, as always):
blah:
cc blah.c -o blah
This time, try simply running make. Since there's no target supplied as an argument to the make command, the first target is run. In this case, there's only one target (blah). The first time you run this, blah will be created. The second time, you'll see make: 'blah' is up to date. That's because the blah file already exists. But there's a problem: if we modify blah.c and then run make, nothing gets recompiled.
We solve this by adding a prerequisite:
blah: blah.c
cc blah.c -o blah
When we run make again, the following set of steps happens:
The first target is selected, because the first target is the default target
This has a prerequisite of blah.c
Make decides if it should run the blah target. It will only run if blah doesn't exist, or blah.c is newer than blah
.phony:
https://dev.to/alexandrunastase/whats-the-meaning-of-phony-in-a-makefile-406k
.PHONY is used to mark a target as phony. That means a target that doesn't take into consideration for execution any file that matches its name.
Let's say we have a target called clear-cache, which removes the cache of an application
clear-cache:
rm -rf cache/*
Which results in the following command:
The cache removal cli command will be run fine most of the time, but let's check what happens if we add a file with the same name as the target at the same level as the Makefile
Now when running make clear-cache again we get:
The Makefile says basically that it has the target file already and doesn't need
to execute
This default behavior is not what we expect in this case and we want to override it. This is when the .PHONY directive comes to the rescue. Let's update our example to use it
.PHONY: clear-cache
clear-cache:
rm -rf cache/*makefile usage with docker, docker-compose :
https://medium.com/freestoneinfotech/simplifying-docker-compose-operations-using-makefile-26d451456d63#:~:text=Our%20makefile%20will%20contain%20native,container%2C%20tail%20container%20logs%20etc.
we use makefile with docker-compose when we want to do different things with docker containers and we want to autmoate the process instead of typing docker-compose up, docker exec <container_name> /bin/bash after docker containers are up:
The makeprogram is basically an automation tool for building programs and libraries from source code. Generally though, makeis applicable to any process that involves executing arbitrary commands to transform a source command to a target result. We will specifically use the PHONY targets feature of make to control docker-compose commands.
To tell make what to do, we need a file called a makefile
Our makefile will contain native dockerand docker-compose commands to build image, start/stop/restart container, login to the container, tail container logs etc.
A typical use-case
Let us assume a standard web application with the following components.
- Timescaledb (postgres)
- ExpressJs app
- Ping ( just a dummy container )
This app will need 3 docker containers and a docker-compose file over these containers. Now, each of these containers will have different interaction points. For e.g. timescaledb might have db-like interactions:
- Login to the postgres shell
- Import/Export a table
- Take a
pg_dumpof table/database
Similarly expressjs might have the following app-like interactions:
taila log fileloginto the shell to run some command
Interacting with the containers
Once we have the containers linked using Docker Compose, the next steps are to actually interact with them. Docker Compose provides a docker-compose command and a -f option to take a docker-compose.yml file.
Using this switch we can restrict our interactions to only the containers that are there in the docker-compose.yml file.
Let us look at how these interactions happen using the docker-compose commands. Suppose, we want to login to psql shell, the command might look like:
docker-compose -f docker-compose.yml exec timescale psql -UpostgresThe same command, without using docker-compose, but using the docker might look like:
docker exec -it edp_timescale_1 psql -UpostgresNote: It is always better to use docker-compose over docker in such cases, since you dont need to remember the container names.
However, if we have a Makefile wrapper, that exposes a simple command and internally calls these commands, it will look like:
make db-shellIt's very clear how concise the command is using the Makefile wrapper!
Working example
Using our typical use-case above, we can create a docker-compose file as follows:
version: '3.3'
services:
api:
build: .
image: mywebimage:0.0.1
ports:
- 8080:8080
volumes:
- /app/node_modules/
depends_on:
- timescale
command: npm run dev
networks:
- webappnetwork
timescale:
image: timescale/timescaledb-postgis:latest-pg11
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
command: ["postgres", "-c", "log_statement=all", "-c", "log_destination=stderr"]
volumes:
- ./create_schema.sql:/docker-entrypoint-initdb.d/create_schema.sql
networks:
- webappnetwork
ping:
image: willfarrell/ping
environment:
HOSTNAME: "localhost"
TIMEOUT: 300
networks:
webappnetwork:
driver: bridgeTo manage the above docker-compose and interact with its various containers, we create the following makefile
THIS_FILE := $(lastword $(MAKEFILE_LIST))
.PHONY: help build up start down destroy stop restart logs logs-api ps login-timescale login-api db-shell
help:
make -pRrq -f $(THIS_FILE) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
build:
docker-compose -f docker-compose.yml build $(c)
up:
docker-compose -f docker-compose.yml up -d $(c)
start:
docker-compose -f docker-compose.yml start $(c)
down:
docker-compose -f docker-compose.yml down $(c)
destroy:
docker-compose -f docker-compose.yml down -v $(c)
stop:
docker-compose -f docker-compose.yml stop $(c)
restart:
docker-compose -f docker-compose.yml stop $(c)
docker-compose -f docker-compose.yml up -d $(c)
logs:
docker-compose -f docker-compose.yml logs --tail=100 -f $(c)
logs-api:
docker-compose -f docker-compose.yml logs --tail=100 -f api
ps:
docker-compose -f docker-compose.yml ps
login-timescale:
docker-compose -f docker-compose.yml exec timescale /bin/bash
login-api:
docker-compose -f docker-compose.yml exec api /bin/bash
db-shell:
docker-compose -f docker-compose.yml exec timescale psql -UpostgresMost of the commands run on all containers, however, using the c= option we can limit the command to only one container.
Once the makefile is ready, we can use it in the following ways:
make help— list all commands available for make

make build— build the image from Dockerfile. In our example we have used an existing image oftimescaledbandping. However, forapi, we want to build locally. This command will do that.

make start— is used to start all the containers. To start only one container runmake start c=timescale


make login-timescale— is used to log-in to bash session in thetimescalecontainer.

make db-shell— is used to log-in to thepsqlin the timescale container to runsqlqueries on the database

make stop— is used to stop the container

make down— is used to stop and remove containers. To delete specific container usemake down c=timescaledbormake down c=api



No comments:
Post a Comment