generated from hjess/PythonTemplateProject
Initial commit
This commit is contained in:
3
.gitconfig
Normal file
3
.gitconfig
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[core]
|
||||||
|
hooksPath = .githooks
|
||||||
|
|
||||||
1
.gitea/installers/renders/README.md
Normal file
1
.gitea/installers/renders/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
shiv -c project-installer -o ../../../project-installer .
|
||||||
0
.gitea/installers/renders/__init__.py
Normal file
0
.gitea/installers/renders/__init__.py
Normal file
61
.gitea/installers/renders/project_installer.py
Normal file
61
.gitea/installers/renders/project_installer.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import os
|
||||||
|
import random
|
||||||
|
import pystache
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
|
||||||
|
def render_templates(template_dir, project_name):
|
||||||
|
import pystache # Import after ensuring it's installed
|
||||||
|
|
||||||
|
# Generate a random port number
|
||||||
|
port = random.randint(8900, 9400)
|
||||||
|
|
||||||
|
# Mustache data (dynamic placeholders)
|
||||||
|
data = {
|
||||||
|
"PROJECT_NAME": str(project_name).lower(),
|
||||||
|
"PORT": port
|
||||||
|
}
|
||||||
|
|
||||||
|
# Define a regex for detecting [[ ... ]] custom placeholders
|
||||||
|
pattern = re.compile(r"\[\[(.*?)\]\]")
|
||||||
|
|
||||||
|
# Process all .tmpl files in the directory
|
||||||
|
for root, _, files in os.walk(template_dir):
|
||||||
|
for file in files:
|
||||||
|
if file.endswith(".tmpl"):
|
||||||
|
tmpl_file = os.path.join(root, file)
|
||||||
|
output_file = os.path.join(root, file.replace(".tmpl", ""))
|
||||||
|
|
||||||
|
# Read the template file
|
||||||
|
with open(tmpl_file, 'r') as f:
|
||||||
|
template_content = f.read()
|
||||||
|
|
||||||
|
# Replace placeholders wrapped with [[ ... ]]
|
||||||
|
def replace_placeholder(match):
|
||||||
|
key = match.group(1)
|
||||||
|
return str(data.get(key, match.group(0))) # Replace only if key exists
|
||||||
|
|
||||||
|
rendered_content = pattern.sub(replace_placeholder, template_content)
|
||||||
|
|
||||||
|
# Write to output file
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write(rendered_content)
|
||||||
|
print(f"Generated: {output_file}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Parse arguments
|
||||||
|
parser = argparse.ArgumentParser(description="Render Mustache templates in a directory.")
|
||||||
|
parser.add_argument('--project-name', type=str, help='Project name (defaults to current directory name)')
|
||||||
|
parser.add_argument('--template-dir', type=str, default='.gitea/workflows', help='Template directory')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Get the project name (current directory name if not provided)
|
||||||
|
project_name = args.project_name or os.path.basename(os.getcwd())
|
||||||
|
|
||||||
|
# Render templates
|
||||||
|
render_templates(args.template_dir, project_name)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
14
.gitea/installers/renders/setup.py
Normal file
14
.gitea/installers/renders/setup.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="project-installer", # Name of your package
|
||||||
|
version="0.1.0", # Version of your package
|
||||||
|
description="Project Installer Tool", # Short description
|
||||||
|
py_modules=["project_installer"], # Module(s) to include (no .py extension)
|
||||||
|
install_requires=["pystache"], # List of dependencies
|
||||||
|
entry_points={
|
||||||
|
"console_scripts": [
|
||||||
|
"project-installer=project_installer:main", # Entry point
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
88
.gitea/workflows/README-nomad-job.md
Normal file
88
.gitea/workflows/README-nomad-job.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
|
||||||
|
### **Top-Level Job Configuration**
|
||||||
|
#### `job`
|
||||||
|
- **Purpose**: Defines the Nomad job.
|
||||||
|
- **Attributes**:
|
||||||
|
- `region`: Specifies the Nomad region where the job should run. [Reference: Nomad Regions](https://developer.hashicorp.com/nomad/docs/regions)
|
||||||
|
- `datacenters`: Lists the datacenters in which the job is eligible to run. [Reference: Job Placement](https://developer.hashicorp.com/nomad/docs/job-specification/datacenters)
|
||||||
|
- `type`: Defines the job type (`service` in this case). Service jobs are typically long-running. [Reference: Job Types](https://developer.hashicorp.com/nomad/docs/job-specification/job)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Update Block**
|
||||||
|
#### `update`
|
||||||
|
- **Purpose**: Specifies rolling update strategy for service jobs.
|
||||||
|
- **Attributes**:
|
||||||
|
- `stagger`: Time between starting updates for each allocation.
|
||||||
|
- `max_parallel`: Number of allocations to update simultaneously.
|
||||||
|
- `progress_deadline`: Time to wait for a deployment to progress before failing.
|
||||||
|
- [Reference: Update Stanza](https://developer.hashicorp.com/nomad/docs/job-specification/update)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Group Configuration**
|
||||||
|
#### `group`
|
||||||
|
- **Purpose**: Defines a group of tasks that should be placed together on the same node.
|
||||||
|
- **Attributes**:
|
||||||
|
- `count`: Number of task groups to run.
|
||||||
|
- [Reference: Task Group](https://developer.hashicorp.com/nomad/docs/job-specification/group)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Network Configuration**
|
||||||
|
#### `network`
|
||||||
|
- **Purpose**: Specifies networking requirements for the task group.
|
||||||
|
- **Attributes**:
|
||||||
|
- `port`: Defines a named port mapping for the task group.
|
||||||
|
- `to`: Specifies the internal port the application listens to within the container.
|
||||||
|
- [Reference: Network Stanza](https://developer.hashicorp.com/nomad/docs/job-specification/network)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Consul Integration**
|
||||||
|
#### `service`
|
||||||
|
- **Purpose**: Registers the service with Consul for discovery.
|
||||||
|
- **Attributes**:
|
||||||
|
- `provider`: Specifies the service discovery provider (`consul`).
|
||||||
|
- `name`: The name of the service in Consul.
|
||||||
|
- `port`: References the named port defined in the `network` block.
|
||||||
|
- `tags`: Metadata tags to annotate the service (e.g., for routing in Traefik).
|
||||||
|
- `check`: Defines health check parameters for the service.
|
||||||
|
- `name`: Name of the health check.
|
||||||
|
- `type`: Health check type (`tcp` in this case).
|
||||||
|
- `interval`: Frequency of the health check.
|
||||||
|
- `timeout`: Maximum duration for the health check.
|
||||||
|
- [Reference: Consul Service Stanza](https://developer.hashicorp.com/nomad/docs/job-specification/service)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Task Configuration**
|
||||||
|
#### `task`
|
||||||
|
- **Purpose**: Defines a single executable unit of work.
|
||||||
|
- **Attributes**:
|
||||||
|
- `driver`: Specifies the driver (`docker` in this case).
|
||||||
|
- `config`: Driver-specific configuration.
|
||||||
|
- `image`: Docker image for the task.
|
||||||
|
- `ports`: References the named port defined in the `network` block.
|
||||||
|
- `env`: Sets environment variables for the task.
|
||||||
|
- `resources`: Specifies resource requirements for the task.
|
||||||
|
- `cpu`: CPU allocation in MHz.
|
||||||
|
- `memory`: Memory allocation in MB.
|
||||||
|
- [Reference: Task Stanza](https://developer.hashicorp.com/nomad/docs/job-specification/task)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Dynamic Port Allocation**
|
||||||
|
#### `${NOMAD_PORT_<port-label>}`
|
||||||
|
- **Purpose**: Refers to the dynamically allocated host port mapped to the internal container port.
|
||||||
|
- **Usage**: This is used in the `env` and `tags` sections to dynamically configure the application and Consul registration.
|
||||||
|
- [Reference: Port Variables](https://developer.hashicorp.com/nomad/docs/runtime/environment#ports)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Key Takeaways**
|
||||||
|
1. This job defines a **service** that runs as a Docker container, listens on a dynamically assigned port, and registers itself in **Consul** for service discovery.
|
||||||
|
2. The `network` stanza ensures that Nomad assigns a dynamic host port, while the `${NOMAD_PORT_<port-label>}` variable is used to pass this information to the container and Consul.
|
||||||
|
3. The `update` stanza ensures smooth rolling updates for the service.
|
||||||
|
|
||||||
|
For further details and advanced configurations, refer to the [Nomad Job Specification Documentation](https://developer.hashicorp.com/nomad/docs/job-specification).
|
||||||
63
.gitea/workflows/main.yml.tmpl
Normal file
63
.gitea/workflows/main.yml.tmpl
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
name: Build, Push, and Deploy to Nomad
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker-nomad:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Log in to Container Registry
|
||||||
|
run: echo ${{ secrets.password }} | docker login registry.i80.dk -u ${{ secrets.username }} --password-stdin
|
||||||
|
|
||||||
|
- name: Build Docker Image
|
||||||
|
run: |
|
||||||
|
COMMIT_HASH=$(git rev-parse --short HEAD)
|
||||||
|
docker build -t registry.i80.dk/gitea/[[PROJECT_NAME]]:latest -t registry.i80.dk/gitea/[[PROJECT_NAME]]:${COMMIT_HASH} .
|
||||||
|
|
||||||
|
|
||||||
|
- name: Push Docker Image
|
||||||
|
run: |
|
||||||
|
COMMIT_HASH=$(git rev-parse --short HEAD)
|
||||||
|
echo "registry.i80.dk/gitea/[[PROJECT_NAME]]:latest"
|
||||||
|
echo "registry.i80.dk/gitea/[[PROJECT_NAME]]:${COMMIT_HASH}"
|
||||||
|
docker push registry.i80.dk/gitea/[[PROJECT_NAME]]:${COMMIT_HASH}
|
||||||
|
docker push registry.i80.dk/gitea/[[PROJECT_NAME]]:latest
|
||||||
|
|
||||||
|
|
||||||
|
- name: Validate Nomad Job
|
||||||
|
env:
|
||||||
|
NOMAD_ADDR: https://nomad.i80.dk
|
||||||
|
run: nomad job validate .gitea/workflows/nomad-job.hcl
|
||||||
|
|
||||||
|
- name: Stop old deployment
|
||||||
|
env:
|
||||||
|
NOMAD_ADDR: https://nomad.i80.dk
|
||||||
|
run: nomad job stop -purge -no-shutdown-delay [[PROJECT_NAME]]
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
|
||||||
|
- name: Apply Nomad Job
|
||||||
|
env:
|
||||||
|
NOMAD_ADDR: https://nomad.i80.dk
|
||||||
|
run: nomad job run .gitea/workflows/nomad-job.hcl
|
||||||
|
|
||||||
|
- name: Update Nginx Configuration
|
||||||
|
run: ssh runner@nomad sudo /opt/nginx_updater/venv/bin/python3 /opt/nginx_updater/nginx_updater.py [[PROJECT_NAME]]
|
||||||
|
|
||||||
|
- name: Update Forwarder Configuration
|
||||||
|
run: ssh runner@nomad sudo /opt/nginx_updater/venv/bin/python3 /opt/nginx_updater/update_forwarder.py [[PROJECT_NAME]]
|
||||||
|
|
||||||
|
|
||||||
|
# - name: Restart Nomad Job
|
||||||
|
# env:
|
||||||
|
# NOMAD_ADDR: https://nomad.i80.dk
|
||||||
|
# run: |
|
||||||
|
# nomad job stop [[PROJECT_NAME]]
|
||||||
|
# sleep 5 # Optional: Wait to ensure the old allocation is stopped
|
||||||
|
# nomad job run .gitea/workflows/nomad-job.hcl
|
||||||
60
.gitea/workflows/nomad-job.hcl.tmpl
Normal file
60
.gitea/workflows/nomad-job.hcl.tmpl
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
job "[[PROJECT_NAME]]" {
|
||||||
|
region = "global"
|
||||||
|
datacenters = ["dc1"]
|
||||||
|
type = "service"
|
||||||
|
|
||||||
|
update {
|
||||||
|
stagger = "60s"
|
||||||
|
max_parallel = 1
|
||||||
|
progress_deadline = "6m"
|
||||||
|
}
|
||||||
|
|
||||||
|
group "[[PROJECT_NAME]]-group" {
|
||||||
|
count = 1
|
||||||
|
|
||||||
|
network {
|
||||||
|
port "port-app" {
|
||||||
|
to = [[PORT]] # Internal application port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Register the service with Consul
|
||||||
|
service {
|
||||||
|
provider = "consul"
|
||||||
|
name = "[[PROJECT_NAME]]"
|
||||||
|
port = "port-app"
|
||||||
|
|
||||||
|
# Traefik-specific tags for routing
|
||||||
|
tags = [
|
||||||
|
"PORT=${NOMAD_PORT_port-app}"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Define a health check using TCP
|
||||||
|
check {
|
||||||
|
name = "tcp_check"
|
||||||
|
type = "tcp"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "2s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task "[[PROJECT_NAME]]-task" {
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "registry.i80.dk/gitea/[[PROJECT_NAME]]:latest"
|
||||||
|
ports = ["port-app"]
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
APP_ENV = "production"
|
||||||
|
PORT = "${NOMAD_PORT_port-app}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 250
|
||||||
|
memory = 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.venv
|
||||||
|
.venv/*
|
||||||
|
.ídea
|
||||||
|
.idea/*
|
||||||
|
.gitea/**/build*/
|
||||||
|
|
||||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Base image with Python 3.11
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Set the working directory in the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the requirements file to the working directory
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
# Install Python dependencies
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Copy the rest of the application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose the port the app runs on (default Flask port)
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
# Define environment variables
|
||||||
|
ENV FLASK_APP=app.py
|
||||||
|
ENV FLASK_RUN_HOST=0.0.0.0
|
||||||
|
ENV PORT=5000
|
||||||
|
# Command to run the application
|
||||||
|
#CMD ["flask", "run", "--port", "${PORT}"]
|
||||||
|
CMD flask run --port ${PORT}
|
||||||
BIN
project-installer
Executable file
BIN
project-installer
Executable file
Binary file not shown.
0
requirements.txt
Normal file
0
requirements.txt
Normal file
Reference in New Issue
Block a user