web-dev-qa-db-fra.com

Comment faire en sorte que les scripts de démarrage cloud-init soient exécutés à chaque démarrage de mon instance EC2?

J'ai une instance EC2 exécutant une AMI basée sur l'AMI Amazon Linux. Comme toutes ces AMI, il prend en charge le système cloud-init pour l'exécution de scripts de démarrage basés sur les données utilisateur transmises à chaque instance. Dans ce cas particulier, mon entrée de données utilisateur se trouve être un fichier Include qui contient plusieurs autres scripts de démarrage:

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

Lors du premier démarrage de mon instance, le script de démarrage de cloud-init s'exécute correctement. Cependant, si je procède à un redémarrage à chaud de l'instance (en exécutant Sudo shutdown -r now, par exemple), l'instance se rétablit sans en exécutant le script de démarrage la deuxième fois. Si je vais dans les journaux du système, je peux voir:

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

Ce n'est pas ce que je veux - je peux voir l'utilité d'avoir des scripts de démarrage qui ne s'exécutent qu'une fois par durée de vie d'instance, mais dans mon cas, ils devraient être exécutés à chaque démarrage de l'instance, comme des scripts de démarrage normaux.

Je me rends compte qu'une solution possible consiste à insérer manuellement mes scripts dans rc.local après la première exécution. Cela semble toutefois fastidieux, car les environnements cloud-init et rc.d sont légèrement différents et que je devrais maintenant déboguer les scripts lors du premier lancement et de tous les lancements ultérieurs séparément.

Est-ce que quelqu'un sait comment je peux dire à cloud-init de toujours exécuter mes scripts? Cela ressemble certainement à quelque chose que les concepteurs de cloud-init auraient envisagé.

47
Adrian Petrescu

Dans les versions 11.10, 12.04 et ultérieures, vous pouvez y parvenir en faisant en sorte que "l'utilisateur de scripts" exécute "toujours" .. Dans /etc/cloud/cloud.cfg, vous verrez quelque chose comme:

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

Cela peut être modifié après le démarrage ou des données cloud-config remplaçant cette strophe peuvent être insérées via les données utilisateur. En d'autres termes, dans les données utilisateur, vous pouvez fournir:

#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

Cela peut aussi être '# inclus' comme vous l'avez fait dans votre description . Malheureusement, pour l'instant, vous ne pouvez pas modifier le 'cloud_final_modules', mais seulement le remplacer. J'espère ajouter la possibilité de modifier les sections de configuration à un moment donné.

Il y a un peu plus d'informations à ce sujet dans le doc cloud-config à l'adresse http://Bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/view/head:/doc /examples/cloud-config.txt

Alternativement, vous pouvez placer des fichiers dans/var/lib/cloud/scripts/per-boot, et ils seront exécutés par le chemin 'scripts-per-boot'.

49
smoser

Dans /etc/init.d/cloud-init-user-scripts, éditez cette ligne:

/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

Bonne chance !

19
EvanG

Une possibilité, bien que quelque peu furtive, consiste à supprimer le fichier de verrouillage utilisé par cloud-init pour déterminer si le script utilisateur a déjà été exécuté. Dans mon cas (Amazon Linux AMI), ce fichier de verrouillage est situé dans /var/lib/cloud/sem/ et est nommé user-scripts.i-7f3f1d11 (la partie de hachage à la fin change à chaque démarrage). Par conséquent, le script de données utilisateur suivant ajouté à la fin du fichier Include fera l'affaire:

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

Je ne suis pas sûr que cela aura des effets néfastes sur autre chose, mais cela a fonctionné dans mes expériences.

7
Adrian Petrescu

cloud-init le supporte maintenant de manière native, voir les descriptions des commandes runcmd vs bootcmd dans la documentation ( 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 ]

notez également l'exemple de commande "cloud-init-per" dans bootcmd. De son aide:

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

J'ai lutté avec ce problème pendant près de deux jours, j'ai essayé toutes les solutions que je pouvais trouver et finalement, combinant plusieurs approches, j'ai obtenu les éléments suivants:

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}

Il s'agit de la configuration du processus de réplication entre régions DynamoDb.

0
Enigo