Skip to main content

Unit 4 - Deploying a dockerized application to AWS

About 5 minGitlabcrashcourseyoutubefreecodecampvdespagitlabyamlcicdcicd

Unit 4 - Deploying a dockerized application to AWS κ΄€λ ¨


4.1 Section overview

  • modern applications tend to be more complex, and most of them use Docker
  • we will build & deploy an application that runs in a Docker container

4.2 Introduction to AWS Elastic Beanstalk

  • AWS Elastic Beanstalk (AWS EB) is a service that allows us to deploy an application in the AWS cloud without having to worry about managing the virtual server(s) that runs it

4.3 Creating a new AWS Elastic Beanstalk application

  • when creating an EB app, choose the Docker platform and deploy the sample app
  • AWS EB will use two AWS services to run the application:
    • EC2 (virtual servers)
    • S3 (storage)
  • to deploy a new version, go to the environment in EB and upload the file in templates called Dockerrun.aws.public.json
Dockerrun.aws.public.json Dockerrun.aws.public.json
{
  "AWSEBDockerrunVersion": "1",
  "Image": {
    "Name": "nginx"
  },
  "Ports": [
    {
      "ContainerPort": 80
    }
  ]
}

4.4 Creating the Dockerfile

  • create a new file called Dockerfile in the root of the project
  • add the following contents to it:
FROM nginx:1.20-alpine
COPY build /usr/share/nginx/html

πŸ“š Resources


4.5 Building the Docker image

  • to build the Docker image, we will use the command docker build
  • to build Docker images from a GitLab CI pipeline, we need to start the Docker Daemon as a service
Pipeline after this lecture .gitlab-ci.yml
stages:
  - build
  - package

variables:
  APP_VERSION: $CI_PIPELINE_IID

build website:
  image: node:16-alpine
  stage: build
  script:
    - yarn install
    - yarn lint
    - yarn test
    - yarn build
    - echo $APP_VERSION > build/version.html
  artifacts:
    paths:
      - build

build docker image:
  stage: package
  image: docker:20.10.12
  services:
    - docker:20.10.12-dind
  script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
    - docker build -t $CI_REGISTRY_IMAGE -t $CI_REGISTRY_IMAGE:$APP_VERSION .
    - docker image ls
    - docker push --all-tags $CI_REGISTRY_IMAGE

πŸ“š Resources


4.6 Docker container registry

  • to preserve a Docker image, we need to push it to a registry
  • Dockerhub is a public registry with Docker images
  • GitLab offers a private Docker registry which is ideal for private projects
Pipeline after this lecture .gitlab-ci.yml
stages:
  - build
  - package

variables:
  APP_VERSION: $CI_PIPELINE_IID

build website:
  image: node:16-alpine
  stage: build
  script:
    - yarn install
    - yarn lint
    - yarn test
    - yarn build
    - echo $APP_VERSION > build/version.html
  artifacts:
    paths:
      - build

build docker image:
  stage: package
  image: docker:20.10.12
  services:
    - docker:20.10.12-dind
  script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
    - docker build -t $CI_REGISTRY_IMAGE -t $CI_REGISTRY_IMAGE:$APP_VERSION .
    - docker image ls
    - docker push --all-tags $CI_REGISTRY_IMAGE

πŸ“š Resources


4.7 Testing the container

  • we want to test the container to see if the application running on it (web server) is working properly
  • to start the container, we will use the services: keyword
Pipeline after this lecture .gitlab-ci.yml
stages:
  - build
  - package
  - test

variables:
  APP_VERSION: $CI_PIPELINE_IID

build website:
  image: node:16-alpine
  stage: build
  script:
    - yarn install
    - yarn lint
    - yarn test
    - yarn build
    - echo $APP_VERSION > build/version.html
  artifacts:
    paths:
      - build

build docker image:
  stage: package
  image: docker:20.10.12
  services:
    - docker:20.10.12-dind
  script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
    - docker build -t $CI_REGISTRY_IMAGE -t $CI_REGISTRY_IMAGE:$APP_VERSION .
    - docker image ls
    - docker push --all-tags $CI_REGISTRY_IMAGE

test docker image:
  stage: test
  image: curlimages/curl
  services:
    - name: $CI_REGISTRY_IMAGE:$APP_VERSION
      alias: website
  script:
    - curl http://website/version.html | grep $APP_VERSION

4.8 Private registry authentication

  • AWS EB requires authentication credentials to pull our Docker image
  • GitLab allows us to create a Deploy Token that AWS can use to log to the registry
  • to generate a Deploy Token, from your project, go to Settings > Repository > Deploy tokens.
  • create a new Deploy Token with the following scopes:
    • read_repository
    • read_registry
Pipeline after this lecture .gitlab-ci.yml
stages:
  - build
  - package
  - test
  - deploy

variables:
  APP_VERSION: $CI_PIPELINE_IID

.build website:
  image: node:16-alpine
  stage: build
  script:
    - yarn install
    - yarn lint
    - yarn test
    - yarn build
    - echo $APP_VERSION > build/version.html
  artifacts:
    paths:
      - build

.build docker image:
  stage: package
  image: docker:20.10.12
  services:
    - docker:20.10.12-dind
  script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
    - docker build -t $CI_REGISTRY_IMAGE -t $CI_REGISTRY_IMAGE:$APP_VERSION .
    - docker image ls
    - docker push --all-tags $CI_REGISTRY_IMAGE

.test docker image:
  stage: test
  image: curlimages/curl
  services:
    - name: $CI_REGISTRY_IMAGE:$APP_VERSION
      alias: website
  script:
    - curl http://website/version.html | grep $APP_VERSION

deploy to production:
  image:
    name: amazon/aws-cli:2.4.11
    entrypoint: [""]
  stage: deploy
  variables:
    APP_NAME: My website
    APP_ENV_NAME: Mywebsite-env
  environment: production
  script:
    - aws --version
    - yum install -y gettext
    - export DEPLOY_TOKEN=$(echo $GITLAB_DEPLOY_TOKEN | tr -d "\n" | base64)
    - envsubst < templates/Dockerrun.aws.json > Dockerrun.aws.json
    - envsubst < templates/auth.json > auth.json
    - cat Dockerrun.aws.json
    - cat auth.json
    - aws s3 cp Dockerrun.aws.json s3://$AWS_S3_BUCKET/Dockerrun.aws.json
    - aws s3 cp auth.json s3://$AWS_S3_BUCKET/auth.json


4.9 Deploying to AWS Elastic Beanstalk

  • a new deployment to AWS EB happens in two steps
  • step 1: we create a new application version with aws elasticbeanstalk create-application-version
  • step 2: we update the environment with the new application version with aws elasticbeanstalk update-environment
Pipeline after this lecture .gitlab-ci.yml
stages:
  - build
  - package
  - test
  - deploy

variables:
  APP_VERSION: $CI_PIPELINE_IID

build website:
  image: node:16-alpine
  stage: build
  script:
    - yarn install
    - yarn lint
    - yarn test
    - yarn build
    - echo $APP_VERSION > build/version.html
  artifacts:
    paths:
      - build

build docker image:
  stage: package
  image: docker:20.10.12
  services:
    - docker:20.10.12-dind
  script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
    - docker build -t $CI_REGISTRY_IMAGE -t $CI_REGISTRY_IMAGE:$APP_VERSION .
    - docker image ls
    - docker push --all-tags $CI_REGISTRY_IMAGE

test docker image:
  stage: test
  image: curlimages/curl
  services:
    - name: $CI_REGISTRY_IMAGE:$APP_VERSION
      alias: website
  script:
    - curl http://website/version.html | grep $APP_VERSION

deploy to production:
  image:
    name: amazon/aws-cli:2.4.11
    entrypoint: [""]
  stage: deploy
  variables:
    APP_NAME: My website
    APP_ENV_NAME: Mywebsite-env
  environment: production
  script:
    - aws --version
    - yum install -y gettext
    - export DEPLOY_TOKEN=$(echo $GITLAB_DEPLOY_TOKEN | tr -d "\n" | base64)
    - envsubst < templates/Dockerrun.aws.json > Dockerrun.aws.json
    - envsubst < templates/auth.json > auth.json
    - cat Dockerrun.aws.json
    - cat auth.json
    - aws s3 cp Dockerrun.aws.json s3://$AWS_S3_BUCKET/Dockerrun.aws.json
    - aws s3 cp auth.json s3://$AWS_S3_BUCKET/auth.json
    - aws elasticbeanstalk create-application-version --application-name "$APP_NAME" --version-label $APP_VERSION --source-bundle S3Bucket=$AWS_S3_BUCKET,S3Key=Dockerrun.aws.json
    - aws elasticbeanstalk update-environment --application-name "$APP_NAME" --version-label $APP_VERSION --environment-name $APP_ENV_NAME


4.10 Post-deployment testing

  • updating an EB environment does not happen instantly
  • we will use aws elasticbeanstalk wait to know when the environment has been updated
Pipeline after this lecture .gitlab-ci.yml
stages:
  - build
  - package
  - test
  - deploy

variables:
  APP_VERSION: $CI_PIPELINE_IID

build website:
  image: node:16-alpine
  stage: build
  script:
    - yarn install
    - yarn lint
    - yarn test
    - yarn build
    - echo $APP_VERSION > build/version.html
  artifacts:
    paths:
      - build

build docker image:
  stage: package
  image: docker:20.10.12
  services:
    - docker:20.10.12-dind
  script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
    - docker build -t $CI_REGISTRY_IMAGE -t $CI_REGISTRY_IMAGE:$APP_VERSION .
    - docker image ls
    - docker push --all-tags $CI_REGISTRY_IMAGE

test docker image:
  stage: test
  image: curlimages/curl
  services:
    - name: $CI_REGISTRY_IMAGE:$APP_VERSION
      alias: website
  script:
    - curl http://website/version.html | grep $APP_VERSION

deploy to production:
  image:
    name: amazon/aws-cli:2.4.11
    entrypoint: [""]
  stage: deploy
  variables:
    APP_NAME: My website
    APP_ENV_NAME: Mywebsite-env
  environment: production
  script:
    - aws --version
    - yum install -y gettext
    - export DEPLOY_TOKEN=$(echo $GITLAB_DEPLOY_TOKEN | tr -d "\n" | base64)
    - envsubst < templates/Dockerrun.aws.json > Dockerrun.aws.json
    - envsubst < templates/auth.json > auth.json
    - cat Dockerrun.aws.json
    - cat auth.json
    - aws s3 cp Dockerrun.aws.json s3://$AWS_S3_BUCKET/Dockerrun.aws.json
    - aws s3 cp auth.json s3://$AWS_S3_BUCKET/auth.json
    - aws elasticbeanstalk create-application-version --application-name "$APP_NAME" --version-label $APP_VERSION --source-bundle S3Bucket=$AWS_S3_BUCKET,S3Key=Dockerrun.aws.json
    - aws elasticbeanstalk update-environment --application-name "$APP_NAME" --version-label $APP_VERSION --environment-name $APP_ENV_NAME
    - aws elasticbeanstalk wait environment-updated --application-name "$APP_NAME" --version-label $APP_VERSION --environment-name $APP_ENV_NAME
    - curl $CI_ENVIRONMENT_URL/version.html | grep $APP_VERSION

이찬희 (MarkiiimarK)
Never Stop Learning.