avatarEli Elad Elrom

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

9552

Abstract

ws-actions/amazon-ecr-login@v1</span>

<span class="hljs-bullet">-</span> <span class="hljs-string">name: Build, tag, and push image to Amazon ECR</span>
  <span class="hljs-attribute">id</span><span class="hljs-punctuation">:</span> <span class="hljs-string">build-image</span>
  <span class="hljs-attribute">env</span><span class="hljs-punctuation">:</span>
    <span class="hljs-attribute">ECR_REGISTRY</span><span class="hljs-punctuation">:</span> <span class="hljs-string">${{ steps.login-ecr.outputs.registry }}</span>
    <span class="hljs-attribute">ECR_REPOSITORY</span><span class="hljs-punctuation">:</span> <span class="hljs-string">myrepo</span>
    <span class="hljs-attribute">IMAGE_TAG</span><span class="hljs-punctuation">:</span> <span class="hljs-string">${{ github.sha }}</span>
  <span class="hljs-attribute">run</span><span class="hljs-punctuation">:</span> <span class="hljs-string">|</span>
    echo "Build docker container"
    <span class="hljs-comment"># Build a docker container and</span>
    <span class="hljs-comment"># push it to ECR so that it can</span>
    <span class="hljs-comment"># be deployed to ECS.</span>
    docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
    docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
    echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

<span class="hljs-bullet">-</span> <span class="hljs-string">name: Fill in the new image ID in the Amazon ECS task definition</span>
  <span class="hljs-attribute">id</span><span class="hljs-punctuation">:</span> <span class="hljs-string">task-def</span>
  <span class="hljs-attribute">uses</span><span class="hljs-punctuation">:</span> <span class="hljs-string">aws-actions/amazon-ecs-render-task-definition@v1</span>
  <span class="hljs-attribute">with</span><span class="hljs-punctuation">:</span>
    <span class="hljs-attribute">task-definition</span><span class="hljs-punctuation">:</span> <span class="hljs-string">devops/task-definition.json</span>
    <span class="hljs-attribute">container-name</span><span class="hljs-punctuation">:</span> <span class="hljs-string">development-container</span>
    <span class="hljs-attribute">image</span><span class="hljs-punctuation">:</span> <span class="hljs-string">${{ steps.build-image.outputs.image }}</span>

<span class="hljs-bullet">-</span> <span class="hljs-string">name: Deploy Amazon ECS task definition</span>
  <span class="hljs-attribute">uses</span><span class="hljs-punctuation">:</span> <span class="hljs-string">aws-actions/amazon-ecs-deploy-task-definition@v1</span>
  <span class="hljs-attribute">with</span><span class="hljs-punctuation">:</span>
    <span class="hljs-attribute">task-definition</span><span class="hljs-punctuation">:</span> <span class="hljs-string">${{ steps.task-def.outputs.task-definition }}</span>
    <span class="hljs-attribute">service</span><span class="hljs-punctuation">:</span> <span class="hljs-string">development-service</span>
    <span class="hljs-attribute">cluster</span><span class="hljs-punctuation">:</span> <span class="hljs-string">development-cluster</span>
    <span class="hljs-attribute">wait-for-service-stability</span><span class="hljs-punctuation">:</span> <span class="hljs-string">true</span></pre></div><p id="f948">Click start commit and commit the <code>aws.yml </code>file to add the git action;</p><figure id="6373"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*i-12h2D20oWWoHUdSHaZEw.png"><figcaption></figcaption></figure><p id="08c3">Keep in mind that for the git-action to show they need to be added to the main branch, however when using the <code>workflow_dispatch</code><b> </b>the<b> </b>hook will take the <code>aws.yml</code> file from the branch it’s deployed from.</p><p id="77ec">If you click the Actions tab in GitHub you will see the <code>Deploy to Amazon ECS</code> there;</p><figure id="c03b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*1l9d1h5ONGDpEcC_Vsv82g.png"><figcaption></figcaption></figure><h1 id="245d">AWS Security Credentials</h1><p id="d749">Next, we will set access keys to deploy our container to AWS;</p><p id="1137">You can get these in;</p><ol><li>Go to: <a href="http://aws.amazon.com/">http://aws.amazon.com/</a></li><li>Sign Up &amp; create a new account</li><li>Go to your <a href="https://console.aws.amazon.com/">AWS account overview</a></li><li>Account menu in the upper-right (has your name on it)</li><li>sub-menu: <code>Security Credentials</code></li><li>Click &gt; <b>Create New Access Key</b></li></ol><figure id="51c9"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*WIL9ek2DJmlXDvuA9l0iCg.png"><figcaption></figcaption></figure><p id="c8b2">Store your key and secret;</p><figure id="14fa"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*PmTWL05nERzvtqLAn5bvwQ.jpeg"><figcaption></figcaption></figure><p id="77f0">Next, let’s set the secret that we will be using in our deployment.</p><p id="4db5">Project <code>Settings</code> &gt; <code>Secrets</code> &gt; <code>Actions</code> and set these up from the values in your AWS account;</p><p id="1cac"><a href="https://github.com/[your-repo]/new-repo/settings/secrets/actions">https://github.com/[your-repo]/new-repo/settings/secrets/actions</a></p><ul><li>AWS_ACCESS_KEY_ID — your access key id</li><li>AWS_DEFAULT_REGION — such as; us-east-1, us-east-2</li><li>AWS_SECRET_ACCESS_KEY — your secret access key</li></ul><p id="2258">In terms of picking a region, I recommend you use <code>us-east-2 </code>or <code>us-west-2</code> over <code>us-east-1</code> or <code>us-west-1</code> they have been proven to be more stable at the time of writing. Keep in mind that without a <code>Global accelerator</code> (<a href="https://aws.amazon.com/global-accelerator/">https://aws.amazon.com/global-accelerator/</a>) or some product in place that will divert traffic when service is down and available globally quickly.</p><figure id="7e72"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*O1u0HJijlwv77kAdUO8Sig.png"><figcaption></figcaption></figure><p id="ff57">Take a look;</p><figure id="25d7"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*vnLZ4cfHdy83TC5xDQ6-LA.png"><figcaption></figcaption></figure><p id="3680">Another option instead of storing the static passwords, which is more secured is to use static credentials. That can be done with <code>OpenID</code> connect, this allows reduce the need to store AWS credentials as long-lived GitHub secrets: <a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services">https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services</a></p><h1 id="75fe">AWS ECR</h1><p id="c0cf">Next, set up a repo that ECR can use. Go here: <a href="https://console.aws.amazon.com/ecr/home?region=us-east-1#">https://console.aws.amazon.com/ecr/home</a></p><p id="533e">Set the name and create the repo;</p><figure id="3335"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*PhYd-9tjv_2yyieVVOQcVA.png"><figcaption></figcaption></figure><p id="eacb">Copy the URI —</p><div id="fe68"><pre><span class="hljs-selector-attr">[account Id]</span><span class="hljs-selector-class">.dkr</span><span class="hljs-selector-class">.ecr</span>.<span class="hljs-selector-attr">[region]</span><span class="hljs-selector-class">.amazonaws</span>.com/myrepo</pre></div><p id="2298">Copy the <code>Docker</code> specific image <code>URI</code>, it will look like this;</p><div id="9220"><pre><span class="hljs-selector-attr">[account Id]</span><span class="hljs-selector-class">.dkr</span><span class="hljs-selector-class">.ecr</span>.<span class="hljs-selector-attr">[region]</span><span class="hljs-selector-class">.amazonaws</span>.com/myrepo:<span class="hljs-selector-attr">[commit Id]</span></pre></div><p id="5cb3">We will use <code>latest</code> to have the hook use the latest commit;</p><div id="b8be"><pre><span class="hljs-selector-attr">[account Id]</span><span class="hljs-selector-class">.dkr</span><span class="hljs-selector-class">.ecr</span>.<span class="hljs-selector-attr">[region]</span><span class="hljs-selector-class">.amazonaws</span>.com/<span class="hljs-selector-attr">[repo name]</span>:latest</pre></div><figure id="ca92"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*OvJzKokHGpDslPeyfuji2g.png"><figcaption></figcaption></figure><h2 id="d36a">ECR — Task Definitions</h2><p id="6ce8">Next, I am setting the task definitions. You can read more about the task def in the AWS Docs: <a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html">https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html</a></p><p id="e34a">Link: <a href="https://console.aws.amazon.com/ecs/home?region=us-east-1#/taskDefinitions">https://console.aws.amazon.com/ecs/home</a></p><p id="09be">Create <code>new task definitions</code></p><figure id="a79f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*PBON_ABz6wsIuOInyb2hew.png"><figcaption></figcaption></figure><p id="29ec"><code>Fargate</code> &gt; Next Step</p><figure id="ac52"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*xjoNaiCKVmi4CTbiD1BjeA.png"><figcaption></figcaption><

Options

/figure><div id="e33b"><pre>- Task Definition Name: myrepo-development-task

  • <span class="hljs-keyword">Role</span> <span class="hljs-title">> None</span></pre></div><div id="f5fa"><pre>Pick how much you want
  • <span class="hljs-keyword">Task</span> memory (GB) > <span class="hljs-number">0.5</span> GB
  • <span class="hljs-keyword">Task</span> CPU (vCPU) > <span class="hljs-number">0.25</span> GB</pre></div><div id="f232"><pre>Open<span class="hljs-built_in"> port </span>80 <span class="hljs-keyword">and</span> 8000 <span class="hljs-keyword">or</span> whatever<span class="hljs-built_in"> port </span>you set; Security<span class="hljs-built_in"> group </span>> <span class="hljs-built_in">Edit</span> > <span class="hljs-built_in">add</span> custom 80, 8000 > Save</pre></div><h2 id="bad8">Add container</h2><figure id="88b5"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*RsSUAn37nEnTUanjwKvzMg.png"><figcaption></figcaption></figure><div id="f806"><pre>Name > development-<span class="hljs-keyword">container</span> Image > Docker image URI we stored; <span class="hljs-comment">[account Id]</span>.dkr.ecr.<span class="hljs-comment">[region]</span>.amazonaws.com/myrepo:latest</pre></div><div id="a880"><pre>Memory Limits (MiB) > Soft <span class="hljs-keyword">limit</span> > <span class="hljs-number">1024</span> Port mappings (<span class="hljs-keyword">add</span> whatever ports you want <span class="hljs-keyword">open</span>) > <span class="hljs-number">80</span> <span class="hljs-number">8000</span> <span class="hljs-keyword">Add</span> <span class="hljs-keyword">Create</span></pre></div><figure id="9a12"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*j8tOL6qjecftnhhXpmnrTQ.png"><figcaption></figcaption></figure><p id="3b98">You will get a create message;</p><figure id="89b5"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*mLOnT_mp9XjKcUy5KH0byA.png"><figcaption></figcaption></figure><p id="2b76">Now we will copy the task definition content, and place it in our project, click the json tab;</p><figure id="baf9"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Pskb6mHE5mJnE3K7ptBTcQ.png"><figcaption></figcaption></figure><p id="56dc">Place in <code>devops/task-definition.json</code> Remember to commit that file into the repo.</p><figure id="b6e5"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*FkcQDzGgYCBwvG3kKTbARA.png"><figcaption></figcaption></figure><p id="d472">We mapped the <code>aws.yml </code>file to point there.</p><figure id="3bcc"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*qHJGz4kGzlBLo-0z4Bi7yw.png"><figcaption></figcaption></figure><h2 id="ca90">Add ECS Cluster -</h2><p id="295f">Next, create a Cluster in ECS clusters: <a href="https://console.aws.amazon.com/ecs/v2/clusters">https://console.aws.amazon.com/ecs/v2/clusters</a></p><figure id="5a7d"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*1b1M8RhwMElnlP-ll2ntSQ.png"><figcaption></figcaption></figure><div id="b81e"><pre><span class="hljs-keyword">Create</span> a <span class="hljs-keyword">cluster</span> > Networking <span class="hljs-keyword">only</span> > Next Step</pre></div><div id="e14d"><pre>- <span class="hljs-keyword">Cluster</span> <span class="hljs-type">name</span> > development-<span class="hljs-keyword">cluster</span>
  • <span class="hljs-keyword">Create</span></pre></div><p id="f780">I picked the name <code>development-cluster </code>to match with the <code>aws.yml</code> file setup.</p><figure id="50c1"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*mmJ7NkW8Pe6bjsvbc4iqfw.png"><figcaption></figcaption></figure><p id="4166">We can see our <code>development-cluster</code> listed;</p><figure id="dab2"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*1easDBgbW_5f1cbIbnTO3g.png"><figcaption></figcaption></figure><h1 id="ef35">ECS Service</h1><p id="c56b">Next, create a service. Click the <code>development-cluster</code>cluster or use the URL; <a href="https://us-east-1.console.aws.amazon.com/ecs/home">https://us-east-1.console.aws.amazon.com/ecs/home</a> > Services tab</p><figure id="147e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*XOyCBt6YKsy3KfQAFK8dFw.png"><figcaption></figcaption></figure><div id="4f06"><pre>Click Services <span class="hljs-built_in">tab</span> > <span class="hljs-keyword">create</span></pre></div><div id="c41f"><pre><span class="hljs-bullet">- </span>Launch type > FARGATE <span class="hljs-bullet">- </span>Service name: development-service <span class="hljs-bullet">- </span>Number of tasks: 1 <span class="hljs-bullet">- </span>Next Step</pre></div><div id="e6ed"><pre><span class="hljs-keyword">Load</span> balancing</pre></div><div id="1ad2"><pre>- <span class="hljs-keyword">Cluster</span> VPC > first item
  • Subnets > first item
  • <span class="hljs-keyword">Security</span> <span class="hljs-keyword">groups</span> > Edit > <span class="hljs-number">80</span>, <span class="hljs-number">8000</span> > Save
  • <span class="hljs-keyword">Load</span> balancer <span class="hljs-keyword">type</span> > <span class="hljs-keyword">none</span>
  • Service Auto Scaling > <span class="hljs-keyword">Do</span> <span class="hljs-keyword">not</span> adjust the service’s desired count
  • Next step
  • <span class="hljs-keyword">Create</span> service
  • <span class="hljs-keyword">View</span> service</pre></div><p id="3c4e">We will name the service <code>development-service</code> to match our <code>aws.yml</code> configurations.</p><p id="26f1">Here are some screenshots for you to see the configuration I set;</p><figure id="6b5f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*6aQxa2YkguoPIbVJMznJBg.png"><figcaption></figcaption></figure><figure id="1842"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*MOGjxLbDystA4-s9nRfoEA.png"><figcaption></figcaption></figure><p id="e68b">Once you complete setting up the service. It will take a few mins;</p><div id="0ed9"><pre>Last status: pending <span class="hljs-string">...</span> running <span class="hljs-string">...</span></pre></div><figure id="45c7"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*2UEfLKk0zIJs_vOU59L1TQ.png"><figcaption></figcaption></figure><p id="3927">If you check the configuration you will see that the service keeps failing, the reason is that we don’t have the repo set up yet.</p><figure id="e760"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*6AESOTxpci2I_en2a1ySaw.png"><figcaption></figcaption></figure><h1 id="6aad">Deployment using Git Action</h1><p id="e04c">Now we are ready to deploy our Docker container using the <code>Deploy to Amazon ECR</code> git-action we set. If you recall I set it up to deploy using the workflow from a branch instead of automatic deployment, so follow this step to deploy;</p><p id="9f24"><code>Click Actions > Deploy to Amazon ECS > Run workflow > Branch: main > Run workflow;</code></p><figure id="3dea"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*WMV5b8qmnkQ9yEdda75biQ.png"><figcaption></figcaption></figure><p id="1106">This could be easily changed to deploy on a <code>main</code> branch push instead.</p><p id="fb95">Click the deployment to confirm all went well, of fix any errors you have;</p><figure id="115b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*4GVwpHdhOZqN3GvDuqxjdA.png"><figcaption></figcaption></figure><p id="4c26">If you check ECR the repo should have the image tag with the container we deployed;</p><figure id="9527"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Fv-HQ_ObdANp8U930EGPVg.png"><figcaption></figcaption></figure><p id="97a4">Click the service to extract the public IP address;</p><figure id="d8c0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*okNoCwJkXMzrJtgcm8XVMA.png"><figcaption></figcaption></figure><p id="a67c">Now you can navigate to the URL to ensure the content is there;</p><figure id="0c8e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*yD85lv21CkSVkxegnddszQ.png"><figcaption></figcaption></figure><p id="6931">As you can tell, there is much that goes into these configurations and much you can change, however for the sake of simplifying this article I did not go into a deep explanation but feel free to explore on your own;</p><h2 id="e78e">Related Amazon articles:</h2><ul><li><a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/getting-started-fargate.html">https://docs.aws.amazon.com/AmazonECS/latest/developerguide/getting-started-fargate.html</a></li><li><a href="https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun">https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun</a></li><li><a href="https://aws.amazon.com/blogs/devops/build-a-continuous-delivery-pipeline-for-your-container-images-with-amazon-ecr-as-source/https://285146546915.signin.aws.amazon.com/console">https://aws.amazon.com/blogs/devops/build-a-continuous-delivery-pipeline-for-your-container-images-with-amazon-ecr-as-source/https://285146546915.signin.aws.amazon.com/console</a></li></ul><h1 id="3cba">Where to go from here</h1><ul><li>Download the code from this example: <a href="https://github.com/EliEladElrom/react-tutorials">Learning React</a> > <code>ecr-ecs-github-ci-cd</code></li></ul></article></body>

Quick CI-CD from Github to Prod with AWS ECR, ECS creating a serverless Docker container

There are so many ways to configure your project CI-CD pipeline when deploying to Amazon Web Services (AWS). In this tutorial, I will give the rundown of how to set up a serverless docker container using AWS ECR ECS that would be suitable as a starting point for a smaller size startup or MVP project.

There are a large number of products of AWS such as CodeDeploy, CodeCommit, S3, CodeBuilt, CodePipeline, EC2, SNS, etc. These products are a good fit for certain configurations for example to create a build and run tests against that built or a build that demands more resources.

However, there are many cases that your App doesn’t need that many resources and can be deployed as Elastic Container Service(ECS) using a serverless compute engine (AWS Fargate) — think shared virtual server vs EC2 dedicated server.

This configuration reduces costs but allows easily scaling, take a look, at a diagram of setting up GitHub using git action to deploy a serverless container on ECS;

This opinionated CI-CD setup is quick and relatively simple but gives you the power of scaling only when needed and automating your deployment process;

Github Actions > Docker Image > ECR > ECS > AWS Fargate

The setup we will create can be split into what we will do in Github, docker, and AWS;

Github — Setting up our project — Create a Git Action — Deployment using Git Action

Docker — Create a docker container

AWS — Get AWS Security Credentials — Set up AWS ECR — Set Task Definitions — Add ECS Cluster — ECS Service

Take a look.

Github

Setting up our project

Create a new repo on Github and push the code into that newly created repo.

For the repo files, I will be using the Docker getting started project that can be found here: https://github.com/docker/getting-started

$ git clone https://github.com/docker/getting-started.git
$ cd getting-started
$ rm -rf .git
$ git init

Push existing files:

git remote add origin https://github.com/EliEladElrom/new-repo.git
git add . && git commit -m 'init upload'
git branch --set-upstream-to=origin/main main
git push --set-upstream origin main

Docker

Now we can create a docker container (make sure docker is open)

docker build — tag latest .

Run the container on port 80;

docker run -d -p 80:80 docker/getting-started

Confirm;

% docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
latest latest 772be3a09969 1 minutes ago 28.8MB

We can view in the browser;

Git Action

Next, let’s set up git actions: https://github.com/[your account]/new-repo/actions/new

Github > actions > search for ECS > Deploy to Amazon ECS > Set up this workflow by clicking Configure;

The aws.yml file code view opens up;

In the aws.yml file, I made some changes such as setting up a hook so you can run the action without committing a push change using the workflow_dispatch hook instead of having every change in the branch create a deployment. Additionally, I placed the region as a secret secrets.AWS_DEFAULT_REGION and changed the environments variables such as repo name, container name, service, and cluster.

Lastly, I will be placing the task def in here: devops/task-definition.json

I put in bold the changes I made;

on:
  push:
    branches:
      - master
  # run manually
  workflow_dispatch:

name: Deploy to Amazon ECS

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    environment: production

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ secrets.AWS_DEFAULT_REGION }}

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - name: Build, tag, and push image to Amazon ECR
      id: build-image
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_REPOSITORY: myrepo
        IMAGE_TAG: ${{ github.sha }}
      run: |
        echo "Build docker container"
        # Build a docker container and
        # push it to ECR so that it can
        # be deployed to ECS.
        docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

    - name: Fill in the new image ID in the Amazon ECS task definition
      id: task-def
      uses: aws-actions/amazon-ecs-render-task-definition@v1
      with:
        task-definition: devops/task-definition.json
        container-name: development-container
        image: ${{ steps.build-image.outputs.image }}

    - name: Deploy Amazon ECS task definition
      uses: aws-actions/amazon-ecs-deploy-task-definition@v1
      with:
        task-definition: ${{ steps.task-def.outputs.task-definition }}
        service: development-service
        cluster: development-cluster
        wait-for-service-stability: true

Click start commit and commit the aws.yml file to add the git action;

Keep in mind that for the git-action to show they need to be added to the main branch, however when using the workflow_dispatch the hook will take the aws.yml file from the branch it’s deployed from.

If you click the Actions tab in GitHub you will see the Deploy to Amazon ECS there;

AWS Security Credentials

Next, we will set access keys to deploy our container to AWS;

You can get these in;

  1. Go to: http://aws.amazon.com/
  2. Sign Up & create a new account
  3. Go to your AWS account overview
  4. Account menu in the upper-right (has your name on it)
  5. sub-menu: Security Credentials
  6. Click > Create New Access Key

Store your key and secret;

Next, let’s set the secret that we will be using in our deployment.

Project Settings > Secrets > Actions and set these up from the values in your AWS account;

https://github.com/[your-repo]/new-repo/settings/secrets/actions

  • AWS_ACCESS_KEY_ID — your access key id
  • AWS_DEFAULT_REGION — such as; us-east-1, us-east-2
  • AWS_SECRET_ACCESS_KEY — your secret access key

In terms of picking a region, I recommend you use us-east-2 or us-west-2 over us-east-1 or us-west-1 they have been proven to be more stable at the time of writing. Keep in mind that without a Global accelerator (https://aws.amazon.com/global-accelerator/) or some product in place that will divert traffic when service is down and available globally quickly.

Take a look;

Another option instead of storing the static passwords, which is more secured is to use static credentials. That can be done with OpenID connect, this allows reduce the need to store AWS credentials as long-lived GitHub secrets: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services

AWS ECR

Next, set up a repo that ECR can use. Go here: https://console.aws.amazon.com/ecr/home

Set the name and create the repo;

Copy the URI —

[account Id].dkr.ecr.[region].amazonaws.com/myrepo

Copy the Docker specific image URI, it will look like this;

[account Id].dkr.ecr.[region].amazonaws.com/myrepo:[commit Id]

We will use latest to have the hook use the latest commit;

[account Id].dkr.ecr.[region].amazonaws.com/[repo name]:latest

ECR — Task Definitions

Next, I am setting the task definitions. You can read more about the task def in the AWS Docs: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html

Link: https://console.aws.amazon.com/ecs/home

Create new task definitions

Fargate > Next Step

- Task Definition Name: myrepo-development-task
- Role > None
Pick how much you want
- Task memory (GB) > 0.5 GB
- Task CPU (vCPU) > 0.25 GB
Open port 80 and 8000 or whatever port you set;
Security group > Edit > add custom 80, 8000 > Save

Add container

Name > development-container
Image > Docker image URI we stored;
[account Id].dkr.ecr.[region].amazonaws.com/myrepo:latest
Memory Limits (MiB) > Soft limit > 1024
Port mappings (add whatever ports you want open) >
    80
    8000
Add
Create

You will get a create message;

Now we will copy the task definition content, and place it in our project, click the json tab;

Place in devops/task-definition.json Remember to commit that file into the repo.

We mapped the aws.yml file to point there.

Add ECS Cluster -

Next, create a Cluster in ECS clusters: https://console.aws.amazon.com/ecs/v2/clusters

Create a cluster > Networking only > Next Step
- Cluster name > development-cluster
- Create

I picked the name development-cluster to match with the aws.yml file setup.

We can see our development-cluster listed;

ECS Service

Next, create a service. Click the development-clustercluster or use the URL; https://us-east-1.console.aws.amazon.com/ecs/home > Services tab

Click Services tab > create
- Launch type > FARGATE
- Service name: development-service
- Number of tasks: 1
- Next Step
Load balancing
- Cluster VPC > first item
- Subnets > first item
- Security groups > Edit > 80, 8000 > Save
- Load balancer type > none
- Service Auto Scaling > Do not adjust the service’s desired count
- Next step
- Create service
- View service

We will name the service development-service to match our aws.yml configurations.

Here are some screenshots for you to see the configuration I set;

Once you complete setting up the service. It will take a few mins;

Last status: pending ... running ...

If you check the configuration you will see that the service keeps failing, the reason is that we don’t have the repo set up yet.

Deployment using Git Action

Now we are ready to deploy our Docker container using the Deploy to Amazon ECR git-action we set. If you recall I set it up to deploy using the workflow from a branch instead of automatic deployment, so follow this step to deploy;

Click Actions > Deploy to Amazon ECS > Run workflow > Branch: main > Run workflow;

This could be easily changed to deploy on a main branch push instead.

Click the deployment to confirm all went well, of fix any errors you have;

If you check ECR the repo should have the image tag with the container we deployed;

Click the service to extract the public IP address;

Now you can navigate to the URL to ensure the content is there;

As you can tell, there is much that goes into these configurations and much you can change, however for the sake of simplifying this article I did not go into a deep explanation but feel free to explore on your own;

Related Amazon articles:

Where to go from here

  • Download the code from this example: Learning React > ecr-ecs-github-ci-cd
Ci Cd Pipeline
Cicd
AWS
Aws Ecs
Github Actions
Recommended from ReadMedium