2020年7月7日火曜日

AWS CDKで立てたEC2インスタンスのTimeZoneとかいじりたかった話

EC2を立てることはできたけど、立てたインスタンスは UTCのままだし設定ファイルとかいちいちscpしてくるのはダルい。

当初UserDataでなんとかしようとしたものの、「書く量がヤバいしメンテしにくい」と悩んでいたところ見かけたのが AWS::CloudFormation::Init 
調べたら YAMLやJSONでの書き方ばかりだったけど、CDKも結局最後は CloudFormationになるはず!とツッコんでみた。

■ どんなことができるのか


使った機能だけだけど

package    : yum install できるものはここで宣言しておくのが楽っぽい。
files          : その名の通りファイルの配置。インスタンス作った直後にscpで送るのか…とか頭抱えてた課題の救世主。
command : その名の通りコマンド実行。ただし実行ユーザーはrootユーザーの模様。

サーバ作った後、最初にやりたいセットアップまでコード化できるのは色々嬉しい。(最悪 README.mdにインスタンス立てた後のコマンドつらつら書くことを覚悟してた。)

■ どんな風に書くのか

 instance.addOverride('Metadata', {
  'AWS::CloudFormation::Init': {
    'config': {
      'packages': {
        'yum': {
          'git': []
        }
      },
      'files': {
        '/home/ec2-user/.ssh/config': {
          'content': fs.readFileSync(path.resolve(__dirname, "../files/config")).toString(),
          'mode': '600',
          'owner': 'ec2-user',
          'group': 'ec2-user'
        },
      },
      'commands': {
        '01_set_timezone': {
          'command': 'timedatectl set-timezone Asia/Tokyo',
          'ignoreErrors': false
        }
      },
    }
  }
});

let userData = ec2.UserData.forLinux({ shebang: "#!/bin/bash" });
userData.addCommands(
  `/opt/aws/bin/cfn-init --region ${this.region} --stack ${this.stackName} --resource ${instance.logicalId}`
);
instance.userData = cdk.Fn.base64(userData.render());

前回 のものに追加した。
config の子要素としてそれぞれやりたいことを書いていく感じ。

filesは当然権限やファイルのowner:group なんかを設定できる。
コード化しているので配置したいファイルそのままを fs.readFileSync().toString() してしまえば、ファイルの中身をベタ書きせずに済むのも嬉しい。(【追記】 ただしこの場合、readFileSyncするfileの中身が空だと実行時にエラーになる…(´・ω・`))

commandsには「このコマンド実行の失敗を無視するか」を設定できる。
手作業でリカバーできる内容なら無視してしまってもよい?
また commandsは(今回は一つしか無いけど) key名(例だと 01_set_timezone)のソート昇順で実行するらしい。
ので今回の様にprefix的に番号でも付けておくと実行順の管理もしやすそう。

なおcommands自体の実行前に packages、filesの処理は終わってる模様。
なので「filesでshellファイルを配置し、commandsでそれを実行する」なんてこともできる。(この後さらにコマンドを追加しようと思ったら実行ユーザーの関係でどうしてもうまく行かなかったので、妥協して上記の形にしたのは内緒)

ただ最終的には UserDataから cfn-init を実行する。 オプションは無いと動いてくれないので忘れずに。

■ ついでに

これ作ってて一番アホだったミスが「コードは書き換えたが生成物に反映されていなかった」問題。「あれれ〜?変更されないぞ〜?」とかアホ面下げて調査してたらよく見たらFormationの更新がされていないというオチ。
なので必ず clean build( tcs --build --clean ) をdeploy前に実施するようにした。

…ホントこれのせいで一日潰したことに気づいた時の脱力感よ…(´・ω・`)

■ 不満点


ここまで「スゴイベンリ!」「ヤッター!」と来たものの、ここに至るまでに何度インスタンスを立てたか…
もっとこう、テストがしたいです…

ちなみに /var/log/cfn-init.log に実行ログが出るので、「なんかコマンド効いてなくない?」と思ったらここを確認すると幸せになれるかも




0 件のコメント:

コメントを投稿

AWS CDKで立てたEC2インスタンスのTimeZoneとかいじりたかった話

EC2を立てることはできたけど、立てたインスタンスは UTCのままだし設定ファイルとかいちいちscpしてくるのはダルい。 当初UserDataでなんとかしようとしたものの、「書く量がヤバいしメンテしにくい」と悩んでいたところ見かけたのが  AWS::CloudFormation:...