lib_sxng_container.sh 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. #!/usr/bin/env bash
  2. # SPDX-License-Identifier: AGPL-3.0-or-later
  3. container.help() {
  4. cat <<EOF
  5. container.:
  6. build : build container image
  7. EOF
  8. }
  9. CONTAINER_IMAGE_ORGANIZATION=${GITHUB_REPOSITORY_OWNER:-"searxng"}
  10. CONTAINER_IMAGE_NAME="searxng"
  11. container.build() {
  12. local parch=${OVERRIDE_ARCH:-$(uname -m)}
  13. local container_engine
  14. local dockerfile
  15. local arch
  16. local variant
  17. local platform
  18. # Check if git is installed
  19. if ! command -v git &>/dev/null; then
  20. die 1 "Git is not installed"
  21. fi
  22. # Check if podman or docker is installed
  23. if [ "$1" = "docker" ]; then
  24. if command -v docker &>/dev/null; then
  25. container_engine="docker"
  26. else
  27. die 1 "Docker is not installed"
  28. fi
  29. elif [ "$1" = "podman" ]; then
  30. if command -v podman &>/dev/null; then
  31. container_engine="podman"
  32. else
  33. die 1 "Podman is not installed"
  34. fi
  35. else
  36. # If no explicit engine is passed, prioritize podman over docker
  37. if command -v podman &>/dev/null; then
  38. container_engine="podman"
  39. elif command -v docker &>/dev/null; then
  40. container_engine="docker"
  41. else
  42. die 1 "Podman/Docker is not installed"
  43. fi
  44. fi
  45. info_msg "Selected engine: $container_engine"
  46. # Setup arch specific
  47. case $parch in
  48. "X64" | "x86_64" | "amd64")
  49. dockerfile="Dockerfile"
  50. arch="amd64"
  51. variant=""
  52. platform="linux/$arch"
  53. ;;
  54. "ARM64" | "aarch64" | "arm64")
  55. dockerfile="Dockerfile"
  56. arch="arm64"
  57. variant=""
  58. platform="linux/$arch"
  59. ;;
  60. "ARMV7" | "armhf" | "armv7l" | "armv7")
  61. dockerfile="legacy/Dockerfile"
  62. arch="arm"
  63. variant="v7"
  64. platform="linux/$arch/$variant"
  65. ;;
  66. *)
  67. err_msg "Unsupported architecture; $parch"
  68. exit 1
  69. ;;
  70. esac
  71. info_msg "Selected platform: $platform"
  72. pyenv.install
  73. (
  74. set -e
  75. pyenv.activate
  76. # Check if it is a git repository
  77. if [ ! -d .git ]; then
  78. die 1 "This is not Git repository"
  79. fi
  80. if ! git remote get-url origin &>/dev/null; then
  81. die 1 "There is no remote origin"
  82. fi
  83. # This is a git repository
  84. git update-index -q --refresh
  85. python -m searx.version freeze
  86. eval "$(python -m searx.version)"
  87. info_msg "Set \$VERSION_STRING: $VERSION_STRING"
  88. info_msg "Set \$VERSION_TAG: $VERSION_TAG"
  89. info_msg "Set \$DOCKER_TAG: $DOCKER_TAG"
  90. info_msg "Set \$GIT_URL: $GIT_URL"
  91. info_msg "Set \$GIT_BRANCH: $GIT_BRANCH"
  92. if [ "$container_engine" = "podman" ]; then
  93. params_build_builder="build --format=docker --platform=$platform --target=builder --layers --identity-label=false"
  94. params_build="build --format=docker --platform=$platform --layers --squash-all --omit-history --identity-label=false"
  95. else
  96. params_build_builder="build --platform=$platform --target=builder"
  97. params_build="build --platform=$platform --squash"
  98. fi
  99. if [ "$GITHUB_ACTIONS" = "true" ]; then
  100. params_build_builder+=" --cache-from=ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache --cache-to=ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache"
  101. params_build+=" --cache-from=ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache --cache-to=ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache"
  102. # Tags
  103. params_build+=" --tag=ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-$arch$variant"
  104. else
  105. # Tags
  106. params_build+=" --tag=localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:latest"
  107. params_build+=" --tag=localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$DOCKER_TAG"
  108. fi
  109. # shellcheck disable=SC2086
  110. "$container_engine" $params_build_builder \
  111. --build-arg="TIMESTAMP_SETTINGS=$(git log -1 --format="%cd" --date=unix -- ./searx/settings.yml)" \
  112. --build-arg="TIMESTAMP_UWSGI=$(git log -1 --format="%cd" --date=unix -- ./container/uwsgi.ini)" \
  113. --tag="localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:builder" \
  114. --file="./container/$dockerfile" \
  115. .
  116. build_msg CONTAINER "Image \"builder\" built"
  117. # shellcheck disable=SC2086
  118. "$container_engine" $params_build \
  119. --build-arg="GIT_URL=$GIT_URL" \
  120. --build-arg="SEARXNG_GIT_VERSION=$VERSION_STRING" \
  121. --build-arg="LABEL_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  122. --build-arg="LABEL_VCS_REF=$(git rev-parse HEAD)" \
  123. --build-arg="LABEL_VCS_URL=$GIT_URL" \
  124. --file="./container/$dockerfile" \
  125. .
  126. build_msg CONTAINER "Image built"
  127. if [ "$GITHUB_ACTIONS" = "true" ]; then
  128. "$container_engine" push "ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-$arch$variant"
  129. # Output to GHA
  130. {
  131. echo "version_string=$VERSION_STRING"
  132. echo "version_tag=$VERSION_TAG"
  133. echo "docker_tag=$DOCKER_TAG"
  134. echo "git_url=$GIT_URL"
  135. echo "git_branch=$GIT_BRANCH"
  136. } >>"$GITHUB_OUTPUT"
  137. fi
  138. )
  139. dump_return $?
  140. }
  141. container.test() {
  142. local parch=${OVERRIDE_ARCH:-$(uname -m)}
  143. local arch
  144. local variant
  145. local platform
  146. if [ "$GITHUB_ACTIONS" != "true" ]; then
  147. die 1 "This command is intended to be run in GitHub Actions"
  148. fi
  149. # Check if podman is installed
  150. if ! command -v podman &>/dev/null; then
  151. die 1 "podman is not installed"
  152. fi
  153. # Setup arch specific
  154. case $parch in
  155. "X64" | "x86_64" | "amd64")
  156. arch="amd64"
  157. variant=""
  158. platform="linux/$arch"
  159. ;;
  160. "ARM64" | "aarch64" | "arm64")
  161. arch="arm64"
  162. variant=""
  163. platform="linux/$arch"
  164. ;;
  165. "ARMV7" | "armhf" | "armv7l" | "armv7")
  166. arch="arm"
  167. variant="v7"
  168. platform="linux/$arch/$variant"
  169. ;;
  170. *)
  171. err_msg "Unsupported architecture; $parch"
  172. exit 1
  173. ;;
  174. esac
  175. build_msg CONTAINER "Selected platform: $platform"
  176. (
  177. set -e
  178. podman pull "ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-$arch$variant"
  179. name="$CONTAINER_IMAGE_NAME-$(date +%N)"
  180. podman create --name="$name" --rm --timeout=60 --network="host" \
  181. "ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-$arch$variant" >/dev/null
  182. podman start "$name" >/dev/null
  183. podman logs -f "$name" &
  184. pid_logs=$!
  185. # Wait until container is ready
  186. sleep 5
  187. curl -vf --max-time 5 "http://localhost:8080/healthz"
  188. kill $pid_logs &>/dev/null || true
  189. podman stop "$name" >/dev/null
  190. )
  191. dump_return $?
  192. }
  193. container.push() {
  194. # Architectures on manifest
  195. local release_archs=("amd64" "arm64" "armv7")
  196. local archs=()
  197. local variants=()
  198. local platforms=()
  199. if [ "$GITHUB_ACTIONS" != "true" ]; then
  200. die 1 "This command is intended to be run in GitHub Actions"
  201. fi
  202. # Check if podman is installed
  203. if ! command -v podman &>/dev/null; then
  204. die 1 "podman is not installed"
  205. fi
  206. for arch in "${release_archs[@]}"; do
  207. case $arch in
  208. "X64" | "x86_64" | "amd64")
  209. archs+=("amd64")
  210. variants+=("")
  211. platforms+=("linux/${archs[-1]}")
  212. ;;
  213. "ARM64" | "aarch64" | "arm64")
  214. archs+=("arm64")
  215. variants+=("")
  216. platforms+=("linux/${archs[-1]}")
  217. ;;
  218. "ARMV7" | "armv7" | "armhf" | "arm")
  219. archs+=("arm")
  220. variants+=("v7")
  221. platforms+=("linux/${archs[-1]}/${variants[-1]}")
  222. ;;
  223. *)
  224. err_msg "Unsupported architecture; $arch"
  225. exit 1
  226. ;;
  227. esac
  228. done
  229. (
  230. set -e
  231. # Pull archs
  232. for i in "${!archs[@]}"; do
  233. podman pull "ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-${archs[$i]}${variants[$i]}"
  234. done
  235. # Manifest tags
  236. release_tags=("latest")
  237. release_tags+=("$DOCKER_TAG")
  238. # Create manifests
  239. for tag in "${release_tags[@]}"; do
  240. if ! podman manifest exists "localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag"; then
  241. podman manifest create "localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag"
  242. fi
  243. # Add archs to manifest
  244. for i in "${!archs[@]}"; do
  245. podman manifest add \
  246. "localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag" \
  247. "containers-storage:ghcr.io/$CONTAINER_IMAGE_ORGANIZATION/cache:$CONTAINER_IMAGE_NAME-${archs[$i]}${variants[$i]}"
  248. done
  249. done
  250. podman image list
  251. # Push manifests
  252. for tag in "${release_tags[@]}"; do
  253. build_msg CONTAINER "Pushing manifest with tag: $tag"
  254. podman manifest push \
  255. "localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag" \
  256. "docker://docker.io/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:$tag"
  257. done
  258. )
  259. dump_return $?
  260. }
  261. # Alias
  262. podman.build() {
  263. container.build podman
  264. }
  265. # Alias
  266. docker.build() {
  267. container.build docker
  268. }
  269. # Alias
  270. docker.buildx() {
  271. container.build docker
  272. }