CloudFoundry:如何使用多个构建包? (NGINX + Django/Gunicorn)

CloudFoundry: How to use multiple buildpacks? (NGINX + Django/Gunicorn)

我有 Django/Gunicorn + whitenoise(用于静态文件服务)在 Cloud Foundry 中作为单个应用程序使用以下 manifest.yml 文件工作:

---
applications:
- name: mydjango
  instances: 1
  command: src/tvpv_portal/bin/start_gunicorn_django.sh
  memory: 2048M
  disk_quota: 1024M
  buildpacks:
    - https://github.com/cloudfoundry/python-buildpack.git
  stack: cflinuxfs3
  env:
    DJANGO_MODE: Production

对于 learning/experimentation,我想删除白噪声并使用 nginx_buildpack 设置 Nginx 以与 Django/Gunicorn 一起工作。但是,我不确定如何在单个应用程序上使用多个构建包。我按照 https://docs.cloudfoundry.org/buildpacks/nginx/index.html 中的说明在我的项目目录中创建了 nginx.confmime.typesbuildpack.yml

nginx.conf

daemon off;

error_log /home/vcap/app/nginx-error.log;
events { worker_connections 1024; }

http {
    log_format cloudfoundry '$http_x_forwarded_for - $http_referer - [$time_local] "$request" $status $body_bytes_sent';
    access_log /home/vcap/app/nginx-access.log cloudfoundry;

    default_type application/octet-stream;
    include mime.types;

    sendfile on;
    gzip on;

    tcp_nopush on;
    keepalive_timeout 30;
    port_in_redirect off; # Ensure that redirects don't include the internal container PORT - 8080

    server {
        listen {{port}};
        server_name localhost;

        # Serve static files.
        location /static/ {
            alias /home/vcap/app/src/tvpv_portal/static/;
        }

        # Serve media files.
        location /media/ {
            alias /home/vcap/app/src/tvpv_portal/media/;
        }

        # Reverse proxy to forward to main app.
        location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_pass http://127.0.0.1:8000;
        }
    }
}

我试过 cf push mydjango -b nginx_buildpack -b python_buildpack。但是从查看文档来看,似乎只有最后一个构建包能够启动命令。来自前面 buildpack 的命令将被忽略。因此,我无法启动 nginx 服务器。如何正确设置多个构建包?

我确实读过 CloudFoundry: nginx for serving static content on top of Gunicorn (Docker),但回复是关于有两个具有不同路由的独立应用程序。由于这更适用于 learning/experimentation 和 CF,我想知道是否可以在不分离静态内容的情况下使用单个应用程序来完成此操作。感谢您的帮助。

对于生产工作负载(或任何重要的事情),您真的不想将多个逻辑上独立的进程放入一个容器中。主要原因是这使您的应用程序难以扩展。假设您的应用程序变得流行,并且您需要更多的 Django 处理来处理负载,同时 Nginx 和 Django 在同一个容器中,您必须一起扩展。如果它们是单独的应用程序,您可以根据每个逻辑进程的需要独立扩展它们。

还有其他痛点:

  • CPU & 内存管理比较棘手。您有多个进程竞争同一个资源池。这对于 Java 应用程序来说尤其棘手,因为 JVM 喜欢占用 all 内存。这意味着您必须更好地进行估算,以免耗尽内存导致应用程序崩溃。
  • 正确响应健康检查更复杂。您的健康检查需要准确地表明您的应用是 "working"。如果在同一个应用程序中有多个进程,那就更难了。
  • 当其中一个进程终止时让应用程序退出是很棘手的。这类似于正确进行健康检查。如果应用程序没有完全退出,那么应用程序将不会重新启动,你可能会剩下一半的应用程序,或者无法自动退出的损坏的应用程序 restarted/fixed.
  • 两个独立的应用程序让您更加灵活,特别是您可以独立更新应用程序。

无论如何,如果您仍然想将两者都塞入同一个应用程序中,您有几个选择。

  1. 您可以简单地使用cf push -c或将command:添加到manifest.yml来控制启动命令。这将允许您覆盖最终 buildpack 设置的命令。请小心,因为它会完全覆盖 buildpack 设置的内容,因此您确实需要知道要调用的正确命令,否则您的应用程序将无法启动(这对于 Java 应用程序尤其棘手,其中启动命令可以是复杂)。

  2. 您可以将 .profile 文件放入应用程序目录的根目录(即您设置 cf push -p 的位置)。此脚本将在最终 buildpack 设置的命令之前执行,您可以使用它在后台启动其他进程。

如上所述,使用上述方法时,要让两个进程都正确退出尤其棘手。这是我发现的一个有用的技巧:

#!/bin/bash
set -e

run_second_process() {
    # insert the command to run the second process here
    #   it should run and keep running (i.e. foreground)
    nginx -c nginx.conf
    # should never get to here, if it does the app crashed
    pkill python  # insert name of your primary process
    # now we are all dead and the container will restart
}

# runs the second process in the background
#   that is important otherwise the primary process will never run
run_updater &

您需要找出解决其他缺点的方法,或者转而使用多个应用程序。