Samuel Passman - 1k GitLab - 29 Oct 2025

- In the Title field of this issue, use <Your Name> - <Your Company> - <Date>

Deploying GitLab 1K Reference Architecture on AWS with GET

IMPORTANT This workshop assumes that you are using GET 3.3.2 or newer.

GitLab Team Members

If you are a GitLab Team member, be sure to use GitLab Sandbox Cloud to create an AWS account for yourself and request an ultimate license.

If you are using the staging license, you will need to make additions to the gitlab.rb file for the license to be able to be verified. We will do this by adding the needed environment variables to a configuration file and GET will include the addition.

To make this implementation more realistic, you may want to use a domain instead of an IP address. You may also want to use SSL certificates to ensure secure communication.

See Registering a new domain to create a domain.

When you have a domain, you can use Certbot to create an SSL certificate. Directions for this are in the pre-work.

Workshop pre-work

GET uses Terraform to provision Infrastructure and Ansible to manage GitLab configuration;

It is possible to use Terraform and Ansible installed locally; however, during this session, to avoid potential environmental issues, we are going to use Toolkit's image.

Note The paths that are defined in the Terraform and Ansible configuration files are paths inside the GET container. If you are running commands locally, you will need to modify the paths to relative paths for your environment.

To do so, we need to prepare our environment by installing Docker. We will deploy an EC2 instance, with Amazon Linux 2, in the region chosen to run this workshop. The instance's OS is a suggestion but the Docker installation might be different if you pick a different OS. Check the official Docker documentation.

  1. Identify your preferred AWS Region and environment prefix

    • AWS Region (e.g. us-east-2): eu-west-2
    • Environment prefix (e.g. gitlab-<GitLabHandle>-1k): gitlab-spassman-1k
      • This will be used to replace <prefix> in the configuration
  2. Create an IAM role to use for SSM - arn:aws:iam::642351122621:role/gitlab-spassman-1k-main

  3. Reserve an Elastic IP

    • Elastic IP: 3.11.115.152

    • Allocation ID: eipalloc-0ece8b26dbcc0247a

    • Optional - Update DNS, if you are using a domain name for your GitLab instance

      Click to Expand
      • GitLab URL (e.g. https://gitlab.example.com): __________
      • Create a DNS entry (A Record) for your GitLab URL with the allocated IP address as the value.
      • Requires that you are using SSL - Create a DNS entry (A Record) for your GitLab Registry URL with the allocated IP address as the value. The registry URL will be formatted like https://registry.gitlab.example.com.
  4. Launch an EC2 instance to use as a jump box

    Note The costs of deploying GitLab in this workshop are the responsibility of the workshop student or student's company.

    • Give it a name
    • AMI - Amazon Linux 2 AMI (HVM) 64-bit (x86)
    • Instance type - c5.large
    • Key pair - None
    • Advanced details - IAM instance profile - Select the IAM role you created
  5. Install Docker and pull GET image

    • Access your instance by selecting from the Instances listing your Instance ID, followed by selecting Connect, and selecting Connect again under the Session Manager tab

    • Install Docker by running in the terminal you connected to the following commands:

      sudo sh -c 'yum update -y && \
          yum install -y docker && \
          systemctl enable docker && \
          systemctl start docker && \
          usermod -aG docker ec2-user && \
          docker --version'
    • Pull the toolkit's image

      sudo docker pull registry.gitlab.com/gitlab-org/gitlab-environment-toolkit:3.3.2
      • If you got Getting permission denied while trying to connect to the Docker daemon socket just restart the instance, if the issue persist you can run sudo chmod 666 /var/run/docker.sock ssh on it again.
  6. Prepare GET requirements

    • Create GET directory structure

      mkdir -p \
          ~/get_environments/<prefix>/ansible/inventory \
          ~/get_environments/<prefix>/ansible/files/certificates \
          ~/get_environments/<prefix>/ansible/files/gitlab_configs \
          ~/get_environments/<prefix>/terraform \
          ~/get_environments/keys

      The directory structure should look like below:

      ~/get_environments
      ├──keys
      └──<prefix>
          ├──ansible
          |   ├──inventory
          |   └──files
          |       ├──certificates
          |       └──gitlab_configs
          └──terraform
    • Create SSH key with no passphrase

      ssh-keygen -t rsa -b 2048 -f ~/get_environments/keys/id_rsa
  7. Optional - Create an SSL certificate for your domain. This example is for the example.com domain.

    Click to Expand
    • Create SSL certificate. This will require you to make additions in Route53.

      • Update email
      • Update cert-name
      • Update domains
      # Must be super user to use certbot
      sudo -i
      amazon-linux-extras install epel
      yum install certbot -y
      certbot certonly \
          --manual \
          --preferred-challenges=dns \
          --agree-tos \
          --email <youremail@email.com> \
          --cert-name gitlab.example.com \
          --expand \
          --domains gitlab.example.com,registry.gitlab.example.com
      exit
    • Add SSL certificate to certificates directory and change owner

      • Update <gitlab_url> e.g.gitlab.example.com
      • Update <gitlab_registry_url> e.g. registry.gitlab.example.com
      • Update <prefix>
      sudo cp \
      /etc/letsencrypt/live/<gitlab_url>/fullchain.pem \
      ~/get_environments/<prefix>/ansible/files/certificates/<gitlab_url>.crt
      
      sudo cp \
      /etc/letsencrypt/live/<gitlab_url>/privkey.pem  \
      ~/get_environments/<prefix>/ansible/files/certificates/<gitlab_url>.key
      
      sudo chown -R $UID:$UID ~/get_environments/<prefix>/ansible/files/certificates
      
      cp ~/get_environments/<prefix>/ansible/files/certificates/<gitlab_url>.crt \
      ~/get_environments/<prefix>/ansible/files/certificates/<gitlab_registry_url>.crt
      
      cp ~/get_environments/<prefix>/ansible/files/certificates/<gitlab_url>.key \
      ~/get_environments/<prefix>/ansible/files/certificates/<gitlab_registry_url>.key
  8. Optional - Add GitLab License file

    Click to Expand
    • Create your GitLab license file in the keys directory and add your key

      touch ~/get_environments/keys/Gitlab.gitlab-license
      vim ~/get_environments/keys/Gitlab.gitlab-license
      # Copy the contents of your license key into the file
    • For GitLab team members using a staging license, add the GitLab Rails configuration to connect to the proper license server

      • Create the configuration file

        touch ~/get_environments/<prefix>/ansible/files/gitlab_configs/gitlab_rails.rb.j2
      • Edit the configuration file and add the required configuration

        gitlab_rails['env'] = {
            "GITLAB_LICENSE_MODE" => "test",
            "CUSTOMER_PORTAL_URL" => "https://customers.staging.gitlab.com"
        }
  9. If there is time before you plan on continuing with the workshop, you should put the EC2 instance into a stopped state.

Workshop work

If your EC2 instance is in a stopped state, you will need to start it.

Terraform Configuration

Configure GET to deploy the 1K reference architecture.

  1. Create the Terraform files

    • Connect to the instance and create required Terraform files

      cd ~/get_environments/<prefix>/terraform
      touch environment.tf main.tf variables.tf

      The directory structure should look like below:

      get_environments
      ├──keys
      └──<prefix>
          ├──ansible
          └──terraform
              ├── environment.tf
              ├── main.tf
              └── variables.tf
  2. Following the documentation we are going to edit the 3 files created in the previous step.

  3. Edit thevariables.tf file and replace the variables accordingly.

    • Update <prefix> value
    • Update region value, if needed
    • Update external_ip_allocation
    • Update ssh_public_key_file with your key location (if the pre-work instructions were followed, the location is "/gitlab-environment-toolkit/keys/id_rsa.pub")

    Both the public key and the allocation ID were provisioned as part of workshop pre-work (beginning of this tutorial) as well as the prefix. This prefix variable later is going to be used on our Ansible configuration. Your variables.tf file should look like the following:

    variable "prefix" {
        default = "<prefix>"
    }
    
    variable "region" {
        default = "us-east-2"
    }
    
    variable "ssh_public_key_file" {
        default = "/gitlab-environment-toolkit/keys/id_rsa.pub"
    }
    
    # This can be found in the Elastic IPs section
    variable "external_ip_allocation" {
        default = "eipalloc-08d875f994cb379bb" 
    }
  4. Edit the main.tf file. The main change is where you want to store you Terraform state file

    Note We use local storage of the Terraform state for this workshop. Alternatively, you can store it in a previously provisioned bucket.

    • Terraform state file stored locally

      Click to Expand
      terraform {
          required_providers {
              aws = {
              source = "hashicorp/aws"
              }
          }
      }
      
      # Configure the AWS Provider
      provider "aws" {
          region = var.region
      }
    • OR Terraform state file stored in S3 bucket

      Click to Expand
      terraform {
          backend "s3" {
              bucket = "<state_aws_storage_bucket_name>"
              key    = "<state_file_path_and_name>"
              region = "<state_aws_storage_bucket_region>"
          }
          required_providers {
              aws = {
              source = "hashicorp/aws"
              }
          }
      }
      
      # Configure the AWS Provider
      provider "aws" {
          region = var.region
      }
  5. Edit the environment.tf file to configure Terraform with the target Reference Architecture. During this workshop, we are going to use created network mode. GET is quite flexible and the network configuration can be customized to your needs. For more information check the Advanced Network documentation.

    • For the 1K Architecture this file should look like follows:

      module "gitlab_ref_arch_aws" {
          source = "../../modules/gitlab_ref_arch_aws"
      
          prefix              = var.prefix
          ssh_public_key      = file(var.ssh_public_key_file)
      
          # Create Network requirements
          create_network = true
          
          # Do not create buckets
          object_storage_buckets = []
      
          #rails   
          gitlab_rails_node_count = 1
          gitlab_rails_instance_type = "c5.2xlarge"
          gitlab_rails_elastic_ip_allocation_ids = [var.external_ip_allocation]
      }

Ansible configuration

Now let's configure Ansible, first creating the required directory structure and files.

  1. Create the Ansible files
    • Connect to the instance and create the required Ansible inventory files

      cd ~/get_environments/<prefix>/ansible/inventory
      touch 1k.aws_ec2.yml vars.yml

      The directory structure should look like below:

      ~/get_environments
      ├──keys
      └──<prefix>
          ├──ansible
          |   ├──inventory
          |   |   ├──1k.aws_ec2.yml
          |   |   └──vars.yml
          |   └──files
          └──terraform
  2. Now lets configure the AWS Dynamic Inventory plugin.
    • Edit the 1k.aws_ec2.yml file:

      vim ~/get_environments/<prefix>/ansible/inventory/1k.aws_ec2.yml
      • Update region accordingly
      • Update tag:gitlab_node_prefix: accordingly to your <prefix> in the
      • Don't change ansible_host. The value public_ip_address is the correct value.
      plugin: aws_ec2
      regions:
        - us-east-2
      filters:
        tag:gitlab_node_prefix: <prefix> # Same prefix set in Terraform
      keyed_groups:
        - key: tags.gitlab_node_type
          separator: ''
        - key: tags.gitlab_node_level
          separator: ''
      hostnames:
        # List host by name instead of the default public ip
        - tag:Name
      compose:
        # Use the public IP address to connect to the host
        # (note: this does not modify inventory_hostname, which is set via (hostnames))
        ansible_host: public_ip_address
  3. Now we need to provide the variables to the Ansible playbooks. We are also avoiding passwords in the playbooks by setting environment variables. In the next section, the variables GITLAB_ROOT_PASSWORD and GITLAB_EXTERNAL_URL will be defined.
    • Edit the vars.yml file:

      vim ~/get_environments/<prefix>/ansible/inventory/vars.yml
      • Update aws_region, if needed
      • Update <prefix>
      • If not using a license, comment out the License section
      • If using SSL certificates, replace <prefix> in gitlab_rails_custom_files_paths, otherwise, comment out the SSL section
      all:
        vars:
          # Ansible Settings
          ansible_user: ubuntu
          ansible_ssh_private_key_file: "/gitlab-environment-toolkit/keys/id_rsa"
      
          # Cloud Settings, available options: gcp, aws, azure
          cloud_provider: "aws"
      
          # AWS only settings
          aws_region: "us-east-2"
          gitlab_object_storage_type: "none"
      
          # General Settings
          prefix: "<prefix>"
          external_url: "{{ lookup('env', 'GITLAB_EXTERNAL_URL') }}"
          gitlab_single_node_without_lb: true
      
          # License
          # Comment this section if not providing a license
          common_custom_files_paths: [
            { src_path: "/gitlab-environment-toolkit/keys/Gitlab.gitlab-license", dest_path: "/etc/gitlab/Gitlab.gitlab-license" }
          ]
      
          # SSL
          # Comment this section if you are not using SSL
          external_ssl_source: "user"
          gitlab_rails_custom_files_paths: [
            { src_path: "/gitlab-environment-toolkit/ansible/environments/<prefix>/files/certificates/", dest_path: "/etc/gitlab/ssl/", mode: "0644" }
          ]
      
          # Passwords / Secrets
          gitlab_root_password: "{{ lookup('env', 'GITLAB_ROOT_PASSWORD') }}"

Running Terraform and Ansible from Toolkit's Container

  1. Set environment variables

    • Set values for GITLAB_ROOT_PASSWORD and GITLAB_EXTERNAL_URL environment variables
    export GITLAB_ROOT_PASSWORD='Sup3rS8cur#P@s$w0rd'
    export GITLAB_EXTERNAL_URL='https://gitlab.example.com'

    Note To generate your own random password use a password generator uncheck Include Symbols: and check Exclude Ambiguous Characters to avoid issues with password polices across architecture components. The requirements below generally work fine:

  2. Optional - Configure Ansible output logging

    Click to Expand
    • Set values for ANSIBLE_LOG_PATH and ANSIBLE_DISPLAY_ARGS_TO_STDOUT environment variables
    export ANSIBLE_LOG_PATH='/gitlab-environment-toolkit/ansible/environments/<prefix>/ansible.log'
    export ANSIBLE_DISPLAY_ARGS_TO_STDOUT=True
  3. Run a Toolkit Docker Container with the interactive option, passing the environment variables and mounting the required volume folder.

    • Execute the Docker Run command
    sudo docker run -it \
    -v ~/get_environments:/environments \
    -e GITLAB_ROOT_PASSWORD=$GITLAB_ROOT_PASSWORD \
    -e GITLAB_EXTERNAL_URL=$GITLAB_EXTERNAL_URL \
    -e ANSIBLE_LOG_PATH=$ANSIBLE_LOG_PATH \
    -e ANSIBLE_DISPLAY_ARGS_TO_STDOUT=$ANSIBLE_DISPLAY_ARGS_TO_STDOUT \
    registry.gitlab.com/gitlab-org/gitlab-environment-toolkit:3.3.2
  4. Run the Terraform sequence to provision the required infrastructure from within the container

    • Install Terraform in the container and set the version

      mise install terraform -y && mise use -g terraform@1.9.4
    • Change directories to your Terraform environments directory

      cd /gitlab-environment-toolkit/terraform/environments/<prefix>
    • Initialize Terraform

      terraform init
    • Optional - produce a Terraform plan

      Click to Expand
      terraform plan -out <prefix>.aws_ec2.tfplan
    • Apply Terraform changes

      # Apply the plan file
      terraform apply <prefix>.aws_ec2.tfplan
      
      # Apply without a plan file
      terraform apply
  5. Execute the Ansible playbooks to configure the environment

    • Move to the Ansible directory

      cd /gitlab-environment-toolkit/ansible
    • Validate Ansible inventory configuration is correct by pinging host

      ansible all -m ping -i environments/<prefix>/inventory --list-hosts
    • Execute the Ansible playbooks

      ansible-playbook -i environments/<prefix>/inventory playbooks/all.yml

      Note This might take up to an hour to complete.

    • Once the process is complete, with no ERRORs, you may exit the container by typing exit (or via Ctrl+D)

Checking the GitLab Deployment

  1. Check the GitLab status and Puma logs.
    • SSH to the GitLab node

      ssh -i ~/get_environments/keys/id_rsa ubuntu@your-rails-node-public-ip
    • Check the GitLab status

      sudo gitlab-ctl status
    • Tail the Puma logs

      sudo gitlab-ctl tail puma
    • Access the GitLab application by navigating to your GitLab external URL, ie https://gitlab.example.com (same as provided int the GITLAB_EXTERNAL_URL environment variable)

      • Login with user root and the password as set in the variable GITLAB_ROOT_PASSWORD
      • Create a new project
      • Create an issue in the new project, including the default README.md file
      • Create a merge request (MR) from the issue and change the project's README.md by adding the title Congratulations! You deployed GitLab with GET
      • Commit the change and merge the MR

Next Steps

Cleanup the workshop

  1. Clean up the environment by leveraging terraform destroy
    • Enter the GET Docker container

      docker run -it \
      -v ~/get_environments:/environments \
      registry.gitlab.com/gitlab-org/gitlab-environment-toolkit:3.3.2
    • Install Terraform in the container and set the version

      mise install terraform -y
      mise use -g terraform@1.9.4
    • Move to the Terraform environment directory

      cd /gitlab-environment-toolkit/terraform/environments/<prefix>
    • Destroy the AWS resources created

      terraform destroy
    • To terminate the GET instance, through the AWS EC2 console right click it and then Terminate instance.

    • Release the Elastic IP association in AWS

That is everything for today. Thank you so much for your attendance!

Edited by Samuel Passman