ansible
https://bbs.oldboyedu.com/thread-1513-1-1.html
- 安装配置
自动化运维工具ansible
ansible基于python开发的自动化运维工具(saltstack)
python语言是运维人员最佳的语言
其功能实现基于SSH远程连接服务
批量系统配置、批量软件部署、批量文件拷贝、批量运行命令等功能
特点:
1、不需要单独安装客户端,基于sshd服务的,sshd就相当于ansible的客户端
2、不需要服务端
3、依靠大量的模块实现
http://docs.ansible.com/ansible/intro_installation.html
http://docs.ansible.com/modules_by_category.html
http://docs.ansible.com/ansible/authorized_key_module.html
- ansible特点
不需要单独安装客户端,基于sshd服务,sshd就相当于ansible的客户端
不需要服务端
需要依靠大量的模块实现批量管理
- 管理机安装
yum install epel-release -y
yum install ansible -y
- 客户端安装(如果selinux开启则安装)
yum install libselinux-python -y
- 查看
[root@m01 ~]# ansible --version
ansible 2.2.0.0
config file = /etc/ansible/ansible.cfg
configured module search path = Default w/o overrides
- ansible配置文件
[root@m01 ~]# tree /etc/ansible/
/etc/ansible/
├── ansible.cfg
├── hosts
└── roles
1 directory, 2 files
ansible配置文件读取顺序
ANSIBLE_CONFIG (如果设置了环境变量)
ansible.cfg (在当前目录中)
~/.ansible.cfg (在家目录中)
/etc/ansible/ansible.cfg
- 管理机配置
vim /etc/ansible/hosts
添加
[oldboy]
172.16.1.31
172.16.1.41
172.16.1.61
172.16.1.7
172.16.1.8
[oldboy]
172.16.1.31 ansible_ssh_user=oldboy ansible_ssh_pass=123456 ansible_ssh_port=12345
172.16.1.41 ansible_ssh_user=oldboy ansible_ssh_pass=123456 ansible_ssh_port=12345
- 查看主机列表
ansible web --list-host
- ansible配置sudo
ansible及客户端都添加sudo授权用户
/etc/ansible/ansible.cfg
deprecation_warnings=False
sudo_user = oldboy
remote_port = 52113
ansible_connection
连接类型到主机。这可以是任何ansible连接插件的名称。SSH协议类型是smart,ssh或paramiko。默认是智能的。基于非SSH的类型将在下一节中介绍。
ansible_host 要连接的主机的名称,如果与您希望提供给它的别名不同。
ansible_port ssh端口号,如果不是22
ansible_user 要使用的默认ssh用户名。
ansible_ssh_host: ansible使用ssh要连接的主机。
ansible_ssh_port: ssh的端口。默认为22。
ansible_ssh_user: ssh登录的用户名。默认为root。
ansible_ssh_pass
要使用的ssh密码(永远不要将此变量存储为纯文本;始终使用保险库。请参阅变量和保险柜)
ansible_ssh_private_key_file
ssh使用的私钥文件。如果使用多个密钥并且您不想使用SSH代理,则很有用。
ansible_ssh_common_args
此设置始终附加到sftp,scp和ssh的默认命令行。ProxyCommand用于为特定主机(或组)配置
ansible_sftp_extra_args 此设置始终附加到默认的sftp命令行。
ansible_scp_extra_args 此设置始终附加到默认scp命令行。
ansible_ssh_extra_args 此设置始终附加到默认的ssh命令行。
ansible_ssh_pipelining 确定是否使用SSH流水线。这可以覆盖中的pipelining设置ansible.cfg。
ansible_ssh_executable(在2.2版中添加)
此设置将覆盖使用系统ssh的默认行为。这可以覆盖中的ssh_executable设置ansible.cfg。
ansible_become 等同于ansible_sudo或ansible_su允许强制权限升级
ansible_become_method 允许设置权限提升方法
ansible_become_user 等同于ansible_sudo_user或ansible_su_user允许通过权限提升设置您成为的用户
ansible_become_pass 等效于ansible_sudo_pass或ansible_su_pass允许您设置权限提升密码(永远不要将此变量存储为纯文本;始终使用保管库。请参阅变量和保管库)
ansible_become_exe 等效于ansible_sudo_exe或ansible_su_exe允许您为所选的升级方法设置可执行文件
ansible_become_flags 等效于ansible_sudo_flags或ansible_su_flags允许您设置传递给选定升级方法的标志。这也可以ansible.cfg在sudo_flags选项中全局设置
ansible_shell_type
目标系统的shell类型。除非已将ansible_shell_executable设置为非Bourne(sh)兼容shell,否则不应使用此设置 。默认情况下,命令使用sh-style语法格式化。将此设置为csh或fish将导致在目标系统上执行的命令遵循这些shell的语法。
ansible_python_interpreter
目标主机python路径。这对于具有多个Python或不位于/ usr / bin / python的系统(如* BSD)或/ usr / bin / python 不是2.X系列Python的系统非常有用。我们不使用/ usr / bin / env机制,因为它需要设置远程用户的路径,并假设python可执行文件名为python,其中可执行文件可能被命名为python2.6。
ansible_shell_executable
这将设置ansible控制器将目标机器上使用的壳,将覆盖executable在ansible.cfg其中默认为 / bin / sh的。如果无法使用/ bin / sh(即/ bin / sh未安装在目标计算机上或无法从sudo运行),您应该只更改它。
- 普通用户批量管理
1、管理机与所有被管理机都创建普通用户并sudo授权
wuxingge ALL=(ALL) NOPASSWD: ALL
2、管理机普通用户创建密钥对并分发公钥
3、ansible配置
/etc/ansible/ansible.cfg
...
sudo_user = wuxingge
deprecation_warnings = False
private_key_file = /home/wuxingge/.ssh/id_rsa
4、测试
ansible web -m copy -a "src=/etc/hosts dest=/root/" -s
ansible-playbook test.yml -s
提示信息颜色
ansible软件颜色信息
绿色: 表示查看信息,对远程主机未做改动的命令
红色: 批量管理产生错误信息
黄色: 对远程主机做了相应改动
粉色: 对操作提出建议或忠告
hosts
[https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html)
/etc/ansible/hosts
mail.example.com
[webservers]
foo.example.com
bar.example.com
[dbservers]
one.example.com
two.example.com
three.example.com
###################yaml
all:
hosts:
mail.example.com:
children:
webservers:
hosts:
foo.example.com:
bar.example.com:
dbservers:
hosts:
one.example.com:
two.example.com:
three.example.com:
jumper ansible_port=5555 ansible_host=192.0.2.50
############# yaml
hosts:
jumper:
ansible_port: 5555
ansible_host: 192.0.2.50
##
children
[oldboyall:children]
oldboydb
oldboyweb
[oldboydb]
172.16.1.31
[oldboyweb]
172.16.1.7
[atlanta]
host1
host2
[raleigh]
host2
host3
[southeast:children]
atlanta
raleigh
[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2
[usa:children]
southeast
northeast
southwest
northwest
############ yaml
all:
children:
usa:
children:
southeast:
children:
atlanta:
hosts:
host1:
host2:
raleigh:
hosts:
host2:
host3:
vars:
some_server: foo.southeast.example.com
halon_system_timeout: 30
self_destruct_countdown: 60
escape_pods: 2
northeast:
northwest:
southwest:
##
变量(vars)
[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
################yaml
atlanta:
hosts:
host1:
host2:
vars:
ntp_server: ntp.atlanta.example.com
proxy: proxy.atlanta.example.com
##
hosts (inventory)
grep -i "^inventory" ansible.cfg
inventory = /etc/ansible/inventory/
cat **inventory**/data
[backup]
172.16.1.41
cat test.yml
---
- hosts:
- backup
tasks:
- name: Another symbolic mode example, adding some permissions and removing others
copy:
src: /etc/hosts
dest: /etc/hosts
...
* * *
#
**模块**
http://docs.ansible.com
**ansible [-m module_name] [-a args] [options]**
1. **command模块**
oldboy为主机组的名字
-m 后边是模块名
-m MODULE_NAME, --module-name=MODULE_NAME
module name to execute (default=command)
默认的模块是command
-a 后面是要执行的命令,也可以写一个ip,针对一台机器来执行命令
-a MODULE_ARGS, --args=MODULE_ARGS
module arguments
ansible oldboy -m command -a 'uptime'
- name: return motd to registered var
command: cat /etc/motd
ansible oldboy -m command -a "chdir=/tmp touch hosts01"
ansible oldboy -m command -a "creates=/tmp/hosts01 touch hosts01"
##
**shell模块**
http://docs.ansible.com/ansible/latest/shell_module.html
执行脚本(脚本需要分发到远程机器)
[root@m01 ~]# echo 'yum install -y ipvsadm' >> /server/scripts/yum.sh
[root@m01 ~]# cat /server/scripts/yum.sh
yum install -y ipvsadm
ansible oldboy -m copy -a "src=/server/scripts/yum.sh dest=/server/scripts/ mode=0755"
ansible oldboy -m shell -a "/bin/bash /server/scripts/yum.sh"
- name: Execute the command in remote shell; stdout goes to the specified file on the remote.
shell: somescript.sh >> somelog.txt
- name: Change the working directory to somedir/ before executing the command.
shell: somescript.sh >> somelog.txt
args:
chdir: somedir/
# You can also use the 'args' form to provide the options.
- name: This command will change the working directory to somedir/ and will only run when somedir/somelog.txt doesn't exist.
shell: somescript.sh >> somelog.txt
args:
chdir: somedir/
creates: somelog.txt
- name: Run a command that uses non-posix shell-isms (in this example /bin/sh doesn't handle redirection and wildcards together but
shell: cat < /tmp/*txt
args:
executable: /bin/bash
1. **ping模块**
http://docs.ansible.com/ansible/latest/ping_module.html
ansible oldboy -m ping
##
**copy模块**
[https://docs.ansible.com/ansible/latest/modules/copy_module.html#copy-module](https://docs.ansible.com/ansible/latest/modules/copy_module.html#copy-module)
copy模块将文件从本地复制到远程计算机上的某个位置
ansible oldboy -m copy -a "src=/etc/passwd dest=/tmp/oldgirl.txt owner=oldboy group=oldboy mode=0755"
ansible copy模块 会自动创建多级目录
[root@m01 scripts]# ansible oldboy -m copy -a "src=/etc/hosts dest=/tmp/a/b/c/e/d/f/f/g/"
目标目录都存在的情况下,可以传输过去同时修改文件名
ansible oldboy -m copy -a "src=/etc/hosts dest=/tmp/HOSTS"
ansible oldboy -m copy -a "src=/etc/hosts dest=/mnt backup=yes"
backup=yes 备份
# Example from Ansible Playbooks
- copy:
src: /srv/myfiles/foo.conf
dest: /etc/foo.conf
owner: foo
group: foo
mode: 0644
- copy:
content: xxxxxxxxxxx
dest: /some/path/systems.csv
owner: foo
group: foo
mode: 0644
backup: yes
ansible oldboy -m copy -a "content='alex.python' dest=/tmp/alex.txt"
##
template
[https://docs.ansible.com/ansible/latest/modules/template_module.html#template-module](https://docs.ansible.com/ansible/latest/modules/template_module.html#template-module)
# Example from Ansible Playbooks
- template:
src: /mytemplates/foo.j2
dest: /etc/file.conf
owner: bin
group: wheel
mode: 0644
# The same example, but using symbolic modes equivalent to 0644
- template:
src: /mytemplates/foo.j2
dest: /etc/file.conf
owner: bin
group: wheel
mode: "u=rw,g=r,o=r"
# Create a DOS-style text file from a template
- template:
src: config.ini.j2
dest: /share/windows/config.ini
newline_sequence: '\r\n'
# Copy a new "sudoers" file into place, after passing validation with visudo
- template:
src: /mine/sudoers
dest: /etc/sudoers
validate: '/usr/sbin/visudo -cf %s'
# Update sshd configuration safely, avoid locking yourself out
- template:
src: etc/ssh/sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0600'
validate: /usr/sbin/sshd -t -f %s
backup: yes
1. **fetch 模块**
从远程节点获取文件
#指定目的路径
fetch:
src: /tmp/uniquefile
dest: /tmp/special/
flat: yes
ansible 10.0.0.41 -m fetch -a "src=/etc/rsyncd.conf dest=/etc/ansible/conf/rsync/ flat=yes"
##
**script 模块(不需要分发脚本)**
http://docs.ansible.com/ansible/latest/script_module.html
echo 'mkdir -p /tmp/oldboy/{a..d}' > /server/scripts/mkdir.sh
ansible oldboy -m script -a "/server/scripts/mkdir.sh"
cat >>/server/scripts/yuan.sh< /dev/null"
cron:
name: "check dirs"
minute: "0"
hour: "5,2"
job: "ls -alh > /dev/null"
- name: 'Ensure an old job is no longer present. Removes any job that is prefixed by "#Ansible: an old job" from the crontab'
cron:
name: "an old job"
state: absent
- name: Creates an entry like "@reboot /some/job.sh"
cron:
name: "a job for reboot"
special_time: reboot
job: "/some/job.sh"
- name: Creates an entry like "PATH=/opt/bin" on top of crontab
cron:
name: PATH
env: yes
value: /opt/bin
- name: Creates an entry like "APP_HOME=/srv/app" and insert it after PATH declaration
cron:
name: APP_HOME
env: yes
value: /srv/app
insertafter: PATH
- name: Creates a cron file under /etc/cron.d
cron:
name: yum autoupdate
weekday: 2
minute: 0
hour: 12
user: root
job: "YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate"
cron_file: ansible_yum-autoupdate
- name: Removes a cron file from under /etc/cron.d
cron:
name: "yum autoupdate"
cron_file: ansible_yum-autoupdate
state: absent
- name: Removes "APP_HOME" environment variable from crontab
cron:
name: APP_HOME
env: yes
state: absent
##
**mount 模块**
[https://docs.ansible.com/ansible/latest/modules/mount_module.html#mount-module](https://docs.ansible.com/ansible/latest/modules/mount_module.html#mount-module)
Control active and configured mount points
This module controls active and configured mount points in /etc/fstab
# Before 2.3, option 'name' was used instead of 'path'
- name: Mount DVD read-only
mount:
path: /mnt/dvd
src: /dev/sr0
fstype: iso9660
opts: ro
state: present
- name: Mount up device by label
mount:
path: /srv/disk
src: LABEL=SOME_LABEL
fstype: ext4
state: present
- name: Mount up device by UUID
mount:
path: /home
src: UUID=b3e48f45-f933-4c8e-a700-22a159ec9077
fstype: xfs
opts: noatime
state: present
- name: mount
mount:
path: /mnt
src: 10.0.0.31:/data
fstype: nfs
state: mounted
##
**file模块**
[https://docs.ansible.com/ansible/latest/modules/file_module.html](https://docs.ansible.com/ansible/latest/modules/file_module.html)
# change file ownership, group and mode
- file:
path: /etc/foo.conf
owner: foo
group: foo
# when specifying mode using octal numbers, add a leading 0
mode: 0644
- file:
path: /work
owner: root
group: root
mode: 01777
- file:
src: /file/to/link/to
dest: /path/to/symlink
owner: foo
group: foo
state: link
- file:
src: '/tmp/{{ item.src }}'
dest: '{{ item.dest }}'
state: link
with_items:
- { src: 'x', dest: 'y' }
- { src: 'z', dest: 'k' }
# touch a file, using symbolic modes to set the permissions (equivalent to 0644)
- file:
path: /etc/foo.conf
state: touch
mode: "u=rw,g=r,o=r"
# touch the same file, but add/remove some permissions
- file:
path: /etc/foo.conf
state: touch
mode: "u+rw,g-wx,o-rwx"
# touch again the same file, but dont change times
# this makes the task idempotents
- file:
path: /etc/foo.conf
state: touch
mode: "u+rw,g-wx,o-rwx"
modification_time: "preserve"
access_time: "preserve"
# create a directory if it doesn't exist
- file:
path: /etc/some_directory
state: directory
mode: 0755
##
**setup ( 收集关于远程主机的信息)**
[https://docs.ansible.com/ansible/latest/modules/setup_module.html#setup-module](https://docs.ansible.com/ansible/latest/modules/setup_module.html#setup-module)
用于收集信息
ansible all -m setup -vvvv
ansible all -m setup -a "filter=ansible_all_ipv4_addresses"
ansible all -m setup -a "filter=ansible_eth0[ipv4]"
ansible_all_ipv4_addresses:仅显示ipv4的信息。
ansible_devices:仅显示磁盘设备信息。
ansible_distribution:显示是什么系统,例:centos,suse等。
ansible_distribution_major_version:显示是系统主版本。
ansible_distribution_version:仅显示系统版本。
ansible_machine:显示系统类型,例:32位,还是64位。
ansible_eth0:仅显示eth0的信息。
ansible_hostname:仅显示主机名。
ansible_kernel:仅显示内核版本。
ansible_lvm:显示lvm相关信息。
ansible_memtotal_mb:显示系统总内存。
ansible_memfree_mb:显示可用系统内存。
ansible_memory_mb:详细显示内存情况。
ansible_swaptotal_mb:显示总的swap内存。
ansible_swapfree_mb:显示swap内存的可用内存。
ansible_mounts:显示系统磁盘挂载情况。
ansible_processor:显示cpu个数(具体显示每个cpu的型号)。
ansible_processor_vcpus:显示cpu个数(只显示总的个数)。
##
debug
ansible 172.16.1.7 -m debug -a "var=ansible_eth1.ipv4.address"
##
**查看Ansible的帮助**
ansible-doc -l 列出所有的模块
ansible-doc -s service 查看指定模块用法
ansible-doc yum
ansible-doc -l
问题:
[root@m01 ~]# ansible-doc -l
[DEPRECATION WARNING]: docker is kept for backwards compatibility but usage is discouraged.
The module documentation details page may explain more about this rationale..
This feature
will be removed in a future release. Deprecation warnings can be disabled by setting
**deprecation_warnings=False** in ansible.cfg.
[ERROR]: unable to parse **/usr/lib/python2.6/site-packages/ansible/modules/extras/cloud/misc/rhevm.py**
ERROR! module rhevm has a documentation error formatting or is missing documentation
解决:
[root@m01 ~]# grep deprecation_warnings /etc/ansible/ansible.cfg
#deprecation_warnings = True
[root@m01 ~]# sed -i.bak 's@#deprecation_warnings = True@deprecation_warnings = False@g' /etc/ansible/ansible.cfg
[root@m01 ~]# grep deprecation_warnings /etc/ansible/ansible.cfg
deprecation_warnings = False
mv /usr/lib/python2.6/site-packages/ansible/modules/extras/cloud/misc/rhevm.py /tmp/
##
**yum模块**
http://docs.ansible.com/ansible/latest/yum_module.html
ansible oldboy -m yum -a "name=keepalived state=installed"
- name: install the latest version of Apache
yum:
name: httpd
state: latest
- name: ensure a list of packages installed
yum:
name: "{{ packages }}"
vars:
packages:
- httpd
- httpd-tools
- name: remove the Apache package
yum:
name: httpd
state: absent
- name: install the latest version of Apache from the testing repo
yum:
name: httpd
enablerepo: testing
state: present
##
yum_repository模块
- name: Add repository
yum_repository:
name: epel
description: EPEL YUM repo
baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
- name: Add multiple repositories into the same file (1/2)
yum_repository:
name: epel
description: EPEL YUM repo
file: external_repos
baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
gpgcheck: no
- name: Add multiple repositories into the same file (2/2)
yum_repository:
name: rpmforge
description: RPMforge YUM repo
file: external_repos
baseurl: http://apt.sw.be/redhat/el7/en/$basearch/rpmforge
mirrorlist: http://mirrorlist.repoforge.org/el7/mirrors-rpmforge
enabled: no
# Handler showing how to clean yum metadata cache
- name: yum-clean-metadata
command: yum clean metadata
args:
warn: no
# Example removing a repository and cleaning up metadata cache
- name: Remove repository (and clean up left-over metadata)
yum_repository:
name: epel
state: absent
notify: yum-clean-metadata
- name: Remove repository from a specific repo file
yum_repository:
name: epel
file: external_repos
state: absent
- name: Add Base Yum Repository
yum_repository:
name: base
description: Base Aliyun Repository
baseurl: http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
gpgcheck: yes
gpgkey: http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
- name: Add nginx Yum Repository
yum_repository:
name: nginx-stable
description: nginx-stable Repository
baseurl: http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck: yes
gpgkey: https://nginx.org/keys/nginx_signing.key
##
**service模块**
http://docs.ansible.com/ansible/latest/service_module.html
ansible oldboy -m service -a "name=crond state=started enabled=yes"
- name: Start service httpd, if not started
service:
name: httpd
state: started
- name: Stop service httpd, if started
service:
name: httpd
state: stopped
- name: Restart service httpd, in all cases
service:
name: httpd
state: restarted
- name: Reload service httpd, in all cases
service:
name: httpd
state: reloaded
- name: Enable service httpd, and not touch the state
service:
name: httpd
enabled: yes
- name: Start service foo, based on running process /usr/bin/foo
service:
name: foo
pattern: /usr/bin/foo
state: started
- name: Restart network service for interface eth0
service:
name: network
state: restarted
args: eth0
##
**user模块**
- name: Add the user 'johnd' with a specific uid and a primary group of 'admin'
user:
name: johnd
comment: John Doe
uid: 1040
group: admin
shell: /bin/bash
groups: admins,developers
create_home: no
append: yes
- name: Remove the user 'johnd'
user:
name: johnd
state: absent
remove: yes
##
group模块
- name: Ensure group "somegroup" exists
group:
name: somegroup
gid: 1000
state: present
##
**archive模块**
[https://docs.ansible.com/ansible/latest/modules/archive_module.html#archive-module](https://docs.ansible.com/ansible/latest/modules/archive_module.html#archive-module)
- name: Create a bz2 archive of a globbed path, while excluding a glob of dirnames
archive:
path:
- /path/to/foo/*
dest: /path/file.tar.bz2
exclude_path:
- /path/to/foo/ba*
format: bz2
- name: Create a zip archive of /path/to/foo
archive:
path: /path/to/foo
format: zip
##
**unarchive模块**
[https://docs.ansible.com/ansible/latest/modules/unarchive_module.html#unarchive-module](https://docs.ansible.com/ansible/latest/modules/unarchive_module.html#unarchive-module)
默认解压方式 **/usr/bin/gtar /usr/bin/unzip**
- name: Unarchive a file that is already on the remote machine
unarchive:
src: /tmp/foo.zip
dest: /usr/local/bin
remote_src: yes
- name: Unarchive a file that needs to be downloaded (added in 2.0)
unarchive:
src: https://example.com/example.zip
dest: /usr/local/bin
remote_src: yes
**creates**
##
**selinux模块**
- selinux:
state: disabled
##
**synchronize模块**
# Synchronization of src on the control machine to dest on the remote hosts
- synchronize:
src: some/relative/path
dest: /some/absolute/path
# Synchronization using rsync protocol (push)
- synchronize:
src: some/relative/path/
dest: rsync://somehost.com/path/
# Synchronization using rsync protocol (pull)
- synchronize:
mode: pull
src: rsync://somehost.com/path/
dest: /some/absolute/path/
##
**authorized_key模块**
1. **修改配置文件**
[root@m01 ~]# grep host_key_checking /etc/ansible/ansible.cfg -n
59:#host_key_checking = False
[root@m01 ~]# sed -i.ori '59s@#host_key_checking = False@host_key_checking = False@g' /etc/ansible/ansible.cfg
[root@m01 ~]# grep host_key_checking /etc/ansible/ansible.cfg -n
59:host_key_checking = False
1. **分发公钥**
ssh-keygen -t dsa -P "" -f /root/.ssh/id_dsa &> /dev/null
ansible oldboy -m authorized_key -a "user=oldboy key='{{ lookup('file', '/home/oldboy/.ssh/id_rsa.pub') }}'" -k
- name: Set authorized key took from file
authorized_key:
user: charlie
state: present
key: "{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"
---
- hosts: nginx
tasks:
- name: Set authorized key took from file
authorized_key:
user: root
state: present
key: "{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"
cat authkey.yml
---
- hosts:
- nfs01
- backup
tasks:
- name: Set authorized key took from file
authorized_key:
user: root
state: present
key: "{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"
...
##
debug
- debug:
msg: "System {{ inventory_hostname }} has uuid {{ ansible_product_uuid }}"
##
mysql_db模块
添加或删除数据库
ansible安装
yum install MySQL-python
yum install python2-PyMySQL
远程主机安装
yum install MySQL-python
yum install python2-PyMySQL
**cat ~/.my.cnf **
[mysql]
host=172.16.1.7
user=root
password=123456
- name: Create a new database with name 'bobdata'
mysql_db:
name: bobdata
state: present
# Copy database dump file to remote host and restore it to database 'my_db'
- name: Copy database dump file
copy:
src: dump.sql.bz2
dest: /tmp
- name: Restore database
mysql_db:
name: my_db
state: import
target: /tmp/dump.sql.bz2
- name: Dump all databases to hostname.sql
mysql_db:
state: dump
name: all
target: /tmp/{{ inventory_hostname }}.sql
- name: Import file.sql similar to mysql -u -p < hostname.sql
mysql_db:
state: import
name: all
target: /tmp/{{ inventory_hostname }}.sql
state
present
absent
dump
import
---
- hosts: 172.16.1.7
tasks:
- name: Create a new database with name 'bobdata'
mysql_db:
name: blog
state: present
##
mysql_user模块
# Removes anonymous user account for localhost
- mysql_user:
name: ''
host: localhost
state: absent
# Removes all anonymous user accounts
- mysql_user:
name: ''
host_all: yes
state: absent
# Create database user with name 'bob' and password '12345' with all database privileges
- mysql_user:
name: bob
password: 12345
priv: '*.*:ALL'
state: present
# Create database user with name 'bob' and previously hashed mysql native password '*EE0D72C1085C46C5278932678FBE2C6A782821B4' with all database privileges
- mysql_user:
name: bob
password: '*EE0D72C1085C46C5278932678FBE2C6A782821B4'
encrypted: yes
priv: '*.*:ALL'
state: present
# Creates database user 'bob' and password '12345' with all database privileges and 'WITH GRANT OPTION'
- mysql_user:
name: bob
password: 12345
priv: '*.*:ALL,GRANT'
state: present
# Modify user Bob to require SSL connections. Note that REQUIRESSL is a special privilege that should only apply to *.* by itself.
- mysql_user:
name: bob
append_privs: true
priv: '*.*:REQUIRESSL'
state: present
# Ensure no user named 'sally'@'localhost' exists, also passing in the auth credentials.
- mysql_user:
login_user: root
login_password: 123456
name: sally
state: absent
# Ensure no user named 'sally' exists at all
- mysql_user:
name: sally
host_all: yes
state: absent
# Specify grants composed of more than one word
- mysql_user:
name: replication
password: 12345
priv: "*.*:REPLICATION CLIENT"
state: present
# Revoke all privileges for user 'bob' and password '12345'
- mysql_user:
name: bob
password: 12345
priv: "*.*:USAGE"
state: present
# Example privileges string format
# mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanotherdb.*:ALL
# Example using login_unix_socket to connect to server
- mysql_user:
name: root
password: abc123
login_unix_socket: /var/run/mysqld/mysqld.sock
# Example of skipping binary logging while adding user 'bob'
- mysql_user:
name: bob
password: 12345
priv: "*.*:USAGE"
state: present
sql_log_bin: no
# Example .my.cnf file for setting the root password
# [client]
# user=root
# password=n<_665{vS43y
---
- hosts: 172.16.1.7
tasks:
- name: create mysql user
mysql_user:
login_host: 172.16.1.7
login_user: root
login_password: 123456
name: www
host: '%'
password: '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9'
encrypted: yes
priv: '*.*:ALL'
state: present
**cat ~/.my.cnf **
[mysql]
host=172.16.1.7
user=root
password=123456
---
- hosts: 172.16.1.7
tasks:
- name: create mysql user
mysql_user:
name: wuxingge
host: '%'
password: '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9'
encrypted: yes
priv: '*.*:ALL'
state: present
##
mysql_replication模块
# Stop mysql slave thread
- mysql_replication:
mode: stopslave
# Get master binlog file name and binlog position
- mysql_replication:
mode: getmaster
# Change master to master server 192.0.2.1 and use binary log 'mysql-bin.000009' with position 4578
- mysql_replication:
mode: changemaster
master_host: 192.0.2.1
master_log_file: mysql-bin.000009
master_log_pos: 4578
# Check slave status using port 3308
- mysql_replication:
mode: getslave
login_host: ansible.example.com
login_port: 3308
**mode**
getslave
getmaster
changemaster
stopslave
startslave
resetslave
resetslaveall
#
**ansible playbook(剧本)**
[https://docs.ansible.com/ansible/latest/user_guide/playbooks.html](https://docs.ansible.com/ansible/latest/user_guide/playbooks.html)
关键字
[https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html](https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html)
##
**语法格式**
ansible剧本格式 yaml语法格式
rsync配置文件格式 ini语法格式
sersync配置文件格式 xml语法格式
json语法格式
##
yaml语法
1.缩进
aaaa
bbbb
cccc
2.列表
项目:
- 项目名1
- 项目名2
3.冒号空格
key: value
1. **剧本存放目录**
[root@m01 ~]# cd /etc/ansible/
[root@m01 ansible]# ll
总用量 32
-rw-r--r-- 1 root root 18066 6月 2 05:49 ansible.cfg
-rw-r--r-- 1 root root 33 6月 30 10:14 hosts
-rw-r--r-- 1 root root 1016 6月 30 10:13 hosts.bak
drwxr-xr-x 2 root root 4096 6月 2 05:49 roles
/etc/ansible/ansible_playbook
1. **一个标准的剧本写法**
cat /etc/ansible/test.yml
---
- hosts: 10.0.0.31
gather_facts: no
tasks:
- name: add user
user:
name: rsync
shell: /sbin/nologin
createhome: no
...
---
- hosts:
- backup
- nfs
gather_facts: no
tasks:
- name: touch file
file:
path: /tmp/test01.txt
state: touch
...
atlanta:
hosts:
host1:
host2:
vars:
ntp_server: ntp.atlanta.example.com
proxy: proxy.atlanta.example.c
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: write the apache config file
template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service:
name: httpd
state: started
handlers:
- name: restart apache
service:
name: httpd
state: restarted
---
- hosts: webservers
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: write the apache config file
template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
- hosts: databases
remote_user: root
tasks:
- name: ensure postgresql is at the latest version
yum:
name: postgresql
state: latest
- name: ensure that postgresql is started
service:
name: postgresql
state: started
/etc/ansible/hosts
...
[oldboy]
10.0.0.31
10.0.0.8
1. **编写剧本**
cat /etc/ansible/test1.yml
---
- hosts: oldboy
tasks:
- name: add user
user:
name: rsync
shell: /sbin/nologin
createhome: no
...
[root@m01 ansible]# cat /etc/ansible/show.yml
---
- hosts: all
tasks:
- command: ifconfig
[root@m01 ansible]# cat /etc/ansible/ifconfig.yml
---
- hosts: oldboy
tasks:
- name: show ip
shell: ifconfig >/tmp/new.txt
cat /etc/ansible/ansible_playbook/test01.yaml
---
- hosts: oldboy
tasks:
- file: dest=/tmp/oldgirl.txt state=touch
...
1. **检查剧本语法**
ansible-playbook --syntax-check /etc/ansible/ansible_playbook/test01.yaml
1. **模拟执行剧本(检查)**
[root@m01 ansible]# **ansible-playbook /etc/ansible/show.yml -C**
PLAY [all] ********************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************
ok: [172.16.1.41]
ok: [172.16.1.31]
TASK [command] ****************************************************************************************************
skipping: [172.16.1.41]
skipping: [172.16.1.31]
PLAY RECAP ********************************************************************************************************
172.16.1.31 : ok=1 changed=0 unreachable=0 failed=0
172.16.1.41 : ok=1 changed=0 unreachable=0 failed=0
ansible oldboy -m shell -a "ifconfig >/tmp/new.txt"
变为剧本
[root@m01 ansible]# cat /etc/ansible/ifconfig.yml
---
- hosts: oldboy
tasks:
- shell: ifconfig >/tmp/new.txt
[root@m01 ansible]# ansible-playbook /etc/ansible/ifconfig.yml -C
PLAY [oldboy] *****************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************
ok: [172.16.1.31]
ok: [172.16.1.41]
TASK [command] ****************************************************************************************************
skipping: [172.16.1.41]
skipping: [172.16.1.31]
PLAY RECAP ********************************************************************************************************
172.16.1.31 : ok=1 changed=0 unreachable=0 failed=0
172.16.1.41 : ok=1 changed=0 unreachable=0 failed=0
给所有服务器添加定时任务----变为剧本
ansible oldboy -m cron -a 'name="restart network" minute=00 hour=00 job="/etc/init.d/network restart >/dev/null 2>&1" state=present'
#ansible oldboy
#-m cron -a 'name="network restart 007" minute=00 hour=00 job="/etc/init.d/network restart >/dev/null 2>&1" state=present '
[root@m01 ansible]# cat /etc/ansible/network-restart.yml
---
- hosts: oldboy
tasks:
- name: restart network 007
cron: name="network restart 007" minute=00 hour=00 job="/etc/init.d/network restart > /dev/null 2>&1" state=present
1. **handler**
web.yaml
- hosts: web
tasks:
- name: Install Httpd Server
yum:
name: httpd,httpd-tools
state: installed
- name: Config Httpd Server
copy:
src: ./httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify: restart httpd
- name: Start Httpd Server
service:
name: httpd
state: started
enabled: yes
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
1. **剧本编写多个命令**
[root@m01 ansible]# cat show.yml
---
- hosts: oldboy
tasks:
- name: show hostname
shell: hostname >> /tmp/name.log
- name: show ipaddr
shell: ip a >> /tmp/ip.log
[root@m01 ansible]# **ansible-playbook show.yml -C**
PLAY [oldboy] *******************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************
ok: [172.16.1.41]
ok: [172.16.1.31]
TASK [show hostname] ************************************************************************************************************
skipping: [172.16.1.31]
skipping: [172.16.1.41]
TASK [show ipaddr] **************************************************************************************************************
skipping: [172.16.1.31]
skipping: [172.16.1.41]
PLAY RECAP **********************************************************************************************************************
172.16.1.31 : ok=1 changed=0 unreachable=0 failed=0
172.16.1.41 : ok=1 changed=0 unreachable=0 failed=0
[root@m01 ansible]# ansible-playbook show.yml
PLAY [oldboy] *******************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************
ok: [172.16.1.41]
ok: [172.16.1.31]
TASK [show hostname] ************************************************************************************************************
changed: [172.16.1.31]
changed: [172.16.1.41]
TASK [show ipaddr] **************************************************************************************************************
changed: [172.16.1.31]
changed: [172.16.1.41]
PLAY RECAP **********************************************************************************************************************
172.16.1.31 : ok=3 changed=2 unreachable=0 failed=0
172.16.1.41 : ok=3 changed=2 unreachable=0 failed=0
1. **剧本编写多个主机**
[root@m01 ansible]# cat /etc/ansible/multi-host.yml
- hosts: 172.16.1.41
tasks:
- name: show hostname
shell: hostname >>/tmp/name2.log
- hosts: 172.16.1.31
tasks:
- name: show ipaddr
shell: ip a >>/tmp/ip2.log
yum install htop -y
1、翻译为ansible命令
ansible all -m shell -a "yum install htop -y" #ansible all -m yum -a "name=cowsay,sl"
2、翻译为playbook
- hosts: all
tasks:
- name: yum install htop
yum: name=htop,sl,cowsay
3、测试、执行
- name: install the latest version of Apache
yum:
name: httpd
state: latest
- name: install httpd,vsftpd,htop
yum:
name: httpd,vsftpd,htop
state: latest
1. **剧本执行多条命令**
cat rsync.yml
#rsync server play-book
- hosts: 172.16.1.41
tasks:
- name: 1.install rsync
yum: name=rsync state=installed
- name: 2.edit rsyncd.conf
copy: src=/etc/ansible/conf/rsync/rsyncd.conf dest=/etc/
- name: 3.create rsync user
shell: userdel -r rsync && useradd rsync -s /sbin/nologin -M
- name: 4.create auth file
copy: src=/etc/ansible/conf/rsync/rsync.password dest=/etc/ mode=600
- name: 5.create backup dir
file: dest=/backup state=directory owner=rsync group=rsync
- name: 6.start rsync server
shell: rsync –daemon
1. **部署rsync**
---
- hosts: 10.0.0.31
tasks:
- name: add user
user: name=rsync shell=/sbin/nologin createhome=no
- name: install rsync
yum: name=rsync state=latest
- name: copy rsyncd.conf
copy: src=/etc/rsyncd.conf dest=/etc/rsyncd.conf owner=root group=root mode=0644
- name: rsync password
copy: content='rsync_backup:123' dest=/etc/rsync.password owner=root group=root mode=0600
- name: create /backup dir
file: path=/backup state=directory owner=rsync group=rsync mode=0755
- name: start rsync
shell: /usr/bin/rsync --daemon
...
---
- hosts: 10.0.0.31
tasks:
- name: add user
user:
name: rsync
shell: /sbin/nologin
createhome: no
- name: install rsync
yum:
name: rsync
state: latest
- name: copy rsyncd.conf
copy:
src: /etc/rsyncd.conf
dest: /etc/rsyncd.conf
owner: root
group: root
mode: 0644
- name: rsync password
copy:
content: rsync_backup:123
dest: /etc/rsync.password
owner: root
group: root
mode: 0600
- name: create /backup dir
file:
path: /backup
state: directory
owner: rsync
group: rsync
mode: 0755
- name: start rsync
shell: rsync --daemon
args:
chdir: /usr/bin/
...
---
- hosts: 10.0.0.31
tasks:
- name: add user
user:
name: rsync
shell: /sbin/nologin
createhome: no
- name: install rsync
yum:
name: rsync
state: latest
- name: copy rsyncd.conf
copy:
src: /etc/rsyncd.conf
dest: /etc/rsyncd.conf
owner: root
group: root
mode: 0644
- name: rsync password
copy:
content: rsync_backup:123
dest: /etc/rsync.password
owner: root
group: root
mode: 0600
- name: create /backup dir
file:
path: /backup
state: directory
owner: rsync
group: rsync
mode: 0755
- name: start rsync
shell: /usr/bin/rsync --daemon
...
变量
[https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html)
#
在剧本文件中进行定义 vars
- hosts: webservers
vars:
http_port: 80
#
利用执行参数赋值变量 --extra-vars
ansible-playbook -e dir_info=/oldboy/ -e file_info=oldboy01.txt test_var.yaml
#
单独在一个文件中定义 /etc/ansible/hosts
[oldboy]
172.16.1.31
172.16.1.41
172.16.1.7
[oldboy:vars]
dir_info=/oldboy/
file_info=oldboy01.txt
变量优先级
**命令行 > 剧本 > 主机清单**
#
采用注册方式定义变量 register
- name: check rpc port
shell: ss -lntup |grep 111
register: check_port_info
- name: output check info
debug:
msg: '{{ check_port_info.stdout_lines }}'
foo:
field1: one
field2: two
foo['field1']
foo.field1
引用变量
{{ foo }}
cat var.yml
---
- hosts: oldboy
remote_user: root
vars:
file_info: oldboy01.txt
dir_info: /oldboy/
tasks:
- name: create dir
file:
path: '{{ dir_info }}'
state: directory
- name: copy file
copy:
src: '{{ dir_info }}{{ file_info }}'
dest: '{{ dir_info }}'
**group_vars/**和**host_vars/**目录可以存在于**playbook目录**或**inventory目录**中。如果两个路径都存在,则playbook目录中的变量将覆盖inventory目录中设置的变量。
**/etc/ansible/group_vars/raleigh** #可以选择以'.yml','。yaml'或'.json'
/etc/ansible/host_vars/foosball
例如,假设您有按数据中心分组的主机,并且每个数据中心使用一些不同的服务器。'raleigh'组的组文件 **/etc/ansible/group_vars/raleigh** 中的数据可能如下所示:
---
ntp_server: acme.example.org
database_server: storage.example.org
**group variable**
[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
atlanta:
hosts:
host1:
host2:
vars:
ntp_server: ntp.atlanta.example.com
proxy: proxy.atlanta.example.com
* * *
tags
[https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html](https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html)
指定位置添加标签,可以指定标签执行剧本
- hosts: 172.16.1.7
gather_facts: no
tasks:
- name: mount
mount:
src: "172.16.1.31:/data"
path: "/mnt"
fstype: nfs
state: mounted
tags: mount-nfs
只执行标签
ansible-playbook -t mount-nfs nfs.yml
不执行标签
ansible-playbook --skip-tags "mount-nfs" nfs.yml
忽略错误
**ignore_errors: yes**
* * *
notify和handler
notify
tasks:
- name: copy template file to remote host
template:
src: /etc/ansible/nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- restart nginx
- test web page
copy:
src: nginx/index.html.j2
dest: /usr/share/nginx/html/index.html
notify:
- restart nginx
handler
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
- name: test web page
shell: curl -I http://192.168.100.10/index.html | grep 200 || /bin/false
* * *
nfs.yml
---
- hosts: all
gather_facts: no
tasks:
- name: install nfs
yum:
name:
- nfs-utils
- rpcbind
state: installed
- hosts: 172.16.1.31
gather_facts: no
tasks:
- name: push exports
copy:
src: export.temp
dest: /etc/exports
notify: restart nfs
- name: create data dir
file:
path: /data
owner: nfsnobody
group: nfsnobody
state: directory
- name: start nfs
service:
name: rpcbind
name: nfs
state: started
enabled: yes
tags: test-nfs-start
- name: check rpc port
shell: ss -lntup |grep 111
register: check_port_info
- name: output check info
debug:
msg: '{{ check_port_info.stdout_lines }}'
tags: test_port
handlers:
- name: restart nfs
service:
name: nfs
state: restarted
- hosts: 172.16.1.7
gather_facts: no
tasks:
- name: mount
mount:
src: "172.16.1.31:/data"
path: "/mnt"
fstype: nfs
state: mounted
tags: mount-nfs
...
cat rsync.yml
---
- hosts: all
remote_user: root
tasks:
- name: install rsync
yum:
name: rsync
state: installed
tags: install rsync
- hosts: 172.16.1.41
tasks:
- name: copy rsyncd.conf
copy:
src: '{{ item.src }}'
dest: '{{ item.dest }}'
mode: '{{ item.mode }}'
with_items:
- { src: 'rsyncd.conf.temp',dest: /etc/rsyncd.conf,mode: '0644' }
- { src: 'rsync.password.temp',dest: /etc/rsync.password,mode: '0600' }
notify: restart rsync
- name: create user
user:
name: rsync
shell: /sbin/nologin
create_home: no
- name: create backup directory
file:
path: '{{ item }}'
owner: rsync
group: rsync
state: directory
with_items:
- /backup
- /wuxing
- name: start rsync
service:
name: rsyncd
state: started
handlers:
- name: restart rsync
service:
name: rsyncd
state: restarted
- hosts:
- 172.16.1.31
- 172.16.1.7
tasks:
- name: create pass file
copy:
content: "123"
dest: /etc/rsync.password
mode: 0600
* * *
条件
[https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html](https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html)
**when**
tasks:
- name: "shut down CentOS 6 systems"
command: /sbin/shutdown -t now
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "6"
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result is failed
# In older versions of ansible use ``success``, now both are valid but succeeded uses the correct tense.
- command: /bin/something_else
when: result is succeeded
- command: /bin/still/something_else
when: result is skipped
布尔
vars:
epic: true
tasks:
- shell: echo "This certainly is epic!"
when: epic
tasks:
- shell: echo "This certainly isn't epic!"
when: not epic
tasks:
- shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
when: foo is defined
- fail: msg="Bailing out. this play requires 'bar'"
when: bar is undefined
cat judge.yml
---
- hosts: oldboy
remote_user: root
tasks:
- name: push file01 info
copy:
src: /oldboy/oldboy01
dest: /tmp/
when: ansible_hostname == 'web01'
cat judge.yml
---
- hosts: oldboy
remote_user: root
tasks:
- name: push file01 info
copy:
src: /oldboy/oldboy01
dest: /tmp/
when: ansible_facts.eth1.ipv4.address == '172.16.1.7'
---
- hosts: oldboy
remote_user: root
tasks:
- name: push file01 info
copy:
src: /oldboy/oldboy01
dest: /tmp/
when: ansible_facts["eth1"]["ipv4"]["address"] == '172.16.1.7'
**and**
when: (ansible_hostname == "web01") and (ansible_distribution == "CentOS")
**or**
**not**
#
循环和条件
tasks:
- command: echo {{ item }}
loop: [ 0, 2, 4, 6, 8, 10 ]
when: item > 5
循环
[https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html)
#
loop
- name: add several users
user:
name: "{{ item }}"
state: present
groups: "wheel"
loop:
- testuser1
- testuser2
loop: "{{ somelist }}"
- name: optimal yum
yum:
name: "{{list_of_packages}}"
state: present
- name: non optimal yum, not only slower but might cause issues with interdependencies
yum:
name: "{{item}}"
state: present
loop: "{{list_of_packages}}"
- name: add several users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
- name: create a tag dictionary of non-empty tags
set_fact:
tags_dict: "{{ (tags_dict|default({}))|combine({item.key: item.value}) }}"
loop: "{{ tags|dict2items }}"
vars:
tags:
Environment: dev
Application: payment
Another: "{{ doesnotexist|default() }}"
when: item.value != ""
- shell: "echo {{ item }}"
loop:
- "one"
- "two"
register: echo
##
[Loop Control](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id12)
# main.yml
- include_tasks: inner.yml
loop:
- 1
- 2
- 3
loop_control:
loop_var: outer_item
# inner.yml
- debug:
msg: "outer item={{ outer_item }} inner item={{ item }}"
loop:
- a
- b
- c
#
直到循环 until
- shell: /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10
#
[with_list](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id14)
- name: with_list
debug:
msg: "{{ item }}"
with_list:
- one
- two
- name: with_list -> loop
debug:
msg: "{{ item }}"
loop:
- one
- two
#
[with_items](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id15)
- name: with_items
debug:
msg: "{{ item }}"
with_items: "{{ items }}"
- name: with_items -> loop
debug:
msg: "{{ item }}"
loop: "{{ items|flatten(levels=1) }}"
cat with_items.yml
---
- hosts: oldboy
tasks:
- name: create user
user:
name: '{{ item.name }}'
uid: '{{ item.uid }}'
shell: '{{ item.shell }}'
with_items:
- { name: "alex01", uid: "3001", shell: "/sbin/nologin" }
- { name: "alex02", uid: "3002", shell: "/sbin/nologin" }
- { name: "alex03", uid: "3003", shell: "/sbin/nologin" }
#
[with_indexed_items](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id16)
- name: with_indexed_items
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_indexed_items: "{{ items }}"
- name: with_indexed_items -> loop
debug:
msg: "{{ index }} - {{ item }}"
loop: "{{ items|flatten(levels=1) }}"
loop_control:
index_var: index
#
[with_flattened](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id17)
- name: with_flattened
debug:
msg: "{{ item }}"
with_flattened: "{{ items }}"
- name: with_flattened -> loop
debug:
msg: "{{ item }}"
loop: "{{ items|flatten }}"
#
[with_together](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id18)
- name: with_together
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_together:
- "{{ list_one }}"
- "{{ list_two }}"
- name: with_together -> loop
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ list_one|zip(list_two)|list }}"
#
[with_dict](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id19)
- name: with_dict
debug:
msg: "{{ item.key }} - {{ item.value }}"
with_dict: "{{ dictionary }}"
- name: with_dict -> loop (option 1)
debug:
msg: "{{ item.key }} - {{ item.value }}"
loop: "{{ dictionary|dict2items }}"
- name: with_dict -> loop (option 2)
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ dictionary|dictsort }}"
#
[with_sequence](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id20)
- name: with_sequence
debug:
msg: "{{ item }}"
with_sequence: start=0 end=4 stride=2 format=testuser%02x
- name: with_sequence -> loop
debug:
msg: "{{ 'testuser%02x' | format(item) }}"
# range is exclusive of the end point
loop: "{{ range(0, 4 + 1, 2)|list }}"
#
[with_subelements](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id21)
- name: with_subelements
debug:
msg: "{{ item.0.name }} - {{ item.1 }}"
with_subelements:
- "{{ users }}"
- mysql.hosts
- name: with_subelements -> loop
debug:
msg: "{{ item.0.name }} - {{ item.1 }}"
loop: "{{ users|subelements('mysql.hosts') }}"
#
[with_nested/with_cartesian](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id22)
- name: with_nested
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_nested:
- "{{ list_one }}"
- "{{ list_two }}"
- name: with_nested -> loop
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ list_one|product(list_two)|list }}"
#
[with_random_choice](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#id23)
- name: with_random_choice
debug:
msg: "{{ item }}"
with_random_choice: "{{ my_list }}"
- name: with_random_choice -> loop (No loop is needed here)
debug:
msg: "{{ my_list|random }}"
tags: random
剧本整合
#
指令参数
##
指令参数1
- hosts:
tasks:
- include_tasks: nfs.yml
- include_tasks: rsync.yml
##
指令参数2
- import_playbook: nfs.yml
- import_playbook: rsync.yml
roles/x/tasks/main.yml
---
- include: create_dir.yml
- include: static_git_pull.yml
- include: git_checkout.yml
**roles**
[https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html)
[图片上传失败...(image-587598-1558773318884)]
**group_vars目录下的文件定义Roles中调用的变量**
**Roles对应调用该目录同名文件中定义的变量**
**文件名为all的文件定义的变量针对所有Roles生效**
##
**角色目录结构**
site.yml
webservers.yml
fooservers.yml
roles/
common/
tasks/
handlers/
files/
templates/
vars/
defaults/
meta/
webservers/
tasks/
defaults/
meta/
角色期望文件位于某些目录名称中。**角色必须至少包含其中一个目录**,但是排除任何未使用的目录是完全正确的。在使用时,**每个目录必须包含一个main.yml文件**,其中包含相关内容:
**tasks** - 包含角色要执行的主要任务列表
**handlers** - 包含处理程序,可以由此角色使用,甚至可以在此角色之外的任何位置使用
**defaults** - 角色的默认变量(有关更多信息,请参阅使用变量)
**vars** - 角色的其他变量(有关更多信息,请参阅使用变量)
**files** - 包含可以通过此角色部署的文件
**templates** - 包含可以通过此角色部署的模板
**meta** - 为此角色定义一些元数据
其他YAML文件可能包含在某些目录中。例如,通常的做法是从**tasks/main.yml**文件中包含特定于平台的任务:
# roles/example/tasks/main.yml
- name: added in 2.4, previously you used 'include'
import_tasks: redhat.yml
when: ansible_facts['os_family']|lower == 'redhat'
- import_tasks: debian.yml
when: ansible_facts['os_family']|lower == 'debian'
# roles/example/tasks/redhat.yml
- yum:
name: "httpd"
state: present
# roles/example/tasks/debian.yml
- apt:
name: "apache2"
state: present
---
- hosts: webservers
roles:
- common
- webservers
---
- hosts: webservers
roles:
- role: '/path/to/my/roles/common'
---
- hosts: 172.16.1.31
roles:
- { role: nfs }
- hosts: 172.16.1.41
roles:
- { role: rsync }
---
- hosts: webservers
roles:
- common
- role: foo_app_instance
vars:
dir: '/opt/a'
app_port: 5000
- role: foo_app_instance
vars:
dir: '/opt/b'
app_port: 5001
---
- hosts: webservers
tasks:
- include_role:
name: foo_app_instance
vars:
dir: '/opt/a'
app_port: 5000
...
---
- hosts: webservers
tasks:
- include_role:
name: some_role
when: "ansible_facts['os_family'] == 'RedHat'"
---
- hosts: webservers
roles:
- role: bar
tags: ["foo"]
# using YAML shorthand, this is equivalent to the above
- { role: foo, tags: ["bar", "baz"] }
---
- hosts: webservers
tasks:
- import_role:
name: foo
tags:
- bar
- baz
- hosts: webservers
tasks:
- include_role:
name: bar
tags:
- foo
---
- hosts: webservers
roles:
- role: foo
vars:
message: "first"
- { role: foo, vars: { message: "second" } }
角色中使用模块与插件
roles/
my_custom_modules/
library/
module1
module2
- hosts: webservers
roles:
- my_custom_modules
- some_other_role_using_my_custom_modules
- yet_another_role_using_my_custom_modules
* * *
roles/myapp/meta/main.yml
---
dependencies:
- role: common
vars:
some_parameter: 3
- role: apache
vars:
apache_port: 80
- role: postgres
vars:
dbname: blarg
other_parameter: 12
##
**配置角色**
###
**配置角色websrvs**
[root@node1 opt]# cd ansible_playbooks/roles/
[root@node1 roles]# cd websrvs/
[root@node1 websrvs]# ls
files handlers meta tasks templates vars
a. 将httpd配置文件上传到files目录下,我这里假设httpd.conf每台主机都是一样的,实际上应该用模板,先用一样的配置文件举例
[root@node1 websrvs]# cp /etc/httpd/conf/httpd.conf files/
直接复制的静态文件都放在files目录下。打算用模板文件的都放在templates目录下
b.编写任务列表tasks
[root@node1 websrvs]# vim **tasks/main.yml**
- name: install httpd package
yum: name=httpd
- name: install configuration file
copy: src=httpd.conf dest=/etc/httpd/conf
tags:
- conf
notify:
- restart httpd
- name: start httpd
service: name=httpd state=started
c.由于上面的tasks中定义了notify,所以要定义handlers
[root@node1 websrvs]# vim handlers/main.yml
- name: restart httpd
service: name=httpd state=restarted
如果需要定义变量,则在vars目录下创建main.yml文件,在文件中写入变量,以key:value的形式定义,比如:
http_port: 8080
###
**配置角色dbsrvs**
[root@node1 roles]# cd dbsrvs/
[root@node1 dbsrvs]# ls
files handlers meta tasks templates vars
a.将MySQL配置文件上传到files目录下
b.编写任务列表tasks
[root@node1 dbsrvs]# vim tasks/main.yml
- name: install mysql-server package
yum: name=mysql-server state=latest
- name: install configuration file
copy: src=my.cnf dest=/etc/my.cnf
tags:
- conf
notify:
- restart mysqld
- name:
service: name=mysqld enabled=true state=started
c.定义handlers
[root@node1 dbsrvs]# vim handlers/main.yml
- name: restart mysqld
service: name=mysqld state=restarted
###
**定义playbook**
【注意】:要在roles目录同级创建playbook
[root@node1 ansible_playbooks]# vim web.yml
- hosts: 172.16.7.152
roles:
- websrvs
[root@node1 ansible_playbooks]# vim db.yml
- hosts: 172.16.7.151
roles:
- dbsrvs
[root@node1 ansible_playbooks]# vim site.yml
- hosts: 172.16.7.153
roles:
- websrvs
- dbsrvs
###
**运行**
[root@node1 ansible_playbooks]# ansible-playbook web.yml
[root@node1 ansible_playbooks]# ansible-playbook db.yml
[root@node1 ansible_playbooks]# ansible-playbook site.yml
* * *
##
roles剧本实例
###
创建目录
[root@m01 roles]# mkdir {nfs,rsync}/{tasks,files,templates,meta,handlers,vars}
[root@m01 roles]# tree
.
├── nfs
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ ├── templates
│ └── vars
└── rsync
├── files
├── handlers
├── meta
├── tasks
├── templates
└── vars
[root@m01 roles]# pwd
/etc/ansible/roles
[root@m01 roles]# ll
total 8
drwxr-xr-x 8 root root 89 Mar 8 11:32 nfs
drwxr-xr-x 8 root root 89 Mar 8 11:32 rsync
-rw-r--r-- 1 root root 35 Mar 8 12:13 site.yml
[root@m01 roles]# tree nfs
nfs
├── files
│ └── exports
├── handlers
│ └── main.yml
├── meta
├── tasks
│ └── main.yml
├── templates
└── vars
└── main.yml
###
var
[root@m01 roles]# cat nfs/vars/main.yml
data_dir: /data
###
handler
[root@m01 roles]# cat nfs/handlers/main.yml
- name: restart nfs
service:
name: nfs
state: restarted
###
tasks
[root@m01 roles]# cat nfs/tasks/main.yml
- name: install nfs
yum:
name:
- nfs-utils
- rpcbind
state: installed
- name: push exports
copy:
src: exports
dest: /etc/exports
when: ansible_facts.eth1.ipv4.address == '172.16.1.31'
notify: restart nfs
- name: create data dir
file:
path: '{{ data_dir }}'
owner: nfsnobody
group: nfsnobody
state: directory
when: ansible_facts.eth1.ipv4.address == '172.16.1.31'
- name: start nfs
service:
name: rpcbind
name: nfs
state: started
enabled: yes
when: ansible_facts.eth1.ipv4.address == '172.16.1.31'
tags: test-nfs-start
- name: check rpc port
shell: ss -lntup |grep 111
when: ansible_facts.eth1.ipv4.address == '172.16.1.31'
register: check_port_info
- name: output check info
debug:
msg: '{{ check_port_info.stdout_lines }}'
when: ansible_facts.eth1.ipv4.address == '172.16.1.31'
tags: test_port
- name: mount
mount:
src: "172.16.1.31:/data"
path: "/mnt"
fstype: nfs
state: mounted
when: ansible_facts.eth1.ipv4.address == '172.16.1.41' or ansible_facts.eth1.ipv4.address == '172.16.1.7'
tags: mount-nfs
###
调用角色
[root@m01 roles]# cat site.yml
- hosts: oldboy
roles:
- nfs
* * *
##
Templating (Jinja2)
[https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html](https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html)
[root@m01 roles]# cat rsync/templates/rsyncd.conf.j2
uid = rsync
gid = rsync
port = {{ port }}
fake super = yes
use chroot = no
max connections = 200
timeout = 600
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
ignore errors
read only = false
list = true
hosts allow = 172.16.1.0/24
auth users = rsync_backup
secrets file = /etc/rsync.password
[backup]
path = /backup
[wuxing]
path = /wuxing
[root@m01 roles]# cat rsync/vars/main.yml
port: 874
[root@m01 roles]# cat rsync/tasks/main.yml
- name: install rsync
yum:
name: rsync
state: installed
- name: push conf
template:
src: rsyncd.conf.j2
dest: /etc/rsyncd.conf
[root@m01 roles]# cat site.yml
- hosts: oldboy
roles:
- nfs
- hosts: 172.16.1.41
roles:
- { role: rsync }
##
角色依赖
---
dependencies:
- role: common
vars:
some_parameter: 3
- role: apache
vars:
apache_port: 80
- role: postgres
vars:
dbname: blarg
other_parameter: 12