Created
June 11, 2025 16:50
-
-
Save zlwu/f56b87b14468168bd7f99c49d8f07984 to your computer and use it in GitHub Desktop.
simple docker stack cli tool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import sys | |
import subprocess | |
import re | |
def load_env_vars(env_file): | |
"""从.env文件加载环境变量""" | |
if not os.path.isfile(env_file): | |
return {} | |
env_vars = {} | |
with open(env_file, 'r') as f: | |
for line in f: | |
line = line.strip() | |
# 跳过空行和注释 | |
if not line or line.startswith('#') or '=' not in line: | |
continue | |
key, value = line.split('=', 1) | |
env_vars[key] = value | |
return env_vars | |
def interpolate_variables(content, env_vars): | |
"""使用环境变量替换内容中的变量引用""" | |
# 处理${VAR}形式的变量 | |
def replace_var(match): | |
var_name = match.group(1) | |
return env_vars.get(var_name, '') | |
content = re.sub(r'\$\{(\w+)\}', replace_var, content) | |
# 处理$VAR形式的变量 | |
def replace_simple_var(match): | |
var_name = match.group(1) | |
return env_vars.get(var_name, '') | |
return re.sub(r'\$(\w+)', replace_simple_var, content) | |
def deploy_stack(app_name): | |
"""部署指定的应用栈""" | |
stack_root = os.environ.get('STACK_ROOT', '/opt/stacks') | |
app_dir = os.path.join(stack_root, app_name) | |
if not os.path.isdir(app_dir): | |
print(f"Error: Application '{app_name}' not found in {stack_root}") | |
sys.exit(1) | |
stack_file = os.path.join(app_dir, 'stack.yml') | |
if not os.path.isfile(stack_file): | |
print(f"Error: stack.yml not found in {app_dir}") | |
sys.exit(1) | |
# 加载环境变量 | |
env_vars = os.environ.copy() | |
env_vars.update(load_env_vars(os.path.join(stack_root, '.env'))) | |
env_vars.update(load_env_vars(os.path.join(app_dir, '.env'))) | |
# 读取并处理stack.yml内容 | |
with open(stack_file, 'r') as f: | |
content = f.read() | |
env_vars['PWD'] = app_dir | |
processed_content = interpolate_variables(content, env_vars) | |
# 在应用目录执行部署命令 | |
cmd = ['docker', 'stack', 'deploy', '-d', '-c', '-', app_name] | |
try: | |
subprocess.run( | |
cmd, | |
input=processed_content.encode('utf-8'), | |
cwd=app_dir, | |
check=True | |
) | |
except subprocess.CalledProcessError as e: | |
print(f"Deployment failed: {e}") | |
sys.exit(1) | |
def main(): | |
if len(sys.argv) < 2: | |
print("Usage: dstack <command> [app_name] [options]") | |
print("Commands:") | |
print(" deploy <app_name> Deploy an application stack") | |
print(" Other docker stack commands (ls, services, ps, rm, etc.)") | |
sys.exit(1) | |
command = sys.argv[1] | |
if command == 'deploy': | |
if len(sys.argv) < 3: | |
print("Error: Missing application name for deploy") | |
sys.exit(1) | |
app_name = sys.argv[2] | |
deploy_stack(app_name) | |
else: | |
# 直接传递命令给docker stack | |
cmd = ['docker', 'stack'] + sys.argv[1:] | |
try: | |
subprocess.run(cmd, check=True) | |
except subprocess.CalledProcessError as e: | |
sys.exit(e.returncode) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment