go-app-intern is a web app written in Go that is dockerized, automated using jenkins and deployed on minikube.
Contains:
- Dockerfile
- dockercompose
- Jenkinsfile
- kubernetes files
- Docker
- docker compose
- Jenkins
- helm
- Minikube
This is the tree of the repository
.
├── Dockerfile
├── Jenkinsfile
├── README.md
├── app
│ ├── db.go
│ ├── go.mod
│ ├── go.sum
│ ├── main-app
│ └── main.go
├── charts
│ └── myapp
│ ├── Chart.yaml
│ ├── charts
│ │ └── mysql-8.8.16.tgz
│ ├── templates
│ │ ├── app-deployment.yaml
│ │ ├── app-service.yaml
│ │ ├── mysql-deployment.yaml
│ │ ├── mysql-service.yaml
│ │ ├── pv.yaml
│ │ ├── pvc.yaml
│ │ └── storageclass.yaml
│ └── values.yaml
├── docker-compose.yml
├── init.sql
└── main-app
go build -o main-app .
This will produce an artifiact called main-app then to run it
./main-app
FROM golang:1.19
WORKDIR /main-app
COPY ./app .
RUN GOOS=linux go build -o main-app .
EXPOSE 9090
CMD ["./main-app"]
To build image
docker build . -t app
The size of the image is more than 1 GB!!!
As we saw single stage Dockerfile generated an image that has very big size and that isn`t effiecient
FROM golang:1.19 AS build-stage
WORKDIR /app
COPY ./app .
RUN GOOS=linux go build -o main-app .
# Deploy the application binary into a lean image
FROM debian:11-slim AS build-release-stage
WORKDIR /app
COPY --from=build-stage /app .
#Create a non-root user
RUN adduser --disabled-password --gecos "" appuser
USER appuser
EXPOSE 9090
CMD ["./main-app"]
To build image
docker build . -t ahmedelmelegy3570/app-multistage
What we benifted from that?
The size of the image is greatly reduced
Now it is less than 0.1 GB!
To run container with the built image, we will map port 9090 from host to port 9090 in the container
docker run -p 9090:9090 ahmedelmelegy3570/app-multistage
to create a user and use it instead of root user
RUN adduser --disabled-password --gecos "" appuser
USER appuser
in dockercompose.yaml, I combined both app and mysql db so they have the same network and I made the app depend on mysql
version: '3'
services:
app:
image: app-multistage
ports:
- 9090:9090
depends_on:
- mysql
mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=1234
- MYSQL_DATABASE=mydb
- MYSQL_USER=ahmed
- MYSQL_PASSWORD=1234
volumes:
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- 3306:3306
command: ["--log-error-verbosity=3"]
To apply this docker compose file
docker-compose up
To install jenkins as container and it will run on port 8080
docker run -p 8080:8080 -p 50000:50000 -d -v /var/run/docker.sock:/var/run/docker.sock -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts
and this is the configuration of it
and I created credentials to be able to securly login to dockerhub to push image
This is the pipeline output after build it
app-deployment.yaml: Added support for multiple replicas using a configurable value. Added volume mounts and persistent volume claim (PVC) for volume persistence
spec:
replicas: {{ .Values.replicaCount }}
spec:
{{- if .Values.persistence.enabled }}
volumeMounts:
- name: app-persistent-storage
mountPath: /path/to/persistent/storage
{{- end }}
{{- if .Values.persistence.enabled }}
volumes:
- name: app-persistent-storage
persistentVolumeClaim:
claimName: app-pv-claim
{{- end }}
app-service.yaml: service type LoadBalancer to expose the service publicly.
apiVersion: v1
kind: Service
metadata:
name: app
spec:
selector:
app: app
ports:
- name: http
port: 9090
targetPort: 9090
type: LoadBalancer
Created values.yaml: Added configuration values for replica count, autoscaling, and persistence.
replicaCount: 3
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 5
targetCPUUtilizationPercentage: 50
persistence:
enabled: true
size: 10Gi
Created autoscaling.yaml: Added an autoscaling manifest to scale the number of replicas based on CPU utilization.
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: app-autoscaler
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: app
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
targetCPUUtilizationPercentage: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
Created app-pvc.yaml: Added a persistent volume claim definition for the app.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-pv-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.persistence.size }}
storageClassName: local-storage
Created storageclass.yaml: Defined a storage class for local storage.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
To deploy this app using helm run this command but before that you must need minikube cluster up and running
helm install myapp .
To browse the app
localhost:9090
localhost:9090/healthcheck
I tried to figure out where is the problem in the api but I couldn
t. I tried to debug the code so I put log.Println() in each function but I couldn
t find the problem.
The intenrship database and table named stuff is created so there is no problem in the connection between the app and mysql
mysql -h 127.0.0.1 -P 3306 -u ahmed -p
Enter password: 1234
mysql> use internship
mysql> SHOW TABLES;