Lando Service
The lando
service is the lowest level api: 3
service available in Lando.
Generally you will want to use a more specific service like type: php
but this service can be good if you are:
- Thinking about contributing your own custom Lando service and just want to prototype something
- Using Docker Compose config from other projects
- Need a service not currently provided by Lando itself
It implements a super-set of the Docker Compose Version 3 Spec and usually requires some slight tweaks of existing Docker Compose configuration to work correctly.
Here is a birds-eye view of all its options:
Landofile
name: "my-app"
services:
my-service:
# set type and api
api: 3
type: lando
# these directly map to docker compose things
# see: https://docs.docker.com/reference/compose-file/
# note that these are only available if you invoke the service directly
services: {}
networks: {}
volumes: {}
# below are features available in every api 3 service
app_mount: cached
# build steps
build: []
build_as_root: []
run: []
run_as_root: []
# ssl
ssl: false
sslExpose: false
# other
meUser: www-data
moreHttpPorts: []
overrides: {}
Services, Networks, Volumes
These three: services,
networks
and volumes
map directly to the Docker Compose Version 3 Spec which means that the below is a valid Landofile:
Landofile
name: lampy
services:
appserver:
api: 3
type: lando
services:
image: php:8.2-apache
command: docker-php-entrypoint apache2-foreground
ports:
- 80
database:
api: 3
type: lando
services:
image: mariadb:10.4
command: docker-entrypoint.sh mysqld
Note that services
, volumes
and networks
are only available if you use this service
directly with type: lando
. If you are in an upstream service we recommend you use overrides
.
Also note that there are a few caveats and behavioral considerations you should be aware of while using the above:
App Mount
Lando will automatically mount your codebase in every container at /app
using the :cached
performance optimization flag. However, you can change the mount flag on a per-service basis or disable the mount entirely if you so choose.
Do not mount my application code
Set app_mount
to either false
or disabled
.
Landofile
services:
my-service:
api: 3
type: lando
app_mount: false
services:
image: php:8.2-apache
command: docker-php-entrypoint apache2-foreground
my-service2:
api: 3
type: lando
app_mount: disabled
services:
image: php:8.2-apache
command: docker-php-entrypoint apache2-foreground
Mount with a different flag
Set app_mount
to any valid Docker bind mount third field.
Landofile
services:
my-service:
api: 3
type: lando
app_mount: ro
services:
image: php:8.2-apache
command: docker-php-entrypoint apache2-foreground
my-service2:
api: 3
type: lando
app_mount: delegated
services:
image: php:8.2-apache
command: docker-php-entrypoint apache2-foreground
Build Steps
One of the great features of Lando is its ability to destroy a single planet... we mean add additional dependencies or build steps to your service without the hassle of having to build or manage your own Dockerfiles.
Note that build steps will ONLY RUN THE FIRST TIME YOU SPIN UP YOUR APP. That means if you change them, you will need to run lando rebuild
for them to re-run. An exception to this is if one or more of your build steps error. When this happens Lando will run the build steps on every subsequent lando start
until they complete without error.
When should I use build steps?
If you need additional on-server dependencies like php extensions or node modules, it sounds like a build step may be for you. If you have automation, you want to run EVERY TIME and you may want to consider using events instead.
There are four major build steps.
build
runs as "you" and before your service boots upbuild_as_root
runs asroot
and before your service boots uprun
runs as "you" and after your service boots uprun_as_root
runs asroot
and after your service boots up
An example to consider is shown below:
Landofile
services:
appserver:
api: 3
type: lando
services:
image: php:8.2-apache
command: docker-php-entrypoint apache2-foreground
build_as_root:
- apt-get update -y && apt-get install -y libmemcached-dev
- pecl install memcached
- docker-php-ext-enable memcached
run:
- composer install
node:
api: 3
type: lando
services:
image: node:16
command: yarn dev
build:
- yarn
run:
- /helpers/some-helper-script.sh
run_as_root:
- echo "127.0.0.1 mysite.lndo.site" >> /etc/hosts
As you can likely surmise from the above, each step is intended for a pretty specific use case:
- Use
build
to install application dependencies that are needed before you start your application - Use
build_as_root
to install low level server packages required by your application - Use
run
to install application dependencies or run build steps that require your application be started first - Use
run_as_root
for any other post-startroot
level one-time setup commands.
Of course, these steps must make sense within the context of the container you are running them in. For example, you will not be able to run dnf
inside of a debian
flavored container.
Also, note that the default working directory that the commands run in inside the container is /app
.
Another potential consideration is "dependent commands". Each line of a build step runs in a separate subshell; so if COMMAND B is dependent on something provided by COMMAND A such as sourcing
a file, you should combine the commands with &&
and put them on a single line.
Using SCRIPTY things
While the following example can work, please note that it is NOT SUPPORTED.
run:
- |
if [ ! -z $LANDO_MOUNT ]; then
do something
some other command
fi
In these situations, it is highly recommended you create a script and reference that instead. This keeps things cleaner and more portable.
#!/bin/bash
if [ ! -z $LANDO_MOUNT ]; then
do something
some other command
fi
run:
- /app/my-script.sh
Using Dockerfiles
If you find that your build steps are approaching the length of Herman Melville's seminal work Moby Dick, you can use overrides to build directly from a Dockerfile instead.
This can keep your Landofile tidy and has the added benefit of your service being shippable like any Dockerfile.
An example that extends our base php
image to add another extension is shown below:
Landofile
Note that build
is going to be relative to your app root.
services:
appserver:
api: 3
type: lando
overrides:
build: ./php
image: pirog/php:8.2-fpm-custom
Dockerfile
This lives inside of the ./php
directory referenced in the build
above.
FROM devwithlando/php:8.2-fpm
RUN apt-get update -y \
&& docker-php-ext-install pcntl
Entrypoint
By default, Lando will hijack the containers entrypoint
as this is how it serves its secret sauce. This does introduce some different behavior when setting the command of your service.
You can, however, set a different entrypoint.
Landofile
services:
appserver:
api: 3
type: lando
entrypoint: docker-php-entrypoint
services:
image: php:8.2-apache
command: apache2-foreground
Note that the above example will lose any Lando functionality that is provided by our default entrypoint
.
Healthcheck
Since Lando 3.20.0 service URL scanning is in its own plugin.
Localhost Assignment
By default Lando will attempt to assign localhost
addresses to any service that has ports 80
or 443
exposed. You can tell Lando to assign localhost
addresses to additional http
ports with the following.
Landofile
services:
my-service:
api: 3
type: lando
moreHttpPorts:
- 8888
services:
image: php:8.2-apache
command: apache2-foreground
ports:
- 8888
Note that if you are adding additional moreHttpPorts
you must also make sure that port
is exposed as in the example above.
meUser
For the purposes of things like events and tooling you may wish to set the "non-root" user to run commands as "you".
Landofile
services:
my-service:
api: 3
type: lando
meUser: node
services:
image: node:16
command: npm start
By default meUser
is set to www-data
which exists in most services by default.
SSL
You can tell Lando to create certificates to use with ssl: true
. This will also automatically expose the sport
which is 443
by default. The certificates will live in /certs/*
inside the container.
Landofile
services:
my-service:
api: 3
type: lando
# generate certificates
ssl: true
# expose this "secure port"
sport: 3001
# set to false to disable sport exposure
sslExpose: true
services:
image: node:16
command: npm start --https 3001
Note that this does not automatically set up the service to use the certs, it merely creates the certs and exposes some ports. It is up to you to configure your service correctly to use them.
Also note that cert creation requires running the service as the root
user. To work around this limitation check out this.
URL Scanning
Since Lando 3.14.0 service URL scanning is in its own plugin.
Overrides
Lando services are just an abstraction layer on top of the Docker compose v3 file format. What this means is that behind the scenes your Landofile is being translated into a SHLOAD of SUPERNASTY looking docker-compose
files which are then being used to power your app.
We give you access to the Docker Compose layer with the overrides
key.
You can only override Docker Compose's top-level services
config
Overrides you specify get merged and injected directly into the services
config used by Docker Compose. This means that you cannot use overrides to alter top level networks
or volumes
.
Also note that if you are using this service directly it probably makes more sense to just use services
, networks
and volumes
directly. overrides
is really meant to be used in downstream services as in the example below:
Landofile
services:
html:
api: 3
# note that setting custom as the service version
# will automatically skip landos "supported" check
type: apache:custom
overrides:
environment:
STUFF: THINGS
THINGS: GUYS
image: pirog/myapache:2
volumes:
- ./mythings:/tmp/mythings
Caveats
Setting the command
By default, Lando will hijack the containers entrypoint
as this is how it serves its secret sauce.
However, this means if your custom container sets its own entrypoint, you will need to remove that entrypoint and set it as the first argument in the command
.
In the example below, docker-php-entrypoint
is the default entrypoint
for the drupal:8
image but we have moved it so that it is the first argument of command
. This both allows the container to run as expected and allows Lando to do its thing.
Landofile
services:
custom-service:
api: 3
type: lando
services:
image: drupal:8
ports:
- '80'
# Required. See Below
command: docker-php-entrypoint apache2-foreground
You can probably force the original container behavior and by extention forego the Lando magic by explicitly resetting the entrypoint.
Setting the app mount
Many Docker images will put code in /app
. This directly conflicts with Lando's default codebase mount point. If you are running into a problem because of this collision, we recommend you disable the app_mount
by setting it to false
or disabled
.
This will prevent Lando from mounting your codebase to /app
so the Docker image can use its own code at /app
.
Landofile
services:
pghero:
api: 3
type: lando
app_mount: false
services:
image: ankane/pghero
command: puma -C config/puma.rb
Choosing the user
Many non-Lando containers do not run as the root
user by default. This is OK but comes with a few caveats. The most relevant are that Lando will not be able to execute its normal boot up steps which:
- Map
host:container
user permissions - Generate a certificate for the service
- Load user and lando managed SSH keys
Also note that containers that do not have bash
installed, like some alpine
ones, will similarly not be able to load up SSH keys.
These factors may or may not be relevant depending on what you are doing so they are here just as a FYI.
If you are using a container that cannot run as root
but still want that Lando magic you can try something like below.
Landofile
services:
custom-service:
api: 3
type: lando
services:
user: root
image: drupal:8
# Required. See Below
command: docker-php-entrypoint apache2-foreground
ports:
- '80'
environment:
LANDO_DROP_USER: otheruser
volumes:
my-volume:
networks:
my-network:
The relevant pieces here are setting user: root
and then the environment variable LANDO_DROP_USER
to whatever user the container is suppose to run as.
In this example the container will boot as root
do the Lando things it needs to do and then run docker-php-entrypoint apache2-foreground
as otheruser
.
Examples
Almost all of the core tests use this service.