2011-06-25 251 views
41

我有一個基於Amazon Linux AMI運行AMI的EC2實例。像所有這樣的AMI一樣,它支持cloud-init系統根據傳遞到每個實例的用戶數據來運行啓動腳本。在這種特殊情況下,我的用戶數據輸入恰好是一個包含文件來源的其它幾個啓動腳本:如何在每次啓動EC2實例時運行cloud-init啓動腳本?

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

我第一次開機我的實例中,雲初始化啓動腳本正確運行。但是,如果我對該實例執行軟重啓(例如,通過運行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的設計師會考慮的事情。

回答

42

在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_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.txt

更多的信息,或者,你可以把文件在/ var/lib中/雲/腳本/每引導,他們會按'腳本每啓動'路徑運行。

+1

>我希望增加修改配置部分的功能。 現在是否已添加此功能?我發現最新的cloud-init中有一個「合併」功能,但我不知道如何使用它來只改變'scripts-user'這一行。無論我通過的選項如何,它都會覆蓋整個列表。 – Meta

+2

下面是一個在線修改的代碼:'sed -i's/scripts-user $/\ [scripts-user,always \] /'/ etc/cloud/cloud.cfg' – wjordan

+0

將文件放入'/ var/lib/cloud/scripts/per-boot'似乎更容易,我可以使用它來設置[auto ec2 shutdown](http://stackoverflow.com/a/38186787/4058484)。 – hyip

7

一種可能性,儘管有點冒失,但是要刪除cloud-init用來確定用戶腳本是否已經運行的鎖定文件。在我的情況下(亞馬遜Linux AMI),這個鎖文件位於/var/lib/cloud/sem/中,並且被命名爲user-scripts.i-7f3f1d11(末尾的散列部分每次啓動都會改變)。因此,以下用戶數據腳本添加到包含文件的末尾將這樣的伎倆:

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

我不知道這是否會對別的任何不良影響,但它已經在我的工作實驗。

+1

「哈希部分」似乎是一個亞馬遜機器ID¿是不是? – theist

+1

它看起來像一個AWS實例ID,在這種情況下,它會隨着每個實例的啓動而改變,但在同一個實例的停止和重新啓動期間保持不變。 – froggythefrog

18

/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 

祝你好運!

+4

適用於亞馬遜Linux AMI ... – rbawaskar

4

雲初始化支持此現在本身,參見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 
+0

更新回答來自官方文檔的相應引文,並鏈接到原始文檔,僅供參考 –

+1

bootcmd部分在未完全引導並且可能無法正常工作的系統上執行。 – Nico

0

我這個問題掙扎了近兩天,嘗試了所有的解決方案,我能找到,最後,結合幾種方法,具有以下傳來:

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跨區域複製過程的設置。