1+ #!/usr/bin/env python3
2+
3+ import os
4+ import requests # HTTP 요청을 위한 모듈 추가
5+ import subprocess
6+ import time
7+ from typing import Dict , Optional
8+
9+
10+ class ServiceManager :
11+ # 초기화 함수
12+ def __init__ (self , socat_port : int = 8081 , sleep_duration : int = 3 ) -> None :
13+ self .socat_port : int = socat_port
14+ self .sleep_duration : int = sleep_duration
15+ self .services : Dict [str , int ] = {
16+ 'cmf_1' : 8082 ,
17+ 'cmf_2' : 8083
18+ }
19+ self .current_name : Optional [str ] = None
20+ self .current_port : Optional [int ] = None
21+ self .next_name : Optional [str ] = None
22+ self .next_port : Optional [int ] = None
23+
24+ # 현재 실행 중인 서비스를 찾는 함수
25+ def _find_current_service (self ) -> None :
26+ cmd : str = f"ps aux | grep 'socat -t0 TCP-LISTEN:{ self .socat_port } ' | grep -v grep | awk '{{print $NF}}'"
27+ current_service : str = subprocess .getoutput (cmd )
28+ if not current_service :
29+ self .current_name , self .current_port = 'cmf_2' , self .services ['cmf_2' ]
30+ else :
31+ self .current_port = int (current_service .split (':' )[- 1 ])
32+ self .current_name = next ((name for name , port in self .services .items () if port == self .current_port ), None )
33+
34+ # 다음에 실행할 서비스를 찾는 함수
35+ def _find_next_service (self ) -> None :
36+ self .next_name , self .next_port = next (
37+ ((name , port ) for name , port in self .services .items () if name != self .current_name ),
38+ (None , None )
39+ )
40+
41+ # Docker 컨테이너를 제거하는 함수
42+ def _remove_container (self , name : str ) -> None :
43+ os .system (f"docker stop { name } 2> /dev/null" )
44+ os .system (f"docker rm -f { name } 2> /dev/null" )
45+
46+ # Docker 컨테이너를 실행하는 함수
47+ def _run_container (self , name : str , port : int ) -> None :
48+ os .system (
49+ f"docker run -d --name={ name } --restart unless-stopped -p { port } :8090 -e TZ=Asia/Seoul -v /dockerProjects/cmf/volumes/gen:/gen --pull always ghcr.io/commitfield/commitfield" )
50+
51+ def _switch_port (self ) -> None :
52+ # Socat 포트를 전환하는 함수
53+ cmd : str = f"ps aux | grep 'socat -t0 TCP-LISTEN:{ self .socat_port } ' | grep -v grep | awk '{{print $2}}'"
54+ pid : str = subprocess .getoutput (cmd )
55+
56+ if pid :
57+ os .system (f"kill -9 { pid } 2>/dev/null" )
58+
59+ time .sleep (5 )
60+
61+ os .system (
62+ f"nohup socat -t0 TCP-LISTEN:{ self .socat_port } ,fork,reuseaddr TCP:localhost:{ self .next_port } &>/dev/null &" )
63+
64+ # 서비스 상태를 확인하는 함수
65+
66+ def _is_service_up (self , port : int ) -> bool :
67+ url = f"http://127.0.0.1:{ port } /actuator/health"
68+ try :
69+ response = requests .get (url , timeout = 5 ) # 5초 이내 응답 없으면 예외 발생
70+ if response .status_code == 200 and response .json ().get ('status' ) == 'UP' :
71+ return True
72+ except requests .RequestException :
73+ pass
74+ return False
75+
76+ # 서비스를 업데이트하는 함수
77+ def update_service (self ) -> None :
78+ self ._find_current_service ()
79+ self ._find_next_service ()
80+
81+ self ._remove_container (self .next_name )
82+ self ._run_container (self .next_name , self .next_port )
83+
84+ # 새 서비스가 'UP' 상태가 될 때까지 기다림
85+ while not self ._is_service_up (self .next_port ):
86+ print (f"Waiting for { self .next_name } to be 'UP'..." )
87+ time .sleep (self .sleep_duration )
88+
89+ self ._switch_port ()
90+
91+ if self .current_name is not None :
92+ self ._remove_container (self .current_name )
93+
94+ print ("Switched service successfully!" )
95+
96+
97+ if __name__ == "__main__" :
98+ manager = ServiceManager ()
99+ manager .update_service ()
0 commit comments