[2021更新]:现在可以使用AWS Fargate以交互模式运行命令!
要运行的命令是:
aws ecs execute-command \
--cluster cluster-name \
--task task-id \
--container container-name \ # optional
--interactive \
--command "rails c"
故障排除:
查看AWS文档以获取IAM权限: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-exec.html#ecs-exec-prerequisites
经过尝试很多方法,我找到了一种打开指向生产环境的Rails控制台的方法,所以我在这里发布,以防有人遇到相同的问题
总结一下,我创建了一个部署在Fargate上的Rails应用程序,并连接到RDS postgres数据库
我的做法是创建一个VPN客户端端点,连接到托管Rails应用程序和RDS数据库的VPC
然后,在连接到该VPN后,我只需运行我的Rails生产容器(使用相同的环境变量),覆盖容器命令以运行控制台启动脚本 (bundle exec rails c production
)
由于在我的本地计算机上运行,我可以正常附加TTY到此容器并访问我的生产控制台
我认为这个解决方案很好,因为它允许任何在该项目上工作的开发人员打开控制台,而不会产生任何费用,并且AWS端的一个经过深思熟虑的安全策略确保了控制台访问的安全性,此外你也不必将数据库暴露在你的VPC之外
希望这对某些人有所帮助
在ECS和Fargate中执行任何类型的docker exec
都是一场噩梦。这使得像shell或迁移这样的操作非常困难。
幸运的是,ECS上的Fargate任务实际上只是运行了一些超级定制的docker run
命令的AWS服务器。因此,如果您在EC2或本地机器上安装了docker
、jq
和AWS CLI,则可以自己伪造一些docker run
命令并进入bash shell。我为Django这样做,以便可以运行迁移并进入python shell,但我认为对于Rails(或任何其他需要bash的容器)也是如此。
请注意,这仅适用于您只关心同时运行在任务定义中指定的1个容器的情况,尽管我想你可以很容易地将其变得更加复杂。
为此,AWS CLI将需要使用与您的fargate任务相同的IAM权限进行登录。您可以通过使用aws configure
在本地提供具有正确IAM权限的用户的凭据来完成此操作,或者通过启动一个具有相同权限的角色的EC2实例(或者为了保持简单性而是您的fargate任务正在运行的角色)和具有相同访问权限的安全组(加上一个允许您SSH到堡垒主机的规则)。我喜欢使用EC2路线,因为通过公共互联网和VPN来传输所有内容是......很慢的。而且您总是保证具有与任务相同的IAM访问权限。
您还需要在与Fargate任务位于同一子网上,这通常可以通过VPN或在您的私有子网中运行此代码的堡垒EC2主机来完成。
在我的情况下,我将我的配置参数存储为AWS系统管理器参数存储中的SecureStrings,并使用ECS任务定义将它们传递进去。这些可以很容易地获取并设置为本地环境变量。
export DATABASE_URL=$(aws ssm get-parameter --region $REGION \
--with-decryption --name parameter.name.database_url \
| jq '.Parameter["Value"]' -r)
eval $(aws ecr get-login --no-include-email --region $REGION)
接下来只需要运行一个交互式的docker容器,将DATABASE_URL传入,从ECR中获取正确的镜像并进入bash。我还暴露了端口8000,这样我就可以在shell内运行web服务器(如果需要的话),但这是可选的。
docker run -i -t \
-e DATABASE_URL \
-p 8000:8000 \
$ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$DOCKER_REPO_NAME:$TAG \
/bin/bash
一旦你运行了这个命令,你应该看到docker从容器库下载镜像,然后启动bash(假设在你的容器中已经安装了bash)。 Docker有一个相当稳定的缓存,因此第一次下载和启动需要一些时间,但之后应该会很快。
以下是我的完整脚本:
#!/bin/bash
REGION=${REGION:-us-west-2}
ENVIRONMENT=${ENVIRONMENT:-staging}
DOCKER_REPO_NAME=${DOCKER_REPO_NAME:-reponame}
TAG=${TAG:-latest}
ACCOUNT_ID=$(aws sts get-caller-identity | jq -r ".Account")
export DATABASE_URL=$(aws ssm get-parameter --region $REGION \
--with-decryption --name projectname.$ENVIRONMENT.database_url \
| jq '.Parameter["Value"]' -r)
eval $(aws ecr get-login --no-include-email --region $REGION)
IMAGE=$ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$DOCKER_REPO_NAME:$TAG
docker run -i -t \
-e DATABASE_URL \
-p 8000:8000 \
$IMAGE \
/bin/bash
当您使用Fargate执行类型的ECS时,无法通过ssh连接到底层主机。这意味着您无法在运行中的容器中使用docker exec。
好的,我最终以稍微不同的方式处理了事情。我没有尝试在Fargate上运行控制台,而是在本地主机上运行控制台,但将其配置为使用RAILS_ENV='production'
并让它使用我的RDS实例。
当然,要使此工作正常,您必须通过安全组中的出站规则公开RDS实例。明智的做法是以仅允许本地IP的方式进行配置,以使其更加安全。
然后docker-compose.yml看起来像这样:
version: '3'
web:
stdin_open: true
tty: true
build: .
volumes:
- ./rails/.:/your-app
ports:
- "3000:3000"
environment: &env_vars
RAILS_ENV: 'production'
PORT: '8080'
RAILS_LOG_TO_STDOUT: 'true'
RAILS_SERVE_STATIC_FILES: 'true'
DATABASE_URL: 'postgresql://username:password@yours-aws-rds-instance:5432/your-db'
docker-compose run web rails c
时,它将使用您本地的Rails代码库,但会对您的RDS数据库进行实时更改(这也是您想要访问rails控制台的主要原因)。