Skip to content

Commit 2741a48

Browse files
committed
chore(*): setup Makefile
1 parent 5b86efa commit 2741a48

File tree

4 files changed

+187
-9
lines changed

4 files changed

+187
-9
lines changed

.makefile-utils.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
3+
function image_exists() {
4+
docker images -q $1
5+
}

Makefile

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
UTILS := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))/.makefile-utils.sh
2+
3+
OK_COLOR = \033[0;32m
4+
NO_COLOR = \033[m
5+
6+
DOCKER_USER = topheman
7+
DOCKER_IMAGE_PREFIX = $(DOCKER_USER)/my-docker-fullstack-project
8+
DOCKER_IMAGE_NAME_FRONT_DEV = $(DOCKER_IMAGE_PREFIX)_front_development
9+
DOCKER_IMAGE_NAME_API_DEV = $(DOCKER_IMAGE_PREFIX)_api_development
10+
DOCKER_IMAGE_NAME_API_PROD = $(DOCKER_IMAGE_PREFIX)_api_production
11+
DOCKER_IMAGE_NAME_NGINX = $(DOCKER_IMAGE_PREFIX)_nginx
12+
13+
TAG_LATEST = latest
14+
TAG ?= 0.1.0
15+
16+
# development docker-compose
17+
COMPOSE = docker-compose
18+
COMPOSE_RUN = $(COMPOSE) run --rm
19+
COMPOSE_RUNCI = $(COMPOSE_RUN) -e CI=true
20+
COMPOSE_RUN_FRONT = $(COMPOSE_RUN) front
21+
COMPOSE_RUNCI_FRONT = $(COMPOSE_RUNCI) front
22+
COMPOSE_RUN_API = $(COMPOSE_RUN) api
23+
24+
# production docker-compose
25+
COMPOSEPROD = docker-compose -f ./docker-compose.yml -f ./docker-compose.prod.yml
26+
27+
# kubernetes
28+
KUBECTL_CONFIG = -f ./deployments/api.yml -f ./deployments/front.yml
29+
30+
default: help
31+
32+
.PHONY: build-front-assets dev-logs-api dev-logs-front dev-logs dev-ps dev-start-d dev-start dev-stop docker-build-prod docker-images-clean docker-images-id docker-images-name docker-images kube-ps kube-start-no-rebuild kube-start kube-stop prod-logs-api prod-logs-front prod-logs prod-ps prod-start-d prod-start prod-stop test-api test-front test
33+
34+
# rename ?
35+
build-front-assets: ## Build frontend assets into ./front/build folder
36+
$(COMPOSE_RUN_FRONT) npm run build
37+
38+
test-front: ## Test react frontend
39+
$(COMPOSE_RUNCI_FRONT) npm run -s test
40+
41+
test-api: ## Test golang backend
42+
$(COMPOSE_RUN_API) go test -run ''
43+
44+
test: test-front test-api ## 🌡 Test both frontend and backend
45+
46+
docker-images: ## List project's docker images
47+
@docker images --filter=reference='$(DOCKER_IMAGE_PREFIX)*'
48+
49+
docker-images-name: ## List project's docker images formatted as <name>:<tag>
50+
@docker images --format "{{.Repository}}:{{.Tag}}" --filter=reference='$(DOCKER_IMAGE_PREFIX)*'
51+
52+
docker-images-id: ## List project's docker images formatted as <id>
53+
@docker images --quiet --filter=reference='$(DOCKER_IMAGE_PREFIX)*'
54+
55+
docker-images-clean: ## Clean dangling images (tagged as <none>)
56+
docker rmi $(shell docker images -q --filter="dangling=true")
57+
58+
docker-build-prod: ## Build production images
59+
$(MAKE) build-front
60+
docker build ./api -t $(DOCKER_IMAGE_NAME_API_PROD):$(TAG)
61+
docker build . -f Dockerfile.prod -t $(DOCKER_IMAGE_NAME_NGINX):$(TAG)
62+
63+
dev-start: ## 🐳 Start development stack
64+
$(COMPOSE) up
65+
dev-start-d: ## Start development stack (in daemon mode)
66+
$(COMPOSE) up -d
67+
dev-stop: ## Stop development stack
68+
$(COMPOSE) down
69+
dev-ps: ## List development stack active containers
70+
$(COMPOSE) ps
71+
dev-logs: ## 🐳 Follow ALL logs (dev)
72+
$(COMPOSE) logs -f
73+
dev-logs-front: ## Follow front logs (dev)
74+
$(COMPOSE) logs -f front
75+
dev-logs-api: ## Follow api logs (dev)
76+
$(COMPOSE) logs -f api
77+
78+
prod-start: ## 🐳 Start production stack (bundles frontend before)
79+
$(MAKE) build-front
80+
$(COMPOSEPROD) up --build
81+
prod-start-d: ## Start production stack (in daemon mode)
82+
$(MAKE) build-front
83+
$(COMPOSEPROD) up --build -d
84+
prod-stop: ## Stop production stack
85+
$(COMPOSEPROD) down
86+
prod-ps: ## List production stack active containers
87+
$(COMPOSEPROD) ps
88+
prod-logs: ## 🐳 Follow ALL logs (prod)
89+
$(COMPOSEPROD) logs -f
90+
prod-logs-front: ## Follow front logs (prod)
91+
$(COMPOSEPROD) logs -f front
92+
prod-logs-api: ## Follow api logs (prod)
93+
$(COMPOSEPROD) logs -f api
94+
95+
kube-start-no-rebuild: ## Create kubernetes deployment without recreating docker images
96+
kubectl create $(KUBECTL_CONFIG)
97+
kube-start: ## ☸️ Create kubernetes deployment with fresh docker images
98+
$(MAKE) docker-build-prod
99+
@echo ""
100+
$(MAKE) kube-start-no-rebuild
101+
@echo "\nYou may use $(OK_COLOR)make kube-start-no-rebuild$(NO_COLOR) next time to avoid rebuilding images each time\n"
102+
kube-stop: ## Delete kubernetes deployment with fresh docker images
103+
kubectl delete $(KUBECTL_CONFIG)
104+
kube-ps: ## List kubernetes pods and services
105+
kubectl get pods,services
106+
107+
help:
108+
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
109+
110+
list-phony:
111+
# List all the tasks to add the to .PHONY (choose between inlined and linefeed)
112+
# bash variables are expanded with $$
113+
# make|sed 's/\|/ /'|awk '{printf "%s+ ", $1}'
114+
# make|sed 's/\|/ /'|awk '{print $1}'
115+
@$(MAKE) help|sed 's/\|/ /'|awk '{printf "%s ", $$1}'
116+
@echo "\n"
117+
@$(MAKE) help|sed 's/\|/ /'|awk '{print $$1}'
118+
119+
# deprecated - example of how to call a function from an other .sh file
120+
image-exists:
121+
@. $(UTILS); image_exists $(DOCKER_IMAGE_NAME_NGINX):$(TAG)

README.md

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,44 @@
22

33
<p align="center"><img src="./logo.png" width=530 /></p>
44

5-
This started as a simple use case to discover `docker`, `docker-compose` 🐳 and the creation of `Dockerfile` in both development and production:
5+
This started as a simple use case to discover `docker` and `docker-compose` 🐳 :
66

7-
* A [front](front) made with create-react-app, running in a nodejs container for development (only the built artefacts will be used in production, not this container)
8-
* A very simple [api](api) made in go (the challenge is also not to have everything in JavaScript), containerized in docker with a development and a production image
7+
* A [front](front) made with create-react-app, running in a nodejs container for development
8+
* A very simple [api](api) made in go (the challenge is also not to have everything in JavaScript)
99

10-
I also setup **deployments on a local kubernetes** ☸️ - it can be fun to start to play with if you want to discover kubernetes.
10+
I also setup **deployments on a local kubernetes** ☸️ .
11+
12+
## TL;DR
13+
14+
You are a true developer? You don't RTFM? After all, this is why we have docker ... not to bother with all the boring setup/install steps ... 😉
15+
16+
```shell
17+
git clone https://github.com/topheman/my-docker-fullstack-project.git
18+
cd my-docker-fullstack-project
19+
docker-compose up -d
20+
```
21+
22+
You are good to go with a development server running at [http://localhost:3000](http://localhost:3000), with the front in react, the api in go and everything hot reloading. 👏
23+
24+
Try to take a few minutes to read the doc bellow ... 😇
25+
26+
## Summary
27+
28+
* [Prerequisites](#prerequisites)
29+
* [Setup](#setup)
30+
* [Development 🛠](#development)
31+
* [Tests 🌡](#tests)
32+
* [Production - docker-compose 🐳](#production---docker-compose)
33+
* [Deployment - kubernetes ☸️](#deployment---kubernetes)
34+
* [Notes 📋](#notes)
35+
* [Docker Multi-stage builds](#docker-multi-stage-builds)
36+
* [Docker networks / Kubernetes services](#docker-networks--kubernetes-services)
37+
* [Restart on failure](#restart-on-failure)
38+
* [Commands](#commands)
39+
* [Docker commands](#docker-commands)
40+
* [Kubernetes commands](#kubernetes-commands)
41+
* [What's next?](#whats-next)
42+
* [Resources](#resources)
1143

1244
## Prerequisites
1345

@@ -17,9 +49,19 @@ You need to have installed:
1749
* npm / node (optional)
1850
* local kubernetes server and client (only if you want to play with kubernetes deployment - more about that on the [deployment section](#deployment---kubernetes))
1951

52+
## Setup
53+
54+
```shell
55+
git clone https://github.com/topheman/my-docker-fullstack-project.git
56+
```
57+
58+
A [Makefile](Makefile) is available that automates all the commands that are described bellow. For each section, you'll find the related commands next to the 🖊 emoji.
59+
60+
Just run `make help` to see the whole list.
61+
2062
## Development
2163

22-
### Install / launch
64+
### Launch development
2365

2466
```shell
2567
docker-compose up -d
@@ -33,15 +75,17 @@ This will create (if not already done) and launch a whole development stack, bas
3375

3476
Go to http://localhost:3000/ to access the frontend, you're good to go, the api is accessible at http://localhost:5000/.
3577

78+
🖊 `make dev-start`, `make dev-start-d`, `make dev-stop`, `make dev-ps`, `make dev-logs`, `make dev-logs-front`, `make dev-logs-api`
79+
3680
## Tests
3781

38-
To run all tests:
82+
### Launch tests
3983

4084
```shell
4185
docker-compose run --rm -e CI=true front npm run -s test && docker-compose run --rm api go test -run ''
4286
```
4387

44-
⚠️ TODO: Make shortcuts for tests from the root of the project (some shortcuts are already available in [front](front#tasks)) / parallelize tests ? Maybe a Makefile ?
88+
🖊 `make test`, `make test-front`, `make test-api`
4589

4690
## Production - docker-compose
4791

@@ -53,6 +97,8 @@ Make sure you have built the frontend with `docker-compose run --rm front npm ru
5397
docker-compose -f ./docker-compose.yml -f ./docker-compose.prod.yml up --build
5498
```
5599

100+
Note: make sure to use the `--build` flag so that it will rebuild the images if anything changed (in the source code or whatever), thanks to [docker images layers](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/), only changes will be rebuilt, based on cache (not the whole image).
101+
56102
This will create (if not already done) and launch a whole production stack:
57103

58104
* No nodejs image (it should not be shipped to production, the development image is only used to launch the container that creates the build artefacts with create-react-app).
@@ -63,6 +109,8 @@ This will create (if not already done) and launch a whole production stack:
63109

64110
Access [http://localhost](http://localhost) and you're good to go.
65111

112+
🖊 `make prod-start`, `make prod-start-d`, `make prod-stop`, `make prod-ps`, `make prod-logs`, `make prod-logs-front`, `make prod-logs-api`
113+
66114
## Deployment - kubernetes
67115

68116
This section is about **deploying the app locally with kubernetes** ☸️ (not tested with a cloud provider). To stay simple, there aren't any TLS termination management (only port 80 exposed).
@@ -74,7 +122,7 @@ Local kubernetes server and client:
74122

75123
The files descripting the deployments are stored in the [deployments](deployments) folder. You will find two files, each containing the deployment and the service.
76124

77-
### Deploy
125+
### Deploy with kubernetes
78126

79127
1) If you haven't built the frontend, run `docker-compose run --rm front npm run build`
80128

@@ -111,6 +159,8 @@ kubectl get pods,services
111159

112160
[More commands](#kubernetes-commands)
113161

162+
🖊 `make kube-start`, `make kube-start-no-rebuild`, `make kube-stop`, `make kube-ps`
163+
114164
## Notes
115165

116166
### Docker Multi-stage builds
@@ -171,6 +221,7 @@ Don't want to use `docker-compose` (everything bellow is already specified in th
171221
* exposes the port 3000
172222
* creates (if not exists) and bind the volumes
173223
* the container will be removed once you kill the process (`--rm`)
224+
* `docker rmi $(docker images -q --filter="dangling=true")`: remove dangling images (layers that have no more relationships to any tagged image. Tagged as <none>, they no longer serve a purpose and consume disk space)
174225

175226
#### Kubernetes commands
176227

@@ -230,4 +281,5 @@ More bookmarks from my research:
230281
* [Advanced kubernetes ingress](https://koudingspawn.de/advanced-ingress/)
231282
* [Kubernetes NodePort vs LoadBalancer vs Ingress? When should I use what?](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
232283
* [Kubectl apply vs kubectl create?](https://stackoverflow.com/questions/47369351/kubectl-apply-vs-kubectl-create)
233-
* [awesome-kubernetes - A curated list for awesome kubernetes sources](https://ramitsurana.github.io/awesome-kubernetes/)
284+
* [awesome-kubernetes - A curated list for awesome kubernetes sources](https://ramitsurana.github.io/awesome-kubernetes/)
285+
* [Tutoriel Linux : Makefile](https://youtu.be/2VV9FAQWHdw)
File renamed without changes.

0 commit comments

Comments
 (0)