Internet Explorer is no longer supported. Many things will still work, but your experience will be degraded and some things won't function. Please use a modern browser such as Edge, Chrome, or Firefox.

What is a "Container" (vs a package)

view on GitHub

Even for experienced developers, containers can be quite difficult to understand. There is a lot to learn, but this article will help explain how containers work compared to packages. You may also find the Docker terminology article helpful.

Package Files and Versions

Packages are generally simple. They are just a file that contains other files.

Everything you need to know about a package is contained in the package itself. Since the manifest file contained in the package contains the name and version number of the package, the file name of the package file doesn't really matter. It should reflect the name and version, but it doesn't have to.

Package versioning is just as simple: packages are uniquely identified by a name and version, which allows not only easy identification, but also sorting and comparison to determine which package is the newest, which is the newer, and so on. Since version numbers are stored in the manifest file (i.e., in the package itself), the package name and version are an integral part of the package and are as immutable as its contents.

Container Image Basics

A container image is like a package file in that it's composed of other files.

But unlike packages, container images don't have a manifest file that contains a name and version. It's essentially a huge zip file that contains all the files an application needs to run, as well as the underlying operating system.

Unlike ordinary zip files, container images don't even have a name. Instead, they're identified by a "cryptographic hash" (or digest) of their contents. This is a 64-character string that, to a human reader, might as well be a bunch of random numbers and letters. This basically means that a container image is essentially 40510175845988f13f6162ed8526f0b09f73384467fa855e1e79b44a56562a58.zip

To make container images usable by humans, these cryptographic hashes can be "named". This works much like files on disk: the name of a file is not part of the file itself. You can rename it, and the contents remain the same. The same is true for container images: you can tag them and rename them, and the content remains the same.

Container Image Versioning

Like a bunch of random files on disk, container images aren't versioned. It's up to the publisher to determine which container images have which tags and when those tags change.

For example, some publishers may use [v6] to refer to the last version, whereas another may use [4.2-stable] to indicate a non-beta version of a container image. There are also tags like [latest-2], [old-1], [new-test11-new-new], etc., which are exactly what one might expect when using the file system for versioning instead of packages.

Many publishers use a form of semantic versioning when tagging images (such as [4.3.0], [2.3.4-latest], etc., but the mutable nature of tags means that a publisher can also change [hdards-3.2.4] (which appears to be a specific version) to point to any container image, at any time.

Since publishers can change their tags at any time, this leads to a lot of confusion when container versions change depending on the day of installation. Ultimately, this leads to a lot of lost productivity and even production downtime for companies when the wrong containers are tested and deployed.

Best Practices with Container Tags

With ProGet's Semantic Versioning for Containers, you no longer have to worry about meaningless or changing tags. Once enabled, this feature helps you manage your container images with the same rigor as your packages: Tags can only be used for correctly formatted version numbers and cannot be overwritten.

Private Registries & Container Naming

One of Docker's quirks is the peculiar relationship between a container's name (technically, the "repository name") and its private container registries. If you do not specify the server's network address (IP or DNS name) when creating, dragging, or moving containers, Docker assumes that the image is hosted on hub.docker.org.

For example, proget.kramerica.local\registry-name\kramerica\my-app-name is the only way to reference a container image that's not hosted at hub.docker.org.

This is the only way to use Docker with a private registry. When you build, push, or pull an image, the Docker client will search for a . or a : in the first part of the repository name (that is, before the first /). If neither of these characters is present, Docker uses hub.docker.com; otherwise, Docker pulls or pushes to the server address specified in the first part.

This behavior is important to note because, unlike package managers, there is no option when you build, pull, or push container images that tells Docker to "use this private registry instead of Docker hub".

While it's unfortunate that you always have to specify the source, ProGet helps you by ignoring the first part of the repository name (i.e., the server address) and treating the second part as the registry (feed) name. So if you change ProGet's server address or rename your registry, your repositories will work the same way.

Registry Mirroring

You have the option to "mirror" hub.docker.org, but this feature was really only designed to allow Docker, Inc. to host public registries in sensitive regions like China (so you can mirror to registry.docker-cn.com instead).

Unfortunately, the Docker client only uses the configured "mirror" for building and pulling; the images are always pushed to hub.docker.org.

Docker, Inc. doesn't seem interested in enabling this, and we're not particularly keen on forking the Docker client to enable this. Therefore, it doesn't seem to make sense for ProGet to support this in the near future, but feel free to discuss this on the forums.