Local mode environment variables

For Local Mode, is there an easy way to leverage environment variables?

If I am not mistaken, you previously were able to use .balena-sync.yml, a config file with env vars, with balena local push. Has that gone away? Is there documentation?

Using your docker-compose.yml file you can add an environment section to one of the services and then reference it for any others. Here’s the docker-compose documentation: https://docs.docker.com/compose/compose-file/compose-file-v2/#environment

Here’s a made up example:

services:
  service_a:
    environment: &env_vars
      - VAR_1="true"
      - VAR_A=12345235235325
  service_b:
    environment: *env_vars

My understanding is that docker-compose.yml only works for multi-container applications. What about single container?

For a single Dockerfile I believe using ENV should work. Here’s the documentation here: https://docs.docker.com/engine/reference/builder/#env

Probably best practice to put those at the end of the Dockerfile because the variables created with this instruction persist through the rest of the build and when the container is run.

What I am trying to do is pass environment variables into the build process. ENV doesn’t work – if I am thinking about this correctly – because I ultimately need to be able to pass different variables for any given device in my fleet.

I can achieve this in “Local Mode” with a command like:

balena push [device_id].local -s -f . \
  --env VAR1=true \
  --env VAR_A=12345235235325

But I have quite a few env vars and I thought the .balena-sync.yml approach worked pretty well.

Hmm, maybe your case is more dynamic than ours. In my case I have a set of known environment variables that are the same for any device I would be using in local mode. I suppose you could create a script that modifies the Dockerfile just before running balena push with the desired value? Sorry I thought your setup was similar to ours.

It seems that this approach will inevitably run into problems when attempting to take advantage of the prod deployment system, the dashboard, etc. since the service can only have one image per fleet. I’d ask the question at this point whether you truly need a device-specific env var in the build phase, or whether it wouldn’t be possible to include these env vars during runtime as device env vars, or in a config file, etc.?

Right. I should clarify that the variables that I am using are not truly needed at build time. My application uses them at runtime, and it seems to make sense that these be managed as environment variables so that we can make a change using the Balena dashboard (and restart the application).

For example, one of the env vars might refer to a pin or channel number that relates to a particular sensor.

Hi @eczajkowski, have you tested declaring your environment variables in the Dockerfile? Do you have any issues with it?

These variables are accessible within your container.

You could take a look at this documentation about the local mode and its caveats:

As the doc says, the variables you define from your dashboard won’t apply to the devices running in localMode. Furthermore, switching out of localMode will make the balena supervisor to destroy and re-create these containers with your setup provided to the balenaCloud.

Thanks. Again, I do not want to declare variables inside of the Dockerfile using ENV, because I want to maintain the ability to change them at runtime (via the dashboard, when the application is running in production).

I think I understand the caveats that you refer to. I am simply looking for an efficient way of passing env vars into my application while it is running locally, for testing purposes. I have quite a few variables to pass in, so I was hoping to avoid a long script where I need to pass an --env flag for each variable.

Hi @eczajkowski , unfortunately adding env vars via the command line for local push is not yet supported, but will be in the future. The option of setting them in your dockerfile is not idea, but just as a note, the env vars set in the dashboard will always override the ones set in the dockerfile or docker-compose.yml. You can think of the env vars in the dockerfile as the “default fleet” env vars, so this would still work for what you want, although not as elegant until we have the feature.

I am currently handling this on Mac OS by using an inline npm script to grep a .env file and pass that through xargs to the balena push command. Works well at the moment and closely mimics my local dev setup. Using a multi-container setup with app and server services I just put a simple package.json file next to my docker-compose.yml file with:

project folder

.
├── .env
├── .git
├── .gitignore
├── app
├── docker-compose.yml
├── package.json
└── server

package.json

...
  "scripts": {
    "dev": "grep -v '^#' .env | sed 's/^/--env /' | xargs balena push development.local"
  },
...

.env

# Service specific
app:APP_HEIGHT="1920"
app:APP_WIDTH="1080"
# Device wide
DISPLAY_PRIMARY_ID="DP-1"
DISPLAY_SECONDARY_ID="DP-2"
DISPLAY_PRIMARY_ROTATION="right"
DISPLAY_SECONDARY_ROTATION="normal"

Now yarn dev or npm run dev will read all uncommented lines from .env, append --env to each line, and pass the arguments through to balena push.

By keeping this file in the root folder you can still keep local .env files in their respective service folders (app, server) for local development if thats how you choose to load ENVs in development.

@shaunmulligan maybe something similar and cross-platform could be implemented into the cli?

Thanks for the feedback and ideas! We actually have an issue open for this, where you can track any progress as well.

I’ve passed on your comments to our team