Better builds with earthly

I'm Mary Poppins, y'all!

Better builds with earthly


I like to automate everything. It saves time which I can to spend to develop another automation :)

Today I’d like to show you how to use earthly to automate your build processes.

Installation

Installation process is very simple - (if you’re using macOS like me) all you need is a docker, homebrew and git. Just run from your terminal

$ brew install earthly/earthly/earthly && earthly bootstrap

And that’s it. If you are Linux or Windows user - you can check this guide.

How to use earthly

Firstly, let’s define our task. I’d like to propose to you to develop a script which will build a simple astro-based application, let’s say - some landing page. Later I’ll write a post about benefits of astro, but now let’s focus on earthly.

In most cases, all you need is to just write 2 files - Earthfile and .earthlyignore, so let’s do it!

Let’s start with Earthfile. I’ll write the following tasks:

Earthfile looks like a mutant with a genes of Makefile and Docker, but it is a powerful creature :)

VERSION 0.6
FROM node:latest
WORKDIR /app
ARG image_name=blog

First line VERSION 0.6 defines the version of the Earthfile. Currently, it is 0.6. Lines 2 and 3 is quite similar to Dockerfile and defines parental package and working directory in our container.

deps:
  RUN npm install -g pnpm
  COPY package.json pnpm-lock.yaml* ./
  RUN pnpm install
  SAVE ARTIFACT package.json   AS LOCAL ./package.json
  SAVE ARTIFACT pnpm-lock.yaml AS LOCAL ./pnpm-lock.yaml
  RUN pnpm add object-hash potrace find-cache-dir @astropub/codecs file-type

Line deps: - is the name of the target. You can call this target from command line with following command (just prepend name of the target with ”+” sign):

$ earthly +deps

Next 3 lines (and the last one on this code block) are similar with Dockerfile - it is about to install pnpm, copy package.json and pnpm-lock.yaml files and running pnpm command. But I’d like to ask you to have a look at the next 2 lines

  SAVE ARTIFACT package.json   AS LOCAL ./package.json
  SAVE ARTIFACT pnpm-lock.yaml AS LOCAL ./pnpm-lock.yaml

Everything we’ve done before was in the container, but now we need to save those files locally. SAVE ARTIFACT ... AS LOCAL ... allows you to export data from the container to the local filesystem.

build:
    FROM +deps
    COPY . .
    RUN pnpm run build
    SAVE ARTIFACT dist /dist AS LOCAL dist

Another one part of our Earthfile. Nothing new for you, except FROM +deps. This line forces earthly to call deps-target before build. Note that target name must be start with ”+“.

docker:
    FROM nginx
    COPY +build/dist /usr/share/nginx/html
    EXPOSE 80
    SAVE IMAGE --push ${image_name}:latest

Well, the last part of our config. There are two lines you need to focus on. COPY +build/dist /usr/share/nginx/html - with this command we took everything in dist-directory we’ve produced in our build-target and copy it to the local environment. SAVE IMAGE --push ${image_name}:latest - uses this command we save what we’ve done before as a docker image, which can be used later in production environment.

Everything works fine, but there is one more thing I’ve mentioned before - .earthlyignore file. This file is useful when you copy directory, but you need to avoid copying of some files or directories to your container. The format of this file is similar with .dockerignore and .gitignore - everything you need to ignore is located on the new line.

Finally - the complete Earthfile

VERSION 0.6
FROM node:latest
WORKDIR /app
ARG image_name=blog

deps:
  RUN npm install -g pnpm
  COPY package.json pnpm-lock.yaml* ./
  RUN pnpm install
  SAVE ARTIFACT package.json   AS LOCAL ./package.json
  SAVE ARTIFACT pnpm-lock.yaml AS LOCAL ./pnpm-lock.yaml
  RUN pnpm add object-hash potrace find-cache-dir @astropub/codecs file-type

build:
  FROM +deps
  COPY . .
  RUN pnpm run build
  SAVE ARTIFACT dist /dist AS LOCAL dist

docker:
  FROM nginx
  COPY +build/dist /usr/share/nginx/html
  EXPOSE 80
  SAVE IMAGE --push ${image_name}:latest

and .earthlyignore

node_modules
.git
.gitignore
.earthlyignore
.idea
.vscode
dist