Ansible-Playbook之异步执行

    技术2022-07-15  73

    异步功能不作为单独的模块出现,而是作为任务参数使用,因此,大多数模块都可以异步执行;

    异步执行功能通常是用来解决执行任务时间过长导致SSH连接超时。

    示例:

    --- - hosts: "ansible-server" tasks: - name: simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec command: /bin/sleep 15 async: 45 poll: 5

     

    1. 参数讲解:

       

    async

    任务最大执行时间

     

    poll

    轮询间隔

     

    > POLL:

    当 poll > 0 的时候,任务本身依然会阻塞运行,但是,实际上ansible任务与内部执行的shell脚本之间是异步执行,在脚本执行过程中,ansible任务会根据poll设置的轮询时间间隔取获取脚本执行的状态,并根据async判断是否超时了;举个例子:

    这是剧本,超时时间设置的很大,轮询间隔是20s,即每20秒获取一次执行状态;

    --- - hosts: "ansible-server" tasks: - name: test for sync job shell: | cd ~/scripts sh sleep.sh async: 999 poll: 20

    这是sleep.sh脚本,睡眠5s;

    sleep 5s

    执行结果是整个任务依然需要等待大约20s才能执行完成(虽然实际上有效工作时间只有5s);

    当 poll = 0 的时候,任务本身实现了非阻塞的异步执行,由于没有轮询间隔,代表着该任务本身并不会主动获取任务执行状态和结果;此时异步任务会一直执行,直到完成、失败或超时;

    我们举个例子:

    这是剧本,这次设置poll参数为0,这意味着这个任务是异步执行的,也就是,一旦开启了这个任务,剧本就会退出;

    --- - hosts: "ansible-server" tasks: - name: test for sync job shell: | cd ~/scripts sh sleep.sh async: 999 poll: 0

    这是sleep.sh脚本,在睡眠20s后,会创建一个时间戳文件;

    sleep 20s mkdir `date +%H%M%S`.txt

    我们运行剧本,发现几乎在启动的同时剧本就执行完成了,而等待20s左右,在sleep.sh同级目录下生成了一个.txt文件;这说明异步执行的任务即使剧本退出,也会继续执行下去;

    2. 获取异步任务执行状态

    异步功能本身无法自身向用户反馈执行状态和结果,如果要异步执行任务并稍后进行检查,可以使用async_status模块进行监控与反馈;

    示例:

    --- # Requires ansible 1.8+ - name: 'YUM - async task' yum: name: docker-io state: present async: 1000 poll: 0 register: yum_sleeper - name: 'YUM - check on async task' async_status: jid: "{{ yum_sleeper.ansible_job_id }}" register: job_result until: job_result.finished retries: 30 delay: 5

     

    2.1. 参数

    参数名

     

    jid 

    作业或任务标识符

    mode

    如果为status,则获取状态

    如果是cleanup,清理指定的作业jid异步作业缓存(~/.ansible_async/)

     

    2.2. 返回值

    返回值名

     

    ansible_job_id

    异步任务的id

    finished

    异步任务是否完成(1:已完成;0:未完成)

    started

    异步任务是否开始(1:已开始;0:未开始)

    获取异步任务执行状态通常可以与until参数配置使用,在可控制的次数内,不断地取查询任务执行状态,直到任务执行结束、失败或超时;

     

    2.3. Until条件循环

    简单介绍一下until循环参数:

      

    until

    条件终止表达式

    retries

    最大循环次数

    delay

    每次循环时间间隔(秒)

    循环终止有两个条件,任意满足其一就可以:

    1. 循环次数超过最大次数;

    2. 满足until条件,直接跳出循环;

     

    综合举个例子:

    剧本如下:

    --- - hosts: "ansible-server" tasks: - name: test for sync job shell: | sleep 15 async: 999 poll: 0 register: sleeper - name: Monitor and feedback async_status: jid: "{{ sleeper.ansible_job_id }}" register: backer until: backer.finished retries: 20 delay: 1

    一个睡眠15秒的异步任务,为任务本身注册一个变量sleeper;

    一个监控任务,输入jid为监控对象的id,利用Until循环,条件为输出数据的finished字段,设置的最大循环次数为20,循环间隔时间为1秒;

    输出日志打印:

    [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details PLAY [ansible-server] *************************************************************************************** TASK [Gathering Facts] ************************************************************************************** ok: [localhost] TASK [test for sync job] ************************************************************************************ changed: [localhost] TASK [Monitor and feedback] ********************************************************************************* FAILED - RETRYING: Monitor and feedback (20 retries left). FAILED - RETRYING: Monitor and feedback (19 retries left). FAILED - RETRYING: Monitor and feedback (18 retries left). FAILED - RETRYING: Monitor and feedback (17 retries left). FAILED - RETRYING: Monitor and feedback (16 retries left). FAILED - RETRYING: Monitor and feedback (15 retries left). FAILED - RETRYING: Monitor and feedback (14 retries left). FAILED - RETRYING: Monitor and feedback (13 retries left). FAILED - RETRYING: Monitor and feedback (12 retries left). FAILED - RETRYING: Monitor and feedback (11 retries left). FAILED - RETRYING: Monitor and feedback (10 retries left). FAILED - RETRYING: Monitor and feedback (9 retries left). changed: [localhost] PLAY RECAP ************************************************************************************************** localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

    如图所示,大概在循环11次的时候满足Until条件(任务之间有时间间隔造成的误差),跳出循环,结束执行;

     

    3. 案例

    设workflow.sh脚本执行时间久,为了保持jenkins服务器与部署服务器保持连接(设置未通信状态下超时时间为15分钟),则希望不断返回日志;

    方式一:使用异步任务执行+async_status模块

    - name: 执行脚本 shell: | . ~/.profile && sh workflow.sh > workflow.log args: chdir: ~/ async: 1 poll: 0 register: work_stat - name: 监控状态 async_status: jid={{ work_stat.ansible_job_id }} register: task_result until: task_result.finished retries: 20 delay: 10

    注意:某些脚本如果没有显式退出程序,则永远不会执行完成;

     

    方式二:使用nohup异步+Until轮询进程

    剧本如下:

    - name: 执行脚本 shell: | . ~/.profile && nohup sh workflow.sh > workflow.log 2>&1 & args: chdir: ~/ ignore_errors:True - name: 监控进程 shell: | ps -ef | grep workflow | grep -v grep | wc -l register: processStatus until: processStatus.stdout|int < 1 retries:20 delay: 10 ignore_errors: True

     

    Processed: 0.013, SQL: 9