Skip to content

Commit c11d95c

Browse files
chaenchrisburr
authored andcommitted
chore: replace container base images with pixi-managed environments
1 parent a3f9c96 commit c11d95c

17 files changed

Lines changed: 22623 additions & 150 deletions

File tree

.github/workflows/deployment.yml

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ jobs:
9797

9898
docker:
9999
needs: deploy-pypi
100-
timeout-minutes: 30
100+
timeout-minutes: 30
101101
runs-on: ubuntu-latest
102102
steps:
103103
- name: Checkout
@@ -112,58 +112,46 @@ jobs:
112112
registry: ghcr.io
113113
username: ${{ github.actor }}
114114
password: ${{ secrets.GITHUB_TOKEN }}
115-
- name: Download diracx wheels
116-
uses: actions/download-artifact@v8
117-
with:
118-
name: diracx-whl
119-
- name: "Find wheels"
120-
id: find_wheel
121-
run: |
122-
# We need to copy them there to be able to access them in the RUN --mount
123-
cp diracx*.whl containers/client/
124-
cp diracx*.whl containers/services/
125-
for wheel_fn in *.whl; do
126-
pkg_name=$(basename "${wheel_fn}" | cut -d '-' -f 1)
127-
echo "${pkg_name}-wheel-name=$(ls "${pkg_name}"-*.whl)" >> $GITHUB_OUTPUT
128-
done
129115

130-
- name: Build and push client (release)
116+
- name: Build and push services (release)
131117
uses: docker/build-push-action@v7
132118
if: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
133119
with:
134-
context: containers/client/
135-
push: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
136-
tags: "ghcr.io/diracgrid/diracx/client:${{ needs.deploy-pypi.outputs.new-version }}"
120+
context: .
121+
file: containers/Dockerfile
122+
build-args: PIXI_ENV=container-services
123+
push: true
124+
tags: "ghcr.io/diracgrid/diracx/services:${{ needs.deploy-pypi.outputs.new-version }}"
137125
platforms: linux/amd64,linux/arm64
138-
build-args: EXTRA_PACKAGES_TO_INSTALL=DIRACCommon~=9.0.0
139-
- name: Build and push services (release)
126+
- name: Build and push client (release)
140127
uses: docker/build-push-action@v7
141128
if: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
142129
with:
143-
context: containers/services/
144-
push: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
145-
tags: "ghcr.io/diracgrid/diracx/services:${{ needs.deploy-pypi.outputs.new-version }}"
130+
context: .
131+
file: containers/Dockerfile
132+
build-args: PIXI_ENV=container-client
133+
push: true
134+
tags: "ghcr.io/diracgrid/diracx/client:${{ needs.deploy-pypi.outputs.new-version }}"
146135
platforms: linux/amd64,linux/arm64
147-
build-args: EXTRA_PACKAGES_TO_INSTALL=DIRACCommon~=9.0.0
148136

149-
- name: Build and push client (dev)
137+
- name: Build and push services (dev)
150138
uses: docker/build-push-action@v7
151139
with:
152-
context: containers/client/
140+
context: .
141+
file: containers/Dockerfile
142+
build-args: PIXI_ENV=container-services
153143
push: ${{ github.event_name != 'pull_request' && github.repository == 'DIRACGrid/diracx' && github.ref_name == 'main' }}
154-
tags: ghcr.io/diracgrid/diracx/client:dev
144+
tags: ghcr.io/diracgrid/diracx/services:dev
155145
platforms: linux/amd64,linux/arm64
156-
build-args: |
157-
EXTRA_PACKAGES_TO_INSTALL=git+https://github.com/DIRACGrid/DIRAC.git@integration#egg=diraccommon\&subdirectory=dirac-common
158-
- name: Build and push services (dev)
146+
- name: Build and push client (dev)
159147
uses: docker/build-push-action@v7
160148
with:
161-
context: containers/services/
149+
context: .
150+
file: containers/Dockerfile
151+
build-args: PIXI_ENV=container-client
162152
push: ${{ github.event_name != 'pull_request' && github.repository == 'DIRACGrid/diracx' && github.ref_name == 'main' }}
163-
tags: ghcr.io/diracgrid/diracx/services:dev
153+
tags: ghcr.io/diracgrid/diracx/client:dev
164154
platforms: linux/amd64,linux/arm64
165-
build-args: |
166-
EXTRA_PACKAGES_TO_INSTALL=git+https://github.com/DIRACGrid/DIRAC.git@integration#egg=diraccommon\&subdirectory=dirac-common
167155

168156
update-charts:
169157
name: Update Helm charts

.github/workflows/main.yml

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -121,38 +121,20 @@ jobs:
121121
with:
122122
cache: false
123123
environments: ${{ matrix.extension == 'diracx' && 'default' || 'default-gubbins' }}
124-
- name: Build gubbins wheels
125-
if: ${{ matrix.extension == 'gubbins' }}
126-
run: |
127-
for pkg_dir in $PWD/diracx-*; do
128-
echo "Building $pkg_dir"
129-
pixi exec python-build --outdir $PWD/extensions/containers/services/ $pkg_dir
130-
done
131-
# Also build the diracx metapackage
132-
pixi exec python-build --outdir $PWD/extensions/containers/services/ .
133-
# And build the gubbins package
134-
for pkg_dir in $PWD/extensions/gubbins/gubbins-*; do
135-
# Skip the testing package
136-
if [[ "${pkg_dir}" =~ .*testing.* ]];
137-
then
138-
echo "Do not build ${pkg_dir}";
139-
continue;
140-
fi
141-
echo "Building $pkg_dir"
142-
pixi exec python-build --outdir $PWD/extensions/containers/services/ $pkg_dir
143-
done
144124
- name: Set up Docker Buildx
145125
if: ${{ matrix.extension == 'gubbins' }}
146126
uses: docker/setup-buildx-action@v4
147127
- name: Build container for gubbins
148128
if: ${{ matrix.extension == 'gubbins' }}
149129
uses: docker/build-push-action@v7
150130
with:
151-
context: extensions/containers/services
131+
context: .
132+
file: containers/Dockerfile
133+
build-args: |
134+
PIXI_ENV=gubbins-container-services
135+
DIRACX_EXTENSIONS=gubbins,diracx
152136
tags: gubbins/services:dev
153137
outputs: type=docker,dest=/tmp/gubbins_services_image.tar
154-
build-args: |
155-
EXTENSION_CUSTOM_SOURCES_TO_INSTALL=/bindmount/gubbins_db*.whl,/bindmount/gubbins_logic*.whl,/bindmount/gubbins_routers*.whl,/bindmount/gubbins_client*.whl
156138
- name: Load image
157139
if: ${{ matrix.extension == 'gubbins' }}
158140
run: |

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ docs/source/_build
9797

9898
# pixi environments
9999
.pixi
100-
pixi.lock
101100
*.egg-info
102101
docs/templates/_builtin_markdown.jinja
103102

@@ -106,3 +105,7 @@ docs/templates/_builtin_markdown.jinja
106105

107106
# docs site
108107
site
108+
109+
# DiracX specific
110+
# No point in committing the pixi.lock for gubbins as it cannot work properly within the diracx repo
111+
extensions/gubbins/pixi.lock

.pre-commit-config.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ repos:
2828
- id: check-yaml
2929
args: ["--unsafe"]
3030
- id: check-added-large-files
31+
exclude: pixi\.lock$
3132

3233
- repo: https://github.com/astral-sh/ruff-pre-commit
3334
rev: "v0.15.7"
@@ -66,6 +67,7 @@ repos:
6667
hooks:
6768
- id: codespell
6869
args: ["-w"]
70+
exclude: pixi\.lock$
6971

7072
- repo: https://github.com/adamchainz/blacken-docs
7173
rev: 1.20.0

containers/Dockerfile

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
FROM ghcr.io/prefix-dev/pixi:latest AS build
2+
3+
ARG PIXI_ENV=container-services
4+
ARG DIRACX_EXTENSIONS=diracx
5+
6+
WORKDIR /app
7+
COPY pixi.toml pixi.lock ./
8+
9+
# Copy source directories needed for path-based installs
10+
COPY .git/ .git/
11+
COPY diracx-api/ diracx-api/
12+
COPY diracx-cli/ diracx-cli/
13+
COPY diracx-client/ diracx-client/
14+
COPY diracx-core/ diracx-core/
15+
COPY diracx-db/ diracx-db/
16+
COPY diracx-logic/ diracx-logic/
17+
COPY diracx-routers/ diracx-routers/
18+
COPY diracx-testing/ diracx-testing/
19+
COPY pyproject.toml ./
20+
COPY README.md ./
21+
COPY extensions/gubbins/gubbins-api/ extensions/gubbins/gubbins-api/
22+
COPY extensions/gubbins/gubbins-cli/ extensions/gubbins/gubbins-cli/
23+
COPY extensions/gubbins/gubbins-client/ extensions/gubbins/gubbins-client/
24+
COPY extensions/gubbins/gubbins-core/ extensions/gubbins/gubbins-core/
25+
COPY extensions/gubbins/gubbins-db/ extensions/gubbins/gubbins-db/
26+
COPY extensions/gubbins/gubbins-logic/ extensions/gubbins/gubbins-logic/
27+
COPY extensions/gubbins/gubbins-routers/ extensions/gubbins/gubbins-routers/
28+
COPY extensions/gubbins/gubbins-testing/ extensions/gubbins/gubbins-testing/
29+
COPY extensions/gubbins/pyproject.toml extensions/gubbins/
30+
COPY extensions/gubbins/README.md extensions/gubbins/
31+
32+
# Switch to non-editable installs (same workaround as CI)
33+
RUN sed -i 's@editable = true@editable = false@g' pixi.toml
34+
35+
RUN pixi install --frozen -e ${PIXI_ENV}
36+
37+
# Generate activation script
38+
RUN pixi shell-hook -e ${PIXI_ENV} > /activate.sh
39+
40+
FROM ubuntu:24.04
41+
42+
ARG PIXI_ENV=container-services
43+
ARG DIRACX_EXTENSIONS=diracx
44+
ENV PIXI_ENV=${PIXI_ENV}
45+
ENV DIRACX_EXTENSIONS=${DIRACX_EXTENSIONS}
46+
47+
EXPOSE 8000
48+
49+
# Copy the installed environment
50+
COPY --from=build /app/.pixi/envs/${PIXI_ENV} /app/.pixi/envs/${PIXI_ENV}
51+
COPY --from=build /activate.sh /activate.sh
52+
COPY containers/entrypoint.sh /entrypoint.sh
53+
54+
# In many clusters the container is run as a random uid for security reasons.
55+
# If we mark the environment directory as group 0 and give it group write
56+
# permissions then we're still able to manage the environment from inside the
57+
# container.
58+
RUN chmod -R g=u /app/.pixi
59+
60+
# Use tini as init (installed by pixi in the env)
61+
ENTRYPOINT ["/bin/bash", "-c", \
62+
"exec /app/.pixi/envs/${PIXI_ENV}/bin/tini -- /entrypoint.sh"]

containers/client/Dockerfile

Lines changed: 0 additions & 12 deletions
This file was deleted.

containers/entrypoint.sh

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/bin/bash
2+
set -e
3+
4+
source /activate.sh
5+
6+
function install_sources() {
7+
extension_name=$1
8+
source_prefix=$2
9+
image_packages=$3
10+
11+
IFS=','
12+
to_install=()
13+
for dir in ${!source_prefix}; do
14+
for package_name in ${!image_packages}; do
15+
if [[ "${package_name}" == "." ]]; then
16+
wheel_name="${extension_name}"
17+
else
18+
wheel_name="${extension_name}_${package_name}"
19+
fi
20+
wheels=( $(find "${dir}" -name "${wheel_name}-*.whl") )
21+
if [[ ${#wheels[@]} -gt 1 ]]; then
22+
echo "ERROR: Multiple wheels found for ${package_name} in ${dir}"
23+
exit 1
24+
elif [[ ${#wheels[@]} -eq 1 ]]; then
25+
to_install+=("${wheels[0]}")
26+
else
27+
if [[ "${package_name}" == "." ]]; then
28+
src_dir=("${dir}")
29+
else
30+
src_dir=("${dir}-${package_name}")
31+
fi
32+
if [[ -f "${src_dir}/pyproject.toml" ]]; then
33+
to_install+=("${src_dir}")
34+
fi
35+
fi
36+
done
37+
done
38+
if [[ ${#to_install[@]} -gt 0 ]]; then
39+
pip install --no-deps "${to_install[@]}"
40+
fi
41+
}
42+
43+
44+
# If we have extensions, we install them all the same way
45+
if [[ -n "${DIRACX_EXTENSIONS:-}" ]]; then
46+
47+
# Loop over the extension in reverse order
48+
IFS=', ' read -r -a extension_array <<< "$DIRACX_EXTENSIONS"
49+
for (( idx=${#extension_array[@]}-1 ; idx>=0 ; idx-- )) ; do
50+
51+
extension_name="${extension_array[idx]}"
52+
source_prefix="${extension_name^^}_CUSTOM_SOURCE_PREFIXES"
53+
image_packages="${extension_name^^}_IMAGE_PACKAGES"
54+
55+
if [[ -n "${!source_prefix:-}" ]]; then
56+
install_sources "${extension_name}" "${source_prefix}" "${image_packages}"
57+
fi
58+
done
59+
# No extensions, just diracx
60+
elif [[ -n "${DIRACX_CUSTOM_SOURCE_PREFIXES:-}" ]]; then
61+
install_sources "diracx" "DIRACX_CUSTOM_SOURCE_PREFIXES" "DIRACX_IMAGE_PACKAGES"
62+
fi
63+
64+
65+
exec "$@"

containers/services/Dockerfile

Lines changed: 0 additions & 12 deletions
This file was deleted.

diracx-routers/src/diracx/routers/otel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def instrument_otel(app: FastAPI) -> None:
105105
# # override logger format which with trace id and span id
106106
# https://github.com/mhausenblas/ref.otel.help/blob/main/how-to/logs-collection/yoda/main.py
107107

108-
LoggingInstrumentor().instrument(set_logging_format=False)
108+
LoggingInstrumentor().instrument(set_logging_format=True)
109109

110110
logger_provider = LoggerProvider(resource=resource)
111111
_logs.set_logger_provider(logger_provider)

0 commit comments

Comments
 (0)