Integrating PostgreSQL Databases with ANF: Join this workshop to learn how to create a PostgreSQL server using Instaclustr’s managed service
Mobile Database Essentials: Assess data needs, storage requirements, and more when leveraging databases for cloud and edge applications.
In the SDLC, deployment is the final lever that must be pulled to make an application or system ready for use. Whether it's a bug fix or new release, the deployment phase is the culminating event to see how something works in production. This Zone covers resources on all developers’ deployment necessities, including configuration management, pull requests, version control, package managers, and more.
Docker and Kubernetes Transforming Modern Deployment
Streamlined Infrastructure Deployment: Harnessing the Power of Terraform and Feature Toggles
This is an article from DZone's 2023 Automated Testing Trend Report.For more: Read the Report DevOps and CI/CD pipelines help scale application delivery drastically — with some organizations reporting over 208 times more frequent code deployments. However, with such frequent deployments, the stability and reliability of the software releases often become a challenge. This is where automated testing comes into play. Automated testing acts as a cornerstone in supporting efficient CI/CD workflows. It helps organizations accelerate applications into production and optimize resource efficiency by following a fundamental growth principle: build fast, fail fast. This article will cover the importance of automated testing, some key adoption techniques, and best practices for automated testing. The Importance of Automated Testing in CI/CD Manual tests are prone to human errors such as incorrect inputs, misclicks, etc. They often do not cover a broad range of scenarios and edge cases compared to automated testing. These limitations make automated testing very important to the CI/CD pipeline. Automated testing directly helps the CI/CD pipeline through faster feedback cycles to developers, testing in various environments simultaneously, and more. Let's look at the specific ways in which it adds value to the CI/CD pipeline. Validate Quality of Releases Releasing a new feature is difficult and often very time-consuming. Automated testing helps maintain the quality of software releases, even on a tight delivery timeline. For example, automated smoke tests ensure new features work as expected. Similarly, automated regression tests check that the new release does not break any existing functionality. Therefore, development teams can have confidence in the release's reliability, quality, and performance with automated tests in the CI/CD pipeline. This is especially useful in organizations with multiple daily deployments or an extensive microservices architecture. Identify Bugs Early Another major advantage of automated testing in CI/CD is its ability to identify bugs early in the development cycle. Shifting testing activities earlier in the process (i.e., shift-left testing) can detect and resolve potential issues during the non-development phases. For example, instead of deploying a unit of code to a testing server and waiting for testers to find the bugs, you can add many unit tests in the test suite. This will allow developers to identify and fix issues on their local systems, such as data handling or compatibility with third-party services in the proof of concept (PoC) phase. Figure 1: Shift-left testing technique Faster Time to Market Automated testing can help reduce IT costs and ensure faster time to market, giving companies a competitive edge. With automated testing, the developer receives rapid feedback instantly. Thus, organizations can catch defects early in the development cycle and reduce the inherent cost of fixing them. Ease of Handling Changes Minor changes and updates are common as software development progresses. For example, there could be urgent changes based on customer feedback on a feature, or an issue in a dependency package, etc. With automated tests in place, developers receive quick feedback on all their code changes. All changes can be validated quickly, making sure that new functionalities do not introduce unintended consequences or regressions. Promote Collaboration Across Teams Automated testing promotes collaboration among development, testing, and operations teams through DevTestOps. The DevTestOps approach involves ongoing testing, integration, and deployment. As you see in Figure 2, the software is tested throughout the development cycle to proactively reduce the number of bugs and inefficiencies at later stages. Using automated testing allows teams to be on the same page regarding the expected output. Teams can communicate and align their understanding of the software requirements and expected behavior with a shared set of automated tests. Figure 2: DevTestOps approach Maintain Software Consistency Automated testing also contributes to maintaining consistency and agility throughout the CI/CD pipeline. Teams can confirm that software behaves consistently by generating and comparing multiple test results across different environments and configurations. This consistency is essential in achieving predictable outcomes and avoiding deployment issues. Adoption Techniques Adopting automated testing in a CI/CD pipeline requires a systematic approach to add automated tests at each stage of the development and deployment processes. Let's look at some techniques that developers, testers, and DevOps can follow to make the entire process seamless. Figure 3: Automated testing techniques in the CI/CD process Version Control for Test Data Using version control for your test assets helps synchronize tests with code changes, leading to collaboration among developers, testers, and other stakeholders. Organizations can effectively manage test scripts, test data, and other testing artifacts with a version control system, such as Git, for test assets. For example, a team can use centralized repositories to keep all test data in sync instead of manually sharing Java test cases between different teams. Using version control for your test data also allows for quick database backups if anything goes wrong during testing. Test data management involves strategies for handling test data, such as data seeding, database snapshots, or test data generation. Managing test data effectively ensures automated tests are performed with various scenarios and edge cases. Test-Driven Development Test-driven development (TDD) is an output-driven development approach where tests are written before the actual code, which guides the development process. As developers commit code changes, the CI/CD system automatically triggers the test suite to check that the changes adhere to the predefined requirements. This integration facilitates continuous testing, and allows developers to get instant feedback on the quality of their code changes. TDD also encourages the continuous expansion of the automated test suite, and hence, greater test coverage. Implement Continuous Testing By implementing continuous testing, automated tests can be triggered when code is changed, a pull request (PR) is created, a build is generated, or before a PR is merged within the CI/CD pipeline. This approach helps reduce the risk of regression issues, and ensures that software is always in a releasable state. With continuous testing integration, automated tests are seamlessly integrated into the development and release process, providing higher test coverage and early verification of non-functional requirements. Use Industry Standard Test Automation Frameworks Test automation frameworks are crucial to managing test cases, generating comprehensive reports, and seamlessly integrating with CI/CD tools. These frameworks provide a structured approach to organizing test scripts, reducing redundancy, and improving maintainability. Test automation frameworks offer built-in features for test case management, data-driven testing, and modular test design, which empower development teams to streamline their testing efforts. Example open-source test automation frameworks include — but are not limited to — SpecFlow and Maven. Low-Code Test Automation Frameworks Low-code test automation platforms allow testers to create automated tests with minimal coding by using visual interfaces and pre-built components. These platforms enable faster test script creation and maintenance, making test automation more accessible to non-technical team members. A few popular open-source low-code test automation tools include: Robot Framework Taurus Best Practices for Automated Testing As your automated test suite and test coverage grow, it's important to manage your test data and methods efficiently. Let's look at some battle-tested best practices to make your automated testing integration journey simpler. Parallel vs. Isolated Testing When implementing automated testing in CI/CD, deciding whether to execute tests in isolation or parallel is important. Isolated tests run independently and are ideal for unit tests, while parallel execution is great for higher-level tests such as integration and end-to-end tests. Prioritize tests based on their criticality and the time required for execution. To optimize testing time and accelerate feedback, consider parallelizing test execution. Developers can also significantly reduce the overall test execution time by running multiple tests simultaneously across different environments or devices. However, make sure to double-check that the infrastructure and test environment can handle the increased load to avoid any resource constraints that may impact test accuracy. DECISION MATRIX FOR ISOLATED vs. PARALLEL TESTING Factor Isolated Tests Parallel Tests Test execution time Slower execution time Faster execution time Test dependencies Minimal dependencies Complex dependencies Resources Limited resources Abundant resources Environment capacity Limited capacity High capacity Number of test cases Few test cases Many test cases Scalability Scalable Not easily scalable Resource utilization efficiency High Low Impact on CI/CD pipeline performance Minimal Potential bottleneck Testing budget Limited Sufficient Table 1 One-Click Migration Consider implementing a one-click migration feature in the CI/CD pipeline to test your application under different scenarios. Below is how you can migrate automated test scripts, configurations, and test data between different environments or testing platforms: Store your automated test scripts and configurations in version control. Create a containerized test environment. Create a build automation script to automate building the Docker image with the latest version of test scripts and all other dependencies. Configure your CI/CD tool (e.g., Jenkins, GitLab CI/CD, CircleCI) to trigger the automation script when changes are committed to the version control system. Define a deployment pipeline in your CI/CD tool that uses the Docker image to deploy the automated tests to the target environment. Finally, to achieve one-click migration, create a single button or command in your CI/CD tool's dashboard that initiates the deployment and execution of the automated tests. Use Various Testing Methods The next tip is to include various testing methods in your automated testing suite. Apart from traditional unit tests, you can incorporate smoke tests to quickly verify critical functionalities and regression tests to check that new code changes do not introduce regressions. Other testing types, such as performance testing, API testing, and security testing, can be integrated into the CI/CD pipeline to address specific quality concerns. In Table 2, see a comparison of five test types. COMPARISON OF VARIOUS TEST TYPES Test Type Goal Scope When to Perform Time Required Resources Required Smoke test Verify if critical functionalities work after changes Broad and shallow After code changes — build Quick — minutes to a few hours Minimal Sanity test Quick check to verify if major functionalities work Focused and narrow After smoke test Quick — minutes to a few hours Minimal Regression test Ensure new changes do not negatively impact existing features Comprehensive — retests everything After code changes — build or deployment Moderate — several hours to a few days Moderate Performance test Evaluate software's responsiveness, stability, and scalability Load, stress, and scalability tests Toward end of development cycle or before production release Moderate — several hours to a few days Moderate Security test Identify and address potential vulnerabilities and weaknesses Extensive security assessments Toward end of development cycle or before production release Moderate to lengthy — several days to weeks Extensive Table 2 According to the State of Test Automation Survey 2022, the following types of automation tests are preferred by most developers and testers because they have clear pass/fail results: Functional testing (66.5%) API testing (54.2%) Regression testing (50.5%) Smoke testing (38.2%) Maintain Your Test Suite Next, regularly maintain the automated test suite to match it to changing requirements and the codebase. An easy way to do this is to integrate automated testing with version control systems like Git. This way, you can maintain a version history of test scripts and synchronize your tests with code changes. Additionally, make sure to document every aspect of the CI/CD pipeline, including the test suite, test cases, testing environment configurations, and the deployment process. This level of documentation helps team members access and understand the testing procedures and frameworks easily. Documentation facilitates collaboration and knowledge sharing while saving time in knowledge transfers. Conclusion Automated testing processes significantly reduce the time and effort for testing. With automated testing, development teams can detect bugs early, validate changes quickly, and guarantee software quality throughout the CI/CD pipeline. In short, it helps development teams to deliver quality products and truly unlock the power of CI/CD. This is an article from DZone's 2023 Automated Testing Trend Report.For more: Read the Report
Machine learning (ML) has seen explosive growth in recent years, leading to increased demand for robust, scalable, and efficient deployment methods. Traditional approaches often need help operationalizing ML models due to factors like discrepancies between training and serving environments or the difficulties in scaling up. This article proposes a technique using Docker, an open-source platform designed to automate application deployment, scaling, and management, as a solution to these challenges. The proposed methodology encapsulates the ML models and their environment into a standardized Docker container unit. Docker containers offer numerous benefits, including consistency across development and production environments, ease of scaling, and simplicity in deployment. The following sections present an in-depth exploration of Docker, its role in ML model deployment, and a practical demonstration of deploying an ML model using Docker, from the creation of a Dockerfile to the scaling of the model with Docker Swarm, all exemplified by relevant code snippets. Furthermore, the integration of Docker in a Continuous Integration/Continuous Deployment (CI/CD) pipeline is presented, culminating with the conclusion and best practices for efficient ML model deployment using Docker. What Is Docker? As a platform, Docker automates software application deployment, scaling, and operation within lightweight, portable containers. The fundamental underpinnings of Docker revolve around the concept of 'containerization.' This virtualization approach allows software and its entire runtime environment to be packaged into a standardized unit for software development. A Docker container encapsulates everything an application needs to run (including libraries, system tools, code, and runtime) and ensures that it behaves uniformly across different computing environments. This facilitates the process of building, testing, and deploying applications quickly and reliably, making Docker a crucial tool for software development and operations (DevOps). When it comes to machine learning applications, Docker brings forth several advantages. Docker's containerized nature ensures consistency between ML models' training and serving environments, mitigating the risk of encountering discrepancies due to environmental differences. Docker also simplifies the scaling process, allowing multiple instances of an ML model to be easily deployed across numerous servers. These features have the potential to significantly streamline the deployment of ML models and reduce associated operational complexities. Why Dockerize Machine Learning Applications? In the context of machine learning applications, Docker offers numerous benefits, each contributing significantly to operational efficiency and model performance. Firstly, the consistent environment provided by Docker containers ensures minimal discrepancies between the development, testing, and production stages. This consistency eliminates the infamous "it works on my machine" problem, making it a prime choice for deploying ML models, which are particularly sensitive to changes in their operating environment. Secondly, Docker excels in facilitating scalability. Machine learning applications often necessitate running multiple instances of the same model for handling large volumes of data or high request rates. Docker enables horizontal scaling by allowing multiple container instances to be deployed quickly and efficiently, making it an effective solution for scaling ML models. Finally, Docker containers run in isolation, meaning they have their runtime environment, including system libraries and configuration files. This isolation provides an additional layer of security, ensuring that each ML model runs in a controlled and secure environment. The consistency, scalability, and isolation provided by Docker make it an attractive platform for deploying machine learning applications. Setting up Docker for Machine Learning This section focuses on the initial setup required for utilizing Docker with machine learning applications. The installation process of Docker varies slightly depending on the operating system in use. For Linux distributions, Docker is typically installed via the command-line interface, whereas for Windows and MacOS, a version of Docker Desktop is available. In each case, the Docker website provides detailed installation instructions that are straightforward to follow. The installation succeeded by pulling a Docker image from Docker Hub, a cloud-based registry service allowing developers to share applications or libraries. As an illustration, one can pull the latest Python image for use in machine learning applications using the command: Shell docker pull python:3.8-slim-buster Subsequently, running the Docker container from the pulled image involves the docker run command. For example, if an interactive Python shell is desired, the following command can be used: Shell docker run -it python:3.8-slim-buster /bin/bash This command initiates a Docker container with an interactive terminal (-it) and provides a shell (/bin/bash) inside the Python container. By following this process, Docker is effectively set up to assist in deploying machine learning models. Creating a Dockerfile for a Simple ML Model At the heart of Docker's operational simplicity is the Dockerfile, a text document that contains all the commands required to assemble a Docker image. Users can automate the image creation process by executing the Dockerfile through the Docker command line. A Dockerfile comprises a set of instructions and arguments laid out in successive lines. Instructions are Docker commands like FROM (specifies the base image), RUN (executes a command), COPY (copies files from the host to the Docker image), and CMD (provides defaults for executing the container). Consider a simple machine learning model built using Scikit-learn's Linear Regression algorithm as a practical illustration. The Dockerfile for such an application could look like this: Dockerfile # Use an official Python runtime as a parent image FROM python:3.8-slim-buster # Set the working directory in the container to /app WORKDIR /app # Copy the current directory contents into the container at /app ADD . /app # Install any needed packages specified in requirements.txt RUN pip install --no-cache-dir -r requirements.txt # Make port 80 available to the world outside this container EXPOSE 80 # Run app.py when the container launches CMD ["python", "app.py"] The requirements.txt file mentioned in this Dockerfile lists all the Python dependencies of the machine learning model, such as Scikit-learn, Pandas, and Flask. On the other hand, the app.py script contains the code that loads the trained model and serves it as a web application. By defining the configuration and dependencies in this Dockerfile, an image can be created that houses the machine learning model and the runtime environment required for its execution, facilitating consistent deployment. Building and Testing the Docker Image Upon successful Dockerfile creation, the subsequent phase involves constructing the Docker image. The Docker image is constructed by executing the docker build command, followed by the directory that contains the Docker file. The -t flag tags the image with a specified name. An instance of such a command would be: Shell docker build -t ml_model_image:1.0 Here, ml_model_image:1.0 is the name (and version) assigned to the image, while '.' indicates that the Dockerfile resides in the current directory. After constructing the Docker image, the following task involves initiating a Docker container from this image, thereby allowing the functionality of the machine learning model to be tested. The docker run command aids in this endeavor: Shell docker run -p 4000:80 ml_model_image:1.0 In this command, the -p flag maps the host's port 4000 to the container's port 80 (as defined in the Dockerfile). Therefore, the machine learning model is accessible via port 4000 of the host machine. Testing the model requires sending a request to the endpoint exposed by the Flask application within the Docker container. For instance, if the model provides a prediction based on data sent via a POST request, the curl command can facilitate this: Shell curl -d '{"data":[1, 2, 3, 4]}' -H 'Content-Type: application/json' http://localhost:4000/predict The proposed method ensures a seamless flow from Dockerfile creation to testing the ML model within a Docker container. Deploying the ML Model With Docker Deployment of machine learning models typically involves exposing the model as a service that can be accessed over the internet. A standard method for achieving this is by serving the model as a REST API using a web framework such as Flask. Consider an example where a Flask application encapsulates a machine learning model. The following Python script illustrates how the model could be exposed as a REST API endpoint: Python from flask import Flask, request from sklearn.externals import joblib app = Flask(__name__) model = joblib.load('model.pkl') @app.route('/predict', methods=['POST']) def predict(): data = request.get_json(force=True) prediction = model.predict([data['features']]) return {'prediction': prediction.tolist()} if __name__ == '__main__': app.run(host='0.0.0.0', port=80) In this example, the Flask application loads a pre-trained Scikit-learn model (saved as model.pkl) and defines a single API endpoint /predict. When a POST request is sent to this endpoint with a JSON object that includes an array of features, the model makes a prediction and returns it as a response. Once the ML model is deployed and running within the Docker container, it can be communicated using HTTP requests. For instance, using the curl command, a POST request can be sent to the model with an array of features, and it will respond with a prediction: Shell curl -d '{"features":[1, 2, 3, 4]}' -H 'Content-Type: application/json' http://localhost:4000/predict This practical example demonstrates how Docker can facilitate deploying machine learning models as scalable and accessible services. Scaling the ML Model With Docker Swarm As machine learning applications grow in scope and user base, the ability to scale becomes increasingly paramount. Docker Swarm provides a native clustering and orchestration solution for Docker, allowing multiple Docker hosts to be turned into a single virtual host. Docker Swarm can thus be employed to manage and scale deployed machine learning models across multiple machines. Inaugurating a Docker Swarm is a straightforward process, commenced by executing the 'docker swarm init' command. This command initializes the current machine as a Docker Swarm manager: Shell docker swarm init --advertise-addr $(hostname -i) In this command, the --advertise-addr flag specifies the address at which the Swarm manager can be reached by the worker nodes. The hostname -i command retrieves the IP address of the current machine. Following the initialization of the Swarm, the machine learning model can be deployed across the Swarm using a Docker service. The service is created with the docker service create command, where flags like --replicas can dictate the number of container instances to run: Shell docker service create --replicas 3 -p 4000:80 --name ml_service ml_model_image:1.0 In this command, --replicas 3 ensures three instances of the container are running across the Swarm, -p 4000:80 maps port 4000 of the Swarm to port 80 of the container, and --name ml_service assigns the service a name. Thus, the deployed machine learning model is effectively scaled across multiple Docker hosts by implementing Docker Swarm, thereby bolstering its availability and performance. Continuous Integration/Continuous Deployment (CI/CD) With Docker Continuous Integration/Continuous Deployment (CI/CD) is a vital aspect of modern software development, promoting automated testing and deployment to ensure consistency and speed in software release cycles. Docker's portable nature lends itself well to CI/CD pipelines, as Docker images can be built, tested, and deployed across various stages in a pipeline. An example of integrating Docker into a CI/CD pipeline can be illustrated using a Jenkins pipeline. The pipeline is defined in a Jenkinsfile, which might look like this: Groovy pipeline { agent any stages { stage('Build') { steps { script { sh 'docker build -t ml_model_image:1.0 .' } } } stage('Test') { steps { script { sh 'docker run -p 4000:80 ml_model_image:1.0' sh 'curl -d '{"features":[1, 2, 3, 4]}' -H 'Content-Type: application/json' http://localhost:4000/predict' } } } stage('Deploy') { steps { script { sh 'docker service create --replicas 3 -p 4000:80 --name ml_service ml_model_image:1.0' } } } } } In this Jenkinsfile, the Build stage builds the Docker image, the Test stage runs the Docker container and sends a request to the machine learning model to verify its functionality, and the Deploy stage creates a Docker service and scales it across the Docker Swarm. Therefore, with Docker, CI/CD pipelines can achieve reliable and efficient deployment of machine learning models. Conclusion and Best Practices Wrapping up, this article underscores the efficacy of Docker in streamlining the deployment of machine learning models. The ability to encapsulate the model and its dependencies in an isolated, consistent, and lightweight environment makes Docker a powerful tool for machine learning practitioners. Further enhancing its value is Docker's potential to scale machine learning models across multiple machines through Docker Swarm and its seamless integration with CI/CD pipelines. However, to extract the most value from Docker, certain best practices are recommended: Minimize Docker image size: Smaller images use less disk space, reduce build times, and speed up deployment. This can be achieved by using smaller base images, removing unnecessary dependencies, and efficiently utilizing Docker's layer caching. Use .dockerignore: Similar to .gitignore in Git, .dockerignore prevents unnecessary files from being included in the Docker image, reducing its size. Ensure that Dockerfiles are reproducible: Using specific versions of base images and dependencies can prevent unexpected changes when building Docker images in the future. By adhering to these guidelines and fully embracing the capabilities of Docker, it becomes significantly more feasible to navigate the complexity of deploying machine learning models, thereby accelerating the path from development to production. References Docker Official Documentation. Docker, Inc. Docker for Machine Learning. O'Reilly Media, Inc. Continuous Integration with Docker. Jenkins Documentation. Scikit-learn: Machine Learning in Python. Scikit-learn Developers. Kalade, S., Crockett, L. H., & Stewart, R. (2018). Using Sequence to Sequence Learning for Digital BPSK and QPSK Demodulation. Blog — Page 3 — Liran Tal. Introduction to the Dockerfile Part II | by Hakim | Medium. Spring Boot 2.2 with Java 13 CRUD REST API Tutorial: Using JPA Hibernate & MySQL | Techiediaries.
As a developer, you know that deploying code can be a time-consuming and complex process. Streamlining production deployment is crucial for ensuring your code gets into the hands of users as quickly and efficiently as possible. But how do you achieve this? In this article, we'll discuss some essential tips and tricks for streamlining production deployments. From automating your build process to optimizing your release strategy, we'll cover everything you need to know to make the deployment process as smooth as possible. So whether you're a seasoned developer or just starting, read on to learn how you can make your production deployment process smoother and more efficient. Common Challenges Faced During Production Deployments Before we dive into the tips and tricks of streamlining production deployment, let's first identify some of the common challenges that developers face during this process. One of the biggest challenges is the coordination of the different teams involved in the deployment process. There are various teams involved in the deployment process, including development, testing, and operations teams. Each team has different goals, priorities, and timelines, which can lead to confusion and delays if not adequately managed. Another challenge is ensuring consistency across different environments, from development to production. This can be tricky, as different environments may have different configurations, dependencies, and infrastructure. Finally, security is a significant concern during production deployment. As the deployment process involves moving code from a non-production environment to a production environment, there is a risk of exposing vulnerabilities or sensitive data. What Are the Benefits of Streamlined Production Deployments? While production deployment can be a challenging process, streamlining it has several benefits. 1. Faster code delivery: By streamlining the production deployment process, you can significantly reduce the time and effort required for deployment. This allows you to release code more frequently, enabling faster delivery of new features and bug fixes to users. 2. Reduced risk of errors and bugs: Streamlining production deployment involves following best practices and utilizing appropriate tools. This helps in identifying and fixing issues before they become problematic, reducing the risk of errors and bugs during the deployment process. 3. Improved collaboration and communication: A streamlined production deployment process fosters better collaboration and communication among different teams. By establishing a unified deployment process, goals and priorities can be aligned, minimizing confusion and delays. 4. Automation and continuous integration: Implementing automation and continuous integration practices further enhances the benefits of streamlining production deployment. These practices ensure a seamless and efficient deployment pipeline, improving overall productivity and reducing manual errors. Best Practices for Streamlining Production Deployment Now that we've identified the common challenges and benefits of streamlining production deployment let's explore some best practices to help you achieve this goal. Choosing the Right Tools Introducing tools and resources to streamline production deployments can help you achieve faster, more efficient deployments. Utilizing version control systems, automated testing, and deployment pipelines can help catch errors early in the development process and ensure consistency throughout. When selecting a tool, consider your business needs, such as the size of the team, the complexity of the application, and the infrastructure requirements. For instance, if you are working with a complex application, you may need a tool that provides advanced features for managing dependencies and configurations. Defining a Release Strategy Creating a release strategy for production deployments is necessary to ensure a structured approach to manage and control the deployment process. It promotes transparency, collaboration, and coordination among development, operations, and other relevant teams. The strategy involves carefully planning and organizing the release of new features, updates, and bug fixes. This phase involves gathering requirements, prioritizing features, and setting realistic timelines for each release. One important aspect is defining release criteria and establishing clear guidelines for when a release is considered ready for deployment. Also, utilizing a version control system and establishing branching strategies is essential for managing code changes during the release process. Branching allows for parallel development and enables the isolation of new features or bug fixes, reducing the risk of disrupting the main codebase. Additionally, the strategy should include rollback plans and contingencies in case unexpected issues arise during deployment. Thorough testing in staging environments to validate functionality and compatibility should also be part of the release strategy. In this phase, it’s important to consider the impact of the release on users and have a communication plan in place to notify them of any potential disruptions or changes. Integration With CI/CD Pipelines Continuous integration and continuous deployment (CI/CD) pipelines can help you automate the deployment process, and deploy it to different environments as per your release strategy. CI/CD tools can automatically build, test, and deploy code changes to production environments, reducing manual errors and improving overall efficiency. Microtica's integrated CI/CD pipelines, along with other popular tools like Jenkins, Travis CI, and CircleCI, help streamline the deployment process by integrating with version control systems, automated testing frameworks, and release management tools. Implementing Automation for Deployment Automation is an essential component of streamlining production deployment. Automation enables you to improve consistency across different environments and reduce the time and effort required for deployment. Some of the key areas where you can implement automation for deployment include: Configuration management: Automate the management of configurations across different environments, reducing the risk of inconsistencies and errors. Infrastructure provisioning: Automate the provisioning of infrastructure, enabling you to create and manage environments quickly and efficiently. Testing: Automate the testing process, enabling you to identify and fix issues before they become alarming. Monitoring and Tracking Production Deployment Monitoring and tracking production deployment are crucial for maintaining the stability and performance of deployed infrastructure and applications. By implementing robust monitoring practices, development teams can gain real-time visibility into the health and status of deployed systems. During your deployment process, it is crucial to monitor and track specific areas to ensure a smooth operation. Firstly, monitoring the performance of your application and infrastructure is essential to identify any potential issues and ensure smooth functioning. Secondly, keeping an eye on logs allows for the detection of errors or issues that might have occurred during deployment. Accurate auditing and traceability enable effective troubleshooting by pinpointing the source of problems. Lastly, tracking key metrics such as deployment frequency, response times, error rates, and resource utilization provides valuable insights into potential bottlenecks and issues that require attention. By actively monitoring and tracking these areas, you can proactively address any issues, maintain optimal performance, and ensure the success of your deployments. Strategies for Handling Rollback and Recovery Having strategies in place for handling rollback and recovery in case of any issues during deployment is essential for maintaining application stability and minimizing downtime. One effective strategy is to use Git for version control and maintain a rollback mechanism. This allows for reverting to a previously known working state in case of unexpected issues or failures. Additionally, taking regular backups of critical data and configurations ensures that recovery can be performed quickly and accurately. Implementing automated testing and staging environments also helps mitigate risks by allowing for thorough testing before deploying to production. Case studies: Success Stories of Streamlined Production Deployments Let’s take a look at some real-world case studies highlighting companies that have achieved remarkable results through streamlined production deployments. These success stories will illustrate how streamlined deployments have reduced deployment time, achieved high availability and scalability, and optimized costs. Banzae: Reducing Delivery Time by 80% Hypha: Achieving Fast Customer Onboarding Blackprint: Cost Optimization through Streamlined Deployments Conclusion: The Future of Production Deployments Streamlining production deployment is critical to ensuring that your code gets into the hands of users as quickly and efficiently as possible. By following best practices, choosing the right deployment tools, and implementing automation, you can reduce the time and effort required for deployment, identify and fix issues quickly, and improve collaboration and communication across teams. As technology continues to evolve, we can expect to see more innovations in the production deployment space. From the use of AI and machine learning to more advanced automation and DevOps practices, the future of production deployment looks bright. So, keep exploring, experimenting, and implementing new ways to streamline your production deployment process, and you'll be well on your way to delivering software with greater speed, efficiency, and quality.
In this post, I will provide a step-by-step guide on deploying a MuleSoft application to CloudHub2 using GitHub Actions. Prerequisites GitHub account and basic knowledge of git. Anypoint Platform account. Anypoint Studio and basic knowledge of MuleSoft. Before we start, let's learn about GitHub Actions. GitHub Actions is a versatile and powerful automation platform provided by GitHub. It enables developers to define and automate workflows for their software development projects. With GitHub Actions, you can easily set up custom workflows to build, test, deploy, and integrate your code directly from your GitHub repository. Deploying the MuleSoft Application We will outline three key steps involved in this process. 1. Creating a Connected App Go to Access Management in the Anypoint Platform. Click on "Connected Apps" from the left side menu. Click on the "Create App" button. Give a suitable name to the application and select the "App acts on its own behalf (client credentials)" radio button. "Click on Add Scopes" button. Add the following scopes to the connected app and click on the "Save" button. The Connected App will be created. Copy the Id and Secret and keep it aside for further use. 2. Configuring the MuleSoft App Open the project in the Anypoint studio and go to the pom.xml file. In the pom.xml file, replace the value of "groupId" with the "Business Group Id" of your Anypoint Platform. Remove the "-SNAPSHOT" from the version. Go to the project folder in system explorer and add a folder named ".maven" inside the project folder. Inside the ".maven" folder, create a file named "settings.xml" and add the following configuration in the settings.xml file. XML <settings> <servers> <server> <id>ca.anypoint.credentials</id> <username>~~~Client~~~</username> <password>${CA_CLIENT_ID}~?~${CA_CLIENT_SECRET}</password> </server> </servers> </settings> Add the CloudHub2 Deployment configurations in the "mule-maven-plugin" inside the "build" tag like the image below. After the "build" tag, add the "distributionManagement." XML <configuration> <cloudhub2Deployment> <uri>https://anypoint.mulesoft.com</uri> <provider>MC</provider> <environment>Sandbox</environment> <target>Cloudhub-US-East-2</target> <muleVersion>4.4.0</muleVersion> <server>ca.anypoint.credentials</server> <applicationName>ashish-demo-project-v1</applicationName> <replicas>1</replicas> <vCores>0.1</vCores> <skipDeploymentVerification>${skipDeploymentVerification}</skipDeploymentVerification> <integrations> <services> <objectStoreV2> <enabled>true</enabled> </objectStoreV2> </services> </integrations> </cloudhub2Deployment> </configuration> XML <distributionManagement> <repository> <id>ca.anypoint.credentials</id> <name>Corporate Repository</name> <url>https://maven.anypoint.mulesoft.com/api/v2/organizations/${project.groupId}/maven</url> <layout>default</layout> </repository> </distributionManagement> Note: Keep the "applicationName" unique. "skipDeploymentVerification" is optional. "server" should match with the "id" provider in "distributionManagement". "id" provided in "distributionManagement" should match with the 'id" provided in the "settings.xml" file. For more information, visit the MuleSoft documentation. 3. Creating a Workflow File and Deploying the App Create a GitHub repository and push the project code to the repository. In this post, we will be using the "main" branch. Click on the "Settings" tab and select "Actions" from the "Secrets and variables" dropdown menu from the left side panel on the "Settings" page. Click on the "New Repository Secret" button and add the Client-Id of the Connected app that we created in Step 1. Similarly, add the Client-Secret also. Click on the "Actions" tab and select "Simple workflow" from the "Actions" page. Change the name of the pipeline and replace the default code with the pipeline code given below. YAML # This workflow will build a MuleSoft project and deploy to CloudHub name: Build and Deploy to Sandbox on: push: branches: [ main ] workflow_dispatch: jobs: build: runs-on: ubuntu-latest env: CA_CLIENT_ID: ${{ secrets.CA_CLIENT_ID } CA_CLIENT_SECRET: ${{ secrets.CA_CLIENT_SECRET } steps: - uses: actions/checkout@v3 - uses: actions/cache@v3 with: path: ~/.m2/repository key: ${{ runner.os }-maven-${{ hashFiles('**/pom.xml') } restore-keys: | ${{ runner.os }-maven- - name: Set up JDK 11 uses: actions/setup-java@v3 with: java-version: 11 distribution: 'zulu' - name: Print effective-settings (optional) run: mvn help:effective-settings - name: Build with Maven run: mvn -B package -s .maven/settings.xml - name: Stamp artifact file name with commit hash run: | artifactName1=$(ls target/*.jar | head -1) commitHash=$(git rev-parse --short "$GITHUB_SHA") artifactName2=$(ls target/*.jar | head -1 | sed "s/.jar/-$commitHash.jar/g") mv $artifactName1 $artifactName2 - name: Upload artifact uses: actions/upload-artifact@master with: name: artifacts path: target/*.jar upload: needs: build runs-on: ubuntu-latest env: CA_CLIENT_ID: ${{ secrets.CA_CLIENT_ID } CA_CLIENT_SECRET: ${{ secrets.CA_CLIENT_SECRET } steps: - uses: actions/checkout@v3 - uses: actions/cache@v3 with: path: ~/.m2/repository key: ${{ runner.os }-maven-${{ hashFiles('**/pom.xml') } restore-keys: | ${{ runner.os }-maven- - uses: actions/download-artifact@master with: name: artifacts - name: Upload to Exchange run: | artifactName=$(ls *.jar | head -1) mvn deploy \ -s .maven/settings.xml \ -Dmule.artifact=$artifactName \ deploy: needs: upload runs-on: ubuntu-latest env: CA_CLIENT_ID: ${{ secrets.CA_CLIENT_ID } CA_CLIENT_SECRET: ${{ secrets.CA_CLIENT_SECRET } steps: - uses: actions/checkout@v3 - uses: actions/cache@v3 with: path: ~/.m2/repository key: ${{ runner.os }-maven-${{ hashFiles('**/pom.xml') } restore-keys: | ${{ runner.os }-maven- - uses: actions/download-artifact@master with: name: artifacts - name: Deploy to Sandbox run: | artifactName=$(ls *.jar | head -1) mvn deploy -DmuleDeploy \ -Dmule.artifact=$artifactName \ -s .maven/settings.xml \ -DskipTests \ -DskipDeploymentVerification="true" This workflow contains three jobs. 1. Build: This step sets up the required environment, such as the Java Development Kit (JDK) version 11. It then executes Maven commands to build the project, package it into a JAR file, and append the commit hash to the artifact's filename. The resulting artifact is uploaded as an artifact for later use. 2. Upload: This step retrieves the previously built artifact and prepares it for deployment. It downloads the artifact from the artifacts repository and uses Maven to upload the artifact to the desired destination, such as the MuleSoft Exchange. The necessary credentials and settings are provided to authenticate and configure the upload process. 3. Deploy: The final step involves deploying the uploaded artifact to the CloudHub Sandbox environment. The artifact is downloaded, and the Maven command is executed with specific parameters for deployment, including the artifact name and necessary settings. Tests are skipped during deployment, and deployment verification is disabled. Commit the workflow file and click on the "Actions" tab. The workflow will automatically start since we made a commit. Click on the workflow and observe the steps as they execute. After Completion of the "Upload" stage, go to "Anypoint Exchange" and go to "root" from the left side menu and in the address bar, append "&type=app" and hit enter. You will see the uploaded artifact. Wait for the workflow to complete execution. After all three stages get executed successfully, go to "Runtime Manager" in "Anypoint Platform," and you will see your app being deployed there. Note: If you change the name of Client-Id and Client-Secret, make sure to update it in the Workflow file and the Repository Secrets as well. In this tutorial, we have used the main branch; you can change the branch in the workflow file to target some other branch. Changes in the CloudHub2 deployment configurations can be made according to the MuleSoft documentation. I hope this tutorial will help you. You can find the source code here.
Open-source Cloud Foundry Korifi is designed to provide developers with an efficient approach to delivering and managing cloud-native applications on Kubernetes with automated networking, security, availability, and more. With Korifi, the simplicity of the cf push command is now available on Kubernetes. In this tutorial, I will walk you through the installation of Korifi on kind using a locally deployed container registry. The installation process happens in two steps: Installation of prerequisites Installation of Korifi and dependencies Then, we will deploy two applications developed in two very different programming languages: Java and Python. This tutorial has been tested on Ubuntu Server 22.04.2 LTS. Let's dive in! Installing Prerequisites There are several prerequisites needed to install Korifi. There is a high chance that Kubernetes users will already have most of them installed. Here is the list of prerequisites: Cf8 cli Docker Go Helm Kbld Kind Kubectl Make To save time, I wrote a Bash script that installs the correct version of prerequisites for you. You can download it and run it by running the two commands below. Shell git clone https://github.com/sylvainkalache/korifi-prerequisites-installation cd korifi-prerequisites-installation && ./install-korifi-prerequisites.sh Installing Korifi The Korifi development team maintains an installation script to install Korifi on a kind cluster. It installs the required dependencies and a local container registry. This method is especially recommended if you are trying Korifi for the first time. Shell git clone https://github.com/cloudfoundry/korifi cd korifi/scripts && ./deploy-on-kind.sh korifi-cluster The install script does the following: Creates a kind cluster with the correct port mappings for Korifi Deploys a local Docker registry using the twuni helm chart Creates an admin user for Cloud Foundry Installs cert-manager to create and manage internal certificates within the cluster Installs kpack, which is used to build runnable applications from source code using Cloud Native Buildpacks Installs contour, which is the ingress controller for Korifi Installs the service binding runtime, which is an implementation of the service binding spec Installs the metrics server Installs Korifi Similar to installing prerequisites, you can always do this manually by following the installation instructions. Setting up Your Korifi Instance Before deploying our application to Kubernetes, we must sign into our Cloud Foundry instance. This will set up a tenant, known as a target, to which our apps can be deployed. Authenticate with the Cloud FoundryAPI: Shell cf api https://localhost --skip-ssl-validation cf auth cf-admin Create an Org and a Space. Shell cf create-org tutorial-org cf create-space -o tutorial-org tutorial-space Target the Org and Space you created. Shell cf target -o tutorial-org -s tutorial-space Everything is ready; let’s deploy two applications to Kubernetes. Single-Command Deployment to Kubernetes Deploying a Java Application For the sake of the tutorial, I am using a sample Java app, but you feel free to try it out on your own. Shell git clone https://github.com/sylvainkalache/sample-web-apps cd sample-web-apps/java Once you are inside your application repository, run the following command. Note that the first run of this command will take a while as it needs to install language dependencies from the requirements.txt and create a runnable container image. But all subsequent updates will be much faster: Shell cf push my-java-app That’s it! The application has been deployed to Kubernetes. To check the application status, you can simply use the following command: Shell cf app my-java-app Which will return an output similar to this: Showing health and status for app my-java-app in org tutorial-org / space tutorial-space as cf-admin... Shell Showing health and status for app my-java-app in org tutorial-org / space tutorial-space as cf-admin... name: my-java-app requested state: started routes: my-java-app.apps-127-0-0-1.nip.io last uploaded: Tue 25 Jul 19:14:34 UTC 2023 stack: io.buildpacks.stacks.jammy buildpacks: type: web sidecars: instances: 1/1 memory usage: 1024M state since cpu memory disk logging details #0 running 2023-07-25T20:46:32Z 0.1% 16.1M of 1G 0 of 1G 0/s of 0/s type: executable-jar sidecars: instances: 0/0 memory usage: 1024M There are no running instances of this process. type: task sidecars: instances: 0/0 memory usage: 1024M There are no running instances of this process. Within this helpful information, we can see the app URL of our app and the fact that it is properly running. You can double-check that the application is properly responding using curl: Shell curl -I --insecure https://my-java-app.apps-127-0-0-1.nip.io/ And you should get an HTTP 200 back. Shell HTTP/2 200 date: Tue, 25 Jul 2023 20:47:07 GMT x-envoy-upstream-service-time: 134 vary: Accept-Encoding server: envoy Deploying a Python Application Next, we will deploy a simple Python Flask application. While we could deploy a Java application directly, there is an additional step for a Python one. Indeed, we need to provide a Buildpack that Korifi can use for Python applications – a more detailed explanation is available in the documentation. Korifi uses Buildpacks to transform your application source code into images that are eventually pushed to Kubernetes. The Paketo open-source project provides base production-ready Buildpacks for the most popular languages and frameworks. In this example, I will use the Python Paketo Buildpacks as the base Buildpacks. Let’s start by adding the Buildpacks source to our ClusterStore by running the following command: Shell kubectl edit clusterstore cf-default-buildpacks -n tutorial-space Then add the line - image: gcr.io/paketo-buildpacks/python, your file should look like this: Shell spec: sources: - image: gcr.io/paketo-buildpacks/java - image: gcr.io/paketo-buildpacks/nodejs - image: gcr.io/paketo-buildpacks/ruby - image: gcr.io/paketo-buildpacks/procfile - image: gcr.io/paketo-buildpacks/go - image: gcr.io/paketo-buildpacks/python Then we need to specify when to use these Buildbacks by editing our ClusterBuilder. Execute the following command: Shell kubectl edit clusterbuilder cf-kpack-cluster-builder -n tutorial-space Add the line - id: paketo-buildpacks/python at the top of the spec order list. your file should look like this: Shell spec: order: - group: - id: paketo-buildpacks/python - group: - id: paketo-buildpacks/java - group: - id: paketo-buildpacks/go - group: - id: paketo-buildpacks/nodejs - group: - id: paketo-buildpacks/ruby - group: - id: paketo-buildpacks/procfile That’s it! Now you can either bring your own Python app or use this sample one by running the following commands: Shell git clone https://github.com/sylvainkalache/sample-web-apps cd sample-web-apps/python And deploy it: Shell cf push my-python-app Run curl to make sure the app is responding: Shell curl --insecure https://my-python-app.apps-127-0-0-1.nip.io/dzone Curl should return the following output: Shell Hello world! Python version: 3.10.12 Video Conclusion As you can see, Korifi makes deploying applications to Kubernetes very easy. While Java and Python are two very different stacks, the shipping experience remains the same. Korifi supports many other languages like Go, Ruby, PHP, Node.js, and more.
As an average user, choosing the right software can be a challenge. However, how you deploy the software can make a significant difference in its effectiveness. The process of deploying software involves making a tool ready for use in a way that ensures it is optimized, secure, and compatible. Software varies in its purpose and performance; the deployment process must be tailored to its specific requirements. What Is Software Deployment? The deployment of software or applications is one of the final steps in the development process. This process entails the installation, configuration, and testing of a software application to ensure its readiness for use in a specific environment. When deploying software, developers should choose a time that causes the least disruption to the organization's workflow. They can use software asset management tools to manage software deployment and licenses for all users, making the installation process easier. DevOps tools like continuous delivery software can help developers generate deployable code quickly, allowing for automatic deployment to production within seconds. Regarding management, the deployment phase occurs immediately after the purchase process. This is when you are prepared to introduce the new solution to your team. The deployment phase encompasses the time when your company transitions from not using the new software to utilizing it effectively. Why Is Seamless Software Deployment Important? Deploying software is an essential part of the development process. Until it is distributed correctly, the software can't fulfill its intended purpose. Software deployment aims to satisfy changing business needs by providing new features and updates that enhance customer satisfaction. It allows developers to release patches and software updates to users after testing the impact of new code and its response time to demand changes. Patch management software solutions can automatically notify users of new updates. Using software deployment can streamline business processes by creating customized solutions that boost overall productivity. With an automated deployment process, installation is faster than traditional methods, saving valuable time. Additionally, continuous monitoring of newly deployed environments allows for a quick rollback of updates in case of any issues. This ensures the safety of critical processes and sensitive information by promptly providing necessary updates. Best Practices for Deployment in Software When deploying software, it's important to be cautious and proactive in anticipating and addressing potential challenges. To ensure a smooth deployment process, below are the recommended to follow these best practices: Creating a deployment checklist is crucial to ensure that important tasks are not missed and to keep track of every detail. To prevent issues with resource consumption and security, it is recommended to use separate clusters for production and non-production instead of one large cluster. It is also advisable to use software deployment tools that are compatible with multiple platforms, such as Windows, Linux, macOS, Android, and iOS. This will provide greater flexibility and functionality while avoiding vendor lock-in. It is important to track deployment metrics to monitor the performance of the process and measure its success. Ideally, these metrics should be tracked automatically as part of a workflow. It is a good idea to automate the database to application code and include a rollback mechanism in case of a failed update. This will create an automatic update pipeline for new changesets and allow for safe code review in a temporary environment. Types of Software Deployment There are various types of software deployment and strategies that you should know about. Below are some common ones: Basic Deployment This type is straightforward, fast, and cost-effective. It updates all target environments simultaneously with the new software version. However, it can be risky as there is no controlled deployment, making it difficult to roll back an update. Rolling Deployment With this deployment, the old application version is slowly updated and replaced with the new one. There will be no downtime because it allows for a progressive scaling up of the new version before scaling down the old version. But in this instance, rollbacks are similarly incremental and slow. Blue/Green Deployment This type of deployment works with two versions of the application - the current version (blue) and the new version (green). Because only one version is active at once, developers can use the blue version while testing the green version. After a successful deployment, traffic is switched from the old version to the new one. Instant rollbacks are possible with this deployment, which reduces risk. However, because two environments must be operating, it is expensive. Canary Deployment This method sends out application updates incrementally, starting with a small group of users and continuing the rollout until reaching 100% deployment. This is the least risky deployment strategy as it allows teams to test live updates on small user groups before pushing them out to larger groups. Rollbacks are fast, and there is no downtime in this case. Multi-Service Deployment Similar to basic deployment, this type updates the target environment with multiple services simultaneously. It is useful for applications that have version dependencies. This deployment style rolls out quickly but rolls back slowly. Shadow Deployment By switching incoming requests from the current version to the new version, this deployment strategy distributes two concurrent versions of the software. It aims to test whether the newer version meets the performance and stability requirements. If it does, the deployment can proceed without risk. While this is considered low-risk and accurate in testing, this strategy is highly specialized and complex to set up. A/B Testing Although this methodology functions similarly to canary deployment, it is more of a testing strategy. A/B testing entails comparing two updates in targeted small groups of consumers. It aids businesses in determining which features have higher conversion rates. Wrapping It Up Seamless software deployment is important as it streamlines business processes by creating customized solutions that boost overall productivity. It allows developers to release patches and software updates to users after testing the impact of new code and its response time to demand changes. Continuous monitoring of newly deployed environments can allow you quick rollback of updates, ensuring the safety of critical processes and sensitive information. Best practices for deployment include creating a deployment checklist and using separate clusters for production and non-production. Also, by using software deployment tools compatible with multiple platforms, it can make it easier to track deployment metrics. You can effortlessly deploy software by automating the database to application code and including a rollback mechanism in case of a failed update.
GitOps is a relatively new addition to the growing list of "Ops" paradigms taking shape in our industry. It all started with DevOps, and while the term DevOps has been around for some years now, it seems we still can't agree whether it's a process, mindset, job title, set of tools, or some combination of them all. We captured our thoughts about DevOps in our introduction to DevOps post, and we dive even deeper in our DevOps engineer's handbook. The term GitOps suffers from the same ambiguity, so in this post we look at: The history of GitOps GitOps goals and ideals The limitations of GitOps The tools that support GitOps The practical implications of adopting GitOps in your own organization The Origins of GitOps The term GitOps was originally coined in a blog post by WeaveWorks called GitOps - Operations by Pull Request. The post described how WeaveWorks used Git as a source of truth, leading to the following benefits: Since that original blog post, initiatives like the GitOps Working Group have been organized to: This working group recently released version one of their principles, which states that: The contrast between low level implementations of GitOps found in most blog posts and the high level ideals of a GitOps system described by the working group is worth discussion, as the differences between them is a source of much confusion. GitOps Doesn't Imply the Use of Git Most discussions around GitOps center on how building processes on Git give rise to many of the benefits ascribed to the GitOps paradigm. Git naturally provides an (almost) immutable history of changes, with changes annotated and approved via pull requests, and where the current state of the Git repository naturally represents the desired state of a system, thus acting as a source of truth. The overlap between Git and GitOps is undeniable. However, you may have noticed that Git was never mentioned as a requirement of GitOps by the working group. So while Git is a convenient component of a GitOps solution, GitOps itself is concerned with the functional requirements of a system rather than checking your declarative templates into Git. This distinction is important, because many teams fixate on the "Git" part of GitOps. The term GitOps is an unfortunate name for the concept it's trying to convey, leading many to believe Git is the central aspect of GitOps. But GitOps has won the marketing battle and gained mind share in IT departments. While it may be a restrictive term to describe functional requirements unrelated to Git, GitOps is now the shorthand for describing processes that implement a set of high level concerns. GitOps Doesn't Imply the Use of Kubernetes Kubernetes was the first widely used platform to combine the ideas of declarative state and continuous reconciliation with an execution environment to implement the reconciliation and host running applications. It really is magic to watch a Kubernetes cluster reconfigure itself to match the latest templates applied to the system. So it's no surprise that Kubernetes is the foundation of GitOps tools like Flux and Argo CD, while posts like 30+ Tools List for GitOps mention Kubernetes 20 times. While continuous reconciliation is impressive, it's not really magic. Behind the scenes Kubernetes runs a number of operators that are notified of configuration changes and execute custom logic to bring the cluster back to the desired state. The key requirements of continuous reconciliation are: Access to the configuration or templates declaratively expressing the desired state The ability to execute a process capable of reconciling a system when configuration is changed An environment in which the process can run Kubernetes bakes these requirements into the platform, making it easy to achieve continuous reconciliation. But these requirements can also be met with some simple orchestration, Infrastructure as Code (IaC) tools like Terraform, Ansible, Puppet, Chef, CloudFormation, Arm Templates, and an execution environment like a CI server: IaC templates can be stored in Git, file hosting platforms like S3 or Azure Blob Storage, complete with immutable audit histories. CI/CD systems can poll the storage, are notified of changes via webhooks, or have builds or deployments triggered via platforms like GitHub Actions. The IaC tooling is then executed, bringing the system in line with the desired state. Indeed, a real world end-to-end GitOps system inevitably incorporates orchestration outside of Kubernetes. For example, Kubernetes is unlikely to manage your DNS records, centralized authentication platforms, or messaging systems like Slack. You'll also likely find at least one managed service for things like databases, message queues, scheduling, and reporting more compelling than attempting to replicate them in a Kubernetes cluster. Also, any established IT department is guaranteed to have non-Kubernetes systems that would benefit from GitOps. So while the initial selection of specialized GitOps tools tends to be tightly integrated into Kubernetes, achieving the functional requirements of GitOps across established infrastructure will inevitably require orchestrating one or more IaC tools. Continuous Reconciliation Is Half the Battle Continuous reconciliation, as described by the working group, describes responses to two types of system changes. The first is what you expect, where deliberate changes to the configuration held in Git or other versioned storage is detected and applied to the system. This is the logical flow of configuration change and represents the normal operation of a correctly configured GitOps workflow. The second is where an agent detects undesirable changes to the system that are not described in the source configuration. In this case, your system no longer reflects the desired state, and the agent is expected to reconcile the system back to the configuration maintained in Git. This ability to resolve the second situation is a neat technical capability, but represents an incomplete business process. Imagine the security guards from your front desk reporting they had evicted an intruder. As a once-off occurrence, this report would be mildly concerning, but the security team did their job and resolved the issue. But now imagine you were receiving these reports every week. Obviously there is a more significant problem forcing the security team to respond to weekly intrusions. In the same manner, a system that continually removes undesirable system states is an incomplete solution to a more fundamental root problem. The real question is who is making those changes, why are the changes being made, and why are they not being made through the correct process? The fact your system can respond to undesirable states is evidence of a robust process able to adapt to unpredictable events, and this ability should not be underestimated. It's a long established best practice that teams should exercise their recovery processes, so in the event of disaster, teams are able to run through a well-rehearsed restoration. Continuous reconciliation can be viewed as a kind of automated restoration process, allowing the process to be tested and verified with ease. But if your system has to respond to undesirable states, it's evidence of a flawed process where people have access that they shouldn't or are not following established processes. An over-reliance on a system that can undo undesirable changes after they've been made runs the risk of masking a more significant underlying problem. GitOps Is Not a Complete Solution While GitOps describes many desirable traits of well-managed infrastructure and deployment processes, it's not a complete solution. In addition to the 4 functional requirements described by GitOps, a robust system must be: Verifiable - infrastructure and applications must be testable once they are deployed. Recoverable - teams must be able to recover from an undesirable state. Visible - the state of the infrastructure and the applications deployed to it must be surfaced in an easily consumed summary. Secure - rules must exist around who can make what changes to which systems. Measurable - meaningful metrics must be collected and exposed in an easily consumed format. Standardized - applications and infrastructure must be described in a consistent manner. Maintainable - support teams must be able to query and interact with the system, often in non-declarative ways. Coordinated - changes to applications and infrastructure must be coordinated between teams. GitOps offers little advice or insight into what happens before configuration is committed to a Git repo or other versioned and immutable storage, but it is "left of the repo" where the bulk of your engineering process will be defined. If your Git repo is the authoritative representation of your system, then anyone who can edit a repo essentially has administrative rights. However, Git repos don't provide a natural security boundary for the kind of nuanced segregation of responsibility you find in established infrastructure. This means you end up creating one repo per app per environment per role. Gaining visibility over each of these repos and ensuring they have the correct permissions is no trivial undertaking. You also quickly find that just because you can save anything in Git doesn't mean you should. It's not hard to imagine a rule that says development teams must create Kubernetes deployment resources instead of individual pods, use ingress rules that respond to very specific hostnames, and always include a standard security policy. This kind of standardization is tedious to enforce through pull requests, so a much better solution is to give teams standard resource templates that they populate with their specific configuration. But this is not a feature inherent to Git or GitOps. We then have those processes "right of the cluster," where management and support tasks are defined. Reporting on the intent of a Git commit is almost impossible. If you looked at a diff between two commits and saw that a deployment image tag was increased, new secret values were added, and a config map was deleted, how would you describe the intent of that change? The easy answer is to read the commit message, but this isn't a viable option for reporting tools that must map high level events like "deployed a new app version" or "bug fix release" (which are critical if you want to measure yourself against standard metrics like those presented in the DORA report) to the diff between two commits. Even if you could divine an algorithm that understood the intent of a Git commit, a Git repo was never meant to be used as a time-series database. GitOps also provides no guidance on how to perform support tasks after the system is in its desired state. What would you commit to a Git repo to delete misbehaving pods so they can be recreated by their parent deployment? Maybe a job could do this, but you have to be careful that Kubernetes doesn't try to apply that job resource twice. But then what would you commit to the repo to view the pod logs of a service like an ingress controller that was preinstalled on your cluster? My mind boggles at the thought of all the asynchronous message handling you would need to implement to recreate kubectl logs mypod in a GitOps model. Adhoc reporting and management tasks like this don't have a natural solution in the GitOps model. This is not to say that GitOps is flawed or incomplete, but rather that it solves specific problems, and must be complemented with other processes and tools to satisfy basic operational requirements. Git Is the Least Interesting Part of GitOps I'd like to present you with a theory and a thought experiment to apply it to: In any sufficiently complex GitOps process, your Git repo is just another structured database. You start your GitOps journey using the common combination of Git and Kubernetes. All changes are reviewed by pull request, committed to a Git repo, consumed by a tool like Argo CD or Flux, and deployed to your cluster. You have satisfied all the functional requirements of GitOps, and enjoy the benefits of a single source of truth, immutable change history, and continuous reconciliation. But it becomes tedious to have a person open a pull request to bump the image property in a deployment resource every time a new image is published. So you instruct your build server to pull the Git repo, edit the deployment resource YAML file, and commit the changes. You now have GitOps and CI/CD. You now need to measure the performance of your engineering teams. How often are new releases deployed to production? You quickly realize that extracting this information from Git commits is inefficient at best, and that the Kubernetes API was not designed for frequent and complex queries, so you choose to populate a more appropriate database with deployment events. As the complexity of your cluster grows, you find you need to implement standards regarding what kind of resources can be deployed. Engineering teams can only create deployments, secrets, and configmaps. The deployment resources must include resource limits, a set of standard labels, and the pods must not be privileged. In fact, it turns out that of the hundreds of lines of YAML that make up the resources deployed to the cluster, only about 10 should be customized. As you did with the image tag updates, you lift the editing of resources from manual Git commits to an automated process where templates have a strictly controlled subset of properties updated with each deployment. Now that your CI/CD is doing most of the commits to Git, you realize that you no longer need to use Git repos as a means of enforcing security rules. You consolidate the dozens of repos that were created to represent individual applications and environments to a single repo that only the CI/CD system interacts with on a day-to-day basis. You find yourself having to roll back a failed deployment, only to find that the notion of reverting a Git commit is too simplistic. The changes to the one application you wanted to revert have been mixed in with a dozen other deployments. Not that anyone should be touching the Git repo directly anyway, because merge conflicts can have catastrophic consequences. But you can use your CI/CD server to redeploy an old version of the application, and because the CI/CD server has the context of what makes up a single application, the redeployment only changes the files relating to that application. At this point, you concede that your Git repo is another structured database reflecting a subset of "the source of truth:" Humans aren't to touch it. All changes are made by automated tools. The automated tools require known files of specific formats in specific locations. The Git history shows a list of changes made by bots rather than people. The Git history now reads "Deployment #X.Y.Z", and other commit information only makes sense in the context of the automated tooling. Pull requests are no longer used. The "source of truth" is now found in the Git repo (showing changes to files), the CI/CD platform's history (showing the people who initiated the changes, and the scripts that made them), and the metrics database. You consolidated your Git repos, meaning you have limited ability to segregate access to humans even if you want to. You also realize that the parts of your GitOps process that are adding unique business value are "left of the repo" with metrics collection, standardized templates, release orchestration, rollbacks, and deployment automation; and "right of the cluster" with reports, dashboards, and support scripts. The process between the Git repo and cluster is now so automated and reliable that it's not something you need to think about. Conclusion GitOps has come to encapsulate a subset of desirable functional requirements that are likely to provide a great deal of benefit for any teams that fulfill them. While neither Git nor Kubernetes are required to satisfy GitOps, they are the logical platforms on which to start your GitOps journey, as they're well supported by the more mature GitOps tools available today. But GitOps tooling tends to be heavily focused on what happens between a commit to a Git repo and the Kubernetes cluster. While this is no doubt a critical component of any deployment pipeline, there's much work to be done "left of the repo" and "right of the cluster" to implement a robust CI/CD pipeline and DevOps workflow. GitOps tools also tend to assume that because everything is in Git, the intent of every change is annotated with commit messages, associated with the author, put through a review process, and is available for future inspection. However, this is overly simplistic, as any team advanced enough to consider implementing GitOps will immediately begin iterating on the process by automating manual touch points, usually with respect to how configuration is added to the Git repo in the first place. As you project the natural evolution of a GitOps workflow, you're likely to conclude that so many automated processes rely on the declarative configuration being in a specific location and format, that Git commits must be treated in much the same way as a database migration. The inputs to a GitOps process must be managed and orchestrated, and the outputs must be tested, measured, and maintained. Meanwhile the processing between the Git repo and cluster should be automated, rendering much of what we talk about as GitOps today as simply an intermediate step in a specialized CI/CD pipeline or DevOps workflow. Perhaps the biggest source of confusion around GitOps is the misconception that it represents an end-to-end solution, and that you implement GitOps and GitOps-focused tooling to the exclusion of alternative processes and platforms. In practice, GitOps encapsulates one step in your infrastructure and deployment pipelines, and must be complemented with other processes and platforms to fulfill common business requirements. Happy deployments!
AI is under the hype now, and some products overuse the AI topic a lot — however, many companies and products are automating their processes using this technology. In the article, we will discover AI products and build an AI landing zone. Let’s look into the top 3 companies that benefit from using AI. Github Copilot Github Copilot’s primary objective is to aid programmers by providing code suggestions and auto-completing lines or blocks of code while they write. By intelligently analyzing the context and existing code, it accelerates the coding process and enhances developer productivity. It becomes an invaluable companion for developers throughout their coding journey, capable of supporting various programming languages and comprehending code patterns. Neuraltext Neuraltext strives to encompass the entire content workflow, encompassing everything from generating ideas to executing them, all powered by AI. It is an AI-driven copywriter, SEO content, and keyword research tool. By leveraging AI copywriting capabilities, you can effortlessly produce compelling copy for your campaigns, generating numerous variations. With a vast collection of over 50 pre-designed templates for various purposes, such as Facebook ads, slogan ideas, blog sections, and more, Neuraltext simplifies the content creation process. Motum Motum is the intelligent operating system for operational fleet management. It has damage recognition that uses computer vision and machine learning algorithms to detect and assess damages to vehicles automatically. By analyzing images of vehicles, the AI system can accurately identify dents, scratches, cracks, and other types of damage. This technology streamlines the inspection process for insurance claims, auto body shops, and vehicle appraisals, saving time and improving accuracy in assessing the extent of damages. What Is a Cloud Landing Zone? AI Cloud landing zone is a framework that includes fundamental cloud services, tools, and infrastructure that form the basis for developing and deploying artificial intelligence (AI) solutions. What AI Services Are Included in the Landing Zone? Azure AI Landing zone includes the following AI services: Azure Open AI — Provides pre-built AI models and APIs for tasks like image recognition, natural language processing, and sentiment analysis, making it easier for developers to incorporate AI functionalities; Azure AI services also include machine learning tools and frameworks for building custom models and conducting data analysis. Azure AI Services — A service that enables organizations to create more immersive, personalized, and intelligent experiences for their users, driving innovation and efficiency in various industries; Developers can leverage these pre-built APIs to add intelligent features to their applications, such as face recognition, language understanding, and sentiment analysis, without extensive AI expertise. Azure Bot Services — This is a platform Microsoft Azure provides and is part of AI Services. It enables developers to create chatbots and conversational agents to interact with users across various channels, such as web chat, Microsoft Teams, Skype, Telegram, and other platforms. Architecture We started integrating and deploying the Azure AI Landing Zone into our environment. Three logical boxes separate the AI landing zone: Azure DevOps Pipelines Terraform Modules and Environments Resources that deployed to Azure Subscriptions We can see it in the diagram below. Figure 1: AI Landing Zone Architecture (author: Boris Zaikin) The architecture contains CI/CD YAML pipelines and Terraform modules for each Azure subscription. It contains two YAML files: tf-provision-ci.yaml is the main pipeline that is based on stages. It reuses tf-provision-ci.jobs.yaml pipeline for each environment. tf-provision-ci.jobs.yaml contains workflow to deploy terraform modules. YAML trigger: - none pool: vmImage: 'ubuntu-latest' variables: devTerraformDirectory: "$(System.DefaultWorkingDirectory)/src/tf/dev" testTerraformDirectory: "$(System.DefaultWorkingDirectory)/src/tf/test" prodTerraformDirectory: "$(System.DefaultWorkingDirectory)/src/tf/prod" stages: - stage: Dev jobs: - template: tf-provision-ci-jobs.yaml parameters: environment: test subscription: 'terraform-spn' workingTerraformDirectory: $(devTerraformDirectory) backendAzureRmResourceGroupName: '<tfstate-rg>' backendAzureRmStorageAccountName: '<tfaccountname>' backendAzureRmContainerName: '<tf-container-name>' backendAzureRmKey: 'terraform.tfstate' - stage: Test jobs: - template: tf-provision-ci-jobs.yaml parameters: environment: test subscription: 'terraform-spn' workingTerraformDirectory: $(testTerraformDirectory) backendAzureRmResourceGroupName: '<tfstate-rg>' backendAzureRmStorageAccountName: '<tfaccountname>' backendAzureRmContainerName: '<tf-container-name>' backendAzureRmKey: 'terraform.tfstate' - stage: Prod jobs: - template: tf-provision-ci-jobs.yaml parameters: environment: prod subscription: 'terraform-spn' prodTerraformDirectory: $(prodTerraformDirectory) backendAzureRmResourceGroupName: '<tfstate-rg>' backendAzureRmStorageAccountName: '<tfaccountname>' backendAzureRmContainerName: '<tf-container-name>' backendAzureRmKey: 'terraform.tfstate' tf-provision-ci.yaml — Contains the main configuration, variables, and stages: Dev, Test, and Prod; The pipeline re-uses the tf-provision-ci.jobs.yaml in each stage by providing different parameters. After we’ve added and executed the pipeline to AzureDevOps, we can see the following staging structure. Figure 2: Azure DevOps Stages UI Azure DevOps automatically recognizes stages in the main YAML pipeline and provides a proper UI. Let’s look into tf-provision-ci.jobs.yaml. YAML jobs: - deployment: deploy displayName: AI LZ Deployments pool: vmImage: 'ubuntu-latest' environment: ${{ parameters.environment } strategy: runOnce: deploy: steps: - checkout: self # Prepare working directory for other commands - task: TerraformTaskV3@3 displayName: Initialise Terraform Configuration inputs: provider: 'azurerm' command: 'init' workingDirectory: ${{ parameters.workingTerraformDirectory } backendServiceArm: ${{ parameters.subscription } backendAzureRmResourceGroupName: ${{ parameters.backendAzureRmResourceGroupName } backendAzureRmStorageAccountName: ${{ parameters.backendAzureRmStorageAccountName } backendAzureRmContainerName: ${{ parameters.backendAzureRmContainerName } backendAzureRmKey: ${{ parameters.backendAzureRmKey } # Show the current state or a saved plan - task: TerraformTaskV3@3 displayName: Show the current state or a saved plan inputs: provider: 'azurerm' command: 'show' outputTo: 'console' outputFormat: 'default' workingDirectory: ${{ parameters.workingTerraformDirectory } environmentServiceNameAzureRM: ${{ parameters.subscription } # Validate Terraform Configuration - task: TerraformTaskV3@3 displayName: Validate Terraform Configuration inputs: provider: 'azurerm' command: 'validate' workingDirectory: ${{ parameters.workingTerraformDirectory } # Show changes required by the current configuration - task: TerraformTaskV3@3 displayName: Build Terraform Plan inputs: provider: 'azurerm' command: 'plan' workingDirectory: ${{ parameters.workingTerraformDirectory } environmentServiceNameAzureRM: ${{ parameters.subscription } # Create or update infrastructure - task: TerraformTaskV3@3 displayName: Apply Terraform Plan continueOnError: true inputs: provider: 'azurerm' command: 'apply' environmentServiceNameAzureRM: ${{ parameters.subscription } workingDirectory: ${{ parameters.workingTerraformDirectory } tf-provision-ci.jobs.yaml — Contains Terraform tasks, including init, show, validate, plan, and apply. Below, we can see the execution process. Figure 3: Azure DevOps Landing Zone Deployment UI As we can see, the execution of all pipelines is done successfully, and each job provides detailed information about state, configuration, and validation errors. Also, we must not forget to fill out the Request Access Form. It takes a couple of days to get a response back. Otherwise, the pipeline will fail with a quota error message. Terraform Scripts and Modules By utilizing Terraform, we can encapsulate the code within a Terraform module, allowing for its reuse across various sections of our codebase. This eliminates the need for duplicating and replicating the same code in multiple environments, such as staging and production. Instead, both environments can leverage code from a shared module, promoting code reusability and reducing redundancy. A Terraform module can be defined as a collection of Terraform configuration files organized within a folder. Technically, all the configurations you have written thus far can be considered modules, although they may not be complex or reusable. When you directly deploy a module by running “apply” on it, it is called a root module. However, to truly explore the capabilities of modules, you need to create reusable modules intended for use within other modules. These reusable modules offer greater flexibility and can significantly enhance your Terraform infrastructure deployments. Let’s look at the project structure below. Figure 4: Terraform Project Structure Modules The image above shows that all resources are placed in one Module directory. Each Environment has its directory, index terraform file, and variables where all resources are reused in an index.tf file with different parameters that are inside variable files. We will place all resources in a separate file in the module, and all values will be put into Terraform variables. This allows managing the code quickly and reduces hardcoded values. Also, resource granularity allows organized teamwork with a GIT or other source control (fewer merge conflicts). Let’s have a look into the open-ai tf module. YAML resource "azurerm_cognitive_account" "openai" { name = var.name location = var.location resource_group_name = var.resource_group_name kind = "OpenAI" custom_subdomain_name = var.custom_subdomain_name sku_name = var.sku_name public_network_access_enabled = var.public_network_access_enabled tags = var.tags identity { type = "SystemAssigned" } lifecycle { ignore_changes = [ tags ] } } The Open AI essential parameters lists: prefix: Sets a prefix for all Azure resources domain: Specifies the domain part of the hostname used to expose the chatbot through the Ingress Controller subdomain: Defines the subdomain part of the hostname used for exposing the chatbot via the Ingress Controller namespace: Specifies the namespace of the workload application that accesses the Azure OpenAI Service service_account_name: Specifies the name of the service account used by the workload application to access the Azure OpenAI Service vm_enabled: A boolean value determining whether to deploy a virtual machine in the same virtual network as the AKS cluster location: Specifies the region (e.g., westeurope) for deploying the Azure resources admin_group_object_ids: The array parameter contains the list of Azure AD group object IDs with admin role access to the cluster. We need to pay attention to the subdomain parameters. Azure Cognitive Services utilize custom subdomain names for each resource created through Azure tools such as the Azure portal, Azure Cloud Shell, Azure CLI, Bicep, Azure Resource Manager (ARM), or Terraform. These custom subdomain names are unique to each resource and differ from regional endpoints previously shared among customers in a specific Azure region. Custom subdomain names are necessary for enabling authentication features like Azure Active Directory (Azure AD). Specifying a custom subdomain for our Azure OpenAI Service is essential in some cases. Other parameters can be found in “Create a resource and deploy a model using Azure OpenAI.” In the Next Article Add an Az private endpoint into the configuration: A significant aspect of Azure Open AI is its utilization of a private endpoint, enabling precise control over access to your Azure Open AI services. With private endpoint, you can limit access to your services to only the necessary resources within your virtual network. This ensures the safety and security of your services while still permitting authorized resources to access them as required. Integrate OpenAI with Aazure Kubernetes Services: Integrating OpenAI services with a Kubernetes cluster enables efficient management, scalability, and high availability of AI applications, making it an ideal choice for running AI workloads in a production environment. Describe and compare our lightweight landing zone and OpenAI landing zone from Microsoft. Project Repository GitHub - Boriszn/Azure-AI-LandingZone Conclusion This article explores AI products and creating an AI landing zone. We highlight three key players benefiting from AI: Reply.io for sales engagement, Github Copilot for coding help, and Neuraltext for AI-driven content. Moving to AI landing zones, we focus on Azure AI services, like Open AI, with pre-built models and APIs. We delve into architecture using Terraform and CI/CD pipelines. Terraform’s modular approach is vital, emphasizing reusability. We delve into Open AI module parameters, especially custom subdomains for Azure Cognitive Services. In this AI-driven era, automation and intelligent decisions are revolutionizing technology.
Explore the step-by-step process of deploying a Lambda-backed API using AWS CDK in this detailed guide. From setting up your environment to implementing and testing the API, this blog post covers it all. Ideal for both beginners and experienced developers, this guide offers practical examples and clear explanations to help you manage complex cloud infrastructure effectively. Dive in to enhance your understanding of AWS CDK and learn how to deploy a functional web API. Step 1: Setting up Your Environment Before you can start using AWS CDK, ensure you have Node.js, AWS CLI, and AWS CDK Toolkit installed. Configure your AWS credentials using the AWS CLI... Here’s a more detailed breakdown: Install Node.js: AWS CDK requires Node.js, which is a JavaScript runtime that lets you run JavaScript code on your computer. You can download Node.js from the official website. AWS CDK requires Node.js version 10.x or later. After installing, you can verify the installation by running node --version in your terminal or command prompt. Install AWS CLI: The AWS Command Line Interface (CLI) is a tool that allows you to interact with AWS services from your terminal or command prompt. You can download AWS CLI from the official AWS website. After installing, you can verify the installation by running aws --version. Configure AWS CLI: After installing AWS CLI, you need to configure it with your AWS credentials. You can do this by running aws configureand then entering your Access Key ID, Secret Access Key, Default Region Name, and Default Output Format when prompted. These credentials are associated with your AWS account and are used to authenticate your requests. Install AWS CDK Toolkit: The AWS CDK Toolkit, also known as AWS CDK Command Line Interface (CLI), is a command-line tool that allows you to work with AWS CDK apps. You can install it by running npm install -g aws-cdk in your terminal or command prompt. The -g option installs the toolkit globally, making it available to all your projects. After installing, you can verify the installation by running cdk --version. Once you’ve completed these steps, your environment is set up and ready for AWS CDK development. Remember to keep your software up to date, as new versions often come with important features, improvements, and bug fixes. Step 2: Creating a New CDK Project Create a new CDK project using the cdk init command. For this example, we'll use TypeScript: cdk init app --language typescript Your output should look like this. After the execution is finished, you’ll notice that your project directory is populated with several new directories and files. These files form the basic structure of your CDK application. To give you a clearer picture, here’s what your filesystem should look like: Step 3: Defining the Infrastructure We’ll be creating a simple hit counter API. For that, we'll need an Amazon API Gateway to handle requests, an AWS Lambda function to process these requests and increment the hit counter, and an Amazon DynamoDB table to store the hit count. Start by navigating to the lib directory of your CDK project. This is where you’ll define your infrastructure. Within the lib directory, create a new directory called lambda at the root level and, within this directory, create a file named hitcounter.js. This directory and file will serve as the storage location and the codebase, respectively, for our backing lambda function. const { DynamoDB } = require('aws-sdk'); exports.handler = async function(event) { console.log("request:", JSON.stringify(event, undefined, 2)); try { // create AWS SDK clients const dynamo = new DynamoDB(); // update dynamo entry for "path" with hits++ const response = await dynamo.updateItem({ TableName: process.env.HITS_TABLE_NAME, Key: { path: { S: event.path } }, UpdateExpression: 'ADD hits :incr', ExpressionAttributeValues: { ':incr': { N: '1' } }, ReturnValues: 'UPDATED_NEW' }).promise(); const hits = Number(response.Attributes.hits.N); return { statusCode: 200, body: `This page has been viewed ${hits} times!` }; } catch (error) { console.error("Error:", error); return { statusCode: 500, body: "An error occurred. Please try again later." }; } }; Now, it’s time to create a Construct that will wire everything together. Back in the lib directory, create a file named hitcounter.ts. This file will define the Construct. import { Construct } from "constructs"; import { aws_apigateway as apigw, StackProps } from "aws-cdk-lib"; import { aws_dynamodb as dynamo} from "aws-cdk-lib"; import { aws_lambda as _lambda } from "aws-cdk-lib"; export class HitCounter extends Construct { constructor(scope: Construct, id: string, props: StackProps) { super(scope, id); const table = new dynamo.Table(this, 'Hits', { partitionKey: {name: 'path', type: dynamo.AttributeType.STRING} }); const func = new _lambda.Function(this, 'HitCounterHandler', { runtime: _lambda.Runtime.NODEJS_14_X, handler: 'hitcounter.handler', code: _lambda.Code.fromAsset('lambda'), environment: { HITS_TABLE_NAME: table.tableName } }); // grant the lambda role read/write permissions to our table table.grantReadWriteData(func); // defines an API Gateway REST API resource backed by our lambda function. new apigw.LambdaRestApi(this, 'Endpoint', { handler: func }); } } Lastly, we need to instantiate our Construct within a Stack to make it deployable. To do this, open the file lib/demo-project-stack.ts and add the necessary code to create an instance of the Construct. import * as cdk from 'aws-cdk-lib'; import { HitCounter } from "./hitcounter"; export class DemoProjectStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); new HitCounter(this, 'HelloHitCounter', {}) } } Step 4: Deploying the Infrastructure At this stage, we’re ready to deploy. Deploy the infrastructure using the cdk deploy command. This will create a CloudFormation stack with your API Gateway, Lambda function, and DynamoDB table. Here’s what happens in the backend when you run cdk deploy: CloudFormation Template Synthesis: AWS CDK first takes your app and compiles it into a CloudFormation template. This template is a JSON or YAML file that describes all the AWS resources your app is composed of. CloudFormation Stack Creation: AWS CDK then takes this CloudFormation template and deploys it as a CloudFormation stack. A stack is a collection of AWS resources that you can manage as a single unit. In other words, all the resources in a stack are created, updated, or deleted together. Resource Provisioning: AWS CloudFormation then looks at the template and provisions all the resources described in it. This includes creating AWS Lambda functions, setting up API Gateways, creating DynamoDB tables, and more. Stack Outputs: After the stack is successfully created, AWS CDK will display any outputs specified in your CDK app. Outputs are a way to export information about the resources in your stack, such as a URL for an API Gateway or the name of a DynamoDB table. Step 5: Testing the Hit Counter API You can test your hit counter API by making a GET request to the API Gateway URL. Each time you make a request, the hit counter should increment, and the new count should be displayed and stored in the DynamoDB table. Step 6: Cleaning Up After you’ve finished your project, it’s crucial to clean up and remove the resources you’ve deployed. This can be done by executing the cdk destroy command. This command will delete the CloudFormation stack, effectively removing all the resources that were provisioned as part of the stack. It’s important to note that if you neglect this cleanup step, AWS may continue to charge you for the resources that are still running. Therefore, to avoid any unnecessary costs, always remember to destroy your resources once you’re done using them. Conclusion By following these steps, you can deploy a hit counter API using AWS CDK. This API increments a hit counter every time it’s accessed, displays the latest count, and stores this data in a DynamoDB table. This example demonstrates the power and flexibility of AWS CDK, and how it can be used to manage complex cloud infrastructure. Resources CDK V2 Guide Create or Extend Constructs AWS Construct Library
The world of infrastructure management is constantly evolving, with new technologies and strategies emerging all the time. One such strategy that has gained traction in recent years is the use of feature flags in Infrastructure as Code (IaC). This powerful technique allows developers to control the release of new features and changes, minimizing the risk of disruption to critical systems. By using feature flags, teams can release new code with confidence, knowing that any issues can be quickly and easily rolled back. In this article, we'll explore the benefits of feature flags in IaC and how they can revolutionize the way we manage infrastructure. Whether you're a seasoned developer or new to the world of IaC, read on to discover how this technique can help you streamline your development process, improve your code quality, and deliver better outcomes for your organization. Understanding Infrastructure as Code (IaC) Infrastructure as Code (IaC) is a process of managing infrastructure in a programmable way, using code to define and deploy infrastructure resources. It allows you to automate the deployment and management of infrastructure resources, such as servers, networks, and databases, using the same tools and processes as you would for software development. IaC provides several benefits over traditional infrastructure management, including increased consistency and repeatability, faster deployment times, and better collaboration between teams. With IaC, you can manage and version your infrastructure as you would your code, enabling you to track changes, roll back to previous versions, and collaborate with other developers on changes. However, managing infrastructure as code can present its own challenges, particularly when it comes to deploying changes to live systems. This is where the use of feature flags can be helpful. Challenges in Infrastructure Management Managing infrastructure is a complex task that involves many moving parts, from servers and networks to databases and applications. As the number of systems and applications grows, managing changes becomes increasingly difficult, with more opportunities for things to go wrong. Deploying changes to live systems can be particularly challenging, as any disruption to critical systems can have serious consequences for your organization. Even small changes can have unforeseen consequences, leading to downtime, data loss, or other issues. To mitigate these risks, many organizations have turned to IaC as a way of automating the deployment and management of infrastructure resources. However, even with IaC, deploying changes can still be risky, as it can be difficult to predict the impact of changes on live systems. Using feature flags along with IaC can help in mitigating this risk to a greater extent. Benefits of Feature Flags in IaC Feature flags provide a way of controlling the release of new features and changes, allowing developers to deploy changes gradually and test them in a controlled environment before releasing them to live systems. By using feature flags, teams can release new code with confidence, knowing that any issues can be quickly and easily rolled back. Feature flags provide several benefits over traditional deployment methods, including: Reduced risk: By controlling the release of new features and changes, you can minimize the risk of disruption to critical systems. Faster iteration: By releasing new features gradually and testing them in a controlled environment, you can iterate more quickly and get feedback from users earlier in the development process. Improved code quality: By testing new features in a controlled environment before releasing them to live systems, you can catch issues earlier in the development process and improve the overall quality of your code. Better collaboration: By using feature flags, you can collaborate more effectively with other developers, as you can work on changes in parallel without disrupting each other's work. Better user experience: By releasing new features gradually and testing them in a controlled environment, you can ensure that new features are working as expected and provide a better user experience. Feature Flag Implementation in IaC Implementing feature flags in IaC involves several steps, including: Define your feature flags: Identify the features or changes that need to be controlled using feature flags. Implement your feature flags: Implement the feature flags in your code, using a feature flag framework or library. Control your feature flags: Use a feature flag management tool to control the release of new features and changes. Monitor your feature flags: Monitor the performance of your feature flags and use analytics to track usage and adoption. Feature Flag Management Best Practices To get the most out of feature flags in IaC, it's important to follow some best practices, including: Use a feature flag management tool: Use a feature flag management tool to centralize the management of your feature flags and control their release. Define clear naming conventions: Use clear and consistent naming conventions for your feature flags, to make it easier to understand what they do and how they're being used. Use feature flags sparingly: Use feature flags only when necessary, to minimize the complexity of your code and reduce the risk of bugs. Test your feature flags: Test your feature flags thoroughly before releasing them to live systems, to ensure that they're working as expected and won't cause any issues. Monitor your feature flags: Monitor the performance of your feature flags and use analytics to track usage and adoption. Popular Feature Flag Tools for IaC There are several popular feature flag tools available for IaC, including: IBM Cloud App Configuration: IBM Cloud App Configuration is a centralized feature management and configuration service available on IBM Cloud for use with web and mobile applications, microservices, and distributed environments. LaunchDarkly: A feature flag management tool that allows you to control the release of new features and changes using feature flags Flagr: An open-source feature flagging and A/B testing service that can be used to manage feature flags in IaC Unleash: An open-source feature flagging and A/B testing framework that can be used to manage feature flags in IaC Split: A feature flagging platform that allows you to control the release of new features and changes using feature flags Case Studies of Feature Flag Implementation in IaC Several organizations have successfully implemented feature flags in IaC, including: Airbnb: Airbnb implemented feature flags in their IaC processes to manage infrastructure changes and rollouts effectively. They used feature flags to control the deployment of new infrastructure components, allowing for gradual rollouts and testing. This approach helped them mitigate risks, identify issues early, and ensure a smooth transition during infrastructure updates. Atlassian: Atlassian, the company behind popular software tools like Jira and Confluence, used feature flags extensively in their IaC workflows. They employed feature flags to manage feature releases, gradual rollouts, and A/B testing of infrastructure components. By enabling and disabling feature flags, they controlled the visibility and availability of specific infrastructure features, allowing for iterative improvements and controlled deployments. SoundCloud: SoundCloud, the popular music streaming platform, adopted feature flags in their IaC practices. They utilized feature flags to control the rollout of infrastructure changes, including the deployment of new services and configurations. This enabled them to verify the impact of changes, collect user feedback, and ensure a seamless transition during infrastructure updates. Etsy: Etsy, the e-commerce marketplace, implemented feature flags as a fundamental part of their IaC strategy. They utilized feature flags to control the deployment of infrastructure changes, manage the visibility of features, and test new configurations. This approach allowed them to iterate quickly, validate changes, and maintain a reliable infrastructure environment. Future of Feature Flags in IaC The use of feature flags in IaC is likely to continue to grow in popularity, as more organizations look for ways to streamline their development process and reduce risk. As feature flagging tools become more sophisticated, it's likely that we'll see more advanced features, such as automated rollbacks, A/B testing, and machine learning-based feature flagging. One area where feature flags could have a significant impact is in the development of microservices and serverless architectures. As these architectures become more prevalent, the need for fine-grained control over features and changes will become increasingly important, making feature flags an essential tool for managing infrastructure. Conclusion Feature flags provide a powerful way of controlling the release of new features and changes in IaC, allowing teams to deploy changes gradually and test them in a controlled environment before releasing them to live systems. By using feature flags, teams can reduce risk, iterate more quickly, improve code quality, collaborate more effectively, and provide a better user experience. To get the most out of feature flags in IaC, it's important to follow best practices, such as using a feature flag management tool, defining clear naming conventions, using feature flags sparingly, testing your feature flags, and monitoring their performance. As the use of feature flags in IaC continues to grow, we can expect to see more advanced features and tools that make it even easier to manage infrastructure in a programmable way. Whether you're a seasoned developer or new to the world of IaC, incorporating feature flags into your development process can help you streamline your development process, improve your code quality, and deliver better outcomes for your organization.
John Vester
Staff Engineer,
Marqeta @JohnJVester
Marija Naumovska
Product Manager,
Microtica
Vishnu Vasudevan
Head of Product Engineering & Management,
Opsera
Seun Matt
Engineering Manager,
Cellulant