Kubernetes + EKS + Docker + Node

jerome.decoster
6 min readMay 28, 2021

--

Creation of a website, hosted on a Kubernetes cluster. Use Kubectl, Kustomize and Github actions to deploy it in a GitOps way.

The Goal

  • Create a website to convert our images to black and white
  • Create 3 microservices : the website, the black and white image converter, the uploader to S3
  • Use Docker-compose to orchestrate these microservices locally
  • Create a Kubernetes cluster on EKS with eksctl
  • Create 3 ECR registries and push the production docker images of our services
  • Putting the application online with kubectl

Install, setup and explore the project

Get the code from this github repository :

To setup the project, run the following command :

# install eksctl + kubectl, create aws user + s3 bucket
$ make setup

This command will :

  • Install eksctl if it is not already installed.
  • Install kubectl if it is not already installed.
  • Creates an AWS Power User for the project.
  • Creates an S3 bucket.
  • Creates an .env file from the .env.sample file. You can modify some variables if you wish.

Let’s test the image conversion service by starting the development version :

# convert service local development (on current machine, by calling npm script directly)
$ make convert-dev

This script performs the following :

$ DOTENV_CONFIG_PATH=../.env DEBUG=convert npx nodemon --require dotenv/config server.js

We can test the service with curl :

It works :

We can stop the service with Ctrl + C.

The services have a series of tests of which here are some extracts :

We run the tests with this command :

# run convert service tests (on current machine, by calling npm script directly)
$ make convert-test

This script performs the following :

$ DOTENV_CONFIG_PATH=../.env npx mocha --require dotenv/config 'test/*.test.js'

Run the site locally

The application is an association of 3 microservices :

  • website : which displays the gallery and allows the upload of new images to convert.
  • convert : which converts JPG, PNG or WEBP images to black and white.
  • storage : which stores the converted image in an S3 bucket.

It is possible to start the services separately like this :

# sample script, don't do this !
$ make convert-dev
$ make storage-dev
$ make website-dev

But we choose to use docker-compose to orchestrate the local development :

# local development with docker-compose
$ make dev

This script performs the following :

$ docker-compose \
--file docker-compose.dev.yml \
--project-name compose_gallery_kubernetes_dev \
--env-file .env \
up

The docker-compose.dev.yml file defines the 3 services like this :

The Dockerfile.dev file from the convert service :

Our services are launched, we can go and see http://localhost:3000 :

We choose an image to upload then click the Send button :

The page is reloaded, we can see the black and white image :

We can see the uploaded file on S3 :

The upload is done via the storage service, here is an extract :

Hosting the production image on the docker hub

We build the 3 production images and push them with this command :

# build production images and push to ECR
$ make build-push

This command does this :

The script build 3 production images and push them on ECR.

The state of my ECR repositories page before the script execution :

The creation of the production image uses a specific, optimized Dockerfile.

The optimization of the image weight is achieved with :

  • The declaration of the environment variable NODE_ENV=production. The installation of npm modules will be reduced.
  • The use of node-prune to reduce the weight of the node_modules folder.

The build and push action is quite long. We end up with our 3 repositories :

The uploaded convert image :

Creating the Kubernetes cluster

We launch the creation of the EKS cluster. You have to be patient because it takes about 15 minutes !

$ make cluster-create

The creation of the cluster is managed via a Cloudformation Stack :

Here are some more details :

We see the cluster being created in the EKS interface :

Once the deployment is complete, we check that kubectl points to the right cluster :

$ kubectl config current-context
user@gallery-kubernetes.eu-west-3.eksctl.io

We query the namespaces :

$ kubectl get ns
NAME STATUS AGE
default Active 20m
kube-node-lease Active 20m
kube-public Active 20m
kube-system Active 20m

We will deploy the services :

$ make cluster-deploy 
namespace/gallery-kubernetes created
secret/gallery-kubernetes created
deployment.apps/storage created
service/storage created
deployment.apps/convert created
service/convert created
deployment.apps/website created
service/website created

This command takes the templates present in the k8s directory and injects the variables contained in the .env file previously created :

The starting namespace.yml template :

Go through a bash script similar to this :

The template therefore becomes :

The template is sent directly to the cluster by adding :

If we query the namespaces again we see the one we just added :

$ kubectl get ns
NAME STATUS AGE
default Active 22m
gallery-kubernetes Active 10s
kube-node-lease Active 22m
kube-public Active 22m
kube-system Active 22m

We query the pods :

$ kubectl get pods -n gallery-kubernetes
NAME READY STATUS RESTARTS AGE
convert-5c85c7c869-5vzgd 1/1 Running 0 22m
convert-5c85c7c869-xlvwq 1/1 Running 0 22m
storage-66b6998c9-s46m5 1/1 Running 0 40s
storage-66b6998c9-wjsxd 1/1 Running 0 40s
website-584cc7f864-bmjdg 1/1 Running 0 22m
website-584cc7f864-th4fx 1/1 Running 0 22m

The website service uses a LoadBalancer type :

We get the URL of the LoadBalancer with this command :

$ make cluster-elb

This command does this :

By using this URL in our browser we should see the service working. We select an image type :

By clicking on the Send button, the page reloads and displays the converted image in black and white :

We can query the logs of the convert service with this command :

This command does this :

$ kubectl logs \
--namespace gallery-kubernetes \
--selector app=convert \
--tail=1000

The demonstration is over. We can delete our cluster with this command :

$ make cluster-delete

--

--