Writing this as an answer as the comment won't be clear enough in formatting.
I highly doubt nginx or jboss install method vary between your apps, so you just need to override attributes in your app cookbook.
So you end up with coderanger answer: 1 cookbook per infrastructure work (nginx, jboss, storage)
And then 1 application cookbook which
- supply attributes values for this application to the infrastructure cookbooks.
- depends on the infrastructure cookbooks on specific versions
- have 3 recipes:
- 1 including storage and nginx
- 1 including storage and jboss
- 1 including both previous (don't bother, 2 include_recipe for the same one will not be a problem, chef is smart enough to include only once)
On your node you'll set the runlist with one of this recipes.
You gain control of which version of jboss or nginx is actually set up with your app at a particular time (which you can't have with role)
The way attribute loading and recipe compilation works will make your application cookbook attributes override the attributes from nginx cookbook (for exemple) and then will compile the recipe for nginx.
Just ensure the include_recipe nginx/jboss is before your application deployment code so you're sure nginx/jboss is setup before you try to deploy to it.
To expose my case (not so far from yours I think):
We have 53 in house apps, 53 cookbooks settings attributes (jvm options for exemple).
We have 20 application servers pairs so roughly 60 cookbooks (1 for the cluster, and 1 for each instance in the cluster)
Each instance cookbook set up the server name and deployment directory.
Each cluster cookbook depends on application cookbooks and include their recipes (which use the previsouly mentionned deployment directory)
Some tooling like berkshelf exist to help you maintain the whole chain with version constraint.
It sounds complex at first, but with time it saves you from unintentional changes in production because you did a change for staging and forgot it will be propagated (with a role).