diff --git a/content/amazon-ec2-spot-cicd-workshop/_index.md b/content/amazon-ec2-spot-cicd-workshop/_index.md index e3b47bc5..b6a21d4d 100644 --- a/content/amazon-ec2-spot-cicd-workshop/_index.md +++ b/content/amazon-ec2-spot-cicd-workshop/_index.md @@ -7,27 +7,6 @@ pre: "8. " --- ## Overview -During this workshop, you'll get hands-on with Amazon EC2 Spot and discover architectural best practices through the lens of DevOps and CI/CD. You'll deploy Jenkins build agents and test environments on Spot instances at a fraction of the cost of on-demand instances. You'll also implement mechanisms to ensure that your CI/CD tooling recovers from spot market events by decoupling application state from your compute resources. Finally, you'll migrate your CI/CD environment to a containered environment to eke out maximum performance and cost efficiency. In addition to covering the ins and outs of Spot, we'll share some of the Spot-based mechanisms used by customers to reduce the cost of their test and production workloads. - -## Workshop Details -This workshop will be broken down into a series of labs that flow on from each other (that is, you must complete each lab in order before proceeding with the next). The lab exercises that will be covered are: - -* Workshop preparation: Deploy pre-requisite resources through Amazon CloudFormation; -* Lab 1: Reduce the cost of builds using Amazon EC2 Spot Fleet; -* Lab 2: Deploy testing environments using Amazon EC2 Spot, Amazon CloudFormation & Amazon EC2 Launch Templates; -* Lab 3: Externalize state data to add resiliency and reduce cost for your CI/CD tooling; -* Lab 4: Using containers backed by Auto Scaling Groups comprised of both on-demand and Spot instances; -* Workshop clean up. - -As a reminder, you should have a laptop device (Windows/OSX/Linux are supported - tablets are not appropriate) with the current version of Google Chrome or Mozilla Firefox installed. You should also have a clean AWS account, with **AdministratorAccess** policy-level access. - -This workshop should take between two and three hours to complete, depending on your proficiency with the AWS services being featured. - -#### Additional considerations when running this workshop in a corporate IT environment -If you are running this workshop from a corporate IT environment, contact your Systems Administrator to ensure that you will be able to establish outbound Secure Shell (SSH) connections to an Internet host: - -* If you cannot establish SSH connections to Internet hosts (and do not have a suitable workaround), you will not be able to complete Labs 3 & 4; -* If you can establish SSH connections to Internet hosts, obtain from your Systems Administrator the source IP address CIDR block that connections will be established from. - -If you access the Internet through a transparent proxy server running in your corporate IT environment and this proxy server uses a different source address than where SSH connections come from, additional configuration of AWS Security Groups will need to be carried out. The lab guide will indicate the configuration steps required when appropriate. - +Amazon EC2 Spot Instances are a good fit in DevOps scenarios: to run your CI/CD pipelines (including build and test runners) and to deploy your testing environments. In this section you can select one of the two workshops for CI/CD depending on the tool that you use: +* [Jenkins](/amazon-ec2-spot-cicd-workshop/jenkins-spot.html) +* [GitLab](/amazon-ec2-spot-cicd-workshop/gitlab-spot.html) \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/_index.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/_index.md new file mode 100644 index 00000000..5b5fbf5c --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/_index.md @@ -0,0 +1,25 @@ +--- +title: "CI/CD and Test Workloads (GitLab) with EC2 Spot Instances" +menuTitle: "GitLab" +weight: 20 +pre: "" +--- + +## Overview +In this workshop you will add runners on Amazon EC2 Spot instances to a pre-installed GitLab. Then you will build a containerized demo application on them and install it into Kubernetes cluster that also uses only spot instances as its worker nodes. In the end you will test it to verify the results. + +You can perform all workshop steps one-by-one to get to the expected results, but for better understanding of using Spot instances with GitLab we recommend that you also look into the used templates and result files and try modifying them additionally. + +Many workshop steps imply manual actions in the AWS console to better demonstrate the underlying concepts, but in a Production environment it is better to automate them using Infrastructure as Code (IaC), such as [AWS CloudFormation](https://aws.amazon.com/cloudformation/) and [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/home.html). + +## Workshop Details +This workshop will be broken down into a series of labs that flow on from each other (that is, you must complete each lab in order before proceeding with the next). The lab exercises that will be covered are: + +* [Starting the workshop](gitlab-spot/before.html) where you will log in to AWS accounts and deploy GitLab, if it is not yet deployed +* [Workshop Preparation](gitlab-spot/prep.html) where you will save GitLab access details and create an AWS Cloud9 environment to execute the workshop steps +* [Lab 1: Create a GitLab repository](gitlab-spot/lab1.html) where you will create a repository in GitLab CI/CD and create a demo application. +* [Lab 2: Configure GitLab runners on Spot instances](gitlab-spot/lab2.html) where you will deploy the GitLab Runners in an auto-scaling group on spot instances +* [Lab 3: Building the demo app](gitlab-spot/lab3.html) where you will push the changes and make sure that your pipeline executes successfully. +* [Lab 4: Deploying Amazon EKS on Spot instances](gitlab-spot/lab4.html) where you will create a new Kubernetes cluster in Amazon EKS that will only have worker nodes on spot instances +* [Lab 5: Installing the demo app into Amazon EKS](gitlab-spot/lab5.html) where you will modify your GitLab CI/CD scripts to add a stage of deploying on Amazon EKS and test the result +* [Workshop Cleanup](gitlab-spot/cleanup.html) where you will remove all the resources created during the workshop \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/_index.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/_index.md new file mode 100644 index 00000000..36537721 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/_index.md @@ -0,0 +1,11 @@ ++++ +title = "Starting the workshop" +chapter = false +weight = 10 ++++ + +To start the workshop, follow one of the following pages, depending on whether you are... + +{{% children %}} + +Once you are done with either setup, continue with [**Workshop Preparation**](prep.html). \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/aws_event.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/aws_event.md new file mode 100644 index 00000000..3d8205f2 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/aws_event.md @@ -0,0 +1,48 @@ ++++ +title = "...At an AWS event" +weight = 10 ++++ + +{{% notice warning %}} +Only complete this section if you are at an AWS hosted event (such as re:Invent, public workshop, Immersion Day, or any other event hosted by an AWS employee). If you are running the workshop on your own, go to: [Start the workshop on your own]({{< ref "/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/self_paced.md" >}}) +{{% /notice %}} + +### Login to the AWS Workshop Portal + +If you are at an AWS event, an AWS account created for you to use throughout the workshop. You will need the **Participant Hash** provided to you by the event's organizers. + +1. Connect to the portal by browsing to [https://dashboard.eventengine.run/](https://dashboard.eventengine.run/). +2. Enter the Hash in the text box, and click **Accept Terms & Login** . +3. Select one of the options to sign-in, for example **Email One-Time Password (OTP)** which would request you to type your e-mail address and enter a passcode that you receive. + +![Event Engine Screenshot: Sign in with](/images/gitlab-spot/EE-SignInMethod.png) + +### Get the SSH key and log in to AWS Console + +1. In the Team Dashboard screen, choose **SSH Key**. +2. In the popup page, choose **Download Key**. You will only need it if you decide to do an optional task of configuring runners using Docker Machine (this had been the only way before Auto-Scaling Groups support was added). + +![Event Engine Screenshot: SSH Key](/images/gitlab-spot/EE-SSHKey.png) + +3. Close the popup and back in the Team Dashboard screen, choose **AWS Console**. +4. In the popup page, choose **Open AWS Console**. +5. Select the AWS region specified by your facilitator. + +You are now logged in to the AWS console in an account that was created for you, and will be available only throughout the workshop run time. + +### Open the pre-provisioned CloudFormation stack + +In the next section we will get the login details of the GitLab environment that was pre-provisioned for you via AWS CloudFormation. First, you need to find and open the CloudFormation stack: it is the only one in the account. + +{{%expand "Click to reveal detailed instructions" %}} +1. In the AWS Console enter **CloudFormation** in the search box at the top of the screen and open the service: + +![AWS Console Screenshot: Search for CloudFormation](/images/gitlab-spot/AWSConsole-CloudFormationSearch.png) + +2. In the navigation pane on the left choose **Stacks**. +3. You should see exactly one stack in the list (with the name like `mod-...`), click on it. +{{% /expand%}} + +If there is no CloudFormation stack present, provision it as specified in the section [**...On your own**](self_paced.html). + +You can now proceed to the [**Workshop Preparation**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.html) where you will save the required output values from the stack. \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/self_paced.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/self_paced.md new file mode 100644 index 00000000..97238c7a --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/self_paced.md @@ -0,0 +1,43 @@ ++++ +title = "...On your own" +weight = 20 ++++ + +{{% notice warning %}} +Only complete this section if you are running the workshop on your own or if you do not have a CloudFormation stack with GitLab available. If you are at an AWS hosted event (such as re:Invent, public workshop, Immersion Day, or any other event hosted by an AWS employee), go to [Start the workshop at an AWS event]({{< ref "/amazon-ec2-spot-cicd-workshop/gitlab-spot/before/aws_event.md" >}}). +{{% /notice %}} + +### Preparation + +{{% notice warning %}} +Your account must have the ability to create new IAM roles and scope other IAM permissions. +{{% /notice %}} + +1. If you don't already have an AWS account with Administrator access: [create one now by clicking here](https://aws.amazon.com/getting-started/) +2. Log in to [AWS Console](https://console.aws.amazon.com/) with an IAM user having administrator permissions. +3. Download the CloudFormation YAML-template from [this link](https://raw.githubusercontent.com/awslabs/ec2-spot-workshops/master/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/gitlab-deploy.yml). + +### Create an SSH key + +You will need an SSH key if you decide to do an optional task of configuring runners using Docker Machine (this had been the only way before Auto-Scaling Groups support was added). The following steps show how to create it. + +1. Open **EC2** service in the AWS Console. +2. In the navigation pane choose **Key Pairs** in the **Network & Security** section. +3. If there is already an existing SSH key and you have its private key, remember its name, otherwise create a new one: + * Choose **Create key pair** + * In the **Name** field enter `ee-default-key-pair` + * In the **Private key file format** list select `.pem` (even if you use Microsoft Windows: we will be uploading this key into an AWS Cloud9 environment) + * Choose **Create key pair** + * Save the .pem file as suggested by your browser + +### Deploy GitLab +Now you will deploy a GitLab instance without any runners. As it is not the purpose of this workshop to dive deep into GitLab itself, the deployment will be fully automated using Infrastructure as Code template in AWS CloudFormation. It will deploy a VPC with two public subnets, an Amazon S3 bucket that you can configure as GitLab cache, an EC2 instance with GitLab itself, an Application Load Balancer and an Amazon CloudFront distribution to organize a secure access to it, an Amazon ECR repository for storing the container image, and a number of supplementary resources. + +1. Open **CloudFormation** service in the AWS Console. +2. In the navigation pane choose **Stacks**. +3. Choose **Create stack** and in the dropdown choose **With new resources (standard)**. +4. In the **Template source** field select **Upload a template file**, choose the file you saved in the [**Preparation**](#preparation) section above, and choose **Next**. +5. In the **Stack name** field enter `mod-gitlab-spot-workshop`, in the **SSHKeyName** field select `ee-default-key-pair` or the name of the key you used in the steps above, and choose **Next**. +6. Choose **Next**. +7. Mark the checkbox **I acknowledge that AWS CloudFormation might create IAM resources.** and choose **Create stack**. +8. Wait until the stack is in `CREATE_COMPLETE` status (it should take approximately 15 minutes) and continue with [**Workshop Preparation**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.html). \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cleanup.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cleanup.md new file mode 100644 index 00000000..622871a8 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cleanup.md @@ -0,0 +1,36 @@ ++++ +title = "Workshop Cleanup" +weight = 60 ++++ + +You will now remove the resources created during the workshop. + +1. Return to the browser tab with Cloud9 and perform the following commands in the terminal to remove the Kubernetes ingress, service, and deployment: + +``` +kubectl delete ingress/spot-demo +kubectl delete service/spot-demo +kubectl delete deployment/spot-demo +``` + +2. Perform the following commands to remove the Amazon EKS cluster (when asked, use the same parameter values as when you were creating it: Kubernetes version and the VPC ID): + +``` +cd ~/environment/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster +TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 600") +export TF_VAR_aws_region=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) +export TF_VAR_alb_policy=$(aws iam get-policy --policy-arn arn:aws:iam::$(aws sts get-caller-identity --output text --query Account):policy/AWSLoadBalancerControllerIAMPolicy --query Policy.Arn --output text) +terraform destroy +``` + +3. When asked if you want to destroy all resources, type `yes` and press Enter. After that, you can close your Cloud9 environment. +4. Depending on how you deployed the runners, do one of the following: + - If you deployed runners using Auto-Scaling Group, in CloudFormation console delete the stack `linux-docker-scaling-spotonly` (the NESTED stack will be removed automatically). + - If you performed the optional steps to deploy runners using Docker Machine, terminate all runner instances in the EC2 console (name starts with `runner-`) if they have not been yet terminated automatically. Also, terminate the instace `GitLabRunnerManager`. Finally, in the EC2 console choose **Security Groups** in the navigation pane and delete the security groups `GitLabRunner` first and then `GitLabRunnerManager`. +5. In Cloud9 console remove the environment you created. +6. In the IAM console remove all roles you created (`gitlab-spot-workshop-admin` and `GitLabRunner`) and all policies (`EKS-ReadAll`, `AWSLoadBalancerControllerIAMPolicy`, unless you had it before the workshop, and, if you did the Docker Run lab, `IAM-PassRole`). +7. In the ECR console open the repository and remove all images inside it (you do not need to remove the repository itself: it will be done automatically when removing the GitLab stack). +8. If you created the GitLab stack in CloudFormation yourself, remove it too (if you used the one created automatically, you will not be able to delete it, so you can leave it as is). + +### Thank you +At this point, we would like to thank you for attending this workshop. \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/ap-southeast-1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/ap-southeast-1.md new file mode 100644 index 00000000..658eb6cd --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/ap-southeast-1.md @@ -0,0 +1,8 @@ +--- +title: "Singapore" +chapter: false +disableToc: true +hidden: true +--- + +Create a Cloud9 Environment: [https://ap-southeast-1.console.aws.amazon.com/cloud9/home?region=ap-southeast-1](https://ap-southeast-1.console.aws.amazon.com/cloud9/home?region=ap-southeast-1) diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/eu-central-1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/eu-central-1.md new file mode 100644 index 00000000..789fcee4 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/eu-central-1.md @@ -0,0 +1,8 @@ +--- +title: "Frankfurt" +chapter: false +disableToc: true +hidden: true +--- + +Create a Cloud9 Environment: [https://eu-central-1.console.aws.amazon.com/cloud9/home?region=eu-central-1](https://eu-central-1.console.aws.amazon.com/cloud9/home?region=eu-central-1) \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/eu-west-1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/eu-west-1.md new file mode 100644 index 00000000..e3fced02 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/eu-west-1.md @@ -0,0 +1,8 @@ +--- +title: "Ireland" +chapter: false +disableToc: true +hidden: true +--- + +Create a Cloud9 Environment: [https://eu-west-1.console.aws.amazon.com/cloud9/home?region=eu-west-1](https://eu-west-1.console.aws.amazon.com/cloud9/home?region=eu-west-1) \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-east-1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-east-1.md new file mode 100644 index 00000000..ba4c2e30 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-east-1.md @@ -0,0 +1,8 @@ +--- +title: "N.Virginia" +chapter: false +disableToc: true +hidden: true +--- + +Create a Cloud9 Environment: [https://us-east-1.console.aws.amazon.com/cloud9/home?region=us-east-1](https://us-east-1.console.aws.amazon.com/cloud9/home?region=us-east-1) \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-east-2.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-east-2.md new file mode 100644 index 00000000..5d96da8c --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-east-2.md @@ -0,0 +1,8 @@ +--- +title: "Ohio" +chapter: false +disableToc: true +hidden: true +--- + +Create a Cloud9 Environment: [https://us-east-2.console.aws.amazon.com/cloud9/home?region=us-east-2](https://us-east-2.console.aws.amazon.com/cloud9/home?region=us-east-2) \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-west-2.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-west-2.md new file mode 100644 index 00000000..caf14265 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/cloud9/us-west-2.md @@ -0,0 +1,8 @@ +--- +title: "Oregon" +chapter: false +disableToc: true +hidden: true +--- + +Create a Cloud9 Environment: [https://us-west-2.console.aws.amazon.com/cloud9/home?region=us-west-2](https://us-west-2.console.aws.amazon.com/cloud9/home?region=us-west-2) diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab1.md new file mode 100644 index 00000000..9a58d97f --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab1.md @@ -0,0 +1,69 @@ ++++ +title = "Lab 1: Create a GitLab repository" +weight = 30 ++++ +In this lab you will create a new repository in GitLab and configure it in AWS Cloud9. Then you will create the source code of the demo app and commit it into the repository, but before you configure the actual CI/CD in the next lab, will not push it. + +### Log in to GitLab + +1. Open a new browser tab and proceed to GitLab URL: use the output value **GitLabURL** that you saved [**Workshop Preparation**](prep.html). +2. Log in to GitLab with username `root` and the password from **GitLabPassword** output value. + +### Create a new repository + +In GitLab create a new empty private repository called `GitLab Spot Workshop`. + +{{%expand "Click to reveal detailed instructions" %}} +1. Choose **New project** on the **Projects** page. +2. Choose **Create blank project**. +3. In the **Project name** field type `GitLab Spot Workshop`, in the dropdown next to **Project URL** select `root` user, and unmark the checkbox **Initialize repository with a README**. Leave the rest values as default, and choose **Create project**: + +![GitLab Screenshot: Create blank project](/images/gitlab-spot/GitLab-CreateBlankProject.png) + +4. Copy the repository URL (in format `https://xxx.cloudfront.net/root/gitlab-spot-workshop.git`) that is displayed, for example, in **Create a new repository** section on the screen. + +{{% /expand%}} + +### Add GitLab as origin to the demo app repository + +You will now initialize Git repository in the demo app and add your GitLab environment as an origin to it. + +1. Return to Cloud9 tab and execute the following command to switch to the directory with the demo application: + +``` +cd ~/environment/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/ +``` + +2. Execute the following command to substitute the `ECR_ADDRESS` placeholder with the actual address of ECR repository created in the CloudFormation stack and save it into `.gitlab-ci.yml` file as expected by GitLab CI/CD: + +``` +TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 600") +REGION=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) +export ECR_ADDRESS=$(aws ecr describe-repositories --repository-names gitlab-spot-demo --region $REGION --query repositories[0].repositoryUri --output text | awk -F'/' '{print $1}') +sed "s/\${ECR_ADDRESS}/${ECR_ADDRESS}/g" template-gitlab-ci.yml | sed "s/\${AWS_REGION}/${REGION}/g" > .gitlab-ci.yml +``` + +3. In the file tree on the left open file `gitlab-spot-workshop/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/.gitlab-ci.yml` (if you don't see it, make sure you have enabled the hidden files in [**Workshop Preparation**](prep.html)). Look through it to understand what it does. +4. Define your name and email that will be used in Git (replace `Your Name` and `youremail@test.tld` with the values you prefer): + +``` +git config --global user.name "Your Name" +git config --global user.email "youremail@test.tld" +``` + +5. Optionally you can enable the storage of the GitLab login and password in Git configuration, otherwise you will need to enter them each time you work with the repository: + +``` +git config --global credential.helper store +``` + +6. Initialize Git inside the directory (use the actual URL of GitLab repositoy that you saved in the previous section) and do your first commit: + +``` +git init --initial-branch=main +git remote add origin https://xxx.cloudfront.net/root/gitlab-spot-workshop.git +git add . +git commit -m "Initial commit" +``` + +You are now ready to do the key step in configuring GitLab CI/CD on Spot instances: add the runners. Please proceed to [**Lab 2: Configure GitLab runners on Spot instances**](lab2.html). \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/_index.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/_index.md new file mode 100644 index 00000000..296dbcf6 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/_index.md @@ -0,0 +1,128 @@ ++++ +title = "Lab 2: Configure GitLab runners on Spot instances" +chapter = false +weight = 40 ++++ + +In this lab you will configure GitLab CI/CD runners using **GitLab HA Scaling Runner Vending Machine for AWS** solution. You can find more about its features at https://gitlab.com/guided-explorations/aws/gitlab-runner-autoscaling-aws-asg/-/blob/main/FEATURES.md. It is built using Infrastructure as Code (IaC) with AWS CloudFormation, but you can implement similar logic using any IaC solution of your choice. + +If you want to use the previous way of manually configuring runners using Docker Machine (which does not use Auto-Scaling Groups and thus has some drawbacks compared to the current approach), see the steps in the [**Configuring GitLab runners using Docker Machine (optional)**](lab2/docker-machine.html) section instead. + +There are also other ways to create GitLab runners on spot instances that we are not reviewing in this workshop: runners inside containers in a Kubernetes cluster with the worker nodes on spot instances (we will deploy such cluster for application testing, but not for executing the runners) or in Amazon ECS with Fargate Spot. + +### Deploy the CloudFormation stack + +You will now get the runner configuration information from GitLab and then start the AWS CloudFormation stack deployment. + +1. Return to the browser tab with GitLab. +2. In the **GitLab Spot Workshop** repository choose **Settings** > **CI/CD** in the navigation pane. +3. Expand the **Runners** section and save into a text file both GitLab URL and the registration token that are displayed on the screen: + +![GitLab Screenshot: Runners configuration](/images/gitlab-spot/GitLab-RunnersRegistration.png) + +4. Use one of the links at https://gitlab.com/guided-explorations/aws/gitlab-runner-autoscaling-aws-asg#easy-buttons-provided to deploy the stack (make sure to change the link to the correct region). We will be using the **Amazon Linux 2 Docker Simple Scaling Spot Instances**, you can use one of the below links to deploy it depending on the region where you are running the workshop: + +{{< tabs name="Region" >}} + {{< tab name="N. Virginia" include="gitlab-easybutton/us-east-1.md" />}} + {{< tab name="Oregon" include="gitlab-easybutton/us-west-2.md" />}} + {{< tab name="Frankfurt" include="gitlab-easybutton/eu-central-1.md" />}} + {{< tab name="Ireland" include="gitlab-easybutton/eu-west-1.md" />}} + {{< tab name="Ohio" include="gitlab-easybutton/us-east-2.md" />}} + {{< tab name="Singapore" include="gitlab-easybutton/ap-southeast-1.md" />}} +{{< /tabs >}} + +Investigate the parameters presented and try deploying the stack yourself. Expand the section below to see step-by-step instructions. + +{{%expand "Click to reveal detailed instructions" %}} +5. In the **GitLab Instance URL** field enter GitLab URL you saved previously (in the format `https://xxx.cloudfront.net`). +6. In the **One or more runner Registration tokens from the target instance.** field enter the token you saved previously. +7. In the **The VPC in the account and region should be used.** enter the VPC ID you saved from CloudFormation Output values in [**Workshop Preparation**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.html) (in the format `vpc-...`). +8. Leave the rest parameters with their default values, in the bottom of the screen mark the checkboxes **I acknowledge that AWS CloudFormation might create IAM resources with custom names.** and **I acknowledge that AWS CloudFormation might require the following capability: CAPABILITY_AUTO_EXPAND**, and choose **Create stack**: + +![CloudFormation Console Screenshot: Create GitLab Runners stack](/images/gitlab-spot/AWSConsole-CloudFormationGitLabRunnersStack.png) +9. Wait until the stack is in `CREATE_COMPLETE` status, which should take approximately 5-10 minutes. +{{% /expand%}} + +### Enable access to AWS services for GitLab Runners + +You will now create a new IAM role that has access to Amazon EKS, Amazon S3, AWS Systems Manager, Amazon EC2 Auto Scaling, and Amazon ECR, which the GitLab Runners will need to build and deploy the demo app, and then update the CloudFormation stack to use it. + +1. Return to the browser tab with IAM console or open it again using the search box at the top. +2. Choose **Policies** in the navigation pane. +3. Choose **Create Policy**. +4. Switch to **JSON** tab and paste the below policy into the editor window: + +``` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "eks:DescribeNodegroup", + "eks:ListNodegroups", + "eks:DescribeCluster", + "eks:ListClusters", + "eks:AccessKubernetesApi", + "ssm:GetParameter", + "eks:ListUpdates", + "eks:ListFargateProfiles" + ], + "Resource": "*" + } + ] +} +``` + +5. Choose **Next: Tags**. +6. Choose **Next: Review**. +7. In the **Name** field type `EKS-ReadAll` and choose **Create policy**: + +![IAM Console Screenshot: Create EKS-ReadAll policy](/images/gitlab-spot/AWSConsole-IAMCreatePolicy.png) + +8. In the navigation pane choose **Roles** +9. Choose **Create role**. +10. In the **Use case** section select **EC2** and choose **Next**. +11. In the **Permissions policies** table find the following policies one-by-one and select each of them: + - `EKS-ReadAll` + - `AmazonS3FullAccess` + - `AmazonEC2RoleforSSM` + - `CloudWatchAgentServerPolicy` + - `AmazonSSMAutomationRole` + - `AmazonSSMMaintenanceWindowRole` + - `AmazonEC2ContainerRegistryFullAccess` + - A policy created by CloudFormation stack containing `EC2SelfAccessPolicy` in its name + - A policy created by CloudFormation stack containing `ASGSelfAccessPolicy` in its name + +{{% notice warning %}} +Note that here you are assigning quite broad permission policies to the IAM role to avoid creating specific custom policies, but in a real Production environment you should follow the least privilege principle. You can find the best practices in [AWS Blogs](https://aws.amazon.com/blogs/security/techniques-for-writing-least-privilege-iam-policies/). +{{% /notice %}} + +12. Make sure you have 9 policies selected and choose **Next**. +13. In the **Role name** field type **GitLabRunner** and choose **Create role**. +14. Return to CloudFormation stacks and open the stack starting with `linux-docker-scaling-spotonly-` and marked as **NESTED**: + +![CloudFormation Console Screenshot: GitLab nested stack](/images/gitlab-spot/AWSConsole-CloudFormationNestedStack.png) + +15. Select **Update**. +16. In the popup page select **Update nested stack** and then choose **Update stack**. +17. Choose **Next** (leave the default option of **Use current template** unchanged). +18. In the **Override automatic IAM Instance Profile for a precreated one** field type `GitLabRunner`. +19. In the **4ASGUpdateMinInstancesInService** field type `0`, this would allow to update the group faster by leaving no active runners in place. It should not be used in a real environment if you have CI/CD jobs constantly coming in, as there might be no runners to take them. +20. Choose **Next** and then again **Next**. +21. On the final screen select the **I acknowledge that AWS CloudFormation might create IAM resources with custom names.** checkbox and choose **Update stack**. +22. Wait until the stack is in the `UPDATE_COMPLETE` status which should take approximately 5 minutes. + +After that you can open the EC2 console and verify that your runner(s) are using spot instances: open the corresponding EC2 instance (its name starts with `linux-docker-scaling-spotonly-`) and check the **Lifecycle** field: + +![EC2 Console Screenshot: Runner lifecycle](/images/gitlab-spot/AWSConsole-EC2RunnerLifecycle.png) + +23. Return to the browser tab with GitLab, refresh the CI/CD settings page and make sure that your runner(s) have appeared in the **Runners** section: + +![GitLab Screenshot: Runner available](/images/gitlab-spot/GitLab-RunnerAvailable.png) + +{{% notice tip %}} +You had to do an extra step to update the IAM role of the runners, because this parameter is not available in the easy buttons templates. However, you could instead use the full template right away and provide all the required parameters directly. You can find more information at https://gitlab.com/guided-explorations/aws/gitlab-runner-autoscaling-aws-asg. +{{% /notice %}} + +You can now proceed to build your application in [**Lab 3: Building the demo app**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab3.html). \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/docker-machine.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/docker-machine.md new file mode 100644 index 00000000..5c290eb6 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/docker-machine.md @@ -0,0 +1,235 @@ ++++ +title = "Configuring GitLab runners using Docker Machine (optional)" +weight = 10 ++++ + +{{% notice info %}} +Only complete this lab if you want to test the legacy way of deploying spot instances in GitLab using Docker Machine and if you have not performed the lab with runners in an auto-scaling group. Otherwise, skip it and proceed to [**Lab 3: Building the demo app**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab3.html). +{{% /notice %}} + +### Create an IAM role for GitLab Runners + +You will now create a new IAM role that has access to Amazon EKS, Amazon S3, Amazon EC2, and Amazon ECR, which the GitLab Runners will need to build and deploy the demo app. + +1. Return to the browser tab with IAM console or open it again using the search box at the top. +2. Choose **Policies** in the navigation pane. +3. Choose **Create Policy**. +4. Switch to **JSON** tab and paste the below policy into the editor window: + +``` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "eks:DescribeNodegroup", + "eks:ListNodegroups", + "eks:DescribeCluster", + "eks:ListClusters", + "eks:AccessKubernetesApi", + "ssm:GetParameter", + "eks:ListUpdates", + "eks:ListFargateProfiles" + ], + "Resource": "*" + } + ] +} +``` + +5. Choose **Next: Tags**. +6. Choose **Next: Review**. +7. In the **Name** field type `EKS-ReadAll` and choose **Create policy**: + +![IAM Console Screenshot: Create EKS-ReadAll policy](/images/gitlab-spot/AWSConsole-IAMCreatePolicy.png) + +8. Repeat the same steps to create another policy with the following JSON and the name `IAM-PassRole`: + +``` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "iam:PassRole" + ], + "Effect": "Allow", + "Resource": "arn:aws:iam::*:role/GitLabRunner*" + } + ] +} +``` + +9. In the navigation pane choose **Roles** +10. Choose **Create role**. +11. In the **Use case** section select **EC2** and choose **Next**. +12. In the **Permissions policies** table find the following policies one-by-one and select each of them: + - `EKS-ReadAll` + - `IAM-PassRole` + - `AmazonS3FullAccess` + - `AmazonEC2FullAccess` + - `AmazonEC2ContainerRegistryFullAccess` + +{{% notice warning %}} +Note that here you are assigning quite broad permission policies to the IAM role to avoid creating specific custom policies, but in a real Production environment you should follow the least privilege principle. You can find the best practices in [AWS Blogs](https://aws.amazon.com/blogs/security/techniques-for-writing-least-privilege-iam-policies/). +{{% /notice %}} + +13. Make sure you have 5 policies selected and choose **Next**. +14. In the **Role name** field type **GitLabRunner** and choose **Create role**. + +### Deploy GitLab Runner Manager + +You will now configure a new GitLab Runner that will serve as a Runner Manager and using Docker Machine will create new EC2 Spot instances: the actual CI/CD jobs will be executed on them. You can use x86_64 architecture, but to additionally optimize the costs, we suggest that you run the instance on [AWS Graviton](https://aws.amazon.com/ec2/graviton/) processor (as there are no CI/CD jobs running on it, the architecture is not important). + +1. In the browser tab with AWS Console, type `EC2` in the search box at the top and open the service. +2. Choose **Instances** in the navigation pane. +3. Choose **Launch instances**. +4. In the field **Name** type `GitLabRunnerManager`. +5. In the **Architecture** dropdown of the **Application and OS Images (Amazon Machine Image)** pane select `64-bit (Arm)`. Leave the Operating System as **Amazon Linux**. +6. In the **Instance type** dropdown select `t4g.nano`. +7. In the **Key pair name** dropdown select `ee-default-keypair` or any other key you created previously if you run this lab in your own account. +8. In the **Network settings** pane choose **Edit** and then: + - In the **VPC** field select the VPC ID you saved from CloudFormation Output values in [**Workshop Preparation**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.html), it contains `GitLabSpotWorkshop VPC` in its name. + - In the **Security group name** field type `GitLabRunnerManager` +9. Expand the **Advanced details** and in the **IAM instance profile** dropdown select `GitLabRunner`. + +{{% notice warning %}} +In Production configuration it is better to separate the IAM role for the Runner Manager and the actual Runner to follow the least privilege principle. +{{% /notice %}} + +10. Leave the rest settings as default and choose **Launch instance**. + +![EC2 Console Screenshot: Launch an instnace](/images/gitlab-spot/AWSConsole-EC2LaunchInstance.png) + +### Configure GitLab Runner and Docker Machine +You will now configure the instance to serve as a Runner Manager by installing all the necessary tools into it. + +1. Connect to the instance by SSH: you can select it in the EC2 console and then choose **Connect**, select the **EC2 Instance Connect** tab and choose **Connect**. Alternatively, you can return to the browser tab with Cloud9 environment and connect to it using the command below, substituting the `` to the private IP address of the instance: + +``` +ssh -i ~/environment/ee-default-keypair.pem ec2-user@ +``` + +2. After connecting, install the GitLab Runner using the following commands: + +``` +curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash +export GITLAB_RUNNER_DISABLE_SKEL=true; sudo -E yum install gitlab-runner -y +``` + +3. Install Docker: + +``` +sudo yum update -y +sudo amazon-linux-extras install docker -y +sudo service docker start +sudo usermod -a -G docker ec2-user +``` + +4. Terminate the SSH session and then connect again. Verify that Docker is working by running: + +``` +docker info +``` + +5. Install Docker Machine: + +``` +base=https://github.com/docker/machine/releases/download/v0.16.2 \ +&& curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine \ +&& sudo mv /tmp/docker-machine /usr/local/bin/docker-machine \ +&& chmod +x /usr/local/bin/docker-machine +docker-machine version +``` + +### Configure security group for runners +You will now create a new security group that would allow the communication from the Runner Manager on ports 22 and 2376 (used by Docker Machine). + +{{%expand "Click to reveal detailed instructions" %}} +1. Return to the browser tab with EC2 console or open it again. +2. Choose **Security Groups** in the **Network & Security** section of the navigation pane. +3. Choose **Create security group**. +4. In the **Security group name** field type `GitLabRunner`. +5. In the **Description** field type `GitLab Runner Security Group`. +6. In the **VPC** field select the VPC ID you saved from CloudFormation Output values in [**Workshop Preparation**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.html), it contains `GitLabSpotWorkshop VPC` in its name. +6. Create two inbound rules by choosing **Add rule** in the **Inbound rules** pane: + - **Type** = `SSH`, **Source** = `Custom`, select the `GitLabRunnerManager` security group + - **Type** = `Custom TCP`, **Port range** = `2376`, **Source** = `Custom`, select the `GitLabRunnerManager` security group +7. Choose **Create security group**. +{{% /expand%}} + +### Configure runner +Finally, you will configure the runner and register it in GitLab. + +1. Return to the browser tab with GitLab. +2. In the **GitLab Spot Workshop** repository choose **Settings** > **CI/CD** in the navigation pane. +3. Expand the **Runners** section and save into a text file both GitLab URL and the registration token that are displayed on the screen: + +![GitLab Screenshot: Runners configuration](/images/gitlab-spot/GitLab-RunnersRegistration.png) + +3. Return to the browser tab with Cloud9. If you are connected via SSH to the Runner Manager in the terminal, create another terminal and run the following commands in it to get the AMI (Amazon Machine Image) ID to use for the runners, copy and save it: + +``` +TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 600") +REGION=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) +aws ssm get-parameters --names /aws/service/canonical/ubuntu/server/20.04/stable/current/amd64/hvm/ebs-gp2/ami-id --region $REGION --query "Parameters[0].Value" --output text +``` + +4. Return to the browser tab with SSH session with the Runner Manager (reconnect if it has been disconnected by timeout) and run the below command, substituting the values in the angle brackets with the required parameters (without angle brackets): + +``` +sudo gitlab-runner register \ + --non-interactive \ + --url "" \ + --registration-token "" \ + --executor "docker+machine" \ + --description "GitLab Spot Workshop Runner" \ + --docker-privileged \ + --docker-volumes "/var/run/docker.sock:/var/run/docker.sock" \ + --docker-image "docker:latest" \ + --docker-disable-cache="false" \ + --cache-type "s3" \ + --cache-path "/" \ + --cache-shared="true" \ + --cache-s3-server-address "s3.amazonaws.com" \ + --cache-s3-bucket-name "" \ + --cache-s3-bucket-location "" \ + --machine-idle-time 600 \ + --machine-machine-driver "amazonec2" \ + --machine-machine-name "gitlab-spot-workshop-%s" \ + --machine-machine-options "amazonec2-iam-instance-profile=GitLabRunner" \ + --machine-machine-options "amazonec2-region=" \ + --machine-machine-options "amazonec2-vpc-id=" \ + --machine-machine-options "amazonec2-subnet-id=" \ + --machine-machine-options "amazonec2-zone=" \ + --machine-machine-options "amazonec2-use-private-address=true" \ + --machine-machine-options "amazonec2-tags=runner-manager-name,aws-runner,gitlab,true,gitlab-runner-autoscale,true" \ + --machine-machine-options "amazonec2-security-group=GitLabRunner" \ + --machine-machine-options "amazonec2-request-spot-instance=true" \ + --machine-machine-options "amazonec2-instance-type=m5.xlarge" \ + --machine-machine-options "amazonec2-ami=" +``` + +Example: + +![GitLab Runner Screenshot: Runner manager registration](/images/gitlab-spot/GitLab-RunnerManagerRegistration.png) + +5. After successful registration, change the global `concurrent` parameter and restart the runner: + +``` +sudo sed -i 's/concurrent\s*=\s*1/concurrent = 10/' /etc/gitlab-runner/config.toml +sudo gitlab-runner restart +sudo gitlab-runner status +``` + +6. You can now exit the SSH session. +7. Return to the browser tab with GitLab and refresh the **CI/CD** page to make sure that your runner is now present in the **Runners** section: + +![GitLab Screenshot: Docker Machine runner available](/images/gitlab-spot/GitLab-DockerMachineRunnerAvailable.png) + +{{% notice tip %}} +One of the drawbacks of Docker Machine approach is that you can only specify one instance type and one subnet per Runner Manager. As such, it might happen that there is no spot capacity for it available and your CI/CD pipeline hangs running with the latest output in the job execution log staying at `Preparing the "docker+machine" executor`. If this happens, return to the EC2 console and choose **Spot Requests** in the navigation pane. Check if your requests are indeed not getting fulfilled, and if so, on the Runner Manager instance try changing the instance type or the subnet and availability zone in the `/etc/gitlab-runner/config.toml` file and restart the `gitlab-runner`. For a more permanent solution, please use auto-scaling groups as discussed in [**Lab 2: Configure GitLab runners on Spot instances**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2.html). +{{% /notice %}} + +You can now proceed to build your application in [**Lab 3: Building the demo app**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab3.html). \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/ap-southeast-1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/ap-southeast-1.md new file mode 100644 index 00000000..8cfd4d81 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/ap-southeast-1.md @@ -0,0 +1,8 @@ +--- +title: "Singapore" +chapter: false +disableToc: true +hidden: true +--- + +Deploy GitLab stack: https://ap-southeast-1.console.aws.amazon.com/cloudformation/home?region=ap-southeast-1#/stacks/create/review?templateURL=https://gl-public-templates.s3.amazonaws.com/cfn/v1.4.9-alpha14/easybutton-amazon-linux-2-docker-simple-scaling-spotonly.cf.yml&stackName=linux-docker-scaling-spotonly diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/eu-central-1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/eu-central-1.md new file mode 100644 index 00000000..31288421 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/eu-central-1.md @@ -0,0 +1,8 @@ +--- +title: "Frankfurt" +chapter: false +disableToc: true +hidden: true +--- + +Deploy GitLab stack: https://eu-central-1.console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/create/review?templateURL=https://gl-public-templates.s3.amazonaws.com/cfn/v1.4.9-alpha14/easybutton-amazon-linux-2-docker-simple-scaling-spotonly.cf.yml&stackName=linux-docker-scaling-spotonly \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/eu-west-1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/eu-west-1.md new file mode 100644 index 00000000..1bd930a4 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/eu-west-1.md @@ -0,0 +1,8 @@ +--- +title: "Ireland" +chapter: false +disableToc: true +hidden: true +--- + +Deploy GitLab stack: https://eu-west-1.console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/create/review?templateURL=https://gl-public-templates.s3.amazonaws.com/cfn/v1.4.9-alpha14/easybutton-amazon-linux-2-docker-simple-scaling-spotonly.cf.yml&stackName=linux-docker-scaling-spotonly \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-east-1.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-east-1.md new file mode 100644 index 00000000..f5d3be57 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-east-1.md @@ -0,0 +1,8 @@ +--- +title: "N.Virginia" +chapter: false +disableToc: true +hidden: true +--- + +Deploy GitLab stack: https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review?templateURL=https://gl-public-templates.s3.amazonaws.com/cfn/v1.4.9-alpha14/easybutton-amazon-linux-2-docker-simple-scaling-spotonly.cf.yml&stackName=linux-docker-scaling-spotonly \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-east-2.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-east-2.md new file mode 100644 index 00000000..3c734335 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-east-2.md @@ -0,0 +1,8 @@ +--- +title: "Ohio" +chapter: false +disableToc: true +hidden: true +--- + +Deploy GitLab stack: https://us-east-2.console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/create/review?templateURL=https://gl-public-templates.s3.amazonaws.com/cfn/v1.4.9-alpha14/easybutton-amazon-linux-2-docker-simple-scaling-spotonly.cf.yml&stackName=linux-docker-scaling-spotonly \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-west-2.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-west-2.md new file mode 100644 index 00000000..1ed6d0fa --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab2/gitlab-easybutton/us-west-2.md @@ -0,0 +1,8 @@ +--- +title: "Oregon" +chapter: false +disableToc: true +hidden: true +--- + +Deploy GitLab stack: https://us-west-2.console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/create/review?templateURL=https://gl-public-templates.s3.amazonaws.com/cfn/v1.4.9-alpha14/easybutton-amazon-linux-2-docker-simple-scaling-spotonly.cf.yml&stackName=linux-docker-scaling-spotonly \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab3.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab3.md new file mode 100644 index 00000000..e06b7c0e --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab3.md @@ -0,0 +1,38 @@ ++++ +title = "Lab 3: Building the demo app" +weight = 50 ++++ + +In this lab you will push the changes to your origin repository and verify that the pipeline has successfully finished both in GitLab and by checking the image in Amazon ECR. + +{{%expand "Click to reveal detailed instructions" %}} +1. Return to the browser tab with Cloud9 and execute the following command in the terminal. Specify `root` as the username and the same password you used in [**Lab 1: Create a GitLab repository**](lab1.html) to log in to GitLab: + +``` +git push -u origin main +``` + +2. Return to the browser tab with GitLab and in the navigation pane choose **CI/CD** > **Pipelines**. +3. Make sure that the CI/CD pipeline is successfully completed or wait until it does. If there were any issues, open the failed stage by clicking the corresponding circle and check the detailed execution log: + +![GitLab Screenshot: Build pipeline completed](/images/gitlab-spot/GitLab-BuildPipeline.png) + +4. Return to the browser tab with AWS Console. +5. Type `ECR` in the search box at the top and open the **Elastic Container Registry** service. +6. Open the **gitlab-spot-demo** repository and verify that it contains an image that has just been built in GitLab: + +![ECR Console Screenshot: Images](/images/gitlab-spot/AWSConsole-ECRImages.png) + +{{% /expand%}} + +You have successfully built the image and can now proceed to [**Lab 4: Deploying Amazon EKS on Spot instances**](lab4.html). + +### Challenges + +If this and previous labs seemed too easy, try completing the following challenges: + +**Challenge 1:** Configure shared runners for the whole GitLab CI/CD and not just the current repository. Create an additional repository and verify that your runners serve it too. + +**Challenge 2:** If you used the auto-scaling group approach, trigger auto-scaling of the instances to get more runners created (tip: by default, it is done by CPU load, so you can run a CPU load tool inside your build scripts to simulate it). + +**Challenge 3:** If you used the auto-scaling group approach, try modifying it to perform scaling by the number of the jobs instead of the CPU load (you will need to create a custom CloudWatch metric for this). \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab4.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab4.md new file mode 100644 index 00000000..0e264ce1 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab4.md @@ -0,0 +1,112 @@ ++++ +title = "Lab 4: Deploying Amazon EKS on Spot instances" +weight = 50 ++++ + +You will now deploy an Amazon EKS cluster in order to roll out your newly built application into it. In this lab you will use [Terraform by HashiCorp](https://www.terraform.io/) for this purpose. However, you can also do it using AWS CloudFormation, AWS CDK or eksctl. + +The Terraform files are located in `~/environment/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster` directory of your Cloud9 environment. + +{{%expand "Click to reveal detailed instructions" %}} +1. Return to the browser tab with Cloud9 and execute the following commands in the terminal to download and install `kubectl` that you will be using to work with the Kubernetes cluster: + +``` +cd ~/environment +sudo curl -sLo /usr/local/bin/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" +sudo chmod +x /usr/local/bin/kubectl +``` + +2. Switch to the directory with IaC templates, initialize the Terraform working directory, and apply the changes: + +``` +cd ~/environment/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster +terraform init +TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 600") +export TF_VAR_aws_region=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) +curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json +export TF_VAR_alb_policy=$(aws iam get-policy --policy-arn arn:aws:iam::$(aws sts get-caller-identity --output text --query Account):policy/AWSLoadBalancerControllerIAMPolicy --query Policy.Arn --output text 2>/dev/null || aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam-policy.json --query Policy.Arn --output text) +terraform apply +``` + +3. When asked for the parameters, enter the following values: + * **kubernetes_version**: the latest version of Kubernetes that you can find in [Amazon EKS documentation](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html): only major and minor version separated with a dot without patch release, for example, `1.22` + * **vpc_id**: the VPC ID you saved from CloudFormation Output values in [**Workshop Preparation**](/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.html) in the format `vpc-...` + +![Cloud9 Console Screenshot: Terraform variables](/images/gitlab-spot/Cloud9-TerraformVars.png) + +4. When asked if you want to perform the changes, check the list of resources to be created, type `yes`, and press Enter. It should take approximately 15 minutes to deploy the cluster. +5. After the process has finished, execute the following command to update the `kubeconfig`, using the information from Amazon EKS: + +``` +aws eks update-kubeconfig --region $TF_VAR_aws_region --name gitlab-spot-workshop +``` + +6. Execute the below commands to verify that you can reach Kubernetes API. The first should return all Kubernetes resources across the namespaces and the second should show 3 worker nodes: + +``` +kubectl get all -A +kubectl get nodes +``` +7. Execute the below command to install AWS Load Balancer Controller (it will be used to configure Application Load Balancer for your pods): + +``` +curl -sSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash +helm repo add eks https://aws.github.io/eks-charts +helm install aws-load-balancer-controller eks/aws-load-balancer-controller --set clusterName=gitlab-spot-workshop -n kube-system +``` + +8. Return to the browser tab with EC2 console or open it again and make sure that the worker nodes are using spot instances: you can either select each instance called `spot_group` one-by-one and check the value of the **Lifecycle** field in the description tab below or enable its display in the main table by choosing the cogwheel icon in the top-right corner, searching for `Instance lifecycle` in the **Attribute columns** field, enabling the toggle next to it, and choosing **Confirm**: + +![EC2 Console Screenshot: Instance list preferences](/images/gitlab-spot/AWSConsole-EC2Preferences.png) + +![EC2 Console Screenshot: Instance list with instance lifecycle](/images/gitlab-spot/AWSConsole-EC2InstancesLifecycle.png) + +{{% /expand%}} + +### Add GitLab role to Kubernetes RBAC +By default, the IAM user or role that created Amazon EKS cluster gets access to its Kubernetes API. However, as you have different roles assigned to the Cloud9 environment and the GitLab runners, you need to add the latter to Kubernetes Role Based Access Control (RBAC). + +You will do it by manually modifying Kubernetes ConfigMap called `aws-auth`. You could have done it directly in Terraform, but in this workshop we suggest that you do it manually to better understand the concepts. + +{{%expand "Click to reveal detailed instructions" %}} +1. Return to the browser tab with Cloud9 and in the terminal execute the following command, which will save the ConfigMap current manifest into `aws-auth.yaml` file: + +``` +cd ~/environment +kubectl get configmap -n kube-system aws-auth -o yaml > aws-auth.yaml +``` + +2. To generate the lines that you will add into the file, execute the following commands: + +``` +export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account) +cat << EoF + - rolearn: arn:aws:iam::${ACCOUNT_ID}:role/GitLabRunner + groups: + - system:masters + username: gitlab-runner +EoF +``` + +3. Copy the output of the last command, then in the file tree on the left open the file `gitlab-spot-workshop/aws-auth.yaml` by double-clicking it, and finally add the previous command's output that you copied before into `mapRoles` section. You should have something similar to the below screenshot: + +![Cloud9 Console Screenshot: aws-auth ConfigMap](/images/gitlab-spot/Cloud9-AWSAuth.png) + +4. Save the file, using **Ctrl + S** or **Cmd + S** depending on your Operating System, or choosing **File** > **Save**. Then close it. +5. Apply the Kubernetes manifest using the command below (you can ignore the warning about missing annotation): + +``` +kubectl apply -f aws-auth.yaml +``` + +{{% /expand%}} + +You are now ready for the final steps to deploy your demo application into the cluster in [**Lab 5: Installing the demo app into Amazon EKS**](lab5.html). + +### Challenge + +Instead of using Terraform try deploying the Amazon EKS cluster with eksctl. + +{{% notice tip %}} +You can find step-by-step instructions in the [**Containers with EKS**](/using_ec2_spot_instances_with_eks/020_eksctl.html) workshop, but make sure you modify them to use the VPC you created in this workshop. +{{% /notice %}} \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab5.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab5.md new file mode 100644 index 00000000..d05d0ef8 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/lab5.md @@ -0,0 +1,121 @@ ++++ +title = "Lab 5: Installing the demo app into Amazon EKS" +weight = 50 ++++ + +In this lab you will deploy the demo application you built earlier in the new Amazon EKS cluster deployed fully on spot instances. + +{{%expand "Click to reveal detailed instructions" %}} +1. In the Cloud9 file tree on the left open file `gitlab-spot-workshop/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/.gitlab-ci.yml` (if you don't see it, make sure you have enabled the hidden files in [**Workshop Preparation**](prep.html)). +2. Change the jobs `deploy_to_eks` and `test_on_eks` to the following ones: + +``` +deploy_to_eks: + stage: deploy + image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest + before_script: + - aws --version + - aws eks update-kubeconfig --region $REGION --name $K8S_CLUSTER_NAME + - apt-get install -y gettext # To get envsubst + - curl -sLo /usr/local/bin/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + - chmod +x /usr/local/bin/kubectl + script: + - envsubst < k8s_deploy.yaml > k8s_deploy_filled.yaml + - kubectl apply -f k8s_deploy_filled.yaml + - kubectl rollout status deploy/spot-demo + - kubectl get services/spot-demo -o wide + - kubectl get ingress spot-demo -o wide + - echo "SERVICE_ADDRESS=$(kubectl get ingress spot-demo -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')" >> deploy_to_eks.env + artifacts: + reports: + dotenv: deploy_to_eks.env + +test_on_eks: + stage: test + image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest + before_script: + - echo Verifying service on $SERVICE_ADDRESS + script: + - | + echo Waiting for the service to respond with 200 + serviceup=0 + + for i in {1..60} + do + export result=$(curl -s -o /dev/null -w "%{http_code}" http://$SERVICE_ADDRESS/info/) + + if [[ "$result" -eq 200 ]] + then + serviceup=1 + break + fi + + echo Load balancer not ready yet + sleep 10 + done + + if [[ "$serviceup" -eq 1 ]] + then + echo Service responded with 200 + else + echo Service not responded within the timeout + exit 1 + fi + + for i in {1..50} + do + echo -n "Test $i: " + export result=$(curl -s http://$SERVICE_ADDRESS/info/ | egrep 'lifecycle.*spot' | wc -l) + if [[ "$result" -eq 1 ]] + then + echo -e "\033[0;32mOK\033[0m" + else + echo -e "\033[0;31mNOT OK\033[0m" + exit 1 + fi + done + dependencies: + - deploy_to_eks +``` + +The file should look similar to the below screenshot: + +![Cloud9 Console Screenshot: GitLab CI/CD scripts](/images/gitlab-spot/Cloud9-GitLabCI.png) + +3. Save the file, using **Ctrl + S** or **Cmd + S** depending on your Operating System, or choosing **File** > **Save**. Then close it. +4. Create a new commit with the updated file and push it to the origin: + +``` +cd ~/environment/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/ +git add .gitlab-ci.yml +git commit -m "Added deployment to EKS" +git push +``` + +5. Return to the browser tab with GitLab and in the navigation pane choose **CI/CD** > **Pipelines**. +6. Make sure that the CI/CD pipeline is successfully completed or wait until it does. +7. You can click on the circle to see the job output. For example, for the right-most one it would show the testing result: + +![GitLab Screenshot: GitLab Testing Job output](/images/gitlab-spot/GitLab-TestingJob.png) + +8. Return to the Cloud9 tab and print the information about the new service: + +``` +echo http://$(kubectl get ingress spot-demo -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')/info/ +``` + +8. Open the output URL in a new browser tab and refresh the page several times to make sure that the requests reach pods on different worker nodes, all on spot instances: + +![Demo App Screenshot](/images/gitlab-spot/DemoApp.png) + +{{% /expand%}} + +You have deployed the demo application in Kubernetes cluster (created in Amazon EKS service) with all its worker nodes running on Amazon EC2 Spot instances. It is useful for executing tests in your CI/CD pipeline (though AWS customers run full Production clusters on spot instances too): for example, you can add new spot nodes into your cluster right from the pipeline and after finishing testing remove them. + +To view the current economy from using spot instances instead of on-demand ones perform the following steps: + +1. Return to the browser tab with EC2 console or open it again. +2. Choose **Spot Requests** in the **Instances** section of the navigation pane. +3. Choose **Savings summary**. + +You can now clean all the resources created during the workshop using the steps in [**Workshop Cleanup**](cleanup.html). \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.md b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.md new file mode 100644 index 00000000..bfbabb36 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/gitlab-spot/prep.md @@ -0,0 +1,121 @@ ++++ +title = "Workshop Preparation" +weight = 20 ++++ + +You should now have the CloudFormation stack with GitLab opened. If not, refer to [**Starting the workshop**](before.html) section to see the steps to get to that page. + +### Save GitLab access details + +Switch to the **Outputs** tab and save all the information in the table to a text file. You will need it in the later labs. + +![CloudFormation Console Screenshot: Stack outputs](/images/gitlab-spot/AWSConsole-CloudFormationStackOutput.png) + +### Create an AWS Cloud9 environment + +You can execute the steps of this workshop directly on your workstation, but then you will need to make sure that you have the command-line tools for Git, Terraform, kubectl and AWS CLI installed. Instead of that, to not change any local settings, we recommend to use [AWS Cloud9](https://aws.amazon.com/cloud9/): a cloud IDE where you can get access to the terminal and install all the required tools. + +{{% notice warning %}} +If you are running the workshop on your own, the Cloud9 workspace should be built by an IAM user with Administrator privileges, not the root account user. Please ensure you are logged in as an IAM user, not the root +account user. +{{% /notice %}} + +{{% notice info %}} +If you are at an AWS hosted event (such as re:Invent, Kubecon, Immersion Day, or any other event hosted by +an AWS employee) follow the instructions on the region that should be used to launch resources +{{% /notice %}} + +{{% notice tip %}} +Ad blockers, javascript disablers, and tracking blockers should be disabled for +the cloud9 domain, or connecting to the workspace might be impacted. +Cloud9 requires third-party-cookies. You can whitelist the [specific domains]( https://docs.aws.amazon.com/cloud9/latest/user-guide/troubleshooting.html#troubleshooting-env-loading). +{{% /notice %}} + +Launch Cloud9 in your closest region: + +{{< tabs name="Region" >}} + {{< tab name="N. Virginia" include="cloud9/us-east-1.md" />}} + {{< tab name="Oregon" include="cloud9/us-west-2.md" />}} + {{< tab name="Frankfurt" include="cloud9/eu-central-1.md" />}} + {{< tab name="Ireland" include="cloud9/eu-west-1.md" />}} + {{< tab name="Ohio" include="cloud9/us-east-2.md" />}} + {{< tab name="Singapore" include="cloud9/ap-southeast-1.md" />}} +{{< /tabs >}} + +1. Choose **Create environment**. +2. Name it `gitlab-spot-workshop` and choose **Next step**. +3. Expand **Network settings (advanced)** section and select the VPC from the Output parameters you saved above (should contain `GitLabSpotWorkshop VPC` in its name), the subnet can be any of the two: + +![Cloud9 Console Screenshot: Select VPC](/images/gitlab-spot/AWSConsole-CreateCloud9SelectVPC.png) + +4. Choose **Next step**. +5. Choose **Create environment**. +6. When the environment comes up, close all tabs inside it and open a new terminal by clicking **+** > **New Terminal**, you should see a screen like this: + +![Cloud9 Environment Screenshot: Initial view](/images/gitlab-spot/Cloud9-Initial.png) + +### Create an IAM role + +By default, Cloud9 uses AWS managed temporary credentials to make calls to AWS API from the terminal. Instead, you will create an IAM role and EC2 instance profile to ensure the correct Role Based Access Control (RBAC) permissions in Kubernetes cluster later on. + +1. Return to the browser tab with AWS Console (if you closed it, click the icon with the cloud and digit 9 in the top-left corner and then choose **Go To Your Dashboard**) +2. Type `IAM` in the search box at the top and open the service. +3. In the navigation pane choose **Roles** and then choose **Create role**. +4. In the **Use case** section select **EC2** and choose **Next**. +5. In the **Permissions policies** table find `AdministratorAccess` and mark the checkbox next to it, then choose **Next** + +![IAM Console Screenshot: AdministratorAccess permissions](/images/gitlab-spot/AWSConsole-IAMRolePermissions.png) + +6. In the **Role name** field type `gitlab-spot-workshop-admin` and choose **Create role** in the bottom of the screen. + +### Attach IAM role to EC2 instance + +Now, you will attach the new role to the EC2 instance used by your Cloud9 environment. + +1. Type `EC2` in the search box at the top and open the service. +2. In the navigation pane choose **Instances**. +3. You should see two instances in the list. Select the one with name starting with `aws-cloud9-`, then choose **Actions** > **Security** > **Modify IAM role**: + +![EC2 Console Screenshot: Modify the instance role](/images/gitlab-spot/AWSConsole-EC2Instances.png) + +4. In the **IAM role** dropdown select `gitlab-spot-workshop-admin` and choose **Save**. + +### Configure Cloud9 environment + +You will now finalize AWS Cloud9 environment configuration by disabling the AWS managed temporary credentials and download the required workshop files. + +1. Return to the browser tab with Cloud9 environment. +2. Open preferences tab by choosing the cogwheel icon at the top-right corner of the screen. Then choose **AWS Settings** in the navigation pane. +3. Disable **AWS managed temporary credentials** toggle: + +![Cloud9 Screenshot: Preferences](/images/gitlab-spot/Cloud9-Preferences.png) + +4. Close the **Preferences** tab and in the terminal tab, execute the following command to verify that you are using the correct role (in the output you should see `gitlab-spot-workshop-admin`): + +``` +aws sts get-caller-identity --query Arn +``` + +![Cloud9 Screenshot: Caller identity](/images/gitlab-spot/Cloud9-CallerIdentity.png) + +5. Execute the following commands in the terminal to copy all workshop files: + +``` +git clone https://github.com/awslabs/ec2-spot-workshops.git +cp -ar ec2-spot-workshops/workshops/amazon-ec2-spot-cicd-workshop/ . +rm -rf ec2-spot-workshops/ +``` + +6. Now you will upload the SSH key you saved in the previous section. Choose **File** > **Upload Local Files...**. +7. In the popup page choose **Select files** and select the file `ee-default-keypair.pem` that you downloaded previously. +8. Make sure the file appeared in the file tree on the left, close the popup page, and modify the file permissions by executing the following command in the terminal: + +``` +chmod 400 ~/environment/ee-default-keypair.pem +``` + +9. Finally, enable Cloud9 to show hidden files (you will need it to modify the scripts of GitLab CI/CD later). To do this choose the small cogwheel icon right above the file tree and choose **Show Hidden Files**: + +![Cloud9 Screenshot: Show hidden files](/images/gitlab-spot/Cloud9-ShowHiddenFiles.png) + +You are now ready to start the main labs of the workshop! Please proceed to [**Lab 1: Create a GitLab repository**](lab1.html). \ No newline at end of file diff --git a/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/_index.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/_index.md new file mode 100644 index 00000000..29ef7976 --- /dev/null +++ b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/_index.md @@ -0,0 +1,33 @@ +--- +title: "CI/CD and Test Workloads (Jenkins) with EC2 Spot Instances" +menuTitle: "Jenkins" +date: 2019-02-19T02:02:35 +weight: 10 +pre: "" +--- + +## Overview +During this workshop, you'll get hands-on with Amazon EC2 Spot and discover architectural best practices through the lens of DevOps and CI/CD. You'll deploy Jenkins build agents and test environments on Spot instances at a fraction of the cost of on-demand instances. You'll also implement mechanisms to ensure that your CI/CD tooling recovers from spot market events by decoupling application state from your compute resources. Finally, you'll migrate your CI/CD environment to a containered environment to eke out maximum performance and cost efficiency. In addition to covering the ins and outs of Spot, we'll share some of the Spot-based mechanisms used by customers to reduce the cost of their test and production workloads. + +## Workshop Details +This workshop will be broken down into a series of labs that flow on from each other (that is, you must complete each lab in order before proceeding with the next). The lab exercises that will be covered are: + +* Workshop preparation: Deploy pre-requisite resources through Amazon CloudFormation; +* Lab 1: Reduce the cost of builds using Amazon EC2 Spot Fleet; +* Lab 2: Deploy testing environments using Amazon EC2 Spot, Amazon CloudFormation & Amazon EC2 Launch Templates; +* Lab 3: Externalize state data to add resiliency and reduce cost for your CI/CD tooling; +* Lab 4: Using containers backed by Auto Scaling Groups comprised of both on-demand and Spot instances; +* Workshop clean up. + +As a reminder, you should have a laptop device (Windows/OSX/Linux are supported - tablets are not appropriate) with the current version of Google Chrome or Mozilla Firefox installed. You should also have a clean AWS account, with **AdministratorAccess** policy-level access. + +This workshop should take between two and three hours to complete, depending on your proficiency with the AWS services being featured. + +#### Additional considerations when running this workshop in a corporate IT environment +If you are running this workshop from a corporate IT environment, contact your Systems Administrator to ensure that you will be able to establish outbound Secure Shell (SSH) connections to an Internet host: + +* If you cannot establish SSH connections to Internet hosts (and do not have a suitable workaround), you will not be able to complete Labs 3 & 4; +* If you can establish SSH connections to Internet hosts, obtain from your Systems Administrator the source IP address CIDR block that connections will be established from. + +If you access the Internet through a transparent proxy server running in your corporate IT environment and this proxy server uses a different source address than where SSH connections come from, additional configuration of AWS Security Groups will need to be carried out. The lab guide will indicate the configuration steps required when appropriate. + diff --git a/content/amazon-ec2-spot-cicd-workshop/clea.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/clea.md similarity index 100% rename from content/amazon-ec2-spot-cicd-workshop/clea.md rename to content/amazon-ec2-spot-cicd-workshop/jenkins-spot/clea.md diff --git a/content/amazon-ec2-spot-cicd-workshop/lab1.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab1.md similarity index 99% rename from content/amazon-ec2-spot-cicd-workshop/lab1.md rename to content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab1.md index 13f88e32..b2f1e3c8 100644 --- a/content/amazon-ec2-spot-cicd-workshop/lab1.md +++ b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab1.md @@ -95,4 +95,4 @@ Now it’s time to test out how Jenkins handles pushing builds to spot instances 4. After a period of around a five minutes after your builds have completed, one of the Spot instances should be terminated by the plugin - there's no need to wait for this to happen (take our word for it, but you can verify this later). ## PROCEED TO LAB 2 -Once you've verified that builds are succeeding and that your Spot Fleet is capable of scaling out to handle queued build jobs, you may proceed with [Lab 2](/amazon-ec2-spot-cicd-workshop/lab2.html). +Once you've verified that builds are succeeding and that your Spot Fleet is capable of scaling out to handle queued build jobs, you may proceed with [Lab 2](/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab2.html). diff --git a/content/amazon-ec2-spot-cicd-workshop/lab2/_index.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab2/_index.md similarity index 99% rename from content/amazon-ec2-spot-cicd-workshop/lab2/_index.md rename to content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab2/_index.md index f84e1da7..a5e5484c 100644 --- a/content/amazon-ec2-spot-cicd-workshop/lab2/_index.md +++ b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab2/_index.md @@ -102,4 +102,4 @@ Once the deploy stage has been completed successfully: Once you've verified that that the Game of Life web application loads, return to Jenkins and click on the **Test** pipeline stage and click on **Proceed** to get the pipeline to process the Terminate stage. After this final stage has executed, go back to the CloudFormation console to verify that the GameOfLife stack is being deleted. ## PROCEED TO LAB 3 -Once your test environment has been terminated, you may proceed with [Lab 3](/amazon-ec2-spot-cicd-workshop/lab3.html). +Once your test environment has been terminated, you may proceed with [Lab 3](/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab3.html). diff --git a/content/amazon-ec2-spot-cicd-workshop/lab2/clfn.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab2/clfn.md similarity index 100% rename from content/amazon-ec2-spot-cicd-workshop/lab2/clfn.md rename to content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab2/clfn.md diff --git a/content/amazon-ec2-spot-cicd-workshop/lab2/lamb.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab2/lamb.md similarity index 100% rename from content/amazon-ec2-spot-cicd-workshop/lab2/lamb.md rename to content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab2/lamb.md diff --git a/content/amazon-ec2-spot-cicd-workshop/lab3.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab3.md similarity index 99% rename from content/amazon-ec2-spot-cicd-workshop/lab3.md rename to content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab3.md index 1bab0f1a..c51b4656 100644 --- a/content/amazon-ec2-spot-cicd-workshop/lab3.md +++ b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab3.md @@ -86,4 +86,4 @@ Once you've verified that your Spot Fleet is self-healing, you no longer have an {{% /expand%}} ## PROCEED TO LAB 4 -Once your on-demand Jenkins instance has been terminated, you may proceed with [Lab 4](/amazon-ec2-spot-cicd-workshop/lab4.html). +Once your on-demand Jenkins instance has been terminated, you may proceed with [Lab 4](/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab4.html). diff --git a/content/amazon-ec2-spot-cicd-workshop/lab4.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab4.md similarity index 99% rename from content/amazon-ec2-spot-cicd-workshop/lab4.md rename to content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab4.md index 32bccd8e..d7a6fbac 100644 --- a/content/amazon-ec2-spot-cicd-workshop/lab4.md +++ b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab4.md @@ -152,4 +152,4 @@ As things stand now, your projects in Jenkins won't be able to be built - you've {{% /expand%}} ## PROCEED TO WORKSHOP CLEANUP -Once your Jenkins infrastructure is completely running in your ECS cluster, you've completed all of the labs in this workshop. Congratulations! You may now proceed with the [Workshop Cleanup](/amazon-ec2-spot-cicd-workshop/clea.html). +Once your Jenkins infrastructure is completely running in your ECS cluster, you've completed all of the labs in this workshop. Congratulations! You may now proceed with the [Workshop Cleanup](/amazon-ec2-spot-cicd-workshop/jenkins-spot/clea.html). diff --git a/content/amazon-ec2-spot-cicd-workshop/prep.md b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/prep.md similarity index 99% rename from content/amazon-ec2-spot-cicd-workshop/prep.md rename to content/amazon-ec2-spot-cicd-workshop/jenkins-spot/prep.md index aba6a140..85c91c02 100644 --- a/content/amazon-ec2-spot-cicd-workshop/prep.md +++ b/content/amazon-ec2-spot-cicd-workshop/jenkins-spot/prep.md @@ -41,4 +41,4 @@ Be sure to give it a stack name of **SpotCICDWorkshop** and ensure that you supp The stack should take around five minutes to deploy. ## PROCEED TO LAB 1 -Once the CloudFormation is in the process of being deployed, you've completed all of the preparation required to start the workshop, you may proceed with [Lab 1](/amazon-ec2-spot-cicd-workshop/lab1.html). +Once the CloudFormation is in the process of being deployed, you've completed all of the preparation required to start the workshop, you may proceed with [Lab 1](/amazon-ec2-spot-cicd-workshop/jenkins-spot/lab1.html). diff --git a/static/images/gitlab-spot/AWSConsole-CloudFormationGitLabRunnersStack.png b/static/images/gitlab-spot/AWSConsole-CloudFormationGitLabRunnersStack.png new file mode 100644 index 00000000..fbf6d1b9 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-CloudFormationGitLabRunnersStack.png differ diff --git a/static/images/gitlab-spot/AWSConsole-CloudFormationNestedStack.png b/static/images/gitlab-spot/AWSConsole-CloudFormationNestedStack.png new file mode 100644 index 00000000..9a6e9830 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-CloudFormationNestedStack.png differ diff --git a/static/images/gitlab-spot/AWSConsole-CloudFormationSearch.png b/static/images/gitlab-spot/AWSConsole-CloudFormationSearch.png new file mode 100644 index 00000000..acf053ab Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-CloudFormationSearch.png differ diff --git a/static/images/gitlab-spot/AWSConsole-CloudFormationStackOutput.png b/static/images/gitlab-spot/AWSConsole-CloudFormationStackOutput.png new file mode 100644 index 00000000..d1a79054 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-CloudFormationStackOutput.png differ diff --git a/static/images/gitlab-spot/AWSConsole-CreateCloud9SelectVPC.png b/static/images/gitlab-spot/AWSConsole-CreateCloud9SelectVPC.png new file mode 100644 index 00000000..6f8f1b37 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-CreateCloud9SelectVPC.png differ diff --git a/static/images/gitlab-spot/AWSConsole-EC2Instances.png b/static/images/gitlab-spot/AWSConsole-EC2Instances.png new file mode 100644 index 00000000..fd124f5a Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-EC2Instances.png differ diff --git a/static/images/gitlab-spot/AWSConsole-EC2InstancesLifecycle.png b/static/images/gitlab-spot/AWSConsole-EC2InstancesLifecycle.png new file mode 100644 index 00000000..b637f864 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-EC2InstancesLifecycle.png differ diff --git a/static/images/gitlab-spot/AWSConsole-EC2LaunchInstance.png b/static/images/gitlab-spot/AWSConsole-EC2LaunchInstance.png new file mode 100644 index 00000000..5c33d346 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-EC2LaunchInstance.png differ diff --git a/static/images/gitlab-spot/AWSConsole-EC2Preferences.png b/static/images/gitlab-spot/AWSConsole-EC2Preferences.png new file mode 100644 index 00000000..c09d36b4 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-EC2Preferences.png differ diff --git a/static/images/gitlab-spot/AWSConsole-EC2RunnerLifecycle.png b/static/images/gitlab-spot/AWSConsole-EC2RunnerLifecycle.png new file mode 100644 index 00000000..b4ba6676 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-EC2RunnerLifecycle.png differ diff --git a/static/images/gitlab-spot/AWSConsole-ECRImages.png b/static/images/gitlab-spot/AWSConsole-ECRImages.png new file mode 100644 index 00000000..0466cdde Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-ECRImages.png differ diff --git a/static/images/gitlab-spot/AWSConsole-IAMCreatePolicy.png b/static/images/gitlab-spot/AWSConsole-IAMCreatePolicy.png new file mode 100644 index 00000000..6051bdeb Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-IAMCreatePolicy.png differ diff --git a/static/images/gitlab-spot/AWSConsole-IAMRolePermissions.png b/static/images/gitlab-spot/AWSConsole-IAMRolePermissions.png new file mode 100644 index 00000000..aa6b0013 Binary files /dev/null and b/static/images/gitlab-spot/AWSConsole-IAMRolePermissions.png differ diff --git a/static/images/gitlab-spot/Cloud9-AWSAuth.png b/static/images/gitlab-spot/Cloud9-AWSAuth.png new file mode 100644 index 00000000..1d1dc546 Binary files /dev/null and b/static/images/gitlab-spot/Cloud9-AWSAuth.png differ diff --git a/static/images/gitlab-spot/Cloud9-CallerIdentity.png b/static/images/gitlab-spot/Cloud9-CallerIdentity.png new file mode 100644 index 00000000..176ed0c7 Binary files /dev/null and b/static/images/gitlab-spot/Cloud9-CallerIdentity.png differ diff --git a/static/images/gitlab-spot/Cloud9-GitLabCI.png b/static/images/gitlab-spot/Cloud9-GitLabCI.png new file mode 100644 index 00000000..68cc9e4d Binary files /dev/null and b/static/images/gitlab-spot/Cloud9-GitLabCI.png differ diff --git a/static/images/gitlab-spot/Cloud9-Initial.png b/static/images/gitlab-spot/Cloud9-Initial.png new file mode 100644 index 00000000..a28ed1ec Binary files /dev/null and b/static/images/gitlab-spot/Cloud9-Initial.png differ diff --git a/static/images/gitlab-spot/Cloud9-Preferences.png b/static/images/gitlab-spot/Cloud9-Preferences.png new file mode 100644 index 00000000..85f5cf32 Binary files /dev/null and b/static/images/gitlab-spot/Cloud9-Preferences.png differ diff --git a/static/images/gitlab-spot/Cloud9-ShowHiddenFiles.png b/static/images/gitlab-spot/Cloud9-ShowHiddenFiles.png new file mode 100644 index 00000000..91b8ef7a Binary files /dev/null and b/static/images/gitlab-spot/Cloud9-ShowHiddenFiles.png differ diff --git a/static/images/gitlab-spot/Cloud9-TerraformVars.png b/static/images/gitlab-spot/Cloud9-TerraformVars.png new file mode 100644 index 00000000..78a2c3ec Binary files /dev/null and b/static/images/gitlab-spot/Cloud9-TerraformVars.png differ diff --git a/static/images/gitlab-spot/DemoApp.png b/static/images/gitlab-spot/DemoApp.png new file mode 100644 index 00000000..d875c718 Binary files /dev/null and b/static/images/gitlab-spot/DemoApp.png differ diff --git a/static/images/gitlab-spot/EE-SSHKey.png b/static/images/gitlab-spot/EE-SSHKey.png new file mode 100644 index 00000000..c975018f Binary files /dev/null and b/static/images/gitlab-spot/EE-SSHKey.png differ diff --git a/static/images/gitlab-spot/EE-SignInMethod.png b/static/images/gitlab-spot/EE-SignInMethod.png new file mode 100644 index 00000000..6edfc009 Binary files /dev/null and b/static/images/gitlab-spot/EE-SignInMethod.png differ diff --git a/static/images/gitlab-spot/GitLab-BuildPipeline.png b/static/images/gitlab-spot/GitLab-BuildPipeline.png new file mode 100644 index 00000000..a4d93f5c Binary files /dev/null and b/static/images/gitlab-spot/GitLab-BuildPipeline.png differ diff --git a/static/images/gitlab-spot/GitLab-CreateBlankProject.png b/static/images/gitlab-spot/GitLab-CreateBlankProject.png new file mode 100644 index 00000000..cc1ba2db Binary files /dev/null and b/static/images/gitlab-spot/GitLab-CreateBlankProject.png differ diff --git a/static/images/gitlab-spot/GitLab-DockerMachineRunnerAvailable.png b/static/images/gitlab-spot/GitLab-DockerMachineRunnerAvailable.png new file mode 100644 index 00000000..40abeb9a Binary files /dev/null and b/static/images/gitlab-spot/GitLab-DockerMachineRunnerAvailable.png differ diff --git a/static/images/gitlab-spot/GitLab-RunnerAvailable.png b/static/images/gitlab-spot/GitLab-RunnerAvailable.png new file mode 100644 index 00000000..f2f8bc6e Binary files /dev/null and b/static/images/gitlab-spot/GitLab-RunnerAvailable.png differ diff --git a/static/images/gitlab-spot/GitLab-RunnerManagerRegistration.png b/static/images/gitlab-spot/GitLab-RunnerManagerRegistration.png new file mode 100644 index 00000000..4f03b4d6 Binary files /dev/null and b/static/images/gitlab-spot/GitLab-RunnerManagerRegistration.png differ diff --git a/static/images/gitlab-spot/GitLab-RunnersRegistration.png b/static/images/gitlab-spot/GitLab-RunnersRegistration.png new file mode 100644 index 00000000..cdbd8000 Binary files /dev/null and b/static/images/gitlab-spot/GitLab-RunnersRegistration.png differ diff --git a/static/images/gitlab-spot/GitLab-TestingJob.png b/static/images/gitlab-spot/GitLab-TestingJob.png new file mode 100644 index 00000000..bc21fbc8 Binary files /dev/null and b/static/images/gitlab-spot/GitLab-TestingJob.png differ diff --git a/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/Dockerfile b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/Dockerfile new file mode 100644 index 00000000..0c0c6a70 --- /dev/null +++ b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.7-alpine + +RUN mkdir /app +WORKDIR /app +ADD . /app/ + +RUN pip install -r requirements.txt + +EXPOSE 5000 +CMD ["python", "/app/app.py"] \ No newline at end of file diff --git a/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/app.py b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/app.py new file mode 100644 index 00000000..8f1c9c7b --- /dev/null +++ b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/app.py @@ -0,0 +1,56 @@ +import platform +import requests +import socket + +from flask import Flask, request + +app = Flask(__name__) + +@app.route('/info/') +def info(): + result = dict() + + result['hostname'] = socket.gethostname() + result['platform'] = platform.platform() + + try: + headers = {'X-aws-ec2-metadata-token-ttl-seconds': '60'} + req = requests.put('http://169.254.169.254/latest/api/token', headers=headers, timeout=0.3) + if req.status_code == 200: + token = req.text + else: + return result + except: + result['instance-hostname'] = 'undefined' + + headers_get = {'X-aws-ec2-metadata-token': token} + try: + req = requests.get('http://169.254.169.254/latest/meta-data/hostname', headers=headers_get, timeout=0.3) + if req.status_code == 200: + result['instance-hostname'] = req.text + else: + result['instance-hostname'] = 'undefined' + except: + result['instance-hostname'] = 'undefined' + + try: + req = requests.get('http://169.254.169.254/latest/meta-data/instance-id', headers=headers_get, timeout=0.3) + if req.status_code == 200: + result['instance-id'] = req.text + else: + result['instance-id'] = 'undefined' + except: + result['instance-id'] = 'undefined' + + try: + req = requests.get('http://169.254.169.254/latest/meta-data/instance-life-cycle', headers=headers_get, timeout=0.3) + if req.status_code == 200: + result['lifecycle'] = req.text + else: + result['lifecycle'] = 'undefined' + except: + result['lifecycle'] = 'undefined' + + return result + +app.run(debug=True, host='0.0.0.0') \ No newline at end of file diff --git a/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/k8s_deploy.yaml b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/k8s_deploy.yaml new file mode 100644 index 00000000..e0ed39cd --- /dev/null +++ b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/k8s_deploy.yaml @@ -0,0 +1,54 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: spot-demo +spec: + replicas: 3 + selector: + matchLabels: + app: spot-demo + template: + metadata: + labels: + app: spot-demo + spec: + containers: + - name: spot-demo + image: "${ECR_REGISTRY}/${IMAGE_TAG}" + imagePullPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: spot-demo + labels: + app: spot-demo +spec: + ports: + - protocol: TCP + port: 80 + targetPort: 5000 + type: NodePort + selector: + app: spot-demo +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: spot-demo + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/healthcheck-path: /info/ +spec: + ingressClassName: alb + rules: + - http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: spot-demo + port: + number: 80 \ No newline at end of file diff --git a/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/requirements.txt b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/requirements.txt new file mode 100644 index 00000000..c521ff87 --- /dev/null +++ b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/requirements.txt @@ -0,0 +1,3 @@ +Flask +Flask-RESTful +requests \ No newline at end of file diff --git a/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/template-gitlab-ci.yml b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/template-gitlab-ci.yml new file mode 100644 index 00000000..99b4721a --- /dev/null +++ b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/demo-app/template-gitlab-ci.yml @@ -0,0 +1,42 @@ +variables: + ECR_REGISTRY: ${ECR_ADDRESS} + IMAGE_TAG: gitlab-spot-demo:$CI_COMMIT_SHA + REGION: ${AWS_REGION} + K8S_CLUSTER_NAME: gitlab-spot-workshop + DOCKER_DRIVER: overlay2 + DOCKER_TLS_CERTDIR: "" + +stages: +- build +- deploy +- test + +build_image: + stage: build + image: docker:20.10.6 + before_script: + - docker info + - apk add --no-cache curl python3 py3-pip + - | + export TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 600") + - | + curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/hostname + - | + curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region + - pip install awscli + - aws --version + - aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $ECR_REGISTRY + script: + - docker build -t $IMAGE_TAG . + - docker tag $IMAGE_TAG $ECR_REGISTRY/$IMAGE_TAG + - docker push $ECR_REGISTRY/$IMAGE_TAG + +deploy_to_eks: + stage: deploy + script: + - echo "Ok!" + +test_on_eks: + stage: test + script: + - echo "Ok!" \ No newline at end of file diff --git a/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster/main.tf b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster/main.tf new file mode 100644 index 00000000..8e70d119 --- /dev/null +++ b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster/main.tf @@ -0,0 +1,100 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.12.1" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.11.0" + } + } +} + +provider "aws" { + region = var.aws_region +} + +locals { + cluster_name = "gitlab-spot-workshop" +} + +module "eks" { + source = "terraform-aws-modules/eks/aws" + version = "18.20.5" + cluster_name = local.cluster_name + cluster_version = var.kubernetes_version + subnet_ids = data.aws_subnets.eks_subnets.ids + + tags = { + Project = "GitLabSpotWorkshop" + } + + vpc_id = var.vpc_id + + eks_managed_node_group_defaults = { + ami_type = "AL2_x86_64" + disk_size = 40 + } + + node_security_group_additional_rules = { + webhook_ingress = { + description = "Allow cluster to call webhooks" + protocol = "tcp" + from_port = 9443 + to_port = 9443 + type = "ingress" + source_cluster_security_group = true + } + all_ingress_self = { + description = "Allow nodes in the cluster to communicate with each other" + protocol = "-1" + from_port = 0 + to_port = 0 + type = "ingress" + self = true + } + all_egress_self = { + description = "Allow nodes in the cluster to communicate with each other" + protocol = "-1" + from_port = 0 + to_port = 0 + type = "egress" + self = true + } + } + + eks_managed_node_groups = { + spot_group = { + desired_size = 3 + max_size = 5 + min_size = 1 + + instance_types = ["m4.large", "m5.large", "m5a.large", "m6i.large"] + capacity_type = "SPOT" + + iam_role_additional_policies = [var.alb_policy] + } + } +} + +data "aws_subnets" "eks_subnets" { + filter { + name = "vpc-id" + values = [var.vpc_id] + } +} + +data "aws_eks_cluster" "cluster" { + name = module.eks.cluster_id +} + +data "aws_eks_cluster_auth" "cluster" { + name = module.eks.cluster_id +} + +provider "kubernetes" { + host = data.aws_eks_cluster.cluster.endpoint + cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data) + token = data.aws_eks_cluster_auth.cluster.token +} diff --git a/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster/variables.tf b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster/variables.tf new file mode 100644 index 00000000..fe7e7e98 --- /dev/null +++ b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/eks-cluster/variables.tf @@ -0,0 +1,19 @@ +variable "alb_policy" { + type = string + description = "IAM policy for AWS Load Balancer Controller" +} + +variable "aws_region" { + type = string + description = "AWS region" +} + +variable "kubernetes_version" { + type = string + description = "Kubernetes version for the cluster" +} + +variable "vpc_id" { + type = string + description = "VPC ID to create the cluster" +} \ No newline at end of file diff --git a/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/gitlab-deploy.yml b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/gitlab-deploy.yml new file mode 100644 index 00000000..9e90357d --- /dev/null +++ b/workshops/amazon-ec2-spot-cicd-workshop/gitlab-spot/gitlab-deploy.yml @@ -0,0 +1,367 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: GitLab Spot Workshop + +Parameters: + SSHKeyName: + Description: Name of the EC2 key for GitLab + Type: 'AWS::EC2::KeyPair::KeyName' + AmiId: + Description: Do not change + Type: 'AWS::SSM::Parameter::Value' + Default: '/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id' + VpcCIDR: + Description: CIDR for the VPC + Type: String + Default: 10.0.0.0/16 + Subnet1CIDR: + Description: CIDR for the first public subnet + Type: String + Default: 10.0.10.0/24 + Subnet2CIDR: + Description: CIDR for the second public subnet + Type: String + Default: 10.0.20.0/24 + EnvironmentName: + Description: Project name for the tags + Type: String + Default: GitLabSpotWorkshop + +Resources: + VPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: !Ref VpcCIDR + EnableDnsSupport: true + EnableDnsHostnames: true + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} VPC + - Key: Project + Value: !Ref EnvironmentName + + InternetGateway: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Internet Gateway + - Key: Project + Value: !Ref EnvironmentName + + InternetGatewayAttachment: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref InternetGateway + VpcId: !Ref VPC + + Subnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 0, !GetAZs '' ] + CidrBlock: !Ref Subnet1CIDR + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Subnet 1 + - Key: Project + Value: !Ref EnvironmentName + - Key: kubernetes.io/cluster/gitlab-spot-workshop + Value: shared + - Key: kubernetes.io/role/elb + Value: 1 + + Subnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 1, !GetAZs '' ] + CidrBlock: !Ref Subnet2CIDR + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Subnet 2 + - Key: Project + Value: !Ref EnvironmentName + - Key: kubernetes.io/cluster/gitlab-spot-workshop + Value: shared + - Key: kubernetes.io/role/elb + Value: 1 + + PublicRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Public Route Table + - Key: Project + Value: !Ref EnvironmentName + + DefaultPublicRoute: + Type: AWS::EC2::Route + DependsOn: InternetGatewayAttachment + Properties: + RouteTableId: !Ref PublicRouteTable + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref InternetGateway + + Subnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref Subnet1 + + Subnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref Subnet2 + + EC2SecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: SSH and HTTP + VpcId: + Ref: VPC + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 22 + ToPort: 22 + CidrIp: !Ref VpcCIDR + - IpProtocol: tcp + FromPort: 80 + ToPort: 80 + SourceSecurityGroupId: + Ref: ELBSecurityGroup + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} EC2 Security Group + - Key: Project + Value: !Ref EnvironmentName + + ELBSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: HTTP only + VpcId: + Ref: VPC + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 80 + ToPort: 80 + CidrIp: 0.0.0.0/0 + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} ELB Security Group + - Key: Project + Value: !Ref EnvironmentName + + LambdaExecutionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - sts:AssumeRole + Policies: + - + PolicyName: allowLambdaLogging + PolicyDocument: + Version: "2012-10-17" + Statement: + - + Effect: "Allow" + Action: + - "logs:*" + Resource: "*" + + RandomStringLambdaFunction: + Type: AWS::Lambda::Function + Properties: + Architectures: + - arm64 + Code: + ZipFile: | + import json + import cfnresponse + import random + import string + + def handler(event, context): + length = int(event["ResourceProperties"]["Length"]) + + responseData = {} + responseData["RandomString"] = "".join(random.choices(string.ascii_letters + string.digits, k=length)) + + cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData) + Handler: index.handler + Runtime: python3.8 + Role: !GetAtt LambdaExecutionRole.Arn + MemorySize: 128 + Timeout: 3 + + GitLabPassword: + Type: AWS::CloudFormation::CustomResource + Properties: + Length: 16 + ServiceToken: !GetAtt RandomStringLambdaFunction.Arn + + GitLabInstance: + Type: AWS::EC2::Instance + DependsOn: CloudFrontDistribution + Properties: + ImageId: !Ref AmiId + InstanceType: m5.xlarge + KeyName: !Ref SSHKeyName + NetworkInterfaces: + - AssociatePublicIpAddress: true + DeviceIndex: 0 + GroupSet: + - !Ref EC2SecurityGroup + SubnetId: !Ref Subnet1 + UserData: + Fn::Base64: !Sub | + #!/bin/bash -xe + apt-get update + apt-get install -y curl openssh-server ca-certificates tzdata perl python3-setuptools + curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | bash + GITLAB_ROOT_EMAIL="test@workshop.tld" GITLAB_ROOT_PASSWORD="${GitLabPassword.RandomString}" EXTERNAL_URL="http://${CloudFrontDistribution.DomainName}" apt-get install gitlab-ee + sed -i 's|http://${CloudFrontDistribution.DomainName}|https://${CloudFrontDistribution.DomainName}|' /etc/gitlab/gitlab.rb + echo "letsencrypt['enable'] = false" >> /etc/gitlab/gitlab.rb + echo "nginx['listen_port'] = 80" >> /etc/gitlab/gitlab.rb + echo "nginx['listen_https'] = false" >> /etc/gitlab/gitlab.rb + gitlab-ctl reconfigure + gitlab-rails runner "ApplicationSetting.last.update_attribute(:signup_enabled, false)" + wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + python3 /usr/lib/python3/dist-packages/easy_install.py --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz + /opt/aws/bin/cfn-signal \ + -e $? \ + --stack ${AWS::StackName} \ + --resource GitLabInstance \ + --region ${AWS::Region} + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} GitLab + - Key: Project + Value: !Ref EnvironmentName + CreationPolicy: + ResourceSignal: + Count: 1 + Timeout: "PT45M" + + EC2TargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + Name: GitLab-Target-Group + Port: 80 + Protocol: HTTP + Targets: + - Id: !Ref GitLabInstance + Port: 80 + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} GitLab Target Group + - Key: Project + Value: !Ref EnvironmentName + + ALBListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: + Ref: EC2TargetGroup + LoadBalancerArn: + Ref: ApplicationLoadBalancer + Port: 80 + Protocol: HTTP + + ApplicationLoadBalancer: + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + Properties: + Scheme: internet-facing + Subnets: + - Ref: Subnet1 + - Ref: Subnet2 + SecurityGroups: + - Ref: ELBSecurityGroup + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Load Balancer + - Key: Project + Value: !Ref EnvironmentName + + CloudFrontDistribution: + Type: AWS::CloudFront::Distribution + Properties: + DistributionConfig: + Origins: + - DomainName: !GetAtt ApplicationLoadBalancer.DNSName + Id: GitLabOrigin + CustomOriginConfig: + HTTPPort: 80 + OriginProtocolPolicy: http-only + Enabled: true + DefaultCacheBehavior: + TargetOriginId: GitLabOrigin + AllowedMethods: + - DELETE + - GET + - HEAD + - OPTIONS + - PATCH + - POST + - PUT + CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad + OriginRequestPolicyId: 216adef6-5c7f-47e4-b989-5492eafa07d3 + ViewerProtocolPolicy: redirect-to-https + ViewerCertificate: + CloudFrontDefaultCertificate: true + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} CloudFront Distribution + - Key: Project + Value: !Ref EnvironmentName + + DemoRepo: + Type: AWS::ECR::Repository + Properties: + RepositoryName: gitlab-spot-demo + Tags: + - Key: Project + Value: !Ref EnvironmentName + + GitLabCacheBucket: + Type: AWS::S3::Bucket + +Outputs: + VPC: + Description: The VPC with GitLab instance + Value: !Ref VPC + + Subnet1: + Description: The subnet with GitLab instance + Value: !Ref Subnet1 + + Subnet1Zone: + Description: Availability zone of subnet 1 + Value: !GetAtt Subnet1.AvailabilityZone + + GitLabURL: + Description: URL to GitLab installation + Value: !Sub https://${CloudFrontDistribution.DomainName} + + GitLabPassword: + Description: GitLab access credentials + Value: !GetAtt GitLabPassword.RandomString + + GitLabCacheBucket: + Description: Cache for GitLab runners + Value: !Ref GitLabCacheBucket \ No newline at end of file