Unit 4: Deploying a dockerized application to AWS
About 5 min
Unit 4: Deploying a dockerized application to AWS 관련
DevOps with GitLab CI Course
GitLab CI/CD can automatically build, test, deploy, and monitor your applications. We just published a full course on the freeCodeCamp.org YouTube channel that will teach you how to use GitLab CI. Valentin Despa developed this course. Valentin is an ...
DevOps with GitLab CI Course
GitLab CI/CD can automatically build, test, deploy, and monitor your applications. We just published a full course on the freeCodeCamp.org YouTube channel that will teach you how to use GitLab CI. Valentin Despa developed this course. Valentin is an ...
Unit 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
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
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
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "nginx"
},
"Ports": [
{
"ContainerPort": 80
}
]
}
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
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
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
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
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
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
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