Regardless of the starting point for migrating to Managed Kubernetes, there is a general list of steps recommended to be performed before starting.
Let’s take a closer look at each operation.
Preparing The Code
This step is required for scenarios where the company has previously used monolithic applications without containerization. For other types of migration, it is optional: refactoring applications is carried out if necessary.
Preparing the code consists of the following steps:
Partial Or Complete Conversion Of Monolithic Code To Microservices
Take a monolithic application and put it in a container.You will most likely have problems deploying and running the application since containers are not designed for this use case. We talked in more detail about the issues of the work of monoliths in containers in this article. In short, here are just some of the disadvantages of monoliths that complicate their use in the K8s cluster unchanged:
- They are using local data stores. Most often, monoliths store data “under themselves” locally. To prevent data loss, you will need to train the monolith to work with stateful storage. It can be a local database, DBaaS, object storage, or Persistent Volumes of Kubernetes itself, built based on block or file storage of a cloud provider.
- They are using local caches. Monoliths most often use in-memory storage like Memcached or Redis as a cache, accessing them locally. When moving to K8s, you will need to deploy Redis Cluster and interact with it exactly like a cluster, which classic monoliths cannot.
- Failure to work in multiple instances This will also need to train your monolithic application, and the cases must be able to access data stored separately from the monolith.
Failure To Correctly Handle Moving Instances To New Nodes
- In a monolithic architecture, client applications, even those capable of working with multiple models, can interact with only one example within the current session. Therefore, each move of the instance to a new node will reset the session. This contradicts the core K8s concept that application instances must quickly move between nodes to provide balancing, fault tolerance, and auto-failover. Therefore, the monolith needs to be taught to handle such switches, or the balancer needs to implement the Sticky Session method, with the help of which will distribute requests to servers based on the client’s IP addresses.
- To avoid the described problems, increase fault tolerance, and get a higher build and deployment speed, it is recommended to break such programs into small, loosely coupled services immediately. Of course, some monoliths (primarily stateless) can be transferred to containers unchanged. Still, to take advantage of all the advantages of K8s, they will need refactoring in the future. They created containerization and orchestration specifically to work with microservices.
Application Of The “12 Factors” Methodology
It describes best practices for building cloud applications. When migrating to the cloud, it is essential to understand and apply at least some of these principles, for example: storing source code in a version control system, separating the stages of building, deploying and launching an application, storing credentials in environment variables (in Kubernetes, this is possible using secrets).
You must use containerization if you don’t. To write Docker files, you can use ready-made images available in public repositories for most frameworks and environments. Many approach the choice of pictures with an installed application stack responsibly: some of them may be incorrectly configured. In addition, cannot the risk of security problems cannot be ignored. Any images must be checked for vulnerabilities and exclude dependencies not used in a specific project from them.
- There are tools for automatically generating Docker files. For example, Docker Enterprise provides a solution for automatically packaging .NET applications into Docker containers.
- Another essential consideration in containerization is determining the memory, disk, and processor requirements of applications. In the future, this data will be helpful when starting containers (indicating the restrictions on the resources used) and configuring the cluster.
Creation And Configuration Of a Cluster
This step is required for all migration scenarios. It is necessary to select the optimal configuration of the future cluster and create it in the chosen cloud platform. The main points to pay attention to when designing and further configuring a set:
- The number of Master and Worker nodes For production clusters, three Master nodes are recommended. The number of Worker-nodes should allow placing all applications in at least two copies. The more Worker nodes, the higher the fault tolerance of the application.
- Accessibility zone. The closest area should be selected for best performance if traffic is expected from a specific geographic location.
- Configuration of virtual machines. You should first evaluate the memory and CPU requirements of your application. The production node must have sufficient resources to deploy and run it. It is also essential to set quotas for the resources used in the deployment.YAML specifications (in the resources section). Kubernetes will use these limits to select a worker node that has sufficient capacity to run the application.
- Autoscaling. Suppose frequent and unpredictable traffic jumps are possible when using the application. In that case, it is advisable to configure autoscaling, thanks to which new Worker nodes in the cluster will be automatically created at times of peak loads. But at the same time, it is essential to correctly select the boundaries for autoscaling (minimum and a maximum number of nodes) and use AntiDDos programs without fail. Otherwise, DDoS attacks, perceived by K8s as normal loads, can lead to financial losses.
- External access to the cluster. To organize access to the cluster from the outside, you should use the Ingress Controller, for example, Nginx. It will allow you to define rules for routing external traffic.
- Monitoring. When adding a cluster, it is advisable to think about collecting metrics and setting up alerts based on them, for example, using Prometheus and Grafana. Many providers offer these tools as pre-installed services. It is also recommended to use centralized storage of logs – for example, based on ELK.
- Persistent data storage. It Cannot data stored inside a container cannot be transferred to other containers. In addition, if a container crashes or is removed, they are lost. Therefore, instead of storing data on the local file system of the container, you should consider using Persistent Volumes (PV) -based storage in K8s. As a persistent data storage for Docker containers as part of a Kubernetes cluster, providers offer block and file (most often NFS) storage.
- RBAC (Role-Based Access Control) and security policies. K8s can create service accounts and differentiate their access to various cluster resources. It is helpful, in particular, when setting up access to the cluster from the CI / CD pipeline – so that the Runner can deploy applications to Kubernetes.
- Kubernetes namespaces. It is essential to think about adequately organizing the cluster resources: you can work in the default namespace, but creating multiple namespaces with their resource quotas is desirable.
- Secrets. It is recommended to use Kubernetes secrets to store confidential information such as passwords, OAuth tokens, and SSH keys.
- The number of clusters. It is recommended that you separate the development/test and production clusters. On many cloud platforms, cluster configuration templates are even available for various environments, differing in the number of Master nodes and VM configuration.
Providers often offer a convenient admin panel for adding clusters, but another option is also possible – using the IaC (Infrastructure as a Code) approach.
The essence of IaC is that the entire infrastructure is described declaratively in the form of code. The description includes the network topology, a list of virtual machines required by the application, their resource requirements, configuration, etc. Terraform has recently become the de facto standard for these tasks: it is supported by most cloud providers. Its goal is to provide the ability to deploy infrastructure, including when changing cloud providers quickly.
For example, suppose the company has previously used a Kubernetes cluster On-premise or in the cloud, and there is a declarative description of the set. In that case, all that is required to switch to another cloud platform is to change the Environment variables and slightly format the code for a specific Terraform provider. This will significantly speed up cluster migration.
Of course, with a small number of virtual machines, manual configuration of the cluster is also possible. And it’s recommended if your company doesn’t have Kubernetes experience yet. However, in the future, it will not be superfluous to consider the possibility of using IaC, especially if the number of virtual machines is measured in tens and hundreds of complex network topology are used in the project.
Preparing K8s YAML files
This step is required for all migration scenarios, but with the following features:
- If you have not previously had an orchestrator or used an orchestrator other than K8s, the YAML files must be written from scratch.
- At the same time, tools for automatic conversion from Docker Compose files to Kubernetes YAML are available for Docker Swarm, for example, Compose. However, it can only be seen as an aid when migrating a large number of manifests. Experience shows that the converted files still have to be edited manually to exclude unnecessary tags and consider all the advantages of Kubernetes related to deployments, labels, tolerations, and so on.
- Migrating from other orchestrators (Nomad, Mesos, and so on) is only possible manually since their manifests are incompatible with Kubernetes.
- If you previously used a PaaS platform like Rancher or OpenShift, you will most likely need to rewrite the YAML files for vanilla Kubernetes partially.
- When migrating from K8s, which was deployed on-premise or in another cloud platform, in most cases, YAML files will not need to be changed since providers monitor the compatibility of their Managed solutions with the Open Source version of K8s. If there are edits, then cosmetic.
In Kubernetes, almost everything is based on YAML files. Still, first, it is enough to study and configure manifests for three main abstractions: Deployment – to describe the application’s life cycle, Service – to organize network access and balance requests within the cluster, Ingress – to arrange external access to the set.
It is advisable to store all configured manifests in a shared repository and the main application’s code to automatically apply them to the cluster in the future when executing CI / CD pipelines. As the number of YAML files grows, you can develop your Helm charts that will avoid using each file separately and collect the resources needed for your application in one place.
Setting Up CI / CD
Setting up an automated build and application deployment pipeline is recommended for all migration scenarios that have not been used. Of course, you can also manually apply YAML files to a Kubernetes cluster and deploy Docker images in it. Still, with an increase in the number of microservices and the frequency of releases, it will become almost impossible to work without a pipeline. Therefore, it is better to implement CI / CD right away – in both test and production environments. This requires:
- choose a CI / CD build tool – for example, GitLab ;
- Select the Docker Registry – the registry into which the Docker application images generated during the build will be placed. GitLab has a built-in Docker Registry;
- Configure the Runner, which is responsible for launching pipelines. If you are using Managed GitLab at gitlab.com, then public runners may be limited in CI hours. There are Helm charts for installing specific runners, for example, GitLab Runner ;
- Configure the GitLab-ci.yml manifest, which will describe all stages of the pipeline. These stages are most often identified as testing the code (test), building the Docker image (build), and deploying the finished image in the K8s cluster (deploy).
In general, the CI / CD process when working with Kubernetes might look like this. When changes are committed to the source code repository, a new pipeline is launched. The test stage is performed (if it is described in the channel) and the build stage. As a result of the assembly, a ready-to-deploy Docker image with application files is generated. This image is placed in the Docker Registry. Kubernetes pulls the application image from the Docker Registry in the deploy phase and deploys it to the cluster.