[{"data":1,"prerenderedAt":1813},["ShallowReactive",2],{"/blog/using-ansible-and-gitlab-as-infrastructure-for-code":3,"navigation-en-us":1014,"banner-en-us":1441,"footer-en-us":1451,"blog-post-authors-en-us-George Kichukov|Salahddine Aberkan":1696,"blog-related-posts-en-us-using-ansible-and-gitlab-as-infrastructure-for-code":1723,"blog-promotions-en-us":1749,"next-steps-en-us":1803},{"id":4,"title":5,"authors":6,"body":9,"category":993,"date":994,"description":995,"extension":996,"externalUrl":997,"faq":997,"featured":998,"heroImage":999,"meta":1000,"navigation":545,"path":1001,"seo":1002,"slug":1006,"stem":1007,"tags":1008,"template":1011,"updatedDate":1012,"__hash__":1013},"blogPosts/en-us/blog/using-ansible-and-gitlab-as-infrastructure-for-code.md","Build enterprise-grade IaC pipelines with GitLab DevSecOps",[7,8],"George Kichukov","Salahddine Aberkan",{"type":10,"value":11,"toc":982},"minimark",[12,16,19,22,25,32,37,46,49,91,100,106,111,120,154,161,316,324,331,456,461,464,473,479,488,494,498,507,515,680,686,694,700,704,713,719,727,836,842,846,865,904,910,916,925,931,936,940,943,946,952,956,959,963,966,978],[13,14,15],"p",{},"Infrastructure-as-code tools like TerraForm/OpenTofu and configuration management tools like Ansible are often part of mission-critical workflows. Such projects sometimes start as simple automations and are not necessarily subject to the same software development best practices and regulatory controls as business software applications.",[13,17,18],{},"At the same time many of these automations are developed by system engineers or infrastructure engineers who may not have as much experience with DevOps, DevSecOps, CI/CD, and test automation practices. This becomes even more complicated when you work in a large enterprise organization with multiple engineers and siloed teams.",[13,20,21],{},"At GitLab we know DevSecOps and we have been using our unified DevSecOps platform for enterprise-scale, mission-critical automation workloads for more than 10 years. We have thousands of customers who use GitLab as a foundation for infrastructure as code (IaC), automation, cloud, and platform engineering practices.",[13,23,24],{},"In this article, we showcase some of the key features teams can leverage to turn their powerful automations into scalable and auditable software delivery pipelines.",[13,26,27],{},[28,29],"img",{"alt":30,"src":31},"Automation listing","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433380/oipm6tq8qutoh1ctredd.png",[33,34,36],"h2",{"id":35},"implementation","Implementation",[13,38,39,45],{},[40,41,44],"a",{"href":42,"rel":43},"https://gitlab.com/gl-demo-ultimate-saberkan/public/ansible-demo",[],"This project"," demonstrates a comprehensive DevOps workflow that combines the power of OpenTofu with modern Ansible practices, all orchestrated through GitLab CI/CD pipelines. The solution showcases how to provision an AWS lab environment using OpenTofu components integrated with GitLab, and then deploy a Tomcat web server using modern Ansible, including custom execution environments and collections.",[13,47,48],{},"The project leverages numerous GitLab features:",[50,51,52,61,68,75,83],"ul",{},[53,54,55,56],"li",{},"Building and storing custom Ansible execution environments in the ",[40,57,60],{"href":58,"rel":59},"https://docs.gitlab.com/user/packages/container_registry/",[],"GitLab Container Registry",[53,62,63],{},[40,64,67],{"href":65,"rel":66},"https://docs.gitlab.com/user/application_security/iac_scanning/",[],"Security scanning for infrastructure as code and container vulnerabilities",[53,69,70,71],{},"Integrating ",[40,72,74],{"href":65,"rel":73},[],"Ansible linting with GitLab's Code Quality",[53,76,77,78],{},"Storing Tomcat binaries in the ",[40,79,82],{"href":80,"rel":81},"https://docs.gitlab.com/user/packages/generic_packages/",[],"Generic Package Repository",[53,84,85,86],{},"Utilizing ",[40,87,90],{"href":88,"rel":89},"https://docs.gitlab.com/ci/variables/",[],"CI/CD environment variables for configuration",[13,92,93,94,99],{},"The entire workflow is automated through a ",[40,95,98],{"href":96,"rel":97},"https://docs.gitlab.com/ci/pipelines/",[],"GitLab pipeline"," that handles everything from infrastructure provisioning to application deployment and security testing.",[13,101,102],{},[28,103],{"alt":104,"src":105}," Workflow automated through a GitLab pipeline ","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433380/giatmolwn9inusi4cev2.png",[107,108,110],"h3",{"id":109},"provisioning-the-environment-with-opentofu","Provisioning the environment with OpenTofu",[13,112,113,114,119],{},"The project begins with provisioning an AWS lab environment using OpenTofu. This is achieved through native integration with ",[40,115,118],{"href":116,"rel":117},"https://docs.gitlab.com/user/infrastructure/iac/",[],"GitLab's OpenTofu components",", which streamline the infrastructure provisioning process. The pipeline includes validate, plan, and apply stages that ensure proper infrastructure deployment while maintaining GitLab's IaC best practices.",[13,121,122,123,128,129,134,135,140,141,145,146,149,150,153],{},"This project is leveraging ",[40,124,127],{"href":125,"rel":126},"https://docs.gitlab.com/user/infrastructure/iac/terraform_state/",[],"GitLab's Terraform State management"," and ",[40,130,133],{"href":131,"rel":132},"https://docs.gitlab.com/user/packages/terraform_module_registry/",[],"Terraform Module Registry"," capabilities. Both of these features are compatible with OpenTofu and HashiCorp Terraform. GitLab OpenTofu components can also be used with HashiCorp Terraform with ",[40,136,139],{"href":137,"rel":138},"https://gitlab.com/components/opentofu#can-i-use-this-component-with-terraform",[],"slight customization",". You'll need to build your own image that includes a script named ",[142,143,144],"code",{},"gitlab-tofu"," to keep it compatible with the component jobs then you can then modify ",[142,147,148],{},"tofu"," commands with ",[142,151,152],{},"terraform"," commands.",[13,155,156,157,160],{},"The OpenTofu module release component is a sample demonstrating how to build a Terraform module and store it in GitLab's Terraform module registry. The ",[142,158,159],{},"provision_lab.tf"," file imports this module directly from GitLab to deploy the lab environment in AWS. Upon completion, it outputs an inventory file containing the public IP address of the provisioned instance, which can be used in configuration management stages with Ansible.",[162,163,168],"pre",{"className":164,"code":165,"language":166,"meta":167,"style":167},"language-yaml shiki shiki-themes github-light","# From .gitlab-ci.yml\n - component: gitlab.com/components/opentofu/module-release@1.1.0\n   inputs:\n     root_dir: tofu\n     as: 🔍 tofu-module-release\n     stage: 🏗️ build-tofu-module\n     module_version: 0.0.1\n     module_system: aws\n     module_name: aws-lab\n     root_dir: tofu/modules/ansible-demo/aws-lab\n     rules:\n       - if: \"$CI_COMMIT_BRANCH\"\n         when: manual\n\n","yaml","",[142,169,170,179,197,206,217,228,239,251,262,273,283,291,305],{"__ignoreMap":167},[171,172,175],"span",{"class":173,"line":174},"line",1,[171,176,178],{"class":177},"sAwPA","# From .gitlab-ci.yml\n",[171,180,182,186,190,193],{"class":173,"line":181},2,[171,183,185],{"class":184},"sgsFI"," - ",[171,187,189],{"class":188},"shJU0","component",[171,191,192],{"class":184},": ",[171,194,196],{"class":195},"sYBdl","gitlab.com/components/opentofu/module-release@1.1.0\n",[171,198,200,203],{"class":173,"line":199},3,[171,201,202],{"class":188},"   inputs",[171,204,205],{"class":184},":\n",[171,207,209,212,214],{"class":173,"line":208},4,[171,210,211],{"class":188},"     root_dir",[171,213,192],{"class":184},[171,215,216],{"class":195},"tofu\n",[171,218,220,223,225],{"class":173,"line":219},5,[171,221,222],{"class":188},"     as",[171,224,192],{"class":184},[171,226,227],{"class":195},"🔍 tofu-module-release\n",[171,229,231,234,236],{"class":173,"line":230},6,[171,232,233],{"class":188},"     stage",[171,235,192],{"class":184},[171,237,238],{"class":195},"🏗️ build-tofu-module\n",[171,240,242,245,247],{"class":173,"line":241},7,[171,243,244],{"class":188},"     module_version",[171,246,192],{"class":184},[171,248,250],{"class":249},"sYu0t","0.0.1\n",[171,252,254,257,259],{"class":173,"line":253},8,[171,255,256],{"class":188},"     module_system",[171,258,192],{"class":184},[171,260,261],{"class":195},"aws\n",[171,263,265,268,270],{"class":173,"line":264},9,[171,266,267],{"class":188},"     module_name",[171,269,192],{"class":184},[171,271,272],{"class":195},"aws-lab\n",[171,274,276,278,280],{"class":173,"line":275},10,[171,277,211],{"class":188},[171,279,192],{"class":184},[171,281,282],{"class":195},"tofu/modules/ansible-demo/aws-lab\n",[171,284,286,289],{"class":173,"line":285},11,[171,287,288],{"class":188},"     rules",[171,290,205],{"class":184},[171,292,294,297,300,302],{"class":173,"line":293},12,[171,295,296],{"class":184},"       - ",[171,298,299],{"class":188},"if",[171,301,192],{"class":184},[171,303,304],{"class":195},"\"$CI_COMMIT_BRANCH\"\n",[171,306,308,311,313],{"class":173,"line":307},13,[171,309,310],{"class":188},"         when",[171,312,192],{"class":184},[171,314,315],{"class":195},"manual\n",[162,317,322],{"className":318,"code":320,"language":321,"meta":167},[319],"language-text","# From provision_lab.tf\nmodule \"aws-lab\" {\n  source = \"https://gitlab.com/api/v4/projects/67604719/packages/terraform/modules/aws-lab/aws/0.0.1\"\n}\n","text",[142,323,320],{"__ignoreMap":167},[13,325,326,327,330],{},"The validate, plan, and deploy components are configured with ",[142,328,329],{},"**auto_define_backend: true**",", which automatically integrates with GitLab's built-in Terraform state backend. This approach eliminates the need for manual backend configuration or external state storage solutions like S3 buckets.",[162,332,334],{"className":164,"code":333,"language":166,"meta":167,"style":167},"# From gitlab-ci.yml\n- component: gitlab.com/components/opentofu/apply@0.55.0\n  inputs:\n    version: 0.55.0\n    opentofu_version: 1.8.8\n    root_dir: tofu\n    state_name: demo\n    as: ✅ tofu-apply\n    stage: 🏗️ provision-lab\n    auto_define_backend: true\n    rules:\n      - if: \"$CI_COMMIT_BRANCH\"\n        when: manual\n\n",[142,335,336,341,353,360,370,380,389,399,409,419,429,436,447],{"__ignoreMap":167},[171,337,338],{"class":173,"line":174},[171,339,340],{"class":177},"# From gitlab-ci.yml\n",[171,342,343,346,348,350],{"class":173,"line":181},[171,344,345],{"class":184},"- ",[171,347,189],{"class":188},[171,349,192],{"class":184},[171,351,352],{"class":195},"gitlab.com/components/opentofu/apply@0.55.0\n",[171,354,355,358],{"class":173,"line":199},[171,356,357],{"class":188},"  inputs",[171,359,205],{"class":184},[171,361,362,365,367],{"class":173,"line":208},[171,363,364],{"class":188},"    version",[171,366,192],{"class":184},[171,368,369],{"class":249},"0.55.0\n",[171,371,372,375,377],{"class":173,"line":219},[171,373,374],{"class":188},"    opentofu_version",[171,376,192],{"class":184},[171,378,379],{"class":249},"1.8.8\n",[171,381,382,385,387],{"class":173,"line":230},[171,383,384],{"class":188},"    root_dir",[171,386,192],{"class":184},[171,388,216],{"class":195},[171,390,391,394,396],{"class":173,"line":241},[171,392,393],{"class":188},"    state_name",[171,395,192],{"class":184},[171,397,398],{"class":195},"demo\n",[171,400,401,404,406],{"class":173,"line":253},[171,402,403],{"class":188},"    as",[171,405,192],{"class":184},[171,407,408],{"class":195},"✅ tofu-apply\n",[171,410,411,414,416],{"class":173,"line":264},[171,412,413],{"class":188},"    stage",[171,415,192],{"class":184},[171,417,418],{"class":195},"🏗️ provision-lab\n",[171,420,421,424,426],{"class":173,"line":275},[171,422,423],{"class":188},"    auto_define_backend",[171,425,192],{"class":184},[171,427,428],{"class":249},"true\n",[171,430,431,434],{"class":173,"line":285},[171,432,433],{"class":188},"    rules",[171,435,205],{"class":184},[171,437,438,441,443,445],{"class":173,"line":293},[171,439,440],{"class":184},"      - ",[171,442,299],{"class":188},[171,444,192],{"class":184},[171,446,304],{"class":195},[171,448,449,452,454],{"class":173,"line":307},[171,450,451],{"class":188},"        when",[171,453,192],{"class":184},[171,455,315],{"class":195},[13,457,458],{},[28,459],{"alt":460,"src":105},"Validate, plan, and deploy components are configured with auto_define_backend: true",[13,462,463],{},"The infrastructure configuration creates a CentOS Stream 9 EC2 instance with appropriate security groups for SSH access from GitLab runners and HTTP access to the Tomcat server.",[13,465,466,467,472],{},"SSH access and HTTP configuration are configuration thought ",[40,468,471],{"href":469,"rel":470},"https://docs.gitlab.com/ci/variables/#define-a-cicd-variable-in-the-ui",[],"GitLab CI/CD environment variables",".",[13,474,475],{},[28,476],{"alt":477,"src":478},"SSH access and HTTP configuration","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433381/cmqtzg6ahz8ua5w8ybgs.png",[13,480,481,482,487],{},"For secure cloud access, the project implements ",[40,483,486],{"href":484,"rel":485},"https://docs.gitlab.com/ci/cloud_services/aws/",[],"GitLab's OpenID Connect integration"," with AWS, using temporary credentials through AWS Security Token Service (STS):",[162,489,492],{"className":490,"code":491,"language":321,"meta":167},[319],"# From .gitlab-ci.yml\n.tofu_aws_setup:\n id_tokens:\n   OIDC_TOKEN:\n     aud: https://gitlab.com\n before_script:\n   - echo \"${OIDC_TOKEN}\" > /tmp/web_identity_token\n   - export AWS_PROFILE=\"\"\n   - export AWS_ROLE_ARN=\"${AWS_ROLE_ARN}\"\n   - export AWS_WEB_IDENTITY_TOKEN_FILE=\"/tmp/web_identity_token\"\n\n",[142,493,491],{"__ignoreMap":167},[107,495,497],{"id":496},"building-the-ansible-execution-environment","Building the Ansible execution environment",[13,499,500,501,506],{},"A key aspect of modern Ansible deployments is the use of ",[40,502,505],{"href":503,"rel":504},"https://docs.ansible.com/ansible/latest/getting_started_ee/index.html",[],"execution environments",", containerized versions of Ansible with all necessary dependencies including roles and collections pre-installed. This project creates a custom execution environment based on Fedora 39, which includes ansible-core, ansible-runner, and additional collection such as ansible.posix required in this example for firewall and selinux configuration.",[13,508,509,510,472],{},"The third-party roles and collections in this project are natively downloaded from the community Ansible Galaxy repository. This approach leverages the community ecosystem of reusable Ansible content, as shown in the execution environment configuration. While this demo utilizes community Ansible resources, the exact same pipeline implementation is fully compatible with Red Hat Ansible Automation Platform. The pipeline structure remains identical, with only the content sources changing. Organizations using the enterprise version can simply redirect their automation content sources to their private Automation Hub instead of the default community Ansible Galaxy. According to the official enterprise documentation, this can be achieved by ",[40,511,514],{"href":512,"rel":513},"https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/1.2/html/getting_started_with_red_hat_ansible_automation_hub/proc-configure-automation-hub-server#proc-configure-automation-hub-server",[],"configuring your private Automation Hub server and access token in the ansible.cfg",[162,516,518],{"className":164,"code":517,"language":166,"meta":167,"style":167},"# From execution-environment.yml\n---\nversion: 3\n\nimages:\n  base_image:\n    name: quay.io/fedora/fedora:39\n\ndependencies:\n  ansible_core:\n    package_pip: ansible-core\n  ansible_runner:\n    package_pip: ansible-runner\n  system:\n    - openssh-clients\n    - sshpass\n  galaxy:\n    collections:\n    - name: ansible.posix\n      version: \">=2.0.0\"\n\n",[142,519,520,525,531,541,547,554,561,571,575,582,589,599,606,615,623,632,640,648,656,669],{"__ignoreMap":167},[171,521,522],{"class":173,"line":174},[171,523,524],{"class":177},"# From execution-environment.yml\n",[171,526,527],{"class":173,"line":181},[171,528,530],{"class":529},"s7eDp","---\n",[171,532,533,536,538],{"class":173,"line":199},[171,534,535],{"class":188},"version",[171,537,192],{"class":184},[171,539,540],{"class":249},"3\n",[171,542,543],{"class":173,"line":208},[171,544,546],{"emptyLinePlaceholder":545},true,"\n",[171,548,549,552],{"class":173,"line":219},[171,550,551],{"class":188},"images",[171,553,205],{"class":184},[171,555,556,559],{"class":173,"line":230},[171,557,558],{"class":188},"  base_image",[171,560,205],{"class":184},[171,562,563,566,568],{"class":173,"line":241},[171,564,565],{"class":188},"    name",[171,567,192],{"class":184},[171,569,570],{"class":195},"quay.io/fedora/fedora:39\n",[171,572,573],{"class":173,"line":253},[171,574,546],{"emptyLinePlaceholder":545},[171,576,577,580],{"class":173,"line":264},[171,578,579],{"class":188},"dependencies",[171,581,205],{"class":184},[171,583,584,587],{"class":173,"line":275},[171,585,586],{"class":188},"  ansible_core",[171,588,205],{"class":184},[171,590,591,594,596],{"class":173,"line":285},[171,592,593],{"class":188},"    package_pip",[171,595,192],{"class":184},[171,597,598],{"class":195},"ansible-core\n",[171,600,601,604],{"class":173,"line":293},[171,602,603],{"class":188},"  ansible_runner",[171,605,205],{"class":184},[171,607,608,610,612],{"class":173,"line":307},[171,609,593],{"class":188},[171,611,192],{"class":184},[171,613,614],{"class":195},"ansible-runner\n",[171,616,618,621],{"class":173,"line":617},14,[171,619,620],{"class":188},"  system",[171,622,205],{"class":184},[171,624,626,629],{"class":173,"line":625},15,[171,627,628],{"class":184},"    - ",[171,630,631],{"class":195},"openssh-clients\n",[171,633,635,637],{"class":173,"line":634},16,[171,636,628],{"class":184},[171,638,639],{"class":195},"sshpass\n",[171,641,643,646],{"class":173,"line":642},17,[171,644,645],{"class":188},"  galaxy",[171,647,205],{"class":184},[171,649,651,654],{"class":173,"line":650},18,[171,652,653],{"class":188},"    collections",[171,655,205],{"class":184},[171,657,659,661,664,666],{"class":173,"line":658},19,[171,660,628],{"class":184},[171,662,663],{"class":188},"name",[171,665,192],{"class":184},[171,667,668],{"class":195},"ansible.posix\n",[171,670,672,675,677],{"class":173,"line":671},20,[171,673,674],{"class":188},"      version",[171,676,192],{"class":184},[171,678,679],{"class":195},"\">=2.0.0\"\n",[13,681,682],{},[28,683],{"alt":684,"src":685},"Execution environment pushed to GitLab's Container Registry ","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433384/dh1o2ojjmb04ru4tfr9k.png",[13,687,688,689,693],{},"The execution environment is defined in a YAML file and built using ansible-builder, then pushed to ",[40,690,692],{"href":58,"rel":691},[],"GitLab's Container Registry",". This approach ensures consistent execution environments across different systems and simplifies dependency management.",[162,695,698],{"className":696,"code":697,"language":321,"meta":167},[319],"# From gitlab-ci.yml\n🔨 ansible-build-ee:\n  stage: 📦 ansible-build-ee\n  image: docker:24.0.5\n  needs: []\n  services:\n    - docker:24.0.5-dind\n  before_script:\n    - apk add --no-cache python3 py3-pip\n    - pip install ansible-builder\n    - cd ansible/execution-environment\n  script:\n    - ansible-builder build -t ${EE_IMAGE_NAME}:${EE_IMAGE_TAG} --container-runtime docker\n    - docker tag ${EE_IMAGE_NAME}:${EE_IMAGE_TAG} ${CI_REGISTRY_IMAGE}/${EE_IMAGE_NAME}:${EE_IMAGE_TAG}\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - docker push ${CI_REGISTRY_IMAGE}/${EE_IMAGE_NAME}:${EE_IMAGE_TAG}\n\n",[142,699,697],{"__ignoreMap":167},[107,701,703],{"id":702},"deploying-tomcat-with-ansible","Deploying Tomcat with Ansible",[13,705,706,707,712],{},"Once the infrastructure is provisioned and the execution environment is built, the pipeline deploys Tomcat using ",[40,708,711],{"href":709,"rel":710},"https://ansible.readthedocs.io/projects/navigator/",[],"Ansible Navigator",". The execution environment built in previous stage is used as image for deployment job in GitLab pipeline.",[162,714,717],{"className":715,"code":716,"language":321,"meta":167},[319],"# From gitlab-ci.yml\n🚀 ansible-deploy:\n  stage: 🚀 ansible-deploy\n  image: ${CI_REGISTRY_IMAGE}/${EE_IMAGE_NAME}:${EE_IMAGE_TAG}\n  needs:\n    - ✅ tofu-apply\n  extends: [.ssh_private_key_setup, .default_rules]\n  script:\n    - ansible-navigator run ansible/playbook.yml\n      -i ansible/inventory/hosts.ini\n      --execution-environment false\n      --mode stdout\n      --log-level debug\n\n",[142,718,716],{"__ignoreMap":167},[13,720,721,722,726],{},"The Tomcat deployment fetches the application package from ",[40,723,725],{"href":80,"rel":724},[],"GitLab's Generic Package Repository",", configures system users and permissions, and sets up Tomcat as a systemd service.",[162,728,730],{"className":164,"code":729,"language":166,"meta":167,"style":167},"# From playbook.yml\n---\n- name: Deploy Tomcat Server\n  hosts: all\n  become: true\n  roles:\n      - role: tomcat\n\n  vars:\n    # Tomcat package and installation\n    tomcat_package: \"https://gitlab.com/api/v4/projects/67604719/packages/generic/apache-tomcat/10.1.39/apache-tomcat-10.1.39.tar.gz\"\n    tomcat_install_dir: \"/opt/tomcat\"\n    java_package: \"java-17-openjdk-devel\"\n\n",[142,731,732,737,741,752,762,771,778,790,794,801,806,816,826],{"__ignoreMap":167},[171,733,734],{"class":173,"line":174},[171,735,736],{"class":177},"# From playbook.yml\n",[171,738,739],{"class":173,"line":181},[171,740,530],{"class":529},[171,742,743,745,747,749],{"class":173,"line":199},[171,744,345],{"class":184},[171,746,663],{"class":188},[171,748,192],{"class":184},[171,750,751],{"class":195},"Deploy Tomcat Server\n",[171,753,754,757,759],{"class":173,"line":208},[171,755,756],{"class":188},"  hosts",[171,758,192],{"class":184},[171,760,761],{"class":195},"all\n",[171,763,764,767,769],{"class":173,"line":219},[171,765,766],{"class":188},"  become",[171,768,192],{"class":184},[171,770,428],{"class":249},[171,772,773,776],{"class":173,"line":230},[171,774,775],{"class":188},"  roles",[171,777,205],{"class":184},[171,779,780,782,785,787],{"class":173,"line":241},[171,781,440],{"class":184},[171,783,784],{"class":188},"role",[171,786,192],{"class":184},[171,788,789],{"class":195},"tomcat\n",[171,791,792],{"class":173,"line":253},[171,793,546],{"emptyLinePlaceholder":545},[171,795,796,799],{"class":173,"line":264},[171,797,798],{"class":188},"  vars",[171,800,205],{"class":184},[171,802,803],{"class":173,"line":275},[171,804,805],{"class":177},"    # Tomcat package and installation\n",[171,807,808,811,813],{"class":173,"line":285},[171,809,810],{"class":188},"    tomcat_package",[171,812,192],{"class":184},[171,814,815],{"class":195},"\"https://gitlab.com/api/v4/projects/67604719/packages/generic/apache-tomcat/10.1.39/apache-tomcat-10.1.39.tar.gz\"\n",[171,817,818,821,823],{"class":173,"line":293},[171,819,820],{"class":188},"    tomcat_install_dir",[171,822,192],{"class":184},[171,824,825],{"class":195},"\"/opt/tomcat\"\n",[171,827,828,831,833],{"class":173,"line":307},[171,829,830],{"class":188},"    java_package",[171,832,192],{"class":184},[171,834,835],{"class":195},"\"java-17-openjdk-devel\"\n",[13,837,838],{},[28,839],{"alt":840,"src":841},"GitLab Package Registry","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433381/mynak8i2k7ms9vhdijqg.png",[107,843,845],{"id":844},"security-scanning-and-code-quality","Security scanning and code quality",[13,847,848,849,853,854,859,860,472],{},"Security is integrated throughout the pipeline with multiple scanning tools. The project uses ",[40,850,852],{"href":65,"rel":851},[],"GitLab's built-in SAST IaC scanner"," to detect vulnerabilities in both Terraform and Ansible code. ",[40,855,858],{"href":856,"rel":857},"https://docs.gitlab.com/user/application_security/container_scanning/",[],"Container scanning"," is applied to the execution environment image to identify any security issues and generate a ",[40,861,864],{"href":862,"rel":863},"https://docs.gitlab.com/user/application_security/container_scanning/#cyclonedx-software-bill-of-materials",[],"software bill of materials (SBOM)",[162,866,868],{"className":164,"code":867,"language":166,"meta":167,"style":167},"# From gitlab-ci.yml\ninclude:\n- template: Jobs/SAST-IaC.gitlab-ci.yml\n- template: Jobs/Container-Scanning.gitlab-ci.yml\n",[142,869,870,874,881,893],{"__ignoreMap":167},[171,871,872],{"class":173,"line":174},[171,873,340],{"class":177},[171,875,876,879],{"class":173,"line":181},[171,877,878],{"class":188},"include",[171,880,205],{"class":184},[171,882,883,885,888,890],{"class":173,"line":199},[171,884,345],{"class":184},[171,886,887],{"class":188},"template",[171,889,192],{"class":184},[171,891,892],{"class":195},"Jobs/SAST-IaC.gitlab-ci.yml\n",[171,894,895,897,899,901],{"class":173,"line":208},[171,896,345],{"class":184},[171,898,887],{"class":188},[171,900,192],{"class":184},[171,902,903],{"class":195},"Jobs/Container-Scanning.gitlab-ci.yml\n",[13,905,906],{},[28,907],{"alt":908,"src":909},"Security is integrated throughout the pipeline with multiple scanning tools","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433386/e6ejckcv5kdyhhosej2f.png",[13,911,912],{},[28,913],{"alt":914,"src":915},"Dependency listing","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433380/gsfpaldra4rmtkseaudo.png",[13,917,918,919,924],{},"Additionally, the project integrates Ansible Linter with ",[40,920,923],{"href":921,"rel":922},"https://docs.gitlab.com/ci/testing/code_quality/#import-code-quality-results-from-a-cicd-job",[],"GitLab's Code Quality",". This integration produces reports that are displayed directly in the GitLab interface, making it easy to identify and address issues.",[162,926,929],{"className":927,"code":928,"language":321,"meta":167},[319],"# From gitlab-ci.yml\n🔍 ansible-lint:\n  stage: 🚀 ansible-deploy\n  image: ${CI_REGISTRY_IMAGE}/${EE_IMAGE_NAME}:${EE_IMAGE_TAG}\n  needs: []\n  script:\n    - ansible-lint ansible/playbook.yml -f codeclimate | python3 -m json.tool | tee gl-code-quality-report.json || true\n  artifacts:\n    reports:\n      codequality:\n        - gl-code-quality-report.json\n\n",[142,930,928],{"__ignoreMap":167},[13,932,933],{},[28,934],{"alt":935,"src":915},"The project integrates Ansible Linter with GitLab code quality",[107,937,939],{"id":938},"health-checking-the-deployment","Health-checking the deployment",[13,941,942],{},"After deployment, the pipeline performs health checks to ensure that the Tomcat server is running correctly. The health-check job attempts to connect to the server's HTTP port and verifies that it returns a successful response. This ensures that the deployment has completed successfully, and the application is accessible.",[13,944,945],{},"You can test access from your browser into the Tomcat-provisioned instance using the public IP address of the EC2 provisioned instance.",[13,947,948],{},[28,949],{"alt":950,"src":951},"Checking the health of a job","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433385/uksdkjryydxhu94v1naj.png",[33,953,955],{"id":954},"destroying-the-lab-environment","Destroying the lab environment",[13,957,958],{},"The final stage of the pipeline is the cleanup process, which destroys the lab environment. This is implemented using the OpenTofu destroy component, which ensures that all resources created during the provisioning stage are properly removed.",[33,960,962],{"id":961},"summary","Summary",[13,964,965],{},"GitLab provides a unified DevSecOps platform and a framework to manage enterprise-scale, mission-critical infrastructure as code and configuration management automation practices. The framework includes version control, project planning and issue management, team collaboration, CI/CD pipelines, binary package and container registry, security scanning, and many other helpful features along with the ability to embed governance and controls in the processes. If you are looking to expand your private or public cloud practices or in general any governed, self-service automation workflow, consider GitLab, TerraForm, and Ansible as the three-legged stool and the foundation for a scalable and governed automation platform.",[967,968,969],"blockquote",{},[13,970,971,972,977],{},"Get started with a ",[40,973,976],{"href":974,"rel":975},"http://bout.gitlab.com/free-trial/",[],"free trial of GitLab Ultimate",". Sign up today!",[979,980,981],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":167,"searchDepth":181,"depth":181,"links":983},[984,991,992],{"id":35,"depth":181,"text":36,"children":985},[986,987,988,989,990],{"id":109,"depth":199,"text":110},{"id":496,"depth":199,"text":497},{"id":702,"depth":199,"text":703},{"id":844,"depth":199,"text":845},{"id":938,"depth":199,"text":939},{"id":954,"depth":181,"text":955},{"id":961,"depth":181,"text":962},"engineering","2019-07-01","Learn how to transform infrastructure automation into scalable, secure pipelines using GitLab, Terraform/OpenTofu, and Ansible with integrated security scanning and CI/CD.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1746211002/zlet4rmfg2z0j6lg16mc.png",{},"/en-us/blog/using-ansible-and-gitlab-as-infrastructure-for-code",{"ogTitle":5,"ogImage":999,"ogDescription":995,"ogSiteName":1003,"noIndex":998,"ogType":1004,"ogUrl":1005,"title":5,"canonicalUrls":1005,"description":995},"https://about.gitlab.com","article","https://about.gitlab.com/blog/using-ansible-and-gitlab-as-infrastructure-for-code","using-ansible-and-gitlab-as-infrastructure-for-code","en-us/blog/using-ansible-and-gitlab-as-infrastructure-for-code",[1009,1010],"demo","CI/CD","BlogPost","2025-04-24","eHqBHdfjcjwVWoXt_xq80xp3fF_lSuLUbhIC4UT8x_s",{"logo":1015,"freeTrial":1020,"sales":1025,"login":1030,"items":1035,"search":1361,"minimal":1392,"duo":1411,"switchNav":1420,"pricingDeployment":1431},{"config":1016},{"href":1017,"dataGaName":1018,"dataGaLocation":1019},"/","gitlab logo","header",{"text":1021,"config":1022},"Get free trial",{"href":1023,"dataGaName":1024,"dataGaLocation":1019},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":1026,"config":1027},"Request a demo",{"href":1028,"dataGaName":1029,"dataGaLocation":1019},"/sales/?contact-topic=request-demo","sales",{"text":1031,"config":1032},"Sign in",{"href":1033,"dataGaName":1034,"dataGaLocation":1019},"https://gitlab.com/users/sign_in/","sign in",[1036,1065,1164,1169,1283,1339],{"text":1037,"config":1038,"menu":1040},"Platform",{"dataNavLevelOne":1039},"platform",{"type":1041,"columns":1042},"cards",[1043,1049,1057],{"title":1037,"description":1044,"link":1045},"The intelligent orchestration platform for DevSecOps",{"text":1046,"config":1047},"Explore our Platform",{"href":1048,"dataGaName":1039,"dataGaLocation":1019},"/platform/",{"title":1050,"description":1051,"link":1052},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":1053,"config":1054},"Meet GitLab Duo",{"href":1055,"dataGaName":1056,"dataGaLocation":1019},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":1058,"description":1059,"link":1060},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":1061,"config":1062},"Learn more",{"href":1063,"dataGaName":1064,"dataGaLocation":1019},"/why-gitlab/","why gitlab",{"text":1066,"left":545,"config":1067,"menu":1069},"Product",{"dataNavLevelOne":1068},"solutions",{"type":1070,"link":1071,"columns":1075,"feature":1143},"lists",{"text":1072,"config":1073},"View all Solutions",{"href":1074,"dataGaName":1068,"dataGaLocation":1019},"/solutions/",[1076,1099,1122],{"title":1077,"description":1078,"link":1079,"items":1084},"Automation","CI/CD and automation to accelerate deployment",{"config":1080},{"icon":1081,"href":1082,"dataGaName":1083,"dataGaLocation":1019},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[1085,1088,1091,1095],{"text":1010,"config":1086},{"href":1087,"dataGaLocation":1019,"dataGaName":1010},"/solutions/continuous-integration/",{"text":1050,"config":1089},{"href":1055,"dataGaLocation":1019,"dataGaName":1090},"gitlab duo agent platform - product menu",{"text":1092,"config":1093},"Source Code Management",{"href":1094,"dataGaLocation":1019,"dataGaName":1092},"/solutions/source-code-management/",{"text":1096,"config":1097},"Automated Software Delivery",{"href":1082,"dataGaLocation":1019,"dataGaName":1098},"Automated software delivery",{"title":1100,"description":1101,"link":1102,"items":1107},"Security","Deliver code faster without compromising security",{"config":1103},{"href":1104,"dataGaName":1105,"dataGaLocation":1019,"icon":1106},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[1108,1112,1117],{"text":1109,"config":1110},"Application Security Testing",{"href":1104,"dataGaName":1111,"dataGaLocation":1019},"Application security testing",{"text":1113,"config":1114},"Software Supply Chain Security",{"href":1115,"dataGaLocation":1019,"dataGaName":1116},"/solutions/supply-chain/","Software supply chain security",{"text":1118,"config":1119},"Software Compliance",{"href":1120,"dataGaName":1121,"dataGaLocation":1019},"/solutions/software-compliance/","software compliance",{"title":1123,"link":1124,"items":1129},"Measurement",{"config":1125},{"icon":1126,"href":1127,"dataGaName":1128,"dataGaLocation":1019},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[1130,1134,1138],{"text":1131,"config":1132},"Visibility & Measurement",{"href":1127,"dataGaLocation":1019,"dataGaName":1133},"Visibility and Measurement",{"text":1135,"config":1136},"Value Stream Management",{"href":1137,"dataGaLocation":1019,"dataGaName":1135},"/solutions/value-stream-management/",{"text":1139,"config":1140},"Analytics & Insights",{"href":1141,"dataGaLocation":1019,"dataGaName":1142},"/solutions/analytics-and-insights/","Analytics and insights",{"title":1144,"type":1070,"items":1145},"GitLab for",[1146,1152,1158],{"text":1147,"config":1148},"Enterprise",{"icon":1149,"href":1150,"dataGaLocation":1019,"dataGaName":1151},"Building","/enterprise/","enterprise",{"text":1153,"config":1154},"Small Business",{"icon":1155,"href":1156,"dataGaLocation":1019,"dataGaName":1157},"Work","/small-business/","small business",{"text":1159,"config":1160},"Public Sector",{"icon":1161,"href":1162,"dataGaLocation":1019,"dataGaName":1163},"Organization","/solutions/public-sector/","public sector",{"text":1165,"config":1166},"Pricing",{"href":1167,"dataGaName":1168,"dataGaLocation":1019,"dataNavLevelOne":1168},"/pricing/","pricing",{"text":1170,"config":1171,"menu":1173},"Resources",{"dataNavLevelOne":1172},"resources",{"type":1070,"link":1174,"columns":1178,"feature":1272},{"text":1175,"config":1176},"View all resources",{"href":1177,"dataGaName":1172,"dataGaLocation":1019},"/resources/",[1179,1212,1239],{"title":1180,"items":1181},"Getting started",[1182,1187,1192,1197,1202,1207],{"text":1183,"config":1184},"Install",{"href":1185,"dataGaName":1186,"dataGaLocation":1019},"/install/","install",{"text":1188,"config":1189},"Quick start guides",{"href":1190,"dataGaName":1191,"dataGaLocation":1019},"/get-started/","quick setup checklists",{"text":1193,"config":1194},"Learn",{"href":1195,"dataGaLocation":1019,"dataGaName":1196},"https://university.gitlab.com/","learn",{"text":1198,"config":1199},"Product documentation",{"href":1200,"dataGaName":1201,"dataGaLocation":1019},"https://docs.gitlab.com/","product documentation",{"text":1203,"config":1204},"Best practice videos",{"href":1205,"dataGaName":1206,"dataGaLocation":1019},"/getting-started-videos/","best practice videos",{"text":1208,"config":1209},"Integrations",{"href":1210,"dataGaName":1211,"dataGaLocation":1019},"/integrations/","integrations",{"title":1213,"items":1214},"Discover",[1215,1220,1225,1230,1234],{"text":1216,"config":1217},"Customer success stories",{"href":1218,"dataGaName":1219,"dataGaLocation":1019},"/customers/","customer success stories",{"text":1221,"config":1222},"Blog",{"href":1223,"dataGaName":1224,"dataGaLocation":1019},"/blog/","blog",{"text":1226,"config":1227},"Demo Hub",{"href":1228,"dataGaName":1229,"dataGaLocation":1019},"/demo-hub/","demo hub",{"text":1231,"config":1232},"The Source",{"href":1233,"dataGaName":1224,"dataGaLocation":1019},"/the-source/",{"text":1235,"config":1236},"Remote",{"href":1237,"dataGaName":1238,"dataGaLocation":1019},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1240,"items":1241},"Connect",[1242,1247,1252,1257,1262,1267],{"text":1243,"config":1244},"GitLab Services",{"href":1245,"dataGaName":1246,"dataGaLocation":1019},"/services/","services",{"text":1248,"config":1249},"Contribute",{"href":1250,"dataGaName":1251,"dataGaLocation":1019},"https://contributors.gitlab.com","contribute",{"text":1253,"config":1254},"Community",{"href":1255,"dataGaName":1256,"dataGaLocation":1019},"/community/","community",{"text":1258,"config":1259},"Forum",{"href":1260,"dataGaName":1261,"dataGaLocation":1019},"https://forum.gitlab.com/","forum",{"text":1263,"config":1264},"Events",{"href":1265,"dataGaName":1266,"dataGaLocation":1019},"/events/","events",{"text":1268,"config":1269},"Partners",{"href":1270,"dataGaName":1271,"dataGaLocation":1019},"/partners/","partners",{"config":1273,"title":1276,"text":1277,"link":1278},{"background":1274,"textColor":1275},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1279,"config":1280},"Read the latest",{"href":1281,"dataGaName":1282,"dataGaLocation":1019},"/whats-new/","whats new",{"text":1284,"config":1285,"menu":1287},"Company",{"dataNavLevelOne":1286},"company",{"type":1070,"columns":1288},[1289],{"items":1290},[1291,1296,1302,1304,1309,1314,1319,1324,1329,1334],{"text":1292,"config":1293},"About",{"href":1294,"dataGaName":1295,"dataGaLocation":1019},"/company/","about",{"text":1297,"config":1298,"footerGa":1301},"Jobs",{"href":1299,"dataGaName":1300,"dataGaLocation":1019},"/jobs/","jobs",{"dataGaName":1300},{"text":1263,"config":1303},{"href":1265,"dataGaName":1266,"dataGaLocation":1019},{"text":1305,"config":1306},"Leadership",{"href":1307,"dataGaName":1308,"dataGaLocation":1019},"/company/team/e-group/","leadership",{"text":1310,"config":1311},"Handbook",{"href":1312,"dataGaName":1313,"dataGaLocation":1019},"https://handbook.gitlab.com/","handbook",{"text":1315,"config":1316},"Investor relations",{"href":1317,"dataGaName":1318,"dataGaLocation":1019},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1320,"config":1321},"Trust Center",{"href":1322,"dataGaName":1323,"dataGaLocation":1019},"/security/","trust center",{"text":1325,"config":1326},"AI Transparency Center",{"href":1327,"dataGaName":1328,"dataGaLocation":1019},"/ai-transparency-center/","ai transparency center",{"text":1330,"config":1331},"Newsletter",{"href":1332,"dataGaName":1333,"dataGaLocation":1019},"/company/contact/#contact-forms","newsletter",{"text":1335,"config":1336},"Press",{"href":1337,"dataGaName":1338,"dataGaLocation":1019},"/press/","press",{"text":1340,"config":1341,"menu":1342},"Contact us",{"dataNavLevelOne":1286},{"type":1070,"columns":1343},[1344],{"items":1345},[1346,1351,1356],{"text":1347,"config":1348},"Talk to sales",{"href":1349,"dataGaName":1350,"dataGaLocation":1019},"/sales/","talk to sales",{"text":1352,"config":1353},"Support portal",{"href":1354,"dataGaName":1355,"dataGaLocation":1019},"https://support.gitlab.com/hc/en-us","support portal",{"text":1357,"config":1358},"Customer portal",{"href":1359,"dataGaName":1360,"dataGaLocation":1019},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1362,"login":1363,"suggestions":1370},"Close",{"text":1364,"link":1365},"To search repositories and projects, login to",{"text":1366,"config":1367},"gitlab.com",{"href":1033,"dataGaName":1368,"dataGaLocation":1369},"search login","search",{"text":1371,"default":1372},"Suggestions",[1373,1375,1379,1381,1385,1389],{"text":1050,"config":1374},{"href":1055,"dataGaName":1050,"dataGaLocation":1369},{"text":1376,"config":1377},"Code Suggestions (AI)",{"href":1378,"dataGaName":1376,"dataGaLocation":1369},"/solutions/code-suggestions/",{"text":1010,"config":1380},{"href":1087,"dataGaName":1010,"dataGaLocation":1369},{"text":1382,"config":1383},"GitLab on AWS",{"href":1384,"dataGaName":1382,"dataGaLocation":1369},"/partners/technology-partners/aws/",{"text":1386,"config":1387},"GitLab on Google Cloud",{"href":1388,"dataGaName":1386,"dataGaLocation":1369},"/partners/technology-partners/google-cloud-platform/",{"text":1390,"config":1391},"Why GitLab?",{"href":1063,"dataGaName":1390,"dataGaLocation":1369},{"freeTrial":1393,"mobileIcon":1398,"desktopIcon":1403,"secondaryButton":1406},{"text":1394,"config":1395},"Start free trial",{"href":1396,"dataGaName":1024,"dataGaLocation":1397},"https://gitlab.com/-/trials/new/","nav",{"altText":1399,"config":1400},"Gitlab Icon",{"src":1401,"dataGaName":1402,"dataGaLocation":1397},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1399,"config":1404},{"src":1405,"dataGaName":1402,"dataGaLocation":1397},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1407,"config":1408},"Get Started",{"href":1409,"dataGaName":1410,"dataGaLocation":1397},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1412,"mobileIcon":1416,"desktopIcon":1418},{"text":1413,"config":1414},"Learn more about GitLab Duo",{"href":1055,"dataGaName":1415,"dataGaLocation":1397},"gitlab duo",{"altText":1399,"config":1417},{"src":1401,"dataGaName":1402,"dataGaLocation":1397},{"altText":1399,"config":1419},{"src":1405,"dataGaName":1402,"dataGaLocation":1397},{"button":1421,"mobileIcon":1426,"desktopIcon":1428},{"text":1422,"config":1423},"/switch",{"href":1424,"dataGaName":1425,"dataGaLocation":1397},"#contact","switch",{"altText":1399,"config":1427},{"src":1401,"dataGaName":1402,"dataGaLocation":1397},{"altText":1399,"config":1429},{"src":1430,"dataGaName":1402,"dataGaLocation":1397},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1432,"mobileIcon":1437,"desktopIcon":1439},{"text":1433,"config":1434},"Back to pricing",{"href":1167,"dataGaName":1435,"dataGaLocation":1397,"icon":1436},"back to pricing","GoBack",{"altText":1399,"config":1438},{"src":1401,"dataGaName":1402,"dataGaLocation":1397},{"altText":1399,"config":1440},{"src":1405,"dataGaName":1402,"dataGaLocation":1397},{"title":1442,"titleMobile":1443,"button":1444,"config":1449},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":1061,"config":1445},{"href":1446,"dataGaName":1447,"dataGaLocation":1448},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1450,"disabled":998},"release",{"data":1452},{"text":1453,"source":1454,"edit":1460,"contribute":1465,"config":1470,"items":1475,"minimal":1685},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1455,"config":1456},"View page source",{"href":1457,"dataGaName":1458,"dataGaLocation":1459},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1461,"config":1462},"Edit this page",{"href":1463,"dataGaName":1464,"dataGaLocation":1459},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1466,"config":1467},"Please contribute",{"href":1468,"dataGaName":1469,"dataGaLocation":1459},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1471,"facebook":1472,"youtube":1473,"linkedin":1474},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1476,1523,1577,1621,1653],{"title":1165,"links":1477,"subMenu":1492},[1478,1482,1487],{"text":1479,"config":1480},"View plans",{"href":1167,"dataGaName":1481,"dataGaLocation":1459},"view plans",{"text":1483,"config":1484},"Why Premium?",{"href":1485,"dataGaName":1486,"dataGaLocation":1459},"/pricing/premium/","why premium",{"text":1488,"config":1489},"Why Ultimate?",{"href":1490,"dataGaName":1491,"dataGaLocation":1459},"/pricing/ultimate/","why ultimate",[1493],{"title":1494,"links":1495},"Contact Us",[1496,1499,1501,1503,1508,1513,1518],{"text":1497,"config":1498},"Contact sales",{"href":1349,"dataGaName":1029,"dataGaLocation":1459},{"text":1352,"config":1500},{"href":1354,"dataGaName":1355,"dataGaLocation":1459},{"text":1357,"config":1502},{"href":1359,"dataGaName":1360,"dataGaLocation":1459},{"text":1504,"config":1505},"Status",{"href":1506,"dataGaName":1507,"dataGaLocation":1459},"https://status.gitlab.com/","status",{"text":1509,"config":1510},"Terms of use",{"href":1511,"dataGaName":1512,"dataGaLocation":1459},"/terms/","terms of use",{"text":1514,"config":1515},"Privacy statement",{"href":1516,"dataGaName":1517,"dataGaLocation":1459},"/privacy/","privacy statement",{"text":1519,"config":1520},"Cookie preferences",{"dataGaName":1521,"dataGaLocation":1459,"id":1522,"isOneTrustButton":545},"cookie preferences","ot-sdk-btn",{"title":1066,"links":1524,"subMenu":1533},[1525,1529],{"text":1526,"config":1527},"DevSecOps platform",{"href":1048,"dataGaName":1528,"dataGaLocation":1459},"devsecops platform",{"text":1530,"config":1531},"AI-Assisted Development",{"href":1055,"dataGaName":1532,"dataGaLocation":1459},"ai-assisted development",[1534],{"title":1535,"links":1536},"Topics",[1537,1542,1547,1552,1557,1562,1567,1572],{"text":1538,"config":1539},"CICD",{"href":1540,"dataGaName":1541,"dataGaLocation":1459},"/topics/ci-cd/","cicd",{"text":1543,"config":1544},"GitOps",{"href":1545,"dataGaName":1546,"dataGaLocation":1459},"/topics/gitops/","gitops",{"text":1548,"config":1549},"DevOps",{"href":1550,"dataGaName":1551,"dataGaLocation":1459},"/topics/devops/","devops",{"text":1553,"config":1554},"Version Control",{"href":1555,"dataGaName":1556,"dataGaLocation":1459},"/topics/version-control/","version control",{"text":1558,"config":1559},"DevSecOps",{"href":1560,"dataGaName":1561,"dataGaLocation":1459},"/topics/devsecops/","devsecops",{"text":1563,"config":1564},"Cloud Native",{"href":1565,"dataGaName":1566,"dataGaLocation":1459},"/topics/cloud-native/","cloud native",{"text":1568,"config":1569},"AI for Coding",{"href":1570,"dataGaName":1571,"dataGaLocation":1459},"/topics/devops/ai-for-coding/","ai for coding",{"text":1573,"config":1574},"Agentic AI",{"href":1575,"dataGaName":1576,"dataGaLocation":1459},"/topics/agentic-ai/","agentic ai",{"title":1578,"links":1579},"Solutions",[1580,1582,1584,1589,1593,1596,1600,1603,1605,1608,1611,1616],{"text":1109,"config":1581},{"href":1104,"dataGaName":1109,"dataGaLocation":1459},{"text":1098,"config":1583},{"href":1082,"dataGaName":1083,"dataGaLocation":1459},{"text":1585,"config":1586},"Agile development",{"href":1587,"dataGaName":1588,"dataGaLocation":1459},"/solutions/agile-delivery/","agile delivery",{"text":1590,"config":1591},"SCM",{"href":1094,"dataGaName":1592,"dataGaLocation":1459},"source code management",{"text":1538,"config":1594},{"href":1087,"dataGaName":1595,"dataGaLocation":1459},"continuous integration & delivery",{"text":1597,"config":1598},"Value stream management",{"href":1137,"dataGaName":1599,"dataGaLocation":1459},"value stream management",{"text":1543,"config":1601},{"href":1602,"dataGaName":1546,"dataGaLocation":1459},"/solutions/gitops/",{"text":1147,"config":1604},{"href":1150,"dataGaName":1151,"dataGaLocation":1459},{"text":1606,"config":1607},"Small business",{"href":1156,"dataGaName":1157,"dataGaLocation":1459},{"text":1609,"config":1610},"Public sector",{"href":1162,"dataGaName":1163,"dataGaLocation":1459},{"text":1612,"config":1613},"Education",{"href":1614,"dataGaName":1615,"dataGaLocation":1459},"/solutions/education/","education",{"text":1617,"config":1618},"Financial services",{"href":1619,"dataGaName":1620,"dataGaLocation":1459},"/solutions/finance/","financial services",{"title":1170,"links":1622},[1623,1625,1627,1629,1632,1634,1637,1639,1641,1643,1645,1647,1649,1651],{"text":1183,"config":1624},{"href":1185,"dataGaName":1186,"dataGaLocation":1459},{"text":1188,"config":1626},{"href":1190,"dataGaName":1191,"dataGaLocation":1459},{"text":1193,"config":1628},{"href":1195,"dataGaName":1196,"dataGaLocation":1459},{"text":1198,"config":1630},{"href":1200,"dataGaName":1631,"dataGaLocation":1459},"docs",{"text":1221,"config":1633},{"href":1223,"dataGaName":1224,"dataGaLocation":1459},{"text":1635,"config":1636},"What's new",{"href":1281,"dataGaName":1282,"dataGaLocation":1459},{"text":1216,"config":1638},{"href":1218,"dataGaName":1219,"dataGaLocation":1459},{"text":1235,"config":1640},{"href":1237,"dataGaName":1238,"dataGaLocation":1459},{"text":1243,"config":1642},{"href":1245,"dataGaName":1246,"dataGaLocation":1459},{"text":1248,"config":1644},{"href":1250,"dataGaName":1251,"dataGaLocation":1459},{"text":1253,"config":1646},{"href":1255,"dataGaName":1256,"dataGaLocation":1459},{"text":1258,"config":1648},{"href":1260,"dataGaName":1261,"dataGaLocation":1459},{"text":1263,"config":1650},{"href":1265,"dataGaName":1266,"dataGaLocation":1459},{"text":1268,"config":1652},{"href":1270,"dataGaName":1271,"dataGaLocation":1459},{"title":1284,"links":1654},[1655,1657,1659,1661,1663,1665,1669,1674,1676,1678,1680],{"text":1292,"config":1656},{"href":1294,"dataGaName":1286,"dataGaLocation":1459},{"text":1297,"config":1658},{"href":1299,"dataGaName":1300,"dataGaLocation":1459},{"text":1305,"config":1660},{"href":1307,"dataGaName":1308,"dataGaLocation":1459},{"text":1310,"config":1662},{"href":1312,"dataGaName":1313,"dataGaLocation":1459},{"text":1315,"config":1664},{"href":1317,"dataGaName":1318,"dataGaLocation":1459},{"text":1666,"config":1667},"Sustainability",{"href":1668,"dataGaName":1666,"dataGaLocation":1459},"/sustainability/",{"text":1670,"config":1671},"Diversity, inclusion and belonging (DIB)",{"href":1672,"dataGaName":1673,"dataGaLocation":1459},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1320,"config":1675},{"href":1322,"dataGaName":1323,"dataGaLocation":1459},{"text":1330,"config":1677},{"href":1332,"dataGaName":1333,"dataGaLocation":1459},{"text":1335,"config":1679},{"href":1337,"dataGaName":1338,"dataGaLocation":1459},{"text":1681,"config":1682},"Modern Slavery Transparency Statement",{"href":1683,"dataGaName":1684,"dataGaLocation":1459},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1686},[1687,1690,1693],{"text":1688,"config":1689},"Terms",{"href":1511,"dataGaName":1512,"dataGaLocation":1459},{"text":1691,"config":1692},"Cookies",{"dataGaName":1521,"dataGaLocation":1459,"id":1522,"isOneTrustButton":545},{"text":1694,"config":1695},"Privacy",{"href":1516,"dataGaName":1517,"dataGaLocation":1459},[1697,1711],{"id":1698,"title":7,"body":997,"config":1699,"content":1701,"description":997,"extension":1705,"meta":1706,"navigation":545,"path":1707,"seo":1708,"stem":1709,"__hash__":1710},"blogAuthors/en-us/blog/authors/george-kichukov.yml",{"template":1700},"BlogAuthor",{"name":7,"config":1702},{"headshot":1703,"ctfId":1704},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664866/Blog/Author%20Headshots/george_kichukov.png","7e8bn05u4pXwYjkRrqdprE","yml",{},"/en-us/blog/authors/george-kichukov",{},"en-us/blog/authors/george-kichukov","UDDMPQ1Z1HpCP1BsB-pj1XWbSni3I2gAijoCAboFU3M",{"id":1712,"title":8,"body":997,"config":1713,"content":1715,"description":997,"extension":1705,"meta":1718,"navigation":545,"path":1719,"seo":1720,"stem":1721,"__hash__":1722},"blogAuthors/en-us/blog/authors/salahddine-aberkan.yml",{"template":1700,"gitlabHandle":1714},"saberkan",{"name":8,"config":1716},{"headshot":1717},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1750434234/comdtybiix8pjqdpsxow.png",{},"/en-us/blog/authors/salahddine-aberkan",{},"en-us/blog/authors/salahddine-aberkan","AdFL3fjgIIL8nyG0v9ZtBFV4z7UKBTjsQpD0IUnQyNY",[1724,1733,1741],{"title":1725,"description":1726,"heroImage":1727,"category":993,"date":1728,"authors":1729,"slug":1732,"externalUrl":997},"Confidential AI for GitLab Self-Hosted","Give developers AI coding agents in GitLab Duo without source code leaving a hardware-encrypted boundary — no GPUs needed.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1773866173/vte9qh8rriznvyclhkes.png","2026-08-06",[1730,1731],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1734,"description":1735,"heroImage":1736,"category":993,"date":1737,"authors":1738,"slug":1740,"externalUrl":997},"Green DevOps: Why carbon measurement belongs in your CI/CD pipeline","CI/CD pipelines have a hidden carbon cost. Here's why measuring it matters, and how you can get started with Eco CI and Carmen in GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1765809212/noh0mdfn9o94ry9ykura.png","2026-07-09",[1739],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1742,"description":1743,"heroImage":1744,"category":993,"date":1745,"authors":1746,"slug":1748,"externalUrl":997},"How to build CI/CD observability at scale","This practical guide to GitLab pipeline analytics helps self-managed users gain operational insights using Prometheus and Grafana.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png","2026-04-28",[1747],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1750},[1751,1765,1777,1789],{"id":1752,"categories":1753,"header":1755,"text":1756,"button":1757,"image":1762},"ai-modernization",[1754],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1758,"config":1759},"Get your AI maturity score",{"href":1760,"dataGaName":1761,"dataGaLocation":1224},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1763},{"src":1764},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1766,"categories":1767,"header":1769,"text":1756,"button":1770,"image":1774},"devops-modernization",[1768,1561],"product","Are you just managing tools or shipping innovation?",{"text":1771,"config":1772},"Get your DevOps maturity score",{"href":1773,"dataGaName":1761,"dataGaLocation":1224},"/assessments/devops-modernization-assessment/",{"config":1775},{"src":1776},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1778,"categories":1779,"header":1781,"text":1756,"button":1782,"image":1786},"security-modernization",[1780],"security","Are you trading speed for security?",{"text":1783,"config":1784},"Get your security maturity score",{"href":1785,"dataGaName":1761,"dataGaLocation":1224},"/assessments/security-modernization-assessment/",{"config":1787},{"src":1788},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1790,"paths":1791,"header":1794,"text":1795,"button":1796,"image":1801},"github-azure-migration",[1792,1793],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":1797,"config":1798},"See how GitLab compares to GitHub",{"href":1799,"dataGaName":1800,"dataGaLocation":1224},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1802},{"src":1776},{"header":1804,"blurb":1805,"button":1806,"secondaryButton":1811},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1807,"config":1808},"Get your free trial",{"href":1809,"dataGaName":1024,"dataGaLocation":1810},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1497,"config":1812},{"href":1349,"dataGaName":1029,"dataGaLocation":1810},1786734962297]