是什么
自动化工具。用来自动化安装,部署,测试。
为什么
让人专注于做什么,而不是怎么做。(不太关心怎么连接,连接多少太机器,怎么验证)
类似的工具还有puppet。ansible 最大的优势就是不用安装客户端,只要ssh 能够连接进去,就能工作了。
安装
简单的方式
For RHEL
$ yum install ansible
For CentOS
$ yum install -y epel-release
$ yum install -y ansible
For ubuntu
# apt-get update
# apt-get install -y software-properties-common
# apt-add-repository ppa:ansible/ansible
# apt-get update
# apt-get install -y ansible
通过pip安装 [推荐]
这种方式可以获取ansible 最新的版本。
For CentOS
$ sudo yum -y install https://centos7.iuscommunity.org/ius-release.rpm
$ sudo yum -y install python36u
$ sudo python3.6 -m ensurepip
$ pip3 install ansible
For ubuntu
# apt update
# apt install python3-pip
# pip3 install ansible
配置文件
Changes can be made and used in a configuration file which will be searched for in the following order:
ANSIBLE_CONFIG
(environment variable if set)ansible.cfg
(in the current directory)~/.ansible.cfg
(in the home directory)/etc/ansible/ansible.cfg
Ansible will process the above list and use the first file found, all others are ignored.
使用(Ad-hoc)
$ ansible web –m ping
$ ansible web -b –m yum –a "name=httpd state=present"
$ ansible web -m command -a 'echo "hello world"'
使用(playbook)
Playbook (who, where, what)
File test.yml
- hosts: localhost
tasks:
- name: check login user
shell: whoami > /tmp/login_user
运行
$ ansible-playbook test.yml
变量
命令行方式
key=value format:
ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"
ansible localhost -m package -a "name=git state=present" -b -e 'ansible_python_interpreter=/usr/bin/python'
JSON string format:
ansible-playbook release.yml --extra-vars '{"version":"1.23.45","other_variable":"foo"}'
ansible-playbook arcade.yml -e '{"pacman":"mrs","ghosts":["inky","pinky","clyde","sue"]}'
YAML string format:
ansible-playbook release.yml --extra-vars '
version: "1.23.45"
other_variable: foo'
ansible-playbook arcade.yml --extra-vars '
pacman: mrs
ghosts:
- inky
- pinky
- clyde
- sue'
vars from a JSON or YAML file:
ansible-playbook release.yml --extra-vars "@some_file.json"
其它参数:
Specifying a user:
ansible-playbook playbooks/atmo_playbook.yml --user atmouser
Using a specific SSH
private key:
ansible -m ping hosts --private-key=~/.ssh/keys/id_rsa -u centos
Inventory vars
[ambari-nodes]
my-vm-hdp-1
my-vm-hdp-2
[ambari-nodes:vars]
ansible_ssh_user=dcpuser
ansible_ssh_private_key_file=group_vars/iot_rsa
Play vars
In a playbook, it’s possible to define variables directly inline like so:
- hosts: webservers
vars:
http_port: 80
Role vars
---
- hosts: webservers
roles:
- role: foo
vars:
message: "first"
- { role: foo, vars: { message: "second" } }
Jinja2
For instance, in a simple template, you can do something like:
My amp goes to {{ max_amp_value }}
This is also valid directly in playbooks, and you’ll occasionally want to do things like:
template: src=foo.cfg.j2 dest={{ remote_install_path }}/foo.cfg
注册变量
- hosts: web_servers
tasks:
- shell: /usr/bin/foo
register: foo_result
ignore_errors: True
- shell: /usr/bin/bar
when: foo_result.rc == 5
动态输入变量
- hosts: ambari-server
vars_prompt:
- name: "ambari"
prompt: "Enter password for [admin]"
confirm: yes
内置变量
Special Variable
变量名称 | 说明 | 使用 |
---|---|---|
hostvars | 包含主机得fcats信息 | {{ hostvars['db.example.com'].ansible_eth0.ipv4.address }} |
inventory_hostname | 当前主机的名称 | {{ hostvars[inventory_hostname] }} , {{ inventory_hostname }} |
group_names | 当前主机所在组的主机列表 | {% if 'webserver' in group_names %}# some part of a configuration file that only applies to webservers{% endif %} |
groups | 包含设备清单组内的所有主机 | {% for host in groups[‘db_servers’] %} {{ host }}{% endfor %} |
play_hosts | 在当前playbook中处于活动状态的主机名列表 | {{play_hosts}} |
playbook_dir | The path to the directory of the playbook that was passed to the ansible-playbook command line. |
{{ playbook_dir }} |
role_path | The path to the dir of the currently running role | {{ role_path }} |
获取主机IP
- hosts: localhost
connection: local
tasks:
- debug: var=ansible_all_ipv4_addresses
- debug: var=ansible_default_ipv4.address
- debug: var=ansible_eth0.ipv4.address
环境变量
You can use the environment
keyword at the play, block, or task level to set an environment variable for an action on a remote host.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_environment.html
- hosts: dev
tasks:
- name: Echo my_env_var
shell: "echo $MY_ENV_VARIABLE"
environment:
MY_ENV_VARIABLE: whatever_value
- name: Echo my_env_var again
shell: "echo $MY_ENV_VARIABLE"
变量优先级
官网
Ansible does apply variable precedence, and you might have a use for it. Here is the order of precedence from least to greatest (the last listed variables override all other variables):
越靠后,优先级越高
- command line values (for example,
-u my_user
, these are not variables)- role defaults (defined in role/defaults/main.yml) 1
- inventory file or script group vars 2
- inventory group_vars/all 3
- playbook group_vars/all 3
- inventory group_vars/* 3
- playbook group_vars/* 3
- inventory file or script host vars 2
- inventory host_vars/* 3
- playbook host_vars/* 3
- host facts / cached set_facts 4
- play vars
- play vars_prompt
- play vars_files
- role vars (defined in role/vars/main.yml)
- block vars (only for tasks in block)
- task vars (only for the task)
- include_vars
- set_facts / registered vars
- role (and include_role) params
- include params
- extra vars (for example,
-e "user=my_user"
)(always win precedence)
本地运行
delegate_to
- name: add back to load balancer pool
command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
local_action
- name: recursively copy files from management server to target
local_action: command rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/
connection
ansible-playbook playbook.yml --connection=local
...
- command: foo
connection: local
tags
ansible-playbook offers five tag-related command-line options:
-
--tags all
- run all tasks, ignore tags (default behavior) -
--tags [tag1, tag2]
- run only tasks with the tagstag1
andtag2
-
--skip-tags [tag3, tag4]
- run all tasks except those with the tagstag3
andtag4
-
--tags tagged
- run only tasks with at least one tag -
--tags untagged
- run only tasks with no tags
Adding tags to individual tasks
tasks:
- name: Install the servers
ansible.builtin.yum:
name:
- httpd
- memcached
state: present
tags:
- packages
- webservers
- name: Configure the service
ansible.builtin.template:
src: templates/src.j2
dest: /etc/foo.conf
tags:
- configuration
Adding tags to plays
- hosts: all
tags: ntp
tasks:
- name: Install ntp
ansible.builtin.yum:
name: ntp
state: present
Adding tags to blocks
特殊替换
想把字符串 abc
替换成 {{ abc }}
默认办法做不到,比如:
- name: change line - fail
lineinfile:
path: a.txt
regexp: 'abc'
line: '{{ abc }}'
它会认为要替换一个变量,而不是字符串。
可以使用 {% raw %} ... {% endraw %}
tags 来解决问题。
- name: change line - succeed
lineinfile:
path: a.txt
regexp: 'abc'
line: '{% raw %} {{ abc }} {% endraw %}'
Tips
Retrieve public IP
方法一
- name: Get my public IP from ipify.org
ipify_facts:
- debug: var=ipify_public_ip
方法二
use uri
module:
- name: Find my public ip
uri:
url: http://ifconfig.me/ip
return_content: yes
register: ip_response
Your IP will be in ip_response.content
refs: https://stackoverflow.com/questions/39819378/ansible-get-current-target-hosts-ip-address
跳板机设置
方法一:直接写入inventory
核心参数: ansible_ssh_common_args options
more ansible_*_args
Ansible 利用了 OpenSSH 的ProxyCommand来实现跳过Bastion(proxy/ jump)的功能。
用分组的方式
# file: tmp_hosts
[gatewayd]
hdp-slave-0
hdp-slave-1
hdp-master-0
hdp-master-1
hdp-master-2
[gatewayd:vars]
ansible_ssh_common_args=' -o ProxyCommand="ssh -W %h:%p -i /home/edaizen/.ssh/docomo-devops -o StrictHostKeyChecking=no [email protected]"'
[all:vars]
ansible_ssh_private_key_file='/home/edaizen/.ssh/docomo-hadoop'
ansible_user=centos
方法二:灵活性更强的配置方式
这是官方FAQ的例子。
定义一个组都要通过proxy 连接(相当于把上面例子中的 [gatewayd:vars] 部分单独拿出来)
# file: group_vars/gatewayed.yml
ansible_ssh_common_args: ' -o ProxyCommand="ssh -i group_vars/eea_rsa -W %h:%p -q [email protected]"'
定义这个组里有哪些机器
# file: hosts
[gatewayed]
foo ansible_host=192.168.3.5
small-test-01
方法三:在命令行中写入参数
参数:--ssh-common-args
e.g.
ansible-playbook --ssh-common-args='-o ProxyCommand="ssh -W %h:%p -q [email protected]"' site.yml
优点:不用关心配置文件关于bastion部分。
缺点:这么长的参数记不住,适合生成脚本再运行。
使用(galaxy)
通过galaxy 获取社区的ansible role,直接调用,不关心具体怎么实现的。
https://galaxy.ansible.com/
比如要对VM 加固,直接用社区的代码
$ ansible-galaxy install git+https://github.com/openstack/ansible-hardening
- extracting ansible-hardening to /home/edaizen/.ansible/roles/ansible-hardening
- ansible-hardening was installed successfully
检查自己安装了什么
$ ansible-galaxy list
# /home/edaizen/.ansible/roles
- ansible-hardening, (unknown version)
要调用这个role,跟其它playbook 一样
# test.yml
- name: Harden all systems
hosts: all
become: yes
vars:
security_enable_firewalld: no
security_rhel7_initialize_aide: no
roles:
- ansible-hardening