Version control Claude Code configuration including: - Global instructions (CLAUDE.md) - User settings (settings.json) - Custom agents (architect, designer, engineer, etc.) - Custom skills (create-skill templates and workflows) Excludes session data, secrets, cache, and temporary files per .gitignore. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
251 lines
8.3 KiB
Python
Executable File
251 lines
8.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Create Docker-Ready LXC Template
|
|
Creates a fully configured LXC template with Docker pre-installed and optimized
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import time
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
from proxmox_client import ProxmoxClient
|
|
|
|
|
|
def create_docker_lxc_template(
|
|
template_id: int = 9001,
|
|
template_name: str = "docker-lxc-template",
|
|
os_template: str = "local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst",
|
|
memory: int = 2048,
|
|
cores: int = 2,
|
|
disk_size: int = 20,
|
|
storage: str = "local-lvm"
|
|
):
|
|
"""
|
|
Create a Docker-ready LXC template
|
|
|
|
Args:
|
|
template_id: Container ID for the template
|
|
template_name: Hostname for the template
|
|
os_template: Base OS template to use
|
|
memory: Memory allocation in MB
|
|
cores: CPU cores
|
|
disk_size: Root disk size in GB
|
|
storage: Storage pool to use
|
|
"""
|
|
|
|
client = ProxmoxClient()
|
|
|
|
print(f"🚀 Creating Docker-Ready LXC Template (ID: {template_id})")
|
|
print("=" * 60)
|
|
|
|
# Step 1: Check if template ID is available
|
|
print("\n📋 Step 1: Checking template ID availability...")
|
|
try:
|
|
existing = client.get_container(template_id)
|
|
print(f"❌ Container ID {template_id} already exists!")
|
|
print(f" Name: {existing.get('hostname', 'unknown')}")
|
|
response = input(" Delete existing container? (yes/no): ")
|
|
if response.lower() == 'yes':
|
|
print(f" Stopping container {template_id}...")
|
|
try:
|
|
client.stop_container(template_id)
|
|
time.sleep(5)
|
|
except:
|
|
pass
|
|
print(f" Deleting container {template_id}...")
|
|
upid = client.delete_container(template_id)
|
|
client.wait_for_task(upid, timeout=60)
|
|
print(" ✅ Container deleted")
|
|
else:
|
|
print(" Aborting...")
|
|
return False
|
|
except:
|
|
print(f"✅ Container ID {template_id} is available")
|
|
|
|
# Step 2: List available OS templates
|
|
print("\n📦 Step 2: Checking available OS templates...")
|
|
templates = client.list_container_templates()
|
|
template_found = False
|
|
for tmpl in templates:
|
|
if os_template in tmpl.get('volid', ''):
|
|
template_found = True
|
|
print(f"✅ Found OS template: {tmpl['volid']}")
|
|
break
|
|
|
|
if not template_found:
|
|
print(f"⚠️ OS template not found: {os_template}")
|
|
print(" Available templates:")
|
|
for tmpl in templates[:5]:
|
|
print(f" - {tmpl['volid']}")
|
|
print("\n Please download Ubuntu 22.04 template from Proxmox web UI:")
|
|
print(" Datacenter → <node> → local → CT Templates → Download from template")
|
|
return False
|
|
|
|
# Step 3: Create the container
|
|
print(f"\n🔨 Step 3: Creating LXC container...")
|
|
print(f" Hostname: {template_name}")
|
|
print(f" Memory: {memory}MB")
|
|
print(f" Cores: {cores}")
|
|
print(f" Disk: {disk_size}GB")
|
|
|
|
try:
|
|
upid = client.create_container(
|
|
vmid=template_id,
|
|
ostemplate=os_template,
|
|
hostname=template_name,
|
|
storage=storage,
|
|
memory=memory,
|
|
cores=cores,
|
|
rootfs=f"{storage}:{disk_size}",
|
|
net0="name=eth0,bridge=vmbr0,ip=dhcp",
|
|
nameserver="8.8.8.8",
|
|
searchdomain="localdomain",
|
|
password="temporary123", # Will be removed later
|
|
onboot=0,
|
|
unprivileged=0, # Privileged for Docker
|
|
features="nesting=1,keyctl=1" # Docker support
|
|
)
|
|
print(f" Task ID: {upid}")
|
|
print(" Waiting for container creation...")
|
|
|
|
if client.wait_for_task(upid, timeout=120):
|
|
print("✅ Container created successfully!")
|
|
else:
|
|
print("❌ Container creation failed or timed out")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"❌ Error creating container: {e}")
|
|
return False
|
|
|
|
# Step 4: Start the container
|
|
print("\n▶️ Step 4: Starting container...")
|
|
try:
|
|
upid = client.start_container(template_id)
|
|
if client.wait_for_task(upid, timeout=60):
|
|
print("✅ Container started")
|
|
time.sleep(10) # Wait for boot
|
|
else:
|
|
print("❌ Failed to start container")
|
|
return False
|
|
except Exception as e:
|
|
print(f"❌ Error starting container: {e}")
|
|
return False
|
|
|
|
# Step 5: Install Docker (via SSH or pct exec)
|
|
print("\n🐳 Step 5: Installing Docker...")
|
|
print(" You need to run these commands manually via:")
|
|
print(f" pct enter {template_id}")
|
|
print("\n Then run:")
|
|
print("""
|
|
# Update system
|
|
apt update && apt upgrade -y
|
|
|
|
# Install Docker
|
|
apt install -y docker.io docker-compose-plugin curl wget git vim htop
|
|
|
|
# Enable Docker service
|
|
systemctl enable docker
|
|
systemctl start docker
|
|
|
|
# Verify Docker
|
|
docker --version
|
|
docker run hello-world
|
|
|
|
# Clean up
|
|
apt clean
|
|
history -c
|
|
|
|
# Exit container
|
|
exit
|
|
""")
|
|
|
|
print("\n⏸️ Pausing for manual Docker installation...")
|
|
print(" Press ENTER after you've completed the Docker installation...")
|
|
input()
|
|
|
|
# Step 6: Stop the container
|
|
print("\n⏹️ Step 6: Stopping container...")
|
|
try:
|
|
upid = client.shutdown_container(template_id, timeout=60)
|
|
if client.wait_for_task(upid, timeout=90):
|
|
print("✅ Container stopped")
|
|
else:
|
|
print("⚠️ Graceful shutdown timed out, forcing stop...")
|
|
client.stop_container(template_id)
|
|
time.sleep(5)
|
|
except Exception as e:
|
|
print(f"⚠️ Error stopping container: {e}")
|
|
print(" Forcing stop...")
|
|
client.stop_container(template_id)
|
|
time.sleep(5)
|
|
|
|
# Step 7: Convert to template
|
|
print("\n📝 Step 7: Converting to template...")
|
|
print(" Run this command manually:")
|
|
print(f" pct template {template_id}")
|
|
print("\n Or via Proxmox web UI:")
|
|
print(f" Right-click container {template_id} → Convert to template")
|
|
|
|
print("\n" + "=" * 60)
|
|
print("🎉 Docker-Ready LXC Template Creation Guide Complete!")
|
|
print("\n📋 Summary:")
|
|
print(f" Template ID: {template_id}")
|
|
print(f" Hostname: {template_name}")
|
|
print(f" Resources: {memory}MB RAM, {cores} cores, {disk_size}GB disk")
|
|
print(f" Features: Docker pre-installed, nesting enabled, privileged")
|
|
print("\n🔄 Next Steps:")
|
|
print(" 1. Convert container to template (see above)")
|
|
print(" 2. Clone template for new Docker hosts:")
|
|
print(f" pct clone {template_id} <newid> --hostname <name> --full")
|
|
print(" 3. Configure network/storage for cloned containers")
|
|
print(" 4. Start and use!")
|
|
|
|
return True
|
|
|
|
|
|
def main():
|
|
"""Main entry point"""
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="Create Docker-ready LXC template")
|
|
parser.add_argument("--id", type=int, default=9001, help="Template container ID (default: 9001)")
|
|
parser.add_argument("--name", default="docker-lxc-template", help="Template hostname")
|
|
parser.add_argument("--memory", type=int, default=2048, help="Memory in MB (default: 2048)")
|
|
parser.add_argument("--cores", type=int, default=2, help="CPU cores (default: 2)")
|
|
parser.add_argument("--disk", type=int, default=20, help="Disk size in GB (default: 20)")
|
|
parser.add_argument("--storage", default="local-lvm", help="Storage pool (default: local-lvm)")
|
|
parser.add_argument("--template", default="local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst",
|
|
help="OS template path")
|
|
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
success = create_docker_lxc_template(
|
|
template_id=args.id,
|
|
template_name=args.name,
|
|
os_template=args.template,
|
|
memory=args.memory,
|
|
cores=args.cores,
|
|
disk_size=args.disk,
|
|
storage=args.storage
|
|
)
|
|
|
|
if success:
|
|
print("\n✅ Template creation process completed!")
|
|
sys.exit(0)
|
|
else:
|
|
print("\n❌ Template creation failed")
|
|
sys.exit(1)
|
|
|
|
except Exception as e:
|
|
print(f"\n❌ Error: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|