GithubHelp home page GithubHelp logo

earthly / earthly Goto Github PK

View Code? Open in Web Editor NEW
10.9K 61.0 382.0 36.29 MB

Super simple build framework with fast, repeatable builds and an instantly familiar syntax – like Dockerfile and Makefile had a baby.

Home Page: https://earthly.dev

License: Mozilla Public License 2.0

Go 76.12% Shell 7.07% ANTLR 0.64% Python 1.09% Dockerfile 0.06% JavaScript 0.02% Earthly 15.00%
build-automation build container-builder hacktoberfest docker-images hacktoberfest2020 reproducible-builds dockerfiles hacktoberfest2021 build-tool

earthly's Introduction

Earthly

Earthly
It’s like Docker for builds

GitHub Actions CI Join the chat on Slack Docs Website Install Earthly Docker Hub License MPL-2

Open in GitHub Codespaces

🔁 Repeatable Builds - Write builds once, and run them anywhere – on your laptop, remote, and in any CI.

❤️ Super Simple - Instantly recognizable syntax – like Dockerfile and Makefile had a baby.

🛠 Compatible with Every Language, Framework, and Build Tool - If it runs on Linux, it runs on Earthly.

🏘 Great for Monorepos and Polyrepos - Organize your build logic however makes the most sense for your project.

💨 Fast Builds - Build caching and parallel execution makes builds fast automatically.

♻️ Reuse, Don't Repeat - Never write the same code in multiple builds again.


🌎 Earthly is a versatile, approachable CI/CD framework that runs every pipeline inside containers, giving you repeatable builds that you write once and run anywhere. It has a super simple, instantly recognizable syntax that is easy to write and understand – like Dockerfile and Makefile had a baby. And it leverages and augments popular build tools instead of replacing them, so you don’t have to rewrite all your builds no matter what languages you use.


Get Earthly

Table of Contents

Why Use Earthly?

🔁 Repeatable Builds

Earthly runs all builds in containers, making them self-contained, isolated, repeatable, and portable. This allows for faster iteration on build scripts and easier debugging when something goes wrong – no more git commit -m "try again". When you write a build, you know it will execute correctly no matter where it runs – your laptop, a colleague’s laptop, or any CI. You don’t have to configure language-specific tooling, install additional dependencies, or complicate your build scripts to ensure they are compatible with different OSs. Earthly gives you consistent, repeatable builds regardless of where they run.

❤️ Super Simple

Earthly’s syntax is easy to write and understand. Most engineers can read an Earthfile instantly, without prior knowledge of Earthly. We combined some of the best ideas from Dockerfiles and Makefiles into one specification – like Dockerfile and Makefile had a baby.

🛠 Compatible with Every Language, Framework, and Build Tool

Earthly works with the compilers and build tools you use. If it runs on Linux, it runs on Earthly. And you don’t have to rewrite your existing builds or replace your package.json, go.mod, build.gradle, or Cargo.toml files. You can use Earthly as a wrapper around your existing tooling and still get Earthly’s repeatable builds, parallel execution, and build caching.

🏘 Great for Monorepos and Polyrepos

Earthly is great for both monorepos and polyrepos. You can split your build logic across multiple Earthfiles, placing some deeper inside the directory structure or even in other repositories. Referencing targets from other Earthfiles is easy regardless of where they are stored. So you can organize your build logic however makes the most sense for your project.

💨 Fast Builds

Earthly automatically executes build targets in parallel and makes maximum use of cache. This makes builds fast. Earthly also has powerful shared caching capabilities that speed up builds frequently run across a team or in sandboxed environments, such as Earthly Satellites, GitHub Actions, or your CI.

If your build has multiple steps, Earthly will:

  1. Build a directed acyclic graph (DAG).
  2. Isolate execution of each step.
  3. Run independent steps in parallel.
  4. Cache results for future use.

♻️ Reuse, Don't Repeat

Never have to write the same code in multiple builds again. With Earthly, you can reuse targets, artifacts, and images across multiple Earthfiles, even ones in other repositories, in a single line. Earthly is cache-aware, based on the individual hashes of each file, and has shared caching capabilities. So you can create a vast and efficient build hierarchy that only executes the minimum required steps.

Where Does Earthly Fit?

Earthly fits between language-specific tooling and the CI

Earthly is meant to be used both on your development machine and in CI. It runs on top of your CI/CD platform (such as Jenkins, Circle CI, GitHub Actions, and GitLab CI/CD). Earthly provides the benefits of a modern build automation system wherever it runs – such as caching and parallelism. It is a glue layer between language-specific build tooling (like maven, gradle, npm, pip, go build) and CI, working like a wrapper around your build tooling and build logic that isolates build execution from the environments they run in.

How Does It Work?

In short: containers, layer caching, and complex build graphs!

Earthly executes builds in containers, where execution is isolated. The dependencies of the build are explicitly specified in the build definition, thus making the build self-sufficient.

We use a target-based system to help users break up complex builds into reusable parts. Nothing is shared between targets other than clearly declared dependencies. Nothing shared means no unexpected race conditions. In fact, the build is executed in parallel whenever possible, without any need for the user to take care of any locking or unexpected environment interactions.

ℹ️ Note Earthfiles might seem very similar to Dockerfile multi-stage builds. In fact, the same technology is used underneath. However, a key difference is that Earthly is designed to be a general-purpose build system, not just a Docker image specification. Read more about how Earthly is different from Dockerfiles.

Installation

See installation instructions.

To build from source, check the contributing page.

Quick Start

Here are some resources to get you started with Earthly

See also the full documentation.

Reference pages

A simple example (for Go)

# Earthfile
VERSION 0.8
FROM golang:1.15-alpine3.13
RUN apk --update --no-cache add git
WORKDIR /go-example

all:
  BUILD +lint
  BUILD +docker

build:
  COPY main.go .
  RUN go build -o build/go-example main.go
  SAVE ARTIFACT build/go-example AS LOCAL build/go-example

lint:
  RUN go get golang.org/x/lint/golint
  COPY main.go .
  RUN golint -set_exit_status ./...

docker:
  COPY +build/go-example .
  ENTRYPOINT ["/go-example/go-example"]
  SAVE IMAGE go-example:latest
// main.go
package main

import "fmt"

func main() {
  fmt.Println("hello world")
}

Invoke the build using earthly +all.

Demonstration of a simple Earthly build

Examples for other languages are available in the examples dir.

Features

⛓ Parallelization that just works

Whenever possible, Earthly automatically executes targets in parallel.

Demonstration of Earthly's parallelization

💾 Caching that works the same as Docker builds

Cut down build times in CI through shared remote caching.

Demonstration of Earthly's caching

🛠 Multi-platform support

Build for multiple platforms in parallel.

VERSION 0.8
all:
    BUILD \
        --platform=linux/amd64 \
        --platform=linux/arm64 \
        --platform=linux/arm/v7 \
        --platform=linux/arm/v6 \
        +build

build:
    FROM alpine:3.18
    CMD ["uname", "-m"]
    SAVE IMAGE multiplatform-image

🤲 Build tools that work everywhere

No need to ask your team to install protoc, a specific version of Python, Java 1.6, or the .NET Core ecosystem. Install once in your Earthfile, and it works for everyone. Or even better, you can just make use of the rich Docker Hub ecosystem.

VERSION 0.8
FROM golang:1.15-alpine3.13
WORKDIR /proto-example

proto:
  FROM namely/protoc-all:1.29_4
  COPY api.proto /defs
  RUN --entrypoint -- -f api.proto -l go
  SAVE ARTIFACT ./gen/pb-go /pb AS LOCAL pb

build:
  COPY go.mod go.sum .
  RUN go mod download
  COPY +proto/pb pb
  COPY main.go ./
  RUN go build -o build/proto-example main.go
  SAVE ARTIFACT build/proto-example

See full example code.

📦 Modern import system

Earthly can be used to reference and build targets from other directories or even other repositories. For example, if we wanted to build an example target from the github.com/earthly/earthly repository, we could issue

# Try it yourself! No need to clone.
earthly github.com/earthly/earthly/examples/go:main+docker
# Run the resulting image.
docker run --rm earthly/examples:go

🔨 Reference other targets using +

Use + to reference other targets and create complex build inter-dependencies.

Target and artifact reference syntax

Examples

  • Same directory (same Earthfile)

    BUILD +some-target
    FROM +some-target
    COPY +some-target/my-artifact ./
  • Other directories

    BUILD ./some/local/path+some-target
    FROM ./some/local/path+some-target
    COPY ./some/local/path+some-target/my-artifact ./
  • Other repositories

    BUILD github.com/someone/someproject:v1.2.3+some-target
    FROM github.com/someone/someproject:v1.2.3+some-target
    COPY github.com/someone/someproject:v1.2.3+some-target/my-artifact ./

🔑 Cloud secrets support built-in

Secrets are never stored within an image's layers and they are only available to the commands that need them.

earthly set /user/github/token 'shhh...'
release:
  RUN --push --secret GITHUB_TOKEN=user/github/token github-release upload file.bin

FAQ

How is Earthly different from Dockerfiles?

Dockerfiles were designed for specifying the make-up of Docker images and that's where Dockerfiles stop. Earthly takes some key principles of Dockerfiles (like layer caching) but expands on the use cases. For example, Earthly can output regular artifacts, run unit and integration tests, and create several Docker images at a time - all outside the scope of Dockerfiles.

It is possible to use Dockerfiles in combination with other technologies (e.g., Makefiles or bash files) to solve such use cases. However, these combinations are difficult to parallelize, challenging to scale across repositories as they lack a robust import system, and often vary in style from one team to another. Earthly does not have these limitations as it was designed as a general-purpose build system.

For example, Earthly introduces a richer target, artifact, and image referencing system, allowing for better reuse in complex builds spanning a single large repository or multiple repositories. Because Dockerfiles are only meant to describe one image at a time, such features are outside the scope of applicability of Dockerfiles.

How do I know if a command is a classic Dockerfile command or an Earthly command?

Check out the Earthfile reference doc page. It has all the commands there and specifies which commands are the same as Dockerfile commands and which are new.

Can Earthly build Dockerfiles?

Yes! You can use the command FROM DOCKERFILE to inherit the commands in an existing Dockerfile.

build:
  FROM DOCKERFILE .
  SAVE IMAGE some-image:latest

You may also optionally port your Dockerfiles to Earthly entirely. Translating Dockerfiles to Earthfiles is usually a matter of copy-pasting and making minor adjustments. See the getting started page for some Earthfile examples.

How is Earthly different from Bazel?

Bazel is a build tool developed by Google to optimize the speed, correctness, and reproducibility of their internal monorepo codebase. The main difference between Bazel and Earthly is that Bazel is a build system, whereas Earthly is a general-purpose CI/CD framework. For a more in-depth explanation see our FAQ.

Contributing

  • Please report bugs as GitHub issues.
  • Join us on Slack!
  • Questions via GitHub issues are welcome!
  • PRs welcome! But please give a heads-up in a GitHub issue before starting work. If there is no GitHub issue for what you want to do, please create one.
  • To build from source, check the contributing page.

Licensing

Earthly is licensed under the Mozilla Public License Version 2.0. See LICENSE.

earthly's People

Contributors

adamgordonbell avatar alexcb avatar andrewsykim avatar brandonsc avatar camerondurham avatar dchw avatar dependabot[bot] avatar everte avatar felpeyu avatar idelvall avatar idodod avatar ingwarsw avatar jalletto avatar jazzdan avatar jensrantil avatar josemyduarte avatar jsoref avatar littleredcorvette avatar mikejholly avatar miles170 avatar nelsam avatar pmembrey avatar r-laforge avatar renovate[bot] avatar rrjjvv avatar shepherdjerred avatar thtmnisamnstr avatar velutas avatar vladaionescu avatar wxdao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

earthly's Issues

Support for docker commands within builds

Docker use is generally not necessary for regular builds. User can always just

FROM <some-image>
RUN --entrypoint

Which is very close to docker run-ing anyway.

However, for complex integration testing, where multiple containers are necessary to run in parallel (eg potentially a whole docker-compose stack), it's necessary that a docker daemon is made available to the build (and also that the docker daemon is isolated well enough with earthly's principles). To allow the use of this docker daemon, the following commands are available, but only as experimental features:

  • DOCKER LOAD - loads a target's image output as a docker image within the docker daemon available within the build
  • DOCKER PULL - pulls an image from a remote repository - it takes into account proper earthly caching
  • RUN --with-docker - allows running docker commands with a docker daemon present

Current issue is that these only work via Docker's vfs storage driver due to docker-in-docker issues. Reason is that overlayfs cannot be used on top of overlayfs. The storage driver vfs is the only driver which works on top of overlayfs. The issue with vfs is that it does not have copy-on-write capabilities, so it ends up copying entire contents for each build layer. This is extremely costly to the disk space and ends up being unusable for anything serious.

Some ideas to work around this:

  • Use a host bind-mounted dir for docker-in-docker uses. Within it, create sub-dirs for each docker daemon used within the build. Pass this bind-mount all the way within the build - and within it, mount the docker dir (/var/lib/docker) of the docker-in-docker daemon. Thus, the daemon can now use a native partition (eg ext4), which allows use of overlayfs on top.
  • The loop device could be formatted as btrfs, rather than ext4. Btrfs has built-in copy-on-write capabilities and it is not necessary to use overlayfs on top. Buildkit and docker could use btrfs storage driver directly. This would allow chaining docker-in-docker without any overlayfs involved. The current issue is that buildkit does not yet support btrfs. I suspect adding support for it is not too difficult, as it's built on top of containerd & docker which have support for btrfs.
  • Use the host docker.sock - however, naming of containers, networks and sharing host resources (eg open ports) would have to be controlled carefully to prevent different parallel builds from interacting with the same resources. This might turn out to be impossible to pull off with good enough isolation.

Not obvious how to run the build

A new user of Earthly reported the following:

I wrote up the earth.file trying to follow the tutorial and then ran the earth command and did not really get much further. I see in the help

COMMANDS:
  prune    Prune earthly build cache
  help, h  Shows a list of commands or help for one command

But I am not sure that I wanted to run either of those commands.

It should be more obvious how to run the build, from both

  1. the tutorial
  2. the earth usage text

Associated buildkit solve's

Currently Earthly builds rely on multiple solve submissions to buildkit. Basically one for the side effects, one for each artifact, one for each image and one for each target with RUN --push instructions.

Although this works reasonably well, there are some possible issues and limitations due to this approach:

  • Performance is impacted
  • Race conditions are possible as the builds are not associated with each other via a single session. It is possible for a GC to kick in between such related solves and end up needing to rebuild parts that have already been built. This is very rare due to the cache typically not evicting very recent builds - but maybe the GC strategy of buildkit may change.
  • Other undiscovered side-effects.

In order to address this, we would need to switch to using the Build API of buildkit, rather than Solve. This would allow to associate multiple solve's within the same session. However, this approach has the following limitations / possible challenges:

  • Local dirs need to be specified at the beginning of the build. Possible ways to address this:
    • Add a way in buildkit to incrementally add local dirs in the middle of the session
    • Use two passes when processing earthfiles: one pass to collect all dirs, and another pass to actually take the commands and convert them to LLB (which may also include intermediate solve's). However, this approach prevents us from using variable args for expanding external targets, should we want to do this in the future.
  • Exports can become gnarly to track and match back to the originating target as they are returned as a single big blob (?). There may be unexpected hoops we'd need to jump through to make it work for the Earthly use-case.
  • The experimental docker-in-docker related features rely on invoking a build in the middle of a build (in order to output a docker image which can be used within a docker-in-docker). This can't be merged into a single build, because the Build API doesn't have the ability to turn a state into a docker .tar in the middle of a build (without exporting to the client).

docker login does not work with Quay

@zenyui reports issues with using Earthly in combination with Quay as a private registry.

It seems that Earthly is able to resolve to the right sha, but pulling doesn't work. It randomly works for some repos, but not for others. Unknown what causes it to work / no work.

System is a Mac. Connection is over VPN.

Error "no space left on device"

This seems to happen now and then, especially if invoking larger builds.

It seems that buildkit GC is not aggressive enough to stay within the confines of the allocated space on the loop device.

Simple workaround is to earth prune --reset and try again. If this happen regularly, increase cache space on disk via export EARTHLY_BUILDKIT_CACHE_SIZE_MB=... (default is 10000).

Cannot build image FROM scratch

Earthly seems to always try pulling images and it won't allow me to build from scratch.

This Dockerfile works:

FROM scratch
WORKDIR /

This earthly build file fails:

FROM scratch
t:
  WORKDIR /

With error:

buildkitd | Found buildkit daemon as docker container (earthly-buildkitd)
Error: parse: apply implicit FROM +base: apply build +base: earthfile2llb for +base: parse: apply FROM scratch: resolve image config for scratch: docker.io/library/scratch:latest: not found

This will also fail if FROM scratch is listed under a target.

How can I build an image from scratch?

Proposal: Support for running commands on the host system

Background

Earthfiles are meant to be the entire build definition for a project and not be wrapped in anything else. The reason is that we want no additional layers between the CI and Earthly which could create complexity / confusion / difficulty reproducing CI failures.

However, sometimes developers need to perform operations outside of containers, for development purposes:

  • Running the app they are working on
  • Running docker containers with host volumes mounted (eg for live reloads)
  • Starting a docker-compose stack
  • Resetting the dev database state
  • Hooking up a debugger
  • Etc etc etc

This kind of operations need to be executed on the host environment (or using the host docker daemon).

Traditionally people have used a combination of Makefile recipes or bash scripts to store long commands that they use regularly. This is a proposal for features in Earthly to satisfy this use case.

Proposal

The proposal is to have special Earthly targets that execute the commands on the host system directly, rather than in containers.

Wrap common dev commands

Here is an example use-case: wrapping common dev commands.

unsafe host compose:
  ENV COMPOSE_FILES="-f file1.yml -f file2.yml -f file3.yml -f file4.yml"

unsafe host up:
  FROM +compose
  RUN docker-compose $COMPOSE_FILES up -d "$@"

unsafe host down:
  FROM +compose
  RUN docker-compose $COMPOSE_FILES down "$@"

In this example, the Earthly is used to wrap a complex docker-compose command into simpler forms that can be invoked with just earth +up, earth +down.

Build + start app in one go

Another example is using Earthly to build a series of containers (or making sure that they are up-to-date) and also starting (or restarting) them in a docker compose stack.

all-images:
  BUILD +image1
  BUILD +image2
  BUILD +image3

unsafe host up:
  BUILD +all-images
  RUN docker-compose up -d

How does it work

Notice first of all, the use of unsafe host in the declaration of a target. This is what informs Earthly to run the instructions on the host.

What commands do:

  • BUILD +some-target - if the target is of type unsafe host, then simply execute the instructions within (calling targets from other dirs is supported - system cd's into the right dir automatically - but calling a remote target is not supported here). If the target is not unsafe host, run earth +some-target.
  • RUN ... - executes the command on the host, in its own shell (eg exporting env vars or cd to different dirs is not propagated from one RUN to another).
  • ARG ... - declares an arg, as usual. Variable args are allowed.
  • ENV ... - declares an env, as usual.
  • FROM ... - executes the commands in the mentioned target before continuing. The referenced target has to be of type local. The key difference from BUILD is that any ENV is propagated in the case of FROM, whereas for BUILD it is not.
  • No other commands are supported.

Referencing a local target from a regular target would not be allowed.

Possible extension

Being able to reuse a set of host commands in the context of a containerized build. Example use-case: the same commands to bring up a docker-compose stack could be used both as a local dev environment and also as a setup step for an integration test that runs within Earthly.

In this case, we could use the word "snippet" to declare such special targets. These snippets can then be exectued within regular Earthly targets. The word unsafe can be used in the execution of the earth command itself, as syntactic salt: earth --unsafe +my-snippet.

Possible issues

Executing commands on the host is exactly the kind of thing Earthly stands against :-) . If misused, the user goes back to builds that cannot be easily reproduced. The different commands may do wildly different things on different systems (linux vs mac vs windows) and also caching and idempotency are lost. This proposal could be mistaken for some kind of April fools joke :-)

Also, the language becomes a little more complicated and possibly confusing for new users. It's easy to miss the local keyword and be confused as to how the build actually works.

However, there may be very valid use-cases for this.

Ask

Please upvote / downvote this issue to signify interest. Also, if you have additional example use-cases for such a feature, please leave a comment.

More obvious build failure reason

When a build fails due to a target, all on-going parallel targets are cancelled. The output then lists several targets as having failed - some with "context canceled" reason and one with the original reason that everything was canceled for. The original reason should be more obvious to spot.

Some ideas:

  • At the end, print the original reason why everything was stopped.
  • Reserve the colors red and orange and use them for this use-case: the original failure gets an extra FAIL label marked with red, while the canceled targets get an extra CANCELED lebel marked with organge.
  • Have a way to retrieve the output of the failed target isolated from everything else. This could be a separate command that would be run subsequently by the user.

Socket files left over from 'dotnet restore' cause buildkit to fail

I'm trying to make an example for .NET Core/C#

I've created sample code based on Java/Scala, but I'm getting extremely confusing error.

radek@radek-ThinkPad-T490s:~/develop/earthly/examples$ earth --no-cache ./dotnet+docker
buildkitd | Found buildkit daemon as docker container (earthly-buildkitd)
context | --> local context ./dotnet
./dotnet+base | --> FROM mcr.microsoft.com/dotnet/core/sdk:3.1.302-alpine3.12
./dotnet+base | resolve mcr.microsoft.com/dotnet/core/sdk:3.1.302-alpine3.12@sha256:a6977770fb5ad9b7535ef867362bb056fa92439a161c2353702440249c2d46dd 0%
./dotnet+base | resolve mcr.microsoft.com/dotnet/core/sdk:3.1.302-alpine3.12@sha256:a6977770fb5ad9b7535ef867362bb056fa92439a161c2353702440249c2d46dd 100%
context | transferring ./dotnet: 0%
context | transferring ./dotnet: 0%
context | transferring ./dotnet: 100%
./dotnet+base | sha256:c991f9f4493de37a1051238d7a1758d68955d4e0b1261fb3e2a87abe94b1a839 100%
./dotnet+base | sha256:a3a43191d31d4956f69774ee89eeea8ceb47b259f7fe0325a6472774cdb8595b 100%
./dotnet+base | sha256:ac47820464eb6c4cde48d5c77047b25ed5d1c629fea54e58ac6604b37bf37bf3 100%
./dotnet+base | sha256:1d4fe617e70734bb22a0d97301c2b87d36cdd66050d3855f74b69f875ba423a3 100%
./dotnet+base | sha256:a6977770fb5ad9b7535ef867362bb056fa92439a161c2353702440249c2d46dd 100%
./dotnet+base | sha256:b0d5a04473425774ee4803fd9c3a89087a60f332c7da8c137ae29a0a48cfe64d 100%
./dotnet+base | sha256:df20fa9351a15782c64e6dddb2d4a6f50bf6d3688060a34c4014b0d9a752eb4c 100%
./dotnet+base | sha256:eff32e99990ceb80c49cb2a8037af3f9b53d2f69763f419018bcc02abc930b23 100%
./dotnet+base | sha256:bb9fc6048a9dd25ab6a26f64809be519e91cca2cf15d4e0cdddd0a8f99a3cd94 100%
./dotnet+base | unpacking mcr.microsoft.com/dotnet/core/sdk:3.1.302-alpine3.12@sha256:a6977770fb5ad9b7535ef867362bb056fa92439a161c2353702440249c2d46dd 0%
./dotnet+base | unpacking mcr.microsoft.com/dotnet/core/sdk:3.1.302-alpine3.12@sha256:a6977770fb5ad9b7535ef867362bb056fa92439a161c2353702440249c2d46dd 100%
./dotnet+base | --> WORKDIR /dotnet-example
./dotnet+build | --> COPY [src] src
./dotnet+build | --> RUN [dotnet publish src/HelloEarthly -o publish]
./dotnet+build | Microsoft (R) Build Engine version 16.6.0+5ff7b0c9e for .NET Core
./dotnet+build | Copyright (C) Microsoft Corporation. All rights reserved.
./dotnet+build | 
./dotnet+build |   Determining projects to restore...
./dotnet+build |   Restored /dotnet-example/src/HelloEarthly/HelloEarthly.csproj (in 146 ms).
./dotnet+build |   HelloEarthly -> /dotnet-example/src/HelloEarthly/bin/Debug/netcoreapp3.1/HelloEarthly.dll
./dotnet+build |   HelloEarthly -> /dotnet-example/publish/
./dotnet+build | --> SAVE ARTIFACT publish ./dotnet+build/publish
./dotnet+docker | --> COPY ([]) ./dotnet+build/publish .
Error: solve side effects: build error group: solve: failed to solve: rpc error: code = Unknown desc = failed to compute cache key: failed to create hash for /tmp/PiDh3VmOno5IZWwRHV_oNjZ+jcby9Rt5wuWKeDyQUJY: archive/tar: sockets not supported

My OS is Ubuntu 18
Earthly version 0.1.3
When running the Java and Scala examples, nothing is wrong and the build succeeds.

My code is here : Euphoric@da9d9cc

Error while creating mount source path '/tmp/ssh-agent.sock.1000'

When I use earth in my default shell/terminal it always results in this error:

$ earth ./dexterity-api/dex/+generate
buildkitd | Found buildkit daemon as docker container (earthly-buildkitd)
buildkitd | Settings do not match. Restarting buildkit daemon with updated settings...
buildkitd | Is docker installed and running? Are you part of the docker group?
Error: buildkitd new client: buildkitd new client (own): maybe start buildkitd: maybe restart: docker run earthly/buildkitd:v0.1.1: 80d0ea1166ef829ef485f42ae43760ba86c1ac13bd00da4d30efeb08bec2c203
docker: Error response from daemon: error while creating mount source path '/tmp/ssh-agent.sock.1000': mkdir /tmp/ssh-agent.sock.1000: file exists.
: exit status 125

From my env vars:

SSH_AUTH_SOCK=/tmp/ssh-agent.sock.1000

I found a quick fix is to unset SSH_AUTH_SOCK and then run earth ... But this will probably cause trouble down the road when I want to let Earthly checkout a private git repo.

Expanding RUN arguments via shlex

Currently the RUN arguments are not expanded for ARG's. They are expanded, however, via the shell. This is different to how Dockerfiles work, however, and may be surprising to the user in some cases.

Error parsing ssh git URL

Experienced this after adding the build.earth to one of my projects:

$ earth +build
buildkitd | Found buildkit daemon as docker container (earthly-buildkitd)
Error: resolve build context for target +build: Unable to parse git URL ssh://[email protected]/ShiftLeftSecurity/check-string.git

Removing .git/ makes it work.

parallel builds based on pattern matching of files

in makefiles one can do pattern matching rules like:

%.o: %.c
	$(CC) -I./src/client -I./src/common -I./src/test_common -c $(CCFLAGS) $< -o $@

earthly is missing a similar feature. It would be nice to be able to run BUILD with multiple args:

I'm not sure what the syntax would look like, but something similar to this idea would be nice:

all:
  FROM +code
  foreach file in *.c:
     BUILD --build-arg FOO=$file +buildtarget

Support for .env files

A feature request is the support for .env files (similar to how compose uses them https://docs.docker.com/compose/env-file/).

It might work like this: if an .env file is present in the current dir, or any dir above the current dir (dirs closer to current dir have higher precendence), load the vars and pass them to the build as both build-args AND secrets. EDIT: Using the .env in the current dir only seems to be the the behavior most similar to how other tools work.

CC @zenyui

Pass all git-related auth via supported buildkit constructs

Currently git auth is passed automatically to the buildkit daemon via some mounts and env vars. This requires meddling with the buildkit daemon in a manner that is difficult to translate to a build-in-the-cloud setup. A better approach is to pass in this auth via the client-daemon connection:

Should chains of buildkit solve commands reuse a session?

Currently, as part of a single build, there are multiple Solve commands issued to buildkit and they share nothing other than some copied state. The copied state allows buildkit to reuse a lot of cache.

It's possible that between these Solve's, the cache is purged and then the system unexpectedly has to build the same thing twice.

Is there a better way to do this? Is there a way for us to reuse the session? Would that help with telling buildkit to hold onto the cache for a while?

automatically remove exited earthly-buildkit image

When earth starts, it checks that the earthly-buildkit container is Running; if not it attempts to start it.

If an existing container exists but is in an exited state the Start() command fails. This should be fixed.

Additionally we will remove the --rm flag so when it does fail, we can look at the logs.

SAVE ARTIFACT empty wildcard ends up as an error after success

When we have something like

SAVE ARTIFACT *.txt AS LOCAL build/

... and say that there are no *.txt files found, the system detects this as an error only after it has deemed the build as success. It should detect the error before that and not declare it as a success.

Ideas:

  • Tie artifact independent states to final side effects with fake deps? This may have performance implications.

Invalid ENV declaration should return an error

If I do the following in my build.earth file:

ENV ${CODE_SRC}=/go/src/<project>

protobuf:
    COPY --dir api ${CODE_SRC}/backend

Then running earth +protobuf results in the files being copied into /backend:

+protobuf | --> COPY [api] /backend

I have worked around this by specifying the full path in the copy command:

ENV ${CODE_SRC}=/go/src/<project>

protobuf:
    COPY --dir api /go/src/<project>/backend

Output shows up misaligned

Sometimes, when the output has some sort of progress bar, earthly does not display it correctly due to the prefix (target name) that it needs to print for every line of the output. This needs to be handled better by Earthly.

Relevant TODO in the code.

Example

Screenshot from 2020-07-08 16-37-18

"Error: parser failure: assignment to entry in nil map" when combining FROM with EXPOSE

I'm using earth to create a Docker image in 2 recipes.
The first stage compiles the source code, the second sets up a run environment and copies over the artifacts.

I boiled it down to this simple example:

FROM alpine

build:
  RUN touch hello.txt
  SAVE ARTIFACT hello.txt

run:
  FROM ubuntu
  COPY +build/hello.txt .
  EXPOSE 8080
  SAVE IMAGE hello-image

Running earth +run fails with the following error:

Error: parser failure: assignment to entry in nil map

If i comment either the EXPOSE 8080 or FROM ubuntu commands, the command works again, so there seems to be an issue when using both commands in a recipe.

Improve logs (introduce a progress-bar for tty devices)

Running the Go example, earth floods the terminal with lines like this:

+base | sha256:61b11419476186415e86da00c53c938fd32dc5904a889e1c3d40e238d69d168e 11%
+base | sha256:61b11419476186415e86da00c53c938fd32dc5904a889e1c3d40e238d69d168e 11%
+base | sha256:61b11419476186415e86da00c53c938fd32dc5904a889e1c3d40e238d69d168e 12%
+base | sha256:61b11419476186415e86da00c53c938fd32dc5904a889e1c3d40e238d69d168e 12%
+base | sha256:61b11419476186415e86da00c53c938fd32dc5904a889e1c3d40e238d69d168e 12%
+base | sha256:61b11419476186415e86da00c53c938fd32dc5904a889e1c3d40e238d69d168e 12%
+base | sha256:61b11419476186415e86da00c53c938fd32dc5904a889e1c3d40e238d69d168e 12%
+base | sha256:61b11419476186415e86da00c53c938fd32dc5904a889e1c3d40e238d69d168e 12%

Though it is a lot more of that than I've included here. I would expect this as a progress bar replacing the line on update rather than drawing a new line.

go build is silent on success so this is a lot messier.

Proposal: Buildkit-based remote cache

Buildkit has functionality to store cache in a docker registry. Initial testing showed that it's not just as easy as turning the setting on. Need to explore why that is and address it.

This would make CI integration even better as the system would be much more performant with a cache designed for the purpose.

Failure reason not obvious when missing -P flag

There is not output when a build requires the -P flag and it is not provided. earth simply exits with non-zero status without outputting anything.

earth should give clear indication as to what the problem is.

Slow Performance

Steps should be taken to make this as fast as possible. As it is now, I really like this project but something is adding a lot of latency here.

Changing the string printed in the Go Hello World example.
Local build is 0.7 seconds whereas earth build is 14.6 seconds.

brandon@dev:~/go-earth$ vim main.go # making edit
brandon@dev:~/go-earth$ time go build

real	0m0.732s
user	0m0.413s
sys	0m0.398s
brandon@dev:~/go-earth$ time earth +build
buildkitd | Found buildkit daemon as docker container (earthly-buildkitd)
context | --> local context .
+base | --> FROM golang:1.13-alpine3.11
+base | resolve docker.io/library/golang:1.13-alpine3.11@sha256:5237fe9c1c891aee9ffb22258a412cc7449f310f8f2f65d4389c516218f90443 0%
+base | resolve docker.io/library/golang:1.13-alpine3.11@sha256:5237fe9c1c891aee9ffb22258a412cc7449f310f8f2f65d4389c516218f90443 100%
context | transferring .: 0%
context | transferring .: 0%
context | transferring .: 100%
+base | *cached* --> WORKDIR /go-example
+build | --> COPY [main.go] .
+build | --> RUN [go build -o build/go-example main.go]
+build | Target <redacted>/go-earth:master+build built successfully
=========================== SUCCESS ===========================
+build | Artifact <redacted>/go-earth:master+build/go-example as local build/go-example

real	0m14.589s
user	0m0.824s
sys	0m0.754s

Even with no change and everything cached, the delay that earth adds is several seconds:

brandon@dev:~/go-earth$ time earth +build
buildkitd | Found buildkit daemon as docker container (earthly-buildkitd)
context | --> local context .
+base | --> FROM golang:1.13-alpine3.11
+base | resolve docker.io/library/golang:1.13-alpine3.11@sha256:5237fe9c1c891aee9ffb22258a412cc7449f310f8f2f65d4389c516218f90443 0%
+base | resolve docker.io/library/golang:1.13-alpine3.11@sha256:5237fe9c1c891aee9ffb22258a412cc7449f310f8f2f65d4389c516218f90443 100%
context | transferring .: 0%
context | transferring .: 0%
context | transferring .: 100%
+base | *cached* --> WORKDIR /go-example
+build | *cached* --> COPY [main.go] .
+build | *cached* --> RUN [go build -o build/go-example main.go]
+build | Target <redacted>/go-earth:master+build built successfully
=========================== SUCCESS ===========================
+build | Artifact <redacted>/go-earth:master+build/go-example as local build/go-example

real	0m4.390s
user	0m0.693s
sys	0m0.451s
brandon@dev:~/go-earth$ time go build

real	0m0.179s
user	0m0.240s
sys	0m0.138s

WSL ERROR: read-only file system

Hello, I have set up earthly to run on Windows with WSL, and I am trying to use a specific image for compiling Unity projects, but I get this error:

+base | ERROR: (FROM gableroux/unity3d:2019.2.11f1-windows) failed to copy: write /tmp/earthly/buildkit/runc-overlayfs/content/ingest/7e1cdf26cfc0f911031b2bd7d6ad7596fe77a38778389fe3f282b2354d40abc6/data: read-only file system
Error: solve side effects: build error group: solve: failed to solve: rpc error: code = Unknown desc = failed to copy: write /tmp/earthly/buildkit/runc-overlayfs/content/ingest/7e1cdf26cfc0f911031b2bd7d6ad7596fe77a38778389fe3f282b2354d40abc6/data: read-only file system

My build.earth simply looks like this:

FROM gableroux/unity3d:2019.2.11f1-windows
WORKDIR /app

build:
        RUN echo "Hello world"`

Better insight of cache usage.

Hi,

so I configured Earthly to use a cache size of 100gb, which should take me a long way, but unfortunately only lasts me for a week or so before I have to clear the cache again.

I'd like to figure out what is actually filling up my cache, but I can't seem to find any way to gain more insight.

I suggest adding commands to help people optimize their builds or decide when a cache clean is necessary:

  1. earth cache du/df could list how much space is used/left in the build cache, making it possible to automatically clear the cache when a threshold is reached.*
  2. earth cache ls could list the individual docker layers and mount posts command that lists the cached layers and mount points with their respective sizes, giving even more insight about where exactly the disk usage is coming from.

(* I understand that one could also use du -s /tmp/earthly, however this is difficult when earth is called from within a container that mounts the docker.sock of the host system. This is a scenario which often happens when e.g. Jenkins is running in a container and using Earthly to run builds. In this constellation, the cache files will be written to the host file system, not the container file system, making it inaccessible to the container).

Again, good work with this project, I do see a great future ahead for it :)

Output distinction between targets with same name but different args

When building the same target twice, but with different args, as part of the same build, currently it is difficult to tell apart the output of the two.

We should use different colors for the console output, at a minimum. Perhaps when the target starts being built, also list the values of the args being used.

Failure to start due to container name overlap

After performing a successful earth +earth-darwin build, the earthly-buildkitd container is unable to start when attempting to update due to the reuse of the container name.

Error: buildkitd new client: buildkitd new client (own): maybe start buildkitd: start: docker run earthly/buildkitd:v0.2.2: docker: Error response from daemon: Conflict. The container name "/earthly-buildkitd" is already in use by container "48b57c80b6bd5778bf438a54de0e1e79db09e3cf8d629d9270bd953ee291c481". You have to remove (or rename) that container to be able to reuse that name.

comments don't work on FROM line

debugger-docker:
	FROM busybox:latest # cant be FROM scratch because the args require sh to exist

produces the error:

buildkitd | Found buildkit daemon as docker container (earthly-buildkitd)
Error: parse: invalid number of arguments for FROM: [busybox:latest # cant be FROM scratch because the args require sh to exist]

single quotes, when used in build-args, should not perform variable substitution or shell out (like how bash works)

earthly errors with: Error: parse: invalid number of arguments for BUILD: [--build-arg FOO='$(date +%s)' +build]

when using single quotes for spaces; e.g.

BUILD --build-arg FOO='$(date +%s)' +build

However when doublequotes are used, it works:

BUILD --build-arg FOO="$(date +%s)" +build

https://github.com/earthly/earthly/blob/master/earthfile2llb/parser/EarthLexer.g4#L78 likely needs to be adjusted

Multiline RUN commands are not possible without spaces

First of all, thanks for this interesting new tool!

I have a Makefile that I'm converting to Earth and am running into a weird issue. Consider the following snipet:

.PHONY: _gengo
_gengo:
	protoc \
		-I=. \
		-I=/src \
		-I=/src/github.com/gogo/protobuf/protobuf \
		--gogofaster_out=\
plugins=grpc,\
Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/empty.proto=github.com/gogo/protobuf/types:\
. \
		./dex.proto

It is important to protoc that the value for --gogofaster_out is a continuous string without spaces. But I'm having trouble getting Earthly to accept the \ escape if it's not preceded by a space.
So when I use the following in my earth.build:

generate-go:
	FROM golang:1-stretch
	RUN go get github.com/gogo/protobuf/protoc-gen-gogofaster
	COPY +protoc/out/bin/protoc /usr/local/bin/protoc
	COPY +gogo-protobuf/out/src /gogo-proto-src
	COPY dex.proto .
	RUN protoc \
		-I=. \
		-I=/gogo-proto-src \
		-I=/gogo-proto-src/github.com/gogo/protobuf/protobuf \
		--gogofaster_out=\
plugins=grpc,\
Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/empty.proto=github.com/gogo/protobuf/types:\
. \
		dex.proto

I get these errors:

line 41:0 token recognition error at: 'plugins='
line 41:8 token recognition error at: 'grpc,'
line 43:1 token recognition error at: 'google/'
line 43:8 token recognition error at: 'protobuf/'
line 43:17 token recognition error at: 'duration.proto='
line 43:32 token recognition error at: 'github.com/'
line 43:43 token recognition error at: 'gogo/'
line 43:48 token recognition error at: 'protobuf/'
line 43:57 token recognition error at: 'types,'

When I add a space before the \'s, earth can parse the file and starts properly, but protoc doesn't accept the arguments as they are now separate arguments instead of a single value to --gogofaster_out.

I can remove the newlines and have a single long line, but that's not very readable/maintanable. I don't understand why \ need a space before it to escape the newline.

reduce output

the progress statuses can take up a lot of output; perhaps we can change to an ncurses-like progress bar (similar to buildkit's), or change the logic to only print out values when they changes (either by 1, or 5 percentage points, or even once a second).

here's the code:
https://github.com/earthly/earthly/blob/master/builder/solver.go#L298

and here's an example of too much output:

./examples/tests+from-expose-test | +base./examples/tests+from-expose-test |  | ./examples/tests+from-expose-test | sha256:df20fa9351a15782c64e6dddb2d4a6f50bf6d3688060a34c4014b0d9a752eb4c 44%
./examples/tests+from-expose-test | +base./examples/tests+from-expose-test |  | ./examples/tests+from-expose-test | sha256:df20fa9351a15782c64e6dddb2d4a6f50bf6d3688060a34c4014b0d9a752eb4c 47%
./examples/tests+git-clone-test | +base | sha256:d838eb6031fe0bb4f1f203ec26c293afccce4db86abde5d3b1c3a923cdca5120 32%
./examples/tests+git-clone-test | +base | sha256:d838eb6031fe0bb4f1f203ec26c293afccce4db86abde5d3b1c3a923cdca5120 33%
./examples/tests+excludes-test | +base | sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08 0%
./examples/tests+excludes-test | +base./examples/tests+excludes-test |  | sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08 0%
./examples/tests+excludes-test | +base./examples/tests+excludes-test |  | ./examples/tests+excludes-test | sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08 0%
./examples/tests+git-clone-test | +base./examples/tests+git-clone-test |  | ./examples/tests+git-clone-test | sha256:d838eb6031fe0bb4f1f203ec26c293afccce4db86abde5d3b1c3a923cdca5120 34%
./examples/tests+git-clone-test | +base./examples/tests+excludes-test | +base./examples/tests+excludes-test |  | ./examples/tests+excludes-test | sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08 0%
./examples/tests+excludes-test | +base./examples/tests+excludes-test |  | sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08 0%

SSH agent socket passing

Hi, I am trying to download a go module from a private github repository within an earthly build and I cannot figure out how this is supposed to work. In the earthly documentation I read about SSH agent socket passing, but I think this is only intended for the GIT CLONE command and won't work for go mod download?

So I tried to do it like described in the buildkit doc, but then docker complains about the missing mount point:

RUN git config --global url."ssh://[email protected]/some-org/".insteadOf https://github.com/some-org/ 
RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh GOPRIVATE=github.com/some-org go mod download

Could you please point me in the right direction?

Allow configuration of cache location

Currently, /tmp/earthly is hard-coded.

I suspect workaround via symlink would not work as docker would mount the symlink, not the dir it links to, but not sure.

Support mTLS for buildkitd

There's no way to use TLS certs for authenticating the client. Looking at these lines, the likely causes is that the newBuildkitdClient() is called without opts.

earthly/cmd/earth/main.go

Lines 468 to 479 in ae214a7

func (app *earthApp) newBuildkitdClient(ctx context.Context, opts ...client.ClientOpt) (*client.Client, error) {
if app.buildkitHost == "" {
// Start our own.
bkClient, err := buildkitd.NewClient(ctx, app.console, app.buildkitdImage, app.buildkitdSettings)
if err != nil {
return nil, errors.Wrap(err, "buildkitd new client (own)")
}
return bkClient, nil
}
// Use provided.
bkClient, err := client.New(ctx, app.buildkitHost, opts...)

In cluster buildkit

Support for in-cluster building would be essential to speed up builds and make use of caching.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.