Better builds with earthly
Tags: devops, tutorial, beginners, docker
Published: 2022-11-07 07:52:48

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](https://earthly.dev/) 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 

```bash
$ brew install earthly/earthly/earthly && earthly bootstrap
```

And that's it. If you are Linux or Windows user - you can check [this guide](https://earthly.dev/get-earthly).

## 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](https://astro.build)-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:

- deps - to download dependencies
- build - to build an application
- docker - do create and save docker image

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

```docker
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.

```docker
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`

  ```docker
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
```

Looking for more? Check my blog [https://alec-c4.com](https://alec-c4.com)