不能直接用 file provisioner 上传 xml 文件——因其仅支持纯文本写入,不处理换行、缩进、xml 实体转义或 utf-8 编码,易致 java 应用解析失败。

不能直接用 file provisioner 上传 XML 文件到远程主机并保证内容被正确解析 —— 因为 file provisioner 只支持纯文本写入,不处理换行、缩进、XML 实体转义或编码问题,容易导致目标服务(如 Tomcat、Camel、Spring Boot)启动失败。
为什么 file provisioner 传 XML 常出错
XML 对空白符、换行、UTF-8 BOM、引号转义敏感。Terraform 的 file provisioner 默认以平台默认编码写入,且会把模板中多余的空行/缩进原样保留,而很多 Java 应用在解析时会因格式异常抛 SAXParseException 或静默跳过配置。
-
fileprovisioner 不校验 XML 语法合法性,传了错误内容也不会报错 - 变量插值(如
${var.app_name})若含特殊字符(&,, <code>"),未手动转义就会破坏 XML 结构 - 远程路径权限未设置,导致应用进程无法读取(如
/opt/app/conf/app.xml需要tomcat:tomcat所有者)
推荐做法:用 remote-exec + cat 写入
绕过 file provisioner 的编码和转义限制,改用 shell here-document 方式,在远程主机上生成 XML,由 shell 层面控制换行与引号行为,更可控。
provisioner "remote-exec" {
inline = [
"mkdir -p /opt/myapp/conf",
"cat > /opt/myapp/conf/config.xml << 'EOF'",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<config>",
" <app-name>${var.app_name}</app-name>",
" <timeout>${var.timeout_sec}</timeout>",
" <endpoint><![CDATA[${var.api_endpoint}]]></endpoint>",
"</config>",
"EOF",
"chown appuser:appgroup /opt/myapp/conf/config.xml",
"chmod 644 /opt/myapp/conf/config.xml"
]
}- 使用
(单引号包裹分界符)可防止本地 Terraform 插值被提前展开,确保 XML 中的 <code>$、`等字符原样写入 -
包裹动态值(如 URL),避免手动转义&、 - 必须显式指定
encoding="UTF-8",否则某些 JVM 默认用 ISO-8859-1 解析,中文会乱码
如果必须用 file provisioner:先本地验证再上传
仅限简单 XML(无 CDATA、无复杂嵌套、无特殊字符)。需配合 templatefile() 函数做预处理。
resource "null_resource" "upload_xml" {
triggers = {
xml_content = templatefile("${path.module}/templates/config.xml.tpl", {
app_name = var.app_name
timeout_sec = var.timeout_sec
api_endpoint = replace(var.api_endpoint, "/&/", "/&/") # 手动转义
})
}
<p>provisioner "file" {
content = templatefile("${path.module}/templates/config.xml.tpl", {
app_name = var.app_name
timeout_sec = var.timeout_sec
api_endpoint = replace(var.api_endpoint, "/&/", "/&/")
})
destination = "/opt/myapp/conf/config.xml"
}
}- 模板文件
config.xml.tpl必须以 UTF-8 无 BOM 编码保存 - 所有可能含
&,, <code>>,"的变量,都得用replace()或format()显式转义 - 上传后建议加一个
remote-execprovisioner 调用xmllint --noout config.xml校验语法,失败则中断
真正麻烦的不是“怎么传”,而是“传完能不能被正确加载”。XML 文件权限、SELinux 上下文、JVM 文件编码参数(-Dfile.encoding=UTF-8)、甚至远程主机 locale 设置,都会让看似成功的上传变成运行时故障。别只盯着 Terraform 是否执行成功。










