使用Ansible防止同时部署

Jam*_*pel 25 ansible

我团队中的任何人都可以通过SSH连接到我们的特殊部署服务器,并从那里运行Ansible playbook将新代码推送到计算机.

如果两个人试图同时进行部署,我们会担心会发生什么.我们想要这样做,以便如果其他人正在运行它,剧本将会失败.

有关如何做到这一点的任何建议?标准解决方案是使用pid文件,但Ansible没有内置支持.

Phi*_*mes 27

我个人使用RunDeck(http://rundeck.org/)作为我的Ansible剧本的包装器有多种原因:

  • 您可以将RunDeck"作业"设置为仅能够一次运行(或将其设置为根据需要同时运行多次)
  • 您可以在系统中设置用户,以便审核谁清楚地运行了列出的内容
  • 您可以使用可以使用的约束设置其他变量(指定选项列表)
  • 它比Ansible Tower便宜很多(RunDeck是免费的)
  • 它有一个完整的API,可以从构建系统中实际运行作业
  • 您不需要在ansible-playbook命令周围编写复杂的bash包装器
  • SSH可以成为"需要编写一个ansible脚本的东西"的试金石 - 我不允许SSH访问,除了在完全中断/修复情况下,我们有更快乐的SA的结果
  • 最后,在"很好拥有"类别中,您可以安排RunDeck作业以非常简单的方式运行ansible playbooks,以便任何登录控制台查看运行时的内容

当然还有很多很好的理由,但我的手指已经厌倦了打字;)


leu*_*cos 18

您可以为ansible命令编写一个包装器,如下所示:

ansible-playbook() {
  lock="/tmp/ansible-playbook.lock"

  # Check if lock exists, return if yes
  if [ -e $lock ]; then
    echo "Sorry, someone is running already ansible from `cat $lock`"
    return
  fi

  # Install signal handlers
  trap "rm -f $lockfile; trap - INT TERM EXIT; return" INT TERM EXIT

  # Create lock file, saving originating IP
  echo $SSH_CLIENT | cut -f1 -d' ' > $lock

  # Run ansible with arguments passed at the command line
  `which ansible-playbook` "$@"

  # Remove lock file
  rm $lock

  # Remove signal handlers
  trap - INT TERM EXIT
}
Run Code Online (Sandbox Code Playgroud)

~/.bashrc在部署框中的用户中定义此功能,然后进行设置.ansible如果你愿意,你也可以为命令做同样的事情,但考虑到问题,我不确定是否需要.

编辑:重写信号处理程序,以防止用户按Ctrl-C时锁定文件悬空.

EDIT2:修正了拼写错误

  • flock with -c是一个选项,就像这样`flock -x $ HOME/.ansible_lock -c'ansible-playbook ......'` (2认同)

pop*_*nic 11

之后,我把它放在我的主要剧本中

    hosts: all. 
Run Code Online (Sandbox Code Playgroud)

lock_file_path:这是一个文件,其存在表明当前正在运行ansible部署,或之前有部署,由于某种原因中止.

force_ignore_lock:默认为false,由选项标志重置,您可以在命令行包装器中将其设置为ansible.它使ansible能够继续部署.

这是做什么的

pre_tasks

第一个pre_task检查是否lock_file_path存在,并将结果记录在一个名为的寄存器中lock_file.

然后,下一个任务检查文件是否存在,以及部署人员是否选择忽略它(希望在与其他队友通信之后).如果没有,则作业失败,并显示有用的错误消息.

如果用户选择继续部署即使存在lock_file,则下一个任务将删除先前创建的lock_file并创建一个新任务.然后,所选角色中的其他任务继续愉快.

post_tasks

这是在部署中的所有任务完成后立即调用的挂钩.这里的任务删除了lock_file,让下一个人快乐地部署,没有任何问题.

vars:
  lock_file_path=/tmp/ansible-playbook-{{ansible_ssh_user}}.lock

pre_tasks: 
   - stat: path={{lock_file_path}}
     register: lock_file

   - fail: msg="Sorry, I found a lockfile, so I'm assuming that someone was already running ansible when you started this deploy job. Add -f to your deploy command to forcefully continue deploying, if the previous deploy was aborted."
   when: lock_file.stat.exists|bool and not force_ignore_lock|bool

   - file: path={{lock_file_path}} state=absent
     sudo: yes
     when: "{{force_ignore_lock}}"

   - file: path={{lock_file_path}} state=touch
     sudo: yes

post_tasks:
   - file: path={{lock_file_path}} state=absent
     sudo: yes
Run Code Online (Sandbox Code Playgroud)


baz*_*rgh 8

你考虑过设置maxsysloginslimits.conf吗?您可以按组限制.

# for a group called 'deployers'
@deployers        -       maxsyslogins      1
Run Code Online (Sandbox Code Playgroud)

这比你要求的要严重得多.您可能希望首先在VM上尝试它.请注意,如果系统上有任何其他用户,则部署者中没有人可以访问,1限制不仅仅计算部署者.此外,如果您作为用户多路复用您的ssh连接(ControlMaster auto),您仍然可以多次登录; 这是其他被锁定的用户.


小智 5

您可以使用flock命令,它将使用基于文件系统的flock(2)包装您的命令:

$ flock /tmp/ansible-playbook.lock ansible-playbook foo bar baz
Run Code Online (Sandbox Code Playgroud)

尽管它最适合您的用户.这将使在/ tmp下的持久锁文件,但要注意它是不是安全地删除[1].它是原子的,非常简单.

[1]
A: flock /tmp/foo.lock -c "echo running; sleep 5; rm /tmp/foo.lock"
B: flock /tmp/foo.lock -c "echo running; sleep 5; rm /tmp/foo.lock"
   B blocks waiting for lock on /tmp/foo.lock
A: Finish, deleting /tmp/foo.lock
B: Runs, using lock on now deleted /tmp/foo.lock
C: flock /tmp/foo.lock -c "echo running; sleep 5; rm /tmp/foo.lock"
   Creates new /tmp/foo.lock, locks it and runs immediately, parallel with B
Run Code Online (Sandbox Code Playgroud)


小智 5

当可以从多个构建主机运行部署作业时,包装脚本无用。对于这种情况,锁定必须由剧本处理。

Ansible现在有一个wait_for模块,可用于锁定。这是一个简短的示例(不考虑过时的锁定):

vars:
  lock_file: "{{ deploy_dir }}/.lock"
pre_tasks:
  - name: check for lock file
    wait_for:
      path: "{{ lock_file }}"
      state: absent
  - name: create lock file
    file:
      path: "{{ lock_file }}"
      state: touch
post_tasks:
  - name: remove lock file
    file:
      path: "{{ lock_file }}"
      state: absent
Run Code Online (Sandbox Code Playgroud)

Ansible将在可配置的超时期限内检查锁定文件,然后在该期限内未将其删除则放弃。