-
Notifications
You must be signed in to change notification settings - Fork 115
refactor(docker): improve Dockerfile security, caching and build stru… #7325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,79 +1,104 @@ | ||||||||||
| # syntax=docker/dockerfile:1.7 | ||||||||||
|
|
||||||||||
| ARG REGISTRY=docker.io | ||||||||||
| ARG NODE_VERSION=24 | ||||||||||
| ARG PYTHON_VERSION=3.12 | ||||||||||
| ARG APP_USER=app | ||||||||||
| ARG APP_UID=10001 | ||||||||||
|
|
||||||||||
| ############################ | ||||||||||
| # Base image | ||||||||||
| ############################ | ||||||||||
| FROM ${REGISTRY}/node:${NODE_VERSION}-bookworm-slim AS base | ||||||||||
|
|
||||||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ||||||||||
| PYTHONUNBUFFERED=1 \ | ||||||||||
| NODE_ENV=production | ||||||||||
|
|
||||||||||
| FROM ${REGISTRY}/python:3.14-slim-bookworm AS python | ||||||||||
| FROM ${REGISTRY}/node:24-bookworm-slim AS node | ||||||||||
| RUN apt-get update \ | ||||||||||
| && apt-get install -y --no-install-recommends \ | ||||||||||
| python3 \ | ||||||||||
| python3-pip \ | ||||||||||
| python3-venv \ | ||||||||||
| ca-certificates \ | ||||||||||
| curl \ | ||||||||||
| git \ | ||||||||||
| && rm -rf /var/lib/apt/lists/* | ||||||||||
|
|
||||||||||
| FROM ${REGISTRY}/buildpack-deps:bookworm AS base | ||||||||||
| ############################ | ||||||||||
| # Python deps | ||||||||||
| ############################ | ||||||||||
| FROM base AS python-deps | ||||||||||
|
|
||||||||||
| COPY --from=python /usr/local/ /usr/local/ | ||||||||||
| COPY --from=node /usr/local/ /usr/local/ | ||||||||||
| COPY --from=node /opt/ /opt/ | ||||||||||
| WORKDIR /tmp | ||||||||||
|
|
||||||||||
| # Add app user/group! Clean packages and fix links! Check version! And install some extra packages! | ||||||||||
| RUN set -ex \ | ||||||||||
| && groupadd -r app --gid=999 \ | ||||||||||
| && useradd --system --create-home --home /app --gid 999 --uid=999 --shell /bin/bash app \ | ||||||||||
| && rm -f /usr/local/bin/docker-entrypoint.sh \ | ||||||||||
| && python --version \ | ||||||||||
| && pip --version \ | ||||||||||
| && node --version \ | ||||||||||
| && yarn --version \ | ||||||||||
| && python3 -m pip install 'psycopg2-binary==2.9.10' && python3 -m pip install 'Django==5.2' \ | ||||||||||
| && echo "OK" | ||||||||||
| COPY requirements.txt . | ||||||||||
|
|
||||||||||
| # Installer | ||||||||||
| FROM base AS installer | ||||||||||
| RUN --mount=type=cache,target=/root/.cache/pip \ | ||||||||||
| pip install --no-cache-dir -r requirements.txt | ||||||||||
|
Comment on lines
+37
to
+38
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Contradictory caching flags: The cache mount at Proposed fix RUN --mount=type=cache,target=/root/.cache/pip \
- pip install --no-cache-dir -r requirements.txt
+ pip install -r requirements.txt📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| ############################ | ||||||||||
| # Node deps | ||||||||||
| ############################ | ||||||||||
| FROM base AS node-deps | ||||||||||
|
|
||||||||||
| WORKDIR /app | ||||||||||
| # Copy pruned monorepo (only package.json + yarn.lock) | ||||||||||
| COPY --chown=app:app ./out /app | ||||||||||
| # Copy yarn berry | ||||||||||
| COPY --chown=app:app ./.yarn /app/.yarn | ||||||||||
| COPY --chown=app:app ./.yarnrc.yml /app/.yarnrc.yml | ||||||||||
|
|
||||||||||
| COPY package.json yarn.lock .yarnrc.yml ./ | ||||||||||
| COPY .yarn .yarn | ||||||||||
|
|
||||||||||
| RUN --mount=type=cache,target=/usr/local/share/.cache/yarn \ | ||||||||||
| yarn install --immutable --inline-builds | ||||||||||
| yarn install --immutable | ||||||||||
|
|
||||||||||
| ############################ | ||||||||||
| # Builder | ||||||||||
| FROM base as builder | ||||||||||
|
|
||||||||||
| ARG TURBO_TEAM | ||||||||||
| ARG TURBO_TOKEN | ||||||||||
| ARG TURBO_API | ||||||||||
| ARG TURBO_REMOTE_ONLY=false | ||||||||||
| ############################ | ||||||||||
| FROM base AS builder | ||||||||||
|
|
||||||||||
| WORKDIR /app | ||||||||||
| # Copy entire repo | ||||||||||
| COPY --chown=app:app . /app | ||||||||||
| # Copy previously installed packages | ||||||||||
| COPY --from=installer --chown=app:app /app /app | ||||||||||
|
|
||||||||||
| ENV TURBO_TEAM=$TURBO_TEAM | ||||||||||
| ENV TURBO_TOKEN=$TURBO_TOKEN | ||||||||||
| ENV TURBO_API=$TURBO_API | ||||||||||
| ENV TURBO_REMOTE_ONLY=$TURBO_REMOTE_ONLY | ||||||||||
|
|
||||||||||
| RUN echo "# Build time .env config!" >> /app/.env && \ | ||||||||||
| echo "COOKIE_SECRET=undefined" >> /app/.env && \ | ||||||||||
| echo "DATABASE_URL=undefined" >> /app/.env && \ | ||||||||||
| echo "REDIS_URL=undefined" >> /app/.env && \ | ||||||||||
| echo "FILE_FIELD_ADAPTER=local" >> /app/.env && \ | ||||||||||
| echo "NEXT_TELEMETRY_DISABLED=1" >> /app/.env && \ | ||||||||||
| echo "NODE_ENV=production" >> /app/.env | ||||||||||
|
|
||||||||||
| RUN chmod +x ./bin/run_condo_domain_tests.sh | ||||||||||
|
|
||||||||||
| COPY --from=node-deps /app /app | ||||||||||
|
|
||||||||||
| COPY . . | ||||||||||
|
|
||||||||||
| RUN --mount=type=cache,target=/usr/local/share/.cache/yarn \ | ||||||||||
| --mount=type=cache,target=/app/.turbo \ | ||||||||||
| set -ex \ | ||||||||||
| && yarn build \ | ||||||||||
| && rm -rf /app/out \ | ||||||||||
| && rm -rf /app/.env \ | ||||||||||
| && rm -rf /app/.config /app/.cache /app/.docker \ | ||||||||||
| && ls -lah /app/ | ||||||||||
|
|
||||||||||
| # Runtime container | ||||||||||
| FROM base | ||||||||||
| USER app:app | ||||||||||
| yarn build | ||||||||||
|
|
||||||||||
| ############################ | ||||||||||
| # Runtime (minimal) | ||||||||||
| ############################ | ||||||||||
| FROM ${REGISTRY}/node:${NODE_VERSION}-bookworm-slim AS runtime | ||||||||||
|
|
||||||||||
| ARG APP_USER | ||||||||||
| ARG APP_UID | ||||||||||
|
|
||||||||||
| ENV NODE_ENV=production \ | ||||||||||
| PYTHONUNBUFFERED=1 | ||||||||||
|
|
||||||||||
| RUN useradd --system \ | ||||||||||
| --uid ${APP_UID} \ | ||||||||||
| --create-home \ | ||||||||||
| --home-dir /app \ | ||||||||||
| ${APP_USER} | ||||||||||
|
|
||||||||||
| WORKDIR /app | ||||||||||
| COPY --from=builder --chown=app:app /app /app | ||||||||||
|
|
||||||||||
| COPY --from=builder /app /app | ||||||||||
| COPY --from=python-deps /usr/local/lib/python3* /usr/local/lib/ | ||||||||||
|
|
||||||||||
|
Comment on lines
+70
to
+88
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's see the full Dockerfile structure
cd . && find . -name "Dockerfile" -type fRepository: open-condo-software/condo Length of output: 81 🏁 Script executed: # Look for werf.yaml to understand the application structure
find . -name "werf.yaml" -o -name "werf.yml" | head -5Repository: open-condo-software/condo Length of output: 80 🏁 Script executed: # Check the full Dockerfile context around the runtime stage
cat -n Dockerfile | head -100Repository: open-condo-software/condo Length of output: 2733 🏁 Script executed: # Check werf.yaml to understand what the application does
head -100 werf.yamlRepository: open-condo-software/condo Length of output: 2273 🏁 Script executed: # Check requirements.txt to see what Python packages are installed
cat requirements.txtRepository: open-condo-software/condo Length of output: 117 🏁 Script executed: # Search for any Python process spawning or execution in the application code
rg -i 'spawn|exec|child_process.*py|python' --type=js --type=ts -g '!node_modules' -C2 | head -80Repository: open-condo-software/condo Length of output: 6516 🏁 Script executed: # Search for requirements.txt throughout the entire repository
find . -name "requirements.txt" -type fRepository: open-condo-software/condo Length of output: 51 🏁 Script executed: # Check for any build scripts or CI/CD configuration that references the Dockerfile
find . -name "*.yml" -o -name "*.yaml" -o -name "*.sh" | grep -E '(workflow|action|compose|script)' | head -20Repository: open-condo-software/condo Length of output: 904 🏁 Script executed: # Check if there are any references to the Dockerfile in the repository
rg -l "Dockerfile" --type=yaml --type=json --type=sh -g '!.git'Repository: open-condo-software/condo Length of output: 87 🏁 Script executed: # Check docker-compose.yml to see if it references the Dockerfile
cat docker-compose.yml | head -50Repository: open-condo-software/condo Length of output: 1201 🏁 Script executed: # Check deployment workflows to see which build system is used (werf vs Dockerfile)
rg -l "werf|Dockerfile" .github/workflows/ | head -5Repository: open-condo-software/condo Length of output: 254 🏁 Script executed: # Look at one of the production deployment workflows to understand the build process
head -80 .github/workflows/deploy_production.yamlRepository: open-condo-software/condo Length of output: 3986 🏁 Script executed: # Check git history to see if requirements.txt was recently removed or if it never existed
git log --all --full-history --oneline -- requirements.txt | head -20Repository: open-condo-software/condo Length of output: 51 🏁 Script executed: # Check if requirements.txt might be generated or created during build
rg "requirements\.txt" Dockerfile werf.yamlRepository: open-condo-software/condo Length of output: 213 🏁 Script executed: # Look for any Python dependencies or imports that might suggest the app needs Python
find apps packages -name "*.py" -type f 2>/dev/null | wc -lRepository: open-condo-software/condo Length of output: 70 Dockerfile cannot build: missing The Dockerfile references Additionally, the application contains zero Python files and is purely Node.js-based. The Python installation (lines 31-38, 87) is unnecessary dead code. Either:
🤖 Prompt for AI Agents |
||||||||||
| RUN chown -R ${APP_USER}:${APP_USER} /app | ||||||||||
|
|
||||||||||
| USER ${APP_USER} | ||||||||||
|
|
||||||||||
| ############################ | ||||||||||
| # Healthcheck | ||||||||||
| ############################ | ||||||||||
| HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ | ||||||||||
| CMD node healthcheck.js || exit 1 | ||||||||||
|
|
||||||||||
| ############################ | ||||||||||
| # Start | ||||||||||
| ############################ | ||||||||||
| EXPOSE 3000 | ||||||||||
|
|
||||||||||
| CMD ["node", "server.js"] | ||||||||||
|
Comment on lines
+96
to
+104
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if healthcheck.js and server.js exist in the repo
echo "=== Checking for healthcheck.js ==="
fd -t f 'healthcheck.js' | head -5
echo "=== Checking for server.js ==="
fd -t f 'server.js' | head -5
echo "=== Checking package.json for entry points ==="
fd -t f 'package.json' -d 1 -x jq -r '.scripts.start // .main // "not found"' {}Repository: open-condo-software/condo Length of output: 502 🏁 Script executed: #!/bin/bash
# Find the Dockerfile
echo "=== Finding Dockerfile ==="
fd -t f 'Dockerfile' | head -10
echo ""
echo "=== Checking app directory structure for the main app ==="
# Look for typical app directories
ls -la apps/ 2>/dev/null | head -20
echo ""
echo "=== Looking for server.js and healthcheck.js in apps ==="
fd -t f -e js 'server\.js|healthcheck\.js|healthCheck\.js' apps/ | head -20Repository: open-condo-software/condo Length of output: 1528 🏁 Script executed: #!/bin/bash
echo "=== Dockerfile content ==="
cat -n Dockerfile | head -110
echo ""
echo "=== Checking for server.js in root and common locations ==="
find . -maxdepth 3 -name "server.js" -type f 2>/dev/null | grep -v node_modules | head -20Repository: open-condo-software/condo Length of output: 2944 🏁 Script executed: #!/bin/bash
echo "=== Searching for all healthcheck variants ==="
fd -i 'healthcheck' | head -20
echo ""
echo "=== Checking if there's a healthcheck.js at root or in common build output ==="
ls -la healthcheck.js 2>/dev/null || echo "Not found at root"
echo ""
echo "=== Checking packages directory for healthcheck files ==="
find packages -name '*healthcheck*' -o -name '*healthCheck*' 2>/dev/null
echo ""
echo "=== Checking build scripts in package.json ==="
jq '.scripts | keys' package.json 2>/dev/null | head -30Repository: open-condo-software/condo Length of output: 709 🏁 Script executed: #!/bin/bash
echo "=== Contents of packages/keystone ==="
ls -la packages/keystone/ | head -30
echo ""
echo "=== Check if healthcheck.js is referenced anywhere in build/config ==="
rg 'healthcheck\.js' --type js --type json | head -20
echo ""
echo "=== Check app entry point expectations ==="
ls -la apps/condo/ | head -20Repository: open-condo-software/condo Length of output: 3280 🏁 Script executed: #!/bin/bash
echo "=== Contents of apps/condo/bin ==="
ls -la apps/condo/bin/
echo ""
echo "=== Check apps/condo/index.js first 50 lines ==="
head -50 apps/condo/index.js
echo ""
echo "=== Check if server.js or healthcheck.js are generated by looking at gitignore patterns ==="
cat .gitignore 2>/dev/null | grep -E 'server\.js|healthcheck\.js' || echo "No specific patterns found"Repository: open-condo-software/condo Length of output: 5114 Fix case sensitivity: use The Dockerfile references lowercase 🤖 Prompt for AI Agents |
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PYTHON_VERSIONARG is defined but never used.The
PYTHON_VERSIONARG at line 5 is declared but not referenced anywhere in the Dockerfile. Either wire it into the base image or package installation, or remove it to avoid confusion.Proposed fix: Remove unused ARG or use it
Option 1: Remove unused ARG
ARG REGISTRY=docker.io ARG NODE_VERSION=24 -ARG PYTHON_VERSION=3.12 ARG APP_USER=app ARG APP_UID=10001Option 2: Use it (e.g., in apt-get install)
📝 Committable suggestion
🤖 Prompt for AI Agents