Project: Lagoon (App Definition and Development / Application Definition & Image Build)
File: lagoon-yml.md

The `.lagoon.yml` file is the central file to set up your project. It contains configuration in order to do the following: . . . . . The `.lagoon.yml` file must be placed at the root of your Git repository. Tells the build script which Docker Compose YAML file should be used, in order to learn which services and containers should be deployed. This defaults to `docker-compose.yml`, but could be used for a specific Lagoon Docker Compose YAML file if needed. This setting allows you to enable injecting the deployed Git SHA into your project as an environment variable. By default this is disabled. Setting the value to `true` sets the SHA as the environment variable `LAGOONGITSHA`. Routes are used to direct traffic to services. Each service in an environnment can have routes, in which the domain names are defined manually or automatically. The top level `routes` section applies to all routes in all environments. This allows you to configure automatically created routes. [Manual routes](#environmentsnameroutes) are defined per environment. `enabled`: Set to `false` to disable autogenerated routes. Default is `true`. `allowPullrequests`: Set to `true` to override `enabled: false` for pull requests. ```yaml title=".lagoon.yml" routes: autogenerate: enabled: false allowPullrequests: true ``` `insecure`: Configures HTTP connections. Default is `Allow`. `Allow`: Route will respond to HTTP and HTTPS. `Redirect`: Route will redirect any HTTP request to HTTPS. `prefixes`: Configure prefixes for the autogenerated routes of each environment. This is useful for things like language prefix domains, or a multi-domain site using the Drupal `domain` module. ```yaml title=".lagoon.yml" routes: autogenerate: prefixes: www de fr it ``` There are different type of tasks you can define, and they differ in when exactly they are executed in a build flow: Here you can specify tasks which will run against your project after all images have been successfully built, but before: Any running containers are updated with the newly built images. Any other changes are made to your existing environment. This feature enables you to, for example, create a database dump before updating your application. This can make it easier to roll back in case of a problem with the deploy. !!! Info The pre-rollout tasks run in the existing pods before they are updated, which means: Changes made to your Dockerfile since the last deploy will not be visible when pre-rollout tasks run. If there are no existing containers (e.g. on the initial deployment of a new environment), pre-rollout tasks are skipped. Here you can specify tasks which need to run against your project, after: All images have been successfully built. All containers are updated with the new images. All containers are running have passed their readiness checks. Common uses for post-rollout tasks include running `drush updb`, `drush cim`, or clearing various caches. `name` The name is an arbitrary label for making it easier to identify each task in the logs. `command` Here you specify what command should run. These are run in the WORKDIR of each container, for Lagoon images this is `/app`. Keep this in mind if you need to `cd` into a specific location to run your task. `service` The service in which to run the task. If following our Drupal example, this will be the CLI container, as it has all your site code, files, and a connection to the database. Typically you do not need to change this. `container` If the service has multiple containers

`nginx-php`), you will need to specify which container in the pod to connect to (e.g. the `php` container within the `nginx` pod). `shell` In which shell the task should be run. By default `sh` is used, but if the container also has other shells \(like `bash`, you can define it here\). This is useful if you want to run some small if/else bash scripts within the post-rollouts. to learn how to write a script with multiple lines. `when` The "when" clause allows for the conditional running of tasks. It expects an expression that will evaluate to a true/false value which determines whether the task should be run. Note: If you would like to temporarily disable pre/post-rollout tasks during a deployment, you can set either of the following environment variables in the API at the project or environment level \(see how on \). `LAGOONPREROLLOUTDISABLED=true` `LAGOONPOSTROLLOUTDISABLED=true` Here are some useful examples of post-rollout tasks that you may want to use or adapt for your projects. Run only if Drupal not installed: ```bash title=".lagoon.yml" run: name: IF no Drupal installed command: | # (1) if tables=$(drush sqlq "show tables like 'node';") && [ -z "$tables" ]; then fi service: cli shell: bash ``` This shows how to create a multi-line command. Different tasks based on branch name: ```yaml title=".lagoon.yml" run: name: Different tasks based on branch name command: | service: cli when: LAGOONGITBRANCH != "production" ``` Run shell script: ```yaml title=".lagoon.yml" run: name: Run Script command: './scripts/script.sh' service: cli ``` Target specific container in pod: ```yaml title=".lagoon.yml" run: name: show php env variables command: env service: nginx container: php ``` Drupal & Drush 9: Sync database & files from master environment: ```bash title=".lagoon.yml" run: name: Sync DB and Files from master if we are not on master command: | if tables=$(drush sqlq 'show tables;') && [ -z "$tables" ]; then drush sql-sync @lagoon.master @self # (1) drush rsync @lagoon.master:%files @self:%files -- --omit-dir-times --no-perms --no-group --no-owner --chmod=ugo=rwX fi service: cli when: LAGOONENVIRONMENTTYPE != "production" ``` Make sure to use the correct aliases for your project here. Specify the number of monthly backups Lagoon should retain for your project's production environment\(s\). The global default is `1` if this value is not specified. Specify the number of weekly backups Lagoon should retain for your project's production environment\(s\). The global default is `6` if this value is not specified. Specify the number of daily backups Lagoon should retain for your project's production environment\(s\). The global default is `7` if this value is not specified. Specify the number of hourly backups Lagoon should retain for your project's production environment\(s\). The global default is `0` if this value is not specified. Specify the backup schedule for this project. Accepts cron-compatible syntax with the notable exception that the `Minute` block must be the letter `M`. Any other value in the `Minute` block will cause the Lagoon build to fail. This allows Lagoon to randomly choose a specific minute for these backups to happen, while users can specify the remainder of the schedule down to the hour. The global default is `M H(22-2) *` if this value is not specified. Take note that these backups will use the cluster's local timezone. Environment names match your deployed branches or pull requests. This allows for each environment to have a different config. In our example it will apply to the `main` and `staging` environment. <iframe width="560" height="315"

title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> Manual routes are domain names that are configured per environment to direct traffic to a service. Since all environments get [automatically created routes](#routesautogenerate) by default, it is typical that manual routes are only setup for the production environment, using the main domain of the project's website like `www.example.com`. !!! Tip Since Lagoon has no control over the manual routes, you'll need to ensure the DNS records are configured properly at your DNS provider. You can likely set a `CNAME` record to point to the automatic route. The first element after the environment is the target service, `nginx` in our example. This is how we identify which service incoming requests will be sent to. The simplest route is `example.com`, as seen in our [example `.lagoon.yml`](#example-lagoonyml) - you can see it has no additional configuration. This will assume that you want a Let's Encrypt certificate for your route and no redirect from HTTPS to HTTP. In the `"www.example.com"` example below, we see three more options (also notice the `:` at the end of the route and that the route is wrapped in `"`, that's important!): ```yaml title=".lagoon.yml" "www.example.com": tls-acme: true insecure: Redirect hstsEnabled: true ``` !!! Warning If you switch from `tls-acme: true` to `tls-acme: false` this will remove any previously generated certificates for this route. This could result in unexpected behaviour if you're using an external CDN and do any certificate pinning. `tls-acme`: Configures automatic TLS certificate generation via Let's Encrypt. Default is `true`, set to `false` to disable automatic certificates. `insecure`: Configures HTTP connections. Default is `Allow`. `Allow`: Route will respond to HTTP and HTTPS. `Redirect`: Route will redirect any HTTP request to HTTPS. `hstsEnabled`: Adds the `Strict-Transport-Security` header. Default is `false`. `hstsMaxAge`: Configures the `max-age` directive. Default is `31536000` (1 year). `hstsPreload`: Sets the `preload` directive. Default is `false`. `hstsIncludeSubdomains`: Sets the `includeSubDomains` directive. Default is `false`. !!! Info If you plan to switch from a SSL certificate signed by a Certificate Authority (CA) to a Let's Encrypt certificate, it's best to get in touch with your Lagoon administrator to oversee the transition. When is configured for your cluster \(Kubernetes or OpenShift\), Lagoon will inject annotations to each route/ingress for use by the `stakater/IngressControllerMonitor`. The default action is to monitor the homepage of the route. If you have a specific route to be monitored, this can be overridden by adding a `monitoring-path` to your route specification. A common use is to set up a path for monitoring which bypasses caching to give a more real-time monitoring of your site. ```yaml title=".lagoon.yml" "www.example.com": monitoring-path: "/bypass-cache" ``` !!! Warning Route/Ingress annotations are only supported by projects that deploy into clusters that run nginx-ingress controllers! Check with your Lagoon administrator if this is supported. `annotations` can be a YAML map of . This is specifically useful for easy redirects and other configurations. Some annotations are disallowed or partially restricted in Lagoon. The table below describes these rules. If your `.lagoon.yml` contains one of these annotations it will cause a build failure. | Annotation | Notes | | | | | `nginx.ingress.kubernetes.io/auth-snippet` | Disallowed | | `nginx.ingress.kubernetes.io/configuration-snippet` | Restricted to `rewrite`, `addheader`, `setrealip`, and `moreset_headers` directives. | | `nginx.ingress.kubernetes.io/modsecurity-snippet` | Disallowed | | `nginx.ingress.kubernetes.io/server-snippet` | Restricted to `rewrite`, `addheader`, `setrealip`, and `moreset_headers` directives. | | `nginx.ingress.kubernetes.io/stream-snippet` | Disallowed | |

| Disallowed | In this example any requests to `example.ch` will be redirected to `https://www.example.ch` while keeping folders or query parameters intact \(`example.com/folder?query` -&gt; `https://www.example.ch/folder?query`\). ```yaml title=".lagoon.yml" "example.ch": annotations: nginx.ingress.kubernetes.io/permanent-redirect: https://www.example.ch$request_uri www.example.ch ``` You can of course also redirect to any other URL not hosted on Lagoon, this will direct requests to `example.de` to `https://www.google.com` ```yaml title=".lagoon.yml" "example.de": annotations: nginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com ``` !!! warning Kubernetes will only process a single `nginx.ingress.kubernetes.io/server-snippet` annotation. Please ensure that if you use this annotation on a non-production environment route that you also include the `add_header X-Robots-Tag "noindex, nofollow";` annotation as part of your server-snippet. This is needed to stop robots from crawling development environments as the default server-snippet set to prevent this in development environments in the ingress templates will get overwritten with any `server-snippets` set in `.lagoon.yml`. Some configurations involve a reverse proxy \(like a CDN\) in front of the Kubernetes clusters. In these configurations, the IP of the reverse proxy will appear as the `REMOTEADDR` `HTTPXREALIP` `HTTPXFORWARDEDFOR` headers field in your applications. The original IP of the requester can be found in the `HTTPXORIGINALFORWARDED_FOR` header. If you want the original IP to appear in the `REMOTEADDR` `HTTPXREALIP` `HTTPXFORWARDED_FOR` headers, you need to tell the ingress which reverse proxy IPs you want to trust: ```yaml title=".lagoon.yml" "example.ch": annotations: nginx.ingress.kubernetes.io/server-snippet: | setrealip_from 1.2.3.4/32; ``` This example would trust the CIDR `1.2.3.4/32` \(the IP `1.2.3.4` in this case\). Therefore if there is a request sent to the Kubernetes cluster from the IP `1.2.3.4` the `X-Forwarded-For` Header is analyzed and its contents injected into `REMOTEADDR` `HTTPXREALIP` `HTTPXFORWARDED_FOR` headers. The Lagoon build process checks the `lagoon.type` label from the `docker-compose.yml` file in order to learn what type of service should be deployed \(read more about them in the \). Sometimes you might want to override the type just for a single environment, and not for all of them. For example, if you want a standalone MariaDB database \(instead of letting the Service Broker/operator provision a shared one\) for your non-production environment called `develop`: `service-name: service-type` `service-name` is the name of the service from `docker-compose.yml` you would like to override. `service-type` the type of the service you would like to use in your override. Example for setting up MariaDB\_Galera: ```yaml title=".lagoon.yml" environments: develop: types: mariadb: mariadb-single ``` The Lagoon build process checks the `lagoon.template` label from the `docker-compose.yml` file in order to check if the service needs a custom template file \(read more about them in the \). Sometimes you might want to override the template just for a single environment, and not for all of them: `service-name: template-file` `service-name` is the name of the service from `docker-compose.yml` you would like to override. `template-file` is the path and name of the template to use for this service in this environment. ```yaml title=".lagoon.yml" environments: main: templates: mariadb: mariadb.main.deployment.yml ``` The Lagoon build process checks the `lagoon.rollout` label from the `docker-compose.yml` file in order to check if the service needs a special rollout type \(read more about them in the \) Sometimes you might want to override the rollout type just for a single environment, especially if you also overwrote the template type for the environment: `service-name: rollout-type` `service-name` is the name of the service from `docker-compose.yml` you would like to override. `rollout-type` is the type of rollout. See \) for possible values. ```yaml

environments: main: rollouts: mariadb: statefulset ``` This allows for any environments to get autogenerated routes when route autogeneration is disabled. ```yaml title=".lagoon.yml" routes: autogenerate: enabled: false environments: develop: autogenerateRoutes: true ``` <iframe width="560" height="315" src="https://www.youtube.com/embed/Yd_JfDyfbR0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> Cron jobs must be defined explicitly for each environment, since it is typically not desirable to run the same ones for all environments. Depending on the defined schedule, cron jobs may run as a Kubernetes native `CronJob` or as an in-pod cron job via the crontab of the defined service. ```yaml title=".lagoon.yml" cronjobs: name: Hourly Drupal Cron schedule: "M " # Once per hour, at a random minute. command: drush cron service: cli name: Nightly Drupal Cron schedule: "M 0 *" # Once per day, at a random minute from 00:00 to 00:59. command: drush cron service: cli ``` `name`: Any name that will identify the purpose and distinguish it from other cron jobs. `schedule`: The schedule for executing the cron job. Lagoon uses an extended version of the crontab format. If you're not sure about the syntax, use a . You can specify `M` for the minute, and your cron job will run once per hour at a random minute (the same minute each hour), or `M/15` to run it every 15 mins, but with a random offset from the hour (like `6,21,36,51`). It is a good idea to spread out your cron jobs using this feature, rather than have them all fire off on minute `0`. You can specify `H` for the hour, and your cron job will run once per day at a random hour (the same hour every day), or `H(2-4)` to run it once per day within the hours of 2-4. !!! Info "Timezones:" The default timezone for cron jobs is UTC. Native cron jobs use the timezone of the node, which is UTC. In-pod cron jobs use the timezone of the defined service, which can be configured to something other than UTC. `command`: The command to execute. This executes in the `WORKDIR` of the service. For Lagoon images, this is `/app`. !!! warning Cronjobs may run in-pod, via crontab, which [doesn't support multiline commands](https://www.man7.org/linux/man-pages/man5/crontab.5.html). If you need a complex or multiline cron command, you must put it in a script that can be used as the command. Consider whether a would work. `service`: Which service of your project to run the command in. For most projects, this should be the `cli` service. In Lagoon, the same Git repository can be added to multiple projects, creating what is called a polysite. This allows you to run the same codebase, but allow for different, isolated, databases and persistent files. In `.lagoon.yml` , we currently only support specifying custom routes for a polysite project. The key difference from a standard project is that the `environments` becomes the second-level element, and the project name the top level. To utilize this, you will need to: Create two (or more) projects in Lagoon, each configured with the same Git URL and production branch, named per your .lagoon.yml (i.e `poly-project1` and `poly-project2` below) Add the deploy keys from each project to the Git repository. Configure the webhook for the repository (if required) - you can then push/deploy. Note that a push to the repository will simultaneously deploy all projects/branches for that Git URL. ```yaml title=".lagoon.yml" poly-project1: environments: main: routes: nginx: project1.com poly-project2: environments: main: routes: nginx:

``` ???+ Info If you run directly on amazee.io hosted Lagoon you will not need this key set. With the key `api` you can define another URL that should be used by the Lagoon CLI and `drush` to connect to the Lagoon GraphQL API. This needs to be a full URL with a scheme, like: `http://localhost:3000` This usually does not need to be changed, but there might be situations where your Lagoon administrator tells you to do so. ???+ Info If you run directly on amazee.io hosted Lagoon you will not need this key set. With the key `ssh` you can define another SSH endpoint that should be used by the Lagoon CLI and `drush` to connect to the Lagoon remote shell service. This needs to be a hostname and a port separated by a colon, like: `localhost:2020` This usually does not need to be changed, but there might be situations where your Lagoon administrator tells you to do so. The `container-registries` block allows you to define your own private container registries to pull custom or private images. To use a private container registry, you will need a `username`, `password`, and optionally the `url` for your registry. If you don't specify a `url` in your YAML, it will default to using Docker Hub. There are 2 ways to define the password used for your registry user. Create an environment variable in the Lagoon API with the type `container_registry`: `lagoon add variable -p <projectname> -N <registrypasswordvariablename> -V <passwordgoeshere> -S container_registry` \(see more on \) The name of the variable you create can then be set as the password: ```yaml title=".lagoon.yml" container-registries: my-custom-registry: username: myownregistryuser password: <registrypasswordvariable_name> url: my.own.registry.com ``` You can also define the password directly in the `.lagoon.yml` file in plain text: ```yaml title=".lagoon.yml" container-registries: docker-hub: username: dockerhubuser password: MySecretPassword ``` To consume a custom or private container registry image, you need to update the service inside your `docker-compose.yml` file to use a build context instead of defining an image: ```yaml title=".docker-compose.yml" services: mariadb: build: context: . dockerfile: Dockerfile.mariadb ``` Once the `docker-compose.yml` file has been updated to use a build, you need to create the `Dockerfile.<service>` and then set your private image as the `FROM <repo>/<name>:<tag>` ```yaml title=".lagoon.yml" FROM dockerhubuser/my-private-database:tag ``` This is an example `.lagoon.yml` which showcases all possible settings. You will need to adapt it to your project. ```yaml linenums="1" title=".lagoon.yml" docker-compose-yaml: docker-compose.yml environment_variables: git_sha: 'true' tasks: pre-rollout: run: name: drush sql-dump command: mkdir -p /app/web/sites/default/files/private/ && drush sql-dump --ordered-dump --gzip --result-file=/app/web/sites/default/files/private/pre-deploy-dump.sql.gz service: cli post-rollout: run: name: drush cim command: drush -y cim service: cli shell: bash run: name: drush cr command: drush -y cr service: cli routes: autogenerate: insecure: Redirect environments: main: routes: nginx: example.com example.net "www.example.com": tls-acme: true insecure: Redirect hstsEnabled: true "example.ch": annotations: nginx.ingress.kubernetes.io/permanent-redirect: https://www.example.ch$request_uri www.example.ch types: mariadb: mariadb templates: mariadb: mariadb.main.deployment.yml rollouts: mariadb: statefulset cronjobs: name: drush cron schedule: "M " # This will run the cron once per hour. command: drush cron service: cli staging: cronjobs: name: drush cron schedule: "M " # This will run the cron once per hour. command: drush cron service: cli feature/feature-branch: cronjobs: name: drush cron schedule: "H " # This will run the cron once per hour. command: drush cron service: cli ``` These settings have been deprecated and should be removed from use in your `.lagoon.yml`. `routes.autogenerate.insecure` The `None` option is equivalent to `Redirect`. `environments.[name].monitoring_urls` `environments.[name].routes.[service].[route].hsts` `environments.[name].routes.[service].[route].insecure` The `None` option is equivalent to `Redirect`.