どもども、キュービックで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を運用する精度を上げていってください。