You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure部署PostgreSQL容器时,如何避免输出重定向生成带回车的文件名?

解决Azure容器应用中PostgreSQL证书文件名含回车符的问题

问题背景

在Azure上使用Terraform(版本:Terraform v1.12.0,运行于windows_386;azurerm v4.29.0)部署PostgreSQL容器应用时,通过init容器将环境变量中的证书内容写入server.crt、server.key、root.crt文件,文件内容正确但文件名末尾带有回车符(显示为'root.crt'$'\r'),导致PostgreSQL启用SSL时无法找到证书。手动执行以下命令可临时修复:

for f in /etc/postgresql/certs/*; do mv "$f" "$(echo "$f" | tr -d '\r')"; done

自动解决方案

方案1:在Init容器中直接修正文件名(推荐)

问题根源是Windows环境下Terraform脚本的CRLF换行符被busybox的shell解析为文件名的一部分。可在init容器的脚本中,写入证书后立即批量清理文件名:

修改Terraform中init容器的command部分:

command = [
  "sh", "-c",
  <<-SCRIPT
      mkdir -p /mnt/certs
      # 写入证书文件
      echo "$SERVER_CERT" > /mnt/certs/server.crt
      echo "$SERVER_KEY" > /mnt/certs/server.key
      echo "$ROOT_CA" > /mnt/certs/root.crt
      # 批量去除文件名中的回车符
      for f in /mnt/certs/*; do mv "$f" "$(echo "$f" | tr -d '\r')"; done
  SCRIPT
]

此方法在init容器阶段完成文件名修正,无需依赖后续容器的启动脚本。

方案2:确保自定义Entrypoint脚本生效

若希望在PostgreSQL容器启动前处理文件名,可确认自定义entrypoint脚本的执行逻辑:

  1. 确保镜像的ENTRYPOINT指向你的自定义脚本(而非默认的docker-entrypoint.sh)
  2. 可在脚本开头添加set -x输出执行日志,排查是否执行了重命名步骤

修正后的entrypoint脚本(可直接使用):

#!/bin/sh
set -x
echo "[entrypoint] Normalizing certificate filenames..."

for f in /etc/postgresql/certs/*; do
clean_name=$(echo "$f" | tr -d '\r')
if [ "$f" != "$clean_name" ]; then
    mv "$f" "$clean_name"
    echo "[entrypoint] Renamed $f to $clean_name"
fi
done

echo "[entrypoint] Fixing permissions..."
chmod 600 /etc/postgresql/certs/server.key
chmod 644 /etc/postgresql/certs/server.crt
chmod 644 /etc/postgresql/certs/root.crt
chmod 644 /etc/postgresql/postgresql.conf
chown postgres:postgres /etc/postgresql/certs/server.*
chown postgres:postgres /etc/postgresql/certs/root.crt
chown postgres:postgres /etc/postgresql/postgresql.conf


echo "[entrypoint] Starting PostgreSQL..."
exec docker-entrypoint.sh postgres -c config_file=/etc/postgresql/postgresql.conf

方案3:使用printf写入并避免换行符干扰

若坚持使用printf写入文件,可明确指定输出格式,同时保留文件名清理步骤:

command = [
  "sh", "-c",
  <<-SCRIPT
      mkdir -p /mnt/certs
      printf "%s" "$SERVER_CERT" > /mnt/certs/server.crt
      printf "%s" "$SERVER_KEY" > /mnt/certs/server.key
      printf "%s" "$ROOT_CA" > /mnt/certs/root.crt
      # 额外清理文件名
      for f in /mnt/certs/*; do mv "$f" "$(echo "$f" | tr -d '\r')"; done
  SCRIPT
]

完整Terraform容器应用定义(修改后)

resource "azurerm_container_app" "postgres" {
  name                         = "frmuat-postgres-kc"
  container_app_environment_id = azurerm_container_app_environment.env.id
  resource_group_name          = var.rg

  revision_mode                = "Single"

  identity {
    type         = "UserAssigned"
    identity_ids = [azurerm_user_assigned_identity.sitevisit.id]
  }
  registry {
    server   = "<registry_server>"
    identity = azurerm_user_assigned_identity.sitevisit.id
  }

  template {
    min_replicas = 1
    max_replicas = 1
    container {
      cpu    = 0.5
      memory = "1.0Gi"
      name   = "postgres"
      image  = "<image_name>:latest"
      
      env {
        name  = "POSTGRES_DB"
        value = var.pg_database
      }
      env {
        name  = "POSTGRES_USER"
        value = var.pg_username
      }
      env {
        name  = "POSTGRES_PASSWORD"
        secret_name = "pgpwd"
      }
      volume_mounts {
        name      = "certs"
        path = "/etc/postgresql/certs/"
      }

    }

    init_container {
        name   = "write-certs"
        image  = "busybox:latest"
        cpu    = 0.25
        memory = "0.5Gi"

        command = [
        "sh", "-c",
        <<-SCRIPT
            mkdir -p /mnt/certs
            echo "$SERVER_CERT" > /mnt/certs/server.crt
            echo "$SERVER_KEY" > /mnt/certs/server.key
            echo "$ROOT_CA" > /mnt/certs/root.crt
            # 添加文件名清理步骤
            for f in /mnt/certs/*; do mv "$f" "$(echo "$f" | tr -d '\r')"; done
        SCRIPT
        ]

        env {
          name  = "SERVER_CERT"
          secret_name = "server-cert"
        }

        env {
          name  = "SERVER_KEY"
          secret_name = "server-key"
        }

        env {
          name  = "ROOT_CA"
          secret_name = "server-root-ca"
        }


        volume_mounts {
          name = "certs"
          path = "/mnt/certs"
        }
    }
    volume {
      name         = "certs"
      storage_type = "EmptyDir"
    } 

  }
  ingress {
    external_enabled = false
    target_port      = 5432
    exposed_port = 5432
    transport = "tcp"
    traffic_weight {
      latest_revision = true
      percentage      = 100
    }
  }

  secret{
    name = "server-cert"
    value = var.server_cert
  }
  secret{
    name = "server-key"
    value = var.server_key
  }
  secret{
    name = "server-root-ca"
    value = var.server_cert_root_ca
  }
  secret{
    name = "pgpwd"
    value = var.pgpwd
  }
}

内容的提问来源于stack exchange,提问作者André Andrade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:35:55