Skip to content

Reduce incremental Docker build times #27998

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,7 @@ prime/

# Manpage
/man

Dockerfile
.dockerignore
.github/
1 change: 0 additions & 1 deletion .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ modifies/migrations:
modifies/internal:
- "Makefile"
- "Dockerfile"
- "Dockerfile.rootless"
- "docker/**"
- "webpack.config.js"
- ".eslintrc.yaml"
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/files-changed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ jobs:

docker:
- "Dockerfile"
- "Dockerfile.rootless"
- "docker/**"
- "Makefile"

Expand Down
14 changes: 5 additions & 9 deletions .github/workflows/pull-docker-dryrun.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,21 @@ jobs:
files-changed:
uses: ./.github/workflows/files-changed.yml

regular:
docker:
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
target: gitea
pull: true
push: false
tags: gitea/gitea:linux-amd64

rootless:
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
target: gitea-rootless
pull: true
push: false
file: Dockerfile.rootless
tags: gitea/gitea:linux-amd64
37 changes: 5 additions & 32 deletions .github/workflows/release-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
- name: upload binaries to s3
run: |
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
nightly-docker-rootful:
nightly-docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -91,44 +91,17 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
target: gitea
platforms: linux/amd64,linux/arm64
pull: true
push: true
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}
nightly-docker-rootless:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
check-latest: true
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Get cleaned branch name
id: clean_name
run: |
# if main then say nightly otherwise cleanup name
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
echo "branch=nightly" >> "$GITHUB_OUTPUT"
exit 0
fi
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: fetch go modules
run: make vendor
- name: build rootless docker image
uses: docker/build-push-action@v5
with:
context: .
target: gitea-rootless
platforms: linux/amd64,linux/arm64
pull: true
push: true
file: Dockerfile.rootless
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless
5 changes: 4 additions & 1 deletion .github/workflows/release-tag-rc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
target: gitea
platforms: linux/amd64,linux/arm64
pull: true
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down Expand Up @@ -118,8 +120,9 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
target: gitea-rootless
platforms: linux/amd64,linux/arm64
pull: true
push: true
file: Dockerfile.rootless
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
5 changes: 4 additions & 1 deletion .github/workflows/release-tag-version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
target: gitea
platforms: linux/amd64,linux/arm64
pull: true
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down Expand Up @@ -134,8 +136,9 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
target: gitea-rootless
platforms: linux/amd64,linux/arm64
pull: true
push: true
file: Dockerfile.rootless
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
102 changes: 74 additions & 28 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,104 @@ RUN apk --no-cache add \
&& rm -rf /var/cache/apk/*

# Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea

COPY ./go.mod .

RUN go mod download

COPY package.json .
COPY package-lock.json .

RUN npm install --no-save --verbose

COPY . .
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could even further optimize by explicitly copying only what is needed here, which would enable us to remove .dockerignore as well. It's a bit risky though in case someone adds new root files/folders and forgets to add them here, but overall I'm in favor of it. Wonder what others think.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you would still want to keep the .dockerignore as this stops the files being moved into the docker build context which is created before the first COPY command, which helps to reduce docker build times.

I use explicit COPYing elsewhere to help reduce build times in other projects. Especially nice to separate frontend and backend compilation, for an even higher chance of caching.

As for the risk of forgetting to add new files/folders to the Dockerfile, I don't think this would be too bad as the docker build workflows should flag this issue pretty quickly.


# Checkout version if set
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
&& make clean-all build

# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go

# Copy local files
COPY docker/root /tmp/local

# Set permissions
RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/tmp/local/usr/local/bin/gitea \
/tmp/local/etc/s6/gitea/* \
/tmp/local/etc/s6/openssh/* \
/tmp/local/etc/s6/.s6-svscan/* \
/go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete

FROM docker.io/library/alpine:3.18
FROM docker.io/library/alpine:3.18 AS gitea-base
LABEL maintainer="maintainers@gitea.io"

EXPOSE 22 3000

RUN apk --no-cache add \
bash \
ca-certificates \
curl \
gettext \
git \
curl \
gnupg \
&& rm -rf /var/cache/apk/*

RUN addgroup -S -g 1000 git

FROM gitea-base AS gitea-rootless
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this build work with the two tags in the same file? Would target: gitea in docker/build-push-action skip over these steps for gitea-rootless? I assume not, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can see in the docker-dryrun workflow, that the first build-push-action build gitea-base and gitea. Then in the next build-push-action you can see the gitea-base layers have all been cached and only the gitea-rootless layers are run.

If not specifying the target when building, docker build will export the final image "as the one to run".

LABEL maintainer="maintainers@gitea.io"

EXPOSE 2222 3000

RUN apk --no-cache add \
dumb-init \
&& rm -rf /var/cache/apk/*

RUN adduser \
-S -H -D \
-h /var/lib/gitea/git \
-s /bin/bash \
-u 1000 \
-G git \
git

RUN mkdir -p /var/lib/gitea /etc/gitea
RUN chown git:git /var/lib/gitea /etc/gitea

# Copy local files
COPY --chmod=755 docker/rootless /tmp/local

COPY --from=build-env --chmod=755 --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env --chmod=755 --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env --chmod=644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh

# git:git
USER 1000:1000
ENV GITEA_WORK_DIR /var/lib/gitea
ENV GITEA_CUSTOM /var/lib/gitea/custom
ENV GITEA_TEMP /tmp/gitea
ENV TMPDIR /tmp/gitea

# TODO add to docs the ability to define the ini to load (useful to test and revert a config)
ENV GITEA_APP_INI /etc/gitea/app.ini
ENV HOME "/var/lib/gitea/git"
VOLUME ["/var/lib/gitea", "/etc/gitea"]
WORKDIR /var/lib/gitea

ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
CMD []

FROM gitea-base AS gitea
LABEL maintainer="maintainers@gitea.io"

EXPOSE 22 3000

RUN apk --no-cache add \
linux-pam \
openssh \
s6 \
sqlite \
su-exec \
gnupg \
&& rm -rf /var/cache/apk/*

RUN addgroup \
-S -g 1000 \
git && \
adduser \
RUN adduser \
-S -H -D \
-h /data/git \
-s /bin/bash \
-u 1000 \
-G git \
git && \
echo "git:*" | chpasswd -e
echo "git:*" | chpasswd -e

ENV USER git
ENV GITEA_CUSTOM /data/gitea
Expand All @@ -80,7 +125,8 @@ VOLUME ["/data"]
ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/bin/s6-svscan", "/etc/s6"]

COPY --from=build-env /tmp/local /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
COPY --chmod=755 docker/root /tmp/local

COPY --from=build-env --chmod=755 /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env --chmod=755 /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env --chmod=644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
90 changes: 0 additions & 90 deletions Dockerfile.rootless

This file was deleted.