it-swarm.com.de

Wie kann ich Cloud-Init-Startskripts bei jedem Start meiner EC2-Instanz ausführen lassen?

Ich habe eine EC2-Instanz, auf der eine AMI ausgeführt wird, die auf der Amazon Linux AMI basiert. Wie alle diese AMIs unterstützt es das System cloud-init zum Ausführen von Startskripts, die auf den in jede Instanz übergebenen Benutzerdaten basieren. In diesem speziellen Fall handelt es sich bei meiner Benutzerdateneingabe um eine Include-Datei, die mehrere andere Startscripts enthält:

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

Beim ersten Start meiner Instanz wird das Cloud-Init-Startskript ordnungsgemäß ausgeführt. Wenn ich jedoch einen sanften Neustart der Instanz durchführe (beispielsweise durch Ausführen von Sudo shutdown -r now), wird die Instanz wieder ohne ausgeführt, ohne dass das Startskript das zweite Mal ausgeführt wird. Wenn ich in die Systemprotokolle gehe, kann ich Folgendes sehen:

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

Das ist nicht das, was ich will - ich kann die Nützlichkeit von Startskripten sehen, die nur einmal pro Instanzlebensdauer ausgeführt werden. In meinem Fall sollten diese jedoch bei jedem Start der Instanz wie normale Startskripts ausgeführt werden.

Mir ist klar, dass eine Möglichkeit besteht, meine Skripte nach dem ersten Start manuell in rc.local einzufügen. Dies erscheint jedoch lästig, da sich die Umgebungen von cloud-init und rc.d subtil unterscheiden und ich jetzt Skripts beim ersten Start und allen nachfolgenden Starts separat debuggen müsste.

Weiß jemand, wie ich cloud-init anweisen kann, meine Skripts immer auszuführen? Das klingt sicherlich nach etwas, was die Designer von cloud-init in Betracht gezogen hätten.

47
Adrian Petrescu

In 11.10, 12.04 und später können Sie dies erreichen, indem Sie "scripts-user" immer ".." ausführen. In /etc/cloud/cloud.cfg sehen Sie etwa Folgendes:

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

Dies kann nach dem Start geändert werden, oder Cloud-Konfigurationsdaten, die diese Zeilengruppe überschreiben, können über Benutzerdaten eingefügt werden. Dh in Benutzerdaten können Sie Folgendes angeben:

#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

Das kann auch "#inclosed" sein, wie Sie es in Ihrer Beschreibung getan haben ..__ Leider können Sie die "cloud_final_modules" momentan nicht ändern, sondern nur überschreiben. Ich hoffe, ich füge die Möglichkeit hinzu, Konfigurationsabschnitte irgendwann zu ändern.

Weitere Informationen hierzu finden Sie im Dokument cloud-config unter http://Bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/view/head:/doc/. Beispiele/cloud-config.txt

Alternativ können Sie Dateien in/var/lib/cloud/scripts/per-boot ablegen und sie werden vom Pfad 'scripts-per-boot' ausgeführt.

49
smoser

Bearbeiten Sie in /etc/init.d/cloud-init-user-scripts diese Zeile:

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

zu

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

Viel Glück !

19
EvanG

Eine Möglichkeit, wenn auch etwas hackhaft, besteht darin, die Sperrdatei zu löschen, die von cloud-init verwendet wird, um festzustellen, ob das Benutzerskript bereits ausgeführt wurde. In meinem Fall (Amazon Linux AMI) befindet sich diese Sperrdatei in /var/lib/cloud/sem/ und heißt user-scripts.i-7f3f1d11 (der Hash-Teil am Ende ändert sich bei jedem Start). Daher wird das folgende Benutzerdatenskript, das am Ende der Include-Datei hinzugefügt wurde, den Trick ausführen:

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

Ich bin nicht sicher, ob dies negative Auswirkungen auf alles andere hat, aber es hat sich in meinen Experimenten bewährt.

7
Adrian Petrescu

cloud-init unterstützt dies nun nativ, siehe Befehlsbeschreibungen für runcmd vs bootcmd in der Dokumentation ( http://cloudinit.readthedocs.io/de/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 ]

beachten Sie auch das Befehlsbeispiel "cloud-init-per" in bootcmd. Von seiner Hilfe:

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
6
Erich Eichinger

Ich hatte fast zwei Tage lang Probleme mit diesem Thema, versuchte alle Lösungen, die ich finden konnte, und schließlich kombinierte ich verschiedene Ansätze und kam zu folgenden Punkten:

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}

Dies ist das Setup für DynamoDb-Regionenübergreifende Replikationsprozesse.

0
Enigo

Ein anderer Ansatz ist die Verwendung von #cloud-boothook in Ihrem Benutzerdatenskript. Aus dem docs :

Wolkenstandhaken

  • Beginnt mit # cloud-boothook oder Content-Type: text/cloud-boothook.
  • Bei diesem Inhalt handelt es sich um Standbuchdaten. Es wird in einer Datei unter/var/lib/cloud gespeichert und sofort ausgeführt.
  • Dies ist der früheste verfügbare "Haken". Es ist kein Mechanismus vorgesehen, um es nur einmal auszuführen. Der Kabinenhaken muss sich selbst darum kümmern. Sie wird mit der Instanz-ID in der Umgebungsvariablen INSTANCE_ID versehen. Verwenden Sie diese Variable, um einmal pro Instanz einen Satz von Standbuchdaten bereitzustellen.
0
BrianV