代码发布基本流程
1. 安装saltstack
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1. 安装salt-master yum install salt-master 2. 修改配置文件:/etc/salt/master interface: 0.0.0.0 # 表示Master的IP 3. 启动 service salt-master start
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1. 安装salt-minion yum install salt-minion 2. 修改配置文件 /etc/salt/minion master: 10.211.55.4 # master的地址 或 master: - 10.211.55.4 - 10.211.55.5 random_master: True id: c2.salt.com # 客户端在salt-master中显示的唯一ID 3. 启动 service salt-minion start
master: salt-master -l debug minion: 以日志形式打开: salt-minion -l debug master防火墙需要关闭: firewall-cmd --state #查看默认防火墙状态 systemctl stop firewalld.service
2. 授权
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
salt-key -L # 查看已授权和未授权的slave salt-key -a salve_id # 接受指定id的salve salt-key -r salve_id # 拒绝指定id的salve salt-key -d salve_id # 删除指定id的salve
3. 执行命令
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
salt 'c2.salt.com' cmd.run 'ifconfig'
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import salt.client local = salt.client.LocalClient() result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
4. grains
静态值:最开始执行一次后,默认永远是当前值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
- SSDs - biosreleasedate - biosversion - cpu_flags - cpu_model - cpuarch - disks - dns - domain - fqdn - fqdn_ip4 - fqdn_ip6 - gid - gpus - groupname - host - hwaddr_interfaces - id - init - ip4_gw - ip4_interfaces - ip6_gw - ip6_interfaces - ip_gw - ip_interfaces - ipv4 - ipv6 - kernel - kernelrelease - kernelversion - locale_info - localhost - lsb_distrib_codename - lsb_distrib_id - machine_id - manufacturer - master - mdadm - mem_total - nodename - num_cpus - num_gpus - os - os_family - osarch - oscodename - osfinger - osfullname - osmajorrelease - osrelease - osrelease_info - path - pid - productname - ps - pythonexecutable - pythonpath - pythonversion - saltpath - saltversion - saltversioninfo - selinux - serialnumber - server_id - shell - swap_total - systemd - uid - username - uuid - virtual - zfs_support - zmqversion
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
vim /srv/salt/_grains/xx.py import time def xxo(): s = {} s['xkkkkkkkkkkkkk1'] = str(time.time()) s['xkkkkkkkkkkkkk2'] = 123 return s PS: 在master上执行 salt '*' saltutil.sync_grains 同步创建granins
salt '*' grains salt '*' grains.ls salt '*' grains.get 'xkkkkkkkkkkkkk1'
5. pillar
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
内置pillar vim /etc/salt/master pillar_opt: True PS: 重启生效
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
vim /srv/pillar/top.sls base: 'c*': - apache vim /srv/pillar/apache.sls x1: {% if grains['os_family'] == 'Debian' %} apache: apache_1 {% elif grains['os_family'] == 'RedHat' %} apache: httpd_2 {% elif grains['os'] == 'Arch' %} apache: apache_3 {% endif %} x2: {% if grains['ip_interfaces'].get('eth0')[0].startswith('10.10') %} nameservers: ['10.10.9.31','10.10.9.135'] zabbixserver: ['10.10.9.234'] {% else %} nameservers: ['10.20.9.75'] zabbixserver: ['10.20.9.234'] {% endif %} PS: 刷新 salt '*' saltutil.refresh_pillar
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
vim /etc/salt/master ext_pillar: - wupeiqi: 或 - wupeiqi:{api:http://www.oldbody.com} vim /usr/lib/python2.7/site-packages/salt/pillar/wupeiqi.py import time import commands import salt.client def ext_pillar(minion_id,pillar,*args,**kwargs): local = salt.client.LocalClient() result = local.cmd(minion_id, 'cmd.run', ['ifconfig']) return {'ifconfig':result.get(minion_id)} PS: 修改配置文件后,需要重启
6. state
state是Saltstack最核心的功能,通过预先定制好的sls(salt state file)文件对被控制主机进行状态管理,支持包括程序包(pkg)、文件(file)、网络配置(network)、系统服务(service)、系统用户(user)等。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/data/lvue: file: - managed - source: salt://luffy_vue/files/lvue - user: root - makedirs: True - mode: 644
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
xxxxxx: file.recurse: - name: /data/codes - source: salt://luffy_vue/files/video - user: root - makedirs: True - file_mode: 644 - dir_mode: 755
# 执行top.sls salt "*" state.highstate # 执行单独模块 salt 'c1.com' state.sls 模块名称 salt 'c1.com' state.sls saltenv='prod' 模块名称
7. 基于git发布流程:
1. 在master上拉代码 如果文件存在,pull;否则clone subprocess.check_call('git clone https://gitee.com/wupeiqi/video.git', cwd='/Users/wupeiqi/PycharmProjects/sansa', shell=True) 2. build 使用编译器进行编译 3. 软连接到saltstack ln -s /data/codes/video /srv/salt/luffy_vue/files/video 3. 将代码推送到指定机器 xxxxxx: file.recurse: - name: /data/codes - source: salt://luffy_vue/files/video - user: root - makedirs: True - file_mode: 644 - dir_mode: 755 salt 'c1.com' state.sls luffy_vue 4. 将代码推送到所有机器 salt '*' state.sls luffy_vue
8. 代码同步
在master上编写如下state:
code/
├── files
│ ├── code_publisher.py
│ └── luffy(程序目录)
│ └── run.py
└── init.sls
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
sync_file: file.recurse: - name: /data/new/{{pillar['appname']}} - source: salt://s7code/files/{{pillar['appname']}} - user: root - makedirs: True - file_mode: 644 - dir_mode: 755 sync_online_script: file.managed: - name: /data/script/code_publisher.py - source: salt://s7code/files/code_publisher.py - user: root - makedirs: True - file_mode: 644 run_online_script: cmd.run: - name: /usr/bin/python /data/script/code_publisher.py {{pillar['appname']}} xxxxxxxx: cmd.run: - name: nohup /usr/bin/python run.py >/dev/null 2>&1 & - cwd: /data/{{pillar['appname']}}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 程序目录
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/usr/bin/env python # -*- coding:utf-8 -*- """ 1. salt state进行文件同步 2. 线上代码移动到 程序-4 名称 3. 新代码移动到线上目录 4. 杀掉原进程 5. 修改文件名 """ import os import sys import signal import shutil from subprocess import check_output, CalledProcessError def online_to_backup4(app_name): """ 线上代码移动到备份4 :return: """ # 检查是否存在线上代码(新服务器没有) online_path = '/data/%s' % app_name if not os.path.exists(online_path): return # 创建备份目录 backup_path = "/data/backup/%s/" % app_name if not os.path.exists(backup_path): os.makedirs(backup_path) # 线上代码移动到备份4 shutil.move('/data/%s' % app_name, '/data/backup/%s/%s-4' % (app_name, app_name,)) def new_to_online(app_name): """ 新代码移动到线上 :return: """ # 检查是否有线上目录,没有则创建 online_path = "/data" if not os.path.exists(online_path): os.makedirs(online_path) # 新代码移动到线上 os.rename('/data/new/%s' % app_name, '/data/%s' % (app_name,)) # shutil.move(('/data/new/%s' % app_name, '/data/%s' % (app_name,)) def rename_backup_name(app_name): """ 备份文件命名:备份-1、备份-2、备份-3 :param app_name: :return: """ base_path = "/data/backup/%s" % app_name for i in range(1, 5): # 1/2/3/4 folder_name = "%s-%d" % (app_name, i,) folder_path = os.path.join(base_path, folder_name) if not os.path.exists(folder_path): continue if i == 1: # 删除 xx-1 shutil.rmtree(folder_path) continue # 2/3 都减1 new_folder_name = "%s-%d" % (app_name, i - 1,) new_folder_path = os.path.join(base_path, new_folder_name) shutil.move(folder_path, new_folder_path) def get_pid_list(name): """ 获取指定进程PID :param name: :return: """ try: output = check_output("pgrep -f '%s'" % (name), shell=True) except CalledProcessError as ex: output = None if not output: return [] return map(int, output.split()) def kill_9(name): """ 杀死指定进程 :param name: :return: """ for pid in get_pid_list(name): try: os.kill(pid, signal.SIGKILL) except OSError as e: pass def run(): app_name = sys.argv[1] # 拷贝 online_to_backup4(app_name) new_to_online(app_name) # 杀进程 kill_9('/usr/bin/python run.py') # 删除第一备份 rename_backup_name(app_name) if __name__ == '__main__': run()
执行上下的命令:
salt '*' state.sls code pillar='{"appname": "luffy"}'
或
import salt.client local = salt.client.LocalClient() returns = local.cmd_batch('*', 'state.highstate', batch='10%') print(returns)
![](https://images.cnblogs.com/cnblogs_com/wupeiqi/662608/o_Warning.png)