What is a container image, and why do we need it?
Containers have become the most popular method of delivering modernized applications into production. Part of why they are so widespread is their ability to run on any hardware platform. On the OS, a container behaves like any other process on the host machine, except that it is completely isolated from all other processes. Running a container requires a container engine like Docker, or in the case of Kubernetes implementations, developers wrap containers into pods that share resources and a local network.
Container images are the files that container engines pull down from repositories and app stores. These images are static files with executable code that create containers on machines. They contain everything needed to run an application, including any application dependencies. They also include vital configuration information for the container like default commands, environmental variables, and metadata.
Container images are composed of many independent layers like the container layer, which make up the parent image. Container images are immutable, read-only, and platform agnostic, and it's up to the container engine to provide a read/write layer to capture any file system changes. These changes, along with any other changes made to a container during runtime, are written to the container layer. This design is what allows container image components and configurations to remain reusable.
Container images in Kubernetes
Container images in Kubernetes, much like any environment, represent binary data that describes an application and its dependencies. The main difference in K8s implementations is that, unlike container engines that run containers directly, Kubernetes runs containers via pods. In a K8s environment, the standard process is to create a container image of an application, push it to a registry, and then assign it to a pod where Kubernetes can implement it into production.
Container images are typically assigned names that describe their function and additional information like a registry hostname and port. It's best to follow a standard naming convention for all container images to ensure reusability. Kubernetes will default to the Docker public registry if a registry hostname is not specified.
In addition to image names, developers can assign a tag to identify versioning for a series of related images. The naming convention for tags allows for lowercase and uppercase letters, underscores, dashes, periods, and digits.
The image pull policy governs the process of updating images in Kubernetes. The default pull policy is IfNotPresent for new deployments, which means that the kubelet will only pull container images if one does not already exist.
In addition to IfNotPresent, there are two imagePullPolicies in Kubernetes:
With this policy configured, the kubelet queries the container image registry every time a container is launched. If there is a container image with a matching digest cached locally, then the kubelet will use the cached image. Otherwise, it will pull an image with a matching digest from the container registry to launch the container.
With this policy configured, the kubelet does not try to locate the image in the registry. The container will only successfully launch if it is already present locally.
Container Image Vulnerabilities
The most common threat type for containers is image vulnerabilities. These vulnerabilities are embedded into individual container images and can threaten production environments if the containers are deployed. Most of these vulnerabilities are introduced to these containers as packaged dependencies or via insecure libraries. In extreme cases, attackers can compromise containers by injecting malicious code somewhere in the DevOps pipeline.
Multi-architecture images with image indexes
Image indexes provide a way to configure pulling-down container images that are designed for specific architectures. It works by pointing to multiple image manifests for containers made for particular architectures. When properly configured with image pull policies, systems will automatically fetch the right image for their architecture.
Using private registries for container images
For extra security, developers can use private registries that require key authentication to read their images. Kubernetes supports multiple methods to provide credentials, such as configuring nodes to authenticate directly with a private registry, using a key to pre-pull images into the cache, or by configuring ImagePullSecrets on a pod.
Why do we need container images?
Simply put, containers can't exist without executable images. That's because container images construct the runtime environments that containers need to function. They also contain everything a container needs to run, including application dependencies.