1
0

setup_deploy.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import os
  2. import sys
  3. import getpass
  4. import subprocess
  5. def clear_screen():
  6. os.system('cls' if os.name == 'nt' else 'clear')
  7. print("="*60)
  8. print(" Local Food AI - Distributed Deployment Configuration Tool")
  9. print("="*60)
  10. # Check Docker availability
  11. try:
  12. subprocess.run(["docker", "info"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
  13. print("[+] Docker is correctly configured and accessible.")
  14. except (subprocess.CalledProcessError, FileNotFoundError):
  15. print("[-] Warning: Docker is not running or not accessible. Please ensure Docker Desktop or Docker Engine is installed and running before deploying.")
  16. print("\nSelect the role for this specific node in the network:")
  17. print("1. All-in-One (Runs everything, default)")
  18. print("2. Application Frontend (Runs Streamlit, Nginx, AI Services)")
  19. print("3. Database Node (Runs MySQL & Ingestion)")
  20. print("4. Monitoring Node (Runs Zabbix Server & UI)")
  21. choice = input("\nEnter choice (1-4) [1]: ").strip() or "1"
  22. # Environment Variables
  23. env_vars = {}
  24. if choice != "1":
  25. print("\n--- Network Configuration ---")
  26. if choice != "3":
  27. env_vars['DB_HOST'] = input("Enter the IP address of the Database Node: ").strip()
  28. else:
  29. env_vars['DB_HOST'] = "mysql"
  30. if choice != "4":
  31. env_vars['ZBX_SERVER_HOST'] = input("Enter the IP address of the Monitoring Node: ").strip()
  32. else:
  33. env_vars['ZBX_SERVER_HOST'] = "zabbix-server"
  34. else:
  35. env_vars['DB_HOST'] = "mysql"
  36. env_vars['ZBX_SERVER_HOST'] = "zabbix-server"
  37. print("\n--- Security Configuration ---")
  38. env_vars['MYSQL_ROOT_PASSWORD'] = getpass.getpass("Enter MySQL Root Password (will not echo): ")
  39. env_vars['DB_READER_PASS'] = getpass.getpass("Enter DB Reader Password: ")
  40. env_vars['DB_LOADER_PASS'] = getpass.getpass("Enter DB Loader Password: ")
  41. env_vars['DB_APP_AUTH_PASS'] = getpass.getpass("Enter App Auth Password: ")
  42. env_vars['MYSQL_ZABBIX_PASSWORD'] = getpass.getpass("Enter Zabbix DB Password: ")
  43. # Generate .env
  44. print("\n[+] Generating .env file...")
  45. with open(".env", "w") as f:
  46. for k, v in env_vars.items():
  47. f.write(f"{k}={v}\n")
  48. # Base compose dictionaries
  49. compose_services = {}
  50. mysql_service = """
  51. mysql:
  52. build:
  53. context: ./docker/mysql
  54. ports:
  55. - "3307:3306"
  56. volumes:
  57. - mysql_data:/var/lib/mysql
  58. - ./my.cnf:/etc/mysql/conf.d/custom_ai_app.cnf
  59. - ./init.sql:/docker-entrypoint-initdb.d/1-init.sql
  60. environment:
  61. - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
  62. healthcheck:
  63. test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
  64. interval: 10s
  65. timeout: 5s
  66. retries: 20
  67. restart: always
  68. """
  69. ingest_service = """
  70. ingest:
  71. build:
  72. context: .
  73. dockerfile: docker/ingest/Dockerfile
  74. environment:
  75. - DB_HOST=${DB_HOST}
  76. - DB_USER=food_loader
  77. - DB_PASS=${DB_LOADER_PASS}
  78. volumes:
  79. - ./:/app
  80. profiles:
  81. - manual
  82. """
  83. ai_services = """
  84. ollama:
  85. image: ollama/ollama:latest
  86. volumes:
  87. - ollama_data:/root/.ollama
  88. restart: always
  89. searxng:
  90. image: searxng/searxng:latest
  91. ports:
  92. - "8080:8080"
  93. volumes:
  94. - ./searxng:/etc/searxng
  95. environment:
  96. - SEARXNG_BASE_URL=http://localhost:8080/
  97. restart: always
  98. """
  99. app_service = """
  100. app:
  101. build:
  102. context: .
  103. dockerfile: docker/app/Dockerfile
  104. ports:
  105. - "8502:8501"
  106. environment:
  107. - DB_HOST=${DB_HOST}
  108. - DB_USER=food_reader
  109. - DB_PASS=${DB_READER_PASS}
  110. - APP_AUTH_USER=food_app_auth
  111. - APP_AUTH_PASS=${DB_APP_AUTH_PASS}
  112. - OLLAMA_HOST=http://ollama:11434
  113. - SEARXNG_HOST=http://searxng:8080
  114. restart: always
  115. nginx:
  116. image: nginx:latest
  117. ports:
  118. - "80:80"
  119. volumes:
  120. - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
  121. restart: always
  122. """
  123. monitoring_services = """
  124. zabbix-server:
  125. image: zabbix/zabbix-server-mysql:ubuntu-7.0-latest
  126. environment:
  127. - DB_SERVER_HOST=${DB_HOST}
  128. - MYSQL_USER=zabbix
  129. - MYSQL_PASSWORD=${MYSQL_ZABBIX_PASSWORD}
  130. - ZBX_SNMPTRAPPER=1
  131. restart: always
  132. ports:
  133. - "10051:10051"
  134. zabbix-web:
  135. image: zabbix/zabbix-web-nginx-mysql:ubuntu-7.0-latest
  136. ports:
  137. - "8081:8080"
  138. - "8444:8443"
  139. environment:
  140. - DB_SERVER_HOST=${DB_HOST}
  141. - MYSQL_USER=zabbix
  142. - MYSQL_PASSWORD=${MYSQL_ZABBIX_PASSWORD}
  143. - ZBX_SERVER_HOST=zabbix-server
  144. - PHP_TZ=Europe/Paris
  145. restart: always
  146. zabbix-agent:
  147. image: zabbix/zabbix-agent:ubuntu-7.0-latest
  148. environment:
  149. - ZBX_HOSTNAME=DistributedNode
  150. - ZBX_SERVER_HOST=${ZBX_SERVER_HOST}
  151. privileged: true
  152. pid: "host"
  153. volumes:
  154. - /var/run:/var/run
  155. restart: always
  156. """
  157. airflow_services = """
  158. airflow-webserver:
  159. image: apache/airflow:2.8.1
  160. environment:
  161. - AIRFLOW__CORE__EXECUTOR=SequentialExecutor
  162. - AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=sqlite:////opt/airflow/airflow.db
  163. - AIRFLOW__CORE__LOAD_EXAMPLES=False
  164. ports:
  165. - "8082:8080"
  166. volumes:
  167. - ./dags:/opt/airflow/dags
  168. - ./logs:/opt/airflow/logs
  169. - ./data:/opt/airflow/data
  170. - /var/run/docker.sock:/var/run/docker.sock
  171. command: webserver
  172. restart: always
  173. airflow-scheduler:
  174. image: apache/airflow:2.8.1
  175. environment:
  176. - AIRFLOW__CORE__EXECUTOR=SequentialExecutor
  177. - AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=sqlite:////opt/airflow/airflow.db
  178. - AIRFLOW__CORE__LOAD_EXAMPLES=False
  179. volumes:
  180. - ./dags:/opt/airflow/dags
  181. - ./logs:/opt/airflow/logs
  182. - ./data:/opt/airflow/data
  183. - /var/run/docker.sock:/var/run/docker.sock
  184. command: bash -c "airflow db migrate && airflow users create --role Admin --username admin --email admin --firstname admin --lastname admin --password admin && airflow scheduler"
  185. restart: always
  186. """
  187. header = "services:\n"
  188. footer = """
  189. volumes:
  190. mysql_data:
  191. ollama_data:
  192. """
  193. compose_content = header
  194. if choice == "1":
  195. compose_content += mysql_service + ingest_service + ai_services + app_service + monitoring_services + airflow_services
  196. elif choice == "2":
  197. compose_content += ai_services + app_service
  198. footer = "volumes:\n ollama_data:\n"
  199. elif choice == "3":
  200. compose_content += mysql_service + ingest_service + airflow_services
  201. footer = "volumes:\n mysql_data:\n"
  202. elif choice == "4":
  203. compose_content += monitoring_services
  204. footer = ""
  205. print("\n[+] Generating docker-compose.yml for selected role...")
  206. with open("docker-compose.yml", "w") as f:
  207. f.write(compose_content + footer)
  208. print("\n" + "="*60)
  209. print("⚠️ IMPORTANT HYPERVISOR NETWORKING REMINDER:")
  210. print("If this node is running inside VirtualBox or Hyper-V, you MUST configure the VM network adapter to use a 'Bridged Adapter' or 'External Virtual Switch' so it shares the host's subnet. Otherwise, cross-node communication will fail.")
  211. print("="*60)
  212. print("\nDone! You can now run `docker compose up -d`.")