Conversation
|
Hi Ben. It would be very useful to have a test |
I am still working on a reproducible script and brave-compose.yml to show an example of the compose command in action, will add them when possible. Just as a quick update: I've added support for dependencies between services in the compose file - the services will be topologically ordered to ensure that each service is built after the services it depends on. Tests for the topological ordering pass, so it appears to work as expected - let me know if I missed any cases. |
b36c9e7 to
cd5727d
Compare
Switching build/deploy directoryA further update: I realized that the majority of service Bravefiles will be written from an individual per-component basis and will rely on copying resources into containers from the local dir of that service. When composing these individual components together from a higher directory the relative paths would be incorrect. To address this, Next stepsWhile working on reproducible examples for
The first problem is much more severe, as it essentially blocks the use of Compose for spinning up multiple servers. The second is less serious but could probably be addressed along with the first. The primary issue seems to be with how the LXD client (lxc) is sending commands currently in bravetools. I have some ideas on how to make the above cases work with a few additions/changes to command execution. |
I've added an example of using |
f893eef to
63f2434
Compare
|
Changes since I last checked in:
I'm happy with the current state of things and think it's ready to merge into master. Potential future additions might be worth considering later, such as
These additions belong in a separate pull request however - the functionality present in the current PR (and its size) is enough to merge it as it is. |
|
Updates: Skip build phase for existing imagesRecent additions to bravetools now raise an error if an image already exists. I've updated brave compose to handle this in what I think is the best way for the tool. If a service's "build" field is set to true and the image already exists, compose will skip building the image and continue with the rest of the compose operations (deploy etc.). This makes it easy to leave the build flag set to true in the compose file regardless of the state of the system, with it acting as a "build if image doesn't exist" flag. This seems better than the alternative (requiring manually tweaking the compose file to turn off build after first building the images). "base" field within compose fileThis one is speculative, but thought it was worth considering. Sometimes several images might share the same base dependencies, and it would be nice to be able to reuse the same base image as a starting point. It is already possible to first build a base image and have other builds import that local image, but it's a hassle to do and relies on the existing state of the system. The base field makes this kind of thing possible within a compose file. A service with "base" set to true is not deployed, only built. In addition, since it is primarily a way of accelerating builds, by default a "base" image will automatically be cleaned up after a build - but if you want to keep it, you may set the "build" field to true. Services that depend on the base image can import it as a local image in their Bravefiles - in the compose file they can also express their dependency on the base image. If every image depending on a base image already exists, the base image build will also be skipped as it is not required. An example using the base idea to reuse a base image between 3 services has been added to the examples folder - in this very basic case it speeds up the build by 25% on my machine (saving ~1 minute) but as cost of building the base image increases the bigger the time savings will be as you'll only need to build it once instead of multiple times (offsetting the fixed cost to importing/exporting a new image). Let me know if you think this is worth adding. |
|
This is where I think that compose shouldn't be about "build", but rather, about "create a new unit based on image and then stand up the system". It feels like having image build and compose declared in one place mixes different concepts. Here's what I thought originally:
Last thought - having various flags, in my opinion, would bring unnecessary complexity and might lead to more complex logic in the Bravetools code. What do you think? |
|
Thanks for you thoughts @adrozdovbering, it is good to have some feedback. I appreciate the vision of bravetools handling multiple remotes for both image storage and for deploy and also see it as something we need to work towards. It would also be good to keep the number of flags low if possible! I felt that the "build" and "base" flags required only minimal changes to the code, are not too much to remember, and are justified by their contributions. BuildI agree that primarily In my view having this option to build and deploy using a single command is in-line with the existing Bravefile structure of having build and deploy defined together. It fits in nicely with the idea of compose operating on a higher level, aiding with the process of managing deployments of multiple services by building on top of the lower level commands. It enables scaling up to build a large number services before deploying them, a proceses that otherwise requires manual work (or a script). BaseThe workflow mentioned regarding using The strength of handling multi-stage builds in the brave-compose file is that the dependencies between images and their descendants are formally expressed in a declarative way and clearly visible in a single file at a glance - there's no need to read multiple Bravefiles to work out the ordering. In addition, since the order of dependencies is resolved by Bravetools, building a images that depend upon others is more reproducible, removing the possibility of manual errors or missing local images. Alternatives?I think the value provided by having these functions in But in a way I like the behaviour of the existing set up - it makes deployments truly reproducible by eliminating the need to consider the state of the server before running the command. |
c87f280 to
3f160b6
Compare
…and CheckResources) functions to just the service component. These functions do not need access to the other fields in the bravefile.
…m a single config file
… the provided Bravefile path. Settings specified in the composefile will override those in the bravefile.
…s set in brave-compose.yml
…topological ordering of the service keys based on their dependencies to each other. If no valid ordering is found (indicative of a cycle in the graph), an error is returned.
… new field "context" that will be used instead if provided. If neither bravefile nor context provided, use current dir.
…m of python web servers.
switching directories in Compose, call filepath.Abs to clean paths.
…h service. In addition each ComposeService now stores the loaded Bravefile in a new BravefileBuild field (not serialized via yaml). As a result, errors in Bravefile loading will be caught early - before potentially building and then deploying several other services. In addition, storing ComposeService pointers in service map merges loaded service information from Bravefile into original composefile struct, making it usable from caller.
…with other tests)
…voured over .yml when possible. Changed examples and tests to use the .yaml extension.
…exists, skip build and continue with compose.
…are automatically only used as base images during a compose build phase. They are not deployed, and they are automatically deleted after compose completes (unless the field Build is set to true). This can enable large speedups in building multi-service systems if several of the services reuse the same underlying enviornment with a few tweaks.
…cess of spinning up a system with compose. Add base field details to compose.md doc file.
Add a new
brave composecommand which reads a brave-compose.yml file and spins up the system of containers defined in it. Defining the system in one place like this makes it much easier to see/manage large deployments made up of multiple containers. In addition, it allows for a higher level of abstraction by thinking of multiple containers as a single deployment.Integration with Bravefiles
brave-compose.yamlfiles integrate well with the existing Bravefiles, allowing the option for default unit settings to be loaded from bravefiles. This allows for thebrave-compose.yamlfile to remain lean and provide a high-level overview of the system. Settings specified in thebrave-compose.yamlfile will override those in the provided Bravefile (if any).Optional Build
Although the focus of the compose tool is on deployment, there is also an optional build flag in the
brave-compose.yamlfile allowing for users to build entire systems and deploy them in a single command. All units and images from a build will be cleaned up if an issue is encountered, encouraging treating the set of containers as a single entity.Changes to bravetools
To make these changes I narrowed the scope of the deployment functions
InitUnitandPostdeployto acceptshared.Servicestructs instead of the whole Bravefile. This change mostly has no effect, but one thing does change - currently the Base unit name name is stored in the DB in UnitData. After this change, the actual Image the unit was derived from name will stored instead. This actually makes more sense to me - multiple images could be based on the same base unit, so it's more important to store the actual image a unit is deployed from.TODO
Example script with example compose.yaml fileDocumentation still needs to be addedDependencies between units to determine deployment order