web-dev-qa-db-ja.com

EC2インスタンスが起動するたびにcloud-init起動スクリプトを実行するにはどうすればよいですか?

Amazon Linux AMIに基づいてAMIを実行しているEC2インスタンスがあります。このようなすべてのAMIと同様に、すべてのインスタンスに渡されるユーザーデータに基づいて起動スクリプトを実行するための cloud-init システムをサポートしています。この特定の場合、ユーザーデータ入力は、他のいくつかの起動スクリプトをソースとするインクルードファイルであることがあります。

#include
http://s3.amazonaws.com/path/to/script/1
http://s3.amazonaws.com/path/to/script/2

インスタンスを初めて起動すると、cloud-init起動スクリプトが正しく実行されます。ただし、インスタンスのソフトリブートを実行すると(たとえば、Sudo shutdown -r nowを実行して)、インスタンスが復旧しますwithout 2回目の起動スクリプトの実行。システムログにアクセスすると、次のことがわかります。

Running cloud-init user-scripts
user-scripts already ran once-per-instance
[  OK  ]

これは私が望んでいるものではありません-インスタンスの有効期間ごとに1回だけ実行される起動スクリプトを持つユーティリティを見ることができますが、私の場合は、通常の起動スクリプトのように、インスタンスが起動するたびに実行する必要があります.

可能な解決策の1つは、最初に実行した後、スクリプトを手動でrc.localに挿入することです。ただし、cloud-init環境とrc.d環境は微妙に異なり、最初の起動時と以降のすべての起動時にスクリプトを個別にデバッグする必要があるため、これは面倒です。

Cloud-initに常にスクリプトを実行するように指示する方法を知っている人はいますか?これは確かに、cloud-initの設計者が検討したもののように聞こえます。

50
Adrian Petrescu

11.10、12.04以降では、「scripts-user」を「always」で実行することでこれを実現できます。 /etc/cloud/cloud.cfgには次のようなものが表示されます。

cloud_final_modules:
 - rightscale_userdata
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - keys-to-console
 - phone-home
 - final-message

これはブート後に変更できます。または、このスタンザをオーバーライドするcloud-configデータをユーザーデータ経由で挿入できます。つまり、ユーザーデータでは次の情報を提供できます。

#cloud-config
cloud_final_modules:
 - rightscale_userdata
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - [scripts-user, always]
 - keys-to-console
 - phone-home
 - final-message

説明で行ったように、「#included」にすることもできます。残念ながら、現時点では、「cloud_final_modules」を変更することはできず、オーバーライドするだけです。ある時点で構成セクションを変更する機能を追加したいと考えています。

http://Bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/view/head:/doc/examplesのcloud-configドキュメントにこれに関するもう少しの情報があります。 /cloud-config.txt

または、ファイルを/ var/lib/cloud/scripts/per-bootに配置すると、「scripts-per-boot」パスで実行されます。

55
smoser

/etc/init.d/cloud-init-user-scripts、次の行を編集します。

/usr/bin/cloud-init-run-module once-per-instance user-scripts execute run-parts ${SCRIPT_DIR} >/dev/null && success || failure

 /usr/bin/cloud-init-run-module always user-scripts execute run-parts ${SCRIPT_DIR} >/dev/null && success || failure

がんばろう !

19
EvanG

cloud-initはこれをネイティブにサポートします。ドキュメントのruncmd vs bootcmdコマンドの説明を参照してください( http://cloudinit.readthedocs.io/en/latest/topics/examples.html#run-commands-on-first- boot ):

「runcmd」:

#cloud-config

# run commands
# default: none
# runcmd contains a list of either lists or a string
# each item will be executed in order at rc.local like level with
# output to the console
# - runcmd only runs during the first boot
# - if the item is a list, the items will be properly executed as if
#   passed to execve(3) (with the first arg as the command).
# - if the item is a string, it will be simply written to the file and
#   will be interpreted by 'sh'
#
# Note, that the list has to be proper yaml, so you have to quote
# any characters yaml would eat (':' can be problematic)
runcmd:
 - [ ls, -l, / ]
 - [ sh, -xc, "echo $(date) ': hello world!'" ]
 - [ sh, -c, echo "=========hello world'=========" ]
 - ls -l /root
 - [ wget, "http://slashdot.org", -O, /tmp/index.html ]

「bootcmd」:

#cloud-config

# boot commands
# default: none
# this is very similar to runcmd, but commands run very early
# in the boot process, only slightly after a 'boothook' would run.
# bootcmd should really only be used for things that could not be
# done later in the boot process.  bootcmd is very much like
# boothook, but possibly with more friendly.
# - bootcmd will run on every boot
# - the INSTANCE_ID variable will be set to the current instance id.
# - you can use 'cloud-init-per' command to help only run once
bootcmd:
 - echo 192.168.1.130 us.archive.ubuntu.com >> /etc/hosts
 - [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ]

bootcmdの「cloud-init-per」コマンドの例にも注意してください。それの助けから:

Usage: cloud-init-per frequency name cmd [ arg1 [ arg2 [ ... ] ]
   run cmd with arguments provided.

   This utility can make it easier to use boothooks or bootcmd
   on a per "once" or "always" basis.

   If frequency is:
      * once: run only once (do not re-run for new instance-id)
      * instance: run only the first boot for a given instance-id
      * always: run every boot
8
Erich Eichinger

1つの可能性は、多少ハッキングですが、ユーザースクリプトが既に実行されているかどうかを判断するためにcloud-initが使用するロックファイルを削除することです。私の場合(Amazon Linux AMI)、このロックファイルは/var/lib/cloud/sem/にあり、user-scripts.i-7f3f1d11という名前です(最後のハッシュ部分はブートごとに変わります)。したがって、インクルードファイルの最後に追加された次のユーザーデータスクリプトがトリックを実行します。

#!/bin/sh
rm /var/lib/cloud/sem/user-scripts.*

これが他の何かに悪影響を与えるかどうかはわかりませんが、私の実験ではうまくいきました。

7
Adrian Petrescu

私はこの問題にほぼ2日間苦労し、見つけることができるすべての解決策を試し、最終的に、いくつかのアプローチを組み合わせて、次のようになりました。

MyResource:
  Type: AWS::EC2::Instance
  Metadata:
    AWS::CloudFormation::Init:
      configSets:
        setup_process:
          - "prepare"
          - "run_for_instance"
      prepare:
        commands:
          01_apt_update:
            command: "apt-get update"
          02_clone_project:
            command: "mkdir -p /replication && rm -rf /replication/* && git clone https://github.com/awslabs/dynamodb-cross-region-library.git /replication/dynamodb-cross-region-library/"
          03_build_project:
            command: "mvn install -DskipTests=true"
            cwd: "/replication/dynamodb-cross-region-library"
          04_prepare_for_apac:
            command: "mkdir -p /replication/replication-west && rm -rf /replication/replication-west/* && cp /replication/dynamodb-cross-region-library/target/dynamodb-cross-region-replication-1.2.1.jar /replication/replication-west/replication-runner.jar"
      run_for_instance:
        commands:
          01_run:
            command: !Sub "Java -jar replication-runner.jar --sourceRegion us-east-1 --sourceTable ${TableName} --destinationRegion ap-southeast-1 --destinationTable ${TableName} --taskName -us-ap >/dev/null 2>&1 &"
            cwd: "/replication/replication-west"
  Properties:
    UserData:
      Fn::Base64:
        !Sub |
          #cloud-config
          cloud_final_modules:
           - [scripts-user, always]
          runcmd:
           - /usr/local/bin/cfn-init -v -c setup_process --stack ${AWS::StackName} --resource MyResource --region ${AWS::Region}
           - /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MyResource --region ${AWS::Region}

これは、DynamoDbクロスリージョンレプリケーションプロセスのセットアップです。

1
Enigo

別のアプローチは、#cloud-boothookユーザーデータスクリプト内。 docs から:

クラウドブートフック

  • #cloud-boothookまたはContent-Type:text/cloud-boothookで始まります。
  • このコンテンツはブートフックデータです。/var/lib/cloudの下のファイルに保存され、すぐに実行されます。
  • これは利用可能な最も早い「フック」です。 一度だけ実行するためのメカニズムは提供されていません。ブートフックはこれ自体を処理する必要があります。環境変数INSTANCE_IDでインスタンスIDが提供されます。この変数を使用して、インスタンスごとに1回のブートフックデータのセットを提供します。
0
BrianV