-
-
Notifications
You must be signed in to change notification settings - Fork 61
Expand file tree
/
Copy pathDockerfile
More file actions
233 lines (195 loc) · 7.73 KB
/
Dockerfile
File metadata and controls
233 lines (195 loc) · 7.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
ARG PYTHON_VERSION=3.13.12
FROM python:${PYTHON_VERSION}-slim-trixie AS build_base
WORKDIR /usr/src/snuba
ENV PATH="/.venv/bin:$PATH" UV_PROJECT_ENVIRONMENT=/.venv \
PIP_NO_CACHE_DIR=1 PIP_DISABLE_PIP_VERSION_CHECK=1 \
UV_COMPILE_BYTECODE=1 UV_NO_CACHE=1
RUN python3 -m pip install \
--index-url 'https://pypi.devinfra.sentry.io/simple' 'uv'
# We don't want uv-managed python, we want to use python from the image.
# We only want to use uv to manage dependencies.
RUN python3 -m venv "$UV_PROJECT_ENVIRONMENT"
RUN set -ex; \
\
buildDeps=' \
git \
gcc \
libc6-dev \
liblz4-dev \
libpcre2-dev \
libssl-dev \
wget \
zlib1g-dev \
pkg-config \
cmake \
make \
g++ \
gnupg \
protobuf-compiler \
'; \
runtimeDeps=' \
curl \
libjemalloc2 \
gdb \
heaptrack \
'; \
apt-get update; \
apt-get install -y $buildDeps $runtimeDeps --no-install-recommends; \
ln -s /usr/lib/*/libjemalloc.so.2 /usr/src/snuba/libjemalloc.so.2; \
echo "$buildDeps" > /tmp/build-deps.txt
FROM build_base AS base
COPY pyproject.toml uv.lock ./
RUN set -ex; \
\
uv sync --no-dev --frozen --no-install-project --no-install-workspace
# We assume that compared to snuba codebase, the Rust consumer is the least likely to get
# changed. We do need requirements.txt installed though, so we cannot use the
# official Rust docker images and rather have to install Rust into the existing
# Python image.
# We could choose to install maturin into the Rust docker image instead of the
# entirety of requirements.txt, but we are not yet confident that the Python
# library we build is portable across Python versions.
# There are optimizations we can make in the future to split building of Rust
# dependencies from building the Rust source code, see Relay Dockerfile.
FROM build_base AS build_rust_snuba_base
RUN set -ex; \
# do not install any toolchain, as rust_snuba/rust-toolchain.toml defines that for us
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y; \
# use git CLI to avoid OOM on ARM64
echo '[net]' > ~/.cargo/config; \
echo 'git-fetch-with-cli = true' >> ~/.cargo/config; \
echo '[registries.crates-io]' >> ~/.cargo/config; \
echo 'protocol = "sparse"' >> ~/.cargo/config
ENV PATH="/root/.cargo/bin/:${PATH}"
FROM build_rust_snuba_base AS build_rust_snuba_deps
COPY ./rust_snuba/Cargo.toml ./rust_snuba/Cargo.toml
COPY ./rust_snuba/rust-toolchain.toml ./rust_snuba/rust-toolchain.toml
COPY ./rust_snuba/Cargo.lock ./rust_snuba/Cargo.lock
COPY ./scripts/rust-dummy-build.sh ./scripts/rust-dummy-build.sh
RUN set -ex; \
sh scripts/rust-dummy-build.sh; \
cd ./rust_snuba/; \
rustup show active-toolchain || rustup toolchain install
FROM build_rust_snuba_deps AS build_rust_snuba
COPY ./rust_snuba/ ./rust_snuba/
COPY ./sentry-options/schemas/ ./sentry-options/schemas/
COPY --from=build_rust_snuba_deps /usr/src/snuba/rust_snuba/target/ ./rust_snuba/target/
COPY --from=build_rust_snuba_deps /root/.cargo/ /root/.cargo/
RUN set -ex; \
cd ./rust_snuba/; \
uvx maturin build --release --compatibility linux --locked; \
rm -rf /root/.rustup/toolchains/*/share/doc
# Install nodejs and yarn and build the admin UI
FROM build_base AS build_admin_ui
ENV VOLTA_HOME=/root/.volta
ENV PATH=$VOLTA_HOME/bin:$PATH
COPY ./snuba/admin ./snuba/admin
RUN set -ex; \
mkdir -p snuba/admin/dist/; \
curl -fsSL https://get.volta.sh | bash && \
cd snuba/admin && \
volta install node yarn && \
yarn install && \
yarn run build
# Layer cache is pretty much invalidated here all the time,
# so try not to do anything heavy beyond here.
FROM base AS application_base
COPY . ./
COPY --from=build_rust_snuba /usr/src/snuba/rust_snuba/target/wheels/ /tmp/rust_wheels/
COPY --from=build_admin_ui /usr/src/snuba/snuba/admin/dist/ ./snuba/admin/dist/
RUN set -ex; \
groupadd -r snuba --gid 1000; \
useradd -r -g snuba --uid 1000 snuba; \
chown -R snuba:snuba ./; \
uv sync --no-dev --frozen --no-install-package rust_snuba; \
# Ensure that we are always importing the installed rust_snuba wheel, and not the
# (basically empty) rust_snuba folder
rm -rf ./rust_snuba/; \
[ -z "`find /tmp/rust_wheels -type f`" ] || uv pip install /tmp/rust_wheels/*; \
rm -rf /tmp/rust_wheels/; \
snuba --help
ARG SOURCE_COMMIT
ENV LD_PRELOAD=/usr/src/snuba/libjemalloc.so.2 \
SNUBA_RELEASE=$SOURCE_COMMIT \
FLASK_DEBUG=0 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# set default path for sentry options values
ENV SENTRY_OPTIONS_DIR=/etc/sentry-options
USER snuba
EXPOSE 1218 1219
ENTRYPOINT [ "./docker_entrypoint.sh" ]
CMD [ "api" ]
FROM application_base AS application
USER 0
RUN set -ex; \
apt-get purge -y --auto-remove $(cat /tmp/build-deps.txt); \
rm /tmp/build-deps.txt; \
rm -rf /var/lib/apt/lists/*;
USER snuba
# --- Distroless stages (additive, no changes to existing stages above) ---
# Prepare artifacts for distroless: fix venv symlinks and verify shared libs.
# The build image has Python at /usr/local/bin/python3, but the DHI
# runtime has it at /opt/python/bin/python3.
FROM application_base AS distroless_prep
USER 0
RUN ln -sf /opt/python/bin/python3 /.venv/bin/python3 && \
ln -sf /opt/python/bin/python3 /.venv/bin/python
RUN find /.venv -name "*.so" -exec ldd {} \; 2>&1 | grep "not found" && exit 1 || true
# Distroless production image — minimal attack surface, no shell
FROM ghcr.io/getsentry/dhi/python:3.13-debian13 AS application-distroless
COPY --from=distroless_prep /.venv /.venv
COPY --from=distroless_prep /usr/src/snuba /usr/src/snuba
COPY --from=distroless_prep /usr/lib/*/libjemalloc.so.2 /usr/lib/libjemalloc.so.2
COPY --from=distroless_prep /etc/passwd /etc/passwd
COPY --from=distroless_prep /etc/group /etc/group
WORKDIR /usr/src/snuba
ARG SOURCE_COMMIT
ENV PATH="/.venv/bin:/opt/python/bin:$PATH" \
LD_PRELOAD=/usr/lib/libjemalloc.so.2 \
SNUBA_RELEASE=$SOURCE_COMMIT \
FLASK_DEBUG=0 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
SENTRY_OPTIONS_DIR=/etc/sentry-options
USER 1000
EXPOSE 1218 1219
ENTRYPOINT ["python3", "/usr/src/snuba/docker_entrypoint.py"]
CMD ["api"]
# Debug distroless image — includes busybox (sh, ls, cat, wget, env, etc.)
FROM ghcr.io/getsentry/dhi/python:3.13-debian13-dev AS application-distroless-debug
COPY --from=distroless_prep /.venv /.venv
COPY --from=distroless_prep /usr/src/snuba /usr/src/snuba
COPY --from=distroless_prep /usr/lib/*/libjemalloc.so.2 /usr/lib/libjemalloc.so.2
COPY --from=distroless_prep /etc/passwd /etc/passwd
COPY --from=distroless_prep /etc/group /etc/group
WORKDIR /usr/src/snuba
ARG SOURCE_COMMIT
ENV PATH="/.venv/bin:/opt/python/bin:$PATH" \
LD_PRELOAD=/usr/lib/libjemalloc.so.2 \
SNUBA_RELEASE=$SOURCE_COMMIT \
FLASK_DEBUG=0 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
SENTRY_OPTIONS_DIR=/etc/sentry-options
USER 1000
EXPOSE 1218 1219
ENTRYPOINT ["python3", "/usr/src/snuba/docker_entrypoint.py"]
CMD ["api"]
# --- End distroless stages ---
FROM application_base AS testing
USER 0
COPY ./rust_snuba/ ./rust_snuba/
# re-"install" rust for the testing image
COPY --from=build_rust_snuba /root/.cargo/ /root/.cargo/
COPY --from=build_rust_snuba /root/.rustup/ /root/.rustup/
COPY --from=build_rust_snuba /usr/src/snuba/rust_snuba/target/wheels/ /tmp/rust_wheels/
RUN set -ex; \
# we need to resync, this time with dev dependencies
uv sync --frozen --no-install-package rust_snuba; \
# this will uninstall the rust wheel so we need to reinstall again
uv pip install /tmp/rust_wheels/*; \
rm -rf /tmp/rust_wheels/; \
snuba --help
ENV PATH="${PATH}:/root/.cargo/bin/"
USER snuba