2024 DevOps Lifecycle: Share your expertise on CI/CD, deployment metrics, tech debt, and more for our Feb. Trend Report (+ enter a raffle!).
Kubernetes in the Enterprise: Join our Virtual Roundtable as we dive into Kubernetes over the past year, core usages, and emerging trends.
Containers allow applications to run quicker across many different development environments, and a single container encapsulates everything needed to run an application. Container technologies have exploded in popularity in recent years, leading to diverse use cases as well as new and unexpected challenges. This Zone offers insights into how teams can solve these challenges through its coverage of container performance, Kubernetes, testing, container orchestration, microservices usage to build and deploy containers, and more.
Ways To Reduce JVM Docker Image Size
Comparative Analysis of Open Source Cluster Management Systems: Kubernetes vs. Apache Mesos
It can be difficult to manage and orchestrate containers across a distributed infrastructure in the world of containerization and cloud computing. A simple and scalable method for deploying, scaling, and managing containers across multiple hosts is provided by Docker Swarm, a native clustering and orchestration solution from Docker. This article explores the fundamentals of Docker Swarm, its key features, and why it has become a popular choice for container orchestration. What Is Docker Swarm? Docker Swarm is a native clustering and orchestration solution provided by Docker. It allows users to create and manage a swarm of Docker nodes, effectively turning them into a single, virtual Docker host. This enables the deployment and management of containerized applications across a distributed infrastructure. At its core, Docker Swarm is designed to simplify the process of container orchestration. It provides a straightforward and scalable approach to deploying and scaling containers, making it easier to manage large-scale containerized environments. With Docker Swarm, organizations can effectively utilize the benefits of containerization while ensuring high availability, load balancing, and fault tolerance. Docker Swarm operates using a manager-worker architecture. The swarm manager is responsible for orchestrating the cluster, managing the workload distribution, and maintaining the desired state of the services running within the swarm. The worker nodes are the hosts where containers are deployed and run. One of the key features of Docker Swarm is its ability to scale applications seamlessly. By adding or removing worker nodes from the swarm, the cluster can dynamically adapt to changing workloads. This scalability ensures that resources are efficiently utilized and applications can handle increased demand without compromising performance. Docker Swarm also provides built-in service discovery, allowing containers within the swarm to communicate with each other seamlessly. Each service within the swarm is assigned a unique hostname and virtual IP address, simplifying the process of connecting and interacting between containers. Load balancing is another important feature of Docker Swarm. It includes an integrated load balancer that evenly distributes incoming requests across multiple containers running the same service. This load balancing mechanism helps optimize resource utilization and ensures that the workload is evenly distributed across the swarm. Docker Swarm incorporates self-healing capabilities to maintain the desired state of services. It continuously monitors the health of containers and nodes within the swarm. If a container or node fails, Swarm automatically restarts or reschedules the affected containers on healthy nodes, ensuring that services remain available and responsive. Security is a key concern in containerized environments, and Docker Swarm addresses this by providing built-in security features. It supports mutual TLS authentication and encryption for secure communication between nodes. Additionally, role-based access control (RBAC) allows administrators to manage user permissions and access to swarm resources. Key Features of Docker Swarm There are several reasons why you might choose Docker Swarm as your container orchestration solution. Here are some key advantages of Docker Swarm: Easy Setup and Integration: Docker Swarm is part of the Docker ecosystem, which means it can be easily set up using Docker Engine. If you’re already familiar with Docker, the learning curve for Docker Swarm is relatively low. It seamlessly integrates with other Docker tools and services, making it a natural choice if you’re already using Docker containers. Simplicity: Docker Swarm focuses on simplicity and ease of use. It offers a user-friendly command-line interface and a straightforward API, making it accessible to developers and operators with varying levels of expertise. Docker Swarm’s simplicity reduces the complexity of managing and orchestrating containers, enabling you to focus more on your applications rather than the infrastructure. Scalability and High Availability: Docker Swarm allows you to easily scale your applications by adding or removing worker nodes from the swarm. It provides a distributed and scalable architecture to handle increasing workloads. Docker Swarm’s built-in load balancing feature ensures efficient resource utilization and improves the availability and performance of your applications. In case of node failures, Swarm automatically redistributes containers to healthy nodes, ensuring high availability. Service Discovery and Networking: Docker Swarm includes a built-in service discovery mechanism. Each service within the swarm is assigned a unique hostname and virtual IP address, making it easy for containers to communicate with each other. Swarm’s networking capabilities simplify the connectivity between containers and enable seamless interaction within the swarm. Rolling Updates and Rollbacks: Docker Swarm supports rolling updates, allowing you to deploy new versions of containers without disrupting the availability of your application. It automatically updates containers one by one, ensuring that the service remains accessible during the update process. If an issue arises, Swarm facilitates easy rollbacks to previous versions, minimizing downtime and maintaining application stability. Security: Docker Swarm provides built-in security features to protect your containerized applications. It supports mutual TLS authentication and encryption for secure communication between nodes. Role-based access control (RBAC) allows you to manage user permissions and restrict access to swarm resources, ensuring that your cluster is secure by default. Flexibility: Docker Swarm is a flexible orchestration solution that can be used for a wide range of applications, from small-scale deployments to large-scale clusters. It provides a balance between ease of use and the ability to handle complex containerized environments. With Docker Swarm, you have the flexibility to scale and adapt your infrastructure as your requirements evolve. Key Components of Docker Swarm Docker Swarm consists of several key components that work together to enable container orchestration and management within a swarm. These components include: Swarm Manager: The Swarm Manager is responsible for managing the overall swarm and its resources. It coordinates the activities of worker nodes, schedules tasks, and maintains the desired state of the services running within the swarm. The manager also handles service discovery, load balancing, and failure recovery. Worker Nodes: Worker nodes are the hosts where containers are deployed and run. These nodes participate in the swarm and execute tasks assigned by the Swarm Manager. Worker nodes provide the computing resources required to run containers and scale services as per demand. Service: In Docker Swarm, a service represents a group of containers that perform the same function or run the same application. A service defines the desired state of the containers, such as the number of replicas, container image, networking configuration, and resource constraints. The Swarm Manager ensures that the desired state is maintained by continuously monitoring and managing the service. Task: A task represents a single instance of a container running on a worker node. The Swarm Manager assigns tasks to worker nodes based on the defined service specifications. It also monitors the health of tasks and takes necessary actions to maintain the desired state, such as restarting failed tasks or rescheduling them on other healthy nodes. Overlay Network: An overlay network is a virtual network that spans across multiple worker nodes in the swarm. It facilitates communication between containers running on different nodes, regardless of their physical network location. The overlay network allows containers within the swarm to discover and communicate with each other using their service names. Load Balancer: Docker Swarm includes an inbuilt load balancer that distributes incoming requests across multiple containers running the same service. The load balancer ensures even distribution of traffic and optimizes resource utilization. It directs requests to healthy containers, providing high availability and scalability for the services. Swarm Visualizer (Optional): Swarm Visualizer is an optional component that provides a visual representation of the swarm’s architecture and the containers running within it. It offers a graphical interface to monitor and track the status of services, tasks, and nodes in real-time. These components work together to create a robust and scalable environment for deploying and managing containerized applications. The Swarm Manager oversees the swarm’s operations, worker nodes execute tasks, services define the desired state of containers, tasks represent running containers, and overlay networks facilitate communication between containers. The load balancer ensures efficient traffic distribution, and the optional Swarm Visualizer provides a visual representation of the swarm’s status. Docker Swarm Success Stories Docker Swarm has been widely adopted by various organizations for container orchestration and management. Here are a few success stories showcasing how Docker Swarm has helped businesses improve their infrastructure and streamline their operations: PayPal: PayPal, a leading online payment platform, adopted Docker Swarm to enhance its infrastructure and improve application deployment. By leveraging Docker Swarm, PayPal achieved simplified container orchestration, scalability, and high availability for their microservices architecture. Docker Swarm allowed PayPal to efficiently manage their containerized applications across multiple hosts, enabling seamless scaling and reducing deployment complexities. Société Générale: Société Générale, a major European financial services company, utilized Docker Swarm to modernize its IT infrastructure. Docker Swarm enabled them to containerize their applications and easily deploy them across their infrastructure. The high availability and fault-tolerant features of Docker Swarm allowed Société Générale to ensure continuous availability of their critical services, improving the resilience of their applications. Schibsted: Schibsted, a Norwegian media conglomerate, adopted Docker Swarm to streamline their application deployment processes and achieve operational efficiency. With Docker Swarm, Schibsted was able to automate the deployment of their services and scale them according to demand. Docker Swarm’s built-in load balancing and service discovery mechanisms simplified their infrastructure management, leading to improved application performance and reduced time to market. REWE Digital: REWE Digital, a leading German retail and e-commerce company, implemented Docker Swarm to optimize their infrastructure and facilitate the deployment of containerized applications. Docker Swarm provided them with a scalable and flexible platform to manage their services across multiple hosts. REWE Digital experienced improved resource utilization, simplified service scaling, and enhanced resilience of their applications using Docker Swarm. Maersk Line: Maersk Line, the world’s largest container shipping company, leveraged Docker Swarm to modernize their IT infrastructure and streamline their application deployment processes. Docker Swarm enabled Maersk Line to manage and scale their containerized applications seamlessly across their global infrastructure. By adopting Docker Swarm, Maersk Line achieved faster deployment times, improved resource efficiency, and increased application availability. These success stories highlight the benefits of Docker Swarm in simplifying container orchestration, enhancing scalability, improving availability, and optimizing resource utilization for various industries. Docker Swarm’s features and capabilities have empowered organizations to efficiently manage their containerized applications, resulting in enhanced operational efficiency, reduced infrastructure complexity, and accelerated application delivery. Why Choose Docker Swarm? Easy Setup: Docker Swarm is part of the Docker ecosystem, which means it can be easily set up using Docker Engine. The learning curve is relatively low, especially if you are already familiar with Docker. Native Integration: Docker Swarm is a native solution provided by Docker, ensuring compatibility and seamless integration with other Docker tools and services. This makes it an excellent choice for organizations already using Docker containers. Simplicity: Docker Swarm focuses on simplicity, offering a user-friendly command-line interface and a straightforward API. The simplicity of Swarm makes it accessible to developers and operators with varying levels of expertise. Flexibility: Swarm is a flexible orchestration solution that can be used for a wide range of applications, from simple single-node deployments to large-scale multi-node clusters. It provides a balance between ease of use and the ability to handle complex containerized environments. Challenges and Drawbacks of Using Docker Swarm While Docker Swarm offers many advantages for container orchestration, there are some challenges and drawbacks to consider: Learning Curve: Although Docker Swarm is designed to be user-friendly, there is still a learning curve involved in understanding its concepts, architecture, and command-line interface. Administrators and developers may need to invest time and effort in familiarizing themselves with Swarm’s specific features and functionalities. Limited Features Compared to Kubernetes: While Docker Swarm provides essential container orchestration capabilities, it may not have the same level of advanced features and flexibility as Kubernetes. Kubernetes has a larger ecosystem and offers more advanced features for managing complex containerized environments, such as advanced networking, storage orchestration, and extensive customization options. Scaling Limitations: Docker Swarm is suitable for small to medium-scale deployments, but it may face challenges in handling very large clusters or highly dynamic workloads. It has a scalability limit and may experience performance degradation or increased management complexity as the swarm size grows beyond a certain threshold. Lack of Third-Party Integrations: Docker Swarm, compared to Kubernetes, may have limited third-party integrations and a smaller ecosystem of tools and services built around it. This could restrict the availability of specific plugins or extensions that organizations may require for their specific use cases. Limited Maturity: Docker Swarm is not as mature as Kubernetes, which has been widely adopted and has a larger community contributing to its development and support. This could result in fewer resources, tutorials, and troubleshooting options available for Docker Swarm compared to Kubernetes. Less Comprehensive Monitoring and Debugging: Docker Swarm’s monitoring and debugging capabilities are not as comprehensive as those provided by other orchestration platforms. While it offers basic monitoring features, organizations may need to rely on third-party tools or custom solutions to gain more advanced monitoring and debugging capabilities. Limited Cluster Management: Docker Swarm’s cluster management capabilities are relatively basic compared to Kubernetes. It may lack certain advanced management features, such as fine-grained control over resource allocation, pod affinity/anti-affinity rules, and more complex scheduling strategies. It’s important to consider these challenges and drawbacks in relation to your specific requirements, the size of your deployment, and the complexity of your containerized applications. Evaluating alternative container orchestration solutions, such as Kubernetes, may be necessary to determine the best fit for your organization’s needs. Conclusion By offering an easy-to-use and scalable method for deploying and controlling a large number of containers, Docker Swarm makes container orchestration simpler. The key features of Docker Swarm, including scalability, service discovery, load balancing, and self-healing capabilities, make it simple for businesses to create and manage reliable containerized applications. Whether you are a small team or a large organization, Docker Swarm offers an adaptable and affordable way for you to take advantage of containerization’s power and effectively manage your distributed infrastructure. In conclusion, the container orchestration tool Docker Swarm is strong and simple to use. Scalability, service discovery, load balancing, self-healing, and security are among the features that make it easier to deploy, scale, and manage containers across a distributed infrastructure. The widespread use of Docker Swarm is a result of its easy integration with other Docker tools and its effectiveness in managing both small- and large-scale containerized environments. To sum up, Docker Swarm provides a strong set of features and advantages for container orchestration. For managing containerized applications, it is a popular option due to its simplicity, scalability, high availability, service discovery, rolling updates, security features, and flexibility. You can concentrate on delivering your applications with confidence whether you are a small team or a large organization because Docker Swarm makes the deployment and management of containers simple.
As you may know, many orchestration tools exist to manage and scale microservices. But, in this case, we will talk about the two most extensive mechanisms: Kubernetes vs. Amazon ECS. In this article, we will review each of them individually. We’re going to talk about their pros and cons. Ultimately, depending on your company's needs, we’ll decide which one is the right container orchestration tool for your web application. Let’s start! Kubernetes vs. Amazon ECS: Which Would Win? These two cluster management systems help microservice applications manage, deploy, autoscale, and network among containers. On the one hand, Kubernetes is a container orchestration service. Developed by Google and hosted in the Cloud, this service also functions with Docker. It is relevant to highlight that Kubernetes has a vital community. On the other hand, Amazon ECS is a container orchestration tool that enables applications to scale up. Continuously, it creates more containers to run the application processes as the demand increases. Both tools have positive and negative sides when adopting one of them, hence the importance of reviewing them to make a good choice depending on what you are looking for in your business. Even with Kubernetes in the cloud (Azure Kubernetes Service or Amazon Kubernetes service), managing it will take around 20% more time. Amazon ECS, a service that doesn’t have a cost, except for the costs associated with the instance assigned to the service, can be as small as a small instance. Features: Kubernetes vs. Amazon ECS Multi-Cloud Well, this is obvious, and the winner is Kubernetes. A compelling reason is that it can be deployed on-prem or any cloud provider, including Azure, Google Cloud, or Amazon. In the case of ECS, the platform is closed code; consequently, it has a vendor lock-in and is not cloud-agnostic. Easy to Operate In this case, Amazon ECS is your best option. The ECS ecosystem is already preconfigured. It is an Amazon service that doesn’t require a full setup. Additionally, it takes the most challenging parts so that you can focus on a few configurations. Alternatively, Kubernetes has an intense configuration process, requiring an appropriate amount of hours to make it work. Availability and Scalability Both platforms cover the features at the same level, but clearly, Amazon ECS has benefits inherently. They can be deployed in different availability zones versus Kubernetes on-prem. This will take you a fair amount of time to replicate a similar approach with multi-region/zones, etc. Deployments With Amazon ECS, the native deployment system is rolling updates. As well as the other deployment strategies. For example, Canary and blue-green deployments. They can be incorporated in your CI-CD process but with the reinforcement of Amazon Code deployment. On the other hand, Kubernetes per se doesn’t have multiple deployment systems, such as rolling updates, canary deployments, etc. Except for blue/green deployments, which work flawlessly with Kubernetes. Costs Organizations aspire to reduce IT costs without compromising quality or agility, right? So, Kubernetes usually is more expensive than Amazon ECS. One strong argument from Kubernetes is that it requires at least two servers. And that will cost you a lot of money from the hosting side. And not just that, if we go deeper into your organization, with Kubernetes on-prem, the likely work efforts are 2X. That’s because of its configuration, deployment, and maintenance complexity. To Conclude Now that we have taken a closer look at each tool and compared Kubernetes vs. Amazon ECS, the time has come to decide which container orchestration tool is your best option! If you’re looking for multi-cloud, Kubernetes can be the right choice. But if you want to reduce IT labor hosting costs and management, then you should consider Amazon ECS.
Ah, Kubernetes! The panacea to all our DevOps challenges. Kubernetes is the open source container orchestration tool that was supposed to speed up software delivery, secure our applications, lower our costs and reduce our headaches, right? Seriously though, Kubernetes has revolutionized how we write and deliver software. And with the proliferation of EKS, AKS, GKE, Red Hat OpenShift, Rancher, and K3s, Kubernetes has truly won the container orchestration battle. As we expand our applications, cloud platforms, and data, we start to identify areas where Kubernetes is not quite fulfilling the requirements for security and ease of use. Therefore, we need to find ways to help Kubernetes in order to keep up with our growth. Kubernetes practitioners have turned to third-party tools for networking, security, and resiliency for stateful apps. This helps to make their deployments more reliable. In this blog, we’ll delve a little deeper into data resiliency for Kubernetes apps. Kubernetes was designed to solve the challenges of application orchestration, the assumption is that Kubernetes nodes are ephemeral. In reality however, applications do consume and/or produce data. This is referred to as StatefulSets in Kubernetes. Additionally, Kubernetes objects, CRDs, artifacts, etc, are all details that need to be available in cases of cluster failure, hence the realization that even Kubernetes deployments need a DR strategy. The Rise of StatefulSets StatefulSets are designed to handle stateful workloads that require unique network identifiers and stable storage. Each instance of Databases, message queues, or distributed file systems, typically requires stable network identity and persistent storage. StatefulSets addresses this challenge by providing ordered, unique network identifiers and persistent storage for each pod in the set. There is, of course, a large contingent of Kubernetes storage deployments that rely on static volume attachments, but they do not have the horizontal scaling capabilities and thus are not part of this blog discussion for now. In addition to providing uniqueIDs and scaling, StatefulSets provide the ability to mount persistent volumes to each pod. This allows stateful applications to store and access data that persists across pod restarts or rescheduling. Each pod in a StatefulSet receives its own unique persistent volume, enabling data locality and minimizing the impact on other pods. The Container Storage Interface (CSI) standard is the most widely used API standard. It enables containerized workloads in Kubernetes to access any block or file storage system. Released at the end of 2019, the Container Storage Interface driver with a snapshot opened the doors to StatefulSets. See Kubernetes CSI. The Cloud Native Computing Foundation (CNCF) framework includes various projects to meet the storage requirements of Kubernetes. However, practitioners must be knowledgeable in storage fundamentals. This is not a skill usually associated with DevOps. Companies like Portworx by Pure, Rancher Longhorn, Rook and LINBIT are setting a new standard for container storage. (in addition to vendor offerings from NetApp and HPE). They are providing several enterprise features to make container storage more efficient. With that background, we turn to the considerations for Multi-cluster database resiliency in Kubernetes. Single Cluster Apps For applications running in a single cluster, Kubernetes (together with the CSI storage component) provide a feature for volume replication. Each persistent volume can be set to have a number of replica copies (typically 3) locally. Kubernetes will take action if a node fails. It will restart the service on a new node and attach it to a replicated version of the volume. This helps to prevent data loss. (Setting aside static CSI or NFS drivers for now) For tools that replicate data locally, the data is copied synchronously, as it is a single local cluster. Restarting the node is done instantly with the Kubernetes control plane. Therefore, the recovery time is considered zero. From a recovery point of view, this is considered to be ZERO Recovery Time Objective (RTO). The Recovery Point Objective (RPO) may also be ZERO in this case, but this, of course, would depend on mitigating for data corruption, journaling, etc. Zooming out to complex environments reveals a murkier picture. These environments include clusters that span multiple clusters, platforms, and even cloud providers. Multi-Cluster Database Resiliency Understanding the why and how of Multi Cluster Kubernetes can be difficult. Fortunately, this article by our friends at Traefiklabs explains Kubernetes Multi Clusters in detail. The architecture of a multi cluster Kubernetes is depicted in the diagram below: What is pertinent in our discussions is the traffic route between these clusters. From a user perspective, application requests are routed to their US cluster or EU cluster by the global load balancer. What happens when a pod from Node 1 in US-Cluster needs to communicate to Node 1 on the EU-Cluster? This could present a challenge due to the distance and complexity between the two clusters. At a minimum, data must travel through at least two network boundaries, exiting the US cluster, crossing the Atlantic, and entering the EU cluster. This network traffic flow between a local network and external networks is referred to as North South traffic. "North" refers to outbound traffic from the local network to external networks. "South" refers to inbound traffic from external networks to the local network. From a data plane perspective, the North/South traffic between clusters introduces a higher level of latency and reduced reliability when compared to traffic within a local cluster. Whereas traffic within a cluster is synchronous (fast, reliable) ; traffic between remote clusters is thus asynchronous (slower, less reliable). For those wishing to learn more about synchronous and asynchronous traffic may want to review this article. How Does North/South Traffic and Synch/Asynchronous Communications Relate Back to Kubernetes Multi-Cluster Database Resiliency? A CSI storage connector in Kubernetes uses synchronous communication for traffic within a local cluster. This means that data is written simultaneously to the primary and replica data volumes. Data for remote clusters is written locally first. Then, a snapshot copy of the data is shipped to the second cluster on a regular schedule. This is done asynchronously. This difference in approach also has implications for data resiliency and how data is recovered after a failure. Kubernetes recovery in a disaster recovery scenario within a local cluster is instantaneous. This is due to data being simultaneously copied to the local replica. As a result, data availability is also instantaneous. In technical terms, there are two metrics that we track. Recovery Time Objective (RTO) is the time it takes to recover from a failure. Recovery Point Objective (RPO) is the maximum allowable data loss. Thus, DR within a local Kubernetes cluster can be said to have Zero RPO / Zero RTO (For an insightful discussion about RPO and RTO considerations in Kubernetes, I highly recommend this post by Bijit Ghosh and another one by Matt LeBlanc.) In a remote cluster situation, however, the picture is somewhat different. When assessing a multi-platform or multi-cloud application, a Cloud Architect or SRE should consider how asynchronous replication impacts the Recovery Time Objective (RTO). Shipping the replica copy, traveling North/South, and restoring it on the active cluster at the recovery site all take time. This means that DR operations have a time lag. This time lag can be significant. Conservative estimates show that CSI solutions can reduce the RTO to 15 minutes. This means we can have an RPO of zero and an RTO of 15. Most DevOps teams and Cloud Architects focus on single cluster, single region, and single platform deployments. They may not consider DR architectures and requirements. As a result, many early adopters may be satisfied with an RTO of 15 minutes. Traditional infrastructure architects and data owners may want to explore new solutions on the market. These solutions can help them reach a close-to-zero recovery time objective and disaster recovery across multiple Kubernetes platforms. Tools such as KubeSlice can lower RTO thresholds by establishing a low latency data plane interconnect between multiple clusters or platforms. This helps to enable faster recovery for Kubernetes applications and data. KubeSlice converts North/South traffic into East-West network traffic via application level virtualization across a secure/encrypted connection, thereby eliminating the need to traverse network boundaries. This creates a lower latency connection for the data plane and enables synchronous replication of data to the DR site. KubeSlice makes the remote cluster seem local to the primary cluster. This enables recovery that is close to having a Zero Recovery Time Objective (RTO). Regardless of which recovery scheme is employed, application owners should carefully consider their application and data resiliency needs and plan accordingly. As the Data on Kubernetes report points out, a full one-third of organizations saw productivity increase twofold by deploying data on Kubernetes, with gains benefiting organizations at all levels of tech maturity. Summary Container Storage Interface (CSI) standard and projects like Portworx and Rancher Longhorn are a great start towards a Software Defined Storage approach for Kubernetes persistent apps. The article explores Multi-cluster database resiliency in Kubernetes, starting with the resiliency of single-cluster applications. It explains how Kubernetes handles volume replication in case of node failures, ensuring zero recovery point objective (RPO) and zero recovery time objective (RTO) within a single cluster. However, the complexity arises when dealing with multi-cluster environments spanning multiple platforms and cloud providers. The challenges of North/South traffic and asynchronous communication between remote clusters are discussed, and the implications for data resiliency and recovery in disaster scenarios are explained. The article introduces KubeSlice as a tool that can lower RTO thresholds by establishing a low-latency data plane interconnect between multiple clusters or platforms. It converts North/South traffic into East-West network traffic, enabling faster recovery for Kubernetes applications and synchronous replication of data to the disaster recovery (DR) site. The importance of carefully considering application and data resiliency needs is emphasized, and the benefits of deploying data on Kubernetes are mentioned. Overall, the article focuses on the challenges and solutions related to data resiliency in Kubernetes, particularly in multi-cluster deployments, and highlights the role of tools like KubeSlice in achieving faster recovery times.
Docker Extensions was announced as a beta at DockerCon 2022. Docker Extensions became generally available in January 2023. Developing performance tools' related extensions was on my to-do list for a long time. Due to my master's degree, I couldn't spend time learning Docker Extensions SDK. I expected someone would have created the extension by now, considering it's almost 2024. It's surprising to me that none has been developed as far as I know. But no more. Introducing the Apache JMeter Docker Extension. Now, you can run Apache JMeter tests in Docker Desktop without installing JMeter locally. In this blog post, we will explore how to get started with this extension and understand its functionality. We will also cover generating HTML reports and other related topics. About Docker Extensions Docker Extensions enables third parties to extend the functionalities of Docker by integrating their tools. Think of it like a mobile app store but for Docker. I frequently use the official Docker Disk Usage extension to analyze disk usage and free up unused space. Extensions enhance the productivity and workflow of developers. Check out the Docker Extension marketplace for some truly amazing extensions. Go see it for yourself! Prerequisite for Docker Extension The only prerequisite for Docker Extension is to have Docker Desktop 4.8.0 and later installed in your local. Apache JMeter Docker Extension Apache JMeter Docker Extension is an open-source, lightweight extension and the only extension available as of this writing. It will help you to run JMeter tests on Docker without installing JMeter locally. This extension simplifies the process of setting up and executing JMeter tests within Docker containers, streamlining your performance testing workflow. Whether you're a seasoned JMeter pro or just getting started, this tool can help you save time and resources. Features Includes base image qainsights/jmeter:latest by default. Light-weight and secured container Supports JMeter plugins Mount volume for easy management Supports property files Supports proxy configuration Generates logs and results Intuitive HTML report Displays runtime console logs Timely notifications How To Install Apache JMeter Docker Extension Installation is a breeze. There are two ways you can install the extension. Command Line Run docker extension install qainsights/jmeter-docker-extension:0.0.2 in your terminal and follow the prompts. IMPORTANT: Before you install, make sure you are using the latest version tag. You can check the latest tags in Docker Hub. Dockerfile $> docker extension install qainsights/jmeter-docker-extension:0.0.1 Extensions can install binaries, invoke commands, access files on your machine and connect to remote URLs. Are you sure you want to continue? [y/N] y Image not available locally, pulling qainsights/jmeter-docker-extension:0.0.1... Extracting metadata and files for the extension "qainsights/jmeter-docker-extension:0.0.1" Installing service in Desktop VM... Setting additional compose attributes Installing Desktop extension UI for tab "JMeter"... Extension UI tab "JMeter" added. Starting service in Desktop VM...... Service in Desktop VM started Extension "JMeter" installed successfully Web Here is the direct link to install the JMeter extension. Follow the prompts to get it installed. Install JMeter Docker Extension Click on Install anyway to install the extension. How To Get Started With JMeter Docker Extension After installing the JMeter Docker extension, navigate to the left sidebar as shown below, then click on JMeter. Now, it is time to execute our first tests on Docker using the JMeter extension. The following are the prerequisites to execute the JMeter tests. valid JMeter test plan optional proxy credentials optional JMeter properties file The user interface is pretty simple, intuitive, and self-explanatory. All it has is text fields, buttons, and the output console log. The extension has the following sections: Image and Volume This extension works well with the qainsights/jmeter:latest image Other images might not work; I have not tested it. Mapping the volume from the host to the Docker container is crucial to sharing the test plan, CSV test data, other dependencies, property files, results, and other files. Test Plan A valid test plan must be kept inside the shared volume. Property Files This section helps you to pass the runtime parameters to the JMeter test plan. Logs and Results This section helps you to configure the logs and results. After each successful test, logs and an HTML report will be generated and saved in a shared volume. Proxy and its credentials Optionally, you can send a proxy and its credentials. This is helpful when you are on the corporate network so that the container can access the application being tested. Below is the example test where the local volume /Users/naveenkumar/Tools/apache-jmeter-5.6.2/bin/jmeter-tests is mapped to the container volume jmeter-tests. Here is the content in /Users/naveenkumar/Tools/apache-jmeter-5.6.2/bin/jmeter-tests folder in my local. The above artifacts will be shared with the Docker container once it is up and running. In the above example, /jmeter-tests/CSVSample.jmx will be executed inside the container. It will use the below loadtest.properties. Once all the values are configured, hit the Run JMeter Test button. During the test, you can pay attention to a couple of sections. One is console logs. For each test, the runtime logs will be streamed from the Docker container, as shown below. In case there are any errors, you can check them under the Notifications section. Once the test is done, Notifications will display the status and the location of the HTML report (your mapped volume). Here is the auto-generated HTML report. How JMeter Docker Extension Works and Its Architecture On a high level, this extension is simple, as shown in the below diagram. Once you click on the Run button, the extension first validates all the input and the required fields. If the validation check passes, then the extension will look up the artifacts from the mapped volume. Then, it passes all respective JMeter arguments to the image qainsights/jmeter:latest. If the image is not present, it will get pulled from the Docker container registry. Then, the container will be created by Docker and perform the test execution. During the test execution, container logs will be streamed to the output console logs. To stop the test, click the Terminate button to nuke the container. This action is irreversible and will not generate any test results. Once the test is done, the HTML report and the logs will be shared with the mapped volume. How To Uninstall the Extension There are two ways to uninstall the extension. Using the CLI, issue docker extension uninstall qainsights/jmeter-docker-extension:0.0.1 or from the Docker Desktop. Navigate to Docker Desktop > Extensions > JMeter, then click on the menu to uninstall, as shown below. Known Issues There are a couple of issues (or more :) if you find) you can start the test as much as you want to generate more load to the target under test. Supports only frequently used JMeter arguments. If you would like to add more arguments, please raise an issue in the GitHub repo. Upcoming Features There are a couple of features I am planning to implement based on the reception. Add a dashboard to track the tests Display graphs/charts runtime Way to add JMeter plugins on the fly If you have any other exciting ideas, please let me know. JMeter Docker Extension GitHub Repo Conclusion In conclusion, the introduction of the Apache JMeter Docker Extension is a significant step forward for developers and testers looking to streamline their performance testing workflow. With this open-source and lightweight extension, you can run JMeter tests in Docker without the need to install JMeter locally, saving you time and resources. Despite a few known issues and limitations, such as supporting only frequently used JMeter arguments, the extension holds promise for the future. In summary, the Apache JMeter Docker Extension provides a valuable tool for developers and testers, enabling them to perform JMeter tests efficiently within Docker containers, and it's a welcome addition to the Docker Extension ecosystem. It's worth exploring for anyone involved in performance testing and looking to simplify their workflow.
The world of application integration is witnessing a transformative shift, one that is redefining the landscape of software development and deployment. This transformation is underpinned by the rise of containerization technologies, which encapsulate applications and their dependencies within isolated, consistent environments. Historically, application integration has faced myriad challenges, from compatibility issues between different systems to the complexities of scaling applications in response to fluctuating demands. The introduction of containers has emerged as a solution to these challenges, offering a paradigm that enhances agility, scalability, and efficiency. This comprehensive exploration delves into the evolution of application integration, the revolutionary impact of containerization technologies such as Docker and Kubernetes, its applications across various sectors, specific use cases, and the challenges that must be navigated. As we examine this fascinating topic, we uncover not just a technological innovation but a shift in thinking that is reshaping the very fabric of the software industry. Evolution of Application Integration The Early Days Application integration has its roots in early enterprise systems, where mainframes and bespoke applications were the norm. The integration was mainly manual and lacked standardization. It was primarily concerned with connecting different in-house systems to ensure that data and processes flowed uniformly. Transition to SOA The introduction of Service-Oriented Architecture (SOA) marked a turning point in application integration. By defining interfaces in terms of services it allowed different applications to communicate without needing to know the underlying details. SOA became a key factor in easing the integration process, but was not without its challenges. It often led to complicated configurations and difficulties in managing services across different systems. Containerization as a Response The limitations of traditional methods led to the emergence of containerization as a novel approach to integration. By encapsulating applications and dependencies within isolated environments called containers it allowed for more scalable, agile, and consistent deployment across various platforms. The Rise of Containerization Technologies Containers represent a groundbreaking form of virtualization. Unlike traditional virtual machines that include a full operating system, containers encapsulate an application and its dependencies within a consistent environment. This allows them to be lightweight, efficient, and highly portable. What Are Containers? At their core, containers are isolated environments that run a single application along with its dependencies, libraries, and binaries. By sharing the host system's kernel, they avoid the overhead of running multiple operating systems, offering a more streamlined and responsive experience. Containers vs. Virtual Machines While virtual machines virtualize the hardware, containers virtualize the operating system. This fundamental difference leads to containers being more efficient, as they eliminate the need for a separate OS for each application. This efficiency translates to faster startup times, lower resource consumption, and increased scalability. Key Technologies: Docker and Kubernetes Docker: Revolutionizing Containerization Docker has become a cornerstone of containerization. It provides a platform where developers can create, package, and deploy applications within containers effortlessly. Docker’s real power comes from its simplicity and accessibility, making it an essential tool for modern development. Docker Architecture Docker utilizes a client-server architecture. The Docker client communicates with the Docker daemon, responsible for building, running, and managing containers. This architecture simplifies both development and deployment, ensuring consistency across various environments. Docker Images and Containers A Docker image is a snapshot of an application and its dependencies. Docker containers are the runtime instances of these images, encompassing everything needed to run the application. This distinction between images and containers ensures repeatability and consistency, eliminating the "it works on my machine" problem. Kubernetes: Orchestrating Containers While Docker simplifies creating and running containers, Kubernetes focuses on managing them at scale. It's an orchestration platform that handles deployment, scaling, and management of containerized applications. Kubernetes Architecture Kubernetes operates based on a cluster architecture. It consists of a master node responsible for the overall management of the cluster and worker nodes that run the containers. This structure facilitates high availability, load balancing, and resilience. Kubernetes in Action Kubernetes automates many of the manual processes involved in managing containers. It can automatically deploy or kill containers based on defined rules, distribute loads, and heal failed containers, making it essential for large-scale applications. Impact on Development and Deployment Containerization technologies have profoundly impacted both development and deployment, introducing new paradigms and methodologies. Streamlined Development Process Containerization simplifies the development process by standardizing the environment across different stages. This ensures that the application behaves consistently from development through to production. Deployment and Scaling With container orchestration through Kubernetes, deployment and scaling become automated and highly responsive. Organizations can swiftly adapt to changing demands, scaling up or down as needed without human intervention. Collaboration and Innovation Containerization fosters collaboration across development, testing, and operations teams. By ensuring environment consistency, it encourages more iterative and innovative approaches, allowing teams to experiment without risking the broader system. In the words of Solomon Hykes, founder of Docker, "Containers are changing the way people think about developing, deploying, and maintaining software." Containerization in Application Integration Unifying Disparate Systems Containerization facilitates the integration of disparate systems by encapsulating them within uniform environments. This unification simplifies the complexities of connecting different technologies and platforms, fostering a more collaborative and efficient workflow. Microservices and Scalability The adoption of containerization in microservices architecture provides a pathway to create more modular, resilient, and scalable applications. Containers enable the individual services to be developed and deployed independently while still maintaining seamless integration. Facilitating Digital Transformation Containerization is playing a significant role in driving digital transformation initiatives within organizations. It supports rapid innovation and agility, enabling businesses to adapt and respond to the ever-changing market landscape. Challenges and Considerations Security Concerns Security remains a significant challenge when implementing containerization. Containers can present vulnerabilities if not configured and managed correctly. This requires constant vigilance and adherence to best practices to maintain the integrity of the containerized environment. Performance Considerations While containerization offers many efficiencies, it also brings some performance considerations. Understanding the resources utilized by containers and tuning them appropriately is vital to ensure that the system performs optimally. Compliance and Governance Integrating containerization into existing enterprise systems must also consider compliance with various regulations and governance policies. This requires thorough planning and alignment with organizational standards and legal requirements. As a software architect, Adrian Cockcroft who was the VP of Cloud Architecture Strategy at Amazon Web Services (AWS). insightfully noted, "Containerization's impact reaches far beyond just technological considerations. It's reshaping how we think about applications, from development to deployment, integration, and management." Real-World Applications of Containerization in Application Integration The real-world applications of containerization in application integration are a testament to the transformative power of this technology. Organizations across different industries have realized significant benefits through its adoption. Financial Industry A global financial institution grappling with a multitude of applications and complex legacy systems turned to containerization as a solution. Implementing Docker and Kubernetes, they were able to orchestrate a unified platform that enhanced communication across various business functions. The success of this project led to reduced operational costs, improved efficiency, and fostered a culture of innovation. Healthcare Sector In the healthcare sector, a leading hospital network leveraged containerization to integrate various patient care systems. This ensured that patient records, treatment plans, and medical histories were accessible across different departments and locations. By providing a consistent and secure environment, containerization enabled better collaboration between healthcare professionals, leading to improved patient outcomes. E-Commerce An e-commerce giant harnessed the power of containerization to integrate its supply chain management, inventory tracking, and customer relationship systems. The containerized environment allowed for real-time updates and synchronization, enabling them to respond rapidly to market trends and customer demands. The enhanced agility and responsiveness proved crucial in maintaining a competitive edge in the fast-paced online marketplace. Use Cases in Containerized Application Integration The use cases of containerization in application integration are vast and diverse, reflecting the adaptability and potential of this technology. Microservices Architecture Microservices architecture, a key trend in software development, has found a strong ally in containerization. By allowing individual services to run in separate containers, developers can create more modular and scalable applications. This approach not only makes deployment and maintenance more straightforward but also facilitates more flexible development cycles, catering to the unique demands of each service. Cross-Platform Integration The days of struggling with cross-platform compatibility issues are alleviated with containerization. Whether integrating applications running on Linux with those on Windows or bridging the gap between on-premises and cloud systems, containerization ensures that the application environment remains consistent. This consistency accelerates development, simplifies testing, and ensures that applications run smoothly across different platforms. Enhancing Scalability For businesses operating in a dynamic market, scalability is often a pressing concern. Containerization's inherent ability to scale quickly enables organizations to adapt to changing business conditions without overhauling their existing infrastructure. It allows them to deploy or modify services efficiently, whether scaling up to meet peak demands or scaling down during quieter periods. As Mark Russinovich, CTO of Microsoft Azure, states, "Containerization is not a mere technology trend; it's a strategic enabler that's shaping the future of application integration, offering unprecedented agility, scalability, and efficiency." The Horizon: Containerization's Revolutionary Impact Containerization in application integration is more than a mere technological advancement; it represents a philosophical shift in how we approach software development and integration. From its roots in resolving the complexities of integrating disparate systems to its current role in facilitating microservices architecture, cross-platform integration, and scalability, containerization stands as a testament to innovation and adaptability. The real-world applications across industries like finance, healthcare, and e-commerce, coupled with specific use cases such as enhancing scalability and ensuring consistency across platforms, paint a vivid picture of containerization's expansive influence. While challenges related to security, performance, and compliance cannot be overlooked, the trajectory of containerization's growth, underscored by technologies like Docker and Kubernetes, demonstrates a forward-thinking approach that is here to stay. In reflecting on the journey of containerization, one can't help but agree with Martin Fowler, a prominent figure in software development, who remarked, "Containerization has not only solved technical problems but has started a conversation about collaboration, consistency, and experimentation that transcends traditional boundaries."
Containerization has completely transformed the process of developing and deploying applications in modern software development practices. Docker, a prominent containerization platform, has experienced widespread adoption owing to its ease of use, portability, and effectiveness. Nevertheless, handling containers on a large scale can present challenges. This is precisely where Amazon Elastic Container Service (ECS) proves invaluable. This article will discover the benefits and capabilities of employing Amazon ECS for Docker containerization. What Is Amazon ECS? Amazon Elastic Container Service (ECS) is a completely managed container orchestration service that Amazon Web Services (AWS) offers. It facilitates the execution of Docker containers in a scalable and highly available environment. While it also prioritizes security. It streamlines the deployment, management, and scaling of containerized applications. This allows developers to concentrate on enhancing and constructing their applications rather than being preoccupied with infrastructure management. ECS Task Definitions In Amazon ECS, a task definition serves as a blueprint that outlines the launch and execution of a container within a cluster. It encompasses vital details like the Docker image selection, container resource needs, networking information, and additional configurations. Task definitions offer a declarative approach to specifying your application's requirements, simplifying the management and upkeep of containerized applications. ECS Task Scheduling Strategies Amazon ECS provides two task scheduling strategies: EC2 launch type and Fargate launch type. EC2 Launch Type Using the EC2 launch type, ECS runs containers on a cluster of EC2 instances you manage. This provides greater control over the infrastructure, allowing you to utilize EC2 features like custom instance types and placement strategies. The EC2 launch type is ideal for applications with specific networking or hardware requirements. Fargate Launch Type Conversely, the Fargate launch type enables you to deploy containers without managing any underlying infrastructure. ECS takes care of the provisioning and scaling of Fargate containers, making it a serverless containerization solution. Fargate is perfect for users seeking a straightforward and cost-efficient method of running containers without the need to handle EC2 instances. Benefits of Using Amazon ECS for Docker Containerization Simplified Management Amazon ECS simplifies the management of containers at scale by abstracting away complexities. Users can concentrate on application development as ECS handles container deployment, scaling, and monitoring, thereby minimizing operational overhead. Cost-Effective By employing Amazon ECS, users can optimize resource utilization, guaranteeing payment solely for the consumed compute resources. The Fargate launch type, specifically, presents a serverless and cost-effective approach to containerization. Reliable and Highly Available Equipped with features such as multi-AZ deployment and container health monitoring, Amazon ECS ensures high availability and fault tolerance, promoting application reliability and accessibility. Conclusion Amazon ECS is a reliable and intuitive container orchestration service, making it a top pick for Docker containerization on AWS. It streamlines the administration of containerized applications, seamlessly integrates with various AWS services, and offers economical and scalable options for container deployment. With both the EC2 launch type and Fargate launch type to choose from, Amazon ECS enables developers to prioritize innovation while AWS handles the foundational infrastructure.
In the rapidly evolving domain of machine learning (ML), the ability to seamlessly package and deploy models is as crucial as the development of the models themselves. Containerization has emerged as the game-changing solution to this, offering a streamlined path from the local development environment to production. Docker, a leading platform in containerization, provides the tools necessary to encapsulate ML applications into portable and scalable containers. This article delves into the step-by-step process of containerizing a simple ML application with Docker, making it accessible to ML practitioners and enthusiasts alike. Whether you're looking to share your ML models with the world or seeking a more efficient deployment strategy, this tutorial is designed to equip you with the fundamental skills to transform your ML workflows using Docker. Docker and Containerization Docker is a powerful platform that has revolutionized the development and distribution of applications by utilizing containerization, a lightweight alternative to full-machine virtualization. Containerization involves encapsulating an application and its environment — dependencies, libraries, and configuration files — into a container, which is a portable and consistent unit of software. This approach ensures that the application runs uniformly and consistently across any infrastructure, from a developer's laptop to a high-compute cloud-based server. Unlike traditional virtual machines that replicate an entire operating system, Docker containers share the host system's kernel, making them much more efficient, fast to start, and less resource-intensive. Docker's simple and straightforward syntax hides the complexity often involved in deployment processes, streamlining the workflow and enabling a DevOps approach to the lifecycle management of the software development process. Tutorial Below is a step-by-step tutorial that will guide you through the process of containerizing a simple ML application using Docker. Setting Up Your Development Environment Before you start, make sure you have Docker installed on your machine. If not, you can download it from the Docker website. Creating a Simple Machine Learning Application For this tutorial, let's create a simple Python application that uses the Scikit-learn library to train a model on the Iris dataset. Create a Project Directory Open your terminal or command prompt and run the following: Shell mkdir ml-docker-app cd ml-docker-app Set up a Python Virtual Environment (Optional, but Recommended) Shell python3 -m venv venv On Windows use venv\Scripts\activate Create a requirements.txt File List the Python packages that your application requires. For our simple ML application: Shell scikit-learn==1.0.2 pandas==1.3.5 Create the Machine Learning Application Script Save the following code into a file named app.py in the ml-docker-app directory: Python from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score import joblib # Load dataset iris = datasets.load_iris() X = iris.data y = iris.target # Split dataset into training set and test set X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3) # Create a Gaussian Classifier clf = RandomForestClassifier() # Train the model using the training sets clf.fit(X_train, y_train) # Predict the response for test dataset y_pred = clf.predict(X_test) # Model Accuracy, how often is the classifier correct? print(f"Accuracy: {accuracy_score(y_test, y_pred)}") # Save the trained model joblib.dump(clf, 'iris_model.pkl') Install the Dependencies Run the following command to install the dependencies listed in requirements.txt: Shell pip install -r requirements.txt Run Your Application Run your application to make sure it works: Shell python3 app.py You should see the accuracy of the model printed to the console and a file named iris_model.pkl created, which contains the trained model. This script provides an end-to-end flow of a very basic machine learning task: loading data, preprocessing it, training a model, evaluating the model, and then saving the trained model for future use. Containerize the Application With Docker Create a ‘Dockerfile’ In the root of your ml-docker-app directory, create a file named Dockerfile with the following content: Python # Use an official Python runtime as a parent image FROM python:3.9-slim # Set the working directory in the container WORKDIR /usr/src/app # Copy the current directory contents into the container at /usr/src/app COPY . . # Install any needed packages specified in requirements.txt RUN pip install --no-cache-dir -r requirements.txt # Run app.py when the container launches Build the Docker Image Run the following command in your terminal to build the Docker image: Shell docker build -t ml-docker-app . Run the Docker Container Once the image is built, run your application in a Docker container: Shell docker run ml-docker-app If everything is set up correctly, Docker will run your Python script inside a container, and you should see the accuracy of the model outputted to your terminal, just like when you ran the script natively. Tag and Push the Container to DockerHub Log in to Docker Hub from the Command Line Once you have a Docker Hub account, you need to log in through the command line on your local machine. Open your terminal and run: Shell docker login You will be prompted to enter your Docker ID and password. Once logged in successfully, you can push images to your Docker Hub repository. Tag Your Docker Image Before you can push an image to Docker Hub, it must be tagged with your Docker Hub username. If you don’t tag it correctly, Docker will not know where to push the image. Assuming your Docker ID is a username, and you want to name your Docker image ml-docker-app, run: Shell docker tag ml-docker-app username/ml-docker-app This will tag the local ml-docker-app image as username/ml-docker-app, which prepares it to be pushed to your Docker Hub repository. Push the Image to Docker Hub To push the image to Docker Hub, use the docker push command followed by the name of the image you want to push: Shell docker push username/ml-docker-app Docker will upload the image to your Docker Hub repository. Check the Pushed Container Image on Docker Hub You can go to your Docker Hub repository and see the recently pushed image. That's it! You have successfully containerized a simple machine learning application, pushed it to Docker Hub, and made it available to be pulled and run from anywhere.
Welcome back to the series exploring the synergy between Ballerina and GraalVM. In the previous article, ‘Ballerina Code to GraalVM Executable,’ we delved into the seamless integration of Ballerina and GraalVM, witnessing how Ballerina applications can build GraalVM native executable and achieve improved performance and reduced memory consumption. In this continuation, we take the next step in our journey, exploring how to containerize a Ballerina GraalVM executable. If you have not read the previous article, I recommend you do so before continuing with this one. We will use the same Conference Service application to build a Docker image containing the GraalVM executable. The code for this application can be found in the below link: GitHub — TharmiganK/conference-service-ballerina: A RESTful conference service written in…A RESTful conference service which is written in Ballerina. — GitHub — TharmiganK/conference-service-ballerina: A RESTful…github.com We will be looking into the following ways to create the Docker image. Using a custom Docker file. Using the Ballerina Code to Cloud feature. Using a Custom Docker File As we know already, the GraalVM native executable is platform-dependent. If you are a Linux user, then you can build the GraalVM executable locally and pass it to a Docker with the simplest slim container. If you are using macOS or Windows to build a Docker image containing the GraalVM executable, then you have to build the executable in a Docker container. In this post, I am using a macOS, so I need to build the executable in a Docker container that has the GraalVM native image tool. The GraalVM community already has container images with the native-image tool. The images can be found on the GraalVM container page. Since Ballerina Swan Lake Update 7 works with Java11, I have chosen this image: ghcr.io/graalvm/native-image:ol8-java11–22.3.3. Let’s start by building the application and obtaining the JAR file. $ bal build Compiling source tharmigan/conference_service:1.0.0 Generating executable target/bin/conference_service.jar Use the following Docker file to build the GraalVM executable in the graalvm/native-image container and run the executable in adebian:stable-slim container. Dockerfile FROM ghcr.io/graalvm/native-image:ol8-java11-22.3.3 as build WORKDIR /app/build COPY target/bin/conference_service.jar . RUN native-image -jar conference_service.jar --no-fallback FROM debian:stable-slim WORKDIR /home/ballerina COPY --from=build /app/build/conference_service . CMD echo "time = $(date +"%Y-%m-%dT%H:%M:%S.%3NZ") level = INFO module = tharmigan/conference_service message = Executing the Ballerina application" && "./conference_service" Build the Docker image. $ docker build . -t ktharmi176/conference-service:1.0.0 Use the following Docker compose file to run the conference_service and the mock country_service in the host network. YAML version: '2' services: conference-service: image: 'ktharmi176/conference-service:1.0.0' ports: - '8102:8102' volumes: - ./Config.toml:/home/ballerina/Config.toml depends_on: country-service: condition: service_started network_mode: "host" country-service: image: 'ktharmi176/country-service:latest' hostname: country-service container_name: country-service ports: - '9000:9000' network_mode: "host" Check the image names and run the following command: $ docker compose up Now, the two services have been started. Test the service using the request.http file. Using the Ballerina Code to Cloud Feature Default Mode The Code to Cloud feature in Ballerina enables developers to quickly deploy their Ballerina applications to cloud platforms without the need for extensive configuration or manual setup. It aims to reduce the complexity of cloud-native development and streamline the deployment process. We can simply run the following command to build the GraalVM executable in a Docker container. $ bal build --graalvm --cloud=docker Compiling source tharmigan/conference_service:1.0.0 Generating artifacts Building the native image. This may take a while [+] Building 331.1s (13/13) FINISHED docker:default => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 439B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for gcr.io/distroless/base:latest 3.0s => [internal] load metadata for ghcr.io/graalvm/native-image:ol8-java11-22.3.3 3.7s => [build 1/4] FROM ghcr.io/graalvm/native-image:ol8-java11-22.3.3@sha256:c0b4d9c31013d4fd91c4dec25f8772602e851ee67b8510d21bfdab532da4c17c 0.0s => [stage-1 1/3] FROM gcr.io/distroless/base@sha256:73deaaf6a207c1a33850257ba74e0f196bc418636cada9943a03d7abea980d6d 0.0s => [internal] load build context 0.4s => => transferring context: 42.65MB 0.4s => CACHED [stage-1 2/3] WORKDIR /home/ballerina 0.0s => CACHED [build 2/4] WORKDIR /app/build 0.0s => [build 3/4] COPY conference_service.jar . 0.1s => [build 4/4] RUN native-image -jar conference_service.jar -H:Name=conference_service --no-fallback -H:+StaticExecutableWithDynamicLibC 326.3s => [stage-1 3/3] COPY --from=build /app/build/conference_service . 0.3s => exporting to image 0.3s => => exporting layers 0.3s => => writing image sha256:4a6e1223a8d5a0446b688b110522bdc796027bfc1bc4fe533c62be649900ee05 0.0s => => naming to docker.io/library/conference_service:latest 0.0s Execute the below command to run the generated Docker image: docker run -d conference_service:latest The auto-generated Docker file can be found in the following path: target/docker/conference_service Dockerfile # Auto Generated Dockerfile FROM ghcr.io/graalvm/native-image:ol8-java11-22.3.3 as build WORKDIR /app/build COPY conference_service.jar . RUN native-image -jar conference_service.jar -H:Name=conference_service --no-fallback -H:+StaticExecutableWithDynamicLibC FROM gcr.io/distroless/base WORKDIR /home/ballerina COPY --from=build /app/build/conference_service . CMD ["./conference_service"] Note: By default, Ballerina builds a mostly-static native-image and packs it in a distorless container. For more information on GraalVM mostly-static images, see Static and Mostly Static Images. Now, let’s run docker-compose after changing the image name of the conference_service. YAML version: '2' services: conference-service: image: 'conference_service:latest' ports: - '8102:8102' volumes: - ./Config.toml:/home/ballerina/Config.toml depends_on: country-service: condition: service_started network_mode: "host" country-service: image: 'ktharmi176/country-service:latest' hostname: country-service container_name: country-service ports: - '9000:9000' network_mode: "host" Test the service using the request.http file. Configure Mode The Code to Cloud feature supports overriding the default mode where we configure the following: The GraalVM build-image The native-image build command The base image for the deployment This can be achieved by providing the configurations via Cloud.toml file. The following shows an example to provide the same configurations used for the custom Docker file. TOML [container.image] name = "conference-service" repository = "ktharmi176" tag = "1.0.0" base = "debian:stable-slim" [graalvm.builder] base = "ghcr.io/graalvm/native-image:ol8-java11-22.3.3" buildCmd = "native-image -jar conference_service.jar --no-fallback" Run the following command to build the Docker image with the above configurations. $ bal build --graalvm --cloud=docker Compiling source tharmigan/conference_service:1.0.0 Generating artifacts Building the native image. This may take a while [+] Building 310.0s (14/14) FINISHED docker:default => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 372B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/debian:stable-slim 3.9s => [internal] load metadata for ghcr.io/graalvm/native-image:ol8-java11-22.3.3 2.5s => [auth] library/debian:pull token for registry-1.docker.io 0.0s => [build 1/4] FROM ghcr.io/graalvm/native-image:ol8-java11-22.3.3@sha256:c0b4d9c31013d4fd91c4dec25f8772602e851ee67b8510d21bfdab532da4 0.0s => [stage-1 1/3] FROM docker.io/library/debian:stable-slim@sha256:6fe30b9cb71d604a872557be086c74f95451fecd939d72afe3cffca3d9e60607 0.0s => [internal] load build context 0.3s => => transferring context: 42.65MB 0.3s => CACHED [stage-1 2/3] WORKDIR /home/ballerina 0.0s => CACHED [build 2/4] WORKDIR /app/build 0.0s => [build 3/4] COPY conference_service.jar . 0.1s => [build 4/4] RUN native-image -jar conference_service.jar --no-fallback 305.1s => [stage-1 3/3] COPY --from=build /app/build/conference_service . 0.2s => exporting to image 0.3s => => exporting layers 0.3s => => writing image sha256:1f5b5b30653a48a6d27258f785d93a1654dde25d2e70899e14f2b61996e01996 0.0s => => naming to docker.io/ktharmi176/conference-service:1.0.0 0.0s Execute the below command to run the generated Docker image: docker run -d ktharmi176/conference-service:1.0.0 The auto-generated Docker file with the above configurations will look like this. Dockerfile # Auto Generated Dockerfile FROM ghcr.io/graalvm/native-image:ol8-java11-22.3.3 as build WORKDIR /app/build COPY conference_service.jar . RUN native-image -jar conference_service.jar --no-fallback FROM debian:stable-slim WORKDIR /home/ballerina COPY --from=build /app/build/conference_service . CMD ["./conference_service"] This is the same as the one we wrote manually. Run Docker-compose and check the functionality using the request.http file. In conclusion, we have built a GraalVM executable for a Ballerina application and containerized it in Docker. GraalVM and Ballerina with the Code to Cloud feature simplify the experience of developing and deploying the Ballerina GraalVM native image in the cloud. It also enables the use of cloud-native technologies with GraalVM easily without in-depth knowledge.
Building complex container-based architectures is not very different from programming in terms of applying design best practices and principles. The goal of this article is to present three popular extensibility architectural patterns from a developer's perspective using well-known programming principles. Let's start with the Single Responsibility Principle. According to R. Martin, "A class should have only one reason to change." But classes are abstractions used to simplify real-world problems and represent software components. Hence, a component should have only one reason to change over time. Software services and microservices in particular are also components (runtime components) and should have only one reason to change. Microservices are supposed to be a single deployable unit, meaning they are deployed independently of other components and can have as many instances as needed. But is that always true? Are microservices always deployed as a single unit? In Kubernetes, the embodiment of a microservice is a Pod. A Pod is defined as a group of containers that share resources like file systems, kernel namespaces, and an IP address. The Pod is the atomic unit of scheduling in a Kubernetes cluster and each Pod is meant to run a single instance of a given application. According to the documentation, "Pods are designed to support multiple cooperating processes (as containers) that form a cohesive unit of service. The containers in a Pod are automatically co-located and co-scheduled on the same physical or virtual machine in the cluster. Scaling an application horizontally means replicating Pods. According to the Kubernetes documentation, Pods can be configured using two strategies: Pods that run a single container: The "one-container-per-Pod" model is the most common Kubernetes use case; the Pod is a wrapper around a single container and Kubernetes manages Pods rather than managing the containers directly. Pods that run multiple containers working together: A Pod can encapsulate an application composed of multiple co-located containers that are tightly coupled and need to share resources. These co-located containers form a single cohesive unit of service—for example, one container serving data stored in a shared volume to the public, while a separate sidecar container refreshes or updates those files. The Pod wraps these containers, storage resources, and an ephemeral network identity together as a single unit." The answer is: NO! Microservices are NOT always deployed as a single unit! Next to some popular architectural patterns for the cloud like scalability patterns, deployment and reliability patterns are extensibility architectural patterns. We will have a closer look at the three most popular extensibility patterns for cloud architectures: Sidecar pattern Ambassador pattern Adapter pattern Sidecar Pattern Problem Each deployable service/application has its own "reason to change," or responsibility. However, in addition to its core functionality it needs to do other things called in the software developer terminology "cross-cutting concerns." One example is the collection of performance metrics that need to be sent to a monitoring service. Another one is logging events and sending them to a distributed logging service. I called them cross-cutting concerns, as they do not directly relate to business logic and are needed by multiple services, they basically represent reusable functionality that needs to be part of each deployed unit. Solution The solution to that problem is called the sidecar pattern and imposes the creation of an additional container called a sidecar container. Sidecar containers are an extension of the main container following the Open-Closed design principle (opened for extension, closed for modification). They are tightly coupled with the "main" container in terms of deployment as they are deployed as part of the same Pod but are still easy to replace and do not break the single responsibility of the extended container. Furthermore, the achieved modularity allows for isolated testing of business-related functionality and additional helper services like event logging or monitoring. The communication of the two containers is fast and reliable and they share access to the same resources enabling the helper component to provide reusable infrastructure-related services. In addition, it is applicable to many types of services solving the issue with heterogeneity in terms of different technologies used. The upgrade of the sidecar components is also straightforward as it usually means the upgrade of a Docker container version and redeploying using for example the no-down-time Kubernetes strategies. Ambassador Containers Problem Deployed services do not function in isolation. They usually communicate over the network to other services even outside the application or software platform controlled by a single organization. Integrations between components in general imply integration with external APIs and also dealing with failures or unavailability of external systems. A common practice for external systems integration is to define the so-called API Facade, an internal API that hides the complexity of external system APIs. The role of the API Facades is to isolate the external dependencies providing an implementation of the internal API definition and taking care of security and routing if needed. In addition, failures and unavailability of external systems are usually handled using some common patterns like the Retry Pattern, Circuit Breaker Pattern, and sometimes backed by Local Caching. All these technicalities would complicate the main service and appear to be candidates for a helper container. Solution The solution to that problem is called Ambassador Pattern and implies the creation of an additional container called an Ambassador container. Ambassador containers proxy a local connection to the world, they are basically a type of Sidecar container. This composition of containers is powerful, not just because of the separation of concerns and the fact that different teams can easily own the components but it also allows for an easy mocking of external services for local development environments. Adapter Containers Problem There are still many monolith systems planned for migration to more lightweight architectures. Migrations, though, can not happen in one pass, and it is also risky to wait for the rewriting of a whole system for years while also supporting the addition of new features in both versions of the system. Migrations should happen in small pieces publishing separate services and integrating them one by one. That process repeats until the legacy monolith system is gone. So we have a new part of the system supporting new APIs and an old part that still supports old APIs. For example, we might have newly implemented REST services and still have some old SOAP-based services. We need something that takes care of exposing the old functionality as if all the services were migrated and can be integrated by the clients' systems. Solution The solution to that problem is called Adapter or Anti-Corruption pattern. The Adapter container takes care of translating from one communication protocol to another and from one data model to another while hiding the actual service from the external world. Furthermore, the Adapter container can provide two-way communication. If the legacy system needs to communicate with the new services it could also be the adapting component for that communication serving as a kind of an Ambassador container until the migration is finalized. In this article, we saw how container composition provides an extensibility mechanism without an actual change of the main application container providing stability and reusability by allowing the composite pod to be treated as any other simple pod exposing a single and simple service in a microservice architecture. One would ask why not use a library and share it across many containers. Well, that is also a solution but then we are facing the shared responsibility problem of introducing coupling between all the services using it. In addition, heterogeneous services would require rewriting the libraries using all the supported languages. That also breaks the Single Responsibility Principle, which we would in any case like to keep.
This is an article from DZone's 2023 Kubernetes in the Enterprise Trend Report.For more: Read the Report Cloud-native architecture is a transformative approach to designing and managing applications. This type of architecture embraces the concepts of modularity, scalability, and rapid deployment, making it highly suitable for modern software development. Though the cloud-native ecosystem is vast, Kubernetes stands out as its beating heart. It serves as a container orchestration platform that helps with automatic deployments and the scaling and management of microservices. Some of these features are crucial for building true cloud-native applications. In this article, we explore the world of containers and microservices in Kubernetes-based systems and how these technologies come together to enable developers in building, deploying, and managing cloud-native applications at scale. The Role of Containers and Microservices in Cloud-Native Environments Containers and microservices play pivotal roles in making the principles of cloud-native architecture a reality. Figure 1: A typical relationship between containers and microservices Here are a few ways in which containers and microservices turn cloud-native architectures into a reality: Containers encapsulate applications and their dependencies. This encourages the principle of modularity and results in rapid development, testing, and deployment of application components. Containers also share the host OS, resulting in reduced overhead and a more efficient use of resources. Since containers provide isolation for applications, they are ideal for deploying microservices. Microservices help in breaking down large monolithic applications into smaller, manageable services. With microservices and containers, we can scale individual components separately. This improves the overall fault tolerance and resilience of the application as a whole. Despite their usefulness, containers and microservices also come with their own set of challenges: Managing many containers and microservices can become overly complex and create a strain on operational resources. Monitoring and debugging numerous microservices can be daunting in the absence of a proper monitoring solution. Networking and communication between multiple services running on containers is challenging. It is imperative to ensure a secure and reliable network between the various containers. How Does Kubernetes Make Cloud Native Possible? As per a survey by CNCF, more and more customers are leveraging Kubernetes as the core technology for building cloud-native solutions. Kubernetes provides several key features that utilize the core principles of cloud-native architecture: automatic scaling, self-healing, service discovery, and security. Figure 2: Kubernetes managing multiple containers within the cluster Automatic Scaling A standout feature of Kubernetes is its ability to automatically scale applications based on demand. This feature fits very well with the cloud-native goals of elasticity and scalability. As a user, we can define scaling policies for our applications in Kubernetes. Then, Kubernetes adjusts the number of containers and Pods to match any workload fluctuations that may arise over time, thereby ensuring effective resource utilization and cost savings. Self-Healing Resilience and fault tolerance are key properties of a cloud-native setup. Kubernetes excels in this area by continuously monitoring the health of containers and Pods. In case of any Pod failures, Kubernetes takes remedial actions to ensure the desired state is maintained. It means that Kubernetes can automatically restart containers, reschedule them to healthy nodes, and even replace failed nodes when needed. Service Discovery Service discovery is an essential feature of a microservices-based cloud-native environment. Kubernetes offers a built-in service discovery mechanism. Using this mechanism, we can create services and assign labels to them, making it easier for other components to locate and communicate with them. This simplifies the complex task of managing communication between microservices running on containers. Security Security is paramount in cloud-native systems and Kubernetes provides robust mechanisms to ensure the same. Kubernetes allows for fine-grained access control through role-based access control (RBAC). This certifies that only authorized users can access the cluster. In fact, Kubernetes also supports the integration of security scanning and monitoring tools to detect vulnerabilities at an early stage. Advantages of Cloud-Native Architecture Cloud-native architecture is extremely important for modern organizations due to the evolving demands of software development. In this era of digital transformation, cloud-native architecture acts as a critical enabler by addressing the key requirements of modern software development. The first major advantage is high availability. Today's world operates 24/7, and it is essential for cloud-native systems to be highly available by distributing components across multiple servers or regions in order to minimize downtime and ensure uninterrupted service delivery. The second advantage is scalability to support fluctuating workloads based on user demand. Cloud-native applications deployed on Kubernetes are inherently elastic, thereby allowing organizations to scale resources up or down dynamically. Lastly, low latency is a must-have feature for delivering responsive user experiences. Otherwise, there can be a tremendous loss of revenue. Cloud-native design principles using microservices and containers deployed on Kubernetes enable the efficient use of resources to reduce latency. Architecture Trends in Cloud Native and Kubernetes Cloud-native architecture with Kubernetes is an ever-evolving area, and several key trends are shaping the way we build and deploy software. Let's review a few important trends to watch out for. The use of Kubernetes operators is gaining prominence for stateful applications. Operators extend the capabilities of Kubernetes by automating complex application-specific tasks, effectively turning Kubernetes into an application platform. These operators are great for codifying operational knowledge, creating the path to automated deployment, scaling, and management of stateful applications such as databases. In other words, Kubernetes operators simplify the process of running applications on Kubernetes to a great extent. Another significant trend is the rise of serverless computing on Kubernetes due to the growth of platforms like Knative. Over the years, Knative has become one of the most popular ways to build serverless applications on Kubernetes. With this approach, organizations can run event-driven and serverless workloads alongside containerized applications. This is great for optimizing resource utilization and cost efficiency. Knative's auto-scaling capabilities make it a powerful addition to Kubernetes. Lastly, GitOps and Infrastructure as Code (IaC) have emerged as foundational practices for provisioning and managing cloud-native systems on Kubernetes. GitOps leverages version control and declarative configurations to automate infrastructure deployment and updates. IaC extends this approach by treating infrastructure as code. Best Practices for Building Kubernetes Cloud-Native Architecture When building a Kubernetes-based cloud-native system, it's great to follow some best practices: Observability is a key practice that must be followed. Implementing comprehensive monitoring, logging, and tracing solutions gives us real-time visibility into our cluster's performance and the applications running on it. This data is essential for troubleshooting, optimizing resource utilization, and ensuring high availability. Resource management is another critical practice that should be treated with importance. Setting resource limits for containers helps prevent resource contention and ensures a stable performance for all the applications deployed on a Kubernetes cluster. Failure to manage the resource properly can lead to downtime and cascading issues. Configuring proper security policies is equally vital as a best practice. Kubernetes offers robust security features like role-based access control (RBAC) and Pod Security Admission that should be tailored to your organization's needs. Implementing these policies helps protect against unauthorized access and potential vulnerabilities. Integrating a CI/CD pipeline into your Kubernetes cluster streamlines the development and deployment process. This promotes automation and consistency in deployments along with the ability to support rapid application updates. Conclusion This article has highlighted the significant role of Kubernetes in shaping modern cloud-native architecture. We've explored key elements such as observability, resource management, security policies, and CI/CD integration as essential building blocks for success in building a cloud-native system. With its vast array of features, Kubernetes acts as the catalyst, providing the orchestration and automation needed to meet the demands of dynamic, scalable, and resilient cloud-native applications. As readers, it's crucial to recognize Kubernetes as the linchpin in achieving these objectives. Furthermore, the takeaway is to remain curious about exploring emerging trends within this space. The cloud-native landscape continues to evolve rapidly, and staying informed and adaptable will be key to harnessing the full potential of Kubernetes. Additional Reading: CNCF Annual Survey 2021 CNCF Blog "Why Google Donated Knative to the CNCF" by Scott Carey Getting Started With Kubernetes Refcard by Alan Hohn "The Beginner's Guide to the CNCF Landscape" by Ayrat Khayretdinov This is an article from DZone's 2023 Kubernetes in the Enterprise Trend Report.For more: Read the Report
Yitaek Hwang
Software Engineer,
NYDIG
Abhishek Gupta
Principal Developer Advocate,
AWS
Marija Naumovska
Product Manager,
Microtica