LinuxIT必备技能

Ansible - 运维神器

2020-11-14  本文已影响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

$ sudo apt install vagrant virtualbox -y
ubuntu20.04 vagrant box
# -*- 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
$ 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免密登录

...

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. 补充说明

# 生成SSH密钥
$ ssh-keygen

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

3. Ansible Host Inventory配置

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

3.1. 静态Inventory

单个Inventory文件
[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文件
...
inventory      = /etc/ansible/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

#!/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 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

$ ansible test -m ping
$ ansible test -m debug -a "msg={{inventory_hostname}}"
$ ansible test11 -m copy -a "src=./1.log dest=~/"
$ ansible test11 -m shell -a "cat ~/1.log"
$ 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
$ ansible test11 -m shell -a "chdir=~ cat 1.log"
$ ansible test11 -m shell -a "pwd && cat 1.log"

4.2. 其他模块,举个栗子

$ ansible wave1 -m script -a "install_docker.sh" -bK
# 将文件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会调用一个模块,然后在模块中检查当前系统状态是否需要重新执行。

模块的执行状态的具体判断规则由各个模块自己决定和实现。例如,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

上一篇 下一篇

猜你喜欢

热点阅读