How to Deploy Your Application or Microservice on Kubernetes
Antoine CHOULA
AWS Community Builder | Solution Architech | Devops | Certified AWS ? | CI/CD ?? | Jenkins | Gitlab | Docker ?? | Kubernetes ? | Terraform ?? | Ansible | Python ?? | Linux ??
Kubernetes is a very powerful platform to scale your applications, as the lower resource usage of containers can give you greater efficiency. The Linode Kubernetes Engine allows you to easily deploy containers in the cloud, eliminating the need for you to maintain your own hardware for your Kubernetes stack.
In this article, we are going to Deploy our Shopping Microservices on Kubernetes. Kubernetes retrieve microservices images from Google Cloud Platform Container Registry.
Introduction to Kubernetes
Before we start to deploy microservices on Kubernetes, we are going to give introduction about Kubernetes.
We will talk about What Kubernetes is and why we should use Kubernetes for deploying microservices. Also we will talk about kubernetes components and general architecture of operations. We will discuss minimum manifest definitions for deploying microservices, we will talk about deployments, replicasets, pods, services and so on
What is Kubernetes ?
Kubernetes (also known as k8s or “kube”) is an open source container orchestration platform that automates many of the manual processes involved in deploying, managing, and scaling containerized applications.
Kubernetes Architecture
Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation. It has a large, rapidly growing ecosystem. Kubernetes services, support, and tools are widely available.
You can cluster together groups of hosts running Linux containers, and Kubernetes helps you easily and efficiently manage those clusters.
Benefits of Kubernetes for microservices
Containerization with Kubernetes orchestration and management is designed to support microservices. Before you use the tutorial to build a?Kubernetes deployment, you should decide if it is a fit for your project. Some high-level advantages Kubernetes offers for microservice architecture are:
Kubernetes Components
we are going to talk about Kubernetes Components like?deployment, replicaset, pod, service, configmap?and so on. We will explain most basics of components that we can use and deploy our microservice to the k8s.
Pods
Pods are the smallest deployable units of computing that you can create and manage in Kubernetes. A Pod represents a single instance of a running process in your cluster. A Pod is a group of one or more containers, with shared storage/network resources, and a specification for how to run the containers. So we can say that pods stores and manage our docker containers.
ReplicaSet
A ReplicaSet is a process that runs multiple instances of a Pod and keeps the specified number of Pods constant. Its purpose is to maintain the specified number of Pod instances running in a cluster at any given time to prevent users from losing access to their application when a Pod fails or is inaccessible. it purpose is to maintain a stable set of replica Pods running at any given time. For example, it is often used to guarantee the availability of a specified number of identical Pods.
Deployments
A Deployment runs multiple replicas of your application and automatically replaces any instances that fail or become unresponsive. In this way, Deployments help ensure that one or more instances of your application are available to serve user requests. Deployments are managed by the Kubernetes Deployment controller.
A Deployment provides declarative updates for Pods and ReplicaSets. You describe a desired state in a Deployment, and the Deployment Controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new ReplicaSets, or to remove existing Deployments and adopt all their resources with new Deployments.
So we can say that Deployments are an abstraction of ReplicaSets, and ReplicaSets are an abstraction of Pods. So Pods should not created directly, if needed, Deployment objects should be created and the rest operation will handle by k8s with creating replicaset and pods automatically.
Service
A Kubernetes service is a logical abstraction for a deployed group of pods in a cluster (which all perform the same function). Since pods are ephemeral, a service enables a group of pods, which provide specific functions (web services, image processing, etc.) to be assigned a name and unique IP address (clusterIP). In other words it is an abstract way to expose an application running on a set of Pods as a network service. With Kubernetes you don’t need to modify your application to use an unfamiliar service discovery mechanism. Kubernetes gives Pods their own IP addresses and a single DNS name for a set of Pods, and can load-balance across them.
ConfigMaps
A Kubernetes ConfigMap is an API object that allows you to store non-confidential data as key-value pairs. Kubernetes pods can consume ConfigMaps as configuration files, environment variables or command-line arguments or as configuration files in a volume. ConfigMaps allow you to decouple environment-specific configurations from containers to make applications portable.
Secrets
Kubernetes Secrets let you store and manage sensitive information, such as passwords, OAuth tokens, and ssh keys. Storing confidential information in a Secret is safer and more flexible than putting it verbatim in a Pod definition or in a container image.
领英推荐
Before You Begin
Prepare the Environment
laptopuser@LaptopB3:~$ mkdir online-shop-microservices
2. Clone this repository:
git clone https://github.com/kevAnto/microservices-app
cd microservices-app
3. Create a Linode cluster:
https://www.linode.com/docs/guides/deploy-and-manage-a-cluster-with-linode-kubernetes-engine-a-tutorial/#create-an-lke-cluster
Once the cluster created, download kubeconfig.yaml to access your cluster and edit it permission to read only
laptopuser@LaptopB3:~$ chmod 400 ~/Downloads/online-shop-microservices-kubeconfig.yaml
laptopuser@LaptopB3:~$ ls -l ~/Downloads/online-shop-microservices-kubeconfig.yam
-r-------- 1 laptopuser laptopuser 2808 Apr 27 09:27 /home/laptopuser/Downloads/online-shop-microservices-kubeconfig.yamll
and export kubeconfig with the command below
laptopuser@LaptopB3:~$ export KUBECONFIG=~/Downloads/online-shop-microservices-kubeconfig.yaml
4. Verify if our cluster status:
laptopuser@LaptopB3:~/Downloads$ kubectl get nod
NAME STATUS ROLES AGE VERSION
lke58942-91932-6268fd6d5a1b Ready <none> 5m22s v1.23.6
lke58942-91932-6268fd6db96f Ready <none> 7m1s v1.23.6
lke58942-91932-6268fd6e1a72 Ready <none> 7m3s v1.23.6e
5. Edit config.yaml file so as each services serve on a distinct port and health check apply every 5 seconds on the container. Since our app has 11 microservices we will do that for each of them.
apiVersion: apps/v
kind: Deployment
metadata:
name: emailservice
spec:
selector:
matchLabels:
app: emailservice
template:
metadata:
labels:
app: emailservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/emailservice:v0.3.6
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
- name: DISABLE_TRACING
value: "1"
- name: DISABLE_PROFILER
value: "1"
readinessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
livenessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: emailservice
spec:
type: ClusterIP
selector:
app: emailservice
ports:
- name: grpc
port: 5000
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: checkoutservice
spec:
selector:
matchLabels:
app: checkoutservice
template:
metadata:
labels:
app: checkoutservice
spec:
serviceAccountName: default
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/checkoutservice:v0.3.6
ports:
- containerPort: 5050
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:5050"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:5050"]
env:
- name: PORT
value: "5050"
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"
- name: SHIPPING_SERVICE_ADDR
value: "shippingservice:50051"
- name: PAYMENT_SERVICE_ADDR
value: "paymentservice:50051"
- name: EMAIL_SERVICE_ADDR
value: "emailservice:5000"
- name: CURRENCY_SERVICE_ADDR
value: "currencyservice:7000"
- name: CART_SERVICE_ADDR
value: "cartservice:7070"
- name: DISABLE_STATS
value: "1"
- name: DISABLE_TRACING
value: "1"
- name: DISABLE_PROFILER
value: "1"
# - name: JAEGER_SERVICE_ADDR
# value: "jaeger-collector:14268"
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: checkoutservice
spec:
type: ClusterIP
selector:
app: checkoutservice
ports:
- name: grpc
port: 5050
targetPort: 5050
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: recommendationservice
spec:
selector:
matchLabels:
app: recommendationservice
template:
metadata:
labels:
app: recommendationservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/recommendationservice:v0.3.6
ports:
- containerPort: 8080
readinessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
livenessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:8080"]
env:
- name: PORT
value: "8080"
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"
- name: DISABLE_TRACING
value: "1"
- name: DISABLE_PROFILER
value: "1"
- name: DISABLE_DEBUGGER
value: "1"
resources:
requests:
cpu: 100m
memory: 220Mi
limits:
cpu: 200m
memory: 450Mi
---
apiVersion: v1
kind: Service
metadata:
name: recommendationservice
spec:
type: ClusterIP
selector:
app: recommendationservice
ports:
- name: grpc
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
annotations:
sidecar.istio.io/rewriteAppHTTPProbers: "true"
spec:
serviceAccountName: default
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/frontend:v0.3.6
ports:
- containerPort: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "shop_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "shop_session-id=x-liveness-probe"
env:
- name: PORT
value: "8080"
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: "productcatalogservice:3550"
- name: CURRENCY_SERVICE_ADDR
value: "currencyservice:7000"
- name: CART_SERVICE_ADDR
value: "cartservice:7070"
- name: RECOMMENDATION_SERVICE_ADDR
value: "recommendationservice:8080"
- name: SHIPPING_SERVICE_ADDR
value: "shippingservice:50051"
- name: CHECKOUT_SERVICE_ADDR
value: "checkoutservice:5050"
- name: AD_SERVICE_ADDR
value: "adservice:9555"
# # ENV_PLATFORM: One of: local, gcp, aws, azure, onprem, alibaba
# # When not set, defaults to "local" unless running in GKE, otherwies auto-sets to gcp
# - name: ENV_PLATFORM
# value: "aws"
- name: DISABLE_TRACING
value: "1"
- name: DISABLE_PROFILER
value: "1"
# - name: JAEGER_SERVICE_ADDR
# value: "jaeger-collector:14268"
# - name: CYMBAL_BRANDING
# value: "true"
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: ClusterIP
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: frontend-external
spec:
type: LoadBalancer
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: paymentservice
spec:
selector:
matchLabels:
app: paymentservice
template:
metadata:
labels:
app: paymentservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/paymentservice:v0.3.6
ports:
- containerPort: 50051
env:
- name: PORT
value: "50051"
- name: DISABLE_TRACING
value: "1"
- name: DISABLE_PROFILER
value: "1"
- name: DISABLE_DEBUGGER
value: "1"
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: paymentservice
spec:
type: ClusterIP
selector:
app: paymentservice
ports:
- name: grpc
port: 50051
targetPort: 50051
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: productcatalogservice
spec:
selector:
matchLabels:
app: productcatalogservice
template:
metadata:
labels:
app: productcatalogservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/productcatalogservice:v0.3.6
ports:
- containerPort: 3550
env:
- name: PORT
value: "3550"
- name: DISABLE_STATS
value: "1"
- name: DISABLE_TRACING
value: "1"
- name: DISABLE_PROFILER
value: "1"
# - name: JAEGER_SERVICE_ADDR
# value: "jaeger-collector:14268"
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:3550"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:3550"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: productcatalogservice
spec:
type: ClusterIP
selector:
app: productcatalogservice
ports:
- name: grpc
port: 3550
targetPort: 3550
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cartservice
spec:
selector:
matchLabels:
app: cartservice
template:
metadata:
labels:
app: cartservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/cartservice:v0.3.6
ports:
- containerPort: 7070
env:
- name: REDIS_ADDR
value: "redis-cart:6379"
resources:
requests:
cpu: 200m
memory: 64Mi
limits:
cpu: 300m
memory: 128Mi
readinessProbe:
initialDelaySeconds: 15
exec:
command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
livenessProbe:
initialDelaySeconds: 15
periodSeconds: 10
exec:
command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
---
apiVersion: v1
kind: Service
metadata:
name: cartservice
spec:
type: ClusterIP
selector:
app: cartservice
ports:
- name: grpc
port: 7070
targetPort: 7070
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: loadgenerator
spec:
selector:
matchLabels:
app: loadgenerator
replicas: 1
template:
metadata:
labels:
app: loadgenerator
annotations:
sidecar.istio.io/rewriteAppHTTPProbers: "true"
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
restartPolicy: Always
initContainers:
- command:
- /bin/sh
- -exc
- |
echo "Init container pinging frontend: ${FRONTEND_ADDR}..."
STATUSCODE=$(wget --server-response https://${FRONTEND_ADDR} 2>&1 | awk '/^ HTTP/{print $2}')
if test $STATUSCODE -ne 200; then
echo "Error: Could not reach frontend - Status code: ${STATUSCODE}"
exit 1
fi
name: frontend-check
image: busybox:latest
env:
- name: FRONTEND_ADDR
value: "frontend:80"
containers:
- name: main
image: gcr.io/google-samples/microservices-demo/loadgenerator:v0.3.6
env:
- name: FRONTEND_ADDR
value: "frontend:80"
- name: USERS
value: "10"
resources:
requests:
cpu: 300m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: currencyservice
spec:
selector:
matchLabels:
app: currencyservice
template:
metadata:
labels:
app: currencyservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/currencyservice:v0.3.6
ports:
- name: grpc
containerPort: 7000
env:
- name: PORT
value: "7000"
- name: DISABLE_TRACING
value: "1"
- name: DISABLE_PROFILER
value: "1"
- name: DISABLE_DEBUGGER
value: "1"
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:7000"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:7000"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: currencyservice
spec:
type: ClusterIP
selector:
app: currencyservice
ports:
- name: grpc
port: 7000
targetPort: 7000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: shippingservice
spec:
selector:
matchLabels:
app: shippingservice
template:
metadata:
labels:
app: shippingservice
spec:
serviceAccountName: default
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/shippingservice:v0.3.6
ports:
- containerPort: 50051
env:
- name: PORT
value: "50051"
- name: DISABLE_STATS
value: "1"
- name: DISABLE_TRACING
value: "1"
- name: DISABLE_PROFILER
value: "1"
# - name: JAEGER_SERVICE_ADDR
# value: "jaeger-collector:14268"
readinessProbe:
periodSeconds: 5
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: shippingservice
spec:
type: ClusterIP
selector:
app: shippingservice
ports:
- name: grpc
port: 50051
targetPort: 50051
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cart
spec:
selector:
matchLabels:
app: redis-cart
template:
metadata:
labels:
app: redis-cart
spec:
containers:
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
volumeMounts:
- mountPath: /data
name: redis-data
resources:
limits:
memory: 256Mi
cpu: 125m
requests:
cpu: 70m
memory: 200Mi
volumes:
- name: redis-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: redis-cart
spec:
type: ClusterIP
selector:
app: redis-cart
ports:
- name: redis
port: 6379
targetPort: 6379
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: adservice
spec:
selector:
matchLabels:
app: adservice
template:
metadata:
labels:
app: adservice
spec:
serviceAccountName: default
terminationGracePeriodSeconds: 5
containers:
- name: server
image: gcr.io/google-samples/microservices-demo/adservice:v0.3.6
ports:
- containerPort: 9555
env:
- name: PORT
value: "9555"
- name: DISABLE_STATS
value: "1"
- name: DISABLE_TRACING
value: "1"
# - name: JAEGER_SERVICE_ADDR
# value: "jaeger-collector:14268"
resources:
requests:
cpu: 200m
memory: 180Mi
limits:
cpu: 300m
memory: 300Mi
readinessProbe:
initialDelaySeconds: 20
periodSeconds: 15
exec:
command: ["/bin/grpc_health_probe", "-addr=:9555"]
livenessProbe:
initialDelaySeconds: 20
periodSeconds: 15
exec:
command: ["/bin/grpc_health_probe", "-addr=:9555"]
---
apiVersion: v1
kind: Service
metadata:
name: adservice
spec:
type: ClusterIP
selector:
app: adservice
ports:
- name: grpc
port: 9555
targetPort: 9555
---1
6. Create a namespace and deploy the microservices:
laptopuser@LaptopB3:~/online-shop-microservices$ kubectl create ns microservice
namespace/microservices created
laptopuser@LaptopB3:~/online-shop-microservices$ kubectl apply -f config.yaml -n microservicess
After some few minutes we have our microservices up and running and we can verify that either by using the commend below or by using kubenetes dashboard
$ kubectl get svc -n microservice
$ kubectl get podss
The result will be as follow. wait some minutes if all the services are not running before entering the command
In other to access your app via the browser, use one of the cluster ip address plus the port on which the external frontend is served.
https://194.233.170.149:32031/
And boooom
The Conclusion
Microservices are not new. It's an old software design pattern which has been growing in popularity due to the growing scale of Internet companies. Microservices do not necessarily have to be containerized. Similarly, a monolithic application can be a microservice. Small projects should not shy from the monolithic design. It offers higher productivity for smaller teams. Kubernetes is a great platform for complex applications comprised of multiple microservices.