L-337 Service
The l337
service is the lowest level api: 4
service and it implements Lando Specification 337. It is so low level that it's too low to be the default service so you need to set type: l337
to use it.
You're low, go high
This is the lowest-level abstraction in Lando; we do not recommend using it directly.
If you are looking to build your own service or just need a generic service type you'll probably want to start with the Lando Service.
In high level terms it combines service orchestration and image specification into a single format.
Specifically, it is a light superset around the Docker Compose Version 3 format that also uses the Dockerfile specification.
This means that you should be able to paste Docker Compose content into your Landofile, add api: 4
to each service and have it "just work".
WORKS WITH MORE THAN JUST DOCKER!
The adoption of the Docker Compose and Dockerfile formats is purely for specification/meta purposes and does not mean Lando 4 can only be used with Docker.
That said Docker and Docker Compose are the default Lando 4 build engine and orchestrator, respectively.
As noted above Lando Specification 337 extends the Docker Compose 3 spec with Dockerfile stuff. That means that everything in both of those specs is supported by default. So this is a valid Landofile:
Landofile
name: "my-app"
services:
# this is a Lando 3 php service
php:
type: "php:7.4"
api: 3
# these are Lando 4 "l337" services
web:
api: 4
type: l337
image: "nginx:1.15"
networks:
my-network:
volumes:
- "./:/app"
- "my-data:/data"
db:
api: 4
type: l337
build:
dockerfile: "./Dockerfile"
networks:
my-network:
volumes:
my-data:
OK cool, got it, but how does Dockerfile stuff factor in?
What is actually different in the spec besides api
?
Two questions. One Answer: image
... and that's it.
Image
Lando Specification 337 is identical to the Docker Compose spec with the exception of the image
key which now handles different string inputs and has an extended object format for MOAR POWAH.
The string input for image
has been extended and now allows the below:
Landofile
name: "my-app"
services:
# a valid registry image, eg the original Docker Compose usage
example-1:
api: 4
type: l337
image: "nginx:1.21"
# a path to a Dockerfile compatible file
example-2:
api: 4
type: l337
image: "./images/nginx/Dockerfile"
# raw Dockerfile compatible instructions
example-3:
api: 4
type: l337
image: |
FROM nginx:1.21
ENV HELLO there
...
CMD run-stuff
You can extend image
into object format to get access to more features. Here is an example that implements all the keys available in object format.
Landofile
name: "my-app"
services:
example-1:
api: 4
type: l337
image:
imagefile: "nginx:1.21"
tag: "pirog/nginx:1.21"
context:
- "./nginx.conf:/etc/nginx/conf.d/default.conf"
groups:
- reallllllearly: -8675309
steps:
- instructions: "RUN id > /tmp/user"
group: "reallllllearly"
- instructions: |
ENV VIBES rising
RUN echo "hello" id > /var/ww/index.html
group: "reallllllearly-10-before-root"
Imagefile
The image
string notation format above actually populates the imagefile
key behind the scenes. For that reason, this usage is the same as above but with a different key.
Use context instead of COPY/ADD
While you can use COPY
and ADD
instructions here we recommend you use context
instead. See this for more information.
Landofile
name: "my-app"
services:
# a valid registry image
example-1:
api: 4
type: l337
image:
imagefile: nginx:1.21
# a path to a Dockerfile compatible file
example-2:
api: 4
type: l337
image:
imagefile: ./images/nginx/Dockerfile
# raw Dockerfile compatible instructions
example-3:
api: 4
type: l337
image:
imagefile: |
FROM nginx:1.21
ENV HELLO there
...
CMD run-stuff
Note that you can also use dockerfile
instead of imagefile
if you prefer that usage. If you use both imagefile
will win.
Tag
If you wish to force Lando to use a particular tag on successful image creation, you can.
Landofile
name: "my-app"
services:
tag-me-bro:
api: 4
type: l337
image:
imagefile: |
FROM nginx:1.21
ENV SERVER=apache
ENV CONFUSED=true
tag: "loki/apache:1.21"
Context
If you would like to COPY
and/or ADD
files into your build context and image then use context
. Many forms and options are supported:
Landofile
name: "my-app"
services:
example-1:
api: 4
type: l337
image:
imagefile: "nginx:1.21"
context:
# COPY ./folder to /folder
- "./folder"
# COPY ./folder to /thing
- "./folder:thing"
# COPY file1 to /file2
- "file1:/file2"
# COPY file1 to /file3
- src: "file1"
dest: "file3"
# COPY file1 to /file4
- source: "file1"
destination: "file4"
# COPY ./images/Dockerfile to /images/Dockerfile
- source: "./images/Dockerfile"
# COPY file1 to /file6 and set ownership to nginx:nginx
- source: "file1"
destination: "file6"
owner: "nginx:nginx"
# COPY file1 to /file7 and set ownership to nginx:nginx
- source: "file1"
destination: "file7"
user: "nginx"
group: "nginx"
# ADD HeresAHealthToTheCompany.json
# to /SeaShanties/lyrics/main/shanties/HeresAHealthToTheCompany.json
- source: "https://raw.githubusercontent.com/SeaShanties/lyrics/main/shanties/HeresAHealthToTheCompany.json"
# ADD available-shanties.json
# to /etc/config/available-shanties.json and set ownership to blackbeard
- source: "https://raw.githubusercontent.com/SeaShanties/lyrics/main/available-shanties.json"
dest: "/etc/config/available-shanties.json"
owner: "eddie-teach"
Groups
groups
allow you to organize steps
.
By default every l337
service has two groups, default
and context
, with the following values:
context:
description: "A group for adding and copying sources to the image"
weight: 0
user: "root"
default:
description: "A default general purpose build group around which other groups can be added"
weight: 1000
user: "root"
You can add additional groups into your Landofile and then use them in your steps
.
Landofile
name: "my-app"
services:
example-1:
api: 4
type: l337
image:
imagefile: "nginx:1.21"
groups:
# adds a group called "val-jean" with weight "24601"
# uses root user by default
- val-jean: 24601
# adds a root user group called "system" that runs first
- name: "system"
description: "Install system packages and stuff"
weight: -10000
user: "root"
# adds a nginx user group called "user" that runs last
- name: "user"
description: "Allows for user run commands after other groups"
weight: 10000
user: "nginx"
Steps
While you can specify an entire Imagefile's contents directly in image.imagefile
it's often better to use steps
which are ordered and partial Dockerfile-compatible instructions.
Because steps
are wrapped in a standardized and ordered layer, Lando and any of its plugins can insert instructions
into the resulting imagefile
wherever they make the most sense. This allows for great flexibility.
However, we are mostly interested here in how steps
can be used directly in a Landofile.
Landofile
name: "my-app"
services:
example-1:
api: 4
type: l337
image:
imagefile: "nginx:1.21"
groups:
... # as defined [above](#groups) and omitted here for brevity
steps:
# insert string instructions into the default group
- instructions: |
ENV VIBES RISING
RUN apt-get update -y
RUN /my-script.sh
# insert array format instructions into the default group
# See: https://www.npmjs.com/package/dockerfile-generator for syntax
- instructions:
- env:
KIRK: "wesley"
SPOCK: "peck"
- run: "env"
- run:
- "stat"
- "/tmp"
# insert group detached, one-off, singleton, instructions
# at arbitrary weight
- instructions: "ENV PIKE mount"
weight: 1001
- instructions: |
RUN echo "last" >> /stuff
weight: 999
- instructions: |
RUN echo "first" >> /stuff
weight: 1
# insert instructions into groups
- instructions: |
ENV KIRK pine
ENV SPOCK quinto
RUN id > /system-user
group: "system"
- instructions: "RUN id > /tmp/user"
group: "user"
# insert instructions using group-override format
# runs -4 weight units before the system group
- instructions: |
ENV KIRK shatner
ENV SPOCK nimoy
group: "system-4-before"
# run 10 weight units after the user group but uses the root user
- instructions: |
ENV KIRK shatner
ENV SPOCK nimoy
group: "user-10-root"
Note that if you specify both a group
and a weight
the step will run at the weight
regardless of the weight of the group. Generally it's a good idea to not use both group
and weight
in the same step.
If you reference a group
that does not exist then the default
group will be used.
COPY/ADD
While you can use COPY
and ADD
instructions here we recommend you use context
instead. See this for more information.
Override syntax
The group override syntax is flexible as long as the parent group is first. For example the following overrides are equivalent:
system-2
system-2-after
system-root-after-2
system-2-after-root
system-root-2-after
That said, we like the GROUP-OFFSET-DIRECTION-USER
format. 😉
Also note that it is totally possible to have defined two groups
like system
and system-4
. In this scenario a step
using the system-4
group will actually use the system-4
group and not override the system
group with a 4-after
offset.
Since this can easily get confusing it's best to be careful when defining your group names.
Caveats
As you may have already suspected because the l337
service sits below the main lando
service it lacks ALL the features in that service. Using it is pretty close to just using Docker Compose/Dockerfiles straight up.
Said another way, you should really only use this service directly if you are intentionally looking to avoid normal Lando features or want to use something that is more-or-less like Docker Compose.
That said, here are the things that make it pretty close but identical to Docker Compose/Dockerfiles:
1. Auto app mount discovery
If you volume
mount your app root directory then Lando will assume its mount destination as the app mount for tooling purposes. Consider the following example:
Landofile
name: "my-app"
services:
my-service:
api: 4
type: l337
image: "php:8.2-cli"
volumes:
- "./:/home"
tooling:
pwd:
service: "my-service"
Note that changing the directory on the host also changes the location at which lando pwd
is executed within the container:
lando pwd
# /home
cd subdir && lando pwd
# /home/subdir
2. Working dir support
If you do not mount your app root directory as above then Lando will use working_dir
to set the default tooling dir
for that service.
Landofile
name: "my-app"
services:
my-service:
api: 4
type: l337
image: "php:8.2-cli"
working_dir: "/var/www"
tooling:
pwd:
service: "my-service"
Note that lando pwd
still executes in the working_dir
location, even though we change directories on the host machine:
lando pwd
# /var/www
cd subdir && lando pwd
# /var/www
3. COPY & ADD considerations
While you can use the COPY
and ADD
instructions in various places in the l337
service we recommend you use our context
convention instead. The tl;dr
there is it will be more performant.
The full explanation is that if Lando detects a COPY
or ADD
instruction it will automatically copy the entire application root into the build context. So if you have a BIG app this can drastically slow build performance.
If for some reason you need COPY/ADD
to work eg you are basing your service on some preexisting Dockerfile with some build assets then we recommend you copy the build assets and Dockerfile into a subfolder and build from there. In this case only the files in that subfolder will be used and not the entire application.
Examples
If you would like to look at concrete and tested examples you can check out the below: