从零开始尝试Ansible实操

首先

这是拉克斯(LACS)圣诞降临日历2017中的第八天内容。
12月已经过去了一周,圣诞节确实越来越近了!
昨天我去了大阪港开港纪念活动车船编程马拉松,超级艰苦!
今天是我在Qiita的首次投稿,我负责。

今天的话题是最近在公司内各个地方经常听到的一个词叫做「Ansible」,

Ansible?是一种配置管理工具?而不是版本管理工具?

因为这种情况,所以我决定从零开始学习。

本文是针对初学者开始使用Ansible的人写的。目的是通过记录在参与Hands-On过程中获取的知识和通过各种调查获得的信息,用初学者的语言简单地总结并把握大体情况。请注意,本文的目标读者只有不了解”Ansible”的人。

Ansible是什么?

Ansible被称为一种配置管理工具,类似的工具有Puppet和Chef。
配置管理工具不同于像shell脚本那样只是自动化处理机器的角度,而是指为了将机器调整为特定状态而创建的工具。
如果单单听这样说可能还不太明白,我们可以通过将”在目标机器上添加用户”作为例子来确认区别。

从自动化处理的角度来看,执行”添加用户”操作会导致机器自动化处理。如果用户已经存在,则在重新执行时,如果没有进行任何错误处理,则会出现”用户已经存在”的错误。

相反,从将机器置于所需状态的角度来看,重要的是将其置于”用户已添加”的状态。判断”用户是否存在”由配置管理工具来处理,因此不会出错。

你明白了吗,有没有理解到区别呢?
不只是会不会出错的问题吗?不能轻视错误,是绝对不可以的。

Ansible的特点

以下是Ansible的特点:

一. 简单易用:Ansible具有直观的语法和用户友好的界面,使得操作与配置变得轻松。

二. 自动化:Ansible可以自动化各种任务和工作流程,减少人工干预并提高效率。

三. 可扩展性:Ansible支持模块化设计和插件系统,可以灵活地扩展功能。

四. 高度可定制性:Ansible提供丰富的选项和配置,使用户能够根据自身需求进行个性化定制。

五. 好的可扩展性:Ansible能够与各种云平台、操作系统和网络设备进行集成,适应不同的环境和需求。

六. 强大的协作能力:Ansible支持批量操作和并行执行,方便团队协作和管理多个主机。

七. 安全性:Ansible提供了各种安全机制和认证方式,确保系统和数据的安全性。

    • エージェントレスである

 

    • 何度同じ操作をしても同じ状態になる(冪等性)

 

    設定ファイルがシンプルに記述できる

当你实际亲自动手尝试之后,你会发现”能够简单地编写设置文件”这一部分需要一些知识,但其中所写的内容应该会让你产生”啊,原来如此”的感觉。

Ansible培训指南

我对Ansible的解释可能有点长,但正题从这里开始。
我试着实际操作了一些在“适合Ansible初学者”的介绍中提到的内容。
作为一个对配置管理没有了解的人,有些东西我可能不太明白,所以让我们先整理一下涉及的人物角色。

在Hands-On使用的软件。

VirtualBox:言わずと知れた仮想化ソフト

Vagrant:VirtualBoxなどの仮想化ソフトの操作を代行してくれます。使用方法までは割愛しますがOSインストール済みVMの作成、ネットワーク設定やSSH環境の整備までやってくれちゃいます。(素晴らしい)

Ansible:本日の主人公です。ここまで律儀に読んでくださった方、読み飛ばした方には説明不要でしょう。

这三个角色在其中扮演了重要角色。
为了进行实践,我们已经准备好了基于Vagrant+VirtualBox的虚拟机,并将使用Ansible进行试验。
这就是我们的实践流程。
我们可以通过ssh从自己的电脑连接到实践用虚拟机,并轻松地进行实践。(感到幸福)

准备用于Ansible Hands-on的虚拟机。

好的,为了进行Ansible实践,在Vagrant中准备虚拟机。利用Box和Vagrantfile创建虚拟机环境。
Box是虚拟机的基础镜像,在实践中使用的是CentOS 6.7,但也有其他各种选择。
通过以下命令准备Box。

vagrant box add centos6.7 https://github.com/CommanderK5/packer-centos-template/releases/download/0.6.7/vagrant-centos-6.7.box

现在我们来看一下 Vagrantfile 中描述另一个虚拟机配置的内容。

Vagrant.configure(2) do |config|
  config.vm.define "controller" do |node|
        node.vm.box = "centos6.7"
        node.vm.hostname = "controller"
        node.vm.network :private_network, ip: "192.168.100.10"
        node.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2210
  end
  config.vm.define "target" do |node|
        node.vm.box = "centos6.7"
        node.vm.hostname = "target"
        node.vm.network :private_network, ip: "192.168.100.20"
        node.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2220
  end
end

我能大致理解这个意思。

根据Vagrantfile的内容,我认为在实践中我们将准备一个控制器和目标环境。
我们将在控制器(管理机器)上运行Ansible来操作目标(受控机器)的状态。
然后,在与Vagrantfile相同的目录下执行vagrant up命令来构建虚拟机环境。
完成以上步骤后,我们将得到如下所示的状态。

Ansibleハンズオン図解.001.jpeg

准备Ansible

现在我们已经准备好了Hands-on的环境,让我们开始准备Ansible吧。
我们将通过SSH连接到controller来安装Ansible。

Ansible的管理机器需要满足以下要求之一:已安装Python 2(版本为2.6或2.7)或Python 3(版本为3.5以上)。因此,让我们首先确认Python的版本。

[root@controller ~]# python --version
Python 2.6.6

终于轮到Ansible出场了。
我们将使用yum命令进行安装。

[root@controller ~]# yum install ansible
  省略
[root@controller ~]# ansible --version
ansible 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.6.6 (r266:84292, Jul 23 2015, 15:22:56) [GCC 4.4.7 20120313 (Red Hat 4.4.7-11)]

成功安装了Ansible。

我们将进行使用Ansible的配置。由于在Ansible中通过SSH连接并执行管理目标机器的操作,因此为了方便起见,我们将进行配置以实现无密码登录(发送公钥)。详细信息请查看此处。

[root@controller ~]# ssh-keygen -t rsa
特に設定しないのでEnter
[root@controller ~]# ssh-copy-id root@192.168.100.20

尝试使用Ansible①

终于可以尝试使用Ansible了。
剩下的只需要编写配置文件并执行命令即可。
在Ansible中,存在两个配置文件,一个是用于编写管理目标的inventory文件,另一个是用于编写管理目标配置内容的Playbook文件。

首先从清单文件中将要管理的对象整理成列表并进行描述。

[root@controller ~]# mkdir /ansible
[root@controller ~]# cd /ansible
[root@controller ansible]# mkdir inventory
[root@controller ansible]# vi inventory/hosts
[target]
192.168.100.20

由于这次只有一个目标,所以非常简单。
这意味着192.168.100.20属于名为”target”的组。
(本来可能需要进行分组处理,听说不是很简单…)

接下来,我们将创建一个包含管理对象配置内容描述的Playbook。
可以说Playbook是Ansible的主要组成部分,毫不夸张地说。大概的!

message: "Hello Ansible !"

fruits:
  apples:
    amount: 10
  bananas:
    amount: 20
  oranges:
    amount: 30

目标.yml不是Playbook。
它是描述组变量的文件。
关于YAML格式,先不谈。(重要的是空格的数量)

- hosts: targets
  user: root
  tasks:
    - name: output message.
      debug: msg="{{ message }}"

    - name: output fruits
      debug: msg="We want {{ item.value.amount }} {{ item.key }} !" 
      with_dict: "{{ fruits }}"

这个test.yml是一个Playbook。它包含了要执行的组、执行的用户和执行的内容。
为了更直观地查看执行结果,我们将使用ansible-playbook命令进行执行。

[root@controller ansible]# ansible-playbook -i inventory/hosts test.yml
PLAY [targets] ****************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.100.20]

TASK: [output message.] *******************************************************
ok: [192.168.100.20] => {
    "msg": "Hello Ansible !"
}

TASK: [output fruits] *********************************************************
ok: [192.168.100.20] => (item={'key': 'apples', 'value': {'amount': 10}}) => {
    "item": {
        "key": "apples",
        "value": {
            "amount": 10
        }
    },
    "msg": "We want 10 apples !"
}
ok: [192.168.100.20] => (item={'key': 'oranges', 'value': {'amount': 30}}) => {
    "item": {
        "key": "oranges",
        "value": {
            "amount": 30
        }
    },
    "msg": "We want 30 oranges !"
}
ok: [192.168.100.20] => (item={'key': 'bananas', 'value': {'amount': 20}}) => {
    "item": {
        "key": "bananas",
        "value": {
            "amount": 20
        }
    },
    "msg": "We want 20 bananas !"
}

PLAY RECAP ********************************************************************
192.168.100.20             : ok=3    changed=0    unreachable=0    failed=0

哦,好像执行了一个我熟悉的东西。
我要查看执行的命令。
ansible-playbook -i inventory/hosts test.yml
指定的参数是什么。

    • inventory

 

    Playbook

这两个是的。
然而,无论怎么看,似乎使用了在targets.yml中记载的群组变量。(很奇怪)

因为在test.yml文件中指定了hosts: targets这个组作为执行目标,所以会自动从group_vars目录加载targets.yml文件,并且定义的变量会被应用。

据说这个机制是由Ansible的依赖关系驱动的,它会从指定的目录等隐式地获取信息。(理解这一点似乎很困难)

试用Ansible②

进行了上一次的执行只是输出,但接下来将使用Ansible的模块对目标进行操作。

    • パッケージのインストール > yamモジュール

 

    • ジョブの設定 > cronモジュール

 

    • ディレクトリの作成、ファイルの配置 > fileモジュール

 

    ファイルのコピー > copyモジュール

我会继续进行。

- hosts: targets
  user: root
  tasks:
  - name: install packages from yum
    yum: name={{ item }} state=latest
    with_items:
      - jq
      - ruby
      - httpd

  - name: register cron job
    cron: name="check ping" day="*/2" hour="12" minute="0" job="ping -c 3 192.168.100.10"

  - name: create directories
    file: path={{ item.path }} owner={{ item.owner }} group={{ item.group }} mode=0{{ item.mode }} state=directory
    with_items:
      - { "path":"/opt/ansible", "owner":"root", "group":"root", "mode":"755" }
      - { "path":"/opt/vagrant", "owner":"vagrant", "group":"vagrant", "mode":"755" }

  - name: copy files
    copy: src=./files/hoge dest=/opt/ansible/hoge owner=root group=root mode=0755

这份Playbook

    • jq, ruby, httpdをインストール

 

    • pingを実行するjobの設定

 

    • ansible,vagrantディレクトリの作成

 

    hogeファイルのコピー

进行。

[root@controller ansible]# ansible-playbook -i inventory/hosts main.yml

PLAY [targets] ****************************************************************************************************************************************************************************************************

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

TASK [install packages from yum] **********************************************************************************************************************************************************************************
changed: [192.168.100.20] => (item=[u'jq', u'ruby', u'httpd'])

TASK [register cron job] ******************************************************************************************************************************************************************************************
changed: [192.168.100.20]

TASK [create directories] *****************************************************************************************************************************************************************************************
changed: [192.168.100.20] => (item={u'owner': u'root', u'path': u'/opt/ansible', u'group': u'root', u'mode': u'755'})
changed: [192.168.100.20] => (item={u'owner': u'vagrant', u'path': u'/opt/vagrant', u'group': u'vagrant', u'mode': u'755'})

TASK [copy files] *************************************************************************************************************************************************************************************************
changed: [192.168.100.20]

PLAY RECAP ********************************************************************************************************************************************************************************************************
192.168.100.20             : ok=5    changed=4    unreachable=0    failed=0   

执行成功!很明显地看到了所期望的四项变更。

幂等性

如果你继续进行到这一步的实践,你将了解到Ansible的特点。

    • エージェントレスである

 

    設定ファイルがシンプルに記述できる

让我们确认一下无论进行多少次相同的操作,最终将得到相同的状态(冪等性)。再次执行相同的 main.yml 的 Playbook。

[root@controller ansible]# ansible-playbook -i inventory/hosts main.yml

PLAY [targets] ****************************************************************************************************************************************************************************************************

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

TASK [install packages from yum] **********************************************************************************************************************************************************************************
ok: [192.168.100.20] => (item=[u'jq', u'ruby', u'httpd'])

TASK [register cron job] ******************************************************************************************************************************************************************************************
ok: [192.168.100.20]

TASK [create directories] *****************************************************************************************************************************************************************************************
ok: [192.168.100.20] => (item={u'owner': u'root', u'path': u'/opt/ansible', u'group': u'root', u'mode': u'755'})
ok: [192.168.100.20] => (item={u'owner': u'vagrant', u'path': u'/opt/vagrant', u'group': u'vagrant', u'mode': u'755'})

TASK [copy files] *************************************************************************************************************************************************************************************************
ok: [192.168.100.20]

PLAY RECAP ********************************************************************************************************************************************************************************************************
192.168.100.20             : ok=5    changed=0    unreachable=0    failed=0   

得到了一个结果,称为没有任何变化。当该机器已经处于目标状态时,不会进行任何更改,多次相同的操作也会得到相同的状态。这种性质被称为幂等性。不进行包的安装,也不进行文件的复制。将跳过所有不必要的处理。

最后

这次省略了一部分实际操作的解释,但是为了抓住大致内容,敬请谅解。

這個工作坊是根據在公司內討論熱烈的工具而進行的,即使是完全沒有知識基礎的人也能輕鬆參與,我覺得我至少能理解到一定程度。(這僅僅是我的個人感想)也許這也是Ansible的特點之一吧。

我不太自然地说出这句话,但如果大家能够接触Ansible,我会感到非常高兴。

参考资料:

参考文献

    • Ansibleをはじめる人に。

https://qiita.com/t_nakayama0714/items/fe55ee56d6446f67113c

サーバ管理者も開発者も知っておきたい構成管理ツールとAnsibleの基礎知識

http://www.atmarkit.co.jp/ait/articles/1603/24/news014.html

エージェントレスでシンプルな構成管理ツール「Ansible」入門

https://knowledge.sakura.ad.jp/3124/

VagrantとDockerについて名前しか知らなかったので試した

https://qiita.com/hidekuro/items/fc12344d36d996198e96

ssh-copy-idで公開鍵を渡す

https://qiita.com/kentarosasaki/items/aa319e735a0b9660f1f0