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