当前位置: 首页 > 后端技术 > Python

【译文】UsingSystemdtorunaFlaskapplicationasaservice

时间:2023-03-25 20:28:08 Python

翻译RunningaFlaskApplicationasaServicewithSystemd在服务器上部署应用程序时,需要确保应用程序不间断运行。如果应用程序崩溃,您希望它自动重启,如果服务器断电,您希望应用程序在电源恢复时立即启动。基本上,您需要的是监视应用程序并在发现它不再运行时重新启动它。在之前的教程中,我向您展示了如何使用用Python编写的第三方实用程序supervisord来执行此操作。今天,我将向您展示一个基于systemd的类似解决方案,它是许多Linux发行版中的原生组件,包括Ubuntu等Debian衍生产品和Fedora和CentOS等RedHat衍生产品。使用Systemd配置服务Systemd通过称为单元的实体进行配置。有几种类型的单元,包括服务、套接字、设备、定时器等。对于服务,单元配置文件必须具有.service扩展名。下面,你可以看到服务单元配置文件的基本结构:Restart=always[Install]WantedBy=multi-user.target[Unit]部分对于所有类型的单元配置文件都是通用的。它用于配置有关单元的一般信息以及帮助系统确定启动顺序的任何依赖项。在我的模板中,我添加了服务的描述,我还指定我希望我的应用程序在网络子系统初始化后启动,因为它是一个Web应用程序。[服务]部分包含特定于您的应用程序的详细信息。我使用最常见的选项来定义运行服务的用户、起始目录和要执行的命令。重启选项告诉systemd,除了在系统启动时启动服务外,我还希望应用程序在退出时重新启动。这修复了可能导致进程结束的崩溃或其他意外问题。最后,[Install]部分配置启用设备的方式和时间。通过添加行WantedBy=multi-user.target我告诉systemd在系统以多用户模式运行时激活此单元,这是运行时Unix服务器的正常模式。如果您想了解有关多用户模式的更多详细信息,请参阅有关Unix运行级别的讨论。单元配置文件添加到/etc/systemd/system目录,供systemd查看。每次添加或修改单元文件时,必须告诉systemd刷新其配置:$sudosystemctldaemon-reload然后可以使用systemctl命令启动、停止、重启或获取服务状态:$sudosystemctlstart$sudosystemctlstop$sudosystemctlrestart$sudosystemctlstatus注意:您可以使用服务命令来管理服务而不是使用systemctl。在大多数发行版中,服务命令映射到systemctl并给出相同的结果。为Flask应用程序编写系统配置文件如果你想为自己的应用程序创建一个systemd服务文件,只需使用上面的模板并填写Description、User、WorkingDirectory和ExecStart。举个例子,假设我想在Linux服务器上部署FlaskMega-Tutorial中提到的微博应用程序,但我想使用systemd而不是supervisord来监控进程。供您参考,这是我在教程中使用的supervisord配置文件:[program:microblog]command=/home/ubuntu/microblog/venv/bin/gunicorn-blocalhost:8000-w4microblog:appdirectory=/home/ubuntu/microbloguser=ubuntuautostart=trueautorestart=truestopasgroup=truekillasgroup=truesystemd的等效单元配置文件会写在/etc/systemd/system/microblog.service中,内容如下:[Unit]Description=MicroblogwebapplicationAfter=network.target[Service]User=ubuntuWorkingDirectory=/home/ubuntu/microblogExecStart=/home/ubuntu/microblog/venv/bin/gunicorn-blocalhost:8000-w4microblog:appRestart=always[Install]WantedBy=多用户.target请注意启动命令如何到达可执行gunicorn的虚拟环境内部。这相当于激活虚拟环境,然后在没有路径的情况下运行gunicorn,但优点是可以在单个命令中完成。将此文件添加到您的系统后,您可以使用以下命令启动服务:$sudosystemctldaemon-reload$sudosystemctlstartmicroblog环境变量如果Flask应用程序希望提前设置一个或多个环境变量,它可以将它们添加到服务文件中。比如需要设置FLASK_CONFIG和DATABASE_URL变量,可以使用Environment选项定义如下:[Unit]Description=MicroblogwebapplicationAfter=network.target[Service]User=ubuntuWorkingDirectory=/home/ubuntu/microblogEnvironment=FLASK_CONFIG=productionEnvironment=DATABASE_URL=sqlite:////path/to/the/database.sqliteExecStart=/home/ubuntu/microblog/venv/bin/gunicorn-blocalhost:8000-w4microblog:appRestart=always[安装]WantedBy=多用户。target请注意,如果您遵循我的教程风格并使用.env文件作为环境变量,则无需通过systemd服务文件添加它们。我实际上更喜欢通过.env文件处理环境,因为它是一种适用于开发和生产的统一方法。访问日志Systemd有一个名为journal的日志子系统,由journald守护进程实现,它从所有正在运行的Systemd单元收集日志。可以使用journalctl实用程序查看日志的内容。以下是一些常见日志访问命令的示例。查看微博服务日志:$journalctl-umicroblog查看微博服务最近25条日志:$journalctl-umicroblog-n25跟踪微博服务日志:$journalctl-umicroblog-f还有更多选项可供选择。运行journalctl--help以查看更完整的选项摘要。高级用法:使用Systemd运行工作池如果您使用Celery运行后台进程,那么扩展上述解决方案以供您的工作人员使用是微不足道的,因为Celery允许您使用单个命令启动工作池。这实际上与您处理具有多个工作人员的gunicorn的方式相同,因此您所要做的就是创建第二个.service文件来管理Celery主进程,该进程将管理工作人员。但是,如果你读过我的FlaskMega-Tutorial的最后几章,你就会知道我已经介绍了一个基于RQ的任务队列来执行后台任务。使用RQ时,您必须单独启动工作人员,没有主进程为您管理工作人员池。这是我在教程中使用supervisor来管理RQworker的方式:=trueautorestart=truestopasgroup=truekillasgroup=true在这里,numprocs参数允许您启动任意数量的worker。使用此参数,supervisor将从单个配置文件启动并监视指定数量的实例。遗憾的是,systemd中没有numprocs选项,因此此类服务需要不同的解决方案。最简单的方法是为每个工作实例创建一个单独的服务文件,但这样做会很麻烦。我所做的是创建一个服务文件作为模板,可用于启动所有这些相同的实例:[Unit]Description=Microblogtaskworker%IAAfter=network.target[Service]User=ubuntuWorkingDirectory=/home/ubuntu/microblogExecStart=/home/ubuntu/microblog/venv/bin/rqworkermicroblog-tasksRestart=always[Install]WantedBy=multi-user.target你可能会注意到这个文件中的奇怪之处是我在服务描述中添加了Got%I.这是服务参数,一个要传递给每个实例的数字。在描述中包含此%I将帮助我识别实例,因为systemd命令的所有输出都将替换为实例编号。对于这种特殊情况,我实际上不需要使用此参数,但通常将%I包含在其他字段中,例如在必要时使用start命令。与常规服务文件的另一个区别是,我将使用名称/etc/systemd/system/microblog-tasks@.service来编写此服务文件。文件名中的@表示这是一个模板,因此在它之后会有一个参数来标识从它派生的每个实例。我将使用实例编号作为参数,因此服务的不同实例将在systemd中称为microblog-tasks@1、microblog-tasks@2等。现在,我可以在bash中使用大括号展开来启动四个worker:$sudosystemctldaemon-reload$sudosystemctlstartmicroblog-tasks@{1..4}$sudosystemctlstatusmicroblog-tasks@{1..4}如果你想单独处理一个实例,你也可以这样做:$sudosystemctlrestartmicroblog-tasks@3这几乎和单个supervisord配置一样方便,但是当你想对所有worker执行操作时有一个缺点,您必须在命令中包含{1..4}范围。要真正将整个工作池视为一个实体,我可以创建一个新的systemd目标,这是另一种类型的单元。然后我可以将所有实例映射到该目标,这将允许我在想要对组的所有成员执行操作时引用该目标。让我们从新目标的单元配置文件开始,我将其命名为/etc/systemd/system/microblog-tasks.target:[Unit]Description=MicroblogRQworkerpool[Install]WantedBy=multi-user.target除了description此外,唯一需要的定义是对multi-user.target的依赖,正如您所记得的,它是上面定义的所有上述单元文件的目标。现在,我可以更新服务文件模板以引用新目标,由于对原始multi-user.target的传递引用,它最终等同于新目标。[Unit]Description=微博任务worker%IAfter=network.target[Service]User=ubuntuWorkingDirectory=/home/ubuntu/microblogExecStart=/home/ubuntu/microblog/venv/bin/rqworkermicroblog-tasksRestart=always[Install]WantedBy=microblog-tasks.target现在可以使用以下命令使用新设置重新配置系统:$sudosystemctldaemon-reload$sudosystemctldisablemicroblog-tasks@{1..4}$sudosystemctlenablemicroblog-tasks@{1..4}必须使用disable和enable命令强制systemd删除旧目标并为工作任务应用新目标。现在可以使用目标处理woker池:$sudosystemctlrestartmicroblog-tasks.target如果你决定稍后添加第五个worker,你可以这样做:$sudosystemctlenablemicroblog-tasks@5$sudosystemctlstartmicroblog-tasks.target当然也可以减少workers。以下是减少worker4和5的方法:$sudosystemctlstopmicroblog-tasks@{4..5}$sudosystemctldisablemicroblog-tasks@{4..5}在这一点上,我认为这个解决方案是得心应手的它超过了主管的numprocs命令在功能和功能方面,因为我不仅可以控制整个worker进程,而且我可以添加和删除worker而无需编辑任何配置文件!