Ansible快速入门

配置Inventory

Ansible把主机与主机分组信息的配置称为Inventory,默认路径为/etc/ansible/hosts

如果在ssh配置文件(~/.ssh/config)有如下配置

Host dev-server
     HostName 111.223.19.18
     Port 1212
     User someone
Host test-server
     HostName 111.223.19.10
     User someone

那么可以在ansible的hosts文件中直接使用这些主机名,例如

dev-server:1212
test-server

注意需要在这里显示地指定ssh端口。

也可以通过以下方式为主机定义别名:

host_alias ansible_ssh_host=192.168.0.73 ansible_ssh_port=2121 ansible_ssh_user=username

Ansible模块

Ansible包含了众多模块,用于完成常见的运维任务。可通过ansible-doc命令查看模块文档。

ansible-doc file

Ansible playbook

ansible playbook使用的是YAML格式

列出playerbook里的任务

ansible-playbook mezzanine.yml --list-tasks

使用标签(tags)

若想有选择地执行playbook里的部分任务应该怎么办呢?这个时候就要用到标签(tags)

  - name: build bell.api
    shell:  "{{ home }}//bin/my_program my_args"
    tags:
      - java
    args:
      executable:  /bin/bash

下面的命令执行带有javarun标签的所有任务:

ansible-playbook -i hosts  --ask-become-pass centos-web.yml  --tags "java,run"

下面的命令执行java标签外的所有任务

ansible-playbook -i hosts  --ask-become-pass centos-web.yml  --skip-tags "java"

引用变量文件

可将变量集中定义在某一文件里,通过vars_files指令引入,其后可以像使用本地变量那样使用这些变量。

vars_files:
    - secrets.yml

复杂参数

同一任务的参数较多时,可能造成难以阅读,将字符串参数转换为字典格式,以上面的检出git仓库的代码为例:

- name: checkout a git repo 
  git: 
      repo: "{{ repo_url }}" 
      dest: "{{ proj_path }}" 
      accept_hostkey: True

关闭facts采集

可在playbook中声明gather_facts: False,这样做可能是因为

  1. 运行playbook的时候,服务器可能还没有开始运行,facts采集会失败;或
  2. 关闭facts采集,减少ansible执行任务的等待时间

但需要注意,关闭facts采集后,主机信息相关的参数也变得不可用。

逐台运行,不允许失败

如果全部并行执行,负载均衡后的服务器可能在某段时间全部失败。为避免此类情况,可让任务串行执行:

serial: 1
max_fail_percentage: 0

只执行一次

让任务在多台服务器上只执行一次,也就是说对于同一个任务,在任意一台主机上执行成功后将不会在其它主机上再执行。 应用场景如数据库迁移或依赖库代码初始化

run_once: true

使用条件判断(conditionals )

conditionals文档, 比如when

修改任务状态的判断条件

这里的状态是指任务执行结束时,ansible判定的changedfailed状态。可通过changed_whenfailed_when修改自定义判断方法。

启用pipeline

需要关闭/etc/sudoers/里的requiretty

[ssh_connection]
pipelining = True

fact缓存

[defaults]
# smart - gather by default, but don't regather if already gathered
# implicit - gather by default, turn off with gather_facts: False
# explicit - do not gather by default, must say gather_facts: True
gathering = smart
fact_caching_timeout=86400
fact_caching=jsonfile
fact_caching_connection=/tmp/ansible_fact_cache

一些常见任务

ping - 测试与服务器的连接

ansible -i hosts all -m ping

上传文件

- name: copy file/directory
  synchronize:
    src: /local-path/
    dest: /remote-path/

删除远程文件

- name: delete remote file/path
  file:
    state: absent
    path: "/remote/path/"

执行远程shell命令

ansible dev-server -m shell -a "ps aux |grep java"

如果用ansible-playbook,则用如下配置

- name: restart docker
  shell: docker restart $(docker ps -aqf 'name=mydocker-image-name)

这个例子通过镜像名查找正在运行的docker容器ID,并重启这个容器。注意这里要使用shell而非command模块,因为后者会解析命令行参数,导致错误

本地命令

使用local_action模块。例如检查本地文件是否存在:

- name: Check for {{ dump_root }}
  local_action: stat path="{{ dump_root }}"
  register: stat_path_dump_root

从源码安装nginx

参考https://github.com/nickjj/ansible-nginxhttps://github.com/ANXS/nginx

定义安装软件包的任务

下面的代码片断在远程主机使用Debian 系统的apt命令安装aptitude, python3-pip等软件包。

- hosts: my_web_servers
  gather_facts: no
  become: yes
  become_method: sudo
  tasks:
  - name: install pip3
    apt:
      name: "{{pkg}}"
      state: latest
    vars:
      pkg:
        - aptitude
        - python3-pip

检出git仓库的代码

- name: checkout a git repo 
  git: repo={{ repo_url }} dest={{ proj_path }} accept_hostkey=yes

在控制主机上打开Agent Forwarding,编辑ansible配置文件,如/etc/ansible/ansible.cfg

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ForwardAgent=yes

通过pip安装python软件包

可使用requirements.txt文件安装软件包,注意调用前必须先将此文件上传到远程服务器:

- name: install python packages
  pip:
    requirements: requirements.txt
    extra_args: --user
    executable: pip3
    state: present

MySQL数据库初始化

数据库初始化包含自动创建数据库与数据库用户,对于MySQL数据库,可以参考以下文档

常见问题

sudo的问题

使用远程sudo时,

ansible all -m ping --sudo

如果没有在远程主机上配置sudo免密,则会出现错误"module_stdout": "sudo: a password is required\r\n"。这时候有两种选择,要么为远程sudo用户设置免密sudo权限,要么在执行ansible命令时输入远程sudo密码。

设置免密sudo权限

需要通过sudo visudo(或sudo visudo -f /etc/sudoers)命令编辑/etc/sudoers文件,将其中的your_username改为远程主机的用户名。

your_username ALL=(ALL) NOPASSWD:ALL

也可以对整个sudo用户组免密,例如对Centos系统,添加下面一行

%wheel  ALL=(ALL)       NOPASSWD: ALL

在执行ansible命令时输入远程sudo密码

添加-ask-sudo-pass选项,如

ansible -i hosts --sudo -ask-sudo-pass playhost -m ping

在新版ansible里,用--ask-become-pass,如

ansible-playbook -i hosts --ask-become-pass centos-web.yml

执行远程脚本错误

远程脚本如果没有开头的#!/bin/bash,使用ansible的command模块则可能报错: [Errno 8] Exec format error

sudo: sorry, you must have a tty to run sudo

编辑sudo visudo /etc/sudoers, 注释Defaults requiretty

使用synchronize模块与delegate_to同步文件时很慢

  • 首先确保两台过程主机间rsync是正常的
  • /etc/ansible/ansible.cfg中配置ssh连接选项(ssh_connection),即在默认配置上添加-o ForwardAgent=yes
  • 配置ControlPersist为保持SSH连接的时长
    [ssh_connection]
    ssh_args=-o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r -o ForwardAgent=yes
    

一个完整示例

下面的示例演示了如何在远程准备python3执行环境,上传脚本并执行的操作。

---
- hosts: example
  gather_facts: no
  become: yes
  become_method: sudo
  tasks:
  - name: install pip3
    apt:
      name: "{{pkg}}"
      state: latest
    vars:
      pkg:
        - aptitude
        - python3-pip


- name: feedly
  hosts: "example"
  gather_facts: False
  vars:
    path: /home/user/fd
    home: /home/user
    token: "my_fd_token"
  tasks:
  - name: Synchronization files
    synchronize:
      src: ./
      dest: "{{ path }}"

  - name: install python packages
    pip:
      requirements: "{{ path }}/requirements.txt"
      extra_args: --user
      executable: pip3
      state: present

  - name: run feedly
    shell:  FEEDLY_TOKEN="{{ token }}" python3 feedly_to_epub.py
    args:
      chdir: "{{ path }}"
      executable:  /bin/bash

参考

Comment