Samuel Passman - 1k GitLab - 29 Oct 2025
<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.
-
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
- This will be used to replace
-
-
Create an IAM role to use for SSM - arn:aws:iam::642351122621:role/gitlab-spassman-1k-main
-
Access the AWS Management Console -
Create an IAM role for EC2use case and withAdministratorAccesspolicy
-
-
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.
-
-
-
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
-
-
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 socketjust restart the instance, if the issue persist you can runsudo chmod 666 /var/run/docker.sockssh on it again.
- If you got
-
-
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/keysThe 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
-
-
Optional - Create an SSL certificate for your domain. This example is for the
example.comdomain.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 certificatesdirectory 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 -
-
-
Optional - Add GitLab License file
Click to Expand
-
Create your GitLab license file in the keysdirectory and add your keytouch ~/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" }
-
-
-
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.
-
Create the Terraform files
-
Connect to the instance and create required Terraform files cd ~/get_environments/<prefix>/terraform touch environment.tf main.tf variables.tfThe directory structure should look like below:
get_environments ├──keys └──<prefix> ├──ansible └──terraform ├── environment.tf ├── main.tf └── variables.tf
-
-
Following the documentation we are going to edit the 3 files created in the previous step.
-
Edit the
variables.tffile and replace the variables accordingly.-
Update <prefix>value -
Update regionvalue, if needed -
Update external_ip_allocation -
Update ssh_public_key_filewith 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. Thisprefixvariable later is going to be used on our Ansible configuration. Yourvariables.tffile 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" } -
-
Edit the
main.tffile. The main change is where you want to store you Terraform state fileNote 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 }
-
-
Edit the
environment.tffile 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.
- 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.ymlThe directory structure should look like below:
~/get_environments ├──keys └──<prefix> ├──ansible | ├──inventory | | ├──1k.aws_ec2.yml | | └──vars.yml | └──files └──terraform
-
- Now lets configure the AWS Dynamic Inventory plugin.
-
Edit the 1k.aws_ec2.ymlfile:vim ~/get_environments/<prefix>/ansible/inventory/1k.aws_ec2.yml-
Update regionaccordingly -
Update tag:gitlab_node_prefix:accordingly to your<prefix>in the -
Don't change ansible_host. The valuepublic_ip_addressis 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 -
-
- 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_PASSWORDandGITLAB_EXTERNAL_URLwill be defined.-
Edit the vars.ymlfile:vim ~/get_environments/<prefix>/ansible/inventory/vars.yml-
Update aws_region, if needed -
Update <prefix> -
If not using a license, comment out the Licensesection -
If using SSL certificates, replace <prefix>ingitlab_rails_custom_files_paths, otherwise, comment out theSSLsection
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
-
Set environment variables
-
Set values for GITLAB_ROOT_PASSWORDandGITLAB_EXTERNAL_URLenvironment 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 checkExclude Ambiguous Charactersto avoid issues with password polices across architecture components. The requirements below generally work fine: -
-
Optional - Configure Ansible output logging
Click to Expand
-
Set values for ANSIBLE_LOG_PATHandANSIBLE_DISPLAY_ARGS_TO_STDOUTenvironment variables
export ANSIBLE_LOG_PATH='/gitlab-environment-toolkit/ansible/environments/<prefix>/ansible.log' export ANSIBLE_DISPLAY_ARGS_TO_STDOUT=True -
-
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 -
-
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
-
-
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.ymlNote This might take up to an hour to complete.
-
Once the process is complete, with no ERRORs, you may exit the container by typingexit(or viaCtrl+D)
-
Checking the GitLab Deployment
- 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 theGITLAB_EXTERNAL_URLenvironment variable)-
Login with user rootand the password as set in the variableGITLAB_ROOT_PASSWORD -
Create a new project -
Create an issue in the new project, including the default README.mdfile -
Create a merge request (MR) from the issue and change the project's README.mdby adding the titleCongratulations! You deployed GitLab with GET -
Commit the change and merge the MR
-
-
Next Steps
Cleanup the workshop
- 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!