Как запускать сценарии запуска cloud-init каждый раз, когда загружается экземпляр EC2?

У меня есть экземпляр EC2 с AMI, основанный на AMI Amazon Linux. Как и все подобные AMI, он поддерживает систему cloud-init для запуска сценариев запуска на основе данных пользователя, передаваемых в каждый экземпляр. В этом конкретном случае ввод данных User Data является файлом Include, который содержит несколько других сценариев запуска:

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

В первый раз, когда я загружаю свой экземпляр, сценарий запуска cloud-init запускается правильно. Однако, если я выполняю мягкую перезагрузку экземпляра (например, путем запуска sudo shutdown -r now , например), экземпляр возвращается без запуска сценария запуска во второй раз. Если я войду в системные журналы, я вижу:

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

Это не то, что я хочу – я вижу, что у вас есть сценарии запуска, которые запускаются только один раз на один экземпляр, но в моем случае они должны запускаться каждый раз, когда запускает экземпляр, например, обычные сценарии запуска.

Я понимаю, что одним из возможных решений является ручное включение моих скриптов в rc.local после запуска в первый раз. Это кажется обременительным, однако, поскольку среды cloud-init и rc.d тонко отличаются, и теперь мне придется отлаживать скрипты при первом запуске и все последующие запуска отдельно.

Кто-нибудь знает, как я могу сказать, что cloud-init всегда запускает мои скрипты? Это, безусловно, звучит, как подумали дизайнеры cloud-init.

В 11.10, 12.04 и более поздних версиях вы можете добиться этого, сделав «скрипт-пользователь» бегом «всегда». В /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_final_modules: - rightscale_userdata - scripts-per-once - scripts-per-boot - scripts-per-instance - [scripts-user, always] - keys-to-console - phone-home - final-message 

Это также может быть «включено», как вы это делали в своем описании. К сожалению, прямо сейчас вы не можете изменить «cloud_final_modules», но только переопределите его. Я надеюсь добавить возможность изменения разделов конфигурации в какой-то момент.

Более подробная информация об этом содержится в документе cloud-config на http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/view/head:/doc/examples/cloud-config .текст

Кроме того, вы можете поместить файлы в / var / lib / cloud / scripts / per-boot, и они будут запускаться по пути «scripts-per-boot».

В /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 

Удачи !

Одна из возможностей, хотя и довольно хакерская, заключается в удалении файла блокировки, который использует cloud-init для определения того, уже запущен ли пользовательский скрипт. В моем случае (Amazon Linux AMI) этот файл блокировки находится в /var/lib/cloud/sem/ и называется user-scripts.i-7f3f1d11 (hash-часть в конце меняет каждую загрузку). Таким образом, следующий скрипт пользовательских данных, добавленный в конец файла Include, сделает трюк:

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

Я не уверен, что это будет иметь какие-либо негативные последствия для чего-либо еще, но он работал в моих экспериментах.

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 ] 

также обратите внимание на пример команды «cloud-init-per» в bootcmd. Из его справки:

 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 

Я боролся с этим вопросом почти два дня, пробовал все решения, которые мог найти, и, наконец, объединив несколько подходов, пришел со следующим:

 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_west: 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.

Давайте будем гением компьютера.