# 3.7 安装 judgehost

必须采取一些额外步骤才能完全安装和配置一个 judgehost

## 非特权用户和用户组

为了在非特权用户下运行提交的程序, 你必须向系统中添加一个充当 judgehost 的用户和用户组; 这个用户不需要 home 目录或密码, 所以下面命令就足以用最小权限添加用户和用户组 `domjudge-run`

在基于 Debian 和 RedHat 的 Linux 发行版上使用:

```
useradd -d /nonexistent -U -M -s /bin/false domjudge-run
```

对于其他系统, 请查阅 `useradd` 命令的详细用法

此用户必须为通过命令 `configure --enable-runuser=USER` 选择的用户; 默认为 `domjudge-run`; 默认情况下, 用户组设置为和用户名相同, 这可以通过选项 `--enable-rungroup=GROUP` 进行修改

## sudo 权限

`runguard` 的一些操作需要 root 权限, 如切换到 `runuser` 并执行 `chroot`; 此外, 默认的 `chroot-startstop.sh` 脚本使用 `sudo` 来获取某些操作的权限; 在 `etc/sudoers-domjudge` 中有一个预生成的 `/etc/sudoers.d` 配置片段包含了所有必须的规则; 你可以将配置片段中的内容附加到 `/etc/sudoers` 最后, 或者将文件放在 `/etc/sudoers.d/` 中; 如果你更改运行 `judgedaemon` 的用户或安装路径, 请务必更新相应的 sudoers 规则

## 创建 chroot 环境

出于安全问题, `judgedaemon` 在 chroot 环境下执行提交的程序; 默认情况下, 评判过程中以只读方式挂在预先构建的 chroot 树的一部分(使用 `lib/judge/chroot-startstop.sh` 脚本); 这是支持运行时访问解释器或支持库的其他语言 (例如 `C#`, `Java` 和一些解释性语言如 `Python`, `Perl`, `Shell` 等) 所必须的

可以使用脚本 `bin/dj_make_chroot` 构建此 chroot 树; 在 `Debian` 和 `Ubuntu` 上使用和本机系统和版本相同的发行版, 在其他 Linux 发行版上, 选择最新的稳定版 `Debian` 以构建 chroot 环境; 任何所支持的语言的额外的软件包都可以通过 `-i` 选项或脚本中的 `INSTALLDEBS` 变量添加; 脚本 `bin/dj_run_chroot` 会在 chroot 环境下启动一个交互式的 `shell` 或执行一个命令; 这样就可以在 chroot 内安装新的软件包或更新现有的软件包; 你可以用 `-h` 选项获取这些脚本的 详细用法

最后, 如果有必要你可以编辑 `lib/judge/chroot-startstop.sh` 以使其适应本地系统; 如果你修改了默认的 chroot 目录, 请确保你更新了 sudo 规则和 `chroot-startstop.sh` 中的 `CHROOTORIGINAL` 变量

启用 chroot 设置后(默认), 必须有一个静态的 `POSIX shell` 才能将其复制到 chroot 环境中; `Linux i386` 包含一个 `Dash shell`, 它可以开箱即用, 这也适用于 `Linux Intel/AMD 64` 架构; 对于其他架构或操作系统, 你必须手动添加一个 shell; 然后将创建符号链接 `lib/sh-static` 指向它即可

## Linux Control Groups

Domjudge 使用 `Linux Control Groups` (cgroups) 来实现 `judgedaemon` 的进程隔离; 与传统的限制资源相比, `Linux cgroups` 可以更准确地测量实际分配的内存 (这对与评测 `Java` 这种保留但实际上没有使用大量内存的解释器语言很有帮助); 此外, cgroups 还能用于限制网络访问, 因此不需要单独的限制网络的措施; cgroups 还可以通过 `CPU 绑定` 在多核计算机上运行多个评测进程

judgedaemon 需要最新的内核 (至少 3.2.0); 以下步骤是在 `Debian wheezy` 上配置 cgroups; 其他发行版的步骤可能不同 (请将您的反馈发送给我们!); 编辑 grub 配置将 cgroups 内存和交换分区数量添加到启动选项; 编辑 `/etc/default/grub` 做如下修改:

```
GRUB_CMDLINE_LINUX_DEFAULT="quiet cgroup_enable=memory swapaccount=1"
```

然后运行 `update-grub` 并重启; 重启后检查 `/proc/cmdline` 是否包含新添加的内核选项; 在 VM 托管提供商 (如 Google Cloud 或 DigitalOcean) 上, `GRUB_CMDLINE_LINUX_DEFAULT` 可能会被 `/etc/default/grub.d/` 中的其他文件覆盖

你现在已经将系统配置为使用 cgroups, 但你仍需创建 Domjudge 要使用的 cgroups; 为此, 你可以使用 `misc-tools/create_cgroups` 脚本; 编辑此脚本以适配你的情况; 每次启动后都要重新运行此脚本 (它已添加到 `judgedaemon init` 脚本中)

## REST API 凭据

judgehost 通过 `REST API` 连接到 domserver 上; 你需要为 judgedaemon 创建一个账户 (所有 judgedaemon 可以共享一个账户), 其中包含一个复杂的随机密码和 judgehost 用户角色(Roles); 在每一个 judgehost 上, 从 domserver 复制(或创建) 一个文件: `etc/restapi.secret`, 其中包含一行以空格分割的 id, URL, 用户名, 密码, 例如:

```
default http://example.edu/domjudge/api/  judgehosts  MzfJYWF5agSlUfmiGEy5mgkfqU
```

**注意**: 密码必须和在管理员 web 界面创建的 judgehost 用户的密码相同; 多行可以指定为多个 domserver 工作; id 用以区分多个 domserver, 它在 `restapi.secret` 中应是唯一的

## 启动 judgedaemon

最后, 启动 judgedaemon (可选: 将其绑定到 CPU 核心 X 上)

```
bin/judgedaemon [-n X]
```

如果使用 `-n X` 选项, 则还必须创建额外的用户 `domjudge-run-X`

首次连接到 domserver API 时, judgehost 将会自动注册并启用; 如果你想创建一个新的 judgehost 但禁用最初的, 你可以通过 Domjudge web 界面手动添加它, 并在启动 judgedaemon 前将其设置为 `disable`
