-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile.cross
More file actions
199 lines (165 loc) · 7.87 KB
/
Dockerfile.cross
File metadata and controls
199 lines (165 loc) · 7.87 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
# Multi-stage Dockerfile for Codex with cross-compilation
#
# This Dockerfile builds ARM64 and AMD64 images efficiently by:
# 1. Always running the Rust compiler on x86_64 (native speed)
# 2. Cross-compiling to the target architecture
# 3. Only the final runtime stage uses the target architecture
#
# This avoids QEMU emulation for Rust compilation, which is ~10-50x slower.
#
# Usage:
# docker buildx build --platform linux/amd64,linux/arm64 -f Dockerfile.cross .
# =============================================================================
# Stage 1: Build frontend (pinned to x86_64 for speed)
# =============================================================================
FROM --platform=linux/amd64 node:22-alpine AS frontend-builder
WORKDIR /web
# Copy package files
COPY web/package.json ./
# Install dependencies
RUN npm install
# Copy frontend source
COPY web/ ./
# Build frontend
RUN npm run build
# =============================================================================
# Stage 2: Rust build with cross-compilation support (always x86_64)
# =============================================================================
FROM --platform=linux/amd64 rust:1.93-bookworm AS chef
# Install base build tools
# clang is needed for proc-macro build scripts (proc-macro2, quote, etc.)
RUN apt-get update && \
apt-get install -y \
build-essential \
pkg-config \
curl \
xz-utils \
clang \
&& rm -rf /var/lib/apt/lists/*
# Install musl cross-compilers from musl.cc (provides both gcc and g++)
# x86_64-linux-musl-cross for amd64 target
# aarch64-linux-musl-cross for arm64 target
RUN curl -sSL https://musl.cc/x86_64-linux-musl-cross.tgz | tar -xz -C /opt && \
curl -sSL https://musl.cc/aarch64-linux-musl-cross.tgz | tar -xz -C /opt
ENV PATH="/opt/x86_64-linux-musl-cross/bin:/opt/aarch64-linux-musl-cross/bin:$PATH"
# Add Rust targets for cross-compilation
RUN rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
# Configure Cargo for cross-compilation
RUN mkdir -p /root/.cargo && \
echo '[target.aarch64-unknown-linux-musl]' >> /root/.cargo/config.toml && \
echo 'linker = "aarch64-linux-musl-gcc"' >> /root/.cargo/config.toml && \
echo '' >> /root/.cargo/config.toml && \
echo '[target.x86_64-unknown-linux-musl]' >> /root/.cargo/config.toml && \
echo 'linker = "x86_64-linux-musl-gcc"' >> /root/.cargo/config.toml
RUN cargo install cargo-chef
WORKDIR /app
# =============================================================================
# Stage 3: Prepare recipe
# =============================================================================
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
# =============================================================================
# Stage 4: Build dependencies (cached layer)
# =============================================================================
FROM chef AS builder
ARG TARGETARCH
# Disable static linking to enable dlopen() for PDFium dynamic loading
# This is required because musl's static linking doesn't support dlopen()
ENV RUSTFLAGS="-C target-feature=-crt-static"
COPY --from=planner /app/recipe.json recipe.json
# Build dependencies (this layer is cached)
# Set CC/CXX for build scripts and AR for static libraries
RUN if [ "$TARGETARCH" = "arm64" ]; then \
export CC=aarch64-linux-musl-gcc && \
export CXX=aarch64-linux-musl-g++ && \
export AR=aarch64-linux-musl-ar && \
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-musl-gcc && \
cargo chef cook --release --target aarch64-unknown-linux-musl --features embed-frontend --recipe-path recipe.json; \
else \
export CC=x86_64-linux-musl-gcc && \
export CXX=x86_64-linux-musl-g++ && \
export AR=x86_64-linux-musl-ar && \
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=x86_64-linux-musl-gcc && \
cargo chef cook --release --target x86_64-unknown-linux-musl --features embed-frontend --recipe-path recipe.json; \
fi
# =============================================================================
# Stage 5: Build application
# =============================================================================
COPY . .
# Copy frontend dist from frontend-builder
COPY --from=frontend-builder /web/dist ./web/dist
# Build with embedded frontend
# Set CC/CXX for build scripts and AR for static libraries
RUN if [ "$TARGETARCH" = "arm64" ]; then \
export CC=aarch64-linux-musl-gcc && \
export CXX=aarch64-linux-musl-g++ && \
export AR=aarch64-linux-musl-ar && \
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-musl-gcc && \
cargo build --release --target aarch64-unknown-linux-musl --features embed-frontend && \
cp target/aarch64-unknown-linux-musl/release/codex /app/codex; \
else \
export CC=x86_64-linux-musl-gcc && \
export CXX=x86_64-linux-musl-g++ && \
export AR=x86_64-linux-musl-ar && \
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=x86_64-linux-musl-gcc && \
cargo build --release --target x86_64-unknown-linux-musl --features embed-frontend && \
cp target/x86_64-unknown-linux-musl/release/codex /app/codex; \
fi
# =============================================================================
# Stage 6: Runtime (uses target architecture)
# =============================================================================
FROM alpine:latest AS runtime
# Install runtime dependencies:
# - ca-certificates for HTTPS
# - su-exec for user switching
# - libstdc++ and libgcc for PDFium
# - nodejs and npm for TypeScript/JavaScript plugins
RUN apk add --no-cache ca-certificates su-exec libstdc++ libgcc curl wget nodejs npm
# Install uv (fast Python package manager) for Python plugins
# uv provides 'uvx' command for running Python packages without installation
RUN wget -qO- https://astral.sh/uv/install.sh | sh && \
mv /root/.local/bin/uv /usr/local/bin/uv && \
mv /root/.local/bin/uvx /usr/local/bin/uvx
# Install PDFium library for PDF page rendering
# This enables rendering of text-only and vector PDF pages
# Using musl build for Alpine Linux compatibility
# Note: Downloads architecture-specific binary based on TARGETARCH
ARG TARGETARCH
ARG PDFIUM_VERSION=latest
RUN if [ "$TARGETARCH" = "arm64" ]; then \
wget -q -O- https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_VERSION}/download/pdfium-linux-musl-arm64.tgz \
| tar -xz -C /usr/local; \
else \
wget -q -O- https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_VERSION}/download/pdfium-linux-musl-x64.tgz \
| tar -xz -C /usr/local; \
fi
# Ensure PDFium library can be found at runtime
# Create symlink in /usr/lib for standard library search path
RUN ln -sf /usr/local/lib/libpdfium.so /usr/lib/libpdfium.so
ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/lib
# Create app user with default UID/GID (can be changed at runtime via PUID/PGID)
RUN addgroup -g 1000 codex && \
adduser -D -u 1000 -G codex codex
WORKDIR /app
# Copy binary from builder
COPY --from=builder /app/codex /usr/local/bin/codex
# Copy entrypoint script
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Create directories
# - /app/data, /app/config: Application data and config
# - /app/.npm: npm cache for npx plugins (avoids permission issues with /.npm)
# Set permissions to allow any UID to write (for custom user: directive in docker-compose)
RUN mkdir -p /app/data /app/config /app/.npm && \
chown -R codex:codex /app && \
chmod 777 /app/data /app/config /app/.npm
# Set npm cache location to avoid permission issues when running as non-root
# This is needed for npx-based plugins to download packages
ENV npm_config_cache=/app/.npm
# Environment variables for user mapping (defaults)
ENV PUID=1000
ENV PGID=1000
EXPOSE 8080
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["codex", "serve"]