Kubernetes + EKS + Docker + Node
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