<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:og="http://ogp.me/ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:schema="http://schema.org/" xmlns:sioc="http://rdfs.org/sioc/ns#" xmlns:sioct="http://rdfs.org/sioc/types#" xmlns:skos="http://www.w3.org/2004/02/skos/core#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" version="2.0" xml:base="http://badzilla.co.uk/">
  <channel>
    <title>AWS CLI</title>
    <link>http://badzilla.co.uk/</link>
    <description/>
    <language>en</language>
    
    <item>
  <title>Hosting Drupal 9 on AWS Fargate Part 2: Bitbucket Pipeline</title>
  <link>http://badzilla.co.uk/hosting-drupal-9-aws-fargate-part-2-bitbucket-pipeline</link>
  <description>
&lt;span&gt;Hosting Drupal 9 on AWS Fargate Part 2: Bitbucket Pipeline&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sun, 17/10/2021 - 09:31&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Introduction&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;In the first instalment of this sequence of blogs we talked about how imperative it is to create an industrial strength local dev environment when AWS Fargate is your target deployment platform. In this blog we discuss something equally important - the deploy and build process. This needs to be automated for Drupal since security patches are issued on a weekly basis by the Drupal Security Group, and an automated solution is the only way to keep on top of these updates.&lt;/p&gt;
&lt;p&gt;Over the last two years I have become accustomed  to using Atlassian's Bitbucket Pipelines, and I am really liking this CI/CD delivery mechanism. It is particularly suited to containerised solutions since the pipeline itself runs in a Docker container, and often times the solution Docker image can be used for the build process - case in point this project! This tutorial will show how the official Drupal PHP Docker container can be used as the pipeline for delivering Drupal 9 projects to AWS Fargate. Let's see how!&lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Bitbucket Pipeline&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-10/Pipeline.jpeg?itok=JFTezBU3 202w, https://assets.badzilla.co.uk/styles/max_650x650/s3/2021-10/Pipeline.jpeg?itok=lB6wJnbM 404w, https://assets.badzilla.co.uk/styles/max_1300x1300/s3/2021-10/Pipeline.jpeg?itok=ICDrDamw 808w, https://assets.badzilla.co.uk/styles/max_2600x2600/s3/2021-10/Pipeline.jpeg?itok=0UNx4Vgp 1616w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-10/Pipeline.jpeg?itok=JFTezBU3" alt="Pipeline" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The diagram above shows the basic steps the pipeline follows. Let's have a look at these in turn with narrative and then see how that transposes into the Pipeline code.A few trivial housekeeping activities have been omitted from the diagram for clarity but will be discussed when we look at the code. &lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Since my Badzilla blog is a hobby project, I don't have multiple environments, and merge all new features into the git master branch. Any merge into master triggers the build process. Commercial pipelines tend to trigger builds on feature branch commits too which may be a consideration depending upon your circumstances.&lt;/li&gt;
	&lt;li&gt;I've already mentioned that the Docker image selected for the pipeline will be the official Drupal / PHP release - and thus contains &lt;em&gt;composer&lt;/em&gt; which is used to build out the codebase.&lt;/li&gt;
	&lt;li&gt;Once the codebase has been built the testing can be undertaken. I have identified two parallel steps in the pipeline - &lt;a href="http://badzilla.co.uk/aws-fargate-automated-testing-cucumber-gherkin-java-maven-selenium-grid-hub-and-chrome-and-firefox"&gt;automated testing&lt;/a&gt; and &lt;a href="http://badzilla.co.uk/aws-fargate-static-analysis-php"&gt;static testing&lt;/a&gt;. I have covered the configuration for these in earlier blogs - so click through for further reading. &lt;/li&gt;
	&lt;li&gt;The next steps involve building the two Docker image artefacts we need for our Fargate bundles - the PHP / FPM / Codebase image, and the NGINX Web Server image. The latter is required since we need to load a configuration for Drupal 9 and for serving the S3 / CloudFront assets. &lt;/li&gt;
	&lt;li&gt;The artefacts are pushed into AWS ECR after being tagged &lt;em&gt;latest&lt;/em&gt;. &lt;/li&gt;
	&lt;li&gt;We are now ready to deploy the images to our ECS Cluster - but before we do this, we provide the opportunity to run any pre-deploy hooks. This would typically be activities such as &lt;em&gt;drush&lt;/em&gt; putting the web app into maintenance mode to prevent public access during updates.&lt;/li&gt;
	&lt;li&gt;One the pre-deploy scripts have completed, the deploy script is invoked. This forces an ECS service update on the cluster. The script loops to determine whether the update fails or completes, and upon a successful completion will move onto the final step. &lt;/li&gt;
	&lt;li&gt;The post-deploy scripts are now run. These would be further &lt;em&gt;drush&lt;/em&gt; commands to update the database schema for example, and to remove the maintenance mode flag. &lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Pipeline Code&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The pipeline code is saved in &lt;strong&gt;bitbucket-pipelines.yml&lt;/strong&gt; and is show below.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;image:
  name: drupal:9.2.6-php7.4-fpm
 
clone:
  depth: full
 
definitions:
  services:
    docker:
      memory: &lt;span style="color: #000000;"&gt;2048&lt;/span&gt;
 
  steps:
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;build-environment
        name: Build Environment
        script:
          &lt;span style="color: #666666; font-style: italic;"&gt;# Install git &amp; unzip for composer&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get update&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;git&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# Install dependencies&lt;/span&gt;
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; &lt;span style="color: #007800;"&gt;COMPOSER_ALLOW_SUPERUSER&lt;/span&gt;=&lt;span style="color: #000000;"&gt;1&lt;/span&gt;
          - composer &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# Copy project settings file in place&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; storage&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;settings.php web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;settings.php
          &lt;span style="color: #666666; font-style: italic;"&gt;# Remove all non-essential dirs and files from top level directory&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rf&lt;/span&gt; assets backup databases .git
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; Makefile README.md docker-compose.yml composer.json composer.lock .env .csslintrc .eslintignore .eslintrc.json
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; .gitignore
          &lt;span style="color: #666666; font-style: italic;"&gt;# Add the bind mount VOLUME so in Fargate the nginx container can do a VOLUME_FROM and load /opt/drupal docroot&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# from the core-drupal container&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-i&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'/^FROM.*/a VOLUME ["/opt/drupal"]'&lt;/span&gt; Dockerfile &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;dev&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;null &lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;
        caches:
          - composer
        artifacts:
          - &lt;span style="color: #ff0000;"&gt;'**'&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Automated Tests placeholder&lt;/span&gt;
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;automated-tests
        name: Automated Tests
        script:
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Add automated tests here"&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Static Analysis tests placeholder&lt;/span&gt;
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;static-tests
        name: Static Analysis Tests
        script:
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Add static analysis here"&lt;/span&gt;
 
pipelines:
  &lt;span style="color: #666666; font-style: italic;"&gt;# Run when code is merged / pushed into specific branches.&lt;/span&gt;
  branches:
    master:
      - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;build-environment
 
      - parallel:
          - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;automated-tests
          - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;static-tests
 
      - step:
          name: Build &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt; Deploy
          deployment: AWS Prod
          script:
            &lt;span style="color: #666666; font-style: italic;"&gt;# Install AWS CLI&lt;/span&gt;
            - apt update &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt; jq &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; python3 python-dev python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev python-pip
            - curl &lt;span style="color: #ff0000;"&gt;"https://s3.amazonaws.com/aws-cli/awscli-bundle-1.18.200.zip"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-o&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"awscli-bundle.zip"&lt;/span&gt;
            - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; awscli-bundle.zip
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;awscli-bundle&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-b&lt;/span&gt; ~&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;aws
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; &lt;span style="color: #007800;"&gt;PATH&lt;/span&gt;=~&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin:&lt;span style="color: #007800;"&gt;$PATH&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Build the codebase + FPM&lt;/span&gt;
            - docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; badzilla-core-drupal .
            &lt;span style="color: #666666; font-style: italic;"&gt;# Authenticate with ECR&lt;/span&gt;
            - aws configure &lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; aws_access_key_id &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_ACCESS_KEY}&lt;/span&gt;"&lt;/span&gt;
            - aws configure &lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; aws_secret_access_key &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_SECRET_KEY}&lt;/span&gt;"&lt;/span&gt;
            - aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Tag and push to the repo&lt;/span&gt;
            - docker tag badzilla-core-drupal:latest &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            - docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# NGINX_DRUPAL_REPO_URL&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;fargate
            - docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; badzilla-nginx-drupal .
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
            &lt;span style="color: #666666; font-style: italic;"&gt;# Authenticate with ECR&lt;/span&gt;
            - aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Tag and push to the repo&lt;/span&gt;
            - docker tag badzilla-nginx-drupal:latest &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            - docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Pre deploy Drush Commands&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; deploy-scripts
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-parser.sh ..&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;webhooks&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;pre-deploy&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
            &lt;span style="color: #666666; font-style: italic;"&gt;# Deploy script&lt;/span&gt;
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-scripts&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;ecs-service-deploy.sh
            &lt;span style="color: #666666; font-style: italic;"&gt;# Post deploy Drush Commands&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; deploy-scripts
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-parser.sh ..&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;webhooks&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;post-deploy&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
          services:
            - docker
          caches:
            - docker&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Now let's inspect the code per section. Firstly the declaration of the Docker image to use for the pipeline. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;image:
  name: drupal:9.2.6-php7.4-fpm&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
You'll note that I'm using the same image as I used for my development environment with one small change. In the pipeline I have abandoned the use of the ultra lightweight Alpine image - the image being used is standard Ubuntu. Why so? Firstly there is less necessity for keeping the image small since Atlassian don't charge for storage of the image, and secondly I will want to add additional Linux packages to this image for the pipeline process, and thus I want to use a package manager I am familiar with - &lt;em&gt;apt&lt;/em&gt;.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;clone:
  depth: full
 
definitions:
  services:
    docker:
      memory: &lt;span style="color: #000000;"&gt;2048&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Here I'm saying I want a full clone of the repository in the pipeline. This is a little unnecessary and causes an overhead. In the future I will consider a more shallow clone for greater performance. The Docker memory setting should provide enough headroom for Drupal builds.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;  steps:
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;build-environment
        name: Build Environment
        script:
          &lt;span style="color: #666666; font-style: italic;"&gt;# Install git &amp; unzip for composer&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get update&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;git&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# Install dependencies&lt;/span&gt;
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; &lt;span style="color: #007800;"&gt;COMPOSER_ALLOW_SUPERUSER&lt;/span&gt;=&lt;span style="color: #000000;"&gt;1&lt;/span&gt;
          - composer &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Steps are defined in the pipeline that are invoked later in the script. This step &lt;em&gt;&amp;build-environment&lt;/em&gt; will build out the environment by installing the packages I will need and then running &lt;em&gt;composer install&lt;/em&gt; to build out the codebase.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;          &lt;span style="color: #666666; font-style: italic;"&gt;# Copy project settings file in place&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; storage&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;settings.php web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;settings.php
          &lt;span style="color: #666666; font-style: italic;"&gt;# Remove all non-essential dirs and files from top level directory&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rf&lt;/span&gt; assets backup databases .git
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; Makefile README.md docker-compose.yml composer.json composer.lock .env .csslintrc .eslintignore .eslintrc.json
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; .gitignore&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Every Drupal site needs a &lt;em&gt;settings.php&lt;/em&gt; file. I decided to have mine saved in the repository in the directory &lt;em&gt;storage&lt;/em&gt; since there is no confidential data. All settings use environmental variables. Your mileage may vary here - other strategies are possible for injecting the &lt;em&gt;settings.php&lt;/em&gt; into the build. &lt;br /&gt;&lt;br /&gt;
I then delete files and directories from the build which won't be needed in a production environment.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;          &lt;span style="color: #666666; font-style: italic;"&gt;# Add the bind mount VOLUME so in Fargate the nginx container can do a VOLUME_FROM and load /opt/drupal docroot&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# from the core-drupal container&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-i&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'/^FROM.*/a VOLUME ["/opt/drupal"]'&lt;/span&gt; Dockerfile &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;dev&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;null &lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
This snippet is a kludge to fix a difference between the local environment &lt;em&gt;docker-compose&lt;/em&gt; and the production Fargate Task Definition. Fargate shared volumes use &lt;em&gt;bind mounts&lt;/em&gt; which are created by initially using the &lt;em&gt;VOLUME&lt;/em&gt; instruction in the &lt;em&gt;Dockerfile&lt;/em&gt; and settings in the Task Definition (to be discussed in a later blog). Here I use interactive &lt;em&gt;sed&lt;/em&gt; to inject the &lt;em&gt;VOLUME&lt;/em&gt; into the &lt;em&gt;Dockerfile&lt;/em&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;        caches:
          - composer
        artifacts:
          - &lt;span style="color: #ff0000;"&gt;'**'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Closing the build step I ensure that Docker is cached to save time next time the pipeline is invoked and the artifact (American spelling) setting tells the pipeline to save the all my work in that pipeline step for steps that follow it.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;    &lt;span style="color: #666666; font-style: italic;"&gt;# Automated Tests placeholder&lt;/span&gt;
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;automated-tests
        name: Automated Tests
        script:
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Add automated tests here"&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Static Analysis tests placeholder&lt;/span&gt;
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;static-tests
        name: Static Analysis Tests
        script:
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Add static analysis here"&lt;/span&gt;
 
pipelines:
  &lt;span style="color: #666666; font-style: italic;"&gt;# Run when code is merged / pushed into specific branches.&lt;/span&gt;
  branches:
    master:
      - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;build-environment
 
      - parallel:
          - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;automated-tests
          - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;static-tests&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Here I have defined the testing steps (both of which are currently placeholders), and then started the 'implementation' section of the code. The steps will be invoked on the master branch, initially the build and then the the two testing steps in parallel.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;      - step:
          name: Build &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt; Deploy
          deployment: AWS Prod
          script:
            &lt;span style="color: #666666; font-style: italic;"&gt;# Install AWS CLI&lt;/span&gt;
            - apt update &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt; jq &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; python3 python-dev python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev python-pip
            - curl &lt;span style="color: #ff0000;"&gt;"https://s3.amazonaws.com/aws-cli/awscli-bundle-1.18.200.zip"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-o&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"awscli-bundle.zip"&lt;/span&gt;
            - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; awscli-bundle.zip
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;awscli-bundle&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-b&lt;/span&gt; ~&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;aws
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; &lt;span style="color: #007800;"&gt;PATH&lt;/span&gt;=~&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin:&lt;span style="color: #007800;"&gt;$PATH&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Once testing has completed successfully we commence the inline deploy step. We are going to need the AWS CLI installing here since the CLI is necessary to issue the correct sequence of commands to AWS to commit and deploy. &lt;br /&gt;&lt;br /&gt;
Note I am also installing the amazing utility &lt;em&gt;jq&lt;/em&gt; - a JSON query language utility. This is imperative for inspecting the output of the CLI commands since their responses are sent in JSON format.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;            &lt;span style="color: #666666; font-style: italic;"&gt;# Build the codebase + FPM&lt;/span&gt;
            - docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; badzilla-core-drupal .
            &lt;span style="color: #666666; font-style: italic;"&gt;# Authenticate with ECR&lt;/span&gt;
            - aws configure &lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; aws_access_key_id &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_ACCESS_KEY}&lt;/span&gt;"&lt;/span&gt;
            - aws configure &lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; aws_secret_access_key &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_SECRET_KEY}&lt;/span&gt;"&lt;/span&gt;
            - aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Tag and push to the repo&lt;/span&gt;
            - docker tag badzilla-core-drupal:latest &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            - docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Now I've got all I need installed I can build the Docker image artefacts. Firstly I build out the Drupal codebase image which also contains PHP and FPM. I then authenticate with AWS ECR where I will push the artefact once its been tagged.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;            &lt;span style="color: #666666; font-style: italic;"&gt;# NGINX_DRUPAL_REPO_URL&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;fargate
            - docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; badzilla-nginx-drupal .
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
            &lt;span style="color: #666666; font-style: italic;"&gt;# Authenticate with ECR&lt;/span&gt;
            - aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Tag and push to the repo&lt;/span&gt;
            - docker tag badzilla-nginx-drupal:latest &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            - docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
I now repeat the process for the NGINX web server Docker image. Note I have the configuration for this in my codebase repo under the directory &lt;em&gt;docker/nginx/fargate&lt;/em&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;            &lt;span style="color: #666666; font-style: italic;"&gt;# Pre deploy Drush Commands&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; deploy-scripts
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-parser.sh ..&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;webhooks&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;pre-deploy&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
            &lt;span style="color: #666666; font-style: italic;"&gt;# Deploy script&lt;/span&gt;
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-scripts&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;ecs-service-deploy.sh
            &lt;span style="color: #666666; font-style: italic;"&gt;# Post deploy Drush Commands&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; deploy-scripts
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-parser.sh ..&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;webhooks&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;post-deploy&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
This is the fun part! I now run the deploy shell scripts which are listed with narratives later in the blog. Firstly I run the pre-deploy commands, then the deploy commands and the post-deploy commands. All will be revealed...&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;          services:
            - docker
          caches:
            - docker&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
To use Docker commands in a pipeline, you need to list &lt;em&gt;Docker&lt;/em&gt; under the &lt;em&gt;services&lt;/em&gt; setting. Installing Docker in the pipeline itself and then invoking it will not work! I tried and failed! Note I am also using caching for greater performance.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Repository Environmental Variables&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=EYhOiCH9 126w, https://assets.badzilla.co.uk/styles/max_650x650/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=SINiOcxN 252w, https://assets.badzilla.co.uk/styles/max_1300x1300/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=7E76dh4f 505w, https://assets.badzilla.co.uk/styles/max_2600x2600/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=YYfDNJB3 536w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=EYhOiCH9" alt="Env Vars" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The pipeline and the shell scripts heavily use environmental variables that are set in the repository in Bitbucket. Their names are self-evident and listed in their entirety above. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Pre- and Post-deploy shell script&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The pre- and post-deploy shell script is defined below. Currently it only works on &lt;em&gt;drush&lt;/em&gt; commands but could be extended to include shell scripts easily enough. The idea is it scans the directory passed as a parameter and it looks for lines in any file that starts with the word &lt;em&gt;drush&lt;/em&gt;. It then takes the runtime arguments of that &lt;em&gt;drush&lt;/em&gt; command and converts it into a Docker &lt;em&gt;cmd&lt;/em&gt; syntax. Once that is done the command is executed as a Fargate task using the codebase image with parameter overrides. This task runs to completion and exits. The status of the command can be captured and reported back to the pipeline. Obviously this isn't as quick as running a &lt;em&gt;drush&lt;/em&gt; command in a terminal shell since the Fargate task needs to be provisioned which takes time. It is however a fiendish way of reusing an existing Docker image since the official Drupal Docker image already contains the &lt;em&gt;drush&lt;/em&gt; command. &lt;br /&gt;&lt;strong&gt;deploy-scripts/deploy-parser.sh&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Parse the passed files and issue commands in accordance.&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# Currently only supports drush commands.&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# This can be expanded out to other shell scripts.&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Output directory to be parsed&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Directory: $1 to be parsed"&lt;/span&gt;
 
set_network_configuration&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
&lt;span style="color: #007800;"&gt;NETWORK&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
    {
        "awsvpcConfiguration":
            {
                "subnets": [
                    $1,
                    $2
                ],
                "securityGroups": [
                    $3
                ],
                "assignPublicIp": "ENABLED"
            }
    }
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NETWORK}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
 
 
set_overrides_command&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
&lt;span style="color: #007800;"&gt;OVERRIDES&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
	{
		"containerOverrides": [
		    {
		        "name": $1,
		        "command": [
		            $2
		        ]
		    }
		]
	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${OVERRIDES}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Process each line in a selected file&lt;/span&gt;
parse_line&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# All lines to be processed must start with the word drush to be considered&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# This grep / sed combination will turn the drush command into docker cmd syntax&lt;/span&gt;
    &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"^drush"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${1}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;while&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;read&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; line ; &lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;cmd&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #007800;"&gt;$line&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/[^ ][^ ]*/"&amp;"/g'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/\s+/,/g'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/drush/vendor\/bin\/drush/'&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
        &lt;span style="color: #666666; font-style: italic;"&gt;# @BUG with quoting in dotenv and how I load into environment. Appears to add newlines making it difficult to add quotes later.&lt;/span&gt;
        &lt;span style="color: #666666; font-style: italic;"&gt;# So already added quotes for $CORE_TASK_DEFINITION_NAME in .env file but need the unquoted version in&lt;/span&gt;
        &lt;span style="color: #666666; font-style: italic;"&gt;# --task-definition flag so unquote here&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;TASK_DEF_UNQUOTE&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #800000;"&gt;${CORE_TASK_DEFINITION_NAME}&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; s&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;\"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;//&lt;/span&gt;g&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
        &lt;span style="color: #666666; font-style: italic;"&gt;# Now execute the command to start the container with the drush cmd&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;FARGATE_TASK&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs run-task \
            &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_CLUSTER_NAME}&lt;/span&gt;"&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--task-definition&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${TASK_DEF_UNQUOTE}&lt;/span&gt;"&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--network-configuration&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(set_network_configuration  ${ECS_SUBNET_1} ${ECS_SUBNET_2}  ${ECS_SECURITY_GROUP})&lt;/span&gt;"&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--launch-type&lt;/span&gt; FARGATE \
            &lt;span style="color: #660033;"&gt;--platform-version&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'1.4.0'&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_DEFAULT_REGION}&lt;/span&gt;"&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--overrides&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(set_overrides_command ${CORE_TASK_DEFINITION_NAME} ${cmd})&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .tasks&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.taskArn -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
        &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;!&lt;/span&gt;= &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Fargate Run Task Failed."&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;elif&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt;  &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_TASK}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Unspecified Fargate Run Task Failure."&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;else&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Cmd run is &lt;span style="color: #007800;"&gt;${cmd}&lt;/span&gt;"&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
        &lt;span style="color: #666666; font-style: italic;"&gt;# Loop round to check on the status of the task. Can't run in parallel so have to wait for each task to finish&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;while&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;true&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
            &lt;span style="color: #007800;"&gt;FARGATE_STATUS&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs describe-tasks &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_CLUSTER_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tasks&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_TASK}&lt;/span&gt;"&lt;/span&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .tasks&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.lastStatus -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
            &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_STATUS}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
                &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Unspecified Fargate Describe Task Failure."&lt;/span&gt;
                &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
            &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_STATUS}&lt;/span&gt;"&lt;/span&gt;
 
            &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_STATUS}&lt;/span&gt;"&lt;/span&gt; == &lt;span style="color: #ff0000;"&gt;"STOPPED"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;||&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_STATUS}&lt;/span&gt;"&lt;/span&gt; == &lt;span style="color: #ff0000;"&gt;"DEPROVISIONING"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
                  &lt;span style="color: #7a0874; font-weight: bold;"&gt;break&lt;/span&gt;
            &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
            &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;20&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
 
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Drush command completed"&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get a list of all the files in the directory and process&lt;/span&gt;
parse_directory&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# loop though all the files in the directory&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;in&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${1}&lt;/span&gt;"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/*&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;base&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(basename ${file})&lt;/span&gt;"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${base}&lt;/span&gt; being parsed"&lt;/span&gt;
        parse_line &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${file}&lt;/span&gt;"&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
parse_directory &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${1}&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;ECS Deploy Script&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The main ECS deploy shell script uses AWS CLI &lt;em&gt;ecs update-service &lt;/em&gt; to force a new deployment. This means that when the Fargate bundles are recycling any new codebase and NGINX Docker image will be used from AWS ECR. The process can take a few minutes so I have added a loop facility which uses AWS CLI &lt;em&gt;ecs describe-services&lt;/em&gt; to capture the current deployment status and act accordingly. Note I am using the previously mentioned &lt;em&gt;jq&lt;/em&gt; utility to interrogate the long JSON response from the CLI and whittle it down to the status field which should contain the word "COMPLETED" or "FAILED" or "IN_PROGRESS".&lt;br /&gt;&lt;strong&gt;deploy-scripts/ecs-service-deploy.sh&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Use the aws cli to force deploy Fargate task running in ECS service&lt;/span&gt;
aws ecs update-service &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_CLUSTER_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--service&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_SERVICE_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--force-new-deployment&lt;/span&gt; &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_DEFAULT_REGION}&lt;/span&gt;"&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Give it a few seconds to take effect&lt;/span&gt;
&lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;5&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the deployment status by looping over the deployment&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# Try for a maximum of 20 minutes then give up. Chances are after 20 minutes of incomplete&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# deployment there is a problem in the task definition&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; i &lt;span style="color: #000000; font-weight: bold;"&gt;in&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #000000;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;6&lt;/span&gt; &lt;span style="color: #000000;"&gt;7&lt;/span&gt; &lt;span style="color: #000000;"&gt;8&lt;/span&gt; &lt;span style="color: #000000;"&gt;9&lt;/span&gt; &lt;span style="color: #000000;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;21&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${i}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-eq&lt;/span&gt; &lt;span style="color: #000000;"&gt;21&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Timed out before could determine if deployment succeeded"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
    &lt;span style="color: #007800;"&gt;STATUS&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs describe-services &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_CLUSTER_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--services&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_SERVICE_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_DEFAULT_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .services&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.deployments&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.rolloutState -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Was it successful?&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${STATUS}&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;"COMPLETED"&lt;/span&gt;  &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Deployment succeeded"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# Anything we need to be concerned about?&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;elif&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${STATUS}&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;"FAILED"&lt;/span&gt;  &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Deployment failed"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# If still deploying echo this&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;elif&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${STATUS}&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;"IN_PROGRESS"&lt;/span&gt;  &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Deployment in progress"&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;else&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Unknown status "&lt;/span&gt;&lt;span style="color: #800000;"&gt;${STATUS}&lt;/span&gt;&lt;span style="color: #ff0000;"&gt;" so quitting"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Wait a minute before retrying&lt;/span&gt;
    &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;60&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Ad hoc Drush Commands&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The solution provides the capability to run &lt;em&gt;drush&lt;/em&gt; during the pre- and post-deploy scripts. But what about running &lt;em&gt;drush&lt;/em&gt; commands on an ad hoc basis from a remote laptop? This is often required by developers or devops and would be crucial for the management of a Drupal 9 website. Stay tuned for a future blog on how to achieve this! &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/taxonomy/term/121" hreflang="en"&gt;Drupal 9&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sun, 17 Oct 2021 08:31:46 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">182 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Hosting Drupal 9 on AWS Fargate Part 1: Local Development </title>
  <link>http://badzilla.co.uk/hosting-drupal-9-aws-fargate-part-1-local-development</link>
  <description>
&lt;span&gt;Hosting Drupal 9 on AWS Fargate Part 1: Local Development &lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sun, 19/09/2021 - 09:46&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Introduction&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Welcome to a series of blogs on hosting Drupal 9 (or legacy Drupal 8) sites on AWS Fargate. Fargate can now be considered a mature product, and provides a simple serverless containerised platform for hosting web apps. It offers considerable savings over traditional Virtual servers without, if configured correctly, loss of performance. Furthermore it offers greater simplicity of operation and setup then its AWS sibling offering ECS over EC2, and again a cost saving. &lt;/p&gt;

&lt;p&gt;The blogs in this series will cover important considerations such as the pipelines to deploy your codebase within Docker images, and their storage; set up of the Drupal S3FS module along with the CloudFront accelerator and S3 object store; auto scaling of the Fargate tasks; load testing your app to ensure you are fully optimised; and how to run your Drush commands in short living Fargate tasks. &lt;/p&gt;

&lt;p&gt;This first blog will cover your team's local environment and how its build will ensure your path to Fargate deploy is smooth, with as much reuse of the configuration in production as possible. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Objective&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-09/FargateServices_1.jpeg?itok=fq097hDo 325w, https://assets.badzilla.co.uk/styles/max_650x650/s3/2021-09/FargateServices_1.jpeg?itok=SeCQrttM 650w, https://assets.badzilla.co.uk/styles/max_1300x1300/s3/2021-09/FargateServices_1.jpeg?itok=vTdoq1tf 1300w, https://assets.badzilla.co.uk/styles/max_2600x2600/s3/2021-09/FargateServices_1.jpeg?itok=TaitKa6l 1581w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-09/FargateServices_1.jpeg?itok=fq097hDo" alt="Fargate Services and Tasks" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The objective is to stand up a Fargate task running as a service which will be the web app, and it will persist and auto scale. Also have Fargate tasks to run which will run Drush commands, stood up on a per Drush command basis, and terminating after each Drush command completes. The diagram above shows the Docker images requires to achieve our goal. &lt;/p&gt;
&lt;h3&gt;Drupal Core + FPM PHP + Codebase&lt;/h3&gt;
&lt;p&gt;The intention is to use the official Drupal FPM Docker image using Alpine, and be as up to date as possible with the versioning. Note that the Alpine build has been chosen since it's an extremely lightweight version of Linux, based on busybox which has a very small footprint. This comes at a price - those with Ubuntu experience will have to learn new commands. For instance Alpine uses the &lt;em&gt;apk&lt;/em&gt; package manager instead of &lt;em&gt;apt-get&lt;/em&gt;. The web app's codebase - ie all the configuration and custom modules and themes created by the dev team - will be copied into this image. &lt;/p&gt;
&lt;h3&gt;Drupal Core + FPM PHP + Codebase + Exec command&lt;/h3&gt;
&lt;p&gt;This will be the Fargate task to run one off Drush commands. Since the codebase will already contain Drush binaries in &lt;em&gt;vendor/bin/drush&lt;/em&gt;, it will be the same as the previously mentioned image. Notwithstanding this, it won't persist. It will use the Fargate equivalent of the Docker command to &lt;em&gt;exec&lt;/em&gt; a particular command and then quit. &lt;/p&gt;
&lt;h3&gt;Memcached&lt;/h3&gt;
&lt;p&gt;I have elected to run individual Memcached caching in each task running in the Web App service. Memcached will be used for caching the Drupal MySQL cache tables and for page caching for anonymous users. There is an alternative strategy to this - centralise the caching using for instance the AWS ElastiCache with Memcached product. Each task in the web service would have an endpoint to the same centralised ElastiCache instance. This would be the preferred option if your website is largely serving logged in traffic, and if you are running an eCommerce site with the users' baskets stored in Memcached. Since that doesn't apply to my own site, and I would like to keep costs down too, my feeling is having Memcached as part of the Fargate task is a better fit. &lt;/p&gt;
&lt;h3&gt;nginx&lt;/h3&gt;
&lt;p&gt;A web server is needed, and I've elected for &lt;em&gt;nginx&lt;/em&gt; although &lt;em&gt;Apache&lt;/em&gt; would also be a good choice. My rationale for selecting nginx is I would like to add the feature of nginx serving slightly stale cached pages when the origin is returning 5xx errors. This would give a seamless switch-over when a task becomes unhealthy - during the period AWS determines that a task is returning errors and has crossed the unhealthy threshold, nginx could still serve pages which would be less than 5 minutes old. The task would then be drained and removed from the pool with no problem noticeable to the end user. This will be the subject of a blog at a later date. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Using a local Virtual Machine&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Those who know me well will know I am not an advocate of using my laptop's OS for development purposes. The reason being that with multiple clients and with multiple projects in each, my host OS would quickly become a mess of different development tooling and versions which could collide and could also generate inconsistencies with other devs in the team should say different versions of bin files end up in the $PATH. &lt;/p&gt;

&lt;p&gt;My ethos has always been &lt;em&gt;do not pollute your host OS! Always use VMs for development!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I have created my own VM for Docker based implementations. My belief is if the target deploy is using Docker containers then the local development environment should match this as much as is practicable. In fact it's impossible to match the ECS/Fargate environment exactly, but it is certainly possible to use Docker with &lt;em&gt;docker-compose&lt;/em&gt; to simulate closely what will be seen in prod. &lt;/p&gt;

&lt;p&gt;My VM can be found in GitHub by clicking on &lt;a href="https://github.com/sanddevil/dockervm"&gt;this link&lt;/a&gt;. It is a very lightweight VM and can be orchestrated easily using Vagrant and Ansible. PHP and MySQL are deliberately not included in the playbook since all development work will be undertaken by using Docker containers.&lt;/p&gt;

&lt;p&gt;All my localhost config examples in this blog will have come from using my DockerVM mentioned above. If you intend to follow this blog closely, you will need to install it, but read the instructions in the README.md carefully!&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Composer&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Once you've got a lightweight VM up and running (hopefully mine), and ssh'd into it, and cloned your repo, you will need to build out the dependencies using &lt;em&gt;composer install&lt;/em&gt;. So how do we go about this when there is no composer and no PHP in the VM? There are two choices:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Use the official Docker Composer image&lt;/li&gt;
	&lt;li&gt;Use the latest official Docker Drupal image (9.2.6-php7.4-fpm-alpine.3.14 at time of writing this blog)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I chose the official Docker Composer image purely because (a) there was more documentation on it readily available, and (b) I wasn't sure at the time whether the Drupal image bundled Composer. It does, and it will be used in the Bitbucket Pipeline later so you may want to select that instead for consistency, but if you do, you'll have to change my composer commands slightly.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Ok so let's build our composer image. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ docker run &lt;span style="color: #660033;"&gt;--rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;--interactive&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tty&lt;/span&gt; &lt;span style="color: #660033;"&gt;--volume&lt;/span&gt; &lt;span style="color: #007800;"&gt;$PWD&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;app composer &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; &lt;span style="color: #660033;"&gt;--ignore-platform-reqs&lt;/span&gt;
Unable to &lt;span style="color: #c20cb9; font-weight: bold;"&gt;find&lt;/span&gt; image &lt;span style="color: #ff0000;"&gt;'composer:latest'&lt;/span&gt; locally
latest: Pulling from library&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;composer
a0d0a0d46f8b: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
153eea49496a: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
11efd0df1fcb: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
b3f3214c344d: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
9abd2f85688c: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
83d85b95eb4c: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
923d73ddadfa: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
711b5c4b02a7: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
ee08fa481788: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
5f9f812bf61d: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
28b3ecec72d5: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
a5ffb14bc4f9: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
d92aff3e5aec: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
cd0274c84e75: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
Digest: sha256:33d2c1d9fb7311cb8f215a8f52669894ef534292ac5d331347f929c27e317bb1
Status: Downloaded newer image &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; composer:latest
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; DrupalProject\composer\ScriptHandler::checkComposerVersion
Installing dependencies from lock &lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;including require-dev&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
Verifying lock &lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt; contents can be installed on current platform.
  - Downloading composer&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;installers &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;v2.0.1&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;---- SNIPPED ----&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;
  - Copy &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;web-root&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;profiles&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;README.txt from assets&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;scaffold&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;profiles.README.txt
  - Copy &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;web-root&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;themes&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;README.txt from assets&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;scaffold&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;themes.README.txt
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; DrupalProject\composer\ScriptHandler::createRequiredFiles
Created a sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files directory with &lt;span style="color: #c20cb9; font-weight: bold;"&gt;chmod&lt;/span&gt; 0777&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Success! Note that there is a requirement to use the composer flag --ignore-platform-reqs since it expects ext-gd locally which obviously we don't have.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;docker-compose: Codebase + FPM&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;In preparation for creating a docker-compose file we'll need to build out an image containing the latest Drupal 9 Docker image + our codebase once composer install has been run.  This will need a Dockerfile, and we can add APCu caching in the Dockerfile for greater Drupal performance. I also noted that Memcached API library needs to be added to Dockerfile since it is my intention to connect to a Memcached server for cache management in the container bundle.  The Dockerfile is listed below. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;FROM drupal:9.2.6-php7.4-fpm-alpine3.14
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Copy the artefact (on Bitbucket) or local files into the image&lt;/span&gt;
COPY .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;opt&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.
 
&lt;span style="color: #666666; font-style: italic;"&gt;# PHP Memcached which needs the libmemcached API&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# Bug in Apline - creates extensions in the wrong directory so add them in correct location&lt;/span&gt;
RUN apk add php7-igbinary php7-pecl-memcached libmemcached \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"extension=memcached.so"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf.d&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;docker-php-ext-memcached.ini \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"extension=igbinary.so"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf.d&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;docker-php-ext-igbinary.ini \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mv&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lib&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php7&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;memcached.so &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lib&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;extensions&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;no-debug-non-zts-&lt;span style="color: #000000;"&gt;20190902&lt;/span&gt; \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mv&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lib&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php7&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;igbinary.so &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lib&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;extensions&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;no-debug-non-zts-&lt;span style="color: #000000;"&gt;20190902&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# APCu cache&lt;/span&gt;
RUN apk add &lt;span style="color: #660033;"&gt;--update&lt;/span&gt; &lt;span style="color: #660033;"&gt;--no-cache&lt;/span&gt; &lt;span style="color: #660033;"&gt;--virtual&lt;/span&gt; .build-dependencies &lt;span style="color: #007800;"&gt;$PHPIZE_DEPS&lt;/span&gt; \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; pecl &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; apcu \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker-php-ext-enable apcu \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; pecl clear-cache \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; apk del .build-dependencies&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;docker-compose: nginx image&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;We will also need to build out an nginx image with the standard Drupal configuration. To do this I created a docker directory at the top level of the repo (i.e. a sibling of web directory) as such:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;tree&lt;/span&gt; docker
docker
├── core-drupal
├── memcached
└── nginx
    ├── fargate
    │   ├── default.conf
    │   ├── Dockerfile
    │   └── nginx.conf
    └── &lt;span style="color: #7a0874; font-weight: bold;"&gt;local&lt;/span&gt;
        ├── default.conf
        ├── Dockerfile
        └── nginx.conf
 
&lt;span style="color: #000000;"&gt;5&lt;/span&gt; directories, &lt;span style="color: #000000;"&gt;6&lt;/span&gt; files&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
You'll note that I have two sets of config files - one for AWS Fargate and one for local development. In fact the differences are minimal and will be discussed later. The local files are below&lt;br /&gt;
&lt;strong&gt;nginx.conf&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;user  nginx;
worker_processes  auto;
 
error_log  &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;log&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;error.log notice;
pid        &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;run&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx.pid;
 
 
events &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    worker_connections  &lt;span style="color: #000000;"&gt;1024&lt;/span&gt;;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
 
http &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    include       &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mime.types;
    default_type  application&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;octet-stream;
 
    fastcgi_buffers &lt;span style="color: #000000;"&gt;16&lt;/span&gt; 16k;
    fastcgi_buffer_size 32k;
 
    log_format  main  &lt;span style="color: #ff0000;"&gt;'$remote_addr - $remote_user [$time_local] "$request" '&lt;/span&gt;
                      &lt;span style="color: #ff0000;"&gt;'$status $body_bytes_sent "$http_referer" '&lt;/span&gt;
                      &lt;span style="color: #ff0000;"&gt;'"$http_user_agent" "$http_x_forwarded_for"'&lt;/span&gt;;
 
    access_log  &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;log&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;access.log  main;
 
    sendfile        on;
    &lt;span style="color: #666666; font-style: italic;"&gt;#tcp_nopush     on;&lt;/span&gt;
 
    keepalive_timeout  &lt;span style="color: #000000;"&gt;65&lt;/span&gt;;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;#gzip  on;&lt;/span&gt;
 
    include &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf.d&lt;span style="color: #000000; font-weight: bold;"&gt;/*&lt;/span&gt;.conf;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;strong&gt;default.conf&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;  server &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    server_name badzilla-fargate.test;
    root &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;opt&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;web; &lt;span style="color: #666666; font-style: italic;"&gt;## &lt;-- Your only path reference.&lt;/span&gt;
 
    location = &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;favicon.ico &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      log_not_found off;
      access_log off;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location = &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;robots.txt &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      allow all;
      log_not_found off;
      access_log off;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location ~ \..&lt;span style="color: #000000; font-weight: bold;"&gt;*/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;\.php$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;403&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location ~ ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*/&lt;/span&gt;private&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;403&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Block access to scripts in site files directory&lt;/span&gt;
    location ~ ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;+&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;\.php$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      deny all;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Allow "Well-Known URIs" as per RFC 5785&lt;/span&gt;
    location ~&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt; ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.well-known&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      allow all;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Block access to "hidden" files and directories whose names begin with a&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# period. This includes directories used by version control systems such&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# as Subversion or Git to store control files.&lt;/span&gt;
    location ~ &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;^&lt;span style="color: #000000; font-weight: bold;"&gt;|/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;\. &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;403&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;# try_files $uri @rewrite; # For Drupal &lt;= 6&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;index.php?&lt;span style="color: #007800;"&gt;$query_string&lt;/span&gt;; &lt;span style="color: #666666; font-style: italic;"&gt;# For Drupal &gt;= 7&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location &lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;rewrite &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;#rewrite ^/(.*)$ /index.php?q=$1; # For Drupal &lt;= 6&lt;/span&gt;
      rewrite ^ &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;index.php; &lt;span style="color: #666666; font-style: italic;"&gt;# For Drupal &gt;= 7&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Don't allow direct access to PHP files in the vendor directory.&lt;/span&gt;
    location ~ &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;vendor&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;\.php$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      deny all;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;404&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Protect files and directories from prying eyes.&lt;/span&gt;
    location ~&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt; \.&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;engine&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;inc&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;module&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;profile&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;po&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;sh&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;sql&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;theme&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;twig&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;tpl&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;\.php&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;?&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;xtmpl&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;yml&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;~&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;\.sw&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;op&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;\.bak&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;\.orig&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;\.save&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;?$&lt;span style="color: #000000; font-weight: bold;"&gt;|/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;\.&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;?&lt;span style="color: #000000; font-weight: bold;"&gt;!&lt;/span&gt;well-known&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;Entries.&lt;span style="color: #000000; font-weight: bold;"&gt;*|&lt;/span&gt;Root&lt;span style="color: #000000; font-weight: bold;"&gt;|/&lt;/span&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {&lt;/span&gt;
      deny all;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;404&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# In Drupal 8, we must also match new paths where the '.php' appears in&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# the middle, such as update.php/selection. The rule we use is strict,&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# and only allows this pattern with the update.php front controller.&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# This allows legacy path aliases in the form of&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# blog/index.php/legacy-path to continue to route to Drupal nodes. If&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# you do not have any paths like that, then you might prefer to use a&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# laxer rule, such as:&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;#   location ~ \.php(/|$) {&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# The laxer rule will continue to work if Drupal uses this new URL&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# pattern with front controllers other than update.php in a future&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# release.&lt;/span&gt;
    location ~ &lt;span style="color: #ff0000;"&gt;'\.php$|^/update.php'&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      fastcgi_split_path_info ^&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;.+?\.php&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;$;
      &lt;span style="color: #666666; font-style: italic;"&gt;# Ensure the php file exists. Mitigates CVE-2019-11043&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$fastcgi_script_name&lt;/span&gt; =&lt;span style="color: #000000;"&gt;404&lt;/span&gt;;
      &lt;span style="color: #666666; font-style: italic;"&gt;# Security note: If you're running a version of PHP older than the&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;# latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;# See http://serverfault.com/q/627903/94922 for details.&lt;/span&gt;
      include fastcgi_params;
      &lt;span style="color: #666666; font-style: italic;"&gt;# Block httpoxy attacks. See https://httpoxy.org/.&lt;/span&gt;
      fastcgi_param HTTP_PROXY &lt;span style="color: #ff0000;"&gt;""&lt;/span&gt;;
      fastcgi_param SCRIPT_FILENAME &lt;span style="color: #007800;"&gt;$document_root&lt;/span&gt;&lt;span style="color: #007800;"&gt;$fastcgi_script_name&lt;/span&gt;;
      fastcgi_param PATH_INFO &lt;span style="color: #007800;"&gt;$fastcgi_path_info&lt;/span&gt;;
      fastcgi_param QUERY_STRING &lt;span style="color: #007800;"&gt;$query_string&lt;/span&gt;;
      fastcgi_intercept_errors on;
      &lt;span style="color: #666666; font-style: italic;"&gt;# PHP 5 socket location.&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;#fastcgi_pass unix:/var/run/php5-fpm.sock;&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;# PHP 7 socket location.&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;#      fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;&lt;/span&gt;
      fastcgi_pass fpm:&lt;span style="color: #000000;"&gt;9000&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# S3FS Module&lt;/span&gt;
    location ~ ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;s3&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;styles&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;rewrite;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location ~&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt; \.&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;js&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;css&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;png&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;jpg&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;jpeg&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;gif&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;ico&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;svg&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;rewrite;
      expires max;
      log_not_found off;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Fighting with Styles? This little gem is amazing.&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# location ~ ^/sites/.*/files/imagecache/ { # For Drupal &lt;= 6&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;#location ~ ^/sites/.*/files/styles/ { # For Drupal &gt;= 7&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;#  try_files $uri @rewrite;&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;#}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Handle private files through Drupal. Private file's path can come&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# with a language prefix.&lt;/span&gt;
    location ~ ^&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;a-z\-&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;+&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;?&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;system&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt; &lt;span style="color: #666666; font-style: italic;"&gt;# For Drupal &gt;= 7&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;index.php?&lt;span style="color: #007800;"&gt;$query_string&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Enforce clean URLs&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# Removes index.php from urls like www.example.com/index.php/my-page --&gt; www.example.com/my-page&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# Could be done with 301 for permanent or other redirect codes.&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #007800;"&gt;$request_uri&lt;/span&gt; ~&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"^(.*/)index\.php/(.*)"&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;307&lt;/span&gt; &lt;span style="color: #007800;"&gt;$1&lt;/span&gt;&lt;span style="color: #007800;"&gt;$2&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;strong&gt;Dockerfile&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;FROM nginx:1.21.1-alpine
COPY .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default.conf &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf.d&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
COPY .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx.conf &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Some commentary is required here. You'll see in the default.conf file there is a snippet:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;    &lt;span style="color: #666666; font-style: italic;"&gt;# S3FS Module&lt;/span&gt;
    location ~ ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;s3&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;styles&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;rewrite;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
This is because the assets are not served locally - they are stored in an AWS S3 bucket with the AWS CloudFront accelerator providing edge capabilities. I will provide a further blog at a later date on setting all this up but in essence, assets shouldn't be kept in individual Fargate tasks, so either an AWS S3 / CloudFront solution needs to be utilised or an AWS EFS drive. &lt;br /&gt;&lt;br /&gt;
Now let's see what the differences are between the local configuration and Fargate. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;diff&lt;/span&gt; docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default.conf docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;fargate&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default.conf 
2c2
&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;     server_name badzilla-fargate.test;
&lt;span style="color: #660033;"&gt;---&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     server_name badzilla.co.uk www.badzilla.co.uk;
4a5,&lt;span style="color: #000000;"&gt;10&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     &lt;span style="color: #666666; font-style: italic;"&gt;# User Agent ELB-HealthChecker sends no headers with the request so nginx by default will respond with a 400&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     &lt;span style="color: #666666; font-style: italic;"&gt;# Fix with this&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     location = &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;health &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;         &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;200&lt;/span&gt;;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; 
92c98
&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;       fastcgi_pass fpm:&lt;span style="color: #000000;"&gt;9000&lt;/span&gt;;
&lt;span style="color: #660033;"&gt;---&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;       fastcgi_pass 127.0.0.1:&lt;span style="color: #000000;"&gt;9000&lt;/span&gt;;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Ok there are three differences. The first is obvious - I am using different server names dependent on the environment. The second difference is the AWS health checking capability that I have included for Fargate but not needed locally. I use the Drupal health_check module by the way, but the problem resides with the AWS Application Load Balancer health check feature. It sends requests to nginx without headers which nginx doesn't like - and always replies with a 400 response. This snippet fixes that problem. The third difference relates to how Fargate handles Docker networking. It is much simplified and all containers in the Fargate task use 127.0.0.1 for communication. Locally I am using a label named &lt;strong&gt;fpm&lt;/strong&gt; for fastcgi_pass communication between nginx and FPM.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;docker-compose: MariaDB and Memcached&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The use of MariaDB is the most significant difference between the local environment and Fargate. Fargate connects to a MariaDB instance in AWS RDS, whilst the local MariaDB persists its data in the VM. I did consider using another RDS instance for local development, but that would require public access to the database which I wasn't keen to do for security reasons. In addition there is a cost implication which isn't viable for a hobby project like my blog. I am using the standard Docker images for both MariaDB and Memcached locally.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;docker-compose Configuration&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;strong&gt;docker-compose&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;version: &lt;span style="color: #ff0000;"&gt;"3"&lt;/span&gt;
 
services:
  mariadb:
    image: &lt;span style="color: #ff0000;"&gt;"mariadb:&lt;span style="color: #007800;"&gt;${MARIADB_VERSION}&lt;/span&gt;"&lt;/span&gt;
    restart: &lt;span style="color: #ff0000;"&gt;'always'&lt;/span&gt;
    container_name: mariadb-drupal
    volumes:
      - &lt;span style="color: #ff0000;"&gt;"/var/lib/mysql/data:&lt;span style="color: #007800;"&gt;${MARIADB_DATA_DIR}&lt;/span&gt;"&lt;/span&gt;
      - &lt;span style="color: #ff0000;"&gt;"/var/lib/mysql/logs:&lt;span style="color: #007800;"&gt;${MARIADB_LOG_DIR}&lt;/span&gt;"&lt;/span&gt;
      - &lt;span style="color: #ff0000;"&gt;"/var/docker/mariadb/conf:/etc/mysql"&lt;/span&gt;
    environment:
      MYSQL_ROOT_PASSWORD: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_ROOT_PASSWORD}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_DATABASE: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_DATABASE}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_USER: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_USER}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_PASSWORD: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_PASSWORD}&lt;/span&gt;"&lt;/span&gt;
  drupal:
    image: core-drupal:latest
    container_name: core-drupal
    depends_on:
      - mariadb
      - memcached
    volumes:
      - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;opt&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;drupal
    restart: &lt;span style="color: #ff0000;"&gt;'always'&lt;/span&gt;
    environment:
      MYSQL_DATABASE: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_DATABASE}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_USER: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_USER}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_PASSWORD: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_PASSWORD}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_HOSTNAME: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_HOSTNAME}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_NAMESPACE: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_NAMESPACE}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_DRIVER: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_DRIVER}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_PORT: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_PORT}&lt;/span&gt;"&lt;/span&gt;
      AH_SITE_ENVIRONMENT: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AH_SITE_ENVIRONMENT}&lt;/span&gt;"&lt;/span&gt;
      S3FS_ACCESS_KEY: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_ACCESS_KEY}&lt;/span&gt;"&lt;/span&gt;
      S3FS_SECRET_KEY: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_SECRET_KEY}&lt;/span&gt;"&lt;/span&gt;
      S3FS_BUCKET: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_BUCKET}&lt;/span&gt;"&lt;/span&gt;
      S3FS_AWS_REGION: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_AWS_REGION}&lt;/span&gt;"&lt;/span&gt;
      S3FS_CLOUDFRONT_CNAME: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_CLOUDFRONT_CNAME}&lt;/span&gt;"&lt;/span&gt;
      S3FS_USE_S3_PUBLIC: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_USE_S3_PUBLIC}&lt;/span&gt;"&lt;/span&gt;
      S3FS_USE_CNAME: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_USE_CNAME}&lt;/span&gt;"&lt;/span&gt;
      S3FS_USE_HTTPS: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_USE_HTTPS}&lt;/span&gt;"&lt;/span&gt;
      S3FS_TWIG_PATH: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_TWIG_PATH}&lt;/span&gt;"&lt;/span&gt;
 
  nginx:
    image: nginx-drupal:latest
    container_name: nginx-drupal
    links:
      - drupal:fpm
    ports:
      - &lt;span style="color: #ff0000;"&gt;"80:80"&lt;/span&gt;
      - &lt;span style="color: #ff0000;"&gt;"443:443"&lt;/span&gt;
    depends_on:
      - drupal
    restart: &lt;span style="color: #ff0000;"&gt;'always'&lt;/span&gt;
    volumes:
      - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;opt&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;drupal
  memcached:
    image: memcached:alpine3.14
    restart: &lt;span style="color: #ff0000;"&gt;'always'&lt;/span&gt;
    container_name: memcached-drupal
    ports:
      - &lt;span style="color: #ff0000;"&gt;"11211:11211"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Note I have all my settings held in the environment. I also use the vlucas/phpdotenv composer dependency so these environmental variables are accessible in Drupal through a dot env file.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Shortcuts&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=ZK1WZKNL 325w, https://assets.badzilla.co.uk/styles/max_650x650/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=5u4dc1HE 650w, https://assets.badzilla.co.uk/styles/max_1300x1300/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=4Rdov1w4 1300w, https://assets.badzilla.co.uk/styles/max_2600x2600/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=9Jbps5Ok 1500w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=ZK1WZKNL" alt="start-web" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Remembering commands to build the Docker images, gain command line access to MariaDB, importing and exporting databases etc is an exercise in tedium I'd rather avoid. I have built a make file with shortcuts although command line aliases could also have been used.&lt;br /&gt;
&lt;strong&gt;Makefile&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;.DEFAULT_GOAL := &lt;span style="color: #7a0874; font-weight: bold;"&gt;help&lt;/span&gt;
 
 
help:
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"See the README.md for available options"&lt;/span&gt;
 
exportdb: set-env
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Exporting the database"&lt;/span&gt;
	docker &lt;span style="color: #7a0874; font-weight: bold;"&gt;exec&lt;/span&gt; &lt;span style="color: #660033;"&gt;-i&lt;/span&gt; mariadb-drupal &lt;span style="color: #c20cb9; font-weight: bold;"&gt;bash&lt;/span&gt; &lt;span style="color: #660033;"&gt;-c&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'mysqldump -u $$MYSQL_USER -p$$MYSQL_PASSWORD $$MYSQL_DATABASE'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
importdb: set-env
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Importing the database"&lt;/span&gt;
	docker &lt;span style="color: #7a0874; font-weight: bold;"&gt;exec&lt;/span&gt; &lt;span style="color: #660033;"&gt;-i&lt;/span&gt; mariadb-drupal &lt;span style="color: #c20cb9; font-weight: bold;"&gt;bash&lt;/span&gt; &lt;span style="color: #660033;"&gt;-c&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'mysql -u $$MYSQL_USER -p$$MYSQL_PASSWORD $$MYSQL_DATABASE'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
core-drupal: set-env
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Building Drupal Core Docker from Official Image"&lt;/span&gt;
	docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; core-drupal .
 
composer-require:
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Composer require running"&lt;/span&gt;
	docker run &lt;span style="color: #660033;"&gt;--rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;--interactive&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tty&lt;/span&gt; &lt;span style="color: #660033;"&gt;--volume&lt;/span&gt; $&lt;span style="color: #007800;"&gt;$PWD&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;app  &lt;span style="color: #660033;"&gt;--volume&lt;/span&gt; $&lt;span style="color: #800000;"&gt;${COMPOSER_HOME:-$$HOME/.composer}&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;tmp composer require &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(module)&lt;/span&gt;"&lt;/span&gt;  &lt;span style="color: #660033;"&gt;--ignore-platform-reqs&lt;/span&gt;
 
build-all: set-env
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Building all non-standard docker images ready for spinning up docker-compose"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;local&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; nginx-drupal .
	docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; core-drupal .
 
start-web: set-env
	docker-compose up
 
stop-web:
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Stopping the web app gracefully. Please wait"&lt;/span&gt;
	docker-compose down
 
set-env:
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Setting the env variables"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; .env &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #660033;"&gt;-v&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'^#'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'\S'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;tr&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'\r'&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'\0'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;xargs&lt;/span&gt; &lt;span style="color: #660033;"&gt;-0&lt;/span&gt; -n1&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
So for instance should I want to build the codebase and nginx Docker images I would simply type:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt; build-all&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
To add a new module using composer, the syntax would be:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt; composer-require &lt;span style="color: #007800;"&gt;module&lt;/span&gt;=drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;module_name&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Note the requirement to use key=value for parameter substitution in make. Similarly to import a database dump it would be:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt; importdb &lt;span style="color: #007800;"&gt;file&lt;/span&gt;=mydump.sql&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Not included in the make commands because of its interactive nature, to gain access to MariaDB do:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;docker &lt;span style="color: #7a0874; font-weight: bold;"&gt;exec&lt;/span&gt; &lt;span style="color: #660033;"&gt;-it&lt;/span&gt; mariadb-drupal mysql &lt;span style="color: #660033;"&gt;-uusername&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ppassword&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Finally when you do:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt; start-web&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
you should see output similar to the screenshot above!&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Drush&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;It's important to have Drush available in your local environment. To achieve this, ensure that drush is a dependency requirement in your composer.json file. If not add it using my shortcut mentioned earlier. This will place drush in path /opt/drupal/vendor/bin inside the drupal-core container which obviously must be running for it to work. Exec-ing a command from the VM command line and escaping it correctly is hard work - so to save you the heartache I've created a shell function in my VM to make light work of it. If you are not using my VM, add this to the bottom of your &lt;strong&gt;/etc/bash.bashrc&lt;/strong&gt; file. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;drush&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
  &lt;span style="color: #007800;"&gt;PARAMS&lt;/span&gt;=$&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;
  &lt;span style="color: #007800;"&gt;CONTAINER&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"core-drupal"&lt;/span&gt;
  &lt;span style="color: #007800;"&gt;CMD&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"sh -c &lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;/opt/drupal/vendor/bin/drush &lt;span style="color: #007800;"&gt;${PARAMS}&lt;/span&gt;&lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;"&lt;/span&gt;
  &lt;span style="color: #007800;"&gt;DCMD&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"docker exec -it &lt;span style="color: #007800;"&gt;$CONTAINER&lt;/span&gt; &lt;span style="color: #007800;"&gt;$CMD&lt;/span&gt;"&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;eval&lt;/span&gt; &lt;span style="color: #007800;"&gt;$DCMD&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Now any Drush command is available to you (when the container is running!)
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;drush cr
 &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;success&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; Cache rebuild complete.&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/taxonomy/term/121" hreflang="en"&gt;Drupal 9&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sun, 19 Sep 2021 08:46:14 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">181 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>AWS Fargate Static Analysis with PHP</title>
  <link>http://badzilla.co.uk/aws-fargate-static-analysis-php</link>
  <description>
&lt;span&gt;AWS Fargate Static Analysis with PHP&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Mon, 13/01/2020 - 14:28&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;In my earlier blog on &lt;a href="http://badzilla.co.uk/aws-fargate-automated-testing-cucumber-gherkin-java-maven-selenium-grid-hub-and-chrome-and-firefox"&gt;AWS Fargate Automated Testing&lt;/a&gt; I spoke about creating an AWS Fargate task definition which would include a web app's codebase and the Cucumber / Gherkin / maven / Java runtime stack. This tutorial is an opportunity to look at the static analysis stage of the pipeline where code is inspected for vulnerabilities, coding standards, compilation errors, copy and paste detection amongst others. Since my background is in Drupal and PHP, my tests will be focused around the PHP language and will use the excellent &lt;a href="https://github.com/jakzal/phpqa"&gt;Static Analysis Tools for PHP repo&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Looking at the jakzal/phpqa repo, it is clear there is a great deal of tooling available. The purpose of this tutorial is take a small sample of these tools and create a Fargate task to run them against my codebase. My somewhat arbitrary selection is:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;phpcpd - Copy/paste detection&lt;/li&gt;
	&lt;li&gt;phpcs - Codesniffer that detects coding standards violations&lt;/li&gt;
	&lt;li&gt;phplint - PHP syntax error checker. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok - let's get started. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Create the Dockerfile and the Entrypoint&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;As I have previously mentioned, Fargate is a black box and it doesn't lend itself to command line invocation of the tooling. Typically locally on a laptop we would run the jakzal/phpqa Docker image like: 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$  docker run &lt;span style="color: #660033;"&gt;-it&lt;/span&gt; &lt;span style="color: #660033;"&gt;--rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;-v&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;PWD&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;project &lt;span style="color: #660033;"&gt;-w&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;project  jakzal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;phpqa phpcpd web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;core&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;views&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;src
$  docker run &lt;span style="color: #660033;"&gt;-it&lt;/span&gt; &lt;span style="color: #660033;"&gt;--rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;-v&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;PWD&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;project &lt;span style="color: #660033;"&gt;-w&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;project  jakzal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;phpqa phpcs web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;core&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;views&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;src
$  docker run &lt;span style="color: #660033;"&gt;-it&lt;/span&gt; &lt;span style="color: #660033;"&gt;--rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;-v&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;PWD&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;project &lt;span style="color: #660033;"&gt;-w&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;project  jakzal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;phpqa phplint web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;core&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;views&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;src&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
This could obviously be placed in a shell script. Now in Fargate we don't have access to the command line and we have to create a Fargate definition up front before that can be provisioned and then run. So it's a little bit more involved. &lt;br /&gt;&lt;br /&gt;
The simplest approach is to create a Dockerfile based on the jakzal/phpqa repo, and an extrypoint script that will run each one of the tools I have identified. &lt;br /&gt;&lt;br /&gt;The Dockerfile is defined below. Note that I have selected PHP version 7.2. This is the closest supported version of PHP to what I'm running on my production box. Think I need to upgrade that at some point..
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;FROM jakzal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;phpqa:1.28.1-php7.2
ADD entry.sh &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;entry.sh
RUN &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;bash&lt;/span&gt; &lt;span style="color: #660033;"&gt;-c&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'chmod +x /entry.sh'&lt;/span&gt;
ENTRYPOINT &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #ff0000;"&gt;"/entry.sh"&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Next up is the entry.sh file. First thing to note is I have added the &lt;strong&gt;set +e&lt;/strong&gt; flag, which is default anyway. This is included to ensure that even if I get some pernickety error messages the script won't terminate immediately, and it acts as an aide memoire that we don't want error termination so don't accidentally copy paste in a competing &lt;strong&gt;set -e&lt;/strong&gt; flag. &lt;br /&gt;&lt;br /&gt;There is then a check whether the shared ECS volume has been loaded - this is the responsibility of the codebase container, but because containers can start at varying times, I have to ensure I don't run the PHP analysis before the volume is ready. &lt;br /&gt;&lt;br /&gt;The path to the source code to perform the analysis on is defined as /var/static_tests/web/core/modules/views/src. This has two components. The first part /var/static_tests/ is the mount point which will correspond to my codebase top level directory. The second component, web/core/modules/views/src points to the core contributed Drupal Views module. This is purely there as a reference to some arbitrary code. I am using the codebase to my own Badzilla which is a site build with no custom code and thus I have none of my own code to use in this sample. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/usr/bin/env sh&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; +e
 
&lt;span style="color: #000000; font-weight: bold;"&gt;while&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;!&lt;/span&gt; &lt;span style="color: #660033;"&gt;-d&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;static_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;web &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
  &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;5&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Waiting for volume to be mounted and files copied into position"&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
 
phpcpd &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;static_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;core&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;views&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;src
phpcs &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;static_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;core&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;views&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;src
phplint &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;static_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;core&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;views&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;src&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Building the Docker image locally&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;It isn't mandatory to test everything works before constructing the Fargate task definition, but it makes sense to me to test my work locally first. If the Fargate task subsequently fails then I know the problem area will be localised to the AWS eco-system, and probably to Fargate. So I always build locally and run locally first. To build I cd into my Dockerfile / entry.sh entry and issue:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666;"&gt;$ &lt;/span&gt;docker build &lt;span style="color: #660033;"&gt;-f&lt;/span&gt; Dockerfile &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; static-fargate  .&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
To run it's 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666;"&gt;$ &lt;/span&gt;docker run &lt;span style="color: #660033;"&gt;-it&lt;/span&gt; &lt;span style="color: #660033;"&gt;--rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;-v&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;PWD&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;static_tests  static-fargate &lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
You can see above I am establishing the Docker volume which will be shared with my codebase.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The Docker Hub repo for this is at &lt;a href="https://hub.docker.com/repository/docker/sanddevil/static-fargate"&gt;https://hub.docker.com/repository/docker/sanddevil/static-fargate&lt;/a&gt; and the GitHub repo for the code is at &lt;a href="https://github.com/sanddevil/devops-static-php"&gt;https://github.com/sanddevil/devops-static-php&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Define the Fargate task&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;With everything working locally it's time to build the Fargate task. This is very similar to the script I created in my earlier automated testing blog. There are a few differences obviously. My container stack comprises of a combined PHP + Apache + my own codebase image, and the PHP static analysis  jakzal/phpqa obviously. I use the shell script heredoc convention to define each container. You should note I have now expanded my codebase container to include two shared volumes - one for the automated tests (not discussed here but discussed previously) and the static tests. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
 
&lt;span style="color: #007800;"&gt;BRANCH&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"master"&lt;/span&gt;
&lt;span style="color: #007800;"&gt;REPO&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"php7.0-apache/&lt;span style="color: #007800;"&gt;${BRANCH}&lt;/span&gt;"&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Repo account and repo&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ECR_ACCOUNT&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"xxxxxxxxxxx.dkr.ecr.eu-west-2.amazonaws.com"&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ECR_REPO&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECR_ACCOUNT}&lt;/span&gt;/&lt;span style="color: #007800;"&gt;${REPO,,}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ECS_CLUSTER&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"FargatePrototype"&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the Task Role ARN for executing the task&lt;/span&gt;
&lt;span style="color: #007800;"&gt;TASK_ARN&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws iam get-role &lt;span style="color: #660033;"&gt;--role-name&lt;/span&gt; ecsTaskExecutionRole &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .Role.Arn -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Execution ARN appears to be the same as the Task ARN&lt;/span&gt;
&lt;span style="color: #007800;"&gt;EXECUTION_ARN&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${TASK_ARN}&lt;/span&gt;"&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Determine if the log group already exists: NOTE: "aws ecs register-task-definition" will not create the log group for you!&lt;/span&gt;
&lt;span style="color: #007800;"&gt;LOG_EXISTS&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws logs describe-log-groups &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;".logGroups[] | select(.logGroupName == &lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;/ecs/"&lt;/span&gt;&lt;span style="color: #800000;"&gt;${BRANCH}&lt;/span&gt;&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;) | .logGroupName"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;wc&lt;/span&gt; -l&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${LOG_EXISTS}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-eq&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	aws logs create-log-group &lt;span style="color: #660033;"&gt;--log-group-name&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"/ecs/&lt;span style="color: #007800;"&gt;${BRANCH}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;CONTAINER_CODEBASE&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
	{
		"dnsSearchDomains": [],
		"logConfiguration": {
			"logDriver": "awslogs",
			"options": {
				"awslogs-group": "/ecs/${BRANCH}",
				"awslogs-region": "eu-west-2",
				"awslogs-stream-prefix": "ecs"
			}
		},
		"entryPoint": [
			"/usr/local/bin/entry.sh"
		],
		"portMappings": [{
			"hostPort": 80,
			"protocol": "tcp",
			"containerPort": 80
		}],
		"command": [],
		"cpu": 0,
		"image": "${ECR_REPO}",
		"name": "PHPApacheCodebase",
		"mountPoints": [{
			"sourceVolume": "automated_tests",
			"containerPath": "/var/automated_tests",
			"readOnly": false
		},{
			"sourceVolume": "static_tests",
			"containerPath": "/var/static_tests",
			"readOnly": false
		}]
	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;CONTAINER_STATIC_PHP&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
	{
		"dnsSearchDomains": [],
		"logConfiguration": {
			"logDriver": "awslogs",
			"options": {
				"awslogs-group": "/ecs/${BRANCH}",
				"awslogs-region": "eu-west-2",
				"awslogs-stream-prefix": "ecs"
			}
		},
		"entryPoint": [],
		"portMappings": [],
		"command": [],
		"cpu": 0,
		"image": "registry.hub.docker.com/sanddevil/static-fargate",
		"name": "StaticPHP",
		"essential": true,
		"mountPoints": [{
			"sourceVolume": "static_tests",
			"containerPath": "/var/static_tests"
		}]
	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
 
&lt;span style="color: #007800;"&gt;CONTAINERS_STATIC&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
[
${CONTAINER_CODEBASE},
${CONTAINER_STATIC_PHP}
]
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
 
aws ecs register-task-definition \
  &lt;span style="color: #660033;"&gt;--family&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"STATIC-&lt;span style="color: #007800;"&gt;${BRANCH}&lt;/span&gt;"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--volumes&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"name=static_tests,host={}"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"name=automated_tests,host={}"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--task-role-arn&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$TASK_ARN&lt;/span&gt;"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--execution-role-arn&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${EXECUTION_ARN}&lt;/span&gt;"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--network-mode&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"awsvpc"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--container-definitions&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CONTAINERS_STATIC}&lt;/span&gt;"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--cpu&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"256"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--memory&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"512"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--requires-compatibilities&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"FARGATE"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
I'm not quite done yet though. Somehow I need to copy my codebase into the shared Docker volume so that the PHP static analysis container can see it. This is done in the entry.sh script of my PHP + Apache + Codebase image (not discussed here) but the entry.sh file is shown below for completeness. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Copy the automated tests into a shared area accessible to maven&lt;/span&gt;
&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; &lt;span style="color: #660033;"&gt;-R&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;www&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;html&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;test&lt;/span&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;automated_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Copy the PHP codebase into a shared area accessible to the PHP static analysis container&lt;/span&gt;
&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; &lt;span style="color: #660033;"&gt;-R&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;www&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;html&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;web  &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;static_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Run Apache in the foreground to prevent the container from quitting&lt;/span&gt;
apache2-foreground&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Here you can see the copying I do for both the automated tests and the static analysis.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Running the Fargate task&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/Screenshot_2020-01-14_at_14_54_17-edited.png?itok=SEUKoW46 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2020-01/Screenshot_2020-01-14_at_14_54_17-edited.png?itok=H29PqVpt 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2020-01/Screenshot_2020-01-14_at_14_54_17-edited.png?itok=vDraWtWi 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2020-01/Screenshot_2020-01-14_at_14_54_17-edited.png?itok=9FcxZ4b4 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/Screenshot_2020-01-14_at_14_54_17-edited.png?itok=SEUKoW46" alt="Task Running" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/Screenshot_2020-01-14_at_14_54_37-edited.png?itok=dd27IZ5a 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2020-01/Screenshot_2020-01-14_at_14_54_37-edited.png?itok=pt6QQe2a 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2020-01/Screenshot_2020-01-14_at_14_54_37-edited.png?itok=sCz9YTr5 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2020-01/Screenshot_2020-01-14_at_14_54_37-edited.png?itok=eTY4vp7U 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/Screenshot_2020-01-14_at_14_54_37-edited.png?itok=dd27IZ5a" alt="CloudWatch Logs" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Normally I would invoke the Fargate task programmatically using AWS CLI but since that leads to a rather dry image-free blog, I will use the console in this instance. My previous blog shows how to navigate around the ECS dashboard to run the task, then you can see the task running in the first screenshot above. It will only run until the entrypoint script terminates as per the rules on how Docker works, so to capture that scrennshot I had to be quick. The second screenshot shows the CloudWatch logs for the task, and you can see there are a few copy/paste errors detected. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/ecs" hreflang="en"&gt;ECS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/docker" hreflang="en"&gt;Docker&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/bash" hreflang="en"&gt;bash&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Mon, 13 Jan 2020 14:28:49 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">176 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>AWS Fargate: CI/CD Architecture for Drupal and PHP Frameworks</title>
  <link>http://badzilla.co.uk/aws-fargate-cicd-architecture-drupal-and-php-frameworks</link>
  <description>
&lt;span&gt;AWS Fargate: CI/CD Architecture for Drupal and PHP Frameworks&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sat, 04/01/2020 - 13:45&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Introduction&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;AWS Fargate is a compute engine for Amazon ECS which allows the running of Docker containers without having to provision and manage the underlying EC2 servers. This makes the standing up of Docker bundles immeasurably easier, and thankfully that ease comes with very few limitations. It is often considered the Docker equivalent of AWS Lambda. &lt;/p&gt;

&lt;p&gt;Fargate's ease of use and convenience makes it a natural fit for CI/CD architecture. Apps can be defined as Fargate tasks which are analogous to Docker Bundles, and pipeline stages can be engineered to perform standard activities such as build, automated testing, static analysis, dev playground, and deploy. &lt;/p&gt;

&lt;p&gt;This architecture statement explains how this can be applied to the world of PHP frameworks and Drupal CMS. With a little imagination, and a few tweaks to the ecosystem and Fargate tasks, and the architecture would be valid for other high level languages and frameworks.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Pipeline Stages&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/CI-CD%20Stages.png?itok=gY0r9mcr 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2020-01/CI-CD%20Stages.png?itok=QMs76Kfz 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2020-01/CI-CD%20Stages.png?itok=PPI9yW8U 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2020-01/CI-CD%20Stages.png?itok=WHPePVns 1580w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/CI-CD%20Stages.png?itok=gY0r9mcr" alt="CI/CD Stages" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Before we get into the physical AWS ecosystem, it's worth discussing what we are trying to achieve. I have identified the four main stages in the pipeline in the diagram above. There will be two entry points into the build stage: it will be either automated on a git pull request creation and approval, but also a manual invocation is possible for times when a dev or QA wants to check progress on a feature after a commit but before a PR is created. In PHP frameworks and Drupal 8+ codebases, it is customary to use the dependency management tool &lt;em&gt;composer&lt;/em&gt; which obviates the need to check into vcs contributed plugins and modules. The build stage will also compile the front end themes and JavaScript and minify / uglify at the same - therefore production ready CSS and JS should not be committed into vcs by developers. Once the codebase has been built, it will be copied into a PHP/Apache Docker image and pushed into the AWS ECR repository for later use. &lt;/p&gt;

&lt;p&gt;The automated testing will cover both functional BDD and unit TDD testing against the codebase image that has just been built. Writing TDD against the largely procedural Drupal 7 was onerous and challenging and therefore overlooked in the main. Thankfully Drupal 8 is OOP which makes writing back-end tests with PHPUnit much more straightforward. &lt;/p&gt;

&lt;p&gt;The static analysis will check for code quality, vulnerability, smell, copy and paste detection, and basic lint type checking. &lt;/p&gt;

&lt;p&gt;The deploy step can mean different things to different people. Deployment can mean pushing your built codebase to the production server, or it can mean simply creating a semantic versioning tag, and pushing the codebase artefact to an upstream repository, ready for a manual deployment to prod by Ops staff. I have opted for the latter interpretation in this instance.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;CI/CD Ecosystem&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/FargateEcoSystem.png?itok=CxZMMUbk 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2020-01/FargateEcoSystem.png?itok=XlOMVQn6 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2020-01/FargateEcoSystem.png?itok=4cI6vzBk 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2020-01/FargateEcoSystem.png?itok=soBHoax5 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/FargateEcoSystem.png?itok=CxZMMUbk" alt="Ecosystem" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The physical ecosystem is described below and shown in diagrammatic form above. Whilst on first glance this may appear quite complex, in fact it is largely self-evident with a little explanation. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jenkins&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jenkins will be the automation tool since it is ubiquitous across the industry and there is a great deal of expertise in the market place. Jenkins has pipeline capability, and new projects should elect to use the Groovy-based declarative scripting DSL. This allows stages to run in parallel, and thus once the build stage is completed, automated testing and static analysis can be concurrent. In addition I propose the standing up of a 'persisting playground' - the built feature branch of the web app with a DNS qualified relevant url which can be shared between devs, QA, and stakeholders. This would be useful for troubleshooting, demonstrations of progress, show and tells etc., and would be torn down at close of business to reduce costs. My tutorial &lt;a href="http://badzilla.co.uk/create-arbitrary-subdomains-aws-fargate-tasks-using-aws-cli"&gt;here&lt;/a&gt; shows how a friendly branch specific url can be created and propagated by AWS Route 53 within 60 seconds. &lt;/p&gt;

&lt;p&gt;The Jenkins pipeline script is responsible for control flow only; all the actual 'doing' activities, such as building the codebase Docker image on the fly and committing it to ECR, is undertaken by shell scripts spawned from the pipeline. This means the power of AWS CLI can be leveraged to undertake all AWS specific tasks. &lt;/p&gt;

&lt;p&gt;The flow of the pipeline will vary depending upon the digital team's needs. I have elected for the following:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;On PR Creation, run build, automated testing, static analysis, persisting playground&lt;/li&gt;
	&lt;li&gt;On PR Approval, run build, automation testing (and fail the pipeline if testing fails), deploy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously you may have different requirements here such as building on each feature branch commit, but the re-configuration effort will be minimal regardless. Adding conditions on the Jenkins pipeline stages is trivial. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS ECR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The PHP-Apache Docker image is a starting point for creating an image that will include the feature branch built by Jenkins. Detailed instructions on how to achieve this are covered i&lt;a href="http://badzilla.co.uk/programmatically-create-aws-ecr-repository-and-commit-docker-image-ecr"&gt;n my earlier blog&lt;/a&gt;, and once the image is created it is committed to ECR. When a Fargate task is run, it must first be provisioned by fetching all the Docker images it needs, and having the codebase + Apache/PHP local to AWS will improve start-up. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Fargate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jenkins will run up to three concurrent AWS Fargate tasks - a task which includes all the Docker containers to run the automated tests, a task that has the static analysis containers, and the basic web app containers for the persisting playground which will contain Apache+PHP along with probably Memcached or Redis, and any other products and services required by your web app. More on the AWS Fargate task definitions later. &lt;/p&gt;

&lt;p&gt;The automated tests and the static analysis run to conclusion and automatically die once their entry point scripts have run. The persisting playground will run Apache in the foreground to prevent termination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS RDS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is impractical to import db dumps into Fargate tasks, so all Fargate tasks will use one shared database resource. Obviously sharing a database can feasibly lead to schema inconsistencies when different schema changes are being developed on different feature branches. In Drupal these are implemented by &lt;em&gt;drush updatedb &lt;/em&gt;and in PHP frameworks there is always specific command line tooling to perform database migrations. To mitigate against schema inconsistencies, there would need to be communication between developers, and the facility to reset the database to a known develop branch datum with a Jenkins job. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS S3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An export of the develop branch database should be held locally in AWS S3 to facilitate quick import into RDS as required, and updated nightly. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS S3 &amp; AWS Cloudfront&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;File assets such as jpg and png images are normally held in &lt;em&gt;/sites/{default|domain name}/files&lt;/em&gt; in Drupal but are not committed to vcs. These need to be synced from the host's server nightly into S3, and for greater performance the use of Cloudfront acceleration is recommended. Configuration changes will be required in the Drupal or PHP framework codebase to point to the Cloudfront endpoints. Drupal will require the use of the Storage API module or the S3 File System module. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS CloudWatch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fargate integrates with CloudWatch easily, and output from each Docker container in the Fargate task definition will send stdout and stderr to a CloudWatch log group. This is imperative not just for troubleshooting, but also to determine the automated test results. By parsing the logs, a full test output can be created. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slack Integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is desirable for the CI/CD pipeline to be hands-free, i.e. Jenkins login not required unless a manual pipeline invocation is necessary. To achieve this goal, Slack integration is required with job statuses being sent to dedicated Slack channels, and output from the test results also sent through Slack. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Existing Host&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Of course to seed RDS and the file asset S3, we need to get database exports and assets from our existing host. Exactly how to achieve this will vary dependent upon the host. If possible, a slave Jenkins can execute remote jobs on the host to upload the db exports and file assets to RDS and S3 respectively, and that is how I have drawn my diagram. If this is not possible, a combination of scp and rsync will suffice. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Fargate Task Definitions&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/Fargate%20Docker.png?itok=jOoDKprr 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2020-01/Fargate%20Docker.png?itok=sZJoL3eU 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2020-01/Fargate%20Docker.png?itok=wV7fKMmL 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2020-01/Fargate%20Docker.png?itok=Vpzxkv5i 1330w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/Fargate%20Docker.png?itok=jOoDKprr" alt="Fargate Docker Containers" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Fargate tasks can be defined in the AWS Console, but I've already identified that AWS CLI is the tool of choice for programmatic creation. The CLI requires the container definitions in JSON format, and for the pipeline discussed above there would be three Fargate definitions per feature branch. The first is the standard web app which would typically have the PHP/Apache container with the codebase copied into it during a &lt;em&gt;docker build&lt;/em&gt; command. The second is the automated testing stack which includes Maven (which has the Java runtime bundled) along with Selenium grid and two nodes: Firefox and Chrome. I spoke about this Fargate task at length in an earlier blog &lt;a href="http://badzilla.co.uk/aws-fargate-automated-testing-cucumber-gherkin-java-maven-selenium-grid-hub-and-chrome-and-firefox"&gt;here&lt;/a&gt;. The third definition is for static analysis and I am suggesting the excellent jakzal/phpqa repository for this. &lt;/p&gt;

&lt;p&gt;The three tasks would be defined and then run within the Jenkins pipeline. It must be noted that once the tasks have been run they should be immediately deleted from AWS ECR. Storage in ECR is costed, and in the unlikely event of the tasks being required at a later date, they can always be recreated by invoking the pipeline again manually and selecting the feature branch from a drop down list. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;The use of Drupal Drush&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Fargate is a black box, without access to the underlying EC2 infrastructure, and therefore it is not possible to ssh into EC2 and then perform a &lt;em&gt;docker exec &lt;/em&gt;command. Furthermore drush aliases require an ssh daemon running on the target alias to be able to execute remote commands from say a developer working on premises. So how can we run the normal set of everyday drush commands such as to apply schema changes, apply features, split the configuration, flush the caches etc?&lt;/p&gt;

&lt;p&gt;Ok so we have PHP installed on Jenkins since we have to run &lt;em&gt;composer install&lt;/em&gt; in the build stage. We also have an RDS instance with the database. We therefore have what we need to bootstrap Drupal - which is a requirement of drush. &lt;/p&gt;

&lt;p&gt;Therefore all drush commands should be run on Jenkins during the build stage. These commands should be listed in a sibling directory to the codebase's &lt;em&gt;docroot&lt;/em&gt; or &lt;em&gt;web&lt;/em&gt; directory, in say &lt;em&gt;devops_hooks&lt;/em&gt; or some such. As part of the Jenkins build stage, the existence of directory &lt;em&gt;devops_hooks &lt;/em&gt;will be checked, and all shell scripts within it will be run.  &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sat, 04 Jan 2020 13:45:57 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">175 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>AWS Fargate Automated Testing with Cucumber, Gherkin, Java, Maven, Selenium Grid Hub and Chrome and Firefox Nodes</title>
  <link>http://badzilla.co.uk/aws-fargate-automated-testing-cucumber-gherkin-java-maven-selenium-grid-hub-and-chrome-and-firefox</link>
  <description>
&lt;span&gt;AWS Fargate Automated Testing with Cucumber, Gherkin, Java, Maven, Selenium Grid Hub and Chrome and Firefox Nodes&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Mon, 09/12/2019 - 08:37&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Tutorial for creating an automated testing AWS Fargate task that will include Docker containers for a full testing framework:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Maven for build automation&lt;/li&gt;
	&lt;li&gt;Java Runtime to enable the execution of maven and the junit unit testing framework&lt;/li&gt;
	&lt;li&gt;Java Cucumber - a tool for BDD testing&lt;/li&gt;
	&lt;li&gt;Gherkin to define behaviours in the English language&lt;/li&gt;
	&lt;li&gt;Selenium Hub being the central loading point for the tests&lt;/li&gt;
	&lt;li&gt;Selenium Chrome - one of the nodes&lt;/li&gt;
	&lt;li&gt;Selenium Firefox - a second node&lt;/li&gt;
	&lt;li&gt;Apache / PHP - the web app and web server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a trivial exercise but by the end of the blog I will have a working automated testing environment which can be slotted into a DevOps pipeline. Please note this blog is not a tutorial on how to write Cucumber / Gherkin tests, however I will create a few sample Gherkin behaviours and their respective Java Cucumber stepdefs as a starting point. These can then be expanded out by your QA team. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Starting Point&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The starting point will be the simple PHP/Apache web app I put together in my previous blog &lt;a href="http://badzilla.co.uk/programmatically-create-aws-ecr-repository-and-commit-docker-image-ecr"&gt;here&lt;/a&gt; - this is a single url website which merely shows the phpinfo() status page. But it's ideal for our automated testing because our testing framework is plenty complex already, and we can still run a few tests against this simple landing page such as whether the additional PHP extensions I included in the Dockerfile are loaded correctly. &lt;/p&gt;

&lt;p&gt;Now we need to build out our testing tree structure. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;At a sibling level to the docroot directory I created in the previous blog, create the following:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mkdir&lt;/span&gt; &lt;span style="color: #660033;"&gt;-p&lt;/span&gt; mytests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;test&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;java&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mkdir&lt;/span&gt; &lt;span style="color: #660033;"&gt;-p&lt;/span&gt; mytests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;test&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;resources&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Now it's time to create the files I need
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; mytests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;touch&lt;/span&gt; pom.xml
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;touch&lt;/span&gt; src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;test&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;java&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;RunCucumberTest.java
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;touch&lt;/span&gt; src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;test&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;java&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;Stepdefs.java
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;touch&lt;/span&gt; src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;test&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;java&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;SetupTestDriver.java
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;touch&lt;/span&gt; src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;test&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;resources&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;home_page.feature&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
This will create a tree structure like this:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;tree&lt;/span&gt;
.
&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;-- pom.xml
&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;-- src
    &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;-- &lt;span style="color: #7a0874; font-weight: bold;"&gt;test&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;-- &lt;span style="color: #c20cb9; font-weight: bold;"&gt;java&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;   &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;-- mytests
        &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;       &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;-- RunCucumberTest.java
        &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;       &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;-- SetupTestDriver.java
        &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;       &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;-- Stepdefs.java
        &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;-- resources
            &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;-- mytests
                &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;-- home_page.feature
 
&lt;span style="color: #000000;"&gt;6&lt;/span&gt; directories, &lt;span style="color: #000000;"&gt;5&lt;/span&gt; files&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Now we need to flesh out those files we created. Firstly the pom file which contains a list of the project's dependencies. Careful inspection will show you that I used the hellocucumber template as my starting point.&lt;br /&gt;
&lt;strong&gt;pom.xml&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="xml geshifilter-xml" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;?xml&lt;/span&gt; &lt;span style="color: #000066;"&gt;version&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"1.0"&lt;/span&gt; &lt;span style="color: #000066;"&gt;encoding&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"UTF-8"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;project&lt;/span&gt; &lt;span style="color: #000066;"&gt;xmlns&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"http://maven.apache.org/POM/4.0.0"&lt;/span&gt;&lt;/span&gt;
&lt;span style="color: #009900;"&gt;         &lt;span style="color: #000066;"&gt;xmlns:xsi&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;&lt;/span&gt;
&lt;span style="color: #009900;"&gt;         &lt;span style="color: #000066;"&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;modelVersion&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;4.0.0&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/modelVersion&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;hellocucumber&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;mytests&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;1.0.0-SNAPSHOT&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;packaging&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;jar&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/packaging&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;properties&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;cucumber.version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;4.2.6&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/cucumber.version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;project.build.sourceEncoding&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;UTF-8&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/project.build.sourceEncoding&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/properties&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependencies&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;io.cucumber&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;cucumber-java&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;${cucumber.version}&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;scope&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;test&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/scope&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;io.cucumber&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;cucumber-junit&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;${cucumber.version}&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;scope&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;test&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/scope&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;junit&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;junit&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;4.12&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;scope&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;test&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/scope&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
    &lt;span style="color: #808080; font-style: italic;"&gt;&lt;!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager --&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;io.github.bonigarcia&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;webdrivermanager&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;3.7.1&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
	&lt;span style="color: #808080; font-style: italic;"&gt;&lt;!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java --&gt;&lt;/span&gt;
	&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    		&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;org.seleniumhq.selenium&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    		&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;selenium-java&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    		&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;3.141.59&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
    &lt;span style="color: #808080; font-style: italic;"&gt;&lt;!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-chrome-driver --&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;org.seleniumhq.selenium&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;selenium-chrome-driver&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;3.141.59&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
    &lt;span style="color: #808080; font-style: italic;"&gt;&lt;!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-surefire-plugin --&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;org.apache.maven.plugins&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;maven-surefire-plugin&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;2.22.2&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 
 
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;org.slf4j&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;slf4j-api&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;1.5.6&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;org.slf4j&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;slf4j-log4j12&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;1.5.6&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependency&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 
 
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/dependencies&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
 
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;build&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;plugins&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;plugin&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;org.apache.maven.plugins&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/groupId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;maven-compiler-plugin&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/artifactId&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;3.7.0&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/version&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;configuration&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;encoding&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;UTF-8&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/encoding&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;source&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;1.8&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/source&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;target&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;1.8&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/target&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/configuration&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/plugin&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/plugins&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/build&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style="color: #009900;"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;/project&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Now my Gherkin tests themselves. These are rather simple - I am checking for whether my GD and Memecached PHP extensions have been loaded, i.e. they are listed on the front page which just shows the entire PHP configuration. Under normal circumstances Gherkin test tend to be GIVEN..WHEN..THEN constructs, but since I am not actually doing anything (e.g. clicking a button to go somewhere) I only need WHEN..THEN&lt;br /&gt;
&lt;strong&gt;home_page.feature&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;Feature: Are we on the Home Page?
 
 
  Scenario: On the home page
    When User is on the Home Page
    Then Message Displayed Memcached
 
    When User is on the Home Page
    Then Message Displayed GD&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Next is the StepDef file where I convert the Gherkin into Cucumber Java containing the actual business logic behind the quasi-English Gherkin. I don't pretend to be an expert Java coder - I have the sum total of about 4 days experience. Therefore my code is probably sub-optimal, but it does the job and an in-house Java professional could whip it into shape. I have defined two browsers - Firefox and Chrome as per our Selenium configuration, although please note there is currently no semblance of parallel running of the tests in here. That again has been left to more talented Java practitioners than myself. &lt;br /&gt;
&lt;strong&gt;StepDefs.java&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="java geshifilter-java" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;package&lt;/span&gt; &lt;span style="color: #006699;"&gt;mytests&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;base.SetupTestDriver&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;java.util.concurrent.TimeUnit&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.By&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.WebDriver&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.chrome.ChromeDriver&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.firefox.FirefoxDriver&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;io.github.bonigarcia.wdm.WebDriverManager&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;cucumber.api.java.en.Given&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;cucumber.api.java.en.Then&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;cucumber.api.java.en.When&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;java.net.MalformedURLException&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;static&lt;/span&gt; org.&lt;span style="color: #006633;"&gt;junit&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;Assert&lt;/span&gt;.&lt;span style="color: #339933;"&gt;*;&lt;/span&gt;
 
 
&lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;class&lt;/span&gt; Stepdefs &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
 
	&lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;static&lt;/span&gt; WebDriver&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt; drivers&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;static&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt; browsers&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
    @When&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"User is on the Home Page"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;void&lt;/span&gt; user_is_on_Home_Page&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;throws&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+throwable"&gt;&lt;span style="color: #003399;"&gt;Throwable&lt;/span&gt;&lt;/a&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
       	browsers &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
       		&lt;span style="color: #009900;"&gt;{&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"linux"&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;"firefox"&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;"http://127.0.0.1"&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;"http://127.0.0.1:4444"&lt;/span&gt;&lt;span style="color: #009900;"&gt;}&lt;/span&gt;,
            &lt;span style="color: #009900;"&gt;{&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"linux"&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;"chrome"&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;"http://127.0.0.1"&lt;/span&gt;, &lt;span style="color: #0000ff;"&gt;"http://127.0.0.1:4444"&lt;/span&gt;&lt;span style="color: #009900;"&gt;}&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
		drivers &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; WebDriver&lt;span style="color: #009900;"&gt;[&lt;/span&gt;browsers.&lt;span style="color: #006633;"&gt;length&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000066; font-weight: bold;"&gt;int&lt;/span&gt; i &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #cc66cc;"&gt;0&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt; i &lt;span style="color: #339933;"&gt;&lt;&lt;/span&gt; browsers.&lt;span style="color: #006633;"&gt;length&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt; i&lt;span style="color: #339933;"&gt;++&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        	drivers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; SetupTestDriver&lt;span style="color: #009900;"&gt;(&lt;/span&gt;browsers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #cc66cc;"&gt;0&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;, browsers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #cc66cc;"&gt;1&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;, browsers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #cc66cc;"&gt;2&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;, browsers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #cc66cc;"&gt;3&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #006633;"&gt;getDriver&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
    @Then&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"Message Displayed Memcached"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;void&lt;/span&gt; message_displayed_memcached&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;throws&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+throwable"&gt;&lt;span style="color: #003399;"&gt;Throwable&lt;/span&gt;&lt;/a&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000066; font-weight: bold;"&gt;int&lt;/span&gt; i &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #cc66cc;"&gt;0&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt; i &lt;span style="color: #339933;"&gt;&lt;&lt;/span&gt; drivers.&lt;span style="color: #006633;"&gt;length&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt; i&lt;span style="color: #339933;"&gt;++&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        	&lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+boolean"&gt;&lt;span style="color: #003399;"&gt;Boolean&lt;/span&gt;&lt;/a&gt; exists &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #339933;"&gt;!&lt;/span&gt;drivers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;.&lt;span style="color: #006633;"&gt;findElements&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;By.&lt;span style="color: #006633;"&gt;name&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"module_memcached"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #006633;"&gt;isEmpty&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        	drivers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;.&lt;span style="color: #006633;"&gt;quit&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        	assertTrue&lt;span style="color: #009900;"&gt;(&lt;/span&gt;exists&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
	@Then&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"Message Displayed GD"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;void&lt;/span&gt; gd&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;throws&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+throwable"&gt;&lt;span style="color: #003399;"&gt;Throwable&lt;/span&gt;&lt;/a&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000066; font-weight: bold;"&gt;int&lt;/span&gt; i &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #cc66cc;"&gt;0&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt; i &lt;span style="color: #339933;"&gt;&lt;&lt;/span&gt; drivers.&lt;span style="color: #006633;"&gt;length&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt; i&lt;span style="color: #339933;"&gt;++&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
			&lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+boolean"&gt;&lt;span style="color: #003399;"&gt;Boolean&lt;/span&gt;&lt;/a&gt; exists &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #339933;"&gt;!&lt;/span&gt;drivers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;.&lt;span style="color: #006633;"&gt;findElements&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;By.&lt;span style="color: #006633;"&gt;name&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"module_gd"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #006633;"&gt;isEmpty&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        	drivers&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;.&lt;span style="color: #006633;"&gt;quit&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        	assertTrue&lt;span style="color: #009900;"&gt;(&lt;/span&gt;exists&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
	&lt;span style="color: #009900;"&gt;}&lt;/span&gt;
&lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The StepDef file doesn't contain any Firefox or Chrome webdriver startup configuration. This has been placed in a separate Java class.&lt;br /&gt;
&lt;strong&gt;SetupTestDriver.java&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="java geshifilter-java" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;// src/main/java/base/SetupTestDriver.java&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;package&lt;/span&gt; &lt;span style="color: #006699;"&gt;base&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.Platform&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.WebDriver&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.chrome.ChromeOptions&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.firefox.FirefoxOptions&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.firefox.FirefoxProfile&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.firefox.FirefoxDriverLogLevel&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.remote.RemoteWebDriver&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.openqa.selenium.Dimension&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;java.net.MalformedURLException&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;java.net.URL&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;java.util.concurrent.TimeUnit&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;class&lt;/span&gt; SetupTestDriver &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;private&lt;/span&gt; WebDriver driver &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;null&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;private&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; browser &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;null&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;private&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; baseUrl &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;null&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;private&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; os &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;null&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;private&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; node &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;null&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
    &lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; SetupTestDriver&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; os, &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; browser, &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; baseUrl, &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; node&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;throws&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+malformedurlexception"&gt;&lt;span style="color: #003399;"&gt;MalformedURLException&lt;/span&gt;&lt;/a&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;browser&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; browser&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;os&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; os&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;baseUrl&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; baseUrl&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;node&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; node&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
        Platform platform &lt;span style="color: #339933;"&gt;=&lt;/span&gt; Platform.&lt;span style="color: #006633;"&gt;fromString&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;os.&lt;span style="color: #006633;"&gt;toUpperCase&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;browser.&lt;span style="color: #006633;"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"chrome"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
            ChromeOptions chromeOptions &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; ChromeOptions&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            chromeOptions.&lt;span style="color: #006633;"&gt;addArguments&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"--headless"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            chromeOptions.&lt;span style="color: #006633;"&gt;setCapability&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"platform"&lt;/span&gt;, platform&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;driver&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; RemoteWebDriver&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+url"&gt;&lt;span style="color: #003399;"&gt;URL&lt;/span&gt;&lt;/a&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;node &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;"/wd/hub"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;, chromeOptions&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;else&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;browser.&lt;span style="color: #006633;"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"firefox"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
            FirefoxOptions firefoxOptions &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; FirefoxOptions&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            firefoxOptions.&lt;span style="color: #006633;"&gt;setProfile&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; FirefoxProfile&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            firefoxOptions.&lt;span style="color: #006633;"&gt;setCapability&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"platform"&lt;/span&gt;, platform&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            firefoxOptions.&lt;span style="color: #006633;"&gt;setHeadless&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000066; font-weight: bold;"&gt;true&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;driver&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; RemoteWebDriver&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+url"&gt;&lt;span style="color: #003399;"&gt;URL&lt;/span&gt;&lt;/a&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;node &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;"/wd/hub"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;, firefoxOptions&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
        &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;driver&lt;/span&gt;.&lt;span style="color: #006633;"&gt;manage&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #006633;"&gt;timeouts&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #006633;"&gt;implicitlyWait&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #cc66cc;"&gt;10&lt;/span&gt;, TimeUnit.&lt;span style="color: #006633;"&gt;SECONDS&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #666666; font-style: italic;"&gt;// Maximizing the screen doesn't appear to work.&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;driver&lt;/span&gt;.&lt;span style="color: #006633;"&gt;manage&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #006633;"&gt;window&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #006633;"&gt;setSize&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;new&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+dimension"&gt;&lt;span style="color: #003399;"&gt;Dimension&lt;/span&gt;&lt;/a&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #cc66cc;"&gt;1600&lt;/span&gt;,&lt;span style="color: #cc66cc;"&gt;900&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;driver&lt;/span&gt;.&lt;span style="color: #006633;"&gt;get&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;baseUrl&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; getOs&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;os&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; getBrowser&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;browser&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; getBaseUrl&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;baseUrl&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adocs.oracle.com+javase+docs+api+string"&gt;&lt;span style="color: #003399;"&gt;String&lt;/span&gt;&lt;/a&gt; getNode&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;node&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; WebDriver getDriver&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: #006633;"&gt;driver&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
&lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Finally there's some code to perform the glue between Gherkin and Cucumber.&lt;br /&gt;
&lt;strong&gt;RunCucumberTest.java&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="java geshifilter-java" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;package&lt;/span&gt; &lt;span style="color: #006699;"&gt;mytests&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;cucumber.api.CucumberOptions&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;cucumber.api.junit.Cucumber&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;import&lt;/span&gt; &lt;span style="color: #006699;"&gt;org.junit.runner.RunWith&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
@RunWith&lt;span style="color: #009900;"&gt;(&lt;/span&gt;Cucumber.&lt;span style="color: #000000; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;
@CucumberOptions&lt;span style="color: #009900;"&gt;(&lt;/span&gt;plugin &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;"pretty"&lt;/span&gt;&lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;class&lt;/span&gt; RunCucumberTest &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
&lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Build the Docker Codebase + PHP/Apache&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;In my previous blog &lt;a href="http://badzilla.co.uk/programmatically-create-aws-ecr-repository-and-commit-docker-image-ecr"&gt;here&lt;/a&gt; I showed how to add the codebase to the php:7.2-apache image. The codebase has now changed, and I now have two top level sibling directories &lt;em&gt;docroot&lt;/em&gt; and &lt;em&gt;mytests &lt;/em&gt;- which contains the automated test code I've just added. There is a change we need to make to the &lt;em&gt;Dockerfile&lt;/em&gt; in this revision, and the inclusion of an entrypoint script called &lt;em&gt;entry.sh&lt;/em&gt;. The &lt;em&gt;entry.sh &lt;/em&gt;file will copy the test code suite into a shared Fargate non-persistent drive so that the Maven container can access the codebase and run the tests against it. Once the copy of files has been completed, Apache must be run in foreground mode to prevent the container from quitting. Below we have the new version of the &lt;em&gt;Dockerfile&lt;/em&gt;, and the &lt;em&gt;entry.sh&lt;/em&gt; file. The image needs to be rebuilt, but since that was covered in the previous blog, it is omitted here. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;FROM php:&lt;span style="color: #000000;"&gt;7.2&lt;/span&gt;-apache
RUN &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get update&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt; libmemcached-dev zlib1g-dev \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libwebp-dev \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; pecl &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; memcached \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker-php-ext-enable memcached \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker-php-ext-configure gd &lt;span style="color: #660033;"&gt;--with-gd&lt;/span&gt; &lt;span style="color: #660033;"&gt;--with-webp-dir&lt;/span&gt; &lt;span style="color: #660033;"&gt;--with-jpeg-dir&lt;/span&gt; \
       &lt;span style="color: #660033;"&gt;--with-png-dir&lt;/span&gt; &lt;span style="color: #660033;"&gt;--with-zlib-dir&lt;/span&gt; &lt;span style="color: #660033;"&gt;--with-freetype-dir&lt;/span&gt; \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker-php-ext-install gd
COPY &lt;span style="color: #660033;"&gt;--chown&lt;/span&gt;=www-data:www-data .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;www&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;html&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.
COPY entry.sh &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.
ENV AH_SITE_ENVIRONMENT devops
ENV APACHE_DOCUMENT_ROOT &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;www&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;html&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;docroot
RUN &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ri&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;apache2&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites-available&lt;span style="color: #000000; font-weight: bold;"&gt;/*&lt;/span&gt;.conf
RUN &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ri&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s!/var/www/!${APACHE_DOCUMENT_ROOT}!g'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;apache2&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;apache2.conf &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;apache2&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf-available&lt;span style="color: #000000; font-weight: bold;"&gt;/*&lt;/span&gt;.conf
RUN &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;bash&lt;/span&gt; &lt;span style="color: #660033;"&gt;-c&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'chmod +x /usr/local/bin/entry.sh'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;strong&gt;entry.sh&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Copy the automated tests into a shared areaaccessible to maven&lt;/span&gt;
&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; &lt;span style="color: #660033;"&gt;-R&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;www&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;html&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests  &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;automated_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Run Apache in the foreground to prevent the container from quitting&lt;/span&gt;
apache2-foreground&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Maven:3.6.2-jdk-13&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The Java runtime is bundled with the Maven image if the correct tag is selected. I have opted for maven:3.6.2-jdk-13 which is up to date and supported. This requires a small amount of customisation, so again a Dockerfile will be needed. In this instance I want to put a wait loop in the entrypoint script to ensure that there's no attempt to run the tests before the non-persistent shared drive containing the test suite has been mounted by the d8codebase container. At the end I exec the &lt;em&gt;mvn clean install&lt;/em&gt; command to run the tests. &lt;/p&gt;

&lt;p&gt;The easiest way of achieving this is to edit the &lt;em&gt;mvn-entrypoint.sh &lt;/em&gt;script which is in &lt;em&gt;/usrlocal/bin.&lt;/em&gt; I copied out of the image to edit and the Dockerfile copies it back into place. &lt;/p&gt;

&lt;p&gt;Using my previous blog I built this, tagged and pushed to ECR using the image name &lt;em&gt;d8maven. &lt;/em&gt;The instructions aren't copied here for brevity reasons - please refer to my previous blog if you need to. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;FROM maven:3.6.2-jdk-&lt;span style="color: #000000;"&gt;13&lt;/span&gt;
COPY mvn-entrypoint.sh &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mvn-entrypoint.sh
RUN &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;bash&lt;/span&gt; &lt;span style="color: #660033;"&gt;-c&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'chmod +x /usr/local/bin/mvn-entrypoint.sh'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;strong&gt;mvn-entrypoint.sh&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#! /bin/sh -eu&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Copy files from /usr/share/maven/ref into ${MAVEN_CONFIG}&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# So the initial ~/.m2 is set with expected content.&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# Don't override, as this is just a reference setup&lt;/span&gt;
 
copy_reference_files&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;local&lt;/span&gt; &lt;span style="color: #007800;"&gt;log&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$MAVEN_CONFIG&lt;/span&gt;/copy_reference_file.log"&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;local&lt;/span&gt; &lt;span style="color: #007800;"&gt;ref&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"/usr/share/maven/ref"&lt;/span&gt;
 
  &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mkdir&lt;/span&gt; &lt;span style="color: #660033;"&gt;-p&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MAVEN_CONFIG}&lt;/span&gt;/repository"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;touch&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${log}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;dev&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;null &lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt; ; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ref}&lt;/span&gt;"&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;local&lt;/span&gt; &lt;span style="color: #007800;"&gt;reflink&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;""&lt;/span&gt;
      &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; &lt;span style="color: #660033;"&gt;--help&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #660033;"&gt;-q&lt;/span&gt; reflink ; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
          &lt;span style="color: #007800;"&gt;reflink&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"--reflink=auto"&lt;/span&gt;
      &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
      &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-n&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(find "${MAVEN_CONFIG}/repository" -maxdepth 0 -type d -empty 2&gt;/dev/null)&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; ; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# destination is empty...&lt;/span&gt;
          &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"--- Copying all files to &lt;span style="color: #007800;"&gt;${MAVEN_CONFIG}&lt;/span&gt; at &lt;span style="color: #007800;"&gt;$(date)&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&gt;&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${log}&lt;/span&gt;"&lt;/span&gt;
          &lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rv&lt;/span&gt; &lt;span style="color: #800000;"&gt;${reflink}&lt;/span&gt; . &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MAVEN_CONFIG}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&gt;&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${log}&lt;/span&gt;"&lt;/span&gt;
      &lt;span style="color: #000000; font-weight: bold;"&gt;else&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# destination is non-empty, copy file-by-file&lt;/span&gt;
          &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"--- Copying individual files to &lt;span style="color: #007800;"&gt;${MAVEN_CONFIG}&lt;/span&gt; at &lt;span style="color: #007800;"&gt;$(date)&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&gt;&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${log}&lt;/span&gt;"&lt;/span&gt;
          &lt;span style="color: #c20cb9; font-weight: bold;"&gt;find&lt;/span&gt; . &lt;span style="color: #660033;"&gt;-type&lt;/span&gt; f &lt;span style="color: #660033;"&gt;-exec&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sh&lt;/span&gt; &lt;span style="color: #660033;"&gt;-eu&lt;/span&gt; &lt;span style="color: #660033;"&gt;-c&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'
              log="${1}"
              shift
              reflink="${1}"
              shift
              for f in "$@" ; do
                  if [ ! -e "${MAVEN_CONFIG}/${f}" ] || [ -e "${f}.override" ] ; then
                      mkdir -p "${MAVEN_CONFIG}/$(dirname "${f}")"
                      cp -rv ${reflink} "${f}" "${MAVEN_CONFIG}/${f}" &gt;&gt; "${log}"
                  fi
              done
          '&lt;/span&gt; _ &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${log}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${reflink}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt; +
      &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&gt;&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${log}&lt;/span&gt;"&lt;/span&gt;
  &lt;span style="color: #000000; font-weight: bold;"&gt;else&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Can not write to &lt;span style="color: #007800;"&gt;${log}&lt;/span&gt;. Wrong volume permissions? Carrying on ..."&lt;/span&gt;
  &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Wait until we see the test files that are being copied from the PHP/Apache/Codebase container to a shared volume.&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;while&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;!&lt;/span&gt; &lt;span style="color: #660033;"&gt;-d&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;automated_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
  &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;owd&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(pwd)&lt;/span&gt;"&lt;/span&gt;
copy_reference_files
&lt;span style="color: #7a0874; font-weight: bold;"&gt;unset&lt;/span&gt; MAVEN_CONFIG
 
&lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${owd}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;unset&lt;/span&gt; owd
 
&lt;span style="color: #7a0874; font-weight: bold;"&gt;exec&lt;/span&gt; mvn &lt;span style="color: #660033;"&gt;-f&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;automated_tests&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mytests &lt;span style="color: #660033;"&gt;-q&lt;/span&gt; clean &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Define the Fargate Task&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;I now have all parts I need apart from a shell script to actually define the Fargate task which will contain all the config for the containers. I have made extensive use of the heredoc convention in the shell script - one per container definition - which makes it easier to read, and also means when I come to make up other tasks (such as static analysis, and persistent playground) I can simple swap out those containers I don't need.&lt;br /&gt;
&lt;br /&gt;
There are a few comments here to note. &lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;You cannot create a Fargate Task without the IAM ecsTaskExecutionRole, but that will not be created for you. It is however created when you manually create your first Fargate task in the AWS console. Of course ecsTaskExecutionRole can be created programmatically too - and will be the subject of a block at another time.&lt;/li&gt;
	&lt;li&gt;The Fargate task definition will not create your CloudFront log group for you! Therefore I do a check in the script to see if it already exists, and if not then create.&lt;/li&gt;
	&lt;li&gt;I have defined a mount point to where I copy the test suite. This is because the test suite is in the code repository which is copied into the PHP/Apache container, but is needed by the Maven container also.&lt;/li&gt;
	&lt;li&gt;The Selenium Chrome browser is using a non-standard port 5556. This is because it would clash with Firefox otherwise which also defaults to port 5555. You must remember to use an environmental variable NODE_PORT to change the port as well as the hostPort and containerPort.&lt;/li&gt;
	&lt;li&gt;I have defaulted the task's compute to extremely high cpu and memory. They should be reduced using trial and error to avoid incurring high compute fees.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Rewrite branch name so no feature/ hotfix/ forward slash&lt;/span&gt;
&lt;span style="color: #007800;"&gt;BRANCH&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"selenium-testing"&lt;/span&gt;
&lt;span style="color: #007800;"&gt;REPO&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"d8codebase"&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Repo account and repo&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ECR_ACCOUNT&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"XXXXXXXXXXX.dkr.ecr.eu-west-2.amazonaws.com"&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ECR_REPO&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECR_ACCOUNT}&lt;/span&gt;/&lt;span style="color: #007800;"&gt;${REPO,,}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ECS_CLUSTER&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"default"&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the Task Role ARN for executing the task&lt;/span&gt;
&lt;span style="color: #007800;"&gt;TASK_ARN&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws iam get-role &lt;span style="color: #660033;"&gt;--role-name&lt;/span&gt; ecsTaskExecutionRole &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .Role.Arn -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Execution ARN appears to be the same as the Task ARN&lt;/span&gt;
&lt;span style="color: #007800;"&gt;EXECUTION_ARN&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${TASK_ARN}&lt;/span&gt;"&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Determine if the log group already exists: NOTE: "aws ecs register-task-definition" will not create the log group for you!&lt;/span&gt;
&lt;span style="color: #007800;"&gt;LOG_EXISTS&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws logs describe-log-groups &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;".logGroups[] | select(.logGroupName == &lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;/ecs/"&lt;/span&gt;&lt;span style="color: #800000;"&gt;${BRANCH}&lt;/span&gt;&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;) | .logGroupName"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;wc&lt;/span&gt; -l&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${LOG_EXISTS}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-eq&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	aws logs create-log-group &lt;span style="color: #660033;"&gt;--log-group-name&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"/ecs/&lt;span style="color: #007800;"&gt;${BRANCH}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;CONTAINER_CODEBASE&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
	{
		"dnsSearchDomains": [],
		"logConfiguration": {
			"logDriver": "awslogs",
			"options": {
				"awslogs-group": "/ecs/${BRANCH}",
				"awslogs-region": "eu-west-2",
				"awslogs-stream-prefix": "ecs"
			}
		},
		"entryPoint": [
			"/usr/local/bin/entry.sh"
		],
		"portMappings": [{
			"hostPort": 80,
			"protocol": "tcp",
			"containerPort": 80
		}],
		"command": [],
		"cpu": 0,
		"image": "${ECR_REPO}",
		"name": "d8codebase",
		"mountPoints": [{
			"sourceVolume": "automated_tests",
			"containerPath": "/var/automated_tests",
			"readOnly": false
		}]
	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;CONTAINER_SELENIUM_HUB&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
	{
		"dnsSearchDomains": [],
		"logConfiguration": {
			"logDriver": "awslogs",
			"options": {
				"awslogs-group": "/ecs/${BRANCH}",
				"awslogs-region": "eu-west-2",
				"awslogs-stream-prefix": "ecs"
			}
		},
		"entryPoint": [],
		"portMappings": [{
			"hostPort": 4444,
			"protocol": "tcp",
			"containerPort": 4444
		}],
		"command": [],
		"cpu": 0,
		"environment": [{
			"name": "SE_OPTS","value": "-debug"
		}],
		"image": "registry.hub.docker.com/selenium/hub:3.141.59-uranium",
		"name": "selenium-hub"
	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;CONTAINER_SELENIUM_FIREFOX&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
	{
		"dnsSearchDomains": [],
		"logConfiguration": {
			"logDriver": "awslogs",
			"options": {
				"awslogs-group": "/ecs/${BRANCH}",
				"awslogs-region": "eu-west-2",
				"awslogs-stream-prefix": "ecs"
			}
		},
		"entryPoint": [],
		"portMappings": [{
			"hostPort": 5555,
			"protocol": "tcp",
			"containerPort": 5555
		}],
		"command": [],
		"cpu": 0,
		"environment": [{
			"name": "NODE_MAX_INSTANCES", "value": "5"
		},{
			"name": "NODE_MAX_SESSIONS", "value": "5"
		},{
			"name": "HUB_HOST", "value": "127.0.0.1"
		},{
			"name": "HUB_PORT", "value": "4444"
		}],
		"image": "registry.hub.docker.com/selenium/node-firefox:3.141.59-uranium",
		"name": "SeleniumNodeFirefox"
	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;CONTAINER_SELENIUM_CHROME&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
 	{
 		"dnsSearchDomains": [],
 		"logConfiguration": {
 			"logDriver": "awslogs",
 			"options": {
 				"awslogs-group": "/ecs/${BRANCH}",
 				"awslogs-region": "eu-west-2",
 				"awslogs-stream-prefix": "ecs"
 			}
 		},
 		"entryPoint": [],
 		"portMappings": [{
 			"hostPort": 5556,
 			"protocol": "tcp",
 			"containerPort": 5556
 		}],
 		"command": [],
 		"cpu": 0,
 		"environment": [{
 			"name": "NODE_MAX_INSTANCES", "value": "5"
 		},{
 			"name": "NODE_MAX_SESSIONS", "value": "5"
 		},{
 			"name": "HUB_HOST", "value": "127.0.0.1"
 		},{
 			"name": "HUB_PORT", "value": "4444"
 		},{
 			"name": "NODE_PORT", "value": "5556"
 		}],
 		"image": "registry.hub.docker.com/selenium/node-chrome:3.141.59-uranium",
 		"name": "SeleniumNodeChrome"
 	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;CONTAINER_MAVEN&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
	{
		"dnsSearchDomains": [],
		"logConfiguration": {
			"logDriver": "awslogs",
			"options": {
				"awslogs-group": "/ecs/${BRANCH}",
				"awslogs-region": "eu-west-2",
				"awslogs-stream-prefix": "ecs"
			}
		},
		"entryPoint": [],
		"portMappings": [],
		"command": [],
		"cpu": 0,
		"image": "${ECR_ACCOUNT}/d8maven",
		"name": "Maven",
		"essential": true,
		"mountPoints": [{
			"sourceVolume": "automated_tests",
			"containerPath": "/var/automated_tests"
		}]
	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
 
&lt;span style="color: #007800;"&gt;CONTAINERS_AUTOMATIC&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
[
${CONTAINER_CODEBASE},
${CONTAINER_SELENIUM_HUB},
${CONTAINER_SELENIUM_FIREFOX},
${CONTAINER_MAVEN},
${CONTAINER_SELENIUM_CHROME}
]
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
 
aws ecs register-task-definition \
  &lt;span style="color: #660033;"&gt;--family&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"AUTOMATION-&lt;span style="color: #007800;"&gt;${BRANCH}&lt;/span&gt;"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--volumes&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"name=automated_tests,host={}"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--task-role-arn&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$TASK_ARN&lt;/span&gt;"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--execution-role-arn&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${EXECUTION_ARN}&lt;/span&gt;"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--network-mode&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"awsvpc"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--container-definitions&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CONTAINERS_AUTOMATIC}&lt;/span&gt;"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--cpu&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"4096"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--memory&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"30720"&lt;/span&gt; \
  &lt;span style="color: #660033;"&gt;--requires-compatibilities&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"FARGATE"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Running the Fargate Task&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/screencapture-eu-west-2-console-aws-amazon-ecs-home-2019-12-10-16_40_01.png?itok=Fffyjmc5 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/screencapture-eu-west-2-console-aws-amazon-ecs-home-2019-12-10-16_40_01.png?itok=-mwj0Mh3 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/screencapture-eu-west-2-console-aws-amazon-ecs-home-2019-12-10-16_40_01.png?itok=-pRD2LfJ 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/screencapture-eu-west-2-console-aws-amazon-ecs-home-2019-12-10-16_40_01.png?itok=9NKHks8i 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/screencapture-eu-west-2-console-aws-amazon-ecs-home-2019-12-10-16_40_01.png?itok=Fffyjmc5" alt="Run Task" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2016.45.09.png?itok=JCu8fCFw 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/Screenshot%202019-12-10%20at%2016.45.09.png?itok=nNzZaByc 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/Screenshot%202019-12-10%20at%2016.45.09.png?itok=p62Fu_Dl 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/Screenshot%202019-12-10%20at%2016.45.09.png?itok=c3o8LhZS 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2016.45.09.png?itok=JCu8fCFw" alt="Running Task" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2016.45.19.png?itok=O0_8h9c6 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/Screenshot%202019-12-10%20at%2016.45.19.png?itok=rtPVZ1nd 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/Screenshot%202019-12-10%20at%2016.45.19.png?itok=8oFSBSK5 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/Screenshot%202019-12-10%20at%2016.45.19.png?itok=b8-KpJnf 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2016.45.19.png?itok=O0_8h9c6" alt="All containers running" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2016.46.10.png?itok=HtC-w96y 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/Screenshot%202019-12-10%20at%2016.46.10.png?itok=adcaUdoh 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/Screenshot%202019-12-10%20at%2016.46.10.png?itok=G5h9B1j2 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/Screenshot%202019-12-10%20at%2016.46.10.png?itok=E1G0Wpgh 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2016.46.10.png?itok=HtC-w96y" alt="All containers stopped" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Once the script is executed, the task will be defined and ready to run. This can be run by creating a new shell script (or extending the one above) or by using the console. Since this blog is becoming too code focused, I'll document the running of tasks programmatically in another blog later. For now you should be able to see your task in the console and run it. See screenshot 1 above.&lt;/p&gt;

&lt;p&gt;Screenshot 2 show that the task has reached RUNNING state. If you are quick you can click on the task identifier and be taken to the more detailed screen shown in image 3 which shows all the containers that are running. &lt;/p&gt;

&lt;p&gt;Once one of the Docker images completes its activity, a signal will be sent to all the other containers to stop. In the task described in this blog, the first task to complete is the running of the automated tests. Once the tests complete, then all other containers will stop. See image 4. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Did the Tests Actually Succeed?&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/screencapture-eu-west-2-console-aws-amazon-cloudwatch-home-2019-12-10-16_55_13.png?itok=E8ySuBsU 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/screencapture-eu-west-2-console-aws-amazon-cloudwatch-home-2019-12-10-16_55_13.png?itok=TvSbKodT 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/screencapture-eu-west-2-console-aws-amazon-cloudwatch-home-2019-12-10-16_55_13.png?itok=kMWLfPE5 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/screencapture-eu-west-2-console-aws-amazon-cloudwatch-home-2019-12-10-16_55_13.png?itok=PnCz6kAM 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/screencapture-eu-west-2-console-aws-amazon-cloudwatch-home-2019-12-10-16_55_13.png?itok=E8ySuBsU" alt="CloudWatch success" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;A valid question! The output of the Maven container is written to a CloudWatch log stream which can be parsed and echoed back to the screen, or sent to a Slack channel (more on this in a later blog). For now I have created a sequence of commands using pipes which includes the open source &lt;strong&gt;awslogs&lt;/strong&gt; utility.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ aws logs describe-log-streams &lt;span style="color: #660033;"&gt;--log-group-name&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"/ecs/selenium-testing"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--log-stream-name-prefix&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"ecs/Maven"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;'.logStreams|=sort_by(-.creationTime)|.logStreams[0].logeamName'&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;xargs&lt;/span&gt; -I&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt; awslogs get &lt;span style="color: #ff0000;"&gt;"/ecs/selenium-testing"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt; &lt;span style="color: #660033;"&gt;-s1d&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;cut&lt;/span&gt; &lt;span style="color: #660033;"&gt;-d&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;' '&lt;/span&gt; &lt;span style="color: #660033;"&gt;-f&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;,&lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #660033;"&gt;--complement&lt;/span&gt;
mvn
&lt;span style="color: #660033;"&gt;-------------------------------------------------------&lt;/span&gt;
 T E S T S
&lt;span style="color: #660033;"&gt;-------------------------------------------------------&lt;/span&gt;
Running mytests.RunCucumberTest
Dec &lt;span style="color: #000000;"&gt;10&lt;/span&gt;, &lt;span style="color: #000000;"&gt;2019&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt;:&lt;span style="color: #000000;"&gt;43&lt;/span&gt;:&lt;span style="color: #000000;"&gt;46&lt;/span&gt; PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
Dec &lt;span style="color: #000000;"&gt;10&lt;/span&gt;, &lt;span style="color: #000000;"&gt;2019&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt;:&lt;span style="color: #000000;"&gt;43&lt;/span&gt;:&lt;span style="color: #000000;"&gt;47&lt;/span&gt; PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
Dec &lt;span style="color: #000000;"&gt;10&lt;/span&gt;, &lt;span style="color: #000000;"&gt;2019&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt;:&lt;span style="color: #000000;"&gt;43&lt;/span&gt;:&lt;span style="color: #000000;"&gt;49&lt;/span&gt; PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
Dec &lt;span style="color: #000000;"&gt;10&lt;/span&gt;, &lt;span style="color: #000000;"&gt;2019&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt;:&lt;span style="color: #000000;"&gt;43&lt;/span&gt;:&lt;span style="color: #000000;"&gt;50&lt;/span&gt; PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
Feature: Are we on the Home Page?
  Scenario: On the home page         &lt;span style="color: #666666; font-style: italic;"&gt;# mytests/home_page.feature:4&lt;/span&gt;
    When User is on the Home Page    &lt;span style="color: #666666; font-style: italic;"&gt;# Stepdefs.user_is_on_Home_Page()&lt;/span&gt;
    Then Message Displayed Memcached &lt;span style="color: #666666; font-style: italic;"&gt;# Stepdefs.message_displayed_memcached()&lt;/span&gt;
    When User is on the Home Page    &lt;span style="color: #666666; font-style: italic;"&gt;# Stepdefs.user_is_on_Home_Page()&lt;/span&gt;
    Then Message Displayed GD        &lt;span style="color: #666666; font-style: italic;"&gt;# Stepdefs.gd()&lt;/span&gt;
&lt;span style="color: #000000;"&gt;1&lt;/span&gt; Scenarios &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt; passed&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; Steps &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;4&lt;/span&gt; passed&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
0m6.835s
Tests run: &lt;span style="color: #000000;"&gt;1&lt;/span&gt;, Failures: &lt;span style="color: #000000;"&gt;0&lt;/span&gt;, Errors: &lt;span style="color: #000000;"&gt;0&lt;/span&gt;, Skipped: &lt;span style="color: #000000;"&gt;0&lt;/span&gt;, Time elapsed: &lt;span style="color: #000000;"&gt;7.055&lt;/span&gt; sec
Results :
Tests run: &lt;span style="color: #000000;"&gt;1&lt;/span&gt;, Failures: &lt;span style="color: #000000;"&gt;0&lt;/span&gt;, Errors: &lt;span style="color: #000000;"&gt;0&lt;/span&gt;, Skipped: &lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Troubleshooting Selenium Grid&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2017.17.52.png?itok=CyMh5g8X 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/Screenshot%202019-12-10%20at%2017.17.52.png?itok=uKKQA2e6 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/Screenshot%202019-12-10%20at%2017.17.52.png?itok=XEv9FUiO 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/Screenshot%202019-12-10%20at%2017.17.52.png?itok=UcTRu0a3 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2017.17.52.png?itok=CyMh5g8X" alt="Custom Rule" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2017.18.24.png?itok=3Jg4RYn9 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/Screenshot%202019-12-10%20at%2017.18.24.png?itok=xTq_OE_n 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/Screenshot%202019-12-10%20at%2017.18.24.png?itok=aNF-w9z5 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/Screenshot%202019-12-10%20at%2017.18.24.png?itok=EuDe0bIn 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-10%20at%2017.18.24.png?itok=3Jg4RYn9" alt="Selenium Grid" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Getting the Selenium stack working can be fiddly, although the CloudWatch logs are a very good way of diagnosing problems. If you want to satisy yourself that Selenium Hub and its two nodes (Firefox and Chrome) are actually there and available, there is a way but you'll have to work fast on the console since the Fargate tasks completes and shuts down once the tests are complete. &lt;/p&gt;

&lt;p&gt;When the Fargate task transitions from PENDING to RUNNING, click on the task identifier. Copy the public IP address into your clipboard - you'll need it shortly. Now click on the ENI (Elastic Network Interface) link which will launch a new tab. Then click on the security group. Now you need to create a new rule. By default port 4444 is blocked on the public IP address - and to see Selenium working I need that to be open. &lt;/p&gt;

&lt;p&gt;Edit the rules, create a new custom TCP/IP rule, add 4444 as the port and select anywhere for the CIDR, then save. See screenshot 1 above. &lt;/p&gt;

&lt;p&gt;You now instantly have an open port 4444. Open a new browser tab, then paste the IP address you copied a few steps ago, then append /grid/console to it and enter. You should see your Grid + Node configuration as per the second screenshot above. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/ecs" hreflang="en"&gt;ECS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/development" hreflang="en"&gt;Development&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/docker" hreflang="en"&gt;Docker&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/bash" hreflang="en"&gt;bash&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Mon, 09 Dec 2019 08:37:50 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">173 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Programmatically Create AWS ECR Repository and Commit Docker Image to ECR</title>
  <link>http://badzilla.co.uk/programmatically-create-aws-ecr-repository-and-commit-docker-image-ecr</link>
  <description>
&lt;span&gt;Programmatically Create AWS ECR Repository and Commit Docker Image to ECR&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sat, 07/12/2019 - 07:56&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;This is a tutorial for using AWS CLI to programmatically create an AWS ECR repository and then commit a Docker image to that repository. This is the first step in a series of tutorials for creating an automated testing framework in AWS Fargate which can be one step of a DevOps pipeline. &lt;/p&gt;

&lt;p&gt;As an example I am going to use the Docker php:7.2-apache image and to make it a little more complex, add a few more PHP extensions using a new Dockerfile so that my new image will be Drupal 8 compliant. &lt;/p&gt;

&lt;p&gt;Let's get started. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Pull Base Image and Define Dockerfile&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The base php:7.2-apache image needs to be pulled from Docker Hub. Issue the following command. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ docker pull php:&lt;span style="color: #000000;"&gt;7.2&lt;/span&gt;-apache
&lt;span style="color: #000000;"&gt;7.2&lt;/span&gt;-apache: Pulling from library&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php
000eee12ec04: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
8ae4f9fcfeea: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
60f22fbbd07a: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
ccc7a63ad75f: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
a2427b8dd6e7: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
91cac3b30184: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
d6e40015fc10: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
240e21c03bb4: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
504858e1e4aa: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
9a0523b2d73f: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
e3acb84829f4: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
28a372733f87: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
62ee66cdb80a: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
c3f368ddc7aa: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
Digest: sha256:602bef9acc8d54527ae5b7ee0f16e5cdb6ab81364310f5123b93b95e357f608d
Status: Downloaded newer image &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; php:&lt;span style="color: #000000;"&gt;7.2&lt;/span&gt;-apache
docker.io&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;library&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php:&lt;span style="color: #000000;"&gt;7.2&lt;/span&gt;-apache
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
php                 &lt;span style="color: #000000;"&gt;7.2&lt;/span&gt;-apache          fec8a1aaffb8        &lt;span style="color: #000000;"&gt;31&lt;/span&gt; hours ago        410MB
lambci&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lambda       go1.x               8d962cde7e27        &lt;span style="color: #000000;"&gt;3&lt;/span&gt; months ago        707MB
sls-docker          latest              8d962cde7e27        &lt;span style="color: #000000;"&gt;3&lt;/span&gt; months ago        707MB&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Yes the docker image is there. Now I need to create a directory for the Dockerfile and a sample index.php file which will prove our image is working. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666;"&gt;$ &lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;mkdir&lt;/span&gt; automated &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; automated&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
By default the Docker php image uses /var/www/html as Apache's docroot. However, I'm going to alter this to something more standard for Drupal web apps - a directory called docroot will be created and will contain a simple index.php containing a call to phpinfo();
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666;"&gt;$ &lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;mkdir&lt;/span&gt; docroot &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;?php phpinfo();"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; docroot&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;index.php&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
The Dockerfile should now be created and populated. There a number of activities that need to be performed on it. 
&lt;ul&gt;
&lt;li&gt;Reference the base image with a FROM instruction&lt;/li&gt;
&lt;li&gt;Install the libraries that support memcached and graphics manipulation&lt;/li&gt;
&lt;li&gt;Enable memcached PHP extension&lt;/li&gt;
&lt;li&gt;Configure the graphics PHP extension&lt;/li&gt;
&lt;li&gt;Install the graphics PHP extension&lt;/li&gt;
&lt;li&gt;Copy the files in the current directory and below into the Docker image at the /var/www/html ensuring the permissions are correct for the apache user and group&lt;/li&gt;
&lt;li&gt;Set the environment variable AH_SITE_ENVIRONMENT to devops - this is an Acquia Cloud environment variable and only of any significance for those using Acquia as their host - or need a setting in my case to denote that devops is not running on Acquia&lt;/li&gt;
&lt;li&gt;Change the default location for the docroot - that means setting an environment variable and using the sed editor to change the configuration in the sites files&lt;/li&gt;
&lt;/ul&gt;
&lt;strong&gt;Dockerfile&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;FROM php:&lt;span style="color: #000000;"&gt;7.2&lt;/span&gt;-apache
RUN &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get update&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt; libmemcached-dev zlib1g-dev \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libwebp-dev \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; pecl &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; memcached \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker-php-ext-enable memcached \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker-php-ext-configure gd &lt;span style="color: #660033;"&gt;--with-gd&lt;/span&gt; &lt;span style="color: #660033;"&gt;--with-webp-dir&lt;/span&gt; &lt;span style="color: #660033;"&gt;--with-jpeg-dir&lt;/span&gt; \
       &lt;span style="color: #660033;"&gt;--with-png-dir&lt;/span&gt; &lt;span style="color: #660033;"&gt;--with-zlib-dir&lt;/span&gt; &lt;span style="color: #660033;"&gt;--with-freetype-dir&lt;/span&gt; \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker-php-ext-install gd
COPY &lt;span style="color: #660033;"&gt;--chown&lt;/span&gt;=www-data:www-data .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;www&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;html&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.
ENV AH_SITE_ENVIRONMENT devops
ENV APACHE_DOCUMENT_ROOT &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;www&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;html&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;docroot
RUN &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ri&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;apache2&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites-available&lt;span style="color: #000000; font-weight: bold;"&gt;/*&lt;/span&gt;.conf
RUN &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ri&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s!/var/www/!${APACHE_DOCUMENT_ROOT}!g'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;apache2&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;apache2.conf &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;apache2&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf-available&lt;span style="color: #000000; font-weight: bold;"&gt;/*&lt;/span&gt;.conf&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Build the Image, Run the Container&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-07%20at%2012.17.34.png?itok=jwU0kVpn 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/Screenshot%202019-12-07%20at%2012.17.34.png?itok=XLFrcLyd 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/Screenshot%202019-12-07%20at%2012.17.34.png?itok=7J5O5LHx 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/Screenshot%202019-12-07%20at%2012.17.34.png?itok=eCD6F2Tg 2310w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot%202019-12-07%20at%2012.17.34.png?itok=jwU0kVpn" alt="phpinfo" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Once the Dockerfile is complete, it is built with
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666;"&gt;$ &lt;/span&gt;docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; d8codebase .&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
and to confirm it's built correctly:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
d8codebase          latest              c2193f9778a6        &lt;span style="color: #000000;"&gt;33&lt;/span&gt; minutes ago      439MB
&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;none&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;              &lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;none&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;              2a71964685e0        &lt;span style="color: #000000;"&gt;2&lt;/span&gt; hours ago         432MB
php                 &lt;span style="color: #000000;"&gt;7.2&lt;/span&gt;-apache          fec8a1aaffb8        &lt;span style="color: #000000;"&gt;35&lt;/span&gt; hours ago        410MB
lambci&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lambda       go1.x               8d962cde7e27        &lt;span style="color: #000000;"&gt;3&lt;/span&gt; months ago        707MB
sls-docker          latest              8d962cde7e27        &lt;span style="color: #000000;"&gt;3&lt;/span&gt; months ago        707MB&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Great it's there. Now to spin up the container. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666;"&gt;$ &lt;/span&gt;docker run &lt;span style="color: #660033;"&gt;-d&lt;/span&gt; &lt;span style="color: #660033;"&gt;-p&lt;/span&gt; &lt;span style="color: #000000;"&gt;8080&lt;/span&gt;:&lt;span style="color: #000000;"&gt;80&lt;/span&gt; d8codebase&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Note I am mapping port 8080 to the container's port 80 which probably won't be pertinent to you. Long story I will try to make short. I write my blogs on my Macbook on a local network in the 192.168 range assigned by my ISP's hub. But I develop and test all the practical work in my blogs in a VM in the IP 10. range. Routing between 192.168 and 10. is difficult without port forwarding - so I port forward 127.0.0.1 8080 to my VM's 10.0.2.15 8080, so when I run my Docker Apache container I must remember incoming is on port 8080 and map that against the container's port 80. Hope that makes sense!&lt;br /&gt;&lt;br /&gt;Now check it's running:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;ps&lt;/span&gt;
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
9a6dc2fb88ff        d8codebase          &lt;span style="color: #ff0000;"&gt;"docker-php-entrypoi…"&lt;/span&gt;   &lt;span style="color: #000000;"&gt;44&lt;/span&gt; minutes ago      Up &lt;span style="color: #000000;"&gt;44&lt;/span&gt; minutes       0.0.0.0:&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;-&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;80&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;tcp   agitated_feistel&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Yes, and we can see from the screenshot above that it's picking up the memcached and the gd graphics extensions. Success.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Programmatically Create the AWS ECR Repository&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot_2019-12-07_at_13_16_14-edited.png?itok=eiXr6OXC 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/Screenshot_2019-12-07_at_13_16_14-edited.png?itok=6-TIckwl 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/Screenshot_2019-12-07_at_13_16_14-edited.png?itok=inIVYe9n 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/Screenshot_2019-12-07_at_13_16_14-edited.png?itok=cBSia9gB 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot_2019-12-07_at_13_16_14-edited.png?itok=eiXr6OXC" alt="ECR Repository" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;This is quite easy and I've put it into a shell script that requires one parameter - the repo name to be created. The work is done by the aws ecr create-repository call. The rest of the code is simply checking for error conditions. The screenshot above was taken on the AWS console after the shell script below was successfully run with a parameter of d8codebase.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;#Programmatically create an ECR repo&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Check whether we have the args&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; $&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"usage: [repo_name]"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Create the repo&lt;/span&gt;
&lt;span style="color: #007800;"&gt;REPO_NAME&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecr create-repository &lt;span style="color: #660033;"&gt;--repository-name&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"$1"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .repository.repositoryName -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Check it was created ok. We already get a quality stderr msg from aws cli so just quit on error.&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# Similarly, if already exists it will tell us&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${REPO_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;!&lt;/span&gt;= &lt;span style="color: #007800;"&gt;$1&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Successfully created &lt;span style="color: #007800;"&gt;${REPO_NAME}&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Login to Docker and Push Image to ECR&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot_2019-12-08_at_10_20_26-edited.png?itok=sv0QPbaX 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-12/Screenshot_2019-12-08_at_10_20_26-edited.png?itok=AEUf4O-_ 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-12/Screenshot_2019-12-08_at_10_20_26-edited.png?itok=z9aPZ3kh 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-12/Screenshot_2019-12-08_at_10_20_26-edited.png?itok=JirTlXB0 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-12/Screenshot_2019-12-08_at_10_20_26-edited.png?itok=sv0QPbaX" alt="Docker Push" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Now the script to automatically login to Docker and push the image to ECR. Note that AWS ECR does require you to use the docker login command, and therefore provides a AWS CLI ECR command get-login which returns a token than can be piped into the docker login command. The token retrieved from ECR has a large payload, and it is top and tailed with other metadata beyond just the password. Therefore that needs to be removed, and if you look closely at the script below, you can see that I pipe the entire returned payload through sed with a regex, and then the result is piped onwards to docker login. Hopefully the rest is quite self explanatory - and you can see the screenshot above that the push has worked and the image can now be included in ECS / Fargate task definitions. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;#Programmatically push to an ECR repo&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Check whether we have the args&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; $&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"usage: [repo_name]"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;REPO_NAME&lt;/span&gt;=&lt;span style="color: #007800;"&gt;$1&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ECR_ACCOUNT&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"XXXXXXXXXX.dkr.ecr.eu-west-2.amazonaws.com"&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ECR_REPO&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECR_ACCOUNT}&lt;/span&gt;/$1"&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# AWS Authentication - since we need to use docker push&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# The sed regex will top and tail the additional meta data sent by the aws login request.&lt;/span&gt;
aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; eu-west-&lt;span style="color: #000000;"&gt;2&lt;/span&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #800000;"&gt;${ECR_ACCOUNT}&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the image id of the Docker build. If there is a "latest" use that else get the first without latest&lt;/span&gt;
&lt;span style="color: #007800;"&gt;TAG&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;docker images &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #660033;"&gt;-w&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${REPO_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; latest &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;awk&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'{ print $3; }'&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #800000;"&gt;${TAG}&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;TAG&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;docker images &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #660033;"&gt;-w&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${REPO_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;awk&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'{ print $3; }'&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
docker tag &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$TAG&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECR_REPO}&lt;/span&gt;"&lt;/span&gt;
docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECR_REPO}&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/docker" hreflang="en"&gt;Docker&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/fargate" hreflang="en"&gt;Fargate&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/ecs" hreflang="en"&gt;ECS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/development" hreflang="en"&gt;Development&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/bash" hreflang="en"&gt;bash&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sat, 07 Dec 2019 07:56:15 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">172 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Create Arbitrary Subdomains for AWS Fargate Tasks using AWS CLI</title>
  <link>http://badzilla.co.uk/create-arbitrary-subdomains-aws-fargate-tasks-using-aws-cli</link>
  <description>
&lt;span&gt;Create Arbitrary Subdomains for AWS Fargate Tasks using AWS CLI&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Fri, 01/11/2019 - 15:03&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-11/Screenshot_2019-11-03_at_11_24_32-edited1.png?itok=t3-00HWu 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-11/Screenshot_2019-11-03_at_11_24_32-edited1.png?itok=dcZAK-DY 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-11/Screenshot_2019-11-03_at_11_24_32-edited1.png?itok=aY5EToiP 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-11/Screenshot_2019-11-03_at_11_24_32-edited1.png?itok=MUHYEW-M 1695w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-11/Screenshot_2019-11-03_at_11_24_32-edited1.png?itok=t3-00HWu" alt="Success" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;AWS Fargate is a relatively new product offering the capability of running Docker bundles as an ECS compute service on EC2 without the necessity for the user to have to orchestrate the underlying EC2 infrastructure. It is perfect for DevOps, and was the technology I chose as DevOps Architect at my current client. The client wanted standard CI/CD capabilities such as spinning up containerised copies of their website environment per feature branch to perform static analysis, automated testing, and also significantly, a persisting playground that QA or development personnel could use for manual testing and troubleshooting a feature (or hotfix) branch they are currently working on.&lt;/p&gt;

&lt;p&gt;This is similar to the offering of both Platform.sh and Amazee Labs hosting solutions - developers can spin up their feature branches. Alas my client is locked into another host yet needed on-the-fly feature branch Docker bundles.&lt;/p&gt;

&lt;p&gt;AWS Fargate tasks can achieve this, but out of the box it isn't possible to create public domain registration via ECS Service Discovery. The Fargate task is issued a bare IPv4 address which will obviously work but our requirement is to have a subdomain created per branch that would be of the format {hotfix|feature}--{jira ticket}-{suitable branch name}.{top level domain}.  So an example would be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;feature--doi-746-my-whizzy-new-feature.clientdomain.dev&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So whilst we can't create a subdomain like that natively, we can do it by retrieving the IP address from the ECS Fargate task, then add that IP to a public Route 53 Hosted Zone. Furthermore, since the Fargate task is run via a Jenkins pipeline job that uses shell scripts populated with AWS CLI, the good news is we can indeed complete the registration of subdomain also using the AWS CLI *and* have the DNS propagate within 60 seconds! Amazing! Let's dive into how we achieve this. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Requirements + Assumptions&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The solution will be built using the standard httpd Apache2 server sample Fargate task described on the AWS blog &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_AWSCLI_Fargate.html"&gt;Tutorial: Creating a Cluster with a Fargate Task Using the AWS CLI&lt;/a&gt;. I added the task definition into the console, although it is also possible create a shell script and use AWS CLI. I have used the default cluster for brevity's sake, and the AWS account default VPC. I have also transferred a spare domain I had, &lt;em&gt;saasidate.com&lt;/em&gt;, into Route 53 before I started the blog. This will be my tld and all the subdomains will be added off it. It's important that the ownership of the domain is transferred into Route 53 since otherwise subdomains will have authority issues if the parent domain is still registered to other domain providers such as GoDaddy or 123-Reg. &lt;/p&gt;
&lt;p&gt;The solution I am putting together will use AWS CLI which by default returns JSON structured data. It is absolutely essential to use the Linux command line utility &lt;strong&gt;jq&lt;/strong&gt; for parsing the JSON. Documentation on jq is readily available on the net. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Steps&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The solution will need the following steps:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Get the user's default VPC (or create a custom VPC if preferred. We'll need this at a few points in the code. &lt;/li&gt;
	&lt;li&gt;Get a subnet from the VPC. Three subnets are created for use with the default VPC. I pick the first which is arbitrary.&lt;/li&gt;
	&lt;li&gt;Get a security group. A new security group is created per task when using the console but that is unnecessary for the shell scripts we will be building. So in our script, check whether our 'standard' security group has been created. If so use it, if not then create a security group with an ingress port of 80 and a CIDR of 0.0.0.0/0 which allows access worldwide on TCP port 80.&lt;/li&gt;
	&lt;li&gt;Run the Fargate task and loop / sleep until the task has a status of RUNNING. &lt;/li&gt;
	&lt;li&gt;Get the network interface id of the task and interrogate it for the IP address. &lt;/li&gt;
	&lt;li&gt;Get the hosted zone for the parent domain.&lt;/li&gt;
	&lt;li&gt;Add a record set containing the feature branch subdomain to the parent domain's hosted zone.&lt;/li&gt;
	&lt;li&gt;Create a new hosted zone using the feature branch. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ok - let's crack on and put this into AWS CLI shell scripts. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Get the VPC&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;I'm using the default VPC so I can filter the list I get back from AWS using the IsDefault attribute. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #007800;"&gt;VPC&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 describe-vpcs &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;'.Vpcs[] | select(.IsDefault == true) | .VpcId'&lt;/span&gt; -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Note the use of the jq select statement. This is a familiar construct and will be used throughout this blog. Also note the -r flag - this removes the double quotes from the response.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Get the First Subnet in the Default VPC&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Here I am using jq again but piping the results through head to get the first subnet. There wasn't an obvious jq query to do this natively within jq. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;# Get the first subnet of the VPC&lt;/span&gt;
&lt;span style="color: #007800;"&gt;SUBNET&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 describe-subnets &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #660033;"&gt;--arg&lt;/span&gt; VPC &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$VPC&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'.Subnets[] | select(.VpcId == $VPC) | .SubnetId'&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;head&lt;/span&gt; &lt;span style="color: #660033;"&gt;-n&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Get the Security Group&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Here I check whether we already have a dedicated security group which gives us worldwide access to port 80. I search first for a unique security group description and if it doesn't exist, then create it.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;# Check if our security group for port 80 webserver already exists. Search for our funky unique description&lt;/span&gt;
&lt;span style="color: #007800;"&gt;SECURITY&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 describe-security-groups &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;' .SecurityGroups[] | select (.Description == "Ingress Port 80 Anywhere") | .GroupId'&lt;/span&gt; -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Let's inspect what we got back.&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-security-groups failed with code $?"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# If we didn't get a security group then create&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$SECURITY&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #007800;"&gt;SECURITY&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 create-security-group \
		&lt;span style="color: #660033;"&gt;--description&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Ingress Port 80 Anywhere"&lt;/span&gt; \
		&lt;span style="color: #660033;"&gt;--group-name&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Fargate Webserver Port 80"&lt;/span&gt; \
		&lt;span style="color: #660033;"&gt;--vpc-id&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$VPC&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .GroupId &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
 
	aws ec2 authorize-security-group-ingress \
		&lt;span style="color: #660033;"&gt;--group-id&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$SECURITY&lt;/span&gt;"&lt;/span&gt; \
		&lt;span style="color: #660033;"&gt;--ip-permissions&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"FromPort=80,ToPort=80,IpProtocol=TCP,IpRanges=[{CidrIp=0.0.0.0/0}]"&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Run the Fargate Task&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Next I run the Fargate task. This is the sample Fargate task covered in the AWS documentation and uses the httpd docker image. When I created it in the console I called it "first-run-task-definition" - for the life of me I can't remember why I chose such a crazy name! Note I am piping the result through jq as per normal and then onwards through sed to get the task id without all the arn information that precedes it. The sed command looks for the final forward slash in the task arn and crops anything before it. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;# Run the task and parse the task ARN for polling later to determine its status&lt;/span&gt;
&lt;span style="color: #007800;"&gt;TASK&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs run-task \
	&lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"default"&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--task-definition&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"first-run-task-definition"&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--network-configuration&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"awsvpcConfiguration={subnets=[&lt;span style="color: #007800;"&gt;${SUBNET}&lt;/span&gt;],securityGroups=[&lt;span style="color: #007800;"&gt;${SECURITY}&lt;/span&gt;],assignPublicIp=ENABLED}"&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--launch-type&lt;/span&gt; FARGATE  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .tasks&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.taskArn &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"s/.*\///"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Let's inspect what we got back. There should be a task identifier.&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"task-run failed with code $?"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$TASK&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"task-run could not create task"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Loop and Wait for Fargate Task to get to RUNNING Status&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Next I have to wait for the task to acquire RUNNING status, However I can't wait for ever, and thus I have wrapped a shell script rule into a timeout mechanism. I have allowed for 5 minutes for the task to get to RUNNING status and that should be more than enough.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;# Loop around until we see a RUNNING status or timeout after 10 x 30 second sleeps&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; i &lt;span style="color: #000000; font-weight: bold;"&gt;in&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #000000;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;6&lt;/span&gt; &lt;span style="color: #000000;"&gt;7&lt;/span&gt; &lt;span style="color: #000000;"&gt;8&lt;/span&gt; &lt;span style="color: #000000;"&gt;9&lt;/span&gt; &lt;span style="color: #000000;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$i&lt;/span&gt; &lt;span style="color: #660033;"&gt;-eq&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Timed out before could establish task is running"&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
	&lt;span style="color: #007800;"&gt;STATUS&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs describe-tasks &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"default"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tasks&lt;/span&gt; &lt;span style="color: #007800;"&gt;$TASK&lt;/span&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .tasks&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.lastStatus -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
	&lt;span style="color: #666666; font-style: italic;"&gt;# Did it exit unexpectedly?&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-tasks failed with code $?"&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
	&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$STATUS&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;"RUNNING"&lt;/span&gt;  &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;break&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
	&lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;30&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Obtain the Network Interface Id&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The ENI is available in the Fargate task's description so I needed to parse this on my quest to get the public IP. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;# Get the network Interface id&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ENI&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs describe-tasks &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"default"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tasks&lt;/span&gt; &lt;span style="color: #007800;"&gt;$TASK&lt;/span&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;'.tasks[0].attachments[0].details[] | select(.name == "networkInterfaceId") | .value'&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Let's inspect what we got back. There should be a network interface id.&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-tasks failed with code $?"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$ENI&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-tasks could not establish eni"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Get the Public IP Address&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;With the ENI it is possible to parse the the descriptions of all the network interfaces for the public IP address. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #007800;"&gt;PUBLIC_IP&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 describe-network-interfaces &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #660033;"&gt;--arg&lt;/span&gt; ENI &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$ENI&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'.NetworkInterfaces[] | select(.NetworkInterfaceId == $ENI) | .PrivateIpAddresses[0].Association.PublicIp'&lt;/span&gt; -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Did we get an IP address?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-network-interfaces failed with code $?"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$PUBLIC_IP&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-network-interfaces could not retrieve public IP address"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Get the Parent Domain's Hosted Zone Id&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The shell script needs to know about the parent domain and the subdomain name (which in my case is a feature branch name) - so those need to be retrieved from runtime arguments. This will go at the top of the shell script.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #007800;"&gt;$1&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;||&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #007800;"&gt;$2&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"usage: parent_domain_name feature_branch_name"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;BRANCH&lt;/span&gt;=&lt;span style="color: #007800;"&gt;$2&lt;/span&gt;.&lt;span style="color: #007800;"&gt;$1&lt;/span&gt;
&lt;span style="color: #007800;"&gt;PARENT&lt;/span&gt;=&lt;span style="color: #007800;"&gt;$1&lt;/span&gt;.&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Then continuing at the end of the codebase, the following gets the parent domain
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #007800;"&gt;PARENT_ZONE&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws route53 list-hosted-zones-by-name &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #660033;"&gt;--arg&lt;/span&gt; PARENT &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$PARENT&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'.HostedZones[] | select(.Name == $PARENT) | .Id'&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"s/.*\///"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Add the Feature Branch Name and Public IP Address to the Parent Hosted Zone&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Now I created a new record set for the parent domain's hosted zone. This uses the AWS CLI command change-resource-record-sets which allows for insert, upsert and delete. I needed a DNS A record adding. The easiest way of providing the runtime parameters is via a JSON structure and that is created in shell script heredoc format to simplify shell script escaping. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #007800;"&gt;BATCH&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOT
{
  "Comment":"CREATE/DELETE/UPSERT a record",
  "Changes":[{
    "Action": "UPSERT",
    		  "ResourceRecordSet": {
    		  	"Name": "${BRANCH}",
    		  	"Type": "A",
    		  	"TTL": 300,
    		  	"ResourceRecords": [{ "Value": "${PUBLIC_IP}"}]
    		  }
  }]
}
EOT&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Use the hosted zone of the tld&lt;/span&gt;
aws route53 change-resource-record-sets \
	&lt;span style="color: #660033;"&gt;--hosted-zone-id&lt;/span&gt; &lt;span style="color: #007800;"&gt;$PARENT_ZONE&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--change-batch&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$BATCH&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Create the Feature Branch Hosted Zone&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The final AWS CLI call is to use create-hosted-zone, and here I needed to provide the feature branch name and an arbitrary unique caller reference for which I used a timestamp. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #007800;"&gt;timestamp&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;date&lt;/span&gt; +&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;s&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Now create a new hosted zone of the feature branch&lt;/span&gt;
aws route53 create-hosted-zone \
	&lt;span style="color: #660033;"&gt;--name&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$BRANCH&lt;/span&gt;"&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--caller-reference&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$timestamp&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;The Complete Script&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The complete script is listed below. Note that for brevity and easy reading I have cut a few coding standards. There is repetition in the error condition checking. This should be rewritten with calls to shell script functions in a separate file. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Script to assign a public IP address issued by a Fargate task to a subdomain&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #007800;"&gt;$1&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;||&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #007800;"&gt;$2&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"usage: parent_domain_name feature_branch_name"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;BRANCH&lt;/span&gt;=&lt;span style="color: #007800;"&gt;$2&lt;/span&gt;.&lt;span style="color: #007800;"&gt;$1&lt;/span&gt;
&lt;span style="color: #007800;"&gt;PARENT&lt;/span&gt;=&lt;span style="color: #007800;"&gt;$1&lt;/span&gt;.
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the default VPC.&lt;/span&gt;
&lt;span style="color: #007800;"&gt;VPC&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 describe-vpcs &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;'.Vpcs[] | select(.IsDefault == true) | .VpcId'&lt;/span&gt; -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the first subnet of the VPC&lt;/span&gt;
&lt;span style="color: #007800;"&gt;SUBNET&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 describe-subnets &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #660033;"&gt;--arg&lt;/span&gt; VPC &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$VPC&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'.Subnets[] | select(.VpcId == $VPC) | .SubnetId'&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;head&lt;/span&gt; &lt;span style="color: #660033;"&gt;-n&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Check if our security group for port 80 webserver already exists. Search for our funky unique description&lt;/span&gt;
&lt;span style="color: #007800;"&gt;SECURITY&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 describe-security-groups &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;' .SecurityGroups[] | select (.Description == "Ingress Port 80 Anywhere") | .GroupId'&lt;/span&gt; -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Let's inspect what we got back.&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-security-groups failed with code $?"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# If we didn't get a security group then create&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$SECURITY&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;""&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #007800;"&gt;SECURITY&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 create-security-group \
		&lt;span style="color: #660033;"&gt;--description&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Ingress Port 80 Anywhere"&lt;/span&gt; \
		&lt;span style="color: #660033;"&gt;--group-name&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Fargate Webserver Port 80"&lt;/span&gt; \
		&lt;span style="color: #660033;"&gt;--vpc-id&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$VPC&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .GroupId &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
 
	aws ec2 authorize-security-group-ingress \
		&lt;span style="color: #660033;"&gt;--group-id&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$SECURITY&lt;/span&gt;"&lt;/span&gt; \
		&lt;span style="color: #660033;"&gt;--ip-permissions&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"FromPort=80,ToPort=80,IpProtocol=TCP,IpRanges=[{CidrIp=0.0.0.0/0}]"&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Run the task and parse the task ARN for polling later to determine its status&lt;/span&gt;
&lt;span style="color: #007800;"&gt;TASK&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs run-task \
	&lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"default"&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--task-definition&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"first-run-task-definition"&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--network-configuration&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"awsvpcConfiguration={subnets=[&lt;span style="color: #007800;"&gt;${SUBNET}&lt;/span&gt;],securityGroups=[&lt;span style="color: #007800;"&gt;${SECURITY}&lt;/span&gt;],assignPublicIp=ENABLED}"&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--launch-type&lt;/span&gt; FARGATE  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .tasks&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.taskArn &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"s/.*\///"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Let's inspect what we got back. There should be a task identifier.&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"task-run failed with code $?"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$TASK&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"task-run could not create task"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Loop around until we see a RUNNING status or timeout after 10 x 30 second sleeps&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; i &lt;span style="color: #000000; font-weight: bold;"&gt;in&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #000000;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;6&lt;/span&gt; &lt;span style="color: #000000;"&gt;7&lt;/span&gt; &lt;span style="color: #000000;"&gt;8&lt;/span&gt; &lt;span style="color: #000000;"&gt;9&lt;/span&gt; &lt;span style="color: #000000;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$i&lt;/span&gt; &lt;span style="color: #660033;"&gt;-eq&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Timed out before could establish task is running"&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
	&lt;span style="color: #007800;"&gt;STATUS&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs describe-tasks &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"default"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tasks&lt;/span&gt; &lt;span style="color: #007800;"&gt;$TASK&lt;/span&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .tasks&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.lastStatus -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
	&lt;span style="color: #666666; font-style: italic;"&gt;# Did it exit unexpectedly?&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-tasks failed with code $?"&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
	&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$STATUS&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;"RUNNING"&lt;/span&gt;  &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
		&lt;span style="color: #7a0874; font-weight: bold;"&gt;break&lt;/span&gt;
	&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
	&lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;30&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the network Interface id&lt;/span&gt;
&lt;span style="color: #007800;"&gt;ENI&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs describe-tasks &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"default"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tasks&lt;/span&gt; &lt;span style="color: #007800;"&gt;$TASK&lt;/span&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #ff0000;"&gt;'.tasks[0].attachments[0].details[] | select(.name == "networkInterfaceId") | .value'&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Let's inspect what we got back. There should be a network interface id.&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-tasks failed with code $?"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$ENI&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-tasks could not establish eni"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the Public IP Address&lt;/span&gt;
&lt;span style="color: #007800;"&gt;PUBLIC_IP&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ec2 describe-network-interfaces &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #660033;"&gt;--arg&lt;/span&gt; ENI &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$ENI&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'.NetworkInterfaces[] | select(.NetworkInterfaceId == $ENI) | .PrivateIpAddresses[0].Association.PublicIp'&lt;/span&gt; -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Did we get an IP address?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ne&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-network-interfaces failed with code $?"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$PUBLIC_IP&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"describe-network-interfaces could not retrieve public IP address"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;BATCH&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOT
{
  "Comment":"CREATE/DELETE/UPSERT a record",
  "Changes":[{
    "Action": "UPSERT",
    		  "ResourceRecordSet": {
    		  	"Name": "${BRANCH}",
    		  	"Type": "A",
    		  	"TTL": 300,
    		  	"ResourceRecords": [{ "Value": "${PUBLIC_IP}"}]
    		  }
  }]
}
EOT&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
&lt;span style="color: #007800;"&gt;PARENT_ZONE&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws route53 list-hosted-zones-by-name &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq &lt;span style="color: #660033;"&gt;--arg&lt;/span&gt; PARENT &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$PARENT&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'.HostedZones[] | select(.Name == $PARENT) | .Id'&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"s/.*\///"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
aws route53 change-resource-record-sets \
	&lt;span style="color: #660033;"&gt;--hosted-zone-id&lt;/span&gt; &lt;span style="color: #007800;"&gt;$PARENT_ZONE&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--change-batch&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$BATCH&lt;/span&gt;"&lt;/span&gt;
 
 
&lt;span style="color: #007800;"&gt;timestamp&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;date&lt;/span&gt; +&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;s&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Now create a new hosted zone of the feature branch&lt;/span&gt;
aws route53 create-hosted-zone \
	&lt;span style="color: #660033;"&gt;--name&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$BRANCH&lt;/span&gt;"&lt;/span&gt; \
	&lt;span style="color: #660033;"&gt;--caller-reference&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$timestamp&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Invoking the Script&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-11/Screenshot_2019-11-03_at_11_25_07-edited1.png?itok=6zDl28OV 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-11/Screenshot_2019-11-03_at_11_25_07-edited1.png?itok=PtA97zAh 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-11/Screenshot_2019-11-03_at_11_25_07-edited1.png?itok=onEwER9j 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-11/Screenshot_2019-11-03_at_11_25_07-edited1.png?itok=3pXhsRib 1362w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-11/Screenshot_2019-11-03_at_11_25_07-edited1.png?itok=6zDl28OV" alt="Full Domain Name" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The script requires two parameters as previous discussed. Here's my example for the blog:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666;"&gt;$ &lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;feature-branch.sh saasidate.com feature--doi-&lt;span style="color: #000000;"&gt;746&lt;/span&gt;-my-whizzy-new-feature&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Currently the output of the script is the response from the AWS CLI route53 create-hosted-zone call, and here you can detect the full domain name.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Checking the Outcome&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-11/Screenshot%202019-11-03%20at%2011.58.11.png?itok=J7vAfmhk 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-11/Screenshot%202019-11-03%20at%2011.58.11.png?itok=UyDrsDoT 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-11/Screenshot%202019-11-03%20at%2011.58.11.png?itok=vqKiRvSi 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-11/Screenshot%202019-11-03%20at%2011.58.11.png?itok=YUAatBcF 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-11/Screenshot%202019-11-03%20at%2011.58.11.png?itok=J7vAfmhk" alt="Tasks Running" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-11/Screenshot%202019-11-03%20at%2012.00.56.png?itok=d-SSfTq- 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-11/Screenshot%202019-11-03%20at%2012.00.56.png?itok=N4C40cpp 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-11/Screenshot%202019-11-03%20at%2012.00.56.png?itok=oHvt2vUZ 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-11/Screenshot%202019-11-03%20at%2012.00.56.png?itok=wa9icCup 2254w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-11/Screenshot%202019-11-03%20at%2012.00.56.png?itok=d-SSfTq-" alt="Route 53" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Obviously the first check is to copy and paste the url of the feature branch into a browser and see if it loads. An example of this is the blog heading image at the top of the page. &lt;/p&gt;

&lt;p&gt;Also the AWS console is the place to check everything is as required. Navigate to ECS -&gt; default -&gt; Tasks and you should see a screenshot similar to the first one immediately above. This is the task we invoked from inside our shell script. Now navigate to Route 53 -&gt; Hosted Zones -&gt; {domain name} and you can see the feature branch and its IP address.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Steps left to do&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;New hosted zones will normally propagate in 60 seconds in Route 53 - but it would be good if the script above polls Route 53 every 10 seconds or so and reports back the subdomain url and the IP address once the propagation has completed. This should be surfaced on the command line as a minimum, but perhaps a notification on Slack would be even better. Both options are trivial. &lt;/p&gt;

&lt;p&gt;Whilst the idea is that the Fargate tasks should persist, they shouldn't be around forever. Therefore there needs to be clear up activities to remove the feature subdomain from the parent domain's hosted zone, and the subdomain hosted zone. Also there obviously needs a step to stop the Fargate task. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Caveats&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;There are caveats to this solution - but for my use case, it's one of those rare occurrences in life that the caveats don't apply to me. &lt;/p&gt;

&lt;p&gt;Firstly, this solution will only work with a Fargate &lt;strong&gt;task&lt;/strong&gt; and not an ECS &lt;strong&gt;service&lt;/strong&gt; running a Fargate task. Tasks should be run as services for production environments since services give you great things like replication, and health percentages against number of running tasks. There is therefore no scaling, no load balancing, no DDOS protection in what I'm offering here.&lt;/p&gt;

&lt;p&gt;Fargate tasks run in isolation are perfect for spun up short living environments such as playgrounds for devs and QAs to run manual tests against or troubleshoot development issues - which is exactly my use case. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/docker" hreflang="en"&gt;Docker&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/fargate" hreflang="en"&gt;Fargate&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/ecs" hreflang="en"&gt;ECS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/development" hreflang="en"&gt;Development&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/Route53" hreflang="en"&gt;Route 53&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/bash" hreflang="en"&gt;bash&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Fri, 01 Nov 2019 15:03:02 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">171 at http://badzilla.co.uk</guid>
    </item>

  </channel>
</rss>
