安装
centos 7.9.2009
默认安装仓库没有 Ansible 包,需要安装 epel 源
yum install -y epel-release \&& yum install -y ansible
Ubuntu 20.04.2 LTS
sudo apt updatesudo apt install -y software-properties-commonsudo apt-add-repository --yes --update ppa:ansible/ansiblesudo apt install -y ansible
Ansible 参数补全
安装软件包 python-argcomplete 或者 python3-argcomplete
sudo activate-global-python-argcomplete# python3sudo activate-global-python-argcomplete3
使用前准备
准备多台目标机器
以下脚本是示例,请修改后再执行
cat >> /etc/ansible/hosts << EOF[group1]192.168.1.100[group2]server1EOF
注意组名尽量不要用特殊字符,例如用 - 会报 warning
Not replacing invalid character(s) “{‘-‘}” in group name (cluster-1)
生成密钥对
为了实现 ssh 连接免密登录,先生成密钥对
ssh-keygen -t rsa -P '' -f "$HOME/.ssh/id_rsa"
然后通过 ssh-copy-id 将公钥分发到被控目标机器,实现免密登录
target_server_address='server1 192.168.1.100' # 这里可以写多个目标服务器target_login_user='root' # 可根据所有被控机器共有的user修改for server in $target_server_address; dossh-copy-id ${target_login_user}@${server} # 此命令需要以交互方式输入密码done
在目标机器很多的情况,手动输入多次密码很麻烦。如果条件允许,在系统中安装 sshpass 可以自动化这个操作
target_server_addresses='server1 192.168.1.100' # 这里可以写多个目标服务器,或者直接命令获取,如: $(grep -v "^#" /etc/hosts | egrep "etcd-*|k8s-*" | awk '{print $2}')target_login_user='root' # 可根据所有被控机器共有的user修改target_login_pass='*'echo $target_login_pass > ~/sshpassfor target_server_address in $target_server_addresses; doecho "upload public key to $target_server_address"grep $target_server_address ~/.ssh/known_hosts || ssh-keyscan $target_server_address >> ~/.ssh/known_hostssshpass -f ~/sshpass ssh-copy-id $target_login_user@$target_server_addressdone
开始使用
运行第一条 ansible 命令
使用第一个用到的 ansible 模块 “ping” 来运行第一条 ansible 命令
ansible all --module-name ping --user root
- —module-name 可简写成 -m
- —user 可简写成 -u
all 是一个特殊字符,会读取 /etc/ansible/hosts 里面所有的主机地址
控制目标机器执行命令
ansible all --args " w " --user root
—args 可简写成 -a
- 默认模块是 command 即
ansible -m command --args " w " --user root all模块 command 和 shell 有什么不同
ansible all -m command --args 'echo hostname: $HOSTNAME' -u root
10.197.32.151 | CHANGED | rc=0 >>hostname: $HOSTNAME10.197.32.150 | CHANGED | rc=0 >>hostname: $HOSTNAME10.197.32.139 | CHANGED | rc=0 >>hostname: $HOSTNAME10.197.32.149 | CHANGED | rc=0 >>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}}"
