Multiple containers in a Pod
Pods are an extra level of abstraction above containers. Pods allow us to specify additional information for the container as well as simplifying the usage of different underlying container runtimes (e.g. docker, rocket). To learn more about Pods, check out the Pods page.
We can also have tightly coupled containers co-located in the same Pod and they can be managed as a single unit, allowing for better separation of concerns and container image reusability. All of these can be achieved through the following patterns.
Sidecar pattern uses a helper container which is used to extend the functionality of a primary container. The benefits of sidecar pattern is that it helps with isolating failures. If a sidecar like a logging agent fails, the primary container can still work. Common examples include:
- shipping logs to a central aggregation
- syncing files with external systems
As an example, we could have a primary container that writes to log files. We can extend the functionality of this container by using a sidecar container which sends the log files to a central S3 Bucket for collection.
Photo courtesy of Multi-Container PodsThe ambassador pattern can be used to proxy connections from a primary container to the outside world. The primary container only needs to consider connecting to localhost, while the ambassador controls proxying the connections to different environments. This is because containers in the same pod share the same network space, and can communicate with each other over localhost. Common examples include:
- proxying connections to databases
- proxying connections to different environments
- multiple applications written in different languages
As an example, we could have:
- a web app (primary container), and
- a database proxy container
The web app handles requests from clients and when the data needs to be updated the web app sends a request over local host, where it is received by the database proxy.
Photo courtesy of Kubernetes multi-container patternsThe database proxy then forwards the request to the correct database backend. The database could have a single endpoint, or the database could be shared across multiple database instances. The ambassador can encapsulate the logic for sharding the requests in the latter case. Meanwhile, the web app is free from any of the associated complexity.
The adapter pattern provides a standardized interface of an application across multiple Pods. The adaptor pattern is the opposite of the ambassador pattern, in that the ambassador presents a simplified view to the primary container while the adaptor pattern presents a simplified view of the application to the outside world. Common examples include:
- normalizing output logs and monitoring data
- legacy applications that write metrics in non-standard form
- integrating with third-party software
As an example, we could have an application that needs to transform heterogenous monitoring data into a single unified representation. We can refactor the application and develop the needed feature, or we can make use of an adapter container whose sole purpose is the transformation.
Photo courtesy of Adapter containersAs an application developer, learning the networking concepts of Kubernetes and how they can be used to access applications running in a cluster, starting with IP-per-Pod.
- this means each Pod is assigned with one unique IP
- containers in the same Pod share the same IP address
- containers in the same Pod comunicate with each other's ports over localhost
Pods are ephemeral, which means they will be killed and everytime they are restarted, they will have a different IP. Pods may also have multiple replicas spread over many nodes.
Kubernetes Services can help in maintaining a list of endpoints as Pods are added and removed from the set.
- Service sends requests to any of the Pods
- clients of the Service just needs to know the Service, not the Pods
- Pods can discover Services using environment variables or DNS add-on
- IP given to a Service is called Cluster IP
Below are the types of Kubernetes Services available:
- Cluster IP - IP given to a service, accessible only inside the cluster
- Node Port - for opening port on each node for Service access
- Loadbalancer - exposes the service externally
- External Name - Access services outside the cluster using DNS CNAME records
Network Policies are similar to security groups for virtual machines because they are used for controlling access.
- policies can be used to control access to a group of Pods in a namespace
- cluster's network plugin must support network policies
The default behavior of a Pod is to allow traffic from any source, making it a non-isolated Pod. Once a pod is selected by a network policy it becomes isolated. The pods are selected using labels, which are the core grouping primitive in Kubernetes.
In addition to the other patterns mentioned above, it is also beneficial to not just familiarize ourself with kubectl but to leverage its functionalities:
- shell completions helps in command completion
- get tricks for filtering outputs
- generating manifest files for resources
To enable the command completion for kubectl:
suorce <(kubectl completion bash)>
If you have multiple manifest files that you need to run, you can simply put them in one directory:
$ tree my-files
├── web.yml
├── db.yml
└── cache.yml
Then run all files in one go by specifying the directory.
kubectl apply -f my-files
If you want to create the manifest of a resource, let's say a namespace, on the command line, you can simply do all it by forwarding the output of the --dry-run command to a file:
kubectl create namespace my-namespace -o yaml --dry-run > myname.yaml
Then apply the YAML file:
kubectl apply -f myname.yml
In addition to these, another extremely important trick is:
kubectl api-resources
This command display all the available api-resources and their shortnames. Some resources have long names so knowing the shorthand names for the resource can save some time in typing.