Platform.sh container lifecycle
Normally Lando expects containers to undergo a lifecycle like:
- Pre-start build steps run if applicable
- Container starts
In docker-compose
terms this is generally something like:
# If there are build steps
docker-compose up
docker-compose exec appserver command1
...
docker-compose exec database command3
docker-compose kill
# Start the app
docker-compose up
Platform.sh containers have a more complex lifecycle
- The container is BOOTed
- The container undergoes a BUILD
- The container is STARTed
- The containers are OPENed
There are other assumptions these containers have that are provided by platform.sh's actual orchestration layer. As we do not have that layer available locally we seek to "spoof" some of those things.
Most of these things are handled by a python
utility called the platformsh.agent
. There are also useful wrapper scripts, utilities, templates etc that can be found in /etc/platform
inside each platform.sh container.
Here are some key things to know about each step and what Lando does to change them.
BOOT
- BOOT unmounts
/etc/hosts
and/etc/resolv.conf
. This stops Docker from controlling them so platform can - BOOT will setup and prepare any needed directories
- BOOT will run
runsvdir
on/etc/services/
- BOOT will send a ping to a spoofed RPC agent to mimic what platform expects
- BOOT will finish by running
/etc/platform/boot
Lando puts all this logic in scripts/psh-boot.sh
and uses it for both the BOOT
and START
phases by putting it into /scripts
inside of each container. Lando's entrypoint script will run anything it finds in this directory before it hands off to the "main" process/command. Also note that /etc/platform/boot
will finish by handing off to /etc/platform/start
.
Additionally, Lando will run scripts/psh-recreate-users.sh
before anything else. This script handles host:container permission mapping.
On platform.sh application containers run as web:x:10000:10000::/app:/bin/bash
and most services run as app:x:1000:1000::/app:/bin/bash
. However locally we need whatever user is running process 1 to match the host (eg yours) uid and groupid.
BUILD
The platform.sh BUILD step uses an internal Lando build
step behind the scenes. This means it:
- Only runs on the initial
lando start
and subsequentlando rebuilds
- Runs before the container STARTS and before any user-defined build steps
The BUILD step will use scripts/psh-build.sh
. This has a few differences from Platform
- BUILD will set
$HOME
to/var/www
instead of/app
so build artifacts/caches dont potentially in your git repo - BUILD will install the platform CLI first if it needs to
- BUILD will use
platform local:build
(for now) instead of the underlying/etc/platform/build
START
Start has a similar lifecycle to BOOT
except that it ends by running /etc/platform/start
instead of /etc/platform/boot
.
Once /etc/platform/start
finishes the main process/command is run. This is exec init
for all containers. At this point each container should have a main process running and that process shuold be controlling a bunch of other processes eg php-fpm
and nginx
in the case of a php
container.
However, these containers are all "living in the dark" and need to be OPENed so they can both talk to one another and handle requests.
OPEN
OPEN is the step that most diverges from what Lando expects in that it requires Lando do additional things AFTER an app has started. Usually once an app has started Lando expects its ready to go. This is not the case for platform. Generally the flow that needs to happen here is:
- Lando needs to OPEN each platform service eg non-application containers
- Lando needs to collect the output from all these commands together
- Lando needs to merge in additional data its previously collected such as the IP addresses of services
- Lando then needs to inject this payload when it OPENs the application containers
Once this has completed each application container will be "open for business" and ready to handle requests. This is also required to set PLATFORM_RELATIONSHIPS
which is very important so applications can easily connect to services.
Behind the scenes we use the helper script scripts/psh-open.sh
. We also do the open logic in app.js
in a post-start
event.