mirror of
https://github.com/searxng/searxng.git
synced 2025-08-10 13:56:45 +02:00
Building the container currently does not work properly. When rebuilding several times with `make container`, `version_frozen.py` is recreated, which wouldn't be an issue if the file’s timestamp was constant. Now, when creating `version_frozen.py`, it will have the same timestamp as the commit when it was created. (`version_frozen.py` is moved to a dedicated layer). Reusing "builder" cache when building "dist" could be slow (CD reports 2 seconds, but locally I've seen it take up to 10 seconds), so the Dockerfile is now split and we save a couple steps by importing the "builder" image directly. The last changes made it possible to remove the layer cache in "builder", since the overhead is now greater than building the layers from scratch. Until now, all "dist" layers were squashed into a single layer, which in most cases is a good idea (except for storage/delivery pricing/overhead), but in our case, since we manage the entire pipeline, we can ignore this and share layers between builds. This means (for example) that if we change files unrelated to the container in several consecutive commits (documentation changes), we don't have to push the entire image to registry, but only the different layers (`version_frozen.py` in this example). The same applies when pulling, as only the layers that have changed compared to the local layers will be downloaded (that's the theory, we'll see if this works as expected or if we need to tweak something else).
292 lines
8.5 KiB
Bash
292 lines
8.5 KiB
Bash
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
container.help() {
|
|
cat <<EOF
|
|
container.:
|
|
build : build container image
|
|
EOF
|
|
}
|
|
|
|
CONTAINER_IMAGE_ORGANIZATION=${GITHUB_REPOSITORY_OWNER:-"searxng"}
|
|
CONTAINER_IMAGE_NAME="searxng"
|
|
|
|
container.build() {
|
|
local parch=${OVERRIDE_ARCH:-$(uname -m)}
|
|
local container_engine
|
|
local arch
|
|
local variant
|
|
local platform
|
|
|
|
required_commands git
|
|
|
|
# Check if podman or docker is installed
|
|
if [ "$1" = "podman" ] || [ "$1" = "docker" ]; then
|
|
if ! command -v "$1" &>/dev/null; then
|
|
die 42 "$1 is not installed"
|
|
fi
|
|
container_engine="$1"
|
|
else
|
|
# If no explicit engine is passed, prioritize podman over docker
|
|
if command -v podman &>/dev/null; then
|
|
container_engine="podman"
|
|
elif command -v docker &>/dev/null; then
|
|
container_engine="docker"
|
|
else
|
|
die 42 "no compatible container engine is installed (podman or docker)"
|
|
fi
|
|
fi
|
|
info_msg "Selected engine: $container_engine"
|
|
|
|
# Setup arch specific
|
|
case $parch in
|
|
"X64" | "x86_64" | "amd64")
|
|
arch="amd64"
|
|
variant=""
|
|
platform="linux/$arch"
|
|
;;
|
|
"ARM64" | "aarch64" | "arm64")
|
|
arch="arm64"
|
|
variant=""
|
|
platform="linux/$arch"
|
|
;;
|
|
"ARMV7" | "armhf" | "armv7l" | "armv7")
|
|
arch="arm"
|
|
variant="v7"
|
|
platform="linux/$arch/$variant"
|
|
;;
|
|
*)
|
|
err_msg "Unsupported architecture; $parch"
|
|
exit 1
|
|
;;
|
|
esac
|
|
info_msg "Selected platform: $platform"
|
|
|
|
pyenv.install
|
|
|
|
(
|
|
set -e
|
|
pyenv.activate
|
|
|
|
# Check if it is a git repository
|
|
if [ ! -d .git ]; then
|
|
die 1 "This is not Git repository"
|
|
fi
|
|
|
|
if ! git remote get-url origin &>/dev/null; then
|
|
die 1 "There is no remote origin"
|
|
fi
|
|
|
|
# This is a git repository
|
|
git update-index -q --refresh
|
|
python -m searx.version freeze
|
|
eval "$(python -m searx.version)"
|
|
|
|
info_msg "Set \$DOCKER_TAG: $DOCKER_TAG"
|
|
info_msg "Set \$GIT_URL: $GIT_URL"
|
|
|
|
if [ "$container_engine" = "podman" ]; then
|
|
params_build_builder="build --format=oci --platform=$platform --layers --identity-label=false"
|
|
params_build=$params_build_builder
|
|
else
|
|
params_build_builder="build --platform=$platform"
|
|
params_build=$params_build_builder
|
|
fi
|
|
|
|
if [ "$GITHUB_ACTIONS" = "true" ]; then
|
|
params_build+=" --tag=ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-$arch$variant"
|
|
else
|
|
params_build+=" --tag=localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:latest"
|
|
params_build+=" --tag=localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$DOCKER_TAG"
|
|
fi
|
|
|
|
# shellcheck disable=SC2086
|
|
"$container_engine" $params_build_builder \
|
|
--build-arg="TIMESTAMP_SETTINGS=$(git log -1 --format="%cd" --date=unix -- ./searx/settings.yml)" \
|
|
--tag="localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:builder" \
|
|
--file="./container/builder.dockerfile" \
|
|
.
|
|
build_msg CONTAINER "Image \"builder\" built"
|
|
|
|
# shellcheck disable=SC2086
|
|
"$container_engine" $params_build \
|
|
--build-arg="CONTAINER_IMAGE_ORGANIZATION=$CONTAINER_IMAGE_ORGANIZATION" \
|
|
--build-arg="CONTAINER_IMAGE_NAME=$CONTAINER_IMAGE_NAME" \
|
|
--build-arg="CREATED=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
--build-arg="VERSION=$DOCKER_TAG" \
|
|
--build-arg="VCS_URL=$GIT_URL" \
|
|
--build-arg="VCS_REVISION=$(git rev-parse HEAD)" \
|
|
--file="./container/dist.dockerfile" \
|
|
.
|
|
build_msg CONTAINER "Image built"
|
|
|
|
if [ "$GITHUB_ACTIONS" = "true" ]; then
|
|
"$container_engine" push "ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-$arch$variant"
|
|
|
|
# Output to GHA
|
|
cat <<EOF >>"$GITHUB_OUTPUT"
|
|
docker_tag=$DOCKER_TAG
|
|
git_url=$GIT_URL
|
|
EOF
|
|
fi
|
|
)
|
|
dump_return $?
|
|
}
|
|
|
|
container.test() {
|
|
local parch=${OVERRIDE_ARCH:-$(uname -m)}
|
|
local arch
|
|
local variant
|
|
local platform
|
|
|
|
if [ "$GITHUB_ACTIONS" != "true" ]; then
|
|
die 1 "This command is intended to be run in GitHub Actions"
|
|
fi
|
|
|
|
required_commands podman
|
|
|
|
# Setup arch specific
|
|
case $parch in
|
|
"X64" | "x86_64" | "amd64")
|
|
arch="amd64"
|
|
variant=""
|
|
platform="linux/$arch"
|
|
;;
|
|
"ARM64" | "aarch64" | "arm64")
|
|
arch="arm64"
|
|
variant=""
|
|
platform="linux/$arch"
|
|
;;
|
|
"ARMV7" | "armhf" | "armv7l" | "armv7")
|
|
arch="arm"
|
|
variant="v7"
|
|
platform="linux/$arch/$variant"
|
|
;;
|
|
*)
|
|
err_msg "Unsupported architecture; $parch"
|
|
exit 1
|
|
;;
|
|
esac
|
|
build_msg CONTAINER "Selected platform: $platform"
|
|
|
|
(
|
|
set -e
|
|
|
|
podman pull "ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-$arch$variant"
|
|
|
|
name="$CONTAINER_IMAGE_NAME-$(date +%N)"
|
|
|
|
podman create --name="$name" --rm --timeout=60 --network="host" \
|
|
"ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-$arch$variant" >/dev/null
|
|
|
|
podman start "$name" >/dev/null
|
|
podman logs -f "$name" &
|
|
pid_logs=$!
|
|
|
|
# Wait until container is ready
|
|
sleep 5
|
|
|
|
curl -vf --max-time 5 "http://localhost:8080/healthz"
|
|
|
|
kill $pid_logs &>/dev/null || true
|
|
podman stop "$name" >/dev/null
|
|
)
|
|
dump_return $?
|
|
}
|
|
|
|
container.push() {
|
|
# Architectures on manifest
|
|
local release_archs=("amd64" "arm64" "armv7")
|
|
|
|
local archs=()
|
|
local variants=()
|
|
local platforms=()
|
|
|
|
if [ "$GITHUB_ACTIONS" != "true" ]; then
|
|
die 1 "This command is intended to be run in GitHub Actions"
|
|
fi
|
|
|
|
required_commands podman
|
|
|
|
for arch in "${release_archs[@]}"; do
|
|
case $arch in
|
|
"X64" | "x86_64" | "amd64")
|
|
archs+=("amd64")
|
|
variants+=("")
|
|
platforms+=("linux/${archs[-1]}")
|
|
;;
|
|
"ARM64" | "aarch64" | "arm64")
|
|
archs+=("arm64")
|
|
variants+=("")
|
|
platforms+=("linux/${archs[-1]}")
|
|
;;
|
|
"ARMV7" | "armv7" | "armhf" | "arm")
|
|
archs+=("arm")
|
|
variants+=("v7")
|
|
platforms+=("linux/${archs[-1]}/${variants[-1]}")
|
|
;;
|
|
*)
|
|
err_msg "Unsupported architecture; $arch"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
(
|
|
set -e
|
|
|
|
# Pull archs
|
|
for i in "${!archs[@]}"; do
|
|
podman pull "ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-${archs[$i]}${variants[$i]}"
|
|
done
|
|
|
|
# Manifest tags ("latest" should be the last manifest)
|
|
release_tags=("$DOCKER_TAG" "latest")
|
|
|
|
# Create manifests
|
|
for tag in "${release_tags[@]}"; do
|
|
if ! podman manifest exists "localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag"; then
|
|
podman manifest create "localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag"
|
|
fi
|
|
|
|
# Add archs to manifest
|
|
for i in "${!archs[@]}"; do
|
|
podman manifest add \
|
|
"localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag" \
|
|
"containers-storage:ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-${archs[$i]}${variants[$i]}"
|
|
done
|
|
done
|
|
|
|
podman image list
|
|
|
|
# Remote registries
|
|
release_registries=("ghcr.io" "docker.io")
|
|
|
|
# Push manifests
|
|
for registry in "${release_registries[@]}"; do
|
|
for tag in "${release_tags[@]}"; do
|
|
build_msg CONTAINER "Pushing manifest $tag to $registry"
|
|
|
|
podman manifest push \
|
|
"localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag" \
|
|
"docker://$registry/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag"
|
|
done
|
|
done
|
|
)
|
|
dump_return $?
|
|
}
|
|
|
|
# Alias
|
|
podman.build() {
|
|
container.build podman
|
|
}
|
|
|
|
# Alias
|
|
docker.build() {
|
|
container.build docker
|
|
}
|
|
|
|
# Alias
|
|
docker.buildx() {
|
|
container.build docker
|
|
}
|