-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
285 lines (248 loc) Β· 11.6 KB
/
Makefile
File metadata and controls
285 lines (248 loc) Β· 11.6 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
# ==============================================================================
# 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
# --- GCP Configuration ---
PROJECT_ID ?= dataclouder-dev
GCP_REGION ?= us-central1
GCP_SERVICE_NAME ?= $(PROJECT_ID)-python-server
# --- Docker & Container ---
IMAGE_NAME ?= dataclouder-dev-python-image
IMAGE_FILENAME := $(IMAGE_NAME).tar
CONTAINER_NAME ?= $(IMAGE_NAME)-container
HOST_PORT ?= 7992
# --- Credential Configuration ---
# Define paths for different environments
ENV_FILE_QA ?= .env.qa
KEY_FILE_QA ?= ./.cred/key-qa.json
ENV_FILE_PRO ?= .env
KEY_FILE_PRO ?= ./.cred/key.json
ENV_FILE_HOMELAB ?= .env.homelab
# 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_QA)
# --- Computed Variables ---
REMOTE_TAR_FILEPATH := $(REMOTE_DEPLOY_PATH)/$(IMAGE_FILENAME)
REMOTE_CONFIG_PATH := $(REMOTE_DEPLOY_PATH)/config
GCP_IMAGE_URL := gcr.io/$(PROJECT_ID)/$(IMAGE_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: TARGET_KEY_FILE = $(KEY_FILE_PRO)
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: TARGET_KEY_FILE = $(KEY_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-gcp: build-push deploy-service
@echo "β
Deployment to GCP completed successfully."
# ==============================================================================
# INTERNAL HELPER TARGETS
# ==============================================================================
._build-docker:
@echo "1) π³ Building Docker image [$(IMAGE_NAME):latest] for [$(PLATFORM)]..."
$(MAKE_VERBOSE) docker build --platform $(PLATFORM) -t $(IMAGE_NAME):latest .
._transfer-docker-image:
@echo "2) πΎ Saving Docker image to [$(IMAGE_FILENAME)]..."
$(MAKE_VERBOSE) docker save $(IMAGE_NAME):latest -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:/usr/src/app/.cred/key.json:ro \
-e GOOGLE_APPLICATION_CREDENTIALS=/usr/src/app/.cred/key.json \
-p $(HOST_PORT):8080 \
--restart unless-stopped \
$(IMAGE_NAME):latest; \
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)]..."
-$(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):8080 \
--restart unless-stopped \
-v $(shell pwd)/.cred/key-qa.json:/usr/src/app/.cred/key-qa.json:ro \
-e GOOGLE_APPLICATION_CREDENTIALS=/usr/src/app/.cred/key-qa.json \
$(IMAGE_NAME):latest
@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 the Docker image and push to Google Container Registry
build-push:
@echo " -> Building $(GCP_IMAGE_URL) image and pushing to Google Container Registry..."
gcloud builds submit --project $(PROJECT_ID) --tag $(GCP_IMAGE_URL) .
# Deploy to Cloud Run, use .env variables except GOOGLE_APPLICATION_CREDENTIALS
deploy-service:
@echo " π Deploying to Cloud Run..."
@ENV_VARS=$$$$(node scripts/env_parser.js); \
echo "Environment Variables to be deployed:"; \
echo "$${ENV_VARS}" | tr ',' '\n'; \
gcloud run deploy $(GCP_SERVICE_NAME) \
--project $(PROJECT_ID) \
--image $(GCP_IMAGE_URL) \
--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
# ==============================================================================
# Install dependencies using uv
install:
@echo "-> π¦ Installing dependencies..."
$(MAKE_VERBOSE) uv venv
$(MAKE_VERBOSE) uv sync
# Run the application using uvicorn
start:
@echo "-> π Starting application..."
$(MAKE_VERBOSE) uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
# Lint the code using ruff
lint:
@echo "-> π¨ Linting code..."
$(MAKE_VERBOSE) uv run ruff check .
# Format the code using ruff
format:
@echo "-> π¨ Formatting code..."
$(MAKE_VERBOSE) uv run ruff format .
# Alias for building docker image
docker-build: ._build-docker
# Run the application in a docker container
docker-run:
@echo "-> π³ Running application in docker..."
$(MAKE_VERBOSE) docker run -it -p 8000:8080 $(IMAGE_NAME):latest
clean:
@echo "π§Ή Removing virtual environment and __pycache__ files..."
$(MAKE_VERBOSE) rm -rf .venv
$(MAKE_VERBOSE) find . -type d -name "__pycache__" -exec rm -r {} +
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 ""
@echo "----------------------------------------------------------------------"
@echo " Development"
@echo "----------------------------------------------------------------------"
@echo " $(BLUE)make install$(NC) - Install dependencies."
@echo " $(BLUE)make start$(NC) - Run the dev server."
@echo " $(BLUE)make lint$(NC) - Lint the code."
@echo " $(BLUE)make format$(NC) - Format the code."
@echo " $(BLUE)make docker-build$(NC) - Build the docker image."
@echo " $(BLUE)make docker-run$(NC) - Run the docker container."
@echo " $(BLUE)make clean$(NC) - Remove virtual environment and __pycache__ files."
@echo ""
@echo "Run 'make [target] V=1' for verbose output."
@echo ""