2.1 安装
################################################################################ # 远程主机 ################################################################################ # 远程主机无需做过多的配置,只需启动 SSH 服务,并且具有 Python 2.4 以上的环境。 ################################################################################ # 管理节点 ################################################################################ # 安装 Ansible yum install -y epel-release.noarch yum install -y ansible # 配置「管理节点」到「远程主机」的连接 # 即 SSH 连接(这里配置的是密钥连接,而不是密码连接。在 Ansible 中,这两种都是可以的。) ssh-keygen ssh-copy-id username@hostname ssh-keyscan hostname >> ~/.ssh/known_hosts # 测试 SSH 连接 ssh username@hostname
2.2 设置要管理的主机
接下来,需要指定要被 Ansible 管理的主机:“主机目录(Host Inventory)”,一个配置文件,/etc/ansible/hosts,指定了被管理的主机,内容如下:
# 被管理的主机列表 a.example.com b.example.com c.example.com # “[dbserver]”,定义名为 dbserver 的主机组,指定“dbserver”等价于指定了 dbserver 部分下的所有主机 [dbserver] db0.example.com db1.example.com db2.example.com # 同“[dbserver]”,定义主机组。 [webserver] web0.example.com web1.example.com web2.example.com
2.3 使用命令管理主机
Ansible 提供了命令行工具,称为“Ad-Hoc Commands”。
命令通常是ansible <host-pattern> [options]格式。下面是几个命令示例:
# 检查所有的远程主机,是否存在可以访问远程主机的 bruce 用户 ansible all -m ping -u bruce # 以管理节点的当前登录用户名,在远程主机上执行命令 ansible all -a "/bin/echo hello" # 复制文件 ansible web -m copy -a "src=/etc/hosts dest=/tmp/hosts" # 安装软件包 ansible web -m yum -a "name=acme state=present" # 添加用户 ansible all -m user -a "name=foo password=<crypted password>" # 从仓库检出代码 ansible web -m git -a "repo=git://src.exammple.com/project.git dest=/srv/http/project version=HEAD" # 启动服务 ansible web -m service -a "name=httpd state=started" # 并行执行任务,启动 10 个进程执行任务。 ansible lb -a "/sbin/reboot" -f 10 # 查看远程主机的信息 ansible all -m setup
2.5 模块
什么是模块?
在 Shell 中,我们会执行 cp、ls、mv、rm、yum 等命令,进行复制、查看、用户管理、权限管理、服务管理等日常操作。
在 Ansible 中,既然是批量管理主机,那肯定也会进行复制、查看、服务管理等等操作。在 Ansible 中,完成这些操作的不是“命令”,而是称为“模块”的东西。例如,文件复制使用 copy 模块;软件安装使用 yum 模块;用户管理使用 user 模块;服务管理使用 service 模块等等。
如何使用模块?
每个模块都有自己的选项,如同 Shell 命令一样。
使用ansible-doc <module_name>进行查看模块手册,或者查看官方「Module Index」手册。
使用ansible-doc -l列出当前所有可用模块,并显示一句话描述模块的作用。
下面是「在命令行中」使用模块的示例:
#!/bin/bash # 使用模块 copy,复制管理节点文件 /etc/hosts 到所有远程主机 /tmp/hosts ansible all -m copy -a "src=/etc/hosts dest=/trnp/hosts" # 使用模块 yum,在远程主机 Web 上安装 httpd 包 ansible web -rn yum -a "narne=httpd state=present"
上述两个命令中,参数all与web是主机组,在/etc/ansible/hosts中进行配置;选项-m指定要使用的模块;选项-a指定要传递给模块的参数;
下面是「在 Playbook 中」使用模块的示例:
---
tasks:
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=ternplates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
- name: ensure apache is running
service: name=httpd state=started
在 Playbook 中,指令tasks中的每一个“动作(Action)”都是对模块的一次调用。在每个动作中:
- 参数name指定了动作的描述;
- 每个动作的第二行则是要执行的动作。冒号前面是模块的名字。冒号后面是调用模块的参数。
模块的总结:
- 模块既可以在命令行中指定,也可以在 Playbook 中指定;
- 模块作用与参数与所使用的模块有关,使用之前参阅文档;
- 使用ansible-doc <module_name>进行查看模块手册,或者查看官方「Module Index」手册;
- Ansible 提供了一些常用的模块,用户也可以更具自己的需要开发自己的模块。
常用模块示例
debug:用于调试的模块,只是简单打印些消息,有点像 Linux 的 echo 命令。
template:从本地复制文件到远程节点,并进行变量的替换。
file:设置文件属性。
yum:RedHat 系列的发行版上的包管理。
service:管理服务。
firewalld:管理防火墙中的服务和端口。
command:在远程节点上执行命令,不支持“$HOME”、“<”、“>“
模块:ping
测试能否通过 SSH 连接远程主机,并且远程主机的 Python 版本是否满足要求。如果成功则返回“pong”。
#!/bin/bash ansible all -m ping
模块:debug
打印信息,类似于 Linux 中的 echo 命令。
- hosts: all
remote_user: root
tasks:
- name: "debug module"
debug:
msg: "System {{ inventory_hostname }} has gateway {{ ansible_default_ipv4.gateway }}"
{{ inventory_hostname }}与{{ ansible_default_ipv4.gateway }}会被自动替换成变量,这些变量是由 Ansible 在执行 Playbook 之前注入的,不需要定义即可使用。
变量可以是系统变量,也可以是动态的执行结果。如下示例,通过 regester 关键字将执行结果注入 result 变量中,然后使用 debug 模块打印:
- hosts: all
remote_user: root
tasks:
- name: "debug module register"
shell: /usr/bin/uptime
register: result
- name: "debug module var"
debug:
var: result
模块:copy
复制「本地」文件到「远程」主机。该模块会比较文件校验和,如果相同则不会复制,并返回 OK,如果不同则进行复制,并返回 changed。
- hosts: all
remote_user: root
tasks:
- name: "module copy"
template:
src: /etc/sudoers
dest: /tmp/sudoers.backup
backup: yes
owner: root
group: root
mode: 0600
validate: 'visudo - cf %s'
与之前的例子类似,name为动作的描述;src是本地文件位置;dest为远程主机文件保存位置;backup表示文件存在则进行备份,文件名追加时间形式的后缀;owner指定所有者;group指定所属组;mode指定权限;validate对文件进行校验,参数为命令,并且只有命令以“0”退出,则表示复制成功,%s 代表文件。
模块:template
复制静态文件很简单。但有时复制文件的时,我们需要根据远程主机的当前配置调整文件的内容(比如需要在配置文件中设置当前主机的 IP 地址)。这时候就可以使用template模块。该模块使用 Jinja2 模板引擎,使用{{ var_name }}来表示变量。文件/tmp/index.html.j2的内容如下:
<h1>PORT: {{ http_port }}<h1/>
<p>Served by {{ ansible_hostname }} ({{ ansible_default_ipv4.address }}) . </p>
下面是 Playbook 的内容:
- hosts: all
vars:
http_port: 80
remote_user: root
tasks:
- name: "module copy"
template:
src: /tmp/index.html.j2
dest: /tmp/index.html
backup: yes
owner: root
group: root
mode: 0600
如上示例,/tmp/index.html.j2为模板文件,使用的两个变量ansible_hostname和ansible_default_ipv4.address都是远程主机的系统变量,可以直接使用,http_port是环境变量,使用var关键字进行定义,并且template模块具有和copy模块类似的备份、所有权、模式设定等等功能。
模块:file
设置远程主机上的文件、目录、软链接的权限,也可以创建和删除它们。
- hosts: all
remote_user: root
tasks:
- name: "创建文件夹"
file:
state: directory
path: /tmp/module-file
mode: 0755
- name: "创建文件"
file:
state: touch
path: /tmp/module-file/foo.txt
- name: "创建到文件的软链接"
file:
state: link
src: /tmp/module-file/foo.txt
dest: /tmp/module-file/link-to-foo.txt
owner: root
group: root
- name: "修改文件权限"
file:
path: /tmp/module-file/foo.txt
owner: root
group: root
# mode: "u=rw,g=r,o=r"
# mode: "u+w,a-x"
mode: 0600
模块:user
用于管理系统的用户账户,并且设置相关的属性。
- hosts: all
remote_user: root
tasks:
- name: "创建用户"
user:
name: zheng
comment: "Mr. Zheng"
# 设置 UID
uid: 1040
# 设置默认的 Shell
shell: /bin/bash
# 设置组
group: root
# 追加两个附属组,而不是覆盖原由附属组
groups: bin, daemon
append: yes
# 为用户添加过期时间。使用 date --date '2019-01-10' +%s 命令生成
expires: 1547049600
# 为账户 jsmith 创建一个 2048 位的 SSH 密钥,放在~jsmith/.ssh/id_rsa 中。
generate_ssh_key: yes
ssh_key_bits: 2048
ssh_key_file: .ssh/id_rsa
- name: "删除用户"
user:
name: zheng
state: absent
remove: yes
模块:yum
用于在 RHEL、CentOS、Fedora21 等系统发行版中管理软件包。
- hosts: all
remote_user: root
tasks:
- name: "使用 URL 安装软件包"
yum:
name: http://nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.14.2-1.el7_4.ngx.x86_64.rpm
state: present
- name: "安装本地包"
yum:
name: /tmp/nginx-1.14.2-1.el7_4.ngx.x86_64.rpm
state: present
- name: "安装软件包组"
yum:
name: "@gnome-desktop-environment"
state: present
- name: "安装指定仓库中的包"
yum:
name: httpd
enablerepo: testing
state: present
- name: "安装最后一个版本的 Apache 服务"
yum:
name: httpd
state: latest
- name: "安装指定版本的 Apache 服务"
yum:
name: httpd-2.2.29-1.4.amznl
state: present
- name: "删除软件包"
yum:
name: httpd
state: absent
模块:service
用于管理服务器中的服务,进行启动、重启、开机启动等操作。
- hosts: all
remote_user: root
tasks:
- name: "启动"
service:
name: httpd
state: started
- name: "停止"
service:
name: httpd
state: stopped
- name: "重新启动"
service:
name: restarted
state:
- name: "开机启动"
service:
name: httpd
enabled: yes
- name: "重新启动网络服务"
service:
name: network
state: restarted
args: eth0
模块:firewalld
用于添加防火墙规则,这要求远程远程主机的 firewalld 的版本在 0.2.11 以上。
- hosts: all
remote_user: root
tasks:
- name: "允许 HTTPS 请求"
firewalld:
service: https
permanent: true
state: enable
- name: "允许 HTTP 请求"
firewalld:
zone: dmz
service: https
permanent: true
state: enable
- name: "禁用 TCP 端口"
firewalld:
port: 8081/tcp
permanent: true
state: disable
- name: "启用 UDP 端口"
firewalld:
port: 162-189/udp
permanent: true
state: enable
模块:shell
使用 /bin/sh 执行命令,如果一个命令能通过其他模块完成,则不建议使用 shell 模块。因为 shell 模块的状态判断能力比较弱。
- hosts: all
remote_user: root
tasks:
- name: "支持 $HOME、<、>、|、;、& 操作符号"
shell: service jboss start && chkconfig jboss on
- name: "支持脚本调用"
shell: somescript.sh > somelog.txt
- name: "执行命令前改变工作目录"
shell: somescript.sh > somelog.txt
args:
chdir: somedir/
- name: "执行命令前改变工作目录,并且仅在文件 some_log.txt 不存在时执行命令"
shell: somescript.sh > somelog.txt
args:
chdir: somedir/
creates: somelog.txt
- name: "使用 Bash 运行命令"
shell: cat < /tmp/\*txt
args:
executable: /bin/bash
模块:command
该模块与 shell 模块类似,但是不支持 $HOME、<、>、|、;、& 操作符号。
- hosts: all
remote_user: root
tasks:
- name: "调用单条命令"
command: /sbin/shutdown -t now
- name: "执行命令前改变工作目录,并且仅在文件不存在时执行命令"
command : /usr/bin/make_database.sh argl arg2
args:
chdir: somedir/
creates: /path/to/database
- name: "另外一种传参方式"
command: /sbin/shutdown -t now creates=/path/to/database