613 lines
19 KiB
Markdown
613 lines
19 KiB
Markdown
# 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 </dev/tty
|
|
else
|
|
read user_input
|
|
fi
|
|
|
|
if [ -z "${user_input}" ]; then
|
|
user_input="${default_value}"
|
|
fi
|
|
|
|
eval "${var_name}='${user_input}'"
|
|
}
|
|
```
|
|
|
|
### Deployment Flow
|
|
|
|
```
|
|
1. Script Start
|
|
│
|
|
▼
|
|
2. Load Configuration
|
|
├── Check for .env file
|
|
└── Load or trigger wizard
|
|
│
|
|
▼
|
|
3. Detect State
|
|
├── Container exists?
|
|
└── Configuration exists?
|
|
│
|
|
▼
|
|
4. Execute Action
|
|
├── Setup new (wizard + create)
|
|
└── Renew (recreate with config)
|
|
│
|
|
▼
|
|
5. Build Image (Ephemeral)
|
|
├── Create build context
|
|
├── Build Docker image
|
|
└── Cleanup build context
|
|
│
|
|
▼
|
|
6. Deploy Container
|
|
├── Remove old container
|
|
├── Create volumes/networks
|
|
└── Start new container
|
|
│
|
|
▼
|
|
7. Validate
|
|
├── Container running?
|
|
└── Health check passed?
|
|
│
|
|
▼
|
|
8. Complete
|
|
```
|
|
|
|
## Ephemeral Runtime Implementation
|
|
|
|
### Build Context Creation
|
|
|
|
```bash
|
|
create_build_context() {
|
|
log_info "Creating ephemeral build context..."
|
|
|
|
# Create build directory
|
|
mkdir -p "${BUILD_CONTEXT_DIR}"
|
|
|
|
# Create Dockerfile
|
|
cat > "${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 <your-packages>
|
|
|
|
# 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 <name> 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.
|