Skip to content

Commit f20ff6d

Browse files
authored
Merge pull request #674 from lidofinance/develop
Master merge
2 parents efc74f4 + 71e34d5 commit f20ff6d

File tree

7 files changed

+396
-29
lines changed

7 files changed

+396
-29
lines changed

.dockerignore

Lines changed: 155 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,169 @@
1-
__pycache__
2-
*.pyc
3-
*.pyo
4-
*.pyd
1+
### Python template
2+
# Byte-compiled / optimized / DLL files
3+
__pycache__/
4+
*.py[cod]
5+
*$py.class
6+
7+
# C extensions
8+
*.so
9+
10+
# Distribution / packaging
511
.Python
6-
env
12+
build/
13+
develop-eggs/
14+
dist/
15+
downloads/
16+
eggs/
17+
.eggs/
18+
lib/
19+
lib64/
20+
parts/
21+
sdist/
22+
var/
23+
wheels/
24+
share/python-wheels/
25+
*.egg-info/
26+
.installed.cfg
27+
*.egg
28+
MANIFEST
29+
30+
# PyInstaller
31+
# Usually these files are written by a python script from a template
32+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
33+
*.manifest
34+
*.spec
35+
36+
# Installer logs
737
pip-log.txt
838
pip-delete-this-directory.txt
9-
.tox
39+
40+
# Unit test / coverage reports
41+
htmlcov/
42+
.tox/
43+
.nox/
1044
.coverage
1145
.coverage.*
1246
.cache
1347
nosetests.xml
1448
coverage.xml
1549
*.cover
50+
*.py,cover
51+
.hypothesis/
52+
.pytest_cache/
53+
cover/
54+
55+
# Translations
56+
*.mo
57+
*.pot
58+
59+
# Django stuff:
1660
*.log
61+
local_settings.py
62+
db.sqlite3
63+
db.sqlite3-journal
64+
65+
# Flask stuff:
66+
instance/
67+
.webassets-cache
68+
69+
# Scrapy stuff:
70+
.scrapy
71+
72+
# Sphinx documentation
73+
docs/_build/
74+
75+
# PyBuilder
76+
.pybuilder/
77+
target/
78+
79+
# Jupyter Notebook
80+
.ipynb_checkpoints
81+
82+
# IPython
83+
profile_default/
84+
ipython_config.py
85+
86+
# pyenv
87+
# For a library or package, you might want to ignore these files since the code is
88+
# intended to run in multiple environments; otherwise, check them in:
89+
# .python-version
90+
91+
# pipenv
92+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
94+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
95+
# install all needed dependencies.
96+
#Pipfile.lock
97+
98+
# poetry
99+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
100+
# This is especially recommended for binary packages to ensure reproducibility, and is more
101+
# commonly ignored for libraries.
102+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
103+
#poetry.lock
104+
105+
# pdm
106+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
107+
#pdm.lock
108+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
109+
# in version control.
110+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
111+
.pdm.toml
112+
.pdm-python
113+
.pdm-build/
114+
115+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
116+
__pypackages__/
117+
118+
# Celery stuff
119+
celerybeat-schedule
120+
celerybeat.pid
121+
122+
# SageMath parsed files
123+
*.sage.py
124+
125+
# Environments
126+
env
127+
.venv
128+
venv/
129+
env.bak/
130+
venv.bak/
131+
132+
# Spyder project settings
133+
.spyderproject
134+
.spyproject
135+
136+
# Rope project settings
137+
.ropeproject
138+
139+
# mkdocs documentation
140+
/site
141+
142+
# mypy
143+
.mypy_cache/
144+
.dmypy.json
145+
dmypy.json
146+
147+
# Pyre type checker
148+
.pyre/
149+
150+
# pytype static type analyzer
151+
.pytype/
152+
153+
# Cython debug symbols
154+
cython_debug/
155+
156+
# PyCharm
157+
.idea/
158+
159+
# Project-specific
160+
*.pyo
161+
*.pyd
162+
.tox
17163
.git
18-
.mypy_cache
19-
.pytest_cache
20164
.hypothesis
21165
tests/*
22166
fixtures/*
167+
Makefile
168+
*.md
169+
docs
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
---
2+
name: Test Docker image reproducibility
3+
4+
"on":
5+
pull_request:
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
packages: write
11+
12+
jobs:
13+
build1:
14+
runs-on: ubuntu-latest
15+
outputs:
16+
sha256: ${{ steps.hash.outputs.sha256 }}
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v3
20+
with:
21+
persist-credentials: false
22+
23+
- name: Set up Docker Buildx
24+
uses: docker/setup-buildx-action@v3
25+
26+
- name: Login to GHCR
27+
uses: docker/login-action@v3
28+
with:
29+
registry: ghcr.io
30+
username: ${{ github.actor }}
31+
password: ${{ secrets.GITHUB_TOKEN }}
32+
33+
- name: Build image
34+
id: build
35+
uses: docker/build-push-action@v6.15.0
36+
with:
37+
push: false
38+
load: true
39+
outputs: type=docker,dest=image.tar,rewrite-timestamp=true
40+
provenance: false
41+
env:
42+
SOURCE_DATE_EPOCH: 0
43+
44+
- name: Compute SHA256
45+
id: hash
46+
run: echo "sha256=$(sha256sum image.tar | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
47+
48+
- name: Report image hash
49+
run: |
50+
echo "Hash from the second image build: ${{ steps.hash.outputs.sha256 }}"
51+
52+
build2:
53+
runs-on: ubuntu-latest
54+
outputs:
55+
sha256: ${{ steps.hash.outputs.sha256 }}
56+
steps:
57+
- name: Checkout
58+
uses: actions/checkout@v3
59+
with:
60+
persist-credentials: false
61+
62+
- name: Set up Docker Buildx
63+
uses: docker/setup-buildx-action@v3
64+
65+
- name: Login to GHCR
66+
uses: docker/login-action@v3
67+
with:
68+
registry: ghcr.io
69+
username: ${{ github.actor }}
70+
password: ${{ secrets.GITHUB_TOKEN }}
71+
72+
- name: Build image
73+
id: build
74+
uses: docker/build-push-action@v6
75+
with:
76+
push: false
77+
load: true
78+
outputs: type=docker,dest=image.tar,rewrite-timestamp=true
79+
provenance: false
80+
env:
81+
SOURCE_DATE_EPOCH: 0
82+
83+
- name: Compute SHA256
84+
id: hash
85+
run: echo "sha256=$(sha256sum image.tar | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
86+
87+
- name: Report image hash
88+
run: |
89+
echo "Hash from the second image build: ${{ steps.hash.outputs.sha256 }}"
90+
91+
reproducibility:
92+
runs-on: ubuntu-latest
93+
needs:
94+
- build1
95+
- build2
96+
steps:
97+
- name: Fail if empty
98+
if: ${{ needs.build1.outputs.sha256 == '' }}
99+
run: |
100+
echo needs.build1.outputs.sha256 is ${{ needs.build1.outputs.sha256 }}
101+
exit 1
102+
- name: Report image Hash
103+
run: |
104+
echo "Hash from the first image build: ${{ needs.build1.outputs.sha256 }}"
105+
echo "Hash from the second image build: ${{ needs.build2.outputs.sha256 }}"
106+
107+
- name: Check if match
108+
if: ${{ needs.build1.outputs.sha256 != needs.build2.outputs.sha256 }}
109+
run: |
110+
echo ${{ needs.build1.outputs.sha256 }} != ${{ needs.build2.outputs.sha256 }}
111+
exit 1

Dockerfile

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
FROM python:3.12.4-slim as base
1+
FROM python:3.12.4-slim AS base
2+
3+
ARG SOURCE_DATE_EPOCH
24

35
RUN apt-get update && apt-get install -y --no-install-recommends -qq \
46
libffi-dev=3.4.4-1 \
57
g++=4:12.2.0-3 \
68
curl=7.88.1-10+deb12u12 \
79
&& apt-get clean \
8-
&& rm -rf /var/lib/apt/lists/*
10+
&& rm -rf /var/lib/apt/lists/* \
11+
&& rm -rf /var/cache/* \
12+
&& rm -rf /var/log/*
913

1014
ENV PYTHONUNBUFFERED=1 \
1115
PYTHONDONTWRITEBYTECODE=1 \
@@ -14,30 +18,38 @@ ENV PYTHONUNBUFFERED=1 \
1418
PIP_DEFAULT_TIMEOUT=100 \
1519
POETRY_VIRTUALENVS_IN_PROJECT=true \
1620
POETRY_NO_INTERACTION=1 \
17-
VENV_PATH="/.venv"
21+
VENV_PATH="/.venv" \
22+
CFLAGS="-g0 -O2 -ffile-prefix-map=/src=."
1823

1924
ENV PATH="$VENV_PATH/bin:$PATH"
2025

21-
FROM base as builder
26+
FROM base AS builder
2227

2328
ENV POETRY_VERSION=1.3.2
2429
RUN pip install --no-cache-dir poetry==$POETRY_VERSION
2530

2631
WORKDIR /
2732
COPY pyproject.toml poetry.lock ./
28-
RUN poetry install --only main --no-root
33+
34+
# Building lru-dict from source for reproducible .so files by enforcing consistent CFLAGS across builds
35+
RUN poetry config --local installer.no-binary lru-dict && \
36+
poetry install --only main --no-root --no-cache && \
37+
find "$VENV_PATH" -type d -name '.git' -exec rm -rf {} + && \
38+
find "$VENV_PATH" -name '*.dist-info' -exec rm -rf {}/RECORD \; && \
39+
find "$VENV_PATH" -name '*.dist-info' -exec rm -rf {}/WHEEL \; && \
40+
find "$VENV_PATH" -name '__pycache__' -exec rm -rf {} +
2941

3042

31-
FROM base as production
43+
FROM base AS production
3244

3345
COPY --from=builder $VENV_PATH $VENV_PATH
3446
WORKDIR /app
3547
COPY . .
3648

3749
RUN apt-get clean && find /var/lib/apt/lists/ -type f -delete && chown -R www-data /app/
3850

39-
ENV PROMETHEUS_PORT 9000
40-
ENV HEALTHCHECK_SERVER_PORT 9010
51+
ENV PROMETHEUS_PORT=9000
52+
ENV HEALTHCHECK_SERVER_PORT=9010
4153

4254
EXPOSE $PROMETHEUS_PORT
4355
USER www-data

Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
reproducible-build-oracle:
2+
docker buildx rm oracle-buildkit || true
3+
docker volume rm $(shell docker volume ls -q --filter name=buildx_buildkit_oracle-buildkit) || true
4+
docker buildx create --name oracle-buildkit --use || true
5+
docker buildx use oracle-buildkit
6+
docker buildx build \
7+
--platform linux/amd64 \
8+
--build-arg SOURCE_DATE_EPOCH=0 \
9+
--no-cache \
10+
--output type=docker,name=oracle-reproducible-container:local,rewrite-timestamp=true \
11+
-t oracle-reproducible-container:local \
12+
.
13+
docker image inspect oracle-reproducible-container:local --format 'Image hash: {{.Id}}'

0 commit comments

Comments
 (0)