Question: I have multiple environments. They are debug, dev, and prod. I'd like to refer to an image by the latest dev (latest) or dev (version 1.1) or prod (latest). How would I go about tagging builds and pushes? 

My first thought was to create separate repositories for each environment debug, dev, and prod. But I am starting to wonder if I can do this with just one repository. If its possible to do with one container what would the syntax be when building and pushing?

Answer: 
This is what has worked best for me and my team and I recommend it:

I recommend having **a single repo per project for all environments**, it is easier to manage. Especially if you have microservices, then your project is composed by multiple microservices. Managing one repo per env per project is a pain.

For example, I have a users api. 
The docker repo is `users`. And this repo is used by `alpha`, `dev` and `beta`.

We create an env variable called `$DOCKER_TAG` in our CI/CD service and set it at the time the build is created, like this:

`DOCKER_TAG: $(date +%Y%m%d).$BUILD_NUMBER` => This is in bash.

Where `$BUILD_NUMBER` is previously set by the build being run when the CI/CD run is triggered. For example, when we merge a PR, a build is triggered, as build no. 1, so `$BUILD_NUMBER: 1`. 

The resulting tag looks like this when used: `20171612.1`
so our docker image is: `users:20171612.1`

**Why this format?**

* It allows us to deploy the same tag on different environments with a
run task.
* It helps us keep track when an image was created and what
build it belongs to.
* Through the build number, we can find the commit information and map all together as needed, nice for trobleshooting.
* It allows us to use the same docker repo per project.
* It is nice to know when we created the image from the tag itself.

So, when we merge, we create a single build. Then that build is deployed as needed to the different environments. We don't create an independent build per environment. And we keep track on what's deployed where.

If there's a bug in an environment with certain tag, we pull such tag, build and trobleshoot and reproduce the issue under that condition. If we find an issue, we have the build number in the tag `20171612.1` so we know the build no. 1 has the issue. We check our CI/CD service and that tells us what commit is the most current. We check out that commit hash from git and debug and fix the issue. Then we deploy it as a hotfix, for example.

If you don't have a CI/CD yet, and you are doing this manually, just set the tag in that format manually (pretty much type the full string as is) and instead of a build number, use a commit short git hash (if you are using git):

`20170612.ed73d4f`

So you know what is the most current commit so you can troubleshoot issues with a specific image and map back to the code to create fixes as needed.

You can also define any other suffix for your tag that maps to the code version, so you can easily troubleshoot (e.g. map to git tags if you are using those).

Try it, adjust it as need it and do what it works best for you and your team. There's many ways to go around tagging. We tried many and this one is our favorite so far.

Hope this is of help.
There's two schools of thought, stable tagging, where you update a single tag, and unique tagging. Each have their pros and cons. Stable tags can create instability when deploying to self healing clusters as a new node might pull a new version, while the rest of the cluster is running a slightly older version. Unique tagging is a best practice for deployment. However, to manage base image updates of OS & Framework patching, you'll want to build upon stable tags in your dockerfile, and enable automatic container builds. For a more detailed walk through, with visuals, here's a post: 
<https://blogs.msdn.microsoft.com/stevelasker/2018/03/01/docker-tagging-best-practices-for-tagging-and-versioning-docker-images/>