Deno で unix ドメインソケットを使ってnginxと連携(失敗)

仮に Deno でサービス提供するサーバーを用意するなら nginx との連携は、unix ドメインソケット使うんだろな?と見込んで試しました。

結論としては、できなかったのでポート転送しました。

参考

作るもの

denoland/deno:centos docker イメージを使用して、nginx をインストール。
deno アプリが提供する unix ドメインソケットを使って nginx と連携させる。

各種ファイル

Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FROM denoland/deno:centos

RUN yum update -y && \
rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm && \
yum install -y nginx && \
# nginx設定
systemctl enable nginx.service && \
# /etc/nginx をホスト側でマウントした時に空になるので別ディレクトリでバックアップ
# entrypoint.sh でマウント後にバックアップから復元
cp -pr /etc/nginx /etc/nginx_defult

RUN mkdir /usr/src/app
WORKDIR /usr/src/app

ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

EXPOSE 80
EXPOSE 443
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: "3"
services:
app:
build:
context: .
privileged: true
command: /sbin/init
#entrypoint:
# - /sbin/init
ports:
- "127.0.0.1:${HTTP_PORT:-80}:80"
- "127.0.0.1:${HTTPS_PORT:-441}:441"
volumes:
- .:/usr/src/app:cached
# nginx 設定関連もホスト側で管理する
- ./nginx:/etc/nginx/
tty: true
D:\development\test\test290-deno-unix\entrypoint.sh
1
2
3
4
5
6
#!/bin/sh

# nginx設定ファイル群をバックアップから復元存在しているファイルは上書きしない
cp -rp --no-clobber /etc/nginx_defult/* /etc/nginx

exec "$@"

ここまで出来たら、起動。

1
2
3
$ docker-compose build
$ docker-compose up -d
$ docker-compose exec app bash

起動のタイミングで、nginx ディレクトリ以下に、デフォルトの nginx のファイル群がコピーされている。

nginx 設定修正

nginx/conf.d/deno-app.conf を作成。

nginx/conf.d/deno-app.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
upstream deno_app_unix {
server unix:///usr/src/app/tmp/deno.sock;
}

server {
listen 80 default_server;
server_name _;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

root /root/testapp/public;

location / {
try_files $uri @deno_app;
}

location @deno_app {
proxy_pass http://deno_app_unix;
}
}

nginx/nginx.conf について修正。

nginx/nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# user nginx; をコメントアウトし修正、dockerでテスト用にnginxをrootで実行するが本番環境ですべきではないだろう
user root;

# 省略

# もともと設定されている server をコメントアウトしておく
# server {
# listen 80 default_server;
# listen [::]:80 default_server;
# server_name _;
# root /usr/share/nginx/html;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# location / {
# }
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }

起動

deno 側のアプリケーションは、以下の通り。
実は、deno の unix ドメインソケット対応は、現在も不安定なものであるらしく、どうも微妙。

server.ts
1
2
3
4
5
6
7
8
9
10
const listener = await Deno.listen({
path: "tmp/deno.sock",
transport: "unix",
});

const conn = await listener.accept();

for await (const chunk of Deno.iter(conn)) {
console.log(new TextDecoder().decode(chunk));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ systemctl start nginx
$ nginx -t
$ nginx -s reload
$ mkdir tmp
$ deno run --unstable --allow-read --allow-write server.ts

# ブラウザで、localhost:80にアクセス
# 一部情報はマスクしています
GET / HTTP/1.0
Host: localhost
X-Real-IP: xxx.xxx.xxx.xxx
X-Forwarded-Host: localhost:80
X-Forwarded-Server: localhost
X-Forwarded-For: xxx.xxx.xxx.xxx
Connection: close
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"
sec-ch-ua-mobile: ?0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Cookie: _ga=GA1.1.920809382.1611667431; _gid=GA1.1.1380512102.1628268526

アクセスがあることは、拾えます。
サーバーアプリケーションとして、使えるかと、deno でよく見るシンプルなサーバーを書いてみます

server.ts
1
2
3
4
5
6
7
import { serve } from "https://deno.land/std@0.103.0/http/server.ts";
const s = serve({ path: "tmp/deno.sock", transport: "unix" });

console.log("tmp/deno.sock");
for await (const req of s) {
req.respond({ body: "Hello World\n" });
}

実行すると、エラーに。

1
2
3
4
5
6
7
$ deno run --unstable --allow-read --allow-write server.ts

error: TS2345 [ERROR]: Argument of type '{ path: string; transport: string; }' is not assignable to parameter of type 'string | HTTPOptions'.
Object literal may only specify known properties, and 'path' does not exist in type 'HTTPOptions'.
const s = serve({ path: "tmp/deno.sock", transport: "unix" });
~~~~~~~~~~~~~~~~~~~~~
at file:///usr/src/app/server.ts:21:19

std@0.103.0/http/server.ts が、unix ドメインソケット対応がないようです。
まぁ、stable な機能でもないので、仕方がないことかもしれません。

仕方ないので、ポートフォワードで対応

nginx/conf.d/deno-app.conf を修正。

nginx/conf.d/deno-app.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
upstream deno_app_port {
server localhost:8000;
}

server {
listen 80 default_server;
server_name _;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

root /root/testapp/public;

location / {
try_files $uri @deno_app;
}

location @deno_app {
proxy_pass http://deno_app_port;
}
}

server.ts を よく見るものに修正。

server.ts
1
2
3
4
5
6
7
import { serve } from "https://deno.land/std@0.103.0/http/server.ts";
const s = serve({ port: 8000 });

//console.log("http://localhost:8000/");
for await (const req of s) {
req.respond({ body: "Hello World\n" });
}

起動すると、次のようになります。

1
2
3
4
5
$ nginx -s reload
$ deno run --allow-net server.ts
http://localhost:8000/

# ブラウザアクセスすると Hello World が返ってくる

まぁ。これならできると想定はしてた。

ついでに Deno アプリを systemd から実行してみる

/etc/systemd/system/deno.service を作成。
環境変数など、読んでない適当なものですが、一旦いいものとします。

/etc/systemd/system/deno.service
1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=DenoApp
After=network.target

[Service]
Type=simple
WorkingDirectory=/usr/src/app
ExecStart=deno run --allow-net server.ts
Restart=always

[Install]
WantedBy=default.target

作ったら、次のコマンドで起動。

1
2
3
4
$ systemctl start deno
$ ps aux |grep deno
root 377 1.2 0.5 4721192 123556 ? Ssl 03:30 0:02 /usr/bin/deno run --allow-net server.ts
root 387 0.0 0.0 12132 1188 pts/1 S+ 03:32 0:00 grep --color=auto deno

サービスとして、deno アプリを起動できました。
本番運用するときはこういった形がよさそうです。


というわけで、unix ドメインソケットで nginx と連携は、できませんでした。
std@0.103.0/http/server.ts を使わずに Deno.serveHttp 使うことも試しましたが、エラー。
追々、サポートされるといいね。って感じでした。

ではでは。