Deploy the project in the Kubernetes cluster
At this point, we have already the Gitlab agent, the namespace for our deployments, and the credentials of the Container registry stored in a secret in our Kubernetes cluster. Now, let's create some scripts to automate the deployment process every time we push changes to our Gitlab repostiory.
Therefore, we need scripts to:
Create our Docker image of our Next JS project:
Create a file called Dockerfile in the root folder.
In this file we configure the deployment of our Next JS project in a Docker container. In this case, we will expose the port 3000.
./Dockerfile
FROM node:17-alpine
RUN mkdir -p /usr/src/app
ENV PORT 3000
WORKDIR /usr/src/app
COPY package.json /usr/src/app
COPY package-lock.json /usr/src/app
RUN npm ci
COPY . /usr/src/app
RUN npm run build
EXPOSE 3000
CMD [ "npm", "run", "start" ]
Integrate the Gitlab agent to our Next JS project.
Create a file called config.yaml in the folder ./.gitlab/agents/<agent_name>/
In this file we define the access of the Gitlab agent through the project path <project_path>.
./gitlab/agents/<agent_name>/config.yaml
ci_access:
projects:
- id: <project_path>
Define the deployment process in the Kubernetes cluster.
Create a file called deployment.yaml in the folder ./manifest/deploy/.
This file configure how to deploy the Docker image in the Kubernetes cluster.
./manifest/deploy/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: <deployment_name>
namespace: <namespace>
spec:
replicas: 1
selector:
matchLabels:
name: <project_name>
template:
metadata:
labels:
name: <project_name>
spec:
containers:
- name: <project_name>
image: registry.gitlab.com/<project_path>:latest
imagePullPolicy: Always
ports:
- containerPort: 3000
imagePullSecrets:
- name: registrycred
In this case, we will use the same port that was defined in the Dockerfile, port 3000. In addition, we take into consideration the registrycred secret which contains the credentials for the Container Registry.
Define the service that will be exposed in the Kubernetes cluster.
Create a file called service.yaml in the folder ./manifest/deploy/ to expose our service in the port 80 instead of 3000.
./manifest/deploy/service.yaml
apiVersion: v1
kind: Service
metadata:
name: <service_name>
namespace: <namespace>
spec:
type: NodePort
ports:
- name: https
port: 80
protocol: TCP
targetPort: 3000
selector:
name: <project_name>
Configure the Ingress which will manage the external access to the service.
Create a file called ingress.yaml in the folder ./manifest/deploy/ to configure the external access of our service.
./manifest/deploy/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: <ingress_name>
namespace: <namespace>
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: <service_name>
port:
number: 80
Define the pipeline that will run every time we push changes to the Gitlab repository.
Create a file called ./.gitlab-ci.yml in the root folder to configure the steps to deploy our application in the Kubernetes cluster.
./.gitlab-ci.yml
stages:
- build
- deploy
# build a new image, and push it to the cotnainer registry
build:
image: docker:stable
stage: build
services:
- name: docker:dind
alias: thedockerhost
variables:
DOCKER_HOST: tcp://thedockerhost:2375/
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
script:
- docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build . -t $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
only:
- main
# deploy the new image in the k8s cluster
deploy:
image:
name: bitnami/kubectl:latest
entrypoint: [""]
dependencies:
- build
stage: deploy
variables:
KUBE_CONTEXT: "<project_path>:<agent_name>"
before_script:
- if [ -n "$KUBE_CONTEXT" ]; then kubectl config use-context
"$KUBE_CONTEXT"; fi
script:
- kubectl get pods -n <namespace>
- kubectl apply -f $CI_PROJECT_DIR/manifest/deploy/deployment.yaml
- kubectl apply -f $CI_PROJECT_DIR/manifest/deploy/service.yaml
- kubectl apply -f $CI_PROJECT_DIR/manifest/deploy/ingress.yaml
- kubectl rollout restart deployment <deployment_name> -n <namespace>
- kubectl get pods -n <namespace>
only:
- main
We define two steps:
- Build - it will create the Docker image, and push it to the Container registry.
- Deploy - it will deploy the Docker image in our Kubernetes namespace.
Once the scripts are created, we push the changes to the Gitlab repository.
git add .
git commit -m 'Integration with the k8s cluster is done'
git push
We can verify in the Gitlab user interface if the pipeline was successful by navigating to "CI/CD" > "Pipelines".
We can also verify if the new pods were created in the Kubernetes cluster terminal.
kubectl get pods -n <namespace>
Finally, the new ingress can be verified if it has been created correclty.
kubectl describe ingress <ingress_name> -n <namespace>