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

如何在Rails的database.yml中获取AWS CodePipeline环境变量?

问题描述

我已经在AWS CodePipeline的构建阶段添加了环境变量,当执行RUN bundle exec rake db:migrate RAILS_ENV=production命令时,程序会读取database.yml文件查找生产环境数据库配置。我希望让database.yml能够访问AWS CodePipeline构建阶段添加的环境变量,该如何实现?也欢迎提供替代方案。


解决方案

方法1:构建Docker镜像时直接传递环境变量

在CodeBuild的build阶段执行docker build时,通过--env参数将CodePipeline的环境变量注入镜像构建过程,这样Dockerfile中RUN bundle exec rake db:migrate命令就能读取到这些变量,database.yml里的ERB语法也能正确解析。

修改buildspec.yml的build阶段命令:

build:
  commands:
    - echo Building docker image
    - docker build 
        --env DATABASE_HOST=$DATABASE_HOST
        --env DATABASE_NAME=$DATABASE_NAME
        --env DATABASE_USER=$DATABASE_USER
        --env DATABASE_PASSWORD=$DATABASE_PASSWORD
        --env DATABASE_PORT=$DATABASE_PORT
        -t jsm-rails .
    - docker tag jsm-rails <你的ECR仓库URI>:latest

方法2:用Docker ARG+ENV传递变量

在Dockerfile中定义ARG参数,构建时传入变量后转换为ENV,确保后续命令可访问。

修改Dockerfile:

# 定义ARG参数
ARG DATABASE_HOST
ARG DATABASE_NAME
ARG DATABASE_USER
ARG DATABASE_PASSWORD
ARG DATABASE_PORT

# 转换为ENV变量
ENV DATABASE_HOST=$DATABASE_HOST
ENV DATABASE_NAME=$DATABASE_NAME
ENV DATABASE_USER=$DATABASE_USER
ENV DATABASE_PASSWORD=$DATABASE_PASSWORD
ENV DATABASE_PORT=$DATABASE_PORT

# 保留原迁移命令
RUN bundle exec rake db:migrate RAILS_ENV=production

修改buildspec.yml的docker build命令:

build:
  commands:
    - echo Building docker image
    - docker build 
        --build-arg DATABASE_HOST=$DATABASE_HOST
        --build-arg DATABASE_NAME=$DATABASE_NAME
        --build-arg DATABASE_USER=$DATABASE_USER
        --build-arg DATABASE_PASSWORD=$DATABASE_PASSWORD
        --build-arg DATABASE_PORT=$DATABASE_PORT
        -t jsm-rails .
    - docker tag jsm-rails <你的ECR仓库URI>:latest

替代方案1:将数据库迁移移至容器启动阶段

把RUN bundle exec rake db:migrate从Dockerfile中移除,放到启动脚本中,迁移将在容器启动时执行,此时可直接使用运行时环境变量(如ECS/EKS任务定义注入或AWS Secrets Manager获取)。

修改Dockerfile:

# 移除原迁移命令
# RUN bundle exec rake db:migrate RAILS_ENV=production

# 添加启动脚本配置
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

# 保留原启动命令
CMD ["bundle", "exec", "rails", "server", "-e", "production"]

创建entrypoint.sh脚本:

#!/bin/sh
set -e

# 执行数据库迁移
bundle exec rake db:migrate RAILS_ENV=production

# 启动Rails服务器
exec "$@"

该方案优势:构建镜像时无需数据库凭据(更安全),迁移操作与运行环境绑定,避免构建时依赖外部数据库可用性。

替代方案2:用AWS Secrets Manager管理凭据

将数据库用户名、密码等敏感信息存储在AWS Secrets Manager中,在构建或运行时通过AWS CLI获取,避免明文传递环境变量。

修改buildspec.yml的pre_build阶段:

pre_build:
  commands:
    - SECRETS=$(aws secretsmanager get-secret-value --secret-id <你的数据库凭据Secret ARN> --query SecretString --output text)
    - export DATABASE_USER=$(echo $SECRETS | jq -r '.DATABASE_USER')
    - export DATABASE_PASSWORD=$(echo $SECRETS | jq -r '.DATABASE_PASSWORD')
    - export DATABASE_NAME=$(echo $SECRETS | jq -r '.DATABASE_NAME')
    - export DATABASE_HOST=$(echo $SECRETS | jq -r '.DATABASE_HOST')
    - export DATABASE_PORT=$(echo $SECRETS | jq -r '.DATABASE_PORT')
    # 保留原有其他命令

需确保CodeBuild服务角色拥有访问Secrets Manager的权限。


原始配置文件

database.yml

default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: Backend_development

test:
  <<: *default
  database: JSMA_Backend_test

production:
  <<: *default
  username: <%= ENV['DATABASE_USER'] %>
  database: <%= ENV['DATABASE_NAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  host: <%= ENV['DATABASE_HOST'] %>
  port: <%= ENV['DATABASE_PORT'] %>

Dockerfile

# Use an official Ruby runtime as a parent image
FROM ruby:3.1-alpine

# Set the working directory in the container to /app
WORKDIR /app

# Install build dependencies
RUN apk update && apk add --virtual build-dependencies build-base

# Install imagemagick
RUN apk add imagemagick

# Install the PostgreSQL client library
RUN apk add postgresql-dev
# Copy the Gemfile and Gemfile.lock from your host machine to the container
COPY Gemfile Gemfile.lock ./

# Install RubyGems and Bundler
RUN gem update --system && gem install bundler

# Install the RubyGems specified in the Gemfile
RUN bundle install --without development test


# Copy the rest of your application code from your host machine to the container
COPY . .

RUN bundle exec rake db:migrate RAILS_ENV=production

# Start the Rails server
CMD ["bundle", "exec", "rails", "server", "-e", "production"]
# CMD ["bundle", "exec", "rails", "server"]

docker-compose.yml

version: '3'
services:
  db:
    image: postgres:13
    environment:
      POSTGRES_USER: <%= ENV['DATABASE_USER'] %>
      POSTGRES_PASSWORD: <%= ENV['DATABASE_PASSWORD'] %>
      POSTGRES_DB: <%= ENV['DATABASE_NAME'] %>
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db

buildspec.yml

version: 0.2

phases:
  pre_build:
    commands:
      - export DATABASE_HOST=$DATABASE_HOST
      - export DATABASE_NAME=$DATABASE_NAME
      - export DATABASE_USER=$DATABASE_USER
      - export DATABASE_PASSWORD=$DATABASE_PASSWORD
      - export DATABASE_PORT=$DATABASE_PORT
      - echo $DATABASE_HOST
      - echo AWS ECR login
      - $(aws ecr get-login --no-include-email --region ap-south-1)
      - REPO_URI=*** repo here
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      - echo Building docker image
      - docker build -t jsm-rails .
      - docker tag //repo****:latest
  post_build:
    commands:
      - echo build successful!
      - echo pushing image to ecr...
      - docker push //repo url here *** rails:latest
      - echo pushed image!

内容的提问来源于stack exchange,提问作者Krenil Sapariya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:04:59