Skip to content

Commit b504b5e

Browse files
committed
Improve Dockerfile and documentation
* Base the Docker image on openSUSE Leap 15.6 * Introduce `etc/docbuild/env.docker.toml` for a env config especially for Docker images * Update `.dockerignore` * Simplify the Dockerfile * Add new topic about building and running the Docker container
1 parent 89b05d7 commit b504b5e

File tree

7 files changed

+266
-50
lines changed

7 files changed

+266
-50
lines changed

.dockerignore

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Version control
22
.git
3+
.github/
34
.gitignore
45

56
# Dependencies & build artifacts
@@ -12,14 +13,36 @@ build
1213
*.pyd
1314

1415
# Development files
16+
.cache
17+
.config.toml
18+
.config
19+
.coverage
20+
.coveragerc
21+
ci/
22+
devel/
23+
Dockerfile*
24+
.dockerignore
25+
.editorconfig
26+
env.*.toml
27+
etc/
28+
.ipython/
29+
LICENSE
30+
.pytest_cache
31+
.pytest.ini
32+
.python-Version
33+
.ruff_cache
34+
.ruff.toml
35+
towncrier.toml
1536
contrib/
1637
tmp/
1738
.env
1839
.env.local
1940
*.log
2041
coverage
2142
.venv
22-
43+
.venv-*
44+
*.patch
45+
*.diff
2346

2447
# IDE files
2548
.vscode

Dockerfile

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,89 @@
11
# Source: https://docs.astral.sh/uv/guides/integration/docker/#non-editable-installs
22
#
3+
# Build with a pre-configured DAPS toolchain image from openSUSE.
4+
# This version builds a wheel in a builder stage and installs it in a
5+
# clean runtime environment in the final stage.
6+
#
37
# Build it with:
48
# $ docker build -t docbuild:latest .
5-
# -- or --
6-
# $ docker buildx build -t docbuild:latest .
79
#
8-
# If you want to skip the jing installation step, use:
9-
# $ docker build --build-arg WITH_JING=false -t docbuild:latest .
1010

11-
ARG PYTHON_VERSION=3.13-slim
11+
ARG OPENSUSE_VERSION=15.6
12+
ARG IMAGE="registry.opensuse.org/documentation/containers/${OPENSUSE_VERSION}/opensuse-daps-toolchain:latest"
1213

13-
# ------- Stage 1: Build the environment ----------------
14-
FROM python:${PYTHON_VERSION} AS builder
14+
# ------- Stage 1: Build the runtime environment ----------------
15+
FROM ${IMAGE} AS builder
1516

16-
# Create a non-root user
17+
# Create a non-root user.
1718
RUN useradd -m app
18-
USER app
1919

20-
# Install uv
20+
# Install uv.
2121
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
2222

23-
# Change the working directory
24-
WORKDIR /app
23+
# Set the working directory to the user's home.
24+
WORKDIR /home/app
2525

26-
# Install dependencies
27-
RUN --mount=type=cache,target=/root/.cache/uv \
28-
--mount=type=bind,source=uv.lock,target=uv.lock \
29-
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
30-
uv sync --frozen --no-install-project --no-editable
26+
# Copy all project source files.
27+
COPY . .
3128

32-
# Copy the project into the intermediate image
33-
ADD --chown=app:app . /app
34-
35-
# Sync the project
29+
# Build the wheel, create a venv, and install the wheel into it.
30+
# This is all done as root to avoid cache permission issues.
3631
RUN --mount=type=cache,target=/root/.cache/uv \
37-
uv sync --frozen --no-editable
38-
39-
# ------- Stage 2: Build/provide the application --------
40-
FROM python:${PYTHON_VERSION}
41-
42-
# Allow conditional installation of jing for XML validation
43-
ARG WITH_JING=true
44-
45-
# Install runtime dependencies like jing for XML validation
46-
RUN if [ "$WITH_JING" = "true" ]; then \
47-
apt-get update && apt-get install -y --no-install-recommends jing && rm -rf /var/lib/apt/lists/*; \
48-
fi
49-
50-
# Create a non-root user to match the builder stage
32+
set -e; export HOME=/home/app && \
33+
uv build --wheel && \
34+
uv venv && \
35+
uv pip install dist/*.whl
36+
37+
# Fix permissions for the runtime files.
38+
RUN chown -R app:users /home/app
39+
40+
# ------- Stage 2: Create the final, lean image --------
41+
FROM ${IMAGE}
42+
43+
# --- OPTIMIZATION STEP ---
44+
# As root, remove unnecessary files to reduce the final image size.
45+
# This must be done as root, before creating the 'app' user.
46+
# RUN set -x; \
47+
# rpm -v --erase --nodeps --force python3-cssselect python3 python3-base python3-lxml python3-gobject \
48+
# ca-certificates cracklib cups-config diffutils fdupes \
49+
# gio-branding-openSUSE gstreamer gtk2-tools gtk3-data gtk3-schema gtk3-tools \
50+
# hicolor-icon-theme info ncurses-utils netcfg openSUSE-release perl5 pinentry \
51+
# Mesa Mesa-dri Mesa-gallium Mesa-libEGL1 Mesa-libGL1 libglvnd libgstgl; \
52+
# rm -rf /usr/include \
53+
# /usr/lib/{browser-plugins,gstreamer-*,ca-certificates,keyboxd,locale,perl5,git,gpg-*,getconf,scdaemon,ssh,systemd,tmpfiles.d} \
54+
# /usr/local/* \
55+
# /usr/sbin/{fdisk,sfdisk,g13-syshelp,fsck.minix,partx,mkswap,zramctl} \
56+
# /var/log/* \
57+
# /var/cache/{zypp,ldconfig,fontconfig,cups} \
58+
# /var/adm/* \
59+
# /var/lib/{YaST2,alternatives,ca-certificates,selinux,xkb,misc} || true
60+
61+
# --- DIAGNOSTIC STEP ---
62+
# Add this temporary command to see the size of top-level directories
63+
# before the cleanup step. This helps identify what is taking up space.
64+
# RUN du -sh /usr/lib/* | sort -rh | head -n 20 > /du-usrlib-sort.txt
65+
66+
67+
# Create the same non-root user.
5168
RUN useradd -m app
5269

53-
# Copy the environment, but not the source code
54-
COPY --from=builder --chown=app:app /app/.venv /app/.venv
70+
# Copy only the essential runtime directories from the builder.
71+
# This results in a lean final image without build artifacts or source code.
72+
COPY --from=builder --chown=app:users /home/app/.venv /home/app/.venv
73+
COPY --from=builder --chown=app:users /home/app/.local /home/app/.local
5574

56-
# Set the working directory
57-
WORKDIR /app
75+
# Switch to the non-root user for security.
76+
USER app
5877

59-
# Add the virtual environment's bin directory to the PATH
60-
ENV PATH="/app/.venv/bin:${PATH}"
78+
# Set the working directory.
79+
WORKDIR /home/app
6180

62-
# Switch to the non-root user for security
63-
USER app
81+
# Set the PATH to include the virtual environment's bin directory.
82+
ENV PATH="/home/app/.venv/bin:${PATH}"
83+
ENV LANG=en_US.UTF-8
84+
ENV LC_ALL=en_US.UTF-8
85+
ENV TERM=xterm-256color
6486

65-
# Run the application
66-
CMD ["docbuild"]
87+
# Run the application.
88+
# ENTRYPOINT [ "docbuild" ]
89+
# CMD ["docbuild", "--env-config", "env-production.toml", "--help"]

changelog.d/69.doc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve Dockerfile and documentation

docs/source/developer/index.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ This guide provides all the necessary information for contributing to the projec
2626
build-changelog
2727
create-release
2828
trigger-actions
29-
29+
work-with-docker
30+
3031
build-docs
3132
howto
3233

@@ -35,4 +36,4 @@ This guide provides all the necessary information for contributing to the projec
3536
:caption: Appendix
3637

3738
know-tools-config
38-
knowing-github-setup
39+
knowing-github-setup

docs/source/developer/prepare-environment.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ The following steps are recommended to set up your development environment:
7575
uv venv --prompt venv313 --python 3.13 .venv
7676
7777
Keep in mind that the Python version used in the virtual environment should match the version specified in the :file:`pyproject.toml` file.
78-
78+
7979
The example above uses Python 3.13, but you can adjust it according to your needs as long as it is compatible with the project.
8080
See file :file:`pyproject.toml` in ``project.requires-python`` for the exact version.
8181

@@ -101,6 +101,8 @@ The following steps are recommended to set up your development environment:
101101
After completing these steps, your development environment is ready to go.
102102

103103

104+
.. _get-docserv-config:
105+
104106
Getting Docserv's Config Files
105107
------------------------------
106108

@@ -116,4 +118,4 @@ To get started, clone this repository to your local machine (you need VPN access
116118
git clone https://gitlab.suse.de/susedoc/docserv-config.git
117119
118120
You will later need to point ``docbuild`` to the location of this cloned
119-
repository in your configuration.
121+
repository in your configuration.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
.. _work-docker:
2+
3+
Working with Docker Images
4+
==========================
5+
6+
Sometimes it is easier to work with a Docker container that contains all
7+
the necessary dependencies.
8+
9+
10+
Requirements
11+
------------
12+
13+
To build a Docker image and use it as container, check the following
14+
requirements:
15+
16+
* Docker installed and running on your system:
17+
18+
* For openSUSE: Run :command:`sudo zypper install docker` to install it and :command:`sudo systemctl start docker` to start the Docker daemon.
19+
20+
* For MacOS: Refer to https://docs.docker.com/desktop/setup/install/mac-install/.
21+
22+
* Clone the respective configuration repository. Refer to :ref:`get-docserv-config`.
23+
24+
25+
Creating a Docker image
26+
-----------------------
27+
28+
To create a Docker image, use the following command:
29+
30+
.. code-block:: shell-session
31+
:caption: Building the image
32+
33+
docker buildx build -t docbuild:latest .
34+
35+
This creates a Docker image ``docbuild`` with the tag ``latest``. After the successful build, you see:
36+
37+
.. code-block:: shell-session
38+
:caption: Listing the Docker image
39+
40+
$ docker image ls docbuild
41+
REPOSITORY TAG IMAGE ID CREATED SIZE
42+
docbuild latest c13d36935907 16 minutes ago 643MB
43+
44+
45+
Running the Docker container
46+
----------------------------
47+
48+
Before you start the Docker container, you need to collect some paths and file names:
49+
50+
* The path to the configuration repository, marked as ``CONFIG_DIR``.
51+
* The path to the environment file, marked as ``ENV_FILE``. Usually you want to use :file:`$PWD/etc/env-docker.toml` from this repository.
52+
* The path to the cache directory, marked as ``CACHE_DIR``. Under Linux it's usually :file:`/var/cache/docbuild`
53+
* The path of the target directory (the result of all ), marked as ``TARGET_DIR``.
54+
55+
56+
.. admonition:: Make absolute paths
57+
58+
Use absolute paths for the previous variables.
59+
60+
61+
Running the Docker container based on the previous image, use this command:
62+
63+
.. code-block:: shell-session
64+
:caption: Running the Docker container
65+
66+
export CONFIG_DIR="..."
67+
export ENV_FILE="..."
68+
export CACHE_DIR="..."
69+
export TARGET_DIR="..."
70+
docker run --it \
71+
-v $CONFIG_DIR:/etc/docbuild \
72+
-v $ENV_FILE:/app/.env-production.toml \
73+
-v $CACHE_DIR:/var/cache/docbuild/ \
74+
-v $TARGET_DIR:/data/docbuild/external-builds/ \
75+
docbuild:latest \
76+
DOCBUILD_COMMAND

etc/docbuild/env.docker.toml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# TOML example configuration file
2+
#
3+
4+
[server]
5+
# Section "server": deals with all config about server settings
6+
name = "doc-suse-com"
7+
role = "production"
8+
host = "127.0.0.1"
9+
# port =
10+
enable_mail = true
11+
12+
13+
[config]
14+
# Section "config": general configuration
15+
default_lang = "en-us"
16+
languages = [
17+
'de-de',
18+
'en-us',
19+
'es-es',
20+
'fr-fr',
21+
'ja-jp',
22+
'ko-kr',
23+
'pt-br',
24+
'zh-cn',
25+
]
26+
canonical_url_domain = "https://docs.example.com"
27+
28+
29+
[paths]
30+
# Section "paths": Defines several paths
31+
# Paths can hold placeholders in brackets.
32+
root_config_dir = "/etc/docbuild"
33+
jinja_dir = "{root_config_dir}/jinja-doc-suse-com"
34+
config_dir = "{root_config_dir}/config.d"
35+
server_rootfiles_dir = "{root_config_dir}/server-root-files-doc-suse-com"
36+
#
37+
base_cache_dir = "/var/cache/docbuild"
38+
base_server_cache_dir = "{base_cache_dir}/{server.name}"
39+
base_tmp_dir = "{base_cache_dir}/tmp"
40+
repo_dir = "{base_cache_dir}/repos/permanent-full/"
41+
temp_repo_dir = "{base_cache_dir}/repos/temporary-branches/"
42+
# cache_dir = "{base_cache_dir}/{server.name}"
43+
meta_cache_dir = "{base_cache_dir}/{server.name}/meta"
44+
45+
[paths.tmp]
46+
# Section "paths.tmp": Definies temporary paths
47+
# Paths can hold placeholders in brackets.
48+
tmp_base_dir = "{paths.base_tmp_dir}"
49+
tmp_dir = "{tmp_base_dir}/doc-example-com"
50+
tmp_metadata_dir = "{tmp_dir}/metadata"
51+
tmp_deliverable_dir = "{paths.tmp.tmp_dir}/deliverable/"
52+
tmp_build_dir = "{tmp_dir}/build/{{product}}-{{docset}}-{{lang}}"
53+
tmp_out_dir = "{tmp_dir}/out/"
54+
log_dir = "{tmp_dir}/log/"
55+
tmp_deliverable_name = "{{product}}_{{docset}}_{{lang}}_XXXXXX"
56+
57+
[paths.target]
58+
# Section "paths.target": Definies target paths
59+
target_dir = "[email protected]:/srv/docs"
60+
backup_dir = "/data/docbuild/external-builds/"
61+
62+
63+
[build]
64+
# Section "build": General build parameters, independant from any specific
65+
66+
[build.daps]
67+
# Section "build.daps": Configuration for daps
68+
command = "daps -vv"
69+
meta = "daps -vv metadata --output {{output}}"
70+
# html = "daps -vv --builddir='{paths.tmp.tmp_build_dir}' html"
71+
# pdf = "daps -vv --builddir='{paths.tmp.tmp_build_dir}' pdf"
72+
73+
74+
[build.container]
75+
# Section "build.container": Configuration for container
76+
container = "registry.opensuse.org/documentation/containers/15.6/opensuse-daps-toolchain:latest"
77+
78+
[xslt-params]
79+
# Section "xslt-params": Replaces /etc/docserv/xslt-params-doc-suse-com.txt file
80+
# These keys are considered as XSLT parameters and passed
81+
# to the transformation process
82+
homepage = "https://documentation.suse.com/"
83+
overview-page = "https://documentation.suse.com/"
84+
overview-page-title = "documentation.suse.com"
85+
external.js.onlineonly = "/docserv/res/extra.js"
86+
show.edit.link = 1
87+
twittercards.twitter.account = "@SUSE"
88+
generate.json-ld = 1
89+
search.description.length = 118
90+
socialmedia.description.length = 65

0 commit comments

Comments
 (0)