<p>What you're after is referred to as "Review Apps" by <a href="https://about.gitlab.com/product/review-apps/" rel="nofollow noreferrer">Gitlab</a> and <a href="https://devcenter.heroku.com/articles/github-integration-review-apps" rel="nofollow noreferrer">Heroku</a>. It relies on a CI/CD system that runs pipelines on every branch, and exposes the branch name to the build (usually as an environment variable). You can then use the branch name to namespace the resources created by your Infrastructure as Code.</p>

<p>You have mentioned Docker so I will use Kubernetes as an example, but this approach can be applied to just about any deployment method.</p>

<p>Normally when deploying a Docker image, you would name your deployment after the app, e.g.:</p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
# ...
</code></pre>

<p>Using either some kind of preprocessor (Jinja, envsubst, etc.) or a tool like <a href="https://helm.sh/" rel="nofollow noreferrer">Helm</a> we can pass in some parameters to make the resource include the branch name during the pipeline:</p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-${BRANCH_NAME}
# ...
</code></pre>

<p>This way, branches do not deploy on top of each other. The resources they deploy are isolated to the branch.</p>

<p>For an API or web app, you'll want some kind of DNS name and load balancer. Kubernetes handles this quite easily with Ingress and DNS controllers, so I'll use CloudFormation as an example this time.</p>

<pre><code>AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  Branch:
    Type: String
  Environment:
    Type: String
  Zone:
    Type: String

Resources:
# ALB resources omitted for brevity...

  Route53:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: !Sub
        - "my-app-${Branch}.${Environment}.${Zone}"
      HostedZoneName: !Ref Zone
      Type: A
      AliasTarget:
        HostedZoneId: !GetAtt ALB.CanonicalHostedZoneID
        DNSName: !GetAtt ALB.DNSName
</code></pre>

<p>Here we create a DNS record that is very specific to the branch. The DNS record resolves to a load balancer which should point to the containers deployed by the pipeline for this branch. The stack name is also specific to the branch, so pipelines on other branches will not affect it. The end result is that each feature branch will have a dedicated URL (<code>https://my-app-my-feature.dev.example.com</code>) that your developers can use to test and showcase to stakeholders.</p>

<blockquote>
  <p>Should we create 6 new servers/containers if we only make changes in application A?</p>
</blockquote>

<p>No. This isn't specifically related to Review Apps, but microservices in general should be self-contained: decoupled from each other so that they can be deployed in isolation. Removing dependencies and making small changes will increase your development/deployment velocity.</p>

<h2>Considerations</h2>

<h3>Cleanup</h3>

<p>What happens when you merge or delete your branch? Without setting up some kind of cleanup, those containers and DNS records will sit around forever. You need some kind of cleanup. Something that just runs periodically and deletes resources associated to old branches is pretty simple to write, or you could take webhooks from your git server and delete those resources on an event.</p>

<h3>Databases</h3>

<p>Some resources may not warrant getting deployed per-branch, although this should be the exception rather than the norm. You probably don't want to deploy a new database every time someone makes a branch (perhaps unless you have a good schema management tool and DB population scripts). You can have all deployments connect back to the same DB. Ensure that any changes you make to the schema are backwards compatible at least one version behind.</p>

CC BY-SA 4.0
2019-05-09T00:47:43.013Z
2019-05-10T00:53:21.603Z
2019-05-10T00:53:21.603Z
user2640621
<p>Our system consists of</p>

<ul>
<li>2 frontend applications A and B (both in JavaScript/Angular), </li>
<li>3 backend applications C, D and E (main API and two microservices all in Go)</li>
<li>MongoDB as F</li>
</ul>

<p>Our team grows bigger, it's 10 developers at the moment.</p>

<p>We are working on 2, 3 new major features at the same time.</p>

<p>We only have two pre-production environments which makes it hard to test/present different features that are being built at the moment (and on top of that, to test fixed bugs and hot fixes etc.).</p>

<p>We use Git and try to follow git branching model (which might not be relevant here).</p>

<p>To make it easier, we can assume, that each repository has its own Dockerfile to create a fully working container with that application.</p>

<p>What are the options to make it super easy (one command) to publish/switch to a feature that a developer is working on so it's available on one of the environments (that could maybe be created dynamically?)</p>

<p>Should we create 6 new servers/containers if we only make changes in application A?</p>

<p>I would like to have easily accessible versions via a URL like <code>https://a166.preview.example.com</code> where <code>a</code> is the application name and <code>166</code> is the application version (or branch name).</p>

<docker><deployment><environments>
How to approach dynamic environments per Git feature branch workflow?
Marian Kostko
# How to approach dynamic environments per Git feature branch workflow?

(Asked by: username_0 on 2019-05-08)

Our system consists of

* 2 frontend applications A and B (both in JavaScript/Angular),
* 3 backend applications C, D and E (main API and two microservices all in Go)
* MongoDB as F

Our team grows bigger, it's 10 developers at the moment.

We are working on 2, 3 new major features at the same time.

We only have two pre-production environments which makes it hard to test/present different features that are being built at the moment (and on top of that, to test fixed bugs and hot fixes etc.).

We use Git and try to follow git branching model (which might not be relevant here).

To make it easier, we can assume, that each repository has its own Dockerfile to create a fully working container with that application.

What are the options to make it super easy (one command) to publish/switch to a feature that a developer is working on so it's available on one of the environments (that could maybe be created dynamically?)

Should we create 6 new servers/containers if we only make changes in application A?

I would like to have easily accessible versions via a URL like `https://a166.preview.example.com` where `a` is the application name and `166` is the application version (or branch name).

**Tags:** docker, deployment, environments


---

## 1 answers

### Answer by username_1 on 2019-05-09. Score: 3

What you're after is referred to as "Review Apps" by Gitlab and Heroku. It relies on a CI/CD system that runs pipelines on every branch, and exposes the branch name to the build (usually as an environment variable). You can then use the branch name to namespace the resources created by your Infrastructure as Code.
You have mentioned Docker so I will use Kubernetes as an example, but this approach can be applied to just about any deployment method.
Normally when deploying a Docker image, you would name your deployment after the app, e.g.:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
# ...

Using either some kind of preprocessor (Jinja, envsubst, etc.) or a tool like Helm we can pass in some parameters to make the resource include the branch name during the pipeline:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-${BRANCH_NAME}
# ...

This way, branches do not deploy on top of each other. The resources they deploy are isolated to the branch.
For an API or web app, you'll want some kind of DNS name and load balancer. Kubernetes handles this quite easily with Ingress and DNS controllers, so I'll use CloudFormation as an example this time.
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  Branch:
    Type: String
  Environment:
    Type: String
  Zone:
    Type: String

Resources:
# ALB resources omitted for brevity...

  Route53:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: !Sub
        - "my-app-${Branch}.${Environment}.${Zone}"
      HostedZoneName: !Ref Zone
      Type: A
      AliasTarget:
        HostedZoneId: !GetAtt ALB.CanonicalHostedZoneID
        DNSName: !GetAtt ALB.DNSName

Here we create a DNS record that is very specific to the branch. The DNS record resolves to a load balancer which should point to the containers deployed by the pipeline for this branch. The stack name is also specific to the branch, so pipelines on other branches will not affect it. The end result is that each feature branch will have a dedicated URL (https://my-app-my-feature.dev.example.com) that your developers can use to test and showcase to stakeholders.

Should we create 6 new servers/containers if we only make changes in application A?

No. This isn't specifically related to Review Apps, but microservices in general should be self-contained: decoupled from each other so that they can be deployed in isolation. Removing dependencies and making small changes will increase your development/deployment velocity.
Considerations
Cleanup
What happens when you merge or delete your branch? Without setting up some kind of cleanup, those containers and DNS records will sit around forever. You need some kind of cleanup. Something that just runs periodically and deletes resources associated to old branches is pretty simple to write, or you could take webhooks from your git server and delete those resources on an event.
Databases
Some resources may not warrant getting deployed per-branch, although this should be the exception rather than the norm. You probably don't want to deploy a new database every time someone makes a branch (perhaps unless you have a good schema management tool and DB population scripts). You can have all deployments connect back to the same DB. Ensure that any changes you make to the schema are backwards compatible at least one version behind.


---

