Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 24 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Version control
.git
.github/
.gitignore

# Dependencies & build artifacts
Expand All @@ -12,14 +13,36 @@ build
*.pyd

# Development files
.cache
.config.toml
.config
.coverage
.coveragerc
ci/
devel/
Dockerfile*
.dockerignore
.editorconfig
env.*.toml
etc/
.ipython/
LICENSE
.pytest_cache
.pytest.ini
.python-Version
.ruff_cache
.ruff.toml
towncrier.toml
contrib/
tmp/
.env
.env.local
*.log
coverage
.venv

.venv-*
*.patch
*.diff

# IDE files
.vscode
Expand Down
113 changes: 68 additions & 45 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,66 +1,89 @@
# Source: https://docs.astral.sh/uv/guides/integration/docker/#non-editable-installs
#
# Build with a pre-configured DAPS toolchain image from openSUSE.
# This version builds a wheel in a builder stage and installs it in a
# clean runtime environment in the final stage.
#
# Build it with:
# $ docker build -t docbuild:latest .
# -- or --
# $ docker buildx build -t docbuild:latest .
#
# If you want to skip the jing installation step, use:
# $ docker build --build-arg WITH_JING=false -t docbuild:latest .

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

# ------- Stage 1: Build the environment ----------------
FROM python:${PYTHON_VERSION} AS builder
# ------- Stage 1: Build the runtime environment ----------------
FROM ${IMAGE} AS builder

# Create a non-root user
# Create a non-root user.
RUN useradd -m app
USER app

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

# Change the working directory
WORKDIR /app
# Set the working directory to the user's home.
WORKDIR /home/app

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

# Copy the project into the intermediate image
ADD --chown=app:app . /app

# Sync the project
# Build the wheel, create a venv, and install the wheel into it.
# This is all done as root to avoid cache permission issues.
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-editable

# ------- Stage 2: Build/provide the application --------
FROM python:${PYTHON_VERSION}

# Allow conditional installation of jing for XML validation
ARG WITH_JING=true

# Install runtime dependencies like jing for XML validation
RUN if [ "$WITH_JING" = "true" ]; then \
apt-get update && apt-get install -y --no-install-recommends jing && rm -rf /var/lib/apt/lists/*; \
fi

# Create a non-root user to match the builder stage
set -e; export HOME=/home/app && \
uv build --wheel && \
uv venv && \
uv pip install dist/*.whl

# Fix permissions for the runtime files.
RUN chown -R app:users /home/app

# ------- Stage 2: Create the final, lean image --------
FROM ${IMAGE}

# --- OPTIMIZATION STEP ---
# As root, remove unnecessary files to reduce the final image size.
# This must be done as root, before creating the 'app' user.
# RUN set -x; \
# rpm -v --erase --nodeps --force python3-cssselect python3 python3-base python3-lxml python3-gobject \
# ca-certificates cracklib cups-config diffutils fdupes \
# gio-branding-openSUSE gstreamer gtk2-tools gtk3-data gtk3-schema gtk3-tools \
# hicolor-icon-theme info ncurses-utils netcfg openSUSE-release perl5 pinentry \
# Mesa Mesa-dri Mesa-gallium Mesa-libEGL1 Mesa-libGL1 libglvnd libgstgl; \
# rm -rf /usr/include \
# /usr/lib/{browser-plugins,gstreamer-*,ca-certificates,keyboxd,locale,perl5,git,gpg-*,getconf,scdaemon,ssh,systemd,tmpfiles.d} \
# /usr/local/* \
# /usr/sbin/{fdisk,sfdisk,g13-syshelp,fsck.minix,partx,mkswap,zramctl} \
# /var/log/* \
# /var/cache/{zypp,ldconfig,fontconfig,cups} \
# /var/adm/* \
# /var/lib/{YaST2,alternatives,ca-certificates,selinux,xkb,misc} || true

# --- DIAGNOSTIC STEP ---
# Add this temporary command to see the size of top-level directories
# before the cleanup step. This helps identify what is taking up space.
# RUN du -sh /usr/lib/* | sort -rh | head -n 20 > /du-usrlib-sort.txt


# Create the same non-root user.
RUN useradd -m app

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

# Set the working directory
WORKDIR /app
# Switch to the non-root user for security.
USER app

# Add the virtual environment's bin directory to the PATH
ENV PATH="/app/.venv/bin:${PATH}"
# Set the working directory.
WORKDIR /home/app

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

# Run the application
CMD ["docbuild"]
# Run the application.
# ENTRYPOINT [ "docbuild" ]
# CMD ["docbuild", "--env-config", "env-production.toml", "--help"]
1 change: 1 addition & 0 deletions changelog.d/69.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve Dockerfile and documentation
2 changes: 1 addition & 1 deletion docs/source/developer/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ This guide provides all the necessary information for contributing to the projec
build-changelog
create-release
trigger-actions

work-with-docker
build-docs
howto

Expand Down
6 changes: 4 additions & 2 deletions docs/source/developer/prepare-environment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ The following steps are recommended to set up your development environment:
uv venv --prompt venv313 --python 3.13 .venv

Keep in mind that the Python version used in the virtual environment should match the version specified in the :file:`pyproject.toml` file.

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.
See file :file:`pyproject.toml` in ``project.requires-python`` for the exact version.

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


.. _get-docserv-config:

Getting Docserv's Config Files
------------------------------

Expand All @@ -116,4 +118,4 @@ To get started, clone this repository to your local machine (you need VPN access
git clone https://gitlab.suse.de/susedoc/docserv-config.git

You will later need to point ``docbuild`` to the location of this cloned
repository in your configuration.
repository in your configuration.
76 changes: 76 additions & 0 deletions docs/source/developer/work-with-docker.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
.. _work-docker:

Working with Docker Images
==========================

Sometimes it is easier to work with a Docker container that contains all
the necessary dependencies.


Requirements
------------

To build a Docker image and use it as container, check the following
requirements:

* Docker installed and running on your system:

* For openSUSE: Run :command:`sudo zypper install docker` to install it and :command:`sudo systemctl start docker` to start the Docker daemon.

* For MacOS: Refer to https://docs.docker.com/desktop/setup/install/mac-install/.

* Clone the respective configuration repository. Refer to :ref:`get-docserv-config`.


Creating a Docker image
-----------------------

To create a Docker image, use the following command:

.. code-block:: shell-session
:caption: Building the image

docker buildx build -t docbuild:latest .

This creates a Docker image ``docbuild`` with the tag ``latest``. After the successful build, you see:

.. code-block:: shell-session
:caption: Listing the Docker image

$ docker image ls docbuild
REPOSITORY TAG IMAGE ID CREATED SIZE
docbuild latest c13d36935907 16 minutes ago 643MB


Running the Docker container
----------------------------

Before you start the Docker container, you need to collect some paths and file names:

* The path to the configuration repository, marked as ``CONFIG_DIR``.
* The path to the environment file, marked as ``ENV_FILE``. Usually you want to use :file:`$PWD/etc/env-docker.toml` from this repository.
* The path to the cache directory, marked as ``CACHE_DIR``. Under Linux it's usually :file:`/var/cache/docbuild`
* The path of the target directory (the result of all ), marked as ``TARGET_DIR``.


.. admonition:: Make absolute paths

Use absolute paths for the previous variables.


Running the Docker container based on the previous image, use this command:

.. code-block:: shell-session
:caption: Running the Docker container

export CONFIG_DIR="..."
export ENV_FILE="..."
export CACHE_DIR="..."
export TARGET_DIR="..."
docker run --it \
-v $CONFIG_DIR:/etc/docbuild \
-v $ENV_FILE:/app/.env-production.toml \
-v $CACHE_DIR:/var/cache/docbuild/ \
-v $TARGET_DIR:/data/docbuild/external-builds/ \
docbuild:latest \
DOCBUILD_COMMAND
90 changes: 90 additions & 0 deletions etc/docbuild/env.docker.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# TOML example configuration file
#

[server]
# Section "server": deals with all config about server settings
name = "doc-suse-com"
role = "production"
host = "127.0.0.1"
# port =
enable_mail = true


[config]
# Section "config": general configuration
default_lang = "en-us"
languages = [
'de-de',
'en-us',
'es-es',
'fr-fr',
'ja-jp',
'ko-kr',
'pt-br',
'zh-cn',
]
canonical_url_domain = "https://docs.example.com"


[paths]
# Section "paths": Defines several paths
# Paths can hold placeholders in brackets.
root_config_dir = "/etc/docbuild"
jinja_dir = "{root_config_dir}/jinja-doc-suse-com"
config_dir = "{root_config_dir}/config.d"
server_rootfiles_dir = "{root_config_dir}/server-root-files-doc-suse-com"
#
base_cache_dir = "/var/cache/docbuild"
base_server_cache_dir = "{base_cache_dir}/{server.name}"
base_tmp_dir = "{base_cache_dir}/tmp"
repo_dir = "{base_cache_dir}/repos/permanent-full/"
temp_repo_dir = "{base_cache_dir}/repos/temporary-branches/"
# cache_dir = "{base_cache_dir}/{server.name}"
meta_cache_dir = "{base_cache_dir}/{server.name}/meta"

[paths.tmp]
# Section "paths.tmp": Definies temporary paths
# Paths can hold placeholders in brackets.
tmp_base_dir = "{paths.base_tmp_dir}"
tmp_dir = "{tmp_base_dir}/doc-example-com"
tmp_metadata_dir = "{tmp_dir}/metadata"
tmp_deliverable_dir = "{paths.tmp.tmp_dir}/deliverable/"
tmp_build_dir = "{tmp_dir}/build/{{product}}-{{docset}}-{{lang}}"
tmp_out_dir = "{tmp_dir}/out/"
log_dir = "{tmp_dir}/log/"
tmp_deliverable_name = "{{product}}_{{docset}}_{{lang}}_XXXXXX"

[paths.target]
# Section "paths.target": Definies target paths
target_dir = "[email protected]:/srv/docs"
backup_dir = "/data/docbuild/external-builds/"


[build]
# Section "build": General build parameters, independant from any specific

[build.daps]
# Section "build.daps": Configuration for daps
command = "daps -vv"
meta = "daps -vv metadata --output {{output}}"
# html = "daps -vv --builddir='{paths.tmp.tmp_build_dir}' html"
# pdf = "daps -vv --builddir='{paths.tmp.tmp_build_dir}' pdf"


[build.container]
# Section "build.container": Configuration for container
container = "registry.opensuse.org/documentation/containers/15.6/opensuse-daps-toolchain:latest"

[xslt-params]
# Section "xslt-params": Replaces /etc/docserv/xslt-params-doc-suse-com.txt file
# These keys are considered as XSLT parameters and passed
# to the transformation process
homepage = "https://documentation.suse.com/"
overview-page = "https://documentation.suse.com/"
overview-page-title = "documentation.suse.com"
external.js.onlineonly = "/docserv/res/extra.js"
show.edit.link = 1
twittercards.twitter.account = "@SUSE"
generate.json-ld = 1
search.description.length = 118
socialmedia.description.length = 65