diff --git a/docs/core-concepts/1205-container-images.md b/docs/core-concepts/1205-container-images.md index 9f1de38b..0eb9d358 100644 --- a/docs/core-concepts/1205-container-images.md +++ b/docs/core-concepts/1205-container-images.md @@ -4,3 +4,41 @@ displayed_sidebar: europa --- # Building container images + +You can use Dagger to build container images. Here's a simple example of a [Dockerfile](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) build: + +```cue file=../tests/core-concepts/container-images/plans/with-dockerfile.cue +``` + +## Building with CUE + +`Dockerfile` files are easy to start, but you can also build images entirely in CUE. The following example produces the same image as above: + +```cue file=../tests/core-concepts/container-images/plans/build.cue +``` + +## Automation + +Building images in CUE gives you greater flexibility. For example, you can automate building multiple versions of an image, and deploy, all in Dagger: + +```cue file=../tests/core-concepts/container-images/plans/template.cue +``` + +Now you can deploy all versions: + +```shell +dagger do versions +``` + +Or just build a specific version, without pushing: + +```shell +dagger do versions 8.0 build +``` + +## Multi-stage build + +Another common pattern is [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds). This allows you to have heavier build images during the build process, and copy the built artifacts into a cleaner and lighter image to run in production. + +```cue file=../tests/core-concepts/container-images/plans/multi-stage.cue +``` diff --git a/docs/tests/core-concepts/container-images/plans/build.cue b/docs/tests/core-concepts/container-images/plans/build.cue new file mode 100644 index 00000000..21dd39b4 --- /dev/null +++ b/docs/tests/core-concepts/container-images/plans/build.cue @@ -0,0 +1,31 @@ +package main + +import ( + "dagger.io/dagger" + "universe.dagger.io/docker" +) + +dagger.#Plan & { + client: filesystem: ".": read: contents: dagger.#FS + + actions: build: docker.#Build & { + steps: [ + docker.#Pull & { + source: "python:3.9" + }, + docker.#Copy & { + contents: client.filesystem.".".read.contents + dest: "/app" + }, + docker.#Run & { + command: { + name: "pip" + args: ["install", "-r", "/app/requirements.txt"] + } + }, + docker.#Set & { + config: cmd: ["python", "/app/app.py"] + }, + ] + } +} diff --git a/docs/tests/core-concepts/container-images/plans/multi-stage.cue b/docs/tests/core-concepts/container-images/plans/multi-stage.cue new file mode 100644 index 00000000..acd3c693 --- /dev/null +++ b/docs/tests/core-concepts/container-images/plans/multi-stage.cue @@ -0,0 +1,45 @@ +package main + +import ( + "dagger.io/dagger" + "universe.dagger.io/alpine" + "universe.dagger.io/docker" + "universe.dagger.io/go" +) + +dagger.#Plan & { + client: filesystem: src: read: contents: dagger.#FS + + actions: { + // Build app in a "golang" container image. + build: go.#Build & { + source: client.filesystem.src.read.contents + } + + base: alpine.#Build & { + packages: "ca-certificates": _ + } + + // Build lighter image, + // without app's build dependencies. + run: docker.#Build & { + steps: [ + docker.#Copy & { + input: base.output + // This is the important part, it works like + // `COPY --from=build /output /opt` in a Dockerfile. + contents: build.output + dest: "/opt" + }, + docker.#Set & { + config: cmd: ["/opt/app"] + }, + ] + } + + push: docker.#Push & { + image: run.output + dest: "registry.example.com/app" + } + } +} diff --git a/docs/tests/core-concepts/container-images/plans/template.cue b/docs/tests/core-concepts/container-images/plans/template.cue new file mode 100644 index 00000000..4b184373 --- /dev/null +++ b/docs/tests/core-concepts/container-images/plans/template.cue @@ -0,0 +1,35 @@ +package main + +import ( + "dagger.io/dagger" + "universe.dagger.io/docker" +) + +dagger.#Plan & { + actions: versions: { + "8.0": _ + "5.7": _ + + // This is a template + // See https://cuelang.org/docs/tutorials/tour/types/templates/ + [tag=string]: { + build: docker.#Build & { + steps: [ + docker.#Pull & { + source: "mysql:\(tag)" + }, + docker.#Set & { + config: cmd: [ + "--character-set-server=utf8mb4", + "--collation-server=utf8mb4_unicode_ci", + ] + }, + ] + } + push: docker.#Push & { + image: build.output + dest: "registry.example.com/mysql:\(tag)" + } + } + } +} diff --git a/docs/tests/core-concepts/container-images/plans/with-dockerfile.cue b/docs/tests/core-concepts/container-images/plans/with-dockerfile.cue new file mode 100644 index 00000000..0e190eda --- /dev/null +++ b/docs/tests/core-concepts/container-images/plans/with-dockerfile.cue @@ -0,0 +1,24 @@ +package main + +import ( + "dagger.io/dagger" +) + +dagger.#Plan & { + client: filesystem: ".": read: contents: dagger.#FS + + actions: build: dagger.#Dockerfile & { + // This is the context. + source: client.filesystem.".".read.contents + + // Default is to look for a Dockerfile in the context, + // but let's declare it here. + contents: #""" + FROM python:3.9 + COPY . /app + RUN pip install -r /app/requirements.txt + CMD python /app/app.py + + """# + } +}