Blog Engineering How to use a push-based approach for GitOps with Terraform and AWS ECS and EC2
August 10, 2021
9 min read

How to use a push-based approach for GitOps with Terraform and AWS ECS and EC2

Learn how GitLab supports agentless approach for GitOps on AWS.

Blog fallback hero

In part two of our GitOps series, we described how to use a push-based (or agentless) approach for GitOps by using GitLab scripting capabilities as well as integrating infrastructure-as-code tools into GitOps pipelines. In this third blog post, we’ll also dig deep into how to use a push-based approach, but this time our focus will be on the integrations of Terraform, AWS ECS, and AWS EC2 in GitOps flows. This approach may be preferable when using infrastructure components that aren't Kubernetes, such as VMs, physical devices, and cloud-provider services.

Similar to Ansible – an agentless IT automation solution – Terraform can be leveraged by the scripting capabilities of GitLab to shape your infrastructure. GitLab also provides out-of-the-box integrations with Terraform, such as GitLab-managed Terraform state and Terraform plan reports in merge requests.

GitOps flows with GitLab and Terraform

In this section, we explain how to use GitLab and Terraform for a non-Kubernetes GitOps flow and Kubernetes GitOps.

GitLab and Terraform for non-K8s infrastructure

GitLab leverages Terraform to provision a non-Kubernetes infrastructure component, namely a MySQL database running on AWS.

Note: Ideally, the provisioning of a database should be an on-demand, self-service process that developers can just use. We use this scenario to illustrate a GitOps flow using a non-Kubernetes infrastructure component.

How collaboration works in GitLab

Sasha, a developer, creates an issue and assigns the issue to Sidney, the database administrator, who then creates a Merge Request (MR) to start her work and invite collaboration with other stakeholders across the organization. Opening the MR automatically creates a feature branch for the GitLab project. Sidney uses Terraform to create an infrastructure-as-code configuration for the database, named mysqlmain.tf. The database happens to be an AWS RDS MySQL instance. The database Terraform configuration file should look like this:

Terraform configuration file for MySQL database Terraform configuration file for MySQL database.

Take note of the version of the database (engine_version), the database storage (allocated_storage), and the embedded database admin user (username) and password, in the image above.

As soon as Sidney adds the file mysqlmain.tf file to the feature branch, a pipeline is automatically executed by GitLab in the MR. As part of the review process, a "Terraform plan" is executed against the Terraform files and the output is attached to the MR as an artifact:

Terraform plan output attached to Merge Request Terraform plan output attached to MR.

In the picture above, you can see the note "1 Terraform report was generated in your pipelines". You can click on the View full log button to see the output file of the "Terraform plan" command that was run against the new configuration file, as seen below:

Terraform plan output detailed log view Terraform plan output detailed log view.

The Terraform output shows that a database will be created once this configuration file is applied to the infrastructure. The artifacts attached to an MR provide information that can help stakeholders review the proposed changes. The Terraform output in the MR fosters collaboration between stakeholders, and leads to infrastructure that is more consistent, resilient, reliable, and stable, and helps prevent unscheduled outages.

In the image below, we see how reviewers can collaborate in GitLab. The screenshow shows that the original requester, Sasha, notices that a database storage of 5 GB is too small, so she makes an inline suggestion to increase the database storage capacity to 10 GB.

Inline suggestion to increase database storage to 10GB Inline suggestion to increase database storage to 10GB.

Inline suggestions foster collaboration and help increase developer productivity suggested changes can be added with the click of a button.

Next, Sidney invites DevOps engineer Devon to collaborate on the MR. Devon notices that the database version in the configuration file is not the latest one. He proceeds to make an inline suggestion proposing a more up-to-date version for Sidney to review:

Inline suggestion to update database version Inline suggestion to update database version.

Sidney can monitor the discussion between code reviewers on the MR by tracking the number of unresolved threads. So far, there are four unresolved threads:

Number of unresolved threads displayed at the top of the MR Number of unresolved threads displayed at the top of the MR.

Sidney starts resolving the threads by following the convenient thread navigation provided by GitLab, which makes it easy for her to process each of the proposed review items. Sidney just needs to click "Apply suggestion" to accept an input from a reviewer:

Applying a suggestion with a single button click Applying a suggestion with one click.

Devon suggested replacing the embedded database admin username and password with a parameter in the inline review, so Sidney replaces the embedded values with variables. The variable values will be managed by masked variables within GitLab:

Parameterizing variables in Terraform configuration file Parameterizing variables in Terraform configuration file.

Once the threads are resolved and the stakeholders involved in thh MR finish collaborating, it's time to merge.

Learn more about how GitLab fosters collaboration using the principles of GitOps in the video below:

In this next example, Sasha is the one merging the MR:

Merge Request with infrastructure updates being merged MR with infrastructure updates being merged.

Merging automatically launches a pipeline that will apply the changes to the infrastructure:

GitOps pipeline completed execution GitOps pipeline completed execution.

CI/CD with non-K8s infrastructure

The CI/CD pipeline in the previous example works by validating the infrastructure configuration files. Then the pipeline validates the proposed updates against the current state of the infrastructure. Finally, it applies the updates to the production infrastructure.

Running this GitOps flow results in a brand new MySQL database on AWS RDS:

A new MySQL database has been created via a GitOps flow A new MySQL database has been created via a GitOps flow.

By checking the details of the new MySQL database you can corroborate that the database storage is 10 GB and that the database version is the most current"

Resulting MySQL database configuration from the collaboration of stakeholders The MySQL database configuration built by team member collaboration.

In the next section, we look at how a similar GitOps flow can be applied to a Kubernetes cluster.

GitLab and Terraform for K8s infrastructure

We skip past all the collaboration steps to focus on a change to the EKS cluster Terraform configuration file. In the picture below, a user is changing the minimum size of the autoscaling group of the EKS cluster from one to two:

Raising autoscaling group minimum to 2 Increasing autoscaling group minimum to two.

When the stakeholder commits the change in the MR, a CI/CD pipeline validates the configuration, performs a plan against production, and applys the updates to the production infrastructure. After the pipeline finishes, the user can log into the Amazon EC2 console to verify that the EKS cluster now has a minimum of two nodes in its autoscaling group:

GitOps flow modified the number of worker nodes in K8s cluster GitOps flow modified the number of worker nodes in K8s cluster.

See this scenario in action by watching the GitOps presentation on our GitOps topics page.

GitOps flows for non-K8s (like ECS, EC2)

GitLab also provides Auto Deploy capabilities to streamline application deployment to ECS and EC2, so you can shape infrastructure as desired.

Deploying to Amazon ECS

After creating your ECS cluster, GitLab can deliver your application and its infrastructure to the cluster by including the ECS Deployment template in your gitlab-ci.yml, using CI/CD.

include:
Template: AWS/Deploy-ECS.gitlab-ci.yml

Next, create the ECS Task Definition file in your project that specifies your app's infrastructure requirements, along with other details.

ECS Task Definition file snippet ECS Task Definition file snippet.

Finally, define the project variable that will drive the template:

Project variables required to auto-deploy to ECS Project variables required to auto-deploy to ECS.

The ECS deployment template does the rest, including support review pipelines.

Review pipeline in GitOps flow Review pipeline in GitOps flow.

In the review pipeline above, stakeholders can review the proposed changes before sending to production. The two screenshots below show different aspects of the proposed changes in the log output of the review_fargate job:

Configuring load balancers in ECS Configure load balancers in ECS.

See the configuration for infrastructure components like load balancers in the image above. The image below shows infrastructure components like subnets, security groups, and the assignment of a public IP address:

Configuring subnets, security groups in ECS Configuring subnets and security groups in ECS.

Once all stakeholders are done collaborating on a proposed change to the production infrastructure, the updates are applied using a CI/CD pipeline. Below is an example of this type of pipeline:

Applying infrastructure updates to production Applying infrastructure updates to production.

Read our documentation to learn more about how GitLab users can Auto Deploy to ECS.

Deploying to Amazon EC2

GitLab also provides a built-in template to provision infrastructure and deploy your applications to EC2 as part of Auto DevOps. The template:

  • Provisions infrastructure using AWS CloudFormation
  • Pushes application to S3
  • Deploys your application from S3 to EC2

Each of these steps requires a JSON configuration file. Below is an example of a portion of a CloudFormation Stack JSON file used to create your infrastructure:

CloudFormation stack JSON snippet CloudFormation stack JSON snippet.

The JSON used by the Auto Deploy template to push your application to S3 would look similar to this:

JSON to push application to S3 JSON to push application to S3.

And the file used for the actual deployment of your application from S3 to EC2 would be like the following:

JSON to deploy application to EC2 JSON to deploy application to EC2.

After creating these files, you need to create the following variables in your project - displayed here with some sample values:

variables:
  CI_AWS_CF_CREATE_STACK_FILE: 'aws/cf_create_stack.json'
  CI_AWS_S3_PUSH_FILE: 'aws/s3_push.json'
  CI_AWS_EC2_DEPLOYMENT_FILE: 'aws/create_deployment.json'
  CI_AWS_CF_STACK_NAME: 'YourStackName'

The last step is to include the template in your .gitlab-ci.yml file:

include:
  - template: AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml

More details on how GitLab uses Auto Deploy to EC2 are available in the documentation.

Agent or agentless: GitLab has your GitOps flows covered

Whether your situation calls for an agent-based/pull-approach to doing GitOps, or for an agentless/push-approach, GitLab has your back. GitLab offers the flexibility to choose the approach to GitOps that best fits your specific projects or applications. GitLab also supports many types of infrastructures – from physical components and virtual machines, Kubernetes and containers, as well as infrastructure-as-code tools like Terraform, Ansible, and AWS Cloud Formation.

We want to hear from you

Enjoyed reading this blog post or have questions or feedback? Share your thoughts by creating a new topic in the GitLab community forum. Share your feedback

Ready to get started?

See what your team could do with a unified DevSecOps Platform.

Get free trial

New to GitLab and not sure where to start?

Get started guide

Learn about what GitLab can do for your team

Talk to an expert