Ansible

企业应用场景

Dev开发环境

  • 使用者:程序员

  • 功能:程序员开发软件,测试BUG的环境

  • 管理者:程序员

测试环境

  • 使用者:QA测试工程师

  • 功能:测试经过Dev环境测试通过的软件的功能

  • 管理者:运维

测试环境往往有多套,测试环境满足测试功能即可,不宜过多

  1. 测试人员希望测试环境有多套,公司的产品多产品线并发,即多个版本,意味着多个版本同步测试

  2. 通常测试环境有多少套和产品线数量保持一样

预发布环境

  • 使用者:运维

  • 功能:使用和生产环境一样的数据库,缓存服务等配置,测试是否正常

发布环境

通常是代码发布机或者堡垒机 使用者:运维 功能:发布代码至生产环境 管理者:运维(有经验) 发布机:往往需要有2台(主备)

生产环境

使用者:运维,少数情况开放权限给核心开发人员,极少数公司将权限完全 开放给开发人员并其维护 功能:对用户提供公司产品的服务

灰度环境

是生产环境的一部分 使用者:运维 功能:在全量发布代码前将代码的功能面向少量精准用户发布的环境,可基于主机或用户执行灰度发布 案例:共100台生产服务器,先发布其中的10台服务器,这10台服务器就是灰度服务器 管理者:运维

往往该版本功能变更较大,为保险起见特意先让一部分用户优化体验该功能,待这部分用户使用没有重大问题的时候,再全量发布至所有服务器

自动化运维的场景

  1. 文件传输

  2. 应用部署

  3. 配置管理

  4. 任务流编排

Ansible 特性

  1. 模块化:调用特定的模块,完成特定任务

  2. Paramiko(python对ssh的实现),PyYAML,Jinja2(模板语言)三个关键模块

  3. 支持自定义模块

  4. 基于Python语言实现

  5. 部署简单,基于python和SSH(默认已安装),agentless

  6. 安全,基于OpenSSH

  7. 支持playbook编排任务

  8. 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况

  9. 无需代理不依赖PKI(无需ssl)

  10. 可使用任何编程语言写模块

  11. YAML格式,编排任务,支持丰富的数据结构

  12. 较强大的多层解决方案

Ansible 架构以及原理

Ansible主控端作为ssh客户端连接其他机器的ssh server,然后控制其他服务器完成一些操作。

安装Ansible

rpm

yum install ansible

apt

sudo apt update
sudo apt install ansible

mac brew

brew install ansible

编译安装

yum -y install python-jinja2 PyYAML python-paramiko python-babel
python-crypto
tar xf ansible-1.5.4.tar.gz
cd ansible-1.5.4
python setup.py build
python setup.py install
mkdir /etc/ansible
cp -r examples/* /etc/ansible

Git clone 编译安装

git clone git://github.com/ansible/ansible.git --recursive
cd ./ansible
source ./hacking/env-setup

Pip安装

yum install python-pip python-devel
yum install gcc glibc-devel zibl-devel rpm-bulid openssl-devel
pip install --upgrade pip
pip install ansible --upgrade

确认安装成功

ansible --version

相关的主要配置

安装完毕,涉及的相关文件:

配置文件
    /etc/ansible/ansible.cfg  主配置文件,配置ansible工作特性(一般无需修改)
    /etc/ansible/hosts        主机清单(将被管理的主机放到此文件)
    /etc/ansible/roles/       存放角色的目录

程序
    /usr/bin/ansible          主程序,临时命令执行工具
    /usr/bin/ansible-doc      查看配置文档,模块功能查看工具
    /usr/bin/ansible-galaxy   下载/上传优秀代码或Roles模块的官网平台
    /usr/bin/ansible-playbook 定制自动化任务,编排剧本工具
    /usr/bin/ansible-pull     远程执行命令的工具
    /usr/bin/ansible-vault    文件加密工具
    /usr/bin/ansible-console  基于Console界面与用户交互的执行工具

ansible.cfg 配置文件

[defaults]
#inventory     = /etc/ansible/hosts      # 主清单配置文件的位置
#library       = /usr/share/my_modules/  # python库文件存放目录
#local_tmp     = $HOME/.ansible/tmp      # 当执行一条ansible命令,会先在本地生成python脚本,存放到这个路径下
#remote_tmp    = $HOME/.ansible/tmp      # ansible会将上面存放的临时脚本推送到远程主机的该目录下,并执行
#forks         = 5                       # 默认并发数,同时可以执行5次
#sudo_user     = root                    # 指定可使用的sudo的用户
#ask_sudo_pass = True                    # 每次执行ansible命令是否询问ssh密码
#ask_pass      = True                    # 每次执行ansible命令是否询问ssh口令
#remote_port   = 22                      # 远程主机的端口号(默认22)

#下面的配置建议打开
host_key_checking = False               # 检查对应服务器的host_key,如果在.ssh目录下没有对应的 host_key 将会弹出是否连接的确认,当机器过多的时候,该配置建议取消,否则要敲很多yes
deprecation_warnings = False            # 光比deprecation过时警告
log_path=/var/log/ansible.log           # 日志文件
module_name   = command                 # 默认模块,ansible命令在执行动作时,需要使用-m参数指定模块,这个配置默认为命令模块,可以不使用 -m command 直接使用ansible执行shell命令

主机清单 inventory.ini

  1. ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名

  2. 默认的inventory file为 /etc/ansible/hosts

  3. inventory file可以有多个,且也可以通过Dynamic Inventory来动态生成

/etc/ansible/hosts的格式:

# ip:port 远程用户名称 关闭known_host提示
[k8smaster]
10.211.55.100:22 ansible_ssh_user=root

[k8snode]
10.211.55.100 ansible_ssh_user=root
10.211.55.101 ansible_ssh_user=root
10.211.55.102 ansible_ssh_user=root

如果机器ip连续,可以使用如下方式批量加入:

[k8smaster]
10.211.55.100

[k8snode]
10.211.55.[100:102]

相关命令

ansible-doc

适用于查看ansible文档的工具。

# 列出所有的ansible模块
ansible-doc -l
# 查看模块数量,目前有3387个模块
ansible-doc -l | wc -l  
# 查询ping名称的模块
ansible-doc -l | grep ping
# 查询ping模块的详细文档
ansible-doc ping
# 查询ping模块的简略文档
ansible-doc -s ping

ansible

ansible <host-pattern> [-m module_name] [-a args]

# host-pattern 主机选择,可以选择所有或者选择某个组
# 常用的,主要的几个选项
# -m 模块名,可以使用ansible-doc -l
# -a 模块的参数,如果模块没有参数,可选
# -v 查看执行过程
# -vv 查看更详细的执行过程
# -vvv 更更详细

其它选项参数:

--version # 显示版本
--list-hosts # 显示主机清单列表
-k --ask-pass # 提示输入ssh连接密码,默认key验证
-C --check # 检查,并不执行
-T --timeout=TIMEOUT # 执行命令超时时间,默认10s
-u --user=REMOTE_USER # 执行远程执行的用户
-b --become # 代替旧版的sudo切换
--become-user=USERNAME # 指定sudo的runas用户,默认为root
-K --ask-become-pass # 提示输入sudo的口令

建议使用基于sshkey的验证

示例:

# 对主机清单中的所有主机执行ping命令
ansible all -m ping

ansible 的 hostpattern 支持多种复杂的形式:

# 匹配所有
ansible all --list

# 通配符匹配(使用通配符需要使用双引号包裹)
ansible "*" -m ping
ansible "10.211.55.*" -m ping

# 匹配master组
ansible k8smaster --list

# 属于组k8snoder的第1台机器
ansible k8snode[0]  -m  ping

# 属于组k8snode的第1到4台机器
ansible webserver[0:5]  -m  ping

# 逻辑或(master组或者node组)
ansible "k8smaster:k8snode" --list

# 逻辑与(在master组并且在node组)
ansible "k8smaster:&k8snode" --list

# 逻辑非(在k8s-node组,但是不在k8s-master组中)
ansible 'k8snode:!k8smaster' --list

# 正则,master或者node组
ansible "~(k8smaster|k8snode)" --list

ansible-galaxy

ansible galaxy 工具类似于operationhub.io或者hub.docker.com,是一个存储了很多playbook的网站,可以从galaxy中查询需要的playbook并下载使用。注意,一般我们不直接使用上面的东西,而是自己检查修改后使用。

# 列出所哟已经安装的galaxy
ansible-galaxy list
# 安装galaxy
ansible-galaxy install geerlingguy.redis
# 删除galaxy
ansible-galaxy remove geerlingguy.redis

ansible-pull

ansible默认的工作模式为push模式,也就是说不要在远程主机做任何操作只需要在控制机编排playbook,push 到远程主机即可完成任务。而另一个工作模式就是 ansible pull模式:

  1. 每台被控端需要安装Ansible 和git(svn)

  2. 所有的配置及playbooks 都存放在git 仓库

  3. 被控端的ansible-pull 计划任务会定期检查给定的git 的tag 或者分支

  4. ansible-pull 执行特定的playbooks 即local.yml 或者hostname.yml

  5. 每次更改playbooks 只需要提交到git 即可

pull模式适合:

  1. 被控节点在配置时不可用,比如自动伸缩的服务池

  2. 被控节点较多,控制机资源有限无法满足高线程和低时间的运行效率

pull模式的缺点:

  1. 要求在节点上安装ansible软件

pull模式的优点:

  1. 不需要中央管理服务器(取决于repository的类型)

  2. 分散存储库是可能的。(再次:取决于repository的类型)

  3. 连接可以由节点启动(如果不允许您更改防火墙策略,则可能很重要)

  4. 增加并行度节点可用时可以pull(在基于push的模型中,如果节点不可用,则无法对其进行配置)

  5. 非常快,因为避免了每个任务的SSH连接开销

使用ansible pull:

git clone git@xxx:root/pull-test.git
cd pull-test/
vim main.yml
git add main.yml
git commit -m "show route info"
git push -u origin master
# main.yml就是脚本

使用 ansible-pull 拉取配置并应用:

*/5 * * * * ansible-pull  -C master -d /root/test -i /opt/ansible-pull-test/hosts -U <github仓库> -e "role=db" shenchan.yml -o

ansible-playbook

用于执行编写好的playbook任务,playbook实际上就是批量脚本【重点】。

编写hello.yml playbook:

- hosts: k8smaster
  remote_user: root
  tasks:
    - name: hello world
      command: /usr/bin/wall hello world

使用ansible-playbook执行脚本:

 ~/temp ansible-playbook hello.yml

PLAY [k8smaster]  ************************************************

TASK [Gathering Facts]  ******************************************
ok: [10.211.55.100]

TASK [hello world]  **********************************************
changed: [10.211.55.100]

PLAY RECAP  ******************************************************
10.211.55.100              : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

ansible-vault

因为playbook脚本中可能存在敏感信息,就提供ansible-vault加密解密yml文件(让我想起了k8s的secret)。

ansible-vault [create|decrypt|edit|encrypt|rekey|view]

范例:

# 加密playbook,会提示输入秘钥,然后yml文件内容就会被加密
ansible-vault encrypt hello.yml
# 查看playbook,会提示输入秘钥,然后yml文件就会被临时解密输出到终端上
ansible-vault view hello.yml
# 解密playbook,会提示输入秘钥,然后yml文件就会被解密
ansible-vault decrypt hello.yml
# 创建一个新的加密的yml
ansible-vault create new.yml
# 编辑加密的playbook
ansible-vault edit new.yml
# 修改口令秘钥
ansible-vault rekey new.yml

ansible-console

ansible交互执行命令的工具,是2.0新增的功能。

可以通过该命令行进入交互命令行,并提示如下的命令行提示符:

执行用户@当前操作主机组(组中包含的主机数量)[f:并发数]$
示例:
yangsx@all (3)[f:5]$

并通过:

  • list

  • cd 主机组

  • forks 10 设置并发数

  • ? 列出所有命令

等一系列命令管理ansible。

Ansible执行过程

  1. 加载自己的配置文件,默认为/etc/ansible/ansible.cfg

  2. 加载自己的对应的模块文件,如 command

  3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输到远程服务器的对应执行用户的$HOME/.ansible/tmp/ansible-tmp-数字/xxx.py文件

  4. 给文件+x并执行

  5. 执行并返回结果

  6. 删除临时py文件,sleep 0 退出

执行状态:

  1. 绿色:执行成功并且不需要做改变的操作

  2. 黄色:执行成功并且对目标主机做变更

  3. 红色:执行失败

Ansible常用模块

Command

ansible all -m command -a '要执行的命令列表'
# 因为command是默认模块,所以-m可以省略
# -a 是ansible用于指定模块参数的选项
ansible all -a '要执行的命令列表'

# 比如,查看所有的主机的磁盘利用率
ansible all -a 'df -h'

# command在某些场景下,命令无法正确执行,比如
ansible all -a 'echo $HOSTNAME'
# 故提供Shell模块

Shell

# 打印远程主机名称
ansible all -m shell -a 'echo $HOSTNAME'

# 更改远程口令
ansible all -m shell -a 'echo root|passwd --stdin root123'

Script

用于在其他主机上运行脚本,他会先将脚本推送,再执行:

ansible all -m script -a test.sh

Copy

向其他主机发送文件:

# 向其他主机发送selinux配置,并且备份原有配置文件
# src代表当前主机的文件位置,dest代表拷贝到远程主机的文件位置,backup代表备份
ansible all -m copy -a 'src=/root/ansible/selinux dest=/etc/selinux/config backup=yes'

# 复制指定文件的权限与所属
ansible all -m copy -a 'src=/etc/shadow dest=/data/ mode=000 owner=root'

# 生成f2文件,内容手动指定
ansible all -m copy -a 'content="hell\nworld" dest=/data/a.txt'

Fetch

与copy相反,用于拉取远程主机的文件到本机,只能抓取文件,不可以抓取目录:

# 抓取被控端的日志文件到本机
ansible all -m fetch -a "path=/var/log/messages dest=/data"
# 如果要抓取多个文件,或者路径,需要先打包再抓取
ansible all -m shell -a 'tar Jcf /root/log.tar.xz /var/log/*.log'
ansible all -m fetch -a 'src=/root/log.tar.xz dest=/data/'

File

用于操作文件的模块,包含设置文件相关属性,创建目录文件链接,删除等:

# 创建文件
ansible all -m file -a 'name=/data/f3 state=touch'
# 创建文件夹
ansible all -m file -a 'name=/data/mydir state=directory'
# 删除文件、文件夹
ansible all -m file -a 'name=/data/f3 state=absent'
# 创建软链接
ansible all -m file -a 'src=/etc/fstab dest=/data/fstab.link state=link'

Hostname

主机名管理:

# 一改就统一改,永久且立即生效
ansible 192.168.30.101 -m hostname -a 'name=server1'

Cron

计划任务,支持的时间有: minute, hour, day, month, weekday

# 创建时钟同步任务 每五分钟同步一次
ansible all -m cron -a "minute=*5 job='/usr/sbin/update 172.16.0.1 &> /dev/null' name=Synctime"

# 每周一周三周五,每分钟执行FBI Warning
ansible all -m cron -a 'minute=* weekday=1,3,5 job="/usr/bin/wall FBI warning" name=Warning'
# 可以通过 crontab -e查看生成的定时任务

# 禁用定时任务(注意,job和name必须写,否则关闭的可能不是一个定时任务)
ansible all -m cron -a 'disable=true job="/usr/bin/wall FBI warning" name=Warning'

# 重新启用定时任务
ansible all -m cron -a 'disable=false job="/usr/bin/wall FBI warning" name=Warning'

# 删除定时任务
ansible all -m cron -a 'job="/usr/bin/wall FBI warning" name=Warning state=absent'

Yum

yum包管理:

# 安装httpd
ansible all -m yum -a 'name=httpd state=present'
# 安装httpd最新版
ansible all -m yum -a 'name=httpd state=lasted'
# 安装多个包
ansible all -m yum -a 'name=httpd,memcached state=lasted'
# 删除httpd
ansible all -m yum -a 'name=httpd state=absent'
# 查看已安装的包
ansible all -m yum -a 'name=httpd list=installed'

Service

管理服务。

# 启动、并开启激动 vsftpd,支持的状态还有 restarted、stopped、reloaded
ansible websrvs -m service -a 'name=vsftpd state=started enable=yes'

User

管理用户。

# 设置nginx服务账号
ansible nginxs -m user -a 'name=nginx shell=/sbin/nologin system=yes home=/var/nginx groups=root,bin uid=80 comment="Nginx Server"'
# 删除账号
ansible nginxs -m user -a 'name=nginx state=absent'

Group

管理组。

# 设置nginx组
ansible ngins -m group -a 'name=nginx system=yes gid=80'

PlayBook

剧本,由yaml编写,制定了ansible的任务。

创建playbook yaml文件:

# 一个playbook包含多个play
- hosts: all
  remote_user: root

# 一个play包含多个task,一个task对应一个action
  tasks: 
  - name: show me the name
    ansible.builtin.command: hostname
  - name: say hello
    ansible.builtin.shell:
      cmd: echo hello
  - name: other
    # action 等同于上面的写法
    action: shell echo hello2

使用ansible-playbook执行剧本:

ansible-playbook hello.yaml

Playbook是由一个或者多个play组成的列表。一个play主要将事先定义好的一组主机装扮成事先通过ansible的task定义好的角色。从根本上来说,一个task就是调用一个ansible的module,一个paly包含多个task。Playbook将多个Play组织在一起,完成一个复杂的的编排。

如果playbook中某个action返回码不为0,也就是出错状态,如果想要忽略错误继续执行action,共有两种方式:

tasks:
- name: test
  shell: /usr/bin/somecommand || /bin/true
# 短路或,如果前面失败,继续执行后面

或者(推荐):

tasks:
- name: test
  shell: /usr/bin/somecommand
  ignore_errors: True

ansible-playbook的其他属性:

  • --check 只检测可能发生的改变,但是不会真正执行

  • --lists 列出将会被应用的主机清单

  • --limit 只针对某个主机执行,比如--limit 192.168.23.13

  • -v -vvv 详细信息

Handler和Notify

Handler用于监控task中的某个action,如果达到一定的条件,将会使用Notify出发指定的Handler。

# copy action如果发现文件发生变更,将会触发重启
- hosts: all
  remote_user: root

  tasks:
  - name: install httpd package
    ansible.builtin.yum:
      name:
        - httpd
  - name: copy conf file
    ansible.builtin.copy:
      src: /data/httpd/httpd.conf
      dest: /etc/httpd/conf/
      backup: true
    notify: restart service
    tag: update

  handlers:
  - name: restart service
    service: 
      name: httpd
      state: restarted

Tags

上述yaml有一个tags标签,该tags用于标记一个动作。被标记的动作可以在命令行单独执行:

ansible-playbook xxx.yaml -t update

使用变量

变量名,只能有数字、字母、下划线组成,且必须以字母开头

变量来源有:

  1. Ansible的内置变量。(参考:https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html),比较常用的有:

    1. inventory_dir 清单文件夹位置

    2. playbook_dir 当前playbook的文件夹位置

  2. 远程主机信息,ansible setup facts,可以使用filter参数过滤变量名称查看

    # 查询所有主机的所有变量
    ansible all -m setup 
    # 查询所有主机的ip地址(支持通配符)
    ansible all -m setup -a 'filter="ansible_default_ipv4"'
  3. /etc/ansible/hosts中定义

    1. 普通变量:主机组中主机单独定义,优先级高于公共变量

      [k8smaster]
      10.211.55.100:22 ansible_ssh_user=root varname=value
    2. 公共(组)变量:针对主机组中所有主机定义统一变量

      # k8smaster的统一变量
      [k8smaster:vars]
      nodename=www
      dominname=com
  4. 通过命令行制定变量,优先级最高

    ansible-playbook -e varname=value
  5. 在playbook中定义

    vars:
    - var1: value1 
    - var2: value2
  6. 在独立的变量yaml文件中定义

    # 定义vars.yml变量文件
    var1: xxx1
    var2: xxx2
    
    # 应用变量文件,读取变量
    - hosts: web
      remote_user: root
      vars_files:
      - vars.yml
      ....
  7. 在role中定义

使用变变量:

- hosts: appsrvs
  remote_user: root

  tasks:
  - name: install package
    yum: name={{ packagename }}

Template

配置文件通常不能直接copy,因为不同主机中,某些配置可能不同,这个时候可以使用模板来解决。Ansible的模板基于python的Jinja2模版语言。

定义模板文件,需要以 .j2 作为后缀,定义nginx.conf.j2

 

最后更新于