[{"data":1,"prerenderedAt":718},["ShallowReactive",2],{"/en-us/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean/":3,"navigation-en-us":35,"banner-en-us":463,"footer-en-us":480,"Owen Williams":690,"next-steps-en-us":703},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":16,"config":25,"_id":28,"_type":29,"title":30,"_source":31,"_file":32,"_stem":33,"_extension":34},"/en-us/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean","blog",false,"",{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},"How to autoscale continuous deployment with GitLab Runner on DigitalOcean","Our friends over at DigitalOcean share how to configure a highly scalable, responsive and cost-effective GitLab infrastructure.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680042/Blog/Hero%20Images/gitlab-digitalocean-cover.jpg","https://about.gitlab.com/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to autoscale continuous deployment with GitLab Runner on DigitalOcean\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Owen Williams\"}],\n        \"datePublished\": \"2018-06-19\",\n      }",{"title":9,"description":10,"authors":17,"heroImage":11,"date":19,"body":20,"category":21,"tags":22},[18],"Owen Williams","2018-06-19","[GitLab CI/CD](/solutions/continuous-integration/) is an effective way to\nbuild the habit of testing all code before it’s deployed. GitLab CI/CD is\nalso highly scalable thanks to an additional tool, GitLab Runner, which\nautomates scaling your build queue in order to avoid long wait times for\ndevelopment teams trying to release code.\n\n\nIn this guide, we will demonstrate how to configure a highly scalable GitLab\ninfrastructure that manages its own costs, and automatically responds to\nload by increasing and decreasing available server capacity.\n\n\n## Goals\n\n\nWe’re going to build a scalable CI/CD process on DigitalOcean that\nautomatically responds to demand by creating new servers on the platform and\ndestroys them when the queue is empty.\n\n\nThese reusable servers are spawned by the GitLab Runner process and are\nautomatically deleted when no jobs are running, reducing costs and\nadministration overhead for your team.\n\n\nAs we’ll explain in this tutorial, you are in control of how many machines\nare created at any given time, as well as the length of time they’re\nretained before being destroyed.\n\n\nWe’ll be using three separate servers to build this project, so let’s go\nover terminology first:\n\n\n* **GitLab**: Your hosted GitLab instance or self-managed instance where\nyour code repositories are stored.\n\n\n* **GitLab Bastion**: The *bastion* server or Droplet is the core of what\nwe’ll be configuring. It is the control instance that is used to interact\nwith the DigitalOcean API to create Droplets and destroy them when\nnecessary. No jobs are executed on this server.\n\n\n* **GitLab Runner**: Your *runners* are transient servers or Droplets that\nare created on the fly by the *bastion* server when needed to execute a\nCI/CD job in your build queue. These servers are disposable, and are where\nyour code is executed or tested before your build is marked as passing or\nfailing.\n\n\n![GitLab Runners\nDiagram](https://assets.digitalocean.com/articles/gitlab-runner/Autoscaling-GitLab-Runners.png){:\n.medium.center}\n\n\nBy leveraging each of the GitLab components, the CI/CD process will enable\nyou to scale responsively based on demands. With these goals in mind, we are\nready to begin setting up our [continuous deployment](/topics/ci-cd/) with\nGitLab and DigitalOcean.\n\n\n## Prerequisites\n\n\nThis tutorial will assume you have already configured GitLab on your own\nserver or through the hosted service, and that you have an existing\nDigitalOcean account.\n\n\nTo set this up on an Ubuntu 16.04 Droplet, you can use the DigitalOcean\none-click image, or follow our guide: “[How To Install and Configure GitLab\non Ubuntu\n16.04](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-gitlab-on-ubuntu-16-04).”\n\n\nFor the purposes of this tutorial, we assume you have private networking\nenabled on this Droplet, which you can achieve by following our guide on\n“[How To Enable DigitalOcean Private Networking on Existing\nDroplets](https://www.digitalocean.com/community/tutorials/how-to-enable-digitalocean-private-networking-on-existing-droplets),”\nbut it is not compulsory.\n\n\nThroughout this tutorial, we’ll be using non-root users with admin\nprivileges on our Droplets.\n\n\n## Step 1: Import JavaScript project\n\nTo begin, we will create a new example project in your existing GitLab\ninstance containing a sample Node.js application.\n\n\n![GitLab\ninterface](https://assets.digitalocean.com/articles/gitlab-runner/gitlab.jpg){:\n.shadow.large.center}\n\n\nLog into your GitLab instance and click the **plus icon**, then select **New\nproject** from the dropdown menu.\n\n\nOn the new project screen, select the **Import project** tag, then click\n**Repo by URL** to import our example project directly from GitHub.\n\n\nPaste the below clone URL into the Git repository URL:\n\n\n```bash\n\nhttps://github.com/do-community/hello_hapi.git\n\n```\n\n\nThis repository is a basic JavaScript application for the purposes of\ndemonstration, which we won’t be running in production. To complete the\nimport, click the **New Project** button.\n\n\nYour new project will now be in GitLab and we can get started setting up our\nCI pipeline.\n\n\n## Step 2: Set up infrastructure\n\n\nOur GitLab Code Runner requires specific configuration as we’re planning to\nprogrammatically create Droplets to handle CI load as it grows and shrinks.\n\n\nWe will create two types of machines in this tutorial: a **bastion**\ninstance, which controls and spawns new machines, and our **runner**\ninstances, which are temporary servers spawned by the bastion Droplet to\nbuild code when required. The bastion instance uses Docker to create your\nrunners.\n\n\nHere are the DigitalOcean products we’ll use, and what each component is\nused for:\n\n\n* **Flexible Droplets** — We will create memory-optimized Droplets for our\nGitLab Runners as it’s a memory-intensive process which will run using\nDocker for containerization. You can shrink or grow this Droplet in the\nfuture as needed, however we recommend the flexible Droplet option as a\nstarting point to understand how your pipeline will perform under load.\n\n\n* **DigitalOcean Spaces (Object Storage)** — We will use [DigitalOcean\nSpaces](https://www.digitalocean.com/products/spaces/) to persist cached\nbuild components across your runners as they’re created and destroyed. This\nreduces the time required to set up a new runner when the CI pipeline is\nbusy, and allows new runners to pick up where others left off immediately.\n\n\n* **Private Networking** — We will create a private network for your bastion\nDroplet and GitLab runners to ensure secure code compilation and to reduce\nfirewall configuration required.\n\n\nTo start, we’ll create the bastion Droplet. Create a [new\nDroplet](https://cloud.digitalocean.com/droplets/new), then under **choose\nan image**, select the **One-click apps** tab. From there, select **Docker\n17.12.0-ce on 16.04** (note that this version is current at the time of\nwriting), then choose the smallest Droplet size available, as our bastion\nDroplet will manage the creation of other Droplets rather than actually\nperform tests.\n\n\nIt is recommended that you create your server in a data center that\nincludes  [DigitalOcean\nSpaces](https://www.digitalocean.com/community/tutorials/an-introduction-to-digitalocean-spaces)\nin order to use the object storage caching features mentioned earlier.\n\n\nSelect both the **Private networking** and **Monitoring** options, then\nclick **Create Droplet**.\n\n\nWe also need to set up our storage space which will be used for caching.\nFollow the steps in “[How To Create a DigitalOcean Space and API\nKey](https://www.digitalocean.com/community/tutorials/how-to-create-a-digitalocean-space-and-api-key)”\nto create a new Space in the same or nearest data center as your hosted\nGitLab instance, along with an API Key.\n\n\nNote this key down, as we’ll need it later in the tutorial.\n\n\nNow it’s time to get our CI started!\n\n\n## Step 3: Configure the GitLab Runner Bastion Server\n\n\nWith the fresh Droplet ready, we can now configure GitLab Runner. We’ll be\ninstalling scripts from GitLab and GitHub repositories.\n\n\nAs a best practice, be sure to inspect scripts to confirm what you will be\ninstalling prior to running the full commands below.\n\n\nConnect to the Droplet using SSH, move into the `/tmp` directory, then add\nthe [official GitLab Runner\nrepository](https://docs.gitlab.com/runner/install/linux-repository.html) to\nUbuntu’s package manager:\n\n\n```bash\n\ncd /tmp\n\ncurl -L\nhttps://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh\n| sudo bash\n\n```\n\n\nOnce added, install the GitLab Runner application:\n\n\n```bash\n\nsudo apt-get install gitlab-runner\n\n```\n\n\nWe also need to install **[Docker\nMachine](https://docs.docker.com/machine/install-machine/#install-machine-directly)**,\nwhich is an additional Docker tool that assists with automating the\ndeployment of containers on cloud providers:\n\n\n```bash\n\ncurl -L\nhttps://github.com/docker/machine/releases/download/v0.14.0/docker-machine-`uname\n-s`-`uname -m` >/tmp/docker-machine && \\\n\nsudo install /tmp/docker-machine /usr/local/bin/docker-machine\n\n```\n\n\nWith these installations complete, we can move on to connecting our GitLab\nRunner to our GitLab install.\n\n\n## Step 4: Obtain Runner registration token\n\n\nTo link GitLab Runner to your existing GitLab install, we need to link the\ntwo instances together by obtaining a token that authenticates your runner\nto your code repositories.\n\n\nLogin to your existing GitLab instance as the admin user, then click the\nwrench icon to enter the admin settings area.\n\n\nOn the left of your screen, hover over **Overview** and select **Runners**\nfrom the list that appears.\n\n\nOn the Runners page under the **How to set up a shared Runner for a new\nproject** section, copy the token shown in Step 3, and make a note of it\nalong with the publicly accessible URL of your GitLab instance from Step 2.\nIf you are using HTTPS for Gitlab, make sure it is not a self-signed\ncertificate, or GitLab Runner will fail to start.\n\n\n## Step 5: Configure GitLab on the Bastion Droplet\n\n\nBack in your SSH connection with your bastion Droplet, run the following\ncommand:\n\n\n```bash\n\nsudo gitlab-runner register\n\n```\n\n\nThis will initiate the linking process, and you will be asked a series of\nquestions.\n\n\nOn the next step, enter the **GitLab instance URL** from the previous step:\n\n\n```bash\n\nPlease enter the gitlab-ci coordinator URL (e.g. https://gitlab.com)\n\nhttps://example.digitalocean.com\n\n```\n\n\nEnter the token you obtained from your GitLab instance:\n\n\n```bash\n\nPlease enter the gitlab-ci token for this runner\n\nsample-gitlab-ci-token\n\n```\n\n\nEnter a description that will help you recognize it in the GitLab web\ninterface. We recommend naming this instance something unique, like\n`runner-bastion` for clarity.\n\n\n```bash\n\nPlease enter the gitlab-ci description for this runner\n\n[yourhostname] runner-bastion\n\n```\n\n\nIf relevant, you may enter the tags for code you will build with your\nrunner. However, we recommend this is left blank at this stage. This can\neasily be changed from the GitLab interface later.\n\n\n```bash\n\nPlease enter the gitlab-ci tags for this runner (comma separated):\n\ncode-tag\n\n```\n\n\nChoose whether or not your runner should be able to run untagged jobs. This\nsetting allows you to choose whether your runner should build repositories\nwith no tags at all, or require specific tags. Select true in this case, so\nyour runner can execute all repositories.\n\n\n```bash\n\nWhether to run untagged jobs [true/false]: true\n\n```\n\n\nChoose if this runner should be shared among your projects, or locked to the\ncurrent one, which blocks it from building any code other than those\nspecified. Select false for now, as this can be changed later in GitLab’s\ninterface:\n\n\n```bash\n\nWhether to lock Runner to current project [true/false]: false\n\n```\n\n\nChoose the executor which will build your machines. Because we’ll be\ncreating new Droplets using Docker, we’ll choose `docker+machine` here, but\nyou can read more about the advantages of each approach in this\n[compatibility\nchart](https://docs.gitlab.com/runner/executors/README.html#compatibility-chart):\n\n\n```bash\n\nPlease enter the executor: ssh, docker+machine, docker-ssh+machine,\nkubernetes, docker, parallels, virtualbox, docker-ssh, shell:\n\ndocker+machine\n\n```\n\n\nYou’ll be asked which image to use for projects that don’t explicitly define\none. We’ll choose a basic, secure default:\n\n\n```bash\n\nPlease enter the Docker image (e.g. ruby:2.1):\n\nalpine:latest\n\n```\n\n\nNow you’re done configuring the core bastion runner! At this point it should\nappear within the GitLab Runner page of your GitLab admin settings, which we\naccessed to obtain the token.\n\n\nIf you encounter any issues with these steps, the [GitLab Runner\ndocumentation](https://docs.gitlab.com/runner/register/index.html) includes\noptions for troubleshooting.\n\n\n## Step 6: Configure Docker caching and Docker Machine\n\nTo speed up Droplet creation when the build queue is busy, we’ll leverage\nDocker’s caching tools on the Bastion Droplet to store the images for your\ncommonly used containers on DigitalOcean Spaces.\n\n\nTo do so, upgrade Docker Machine on your SSH shell using the following\ncommand:\n\n\n```bash\n\ncurl -L\nhttps://github.com/docker/machine/releases/download/v0.14.0/docker-machine-`uname\n-s`-`uname -m` >/tmp/docker-machine && sudo install /tmp/docker-machine\n/usr/local/bin/docker-machine\n\n```\n\n\nWith Docker Machine upgraded, we can move on to setting up our access tokens\nfor GitLab Runner to use.\n\n\n## Step 7: Gather DigitalOcean credentials\n\n\nNow we need to create the credentials that GitLab Runner will use to create\nnew Droplets using your DigitalOcean account.\n\n\nVisit your DigitalOcean [dashboard](https://cloud.digitalocean.com) and\nclick **API**. On the next screen, look for **Personal access tokens** and\nclick **Generate New Token**.\n\n\nGive the new token a name you will recognize such as `GitLab Runner Access`\nand ensure that both the read and write scopes are enabled, as we need the\nDroplet to create new machines without human intervention.\n\n\nCopy the token somewhere safe as we’ll use it in the next step. You can’t\nretrieve this token again without regenerating it, so be sure it’s stored\nsecurely.\n\n\n## Step 8: Edit GitLab Runner configuration files\n\nTo bring all of these components together, we need to finish configuring our\nbastion Droplet to communicate with your DigitalOcean account.\n\n\nIn your SSH connection to your bastion Droplet, use your favorite text\neditor, such as nano, to open the GitLab Runner configuration file for\nediting:\n\n\n```bash\n\nnano /etc/gitlab-runner/config.toml\n\n```\n\n\nThis configuration file is responsible for the rules your CI setup uses to\nscale up and down on demand. To configure the bastion to autoscale on\ndemand, you need to add the following lines:\n\n\n```bash\n\nconcurrent = 50   # All registered Runners can run up to 50 concurrent\nbuilds\n\n\n[[runners]]\n  url = \"https://example.digitalocean.com\"\n  token = \"existinggitlabtoken\"             # Note this is different from the registration token used by `gitlab-runner register`\n  name = \"example-runner\"\n  executor = \"docker+machine\"        # This Runner is using the 'docker+machine' executor\n  limit = 10                         # This Runner can execute up to 10 builds (created machines)\n  [runners.docker]\n    image = \"alpine:latest\"               # Our secure image\n  [runners.machine]\n    IdleCount = 1                    # The amount of idle machines we require for CI if build queue is empty\n    IdleTime = 600                   # Each machine can be idle for up to 600 seconds, then destroyed\n    MachineName = \"gitlab-runner-autoscale-%s\"    # Each machine will have a unique name ('%s' is required and generates a random number)\n    MachineDriver = \"digitalocean\"   # Docker Machine is using the 'digitalocean' driver\n    MachineOptions = [\n        \"digitalocean-image=coreos-stable\", # The DigitalOcean system image to use by default\n        \"digitalocean-ssh-user=core\", # The default SSH user\n        \"digitalocean-access-token=DO_ACCESS_TOKEN\", # Access token from Step 7\n        \"digitalocean-region=nyc3\", # The data center to spawn runners in\n        \"digitalocean-size=1gb\", # The size (and price category) of your spawned runners\n        \"digitalocean-private-networking\" # Enable private networking on runners\n    ]\n  [runners.cache]\n    Type = \"s3\"   # The Runner is using a distributed cache with the S3-compatible Spaces service\n    ServerAddress = \"nyc3.spaces.digitaloceanspaces.com\"\n    AccessKey = \"YOUR_SPACES_KEY\"\n    SecretKey = \"YOUR_SPACES_SECRET\"\n    BucketName = \"your_bucket_name\"\n    Insecure = true # We do not have a SSL certificate, as we are only running locally\n```\n\n\nOnce you’ve added the new lines, customize the access token, region and\nDroplet size based on  your setup. For the purposes of this tutorial, we’ve\nused the smallest Droplet size of 1GB and created our Droplets in NYC3. Be\nsure to use the information that is relevant in your case.\n\n\nYou also need to customize the cache component, and enter your Space’s\nserver address from the infrastructure configuration step, access key,\nsecret key and the name of the Space that you created.\n\n\nWhen completed, restart GitLab Runner to make sure the configuration is\nbeing used:\n\n\n```bash\n\ngitlab-runner restart\n\n```\n\n\nIf you would like to learn about more all available options, including\noff-peak hours, you can read [GitLab’s advanced\ndocumentation](https://docs.gitlab.com/runner/configuration/autoscale.html).\n\n\n## Step 9 — Test Your GitLab Runner\n\n\nAt this point, our GitLab Runner bastion Droplet is configured and is able\nto create DigitalOcean Droplets on demand, as the CI queue fills up. We’ll\nneed to test it to be sure it works by heading to your GitLab instance and\nthe project we imported in Step 1.\n\n\nTo trigger a build, edit the `readme.md` file by clicking on it, then\nclicking **edit**, and add any relevant testing text to the file, then click\n**Commit changes**.\n\n\nNow a build will be automatically triggered, which can be found under the\nproject’s **CI/CD** option in the left navigation.\n\n\nOn this page you should see a pipeline entry with the status of **running**.\nIn your DigitalOcean account, you’ll see a number of Droplets automatically\ncreated by GitLab Runner in order to build this change.\n\n\nCongratulations! Your CI pipeline is cloud scalable and now manages its own\nresource usage. After the specified idle time, the machines should be\nautomatically destroyed, but we recommend verifying this manually to ensure\nyou aren’t unexpectedly billed.\n\n\n## Troubleshooting\n\n\nIn some cases, GitLab may report that the runner is unreachable and as a\nresult perform no actions, including deploying new runners. You can\ntroubleshoot this by stopping GitLab Runner, then starting it again in debug\nmode:\n\n\n```bash\n\ngitlab-runner stop\n\ngitlab-runner --debug start\n\n```\n\n\nThe output should throw an error, which will be helpful in determining which\nconfiguration is causing the issue.\n\n\nIf your configuration creates too many machines, and you wish to remove them\nall at the same time, you can run this command to destroy them all:\n\n\n```bash\n\ndocker-machine rm $(docker-machine ls -q)\n\n```\n\nFor more troubleshooting steps and additional configuration options, you can\nrefer to [GitLab’s documentation](https://docs.gitlab.com/runner/).\n\n\n## Conclusion\n\n\nYou've successfully set up an automated CI/CD pipeline using GitLab Runner\nand Docker. From here, you could configure higher levels of caching with\nDocker Registry to optimize performance or explore the use of tagging code\nbuilds to specific GitLab code runners.\n\n\nFor more on GitLab Runner, [see the detailed\ndocumentation](https://docs.gitlab.com/runner/), or to learn more, you can\nread [GitLab’s series of blog posts](https://docs.gitlab.com/ee/ci/) on how\nto make the most of your continuous integration pipeline.\n\n\n[This post was originally published by\nDigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-autoscale-gitlab-continuous-deployment-with-gitlab-runner-on-digitalocean)\nand is licensed under [CC BY-NC-SA\n4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).\n\n{: .note}\n","engineering",[23,24],"CI","integrations",{"slug":26,"featured":6,"template":27},"autoscale-continuous-deployment-gitlab-runner-digital-ocean","BlogPost","content:en-us:blog:autoscale-continuous-deployment-gitlab-runner-digital-ocean.yml","yaml","Autoscale Continuous Deployment Gitlab Runner Digital Ocean","content","en-us/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean.yml","en-us/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean","yml",{"_path":36,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"data":38,"_id":459,"_type":29,"title":460,"_source":31,"_file":461,"_stem":462,"_extension":34},"/shared/en-us/main-navigation","en-us",{"logo":39,"freeTrial":44,"sales":49,"login":54,"items":59,"search":390,"minimal":421,"duo":440,"pricingDeployment":449},{"config":40},{"href":41,"dataGaName":42,"dataGaLocation":43},"/","gitlab logo","header",{"text":45,"config":46},"Get free trial",{"href":47,"dataGaName":48,"dataGaLocation":43},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":50,"config":51},"Talk to sales",{"href":52,"dataGaName":53,"dataGaLocation":43},"/sales/","sales",{"text":55,"config":56},"Sign in",{"href":57,"dataGaName":58,"dataGaLocation":43},"https://gitlab.com/users/sign_in/","sign in",[60,104,202,207,311,371],{"text":61,"config":62,"cards":64,"footer":87},"Platform",{"dataNavLevelOne":63},"platform",[65,71,79],{"title":61,"description":66,"link":67},"The most comprehensive AI-powered DevSecOps Platform",{"text":68,"config":69},"Explore our Platform",{"href":70,"dataGaName":63,"dataGaLocation":43},"/platform/",{"title":72,"description":73,"link":74},"GitLab Duo (AI)","Build software faster with AI at every stage of development",{"text":75,"config":76},"Meet GitLab Duo",{"href":77,"dataGaName":78,"dataGaLocation":43},"/gitlab-duo/","gitlab duo ai",{"title":80,"description":81,"link":82},"Why GitLab","10 reasons why Enterprises choose GitLab",{"text":83,"config":84},"Learn more",{"href":85,"dataGaName":86,"dataGaLocation":43},"/why-gitlab/","why gitlab",{"title":88,"items":89},"Get started with",[90,95,100],{"text":91,"config":92},"Platform Engineering",{"href":93,"dataGaName":94,"dataGaLocation":43},"/solutions/platform-engineering/","platform engineering",{"text":96,"config":97},"Developer Experience",{"href":98,"dataGaName":99,"dataGaLocation":43},"/developer-experience/","Developer experience",{"text":101,"config":102},"MLOps",{"href":103,"dataGaName":101,"dataGaLocation":43},"/topics/devops/the-role-of-ai-in-devops/",{"text":105,"left":106,"config":107,"link":109,"lists":113,"footer":184},"Product",true,{"dataNavLevelOne":108},"solutions",{"text":110,"config":111},"View all Solutions",{"href":112,"dataGaName":108,"dataGaLocation":43},"/solutions/",[114,139,163],{"title":115,"description":116,"link":117,"items":122},"Automation","CI/CD and automation to accelerate deployment",{"config":118},{"icon":119,"href":120,"dataGaName":121,"dataGaLocation":43},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[123,127,131,135],{"text":124,"config":125},"CI/CD",{"href":126,"dataGaLocation":43,"dataGaName":124},"/solutions/continuous-integration/",{"text":128,"config":129},"AI-Assisted Development",{"href":77,"dataGaLocation":43,"dataGaName":130},"AI assisted development",{"text":132,"config":133},"Source Code Management",{"href":134,"dataGaLocation":43,"dataGaName":132},"/solutions/source-code-management/",{"text":136,"config":137},"Automated Software Delivery",{"href":120,"dataGaLocation":43,"dataGaName":138},"Automated software delivery",{"title":140,"description":141,"link":142,"items":147},"Security","Deliver code faster without compromising security",{"config":143},{"href":144,"dataGaName":145,"dataGaLocation":43,"icon":146},"/solutions/security-compliance/","security and compliance","ShieldCheckLight",[148,153,158],{"text":149,"config":150},"Application Security Testing",{"href":151,"dataGaName":152,"dataGaLocation":43},"/solutions/application-security-testing/","Application security testing",{"text":154,"config":155},"Software Supply Chain Security",{"href":156,"dataGaLocation":43,"dataGaName":157},"/solutions/supply-chain/","Software supply chain security",{"text":159,"config":160},"Software Compliance",{"href":161,"dataGaName":162,"dataGaLocation":43},"/solutions/software-compliance/","software compliance",{"title":164,"link":165,"items":170},"Measurement",{"config":166},{"icon":167,"href":168,"dataGaName":169,"dataGaLocation":43},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[171,175,179],{"text":172,"config":173},"Visibility & Measurement",{"href":168,"dataGaLocation":43,"dataGaName":174},"Visibility and Measurement",{"text":176,"config":177},"Value Stream Management",{"href":178,"dataGaLocation":43,"dataGaName":176},"/solutions/value-stream-management/",{"text":180,"config":181},"Analytics & Insights",{"href":182,"dataGaLocation":43,"dataGaName":183},"/solutions/analytics-and-insights/","Analytics and insights",{"title":185,"items":186},"GitLab for",[187,192,197],{"text":188,"config":189},"Enterprise",{"href":190,"dataGaLocation":43,"dataGaName":191},"/enterprise/","enterprise",{"text":193,"config":194},"Small Business",{"href":195,"dataGaLocation":43,"dataGaName":196},"/small-business/","small business",{"text":198,"config":199},"Public Sector",{"href":200,"dataGaLocation":43,"dataGaName":201},"/solutions/public-sector/","public sector",{"text":203,"config":204},"Pricing",{"href":205,"dataGaName":206,"dataGaLocation":43,"dataNavLevelOne":206},"/pricing/","pricing",{"text":208,"config":209,"link":211,"lists":215,"feature":298},"Resources",{"dataNavLevelOne":210},"resources",{"text":212,"config":213},"View all resources",{"href":214,"dataGaName":210,"dataGaLocation":43},"/resources/",[216,248,270],{"title":217,"items":218},"Getting started",[219,224,229,234,239,244],{"text":220,"config":221},"Install",{"href":222,"dataGaName":223,"dataGaLocation":43},"/install/","install",{"text":225,"config":226},"Quick start guides",{"href":227,"dataGaName":228,"dataGaLocation":43},"/get-started/","quick setup checklists",{"text":230,"config":231},"Learn",{"href":232,"dataGaLocation":43,"dataGaName":233},"https://university.gitlab.com/","learn",{"text":235,"config":236},"Product documentation",{"href":237,"dataGaName":238,"dataGaLocation":43},"https://docs.gitlab.com/","product documentation",{"text":240,"config":241},"Best practice videos",{"href":242,"dataGaName":243,"dataGaLocation":43},"/getting-started-videos/","best practice videos",{"text":245,"config":246},"Integrations",{"href":247,"dataGaName":24,"dataGaLocation":43},"/integrations/",{"title":249,"items":250},"Discover",[251,256,260,265],{"text":252,"config":253},"Customer success stories",{"href":254,"dataGaName":255,"dataGaLocation":43},"/customers/","customer success stories",{"text":257,"config":258},"Blog",{"href":259,"dataGaName":5,"dataGaLocation":43},"/blog/",{"text":261,"config":262},"Remote",{"href":263,"dataGaName":264,"dataGaLocation":43},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":266,"config":267},"TeamOps",{"href":268,"dataGaName":269,"dataGaLocation":43},"/teamops/","teamops",{"title":271,"items":272},"Connect",[273,278,283,288,293],{"text":274,"config":275},"GitLab Services",{"href":276,"dataGaName":277,"dataGaLocation":43},"/services/","services",{"text":279,"config":280},"Community",{"href":281,"dataGaName":282,"dataGaLocation":43},"/community/","community",{"text":284,"config":285},"Forum",{"href":286,"dataGaName":287,"dataGaLocation":43},"https://forum.gitlab.com/","forum",{"text":289,"config":290},"Events",{"href":291,"dataGaName":292,"dataGaLocation":43},"/events/","events",{"text":294,"config":295},"Partners",{"href":296,"dataGaName":297,"dataGaLocation":43},"/partners/","partners",{"backgroundColor":299,"textColor":300,"text":301,"image":302,"link":306},"#2f2a6b","#fff","Insights for the future of software development",{"altText":303,"config":304},"the source promo card",{"src":305},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":307,"config":308},"Read the latest",{"href":309,"dataGaName":310,"dataGaLocation":43},"/the-source/","the source",{"text":312,"config":313,"lists":315},"Company",{"dataNavLevelOne":314},"company",[316],{"items":317},[318,323,329,331,336,341,346,351,356,361,366],{"text":319,"config":320},"About",{"href":321,"dataGaName":322,"dataGaLocation":43},"/company/","about",{"text":324,"config":325,"footerGa":328},"Jobs",{"href":326,"dataGaName":327,"dataGaLocation":43},"/jobs/","jobs",{"dataGaName":327},{"text":289,"config":330},{"href":291,"dataGaName":292,"dataGaLocation":43},{"text":332,"config":333},"Leadership",{"href":334,"dataGaName":335,"dataGaLocation":43},"/company/team/e-group/","leadership",{"text":337,"config":338},"Team",{"href":339,"dataGaName":340,"dataGaLocation":43},"/company/team/","team",{"text":342,"config":343},"Handbook",{"href":344,"dataGaName":345,"dataGaLocation":43},"https://handbook.gitlab.com/","handbook",{"text":347,"config":348},"Investor relations",{"href":349,"dataGaName":350,"dataGaLocation":43},"https://ir.gitlab.com/","investor relations",{"text":352,"config":353},"Trust Center",{"href":354,"dataGaName":355,"dataGaLocation":43},"/security/","trust center",{"text":357,"config":358},"AI Transparency Center",{"href":359,"dataGaName":360,"dataGaLocation":43},"/ai-transparency-center/","ai transparency center",{"text":362,"config":363},"Newsletter",{"href":364,"dataGaName":365,"dataGaLocation":43},"/company/contact/","newsletter",{"text":367,"config":368},"Press",{"href":369,"dataGaName":370,"dataGaLocation":43},"/press/","press",{"text":372,"config":373,"lists":374},"Contact us",{"dataNavLevelOne":314},[375],{"items":376},[377,380,385],{"text":50,"config":378},{"href":52,"dataGaName":379,"dataGaLocation":43},"talk to sales",{"text":381,"config":382},"Get help",{"href":383,"dataGaName":384,"dataGaLocation":43},"/support/","get help",{"text":386,"config":387},"Customer portal",{"href":388,"dataGaName":389,"dataGaLocation":43},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":391,"login":392,"suggestions":399},"Close",{"text":393,"link":394},"To search repositories and projects, login to",{"text":395,"config":396},"gitlab.com",{"href":57,"dataGaName":397,"dataGaLocation":398},"search login","search",{"text":400,"default":401},"Suggestions",[402,404,408,410,414,418],{"text":72,"config":403},{"href":77,"dataGaName":72,"dataGaLocation":398},{"text":405,"config":406},"Code Suggestions (AI)",{"href":407,"dataGaName":405,"dataGaLocation":398},"/solutions/code-suggestions/",{"text":124,"config":409},{"href":126,"dataGaName":124,"dataGaLocation":398},{"text":411,"config":412},"GitLab on AWS",{"href":413,"dataGaName":411,"dataGaLocation":398},"/partners/technology-partners/aws/",{"text":415,"config":416},"GitLab on Google Cloud",{"href":417,"dataGaName":415,"dataGaLocation":398},"/partners/technology-partners/google-cloud-platform/",{"text":419,"config":420},"Why GitLab?",{"href":85,"dataGaName":419,"dataGaLocation":398},{"freeTrial":422,"mobileIcon":427,"desktopIcon":432,"secondaryButton":435},{"text":423,"config":424},"Start free trial",{"href":425,"dataGaName":48,"dataGaLocation":426},"https://gitlab.com/-/trials/new/","nav",{"altText":428,"config":429},"Gitlab Icon",{"src":430,"dataGaName":431,"dataGaLocation":426},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":428,"config":433},{"src":434,"dataGaName":431,"dataGaLocation":426},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":436,"config":437},"Get Started",{"href":438,"dataGaName":439,"dataGaLocation":426},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":441,"mobileIcon":445,"desktopIcon":447},{"text":442,"config":443},"Learn more about GitLab Duo",{"href":77,"dataGaName":444,"dataGaLocation":426},"gitlab duo",{"altText":428,"config":446},{"src":430,"dataGaName":431,"dataGaLocation":426},{"altText":428,"config":448},{"src":434,"dataGaName":431,"dataGaLocation":426},{"freeTrial":450,"mobileIcon":455,"desktopIcon":457},{"text":451,"config":452},"Back to pricing",{"href":205,"dataGaName":453,"dataGaLocation":426,"icon":454},"back to pricing","GoBack",{"altText":428,"config":456},{"src":430,"dataGaName":431,"dataGaLocation":426},{"altText":428,"config":458},{"src":434,"dataGaName":431,"dataGaLocation":426},"content:shared:en-us:main-navigation.yml","Main Navigation","shared/en-us/main-navigation.yml","shared/en-us/main-navigation",{"_path":464,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"title":465,"button":466,"image":471,"config":475,"_id":477,"_type":29,"_source":31,"_file":478,"_stem":479,"_extension":34},"/shared/en-us/banner","is now in public beta!",{"text":467,"config":468},"Try the Beta",{"href":469,"dataGaName":470,"dataGaLocation":43},"/gitlab-duo/agent-platform/","duo banner",{"altText":472,"config":473},"GitLab Duo Agent Platform",{"src":474},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1753720689/somrf9zaunk0xlt7ne4x.svg",{"layout":476},"release","content:shared:en-us:banner.yml","shared/en-us/banner.yml","shared/en-us/banner",{"_path":481,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"data":482,"_id":686,"_type":29,"title":687,"_source":31,"_file":688,"_stem":689,"_extension":34},"/shared/en-us/main-footer",{"text":483,"source":484,"edit":490,"contribute":495,"config":500,"items":505,"minimal":678},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":485,"config":486},"View page source",{"href":487,"dataGaName":488,"dataGaLocation":489},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":491,"config":492},"Edit this page",{"href":493,"dataGaName":494,"dataGaLocation":489},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":496,"config":497},"Please contribute",{"href":498,"dataGaName":499,"dataGaLocation":489},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":501,"facebook":502,"youtube":503,"linkedin":504},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[506,529,585,614,648],{"title":61,"links":507,"subMenu":512},[508],{"text":509,"config":510},"DevSecOps platform",{"href":70,"dataGaName":511,"dataGaLocation":489},"devsecops platform",[513],{"title":203,"links":514},[515,519,524],{"text":516,"config":517},"View plans",{"href":205,"dataGaName":518,"dataGaLocation":489},"view plans",{"text":520,"config":521},"Why Premium?",{"href":522,"dataGaName":523,"dataGaLocation":489},"/pricing/premium/","why premium",{"text":525,"config":526},"Why Ultimate?",{"href":527,"dataGaName":528,"dataGaLocation":489},"/pricing/ultimate/","why ultimate",{"title":530,"links":531},"Solutions",[532,537,539,541,546,551,555,558,562,567,569,572,575,580],{"text":533,"config":534},"Digital transformation",{"href":535,"dataGaName":536,"dataGaLocation":489},"/topics/digital-transformation/","digital transformation",{"text":149,"config":538},{"href":151,"dataGaName":149,"dataGaLocation":489},{"text":138,"config":540},{"href":120,"dataGaName":121,"dataGaLocation":489},{"text":542,"config":543},"Agile development",{"href":544,"dataGaName":545,"dataGaLocation":489},"/solutions/agile-delivery/","agile delivery",{"text":547,"config":548},"Cloud transformation",{"href":549,"dataGaName":550,"dataGaLocation":489},"/topics/cloud-native/","cloud transformation",{"text":552,"config":553},"SCM",{"href":134,"dataGaName":554,"dataGaLocation":489},"source code management",{"text":124,"config":556},{"href":126,"dataGaName":557,"dataGaLocation":489},"continuous integration & delivery",{"text":559,"config":560},"Value stream management",{"href":178,"dataGaName":561,"dataGaLocation":489},"value stream management",{"text":563,"config":564},"GitOps",{"href":565,"dataGaName":566,"dataGaLocation":489},"/solutions/gitops/","gitops",{"text":188,"config":568},{"href":190,"dataGaName":191,"dataGaLocation":489},{"text":570,"config":571},"Small business",{"href":195,"dataGaName":196,"dataGaLocation":489},{"text":573,"config":574},"Public sector",{"href":200,"dataGaName":201,"dataGaLocation":489},{"text":576,"config":577},"Education",{"href":578,"dataGaName":579,"dataGaLocation":489},"/solutions/education/","education",{"text":581,"config":582},"Financial services",{"href":583,"dataGaName":584,"dataGaLocation":489},"/solutions/finance/","financial services",{"title":208,"links":586},[587,589,591,593,596,598,600,602,604,606,608,610,612],{"text":220,"config":588},{"href":222,"dataGaName":223,"dataGaLocation":489},{"text":225,"config":590},{"href":227,"dataGaName":228,"dataGaLocation":489},{"text":230,"config":592},{"href":232,"dataGaName":233,"dataGaLocation":489},{"text":235,"config":594},{"href":237,"dataGaName":595,"dataGaLocation":489},"docs",{"text":257,"config":597},{"href":259,"dataGaName":5,"dataGaLocation":489},{"text":252,"config":599},{"href":254,"dataGaName":255,"dataGaLocation":489},{"text":261,"config":601},{"href":263,"dataGaName":264,"dataGaLocation":489},{"text":274,"config":603},{"href":276,"dataGaName":277,"dataGaLocation":489},{"text":266,"config":605},{"href":268,"dataGaName":269,"dataGaLocation":489},{"text":279,"config":607},{"href":281,"dataGaName":282,"dataGaLocation":489},{"text":284,"config":609},{"href":286,"dataGaName":287,"dataGaLocation":489},{"text":289,"config":611},{"href":291,"dataGaName":292,"dataGaLocation":489},{"text":294,"config":613},{"href":296,"dataGaName":297,"dataGaLocation":489},{"title":312,"links":615},[616,618,620,622,624,626,628,632,637,639,641,643],{"text":319,"config":617},{"href":321,"dataGaName":314,"dataGaLocation":489},{"text":324,"config":619},{"href":326,"dataGaName":327,"dataGaLocation":489},{"text":332,"config":621},{"href":334,"dataGaName":335,"dataGaLocation":489},{"text":337,"config":623},{"href":339,"dataGaName":340,"dataGaLocation":489},{"text":342,"config":625},{"href":344,"dataGaName":345,"dataGaLocation":489},{"text":347,"config":627},{"href":349,"dataGaName":350,"dataGaLocation":489},{"text":629,"config":630},"Sustainability",{"href":631,"dataGaName":629,"dataGaLocation":489},"/sustainability/",{"text":633,"config":634},"Diversity, inclusion and belonging (DIB)",{"href":635,"dataGaName":636,"dataGaLocation":489},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":352,"config":638},{"href":354,"dataGaName":355,"dataGaLocation":489},{"text":362,"config":640},{"href":364,"dataGaName":365,"dataGaLocation":489},{"text":367,"config":642},{"href":369,"dataGaName":370,"dataGaLocation":489},{"text":644,"config":645},"Modern Slavery Transparency Statement",{"href":646,"dataGaName":647,"dataGaLocation":489},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":649,"links":650},"Contact Us",[651,654,656,658,663,668,673],{"text":652,"config":653},"Contact an expert",{"href":52,"dataGaName":53,"dataGaLocation":489},{"text":381,"config":655},{"href":383,"dataGaName":384,"dataGaLocation":489},{"text":386,"config":657},{"href":388,"dataGaName":389,"dataGaLocation":489},{"text":659,"config":660},"Status",{"href":661,"dataGaName":662,"dataGaLocation":489},"https://status.gitlab.com/","status",{"text":664,"config":665},"Terms of use",{"href":666,"dataGaName":667,"dataGaLocation":489},"/terms/","terms of use",{"text":669,"config":670},"Privacy statement",{"href":671,"dataGaName":672,"dataGaLocation":489},"/privacy/","privacy statement",{"text":674,"config":675},"Cookie preferences",{"dataGaName":676,"dataGaLocation":489,"id":677,"isOneTrustButton":106},"cookie preferences","ot-sdk-btn",{"items":679},[680,682,684],{"text":664,"config":681},{"href":666,"dataGaName":667,"dataGaLocation":489},{"text":669,"config":683},{"href":671,"dataGaName":672,"dataGaLocation":489},{"text":674,"config":685},{"dataGaName":676,"dataGaLocation":489,"id":677,"isOneTrustButton":106},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",[691],{"_path":692,"_dir":693,"_draft":6,"_partial":6,"_locale":7,"content":694,"config":698,"_id":700,"_type":29,"title":18,"_source":31,"_file":701,"_stem":702,"_extension":34},"/en-us/blog/authors/owen-williams","authors",{"name":18,"config":695},{"headshot":696,"ctfId":697},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659488/Blog/Author%20Headshots/gitlab-logo-extra-whitespace.png","Owen-Williams",{"template":699},"BlogAuthor","content:en-us:blog:authors:owen-williams.yml","en-us/blog/authors/owen-williams.yml","en-us/blog/authors/owen-williams",{"_path":704,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"header":705,"eyebrow":706,"blurb":707,"button":708,"secondaryButton":712,"_id":714,"_type":29,"title":715,"_source":31,"_file":716,"_stem":717,"_extension":34},"/shared/en-us/next-steps","Start shipping better software faster","50%+ of the Fortune 100 trust GitLab","See what your team can do with the intelligent\n\n\nDevSecOps platform.\n",{"text":45,"config":709},{"href":710,"dataGaName":48,"dataGaLocation":711},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":50,"config":713},{"href":52,"dataGaName":53,"dataGaLocation":711},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",1759517407277]