Compare commits

...

30 Commits
step2 ... main

Author SHA1 Message Date
5518e818be Deploy the app in sandbox ns not sandbox-gitlab 2026-02-19 04:22:57 +02:00
GitLab CI
1cc53d145d ci: bump image tag to main-5bc9ffce [skip ci] 2026-02-19 02:15:08 +00:00
5bc9ffceff Enable ingress and pvc 2026-02-19 04:14:20 +02:00
007fc00710 Merge branch 'main' of https://gitlab.com/dvirlabs-group/open-meteo-service 2026-02-19 04:14:02 +02:00
9cc2501f89 Enable ingress and pvc 2026-02-19 04:11:37 +02:00
GitLab CI
5bd192ca3f ci: bump image tag to main-00e333cb [skip ci] 2026-02-19 02:09:43 +00:00
00e333cbe7 Enable ingress and pvc 2026-02-19 04:09:00 +02:00
GitLab CI
451a01cc87 ci: bump image tag to main-41a9a1e8 [skip ci] 2026-02-18 15:55:04 +00:00
41a9a1e8e2 Merge branch 'step3' into 'main'
Step3

See merge request dvirlabs-group/open-meteo-service!4
2026-02-18 15:54:26 +00:00
GitLab CI
c8402fd5d8 ci: bump image tag to step3-110ba605 [skip ci] 2026-02-18 09:34:36 +00:00
110ba60513 Update the git url 2026-02-18 11:33:59 +02:00
22c0f9b2ab Update the k3s yaml 2026-02-18 11:18:48 +02:00
b1d56d1cb7 Update the token 2026-02-18 11:17:33 +02:00
5dab10b843 Update the k3s yaml 2026-02-18 11:10:07 +02:00
9435e9a915 Test push 2026-02-18 11:08:38 +02:00
f367a0d032 Update gitlab token 2026-02-18 11:05:59 +02:00
fd817b5334 Set the VALUES_FILE env 2026-02-18 11:01:52 +02:00
cbefc54227 Test push 2026-02-18 10:58:10 +02:00
35a5afc715 Test push 2026-02-18 10:54:16 +02:00
7e6521f3bf Set the VALUES_FILE env 2026-02-18 10:51:45 +02:00
5a6d11c650 Set the env 2026-02-18 10:48:24 +02:00
0d356fb85d Test push 2026-02-18 10:38:13 +02:00
51a6b38c6c Test push 2026-02-18 10:34:57 +02:00
c155dc6b4d Update yq bin path 2026-02-18 10:29:57 +02:00
f490012cec Update yq command 2026-02-18 10:24:00 +02:00
f0d8a1d4da Update the registry 2026-02-18 10:16:45 +02:00
31bce27adf Update the registry 2026-02-18 04:22:47 +02:00
76d3359896 Update the pipeline to deploy on my k3s cluster andupdate the values 2026-02-18 04:04:35 +02:00
572e14d1dd Create cicd pipline 2026-02-17 16:09:16 +02:00
08d0c269d0 Merge branch 'step2' into 'main'
Step2

See merge request dvirlabs-group/open-meteo-service!3
2026-02-16 17:14:03 +00:00
4 changed files with 294 additions and 13 deletions

112
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,112 @@
stages: [build, deploy]
variables:
IMAGE_REPO: "$CI_REGISTRY_IMAGE"
TAG: "${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA}"
RELEASE: "open-meteo-service-gitlab"
NAMESPACE: "sandbox"
CHART_PATH: "./open-meteo-service"
VALUES_FILE: "./values.yaml"
build:
stage: build
tags: [homelab]
script:
- whoami
- set -euo pipefail
- unset DOCKER_HOST DOCKER_TLS_VERIFY DOCKER_CERT_PATH || true
- export DOCKER_HOST=unix:///var/run/docker.sock
- docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
- docker build -t "$IMAGE_REPO:$TAG" .
- docker push "$IMAGE_REPO:$TAG"
- docker tag "$IMAGE_REPO:$TAG" "$IMAGE_REPO:latest"
- docker push "$IMAGE_REPO:latest"
- echo "Built and pushed $IMAGE_REPO:$TAG and $IMAGE_REPO:latest"
deploy:
stage: deploy
tags: [homelab]
rules:
- if: '$CI_COMMIT_MESSAGE =~ /^ci: bump image tag/'
when: never
- when: on_success
script: |-
set -euo pipefail
# Configure kubectl for k3s cluster
export KUBECONFIG=/tmp/k3s.yaml
echo "Configured kubectl to use k3s cluster"
kubectl cluster-info || echo "Warning: Could not connect to cluster yet"
# Update values.yaml with the new tag using sed
sed -i "s/^ tag: .*/ tag: \"${TAG}\"/" "${VALUES_FILE}"
echo "Updated ${VALUES_FILE} with image.tag=${TAG}"
# Verify the change
grep -A 2 "^image:" "${VALUES_FILE}"
# Configure git identity
git config user.email "gitlab-ci@dvirlabs.com"
git config user.name "GitLab CI"
# Commit & push values bump (skip-ci to avoid loop)
git add "${VALUES_FILE}"
git commit -m "ci: bump image tag to ${TAG} [skip ci]" || echo "No changes to commit"
# Push using GITLAB_TOKEN (Project Access Token with api scope)
if [ -n "${GITLAB_TOKEN:-}" ]; then
git remote set-url origin "https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"
git push origin "HEAD:${CI_COMMIT_REF_NAME}" && echo "Pushed values.yaml update successfully" || echo "Failed to push, continuing deployment anyway"
else
echo "GITLAB_TOKEN not set, skipping git push (values.yaml is updated locally for this deployment)"
fi
# Create namespace if it doesn't exist
kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -
# Create or update GitLab registry secret for pulling images
echo "Creating/updating image pull secret..."
kubectl create secret docker-registry gitlab-registry \
--docker-server="${CI_REGISTRY}" \
--docker-username="${CI_REGISTRY_USER}" \
--docker-password="${CI_REGISTRY_PASSWORD}" \
--namespace="${NAMESPACE}" \
--dry-run=client -o yaml | kubectl apply -f -
echo "Deploying with Helm..."
helm upgrade --install "${RELEASE}" "${CHART_PATH}" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--create-namespace \
--wait --timeout 10m \
--debug
echo "Waiting for deployment to be ready..."
kubectl -n "${NAMESPACE}" rollout status deploy -l app.kubernetes.io/name=open-meteo-service --timeout=180s
echo "Port-forward for tests..."
SERVICE_NAME="${RELEASE}-open-meteo-service"
kubectl -n "${NAMESPACE}" port-forward "svc/${SERVICE_NAME}" 8000:8000 >/tmp/pf.log 2>&1 &
PF_PID=$!
sleep 5
echo "Testing /healthz..."
curl -fsS http://localhost:8000/healthz >/dev/null
echo "OK /healthz"
echo "Testing /coordinates..."
COORDS_RESPONSE="$(curl -fsS http://localhost:8000/coordinates)"
echo "$COORDS_RESPONSE" | head -20
if ! echo "$COORDS_RESPONSE" | grep -q '"data"'; then
echo "ERROR: /coordinates response missing 'data' field"
kill $PF_PID || true
exit 1
fi
echo "OK /coordinates"
echo "Testing /metrics..."
curl -fsS http://localhost:8000/metrics | head -20
echo "OK /metrics"
kill $PF_PID || true
echo "All tests passed!"

View File

@ -99,6 +99,78 @@ helm install open-meteo-service ./helm \
--set grafana.persistence.enabled=true
```
## GitLab CI Workflow
This project uses a GitLab CI/CD pipeline that automates building, versioning, deployment, and testing on an external k3s cluster (homelab).
### Pipeline Overview
The pipeline consists of two stages: **build** and **deploy**.
#### 1. Build Stage
- **Docker Image Build**: Builds the application Docker image using the project Dockerfile
- **Tagging Strategy**: Tags each image with a unique identifier combining branch and commit SHA:
- Format: `<branch>-<shortsha>` (e.g., `main-a1b2c3d`, `feature-api-xyz1234`)
- Uses `CI_COMMIT_REF_SLUG` (sanitized branch name) and `CI_COMMIT_SHORT_SHA`
- **Multi-Tag Push**: Pushes two tags to GitLab Container Registry:
- `$IMAGE_REPO:<branch>-<shortsha>` - Specific version tag
- `$IMAGE_REPO:latest` - Always points to the most recent build
- **Registry Authentication**: Uses GitLab's built-in CI variables (`CI_REGISTRY`, `CI_REGISTRY_USER`, `CI_REGISTRY_PASSWORD`)
#### 2. Deploy Stage
- **Values File Update**:
- Uses `yq` to update `open-meteo-service/values.yaml`
- Sets `image.tag` to the newly built tag (`<branch>-<shortsha>`)
- Keeps `image.repository` constant in the values file
- Commits the change with message: `ci: bump image tag to <tag> [skip ci]`
- Pushes back to the repository using `CI_JOB_TOKEN` for authentication
- **Helm Deployment**:
- Deploys to namespace: `sandbox`
- Release name: `open-meteo-service-gitlab`
- Uses the updated values.yaml file from the workspace
- Waits for deployment to be ready (5-minute timeout)
- **Automated Tests**:
- Port-forwards the service to localhost:8000
- `/healthz` - Checks service health
- `/coordinates` - Validates JSON response contains `"data"` field
- `/metrics` - Ensures metrics endpoint is accessible
- All tests must pass for the pipeline to succeed
### Preventing Infinite Loops
The pipeline includes safeguards to prevent infinite pipeline triggers:
- The deploy job includes a rule: `if: '$CI_COMMIT_MESSAGE =~ /^ci: bump image tag/'` with `when: never`
- The values bump commit includes `[skip ci]` to prevent triggering a new pipeline
- The deploy job uses the already-updated values.yaml in the current workspace
### Deployment Target
- **Cluster**: External k3s homelab cluster (not ephemeral)
- **Runner**: Self-hosted GitLab runner tagged with `homelab`
- **Namespace**: `sandbox` (separate from ArgoCD/Harbor setups)
- **Ingress**: Configured for `open-meteo-gitlab.dvirlabs.com` (see values.yaml)
### Viewing Pipeline Status
1. Navigate to **CI/CD > Pipelines** in your GitLab project
2. Click on any pipeline run to see job details
3. Expand jobs to view real-time logs
4. The deploy job shows Helm output, rollout status, and test results
### Manual Deployment
To deploy manually with a specific tag:
```bash
# Option 1: Deploy using updated values.yaml
helm upgrade --install open-meteo-service-gitlab ./open-meteo-service \
-n sandbox --create-namespace
# Option 2: Override tag via --set
helm upgrade --install open-meteo-service-gitlab ./open-meteo-service \
-n sandbox --create-namespace \
--set image.tag=main-a1b2c3d
```
## API Documentation
### Endpoints

View File

@ -1,22 +1,22 @@
replicaCount: 1
image:
repository: harbor.dvirlabs.com/my-apps/open-meteo-service
tag: "1.0.2"
repository: registry.gitlab.com/dvirlabs/open-meteo-service
tag: "latest"
pullPolicy: IfNotPresent
imagePullSecrets:
- name: harbor-regcred
- name: gitlab-registry
service:
type: ClusterIP
port: 8000
ingress:
enabled: true
className: "traefik"
enabled: false
className: ""
hosts:
- host: open-meteo.dvirlabs.com
- host: open-meteo-gitlab.dvirlabs.com
paths:
- path: /
pathType: Prefix
@ -53,10 +53,10 @@ prometheus:
type: ClusterIP
port: 9090
ingress:
enabled: true
className: "traefik"
enabled: false
className: ""
hosts:
- host: open-meteo-prometheus.dvirlabs.com
- host: prometheus.local
paths:
- path: /
pathType: Prefix
@ -80,10 +80,10 @@ grafana:
adminUser: admin
adminPassword: admin
ingress:
enabled: true
className: "traefik"
enabled: false
className: ""
hosts:
- host: open-meteo-grafana.dvirlabs.com
- host: grafana.local
paths:
- path: /
pathType: Prefix
@ -94,4 +94,4 @@ grafana:
- ReadWriteOnce
size: 5Gi
storageClassName: ""
resources: {}
resources: {}

97
values.yaml Normal file
View File

@ -0,0 +1,97 @@
replicaCount: 1
image:
repository: registry.gitlab.com/dvirlabs-group/open-meteo-service
tag: "main-5bc9ffce"
pullPolicy: IfNotPresent
imagePullSecrets:
- name: gitlab-registry
service:
type: ClusterIP
port: 8000
ingress:
enabled: true
className: "traefik"
hosts:
- host: open-meteo-gitlab.dvirlabs.com
paths:
- path: /
pathType: Prefix
tls: []
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/path: /metrics
prometheus.io/port: "8000"
env:
cacheFile: /data/coordinates_cache.json
persistence:
enabled: true
accessModes:
- ReadWriteOnce
size: 1Gi
storageClassName: "nfs-client"
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
prometheus:
enabled: true
replicaCount: 1
image: prom/prometheus:latest
service:
type: ClusterIP
port: 9090
ingress:
enabled: true
className: "traefik"
hosts:
- host: open-meteo-prometheus-gitlab.dvirlabs.com
paths:
- path: /
pathType: Prefix
tls: []
persistence:
enabled: true
accessModes:
- ReadWriteOnce
size: 5Gi
storageClassName: "nfs-client"
resources: {}
extraArgs: []
grafana:
enabled: true
replicaCount: 1
image: grafana/grafana:latest
service:
type: ClusterIP
port: 3000
adminUser: admin
adminPassword: admin
ingress:
enabled: true
className: "traefik"
hosts:
- host: open-meteo-grafana-gitlab.dvirlabs.com
paths:
- path: /
pathType: Prefix
tls: []
persistence:
enabled: true
accessModes:
- ReadWriteOnce
size: 5Gi
storageClassName: "nfs-client"
resources: {}