# GitHub

## Application Pipeline

**Technical details for server admin of the Application workflow:**

{% hint style="info" %}
Local Machine ( Development ) -> GitHub --> GitHub Actions --> Docker Hub --> AWS ECR --> AWS EC2
{% endhint %}

<figure><img src="/files/qgqwnKmXagUhHJMlygmA" alt=""><figcaption><p>System Architecture Diagram includes Cloudformation flow</p></figcaption></figure>

### Fail-over scenarios

<figure><img src="/files/D3y6uoicphip60k3LWWm" alt=""><figcaption><p>Fail over Or Migration scenarios on K8s</p></figcaption></figure>

* Created a very simple **Docker image** --> <https://hub.docker.com/r/cr3w/simple-website> this image exists for failover and just updates with GitHub actions on every PR.
* Once we make an update to the version ( local, or by a PR to GitHub --> <https://github.com/stefanogram/docker-aws> \[needs and approval], we push the change to GitHub, and with GitHub actions (<https://github.com/stefanogram/docker-aws/actions>)&#x20;
* we push the new version to the Docker Hub --> <https://hub.docker.com/r/cr3w/simple-website>&#x20;
* &#x20;will use **AWS Elastic Container Registry as a main source for now.** Will have to create a new repo ( region us-east-02 <https://us-east-2.console.aws.amazon.com/ecr/repositories?region=us-east-2>
* We will push any updates on the app from GitHub to the ECR using GitHub actions
* Then will use ECS -Elastic Container Service for deploying the Docker container into EC2( will create task definition).

### ECR

* we create a new ( private ) repo <https://us-east-2.console.aws.amazon.com/ecr/repositories?region=us-east-2>
* Authenticate Docker to ECR:

```
stefano@teras ~/D/DevOPS> aws ecr create-repository --repository-name simple-website --region us-east-2
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:us-east-2:693505164922:repository/simple-website",
        "registryId": "693505164922",
        "repositoryName": "simple-website",
        "repositoryUri": "693505164922.dkr.ecr.us-east-2.amazonaws.com/simple-website",
        "createdAt": "2023-07-29T16:01:16+01:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": false
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin 693505164922.dkr.ecr.us-east-2.amazonaws.com/simple-website

```

* Tag the Docker image with ECR repo URI:

Now if you want to pull this local, as you might now need to do some changes, and push to AWS instance later, you need to make sure to clone the repo local from GitHub

1. Pull the image local in your machine (or from GitHub or from Docker Hub ) and tag it.

```
docker pull cr3w/simple-website:latest
```

```
docker tag cr3w/simple-website:latest 693505164922.dkr.ecr.us-east-2.amazonaws.com/simple-website:latest
```

2. Then we need to push the image to ECR:

```
 docker push 693505164922.dkr.ecr.us-east-2.amazonaws.com/simple-website:latest
```

3. Verify that the image is in our ECR repository:

```
stefano@teras ~/D/D/d/simple-website> aws ecr describe-images --repository-name simple-website --region us-east-2

{
    "imageDetails": [
        {
            "registryId": "693505164922",
            "repositoryName": "simple-website",
            "imageDigest": "sha256:dbe393a5ab2109eab62ec8ab2bb467462e7214b132ad257c381f036b8bf3ee17",
            "imageTags": [
                "latest"
            ],
            "imageSizeInBytes": 64690050,
            "imagePushedAt": "2023-07-29T16:23:48+01:00",
            "imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "artifactMediaType": "application/vnd.docker.container.image.v1+json"
        }
    ]
}
```

{% hint style="warning" %}
We need to make sure here that when we push new image versions on Docker Hub to have the **`latest`** tag as ECR is listening the "***latest***" tag to get the most up to date version.

You can always revert previous image with pushing older versions example Tag=1.0.0

This will revert the Docker image to ECR which then will push the image to AWS and will revert the updates have made sure once we make an update to GitHub, we also update the docker hub.
{% endhint %}

{% hint style="warning" %}
Also we need to make sure that we have already created Role with permission: \`AmazonEC2ContainerRegistryReadOnly\` for our instances to be able to ready the Docker ECR images.

We define that in our cloudformation.yml file we add the `IamInstanceProfile` property to our `AWS::AutoScaling::LaunchConfiguration`

This is a Global configuration created here: <https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-2#/roles/details/EC2_ECR?section=permissions>

{% endhint %}

Here is our full cloudformation.yml

```
Parameters:
  InstanceType:
    Description: micro ec2 instance with health checks
    Type: String
    Default: t2.micro

  KeyName:
    Description: stefano's keypair
    Type: AWS::EC2::KeyPair::KeyName
    Default: stefano-us-east-2

  ImageId:
    Description: aws Image ID for this instance
    Type: AWS::EC2::Image::Id
    Default: ami-024e6efaf93d85776

  RoleName:
    Description: IAM Role to allow EC2 instances to access ECR
    Type: String
    Default: EC2_ECR

Resources:  
  MyLaunchConfiguration:
    Type: "AWS::AutoScaling::LaunchConfiguration"
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref ImageId
      KeyName: !Ref KeyName
      SecurityGroups:
        - "sg-a7f988c5"
      IamInstanceProfile: !Ref RoleName
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          sudo apt-get update -y
          sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common unzip
          curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
          unzip awscliv2.zip
          sudo ./aws/install
          curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
          sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
          sudo apt-get update
          sudo apt-get install -y docker-ce
          sudo systemctl start docker
          sudo systemctl enable docker
          $(aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin 693505164922.dkr.ecr.us-east-2.amazonaws.com)
          sudo docker pull 693505164922.dkr.ecr.us-east-2.amazonaws.com/simple-website:latest
          sudo docker run -d -p 80:80 693505164922.dkr.ecr.us-east-2.amazonaws.com/simple-website:latest
          

  MyAutoScalingGroup:
    Type: "AWS::AutoScaling::AutoScalingGroup"
    Properties:
      AvailabilityZones:
        - "us-east-2a"
        - "us-east-2b"
      MinSize: "2"
      MaxSize: "4"
      DesiredCapacity: "2"
      HealthCheckType: EC2
      LaunchConfigurationName: !Ref MyLaunchConfiguration
      TargetGroupARNs: 
        - !Ref MyTargetGroup
      
  MyLoadBalancer:
    Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
    Properties: 
      Subnets:
        - "subnet-feced596"
        - "subnet-c7dc8dbd"
        - "subnet-52d9611e"
      SecurityGroups: 
        - "sg-a7f988c5"

  MyTargetGroup:
    Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckPath: "/"
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 5
      UnhealthyThresholdCount: 2
      Matcher:
        HttpCode: '200'
      Port: 80
      Protocol: HTTP
      VpcId: "vpc-73cb3818"
      TargetType: "instance"

  MyListener:
    Type: "AWS::ElasticLoadBalancingV2::Listener"
    Properties: 
      LoadBalancerArn: !Ref MyLoadBalancer
      Protocol: HTTP
      Port: 80
      DefaultActions: 
        - Type: forward
          TargetGroupArn: !Ref MyTargetGroup

```

Improvements of the cloudformation.yml can be tracked here this is only for testing purposes do not use in production.

Finally we will use watchtower in Docker: <https://containrrr.dev/watchtower/> to track updates on our ECR image, and pull it to the EC2 instances.

Watchtower is an application that will monitor our running Docker containers and watch for changes to the images that those containers were originally started from. **If watchtower detects that an image has changed, it will automatically restart the container using the new image.**

Troubleshooting Watchtower:

<pre><code><strong>sudo docker logs --follow watchtower
</strong><a data-footnote-ref href="#user-content-fn-1">sudo docker logs watchtower</a>
</code></pre>

### Resources:

GitHub repo: <https://github.com/stefanogram/docker-aws>

Docker Hub: <https://hub.docker.com/repository/docker/cr3w/simple-website/general>

AWS pipeline ( EC2 Cloudformation LBs Instances ): <https://github.com/stefanogram/aws_pipeline>

## Actions

**What this is doing?**

{% hint style="info" %}

* We push the cloudformation.yml file, that **creates 2 Load Balanced EC2 Instances** with **HA** ( High Availability) the actions/changes logged into a **GitHub repo**, that using **GitHub Actions** and we have the **control of the YAML template**, it can be used later on with Ansible or Terraform.
* We can provide access to the GitHub Organization to Dev Ops and other Engineers by using Zero Trust Security model ( continues authentication ), and SSO authentication methods using Okta, Azure or other type of IdPs.
* We maintain a repo, on GitHub, that Developers can PR ( Pull Request) code changes, once approved will get pushed in to main repo, by using GitHub Actions, we communicate with the Docker Hub (**failover if ECR not available**), where we host our docker app, once there is a new version from GitHub, creates a new version on Docker Hub and **we send a copy also to our Elastic Container Registry**, which then automatically change the content in the AWS EC2 instances by using ECR
* We have the ability to transform the whole project and migrate it on K8s ( Kubernetes) very easily, and create a fail-over scenarios in case of a region failures on AWS or migration to other services.
  {% endhint %}

***

### LB apps:

![](/files/qoPYhUlCfjizpSA65ahI)

![](/files/U6LSVaiLJ9bCMVQba787)

### To Do

* Create fallback in case **Docker** Hub or **GitHub** are are not available. :x:
* Create fallback and reroutes in case **AWS** is not available ( K8s cluster or Linode server fleet with CF tunnels ) :x:

[^1]:


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://devops.stefanogramm.com/devops/ship/github.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
