CUEBiC TEC BLOG

キュービックTECチームの技術ネタを投稿しております。

Ansibleでenjoyするズラ!!

どもども、キュービックでSREをやっているkmsn17です。みなさん夏休みはどうでした? 僕は、9月に夏休みを取って長野でenjoyしてきます! さてさて、 僕が夏休みを取得する前にキュービックのテック記事について紹介します。

皆さん、infrastructure as codeはご存知でしょうか?

知らなかった、そこのアナタ!!そうアナタです!!! 今日は存分に持ち帰ちゃってください。

infrastructure as code、略してIaCはインフラ基盤(サーバ、インスタンス、etc)をコードで管理する構成管理ツールです。

使用する目的は、オペレーションミス・全インフラ環境の設定値を煩雑にせず 全て揃えて管理して冪等性を担保するためです。 誰が!何度!!使っても!!!繰り返し同じ設定になること、これを冪等性といいます。

URL:冪等性とは

Iacには、いくつかツールがありまして、代表的なのはAnsible、Terraform、それぞれ用途別に使います。 例えばTerraformは主にインスタンスの構築など、Ansibleはミドルウェアを変更するために使われています。

URL:Ansibleとは

URL:Ansibleで考える冪等性

では、kmsn17が魂を込めて構成したAnsibleを領域展開しちゃいます。 ヨッ!!

Ansibleの中身について

階層の分け方

* グループ変数(全インスタンスに共通して設定する内容を変数化)
* host変数(設定項目は一緒だけど、設定値が違う内容を変数化)
* hostsファイル(対象のインスタンスが記載されている)
* roles(実施するタスク内容が格納されている)
* playbook(実施したいroleが記載されている)

全体的なディレクトリ構造はこのような感じです。

├── group_vars
│   └── instance
│       ├── all.yml
│       ├── vault.yml
│       └── instancevault.yml
├── host_vars
│   └── kmsn-ubuntu-stg3.yml
├── hosts
├── roles
│   ├── apache2
│   │   ├── tasks
│   │   │   ├── 000-default.yml
│   │   │   ├── a2enmod.yml
│   │   │   ├── apache2.yml
│   │   │   ├── apache2conf.yml
│   │   │   ├── main.yml
│   │   │   ├── mkdir.yml
│   │   │   ├── permision.yml
│   │   │   └── ports.yml
│   │   └── templates
│   │       ├── 000-default.j2
│   │       ├── apache2.conf
│   │       └── ports.conf
│   ├── cwebp
│   │   └── tasks
│   │       ├── cwebp.yml
│   │       └── main.yml
│   ├── fluentd
│   │   ├── files
│   │   │   ├── td-agent.conf
│   │   │   └── yum-reposd-fluentd.repo
│   │   ├── tasks
│   │   │   ├── main.yml
│   │   │   └── setup-Ubuntu.yml
│   │   └── templates
│   │       └── td-agent.conf.j2
│   ├── googlechrome
│   │   └── tasks
│   │       ├── googlechrome.yml
│   │       └── main.yml
│   ├── mackerel
│   │   ├── files
│   │   │   └── conf.d
│   │   │       └── cuebic-vpc_vivo
│   │   │           ├── apache2.conf
│   │   │           ├── mysql.conf
│   │   │           ├── nginx.conf
│   │   │           ├── php-fpm.conf
│   │   │           ├── postfix.conf
│   │   │           ├── ssh.conf
│   │   │           ├── td-agent.conf
│   │   │           └── vivo.conf
│   │   ├── tasks
│   │   │   ├── mackerel.yml
│   │   │   └── main.yml
│   │   └── templates
│   │       ├── mackerel-agent.conf.j2
│   │       └── mackerel-agent.j2
│   ├── mysql
│   │   ├── tasks
│   │   │   ├── 50-server.yml
│   │   │   ├── main.yml
│   │   │   ├── mysql.yml
│   │   │   └── permision.yml
│   │   └── templates
│   │       └── 50-server.cnf
│   ├── node.js
│   │   └── tasks
│   │       ├── main.yml
│   │       └── node-js.yml
│   ├── os
│   │   └── tasks
│   │       ├── hostname.yml
│   │       ├── main.yml
│   │       ├── passwd.yml
│   │       ├── timezone.yml
│   │       ├── update.yml
│   │       └── upgrade.yml
│   ├── php-fpm
│   │   ├── tasks
│   │   │   ├── apcuini.yml
│   │   │   ├── main.yml
│   │   │   ├── mkdir.yml
│   │   │   ├── permision.yml
│   │   │   ├── php-fpm.yml
│   │   │   ├── php-fpmconf.yml
│   │   │   ├── phpini.yml
│   │   │   └── wwwconf.yml
│   │   └── templates
│   │       ├── apcu.ini
│   │       ├── php-fpm.conf
│   │       ├── php.ini
│   │       └── www.conf
│   └── postfix
│       ├── files
│       ├── handlers
│       ├── tasks
│       │   ├── main.yml
│       │   ├── postfix.yml
│       │   └── test-postfix.yml
│       └── templates
│           └── postfix
│               └── main.cf.j2
└── instance.yml

_vars、vault

group_vars

全サーバに対して共通設定を反映する場合に必要な変数ディレクトリです _varとついたものは、変数が置いてあるディレクトリと思ってよいです。

【例】group_varsの中にあるall.ymlの中身

postfix_allow_network: 
postfix_interface: localhost
#ansible_python_interpreter: /usr/bin/python3
mackerel_url: https:hogehoge.com
mackerel_auto_retirement: 0
mackerel_service: hoge-service
mackerel_role: hoge-role
opensearch_host: hoge-host
opensearch_user: hoge-user

vault.ymlについて

vault.ymlには、api、パスワードなどを暗号化して格納します。 ansible vaultを使っています。 URL:ansible vault

host_vars

サーバ1台・1台に対して設定を行うのに必要な変数ディレクトリです。

【例】kmsn-ubuntu-stg3.ymlの中身

name: kmsn-ubuntu-stg3.co.jp
mailname: dev.hoge.co.jp 

上記で設定した変数はapache2のconfigファイルを例に見ましょう。 ServerName {{ name }}と書かれた箇所に変数nameを使用しています。 変数を使用する場合は、必ず{{変数名}}としてください。

<VirtualHost *:8080>
       # The ServerName directive sets the request scheme, hostname and port that
       # the server uses to identify itself. This is used when creating
       # redirection URLs. In the context of virtual hosts, the ServerName
       # specifies what hostname must appear in the request's Host: header to
       # match this virtual host. For the default virtual host (this file) this
       # value is not decisive as it is used as a last resort host regardless.
       # However, you must set it for any further virtual host explicitly.
       #ServerName www.example.com

       ServerName {{ name }}
       ServerAdmin webmaster@localhost
       DocumentRoot /home/ubuntu/wordpress

       # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
       # error, crit, alert, emerg.
       # It is also possible to configure the loglevel for particular
       # modules, e.g.
       #LogLevel info ssl:warn

       SetEnvIf User-Agent "ELB-HealthChecker.*" no_log
       SetEnvIf User-Agent "Amazon-Route53-Health-Check-Service.*" no_log
       SetEnvIf Request_URI "\.(gif)|(css)|(js)|(swf)|(jpeg)|(jpg)|(png)|(ico)|(svg)|(eot)|(ttf)|(woff)$" no_log

       ErrorLog ${APACHE_LOG_DIR}/error.log
       CustomLog ${APACHE_LOG_DIR}/access.log combined env=!no_log

       # For most configuration files from conf-available/, which are
       # enabled or disabled at a global level, it is possible to
       # include a line for only one particular virtual host. For example the
       # following line enables the CGI configuration for this host only
       # after it has been globally disabled with "a2disconf".
       #Include conf-available/serve-cgi-bin.conf
       <FilesMatch \.php$>
               SetHandler "proxy:unix:/run/php/php7.4-fpm.sock|fcgi://localhost/"
       </FilesMatch>
</VirtualHost>

hostsファイル

hostsファイルには、対象先のインスタンスを指定します。 その際に、IPアドレス、接続ポートを指定します。

【例】hostsファイルの中身

[instance]
hoge.co.jp-ec2-stg ansible_ssh_host=xxx.xxx.xxx.xxx ansible_ssh_port=22

[instance:vars]
relay=yes

roles

各プロセス毎にディレクトリ毎に構成しています。 分ける理由として管理しやすいのもありますが、以下の観点の思いもあり自分は分けました。 ・複数のサーバのミドルウェアバージョンアップ対応 ・別構成のサーバにも使い回すため(例えばapacheだけ設定が同じだったり、php-fpmだけ設定が同じだったり)

tasks

各プロセスで実施する内容が格納されているディレクトリで、ymlファイルが配置されています。 以下のようにディレクトリを作成したりする内容などを格納したりするのがtasksです。 ここは特にですが、実施するタスクによって細かく分けるのがポイントです。 理由ですが、前述と同じです。

【例】ディレクトリ作成をするymlファイルの中身

 name: directory created
  file:
   path: /var/log/apache2
   state: directory

ansibleにはansible モジュールがあります。 ansible モジュールとは、ディレクトリを変更したい場合、コピーしたり、など ansibleに適した内容で書くモジュールです。 何か実施したい場合は、その動作に見合ったモジュールを使ってymlファイルに書き込んでください。 これは鉄則です。 どうしてもモジュールがない場合はcommandモジュールを使うのも手です。

main.ymlについて

tasks配下に実施する複数のタスクがありますが、それらのymlを実施 する場合は、main.ymlに記載します。 main.ymlの中に、以下のように記載します

- import_tasks: apache2.yml
- import_tasks: apache2conf.yml
- import_tasks: ports.yml
- import_tasks: 000-default.yml
- import_tasks: a2enmod.yml
- import_tasks: mkdir.yml
- import_tasks: permision.yml

templates

templatesには、例えば独自で作ったconfファイルの内容を格納しておき 指定したディレクトリに移し替えます。

【例】 copyモジュールを使って、指定したディレクトリに移し替える書き方です。

- name: apache2.confの追記
  copy:
   src: roles/apache2/templates/apache2.conf #ansibleに記載したディレクトリ
   dest: /etc/apache2/apache2.conf       #サーバ内に移し替えるディレクトリ先

変数と組み合わせてconfファイルにすり替える場合はjinjaテンプレートを使用します。 その際に使うのが、J2ファイルです。 【例】

000-default.j2

xxxx.yml(playbook)について

playbookの指定ですが、簡単なAnsibleを流す場合にはhostsファイルにだけ記載でもOKです。 例えば、apacheだけを変更するAnsibleだったり、一台だけ複数のプロセスを変更する場合などです。 今回、複数のプロセスを複数台のインスタンスに変更するので、playbookの中身を詳細に書きました。

---
- hosts: instance
  become: true
  gather_facts: yes
  remote_user: hoge

  roles:
    - os
    - php-fpm
    - apache2
    - mysql
    - node.js
    - googlechrome
    - cwebp
    - postfix
    - fluentd
    - mackerel

xxxx.yml(playbook)の項目について

---:YAMLファイルであることを宣言
hosts: instance :instanceと記載されてたものをターゲット対象
become: true :becomeはsudoで実行するモジュール
gather_facts: yes :対象ホストの情報をansible_facts変数に格納し、tasks内の変数で使用
remote_user: ubuntu :インスタンスがsshで接続されるユーザを指定します
roles: 複数のサービスを変更した場合に設定し、使う側が見やすく、管理しやすいように必要

URL:gather_factsについて

実行コマンド

Ansibleを流す場合は以下のコマンドを使用します。

①ansible-playbook -i hosts xxxx.yml --private-key=秘密鍵 --ask-vault-pass --check
②ansible-playbook -i hosts xxxx.yml --private-key=秘密鍵 --ask-vault-pass

①ですが、dry-runと言われており本番に実行する前に問題がないか?確認して検証してみるコマンドです。 実際には適用されません ②ですが、applyとも言われており本番に設定変更を実施するコマンドです。

--ask-vault-pass

ansible vaultで暗号化したものは、--ask-vault-pass というオプションをつけて パスワードを入力してansibleを流します。

総括

Iacを導入する場合は、目的・手段が混同してしまうので見失わないようにお願いします。 設計段階から自動化する範囲を決めましょう。

また、構築のオペレーションミスを減らし、作業コストを削減してくれますが

銀の弾丸ではないことだけは認識してください。

しっかりメンテナンスをして、少しずつ改良して育てていくようにして運用しないと、腐ってしまい作ってきた時間が無駄になります。

信頼性を高めるためにも、IaCを運用する精度を上げていってください。