Ansible - 运维神器

作者: 红薯爱帅 | 来源:发表于2020-11-14 17:01 被阅读0次

1. 概述

Ansible是一个部署一群远程主机的工具。这里“远程主机(Remote Host)”是指任何可以通过SSH登录的主机,所以它既可以是远程虚拟机或物理机,也可以是本地主机。

Ansible通过SSH协议实现管理节点与远程节点之间的通信。理论上来说,只要能通过SSH登录到远程主机来完成的操作,都可以通过Ansible实现批量自动化操作,包括:复制文件、安装包、发起服务,等等。

Ansible解决了如何大批量、自动化地实现系统配置、应用部署、命令和服务操作的问题。其脚本具有灵活、可重入的特性,极大地减少了运维人员的重复劳动,提高了运维效率。

ansible工作原理

2. 准备环境

2.1. host机器安装ansible

$ sudo apt install ansible

2.2. 通过vagrant启动3个vm

  • 安装vagrant和virtualbox
$ sudo apt install vagrant virtualbox -y
ubuntu20.04 vagrant box
  • 创建localfile: ~/learn/vagrant/Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  (1..3).each do |i|
    config.vm.define "node-#{i}" do |node|
      node.vm.box = "ubuntu/2004"
      node.vm.box_url = "file:///home/shuzhang/learn/vagrant/focal-server-cloudimg-amd64-vagrant.box"
      node.vm.hostname = "node#{i}"
      node.vm.network "private_network", ip: "192.168.56.1#{i}"
      node.vm.provider "virtualbox" do |v|
        v.gui = false
        v.name = "ubuntu-#{i}"
        v.cpus = "1"
        v.memory = "2048"
      end
    end
  end
end
  • 启动vm
$ vagrant up
...

$ vagrant status
Current machine states:
node-1                    running (virtualbox)
node-2                    running (virtualbox)
node-3                    running (virtualbox)

$ vagrant ssh-config
...

2.3. 在host配置ssh免密登录

  • 追加~/.ssh/config
...

Host test11
  HostName 192.168.56.11
  User vagrant
  IdentityFile /home/shuzhang/learn/vagrant/.vagrant/machines/node-1/virtualbox/private_key

Host test12
  HostName 192.168.56.12
  User vagrant
  IdentityFile /home/shuzhang/learn/vagrant/.vagrant/machines/node-2/virtualbox/private_key

Host test13
  HostName 192.168.56.13
  User vagrant
  IdentityFile /home/shuzhang/learn/vagrant/.vagrant/machines/node-3/virtualbox/private_key
  • 测试一下下
$ ssh test11
$ ssh test12
$ ssh test13

2.4. 补充说明

  • 手动创建key文件,并配置ssh免密
# 生成SSH密钥
$ ssh-keygen

# 复制SSH密钥到远程主机,这样SSH的时候就不需要输入密码了
$ ssh-copy-id remoteuser@remoteserver

3. Ansible Host Inventory配置

Host Inventory是ansible远程主机列表,分静态Inventory动态Inventory,支持主机组以及主机组嵌套、主机变量、组变量、多个inventory文件等。

3.1. 静态Inventory

单个Inventory文件
  • 默认的inventory文件:/etc/ansible/hosts
[test]
test11
test12
test13
test14 ansible_host=127.0.0.1 ansible_port=2200 ansible_user=vagrant ansible_ssh_private_key_file=/home/shuzhang/learn/vagrant/.vagrant/machines/node-2/virtualbox/private_key
# 也可以配置明文的password(这里不行,因为vagrant vm只支持pem文件登录)
test15 ansible_host=127.0.0.1 ansible_port=2200 ansible_user=vagrant ansible_ssh_pass=vagrant
image.png
多个Inventory文件
  • 创建文件夹/etc/ansible/inventory,修改/etc/ansible/ansible.cfg
...
inventory      = /etc/ansible/inventory
...
  • 创建test文件,存储test主机,维护两个Inventory文件
$ tree /etc/ansible/
/etc/ansible/
├── ansible.cfg
└── inventory
    ├── hosts
    └── test

1 directory, 3 files

参考:http://www.ansible.com.cn/docs/intro_inventory.html

测试
$ ansible test14 -m ping
test14 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

3.2. 动态Inventory

  • 创建Py文件/etc/ansible/inventory/group1.py,并给予可执行权限
#!/usr/bin/env python

import argparse
import sys
import json


def lists():
    inventory = dict(
        group1=dict(
            hosts=['192.168.56.1' + str(i) for i in range(1,4)],
            vars=dict(
                ansible_user="vagrant",
                example_variable="value"
            )
        )
    )
    return json.dumps(inventory, indent=4)

def hosts(name):
    host_config = {
        '192.168.56.11': dict(
            ansible_ssh_private_key_file='/home/shuzhang/learn/vagrant/.vagrant/machines/node-1/virtualbox/private_key'
        ),
        '192.168.56.12': dict(
            ansible_ssh_private_key_file='/home/shuzhang/learn/vagrant/.vagrant/machines/node-2/virtualbox/private_key'
        ),
        '192.168.56.13': dict(
            ansible_ssh_private_key_file='/home/shuzhang/learn/vagrant/.vagrant/machines/node-3/virtualbox/private_key'
        )
    }
    return json.dumps(host_config.get(name, {}))


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-l', '--list', help='hosts list', action='store_true')
    parser.add_argument('-H', '--host', help='hosts vars')
    
    args = parser.parse_args()
    if args.list:
        print(lists())
    elif args.host:
        print(hosts(args.host))
    else:
        parser.print_help()
  • 测试一下,ansible是否可以解析
$ ansible group1 --list-host
  hosts (3):
    192.168.56.11
    192.168.56.12
    192.168.56.13
$ ansible group1 -m ping -o
192.168.56.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"}
192.168.56.12 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"}
192.168.56.13 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"}

4. Ansible Ad-hoc

ansible临时命令,使用起来很方便,可用于测试,或者简单的临时性质的任务

ansible <host-pattern> [options]

4.1. 常用modules

  • ① 调试和测试类的模块。
    ping:ping一下你的远程主机,如果可以通过Ansible连接成功,那么返回pong。
    debug:用于调试的模块,只是简单打印一些消息,有点像Linux的echo命令。
$ ansible test -m ping
$ ansible test -m debug -a "msg={{inventory_hostname}}"
  • ② 文件类的模块。
    copy:从本地复制文件到远程节点。
    template:从本地复制文件到远程节点,并进行变量的替换。
    file:设置文件属性。
$ ansible test11 -m copy -a "src=./1.log dest=~/"
$ ansible test11 -m shell -a "cat ~/1.log"
  • ③ Linux上的常用操作。
    user:管理用户账户。
    yum:Red Hat系Linux上的包管理。
    service:管理服务。
    firewalld:管理防火墙中的服务和端口。
$ ansible test11 -m user -a "name=user1 groups=sudo shell=/bin/bash" -b
$ ansible test11 -m user -a "name=user1 state=absent remove=yes" -b
  • ④ 执行shell命令。
    shell:在节点上执行shell命令,支持$HOME、“<”、“>”、“|”、“;”和“&”
    command:在远程节点上面执行命令,不支持$HOME、“<”、“>”、“|”、“;”和“&”
$ ansible test11 -m shell -a "chdir=~ cat 1.log"
$ ansible test11 -m shell -a "pwd && cat 1.log"

4.2. 其他模块,举个栗子

  • script
$ ansible wave1 -m script -a "install_docker.sh" -bK
  • synchronize
# 将文件redis_5.0.tar同步到/u/devops下,并更名为redis.tar(如果没有redis.tar,则不rename)
ansible wave1 -m synchronize -a "src=./redis_5.0.tar dest=/u/devops/redis.tar"
ansible wave1 -m synchronize -a "src=./xxxx.release.1.4.0.tar.gz dest=/u/devops/"

# 将文件夹data同步到/u/devops/下,同步后的目录结构是/u/devops/data
ansible wave1 -m synchronize -a "src=./data/ dest=/u/devops/"

5. Ansible Playbook

Playbooks 是 Ansible的配置、部署、编排语言,它可以描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合。

任务中每个Action会调用一个模块,然后在模块中检查当前系统状态是否需要重新执行。

  • 如果本次执行了,那么Action会得到返回值changed
  • 如果不需要执行,那么Action会得到返回值ok

模块的执行状态的具体判断规则由各个模块自己决定和实现。例如,copy模块的判断方法是比较文件的checksum,代码如下。

checksum_src = module.sha1(src)
...
checksum_dest = module.sha1(dest)
...
if checksum_src != checksum_dest or os.path.islink(b_dest):
    ...
    changed = True
else:
    changed = False

5.1. 创建用户,并设置免密登录、免密sudo权限

# ansible-playbook add_user.yml -e "remotehost=dev1"
# ansible wave1 -m authorized_key -a "user=testuser1 key=\"{{lookup('file','./id_rsa.ssh.pub') }}\""

- hosts: "{{ remotehost }}"
  become: yes
  gather_facts: False
  vars:
    users:
      - "user1"
      - "user2"
  tasks:
    - name: "Create user accounts"
      user:
        name: "{{ item }}"
        groups: "sudo,docker"
      with_items: "{{ users }}"
    - name: "Create .ssh folder"
      file: path="/home/{{ item }}/.ssh" state=directory owner="{{ item }}" mode=0700
      with_items: "{{ users }}"
    - name: "Add authorized keys"
      authorized_key:
        user: "{{ item }}"
        key: "{{ lookup('file', '~/.ssh/id_rsa.ssh.pub') }}"
      with_items: "{{ users }}"
    - name: "Add sudo without password permission"
      copy:
        content: '{{ item }} ALL=(ALL:ALL) NOPASSWD:ALL'
        dest: "/etc/sudoers.d/{{ item }}_nopasswd"
        mode: 0440
      with_items: "{{ users }}"

5.2. mongodb操作

# ansible-playbook mongo_ops.yml -e "remotehost=dev1" > 1030.log
# cat 1030.log | grep "transaction count"

- hosts: "{{ remotehost }}"
  gather_facts: no
  tasks:
    - name: Copy js file
      become: yes
      copy:
        content: |
          db.transaction.find({
            created_at: {"$gte": ISODate("2020-10-21T16:00:00.000Z"), "$lte": ISODate("2020-10-29T16:00:00.000Z")}
          }).count()
        dest: "/u/mongo/tmp_mongo_ops.js"
        mode: 660
    - name: Count transactions
      register: ps
      shell: |
        docker ps --format {% raw %}{{.Names}}{% endraw %} | grep mongo | grep -v test | \
            xargs -I {} docker exec -t {} \
            bash -c "mongo mongodb://user:passwd@127.0.0.1:27017/testdb?authSource=admin < /data/db/tmp_mongo_ops.js"
    - debug: msg="transaction count - {{inventory_hostname}} - {{ps.stdout_lines[-2]}}"
  post_tasks:
    - name: Clean tmp files
      become: yes
      shell: rm /u/mongo/tmp_mongo_ops.js

# escaping-double-curly-braces-in-ansible
# https://stackoverflow.com/questions/32279519/escaping-double-curly-braces-in-ansible

5.3. More best practice

http://www.ansible.com.cn/docs/playbooks_best_practices.html

6. 尾声

Ansible入门简单,也非常实用,真乃运维神器。但是,时间有限,有些高级玩法还没深入研究,以后有机会再学习。
一些资料:
http://www.ansible.com.cn/index.html
https://github.com/ansible/ansible
https://github.com/ansible/ansible-examples
https://github.com/ansible/ansible-modules-core

相关文章

  • CentOS7 Ansible自动化运维

    企业级自动化运维神器Ansible 一、介绍 1.自动化运维工具对比 2.ansible简介 ansible是新出...

  • Ansible - 运维神器

    1. 概述 Ansible是一个部署一群远程主机的工具。这里“远程主机(Remote Host)”是指任何可以通过...

  • Ansible运维神器详解

    如果做过运维或者网站开发的朋友,一定接触过服务部署,那么一般的服务部署流程是什么呢?找一台Linux机器,安装好运...

  • Asible了解,配置,部署

    一、ansible 简介 1、ansible 是什么?ansible是目前最受运维欢迎的自动化运维工具,基于Pyt...

  • ansible 自动化运维工具

    什么是ansible ansible是目前最受运维欢迎的自动化运维工具,基于Python开发,集合了众多运维工具(...

  • 干货:一文详解 Ansible 的自动化运维

    一、Ansible 概述 Ansible 是近年来越来越火的一款开源运维自动化工具,通过Ansible可以实现运维...

  • 06Ansible服务

    第一章 Ansible介绍 0.手工运维与自动化运维 1.手动运维时代 2.自动化运维 1.什么是Ansible ...

  • Ansible学习——基本概念 day1

    基础概念 1.ansible是什么?ansible是目前最受运维欢迎的自动化运维工具,基于Python开发,集合了...

  • ansible

    参考 ansible 官方手册 Linux轻量级自动运维工具-Ansible浅析 Ansible中文权威指南 An...

  • Ansible

    运维工作 Ansible Architecture 架构简单 架构扩展

网友评论

    本文标题:Ansible - 运维神器

    本文链接:https://www.haomeiwen.com/subject/vsrryktx.html