# Selectively running containers on a device

**URL:** <https://forums.balena.io/t/selectively-running-containers-on-a-device/16086>\
**Category:** balenaOS\
**Tags:** raspberrypi3, docker, docker-compose\
**Created:** [June 18, 2019, 8:35pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086 "2019-06-18T20:35:30Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Craigson](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@Craigson](https://forums.balena.io/u/Craigson)\
**Post date:** [June 18, 2019, 8:35pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086/1 "2019-06-18T20:35:30Z")

</div>

I figured I’d pose the question here first before descending down a rabbit hole. Here’s the hypothetical situation. I have two devices, `deviceOne` and `deviceTwo`, both of which are a Rpi3 running BalenaOS.

Both devices run the same BalenaCloud application, however each has a different functional use. Eg. `deviceOne` has a screen attached and `deviceTwo` reads a sensor. I have two services that run as part of the app, let’s call them `kiosk` and `sensor`. In theory, both devices run both services, each in a separate container. However, there’s no real need for `deviceTwo` to run the `kiosk` service as it has no screen attached, and vice versa for `deviceOne`. To save on resources, I’d like to selectively decide which service to run on each device, probably using a device ENV variable.

My thought process was this:

- create a third service and call it something like `boot-manager`, have this service depend\_on `kiosk` and `sensor` to ensure it launches last. When the container runs, run a script that sends a request to the supervisor API stopping the container that isn’t required (determined by reading of the device ENV, eg. `RUN_KIOSK=0`.

Is there a better way to do this? How do people usually tackle this problem?

Thanks!

---

<div class="post-metadata">

**Author:** ![dt-rush](https://sea2.discourse-cdn.com/balena/user_avatar/forums.balena.io/dt-rush/32/1405_2.png) [@dt-rush](https://forums.balena.io/u/dt-rush)\
**Post date:** [June 18, 2019, 9:24pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086/11 "2019-06-18T21:24:09Z")

</div>

Thanks for your question. I’m currently discussing this with a colleague and we will shortly have a reply laying out some options to consider.

---

<div class="post-metadata">

**Author:** ![dt-rush](https://sea2.discourse-cdn.com/balena/user_avatar/forums.balena.io/dt-rush/32/1405_2.png) [@dt-rush](https://forums.balena.io/u/dt-rush)\
**Post date:** [June 18, 2019, 11:26pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086/19 "2019-06-18T23:26:33Z")

</div>

Thanks for your patience! After discussing it thoroughly and testing on devices, I believe we have some good options for this specific case (and at the end, we discuss why this issue has not come up before, or doesn’t appear to have come up, from searching the forums).

Idea 1:

Do a kind of inverse of what you describe: Have the services optionally stop _themselves_ on start after checking the env var, no need for a third manager service or interfacing with balena engine, etc. You should have `restart: "no"` in the service definition in `docker-compose.yml`, something like this:

```auto
version: '2'
services:
  kiosk:
    restart: "no"
    build: ./kiosk
  sensor:
    restart: "no"
    build: ./sensor

```

and then in the service, you’d have, top level in the entrypoint script (say we were using nodejs):

```auto
if (process.env['IS_SENSOR']) {
    // code to run service ...
} else {
    console.log('sensor not starting, did not find env var');
}

```

Idea 2:

Of course if you wanted to make a manager service for the sake of more control (I don’t know whether this is useful to you as you go on, or whether the simplest solution is best), you could take a look at the supervisor API [1].

Idea 3:

A final option is simply to deploy two separate applications. This would save the unused disk-space / network bandwidth of downloading and storing container images which won’t run. I would use a setup like you requested initially only in the case that I wanted to swap a device between sensor and kiosk mode in the field. If it’s determined when they’re shipped, then better to simply separate at the layer of application. This is the most common pattern and likely is used for this reason in preference to runtime “polymorphism”.

Let us know if you have any questions subsequent on this! We’ll be glad to assist.

[1] [https://github.com/balena-io/balena-supervisor/blob/master/docs/API.md#service-actions](https://github.com/balena-io/balena-supervisor/blob/master/docs/API.md#service-actions)

---

<div class="post-metadata">

**Author:** ![Craigson](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@Craigson](https://forums.balena.io/u/Craigson)\
**Post date:** [June 19, 2019, 4:56pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086/21 "2019-06-19T16:56:40Z")

</div>

@dt-rush thank you for the in-depth description. I understand this is a unique use-case, but the polymorphism is a necessity to manage a complex fleet of devices that are spread between multiple sites / customers. Updates should be infrequent, and the devices stream data to the cloud as opposed to storing it, so the disk usage and/or bandwidth are not a huge concern when compared to the complexity of the task of managing the devices.

I like the approach of Idea 1, however I have a question: it’s my understanding that the service will not start automatically if you have `restart: no` set in the docker-compose. How then is it expected to start the service in the entry point script. In other words, will the entry point script still run if the container is instantiated as “stopped”? Or am I misunderstanding?

---

<div class="post-metadata">

**Author:** ![shaunmulligan](https://sea2.discourse-cdn.com/balena/user_avatar/forums.balena.io/shaunmulligan/32/34_2.png) [@shaunmulligan](https://forums.balena.io/u/shaunmulligan)\
**Post date:** [June 19, 2019, 5:02pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086/22 "2019-06-19T17:02:27Z")

</div>

Hi @craigson , the `restart: no` will not instantiate the container in “stopped”. That field just means the container won’t be `restart`ed in the case that its PID 1 process exits. So it will always start. You can also probably use `restart: on-failure` which would only restart the container if your process exited for some failed reason, but if it was `exit 0` then it would just stop.

---

<div class="post-metadata">

**Author:** ![Craigson](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@Craigson](https://forums.balena.io/u/Craigson)\
**Post date:** [June 19, 2019, 5:13pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086/24 "2019-06-19T17:13:39Z")

</div>

Thanks @shaunmulligan that makes more sense to me. Then having the `restart: "no"` only really makes sense if I’m stopping the container itself, correct? In other words, If I were to use the supervisor API to stop the container, I don’t want it restarting itself.

According to `Idea 1`, running code in the entry point would simply stop a nodejs server from running. If my `Kiosk` service was a container running a webkit browser, I’d need to stop the actual container from running to conserve the resources, wouldn’t that be correct?

---

<div class="post-metadata">

**Author:** ![dt-rush](https://sea2.discourse-cdn.com/balena/user_avatar/forums.balena.io/dt-rush/32/1405_2.png) [@dt-rush](https://forums.balena.io/u/dt-rush)\
**Post date:** [June 21, 2019, 5:51pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086/27 "2019-06-21T17:51:22Z")

</div>

The Supervisor API `stop-service` call [1] will stop a service for good, no need to inhibit restarts.

As to your second question, I’m not quite sure what you mean by “running code in the entry point would simply stop a nodejs server from running”. If the node script ends, the container (“service”) will terminate, since the entrypoint script has exited. That’s why in the example above, we only run the code for the service if its env var is present, otherwise we log and exit, thus terminating the container:

```auto
if (process.env['IS_SENSOR']) {
    // code to run service ...
} else {
    console.log('sensor not starting, did not find env var');
}

```

If you use this method, you will need to inhibit restarts.

I hope this helps clarify the situation! Let us know if you have any further questions and we’ll be glad to assist.

[1] [https://github.com/balena-io/balena-supervisor/blob/master/docs/API.md#stop-a-service-post-v2applicationsappidstop-service](https://github.com/balena-io/balena-supervisor/blob/master/docs/API.md#stop-a-service-post-v2applicationsappidstop-service)

---

<div class="post-metadata">

**Author:** ![Craigson](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@Craigson](https://forums.balena.io/u/Craigson)\
**Post date:** [June 24, 2019, 2:09pm UTC](https://forums.balena.io/t/selectively-running-containers-on-a-device/16086/29 "2019-06-24T14:09:50Z")

</div>

Yea, that makes sense - thank you for clarifying!
