安装

centos 7.9.2009

默认安装仓库没有 Ansible 包,需要安装 epel 源

  1. yum install -y epel-release \
  2. && yum install -y ansible

Ubuntu 20.04.2 LTS

  1. sudo apt update
  2. sudo apt install -y software-properties-common
  3. sudo apt-add-repository --yes --update ppa:ansible/ansible
  4. sudo apt install -y ansible

Ansible 参数补全

安装软件包 python-argcomplete 或者 python3-argcomplete

  1. sudo activate-global-python-argcomplete
  2. # python3
  3. sudo activate-global-python-argcomplete3

使用前准备

准备多台目标机器

以下脚本是示例,请修改后再执行

  1. cat >> /etc/ansible/hosts << EOF
  2. [group1]
  3. 192.168.1.100
  4. [group2]
  5. server1
  6. EOF

注意组名尽量不要用特殊字符,例如用 - 会报 warning
Not replacing invalid character(s) “{‘-‘}” in group name (cluster-1)

生成密钥对

为了实现 ssh 连接免密登录,先生成密钥对

  1. ssh-keygen -t rsa -P '' -f "$HOME/.ssh/id_rsa"

然后通过 ssh-copy-id 将公钥分发到被控目标机器,实现免密登录

  1. target_server_address='server1 192.168.1.100' # 这里可以写多个目标服务器
  2. target_login_user='root' # 可根据所有被控机器共有的user修改
  3. for server in $target_server_address; do
  4. ssh-copy-id ${target_login_user}@${server} # 此命令需要以交互方式输入密码
  5. done

在目标机器很多的情况,手动输入多次密码很麻烦。如果条件允许,在系统中安装 sshpass 可以自动化这个操作

  1. target_server_addresses='server1 192.168.1.100' # 这里可以写多个目标服务器,或者直接命令获取,如: $(grep -v "^#" /etc/hosts | egrep "etcd-*|k8s-*" | awk '{print $2}')
  2. target_login_user='root' # 可根据所有被控机器共有的user修改
  3. target_login_pass='*'
  4. echo $target_login_pass > ~/sshpass
  5. for target_server_address in $target_server_addresses; do
  6. echo "upload public key to $target_server_address"
  7. grep $target_server_address ~/.ssh/known_hosts || ssh-keyscan $target_server_address >> ~/.ssh/known_hosts
  8. sshpass -f ~/sshpass ssh-copy-id $target_login_user@$target_server_address
  9. done

开始使用

运行第一条 ansible 命令

使用第一个用到的 ansible 模块 “ping” 来运行第一条 ansible 命令

  1. ansible all --module-name ping --user root
  • —module-name 可简写成 -m
  • —user 可简写成 -u
  • all 是一个特殊字符,会读取 /etc/ansible/hosts 里面所有的主机地址

    控制目标机器执行命令

    1. ansible all --args " w " --user root
  • —args 可简写成 -a

  • 默认模块是 command 即 ansible -m command --args " w " --user root all

    模块 command 和 shell 有什么不同

    1. ansible all -m command --args 'echo hostname: $HOSTNAME' -u root
    1. 10.197.32.151 | CHANGED | rc=0 >>
    2. hostname: $HOSTNAME
    3. 10.197.32.150 | CHANGED | rc=0 >>
    4. hostname: $HOSTNAME
    5. 10.197.32.139 | CHANGED | rc=0 >>
    6. hostname: $HOSTNAME
    7. 10.197.32.149 | CHANGED | rc=0 >>
    8. hostname: $HOSTNAME
ansible all -m shell --args 'echo hostname: $HOSTNAME' -u root
10.197.32.139 | CHANGED | rc=0 >>
hostname: k8s-master-lb
10.197.32.151 | CHANGED | rc=0 >>
hostname: k8s-master3
10.197.32.149 | CHANGED | rc=0 >>
hostname: k8s-master1
10.197.32.150 | CHANGED | rc=0 >>
hostname: k8s-master2
  • —args 后面跟单引号 ‘ ‘ 时,区别很明显,需要调用目标机器上的环境变量时用 shell,需要使用的是$符号本身就用 command
  • 而 —args 后用双引号 “ “ 时,需要注意的是它调用的是控制机器自身的环境变量,而两个模块的行为没有区别
  • shell 模块还支持 | 管道符 > 重定向这些符号,command 模块不支持

尝试其他 Ansible 封装的模块

command 和 shell 模块在手,基本上能做绝大部分的事情了。但 Ansible 也提供了常用的任务作为模块来使得命令看起来更结构化。当然这种好处浅显易懂,还有更多非常好的功能,比如在每台机器上执行前自动判断是否已经执行过,避免重复执行。

cron

ansible all \
    --user root \
  --module-name cron \
  --args 'name="clean up journal logs"
                  weekday=5
          hour=14
          minute=30
          job="journalctl --vacuum-time=15days"'

# 删除 cronjob
ansible all -u root -m cron -a 'name="clean up journal logs" state=absent'

yum_repository

ansible k8s_masters \
    --user root \
    --module-name yum_repository \
  --args 'name=docker-ce-stable 
                  baseurl=https://download.docker.com/linux/centos/$releasever/$basearch/stable 
          enabled=yes 
          gpgcheck=yes 
          gpgcakey=https://download.docker.com/linux/centos/gpg 
          state=present 
          file=docker-ce 
          description="Docker CE Stable - $basearch"'

# 删除 yum repo
ansible k8s_masters -u root -m yum_repository -a 'file=docker-ce name=docker-ce-stable state=absent'

Ansible Playbook

ansible 命令已经可以帮助我们同时操作多台被控机器来进行批量处理,但使用起来仍然感觉有些瑕疵:

  • 一条复杂的 ansible 命令参数太多,阅读效率低
  • 多任务则需要执行多条 ansible 命令,往往大多数需要设置的参数是重复的,即使预先写成 shell 脚本也会出现重复代码
  • 多条 ansible 没有全局统计和记录,需要人工核查或需要用户做出额外的工作

将上述 ansible 命令转化成 ansible playbook

---
- name: check target hosts alive
  hosts: all
  remote_user: root
  gather_facts: no # A boolean that controls if the play will automatically run the "setup" task to gather facts for the hosts.
  tasks:
    - name: ping target hosts
      ping:
      register: ping_res # 输出结果注册为一个 named 对象
    - name: output ping result
      debug:
        var: ping_res.ping

再试试 command 模块,多获取一些数据,最终全部打印出来

---
- name: run command
  hosts: all
  remote_user: root
  gather_facts: no
  tasks:
    - name: get hostname
      command: "hostname"
      register: hostname
    - name: get date
      command: "date '+%Y-%m-%d'"
      register: date
    - name: get time
      command: "date '+%H:%M:%S'"
      register: time
    - name: get timezone
      command: "date '+%Z'"
      register: timezone
    - name: output command result
      debug:
        msg: "{{date.stdout}} {{time.stdout}} {{timezone.stdout}} {{hostname.stdout}}"