init: go api with CI/CD
All checks were successful
Build & Deploy Go API / build (push) Successful in 33s
All checks were successful
Build & Deploy Go API / build (push) Successful in 33s
This commit is contained in:
50
.gitea/workflows/build.yml
Normal file
50
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
name: Build & Deploy Go API
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: zot-registry.cicd.svc.cluster.local:5000
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- name: Install build tools
|
||||||
|
run: apk add --no-cache curl git docker-cli 2>/dev/null || true
|
||||||
|
|
||||||
|
- name: Clone + prepare
|
||||||
|
run: |
|
||||||
|
WORK=/root/.cache/demo-go-api
|
||||||
|
mkdir -p $WORK
|
||||||
|
cd $WORK
|
||||||
|
[ -d .git ] || git clone http://joe:${GITEA_TOKEN}@192.168.1.212:3000/joe/demo-go-api.git .
|
||||||
|
git pull
|
||||||
|
|
||||||
|
- name: Build & push image
|
||||||
|
run: |
|
||||||
|
cd /root/.cache/demo-go-api
|
||||||
|
SHORT=${GITHUB_SHA::8}
|
||||||
|
TAG="${REGISTRY}/demo-go-api:${SHORT}"
|
||||||
|
LATEST="${REGISTRY}/demo-go-api:latest"
|
||||||
|
docker build --build-arg VERSION=${SHORT} -t "${TAG}" -t "${LATEST}" .
|
||||||
|
docker push "${TAG}"
|
||||||
|
docker push "${LATEST}"
|
||||||
|
echo "✓ Pushed ${TAG}"
|
||||||
|
env:
|
||||||
|
GITHUB_SHA: ${{ github.sha }}
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
- name: Patch ArgoCD
|
||||||
|
run: |
|
||||||
|
SHORT=${GITHUB_SHA::8}
|
||||||
|
if kubectl -n argocd get application demo-go-api &>/dev/null; then
|
||||||
|
kubectl -n argocd patch application demo-go-api --type merge \
|
||||||
|
-p "{\"spec\":{\"source\":{\"helm\":{\"parameters\":[{\"name\":\"image.tag\",\"value\":\"${SHORT}\"}]}}}}"
|
||||||
|
echo "✓ ArgoCD patched"
|
||||||
|
else
|
||||||
|
echo "⚠ demo-go-api Application not yet created"
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
GITHUB_SHA: ${{ github.sha }}
|
||||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
FROM golang:1.23-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY go.mod ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
ARG VERSION=dev
|
||||||
|
RUN CGO_ENABLED=0 go build -ldflags="-s -w -X main.VERSION=${VERSION}" -o /out/api .
|
||||||
|
|
||||||
|
FROM gcr.io/distroless/static-debian12:nonroot
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /out/api /app/api
|
||||||
|
USER nonroot:nonroot
|
||||||
|
EXPOSE 8080
|
||||||
|
ENTRYPOINT ["/app/api"]
|
||||||
9
deploy/helm/Chart.yaml
Normal file
9
deploy/helm/Chart.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Minimal Helm chart for any service
|
||||||
|
# Place at: <repo>/deploy/helm/
|
||||||
|
|
||||||
|
apiVersion: v2
|
||||||
|
name: demo-go-api
|
||||||
|
description: Standard Helm chart for k3s services
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
85
deploy/helm/templates/deployment.yaml
Normal file
85
deploy/helm/templates/deployment.yaml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ .Chart.Name }}
|
||||||
|
labels:
|
||||||
|
app: {{ .Chart.Name }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ .Chart.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ .Chart.Name }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.registry }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.service.port }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- if .Values.probes.liveness.enabled }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.probes.liveness.path }}
|
||||||
|
port: {{ .Values.probes.liveness.port }}
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.probes.readiness.enabled }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.probes.readiness.path }}
|
||||||
|
port: {{ .Values.probes.readiness.port }}
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
{{- end }}
|
||||||
|
env:
|
||||||
|
{{- toYaml .Values.env | nindent 12 }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ .Chart.Name }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
selector:
|
||||||
|
app: {{ .Chart.Name }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ .Chart.Name }}
|
||||||
|
annotations:
|
||||||
|
{{- if .Values.ingress.className }}
|
||||||
|
kubernetes.io/ingress.class: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.ingress.host }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: {{ .Values.ingress.path | default "/" }}
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ .Chart.Name }}
|
||||||
|
port:
|
||||||
|
number: {{ .Values.service.port }}
|
||||||
|
{{- end }}
|
||||||
38
deploy/helm/values.yaml
Normal file
38
deploy/helm/values.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Default values
|
||||||
|
image:
|
||||||
|
registry: 127.0.0.1:5000
|
||||||
|
name: demo-go-api
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: Always
|
||||||
|
|
||||||
|
replicaCount: 2
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
className: traefik
|
||||||
|
host: demo-go-api.local
|
||||||
|
path: /
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
env: []
|
||||||
|
|
||||||
|
probes:
|
||||||
|
liveness:
|
||||||
|
enabled: true
|
||||||
|
path: /healthz
|
||||||
|
port: 8080
|
||||||
|
readiness:
|
||||||
|
enabled: true
|
||||||
|
path: /healthz
|
||||||
|
port: 8080
|
||||||
44
main.go
Normal file
44
main.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Service string `json:"service"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Time string `json:"time"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
port := os.Getenv("PORT")
|
||||||
|
if port == "" {
|
||||||
|
port = "8080"
|
||||||
|
}
|
||||||
|
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hostname, _ := os.Hostname()
|
||||||
|
resp := Response{
|
||||||
|
Service: "demo-go-api",
|
||||||
|
Message: "Hello from Go API!",
|
||||||
|
Time: time.Now().Format(time.RFC3339),
|
||||||
|
Hostname: hostname,
|
||||||
|
Version: os.Getenv("VERSION"),
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(resp)
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("ok"))
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Printf("Listening on :%s", port)
|
||||||
|
log.Fatal(http.ListenAndServe(":"+port, nil))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user