# Structuring Applications with Multiple Services

Below are a few tips on how to efficiently structure applications consisting of multiple containers, which are described in more detail down below:

1. Package your services that are docker images into a single application. This ensures that the user only needs to handle a single `.auterionos` file.
2. Write a common base `Dockerfile` for a shared environment used by your services. This ensures that the resulting `.auterionos` file, as well as the storage space requirements after installation are as low as possible.

## Packaging multiple micro-services into one application

While your app can be composed of multiple docker containers, we advise that they are all packaged into a single Application. The user should only need to handle a single `.auterionos` file when installing or updating your application. This brings a few benefits:

* You can specify the launch order of the individual docker containers, in case some services rely on others
* You can provide all your services at the exact version required for a specific release of the application
* There is no risk of your application being installed incompletely
* There is no risk of your application being updated only partially, resulting in a mismatch of the services inside

### Makefile

Build and tag the required docker images / micro-services in the [Makefile](/app-development/legacy-app-workflow/application-development-guide.md#makefile):

```
build-camera-control:
	docker build --platform=arm64 ./src/camera-control -t camera-control:1.0.0

build-gallery-service:
	docker build --platform=arm64 ./src/gallery-service -t gallery-service:1.0.0
```

In the Makefile's target rule for building your application, you need to export all services as a single image, for example:

```makefile
build: build-camera-control build-gallery-service
	docker save camera-control:1.0.0 gallery-service:1.0.0 | gzip > gallery.image
```

### App.yml

Last but not least include all services the [app.yml](https://docs.auterion.com/app-development/app-framework/pages/huH0u8NqDLe8ajRgPL73#app.yml) file:

```yaml
version: '3.7'
services:
  camera-control:
    image: camera-control:#VERSION#
    container_name: camera-control
  gallery-service:
    image: gallery-service:#VERSION#
    container_name: gallery-service
```

Take a look at the [Photo Gallery example application](/app-development/legacy-app-workflow/examples.md#photo-gallery) to see this in action.

## Leveraging Docker layers to save resources

Docker builds its images using layers. Images that share the same base image can therefore reuse its layers, thus saving storage space. More details can be found in [Docker's official documentation](https://docs.docker.com/get-started/overview/#images).

In the context of Skynode and AuterionOS, identifying, breaking out and reusing base images in your application brings the following advantages:

* Your app uses less space on Skynode, because the base needs to be stored only once in Docker
* Smaller download size of your app, which saves time and bandwidth for downloading files, and speeds up the installation process. This benefit is only achieved when all [micro-services are packaged together](#packaging-multiple-micro-services-into-one-application).

{% hint style="info" %}
The example below uses a custom base image. The same principle can be applied when most of your services inherit from an existing public image such as "arm64v8/python:buster" for example.
{% endhint %}

### Example folder structure

Example folder structure using a base Dockerfile and services:

```bash
.
├── app.yml
├── Makefile
└── src
    ├── Dockerfile.base
    ├── service-1
    │   ├── app.py
    │   └── Dockerfile
    └── service-2
        ├── app.py
        └── Dockerfile

```

### Dockerfiles

Create Dockerfile.base that defines a common environment for your micro-service's images:

{% code title="Dockerfile.base" %}

```docker
FROM arm64v8/ubuntu:focal

ARG DEBIAN_FRONTEND=noninteractive

# Install common dependencies for the micro-services
RUN apt-get update \
    ...
```

{% endcode %}

Create one Dockerfile for each of your services and reuse the base image:

{% code title="src/service-\[1,2]/Dockerfile" %}

```docker
FROM my-arm64-base

ARG DEBIAN_FRONTEND=noninteractive

# Install dependencies specific to this service
RUN apt-get update \
    ...
```

{% endcode %}

### Makefile

In the Makefile, build the base image as well as your services:

```
build-base:
	docker build --platform=arm64 ./src -f src/Dockerfile.base -t my-arm64-base
  
build-service-1:
	docker build --platform=arm64 ./src/service-1 -t service-1:1.0.0
  
build-service-2:
	docker build --platform=arm64 ./src/service-2 -t service-2:1.0.0
```

Combine the use of base images with the method for [packaging multiple micro-services into one application](#packaging-multiple-micro-services-into-one-application) to achieve the most compact **.auterionos** files.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.auterion.com/app-development/app-framework/structuring-applications-with-multiple-services.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
