本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)
本文作者: 苏洋
创建时间: 2019年04月04日 统计字数: 6010字 阅读时间: 12分钟阅读 本文链接: https://soulteary.com/2019/04/04/aria2-with-docker-and-web-ui.html
更好的 Aria2 容器化使用方案
趁着整理 HomeLab 的机会,把 Aria2 封装成了容器镜像。
本文将介绍如何搭配 Traefik 快速使用 Aria2 ,以及如何调整不兼容 Traefik 的应用与之兼容。
镜像介绍
在开始讲解如何做之前,需要先简单介绍一下镜像的构成。
对于长期运行的应用/服务来说,代码是否透明公开很重要,我已经将代码上传至 GitHub:代码仓库地址。
使用到的技术栈/工具主要有以下内容:
- Aria2 WebUI
- 一款Aria2 Web管理界面 ziahamza/webui-aria2
- Aria2
- Aria2 下载工具 ndthuan/aria2-alpine
- Node HTTP Proxy
- Node.js 版的代理模块nodejitsu/node-http-proxy
- Traefik
- 优秀的负载均衡/服务发现工具 containous/traefik
- Compose
- 简单好用的容器编排工具 docker/compose
- Docker
- 简单好用的容器工具 docker
改造过程
网上盛行使用一个容器同时提供 HTTP + ARIA2
所以在使用的过程中,我们需要单独运行这两个部分,使用 docker-compose.yml
定义的话,或许最简单的示例就是下面这样了:
version: '3'
services:
web:
container_name: web
image: ${WEBUI_IMAGE}
expose:
- 8888
aria2:
container_name: aria2
image: ${ARIA2_IMAGE}
volumes:
- ./downloads:/downloads
expose:
- 6800
但如果你将 Aria2 WebUI
之所以这样处理,是因为项目本身是一套使用 Angular 编写的 SPA 程序,不具备服务端接口处理能力,但是实际上,项目在生产环境运行的时候,作者有提供一个简单的 Node Server,是可以支持一定程度的接口定制的。
而我们使用容器将 Web UI 和 Aria2 进行隔离,相当于在两台不同的服务器中执行这两个应用,所以这里我们要进行一些改造。
WebUI 支持和 Aria2 分离部署
影响 WebUI 使用 Aria2 RPC 接口的主要有两处引用,分别在:
/app/src/js/services/configuration.js
/app/src/js/services/rpc/rpc.js
先处理 configuration.js
的内容:
host: location.protocol.startsWith("http") ? location.hostname : "localhost",
path: "/jsonrpc",
port: 6800,
encrypt: false,
找到程序中上面的代码部分,将端口 6800
修改为 80
。
接着处理 rpc.js
的内容:
if (["http", "https"].indexOf(uri.protocol()) != -1 && uri.host() != "localhost") {
configurations.push(
{
host: uri.host(),
path: "/jsonrpc",
port: 6800,
encrypt: false
},
同样找到这段代码,将端口 6800
修改为 80
。
将代码改造完毕,你会发现WebUI中所有的请求都被定位到了当前域名下的 80
端口,前面提过,这个界面是一套前端 SPA 应用,是缺乏接口处理能力的。
所以,接下来我们要对服务端进行处理,我使用 ES6 重写了作者的 Node Server,主要支持了 HTTP
/WS
协议转发至 aria2
容器对应的端口。
const { createServer } = require("http");
const url = require("url");
const { join, extname } = require("path");
const { exists, statSync, readFile } = require("fs");
const port = parseInt(process.argv[2], 10) || 8888;
const baseDir = join(process.cwd(), "docs");
const httpProxy = require('http-proxy');
const { WEB_PROXY, WS_PROXY } = process.env;
const webProxy = httpProxy.createProxyServer({ target: WEB_PROXY });
const wsProxy = httpProxy.createServer({ target: WS_PROXY, ws: true });
createServer(function (request, response) {
const uri = url.parse(request.url).pathname;
let filename = join(baseDir, uri);
let contentType = "text/html";
switch (extname(filename)) {
case ".js":
contentType = "text/javascript";
break;
case ".css":
contentType = "text/css";
break;
case ".ico":
contentType = "image/x-icon";
break;
case ".svg":
contentType = "image/svg+xml";
break;
}
if (filename.endsWith("jsonrpc")) {
webProxy.web(request, response);
return;
}
exists(filename, function (exists) {
if (!exists) {
response.writeHead(404, { "Content-Type": "text/plain" });
response.write("404 Not Foundn");
response.end();
return;
}
if (statSync(filename).isDirectory()) filename += "/index.html";
readFile(filename, "binary", function (err, file) {
if (err) {
response.writeHead(500, { "Content-Type": "text/plain" });
response.write(`${err}n`);
response.end();
return;
}
response.writeHead(200, { "Content-Type": contentType });
response.write(file, "binary");
response.end();
});
});
}).on('upgrade', function (req, socket, head) {
wsProxy.ws(req, socket, head);
}).listen(port);
console.log(`WebUI Aria2 Server is running on http://localhost:${port}`);
当用户访问管理界面的时候,静态资源会直接使用 Node.js 的 HTTP 模块提供服务。而当用户进行下载状态查询,新增下载任务的时候,将通过 Node.js 调用 Aria2 的接口进行处理,并将结果使用 HTTP
或 WS
反馈给用户。
构建镜像
为了方便部署和维护,我们需要将上面的改动记录在 Dockerfile 中。
FROM node:11.12-alpine
LABEL AUTHOR soulteary
ADD webui-aria2/package.json /app/package.json
ADD webui-aria2/package-lock.json /app/package-lock.json
WORKDIR /app
RUN npm install -g yarn && yarn
ADD webui-aria2/ /app
ADD ./patches/configuration.js /app/src/js/services/configuration.js
ADD ./patches/rpc.js /app/src/js/services/rpc/rpc.js
RUN yarn build
RUN yarn add http-proxy
ADD ./patches/node-server.js /app/node-server.js
CMD [ "node", "./node-server.js" ]
执行 docker build -t soulteary/traefik-aria2-with-webui .
,稍等片刻你将得到封装好的容器镜像。
接下来便是使用容器编排工具,正式使用啦。
编排应用
Aria2 的镜像,可以使用 ndthuan/aria2-alpine
,无须重新封装,当然,如果你需要一些新的特性,也可以参考镜像提供的 Dockerfile,进行重新构建。
创建一个 docker-compose.yml
,使用下面的示例代码:
version: '3'
services:
web:
container_name: web
image: ${WEBUI_IMAGE}
expose:
- 8888
networks:
- traefik
environment:
- WEB_PROXY=http://aria2:6800
- WS_PROXY=ws://aria2:6800
labels:
- "traefik.enable=true"
- "traefik.port=8888"
- "traefik.frontend.rule=Host:${BIND_HOSTS}"
- "traefik.frontend.entryPoints=http,https"
aria2:
container_name: aria2
image: ${ARIA2_IMAGE}
volumes:
- ./downloads:/downloads
expose:
- 6800
networks:
- traefik
labels:
- "traefik.enable=false"
networks:
traefik:
external: true
然后再创建一个 .env
文件,在其中填入:
WEBUI_IMAGE=soulteary/traefik-aria2-with-webui
ARIA2_IMAGE=ndthuan/aria2-alpine
BIND_HOSTS=download.lab.com,download.lab.io
使用 docker-compose up
,你将看到类似下面的日志:
Creating web ... done
Creating aria2 ... done
Attaching to aria2, web
aria2 | 2019-04-04T04:28:41Z 48a00033e530 confd[7]: INFO Backend set to env
aria2 | 2019-04-04T04:28:41Z 48a00033e530 confd[7]: INFO Starting confd
aria2 | 2019-04-04T04:28:41Z 48a00033e530 confd[7]: INFO Backend nodes set to
aria2 | 2019-04-04T04:28:41Z 48a00033e530 confd[7]: INFO Target config /etc/aria2.conf out of sync
aria2 | 2019-04-04T04:28:41Z 48a00033e530 confd[7]: INFO Target config /etc/aria2.conf has been updated
aria2 |
aria2 | 04/04 04:28:41 [WARN] Neither --rpc-secret nor a combination of --rpc-user and --rpc-passwd is set. This is insecure. It is extremely recommended to specify --rpc-secret with the adequate secrecy or now deprecated --rpc-user and --rpc-passwd.
aria2 |
aria2 | 04/04 04:28:41 [NOTICE] IPv4 RPC: listening on TCP port 6800
aria2 |
aria2 | 04/04 04:28:41 [NOTICE] IPv6 RPC: listening on TCP port 6800
web | WebUI Aria2 Server is running on http://localhost:8888
在浏览器中打开你在 .env
中定义的域名,不出意外,你将看到属于你的下载应用。
最后
改变习惯不易,尤其是你周围的环境都在使用其他看起来更“标准成熟”的方案时。
但是一旦当你用惯了 Traefik + Docker 之后,你会发现你的服务搭建效率远比使用 Nginx 加 vhost 高的多。
最近快忙晕了,临近小长假,补全了这篇拖了十天的文章,仓促成文,难免有纰漏,欢迎留言指正。