使用 systemd 部署 Twisted

简介

在本教程中,您将学习如何使用 systemd 启动 Twisted 服务。您还将学习如何使用 socket activation 启动服务。

注意

本教程中的示例演示了如何启动 Twisted Web 服务器,但相同的技术适用于任何 Twisted 服务。

先决条件

Twisted

本教程的套接字激活部分需要 Twisted 版本 >= 12.2。

本教程是在 Fedora 18 Linux 操作系统上编写的,该操作系统具有系统范围的 Twisted 和 Twisted Web 安装。

如果您在本地安装了 Twisted,例如在您的主目录或 virtualenv 中,则需要修改以下示例中的一些路径。

通过以下命令在 TCP 端口 8080 上启动 twistd web 服务器来测试您的 Twisted 安装

$ twistd --nodaemon web --listen tcp:8080 --path /srv/www/www.example.com/static
2013-01-28 13:21:35+0000 [-] Log opened.
2013-01-28 13:21:35+0000 [-] twistd 12.3.0 (/usr/bin/python 2.7.3) starting up.
2013-01-28 13:21:35+0000 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
2013-01-28 13:21:35+0000 [-] Site starting on 8080
2013-01-28 13:21:35+0000 [-] Starting factory <twisted.web.server.Site instance at 0x7f57eb66efc8>

假设您在以下目录结构中具有以下静态网页

# tree /srv/
/srv/
└── www
    └── www.example.com
        └── static
            └── index.html
<!doctype html>
<html lang=en>
  <head>
    <meta charset=utf-8>
    <title>Example Site</title>
  </head>
  <body>
    <h1>Example Site</h1>
  </body>
</html>

现在尝试在您的 Web 浏览器中连接到 http://localhost:8080

如果您没有看到您的网页,或者 twistd 没有启动,您应该调查并解决问题,然后再继续。

基本的 Systemd 服务配置

systemd 服务的基本配置文件是 服务文件

在本教程的后面,您将了解其他类型的配置文件,这些文件用于控制服务何时以及如何启动。

但我们将从配置 systemd 开始,以便在系统启动时立即启动 Twisted Web 服务器。

创建 systemd 服务文件

/etc/systemd/system/www.example.com.service 创建 服务文件,内容如下

/etc/systemd/system/www.example.com.service

[Unit]
Description=Example Web Server

[Service]
ExecStart=/usr/bin/twistd \
    --nodaemon \
    --pidfile= \
    web --listen tcp:8080 --path .

WorkingDirectory=/srv/www/www.example.com/static

User=nobody
Group=nobody

Restart=always

[Install]
WantedBy=multi-user.target

此配置文件包含以下值得注意的指令

ExecStart

始终包含 twistd 的完整路径,以防您安装了多个版本。

--nodaemon 标志使 twistd 在前台运行。Systemd 最适合在前景中保持的子进程。

--pidfile= 标志阻止 twistd 编写 pidfile。当 Twisted 作为前台进程运行时,pidfile 不是必需的。

--path 标志指定网站文件的位置。在本例中,我们使用“.”,这使得 twistd 从其当前工作目录提供服务(见下文)。

WorkingDirectory

Systemd 可以配置其子进程的工作环境。

在本例中,twistd 的工作目录设置为静态网站的工作目录。

用户/组

Systemd 还可以控制其子进程的有效用户和组。

本例使用非特权用户“nobody”和非特权组“nobody”。

这是一项重要的安全措施,它确保 Twisted 子进程无法访问文件系统的受限区域。

重启

如果子进程意外退出或崩溃,Systemd 可以自动重启子进程。

在本例中,Restart 选项设置为 always,这确保了 twistd 将在任何情况下都重新启动。

WantedBy

systemd 服务依赖关系由配置文件的 [Install] 部分中的 WantedByRequiredBy 指令控制。

在本例中,使用特殊的 multi-user.target,以便在 systemd 达到引导序列的多用户阶段时启动 twistd web 服务。

还有许多其他服务指令,这些指令在systemd.directives 手册页中有所记录。

重新加载 systemd

$ sudo systemctl daemon-reload

这将强制 systemd 读取新的配置文件。

更改任何 systemd 配置文件后,始终运行 systemctl daemon-reload

启动服务

$ sudo systemctl start www.example.com

twistd 现在应该正在运行并监听 TCP 端口 8080。您可以使用 systemctl status 命令验证这一点。例如

$ systemctl status www.example.com.service
www.example.com.service - Example Web Server
          Loaded: loaded (/etc/systemd/system/www.example.com.service; enabled)
          Active: active (running) since Mon 2013-01-28 16:16:26 GMT; 1s ago
        Main PID: 10695 (twistd)
          CGroup: name=systemd:/system/www.example.com.service
                  └─10695 /usr/bin/python /usr/bin/twistd --nodaemon --pidfile= web --listen tcp:8080 --path .

Jan 28 16:16:26 zorin.lan systemd[1]: Starting Example Web Server...
Jan 28 16:16:26 zorin.lan systemd[1]: Started Example Web Server.
Jan 28 16:16:26 zorin.lan twistd[10695]: 2013-01-28 16:16:26+0000 [-] Log opened.
Jan 28 16:16:26 zorin.lan twistd[10695]: 2013-01-28 16:16:26+0000 [-] twistd 12.1.0 (/usr/bin/python 2.7.3) starting up.
Jan 28 16:16:26 zorin.lan twistd[10695]: 2013-01-28 16:16:26+0000 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
Jan 28 16:16:26 zorin.lan twistd[10695]: 2013-01-28 16:16:26+0000 [-] Site starting on 8080
Jan 28 16:16:26 zorin.lan twistd[10695]: 2013-01-28 16:16:26+0000 [-] Starting factory <twisted.web.server.Site instance at 0x159b758>

systemctl status 命令很方便,因为它同时显示了服务的当前状态和服务输出的简短日志。

这对于调试和诊断服务启动问题特别有用。

twistd 子进程将日志消息记录到 stderr,而 systemd 将这些消息记录到 syslog。您可以通过监控 syslog 消息或使用 Fedora 中的新 journalctl 工具来验证这一点。

有关其他 systemctl 命令行选项的详细信息,请参阅systemctl 手册页

启用服务

我们已经了解了如何手动启动服务,但现在我们需要“启用”它,以便它在启动时自动启动。

使用以下命令启用服务

$ sudo systemctl enable www.example.com.service
ln -s '/etc/systemd/system/www.example.com.service' '/etc/systemd/system/multi-user.target.wants/www.example.com.service'

这将在 multi-user.target.wants 目录中创建一个指向服务文件的符号链接。

Twisted Web 服务器现在将在启动时自动启动。

multi-user.target“特殊” systemd 单位 的一个示例。在本教程的后面,您将学习如何使用另一个特殊单位 - sockets.target

测试服务是否自动重启

www.example.com.service 文件中的 Restart=always 选项确保 systemd 将在 twistd 进程意外退出时重启该进程。

您可以在systemd.service 手册页中阅读有关其他 Restart 选项的信息。

尝试杀死 twistd 进程,然后再次检查其状态

$ sudo kill 12543

$ systemctl status www.example.com.service
www.example.com.service - Example Web Server
          Loaded: loaded (/etc/systemd/system/www.example.com.service; disabled)
          Active: active (running) since Mon 2013-01-28 17:47:37 GMT; 1s ago
        Main PID: 12611 (twistd)

“Active” 时间戳显示 twistd 进程在 1 秒内重启。

现在在继续下一节之前停止服务。

$ sudo systemctl stop www.example.com.service

$ systemctl status www.example.com.service
www.example.com.service - Example Web Server
          Loaded: loaded (/etc/systemd/system/www.example.com.service; enabled)
          Active: inactive (dead) since Mon 2013-01-28 16:51:12 GMT; 1s ago
         Process: 10695 ExecStart=/usr/bin/twistd --nodaemon --pidfile= web --port 8080 --path . (code=exited, status=0/SUCCESS)

套接字激活

首先,您需要了解“套接字激活”是什么。以下摘录来自systemd daemon 手册页,它清楚地解释了这一点。

在基于套接字的激活方案中,创建和绑定监听套接字作为守护进程与本地(有时也包括远程)客户端的主要通信通道,这一操作从守护进程代码中移到了 init 系统中。

根据每个守护进程的配置,init 系统会安装套接字,然后在相应的守护进程即将启动时将其传递给生成的进程。

可以选择延迟服务的激活,直到第一个入站流量到达套接字,以实现守护进程的按需激活。

但是,这种方案的主要优势在于,一旦所有套接字都建立起来,所有提供者和所有消费者都可以并行启动。

除此之外,守护进程可以在重启时只丢失最少的客户端事务,甚至不丢失任何客户端请求(对于无状态协议,例如 DNS 或 syslog,尤其如此),因为套接字在重启期间保持绑定和可访问,并且所有请求都在守护进程无法处理它们时排队。

套接字激活的另一个好处是,systemd 可以监听特权端口,并以已删除的特权启动 Twisted。这允许非 root 用户配置和重启 Twisted 服务。

Twisted(从 12.2 版本开始)包含一个systemd 端点 API 和相应的字符串端口语法,它允许 Twisted 服务从 systemd 继承监听套接字。

以下示例基于前面的示例,演示了如何为简单的 Twisted Web 服务器启用套接字激活。

注意

在继续之前,使用以下命令停止前面的示例服务

$ sudo systemctl stop www.example.com.service

创建 systemd.socket 文件

/etc/systemd/system/www.example.com.socket 处创建 systemd.socket 文件,内容如下

/etc/systemd/system/www.example.com.socket

[Socket]
ListenStream=0.0.0.0:80
FileDescriptorName=my-web-port

[Install]
WantedBy=sockets.target

此配置文件包含以下重要指令

ListenStream=0.0.0.0:80

此选项配置 systemd 创建一个监听 TCP 套接字,该套接字绑定到端口 80 上的所有本地 IPv4 地址。

WantedBy=sockets.target

这是一个由所有套接字激活服务使用的特殊目标systemd 将在启动时自动绑定到所有此类套接字激活端口。

FileDescriptorName=my-web-port

此选项命名套接字的文件描述符。该名称允许从一组继承的描述符中可靠地选择特定的继承描述符。

您还需要修改 www.example.com.service 文件,如下所示

/etc/systemd/system/www.example.com.service

[Unit]
Description=Example Web Server
Requires=www.example.com.socket

[Service]
ExecStart=/usr/bin/twistd \
    --nodaemon \
    --pidfile= \
    web --listen systemd:domain=INET:name=my-web-port --path .

WorkingDirectory=/srv/www/www.example.com/static

User=nobody
Group=nobody

Restart=always

请注意以下重要指令和更改

ExecStart

domain=INET 端点参数使 twistd 将继承的文件描述符视为 IPv4 套接字。

name=my-web-port 端点参数使 twistd 采用从名为 my-web-portsystemd 继承的文件描述符。

套接字激活在技术上也可能与其他套接字族和类型一起使用,但 Twisted 目前只接受 IPv4 和 IPv6 TCP 套接字。请参阅下面的限制和已知问题

需要

服务不再知道如何为自己绑定监听端口。必须启动相应的套接字单元,以便它可以将监听端口传递给 twistd 进程。

[Install]

在此示例中,[Install] 部分已移至套接字配置文件。

重新加载 systemd,以便它读取更新的配置文件。

$ sudo systemctl daemon-reload

启动并启用套接字

您现在可以使用以下命令启动 systemd 在套接字上监听

$ sudo systemctl start www.example.com.socket

此命令专门引用套接字配置文件,而不是服务文件。

systemd 现在应该在端口 80 上监听

$ systemctl status www.example.com.socket
www.example.com.socket
          Loaded: loaded (/etc/systemd/system/www.example.com.socket; disabled)
          Active: active (listening) since Tue 2013-01-29 14:53:17 GMT; 7s ago

Jan 29 14:53:17 zorin.lan systemd[1]: Listening on www.example.com.socket.

twistd 应该还没有启动。您可以使用 systemctl 命令验证这一点。例如

$ systemctl status www.example.com.service
www.example.com.service - Example Web Server
          Loaded: loaded (/etc/systemd/system/www.example.com.service; static)
          Active: inactive (dead) since Tue 2013-01-29 14:48:42 GMT; 6min ago

启用套接字,以便它在启动时与其他套接字激活服务一起自动启动。

$ sudo systemctl enable www.example.com.socket
ln -s '/etc/systemd/system/www.example.com.socket' '/etc/systemd/system/sockets.target.wants/www.example.com.socket'

激活端口以启动服务

现在尝试连接到http://localhost:80(在您的 Web 浏览器中)。

systemd 将接受连接并启动 twistd,并将监听套接字传递给它。您可以使用 systemctl 报告服务的状况来验证这一点。例如

$ systemctl status www.example.com.service
www.example.com.service - Example Web Server
          Loaded: loaded (/etc/systemd/system/www.example.com.service; static)
          Active: active (running) since Tue 2013-01-29 15:02:20 GMT; 3s ago
        Main PID: 25605 (twistd)
          CGroup: name=systemd:/system/www.example.com.service
                  └─25605 /usr/bin/python /usr/bin/twistd --nodaemon --pidfile= web --port systemd:domain=INET:name=my-web-port --path .

Jan 29 15:02:20 zorin.lan systemd[1]: Started Example Web Server.
Jan 29 15:02:20 zorin.lan twistd[25605]: 2013-01-29 15:02:20+0000 [-] Log opened.
Jan 29 15:02:20 zorin.lan twistd[25605]: 2013-01-29 15:02:20+0000 [-] twistd 12.1.0 (/usr/bin/python 2.7.3) starting up.
Jan 29 15:02:20 zorin.lan twistd[25605]: 2013-01-29 15:02:20+0000 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
Jan 29 15:02:20 zorin.lan twistd[25605]: 2013-01-29 15:02:20+0000 [-] Site starting on 80
Jan 29 15:02:20 zorin.lan twistd[25605]: 2013-01-29 15:02:20+0000 [-] Starting factory <twisted.web.server.Site instance at 0x24be758>

结论

在本教程中,您学习了如何使用 systemd 部署 Twisted 服务。您还了解了如何使用套接字激活按需启动服务。

限制和已知问题

  1. Twisted 无法从 systemd 接受数据报套接字。

  2. Twisted 不支持监听从 systemd 继承的套接字上的 SSL 连接。

进一步阅读