dever il y a 7 ans
Parent
commit
b392b4a51f

+ 11 - 6
README.md

@@ -211,12 +211,17 @@ dm shell
 
 
 <pre>
-2018-6-14更新:
+2018-6-20更新:
 1、增加default功能,直接使用dever run web时,只运行里面default定义的进程
-2、增加lvs
+2、增加lvs、consul等组件
 3、增加集群(简易版本):
-dm master:开启主机
-dm slave num=5&master=192.168.0.10&port=1000:开启5个从机,主机地址为192.168.0.10,端口为1000
-
-开启后,从机自动收集信息并同步到主机上
+ds init:开启集群,之后将得到集群主机ip
+ds join ip:加入到集群中
+之后的操作和dm一样
+ds run web:启动web服务组集群
+ds run web-nginx:启动nginx集群
+ds rm web-nginx:删除nginx集群
+ds update web-nginx:更新nginx集群(此命令比较复杂,最好参考docker service update)
+
+之后将把consul和daemon加入进去,并实现可视化
 </pre>

+ 3 - 2
install

@@ -20,14 +20,15 @@ tee /etc/docker/daemon.json <<-'EOF'
 EOF
 service docker restart
 
-# python 
-pip install python-daemon
+# python-daemon
+# pip install python-daemon
 
 chmod -R +x src/*.py
 chmod -R +x src/shell
 chmod -R 777 container/share/
 basepath=$(cd `dirname $0`; pwd)
 ln -sf $basepath/src/dm.py /usr/bin/dm && chmod +x /usr/bin/dm
+ln -sf $basepath/src/ds.py /usr/bin/ds && chmod +x /usr/bin/ds
 ln -sf $basepath/src/dp.py /usr/bin/dp && chmod +x /usr/bin/dp
 ln -sf $basepath/src/dpc.py /usr/bin/dpc && chmod +x /usr/bin/dpc
 ln -sf $basepath/src/dever.py /usr/bin/dever && chmod +x /usr/bin/dever

+ 47 - 7
src/core.py

@@ -62,6 +62,8 @@ class Args(object):
 class Env(object):
 	dm_use = 'base.use'
 	dm_store = 'base.store'
+	dm_cluster = 'base.cluster'
+	dm_dever = 'base.dever'
 	dm_val = 'val.'
 	data = {}
 
@@ -96,12 +98,24 @@ class Env(object):
 			return self.write(self.dm_use, value)
 		return self.read(self.dm_use)
 
+	@classmethod
+	def dever(self, value=None):
+		if value:
+			return self.write(self.dm_dever, value)
+		return self.read(self.dm_dever)
+
 	@classmethod
 	def store(self, value=None):
 		if value:
 			return self.write(self.dm_store, value)
 		return self.read(self.dm_store)
 
+	@classmethod
+	def cluster(self, value=None):
+		if value:
+			return self.write(self.dm_cluster, value)
+		return self.read(self.dm_cluster)
+
 	@classmethod
 	def val(self, name='', value=None):
 		#name = self.dm_val + name.capitalize()
@@ -197,7 +211,7 @@ class Alias(object):
 			#Core.popen('rm -rf ' + action[1], bg=True)
 			#Core.popen('rm -rf ' + action[2], bg=True)
 	@classmethod
-	def add(self, config, name, content, type):
+	def add(self, config, name, content, type, cluster=False):
 		result = self.get(config, name)
 		for key in result:
 			action = self.action(name, key)
@@ -206,19 +220,23 @@ class Alias(object):
 				old = File.get(action[1])
 			env = '#!/usr/bin/env sh \nset -e\n'
 			if type != 'call':
+				dexec = 'docker exec -it ' + name + ' ' + action[0] + ' $@'
+				if cluster:
+					dexec = 'name=`ds name ' + name + '`\n'
+					dexec = dexec + 'docker exec -it $name ' + action[0] + ' $@'
 				if action[0] == 'sh':
-					content = env + self.define(name) + \
+					content = env + self.define(name, cluster) + \
 						'else\n' + \
-						'docker exec -it ' + name + ' ' + action[0] + ' $@\n' + \
+						dexec + '\n' + \
 						'fi'
 				elif old:
-					content = 'docker exec -it ' + name + ' ' + action[0] + ' $@'
+					content = dexec
 					if content not in old:
 						content = old + '\n' + content
 					else:
 						content = ''
 				else:
-					content = env + 'docker exec -it ' + name + ' ' + action[0] + ' $@'
+					content = env + dexec
 			else:
 				content = env + ' $@'
 			if content:
@@ -226,12 +244,15 @@ class Alias(object):
 				Core.popen('ln -sf ' + action[1] + ' ' + action[2])
 
 	@staticmethod
-	def define(name):
+	def define(name, cluster=False):
 		conf = ['logs', 'inspect', 'restart', 'stop', 'rm', 'rmb', 'run', 'uprun', 'show']
 		result = ''
 		for key in conf:
 			control = 'elif'
-			shell = 'dm ' + key + ' ' + name + '\n'
+			command = 'dm'
+			if cluster:
+				command = 'ds'
+			shell = command + ' ' + key + ' ' + name + '\n'
 			if key == 'logs':
 				control = 'if'
 			result = result + control + ' [ "$1" = "'+key+'" ];then\n' + shell
@@ -321,9 +342,28 @@ class Git(object):
 			Core.popen('cd ' + path + ' && git pull', bg=True)
 			print 'update:' + path + ' finished!'
 
+class Service(object):
+	@staticmethod
+	def set(git, path):
+		if File.exists(path) == False:
+			Core.popen('git clone ' + git + ' ' + path, True)
+			print 'init:' + path + ' finished!'
+		else:
+			Core.popen('cd ' + path + ' && git pull', bg=True)
+			print 'update:' + path + ' finished!'
+
 class Core(object):
 	path = ''
 	@classmethod
+	def curl(self, url = '', param={}, method = 'get'):
+		import requests
+		if method == 'get':
+			req = requests.get(url, params=param)
+		else:
+			req = requests.post(url, params=param)
+		result = req.text
+		return result
+	@classmethod
 	def getClass(self, name, path=''):
 		obj = self.getObject(name, path)
 		if path:

+ 1 - 0
src/docker/build/service/consul/consul.sh

@@ -3,6 +3,7 @@ set -e
 
 start_consul()
 {
+	ip=`ifconfig eth0|grep "inet addr:"|awk -F":" '{print $2}'|awk '{print $1}'`
 	if [ "$1" == "server" ]; then
 		process_start consul agent -server -bootstrap-expect 1 -data-dir /root/consul/data -config-dir /root/consul/config -client 0.0.0.0
 	elif [ "$1" == "client" ]; then

+ 17 - 0
src/docker/conf/daemon.conf

@@ -0,0 +1,17 @@
+[base]
+path = {base}
+default = master
+
+[master]
+image = consul
+num = 3
+port = 8500:8500
+volumes = {container}conf/service/consul:/root/consul/config
+command = consul -server -bootstrap-expect=3 -data-dir=/root/consul/data -config-dir=/root/consul/config -client=0.0.0.0 -bind=$ip -join=daemon-master -node={name}
+alias = consul
+
+[client]
+image = consul
+volumes = {container}conf/service/consul:/root/consul/config
+command = consul -client -client=0.0.0.0 -node={name}
+alias = consul

+ 1 - 0
src/docker/conf/web.conf

@@ -32,6 +32,7 @@ volumes = {container}web:/www,{container}conf/web/php7:/etc/php7
 alias = php,composer,pecl,apk,/install.sh->phpInstall
 
 [nginx]
+num = 2
 port = 80:80,443:443
 volumes = {container}web:/www,{container}conf/web/nginx:/etc/nginx,{container}logs/nginx/{name}/logs:/var/log/nginx
 alias = nginx

+ 18 - 0
src/ds.py

@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+	dever-manage tools
+	name:ds.py
+	author:rabin
+	功能:集群管理工具,基本命令和dm一致
+	ds init 初始化
+	ds join ip 加入集群
+	ds run web 运行web服务组
+	ds run web-php 运行web服务组下的php服务
+	ds run web-nginx 运行web服务组下的nginx服务
+	ds rm web 删除web服务组
+	ds show 显示所有服务
+	ds node 查看所有集群节点
+"""
+from main import *
+Main.init('cluster')

+ 0 - 3
src/shell/container/network

@@ -1,3 +0,0 @@
-#!/usr/bin/env sh
-set -e
-docker network create --driver=overlay $1

+ 3 - 0
src/shell/docker/name

@@ -0,0 +1,3 @@
+#!/bin/sh  
+  
+docker ps --format '{{.Names}}' --filter name=$1

+ 3 - 0
src/shell/docker/network

@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+set -e
+docker network create $@

+ 4 - 0
src/shell/swarm/drop

@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+set -e
+
+docker service ls|awk '{print $1}'|xargs docker service rm 

+ 4 - 0
src/shell/swarm/exec

@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+set -e
+
+docker $@

+ 4 - 0
src/shell/swarm/inspect

@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+set -e
+
+docker service inspect $1

+ 4 - 0
src/shell/swarm/logs

@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+set -e
+
+docker service logs $1

+ 4 - 0
src/shell/swarm/node

@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+set -e
+
+docker node ls

+ 11 - 0
src/shell/swarm/rm

@@ -0,0 +1,11 @@
+#!/usr/bin/env sh
+set -e
+
+if [ -n "$1" ];then
+	docker service rm $1
+else
+	result=`docker ps -a|grep Exited|awk '{print $1}'`
+	if [ -n "$result" ];then
+		docker service ls|grep Exited|awk '{print $1}'|xargs docker service rm
+	fi
+fi

+ 8 - 0
src/shell/swarm/show

@@ -0,0 +1,8 @@
+#!/usr/bin/env sh
+set -e
+
+if [ "$1" != "" ];then
+	docker service ls | grep $1
+else
+	docker service ls
+fi

+ 340 - 0
src/tool/cluster.py

@@ -0,0 +1,340 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+    dever-manage tools
+    name:docker.py
+    author:rabin
+"""
+from core import *
+from docker import *
+
+class Cluster(Docker):
+	@classmethod
+	def init(self):
+		action = ('uprun', 'restart','run', 'rm', 'rmb', 'show', 'reset', 'logs', 'update', 'inspect', 'test')
+		super(Cluster, self).init(action, Cluster_Action)
+
+	@classmethod
+	def network(self):
+		Swarm.network(self, self.conf['base'])
+
+	@classmethod
+	def handle(self, method, config, item, action='run', slave=False):
+		if slave == False:
+			self.rely(config, action)
+		if 'num' not in config:
+			config['num'] = 1
+		num = int(config['num'])
+		name = self.name(item, 1)
+		if 'image' not in config:
+			config['image'] = item
+		if self.store == 'private' and config['image'] in self.core['images']:
+			config['image'] = self.core['images'][config['image']]
+		method(config=config, name=name, item=item, index=num, action=action)
+		if action in ('update', 'restart', 'rm', 'rmb', 'reset', 'run', 'uprun'):
+			self.slave(method, config, item, action)
+		if slave == False:
+			self.next(config, action)
+
+class Cluster_Action(Docker_Action):
+	@staticmethod
+	def drop():
+		Swarm.drop()
+		print 'drop cluster:yes'
+
+	@staticmethod
+	def name():
+		arg = Args.name
+		name = Swarm.name(arg)
+		name = name.split("\n")
+		print name[0]
+
+	@staticmethod
+	def names():
+		arg = Args.name
+		name = Swarm.name(arg)
+		print name
+
+	@staticmethod
+	def node():
+		Swarm.node()
+
+	@staticmethod
+	def restart(**param):
+		print 'reloading ' + param['name'] + ', please wait...'
+		name = Swarm.name(param['name'])
+		name = name.split("\n")
+		for i in name:
+			if i:
+				Core.shell('container.restart ' + name, True, bg=True)
+
+	@staticmethod
+	def show(**param):
+		name = ''
+		if param:
+			name = param['name']
+		Swarm.show(name)
+
+	@staticmethod
+	def logs(**param):
+		Swarm.logs(param['name'])
+
+	@staticmethod
+	def update(**param):
+		Swarm.run(param['name'])
+
+	@staticmethod
+	def inspect(**param):
+		Swarm.inspect(param['name'])
+
+	@staticmethod
+	def stop(**param):
+		print 'stop command is not exists'
+
+	@staticmethod
+	def save(**param):
+		tar,backup = Cluster.tar(param['name'])
+		Swarm.save(tar, param['name'], backup)
+
+	@classmethod
+	def load(self, **param):
+		tar,backup = Cluster.tar(param['name'])
+		Swarm.load(tar, param['name'])
+		Cluster.storeHost = ''
+		param['config']['image'] = backup
+		param['action'] = 'run'
+		self.run(**param)
+
+	@classmethod
+	def uprun(self, **param):
+		Image.install(Cluster.storeHost, param['config']['image'])
+		param['action'] = 'run'
+		self.run(**param)
+
+	@staticmethod
+	def rm(**param):
+		if param and 'name' in param:
+			Swarm.delete(param['name'])
+			Alias.delete(param['config'], param['name'])
+		else:
+			Container.delete()
+			print 'rm cluster:yes'
+
+	@staticmethod
+	def rmb(**param):
+		if param and 'name' in param:
+			Swarm.delete(param['name'], bg=True)
+			Alias.delete(param['config'], param['name'])
+		else:
+			Swarm.delete()
+			print 'rm cluster:yes'
+
+	@classmethod
+	def reset(self, **param):
+		self.rm(**param)
+		self.up(**param)
+
+	@classmethod
+	def test(self, **param):
+		param['test'] = True
+		print self.run(**param)
+
+	@classmethod
+	def create(self, **param):
+		self.run(**param)
+
+	@classmethod
+	def call(self, **param):
+		self.run(**param)
+
+	@classmethod
+	def run(self, **param):
+		command = ''
+		state = Swarm.check(param['name'])
+		if state == 0:
+			Cluster.hook('start', param['config'], param['name'])
+			mount = '--mount type=bind,source='+Core.path+'container/share,destination=/share'
+			mount = mount + ' --mount type=bind,source=/etc/hosts,destination=/etc/hosts.main'
+			run = ['--replicas ' + str(param['index']), '--name='+param['name'], '--hostname='+param['name'], mount, '--env HOSTIP="'+Core.ip()+'"']
+
+			args = Swarm.args()
+			for key in args:
+				if args[key] != '':
+					value = Cluster.param(param['config'], key, args[key], param['name'])
+					if value != '':
+						if '--mount' in value and ':' in value:
+							value = value.replace(' /', '/')
+							value = value.replace(':', ',destination=')
+						run.append(value)
+
+			run.append(Cluster.storeHost + param['config']['image'])
+
+			if command == '' and 'command' in args:
+				value = Cluster.param(param['config'], 'command', args['command'], param['name'])
+				command = value
+
+			if command != '':
+				run.append(command)
+
+			command = ' '.join(run)
+			if 'test' in param:
+				return 'docker service create ' + command
+			print 'setuping ' + param['name'] + ', please wait...'
+			method = Core.getMethod(Swarm, param['action'])
+			method(command)
+			Alias.add(param['config'], param['name'], 'docker run ' + command, param['action'], True)
+			Cluster.hook('end', param['config'], param['name'])
+		else:
+			print param['name'] + ' cluster is setuped'
+
+	@staticmethod
+	def setting():
+		ip = Args.name
+		if not ip:
+			ip = Core.ip()
+		ckey = Args.param
+		if ckey:
+			Env.cluster(ckey)
+		ckey = Env.cluster()
+		Env.cluster('yes')
+		return (ip, ckey)
+
+	@classmethod
+	def init(self, **param):
+		(ip, ckey) = self.setting()
+		token = Swarm.init(ip)
+		print token
+		return
+		
+		if token and '--token' in token:
+			command = 'ds run daemon-master'
+			Core.popen(command, True, bg=False)
+
+			token = token.split('docker swarm join --token ')
+			token = token[1].split("\r\n")
+			token = token[0].replace(' ', ':')
+
+			command = 'consul kv put ' + ckey + ' ' + token
+			Core.popen(command, True, bg=True)
+		print 'init cluster('+ip+'):yes'
+
+	@classmethod
+	def join(self, **param):
+		(ip, ckey) = self.setting()
+		import json
+		import base64
+		url = 'http://' + ip + ':8500/v1/kv/' + ckey
+		value = Core.curl(url)
+		value = json.loads(value)
+		if not value:
+			print 'join cluster:'+url+' error'
+		else:
+			value = base64.b64decode(value[0]['Value'])
+			config = value.split(':')
+			print config
+
+			'''
+
+			Swarm.join(config[0])
+
+			command = 'dm run daemon-client'
+			Core.popen(command, True, bg=False)
+
+			command = 'consul join ' + config[1]
+			Core.popen(command, True, bg=False)
+
+			print 'join cluster:yes'
+			'''
+
+class Swarm(object):
+
+	@staticmethod
+	def name(name):
+		result = Core.shell('docker.name ' + name)
+		return result
+	@staticmethod
+	def run(command):
+		#command = 'container.run ' + command
+		#Core.shell(command, True, bg=False)
+		command = 'docker service create ' + command
+		Core.popen(command, True, bg=True)
+		return command
+	@staticmethod
+	def show(name=''):
+		print Core.shell('swarm.show ' + name)
+	@staticmethod
+	def args():
+		return {
+			'port' : '-p'
+			,'volumes' : '--mount type=bind,source='
+			,'environment' : '-e'
+			,'command' : ''
+			,'entrypoint' : '--entrypoint'
+			,'network' : '--network'
+			,'host' : '--add-host'
+			,'root' : '--privileged='
+			,'memory' : '--limit-memory='
+			,'expose' : '--expose',
+		}
+	@staticmethod
+	def drop():
+		Core.shell('swarm.drop', bg=True)
+	@staticmethod
+	def node():
+		print Core.shell('swarm.node')
+	@staticmethod
+	def stop(name):
+		Core.shell('swarm.stop ' + name)
+	@staticmethod
+	def logs(name):
+		Core.shell('swarm.logs ' + name, True)
+	@staticmethod
+	def inspect(name):
+		Core.shell('swarm.inspect ' + name, True)
+	@staticmethod
+	def restart(name):
+		return False
+	@classmethod
+	def delete(self, name='', bg=False):
+		if name != '':
+			print 'rm ' + name + ', please wait...'
+			if self.check(name) == 1:
+				Core.shell('swarm.rm ' + name, False, bg=bg)
+		else:
+			Core.shell('swarm.rm', False)
+			
+	@staticmethod
+	def check(name):
+		result = int(Core.popen('docker service ls | grep '+name+' | wc -l'))
+		if result != 0:
+			return 1
+		else:
+			return 0
+	@staticmethod
+	def network(self, config):
+		if 'network' in config:
+			name = 'overlay'
+			driver = '--driver=' + name
+			config['network'] = name + '_' + config['network']
+			self.conf['base']['network'] = config['network']
+
+			result = int(Core.popen('docker network ls | grep ' + config['network'] + ' | wc -l'))
+			if result == 0:
+				Core.shell('docker.network ' + driver + ' ' + config['network'], True)
+	@staticmethod
+	def save(tar, name, backup):
+		return Container.save(tar, name, backup)
+	@classmethod
+	def load(self, tar, name):
+		Container.save(tar, name)
+		self.delete(name)
+
+	@staticmethod
+	def init(ip):
+		result = Core.shell('swarm.token')
+		if '--token' not in result:
+			result = Core.shell('swarm.init ' + ip)
+		return result
+	@staticmethod
+	def join(token, ip):
+		Core.shell('swarm.join ' + token + ' ' + ip, bg=True)

+ 1 - 1
src/tool/dever.py

@@ -44,7 +44,7 @@ class Dever_Action(object):
 		path = lib + Args.name
 		git = Args.param
 		if not git:
-			git = Env.val('package')
+			git = Env.dever()
 		if not git:
 			git = Dever.git
 		Git.update(git + Dever.package + Args.name, path)

+ 18 - 34
src/tool/docker.py

@@ -11,14 +11,17 @@ class Docker(object):
 	path = 'src/docker/'
 	default = 'shemic'
 	@classmethod
-	def init(self):
+	def init(self, action=False, method=False):
 		self.conf = {}
 		self.core = Config.core(self.path)
 		self.store = Env.store()
 		self.storeHost = self.core['store'][self.store] + '/'
+		if method == False:
+			method = Docker_Action
 
-		action = ('uprun', 'run', 'rm', 'rmb', 'stop', 'create', 'call', 'save', 'load', 'show', 'reset', 'logs', 'restart', 'inspect', 'test')
-		method = Core.getMethod(Docker_Action, Args.action)
+		if action == False:
+			action = ('uprun', 'run', 'rm', 'rmb', 'stop', 'create', 'call', 'save', 'load', 'show', 'reset', 'logs', 'restart', 'inspect', 'test')
+		method = Core.getMethod(method, Args.action)
 		if Args.name and Args.action in action:
 			self.load(method)
 		else:
@@ -27,7 +30,7 @@ class Docker(object):
 	@classmethod
 	def load(self, method):
 		self.config()
-		Container.network(self.conf['base'])
+		self.network()
 		self.rely(self.conf['base'], Args.action)
 		one = False
 		if Args.index in self.conf['config']:
@@ -46,6 +49,10 @@ class Docker(object):
 			if 'network' not in self.conf['base']:
 				self.conf['base']['network'] = 'dm'
 
+	@classmethod
+	def network(self):
+		Container.network(self, self.conf['base'])
+
 	@classmethod
 	def check(self, name, item):
 		if '#' in item:
@@ -72,7 +79,7 @@ class Docker(object):
 			if self.store == 'private' and config['image'] in self.core['images']:
 				config['image'] = self.core['images'][config['image']]
 			method(config=config, name=name, item=item, index=i, action=action)
-			if action in ('stop', 'restart', 'rm', 'rmb', 'reset', 'run', 'create'):
+			if action in ('stop', 'restart', 'rm', 'rmb', 'reset', 'run', 'uprun', 'create'):
 				self.slave(method, config, item, action)
 			i = i + 1
 		if slave == False:
@@ -418,22 +425,6 @@ class Docker_Action(object):
 		else:
 			self.restart(**param)
 
-	@classmethod
-	def init(self, **param):
-		# 启动daemon-master
-		command = 'dm run daemon-master'
-		Core.popen(command, True, bg=False)
-
-		'''
-		ip = Args.name
-		if not ip:
-			ip = Core.ip()
-		token = Cluster.init(ip)
-
-		if token:
-		'''
-		print 'init cluster:yes'
-
 class Container(object):
 	@staticmethod
 	def run(command):
@@ -494,16 +485,18 @@ class Container(object):
 		else:
 			return 0
 	@staticmethod
-	def network(config):
+	def network(self, config):
 		if 'network' in config:
+			name = 'bridge'
+			driver = '--driver=' + name
 			result = int(Core.popen('docker network ls | grep ' + config['network'] + ' | wc -l'))
 			if result == 0:
-				Core.shell('container.network ' + config['network'], True)
+				Core.shell('docker.network ' + driver + ' ' + config['network'], True)
 	@staticmethod
 	def save(tar, name, backup):
 		if File.exists(tar) == True:
 			now = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
-			old = replace('.tar', '.' + now + '.tar', tar)
+			old = tar.replace('.tar', '.' + now + '.tar')
 			File.rename(tar, old)
 		Core.popen('docker commit -p ' + name + ' ' + backup)
 		Core.popen('docker save ' + backup + ' > ' + tar, True)
@@ -548,13 +541,4 @@ class Image(object):
 		pull = 'docker pull';
 		command = pull + ' ' + library + key
 		Core.popen(command, True)
-		print 'finished'
-
-class Cluster(object):
-	@staticmethod
-	def init(ip):
-		#result = Core.shell('swarm.init ' + ip)
-		return 1
-	@staticmethod
-	def join(token, ip):
-		Core.shell('swarm.join ' + token + ' ' + ip, bg=True)
+		print 'finished'