CloudFormationヘルパースクリプト(cfn-init等)でEC2の構成管理

経緯

最近CloudFormationを触っています。CloudFormationでは、cfn-initをはじめとする、「CloudFormationヘルパースクリプト」という構成管理ツールをサポートしています。 CloudFormationヘルパースクリプトの挙動が当初わかりづらかったので、少し前の自分のために書きます。いま思えば、デバッグの方法がわかりにくかったですね。

動画もあります

概要説明、およびデモをYouTubeにアップしました。 https://youtu.be/wdXYkzio6t0

動画から飛んできた方へ

動画内にて、ブログで補足します、と話した情報は、下記の場所にあります

CloudFormationヘルパースクリプトとは何か

公式ドキュメント はこちら。「スタックの一部として作成する Amazon EC2 インスタンスでソフトウェアをインストールしたりサービスを開始したりするために使用」とのこと。ざっくりいうとEC2インスタンスのプロビジョニング&構成管理ツール。

使い方はざっくり以下の通り。

CloudFormationテンプレートファイル(例: template.yml)のEC2のメタ情報に、設定情報を記述する。設定情報を記述してCloudFormationスタックをデプロイすると、EC2インスタンス初回起動時に、設定情報に応じて初期設定が自動で行われる。

更新も可能。EC2起動後も、設定情報はEC2インスタンスにインストールされたCloudFormationヘルパースクリプトが定期的に読み取っている。設定情報を更新してスタックを更新すると、変更が適用される。

4つのPythonスクリプトから成る。

  • cfn-init
    • 設定それ自体を実行する。
  • cfn-signal
    • 設定完了をAWSに通知する。オートスケーリングの準備完了判定、スタックのロールバック判定に使う。
  • cfn-get-metadata
    • 設定情報を読み取る。
    • 自分はほとんど使わない。
  • cfn-hup
    • 更新で活躍する。
    • デーモン。
    • 定期的に設定情報を読み取る。設定情報に変更があれば、指定の操作(例: cfn-initの呼び出し)を実行する。

UserDataとの違いはなにか

EC2では、UserDataパラメータにインスタンス起動時の処理を記述できる。(https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/user-data.html)CloudFormationにおいてももちろん活用可能。テンプレートファイルに記述できる。CloudFormationヘルパースクリプトの役割と重複する部分が大きい。わざわざCloudFormationヘルパースクリプトとのはなにか?

  • CloudFormationヘルパースクリプトのメリット
    • 宣言的に書ける(自分はわかりやすいと感じる)
    • 公式によるメリットの説明
    • EC2インスタンスのパブリックIP、パブリックDNSが変わらない。おそらく上記の「インスタンスを作り直さない」ことに関係するのだろう。
      • 前回案件では、諸々の事情から、DNSの向き先をEC2パブリックIPにしていた。その構成のだとEC2パブリックIPが変わると困ったことになる。
    • 想定された項目の設定が簡単
      • パッケージインストール、グループ作成、ユーザー作成、ファイル作成、コマンド実行、サービス(デーモン)設定、ファイルダウンロード。
    • 失敗の検知が簡単
      • cfn-signalで簡単に検知可能。
      • 失敗したらロールバック、がほぼコードをかかずに実行可能。
  • CloudFormationヘルパースクリプトのデメリット
    • スクリプトのコピペで済まない。
      • ミドルウェアの公式サイトに載ってる手順がコピペできない。
    • CloudFormationにより構成管理に慣れてないため、ハマることがある
      • amazon-linux-extrasがインストールできないのでハマった。下記TIPS参照。
      • いわゆる学習コストがかかる、ということだろうか?

CloudFormationヘルパースクリプトを始めるにはどうすればいいのか

  • Amazon Linux AMI イメージを使っている場合、ヘルパースクリプトは始めから入っている。
    • 最新バージョンでは /opt/aws/bin に存在
    • 2020/09現在、最新バージョンをtar, zip, exe形式で配布している
    • 1系はrpmも配布している
  • 本記事の主題から外れるが、CloudFormation自体を新規に始める場合。
    • CloudFormation Designer
    • CloudFormer
      • 「既存のAWS リソースからAWS CloudFormationテンプレートを作成できる」、とのこと。
      • 自分はちょっと試して、使いこなせないと感じた。CloudFormationの理解度が低い中で、同じく理解度の低いCloudFormerも使うと、意図しない挙動が起きた時どちらのツールによるものか推測できなくなる。(一般に、わからないレイヤーが複数あると、単一の場合よりもはるかに原因解明がやりづらくなると思う。この現象に名前をつけたい。)
    • チュートリアル などからリンクされている サンプルテンプレート から始める
      • 自分はここから始めた。
      • CloudFormationヘルパースクリプトを活用するためには、ヘルパースクリプト自体の設定、呼び出し処理をtemplate.ymlに書く必要が要る。上記テンプレートなら記述済み。

デバッグはどうやるのか

UserDataのログを確認する

方法1: AWS CLIから確認する

aws ec2 get-console-output --instance-id <value> --output text で確認可能。

方法2: ログをファイルに残す

以下をUserDataに追記する。自分は頭に書いている。

#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1

すると、EC2インスタンス内、 /var/log/user-data.log にて出力が記録される。

参考: https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-linux-log-user-data/

ヘルパースクリプトのログを確認する

/var/log/cfn-*.log に記録されます。

テンプレートのAWS::CloudFormation::Initの変更をすばやく反映する

cfn-hupによる確認は、デフォルト15分間隔。おそらく最短5分間隔。EC2内で、直接cfn-initを呼ぶと即座に反映できる。

例:

/opt/aws/bin/cfn-init -v --stack cfn-test-stack --resource WebServerInstance --configsets InstallAndRun --region ap-northeast-1

立ち上げ失敗時、ロールバックしないようにする

設定によっては、AWS::CloudFormation::Initによる初期設定が失敗するとロールバックする。運用時は便利だが、スタックの初回立ち上げまでの試行錯誤中には、スタックが削除されるとログが消え、かつスタック削除自体に数分の時間がかかるのでデバッグしづらい。

CreationPolicyaws cloudformation create-stackコマンドのdisable-rollbackon-failureオプションに注意して、ロールバックしないようにしたほうが良い。 自分はSAMを使っていたのだが、簡単に上記のdisable-rollbackon-failureオプションを指定する方法がわからなかった。CreationPolicyの指定をコメントアウトしてデバッグしていた。

その他TIPS

amazon-linux-extras パッケージがインストールできない

amazon-linux-extras enable <PACKAGE>

してから、パッケージインストールする。

例:

01_prepare_install_docker:
  commands:
    01_enable_docker_in_amazon_linux_extras:
      command: 'amazon-linux-extras enable docker'
02_install_docker:
  packages:
    yum:
      docker: []

参考: https://cloudonaut.io/migrating-to-amazon-linux-2/#cfn-init-is-not-integrated-with-the-Extras-Library

UserDataを更新してスタック更新したら、反映されるのか?

反映される。

ただし、UserDataとの違いはなにか の「CloudFormationヘルパースクリプトのメリット」で挙げた恩恵は受けられないので注意。

UserDataやcfn-initで更新すると、サーバー内で手動で作成したファイルは消えちゃうの?

消えたことがありません。

参考

https://qiita.com/yasuhiroki/items/8463eed1c78123313a6f https://dev.classmethod.jp/articles/cfn-init/

長いおまけ: 挙動を実際に確認してみた

こちらのリポジトリより確認可能です。https://github.com/matzryo/cfn-test 以下手順内のコミットのハッシュ値は上記リポジトリのものになります。

# 最初のコミット
git checkout d916fd300f78777ce26a5d040d1f4ca14560c52d
make create-stack
aws cloudformation create-stack --template-body file://./template.yml --cli-input-json file://./cli-input.json
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:<************>:stack/cfn-test-stack/76ce5280-ff24-11ea-be1e-0e7ed7880c96"
}
make wait-create-stack
aws cloudformation wait stack-create-complete --stack-name cfn-test-stack
# 返ってきたらOutputsでURLを確認、情報が多く、かつブログに出したくない情報もあるためqueryオプションで結果を絞る。
make get-url
aws cloudformation describe-stacks --stack-name cfn-test-stack --query "Stacks[0].Outputs[0]"
{
    "OutputKey": "WebsiteURL",
    "OutputValue": "http://ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com",
    "Description": "URL for newly created LAMP stack"
}
# たしかに上記URLにアクセス可能である。
> make ssh HOST=ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
ssh -i ~/.ssh/cfn-test-key.pem ec2-user@ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com

# 指定パッケージがインストールされている。
[ec2-user@ip-172-31-42-181 ~]$ yum list installed | egrep 'mysql|php|httpd'
httpd.x86_64                         2.2.34-1.16.amzn1             @amzn-main   
httpd-tools.x86_64                   2.2.34-1.16.amzn1             @amzn-main   
mysql.noarch                         5.5-1.6.amzn1                 @amzn-main   
mysql-config.x86_64                  5.5.62-1.23.amzn1             @amzn-updates
mysql-libs.noarch                    5.5-1.6.amzn1                 @amzn-main   
mysql-server.noarch                  5.5-1.6.amzn1                 @amzn-main   
mysql55.x86_64                       5.5.62-1.23.amzn1             @amzn-updates
mysql55-libs.x86_64                  5.5.62-1.23.amzn1             @amzn-updates
mysql55-server.x86_64                5.5.62-1.23.amzn1             @amzn-updates
php.x86_64                           5.3.29-1.8.amzn1              @amzn-main   
php-cli.x86_64                       5.3.29-1.8.amzn1              @amzn-main   
php-common.x86_64                    5.3.29-1.8.amzn1              @amzn-main   
php-mysql.x86_64                     5.3.29-1.8.amzn1              @amzn-main   
php-pdo.x86_64                       5.3.29-1.8.amzn1              @amzn-main 

# ファイルが作成されている。
[ec2-user@ip-172-31-42-181 ~]$ sudo head /var/www/html/index.php
<html>
  <head>
    <title>AWS CloudFormation PHP Sample</title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  </head>
  <body>
    <h1>Welcome to the AWS CloudFormation PHP Sample</h1>
    <p/>
    <?php
      // Print out the current data and time

# サービスが起動している。
[ec2-user@ip-172-31-42-181 ~]$ sudo service --status-all | egrep 'mysqld|httpd|cfn-hup'
cfn-hup (pid  3117) is running...
httpd (pid  3084) is running...
mysqld (pid  3437) is running...

# コマンドが実行されている。
[ec2-user@ip-172-31-42-181 ~]$ mysql -umatzryo --password=q40stBlSEjwi
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.5.62 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test               |
| testdb             |
+--------------------+
3 rows in set (0.00 sec)

mysql> Bye

# cfn関連ログファイル。
[ec2-user@ip-172-31-42-181 ~]$ ls /var/log/cfn*
/var/log/cfn-hup.log  /var/log/cfn-init-cmd.log  /var/log/cfn-init.log  /var/log/cfn-wire.log

# 15分ごとにメタデータを確認している。
[ec2-user@ip-172-31-42-181 ~]$ ls /var/log/cfn*
/var/log/cfn-hup.log  /var/log/cfn-init-cmd.log  /var/log/cfn-init.log  /var/log/cfn-wire.log
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-hup.log 
2020-09-25 11:45:37,446 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.ap-northeast-1.amazonaws.com
2020-09-25 11:45:37,447 [DEBUG] Creating /var/lib/cfn-hup/data
2020-09-25 11:45:37,452 [INFO] No umask value specified in config file. Using the default one: 022
# 以下は別インスタンスの例。
[ec2-user@ip-172-31-30-239 log]$ head cfn-hup.log 
2020-09-25 01:04:09,409 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.ap-northeast-1.amazonaws.com
2020-09-25 01:04:09,410 [DEBUG] Creating /var/lib/cfn-hup/data
2020-09-25 01:04:09,416 [INFO] No umask value specified in config file. Using the default one: 022
2020-09-25 01:19:09,554 [INFO] cfn-hup processing is alive.
2020-09-25 01:34:09,670 [INFO] cfn-hup processing is alive.
2020-09-25 01:49:09,786 [INFO] cfn-hup processing is alive.
2020-09-25 02:04:09,901 [INFO] cfn-hup processing is alive.
2020-09-25 02:19:10,017 [INFO] cfn-hup processing is alive.
2020-09-25 02:34:10,133 [INFO] cfn-hup processing is alive.
2020-09-25 02:49:10,249 [INFO] cfn-hup processing is alive.

# 手動で作成したファイルが消されないかテストするためにファイルを作成。
[ec2-user@ip-172-31-42-181 ~]$ echo created in instance manually. > /home/ec2-user/manual.txt
[ec2-user@ip-172-31-42-181 ~]$ cat /home/ec2-user/manual.txt
created in instance manually.
# cowsayは存在しない。
[ec2-user@ip-172-31-42-181 ~]$ which cowsay
/usr/bin/which: no cowsay in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin:/home/ec2-user/.local/bin:/home/ec2-user/bin)
exit
# EC2インスタンスが再作成されたかわかるよう、インスタンス情報を保存しておく
aws ec2 describe-instances > first-instance.txt

# template.ymlを更新
# CFNヘルパースクリプトによる追加の確認
# パッケージ1つ、ファイル2つ
git checkout a38b4850c43f766cf1eb5a17951f1bb3d6500b98
> git log -p -1 a38b4850c43f766cf1eb5a17951f1bb3d6500b98
diff --git a/template.yml b/template.yml
index a39f3fb..b47ab98 100644
--- a/template.yml
+++ b/template.yml
@@ -108,7 +108,20 @@ Resources:
               httpd: []
               php: []
               php-mysql: []
+              cowsay: []
           files:
+            /tmp/test-cfn-create.txt:
+              content: |
+                hello from cfn-hup!
+              mode: '000400'
+              owner: root
+              group: root
+            /tmp/test-cfn-update.txt:
+              content: |
+                hello from cfn-hup!
+              mode: '000400'
+              owner: root
+              group: root
             /var/www/html/index.php:
               content: !Join 
                 - ''

# パッケージ、ファイルの追加テスト
# 再度EC2インスタンスが初期化されないかテスト
> make deploy
aws cloudformation deploy --stack-name cfn-test-stack --template-file ./template.yml

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - cfn-test-stack

> make ssh HOST=ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
ssh -i ~/.ssh/cfn-test-key.pem ec2-user@ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
# 作成したファイルは存在する
[ec2-user@ip-172-31-42-181 ~]$ cat /home/ec2-user/manual.txt 
created in instance manually.
# インストールされてない。
[ec2-user@ip-172-31-42-181 ~]$ which cowsay
/usr/bin/which: no cowsay in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin:/home/ec2-user/.local/bin:/home/ec2-user/bin)
[ec2-user@ip-172-31-42-181 ~]$ ls /tmp/test-cfn-create.txt
ls: /tmp/test-cfn-create.txt にアクセスできません: そのようなファイルやディレクトリはありません
[ec2-user@ip-172-31-42-181 ~]$ ls /tmp/test-cfn-update.txt
ls: /tmp/test-cfn-update.txt にアクセスできません: そのようなファイルやディレクトリはありません
[ec2-user@ip-172-31-42-181 ~]$ cat /var/log/cfn-hup.log 
2020-09-25 11:45:37,446 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.ap-northeast-1.amazonaws.com
2020-09-25 11:45:37,447 [DEBUG] Creating /var/lib/cfn-hup/data
2020-09-25 11:45:37,452 [INFO] No umask value specified in config file. Using the default one: 022
2020-09-25 12:00:37,590 [INFO] cfn-hup processing is alive.

# ~15分後~
# create-databaseなど愚直に繰り返して失敗している。
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-init.log 
2020-09-25 12:15:40,808 [DEBUG] Test command output: 
2020-09-25 12:15:40,808 [INFO] Test failed with code 1
2020-09-25 12:15:40,808 [DEBUG] Running command 02_create_database
2020-09-25 12:15:40,808 [DEBUG] Running test for command 02_create_database
2020-09-25 12:15:40,824 [DEBUG] Test command output: 
2020-09-25 12:15:40,824 [INFO] Test failed with code 1
2020-09-25 12:15:40,824 [DEBUG] No services specified
2020-09-25 12:15:40,824 [INFO] ConfigSets completed
2020-09-25 12:15:40,824 [DEBUG] Not clearing reboot trigger as scheduling support is not available
2020-09-25 12:15:40,825 [INFO] -----------------------Build complete-----------------------
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-init-cmd.log 
2020-09-25 12:15:40,532 P24817 [INFO] ------------------------------------------------------------
2020-09-25 12:15:40,532 P24817 [INFO] Completed successfully.
2020-09-25 12:15:40,784 P24817 [INFO] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020-09-25 12:15:40,785 P24817 [INFO] Config Configure
2020-09-25 12:15:40,785 P24817 [INFO] ============================================================
2020-09-25 12:15:40,785 P24817 [INFO] Test for Command 01_set_mysql_root_password
2020-09-25 12:15:40,807 P24817 [ERROR] Exited with error code 1
2020-09-25 12:15:40,808 P24817 [INFO] ============================================================
2020-09-25 12:15:40,808 P24817 [INFO] Test for Command 02_create_database
2020-09-25 12:15:40,823 P24817 [ERROR] Exited with error code 1
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-hup.log 
2020-09-25 11:45:37,446 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.ap-northeast-1.amazonaws.com
2020-09-25 11:45:37,447 [DEBUG] Creating /var/lib/cfn-hup/data
2020-09-25 11:45:37,452 [INFO] No umask value specified in config file. Using the default one: 022
2020-09-25 12:00:37,590 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,706 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,821 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:15:37,821 [INFO] Running action for cfn-auto-reloader-hook
# パッケージインストールされた
[ec2-user@ip-172-31-42-181 ~]$ which cowsay
/usr/bin/cowsay
[ec2-user@ip-172-31-42-181 ~]$ cowsay installed!
 ____________ 
< installed! >
 ------------ 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
# ファイルも作成された
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-create.txt 
hello from cfn-hup!
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-update.txt 
hello from cfn-hup!

# CFNヘルパースクリプトによる更新、削除の確認
# パッケージ削除、ファイル削除、ファイル更新
git checkout 4a2db25db123668bf861a3b85165a7bcd191ce63
git log -p -1 4a2db25db123668bf861a3b85165a7bcd191ce63
diff --git a/template.yml b/template.yml
index b47ab98..3e296df 100644
--- a/template.yml
+++ b/template.yml
@@ -108,17 +108,10 @@ Resources:
               httpd: []
               php: []
               php-mysql: []
-              cowsay: []
           files:
-            /tmp/test-cfn-create.txt:
-              content: |
-                hello from cfn-hup!
-              mode: '000400'
-              owner: root
-              group: root
             /tmp/test-cfn-update.txt:
               content: |
-                hello from cfn-hup!
+                hello from cfn-hup! content has been updated!
               mode: '000400'
               owner: root
               group: root
> make deploy
aws cloudformation deploy --stack-name cfn-test-stack --template-file ./template.yml
make ssh HOST=ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
ssh -i ~/.ssh/cfn-test-key.pem ec2-user@ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
# cfn-hupによる更新前
[ec2-user@ip-172-31-42-181 ~]$ which cowsay
/usr/bin/cowsay
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-create.txt 
hello from cfn-hup!
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-update.txt 
hello from cfn-hup!
# cfn-hupによる更新実行
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-init.log 
2020-09-25 12:30:42,676 [DEBUG] Test command output: 
2020-09-25 12:30:42,676 [INFO] Test failed with code 1
2020-09-25 12:30:42,677 [DEBUG] Running command 02_create_database
2020-09-25 12:30:42,677 [DEBUG] Running test for command 02_create_database
2020-09-25 12:30:42,683 [DEBUG] Test command output: 
2020-09-25 12:30:42,683 [INFO] Test failed with code 1
2020-09-25 12:30:42,683 [DEBUG] No services specified
2020-09-25 12:30:42,684 [INFO] ConfigSets completed
2020-09-25 12:30:42,684 [DEBUG] Not clearing reboot trigger as scheduling support is not available
2020-09-25 12:30:42,684 [INFO] -----------------------Build complete-----------------------
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-init-cmd.log
2020-09-25 12:30:41,354 P25033 [INFO] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020-09-25 12:30:41,354 P25033 [INFO] Config Install
2020-09-25 12:30:42,669 P25033 [INFO] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020-09-25 12:30:42,669 P25033 [INFO] Config Configure
2020-09-25 12:30:42,669 P25033 [INFO] ============================================================
2020-09-25 12:30:42,670 P25033 [INFO] Test for Command 01_set_mysql_root_password
2020-09-25 12:30:42,676 P25033 [ERROR] Exited with error code 1
2020-09-25 12:30:42,677 P25033 [INFO] ============================================================
2020-09-25 12:30:42,677 P25033 [INFO] Test for Command 02_create_database
2020-09-25 12:30:42,683 P25033 [ERROR] Exited with error code 1
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-hup.log
2020-09-25 11:45:37,446 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.ap-northeast-1.amazonaws.com
2020-09-25 11:45:37,447 [DEBUG] Creating /var/lib/cfn-hup/data
2020-09-25 11:45:37,452 [INFO] No umask value specified in config file. Using the default one: 022
2020-09-25 12:00:37,590 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,706 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,821 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:15:37,821 [INFO] Running action for cfn-auto-reloader-hook
2020-09-25 12:30:40,854 [INFO] cfn-hup processing is alive.
2020-09-25 12:30:40,969 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:30:40,969 [INFO] Running action for cfn-auto-reloader-hook
# パッケージは削除されない。ファイルも消されない。更新は適用された。
[ec2-user@ip-172-31-42-181 ~]$ which cowsay
/usr/bin/cowsay
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-create.txt 
hello from cfn-hup!
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-update.txt 
hello from cfn-hup! content has been updated!
# 手動作成したファイルは当然残っている。
[ec2-user@ip-172-31-42-181 ~]$ cat /home/ec2-user/manual.txt 
created in instance manually.

# 手動更新のテスト
> git checkout 7ec05844d427de0156c28b27b44a2ad207237c5e
> git log -p -1 7ec05844d427de0156c28b27b44a2ad207237c5e
diff --git a/template.yml b/template.yml
index 3e296df..8da39bb 100644
--- a/template.yml
+++ b/template.yml
@@ -111,7 +111,7 @@ Resources:
           files:
             /tmp/test-cfn-update.txt:
               content: |
-                hello from cfn-hup! content has been updated!
+                hello from cfn-hup! content has been updated! updated again!
               mode: '000400'
               owner: root
               group: root

matzryo@tp-x1c-5 ~/D/cfn (master)> make deploy
aws cloudformation deploy --stack-name cfn-test-stack --template-file ./template.yml

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - cfn-test-stack
matzryo@tp-x1c-5 ~/D/cfn (master)> make ssh HOST=ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
ssh -i ~/.ssh/cfn-test-key.pem ec2-user@ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
# 手動更新前。ちなみに現在、15,30,45,00分ころに自動チェックが入っている状態。 現在40分。
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-update.txt
hello from cfn-hup! content has been updated!
[ec2-user@ip-172-31-42-181 ~]$ sudo /opt/aws/bin/cfn-init -v --stack cfn-test-stack --resource WebServerInstance --configsets InstallAndRun --region ap-northeast-1
# 即座に再確認。更新されている。
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-update.txt
hello from cfn-hup! content has been updated! updated again!
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-init.log
2020-09-25 12:40:09,474 [DEBUG] Test command output: 
2020-09-25 12:40:09,475 [INFO] Test failed with code 1
2020-09-25 12:40:09,475 [DEBUG] Running command 02_create_database
2020-09-25 12:40:09,475 [DEBUG] Running test for command 02_create_database
2020-09-25 12:40:09,481 [DEBUG] Test command output: 
2020-09-25 12:40:09,481 [INFO] Test failed with code 1
2020-09-25 12:40:09,481 [DEBUG] No services specified
2020-09-25 12:40:09,482 [INFO] ConfigSets completed
2020-09-25 12:40:09,482 [DEBUG] Not clearing reboot trigger as scheduling support is not available
2020-09-25 12:40:09,482 [INFO] -----------------------Build complete-----------------------
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-init-cmd.log
2020-09-25 12:40:08,135 P25263 [INFO] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020-09-25 12:40:08,135 P25263 [INFO] Config Install
2020-09-25 12:40:09,467 P25263 [INFO] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020-09-25 12:40:09,467 P25263 [INFO] Config Configure
2020-09-25 12:40:09,468 P25263 [INFO] ============================================================
2020-09-25 12:40:09,468 P25263 [INFO] Test for Command 01_set_mysql_root_password
2020-09-25 12:40:09,474 P25263 [ERROR] Exited with error code 1
2020-09-25 12:40:09,475 P25263 [INFO] ============================================================
2020-09-25 12:40:09,475 P25263 [INFO] Test for Command 02_create_database
2020-09-25 12:40:09,481 P25263 [ERROR] Exited with error code 1
# cfn-hupはスタック更新後、実行されていない。手動更新により、ファイルが更新された。
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-hup.log
2020-09-25 11:45:37,446 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.ap-northeast-1.amazonaws.com
2020-09-25 11:45:37,447 [DEBUG] Creating /var/lib/cfn-hup/data
2020-09-25 11:45:37,452 [INFO] No umask value specified in config file. Using the default one: 022
2020-09-25 12:00:37,590 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,706 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,821 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:15:37,821 [INFO] Running action for cfn-auto-reloader-hook
2020-09-25 12:30:40,854 [INFO] cfn-hup processing is alive.
2020-09-25 12:30:40,969 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:30:40,969 [INFO] Running action for cfn-auto-reloader-hook

# 再度動かしてみる。意味はない。
[ec2-user@ip-172-31-42-181 ~]$ sudo /opt/aws/bin/cfn-init -v --stack cfn-test-stack --resource WebServerInstance --configsets InstallAndRun --region ap-northeast-1
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-init.log 
2020-09-25 12:43:49,390 [DEBUG] Test command output: 
2020-09-25 12:43:49,390 [INFO] Test failed with code 1
2020-09-25 12:43:49,390 [DEBUG] Running command 02_create_database
2020-09-25 12:43:49,390 [DEBUG] Running test for command 02_create_database
2020-09-25 12:43:49,396 [DEBUG] Test command output: 
2020-09-25 12:43:49,397 [INFO] Test failed with code 1
2020-09-25 12:43:49,397 [DEBUG] No services specified
2020-09-25 12:43:49,397 [INFO] ConfigSets completed
2020-09-25 12:43:49,397 [DEBUG] Not clearing reboot trigger as scheduling support is not available
2020-09-25 12:43:49,397 [INFO] -----------------------Build complete-----------------------
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-init-cmd.log 
2020-09-25 12:43:48,088 P25388 [INFO] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020-09-25 12:43:48,088 P25388 [INFO] Config Install
2020-09-25 12:43:49,382 P25388 [INFO] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020-09-25 12:43:49,382 P25388 [INFO] Config Configure
2020-09-25 12:43:49,383 P25388 [INFO] ============================================================
2020-09-25 12:43:49,383 P25388 [INFO] Test for Command 01_set_mysql_root_password
2020-09-25 12:43:49,390 P25388 [ERROR] Exited with error code 1
2020-09-25 12:43:49,390 P25388 [INFO] ============================================================
2020-09-25 12:43:49,390 P25388 [INFO] Test for Command 02_create_database
2020-09-25 12:43:49,396 P25388 [ERROR] Exited with error code 1
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-hup.log 
2020-09-25 11:45:37,446 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.ap-northeast-1.amazonaws.com
2020-09-25 11:45:37,447 [DEBUG] Creating /var/lib/cfn-hup/data
2020-09-25 11:45:37,452 [INFO] No umask value specified in config file. Using the default one: 022
2020-09-25 12:00:37,590 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,706 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,821 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:15:37,821 [INFO] Running action for cfn-auto-reloader-hook
2020-09-25 12:30:40,854 [INFO] cfn-hup processing is alive.
2020-09-25 12:30:40,969 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:30:40,969 [INFO] Running action for cfn-auto-reloader-hook
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-hup.log 
2020-09-25 11:45:37,446 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.ap-northeast-1.amazonaws.com
2020-09-25 11:45:37,447 [DEBUG] Creating /var/lib/cfn-hup/data
2020-09-25 11:45:37,452 [INFO] No umask value specified in config file. Using the default one: 022
2020-09-25 12:00:37,590 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,706 [INFO] cfn-hup processing is alive.
2020-09-25 12:15:37,821 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:15:37,821 [INFO] Running action for cfn-auto-reloader-hook
2020-09-25 12:30:40,854 [INFO] cfn-hup processing is alive.
2020-09-25 12:30:40,969 [INFO] Data has changed from previous state; action for cfn-auto-reloader-hook will be run
2020-09-25 12:30:40,969 [INFO] Running action for cfn-auto-reloader-hook

> aws ec2 describe-instances --filters Name=instance-state-name,Values=running > second-instance-before-update-user-data.txt
# UserData追記、コミット
> git checkout 3f5ae0169511dff276bb1e2a78455871a33b9c8f
> git log -p -1 3f5ae0169511dff276bb1e2a78455871a33b9c8f
diff --git a/template.yml b/template.yml
index 8da39bb..c6e4915 100644
--- a/template.yml
+++ b/template.yml
@@ -378,6 +378,11 @@ Resources:
             - !Ref 'AWS::Region'
             - |+
 
+            - |
+              # craete file from UserData
+            - 'echo test from UserData > created-by-user-data.txt '
+            - |+
+
     CreationPolicy:
       ResourceSignal:
         Timeout: PT5M
> date
2020年  9月 25日 金曜日 23:14:51 JST
> make deploy
aws cloudformation deploy --stack-name cfn-test-stack --template-file ./template.yml

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - cfn-test-stack
# ホストのパブリックDNSアドレスが変わってしまった。
> make ssh HOST=ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
ssh -i ~/.ssh/cfn-test-key.pem ec2-user@ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com
^Cmake: *** [Makefile:27: ssh] 割り込み
> make get-url
aws cloudformation describe-stacks --stack-name cfn-test-stack --query "Stacks[0].Outputs[0]"
{
    "OutputKey": "WebsiteURL",
    "OutputValue": "http://ec2-18-181-198-234.ap-northeast-1.compute.amazonaws.com",
    "Description": "URL for newly created LAMP stack"
}
> date
2020年  9月 25日 金曜日 23:17:44 JST
> make ssh HOST=ec2-18-181-198-234.ap-northeast-1.compute.amazonaws.com
ssh -i ~/.ssh/cfn-test-key.pem ec2-user@ec2-18-181-198-234.ap-northeast-1.compute.amazonaws.com
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-update.txt
hello from cfn-hup! content has been updated! updated again!
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-create.txt 
hello from cfn-hup!
# 気づいていなかったが、バックアップもあった。おそらく前回のcfn-hup更新時に作成されたのだろう。
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /tmp/test-cfn-update.txt.bak 
hello from cfn-hup! content has been updated!
[ec2-user@ip-172-31-42-181 ~]$ cat /home/ec2-user/manual.txt 
created in instance manually.
[ec2-user@ip-172-31-42-181 ~]$ which cowsay
/usr/bin/cowsay
[ec2-user@ip-172-31-42-181 ~]$ ログアウト]
# パブリックDNS名、パブリックIDアドレスが変わった。
# ちなみにプライベートIPアドレス、およびインスタンスIDは変わっていない。
> diff second-instance-before-update-user-data.txt third-instance-after-update-user-data.txx 
12c12
<                     "LaunchTime": "2020-09-25T11:44:41+00:00",
---
>                     "LaunchTime": "2020-09-25T14:15:40+00:00",
24,25c24,25
<                     "PublicDnsName": "ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com",
<                     "PublicIpAddress": "52.192.162.51",
---
>                     "PublicDnsName": "ec2-18-181-198-234.ap-northeast-1.compute.amazonaws.com",
>                     "PublicIpAddress": "18.181.198.234",
53,54c53,54
<                                 "PublicDnsName": "ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com",
<                                 "PublicIp": "52.192.162.51"
---
>                                 "PublicDnsName": "ec2-18-181-198-234.ap-northeast-1.compute.amazonaws.com",
>                                 "PublicIp": "18.181.198.234"
80,81c80,81
<                                         "PublicDnsName": "ec2-52-192-162-51.ap-northeast-1.compute.amazonaws.com",
<                                         "PublicIp": "52.192.162.51"
---
>                                         "PublicDnsName": "ec2-18-181-198-234.ap-northeast-1.compute.amazonaws.com",
>                                         "PublicIp": "18.181.198.234"

# cfn-get-metadataも試してみる。
[ec2-user@ip-172-31-42-181 ~]$ /opt/aws/bin/cfn-get-metadata --stack=cfn-test-stack --resource=WebServerInstance --region=ap-northeast-1
{
    "AWS::CloudFormation::Init": {
        "Configure": {
            "commands": {
                "02_create_database": {
                    "test": "$(mysql testdb -u root --password='q40stBlSEjwi' >/dev/null 2>&1 </dev/null); (( $? != 0 ))",
                    "command": "mysql -u root --password='q40stBlSEjwi' < /tmp/setup.mysql"
                },
                "01_set_mysql_root_password": {
                    "test": "$(mysql testdb -u root --password='q40stBlSEjwi' >/dev/null 2>&1 </dev/null); (( $? != 0 ))",
                    "command": "mysqladmin -u root password 'q40stBlSEjwi'"
                }
            }
        },
        "Install": {
            "files": {
(略)

# intervalの最小値はいくらか
# intervalをデフォルトの15から、1を明示的に指定した。毎分確認されるか?
> git checkotut 270ca343aa48401630c85490bc4b41e58f20dc80
> git log -p -1
diff --git a/template.yml b/template.yml
index c6e4915..d92d2d0 100644
--- a/template.yml
+++ b/template.yml
@@ -270,6 +270,9 @@ Resources:
                   - !Ref 'AWS::Region'
                   - |+
 
+                  - interval=1
+                  - |+
+
               mode: '000400'
               owner: root
               group: root

> make deploy
aws cloudformation deploy --stack-name cfn-test-stack --template-file ./template.yml
[ec2-user@ip-172-31-42-181 ~]$ sudo cat /etc/cfn/cfn-hup.conf
[main]
stack=arn:aws:cloudformation:ap-northeast-1:491846999241:stack/cfn-test-stack/76ce5280-ff24-11ea-be1e-0e7ed7880c96
region=ap-northeast-1
interval=1
# 5分ごとに確認されている。これが最短なのかもしれない。
[ec2-user@ip-172-31-42-181 ~]$ tail /var/log/cfn-hup.log 
2020-09-26 07:11:56,103 [INFO] cfn-hup processing is alive.
2020-09-26 07:16:56,682 [INFO] cfn-hup processing is alive.
2020-09-26 07:21:57,261 [INFO] cfn-hup processing is alive.
2020-09-26 07:26:57,889 [INFO] cfn-hup processing is alive.
2020-09-26 07:31:58,468 [INFO] cfn-hup processing is alive.
2020-09-26 07:36:59,046 [INFO] cfn-hup processing is alive.
2020-09-26 07:41:59,625 [INFO] cfn-hup processing is alive.
2020-09-26 07:47:00,203 [INFO] cfn-hup processing is alive.
2020-09-26 07:52:00,782 [INFO] cfn-hup processing is alive.
2020-09-26 07:57:01,361 [INFO] cfn-hup processing is alive.
[ec2-user@ip-172-31-42-181 ~]$