woodpecker-ci / woodpecker

Woodpecker is a simple yet powerful CI/CD engine with great extensibility.
https://woodpecker-ci.org
Apache License 2.0
3.88k stars 345 forks source link

Idea: Build local docker image #1175

Open silverwind opened 1 year ago

silverwind commented 1 year ago

Clear and concise description of the problem

Docker-based CI systems have an inherent flaw that it's not possible to pre-define an environment for steps/pipelines, so system-wide tools/languages have to be installed again and again into individual steps/pipelines which is a waste of resources and time.

Suggested solution

The CI could provide the ability to build docker images that are only available locally on the system, keyed and cached on the resulting image name. Build should be skipped if an image with the name already exists on the system.

In a file outside of pipelines:

build-images:
  - name: ci.local/golang-1.19-node-18:1
    image: golang:1.19
    commands:
      - curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get -qqy install nodejs

Pipeline using the built image:

pipeline:
  deps:
    image: ci.local/golang-1.19-node-18:1
    commands:
      npm install
      go mod download

Alternative

The alternative is to create and publish these images to a docker registry, but this brings a lot of extra burden in keeping these images up-to-date which many are not willing to do.

Validations

silverwind commented 1 year ago

Actually, thinking about it again, this should be possible with the docker plugin and a Dockerfile in the repo. Certainly not as convenient to configure as above but I think it'd probably be a lot of work to support this in woodpecker as it has no registry, for example.

6543 commented 1 year ago

let's collect cache proposals and then decide ... but that will not be in next release ...

reivilibre commented 1 year ago

This would be an absolute 'killer' feature and I would love to have it.

My current workaround is to have a separate repo of dockerfiles and have CI which publishes those to a private registry, but it's so clunky and it means that my project repos aren't self-contained.

CI performance would be much much faster if I could define an image within the Woodpecker YAML that would be built as needed and cached otherwise, precisely for installing packages or compiling build tools... :)

lafriks commented 1 year ago

Maybe woodpecker server could provide temporary docker registry for docker build images? This would also allow testing built images in separate pipeline and starting them as services.

There could be option on how long images in that registry should be kept either only as long as pipeline is running (temporary) or deleted when not used anymore for some period of time

silverwind commented 1 year ago

Yeah, I guess an option like LOCAL_IMAGE_RETENTION_TIME could be used, default it to something like 2 months, and if a local image is unused for such a period, delete it and rebuild it on-demand.

lafriks commented 1 year ago

Yes but would be nice if that could be specified somehow also in pipeline (with having setting for default value if not specified)

6543 commented 1 year ago

well docker does allow to create a "snapshot" of a running container ... so we could just snapshot a step after exec before stop it and store that, and on next run check if there is already a snapshot.

TODO: are there similar concepts for the kubernetes and podmak backend(s)?

silverwind commented 1 year ago

Updated syntax suggestion in OP slightly to allow multiple images to be built.

gmuellerinform commented 1 year ago

This feature would be really useful. Why not use the docker compose syntax:

pipeline:
  deps:
    build:
      context: ./docker/build
      dockerfile: Dockerfile
      target: wp
    commands:
      npm install
      go mod download
silverwind commented 1 year ago

We've solved this now by running a private docker registry that hosts customized base images. I guess this proposal is still useful for people who don't want to invest into running their own registry, but I personally have no need anymore.

lafriks commented 1 year ago

Something like this could potentially be useful for building docker image for services

Timshel commented 9 months ago

The documentation hinted it might be possible : https://woodpecker-ci.org/docs/usage/volumes

A working example :

steps:
  build-image:
    image: docker
    commands:
      - docker build --rm -t local/project-image .
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  build-project:
    image: local/project-image
    commands:
      - ./build.sh
gmuellerinform commented 9 months ago

This is just a workaround, not a solution:

Volumes are only available to trusted repositories and for security reasons should only be used
in private environments. See [project settings] to enable trusted mode.
Timshel commented 9 months ago

Yep but depending on your setup this might be an acceptable workaround so I thought it was worth mentioning.

airtower-luna commented 2 months ago

I came here looking for something similar to the dockerfile agent in Jenkins. Basically I'd like to be able to do something like this:

steps:
  - name: build
    dockerfile: Dockerfile.ci
    commands:
      - meson # ...

Where the container image would then be built and used to run the commands. With the build cache it's highly efficient when running pipelines repeatedly on the same host, and still pretty good with only a few (when spreading over many hosts an internal registry might indeed be better).

I personally don't see a need to have a context other than an empty directory (anything from the repository should be available from the workspace during commands execution anyway), and while an image tag would be useful to reuse the image in later steps on the same host there'd be the risk of collisions (imagine two builds with different version of the Dockerfile building in parallel, could be alleviated with variables though).