You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

自定义构建Erlang容器启动inet_tls分布式协议失败求助

自定义构建Erlang容器启动inet_tls分布式协议失败求助

我懂你现在的困扰——不管是自己编译OTP 27.2还是用官方镜像,启动Erlang节点指定inet_tls分布式协议时,都会碰到「Protocol 'inet_tls': not supported」的报错,这确实挺让人挠头的。我来帮你拆解下问题根源,再给出具体的解决步骤。

核心错误原因

inet_tls分布式协议的实现依赖Erlang的ssl应用提供底层支持,如果启动节点时ssl应用还没加载,Erlang内核就找不到这个协议的实现代码,自然会抛出「协议不支持」的错误。不管是自定义编译的OTP还是官方镜像,都需要解决这个加载顺序的问题。


办法1:调整启动命令,确保ssl应用提前加载

直接修改你的docker run启动命令,在指定-proto_dist inet_tls之前先启动ssl应用,有两种简单的方式:

方式A:用-eval参数手动启动ssl应用

docker run \
  -d \
  --name node1 \
  --hostname node1 \
  --network mynet \
  erlang-epmdless \
  erl \
  -name node1@node1 \
  -eval "application:ensure_all_started(ssl)." \
  -proto_dist inet_tls \
  -ssl_dist_optfile /app/ssl_dist.conf \
  -epmd_module epmd_static_map \
  -start_epmd false \
  -noshell

方式B:用-ssl参数自动加载ssl应用

Erlang提供了快捷参数-ssl,可以自动初始化并启动ssl应用,命令更简洁:

docker run \
  -d \
  --name node1 \
  --hostname node1 \
  --network mynet \
  erlang-epmdless \
  erl \
  -name node1@node1 \
  -ssl \
  -proto_dist inet_tls \
  -ssl_dist_optfile /app/ssl_dist.conf \
  -epmd_module epmd_static_map \
  -start_epmd false \
  -noshell

办法2:检查自定义编译OTP的完整性(针对第一个Dockerfile)

如果你是自己编译OTP 27.2,需要先确认inet_tls模块是否真的被编译进了OTP:

  1. 在你的Dockerfile的**Stage 1(编译阶段)**末尾,添加一行检查命令,验证模块是否存在:
# 在Stage 1的`make install`之后添加
RUN /opt/erlang/bin/erl -noshell -eval "io:format('inet_tls模块路径: ~p~n', [code:which(inet_tls)])." -s init stop

构建镜像时,如果输出类似inet_tls模块路径: "/opt/erlang/lib/ssl-10.9/ebin/inet_tls.beam"的内容,说明模块存在;如果输出non_existing,则需要调整编译参数:
2. 修改OTP的configure命令,确保编译所有与SSL相关的模块:

# 替换原有的configure命令
RUN ./configure --prefix=/opt/erlang --with-ssl --enable-all --enable-tls

--enable-all会强制编译所有可选的OTP应用,确保ssl应用及其关联的inet_tls模块被完整包含。


办法3:确认ssl_dist.conf配置文件的正确性

即使协议支持了,如果TLS配置文件有问题,后续也会出现握手失败。你的ssl_dist.conf需要和生成的证书路径完全匹配,这里给你一个可用的示例配置(放在/app目录下):

[{server, [
    {certfile, "/etc/pki/tls/certs/localhost.crt"},
    {keyfile, "/etc/pki/tls/private/localhost.key"},
    {cacertfile, "/etc/pki/tls/certs/localhost.crt"},
    {secure_renegotiate, true}
]},
{client, [
    {certfile, "/etc/pki/tls/certs/localhost.crt"},
    {keyfile, "/etc/pki/tls/private/localhost.key"},
    {cacertfile, "/etc/pki/tls/certs/localhost.crt"},
    {verify, verify_peer},
    {fail_if_no_peer_cert, false},
    {secure_renegotiate, true}
]}].

验证问题是否解决

启动节点后,你可以通过以下命令验证节点是否正常运行:

# 进入容器执行Erlang命令,尝试连接到节点1
docker exec -it node1 erl -name checker@node1 -remsh node1@node1 -proto_dist inet_tls -ssl_dist_optfile /app/ssl_dist.conf -epmd_module epmd_static_map -start_epmd false

如果能成功进入节点1的shell,说明问题已经解决;如果还有错误,可以查看容器日志定位细节:

docker logs node1

额外注意事项

  • 官方的erlang:27镜像已经包含了完整的ssl应用,不需要额外编译,用这个镜像时只需要调整启动命令即可。
  • 你生成的证书CN是localhost,但节点hostname是node1,后续TLS握手可能会出现主机名不匹配的警告。测试环境下可以在ssl_dist.conf的client和server配置里添加{verify_fun, {fun(_, _, _) -> {valid, undefined} end, undefined}}来关闭主机名验证;生产环境建议生成与节点hostname匹配的证书。

火山引擎 最新活动