ライン

ポイント:*

ライン

 はじめに

 MacBook Airでお試しを開始するところだったのですが、コマンドのコピペが面倒になりそうなので、手元にあるRaspBSDに入れて試す方を先にすることにしました。MacBookにSSHするでも良かったのですが…。。

 インストール

sysutils/ansible

 pkgでインストールを完了させます。

#pkg install ansible
Updating FreeBSD repository catalogue...
FreeBSD repository is up-to-date.
All repositories are up-to-date.
The following 17 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        ansible: 1.9.4
        python27: 2.7.10_1
        libffi: 3.2.1
        indexinfo: 0.2.4
        readline: 6.3.8
        gettext-runtime: 0.19.6
        py27-setuptools27: 17.0
        py27-yaml: 3.11
        python2: 2_3
        py27-pycrypto: 2.6.1_1
        gmp: 5.1.3_2
        py27-Jinja2: 2.8
        py27-Babel: 2.0
        py27-pytz: 2015.7,1
        py27-MarkupSafe: 0.23
        py27-paramiko: 1.15.2
        py27-ecdsa: 0.11_1

The process will require 98 MiB more space.
15 MiB to be downloaded.

Proceed with this action? [y/N]: y

 RaspBerry Piのパワーが無いので、そこそこ終わるまでに時間がかかっている感じ。
でも、別ターミナルで見た感じではスカスカに見えるので、SDカードがボトルネックなのかも知れない。
Extractingがかかっているだけみたいだし。書いているうちに最後のAnsible 1.9.4の解凍やっているタイミングになりました。
(と書いているうちに終わると思ったら、92%で止まっている)

終わりました。

===========================================================================
Message from ansible-1.9.4:
===============================================================================

To use Ansible, you need at least a host database.
If you installed examples, you will have a sample
host database and a sample configuration file:

  /usr/local/share/examples/ansible/hosts
  /usr/local/share/examples/ansible/ansible.cfg

To use Ansible to control FreeBSD hosts, you need to
install the lang/python package on remote machines.

To use Ansible to control systems other than FreeBSD,
set the Python interpreter in the host database for
that system. Example:

  [freebsd]
  host1
  host2

  [centos]
  host3
  host4

  [centos:vars]
  ansible_python_interpreter=/usr/bin/python

If you have Python 3.x as the default, please set
ansible_python_interpreter=/usr/local/bin/python2

===============================================================================

確かに、2ファイルはあるな。
設定ファイルの作成位置は、/usr/local/etc/ansibleらしいので、ここにサンプルな名前で置いてくれた方が親切なのにな。

ちなみにinventoryファイルのサンプル(hosts)にはこんなになっています。

# This is the default ansible 'hosts' file.
#
# It should live in /usr/local/etc/ansible/hosts
#
#   - Comments begin with the '#' character
#   - Blank lines are ignored
#   - Groups of hosts are delimited by [header] elements
#   - You can enter hostnames or ip addresses
#   - A hostname/ip can be a member of multiple groups

# Ex 1: Ungrouped hosts, specify before any group headers.

green.example.com
blue.example.com
192.168.100.1
192.168.100.10

# Ex 2: A collection of hosts belonging to the 'webservers' group

[webservers]
alpha.example.org
beta.example.org
192.168.1.100
192.168.1.110

# If you have multiple hosts following a pattern you can specify
# them like this:

www[001:006].example.com

# Ex 3: A collection of database servers in the 'dbservers' group

[dbservers]

db01.intranet.mydomain.net
db02.intranet.mydomain.net
10.25.1.56
10.25.1.57

# Here's another example of host ranges, this time there are no
# leading 0s:

db-[99:101]-node.example.com

とりあえず、準備を開始します。

# mkdir /usr/local/etc/ansible
# cp /usr/local/share/examples/ansible/hosts /usr/local/etc/ansible
# cp /usr/local/share/examples/ansible/ansible.cfg  /usr/local/etc/ansible

では、サンプルのhostsを変更していきます。

webservice.example.jp ansible_ssh_user=fkimura

とかにしました。該当マシンはCentOSの6系が動いています。

次は、ansible.cfgを見ておきます。

# config file for ansible -- http://ansible.com/
# ==============================================

# nearly all parameters can be overridden in ansible-playbook
# or with command line flags. ansible will read ANSIBLE_CONFIG,
# ansible.cfg in the current working directory, .ansible.cfg in
# the home directory or /usr/local/etc/ansible/ansible.cfg, whichever it
# finds first

[defaults]

# some basic default values...

inventory      = /usr/local/etc/ansible/hosts
#library        = /usr/share/my_modules/
remote_tmp     = $HOME/.ansible/tmp
pattern        = *
forks          = 5
poll_interval  = 15
sudo_user      = root
#ask_sudo_pass = True
#ask_pass      = True
transport      = smart
#remote_port    = 22
module_lang    = C

# plays will gather facts by default, which contain information about
# the remote system.
#
# smart - gather by default, but don't regather if already gathered
# implicit - gather by default, turn off with gather_facts: False
# explicit - do not gather by default, must say gather_facts: True
gathering = implicit

# additional paths to search for roles in, colon separated
#roles_path    = /usr/local/etc/ansible/roles

# uncomment this to disable SSH key host checking
#host_key_checking = False

# change this for alternative sudo implementations
sudo_exe = sudo

# what flags to pass to sudo
#sudo_flags = -H

# SSH timeout
timeout = 10

# default user to use for playbooks if user is not specified
# (/usr/bin/ansible will use current user as default)
#remote_user = root

# logging is off by default unless this path is defined
# if so defined, consider logrotate
#log_path = /var/log/ansible.log

# default module name for /usr/bin/ansible
#module_name = command

# use this shell for commands executed under sudo
# you may need to change this to bin/bash in rare instances
# if sudo is constrained
#executable = /bin/sh

# if inventory variables overlap, does the higher precedence one win
# or are hash values merged together?  The default is 'replace' but
# this can also be set to 'merge'.
#hash_behaviour = replace

# list any Jinja2 extensions to enable here:
#jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n

# if set, always use this private key file for authentication, same as
# if passing --private-key to ansible or ansible-playbook
#private_key_file = /path/to/file

# format of string {{ ansible_managed }} available within Jinja2
# templates indicates to users editing templates files will be replaced.
# replacing {file}, {host} and {uid} and strftime codes with proper values.
ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}

# by default, ansible-playbook will display "Skipping [host]" if it determines a task
# should not be run on a host.  Set this to "False" if you don't want to see these "Skipping"
# messages. NOTE: the task header will still be shown regardless of whether or not the
# task is skipped.
#display_skipped_hosts = True

# by default (as of 1.3), Ansible will raise errors when attempting to dereference
# Jinja2 variables that are not set in templates or action lines. Uncomment this line
# to revert the behavior to pre-1.3.
#error_on_undefined_vars = False

# by default (as of 1.6), Ansible may display warnings based on the configuration of the
# system running ansible itself. This may include warnings about 3rd party packages or
# other conditions that should be resolved if possible.
# to disable these warnings, set the following value to False:
#system_warnings = True

# by default (as of 1.4), Ansible may display deprecation warnings for language
# features that should no longer be used and will be removed in future versions.
# to disable these warnings, set the following value to False:
#deprecation_warnings = True

# (as of 1.8), Ansible can optionally warn when usage of the shell and
# command module appear to be simplified by using a default Ansible module
# instead.  These warnings can be silenced by adjusting the following
# setting or adding warn=yes or warn=no to the end of the command line
# parameter string.  This will for example suggest using the git module
# instead of shelling out to the git command.
# command_warnings = False


# set plugin path directories here, separate with colons
action_plugins     = /usr/share/ansible_plugins/action_plugins
callback_plugins   = /usr/share/ansible_plugins/callback_plugins
connection_plugins = /usr/share/ansible_plugins/connection_plugins
lookup_plugins     = /usr/share/ansible_plugins/lookup_plugins
vars_plugins       = /usr/share/ansible_plugins/vars_plugins
filter_plugins     = /usr/share/ansible_plugins/filter_plugins

# by default callbacks are not loaded for /bin/ansible, enable this if you
# want, for example, a notification or logging callback to also apply to
# /bin/ansible runs
#bin_ansible_callbacks = False


# don't like cows?  that's unfortunate.
# set to 1 if you don't want cowsay support or export ANSIBLE_NOCOWS=1
#nocows = 1

# don't like colors either?
# set to 1 if you don't want colors, or export ANSIBLE_NOCOLOR=1
#nocolor = 1

# the CA certificate path used for validating SSL certs. This path
# should exist on the controlling node, not the target nodes
# common locations:
# RHEL/CentOS: /etc/pki/tls/certs/ca-bundle.crt
# Fedora     : /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
# Ubuntu     : /usr/share/ca-certificates/cacert.org/cacert.org.crt
#ca_file_path =

# the http user-agent string to use when fetching urls. Some web server
# operators block the default urllib user agent as it is frequently used
# by malicious attacks/scripts, so we set it to something unique to
# avoid issues.
#http_user_agent = ansible-agent

# if set to a persistent type (not 'memory', for example 'redis') fact values
# from previous runs in Ansible will be stored.  This may be useful when
# wanting to use, for example, IP information from one group of servers
# without having to talk to them in the same playbook run to get their
# current IP information.
fact_caching = memory


# retry files
#retry_files_enabled = False
#retry_files_save_path = ~/.ansible-retry

[privilege_escalation]
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False

[paramiko_connection]

# uncomment this line to cause the paramiko connection plugin to not record new host
# keys encountered.  Increases performance on new host additions.  Setting works independently of the
# host key checking setting above.
#record_host_keys=False

# by default, Ansible requests a pseudo-terminal for commands executed under sudo. Uncomment this
# line to disable this behaviour.
#pty=False

[ssh_connection]

# ssh arguments to use
# Leaving off ControlPersist will result in poor performance, so use
# paramiko on older platforms rather than removing it
#ssh_args = -o ControlMaster=auto -o ControlPersist=60s

# The path to use for the ControlPath sockets. This defaults to
# "%(directory)s/ansible-ssh-%%h-%%p-%%r", however on some systems with
# very long hostnames or very long path names (caused by long user names or
# deeply nested home directories) this can exceed the character limit on
# file socket names (108 characters for most platforms). In that case, you
# may wish to shorten the string below.
#
# Example:
# control_path = %(directory)s/%%h-%%r
#control_path = %(directory)s/ansible-ssh-%%h-%%p-%%r

# Enabling pipelining reduces the number of SSH operations required to
# execute a module on the remote server. This can result in a significant
# performance improvement when enabled, however when using "sudo:" you must
# first disable 'requiretty' in /etc/sudoers
#
# By default, this option is disabled to preserve compatibility with
# sudoers configurations that have requiretty (the default on many distros).
#
#pipelining = False

# if True, make ansible use scp if the connection type is ssh
# (default is sftp)
#scp_if_ssh = True

[accelerate]
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0

# The daemon timeout is measured in minutes. This time is measured
# from the last activity to the accelerate daemon.
accelerate_daemon_timeout = 30

# If set to yes, accelerate_multi_key will allow multiple
# private keys to be uploaded to it, though each user must
# have access to the system via SSH to add a new key. The default
# is "no".
#accelerate_multi_key = yes

[selinux]
# file systems that require special treatment when dealing with security context
# the default behaviour that copies the existing context or uses the user default
# needs to be changed to use the file system dependant context.
#special_context_filesystems=nfs,vboxsf,fuse

これはそのままで良さそうです。

 設定

 ssh用の鍵を準備して、相手側に置いてきます。鍵の種類は趣味ですのでお好きにどうぞ。

% ssh-keygen -t rsa
% ll
total 12
-rw-------  1 fkimura  fkimura  1675 Nov 22 08:09 id_rsa
-rw-r--r--  1 fkimura  fkimura   394 Nov 22 08:09 id_rsa.pub
-rw-r--r--  1 fkimura  fkimura   176 Nov 22 08:05 known_hosts

id_rsa.pubの中身を、接続する先の.ssh/authorized_keys に追加してあげます。これでパスワードなしでの接続ができるようになりました。
試しに接続してみます。

% ansible webservice.example.jp -m ping
webservice.example.jp | FAILED >> {
    "failed": true,
    "msg": "/bin/sh: /usr/local/bin/python: そのようなファイルやディレクトリはありません\r\nOpenSSH_6.6.1p1, 
OpenSSL 1.0.1p-freebsd 9 Jul 2015\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: 
auto-mux: Trying existing master\r\ndebug1: mux_client_request_session:
 master session id: 2\r\nShared connection to webservice.example.jp closed.\r\n",
    "parsed": false
}

そうでした。向こう側は、CentOSなので、パス位置が違うのでした。
inventoryファイルのhostsを変更しました。

[centos]
webservice.example.jp ansible_ssh_user=fkimura

[centos:vars]
  ansible_python_interpreter=/usr/bin/python

では、実施してみます。

% ansible webservice.example.jp -m ping
webservice.example.jp | success >> {
    "changed": false,
    "ping": "pong"
}

やっと、動作できたことを確認することができました。

次は、sudoで作業できることを確認です。接続先に以下のようなパーミッションのファイルを準備します。

# ll  /tmp/test
-r-------- 1 root root 205  3月 24 22:40 2015 /tmp/test

では、権限がない状態のままで実施してみます。

% ansible webservice.example.jp -m file -a "dest=/tmp/test mode=604"
webservice.example.jp | FAILED >> {
    "failed": true,
    "msg": "Traceback (most recent call last):\r\n
  File \"/home/fkimura/.ansible/tmp/ansible-tmp-1448150376.3-46681347958483/file\", line 2012, in <module>\r\n
    main()\r\n  File \"/home/fkimura/.ansible/tmp/ansible-tmp-1448150376.3-46681347958483/file\", line 256, in main\r\n
    changed = module.set_fs_attributes_if_different(file_args, changed)\r\n
  File \"/home/fkimura/.ansible/tmp/ansible-tmp-1448150376.3-46681347958483/file\", line 1207, in set_fs_attributes_if_different\r\n
    file_args['path'], file_args['mode'], changed\r\n
  File \"/home/fkimura/.ansible/tmp/ansible-tmp-1448150376.3-46681347958483/file\", line 1090, in set_mode_if_different\r\n
    raise e\r\nOSError: [Errno 1] Operation not permitted: '/tmp/test'\r\nOpenSSH_6.6.1p1, OpenSSL 1.0.1p-freebsd
 9 Jul 2015\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: auto-mux:
 Trying existing master\r\ndebug1: mux_client_request_session: master session id: 2\r\nShared connection
 to webservice.example.jp closed.\r\n",

想定通りに、Operation not permittedでした。

次に、接続先に sudoersの設定をしない状態で再度接続します。
-s がsudoで実行するというパラメータ指定です。

% ansible webservice.example.jp -m file -a "dest=/tmp/test mode=604" -s
webservice.example.jp | FAILED => Missing become password

のように、パスワード入力プロンプトが出ていたことが想像できます。

リモート先のサーバでsudoの設定をしておきます。

# visudo

イントラネットならありかな?という程度に、

fkimura ALL=(ALL)       NOPASSWD: ALL

を加える。

% ansible webservice.example.jp -m file -a "dest=/tmp/test mode=604" -s
webservice.example.jp | success >> {
    "changed": true,
    "gid": 0,
    "group": "root",
    "mode": "0604",
    "owner": "root",
    "path": "/tmp/test",
    "size": 205,
    "state": "file",
    "uid": 0
}

成功が返ってきました。要するに、実行するユーザの鍵の配置とsudoのパスワードなしで動作する設定の2つが必須。
もちろん、相手側にSSH接続できることと、Pythonが導入されていることが前提ということになります。

 Playbook

test.ymlというファイルを準備して実行してみることにします。

---
- hosts: webservice.example.jp
  user: fkimura
  sudo: yes
  tasks:
   - name: install git
     yum: name=git update_cache=yes

こんなファイルをyaml形式で準備し、以下のようにコマンド投入します。

% ansible-playbook test.yml

PLAY [webservice.example.jp] ***********************************************

GATHERING FACTS ***************************************************************
ok: [webservice.example.jp]

TASK: [install git] ***********************************************************
changed: [webservice.example.jp]

PLAY RECAP ********************************************************************
webservice.example.jp   : ok=2    changed=1    unreachable=0    failed=0

先方サーバで導入されたことを確認します。

Nov 22 09:40:34 webserver ansible-setup: Invoked with filter=* fact_path=/usr/local/etc/ansible/facts.d
Nov 22 09:40:36 webserver ansible-yum: Invoked with name=git list=None install_repoquery=True conf_file=None
 disable_gpg_check=False state=installed disablerepo=None update_cache=True enablerepo=None
Nov 22 09:41:38 webserver yum[20041]: Installed: 1:perl-Error-0.17015-4.el6.noarch
Nov 22 09:41:38 webserver yum[20041]: Installed: perl-Git-1.7.1-3.el6_4.1.noarch
Nov 22 09:41:39 webserver yum[20041]: Installed: git-1.7.1-3.el6_4.1.x86_64

導入されていました。同じコマンドが何度投入されても問題のないことを確認します。

Nov 22 09:51:43 webserver ansible-setup: Invoked with filter=* fact_path=/usr/local/etc/ansible/facts.d
Nov 22 09:51:44 webserver ansible-yum: Invoked with name=git list=None install_repoquery=True conf_file=None
 disable_gpg_check=False state=installed disablerepo=None update_cache=True enablerepo=None

問題ありませんでした。元サーバ側は、

% ansible-playbook test.yml

PLAY [webservice.example.jp] ***********************************************

GATHERING FACTS ***************************************************************
ok: [webservice.example.jp]

TASK: [install git] ***********************************************************
ok: [webservice.example.jp]

PLAY RECAP ********************************************************************
webservice.example.jp   : ok=2    changed=0    unreachable=0    failed=0

のように、changed=0と変わらなかったこと確認できていました。

ymlのファイルは、includeで読み込むことができるそうです。

 - include: test.yml

実施ホストごとにファイルを準備しておけば、良さそうですね。

rolesというのが、ディレクトリ構造にしたもので、まさにChefのCookbookのようです。
そのうちに1セット動かしてみたいです。

【改訂履歴】作成:2015/11/22 更新:-
【参考リンク】

Ansible + FreeBSD
ansibleを使ってみる — そこはかとなく書くよん。

Copyright © 1996,1997-2006,2007- by F.Kimura,