<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Liston Fermi</title>
    <description>The latest articles on DEV Community by Liston Fermi (@listonfermi).</description>
    <link>https://dev.to/listonfermi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1859645%2Fc5a6f884-0ac0-4dc8-ab25-53e5ace626a4.jpeg</url>
      <title>DEV Community: Liston Fermi</title>
      <link>https://dev.to/listonfermi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/listonfermi"/>
    <language>en</language>
    <item>
      <title>Deploying Microservices with Google Cloud Platform's GKE</title>
      <dc:creator>Liston Fermi</dc:creator>
      <pubDate>Wed, 31 Jul 2024 09:44:46 +0000</pubDate>
      <link>https://dev.to/listonfermi/deploying-microservices-with-google-cloud-platforms-gke-3npn</link>
      <guid>https://dev.to/listonfermi/deploying-microservices-with-google-cloud-platforms-gke-3npn</guid>
      <description>&lt;p&gt;Stack used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend : React - Next.js&lt;/li&gt;
&lt;li&gt;Backend: Node - Express.js&lt;/li&gt;
&lt;li&gt;DB: Mongodb-atlas&lt;/li&gt;
&lt;li&gt;RabbitMQ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;To Begin with:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have docker desktop &amp;amp; kubectl already installed.&lt;/li&gt;
&lt;li&gt;Create an account with google cloud&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verify your payment method &amp;amp; get a credit of about $300.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Google cloud console,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a project.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a new Kubernetes cluster:
&lt;/h2&gt;

&lt;p&gt;Select standard mode and configure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yattxb7pi17ijky0vxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yattxb7pi17ijky0vxf.png" width="761" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3mscy6w8pn83kx96ivg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3mscy6w8pn83kx96ivg.png" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding a nodepool in your cluster&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before adding-&lt;/p&gt;

&lt;p&gt;Calculate the amount of CPUs &amp;amp; RAM we need according to the no.of services you have:&lt;/p&gt;

&lt;p&gt;In this project we have :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend &lt;/li&gt;
&lt;li&gt;5 different backend servers&lt;/li&gt;
&lt;li&gt;RabbitMQ as the message broker&lt;/li&gt;
&lt;li&gt;Need a load balancer- Nginx&lt;/li&gt;
&lt;li&gt;Also include any database you are going to use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;In this project we don't have the database locally, because we used mongodb's cloud service mongodb-atlas&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The below is the example calculation done using ChatGPT:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example Calculation
Suppose each backend service requires 0.5 CPU and 1 GB of RAM, and the frontend, RabbitMQ, and Nginx each require 1 CPU and 2 GB of RAM:

Backend Services:
5 services * 0.5 CPU + 1 GB RAM = 2.5 CPU + 5 GB RAM
Frontend:
1 CPU + 2 GB RAM
RabbitMQ:
1 CPU + 2 GB RAM
Nginx:
1 CPU + 2 GB RAM
Total estimated requirements:

CPU: 5.5
RAM: 11 GB
If you choose n1-standard-2 nodes (which have 2 CPUs and 7.5 GB RAM each):

Each node can handle: 2 CPU + 7.5 GB RAM
Number of nodes required:
CPU: ceil(5.5 / 2) = 3 nodes
RAM: ceil(11 / 7.5) = 2 nodes
Since the RAM requirement calculation gives a higher number, you would start with 3 nodes to satisfy both CPU and RAM requirements.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Go to Kubernetes Clusters&lt;/li&gt;
&lt;li&gt;Select your cluster&lt;/li&gt;
&lt;li&gt;Inside that cluster, click on "ADD NODE POOL"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So from this calculation, I chose to go with 3 nodes.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkf0rrwoswk24ro7eibh7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkf0rrwoswk24ro7eibh7.png" alt="Adding a node pool" width="800" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4t189c97patjoxbb4ym9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4t189c97patjoxbb4ym9.png" alt="Adding a node pool" width="800" height="743"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating an image of your frontend, servers and pushing it to the docker hub&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create an Dockerfile &amp;amp;&amp;amp; .dockerignore file inside each services &amp;amp; frontend folder if you haven't did it already&lt;/p&gt;

&lt;p&gt;This is my Dockerfile for the frontend.&lt;/p&gt;

&lt;p&gt;There are several ways to use the env. In the frontend dockerfile, we are giving the env using build arguments.&lt;/p&gt;

&lt;p&gt;/frontend/Dockerfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:20.8.0

WORKDIR /app

# Define build argument for JWT key
ARG JWT_KEY

# Set the environment variable
ENV JWT_KEY=$JWT_KEY

COPY package*.json ./

RUN npm install

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "start" ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also add the .dockerignore file and add the necessary files/folders to be ignored while building the image&lt;/p&gt;

&lt;p&gt;Building the image: &lt;/p&gt;

&lt;p&gt;/frontend&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker build --build-arg JWT_KEY=myjwtkey -t listonfermi/wenet-frontend .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker build --build-arg JWT_KEY=JWTKeyGoesHere -t dockerusername/image-name .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Pushing the image to docker:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker push listonfermi/wenet-frontend&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker push dockerusername/image-name&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The same process for the backend severs.&lt;/p&gt;

&lt;p&gt;Before building an image for the backend servers, make sure you have the relevant scripts in package.json and tsconfig.json &lt;/p&gt;

&lt;p&gt;package.json - scripts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
    "dev": "nodemon",
    "build": "tsc",
    "start": "node ./dist/server.js"
  },

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;tsconfig.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs", /* Specify what module code is generated. */
    "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
    "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
    "strict": true, /* Enable all strict type-checking options. */
    "skipLibCheck": true, /* Skip type checking all .d.ts files. */
    "outDir": "./dist"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;/user-service/Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:20.8.0

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

RUN npm run build

EXPOSE 5001

CMD ["node", "dist/server.js"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building the image: &lt;/p&gt;

&lt;p&gt;/user-service:&lt;br&gt;
&lt;code&gt;docker build -t listonfermi/wenet-user-service .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker build dockerusername/image-name .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Pushing the image to docker:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker push listonfermi/wenet-user-service&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker push dockerusername/image-name&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Here also you can give the env in build arguments if you wish.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since we didn't build the user-service image without the env, we can give it in kubernetes configmap or secrets in the google cloud cluster.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating manifest files
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;In Kubernetes, manifest files are text files in JSON or YAML format that describe the desired state of API objects in a cluster&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Deployment &amp;amp; service files for frontend, user-service and rabbitmq should look like this :&lt;/p&gt;

&lt;p&gt;/k8s-manifests/frontend-depl.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
        - name: frontend
          image: listonfermi/wenet-frontend
          envFrom:
            - configMapRef:
                name: frontend-env  //we'll create a configmap named frontend-env inside the GKE cluster
---
apiVersion: v1
kind: Service
metadata: 
  name: frontend-srv
spec:
  selector:
    app: frontend
  ports:
    - name: frontend-ports
      protocol: TCP
      port: 3000
      targetPort: 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;/k8s-manifests/rabbitmq-depl.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: rabbitmq-depl
  labels:
    app: rabbitmq
spec:
  replicas: 1
  selector:
    matchLabels:
      app: rabbitmq
  template:
    metadata:
      labels:
        app: rabbitmq
    spec:
      containers:
        - name: rabbitmq
          image: rabbitmq:3-management
          ports:
            - containerPort: 5672 # RabbitMQ main port
            - containerPort: 15672 # RabbitMQ management plugin port
          volumeMounts:
            - name: rabbitmq-data
              mountPath: /var/lib/rabbitmq
      volumes:
        - name: rabbitmq-data
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: rabbitmq-service
spec:
  selector:
    app: rabbitmq
  ports:
    - name: amqp
      protocol: TCP
      port: 5672
      targetPort: 5672
    - name: management
      protocol: TCP
      port: 15672
      targetPort: 15672
  type: ClusterIP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;/k8s-manifests/user-service-depl.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service-depl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
        - name: user-service-container
          image: listonfermi/wenet-user-service
          envFrom:
            - configMapRef:
                name: user-service-env
---
apiVersion: v1
kind: Service
metadata:
  name: user-service-srv
spec:
  selector:
    app: user-service
  ports:
    - name: user-service-ports
      protocol: TCP
      port: 5001
      targetPort: 5001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Creating manifests for Loadbalancer nginx-ingress&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need a loadbalancer to get external ip address to connect with the cluster and need to route it to the proper paths.&lt;/p&gt;

&lt;p&gt;k8s-manifests/ingress-ngix-depl.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-controller
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  ingressClassName: "nginx"
  rules:
    - host: "*"
          - path: /api/user-service/
            pathType: Prefix
            backend:
              service:
                name: user-service-srv
                port:
                  number: 5001
          - path: /api/posts-service/
            pathType: Prefix
            backend:
              service:
                name: posts-service-srv
                port:
                  number: 5002
          - path: /socket.io
            pathType: Prefix
            backend:
              service:
                name: message-service-srv
                port:
                  number: 5003
          - path: /api/message-service/
            pathType: Prefix
            backend:
              service:
                name: message-service-srv
                port:
                  number: 5003
          - path: /api/notification-service/
            pathType: Prefix
            backend:
              service:
                name: notification-service-srv
                port:
                  number: 5004
          - path: /api/ads-service/
            pathType: Prefix
            backend:
              service:
                name: ads-service-srv
                port:
                  number: 5005
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-srv
                port:
                  number: 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Applying these manifests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before applying these manifests, we need to change our kubernetes context. Because, only if we change the context to our gcloud cluster's context, these yaml files will be applied there. &lt;/p&gt;

&lt;p&gt;You can check the kubernetes context by this command: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl config get-contexts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or in docker-desktop :&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05hxmrcdbkdlr4kawmjk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05hxmrcdbkdlr4kawmjk.png" width="800" height="745"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Changing the context to our GCP cluster:
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl" rel="noopener noreferrer"&gt;Offical doc for configuring the cluster access&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Download the gcloud CLI via this link : &lt;a href="https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe" rel="noopener noreferrer"&gt;gcloud installer&lt;/a&gt; or follow the steps from this &lt;a href="https://cloud.google.com/sdk/docs/install" rel="noopener noreferrer"&gt;doc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From your gcloud terminal :&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2mhhzr496iqi77o8pae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2mhhzr496iqi77o8pae.png" alt="Image description" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This command creates a different context in dockerdesktop:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gcloud container clusters get-credentials wenet-cluster --region=asia-south1-a&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gcloud container clusters get-credentials &amp;lt;your-cluster-name&amp;gt; --zone &amp;lt;your-zone&amp;gt; --project &amp;lt;your-project-id&amp;gt;&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Every kubectl commands we use from now on will be executed in our gcloud cluster.&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding configmaps to the gcloud cluster:
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;We need to create configmaps in the gcloud cluster which is to be used with the user-service deployment&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We are creating a configmap from .env file in the user-service folder to the &lt;/p&gt;

&lt;p&gt;/user-service:&lt;br&gt;
&lt;code&gt;kubectl create configmap user-service-env --from-env-file=.env&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We can do this for all the env of every backend services&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Applying the frontend deployment manifests: *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;/k8s-manifests/ &lt;br&gt;
&lt;code&gt;kubectl apply -f frontend-depl.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f user-service.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f rabbitmq-depl.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Applying ingress-nginx.yaml:&lt;/p&gt;

&lt;p&gt;_ This command is found in this &lt;a href="https://kubernetes.github.io/ingress-nginx/deploy/#gce-gke" rel="noopener noreferrer"&gt;docs&lt;/a&gt;  _&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.1/deploy/static/provider/cloud/deploy.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f ingress-ngix-depl.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now deployments and services will be created in the cluster.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;check for any errors if any in the google cloud console.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Select Ingress from 'Gateways, Services &amp;amp; Ingress' option from Google cloud Console&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F238297bbaw42igx7xbc9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F238297bbaw42igx7xbc9.png" alt="Gateways, Services &amp;amp; Ingress" width="432" height="851"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxk9wh3x7tkk1gd84pdzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxk9wh3x7tkk1gd84pdzd.png" alt="Ingress Controller" width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the above IP address.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Check if you the application works as expected&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting the DNS for the domain
&lt;/h2&gt;

&lt;p&gt;We can buy a domain from any websites like goDaddy, hostinger etc.&lt;/p&gt;

&lt;p&gt;Change the DNS to your ip&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is the DNS settings from GoDaddy&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0boem3hi5qtgzkpkpyxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0boem3hi5qtgzkpkpyxl.png" alt="goDaddy hosting DNS" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Check the working of the application through the domain&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting SSL certificate
&lt;/h2&gt;

&lt;p&gt;For SSL certificate, we can create ClusterIssuer and Certificate yaml files. We're using &lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;letsencrypt.org&lt;/a&gt; 's api.&lt;/p&gt;

&lt;p&gt;/k8s-manifests/letsencrypt-prod.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: listonfermi@gmail.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;k8s-manifests/certificate.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wenet-life-tls
  namespace: default
spec:
  secretName: wenet-life-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  commonName: wenet.life
  dnsNames:
    - wenet.life
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply these files in the GKE cluster kubernetes cluster&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apply cert manager: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f certificate.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f letsencrypt-prod.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After successfully applying,&lt;br&gt;
now do changes in the ingress-nginx-depl.yaml&lt;/p&gt;

&lt;p&gt;Add annotations, rules- host and tls in the depl file.&lt;/p&gt;

&lt;p&gt;/k8s-manifests/ingress-nginx.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-controller
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "http://wenet.life, https://wenet.life"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: "nginx"
  rules:
    - host: wenet.life
      http:
        paths:
          - path: /.well-known/acme-challenge/
            pathType: ImplementationSpecific
            backend:
              service:
                name: cm-acme-http-solver-&amp;lt;random&amp;gt;
                port:
                  number: 8089
          - path: /api/user-service/
            pathType: Prefix
            backend:
              service:
                name: user-service-srv
                port:
                  number: 5001
          - path: /api/posts-service/
            pathType: Prefix
            backend:
              service:
                name: posts-service-srv
                port:
                  number: 5002
          - path: /socket.io
            pathType: Prefix
            backend:
              service:
                name: message-service-srv
                port:
                  number: 5003
          - path: /api/message-service/
            pathType: Prefix
            backend:
              service:
                name: message-service-srv
                port:
                  number: 5003
          - path: /api/notification-service/
            pathType: Prefix
            backend:
              service:
                name: notification-service-srv
                port:
                  number: 5004
          - path: /api/ads-service/
            pathType: Prefix
            backend:
              service:
                name: ads-service-srv
                port:
                  number: 5005
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-srv
                port:
                  number: 3000
  tls:
  - hosts:
    - wenet.life
    secretName: wenet-life-tls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again apply the ingress-nginx-depl.yaml file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f ingress-nginx-depl.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;check the domain with https:// if its working&lt;/em&gt;&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>googlecloud</category>
      <category>kubernetes</category>
      <category>gke</category>
    </item>
  </channel>
</rss>
