At Axelerant, we have experimented with multiple ways of CI/CD of Drupal. We have got a decent taste of integrations ranging from Acquia dev cloud, Pantheon, Platform.sh, etc. As we are a Gitlab massive shop for our code, Gitlab’s “autodevops” has got our attention. We decided to give it a shot and where we landed is an interesting thing. We are not doing “autodevops” or review apps. We have implemented a pipeline to build the application in a Docker container and deploy onto a k8s environment with many possible arbitrary stages for tests, scans, integrations. Let’s just dig a bit into this.
Services and Technologies
The following are the technologies we have used to implement the above. However, you are free to replace EKS with any of the managed k8s offerings.
- AWS EKS
- Hosted Gitlab
- Gitlab runners in AWS and EKS
- Drupal Dockerized
CI/CD onto k8s in a nutshell
We commit the code and push as the CI/CD system needs to build and tag the containers. And we deploy it onto a k8s cluster that exposes us to the URL of an ingress controller acting as a frontend to the application.
Adding a new k8S cluster
- Navigate to your project’s Operations > Kubernetes page
- Click Add Kubernetes cluster
- Click Add an existing Kubernetes cluster and fill in the details:
- Kubernetes cluster name (required): The name you wish to give the cluster
- Environment scope (required): When adding more than one Kubernetes cluster to your project, you need to differentiate them with an environment scope. The default environment scope is * means all jobs, regardless of their environment, will use that cluster
- To add the certificate details, follow GitLab documentation
- Once the cluster is added, this is how it looks:
.gitlab-ci.yml file consists of three stages. Where in the initial step, it focuses on dockerizing the Drupal application and then pushes the newly built image to the Docker repository. In the next stage, we perform Behat tests; for this, we spin up a new deployment by using the latest Drupal image that was built in an earlier stage. If the tests are successful, we use the same image to upgrade the helm deployment.
Dockerize the Drupal Application and push to the repo
- This stage requires the following variables to push to a private docker registry
- In this build stage, in the initial step, we do a docker login with the variables which are stored as variables in GitLab repo settings
- We build the Drupal Docker image with the Dockerfile stored in the repository and tag it
- We add CONTAINER_TEST_IMAGE as a global variable, as we are going to use this for our next stages
- Push that image to the Docker repository
- This step is valid for all the branches, and we assumed the master branch for release image with the latest tag
Deploy onto k8s
- We are using a stable/drupal helm chart to deploy on Kubernetes
- To incorporate the changes, we have to update the image that is used to deploy
- CI_COMMIT_REF_NAME is a predefined variable in GitLab
- In the before_script step, we make sure that the namespace is available
- We initiate helm and then install the helm chart with the image and tag passed as set variables
- Run any tests
Expose the URL: Ingress
Ingress is a part of Kubernetes that manages the external access to the services running on the cluster. Ingress component exposes HTTP and HTTPS from outside of the cluster to services running inside the cluster by providing services externally-reachable URLs, load balance traffic, terminate SSL / TLS, and offer name-based virtual hosting.
The ingress controller manages the ingress with a load balancer created for the cluster. Based on the ingress rules we define, this controller redirects the traffic to the target services.
For this specific task, we have created a cluster-wide Ingress controller and used Lets Encrypt to create SSL certificates for the wildcard domain. We created branch-based ingress, which routes the traffic to the specific services running in the namespace associated with the respective branch.
- Unpluggable components: All the components here are pluggable. We can use alternative platforms or managed hosting and accomplish the same result.
- Agnostic k8s environments: For this case, we have used AWS(EKS). But this will work straight forward with any other managed k8s offerings like AKS, DOKS, etc.
- Faster release cycles. With this approach, we are being very agile and achieving faster releases per sprint and have easy rollbacks in case of failures.
- Deploying onto k8s environments is a ready recipe for high availability. k8s takes care of handling any downtime automatically.
- Gitlab’s declarative CI/CD helps us introduce any number of stages that can perform sanity checks, functional, and integration tests before deploying.