-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmakefile
More file actions
345 lines (299 loc) Β· 14.1 KB
/
makefile
File metadata and controls
345 lines (299 loc) Β· 14.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# ==============================================================================
# PASSWORDLESS DEPLOYMENT SETUP
# ==============================================================================
# To deploy without password prompts, you need to use SSH key-based authentication
# and configure passwordless sudo on the remote server.
#
# 1. Generate an SSH Key Pair (if you don't have one):
# ssh-keygen -t rsa -b 4096
#
# 2. Copy your public key to the remote server:
# ssh-copy-id $(TARGET_USER)@$(TARGET_HOST)
#
# 3. Configure passwordless sudo for Docker on the remote server:
# a. SSH into the remote server: ssh $(TARGET_USER)@$(TARGET_HOST)
# b. Edit the sudoers file: sudo visudo
# c. Add this line at the end: $(TARGET_USER) ALL=(ALL) NOPASSWD: /usr/bin/docker
#
# ==============================================================================
# Shell & Formatting
# ==============================================================================
.PHONY: help deploy-local deploy-homelab deploy-gcp start clean
.DEFAULT_GOAL := help
# Silences command output, use `make V=1` to see verbose output
V ?= 0
ifeq ($(V), 0)
MAKE_VERBOSE = @
else
MAKE_VERBOSE =
endif
BLUE := \033[1;34m
NC := \033[0m # No Color
# ==============================================================================
# Generic Project Configuration
# ==============================================================================
# Load environment variables from .env file if it exists
-include .env
# --- Docker & Container ---
PROJECT_NAME ?= dataclouder-dev-node#βοΈ
VERSION := $(shell node -p "require('./package.json').version")
GIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo "no-git")
IMAGE_FILENAME := $(PROJECT_NAME)-$(VERSION).tar
CONTAINER_NAME ?= $(PROJECT_NAME)-container
HOST_PORT ?= 7991#βοΈ
INNER_PORT ?= 7991
# --- GCP Configuration ---
PROJECT_ID ?= dataclouder-dev#βοΈ
GCP_REGION ?= us-central1#βοΈ
GCP_SERVICE_NAME ?= $(PROJECT_NAME)-node
ARTIFACT_REGISTRY_REPO := us-central1-docker.pkg.dev/$(PROJECT_ID)/images/$(PROJECT_NAME)
# --- GHCR Configuration ---
GHCR_USER ?= adamofig
GHCR_REPO := ghcr.io/$(GHCR_USER)/$(PROJECT_NAME)
# --- Credential Configuration ---
# Define paths for different environments
ENV_FILE_QA ?= .env.qa
ENV_FILE_PRO ?= .env
ENV_FILE_HOMELAB ?= .env.homelab
KEY_FILE ?= ./.cred/key.json
# If your remote user needs a password for sudo, set it here or in your .env file.
# It will be piped to sudo -S. Leave empty to use passwordless sudo.
REMOTE_SUDO_PASSWORD ?=
# If REMOTE_SUDO_PASSWORD is set, configure commands to use it for SSH authentication.
# This requires the `sshpass` utility to be installed on your local machine.
# On macOS: brew install sshpass
# On Debian/Ubuntu: sudo apt-get install sshpass
SSH_CMD = ssh
SCP_CMD = scp
ifneq ($(strip $(REMOTE_SUDO_PASSWORD)),)
SSH_CMD = sshpass -p '$(REMOTE_SUDO_PASSWORD)' ssh
SCP_CMD = sshpass -p '$(REMOTE_SUDO_PASSWORD)' scp
endif
# --- Target-Specific Variables (set by deploy targets) ---
TARGET_USER ?= local
TARGET_HOST ?= localhost
REMOTE_DEPLOY_PATH ?= ~/Documents
PLATFORM ?= linux/amd64 # Default platform
# These will be overridden by deploy targets
TARGET_ENV_FILE := $(ENV_FILE_QA)
TARGET_KEY_FILE := $(KEY_FILE)
# --- Computed Variables ---
REMOTE_TAR_FILEPATH := $(REMOTE_DEPLOY_PATH)/$(IMAGE_FILENAME)
REMOTE_CONFIG_PATH := $(REMOTE_DEPLOY_PATH)/config
ARTIFACT_REGISTRY_REPO := us-central1-docker.pkg.dev/$(PROJECT_ID)/images/$(PROJECT_NAME)
# ==============================================================================
# USER-FACING DEPLOYMENT TARGETS
# ==============================================================================
# Deploy to Local Docker (ARM64)
deploy-local: PLATFORM = linux/arm64
deploy-local: ._build-docker ._deploy-local
@echo "β
Deployment to local Docker completed successfully."
# Deploy to Homelab Server (ARM64)
deploy-homelab: TARGET_USER = adamo
deploy-homelab: TARGET_HOST = home.lab
deploy-homelab: REMOTE_DEPLOY_PATH = /home/adamo/Documents
deploy-homelab: PLATFORM = linux/arm64
deploy-homelab: TARGET_ENV_FILE = $(ENV_FILE_HOMELAB)
deploy-homelab: ._build-docker ._transfer-docker-image ._transfer-credentials ._deploy-remote ._local-cleanup
@echo "β
Deployment to Homelab ($(TARGET_HOST)) completed successfully."
# Deploy to AI Lab Server (AMD64)
deploy-ailab: TARGET_USER = adamo
deploy-ailab: TARGET_HOST = 192.168.2.2
deploy-ailab: REMOTE_DEPLOY_PATH = /home/adamo/Documents
deploy-ailab: PLATFORM = linux/amd64
deploy-ailab: TARGET_ENV_FILE = $(ENV_FILE_PRO)
deploy-ailab: ._build-docker ._transfer-docker-image ._transfer-credentials ._deploy-remote ._local-cleanup
@echo "β
Deployment to AI Lab http://$(TARGET_HOST):$(HOST_PORT) completed successfully."
# Deploy to Google Cloud Platform (GCP)
deploy-cloud-run: build-and-save-in-gcp-artifact-registry deploy-service
@echo "β
Deployment to GCP completed successfully."
# Deploy to GitHub Container Registry (GHCR)
push-ghcr: PLATFORM = linux/amd64
push-ghcr: ._build-and-push-ghcr
@echo "β
Deployment to GHCR ($(GHCR_REPO)) completed successfully."
# Build Docker Image Locally
docker-build: PLATFORM = linux/amd64
docker-build: ._build-docker
@echo "β
Docker image [$(PROJECT_NAME):latest] built successfully."
# Run existing Local Docker Container (without building)
docker-run: PLATFORM = linux/arm64
docker-run: ._deploy-local
@echo "β
Container [$(CONTAINER_NAME)] is running on http://localhost:$(HOST_PORT)"
# ==============================================================================
# INTERNAL HELPER TARGETS
# ==============================================================================
._build-docker:
@echo "1) π³ Building Docker image [$(PROJECT_NAME):$(VERSION)] for [$(PLATFORM)]..."
$(MAKE_VERBOSE) docker build --platform $(PLATFORM) \
--build-arg VERSION=$(VERSION) \
--build-arg GIT_HASH=$(GIT_HASH) \
-t $(PROJECT_NAME):$(VERSION) \
-t $(PROJECT_NAME):latest .
._ghcr-login-check:
@echo "π Checking GHCR login status..."
@echo "π¨ If the next step fails, please run: echo \$$CR_PAT | docker login ghcr.io -u $(GHCR_USER) --password-stdin"
._build-and-push-ghcr: ._ghcr-login-check
@echo "1) π³ Building Docker image for GHCR [$(GHCR_REPO):$(VERSION)]..."
$(MAKE_VERBOSE) docker build --platform $(PLATFORM) \
--build-arg VERSION=$(VERSION) \
--build-arg GIT_HASH=$(GIT_HASH) \
-t $(GHCR_REPO):$(VERSION) \
-t $(GHCR_REPO):latest .
@echo "2) π Pushing to GHCR... COMMAND: __docker push $(GHCR_REPO):$(VERSION)__"
$(MAKE_VERBOSE) docker push $(GHCR_REPO):$(VERSION)
$(MAKE_VERBOSE) docker push $(GHCR_REPO):latest
._transfer-docker-image:
@echo "2) πΎ Saving Docker image to [$(IMAGE_FILENAME)]..."
$(MAKE_VERBOSE) docker save $(PROJECT_NAME):$(VERSION) -o $(IMAGE_FILENAME)
@echo "3) π Transferring [$(IMAGE_FILENAME)] to [$(TARGET_USER)@$(TARGET_HOST):$(REMOTE_TAR_FILEPATH)]..."
$(MAKE_VERBOSE) $(SCP_CMD) $(IMAGE_FILENAME) $(TARGET_USER)@$(TARGET_HOST):$(REMOTE_TAR_FILEPATH)
._transfer-credentials:
@echo "4) π Transferring credentials to [$(TARGET_HOST)] env [$(REMOTE_CONFIG_PATH)/.env] key [$(REMOTE_CONFIG_PATH)/key.json]..."
$(MAKE_VERBOSE) $(SSH_CMD) $(TARGET_USER)@$(TARGET_HOST) "mkdir -p $(REMOTE_CONFIG_PATH)"
$(MAKE_VERBOSE) $(SCP_CMD) $(TARGET_ENV_FILE) $(TARGET_USER)@$(TARGET_HOST):$(REMOTE_CONFIG_PATH)/.env
$(MAKE_VERBOSE) $(SCP_CMD) $(TARGET_KEY_FILE) $(TARGET_USER)@$(TARGET_HOST):$(REMOTE_CONFIG_PATH)/key.json
._deploy-remote:
@echo "5) βοΈ Deploying on remote host [$(TARGET_HOST)]..."
$(MAKE_VERBOSE) $(SSH_CMD) -t $(TARGET_USER)@$(TARGET_HOST) '\
set -e; \
if [ -n "$(REMOTE_SUDO_PASSWORD)" ]; then \
SUDO_CMD="echo \"$(REMOTE_SUDO_PASSWORD)\" | sudo -S"; \
else \
SUDO_CMD="sudo"; \
fi; \
echo " -> π³ Loading Docker image..."; \
eval $$SUDO_CMD docker load -i $(REMOTE_TAR_FILEPATH); \
echo " -> π Stopping existing container [$(CONTAINER_NAME)]..."; \
eval $$SUDO_CMD docker stop $(CONTAINER_NAME) || true; \
echo " -> ποΈ Removing existing container [$(CONTAINER_NAME)]..."; \
eval $$SUDO_CMD docker rm $(CONTAINER_NAME) || true; \
echo " -> π Starting new container [$(CONTAINER_NAME)]..."; \
eval $$SUDO_CMD docker run -d \
--name $(CONTAINER_NAME) \
--env-file $(REMOTE_CONFIG_PATH)/.env \
-v $(REMOTE_CONFIG_PATH)/key.json:/app/.cred/key.json:ro \
-e GOOGLE_APPLICATION_CREDENTIALS=/app/.cred/key.json \
-p $(HOST_PORT):$(INNER_PORT) \
--restart unless-stopped \
$(PROJECT_NAME):$(VERSION); \
echo " -> π§Ή Cleaning up remote tarball..."; \
rm $(REMOTE_TAR_FILEPATH); \
echo " -> β
Remote deployment finished check on http://$(TARGET_HOST):$(HOST_PORT)" '
._deploy-local:
@echo "2) π Deploying on local Docker..."
@echo " -> π Stopping and removing existing container [$(CONTAINER_NAME)] IF EXISTS..."
-$(MAKE_VERBOSE) docker stop $(CONTAINER_NAME) || true
-$(MAKE_VERBOSE) docker rm $(CONTAINER_NAME) || true
@echo " -> π Starting new container [$(CONTAINER_NAME)]..."
$(MAKE_VERBOSE) docker run -d \
--env-file .env \
--name $(CONTAINER_NAME) \
-p $(HOST_PORT):$(INNER_PORT) \
--restart unless-stopped \
-v $(shell pwd)/$(TARGET_KEY_FILE):/app/.cred/key.json:ro \
-e GOOGLE_APPLICATION_CREDENTIALS=/app/.cred/key.json \
$(PROJECT_NAME):$(VERSION)
@echo " -> β
Local deployment finished check on http://localhost:$(HOST_PORT)"
._local-cleanup:
@echo "6) π§Ή Cleaning up local tarball [$(IMAGE_FILENAME)]..."
$(MAKE_VERBOSE) rm -f $(IMAGE_FILENAME)
# ==============================================================================
# GCP DEPLOYMENT TARGETS
# ==============================================================================
# π₯ To deploy RUN ONLY the First Time to garantee you have cloud build and cloud run.
gcp-enable-services:
@echo "π Enabling required services for $(PROJECT_ID)...π§"
gcloud config set project $(PROJECT_ID)
gcloud services enable run.googleapis.com
gcloud services enable cloudbuild.googleapis.com
gcloud services enable artifactregistry.googleapis.com
build-and-save-in-gcp-artifact-registry:
@echo " π³ -> Building docker in GCP with tag $(ARTIFACT_REGISTRY_REPO):$(VERSION) and pushing to Google Container Registry..."
gcloud builds submit --project $(PROJECT_ID) \
--tag $(ARTIFACT_REGISTRY_REPO):$(VERSION) \
--tag $(ARTIFACT_REGISTRY_REPO):latest \
--substitutions _VERSION=$(VERSION),_GIT_HASH=$(GIT_HASH) .
# Build the Docker image and push to Google Container Registry
# Deploy to Cloud Run, use .env variables except GOOGLE_APPLICATION_CREDENTIALS
deploy-service:
@echo " π Deploying to Cloud Run..."
@echo " π¨ NOTE: Your Current ENV variables will be parsed and deployed to Cloud Run. πͺͺ"
@ENV_VARS=$$(node scripts/env_parser.js); \
echo "π Double check your Environment Variables to be deployed: π"; \
echo "$${ENV_VARS}" | tr ',' '\n'; \
gcloud run deploy $(GCP_SERVICE_NAME) \
--project $(PROJECT_ID) \
--image $(ARTIFACT_REGISTRY_REPO):$(VERSION) \
--platform managed \
--region $(GCP_REGION) \
--allow-unauthenticated \
--set-env-vars "$${ENV_VARS}"
@echo "Deployment complete! You can check the status using:"
@echo "gcloud run services describe $(GCP_SERVICE_NAME) --region $(GCP_REGION)"
# ==============================================================================
# DEVELOPMENT & UTILITY TARGETS
# ==============================================================================
start:
npm run start:dev
update-dc:
npm run update:dc
update-all:
ncu -u
publish-mongo:
npm run publish:mongo
publish-google-cloud:
npm run publish:google-cloud
patch:
npm version patch
minor:
npm version minor
major:
npm version major
clean:
@echo "π§Ή Removing node_modules..."
$(MAKE_VERBOSE) rm -rf node_modules
merge-upstream:
@echo "Fetching and merging updates from upstream repository..."
@if ! git config remote.upstream.url > /dev/null; then \
echo "Adding upstream remote..."; \
git remote add upstream https://github.com/dataclouder-dev/startup-template-node.git; \
fi
git fetch upstream
git checkout main
@echo "Merging upstream/main into local main branch..."
git merge upstream/main --allow-unrelated-histories || { \
echo "Merge conflicts detected. Please resolve conflicts and complete the merge manually."; \
echo "After resolving conflicts, commit changes and push to origin."; \
exit 1; \
}
# ==============================================================================
# HELP
# ==============================================================================
help:
@echo "Usage: make [target]"
@echo ""
@echo "----------------------------------------------------------------------"
@echo " Deployment Targets"
@echo "----------------------------------------------------------------------"
@echo " $(BLUE)make deploy-local$(NC) - Build and deploy the app to your local Docker."
@echo " $(BLUE)make deploy-homelab$(NC) - Build and deploy the app to the Homelab server."
@echo " $(BLUE)make deploy-gcp$(NC) - Build and deploy the app to Google Cloud Run."
@echo " $(BLUE)make push-ghcr$(NC) - Build and push the app to GHCR."
@echo " (Note: Requires 'docker login ghcr.io')"
@echo " $(BLUE)make build-docker$(NC) - Build the Docker image locally for testing."
@echo ""
@echo "----------------------------------------------------------------------"
@echo " Versioning"
@echo "----------------------------------------------------------------------"
@echo " $(BLUE)make patch$(NC) - Bump version (0.0.x) and tag."
@echo " $(BLUE)make minor$(NC) - Bump version (0.x.0) and tag."
@echo " $(BLUE)make major$(NC) - Bump version (x.0.0) and tag."
@echo ""
@echo "----------------------------------------------------------------------"
@echo " Development"
@echo "----------------------------------------------------------------------"
@echo " $(BLUE)make start$(NC) - Run the dev server."
@echo " $(BLUE)make clean$(NC) - Remove node_modules."
@echo ""
@echo "Run 'make [target] V=1' for verbose output."
@echo ""