Skip to content

Instantly share code, notes, and snippets.

@humiaozuzu
Last active May 29, 2019 05:13
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save humiaozuzu/a40dbbd857c281d47abb9ca23b689150 to your computer and use it in GitHub Desktop.
Save humiaozuzu/a40dbbd857c281d47abb9ca23b689150 to your computer and use it in GitHub Desktop.
Ansible best practice

Ansible best practice

通用规则

  • YAML 使用 2 空格+.yml后缀
  • Jinja 变量前后需要使用空格 {{ var }}
  • YAML 中引用变量时需要用双引号
  • 环境变量全大写,其他变量全小写
  • 所有变量前需要加上 role name 作为前缀,比如 nginx_xxx
  • role 命名使用短横线
  • 一个 role 只干一件事,从他的命名需要能看出
  • 尽量不要使用 tags,尽量将 role 拆分成小的粒度来避免这个需求
  • 大部分情况下的 role 都需要 root access,所以不要在 task 中单独设定权限

项目结构

inventory/
   prod/
      hosts
      group_vars/
         all
         database
   stag/
      hosts               # inventory file for staging environment
      group_vars/
         all
plays/
   init_connection.yml
   setup.yml
   apps/
      install-mongodb.yml
      install-redis.yml 
   etu/
      install-etuapp.yml
roles/
    mongodb/
    mysql/

项目默认使用上面的目录结构

  • inventory 下单独的目录各自有自己的 hosts 和 group_vars,一般用于有多个环境(production/staging)或者多数据中心的部署形式
  • plays 里面放置执行的 playbook 任务,最外层放置通用的 playbook,其他的按照类型来拆分文件夹,比如软件安装类,比如针对某一类业务的定制化软件配置

常见的 pattern

基础的 playbook

- name: My playbook do sth
  hosts: es-node
  become: true

  roles:
    - elasticsearch
    - git
    - mysql

变量尽量使用非 dict 形式(扁平)的

ruby:
  version: 2.1
  experimental: false

# better
ruby_version: 2.1
ruby_experimental: false

yaml 单行内容较多需要分行时的写法

# 对于自带 module 里面的任务,k=v 少于三对的,写在一行
- name: install nginx
  yum: pkg=nginx state=installed

# 对于自带 module 里面的任务,k=v 较多的,使用 dict 的方式书写
- name: copy Phergie shell script into place.
  template:
    src: "templates/phergie.sh.j2"
    dest: "/home/{{ phergie_user }}/phergie.sh"
    owner: "{{ phergie_user }}"
    group: "{{ phergie_user }}"
    mode: 0755

# 对于单行内容较多需要分行的,使用 >,常用于 shell 和复杂的 when 条件后
- name: install Drupal.
  command: >
    drush si -y
    --site-name="{{ drupal_site_name }}"
    --account-name=admin
    --account-pass={{ drupal_admin_pass }}
    --db-url=mysql://root@localhost/{{ domain }}
    chdir={{ drupal_core_path }}
    creates={{ drupal_core_path }}/sites/default/settings.php

显式指定状态,权限,不要使用默认值

- name: make sure ntpd is running and enabled
  service: name=ntpd state=started enabled=yes

- name: configure dnsmasq
  template:
    src: dnsmasq.conf.j2
    dest: /etc/dnsmasq.conf
    group: root
    owner: root
    mode: 0644
  notify:
    - restart dnsmasq

使用 handlers 时,尽量配合 flush_handlers,因为 handler 是在 task 最后执行,如果 task 进行到一半失败时,下次运行会丢失了上次的 changed 状态,如果放在 notify 后运行可以避免大部分这样的情况(依然不能完全避免)

- name: configure vnstat
  template:
    src: vnstat.conf.j2
    dest: /etc/vnstat.conf
    group: root
    owner: root
    mode: 0644
  notify:
    - restart vnstat

- meta: flush_handlers

添加配置文件时一定要使用 validate 功能,但是 validate 的功能非常有限,只能对程序的主配置进行 validate

- name: set up sudoer
  lineinfile:
    dest: /etc/sudoers
    regexp: '^%sudo'
    line: '%sudo ALL=(ALL) NOPASSWD: ALL'
    state: present
    validate: '/usr/sbin/visudo -cf %s'

一些 tricky 的方法验证更多的文件

安装软件时的说明

  • 安装 ppa 的软件需要 update_cache
  • 不要使用 pkg state=latest 和 git update=yes,present 即可
  • 对于重要的维护的软件,需要显式的指定安装的版本号(redis/mysql/es/docker)

文件权限如果使用八进制,需要0开头,如 0755 0644

shell 命令的处理方法 shell 命令行执行后需要通过检查他输出的结果来手动判断 failed_when 和 changed_when 应该给什么状态

- name: ensure postgresql hstore extension is created
  sudo: yes
  sudo_user: postgres
  shell: "psql my_database -c 'CREATE EXTENSION hstore;'"
  register: psql_result
  failed_when: >
    psql_result.rc != 0 and ("already exists" not in psql_result.stderr)
  changed_when: "psql_result.rc == 0"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment