Managed environments¶
Introduction¶
With flox you can create portable, isolated, and reproducible environments without containers. flox provides two different types of environments that are suited to different purposes. See the environments Concepts guide to learn more about the difference between the two types and when to use either one.
To demonstrate all the awesome stuff flox enables we're going to create a managed environment that contains a web server that queries a Dungeons & Dragons 5th Edition API, then we'll put this server behind a proxy and poke at it with some developer tools to simulate web traffic.
Create an environment¶
Let's start by creating an environment named managed-env
using the flox create
command:
- The
-e
here stands forenvironment
and is used to specify the environment name. - This is what the output looks like on my Apple Silicon machine running macOS, it will look different for you depending on your CPU architecture and operating system.
Subscribe to flox-examples
channel¶
A channel is like a package repository.
We'll make packages in this channel available under the flox-examples
name by subscribing to it with the flox subscribe
command:
Install packages to the environment¶
Now that we have an environment we can install some packages using the flox install
command:
flox-examples.demo-dnd-server
, a web-server that queries a D&D APIcaddy
, a proxy serverprocps
, a collection of utilities for handling processes, provides thepkill
commandcurl
, used to make HTTP requestsjq
, used to navigate and process JSON documents
$ flox install -e managed-env flox-examples.demo-dnd-server caddy procps curl jq
Installed 'flox-examples.demo-dnd-server', 'caddy', 'procps', 'curl', 'jq' package(s) into 'managed-env' environment.
Note that installing packages to an environment doesn't immediately make them available, it just means that when you activate that environment those packages will be available.
Enter the environment¶
You enter an environment with the flox activate
command.
When entering an environment, the packages installed in the environment become available.
Let's activate the environment and verify that caddy
is installed:
Query the server¶
Now let's start the server (which will run on port 5500) and send it to the background so that we can make requests without needing to activate the environment in another shell:
flox [managed-env default] $ demo-dnd-server &>/dev/null & # (1)!
[1] 62712 # (2)!
flox [managed-env default] $ curl -X GET -s localhost:5500/spells/acid-arrow
{"index":"acid-arrow","name":"Acid Arrow",... # (3)!
flox [managed-env default] $ curl -X GET -s localhost:5500/spells/fireball | jq '.damage.damage_at_slot_level["3"]' # (4)!
"8d6" # (5)!
- The
&>/dev/null
invocation redirectsstdout
andstderr
to/dev/null
so that we don't see any output from the server while it's running, otherwise we would see its logging mixed in with what we type into the terminal. The&
at the end of the command tells the shell to run the server asynchronously in the background. - This is the process ID (PID) of the server process on my machine, it will be different on your machine.
- The response from the server contains a lot of information so I've truncated it for space.
- Here we use
jq
to pull out a specific piece of information from the API. - This is the number of dice you roll to calculate damage from your Fireball spell. It's a lot!
Put it behind a proxy¶
Now let's put this server behind a proxy.
We'll start the proxy on port 6600, send it to the background, and see if it all still works (make sure your server is still running!):
flox [managed-env default] $ caddy reverse-proxy --from :6600 --to :5500 &>/dev/null &
[1] 63742
flox [managed-env default] $ curl -X GET -s localhost:6600/spells/sacred-flame | jq '.name'
"Sacred Flame"
Note that now we're using curl
to send requests to port 6600 instead of 5500 since our proxy is up and running!
Start server and proxy automatically¶
Now we'll introduce a new command: flox edit
.
This command lets you manually edit the environment definition that the flox
commands have been editing for you.
Run the command flox edit -e managed-env
(which will open $EDITOR
), and add the following lines before the closing brace:
shell.hook = ''
echo "Starting proxy 6600 -> 5500"
caddy reverse-proxy --from :6600 --to :5500 &>/dev/null &
echo "Starting server on port 5500"
demo-dnd-server &>/dev/null &
''; # (1)!
environmentVariables = {
SOMEVAR = "contents of SOMEVAR";
}; # (2)!
- This
shell.hook
attribute is where you put shell commands you want executed once the environment has been loaded, but before the interactive part of the shell is presented to the user. You can read about other attributes in flox.nix configuration. - The
environmentVariables
dictionary ("attribute set" in Nix terminology) lets you set environment variables declaratively. The example here (SOMEVAR
) is silly, but you could very easily use this to define environment variables important to configuring your application. For instance, we could define the port that the server listens on, provide a path to some credentials, etc.
In order for this shell hook to load you'll have to exit the environment.
First kill caddy
and the server using pkill
, then exit the environment:
Now re-enter the environment with flox activate -e managed-env
and make a request to the server to make sure it's working:
$ flox activate -e managed-env
Starting proxy 6600 -> 5500
[2] 64665
Starting server on port 5500
[3] 64666
flox [managed-env default] $ curl -X GET -s localhost:6600/spells/mage-hand
{"index":"mage-hand","name":"Mage Hand",...
Rollback¶
Our proxy and server now start automatically, but let's say that we'd like to undo that change.
Rather than manually editing our environment definition to remove the shell hook, we can roll back to the previous generation (version) of the environment using flox rollback
:
flox [managed-env default] $ flox rollback -e managed-env
Rolled back environment 'managed-env' from generation 6 to 5. # (1)!
- If you've played around with your environment definition via
flox edit
or by installing more packages you may have different generation numbers. That's totally fine!
A killer feature of managed environments is this concept of transactional updates to environments. Edits that you make to your environment definition either completely succeed and overwrite the previous definition, or completely fail and are thrown away. If you make an edit to your environment definition flox will check that it can be evaluated, will check that all the packages installed in the environment can be built, and will make sure that all the packages installed in the environment can be combined into a single environment. If any of those checks fail, the edit to the environment definition will be throw away so that you aren't left with a broken environment.
Push to share¶
flox managed environments are synchronized as git repositories.
When you push an environment definition a floxmeta
repository is created under your GitHub account.
We'll push our managed-env
definition using the flox push
command, but first we'll need to authenticate with GitHub:
- You'll be asked to configure which GitHub account you're using, whether you'd like to use https or ssh, etc.
- You'll be asked where to host the repository and whether to use https or ssh.
Verify that you now have a floxmeta
repository at the git host you specified.
Your floxmeta
repository is private by default, so if you'd like to share your environment with someone else you'll need to either make the repository public or grant them read access.
Now that you've successfully pushed the environment definition, someone else that has read access to your floxmeta
repository can use the flox pull
command to use your environment!
Conclusion¶
This was a whirlwind tour of what managed environments can do, and we didn't even cover all of it! Take a look at the other tutorials to learn more about what you can do with either managed or project environments.