不科学上网的操作
依次访问:
找到 DNS Resource Records 下的 ip 地址。依次加入到 hosts 中。
# mac 的
sudo vim /etc/hosts
140.82.113.4 github.com
151.101.1.194 github.global.ssl.fastly.net
这样再提交代码,估计就可以了。至少我试过是可以了的。
不行,刷新 DNS 缓存试试。
sudo killall -HUP mDNSResponder
找到 DNS Resource Records 下的 ip 地址。依次加入到 hosts 中。
# mac 的
sudo vim /etc/hosts
140.82.113.4 github.com
151.101.1.194 github.global.ssl.fastly.net
这样再提交代码,估计就可以了。至少我试过是可以了的。
不行,刷新 DNS 缓存试试。
sudo killall -HUP mDNSResponder
对于 github 这类服务,一个 ssh-key 只允许添加一次。也就是你在 a 账号添加了 ssh-key,再想用这个 ssh-key 添加到 b 账号是不行的。这个时候,就需要在该 ssh-key 的电脑上生成新的 ssh-key 来满足多账号的需求。
那么问题也来了,这就需要每次都要指定 git 项目对应的 ssh-key。方法自然是有的。方法有好几个,只用最方便的吧。
假如按照上边的操作,生成了 ssh-key,也将其公钥添加到配置中了。那么只需要指定当前所使用的 ssh-key 就可以了。
# 添加
ssh-add ~/.ssh/ssh-key-私钥
# 查看
ssh-add -l
# 删除
ssh-add -d ~/.ssh/ssh-key-私钥
这样就可以使用 git 来操作代码了。 clone push pull 都是可以的。
不过,这个电脑重启后,就失效了。还是会使用默认的 ssh-key
执行 ssh-add xxx
的时候也许不是顺利的。可能会有下边的报错。
Could not open a connection to your authentication agent.
。
解决:
先看看 ssh 代理是否在运行。 ssh-agent -s
。如果没运行,启动它。如果运行了,看 SSH_AUTH_SOCK 环境变量是否存在。echo $SSH_AUTH_SOCK
如果出现上边那个错误,走到这里了,应该是不存在的,也就是输出为空格。那么重新启动 ssh 代理。再回过去检查。
eval "$(ssh-agent -s)"
在写代码之前,先了解一些 api 和 组件。
skynet.manager
是 skynet
框架中的一个重要组件,它负责管理和调度所有的服务。其主要作用包括:
总的来说,skynet.manager 在 kynet 框架中扮演着中心协调者的角色,它使得服务的交互更加高效、可靠和灵活。
skynet.cluster 是一个用于实现集群功能的模块。它提供了一种机制,使得多个 skynet 节点可以形成一个集群,并实现节点间的通信和协作。其主要作用包括:
总的来说,skynet.cluster 在 skynet 框架中提供了集群功能,使得多个 skynet 节点可以形成一个协同工作的整体,并实现高效、可靠的节点间通信和协调。它简化了分布式系统的构建和管理,使得开发者能够更轻松地构建高可用性、高性能的分布式应用程序。
然后,发现 skynet.manager 的作用和 skynet.cluster 的作用似乎有重合。又是怎么会事呢。
在 skynet 框架中,skynet.manager 和 skynet.cluster 虽然都涉及到了服务管理和集群的功能,但它们的作用和侧重点是有所不同的。
skynet.manager 更侧重于单个 skynet 节点内部的服务管理和调度。它主要负责在单个节点内部协调各个服务的运行,包括服务的注册、发现、负载均衡、监控等。skynet.manager 确保了单个节点内的服务能够高效、可靠地运行,并为其提供了一系列的管理和调度功能。
而 skynet.cluster 则更侧重于多个 skynet 节点之间的集群管理和通信。它主要负责实现多个节点间的通信、协调和管理,以形成一个协同工作的整体。skynet.cluster 提供了节点间消息传递、服务发现、集群管理等功能,使得多个节点可以形成一个分布式系统,并能够进行高效的节点间通信和协作。
虽然两者都涉及到了服务管理和集群的功能,但它们的关注点是不同的。skynet.manager 关注单个节点内部的服务管理,而 skynet.cluster 则关注多个节点间的集群管理和通信。在实际使用中,它们可以相互配合,共同实现分布式系统的构建和管理。
基础镜像构建好了之后,就可以使用镜像来构建容器,从而来进行服务。这里想创建一个 websocket 服务的项目。
这里可以有几个文章可以参考:
https://blog.csdn.net/linxinfa/article/details/120573016
https://github.com/Skycrab/skynet_websocket
按照 https://blog.csdn.net/linxinfa/article/details/120573016 的博客,对文件进行分类安排,创建基础文件夹和文件。如下所示:
│ .dockerignore
│ docker-compose.yaml
│
├─service
│ └─skynet
│ Dockerfile
│
└─www
└─websocket
│ main.lua
│
├─etc
│ cluster.lua
│ config
│
├─luaclib
├─lualib
└─service
对于 skynet
, config 文件会作为入口文件。而这个 config 文件可以是项目中任何位置,因为是由 skynet config
来明确指定的。不过,依照前人的约定习惯,把 config 文件放在 ./websocket/etc/
下。
再来全局来看项目结构。最外层是 docker 相关的配置。 www 目录是项目的总和。这样是方便存放项目。今天存放一个 websocket 的项目,明天可能就会存放 socket.io 的项目。
在 websocket 项目中结果,还是遵循前人的约定习惯。
到此,仅可以看到创建的一些文件夹和两个文件:config 文件和 main.lua 文件。cluster.lua 暂时是空的。
config 文件你也可以命名为 config.lua 文件。
config.lua 作为入口文件,其地位当然是举足轻重的。来看看里边的内容。
-- 根目录
skynet_path = '/skynet'
service_path = '/www/websocket'
-- 节点名称
node = 'node_1'
-- 启用工作线程数 | c 编写的服务模块的位置 | 启动第一个服务
thread = 8
cpath = skynet_path .. '/cservice/?.so'
bootstrap = 'snlua bootstrap'
-- 主程序入库 | 适用 cluster 的集群模式
start = 'main'
harbor = 0
-- lua 配置项
lualoader = skynet_path .. '/lualib/loader.lua'
luaservice = skynet_path .. "/service/?.lua;" .. service_path .. "/?.lua"
lua_path = skynet_path .. "/lualib/?.lua;" .. skynet_path .. "/lualib/?/init.lua;" .. service_path .. "/?.lua"
lua_cpath = skynet_path .. "/luaclib/?.so;" .. service_path .. "/luaclib/?.so"
skynet_path 配置的是 skynet 的安装的位置。
service_path 配置的是项目的位置。
这两个位置下边的配置会用到。
代码中,也加了一些注释说明。下边用表格的方式,再说明一次。
参数 | 描述 |
---|---|
thread | 启用的工作线程数量,一般配置为CPU核心数 |
harbor | 主从节点模式。skynet 初期提供了 master/slave 集群模式,后来提供了更适用的 cluster 集群模式,建议使用 cluster 模式,配 0 |
cpath | 用 C 语言编写的服务模块的路径。cpath 配置项通常用于指定 C 模块的搜索路径。它不是必须的,但是如果你需要在你的服务中使用 C 编写的模块,那么你需要配置 cpath 来指定这些模块的位置。cpath 应该放在 bootstrap 配置之前,因为 bootstrap 会使用 cpath 指定的路径来加载 C 模块。如果你没有配置 cpath,那么你的服务将无法找到和加载C模块。因此,根据你的需求,你可能需要根据你的具体路径来配置 cpath |
bootstrap | 指定 skynet 启动时的第一个服务以及其启动参数。默认配置为 snlua bootstrap,即启动一个名为 bootstrap 的lua服务,通常指的是 service/bootstrap.lua 这段代码。这个服务是启动其他服务的入口点,并且会根据配置文件中的其他参数来加载和启动其他服务。因此,bootstrap 是用于引导 skynet 系统启动的重要配置选项。 |
start | 主服务入口 |
luaservice | 用于指定 Lua 服务的路径。它通常是一个字符串,包含了服务的名称或路径。在配置文件中,你可以指定多个服务,用分号(;)分隔。(包括 skynet 框架自带的一些服务和自己写的服务。) |
lualoader | lua 脚本加载器。用于配置调用哪一段Lua代码加载Lua服务。通常配置为lualib/loader.lua,由这段代码解析服务名称,进一步加载Lua代码。snlua会将核心配置项取出,放置在初始化好的Lua虚拟机的全局变量中。 |
lua_path | lua_path用于指定Lua模块的搜索路径。它通常是一个字符串,包含了多个路径,用分号(;)分隔。 |
lua_cpath | 用于指定C模块的搜索路径。它通常是一个字符串,包含了多个路径,用分号(;)分隔。 |
最后啰嗦一下。在 config 中配置的信息,在后续的逻辑中都可以通过 skynet.getenv
方法获取到。在这里,不需要使用 skynet.setenv
方法来明确设置。
skynet.setenv
有一个严格的问题,就是不能对已存在的变量进行设置。相对于一个 const
的行为。
虽然吧,在其他地方通过 skynet.getenv
方法获取到。但是也能通过 skynet.setenv
进行赋值一次。再第二次赋值就会报错。
从显现来看,虽然可以通过 skynet.getenv
方法获取到 config
中的参数,那似乎不是通过 skynet.setenv
的方式来传递的。
再来看 main.lua 中的代码。
local skynet = require 'skynet'
skynet.start(function()
skynet.error('hello world')
skynet.error(skynet.exit())
end)
就这么多。
代码都准备好了,最后在 docker-compose.yaml
文件中添加使用镜像,构建容器,启动服务的配置。
…
websocket:
image: skynet:1.7
container_name: websocket
volumes:
- ./www:/www
command: /skynet/skynet /www/websocket/etc/config
depends_on:
- skynet
运行 docker-compose up
看看 。
(base) PS D:\Study\skynet\websocket> docker-compose up
[+] Building 0.0s (0/0) docker:default
[+] Running 2/0
✔ Container skynet1.7 Created 0.0s
✔ Container websocket Created 0.0s
Attaching to skynet1.7, websocket
skynet1.7 exited with code 0
websocket | [:00000002] LAUNCH snlua bootstrap
websocket | [:00000003] LAUNCH snlua launcher
websocket | [:00000004] LAUNCH snlua cdummy
websocket | [:00000005] LAUNCH harbor 0 4
websocket | [:00000006] LAUNCH snlua datacenterd
websocket | [:00000007] LAUNCH snlua service_mgr
websocket | [:00000008] LAUNCH snlua main
websocket | [:00000008] hello world
websocket | [:00000008] KILL self
websocket | [:00000002] KILL self
是不是已经运行起来了,也达到了预期的效果了。
git init -b main
git add .
git commit -m 'init skynet'
用 docker 来部署和使用 skynet 其实也不错。
使用 docker init 命令创建基础的文件。将 Dockerfile
移动到 ./service/skynet/Dockerfile
这里。将 compose.yaml
文件重命名为 docker-compose.yaml
在 Dockerfile
文件中,做这些事情:使用一个基础镜像,安装 git,然后将 skynet 代码下下来,对代码进行编译。
Dockerfile
# syntax=docker/dockerfile:1
FROM alpine:latest
# 更新和安装 alpine 工具
RUN apk add --update alpine-sdk
RUN apk add --no-cache bash
RUN apk add readline-dev readline autoconf libgcc
# 安装 git
RUN apk add git
RUN git clone https://github.com/cloudwu/skynet.git /skynet
WORKDIR /skynet
RUN make linux
修改 compose.yaml 文件。
version: '3.9'
services:
skynet:
build:
context: ./service/skynet
image: skynet:1.7
container_name: skynet1.7
然后运行 docker-compose build 构建镜像。
为什么镜像的 tag 的版本号是 1.7 呢。因为 skynet 在 github 上最后的版本就是 1.7。
https://github.com/feross/simple-peer
https://juejin.cn/post/7271974618565705785
https://github.com/livekit/server-sdk-go
https://github.com/livekit/livekit
https://github.com/coturn/coturn
这里使用 docker
来构建。
先准备一份 docker-compose.yaml
文件。
version: '3.9'
services:
coturn:
image: coturn/coturn
ports:
- 3478:3478
- 5349:5349
volumes:
- ./conf/coturn:/etc/coturn
networks: webrtcnet
networks:
webrtcnet:
name: 'webrtcnet'
driver: bridge
这里配置了端口映射和配置文件。当然配置文件可以不要,这样就空账号密码。ip 随主机 ip。这里加了 volumes
, 可以有,但不一定要用。
./conf/coturn/turnserver.conf 配置文件。这里我全注释掉了。
# listening-port=3478
# tls-listening-port=5349
# external-ip=47.**.**.81
# user=17vision:17vision2024
# realm=17vision.com
然后执行 docker-compose up -d
运行起来。
最后,可以通过 https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ 这个站点进行测试。
操作如下图所示:
有的时候只有一个域名。想让其他的服务也用这个域名和 80 端口。用 nginx 做代理就是一种方式。websocket 通常也会用到。
在这里,有一个域名 xxx.com
,通常使用 https
来访问,比如 https://xxx.com
。加入
, 已经有正在使用的业务。下边的场景都不能去干涉已有的业务场景。https://xxx.com
https://xxx.com/blog/xxx
这个服务,就让其转发到 node.js 的服务的 /xxx
上。那么,nginx 可以这样配置。# Upgrade Connection websockets 和 升级的 http 协议才会用到
location ^~/blog/ {
proxy_pass http://blog:3000/;
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection 'upgrade';
# proxy_cache_bypass $http_upgrade;
}
这里的代理 http://blog:3000/
是因为 docker 构建的同一个网络中的服务叫做 blog,所以可以这么写。如果仅仅是宿主机,可以通过具体的 ip 来弄。
其实,之前我是想通过 rewrite 来实现。代码就是下边这样。只是这样虽然 url 修改了,但是似乎又重新发起请求了,并不是直接到代理那边。以至于添加的 location 无效。具体是什么情况,也不是很了解。毕竟 nginx 不精通,遇到具体的需要就去查询。所以想实现修改 url 又能实现代理,可以用上边的 location 语法。
# Upgrade Connection websockets 和 升级的 http 协议才会用到
location /blog {
rewrite ^/dss(.*)$ $1 last;
proxy_pass http://blog:3000;
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Host $host;
# proxy_set_header Connection 'upgrade';
# proxy_cache_bypass $http_upgrade;
}
主要是因为 node 那边定义的路由就是 /xxx/xxx
, 没有 blog
这一节。
使用 docker 是很方便,有的时候掉进去,却找不到原因。使用 docker-compose 对服务进行编排是一个很常见的场景。当执行 docker-compose up -d 的时候,无论是服务端代码,还是配置代码,都是正确的,日志也是正确的。可是容器总是会 Exited 状态。这个时候就很着急。其实,容器退出的原因一般是因为错误和不在前台运行导致的。既然没有错误,那估计就是容器没在前台运行。
今天使用 alpine 为基础镜像,安装一个 supervisord 作为守护进程,然后就是自己的业务环境 skynet 和 skynet 的业务代码。当以前都配置的很好,编写的很好,状态也很好的时候。容器就是退出。这个是一个很痛苦的事情。其实,还是对容器退出没理解透彻。
下边是启动时候,打印的一些日志。
nanjing_dev | NanjingDevServer STARTING
nanjing_dev | NanjingDevServer RUNNING pid 14, uptime 0:00:50
nanjing_dev | Proto Recv-Q Send-Q Local Address Foreign Address State
nanjing_dev | tcp 0 0 127.0.0.11:33351 0.0.0.0:* LISTEN
nanjing_dev | tcp 0 0 0.0.0.0:8105 0.0.0.0:* LISTEN
nanjing_dev | udp 0 0 127.0.0.11:36173 0.0.0.0:*
没有任何错误。错误就在容器没有在前台运行。因为服务是用 supervisord 来启动的。让 supervisord 在前台运行不就好了。这个时候只需要修改 supervisor_xxx.ini 的配置文件,将启动方式改为前台即可。
[supervisord]
nodaemon=true
就是 nodaemon 设置为 true。 默认是 false 哈。