# Project Name - Technical Description ## Architecture Overview This deployment system follows a containerized architecture pattern using Docker as the runtime environment. The system is designed to be self-contained, configurable, and easily deployable across different environments. ### System Components ``` ┌─────────────────────────────────────────────────────────────────┐ │ Deployment Script │ │ (deploy-project.sh) │ │ - Configuration loader │ │ - Interactive wizard │ │ - Docker image builder (ephemeral) │ │ - Container orchestrator │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Configuration Layer │ │ (.env file) │ │ - Environment variables │ │ - Volume bindings │ │ - Network settings │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Docker Runtime │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Container │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Application │ │ Volumes │ │ Network │ │ │ │ │ │ (manual) │ │ (Persistent)│ │ Interfaces │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ │ CMD: tail -f /dev/null (ephemeral runtime) │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Script Structure ### Core Functions #### Configuration Management ```bash # Load environment from .env file load_env_file() { if has_env_file; then set -a source "${ENV_FILE}" set +a fi } # Save configuration to .env file save_env_file() { cat > "${ENV_FILE}" << EOF # Configuration INSTANCE_NAME="${INSTANCE_NAME}" IMAGE_NAME="${IMAGE_NAME}" IMAGE_TAG="${IMAGE_TAG}" EOF } ``` #### State Detection ```bash # Check if container exists has_container() { docker ps -a --format '{{.Names}}' | grep -q "^${INSTANCE_NAME}$" } # Check if container is running is_container_running() { docker ps --format '{{.Names}}' | grep -q "^${INSTANCE_NAME}$" } ``` #### Interactive Prompts ```bash prompt_user() { local prompt_text="$1" local default_value="$2" local var_name="$3" echo -n "${prompt_text} [${default_value}]: " local user_input if [ -r /dev/tty ]; then read user_input "${BUILD_CONTEXT_DIR}/Dockerfile" << 'DOCKERFILE' # Base image FROM alpine:3.19 # Install any required dependencies RUN apk add --no-cache bash coreutils # Create application directory WORKDIR /app # Create data and config directories RUN mkdir -p /app/data /app/config # Keep container running indefinitely without starting any application # tail -f /dev/null runs forever, allowing users to exec in and run commands manually CMD ["tail", "-f", "/dev/null"] DOCKERFILE log_success "Build context created" } ``` ### Image Build ```bash build_image() { log_info "Building Docker image: ${FULL_IMAGE_NAME}" # Create build context create_build_context # Build the image docker build -t "${FULL_IMAGE_NAME}" "${BUILD_CONTEXT_DIR}" log_success "Docker image built successfully" } ``` ### Cleanup (Ephemeral Policy) ```bash cleanup_build_context() { if [ -d "${BUILD_CONTEXT_DIR}" ]; then rm -rf "${BUILD_CONTEXT_DIR}" log_info "Cleaned up ephemeral build context" fi } ``` ## Docker Configuration ### Container Creation The script uses `docker run` with the following pattern: ```bash docker run -d \ --name "${INSTANCE_NAME}" \ --restart unless-stopped \ $(build_volume_args) \ $(build_network_args) \ -e TZ="${TZ:-UTC}" \ "${FULL_IMAGE_NAME}" ``` ### Volume Management Volumes are configured in the `.env` file as an array: ```bash VOLUMES=( "_data-vol:/app/data" "_config-vol:/app/config" ) ``` The script processes these into Docker volume flags: ```bash build_volume_args() { local args="" for vol in "${VOLUMES[@]}"; do local src=$(echo "$vol" | cut -d: -f1) local dst=$(echo "$vol" | cut -d: -f2) # Handle named volumes (start with _) if [[ "$src" == _* ]]; then src="${INSTANCE_NAME}${src}" # Create volume if not exists docker volume inspect "${src}" &>/dev/null || \ docker volume create "${src}" >/dev/null fi args="$args -v ${src}:${dst}" done echo "$args" } ``` ### Network Configuration ```bash NETWORKS=( "_internal-net" # Auto-prefixed with instance name ) ``` ```bash build_network_args() { local args="" for net in "${NETWORKS[@]}"; do # Handle named networks (start with _) if [[ "$net" == _* ]]; then net="${INSTANCE_NAME}${net}" # Create network if not exists docker network inspect "${net}" &>/dev/null || \ docker network create "${net}" >/dev/null fi args="$args --network ${net}" done echo "$args" } ``` ## Error Handling ### Exit Codes | Code | Meaning | |------|---------| | 0 | Success | | 1 | General error | | 2 | Configuration error | | 3 | Docker error | | 4 | Network error | ### Error Recovery ```bash # Trap errors and cleanup trap cleanup_on_error ERR cleanup_on_error() { log_error "Deployment failed. Cleaning up..." docker rm -f "${INSTANCE_NAME}" 2>/dev/null || true cleanup_build_context exit 1 } ``` ## Logging System ### Color-Coded Output ```bash RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } ``` ### Debug Mode ```bash if [ "${DEBUG}" = "true" ] || [ "${DEBUG}" = "1" ]; then set -x # Enable command tracing fi ``` ## Security Considerations ### Environment Variables - Sensitive data stored in `.env` (should be protected) - No secrets logged to console - File permissions should be restricted: `chmod 600 .env` ### Container Security - Runs as root by default (can be modified in Dockerfile) - Network isolation via Docker networks - Minimal base image (Alpine) ### Volume Permissions ```bash # Volumes are mounted with specific ownership # Can be configured in Dockerfile with RUN chown ``` ## Performance Optimization ### Local Build No network pull required for application image: - Faster deployment - Works offline after base image cached - No registry dependencies ### Cleanup ```bash # Remove old container before creating new remove_container # Cleanup build context immediately cleanup_build_context # Prune unused images (optional) docker image prune -f ``` ## Extension Points ### Custom Dockerfile Modify the `create_build_context()` function to customize: ```bash # Add custom packages RUN apk add --no-cache # Add custom users RUN addgroup -g 1000 appgroup && \ adduser -u 1000 -G appgroup -s /bin/bash -D appuser # Set custom workdir WORKDIR /app # Copy application files COPY . /app # Set entrypoint ENTRYPOINT ["/app/entrypoint.sh"] # Keep ephemeral runtime CMD ["tail", "-f", "/dev/null"] ``` ### Custom Hooks Add custom logic at these points: ```bash # Pre-deployment hook pre_deploy() { # Custom validation or setup } # Post-deployment hook post_deploy() { # Health checks, notifications, etc. } ``` ## Testing Strategy ### Unit Tests Test individual functions: ```bash test_has_container() { # Mock docker command # Assert expected behavior } ``` ### Integration Tests Test full deployment flow: ```bash test_full_deployment() { # Run script # Verify container running # Verify configuration # Cleanup } ``` ## Version History | Version | Date | Changes | |---------|------|---------| | 1.0.0 | 2026-01-01 | Initial release with ephemeral runtime policy | # AI Prompt - The content is organised into distinct sections according to the topics below. (Grouped by section) - Messages are sorted chronologically, with the most recent at the top and the oldest at the bottom. (Sorted by date: newest first, oldest last.) ## AI Prompt habit as a reminder - Refer to `Design_Doc/instructions.md` ## Design - I have the following reference project(s) i built before, you go to find the common structure including the folder(s) structure and file(s) with their content except the content as for corresponding project only. These deployment scripts are for auto. deployment application with docker by bash script. - You can read the public sites: - [rvs-prxy](https://app.radicle.xyz/nodes/ash.radicle.garden/rad%3Az3ASs6eodxMzh17pJv4NFbNWELhas) - [qwen-code-cntr](https://app.radicle.xyz/nodes/ash.radicle.garden/rad:z3w8yKCUpzzeVguFnCCWFcQtVeYnV) - [web-srv-nginx-depl](https://app.radicle.xyz/nodes/ash.radicle.garden/rad%3Az3eqQeA4nVrMPgs75H2M3jTLAJha5) - [wg-deploy](https://app.radicle.xyz/nodes/ash.radicle.garden/rad%3Az32iTB6h6Nz9t5CPnwfjnSnHTQ7K1) - Remark, if you are: - VsCode Copilot: not sure can read or not, but not handle the corresponding sites. - qwen-code: canNOT access JS website - OR you read them from the corresponding folder at local current computer - [rvs-prxy](../../cmptr-infra/rvs-prxy) - [qwen-code-cntr](../../cmptr-infra/qwen-code) - [web-srv-nginx-depl](../../pt-ai-big-data-iot-struc/web-app-pf/web-srv-nginx-depl) - [wg-deploy](../../cmptr-infra/vpn/wg/wg) - Remark, if you are: - VsCode Copilot: canNOT access computer folders, need to manually add folder into workspace, then attached those files one by one. - qwen-code: can read other folders in same computer, just do it. - You collect the common items including folders and file's content. Then you build this scaffold at current folder. - Result - structure I've created: 1 scaffold-deply/ 2 ├── README.md # Project overview with documentation links 3 ├── deploy-project.sh # Main deployment script (executable) 4 ├── .env.sample # Configuration template 5 ├── .gitignore # Git ignore rules 6 └── Design_Doc/ 7 ├── Spec.md # Specifications and features 8 ├── Operations.md # User guide and troubleshooting 9 └── Tech_Desc.md # Technical architecture details Common structure extracted from your reference projects: 1. Documentation Structure (4 files): - README.md - Simple overview, links to detailed docs - Design_Doc/Spec.md - Features, capabilities, requirements - Design_Doc/Operations.md - Quick start, common operations, troubleshooting - Design_Doc/Tech_Desc.md - Architecture, code structure, technical details 2. Deploy Script Features: - Color-coded output (INFO, SUCCESS, WARNING, ERROR) - Interactive wizard via /dev/tty (works with curl | bash) - State detection (.env exists? container exists?) - Four scenarios: new setup, reinstall, renew, update - Configuration persistence in .env - Docker volume/network/port management - Help/usage function 3. Configuration: - .env.sample template with documented variables - .gitignore protecting sensitive data To use: Copy this scaffold, rename deploy-project.sh to your project name, and customize the variables and Docker image settings. - Do not need `.env.sample` and `.gitignore` in this scaffold - Remember to add "ephemeral runtime policy", reference - Result Scaffold updated successfully. Here's the final structure: 1 scaffold-deply/ 2 ├── README.md # Project overview with ephemeral runtime highlights 3 ├── deploy-project.sh # Main deployment script (executable, 11KB) 4 └── Design_Doc/ 5 ├── Spec.md # Specifications with ephemeral runtime policy 6 ├── Operations.md # User guide with manual exec instructions 7 ├── Tech_Desc.md # Technical architecture with build/cleanup details 8 └── instructions.md # Task instructions (preserved) Key changes made: 1. Removed: .env.sample and .gitignore (per instructions) 2. Added Ephemeral Runtime Policy: - Docker image built locally from embedded Dockerfile in script - Build context (.app-build/) created temporarily, cleaned up immediately - Container runs with CMD ["tail", "-f", "/dev/null"] for manual exec - No external image dependencies 3. Updated all documentation to reflect: - Local image build process - Manual exec mode (docker exec -it bash) - Clean operation (no leftover build files) - Four-scenario smart setup - I aim to add a "Deployment Complete Output", you reference to `../../pt-ai-big-data-iot-struc/web-app-pf/web-srv-nginx-depl/Design_Doc/Operations.md` -> Section "Deployment Complete Output", then implement into this scaffold, including script and corresponding document(s). - Result 1. Deploy Script (`deploy-project.sh`): - Added show_deployment_complete() function that displays a formatted summary box with: - Re-Run Container instructions - Container Accessing command (docker exec -it -u root) - View Logs command (docker logs --tail 50) - Inspect command - Remove Container command - Remove Volumes command (auto-lists all instance volumes) - Updated validate_deployment() to call show_deployment_complete() on success 2. Operations Guide (`Design_Doc/Operations.md`): - Added new "Deployment Complete Output" section after Quick Start - Shows example output with formatted command reference box - Includes note about volume naming convention Final Scaffold Structure: 1 scaffold-deply/ 2 ├── README.md # 4.3KB 3 ├── deploy-project.sh # 12KB (with Deployment Complete Output) 4 └── Design_Doc/ 5 ├── Spec.md # 6.5KB 6 ├── Operations.md # 6.8KB (with Deployment Complete Output section) 7 ├── Tech_Desc.md # 17KB (AI Prompt section preserved) 8 └── instructions.md # 3.4KB - I aim to add a "Deployment Complete Output" with "Container Accessing" which has node and root users, you reference to `../../cmptr-infra/qwen-code/Design_Doc/Operations.md` -> Section "Deployment Complete Output", then implement into this scaffold, including script and corresponding document(s). - Result 1. Deploy Script (deploy-project.sh) Updated show_deployment_complete() function to show both user options: 1 Container Accessing: 2 docker exec -it -u root ${INSTANCE_NAME} bash 3 docker exec -it -u node ${INSTANCE_NAME} bash 2. Operations Guide (Design_Doc/Operations.md) - Updated example output to show both root and node user access commands - Added explanatory note: - root user: Full privileges for administrative tasks - node user: Non-root, limited privileges for regular application operations Final Scaffold Structure 1 scaffold-deply/ 2 ├── README.md # 4.3KB 3 ├── deploy-project.sh # 12.5KB (with dual-user Container Accessing) 4 └── Design_Doc/ 5 ├── Spec.md # 6.5KB 6 ├── Operations.md # 7.1KB (updated with dual-user access note) 7 ├── Tech_Desc.md # 18.5KB (AI Prompt section preserved) 8 └── instructions.md # 3.4KB The "Container Accessing" section now shows both root and node user options, following the qwen-code project's pattern. Users can choose the appropriate privilege level for their task.