Update Dockerfile and add README.docker

- Fix permissions in `/opt` to allow non-root user to compile Anki (which requires reading and/or creating files below `/opt`).
- Create `pythonbuilder` stage, which runs only `make build`. The wheels from this stage are copied into the final stage.
- Add README.docker
This commit is contained in:
Jakub Kaczmarzyk 2020-09-08 14:58:25 -04:00 committed by GitHub
parent a22f671f3b
commit d07185693c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 8 deletions

View File

@ -1,12 +1,17 @@
FROM python:3.8 AS builder ARG PYTHON_VERSION="3.8"
ARG DEBIAN_FRONTEND="noninteractive" FROM python:$PYTHON_VERSION AS dependencies
# Allow non-root users to install things and modify installations in /opt.
RUN chmod 777 /opt && chmod a+s /opt
# Install rust. # Install rust.
ENV CARGO_HOME="/opt/cargo" \ ENV CARGO_HOME="/opt/cargo" \
RUSTUP_HOME="/opt/rustup" RUSTUP_HOME="/opt/rustup"
ENV PATH="$CARGO_HOME/bin:$PATH" ENV PATH="$CARGO_HOME/bin:$PATH"
RUN curl -fsSL --proto '=https' --tlsv1.2 https://sh.rustup.rs \ RUN mkdir $CARGO_HOME $RUSTUP_HOME \
&& chmod a+rws $CARGO_HOME $RUSTUP_HOME \
&& curl -fsSL --proto '=https' --tlsv1.2 https://sh.rustup.rs \
| sh -s -- -y --quiet --no-modify-path \ | sh -s -- -y --quiet --no-modify-path \
&& rustup update \ && rustup update \
&& cargo install ripgrep && cargo install ripgrep
@ -16,6 +21,16 @@ RUN apt-get update \
&& apt-get install --yes --no-install-recommends \ && apt-get install --yes --no-install-recommends \
gettext \ gettext \
lame \ lame \
libnss3 \
libxcb-icccm4 \
libxcb-image0 \
libxcb-keysyms1 \
libxcb-randr0 \
libxcb-render-util0 \
libxcb-xinerama0 \
libxcb-xkb1 \
libxkbcommon-x11-0 \
libxcomposite1 \
mpv \ mpv \
portaudio19-dev \ portaudio19-dev \
rsync \ rsync \
@ -34,14 +49,24 @@ RUN curl -fsSL --proto '=https' -O https://github.com/protocolbuffers/protobuf/r
&& rm protoc-3.11.4-linux-x86_64.zip && rm protoc-3.11.4-linux-x86_64.zip
ENV PATH="/opt/protoc/bin:$PATH" ENV PATH="/opt/protoc/bin:$PATH"
# Build anki. # Allow non-root users to install toolchains and update rust crates.
RUN chmod 777 $RUSTUP_HOME/toolchains $RUSTUP_HOME/update-hashes $CARGO_HOME/registry \
&& chmod -R a+rw $CARGO_HOME/registry \
# Necessary for TypeScript.
&& chmod a+w /home
# Build anki. Use a separate image so users can build an image with build-time
# dependencies.
FROM dependencies AS builder
WORKDIR /opt/anki WORKDIR /opt/anki
COPY . . COPY . .
RUN make develop \ RUN make develop
&& make build
FROM builder AS pythonbuilder
RUN make build
# Build final image. # Build final image.
FROM python:3.8-slim FROM python:${PYTHON_VERSION}-slim
# Install system dependencies. # Install system dependencies.
RUN apt-get update \ RUN apt-get update \
@ -64,7 +89,7 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Install pre-compiled Anki. # Install pre-compiled Anki.
COPY --from=builder /opt/anki/dist/ /opt/anki/ COPY --from=pythonbuilder /opt/anki/dist/ /opt/anki/
RUN python -m pip install --no-cache-dir \ RUN python -m pip install --no-cache-dir \
PyQtWebEngine \ PyQtWebEngine \
/opt/anki/*.whl \ /opt/anki/*.whl \

99
README.docker Normal file
View File

@ -0,0 +1,99 @@
Anki in Docker
==============
Docker provides a standard method of installing software. This is particularly helpful
when software requires a complex set of dependencies, like Anki.
## Running Anki in Docker
Build and then run the image. The `docker run` command below runs the image as the
current user, and it mounts the user's `$HOME` directory, which is where Anki stores
its local files.
```
docker build --tag anki .
xhost +local:root # Undo when done with `xhost -local:root`
docker run \
--rm -it \
--user 1000:1000 \
--volume $HOME/.local/share:$HOME/.local/share:rw \
--volume /etc/passwd:/etc/passwd:ro \
--volume /tmp/.X11-unix:/tmp/.X11-unix:rw \
--env DISPLAY=$DISPLAY \
anki
xhost -local:root
```
## Developing Anki in Docker
Build your local source tree in Docker.
1. Build the Docker image with build-time dependencies. The Anki Dockerfile uses
multi-stage builds, so the target is the first stage, which includes only the
dependencies.
```
docker build --tag anki:dependencies --target dependencies .
```
2. Compile your source tree
Start the image with dependencies in the background. It is important to run the
image as the current user, because otherwise, some files in the source tree will be
owned by root. Find user id with `id -u` and group ID with `id -g`. These values
are passed to `--user` as in `--user $(id -u):$(id -g)`.
```
docker run --rm -it \
--name ankibuilder \
--detach \
--workdir /work
--volume "$PWD":/work:rw \
--user 1000:1000 \
--volume /etc/passwd:/etc/passwd:ro \
--volume /tmp/.X11-unix:/tmp/.X11-unix:rw \
--env DISPLAY=$DISPLAY \
anki:dependencies bash
```
Allow the Docker container to use the local X server and show the GUI.
```
xhost +local:root
```
(Undo this when done with `xhost -local:root`)
Compile.
```
docker exec -it ankibuilder make run
```
The Anki graphical user interface should appear. The first run will take some time
because Rust code has to be compiled and Python dependencies have to be downloaded,
etc. The following runs will be much faster.
To compile without running the GUI, use `make develop`.
3. Other common operations
If system packages need to be installed, use `apt-get` as below. The Docker image
is based on a Debian Stable image.
```
docker exec -it --user root ankibuilder apt-get update
docker exec -it --user root ankibuilder apt-get install PACKAGES
```
An interactive bash shell can be started with
```
docker exec -it ankibuilder bash
```
or as root user
```
docker exec -it --user root ankibuilder bash
```