分享自己的页游运维架构

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介:

简单画了个图:

wKiom1T5SaGhOLMgAATkhf2Qem8539.jpg


首先,后端程序及客户端都是分成三个版本:内部测试版,线上测试版,线上稳定版。线上测试版是小范围更新,经过一天测试没问题,然后再推到线上稳定版,更新其他服,一般游戏也都是按这个流程来更新的。


运维管理后台,记录了区服信息,提供各种简单API接口给各脚本使用。


然后批量维护脚本,create_list.py是根据运维管理后台提供的API,根据输入的参数(平台,区服范围)生成一份cqbyupdate.py需要使用的iplist文件,然后cqbyupdate.py根据这份ip文件执行相应的操作。


saltstack,是用于全服修改一些配置使用,例如批量修改zabbix的配置,批量修改nginx的配置 等等。


rsync,用于数据同步,例如给游戏服拉取最新版本。


游戏服最关键的只有一个control.py脚本,该脚本集成了管理单个游戏区服的所有操作,根据传进去的版本参数及动作参数执行对应的操作。


整套架构的优点是全服维护可用cqbyupdate.py脚本操作,如果临时游戏服上想做些什么更新,可用单服脚本control.py操作,比较灵活;缺点是对中心机依赖比较高,万一中心机岩了,就麻烦大了,所以搞了一台备份中心机。这套架构已经上线开服3000+


control.py单服维护脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
#!/usr/bin/python
#coding=utf-8
 
import  subprocess
import  shutil
import  os
import  sys
reload (sys)
sys.setdefaultencoding( 'utf-8' )
import  optparse
import  ConfigParser
import  time
import  jinja2
import  urllib2
import  json
import  socket
try :
     import  fcntl
except :
     pass
import  struct
import  MySQLdb
 
def  get_ip_address(ifname):
     =  socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     return  socket.inet_ntoa(fcntl.ioctl(
         s.fileno(),
         0x8915 ,   # SIOCGIFADDR
         struct.pack( '256s' , ifname[: 15 ])
     )[ 20 : 24 ])
 
 
class  Cqby:
 
     def  __init__( self , version, platform, platformid,  id ):
         self .version  =  version
         self .platform  =  platform
         self .platformid  =  platformid
         self . id  =  id
 
         #工作目录:
         self .workdir  =  '/data/init'
 
         #定义游戏程序目录:
         self .gamedir  =  '/data/game/game%s'  %  self . id
         try :
             os.makedirs( '/data/game' )
         except :
             print  "目录已存在"
 
         #当前游戏聊天监控目录:
         self .chatdir  =  '/data/game/chat%s'  %  self . id
 
         #定义游戏端口:
         if  int ( self . id ) >  50000 :
             self .gameport  =  str ( self . id )
         else :
             self .gameport  =  20000  +  int ( self . id )
             self .gameport  =  str ( self .gameport)
 
         try :
             self .localip = get_ip_address( 'eth0' )
         except :
             self .localip = get_ip_address( 'em1' )
 
         #定义数据库名称:
         self .dbname  =  'game%s'  %  self . id
 
         #定义管理员使用的数据库帐号密码:
         self .admindbuser  =  'root'
         self .admindbpass  =  '123456'
 
         #定义备份目录:
         self .backup  =  '/data/backup'
         try :
             os.makedirs( self .backup)
         except :
             print  "目录已经存在"
 
         #建立日志目录:
         self .gamelogdir  =  '/data/gamelogs/chuanqi/%s/S%s'  %  ( self .platform,  self . id )
         if  not  os.path.isdir( self .gamelogdir):
             os.makedirs( self .gamelogdir)
         subprocess.call( 'chown www:www -R /data/gamelogs' ,shell = True )
 
         #程序配置文件模板:
         self .binConfigDir  =  '%s/bin'  %  self .gamedir
         self .binConfigFiles  =  [ 'socket.jinja2' ]
 
         self .confConfigDir  =  '%s/conf'  %  self .gamedir
         self .confConfigFiles  =  [ 'jade.cfg.jinja2' ]
 
         self .independentConfigDir  =  '%s/conf/independent'  %  self .gamedir
         self .independentConfigFiles  =  [
             'auth.properties.jinja2' ,
             'debug.properties.jinja2' ,
             'fcm.properties.jinja2' ,
             'gm.properties.jinja2' ,
             'net.properties.jinja2' ,
             'server.properties.jinja2' ,
             'whiteList.properties.jinja2' ,
             'onlineLimit.properties.jinja2' ,
         ]
 
         self .miscConfigDir  =  '%s/conf/config/common'  %  self .gamedir
         self .miscConfigFiles  =  [
             'misc.properties.jinja2' ,
         ]
 
         #数据库权限:
         baselist  =  [ '127.0.0.1' ,]
         payIPListAll  =  {
             '37wan' : [],
             'liebao' : [],
             '2345' : [],
             'yilewan' : [],
             'renrenwang' : [],
             '6711' : [],
             '1360' : [],
             'duowan' : [],
             'baidu' : [],
             'lianyun' : [],
             'tencent' : []
         }
         try :
             self .platformPayList  =  payIPListAll[ self .platform]
         except :
             self .platformPayList  =  payIPListAll[ 'lianyun' ]
 
         self .payList  =  baselist  +  self .platformPayList
 
         self .mergelist  =  self .__getMerge()
 
     def  __getMerge( self ):
         '''获取合服列表'''
         =  0
         while  True :
             try :
                 if  i > =  3 :
                     print  "请求超时!!!!!!"
                     sys.exit( 2 )
                 url  =  'http://yw.admin.xxx.com/yunwei/api/getmergetarget/%s/%s/'  %  ( self .platform,  self . id )
                 request  =  urllib2.urlopen(url)
                 response  =  request.read().split( ',' )
             except  Exception, e:
                 print  "请求合服信息失败:"  +  str (e)
                 print  "正在重试。。。"
                 =  +  1
             else :
                 break
         return  response
 
     def  createDatabase( self ):
         '''创建数据库'''
         try :
             print  "正在创建数据库:%s"  %  self .dbname
             cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' -e "create database %s DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" '''  %  ( self .admindbuser,  self .admindbpass,  self .dbname)
             ret  =  subprocess.call(cmd,shell = True )
             print  "执行状态:%s"  %  ret
             if  ret:
                 print  "创建数据库失败,请确认!"
                 sys.exit( 2 )
         except  Exception,e:
             print  "捕捉到异常:" ,e
             sys.exit( 2 )
 
     def  updateDB( self , filename):
         ''' 导入数据库文件 '''
         try :
             print  "正在导入SQL文件:%s"  %  filename
             cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' %s < %s '''  %  ( self .admindbuser,  self .admindbpass,  self .dbname, filename)
             ret  =  subprocess.call(cmd, shell = True )
             print  "执行状态:%s"  %  ret
         except  Exception,e:
             print  "捕捉到异常:" ,e
             sys.exit( 2 )
 
     def  dumpDatabase( self ):
         ''' 备份数据库 '''
         try :
             print  "正在备份数据库:%s"  %  self .dbname
             curTime  =  time.strftime( '%Y%m%d%H%M%S' , time.localtime(time.time()))
             cmd  =  ''' /usr/local/mysql/bin/mysqldump -u'%s' -p'%s' %s > %s '''  %  ( self .admindbuser,  self .admindbpass,  self .dbname, ' % s / % s - % s.sql'  %  ( self .backup,curTime, self .dbname))
             ret  =  subprocess.call(cmd, shell = True )
             print  "执行状态:%s"  %  ret
         except  Exception,e:
             print  "捕捉到异常:" ,e
 
     def  dropDatabase( self ):
         ''' 删除数据库 '''
         try :
             print  "正在删除数据库:%s"  %  self .dbname
             cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' -e "drop database %s" '''  %  ( self .admindbuser,  self .admindbpass,  self .dbname)
             ret  =  subprocess.call(cmd, shell = True )
             print  "执行状态:%s"  %  ret
         except  Exception,e:
             print  "捕捉到异常:" ,e
 
     def  createGameDir( self ):
         ''' 创建游戏目录 '''
         try :
             print  "正在检测目录是否存在:%s"  %  self .gamedir
             if  os.path.isdir( self .gamedir):
                 print  "目录已存在,请检查参数!"
                 sys.exit( 2 )
             else :
                 print  "正在复制程序文件至:%s"  %  self .gamedir
                 shutil.copytree( '%s/%s/server'  %  ( self .workdir,  self .version),  self .gamedir)
         except  Exception,e:
             print  "捕捉到异常:" ,e
             sys.exit( 2 )
 
     def  dropGameDir( self ):
         ''' 清理游戏目录 '''
         try :
             print  "正在删除游戏目录:%s"  %  self .gamedir
             if  os.path.isdir( self .gamedir):
                 shutil.rmtree( self .gamedir)
         except  Exception,e:
             print  "遇到错误:" ,e
 
     def  dropGameLogDir( self ):
         ''' 清理游戏日志目录 '''
         try :
             print  "正在删除日志目录:%s"  %  self .gamelogdir
             if  os.path.isdir( self .gamelogdir):
                 shutil.rmtree( self .gamelogdir)
         except  Exception,e:
             print  "遇到错误:" ,e
 
     def  createConfig( self , configdir, configlist):
         '''创建程序配置'''
         try :
             print  "正在生成配置文件:%s"  %  configdir
             url  =  'http://yw.admin.xxx.com/yunwei/api/getmem/%s/%s'  %  ( self .platform,  self . id )
             response  =  urllib2.urlopen(url)
             mem  =  response.read()
             env  =  jinja2.Environment(loader = jinja2.FileSystemLoader(configdir))
             for  gateconfig  in  configlist:
                 print  gateconfig
                 template  =  env.get_template(gateconfig)
                 =  open ( '%s/%s'  %  (configdir,gateconfig.rstrip( '.jinja2' )),  'w' )
                 f.write(
                     template.render(
                         version = self .version,
                         platformid = self .platformid,
                         platform = self .platform,
                         gameid = self . id ,
                         gameport = self .gameport,
                         gamedir = self .gamedir,
                         dbuser = 'game' ,
                         dbpass = 'game123456' ,
                         dbname = self .dbname,
                         paylist = self .platformPayList,
                         mem = mem,
                         mergelist = self .mergelist,
                     )
                 )
                 f.close()
         except  Exception,e:
             print  "生成配置文件遇到错误:" ,e
             sys.exit( 2 )
 
     def  updateconfig( self ):
         self .createConfig( self .binConfigDir,  self .binConfigFiles)
         os.chmod( '%s/bin/socket'  %  self .gamedir, 0755
         self .createConfig( self .confConfigDir,  self .confConfigFiles)
         self .createConfig( self .independentConfigDir,  self .independentConfigFiles)
         #self.createConfig(self.miscConfigDir, self.miscConfigFiles)
 
     def  updategame( self ):
         print  "正在更新游戏程序。。。"
         cmd  =  ''' rsync -avzP --exclude="socket" --exclude="log"  --exclude="onlineLimit.properties" --exclude="jade.cfg" --exclude="auth.properties" --exclude="debug.properties" --exclude="fcm.properties" --exclude="gm.properties" --exclude="net.properties" --exclude="server.properties" --exclude="whiteList.properties"  %s/%s/server/  %s/ '''  %  ( self .workdir, self .version, self .gamedir)
         print  cmd
         result  =  subprocess.call(cmd, shell = True )
         return  result
 
     def  start( self ):
         print  "给JSVC添加执行权限:"
         os.chmod( '%s/bin/jsvc'  %  self .gamedir, 0755 )
         print  "正在启动服务:"
         cmd  =  '''cd %s/bin ; ./socket  start '''  %  self .gamedir
         result  =  subprocess.call(cmd, shell = True )
         return  result
  
     def  stop( self ):
         print  "正在关闭服务:"
         cmd  =  '''cd %s/bin ; ./socket  stop '''  %  self .gamedir
         result  =  subprocess.call(cmd, shell = True )
         return  result
 
     def  clearnow( self ):
 
         self .dumpDatabase()
 
         self .updateDB( '%s/%s/server/sql/database.sql'  %  ( self .workdir, self .version))
 
         self .dropGameLogDir()
 
     def  clear( self ):
         try :
             conn  =  MySQLdb.connect(user = self .admindbuser, passwd = self .admindbpass, host = 'localhost' , db = self .dbname, unix_socket = '/tmp/mysql.sock' )
             cursor  =  conn.cursor(cursorclass  =  MySQLdb.cursors.DictCursor)
             sql  =  ''' select * from Player '''
             sum  =  cursor.execute(sql)
             cursor.close()
             conn.close()
             print  "数据库Player表有:%s"  %  sum
             if  int ( sum ) >  30 :
                 print  "Player表记录总数大于30!请确认后再执行清档操作!!!"
                 sys.exit( 2 )
             else :
                 print  "Player表记录总数小于30,可以执行清档操作!"
                 self .stop()
                 self .clearnow()
                 self .start()
         except  Exception,e:
             print  "连接数据库错误:%s"  %  e
             sys.exit( 2 )
 
 
     def  create( self ):
         '''一键搭服'''
         self .createDatabase()
         self .updateDB( '%s/%s/server/sql/database.sql'  %  ( self .workdir, self .version))
         self .mysqlgrant()
         self .createGameDir()
         self .updateconfig()
         self .createchat()
         self .nginxlogs()
 
     def  drop( self ):
         self .dumpDatabase()
         self .dropDatabase()
         self .dropGameDir()
         self .dropGameLogDir()
         self .dropchat()
 
     def  onekey( self ):
         '''一键更新'''
         self .stop()
         time.sleep( 10 )
         self .updategame()
         self .start()
 
     def  mysqlgrant( self ):
         '''添加数据库授权'''
         print  "正在添加数据库授权:"
 
         for  ip  in  self .payList:
             print  "正在添加%s权限"  %  ip
             cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' -e "grant all privileges on *.* to game@'%s' Identified by 'cqbygame'" '''  %  ( self .admindbuser,  self .admindbpass, ip)
             subprocess.call(cmd, shell = True )
 
         cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' -e "grant select on *.* to db@'119.131.244.178' identified by 'lizhenjie';" '''  %  ( self .admindbuser,  self .admindbpass)
         subprocess.call(cmd, shell = True )
 
if  __name__  = =  "__main__" :
     active_list  =  [ 'create' 'drop' 'updateconfig' 'start' 'stop' 'clear' 'updategame' 'updateDB' , 'onekey' , 'mysqlgrant' , 'clearnow' ]
     gamever_list  =  [ 'test' , '37dev' , '37stable' ]
 
     usage  =  ''' usage: %prog -p platform
                        %prog -v version -i id -a action
                        %prog -v version -i id -a updateDB -s sqlfile
     '''
     parser  =  optparse.OptionParser(
         usage    =  usage,
         version  =  "%prog 2.0"
     )
 
     setplat_opts  =  optparse.OptionGroup(
         parser,  '设置服务器平台标识' ,
         '一台硬件服务器设置一次即可。'
     )
 
     setplat_opts.add_option(
         '-p' , '--platform' ,
         dest = "platform" ,
         help = "平台名称"
     )
 
     parser.add_option_group(setplat_opts)
 
     tools_opts  =  optparse.OptionGroup(
         parser,  '服务器日常功能' ,
     )
 
     tools_opts.add_option(
         '-v' , '--ver' ,
         dest = "ver" ,
         help = "版本目录" ,
         type = "choice"  ,
         choices = gamever_list,
         default = gamever_list[ 1 ]
     )
     tools_opts.add_option(
         '-i' , '--id' ,
         dest = 'id' ,
         help = "服务器ID"
     )
     tools_opts.add_option(
         '-a' , '--action' ,
         dest = 'action' ,
         help = "执行动作" ,
         type = "choice"  ,
         choices = active_list
     )
     tools_opts.add_option(
         '-s' , '--sql' ,
         dest = 'sql' ,
         help = "SQL文件(可选,配合updateDB使用)"
     )
 
     parser.add_option_group(tools_opts)
 
     options, args  =  parser.parse_args()
 
     err_msg  =  '参数不对,请输--help查看详细说明!'
 
     ini  =  'platform.ini'
     if  options.platform:
         apiurl  =  'http://yw.admin.xxx.com/yunwei/api/getplatforminfo/'
         ini  =  'platform.ini'
         result  =  urllib2.urlopen(apiurl)
         response  =  json.loads(result.read())
         for  code,  id  in  response.items():
             if  options.platform  = =  code:
                 platformid  =  id
                 print  "正在设置服务器标识为:%s-%s"  %  (platformid, options.platform)
                 cfd  =  open (ini,  'w' )
                 conf  =  ConfigParser.ConfigParser()
                 conf.add_section( 'platforminfo' )
                 conf. set ( 'platforminfo' , 'name' ,options.platform)
                 conf. set ( 'platforminfo' , 'id' ,platformid)
                 conf.write(cfd)
                 cfd.close()
                 break
         sys.exit( 0 )
 
     if  options. id  and  options.ver  and  options.action:
 
         cf  =  ConfigParser.ConfigParser()
         cf.read(ini)
         platform  =  cf.get( 'platforminfo' , 'name' )
         platformid  =  cf.get( 'platforminfo' , 'id' )
 
         cqby  =  Cqby(options.ver, platform, platformid, options. id )
         run_function  =  getattr (cqby,options.action)
 
         if  options.action  in  [ 'updateDB' ,]:
             run_function( '%s/server/sql/%s'  %  (options.ver,options.sql))
         else :
             run_function()
     else :
         parser.error(err_msg)


cqbyupdate.py批量维护脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/python
#coding:utf-8
 
import  threading
import  Queue
import  subprocess
import  optparse
import  logging
import  logging.config
import  datetime
import  os
import  sys
 
reload (sys)
sys.setdefaultencoding( 'utf-8' )
 
#test:
import  time
 
 
#logging.basicConfig(level = logging.DEBUG,format='(%(threadName)-10s) %(message)s',)
logging.config.fileConfig( "logger.conf" )
logger  =  logging.getLogger( "root" )
logger2  =  logging.getLogger( "file" )
queue  =  Queue.Queue()
 
Failed_List  =  []
 
class  Ahdts(threading.Thread):
     def  __init__( self , queue):
         super (Ahdts, self ).__init__()
         self .queue  =  queue
         self .workdir  =  '/data/init'
 
         #建立日志目录:
         log_path  =  'updatelog'
         today  =  datetime.date.today()
         self .log_path_today  =  '%s/%s'  %  (log_path,today)
         if  not  os.path.isdir( self .log_path_today):
             try :
                 os.makedirs( self .log_path_today)
             except  Exception,e:
                 print  e
                 sys.exit( 2 )
 
     def  run( self ):
         while  True :
             global  action
             global  sqlfile
 
             item  =  self .queue.get()
 
             value  =  item.strip().split( ',' )
             platform  =  value[ 0 ]
             id  =  value[ 1 ]
             ip  =  value[ 2 ]
             port  =  value[ 3 ]
             opentime  =  value[ 4 ]
 
             logging.debug( "%10s %6s %15s %15s %10s ThreadingStart!"  %  (platform, id ,ip,action,ver))
 
 
             if  action  = =  'rsync' :
                 cmd  =  ''' cd %s ; ./rsync '''  %  self .workdir
             elif  action  = =  'ntp' :
                 cmd  =  ''' cd %s ; ./TimeClient.py '''  %  self .workdir
             elif  action  in  [ 'updateDB' ,]:
                 cmd  =  '''  cd %s ; ./control.py -i %s -a %s -v %s -s %s '''  %  ( self .workdir,  id , action, ver, sqlfile)
             elif  action  = =  'platform' :
                 cmd  =  '''  cd %s ; ./control.py -p %s '''  %  ( self .workdir, platform)
             else :
                 cmd  =  '''  cd %s ; ./control.py -i %s -a %s -v %s '''  %  ( self .workdir,  id , action, ver)
             sshcmd  =  ''' ssh root@%s -n "%s" '''  %  (ip, cmd)
             with  open ( '%s/%s-%s-%s-%s.log'  %  ( self .log_path_today, platform,  id , ver, action),  'a' ) as logfile:
                 exitcode  =  subprocess.call(sshcmd,shell = True ,stdout = logfile, stderr = subprocess.STDOUT)
 
             if  exitcode  = =  0 :
                 logger2.debug( '%10s %6s %15s %15s %10s %s'  %  (platform,  id , ip, action, ver, cmd))
 
             rettxt  =  '%10s %6s %15s %15s %10s ThreadingEnd! ExitCode:%s'  %  (platform, id ,ip,action,ver,exitcode)
 
             if  exitcode:
                 Failed_List.append(rettxt)
 
             logging.debug(rettxt)
 
             self .queue.task_done()
 
 
if  __name__  = =  "__main__" :
     action_list  =  [ 'rsync' , 'create' , 'drop' , 'start' , 'stop' , 'clear' , 'updateconfig' , 'updategame' , 'updateDB' , 'onekey' ]
     gamever_list  =  [ 'test' , '37dev' , '37stable' ]
 
     usage  =  ''' usage: %prog --file <file.ini> --action <action>
     Forexample: %prog -f game-test.ini -a create
                 %prog -f game-test.ini -a onekey
                 %prog -f game-test.ini -a updateDB -s test.sql
     '''
     parser  =  optparse.OptionParser(
         usage    =  usage,
         version  =  "%prog 1.4"
     )
 
     parser.add_option( '-f' , '--file' ,dest = "file" , help = "IP文件列表" )
     parser.add_option( '-a' , '--action' ,dest = "action" , help = "执行动作" , type = "choice" ,choices = action_list)
     parser.add_option( '-v' , '--ver' , dest = 'ver' , help = "版本目录标识" , type = "choice" ,choices = gamever_list)
     parser.add_option( '-s' , '--sql' , dest = 'sql' , help = "待更新的SQL文件" )
     options, args  =  parser.parse_args()
 
     err_msg  =  '参数不对,请输--help查看详细说明!'
 
     if  options.action  and  options.ver  and  options. file :
         with  open (options. file ) as  file :
             content  =  file .readlines()
 
         action  =  options.action
         ver  =  options.ver
         sqlfile  =  options.sql
 
         maxThreadNum  =  200
         if  len (content) <  100 :
             maxThreadNum  =  len (content)
 
         for  in  range (maxThreadNum):
             =  Ahdts(queue)
             t.setDaemon( True )
             t.start()
 
         logging.debug( "%10s %6s %15s %15s %10s"  %  ( 'PlatForm' , 'ID' , 'IP' , 'Action' , 'Version' ))
 
         iplist  =  []
         for  in  content:
             ii  =  i.strip().split( ',' )
             ip  =  ii[ 2 ]
             if  action  in  [ 'rsync' , 'platform' and  ip  in  iplist:
                 continue
             queue.put(i)
             iplist.append(ip)
         queue.join()
 
         #打印执行失败列表:
         print  '='  *  20  +  '执行失败列表'  +  '='  *  20
         if  Failed_List:
             for  in  Failed_List:
                 print  i
         else :
             print  "None"
         print  '='  *  52
 
         logging.debug( "Done" )
     else :
         print  err_msg


批量维护脚本其实就是ssh远程过去游戏服执行control.py脚本,后面看能不能改成用socket的方式去连接,把socket的东西练练手,整套东西感觉还是比较简单。

本文转自运维笔记博客51CTO博客,原文链接http://blog.51cto.com/lihuipeng/1617958如需转载请自行联系原作者


lihuipeng

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
运维 监控 Cloud Native
自动化运维的魔法书云原生之旅:从容器化到微服务架构的演变
【8月更文挑战第29天】本文将带你领略自动化运维的魅力,从脚本编写到工具应用,我们将一起探索如何通过技术提升效率和稳定性。你将学会如何让服务器自主完成更新、监控和故障修复,仿佛拥有了一本能够自动翻页的魔法书。
|
1月前
|
弹性计算 运维 网络协议
卓越效能,极简运维,Serverless高可用架构
本文介绍了Serverless高可用架构方案,当企业面对日益增长的用户访问量和复杂的业务需求时如何实现更高的灵活性、更低的成本和更强的稳定性。
|
2月前
|
弹性计算 运维 Serverless
卓越效能,极简运维,体验Serverless高可用架构,完成任务可领取转轮日历!
卓越效能,极简运维,体验Serverless高可用架构,完成任务可领取转轮日历!
|
3月前
|
运维 监控 安全
自动化运维的利剑:Ansible在现代IT架构中的应用
在数字化浪潮中,企业对IT系统的敏捷性和可靠性要求日益提高。Ansible,一种简单但强大的自动化运维工具,正成为现代IT架构中不可或缺的一部分。它通过声明式编程语言YAM,简化了系统配置、应用部署和任务自动化的过程,显著提升了运维效率和准确性。本文将深入探讨Ansible的核心特性、应用场景以及如何有效整合进现有IT环境,为读者揭示其在自动化运维中的实用价值和未来发展潜力。
|
3月前
|
运维 Devops 应用服务中间件
自动化运维的利剑:Ansible在现代IT架构中的应用
【10月更文挑战第42天】本文旨在揭示自动化运维工具Ansible如何革新现代IT架构,通过简化配置管理和部署流程,提升效率和可靠性。我们将探索Ansible的核心功能、语言特性以及其在DevOps文化中的角色。文章还将展示如何借助Ansible构建模块化和可重用的配置代码,实现快速迭代与部署,并确保系统一致性。通过阅读本文,运维人员将了解如何利用Ansible优化日常任务,加速产品上线速度,同时提高系统的稳健性。
65 5
|
4月前
|
存储 运维 监控
高效运维:从基础架构到自动化管理的全面指南
【10月更文挑战第11天】 本文将深入探讨如何通过优化基础架构和引入自动化管理来提升企业IT运维效率。我们将从服务器的选择与配置、存储解决方案的评估,到网络的设计与监控,逐一解析每个环节的关键技术点。同时,重点讨论自动化工具在现代运维中的应用,包括配置管理、持续集成与部署(CI/CD)、自动化测试及故障排除等方面。通过实际案例分析,展示这些技术如何协同工作,实现高效的运维管理。无论是IT初学者还是经验丰富的专业人员,都能从中获得有价值的见解和实操经验。
144 1
|
3月前
|
机器学习/深度学习 运维 监控
智能运维在现代IT架构中的转型之路####
【10月更文挑战第29天】 本文旨在探讨智能运维(AIOps)如何成为现代IT架构不可或缺的一部分,通过分析其核心价值、关键技术及实践案例,揭示AIOps在提升系统稳定性、优化资源配置及加速故障响应中的关键作用。不同于传统运维模式的被动响应,智能运维强调预测性维护与自动化处理,为企业数字化转型提供强有力的技术支撑。 ####
110 0
|
4月前
|
存储 运维 监控
高效运维管理:从基础架构优化到自动化实践
在当今数字化时代,高效运维管理已成为企业IT部门的重要任务。本文将探讨如何通过基础架构优化和自动化实践来提升运维效率,确保系统的稳定性和可靠性。我们将从服务器选型、存储优化、网络配置等方面入手,逐步引导读者了解运维管理的核心内容。同时,我们还将介绍自动化工具的使用,帮助运维人员提高工作效率,降低人为错误的发生。通过本文的学习,您将掌握高效运维管理的关键技巧,为企业的发展提供有力支持。
|
5月前
|
敏捷开发 运维 Prometheus
构建高效运维体系:从基础架构到自动化管理
本文探讨了如何通过优化基础架构、引入自动化工具和流程,以及加强团队协作,构建高效的运维体系。通过案例分析和实践建议,帮助运维人员实现系统的稳定性、可靠性和可维护性。
134 21
|
6月前
|
运维 Kubernetes 安全
云时代的运维之光:容器化与微服务架构的融合之道
在数字化浪潮中,企业IT架构的演进从未停歇。本文以浅显的语言探讨了容器技术与微服务架构如何协同工作,提高运维效率。我们将从基础概念出发,逐步深入到它们在实际工作中的应用,最后分享一些行业内的最佳实践。无论你是运维新手还是资深专家,这篇文章都将为你带来新的视角和思考。

热门文章

最新文章