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脚本的执行逻辑:
- 确保镜像的
ENTRYPOINT指向你的自定义脚本(而非默认的docker-entrypoint.sh) - 可在脚本开头添加
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
相关产品推荐
相关产品推荐

