需求
最近在尝试用基于golang的游戏服务器框架origin开发一个游戏后端,由于游戏服务器需要有多个服(进程),一个服务器进程为一个结点,但引擎的指令不支持一次启动多个结点。
如果需要启动多个结点要开多个终端启动,非常不方便。因此想到使用docker部署进行多结点一次启动。
结点配置如下: 网关服、中心服和游戏服各一个
{
"NodeList":[
{
"NodeId": 1001,
"Private": false,
"ListenAddr": "127.0.0.1:8011",
"NodeName": "Node_Gate",
"remark": "游戏网关服",
"ServiceList": ["Gate"]
},
{
"NodeId": 2001,
"Private": false,
"ListenAddr": "127.0.0.1:8021",
"NodeName": "Node_Center1",
"remark": "游戏中心服",
"ServiceList": ["Center"]
},
{
"NodeId": 3001,
"Private": false,
"ListenAddr": "127.0.0.1:8031",
"NodeName": "Node_Game1",
"remark": "游戏服",
"ServiceList": ["Game"]
}
]
}
单结点启动如下:
docker镜像配置
看网上其他帖子,应该是可以直接下载带对应golang版本的docker镜像,但我是先下载了个Ubuntu镜像,用镜像启动一个临时容器,在容器里配置好相关环境再打包成自己的镜像。
如何生成自己需要的镜像:
(1) 查看所有镜像
docker images
(2) 指定镜像启动容器
docker run -it imageId/imageName bash
(3) 安装各种需要的环境
(4) 导出镜像
docker export -o yourImage.tar containerId
(5) 导入镜像
docker import yourImage.tar yourImageName
docker-conmpose容器管理
因为游戏服一个结点需要在一个结点中运行,因此需要启动多个容器,对多个容器的统一管理可以使用docker-compose
目前我没有使用Dockerfile去build自己的镜像,仅仅是通过docker-compose对容器进行编排
(1)需要管理的资源路径下新建docker-compose.yml文件
(2)根据自己需要填写yml文件
version: '2.4' # yaml文件版本
services: # 服务:一个容器对应一个服务器
gate:
image: d3-server # 指定对应的镜像
ports:
- "8011:8011" # 容器和宿主机的端口映射
command: # 容器启动后需要执行的指令
- bash
- -c
- |
cd ./src/server
/usr/local/go/bin/go run ./main.go -start nodeid=1001
container_name: "gate" # 容器名称
networks: # 网络
- dev
volumes: # 文件映射
- .:/app
working_dir: /app # 工作路径
tty: true # 容器内前台启动
center:
image: d3-server
ports:
- "8021:8021"
command:
- bash
- -c
- |
cd ./src/server
/usr/local/go/bin/go run ./main.go -start nodeid=2001
container_name: "center"
networks:
- dev
volumes:
- .:/app
working_dir: /app
tty: true
game:
image: d3-server
ports:
- "8031:8031"
command:
- bash
- -c
- |
cd ./src/server
/usr/local/go/bin/go run ./main.go -start nodeid=3001
container_name: "game"
networks:
- dev
volumes:
- .:/app
working_dir: /app
tty: true
networks:
dev:
driver: bridge
pro:
driver: bridge
(3)启动docker容器
前台启动:docker compose up
后台启动:docker compose up -d
疑难杂症
docker部署的过程中遇到非常多问题,有些在网上找不到非常确切的答案,只能靠自己一步步摸索,因此记录一下
1、文件映射后找不到路径
在yaml文件中的volumes中已经配置了将当前路径映射到容器内根目录下的/app,但是启动容器后却报错找不到路径
# 以game结点配置为例
game:
image: d3-server
ports:
- "8031:8031"
command:
- bash
- cd ./src/server
- go run ./main.go -start nodeid=3001
container_name: "game"
networks:
- dev
volumes:
- .:/app
working_dir: /app
tty: true
用命令直接启动容器并映射文件路径,查看路径发现映射很正常
启动命令:docker run -it -v .:/app d3-server bash
查了很多资料,发现docker启动的时候用的是sh shell,使用bash shell执行指令需要bash -c "xxx",因此在yaml中的command中加上 -c
2、容器启动后exit 0
在yaml的command的bash指令加上-c参数后,发现容器没有报错,但是没有启动结点直接exit 0
由于cd指令没有报错,因此加入一条ls指令观察容器内路径是否正常
# 以game结点配置为例
game:
image: d3-server
ports:
- "8031:8031"
command:
- bash
- -c
- ls
- cd ./src/server
- go run ./main.go -start nodeid=3001
container_name: "game"
networks:
- dev
volumes:
- .:/app
working_dir: /app
tty: true
可以看到此时app下是有对应的映射文件的,猜测是command指定多条指令的配置问题,上网又查了一番,原来command执行多条指令有两种写法、
(1)多条指令串行运行
command:
- bash
- -c
- |
cmd1
cmd2
cmd3
(2)多条指并行运行
command:
- bash
- -c
- |
cmd1 &
cmd2 &
cmd3 &
3、容器启动后go: command not found
# 以game结点配置为例
game:
image: d3-server
ports:
- "8031:8031"
command:
- bash
- -c
- |
cd ./src/server
go run ./main.go -start nodeid=3001
container_name: "game"
networks:
- dev
volumes:
- .:/app
working_dir: /app
tty: true
首先容器中是存在go环境的,但是为什么会找不到go相关指令?思考了一下,因为是通过bash -c执行指令,执行的是shell指令,但go不属于shell指令,因此报错找不到指令
解决办法:
(1)进入容器,which go查看go所在路径
(2)yaml中的command涉及go的改为绝对路径\
修改后:
# 以game结点配置为例
game:
image: d3-server
ports:
- "8031:8031"
command:
- bash
- -c
- |
cd ./src/server
/usr/local/go/bin/go run ./main.go -start nodeid=3001
container_name: "game"
networks:
- dev
volumes:
- .:/app
working_dir: /app
tty: true