ansibleの練習がてらgce上にletsencryptとnginxでHTTPSプロキシをansibleで作ってみました。awsの情報は多くあったのですが、gcpに関する情報が少なくちょっと苦労したので、そのあたりをまとめてみたいと思います。
ansibleとは
ansibleとは、構成管理ツールのことでインフラをコードで管理しようというものです。だいたいなんでもやろうと思えばできてしまいます。
yamlで宣言的に書くのが特徴で、手順と言うよりはこの状態になっていてほしいと記述することであとはansibleがなんとかしてくれます。
ansibleはコントローラーと呼ばれるホストのpcから管理対象のpcにsshしてコマンドを実行します。今回は手元のpcをコントローラーとし、そこからgceのインスタンスをprovisioningするという構成にしました。複数人で構成管理をする大規模なプロジェクトにでもならない限りこのような構成で十分だと思われます。
今回は最終的に以下のようなディレクトリ構成になります。
├── inventory.gcp.yml
├── nginx
│ ├── README.md
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ └── server.conf.j2
├── playbook.yml
inventoryを作成する
inventoryは管理対象のipアドレスを記載したファイルまたはそれらを返すプログラムのことです。今回はdynamic inventoryといって動的に管理対象となるインスタンスのipを取得して接続するようにしたました。(インスタンス一個だけですけどねw)
[ansibleの公式ドキュメント](https://docs.ansible.com/ansible/latest/scenario_guides/guide_gce.html)の手順にしたがってdynamic inventoryが動く環境を作ります。僕はドキュメントに記載されているpythonの依存ライブラリを作成するだけで動くようになりました。(バージョンが変わって設定がやりやすくなったのかな?)次にinventory.gcp.ymlというファイルを作成し以下のように記述します。
---
plugin: gcp_compute
projects:
- [プロジェクト名]
zones:
- "us-central1-a"
filters:
- name = [検索したいインスタンス名]
auth_kind: serviceaccount
service_account_file: "~/path/to/credential"
これで、指定した名前のインスタンスを取得できるようになりました。sshキーはgcloudコマンドで使っているものを指定しています。
$ ansible-inventory --list -i inventory.gcp.yml
実行するとインスタンスの情報を含んだjsonが取得できているのがわかると思います。GCPのapiを内部的に叩いているみたいで、ymlで指定している項目もそのapiの項目です。これでinvemtoryの作成は終わりです。
nginxのroleを作成する
roleとは、再利用可能はモジュールのようなものです。変数を使ったりループ処理を書くことができます。roleを作成せずにそのままplaybookに記述することもできますが、今回は練習がてらroleから作成することにします。
今回はnginxをinstallするroleを作成してみましょう。ansible-galaxyというコマンドを使うことで一気にディレクトリ構成を作ることができます。
$ ansible-galaxy init nginx
色々作成されましたが、主に使うのはtaskとtemplateです。taskは実際のインストール手順でtemplateは設定ファイルを作成するためのテンプレートファイルを置くところです。
tasks
実際にtaskを作成します。
---
# task file for nginx
- name: install nginx
apt: name=nginx update_cache=yes cache_valid_time=3600
# - name: copy nginx config file
# template: src=templates/server.conf.j2 dest=/etc/nginx/conf.d/default.conf
# notify: restart nginx
一つ目のタスクがnginxのインストールで二つ目がconfファイルの設置です。この段階ではまだ設定ファイルを作っていないので一旦コメントアウトしています。基本的にはnameとそれのコマンドなのですが、よく使うものに関してはmoduleとして提供されています。たとえば一つ目のtaskは、
---
# task file for nginx
- name: install nginx
command: apt install nginx
としてもできるのですが、aptモジュールを使うことでより複雑な設定や完結な記述を行うことができます。(複数のパッケージのインストールの際などはとても完結に書ける)
handlers
handlerとはansibleの状態が更新されたときに一回だけ実行されるコマンドのことです。いろんなところで呼び出しても実行されるのは全部終わったあとの一回だけです。今回は、restart nginx
というhandlerを設定します。設定ファイルやnginx自体の更新などのあとに一回だけrestartさせます。(毎回restartするのはもったいないから)
---
# handlers file for nginx
- name: restart nginx
service: name=nginx state=restarted
これで完了です。
playbookの作成
次に、playbookと言って何をどのような順番で実行するのかといういわば実行ファイルを作成します。と言っても先ほど作成したroleと必要な変数を宣言するだけです。
---
- hosts: all
become: true
roles:
- nginx
今回はそれほど指定することがないのでこれぐらいでおkです。
実行
では、実行してみましょう。
$ ansible-playbook -i inventory.gcp.yml playbook.yml
ら成功です。そのインスタンスにアクセスしてみてnginxの画面が表示されることを確認してください。
HTTPS化する
Let’s Encryptという無料のSSL証明書のサービスを使ってnginxでHTTPの接続ができるようにします。
これをやるまでにgceのインスタンスのipに独自ドメインを設定しておく必要があります。ちなみにこちらの記事で詳しく解説されているので、ここでは簡単な説明だけに留めておきます。
Let’s Encryptのroleをインストールする
先ほどは一からroleを作成しましたが、他の人が作ったroleを再利用することもできます。
$ ansible-galaxy install thefinn93.letsencrypt
これでinstallできて使うことができるようになりました。
あとは、必要な変数をplaybookに記述したらよしなにLet’s Encryptの設定を行ってくれます。
vars:
letsencrypt_email: [YOUR MAIL ADDRESS]
letsencrypt_cert_domains:
- [YOUR DOMAIN]
letsencrypt_renewal_command_args: '--renew-hook "systemctl restart nginx"'
nginxでHTTPSを処理できるようにする
あとは、nginxで証明書の場所を指定してやるだけです。/templates/default.conf.j2に
server{
server_name {{ host_name }};
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/{{ host_name }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ host_name }}/privkey.pem;
location / {
proxy_pass http://localhost:3000;
}
}
と記述してやります。これで、先ほどのroleで取得した証明書がnginxから使えるようになります。
今回はport:3000のローカルのサーバーにプロキシしていますが、ここはなんでも大丈夫です。おそらくなかったらnginxのtopページが表示されるはずです。(default.confを書き換えているのでNot Foundのページになるかもしれませんが)
あとは、playbookに追加してplaybookコマンドを追加するだけです!
roles:
- nginx
- thefinn93.letsencrypt
そして
$ ansible-playbook -i inventory.gcp.yml playbook.yml
を実行したら完了です。