Skip to content
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

ci(framework) Optimize Ubuntu base image #3458

Merged
merged 5 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/_docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
build:
name: Build image
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 180
outputs:
build-id: ${{ steps.build-id.outputs.id }}
strategy:
Expand Down
21 changes: 11 additions & 10 deletions .github/workflows/docker-base.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
name: Build docker base image

on:
push:
branches: ["main"]
paths:
- "src/docker/base/**"
- ".github/workflows/docker-base.yml"
# re-run if something chnages in the bootstrap action (e.g. version of the dependencies)
- ".github/actions/bootstrap/action.yml"
- ".github/workflows/_docker-build.yml"
workflow_dispatch:
inputs:
flwr-version:
description: "Version of Flower."
required: true
type: string

permissions:
contents: read
Expand Down Expand Up @@ -43,7 +41,9 @@ jobs:
python-version: ["3.8", "3.9", "3.10", "3.11"]
distro:
- name: ubuntu
version: 22.04
version: "22.04"
- name: alpine
version: "3.19"
with:
namespace-repository: flwr/base
file-dir: src/docker/base/${{ matrix.distro.name }}
Expand All @@ -53,7 +53,8 @@ jobs:
SETUPTOOLS_VERSION=${{ needs.parameters.outputs.setuptools-version }}
DISTRO=${{ matrix.distro.name }}
DISTRO_VERSION=${{ matrix.distro.version }}
tags: py${{ matrix.python-version }}-${{ matrix.distro.name }}${{ matrix.distro.version }}
FLWR_VERSION=${{ github.event.inputs.flwr-version }}
tags: ${{ github.event.inputs.flwr-version }}-py${{ matrix.python-version }}-${{ matrix.distro.name }}${{ matrix.distro.version }}
secrets:
dockerhub-user: ${{ secrets.DOCKERHUB_USERNAME }}
dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
25 changes: 11 additions & 14 deletions src/docker/base/alpine/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ RUN apk add --no-cache \
g++ \
libffi-dev \
# create virtual env
&& python -m venv /opt/venv
&& python -m venv /app/venv

# Make sure we use the virtualenv
ENV PATH="/opt/venv/bin:$PATH"
ENV PATH=/app/venv/bin:$PATH

# Install specific version of pip, setuptools and flwr
ARG PIP_VERSION
Expand All @@ -53,12 +53,18 @@ FROM python:${PYTHON_VERSION}-${DISTRO}${DISTRO_VERSION} as base

# required by the grpc package
RUN apk add --no-cache \
libstdc++
libstdc++ \
# add non-root user
&& adduser \
--no-create-home \
--disabled-password \
--gecos "" \
--uid 49999 app

COPY --from=compile /opt/venv /opt/venv
COPY --from=compile --chown=app:app /app/venv /app/venv

# Make sure we use the virtualenv
ENV PATH="/opt/venv/bin:$PATH" \
ENV PATH=/app/venv/bin:$PATH \
# Send stdout and stderr stream directly to the terminal. Ensures that no
# output is retained in a buffer if the application crashes.
PYTHONUNBUFFERED=1 \
Expand All @@ -71,15 +77,6 @@ ENV PATH="/opt/venv/bin:$PATH" \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8

# add non-root user
RUN adduser \
--no-create-home \
--disabled-password \
--gecos "" \
--uid 49999 app \
&& mkdir -p /app \
&& chown -R app:app /app

WORKDIR /app
USER app
ENV HOME=/app
88 changes: 64 additions & 24 deletions src/docker/base/ubuntu/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,12 @@
# limitations under the License.
# ==============================================================================

# hadolint global ignore=DL3008
ARG DISTRO=ubuntu
ARG DISTRO_VERSION=22.04
FROM $DISTRO:$DISTRO_VERSION as base
FROM $DISTRO:$DISTRO_VERSION as python

ENV DEBIAN_FRONTEND noninteractive
# Send stdout and stderr stream directly to the terminal. Ensures that no
# output is retained in a buffer if the application crashes.
ENV PYTHONUNBUFFERED 1
# Typically, bytecode is created on the first invocation to speed up following invocation.
# However, in Docker we only make a single invocation (when we start the container).
# Therefore, we can disable bytecode writing.
ENV PYTHONDONTWRITEBYTECODE 1
# Ensure that python encoding is always UTF-8.
ENV PYTHONIOENCODING UTF-8
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
ENV DEBIAN_FRONTEND=noninteractive

# Install system dependencies
RUN apt-get update \
Expand All @@ -40,20 +30,70 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*

# Install PyEnv and Python
ARG PYTHON_VERSION
ENV PYENV_ROOT /root/.pyenv
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
ARG PYTHON_VERSION=3.11
ENV PYENV_ROOT=/root/.pyenv
ENV PATH $PYENV_ROOT/bin:$PATH
# https://github.com/hadolint/hadolint/wiki/DL4006
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
RUN pyenv install ${PYTHON_VERSION} \
&& pyenv global ${PYTHON_VERSION} \
&& pyenv rehash

# Install specific version of pip
ARG PIP_VERSION
RUN python -m pip install --no-cache-dir pip==$PIP_VERSION
# hadolint ignore=DL3003
RUN git clone https://github.com/pyenv/pyenv.git \
&& cd pyenv/plugins/python-build || exit \
&& ./install.sh

# Issue: python-build only accepts the exact Python version e.g. 3.11.1 but
# we want to allow more general versions like 3.11
# Solution: first use pyenv to get the exact version and then pass it to python-build
RUN LATEST=$(pyenv latest -k ${PYTHON_VERSION}) \
&& python-build "${LATEST}" /usr/local/bin/python

FROM $DISTRO:$DISTRO_VERSION as base

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
&& apt-get -y --no-install-recommends install \
libsqlite3-dev \
&& rm -rf /var/lib/apt/lists/*

COPY --from=python /usr/local/bin/python /usr/local/bin/python

ENV PATH=/usr/local/bin/python/bin:$PATH \
# Send stdout and stderr stream directly to the terminal. Ensures that no
# output is retained in a buffer if the application crashes.
PYTHONUNBUFFERED=1 \
# Typically, bytecode is created on the first invocation to speed up following invocation.
# However, in Docker we only make a single invocation (when we start the container).
# Therefore, we can disable bytecode writing.
PYTHONDONTWRITEBYTECODE=1 \
# Ensure that python encoding is always UTF-8.
PYTHONIOENCODING=UTF-8 \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8

# Install specific version of setuptools
# Use a virtual environment to ensure that Python packages are installed in the same location
# regardless of whether the subsequent image build is run with the app or the root user
RUN python -m venv /app/venv
ENV PATH=/app/venv/bin:$PATH

ARG PIP_VERSION
ARG SETUPTOOLS_VERSION
RUN python -m pip install --no-cache-dir setuptools==$SETUPTOOLS_VERSION
ARG FLWR_VERSION
ARG FLWR_PACKAGE=flwr
RUN pip install -U --no-cache-dir \
pip==${PIP_VERSION} \
setuptools==${SETUPTOOLS_VERSION} \
${FLWR_PACKAGE}==${FLWR_VERSION}

# add non-root user
RUN adduser \
--no-create-home \
--disabled-password \
--gecos "" \
--uid 49999 app \
&& chown -R app:app /app

WORKDIR /app
USER app
ENV HOME=/app