runcmd用户数据执行异常:sendmail规则未写入hosts.allow求助
Let’s figure out why your cloud-init runcmd isn’t adding sendmail: ALL to /etc/hosts.allow—especially since it works when you run the steps manually. Here are the most probable culprits and fixes:
1. Quote Parsing Conflicts in sh -c
When you wrap the echo command in double quotes inside sh -c, cloud-init’s YAML parser might be mangling the quotes before the shell gets to execute the command. This is a common gotcha with nested quotes in runcmd arrays.
Fix: Adjust the Quoting
Rewrite the first runcmd entry to use single quotes for the inner echo command (escaped properly for YAML):
[ sh, -c, 'echo '\''sendmail: ALL'\'' >> /etc/hosts.allow' ]
Alternatively, swap the quote types to avoid nesting issues:
[ sh, -c, "echo 'sendmail: ALL' >> /etc/hosts.allow" ]
2. Cloud-init Execution Timing
Cloud-init runs modules in a strict order. If runcmd fires before the filesystem is fully mounted or the /etc/hosts.allow file is available (rare, but possible), the append will fail silently.
Fix: Add a Check & Verify Logs
Modify the command to ensure the file exists before appending:
[ sh, -c, 'if [ -f /etc/hosts.allow ]; then echo "sendmail: ALL" >> /etc/hosts.allow; else echo "/etc/hosts.allow missing" >> /var/log/cloud-init-debug.log; fi' ]
Then check cloud-init’s logs for clues:
grep -E "hosts.allow|runcmd" /var/log/cloud-init-output.log
3. Unexpected File Restrictions
Even though runcmd runs as root, /etc/hosts.allow might have an immutable flag set (via chattr) or restrictive ACLs blocking writes.
Fix: Clear Immutable Flags First
Add a quick pre-step to remove the immutable flag if it exists:
[ sh, -c, 'chattr -i /etc/hosts.allow 2>/dev/null; echo "sendmail: ALL" >> /etc/hosts.allow' ]
4. Better Alternative: Use write_files Module
Cloud-init’s write_files module is designed for file modifications and is more reliable than runcmd for appending content. It handles file locking and existence checks natively.
Updated Configuration
Replace your first runcmd entry with this write_files block:
write_files: - append: true path: /etc/hosts.allow content: | sendmail: ALL runcmd: - [ sh, -c, 'systemctl restart sendmail' ] - [ sh, -c, 'echo "Subject: Instance Deployed" | sendmail user@example.com' ]
Note: I fixed the email address in your sendmail command—there was an extra leading / that would have caused delivery failures.
Debugging Steps to Confirm
After deploying the instance:
- Check if the line was added:
grep "sendmail: ALL" /etc/hosts.allow - Review cloud-init logs for errors:
cat /var/log/cloud-init.log | grep -i error
内容的提问来源于stack exchange,提问作者Aru Dubey

