Kubernetes + Openresty+OpenIM
1. 关于
最近公司需要,研究了openim,有点麻烦,记录一下
1.1. 文档
开源地址:https://github.com/OpenIMSDK
- 官方文档:
https://doc.rentsoft.cn/#/?id=我们的使命
- api接口文档:
https://doc.rentsoft.cn:8000/swagger/index.html
1.2. 环境依赖
OpenIM使用的组件包含MQ和各种数据库组件,保证系统当前可用内存在2G及以上,官方使用docker版本为20.10.14,docker-compose版本为1.24.1,如果用户的系统没有安装docker以及docker-compose可以参照docker以及docker-compose环境搭建。
1.3. 开放端口
IM端口 |
说明 |
操作 |
TCP:10001 |
ws协议,消息端口,比如消息发送,推送等。 |
端口放行或nginx反向代理,关闭防火墙 |
TCP:10002 |
api端口,比如用户、好友、群组等接口。 |
端口放行或nginx反向代理,关闭防火墙 |
TCP:10003 |
ws协议,针对jssdk的专用端口。 |
端口放行或nginx反向代理,关闭防火墙 |
TCP:10004 |
demo使用的用户注册登录端口。 |
端口放行或nginx反向代理,关闭防火墙 |
TCP:10005 |
选择minio存储时需要开通。(openIM的demo默认使用minio存储) |
端口放行或nginx反向代理,关闭防火墙 |
TCP:10006 |
管理后台api端口,需要管理后台服务时开通。 |
端口放行或nginx反向代理,关闭防火墙 |
注:如果使用nginx做反向代理,则只需要开放443端口即可,进行中转。
1.4. 服务分工
1、ETCD(version:{"etcdserver":"3.3.8","etcdcluster":"3.3.0"})//服务注册与发现
2、MySQL(version:5.7)//用户业务信息以及管理后台查询消息使用
3、MongoDB(version:4.0.28)//线上消息存储
4、Redis(version:redis_version:7.0.0)//业务信息缓存,以及seq缓存
5、Kafka(version:kafka_2.13-2.8.1,依赖于组件zookeeper(version: 3.4.13-2d71af4dbe22557fda74f9a9b4309b15a7487f03))//消息队列,消息总线解耦
6、Minio(version:minio version RELEASE.2022-05-26T05-48-41Z)//私有化对象存储服务,用于图片、语音、文件等存储在自己的服务器中(注:如果使用三方云服务器存储媒体文件可不搭建)
2. openim服务部署
2.1. 部署
2.1.1. 下载代码
git clone https://github.com/OpenIMSDK/Open-IM-Server.git
2.1.2. 修改配置文件
配置文件路径:config/config.yaml
- mysql配置修改(必须):
dbMysqlAddress: [xxx.xxx.xxx.xxx:13306 ]
# 不要采用127.0.0.1,则无法发送消息,没有任何报错;就算你mysql搭建在本地也不行,不知道为啥
- minio配置修改(必须):
endpoint: http://10.0.22.124:10005 #minio外网ip 这个ip是给客户端访问的
endpointInner: http://10.0.22.124:10005 #minio内网地址 如果im server 可以通过内网访问到 minio就可以填写
2.1.3. 部署
cd Open-IM-Server
docker-compose up -d
2.1.4. 镜像查看
2.1.5. 脚本检测
- docker_check_service.sh
qiteck@logic2:~/program/open_im/Open-IM-Server/script$ sudo ./docker_check_service.sh
openImSdkWsPort service does not start normally,not initiated port is 10003, 这个没有开启的话,目前看起来是没有问题
- check_all.sh
qiteck@logic2:~/program/open_im/Open-IM-Server/script$ sudo ./check_all.sh
openImSdkWsPort service does not start normally,not initiated port is 10003, 这个没有开启的话,目前看起来是没有问题
2.1.6. URL检测
看下该URL:http://xxx.xxx.xxx.xxx:10004/demo/login, 是否返回这个:
{
"errCode": 10001,
"errMsg": "EOF"
}
返回这个,表示网络是通的,只是参数是错误的,没有权限
2.2. 遇到问题
2.2.1. check_all的时候提示10001异常
等一伙,等启动完成一般就没有问题了。长期这个问题的话,看下日志
2.2.2. etcd-endpoints://0xc0005b6540/127.0.0.1:2379",=>rpc error: code = DeadlineExceeded
open im无法共用k8s的etcd,需要重新搭建。
2.2.3. Couldn't resolve host name. Please check the domain
是启动还没有完成的意思,等等就好了
2.2.4. mongo提示WiredTiger.wt: fatal read error: WT_ERROR: non-specific WiredTiger error
删除/component/mongodb的数据就可以正
2.2.5. openImSdkWsPort service does not start normally,not initiated port is 10003
这个错误是无所谓的,sdk ws都可以不需要配置
2.2.6. 服务器清空redis的缓存,导致客户端发送消息无法被对方接收到,并可能有相关提示WS ReadMsg error userIP 10.0.22.112:50163 userUid platform error websocket
确认的规避方法:客户端app需要杀掉,重新安装才行。
猜想思路:redis和客户端都存储了一些ws的相关信息,这些信息在服务器上没有永久存储,redis清空了以后,服务器找不到相关ws信息,导致客户端发送对方收不到;而重装以后,客户端也没有了ws信息,这时候会重新找服务器沟通,重建ws相关信息。
解决方案:
1. 客户端每次启动不缓存数据,客户端进一步看下问题
2. redis不能清空
2.2.7. 使用k8s的etcd,报错retrying of unary invoker failed
k8s的etcd服务是一个https服务,而openim只可以连接http协议
另外k8s的etcd有限制ip连接,需要改进k8s的etcd配置部署
我没有去研究怎么使用k8s的etcd,而是另外搭建一个etcd服务器
2.2.8. 使用k8s的etcd,报错/demo/login返回{"errCode": 10005,"errMsg": "“}
原因是因为users表里面没有对应的账号信息。
registers里面有没有和这个错误无关
2.2.9. imdb.GetUserByUserID failed record not found
详细错误信息是这样:
2022-07-27 09:41:31.424^[[36m [INFO] [PID:29] [FilePath:auth/auth.go:132] [OperationID:EF8C265E-F869-41B4-A327-94E8619F568A] ^[[0m[UserToken return {{802 EF8C265E-F869-41B4-A327-94E8619F568A imdb.GetUserByUserID failed record not foundtest3} {test3 0}}]
2022-07-27 09:41:31.424^[[31m [ERRO] [PID:522] [FilePath:register/login.go:74] [OperationID:EF8C265E-F869-41B4-A327-94E8619F568A] ^[[0m[request get user token test3 err ]
原因是因为users表里面没有对应的账号信息。
registers里面有没有和这个错误无关
2.2.10. 抓包显示handshake failed
如果是这个接口http://10.0.22.124:10004/demo/login抓包显示handshake failed,可以采用proxyman试着请求一下 post http://10.0.22.124:10004/demo/login,看是否返回这个:
{
"errCode": 10001,
"errMsg": "EOF"
}
返回这个,表示网络是通的,只是参数是错误的,没有权限
这个错误最后发现是openim不支持采用proxyman进行代理,不能proxyman的证书
2.2.11. 此服务器的证书无效。您可能正在连接到一个伪装成“api.test.magefitness.com”的服务器,这会威胁到您的机密信息的安全。
如果确定证书没有问题的情况下,是否有开启proxyman中转抓包,openim会验证证书的有效性,不能中间人攻击。
openim不支持采用proxyman进行代理,不能proxyman的证书
2.2.12. /openim/?location= HTTP/1.1" 404 159 "-" "MinIO (ios; arm64) minio-go/v7.0.22
这个就是说吗minio的proxy设置的有问题,需要单独配置,需要/转发,不能设置其他path
server {
listen 443;
server_name storage.rentsoft.cn;
location / {
proxy_pass http://127.0.0.1:10005;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
}
3. k8s+openresty https转发
3.1. 参考文档
参考官方文档: https://doc.rentsoft.cn/#/v2/server_deploy/nginx_config
3.2. openim配置
假设openim服务部署在10.17.0.94机器上
server {
listen 773 ssl;
server_name localhost;
ssl_certificate /usr/local/openresty/nginx/cert/primary.pem;
ssl_certificate_key /usr/local/openresty/nginx/cert/key.pem;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";
location /openim_rtc/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://10.17.0.94:7880/;
}
location /openim_msg_gateway/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://10.17.0.94:10001/;
}
location /openim_api/ {
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 X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://10.17.0.94:10002/;
}
location /openim_jssdk_gateway/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://10.17.0.94:10003/;
}
location /openim_demo/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://10.17.0.94:10004/;
}
location /openim_cms/ {
proxy_http_version 1.1;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://10.17.0.94:10006/;
}
}
注意这里的各种各种斜杆的配置规则
3.3. minio配置
发送文件/图片/视频等选择minio
Minio需要单独转发
server {
listen 783 ssl;
server_name localhost;
ssl_certificate /usr/local/openresty/nginx/cert/primary.pem;
ssl_certificate_key /usr/local/openresty/nginx/cert/key.pem;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable "MSIE [1-6]\.”;
location / {
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 X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://172.17.0.94:10005;
}
}
注意,minio需要跟路径转发,不能设置任何path,不然会提示:
"GET /openim/?location= HTTP/1.1" 404 159 "-" "MinIO (ios; arm64) minio-go/v7.0.22" "-"
3.4. k8s service配置
apiVersion: v1 kind: Service metadata: name: gateway spec: type: NodePort externalTrafficPolicy: Local selector: app: gateway ports:- protocol: TCP port: 1773 targetPort: 773 nodePort: 1773 name: openim-port - protocol: TCP port: 1783 targetPort: 783 nodePort: 1783 name: minio-openim-port
opemim的pod的端口是773,service端口是1773
minio的pod的端口是783,service端口是1783
3.5. openim服务器修改
假设外网地址是www.test.com
唯一需要修改的地方是minio的地址:
credential: #腾讯cos,发送图片、视频、文件时需要,请自行申请后替换,必须修改 minio: #MinIO 发送图片、视频、文件时需要,请自行申请后替换,必须修改。 客户端初始化InitSDK,中 object_storage参数为minio bucket: openim # 存储内容桶 appBucket: app # 存储app的桶 location: us-east-1 endpoint: https://www.test.com:1783 #minio外网ip 这个ip是给客户端访问的 endpointInner: http://127.0.0.1:10005 #minio内网地址 如果im server 可以通过内网访问到 minio就可以填写 endpointInnerEnable: true #是否启用minio内网地址 启用可以让桶初始化,IM server连接minio走内网地址访问 accessKeyID: user12345 secretAccessKey: key12345
endpoint需要改成实际的外网地址
3.6. openim客户端修改
// 初始化SDK
IMController.shared.setup(
apiAdrr: “https://www.test.com:1773/openim_api",
wsAddr: “wss://www.test.com:1773/openim_msg_gateway/“
)
Let API_BASE_URL = “https://www.test.com:1773/openim_demo”
注意:openim_api和openim_demo它完整的url有其他参数,例如这样http://www.test.com:1773/openim_demo/demo/login,自己会带上斜杆。
但是这里wsaddr的地址必须要带上斜杆,因为它没有其他参数,所以不会自动添加斜杆,但是nginx配置那边是这样配置的:
location /openim_msg_gateway/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://172.17.0.94:10001/;
}
至此就可以使用openim进行聊天了