ansible对接操作系统升级脚本(终篇)

admin 2024年8月7日18:31:16评论7 views字数 7542阅读25分8秒阅读模式

引言 ▼

上篇文章Ansible对接操作系统升级脚本(一)中介绍了项目的基本构成以及ansible系统升级角色中的检查任务。这篇文章将介绍操作系统升级、重启任务和vmtools安装任务。在重启任务中将解决第一篇文章Ansible对接操作系统升级脚本(一)中涉及的三个难点:

(1)如何判断服务器是否需要重启?

(2)如何判断服务器是否重启成功?

(3)如何避免服务器重启过程中ansible会话的断开?

名词解释

▂▂

(1)控制节点:部署ansible环境以及存放playbook的主机。

(2)受管主机执行playbook中的任务的主机。

操作系统升级 ▼

update.yml文件内容如下,文件内容可以分为三个部分。

---- name: create log directory delegate_to: localhost run_once: true file:    path: "{{ playbook_dir }}/log"   state: directory   mode: 0750

- name: start update os  shell: "{{ update_os_url }}"  args:    warn: no  changed_when: false  register: output

- name: Create the log file for the updated packages.  delegate_to: localhost  copy:    content: "{{ output.stdout_lines  | join('n') }}"    dest: "{{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_log"    owner: ugrep    group: ugrep    mode:  0640 

- name: Judge whether the upgrade is successful  delegate_to: localhost   shell: tail -10 {{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_log | grep Complete && echo $?   ignore_errors: true  changed_when: false  register: judge

- name: alert if host has not been updated  fail:    msg: "{{ ansible_default_ipv4.address }} update os failed, manual check needed"  when: judge.rc != 0

第一部分:在控制节点创建存放日志的目录

<

- name: create log directory delegate_to: localhost run_once: true file:    path: "{{ playbook_dir }}/log"   state: directory   mode: 0750

这部分使用ansible的file模块来在控制节点创建日志目录。在ansible运行任务时,默认将任务在受管主机【配置文件ansible.cfg中inventory配置项指定的主机】上执行, delegate_to关键字可以确保日志目录创建在控制节点,而不是受管主机。delegate_to关键字可以将任务委派到指定的主机进行运行。run_once:true表示这个任务只能在控制节点上执行一次。playbook_dir表示当前正在执行playbook的目录路径, 是ansible内置的变量。

第二部分:执行系统升级脚本并记录日志于控制节点

<

- name: start update os  shell: "{{ update_os_url }}"  args:    warn: no  changed_when: false  register: output

- name: Create the log file for the updated packages.  delegate_to: localhost  copy:    content: "{{ output.stdout_lines  | join('n') }}"    dest: "{{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_log"    owner: ugrep    group: ugrep    mode:  0640 

这部分的第一个任务是执行操作系统升级脚本。这个任务有三种方式来实现。

第一种:使用ansible的shell模块。在这种方式中,我们需要先使用ansible的copy模块,将脚本从控制节点复制到受管主机,然后使用shell模块执行已经传到受管主机的脚本。

第二种:使用ansible的script模块。编写方式如下:

- name: start update os  script:  update_os.sh  changed_when: false  register: output

这种方式不需要使用copy模块上传脚本,script模块会自动在受管主机执行playbook用户的家目录下创建一个.ansible/tmp目录,同时这个目录下也会产生一个临时目录,脚本会被上传到这个目录。脚本执行结束后这个临时目录会自动被删除。如下图:

上传升级脚本update_os.sh

ansible对接操作系统升级脚本(终篇)

update_os.sh脚本执行结束后删除临时目录。

ansible对接操作系统升级脚本(终篇)

第三种是使用shell模块:将脚本存放在一台web服务器上,然后shell模块使用curl --noporxy ‘*’ http:/IP/update_os.sh | bash的方式来执行脚本, 这里的IP是提供web服务的主机IP地址。

对比而言,第一种和第二种方式都会在受管主机上产生文件。第三种方式不会存在在受管主机上新建目录或者文件的问题。因此选择第三种方式。在实现过程中,我在update_os角色的vars目录中定义了一个变量update_os_url。

update_os_url: curl --noproxy '*' http://192.168.X.X/install/update_os.sh | bash

然后shell模块调用这个变量来执行升级脚本。如果web服务器地址变化,则只需要修改这个变量,不需要修改playbook。register记录升级的日志到output变量中。

第二个任务是将output变量中记录的日志写到文件中。生成的日志文件名为主机名_主机IP地址_log。

第三部分:判断主机升级系统是否成功

<

- name: Judge whether the upgrade is successful  delegate_to: localhost   shell: tail -10 {{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_log | grep Complete && echo $?   ignore_errors: true  changed_when: false  register: judge

- name: alert if host has not been updated  fail:    msg: "{{ ansible_default_ipv4.address }} update os failed, manual check needed"  when: judge.rc != 0

在主机系统升级成功后,日志文件的最后一行会出现Complete关键字,因此我们通过查找日志中是否存在这个关键字来判断主机是否升级成功。第一个任务是查找日志文件中的Complete关键字。register将shell命令的执行结果赋给注册变量judge。系统升级成功时judge.rc 等于0。第二个任务是终端输出系统升级失败的主机IP地址。

主机重启和vmtools安装 ▼

重启任务和vmtools安装任务分别由reboot.yml和install_vmtools.yml文件实现。

reboot.yml文件的内容如下,文件内容由三部分组成:判断是否需要重启服务器、重启服务器以及判断重启服务器是否成功。

---- name: Judge whether the upgrade is successful  delegate_to: localhost   shell: tail -10 {{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_log | grep Complete && echo $?   ignore_errors: yes  changed_when: false  register: judge

- name: reboot the server from script  delegate_to: localhost    command: sh api.sh  {{ ansible_default_ipv4.address }}  ignore_errors: yes  changed_when: false  when: judge.rc == 0- name: wait for to finish reboot  wait_for_connection:    delay: 180    - name: check if host has booted within last 5min  shell: test $( cat /proc/uptime | cut -d. -f1) -lt 300  ignore_errors: yes  changed_when: false  register:  reboot_check- name: alert if host has not been rebooted  fail:    msg: "{{ ansible_default_ipv4.address }} has  not booted, manual check needed"  when: reboot_check.rc != 0

第一部分:判断是否需要重启服务器

<

- name: Judge whether the upgrade is successful  delegate_to: localhost   shell: tail -10 {{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_log | grep Complete && echo $?   ignore_errors: yes  changed_when: false  register: judge

在前面内容介绍过,在主机系统升级成功后,日志文件的最后一行会出现Complete关键字,我们通过查找日志中是否存在这个关键字来判断主机是否升级成功。register将shell命令的执行结果赋给注册变量judge。系统升级成功时judge.rc 等于0,此时我们将执行重启服务器的任务。

第二部分:重启服务器

<

- name: reboot the server from script  delegate_to: localhost    command: sh api.sh  {{ ansible_default_ipv4.address }}  ignore_errors: yes  changed_when: false  when: judge.rc == 0- name: wait for to finish reboot  wait_for_connection:    delay: 180

当judge.rc 等于0 成立时,ansible将执行reboot the server from script任务来重启服务器,这解决了文章开头的第一个难点。delegate_to声明这个任务的执行是在本机执行,api.sh脚本用来调云管平台的接口来重启服务器(实际使用中可以替换成自己重启服务器的方式)。ansible接着执行wait for to finish reboot任务,这个任务是保证服务器重启之后,ansible的会话还能连接,还能继续后续的任务,这就解决了文章开头的第三个难点。在这里,我设置的等待重新连接的时间是180秒,因为在生产环境中云管平台重启服务器的耗时大约为2分钟。

第三部分:判断服务器是否重启成功

<

- name: check if host has booted within last 5min  shell: test $( cat /proc/uptime | cut -d. -f1) -lt 300  ignore_errors: yes  changed_when: false  register:  reboot_check- name: alert if host has not been rebooted  fail:    msg: "{{ ansible_default_ipv4.address }} has  not booted, manual check needed"  when: reboot_check.rc != 0

在这一部分中,我使用cat /proc/uptime | cut -d. -f1命令来获得服务器从启动到现在的时间(单位是秒),如果这个数值小于300,则判断服务器重启成功,否则服务器重启失败(reboot_check.rc 不等于0)。至此,重启任务的介绍结束了。

vmtool安装任务由install_vmtools.yml文件来实现。文件的内容如下:

---- name: Install  VMtools  block:    - name: start install vmtools       shell:  "{{ install_vmtools_url }}"      changed_when: false      args:        warn:  no      register: vmtools_output

    - name: Create the log file       delegate_to: localhost      changed_when: false      copy:        content: "{{ vmtools_output.stdout_lines  | join('n') }}"        dest: "{{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_vmtools_log"        owner: ugrep        group: ugrep        mode:  0640 

    - name: Judge whether install vmtools is successful      delegate_to: localhost       shell:  grep  -i error {{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_vmtools_log &&  echo $?      ignore_errors: true      changed_when: false      register: judge_vmtools

    - name: alert install vmtools      fail:        msg: "{{ ansible_default_ipv4.address }} install vmtools failed, manual check needed"      when: judge_vmtools == 0

install_vmtools.yml文件和update.yml文件的结构类似,由两部分组成。

第一部分:执行vmtools安装脚本并记录日志于控制节点

<

- name: start install vmtools      shell:  "{{ install_vmtools_url }}"     changed_when: false     args:       warn:  no     register: vmtools_output   - name: Create the log file      delegate_to: localhost     changed_when: false     copy:       content: "{{ vmtools_output.stdout_lines  | join('n') }}"       dest: "{{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_vmtools_log"       owner: ugrep       group: ugrep       mode:  0640

install_vmtools_url变量值为curl --noporxy ‘*’ http:/IP/install_vmtools.sh | bash, 这里的IP是提供web服务的主机IP地址。

第二部分:通过查找日志中是否存在error关键字来判断vmtools的安装是否成功

<

- name: Judge whether install vmtools is successful    delegate_to: localhost     shell:  grep  -i error {{ playbook_dir }}/log/{{ ansible_hostname }}_{{ ansible_default_ipv4.address  }}_vmtools_log &&  echo $?    ignore_errors: true    changed_when: false    register: judge_vmtools  - name: alert install vmtools    fail:      msg: "{{ ansible_default_ipv4.address }} install vmtools failed, manual check needed"    when: judge_vmtools == 0

这里需要注意一点,在update.yml文件中Complete关键字是系统升级成功后自动产生的,在install_vmtools.yml文件中error关键字是人为添加的。人为修改vmtools安装脚本,在程序可能出错的地方添加error关键字。

结语 ▼

至此,Ansible对接操作系统升级脚本的系列介绍完毕。在实际生产环境测试中,存在以下几点问题待后续优化:

  (1)目前ansible升级操作系统是同步模式进行,在一台主机升级出现问题卡住时,后续的ansible任务都将卡住不执行。

  (2)由于操作系统的升级时间较长,因此会出现ssh会话断开现象,此时整个ansible任务都将退出,此时也不能确定每台主机升级步骤进行到了哪一步。

  (3)日志拉取到ansible控制节点的问题。以update.yml文件为例,日志拉取是在操作系统升级结束之后进行,如果一台主机升级卡住,此时即使存在升级成功的主机,它的升级日志也不会被拉取到ansible控制节点。

【文献参考】

1. ansible delegate_to 模块

2. Ansible Documentation

文章作者 | 王振杰

原文始发于微信公众号(EBCloud):ansible对接操作系统升级脚本(终篇)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月7日18:31:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ansible对接操作系统升级脚本(终篇)http://cn-sec.com/archives/3044204.html

发表评论

匿名网友 填写信息