Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker image #936

Merged
merged 21 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
690facc
Adds docker image build action + documentation
fathzer Apr 1, 2024
459d56d
Fixes typo in How-to-use-the-Docker-image.md
fathzer Apr 1, 2024
e48e4e9
Default image is now based on python:3 + creates Alpine flavour + doc
fathzer Apr 6, 2024
162bb08
Makes image easier to use
fathzer Apr 11, 2024
48858b3
Fixes empty lines at the end of some files
fathzer Apr 11, 2024
7436b64
Try again to fix end of lines (my editor does not count lines as Gith…
fathzer Apr 11, 2024
040f583
Try again to fix end of lines (my editor does not count lines as Gith…
fathzer Apr 11, 2024
9efcefe
Copy wiki changes to the right branch
fathzer Apr 12, 2024
313b957
Update How-to-use-the-Docker-image.md -> dir and working_dir note
fathzer Apr 12, 2024
4999665
Adds image push to ghcr.io
fathzer Apr 15, 2024
b39d6e0
Merge branch 'docker-image' of https://github.com/fathzer/lichess-bot…
fathzer Apr 15, 2024
2a550c1
Adds image push to ghcr.io
fathzer Apr 15, 2024
891dd44
Triggers workflow only if lib/versioning.yml changes
fathzer Apr 17, 2024
ca020b2
fix so workflows don't fail
fathzer Apr 19, 2024
4b2530d
Another attempt to fix the Python code so that the workflow succeeds.
fathzer Apr 19, 2024
96e8c1d
Fixes workflow errors with import-untyped and no-redef + engine_wrapper
fathzer Apr 19, 2024
cd74178
Removes the # type: ignore in model.py
fathzer Apr 20, 2024
cdd3e49
Add warning about homemade.py How-to-use-the-Docker-image.md
fathzer Apr 21, 2024
52e6ff8
Implements a failover proxy to access extra_game_handlers
fathzer Apr 21, 2024
9f3c0f1
Adds stop & rm commands to How-to-use-the-Docker-image.md
fathzer Apr 25, 2024
1b83cbb
Replaces occurrences of PWD with TOKEN in docker.yml
fathzer Apr 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Docker CI

on:
push:
branches:
- master
paths:
- lib/versioning.yml

env:
GB_REGISTRY: ghcr.io

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Assign defaultValue
run: |
version=$(grep -m1 '^lichess_bot_version: ' lib/versioning.yml | sed -n -e 's/^.*://p' | tr -d '[:space:]')
echo version="$version" >> "$GITHUB_ENV"

- name: show me docker tags.
run: |
echo "version:'"$version"'"

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_TOKEN }}

- name: Login to Github container registry
uses: docker/login-action@v3
with:
registry: ${{ env.GB_REGISTRY }}
username: ${{ secrets.GB_REPO_USER }}
password: ${{ secrets.GB_REPO_TOKEN }}

- name: build and push fat image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/Dockerfile
push: true
tags: |
${{ vars.DOCKER_ORGANIZATION }}/${{ vars.DOCKER_IMG }}:latest
${{ vars.DOCKER_ORGANIZATION }}/${{ vars.DOCKER_IMG }}:${{ env.version }}
${{ env.GB_REGISTRY }}/${{ vars.DOCKER_ORGANIZATION }}/${{ vars.DOCKER_IMG }}:latest
${{ env.GB_REGISTRY }}/${{ vars.DOCKER_ORGANIZATION }}/${{ vars.DOCKER_IMG }}:${{ env.version }}

- name: build and push alpine image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/Dockerfile
build-args: VARIANT=-alpine
push: true
tags: |
${{ vars.DOCKER_ORGANIZATION }}/${{ vars.DOCKER_IMG }}:alpine
${{ vars.DOCKER_ORGANIZATION }}/${{ vars.DOCKER_IMG }}:${{ env.version }}-alpine
${{ env.GB_REGISTRY }}/${{ vars.DOCKER_ORGANIZATION }}/${{ vars.DOCKER_IMG }}:alpine
${{ env.GB_REGISTRY }}/${{ vars.DOCKER_ORGANIZATION }}/${{ vars.DOCKER_IMG }}:${{ env.version }}-alpine
20 changes: 20 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ARG VARIANT
FROM python:3$VARIANT
MAINTAINER Jean-Marc Astesana <admin@fathzer.com>

ENV LICHESS_BOT_DOCKER="true"
ENV PYTHONDONTWRITEBYTECODE=1

ARG LICHESS_DIR=/lichess-bot
WORKDIR $LICHESS_DIR

COPY . .

RUN python3 -m pip install --no-cache-dir -r requirements.txt

ARG CONF_FOLDER=$LICHESS_DIR/config
RUN ln -s $CONF_FOLDER/config.yml config.yml &&\
ln -sf $CONF_FOLDER/homemade.py homemade.py &&\
ln -sf $CONF_FOLDER/extra_game_handlers.py extra_game_handlers.py

CMD python3 lichess-bot.py ${OPTIONS} --disable_auto_logging
5 changes: 5 additions & 0 deletions docker/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
docker/
docs/
wiki/
.git*
**/__pycache__
14 changes: 14 additions & 0 deletions lib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ def config_assert(assertion: bool, error_message: str) -> None:
raise Exception(error_message)


def config_warn(assertion: bool, warning_message: str) -> None:
"""Raise an exception if an assertion is false."""
if not assertion:
logger.warning(warning_message)


def check_config_section(config: CONFIG_DICT_TYPE, data_name: str, data_type: ABCMeta, subsection: str = "") -> None:
"""
Check the validity of a config section.
Expand Down Expand Up @@ -155,6 +161,7 @@ def insert_default_values(CONFIG: CONFIG_DICT_TYPE) -> None:
set_config_default(CONFIG, key="move_overhead", default=1000)
set_config_default(CONFIG, key="quit_after_all_games_finish", default=False)
set_config_default(CONFIG, key="rate_limiting_delay", default=0)
set_config_default(CONFIG, key="pgn_directory", default=None)
set_config_default(CONFIG, key="pgn_file_grouping", default="game", force_empty_values=True)
set_config_default(CONFIG, "engine", key="working_dir", default=os.getcwd(), force_empty_values=True)
set_config_default(CONFIG, "engine", key="silence_stderr", default=False)
Expand Down Expand Up @@ -293,6 +300,13 @@ def validate_config(CONFIG: CONFIG_DICT_TYPE) -> None:
config_assert(online_section.get("move_quality") != "suggest" or not online_section.get("enabled"),
f"XBoard engines can't be used with `move_quality` set to `suggest` in {subsection}.")

pgn_directory = CONFIG["pgn_directory"]
in_docker = os.environ.get("LICHESS_BOT_DOCKER")
config_warn(not pgn_directory or not in_docker, "Games will be saved to '{}', please ensure this folder is in a mounted "
"volume; Using the Docker's container internal file system will prevent "
"you accessing the saved files and can lead to disk "
"saturation.".format(pgn_directory))

valid_pgn_grouping_options = ["game", "opponent", "all"]
config_pgn_choice = CONFIG["pgn_file_grouping"]
config_assert(config_pgn_choice in valid_pgn_grouping_options,
Expand Down
2 changes: 1 addition & 1 deletion lib/engine_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from lib import config, model, lichess
from lib.config import Configuration
from lib.timer import Timer, msec, seconds, msec_str, sec_str, to_seconds
from extra_game_handlers import game_specific_options
from lib.extra_game_handlers_wrapper import game_specific_options
from typing import Any, Optional, Union, Literal, Type
from types import TracebackType
OPTIONS_TYPE = dict[str, Any]
Expand Down
35 changes: 35 additions & 0 deletions lib/extra_game_handlers_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Proxy to access extra_game_handler functions, with default implementation if the file is missing."""
from lib import model
from typing import Any


def game_specific_options(game: model.Game) -> dict[str, Any]:
"""
Return a dictionary of engine options based on game aspects.

By default, if no custom extra_game_handler is found, an empty dict is returned so that the options
in the configuration file are used.
"""
try:
from extra_game_handlers import game_specific_options
return game_specific_options(game)
except ImportError:
pass

return {}


def is_supported_extra(challenge: model.Challenge) -> bool:
"""
Determine whether to accept a challenge.

By default, if no custom extra_game_handler is found, True is returned so that there are no extra restrictions
beyond those in the config file.
"""
try:
from extra_game_handlers import is_supported_extra
return is_supported_extra(challenge)
except ImportError:
pass

return True
2 changes: 1 addition & 1 deletion lib/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def is_supported(self, config: Configuration,
if self.from_self:
return True, ""

from extra_game_handlers import is_supported_extra
from lib.extra_game_handlers_wrapper import is_supported_extra

allowed_opponents: list[str] = list(filter(None, config.allow_list)) or [self.challenger.name]
decline_reason = (self.decline_due_to(config.accept_bot or not self.challenger.is_bot, "noBot")
Expand Down
6 changes: 6 additions & 0 deletions wiki/How-to-Install.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,10 @@ pip install -r requirements.txt
PowerShell note: If the `activate` command does not work in PowerShell, execute `Set-ExecutionPolicy RemoteSigned` first and choose `Y` there (you may need to run Powershell as administrator). After you execute the script, change execution policy back with `Set-ExecutionPolicy Restricted` and pressing `Y`.
- Copy `config.yml.default` to `config.yml`.

### Docker
If you have a [Docker](https://www.docker.com/) host, you can use the ```lichess-bot-devs/lichess-bot``` [image in DockerHub](https://hub.docker.com/repository/docker/lichess-bot-devs/lichess-bot).
It requires a folder where you have to copy `config.yml.default` to `config.yml`.

See [Running with Docker](https://github.com/lichess-bot-devs/lichess-bot/wiki/How-to-use-the-Docker-image) once you've created the OAuth token and setup the engine.

**Next step**: [Create a Lichess OAuth token](https://github.com/lichess-bot-devs/lichess-bot/wiki/How-to-create-a-Lichess-OAuth-token)
64 changes: 64 additions & 0 deletions wiki/How-to-use-the-Docker-image.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# How to launch your bot
## Prepare the deployment
Create a folder where you will put your configuration file, the UCI/XBoard program that runs your engine (be aware that this program will run inside the container ... in a Linux OS) or your own [`homemade.py`](https://github.com/lichess-bot-devs/lichess-bot/wiki/Create-a-homemade-engine) and, if required, your own [`extra_game_handlers.py`](https://github.com/lichess-bot-devs/lichess-bot/wiki/Extra-customizations).

The configuration file **must** be named `config.yml`.

You can see an example of this file using the following command:
```docker run --rm --entrypoint=cat lichess-bot-devs/lichess-bot config.yml.default```.

You can also find documentation [here](https://github.com/lichess-bot-devs/lichess-bot/wiki/Configure-lichess-bot).

## Run the bot

Once your configuration files are ready, let's say in `/home/me/myEngine` folder, run the following command:
```docker run -d -v /home/me/myEngine:/lichess-bot/config --name myBot lichess-bot-devs/lichess-bot```

That's all!

### Warning:
- Make sure you've set the `dir` and `working_dir` attributes of your `config.yml` to the right path (remember the engine runs in the container's OS, so the path should start with `/lichess-bot/config/`).
- If you are using a homemade engine provided in the original [`homemade.py` file in the Github project](https://github.com/lichess-bot-devs/lichess-bot/blob/master/homemade.py), you **must** add this file to the folder containing your configuration files.
- **If you've configured a folder to save pgn files** using [`pgn_directory`](https://github.com/lichess-bot-devs/lichess-bot/wiki/Configure-lichess-bot#other-options) that is not in `/lichess-bot/config` directory, always mount a volume to that folder. Without that, your saved games will remain unreachable from the outside of the container, and storing a lot of games in the container's file system could result in disk saturation.
- The container uses the standard docker logging system and the bot is always launched with the `--disable_auto_logging` option.
Use the `docker logs myBot` [command](https://docs.docker.com/reference/cli/docker/container/logs/) to access to the bot logs.

## Stop and delete the bot
Use the standard commands.
If you used the command from the [Run chapter](#run-the-bot) above: ```docker stop myBot``` and ```docker rm myBot```

# Image variants

The `lichess-bot` images come in two flavors, each designed for a specific use case.
Both are available through [Docker hub](https://hub.docker.com/repository/docker/lichess-bot-devs/lichess-bot) and [Github container registry](https://github.com/lichess-bot-devs/lichess-bot/pkgs/container/lichess-bot).

## lichess-bot:\<version\>
This is the defacto image. It is based on the [`python:3`](https://hub.docker.com/_/python) image.
If you are unsure about what your needs are, you probably want to use this one.

## lichess-bot:\<version\>-alpine
This image is based on the popular Alpine Linux project, available in the alpine official image. Alpine Linux is much smaller than most distribution base images, and thus leads to a much slimmer image than the default one (80MB instead of 1GB).

This variant is useful when final image size being as small as possible is your primary concern. The main caveat to note is that it does use musl libc instead of glibc and friends, so software will often run into issues depending on the depth of their libc requirements/assumptions. For instance, running [Stockfish](https://stockfishchess.org/) on this image requires extra libraries installation.

# Some tips

## What if my engine requires some software installation?
You will have to create a new Docker image of your own and install the required software in your `Dockerfile`.
For example to install java 17, the docker file would look like:
```
FROM lichess-bot-devs/lichess-bot:alpine

RUN apk add --no-cache openjdk17-jre
```
Please note that, as `lichess-bot:alpine` image is based on [Alpine](https://www.alpinelinux.org/), you'll have to install new software using the ```apk``` command.

## What if I want to add options to ```lichess-bot.py```?

If you want to pass some options to the ```lichess-bot.py``` executed in the container, add them in the ```OPTIONS``` environment variable.
For instance, to launch the bot in verbose mode, run the command:
```docker run -d -v /home/me/myEngine:/lichess-bot/config --env OPTIONS=-v lichess-bot-devs/lichess-bot```

## How to know which release of lichess-bot is running?
Use the following command: ```docker run --rm --entrypoint=cat lichess-bot-devs/lichess-bot lib/versioning.yml```

fathzer marked this conversation as resolved.
Show resolved Hide resolved
Loading