ansible

ansible

https://bbs.oldboyedu.com/thread-1513-1-1.html

  1. 安装配置

自动化运维工具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

  1. ansible特点

不需要单独安装客户端,基于sshd服务,sshd就相当于ansible的客户端

不需要服务端

需要依靠大量的模块实现批量管理

  1. 管理机安装

yum install epel-release -y

yum install ansible -y

  1. 客户端安装(如果selinux开启则安装)

yum install libselinux-python -y

  1. 查看

[root@m01 ~]# ansible --version

ansible 2.2.0.0

config file = /etc/ansible/ansible.cfg

configured module search path = Default w/o overrides

  1. 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

  1. 管理机配置

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

  1. 查看主机列表

ansible web --list-host

  1. 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. 普通用户批量管理

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

你可能感兴趣的:(ansible)