faradayio / cage

Develop and deploy complex Docker applications
http://cage.faraday.io
Apache License 2.0
307 stars 26 forks source link

`cage up` does not work with URL as build context #90

Closed andrewsardone closed 4 years ago

andrewsardone commented 6 years ago

Hi there! 👋 cage looks like a nice tool, and I'm excited to try it out on a project, but I'm hitting snag.

I created a service within pods/frontend.yml that uses a build context of a git repo URL (source code). I can run cargo build to build the image, and things look good.

The problem is with running cage up. I see the following error message:

❯ cage up
WARNING: docker-compose.yml file validation disabled until valico is updated (from compose_yml::v2::validate)
WARNING: docker-compose.yml file validation disabled until valico is updated (from compose_yml::v2::validate)
ERROR: The Compose file is invalid because:
Service web has neither an image nor a build context specified. At least one must be provided.
Error: error running 'docker-compose -p examplecageprojectwithbuildcontext -f /Users/andrew/source/andrewsardone/example-cage-project-with-build-context/.cage/pods/frontend.yml up -d'

Inspecting my generated docker-compose file within the .cage directory, I see it's missing a build context:

❯ cat /Users/andrew/source/andrewsardone/example-cage-project-with-build-context/.cage/pods/frontend.yml
---
version: "2"
services:
  web:
    environment:
      DATABASE_URL: "postgres://postgres@db:5432/example-cage-project-with-build-context_development"
      GLOBAL_PASSWORD: magic
      PROJECT_NAME: "example-cage-project-with-build-context"
      RACK_ENV: development
      RAILS_ENV: development
      SOME_PASSWORD: secret
    labels:
      io.fdy.cage.pod: frontend
      io.fdy.cage.shell: bash
      io.fdy.cage.srcdir: /usr/src/app
      io.fdy.cage.target: development
      io.fdy.cage.test: bundle exec rake
    ports:
      - "3000:3000" 

(Extended description in source code's README).


Is there something I'm missing? Am I using cage improperly? If not, any idea of the source of the bug?

Thanks!

emk commented 6 years ago

This is a deliberate feature, actually. :-)

If you want to build images, you can run cage build directly. But cage up won't automatically build for you, because in typical cage workflows, needing to rebuild images locally is often a sign that something has gone wrong.

Basically, in complex projects, asking users to rebuild images locally for each of 20 different microservices is maddeningly inefficient and slow. A better approach would be to build most images using a CI/CD setup (like TravisCI, CircleCI, etc.), and use cage pull to download those images onto each developer system. Then you can use cage source mount myservice to download the source code for just one service and modify it. The other 19 services can exist as pre-built images, making it easier to keep the whole team up to date.

For convenience, cage build can locally rebuild images if you need to do so. But it's not the default, because cage is built around the idea of treating services as opaque images as much as possible.

We use cage heavily internally at Faraday, every day, but we haven't made too many changes lately because it works extremely well for our use case. (We also have other users.) However, we're definitely interested in hearing how cage works for you, and we'll happily give feedback on PRs.

In the medium term, we have some upgrades we're planning on making, but we're prototyping them internally with shell scripts until we're sure we like the design. The goal of cage is bake a certain set of "best practices" into a tool (focusing on projects with a largeish number of microservices) but still keep the complexity down.

andrewsardone commented 6 years ago

Thank you for the prompt and well-thought-out reply, @emk!

This is a deliberate feature, actually. :-)

If you want to build images, you can run cage build directly. But cage up won't automatically build for you

Understood, but that's where I think I see a bug. cage build does build the images, and it outputs the proper .cage/pods/$service.yml docker-compose file. But cage up outputs a malformed .cage/pods/$service.yml docker-compose file; it's missing the build entry of my original $service.yml. In other words, separate cage commands output separate .cage/pods/*.yml files. This is demonstrated with my sample project.

I can see how it's expected that cage up doesn't build images, but I can't even manually build locally and cage up (via cage build && cage up --init) since the latter commands generates a broken .cage/pods/$service.yml file.

Does that clarify the issue? Is this still expected behavior?

emk commented 6 years ago

Ah, OK, I see the problem! cage definitely expects you to specify an image:. We should probably give a better error in this case. Our docker-compose.yml validation is not quite as thorough as it should be (because the Rust valico library is out of date).

cage basically has two core goals that shape everything else:

  1. Allow developers to use images for all services except the ones they're currently working on.
  2. Manage multiple, independent docker-compose.yml files for complex setups.

cage also has a bunch of other workflow stuff built into it, but those two things are the core. If you're not planning on having a central repository with images shared between all developers, or if you only have a couple of services, cage's defaults may not always make sense. (And you may hit an unexpected case like the one discovered above.)

Also, .cage is a totally private directory and the contents are not defined or specified in any way. You can get official output YAML files using the cage export command if you need them for deploying services.

It might be possible to fix cage to do something sensible without having an image: defined, but it would require some thinking and experimentation. I'd be happy to answer questions and ultimately review a PR, but we're unlikely to tackle that use case ourselves because we always have a central image repository.

Arguably, it might be possible to only strip build: if there's already an image:. I could help you find that code that does that if you want to experiment.

andrewsardone commented 6 years ago

Gotcha, @emk; glad we're now on the same page 🙂

The core goals totally make sense. I think relying on a shared central repository of images is a best practice, but it doesn't feel like a MUST to me when looking at the tool. I'm certainly a cage newbie, but I don't see how limiting cage from building images gains anything; it's just an unimplemented feature (and a totally understandable one at that!). That is, I'm curious where else "cage's default may not always make sense" with respect to build: behavior. If docker-compose supports it, it seems like it should play well ¯\(ツ)\/¯.

It might be possible to fix cage to do something sensible without having an image: defined, but it would require some thinking and experimentation. … Arguably, it might be possible to only strip build: if there's already an image:. I could help you find that code that does that if you want to experiment.

I'd take a stab! Wherever you can point me and provide helpful information, that'd be appreciated. 🍻

emk commented 4 years ago

Hello! cage was very minimally maintained for several years, and I'm sorting through old issues. I'm going to go ahead and close this issue for inactivity, but please feel free to reopen it if anybody is still interested.