github.com/secure-build/gitlab-runner@v12.5.0+incompatible/docs/configuration/runner_autoscale_aws/index.md (about) 1 --- 2 last_updated: 2019-08-21 3 --- 4 5 > **[Article Type](https://docs.gitlab.com/ee/development/writing_documentation.html#types-of-technical-articles):** Admin guide || 6 > **Level:** intermediary || 7 > **Author:** [Achilleas Pipinellis](https://gitlab.com/axil) || 8 > **Publication date:** 2017-11-24 9 10 # Autoscaling GitLab Runner on AWS 11 12 One of the biggest advantages of GitLab Runner is its ability to automatically 13 spin up and down VMs to make sure your builds get processed immediately. It's a 14 great feature, and if used correctly, it can be extremely useful in situations 15 where you don't use your Runners 24/7 and want to have a cost-effective and 16 scalable solution. 17 18 ## Introduction 19 20 In this tutorial, we'll explore how to properly configure a GitLab Runner in 21 AWS that will serve as the Runner Manager where it will spawn new Docker machines on 22 demand. 23 24 In addition, we'll make use of [Amazon's EC2 Spot instances][spot] which will 25 greatly reduce the costs of the Runner instances while still using quite 26 powerful autoscaling machines. 27 28 ## Prerequisites 29 30 NOTE: **Note:** 31 A familiarity with Amazon Web Services (AWS) is required as this is where most 32 of the configuration will take place. 33 34 TIP: **Tip:** 35 We suggest a quick read through docker machine [`amazonec2` driver 36 documentation](https://docs.docker.com/machine/drivers/aws/) to familiarize 37 yourself with the parameters we will set later in this article. 38 39 Your GitLab instance is going to need to talk to the Runners over the network, 40 and that is something you need think about when configuring any AWS security 41 groups or when setting up your DNS configuration. 42 43 For example, you can keep the EC2 resources segmented away from public traffic 44 in a different VPC to better strengthen your network security. Your environment 45 is likely different, so consider what works best for your situation. 46 47 ### AWS security groups 48 49 Docker Machine will attempt to use a 50 [default security group](https://docs.docker.com/machine/drivers/aws/#security-group) 51 with rules for port `2376`, which is required for communication with the Docker 52 daemon. Instead of relying on Docker, you can create a security group with the 53 rules you need and provide that in the Runner options as we will 54 [see below](#the-runnersmachine-section). This way, you can customize it to your 55 liking ahead of time based on your networking environment. 56 57 ### AWS credentials 58 59 You'll need an [AWS Access Key](https://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html) 60 tied to a user with permission to scale (EC2) and update the cache (via S3). 61 Create a new user with [policies](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-policies-for-amazon-ec2.html) 62 for EC2 (AmazonEC2FullAccess) and S3 (AmazonS3FullAccess). To be more secure, 63 you can disable console login for that user. Keep the tab open or copy paste the 64 security credentials in an editor as we'll use them later during the 65 [Runner configuration](#the-runnersmachine-section). 66 67 ## Prepare the Runner Manager instance 68 69 The first step is to install GitLab Runner in an EC2 instance that will serve 70 as the Runner Manager that spawns new machines. This doesn't have to be a powerful 71 machine since it will not run any jobs itself, a `t2.micro` instance will do. 72 This machine will be a dedicated host since we need it always up and running, 73 thus it will be the only standard cost. 74 75 NOTE: **Note:** 76 For the Runner Manager instance, choose a distribution that both Docker and GitLab 77 Runner support, for example either Ubuntu, Debian, CentOS or RHEL will work fine. 78 79 Install the prerequisites: 80 81 1. Log in to your server 82 1. [Install GitLab Runner from the official GitLab repository](../../install/linux-repository.md) 83 1. [Install Docker](https://docs.docker.com/engine/installation/#server) 84 1. [Install Docker Machine](https://docs.docker.com/machine/install-machine/) 85 86 Now that the Runner is installed, it's time to register it. 87 88 ## Registering the GitLab Runner 89 90 Before configuring the GitLab Runner, you need to first register it, so that 91 it connects with your GitLab instance: 92 93 1. [Obtain a Runner token](https://docs.gitlab.com/ee/ci/runners/) 94 1. [Register the Runner](../../register/index.md#gnulinux) 95 1. When asked the executor type, enter `docker+machine` 96 97 You can now move on to the most important part, configuring the GitLab Runner. 98 99 TIP: **Tip:** 100 If you want every user in your instance to be able to use the autoscaled Runners, 101 register the Runner as a shared one. 102 103 ## Configuring the GitLab Runner 104 105 Now that the Runner is registered, you need to edit its configuration file and 106 add the required options for the AWS machine driver. 107 108 Let's first break it down to pieces. 109 110 ### The global section 111 112 In the global section, you can define the limit of the jobs that can be run 113 concurrently across all Runners (`concurrent`). This heavily depends on your 114 needs, like how many users your Runners will accommodate, how much time your 115 builds take, etc. You can start with something low like `10`, and increase or 116 decrease its value going forward. 117 118 The `check_interval` option defines how often the Runner should check GitLab 119 for new jobs, in seconds. 120 121 Example: 122 123 ```toml 124 concurrent = 10 125 check_interval = 0 126 ``` 127 128 [Read more](../advanced-configuration.md#the-global-section) 129 about all the options you can use. 130 131 ### The `runners` section 132 133 From the `[[runners]]` section, the most important part is the `executor` which 134 must be set to `docker+machine`. Most of those settings are taken care of when 135 you register the Runner for the first time. 136 137 `limit` sets the maximum number of machines (running and idle) that this Runner 138 will spawn. For more info check the [relationship between `limit`, `concurrent` 139 and `IdleCount`](../autoscale.md#how-concurrent-limit-and-idlecount-generate-the-upper-limit-of-running-machines). 140 141 Example: 142 143 ```toml 144 [[runners]] 145 name = "gitlab-aws-autoscaler" 146 url = "<URL of your GitLab instance>" 147 token = "<Runner's token>" 148 executor = "docker+machine" 149 limit = 20 150 ``` 151 152 [Read more](../advanced-configuration.md#the-runners-section) 153 about all the options you can use under `[[runners]]`. 154 155 ### The `runners.docker` section 156 157 In the `[runners.docker]` section you can define the default Docker image to 158 be used by the child Runners if it's not defined in [`.gitlab-ci.yml`](https://docs.gitlab.com/ee/ci/yaml/). 159 By using `privileged = true`, all Runners will be able to run 160 [Docker in Docker](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-executor) 161 which is useful if you plan to build your own Docker images via GitLab CI/CD. 162 163 Next, we use `disable_cache = true` to disable the Docker executor's inner 164 cache mechanism since we will use the distributed cache mode as described 165 in the following section. 166 167 Example: 168 169 ```toml 170 [runners.docker] 171 image = "alpine" 172 privileged = true 173 disable_cache = true 174 ``` 175 176 [Read more](../advanced-configuration.md#the-runnersdocker-section) 177 about all the options you can use under `[runners.docker]`. 178 179 ### The `runners.cache` section 180 181 To speed up your jobs, GitLab Runner provides a cache mechanism where selected 182 directories and/or files are saved and shared between subsequent jobs. 183 While not required for this setup, it is recommended to use the distributed cache 184 mechanism that GitLab Runner provides. Since new instances will be created on 185 demand, it is essential to have a common place where the cache is stored. 186 187 In the following example, we use Amazon S3: 188 189 ```toml 190 [runners.cache] 191 Type = "s3" 192 Shared = true 193 [runners.cache.s3] 194 ServerAddress = "s3.amazonaws.com" 195 AccessKey = "<your AWS Access Key ID>" 196 SecretKey = "<your AWS Secret Access Key>" 197 BucketName = "<the bucket where your cache should be kept>" 198 BucketLocation = "us-east-1" 199 ``` 200 201 Here's some more info to further explore the cache mechanism: 202 203 - [Reference for `runners.cache`](../advanced-configuration.md#the-runnerscache-section) 204 - [Reference for `runners.cache.s3`](../advanced-configuration.html#the-runnerscaches3-section) 205 - [Deploying and using a cache server for GitLab Runner](../autoscale.md#distributed-runners-caching) 206 - [How cache works](https://docs.gitlab.com/ee/ci/yaml/#cache) 207 208 ### The `runners.machine` section 209 210 This is the most important part of the configuration and it's the one that 211 tells GitLab Runner how and when to spawn new or remove old Docker Machine 212 instances. 213 214 We will focus on the AWS machine options, for the rest of the settings read 215 about the: 216 217 - [Autoscaling algorithm and the parameters it's based on](../autoscale.md#autoscaling-algorithm-and-parameters) - depends on the needs of your organization 218 - [Off peak time configuration](../autoscale.md#off-peak-time-mode-configuration) - useful when there are regular time periods in your organization when no work is done, for example weekends 219 220 Here's an example of the `runners.machine` section: 221 222 ```toml 223 [runners.machine] 224 IdleCount = 1 225 IdleTime = 1800 226 MaxBuilds = 10 227 OffPeakPeriods = [ 228 "* * 0-9,18-23 * * mon-fri *", 229 "* * * * * sat,sun *" 230 ] 231 OffPeakIdleCount = 0 232 OffPeakIdleTime = 1200 233 MachineDriver = "amazonec2" 234 MachineName = "gitlab-docker-machine-%s" 235 MachineOptions = [ 236 "amazonec2-access-key=XXXX", 237 "amazonec2-secret-key=XXXX", 238 "amazonec2-region=us-central-1", 239 "amazonec2-vpc-id=vpc-xxxxx", 240 "amazonec2-subnet-id=subnet-xxxxx", 241 "amazonec2-zone=x", 242 "amazonec2-use-private-address=true", 243 "amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true", 244 "amazonec2-security-group=xxxxx", 245 "amazonec2-instance-type=m4.2xlarge", 246 ] 247 ``` 248 249 The Docker Machine driver is set to `amazonec2` and the machine name has a 250 standard prefix followed by `%s` (required) that is replaced by the ID of the 251 child Runner: `gitlab-docker-machine-%s`. 252 253 Now, depending on your AWS infrastructure, there are many options you can set up 254 under `MachineOptions`. Below you can see the most common ones. 255 256 | Machine option | Description | 257 | -------------- | ----------- | 258 | `amazonec2-access-key=XXXX` | The AWS access key of the user that has permissions to create EC2 instances, see [AWS credentials](#aws-credentials). | 259 | `amazonec2-secret-key=XXXX` | The AWS secret key of the user that has permissions to create EC2 instances, see [AWS credentials](#aws-credentials). | 260 | `amazonec2-region=eu-central-1` | The region to use when launching the instance. You can omit this entirely and the default `us-east-1` will be used. | 261 | `amazonec2-vpc-id=vpc-xxxxx` | Your [VPC ID](https://docs.docker.com/machine/drivers/aws/#vpc-id) to launch the instance in. | 262 | `amazonec2-subnet-id=subnet-xxxx` | The AWS VPC subnet ID. | 263 | `amazonec2-zone=x` | If not specified, the [availability zone is `a`](https://docs.docker.com/machine/drivers/aws/#environment-variables-and-default-values), it needs to be set to the same availability zone as the specified subnet, for example when the zone is `eu-west-1b` it has to be `amazonec2-zone=b` | 264 | `amazonec2-use-private-address=true` | Use the private IP address of Docker Machines, but still create a public IP address. Useful to keep the traffic internal and avoid extra costs.| 265 | `amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true` | AWS extra tag key-value pairs, useful to identify the instances on the AWS console. The "Name" tag is set to the machine name by default. We set the "runner-manager-name" to match the Runner name set in `[[runners]]`, so that we can filter all the EC2 instances created by a specific manager setup. Read more about [using tags in AWS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html). | 266 | `amazonec2-security-group=xxxx` | AWS VPC security group name, see [AWS security groups](#aws-security-groups). | 267 | `amazonec2-instance-type=m4.2xlarge` | The instance type that the child Runners will run on. | 268 269 TIP: **Tip:** 270 Under `MachineOptions` you can add anything that the [AWS Docker Machine driver 271 supports](https://docs.docker.com/machine/drivers/aws/#options). You are highly 272 encouraged to read Docker's docs as your infrastructure setup may warrant 273 different options to be applied. 274 275 NOTE: **Note:** 276 The child instances will use by default Ubuntu 16.04 unless you choose a 277 different AMI ID by setting `amazonec2-ami`. Set only [supported 278 base operating systems for Docker Machine](https://docs.docker.com/machine/drivers/os-base/). 279 280 NOTE: **Note:** 281 If you specify `amazonec2-private-address-only=true` as one of the machine 282 options, your EC2 instance won't get assigned a public IP. This is ok if your 283 VPC is configured correctly with an Internet Gateway (IGW) and routing is fine, 284 but it’s something to consider if you've got a more complex configuration. Read 285 more in [Docker docs about VPC connectivity](https://docs.docker.com/machine/drivers/aws/#vpc-connectivity). 286 287 [Read more](../advanced-configuration.md#the-runnersmachine-section) 288 about all the options you can use under `[runners.machine]`. 289 290 ### Getting it all together 291 292 Here's the full example of `/etc/gitlab-runner/config.toml`: 293 294 ```toml 295 concurrent = 10 296 check_interval = 0 297 298 [[runners]] 299 name = "gitlab-aws-autoscaler" 300 url = "<URL of your GitLab instance>" 301 token = "<Runner's token>" 302 executor = "docker+machine" 303 limit = 20 304 [runners.docker] 305 image = "alpine" 306 privileged = true 307 disable_cache = true 308 [runners.cache] 309 Type = "s3" 310 Shared = true 311 [runners.cache.s3] 312 ServerAddress = "s3.amazonaws.com" 313 AccessKey = "<your AWS Access Key ID>" 314 SecretKey = "<your AWS Secret Access Key>" 315 BucketName = "<the bucket where your cache should be kept>" 316 BucketLocation = "us-east-1" 317 [runners.machine] 318 IdleCount = 1 319 IdleTime = 1800 320 MaxBuilds = 100 321 OffPeakPeriods = [ 322 "* * 0-9,18-23 * * mon-fri *", 323 "* * * * * sat,sun *" 324 ] 325 OffPeakIdleCount = 0 326 OffPeakIdleTime = 1200 327 MachineDriver = "amazonec2" 328 MachineName = "gitlab-docker-machine-%s" 329 MachineOptions = [ 330 "amazonec2-access-key=XXXX", 331 "amazonec2-secret-key=XXXX", 332 "amazonec2-region=us-central-1", 333 "amazonec2-vpc-id=vpc-xxxxx", 334 "amazonec2-subnet-id=subnet-xxxxx", 335 "amazonec2-use-private-address=true", 336 "amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true", 337 "amazonec2-security-group=docker-machine-scaler", 338 "amazonec2-instance-type=m4.2xlarge", 339 ] 340 ``` 341 342 ## Cutting down costs with Amazon EC2 Spot instances 343 344 As [described by][spot] Amazon: 345 346 > 347 Amazon EC2 Spot instances allow you to bid on spare Amazon EC2 computing capacity. 348 Since Spot instances are often available at a discount compared to On-Demand 349 pricing, you can significantly reduce the cost of running your applications, 350 grow your application’s compute capacity and throughput for the same budget, 351 and enable new types of cloud computing applications. 352 353 In addition to the [`runners.machine`](#the-runnersmachine-section) options 354 you picked above, in `/etc/gitlab-runner/config.toml` under the `MachineOptions` 355 section, add the following: 356 357 ```toml 358 MachineOptions = [ 359 "amazonec2-request-spot-instance=true", 360 "amazonec2-spot-price=", 361 ] 362 ``` 363 364 In this configuration with an empty `amazonec2-spot-price`, AWS sets your 365 bidding price for a Spot instance to the default On-Demand price of that 366 instance class. If you omit the `amazonec2-spot-price` completely, Docker 367 Machine will set the bidding price to a [default value of $0.50 per 368 hour](https://docs.docker.com/machine/drivers/aws/#environment-variables-and-default-values). 369 370 You may further customize your Spot instance request: 371 372 ```toml 373 MachineOptions = [ 374 "amazonec2-request-spot-instance=true", 375 "amazonec2-spot-price=0.03", 376 "amazonec2-block-duration-minutes=60" 377 ] 378 ``` 379 380 With this configuration, Docker Machines are created on Spot instances with a 381 maximum bid price of $0.03 per hour and the duration of the Spot instance is 382 capped at 60 minutes. The `0.03` number mentioned above is just an example, so 383 be sure to check on the current pricing based on the region you picked. 384 385 To learn more about Amazon EC2 Spot instances, visit the following links: 386 387 - <https://aws.amazon.com/ec2/spot/> 388 - <https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html> 389 - <https://aws.amazon.com/blogs/aws/focusing-on-spot-instances-lets-talk-about-best-practices/> 390 391 ### Caveats of Spot instances 392 393 While Spot instances is a great way to use unused resources and minimize the 394 costs of your infrastructure, you must be aware of the implications. 395 396 Running CI jobs on Spot instances may increase the failure rates because of the 397 Spot instances pricing model. If the price exceeds your bid, the existing Spot 398 instances will be terminated within two minutes and all your jobs on that host 399 will fail. 400 401 As a consequence, the auto-scale Runner would fail to create new machines while 402 it will continue to request new instances. This eventually will make 60 requests 403 and then AWS won't accept any more. Then once the Spot price is acceptable, you 404 are locked out for a bit because the call amount limit is exceeded. 405 406 If you encounter that case, you can use the following command in the Runner Manager 407 machine to see the Docker Machines state: 408 409 ```sh 410 docker-machine ls -q --filter state=Error --format "{{.NAME}}" 411 ``` 412 413 NOTE: **Note:** 414 There are some issues regarding making GitLab Runner gracefully handle Spot 415 price changes, and there are reports of `docker-machine` attempting to 416 continually remove a Docker Machine. GitLab has provided patches for both cases 417 in the upstream project. For more information, see issues 418 [#2771](https://gitlab.com/gitlab-org/gitlab-runner/issues/2771) and 419 [#2772](https://gitlab.com/gitlab-org/gitlab-runner/issues/2772). 420 421 ## Conclusion 422 423 In this guide we learned how to install and configure a GitLab Runner in 424 autoscale mode on AWS. 425 426 Using the autoscale feature of GitLab Runner can save you both time and money. 427 Using the Spot instances that AWS provides can save you even more, but you must 428 be aware of the implications. As long as your bid is high enough, there shouldn't 429 be an issue. 430 431 You can read the following use cases from which this tutorial was (heavily) 432 influenced: 433 434 - [HumanGeo - Scaling GitLab CI](http://blog.thehumangeo.com/gitlab-autoscale-runners.html) 435 - [Substrakt Health - Autoscale GitLab CI Runners and save 90% on EC2 costs](https://about.gitlab.com/blog/2017/11/23/autoscale-ci-runners/) 436 437 [spot]: https://aws.amazon.com/ec2/spot/