Jérôme Decoster

Jérôme Decoster

3x AWS Certified - Architect, Developer, Cloud Practionner

18 Oct 2022

Microservice + ArgoCD ApplicationSet + Image Updater

The Goal
  • Build a microservice consisting of 3 different Docker images
  • Build images are pushed to separate private ECR repositories
  • Deploy ArgoCD + ArgoCD Image Updater in a Kind cluster
  • Use an ApplicationSet manifest to manage the 3 applications
  • Update of an application module
  • Deploy a new Docker image and see automatic deployment in Kubernetes

    architecture.svg

    The application

    This project is composed of different repositories :

    You can fork this differents repositories on your machine

    Important : make sure your repositories are private as they will contain sensitive data !

    Storage repository

    Let’s start by initializing the storage module

    The env-create script creates an .env file at the root of the project and installs semver-cli if needed :

    # create .env file + install semver-cli
    make env-create
    

    You must modify the generated .env file with your own variables :

    • AWS_REGION

    Let’s now initialize terraform :

    # terraform init (updgrade) + validate
    make terraform-init
    

    We create the infrastructure with terraform :

    # terraform create s3 bucket + ecr repo + iam user + setup .env file
    make terraform-create
    

    Terraform is used to :

    sm-parameter-store.png

    Let’s start the local module :

    # run storage server using npm - dev mode
    make storage
    

    Run the following command in another terminal window :

    # test storage
    make test
    

    A test image has been successfully uploaded to our S3 bucket :

    s3-01.png

    We build and push this image to ECR :

    # build storage image
    make prod-build
    
    # push storage image to ecr
    make ecr-push
    

    The image is in our repository :

    ecr-storage.png

    Convert repository

    We initialize the convert module :

    # create .env file
    make env-create
    

    You must modify the generated .env file with your own variables :

    • AWS_REGION

    Let’s now initialize terraform :

    # terraform init (updgrade) + validate
    make terraform-init
    

    We create the infrastructure with terraform :

    # terraform create ecr repo + setup .env file
    make terraform-create
    

    Terraform is used to :

    Let’s start the local module :

    # run convert server using npm - dev mode
    make convert
    

    Run the following command in another terminal window :

    # test convert
    make test
    

    Our image :

    rhino-origin.jpg

    is converted to black and white at the root of our project :

    rhino-converted.jpg

    We build and push this image to ECR :

    # build convert image
    make prod-build
    
    # push convert image to ecr
    make ecr-push
    

    The image is in our repository :

    ecr-convert.png

    Website repository

    We initialize the website module :

    # create .env file
    make env-create
    

    You must modify the generated .env file with your own variables :

    • AWS_REGION

    Let’s now initialize terraform :

    # terraform init (updgrade) + validate
    make terraform-init
    

    We create the infrastructure with terraform :

    # terraform create ecr repo + setup .env file
    make terraform-create
    

    Terraform is used to :

    Let’s start the local project :

    # run website server using npm - dev mode
    make website
    

    Attention, if you have a similar error

    CONVERT_PORT  4000 ABORT  localhost:4000 is not working. Status Code 200 required.
    

    … you need to run the others modules on your machine from other terminal windows :

    # run storage server using npm - dev mode
    make storage
    
    # run convert server using npm - dev mode
    make convert
    

    You can see the website at http://localhost:3000 :

    localhost.png

    We upload the rhino.png image located in the applicationset-convert/test directory :

    upload.png

    The image is converted :

    converted.png

    We build and push this image to ECR

    # build website image
    make prod-build
    
    # push website image to ecr
    make ecr-push
    

    The image is in our repository :

    ecr-website.png

    Infra repository

    The most interesting part starts now !

    We initialize the infra module :

    # create .env file
    make env-create
    

    You must modify the generated .env file with your own variables :

    • AWS_REGION
    • GITHUB_OWNER
    • GITHUB_REPO_STORAGE
    • GITHUB_REPO_CONVERT
    • GITHUB_REPO_WEBSITE
    • GITHUB_REPO_INFRA

    You need to create a Github Token

    You need to select repo :

    token-repo.png

    You need to select admin:public_key :

    token-admin-key.png

    This Github Token is used by Terraform’s github provider :

    provider "github" {
      owner = var.github_owner
      token = var.github_token
    }
    

    To assign an SSH key to your Github account :

    resource "github_user_ssh_key" "ssh_key" {
      title = var.project_name
      key   = tls_private_key.private_key.public_key_openssh
    }
    

    Now add the .env file with your own GITHUB_TOKEN

    Let’s now initialize terraform :

    # terraform init (updgrade) + validate
    make terraform-init
    

    We create the infrastructure with terraform :

    # terraform valiate + apply
    make terraform-create
    

    Warning : the creation time is long (~ 8 minutes) !

    Terraform is used to :

    Kind

    Kind (Kubernetes IN Docker) must be previously installed on your machine

    Minikube is very flexible but its startup time is quite long. Kind greatly reduces this time.

    Here is a good comparison minikube / kind / k3s

    The major disadvantage of Kind is to have to be completely reset (destroyed then created again) when changing its configuration

    It’s rather annoying because sometimes you need to change the configuration regularly

    When the creation of the resources is finished, we open the ArgoCD web interface :

    # open argocd (website)
    make argocd-open
    

    argocd.png

    Templates have been generated in your argocd directory

    You have to push them to the git repository :

    Important : make sure your repositories are private as they will contain sensitive data !

    git add . && git commit -m :boom: && git push -u origin master
    

    ApplicationSet

    The ApplicationSet Controller is a factory of ArgoCD Application

    We use a series of Generators to create multiple applications from one place

    Our project uses the List Generator to generate 3 applications

    A very good video explaining how ApplicationSet works

    Note : sometimes it is difficult to debug an ApplicationSet that does not start correctly

    And we sometimes lose time when 3 simple Application would have been simpler !

    We launch our ApplicationSet :

    kubectl apply -f argocd/applicationset.yaml
    

    The 3 applications are installing :

    argocd-as-installing.png

    They are now installed :

    argocd-as-installed.png

    We open our browser on http://0.0.0.0:9000/ :

    localhost-9000.png

    We select an image in the applicationset-convert module and then upload it :

    localhost-9000-upload.png

    The image is converted :

    localhost-9000-converted.png

    Udating the convert image

    Before we start, let’s open a new terminal window in our infra module

    We display the continuous logs of the argocd image updater application :

    #argocd image updater logs
    make image-updater-logs
    

    In the convert module we modify the Javascript code

    We switch from this version :

    .greyscale() // version 0.0.1
    //.tint({ r: 255, g: 0, b: 0 }) // 0.0.2
    

    to this version :

    //.greyscale() // version 0.0.1
    .tint({ r: 255, g: 0, b: 0 }) // 0.0.2
    

    We will increment our version, from 0.0.1 to 0.0.2

    Then build and push this new image to ECR :

    # update-patch + ecr-push
    make increase-build-push
    

    The image is pushed to ECR :

    ecr-convert-0.0.2.png

    After a few seconds, ArgoCD Image Updater commits a .argocd-source-convert.yaml file :

    github-convert.png

    And after another delay, ArgoCD is updating the docker image :

    argocd-convert-updating.png

    The docker image is updated within kubernetes :

    argocd-convert-updated.png

    We are uploading a new image :

    convert-update-upload.png

    The image has been successfully converted :

    convert-update-converted.png

    Udating the website image

    In the website module we modify the CSS code

    We switch from this version :

    h2 {
        margin-bottom: .8em;
    
        /* version 0.0.2 */
        /*
        font-size: 1.8em;
        font-style: italic;
        color: red;
        */
    

    to this version :

    h2 {
        margin-bottom: .8em;
    
        /* version 0.0.2 */
        /* */
        font-size: 1.8em;
        font-style: italic;
        color: red;
    

    We increment, build again and push the new image to ECR :

    # update-patch + ecr-push
    make increase-build-push
    

    The image is pushed :

    ecr-website-0.0.2.png

    Then the file .argocd-source-convert.yaml is added :

    github-website.png

    ArgoCD is updating the docker image :

    argocd-website-updating.png

    The image is updated :

    argocd-website-updated.png

    After a few seconds, we reload http://0.0.0.0:9000/

    The title has changed :

    website-0.0.2.png

    Cleaning

    This demonstration is now over, we are destroying the resources :

    kubectl delete -f argocd/applicationset.yaml
    

    argocd-destroying.png

    In each module, execute the following commands :

    # terraform destroy
    make terraform-destroy
    
    # clear builded docker images
    make clear