在 AWS Linux 2 上运行的 NGINX 配置中访问 Elastic Beanstalk 环境属性

Posted

技术标签:

【中文标题】在 AWS Linux 2 上运行的 NGINX 配置中访问 Elastic Beanstalk 环境属性【英文标题】:Access Elastic Beanstalk environment properties in NGINX configs running on AWS Linux 2 【发布时间】:2020-08-19 12:01:49 【问题描述】:

我之前在 AWS Linux AMI 上工作过,但在 AWS Linux 2 上没有运气。

我需要在 EB 应用程序部署期间从 nginx 配置文件访问我的环境属性。这是一个单实例节点服务器。

我在 AWS Linux AMI 上做了这样的事情,并且没有问题:

.ebextensions/00_options.config

option_settings:
   aws:elasticbeanstalk:application:environment:
      DOMAIN: socket.example.com
      MASTER_DOMAIN: https://example.com
      etc..

.ebextensions/10_proxy.config

... some configs ...

files:

  /etc/nginx/conf.d/proxy.conf:
    mode: "000644"
    owner: root
    group: root
    content: |

      upstream nodejs 
          server 127.0.0.1:8081;
          keepalive 256;
      

      map $http_origin $cors_header 
          hostnames;
          default "";
          `"Fn::GetOptionSetting": "Namespace": "aws:elasticbeanstalk:application:environment", "OptionName": "MASTER_DOMAIN"` "$http_origin";
      

      server 

          listen 80;
          listen 8080;

          server_name `"Fn::GetOptionSetting": "Namespace": "aws:elasticbeanstalk:application:environment", "OptionName": "DOMAIN"`;

          location ~ /.well-known 
              allow all;
              root /usr/share/nginx/html;
          
          location / 
              return 301 https://$host$request_uri;
          
      
      
      etc..


.... some more configs ....
      

我没有包括上面的大多数配置,因为它们不相关。

所以当我之前这样做时,一切都按预期工作。配置文件插入了我的属性并在/etc/nginx/conf.d/proxy.conf 文件夹中创建了该文件。


现在 AWS Linux 2 的规格发生了变化,我们必须将 Nginx 配置文件添加到位于我们的应用程序包根文件夹中的 .platform/nginx/conf.d 文件夹中。

Here the reference(参见反向代理配置

所以我在上面提到的位置创建了一个proxy.conf 文件,其中包含之前插入到/etc/nginx/conf.d/proxy.conf 中的内容。


.platform/nginx/conf.d/proxy.conf

upstream nodejs 
    server 127.0.0.1:8081;
    keepalive 256;

    
map $http_origin $cors_header 
    hostnames;
    default "";
   `"Fn::GetOptionSetting": "Namespace": "aws:elasticbeanstalk:application:environment", "OptionName": "MASTER_DOMAIN"` "$http_origin";


etc...

然后问题就开始了..

第一次试验向我抛出了unexpected "" in /var/proxy/staging/nginx/conf.d/proxy.conf:11

在那之后我尝试了很多东西。尝试使用 $MASTER_DOMAIN 并使用新的 EB AWS Linux 2 hooks(请参阅上面的链接 Platform hooks)。一切都无济于事,您似乎无法从 Nginx 配置中访问属性。我读过一篇来自 Nginx 的文章或文档,今天提到了类似的东西,但我再也找不到了(做了很多谷歌搜索)。


我还尝试创建一个配置文件,就像我对工作版本所做的那样,目的是在某个位置保存一个包含属性的临时文件,然后将此文件包含在所需的 .platform/nginx/conf.d/proxy.conf 文件中,因为我开始认为那里无法将它们直接包含在新规范中。

.ebextensions/10_proxy.config

... some configs ....

files:

  /var/proxy/staging/custom_folder/proxy.conf:
    mode: "000644"
    owner: root
    group: root
    content: |
    
    etc...

.platform/nginx/conf.d/proxy.conf

include custom_folder/proxy.conf;

考虑到这个想法,我做了很多废话,我创建了hooks 来创建(mkdir)目录,我试图在其中临时保存导致新权限错误的文件。我无法为prebuildpostdeploy 文件提供适当的权限,但这是另一个问题。

还有更多的尝试和失败......


但后来我读到(也来自上面的链接):

"如果您将代理配置为向多个应用程序进程发送流量,您可以配置多个环境属性,并在代理配置和您的应用程序代码。"

希望回来了.. 这是否意味着我实际上 CAN 直接将环境变量添加到位于 .platform 目录中的 Nginx 配置中? ...我不知道..你呢?


我可以继续描述我整晚尝试的所有事情,所以我会在这里停下来。我希望你能得到这个问题。如果不问我,我会尽力让这一切变得可以理解。

另外,在与这个问题作斗争 14 小时后,我的想法也不是很清楚了。我需要休息一下。

如果您坚持到最后,感谢您的宝贵时间和帮助,我们将不胜感激。

【问题讨论】:

【参考方案1】:

总结

一种方法是在.platform/hooks/postdeploy 中创建一个shell 脚本。

这是一个简化的示例,假设您有一个名为 MASTER_DOMAIN 的 Elastic Beanstalk 环境属性:

#!/bin/bash
    
# write nginx config file
cat > /etc/nginx/conf.d/elasticbeanstalk/test.conf << LIMIT_STRING
location /test/ 
  default_type text/html;
  return 200 "nginx variable: \$host, and EB env property: $MASTER_DOMAIN";

LIMIT_STRING
    
# restart nginx service so the config takes effect
systemctl restart nginx.service

此示例中的 location 块可以替换为原始帖子中 .ebextensions/10_proxy.config 中的 nginx content。不过不需要Fn::GetOptionSetting 的东西。

我认为您还需要在.platform/confighooks/postdeploy 中复制一个脚本。

详情如下。

(对不起文字墙)

nginx中的环境变量

实际上,正如here 和here 中所讨论的,在httpserver 中使用os 环境变量是不可能的(开箱即用) , 或 location nginx 配置文件中的块。有一些变通方法,例如使用 lua、perl 或模板,但我们不讨论这些。这部分与AWS无关。

在 OP 的 Amazon Linux AMI (AL1) 原始配置中,使用 .ebextensions/10_proxy.config 中的 files 部分,他们实际上是在部署期间使用 shell 脚本编写 nginx 配置文件。 shell 脚本扩展了环境变量,但生成的 nginx 的 proxy.conf 实际上并没有访问任何环境变量。

这就是它在 AL1 上起作用的原因。

平台挂钩

现在,对于 Amazon Linux 2 (AL2),我们可以使用 .platform/hooks.platform/confighooks 文件夹中的 shell 脚本执行类似的操作。

这些.platform 挂钩脚本以root 用户身份执行,它们可以访问Elastic Beanstalk (EB) 环境属性。 EB 环境属性可以像普通操作系统环境变量一样访问,所以不需要使用Fn::GetOptionSetting 的东西。

基本上,我们需要创建一个 shell 脚本,该脚本使用原始 .ebextensions/10_proxy.config 中的 content 写入文件。但是,我们需要考虑两个问题:

    我们应该使用prebuildpredeploypostdeploy 挂钩吗?

    我们的 nginx proxy.conf 文件的正确目标目录是什么?

文件位置

要回答这些问题,我们必须参考 Extending Elastic Beanstalk Linux platforms 的 AWS 文档,特别是 Instance deployment workflow 部分。

... 平台挂钩的当前工作目录 (cwd) 是应用程序的根目录。对于 prebuild 和 predeploy 文件,它是应用程序暂存目录,对于 postdeploy 文件,它是当前应用程序目录。如果其中一个文件失败(以非零退出代码退出),部署将中止并失败。

这很有趣,但留下了一些问题,例如“应用程序暂存目录”在哪里?我们可以通过检查我们的部署日志文件之一来填补空白。根据我们的eb-engine.log,以下是应用部署期间平台挂钩和 nginx 配置文件发生的情况(跳过很多细节):

    源包从S3下载并解压到/var/app/staging/ .platform/hooks/prebuild/ 中的平台挂钩已执行 代理服务器配置从/var/app/staging/.platform/nginx/复制到/var/proxy/staging/nginx .platform/hooks/predeploy/ 中的平台挂钩已执行 代理服务器启动,配置从/var/proxy/staging/nginx/复制到/etc/nginx .platform/hooks/postdeploy/ 中的平台挂钩已执行

注意,部署后应用位于/var/app/current

基于以上,有几种选择:

    .platform/hooks/postdeploy 中创建一个写入/etc/nginx/conf.d/proxy.conf 的shell 脚本。

    nginx服务已经在运行,这个阶段需要重启才能使配置生效。

    下面是一个最小的测试示例。在本例中,我们写入elasticbeanstalk 子目录,因为我们只想在默认的server 块内添加location。然后我们可以在浏览器中访问/test/页面,检查配置是否有效。

    我们使用一些bash io redirection(&lt;&lt;&gt;)来编写nginx配置文件。

    请注意,我们需要转义任何 nginx 变量,例如$host 变为 \$host,否则 shell 会将它们解释为环境变量。

    另请注意,shell 脚本需要具有执行权限,如文档中More about platform hooks 中所述。

#!/bin/bash
    
cat > /etc/nginx/conf.d/elasticbeanstalk/test.conf << LIMIT_STRING
location /test/ 
  default_type text/html
  return 200 "nginx variable: \$host, and EB env property: $MASTER_DOMAIN";

LIMIT_STRING
    
systemctl restart nginx.service

    或者,我们可以在.platform/hooks/predeploy 中创建一个写入/var/proxy/staging/nginx/conf.d/proxy.conf 的shell 脚本。

    这种情况下不需要重启nginx服务,因为这个钩子是在应用服务器配置之前执行的。

注意:

不确定这是错误还是设计功能,但我们新创建的proxy.conf配置 部署(与应用程序 部署相反)后消失了,除非我们在.platform/confighooks/postdeploy 目录中放了一个重复的脚本。不是很干...

编辑:AWS 支持确认我们在这种情况下需要 hooksconfighooks 中的重复脚本。文档中的application example 还显示了hooksconfighooks 中的一些重复项(至少是重复的文件名)。

编辑: 除了复制脚本,我们还可以编写一个调用钩子的配置钩子,例如.platform/confighooks/predeploy/01_my_confighook.sh 可能如下所示:

#!/bin/bash
source "/var/app/current/.platform/hooks/predeploy/01_my_hook.sh"

免责声明:这是在新创建的单个实例 EB 环境中使用所有默认配置和默认 AWS Python 示例应用程序(在 64 位 Amazon Linux 2/3.1.5 上运行 Python 3.7)进行测试的(仅使用我们的自定义挂钩进行扩展)。

【讨论】:

嘿,谢谢你的回答,我会在回到这个问题时尝试一下。

以上是关于在 AWS Linux 2 上运行的 NGINX 配置中访问 Elastic Beanstalk 环境属性的主要内容,如果未能解决你的问题,请参考以下文章

在 AWS Elastic Beanstalk 上运行 Docker 容器 - 502 Bad Gateway nginx/1.6.2

如何在运行 AWS Linux 2 的 AWS Elastic Beanstalk 上配置 Linux 交换空间?

amazon aws ec云Linux ami上安装配置Nginx+PHP+MySQL环境

在 AWS 上安装 nginx 后禁止 403(不欢迎 nginx 消息)

在 aws linux 2 实例上使用弹性 beanstalk 运行 django-q

在 64 位 Amazon Linux 2/3.2.2 和 Dockerrun.aws.json v3 上运行 Docker 的 Elastic Beanstalk