掘金 后端 ( ) • 2024-04-02 18:53

需求

  最近在尝试用基于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"]
        }
    ]
}

单结点启动如下: 1712048589812.png

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

1712049888662.png

后台启动:docker compose up -d

1712049938248.png

疑难杂症

  docker部署的过程中遇到非常多问题,有些在网上找不到非常确切的答案,只能靠自己一步步摸索,因此记录一下

1、文件映射后找不到路径

1712050330006.png

  在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

1712050760744.png

  查了很多资料,发现docker启动的时候用的是sh shell,使用bash shell执行指令需要bash -c "xxx",因此在yaml中的command中加上 -c

2、容器启动后exit 0

1712051222357.png

  在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

1712051312732.png

  可以看到此时app下是有对应的映射文件的,猜测是command指定多条指令的配置问题,上网又查了一番,原来command执行多条指令有两种写法

  (1)多条指令串行运行

    command:
      - bash
      - -c
      - |
          cmd1
          cmd2
          cmd3

  (2)多条指并行运行

    command:
      - bash
      - -c
      - |
          cmd1 &
          cmd2 &
          cmd3 &

3、容器启动后go: command not found

1712051700436.png

# 以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