0.背景

最近浏览又发现一个新的OJ,HOJ,是基于vue+SpringBoot的,部署用的是Docker,这一点有点像前面我研究的青岛OJ。这篇文章简单记录一下搭建HOJ的过程。

官方地址:HOJ: ⚡🔥Hcode Online Judge(HOJ)🔥⚡:基于SpringCloud与Vue前后端分离,分布式架构的在线测评平台OJ (An open source online judge system base on SpringBoot, Springcloud Alibaba and Vue.js !) (gitee.com)

本文环境:

云服务器(CentOS7.5)、宝塔面板、docker、docker-compose、git

PS:按照官方的说法,并不推荐使用CentOS8以下的版本,本文先做一下尝试,如果失败了

1.基于docker的部署

首先要安装docker,具体安装过程可以参考我前面写的文章:

CentOS(宝塔面板)安装docker – 每天进步一点点 (longkui.site)

安装完docker后,参考下面这篇文章安装docker-compose

linux如何安装docker-compose – 每天进步一点点 (longkui.site)

安装这两个完毕后,我们找一个文件夹

执行下面的git命令

git clone https://gitee.com/himitzh0730/hoj-deploy.git && cd hoj-deploy

执行完毕之后,我们可以看到文件夹的目录结构:

docker-compose.yml文件在standAlone文件夹下面,下面贴出默认的配置文件

version: "3"
services:

  hoj-redis:
    image: redis:5.0.9-alpine
    container_name: hoj-redis
    restart: always
    volumes:
      - ${HOJ_DATA_DIRECTORY}/data/redis/data:/data
    networks:
      hoj-network:
        ipv4_address: ${REDIS_HOST:-172.20.0.2}
    ports:
      - ${REDIS_PORT:-6379}:6379
    # --requirepass 后面为redis访问密码
    command: redis-server --requirepass ${REDIS_PASSWORD:-hoj123456} --appendonly yes
        
  hoj-mysql:
    image: registry.cn-shenzhen.aliyuncs.com/hcode/hoj_database
    container_name: hoj-mysql
    restart: always
    volumes:
      - ${HOJ_DATA_DIRECTORY}/data/mysql/data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-hoj123456} # mysql数据库root账号的密码
      - TZ=Asia/Shanghai
      - NACOS_USERNAME=${NACOS_USERNAME:-root} # 后续nacos所用管理员账号
      - NACOS_PASSWORD=${NACOS_PASSWORD:-hoj123456} # 后续nacos所用管理员密码
    ports:
      - ${MYSQL_PUBLIC_PORT:-3306}:3306
    networks:
      hoj-network:
        ipv4_address: ${MYSQL_HOST:-172.20.0.3}
      
  hoj-nacos:
    image: nacos/nacos-server:1.4.2
    container_name: hoj-nacos
    restart: always
    depends_on: 
      - hoj-mysql
    environment:
      - JVM_XMX=384m
      - JVM_XMS=384m
      - JVM_XMN=192m
      - MODE=standalone
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=${MYSQL_HOST:-172.20.0.3}
      - MYSQL_SERVICE_PORT=3306
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=${MYSQL_ROOT_PASSWORD:-hoj123456} # 与上面数据库密码一致
      - MYSQL_SERVICE_DB_NAME=nacos 
      - NACOS_AUTH_ENABLE=true # 开启鉴权
    ports:
      - ${NACOS_PORT:-8848}:8848
    healthcheck:
      test: curl -f http://${NACOS_HOST:-172.20.0.4}:8848/nacos/index.html || exit 1
      interval: 6s
      timeout: 10s
      retries: 10
    networks:
      hoj-network:
        ipv4_address: ${NACOS_HOST:-172.20.0.4}
    
  hoj-backend:
    image: registry.cn-shenzhen.aliyuncs.com/hcode/hoj_backend
    container_name: hoj-backend
    restart: always
    depends_on:
      - hoj-redis
      - hoj-mysql
      - hoj-nacos
    volumes:
      - ${HOJ_DATA_DIRECTORY}/file:/hoj/file
      - ${HOJ_DATA_DIRECTORY}/testcase:/hoj/testcase
      - ${HOJ_DATA_DIRECTORY}/log/backend:/hoj/log/backend
    environment:
      - TZ=Asia/Shanghai
      - JAVA_OPTS=-Xms192m -Xmx384m
      - BACKEND_SERVER_PORT=${BACKEND_PORT:-6688}
      - NACOS_URL=${NACOS_HOST:-172.20.0.4}:8848
      - NACOS_USERNAME=${NACOS_USERNAME:-root} # 登录 http://ip:8848/nacos 分布式配置中心与注册中心的后台的账号
      - NACOS_PASSWORD=${NACOS_PASSWORD:-hoj123456} # 密码
      - JWT_TOKEN_SECRET=${JWT_TOKEN_SECRET:-default} # token加密秘钥 默认则生成32位随机密钥
      - JWT_TOKEN_EXPIRE=${JWT_TOKEN_EXPIRE:-86400} # token过期时间默认为24小时 86400s
      - JWT_TOKEN_FRESH_EXPIRE=${JWT_TOKEN_FRESH_EXPIRE:-43200} # token默认12小时可自动刷新
      - JUDGE_TOKEN=${JUDGE_TOKEN:-default} # 调用判题服务器的token 默认则生成32位随机密钥
      - MYSQL_HOST=${MYSQL_HOST:-172.20.0.3}
      - MYSQL_PUBLIC_HOST=${MYSQL_PUBLIC_HOST:-172.20.0.3} # 如果判题服务是分布式,请提供当前mysql所在服务器的公网ip
      - MYSQL_PUBLIC_PORT=${MYSQL_PUBLIC_PORT:-3306}
      - MYSQL_PORT=3306
      - MYSQL_DATABASE_NAME=hoj # 改动需要修改hoj-mysql镜像,默认为hoj
      - MYSQL_USERNAME=root
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-hoj123456}
      - EMAIL_SERVER_HOST=${EMAIL_SERVER_HOST:-smtp.qq.com} # 请使用邮件服务的域名或ip
      - EMAIL_SERVER_PORT=${EMAIL_SERVER_PORT:-465} # 请使用邮件服务的端口号
      - EMAIL_USERNAME=${EMAIL_USERNAME:-your_email_username} # 请使用对应邮箱账号
      - EMAIL_PASSWORD=${EMAIL_PASSWORD:-your_email_password} # 请使用对应邮箱密码
      - REDIS_HOST=${REDIS_HOST:-172.20.0.2}
      - REDIS_PORT=6379
      - REDIS_PASSWORD=${REDIS_PASSWORD:-hoj123456}
      - OPEN_REMOTE_JUDGE=true # 是否开启各个remote judge
      # 开启虚拟判题请提供对应oj的账号密码 格式为 
      # username1,username2,...
      # password1,password2,...
      - HDU_ACCOUNT_USERNAME_LIST=${HDU_ACCOUNT_USERNAME_LIST}
      - HDU_ACCOUNT_PASSWORD_LIST=${HDU_ACCOUNT_PASSWORD_LIST}
      - CF_ACCOUNT_USERNAME_LIST=${CF_ACCOUNT_USERNAME_LIST}
      - CF_ACCOUNT_PASSWORD_LIST=${CF_ACCOUNT_PASSWORD_LIST}
      - POJ_ACCOUNT_USERNAME_LIST=${POJ_ACCOUNT_USERNAME_LIST}
      - POJ_ACCOUNT_PASSWORD_LIST=${POJ_ACCOUNT_PASSWORD_LIST}
      - ATCODER_ACCOUNT_USERNAME_LIST=${ATCODER_ACCOUNT_USERNAME_LIST}
      - ATCODER_ACCOUNT_PASSWORD_LIST=${ATCODER_ACCOUNT_PASSWORD_LIST}
      - SPOJ_ACCOUNT_USERNAME_LIST=${SPOJ_ACCOUNT_USERNAME_LIST}
      - SPOJ_ACCOUNT_PASSWORD_LIST=${SPOJ_ACCOUNT_PASSWORD_LIST}
      # 是否强制使用配置文件的remote judge账号覆盖原有系统的账号列表
      - FORCED_UPDATE_REMOTE_JUDGE_ACCOUNT=${FORCED_UPDATE_REMOTE_JUDGE_ACCOUNT:-false}
    ports:
      - ${BACKEND_PORT:-6688}:${BACKEND_PORT:-6688}
    networks:
      hoj-network:
        ipv4_address: ${BACKEND_HOST:-172.20.0.5}
  
  hoj-frontend:
    image: registry.cn-shenzhen.aliyuncs.com/hcode/hoj_frontend
    container_name: hoj-frontend
    restart: always
    # 开启https,请提供证书
    #volumes:
    #  - ./server.crt:/etc/nginx/etc/crt/server.crt
    #  - ./server.key:/etc/nginx/etc/crt/server.key
    # 修改前端logo
    #  - ./logo.a0924d7d.png:/usr/share/nginx/html/assets/img/logo.a0924d7d.png
    #  - ./backstage.8bce8c6e.png:/usr/share/nginx/html/assets/img/backstage.8bce8c6e.png
    environment:
      - SERVER_NAME=localhost # # 域名或localhost(本地)
      - BACKEND_SERVER_HOST=${BACKEND_HOST:-172.20.0.5} # backend后端服务地址
      - BACKEND_SERVER_PORT=${BACKEND_PORT:-6688} # backend后端服务端口号
      - USE_HTTPS=false # 使用https请设置为true
    ports:
      - "80:80"
      - "443:443"
    networks:
      hoj-network:
        ipv4_address: 172.20.0.6
  
  hoj-judgeserver:
    image: registry.cn-shenzhen.aliyuncs.com/hcode/hoj_judgeserver
    container_name: hoj-judgeserver
    restart: always
    depends_on:
      - hoj-mysql
      - hoj-nacos
    volumes:
      - ${HOJ_DATA_DIRECTORY}/testcase:/judge/test_case
      - ${HOJ_DATA_DIRECTORY}/judge/log:/judge/log
      - ${HOJ_DATA_DIRECTORY}/judge/run:/judge/run
      - ${HOJ_DATA_DIRECTORY}/judge/spj:/judge/spj
      - ${HOJ_DATA_DIRECTORY}/judge/interactive:/judge/interactive
      - ${HOJ_DATA_DIRECTORY}/log/judgeserver:/judge/log/judgeserver
    environment:
      - TZ=Asia/Shanghai
      - JAVA_OPTS=-Xms192m -Xmx384m # 修正JVM参数以便适应单机部署
      - JUDGE_SERVER_IP=${JUDGE_SERVER_IP:-172.20.0.7}
      - JUDGE_SERVER_PORT=${JUDGE_SERVER_PORT:-8088}
      - JUDGE_SERVER_NAME=${JUDGE_SERVER_NAME:-judger-alone} # 判题服务的名字
      - NACOS_URL=${NACOS_HOST:-172.20.0.4}:8848
      - NACOS_USERNAME=${NACOS_USERNAME:-root}
      - NACOS_PASSWORD=${NACOS_PASSWORD:-hoj123456}
      - MAX_TASK_NUM=${MAX_TASK_NUM:--1} # -1表示最大可接收判题任务数为cpu核心数+1
      - REMOTE_JUDGE_OPEN=${REMOTE_JUDGE_OPEN:-true} # 当前判题服务器是否开启远程虚拟判题功能
      - REMOTE_JUDGE_MAX_TASK_NUM=${REMOTE_JUDGE_MAX_TASK_NUM:--1} # -1表示最大可接收远程判题任务数为cpu核心数*2+1
      - PARALLEL_TASK=${PARALLEL_TASK:-default} # 默认沙盒并行判题程序数为cpu核心数
    ports:
      - ${JUDGE_SERVER_PORT:-8088}:${JUDGE_SERVER_PORT:-8088}
      # - "0.0.0.0:5050:5050" # 一般不开放安全沙盒端口
    healthcheck:
      test: curl -f http://${JUDGE_SERVER_IP:-172.20.0.7}:${JUDGE_SERVER_PORT:-8088}/version || exit 1
      interval: 30s
      timeout: 10s
      retries: 3
    privileged: true # 设置容器的权限为root
    shm_size: 512mb
    networks:
      hoj-network:
        ipv4_address: 172.20.0.7


  hoj-mysql-checker:
    image: registry.cn-shenzhen.aliyuncs.com/hcode/hoj_database_checker
    container_name: hoj-mysql-checker
    depends_on:
      - hoj-mysql
    links:
      - hoj-mysql:mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-hoj123456}
    networks:
      hoj-network:
        ipv4_address: 172.20.0.8
    
  hoj-autohealth:  # 监控不健康的容器进行重启
    restart: always
    container_name: hoj-autohealth
    image: willfarrell/autoheal
    environment:
      - AUTOHEAL_CONTAINER_LABEL=all
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    
networks:
   hoj-network:
     driver: bridge
     ipam:
       config:
         - subnet: ${SUBNET:-172.20.0.0/16}

建议大家把默认的密码改一下,当然,不改也可以运行。

然后,我们在standAlone文件下面执行指令。

docker-compose up -d

注:经过测试发现,用宝塔自带的终端执行docker-compose up -d 容易丢失连接,所以这一步建议用第三方工具来执行上面的命令。

执行完毕后,下载下来的镜像如下:

然后,我们查看一下容器的状态:

容器没有正常启动的原因一般是端口被占用了,比如我这里,已经有一个网站和mysql了,所以80端口和3306端口已经被占用了,本文为了测试,所以先把外层的nginx(apache)和mysql,再启动容器。

如果要不影响原来的程序并成功启动docker,想要修改端口,请参考下面这篇文章,

centos(宝塔)搭建HOJ(2)—依赖关系和修改端口 – 每天进步一点点 (longkui.site)

然后,访问你服务器的IP,就能看到下面的界面了:

第一步大功告成了。