Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,4 @@ jobs:
git remote add gitlab https://gitlab.com/dk-raas/dkai/high-command/high-command-api.git
git config credential.helper '!f() { echo "username=oauth2"; echo "password=${GITLAB_TOKEN}"; }; f'
git fetch gitlab main
git pull gitlab main --no-edit
git push gitlab HEAD:main
git push gitlab HEAD:main --force
217 changes: 194 additions & 23 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,210 @@
stages:
- build
- docker
- release
- deploy

variables:
HARBOR_REGISTRY: harbor.dataknife.net
HARBOR_PROJECT: library
IMAGE_NAME: high-command-api
K8S_NAMESPACE: high-command
DEPLOYMENT_NAME: high-command-api

docker-build:
build:
stage: build
image: docker:latest
services:
- docker:dind
image: harbor.dataknife.net/dockerhub/library/python:3.14-slim
script:
- apt-get update && apt-get install -y --no-install-recommends make git
- make build
artifacts:
paths:
- dist/
- build/
- *.egg-info/
expire_in: 1 hour
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG'
tags:
- kubernetes

publish:
stage: docker
image:
name: moby/buildkit:rootless
entrypoint: [""]
dependencies:
- build
script:
- |
# Use commit SHA if available, otherwise fall back to pipeline ID
IMAGE_TAG="${CI_COMMIT_SHORT_SHA:-$CI_PIPELINE_ID}"

# Build and push images with BuildKit rootless (multiple outputs for multiple tags)
OUTPUT_FLAGS="--output type=image,name=$HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:latest,push=true"
OUTPUT_FLAGS="$OUTPUT_FLAGS --output type=image,name=$HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$IMAGE_TAG,push=true"

# Add version tag if tag exists
if [ -n "$CI_COMMIT_TAG" ]; then
OUTPUT_FLAGS="$OUTPUT_FLAGS --output type=image,name=$HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$CI_COMMIT_TAG,push=true"
fi

buildctl-daemonless.sh build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
$OUTPUT_FLAGS
rules:
- if: '$CI_COMMIT_TAG' # Run on any git tag
tags:
- kubernetes

release:
stage: release
image: registry.gitlab.com/gitlab-org/cli:latest
rules:
- if: $CI_COMMIT_TAG
when: never # Do not run this job when a tag is created manually
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when commits are pushed or merged to the default branch
script:
- |
echo "Creating release for commit $CI_COMMIT_SHORT_SHA"
echo "Release will create tag automatically"
release: # See https://docs.gitlab.com/ee/ci/yaml/#release for available properties
tag_name: 'v0.$CI_PIPELINE_IID' # The version is incremented per pipeline
description: 'Release v0.$CI_PIPELINE_IID'
ref: '$CI_COMMIT_SHA' # The tag is created from the pipeline SHA
tags:
- kubernetes

deploy:
stage: deploy
image: harbor.dataknife.net/dockerhub/library/bitnami/kubectl:latest
dependencies:
- publish
variables:
KUBECONFIG: /tmp/kubeconfig
before_script:
- echo "$HARBOR_PASSWORD" | docker login -u "$HARBOR_USERNAME" --password-stdin $HARBOR_REGISTRY
- |
# Write kubeconfig from GitLab variable
echo "$PRD_APPS_KUBECONFIG" | base64 -d > $KUBECONFIG
chmod 600 $KUBECONFIG
kubectl config use-context prd-apps || kubectl config get-contexts | head -5
script:
- |
# Build image once
docker build -t $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:latest .
# Use semantic version tag if available, otherwise use commit SHA
if [ -n "$CI_COMMIT_TAG" ] && [[ "$CI_COMMIT_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
IMAGE_VERSION="$CI_COMMIT_TAG"
else
IMAGE_VERSION="${CI_COMMIT_SHORT_SHA:-$CI_PIPELINE_ID}"
fi

# Tag with commit SHA
docker tag $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:latest \
$HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
FULL_IMAGE="$HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$IMAGE_VERSION"

# Push images
docker push $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:latest
docker push $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
echo "Deploying $DEPLOYMENT_NAME to prd-apps cluster"
echo "Image: $FULL_IMAGE"
echo "Namespace: $K8S_NAMESPACE"

# Tag with version if tag exists
if [ -n "$CI_COMMIT_TAG" ]; then
docker tag $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:latest \
$HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$CI_COMMIT_TAG
docker push $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$CI_COMMIT_TAG
# Create namespace if it doesn't exist
kubectl create namespace $K8S_NAMESPACE --dry-run=client -o yaml | kubectl apply -f -

# Determine current deployment color (blue or green)
CURRENT_COLOR=$(kubectl get deployment $DEPLOYMENT_NAME -n $K8S_NAMESPACE -o jsonpath='{.spec.template.metadata.labels.deployment-color}' 2>/dev/null || echo "blue")

if [ "$CURRENT_COLOR" = "blue" ]; then
NEW_COLOR="green"
else
NEW_COLOR="blue"
fi

echo "Current deployment: $CURRENT_COLOR"
echo "New deployment: $NEW_COLOR"

# Create green/blue deployment
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${DEPLOYMENT_NAME}-${NEW_COLOR}
namespace: $K8S_NAMESPACE
labels:
app: $DEPLOYMENT_NAME
deployment-color: $NEW_COLOR
spec:
replicas: 2
selector:
matchLabels:
app: $DEPLOYMENT_NAME
deployment-color: $NEW_COLOR
template:
metadata:
labels:
app: $DEPLOYMENT_NAME
deployment-color: $NEW_COLOR
version: $IMAGE_VERSION
spec:
imagePullSecrets:
- name: harbor-registry-secret
containers:
- name: $DEPLOYMENT_NAME
image: $FULL_IMAGE
imagePullPolicy: Always
ports:
- containerPort: 5000
name: http
env:
- name: LOG_LEVEL
value: "info"
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
EOF

# Wait for new deployment to be ready
echo "Waiting for ${DEPLOYMENT_NAME}-${NEW_COLOR} to be ready..."
kubectl rollout status deployment/${DEPLOYMENT_NAME}-${NEW_COLOR} -n $K8S_NAMESPACE --timeout=300s

# Create or update service to point to new deployment
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: $DEPLOYMENT_NAME
namespace: $K8S_NAMESPACE
spec:
type: ClusterIP
selector:
app: $DEPLOYMENT_NAME
deployment-color: $NEW_COLOR
ports:
- port: 80
targetPort: http
protocol: TCP
EOF

# Scale down old deployment (keep for quick rollback)
if [ "$CURRENT_COLOR" != "blue" ] || kubectl get deployment ${DEPLOYMENT_NAME}-${CURRENT_COLOR} -n $K8S_NAMESPACE 2>/dev/null | grep -q ${DEPLOYMENT_NAME}-${CURRENT_COLOR}; then
echo "Scaling down old deployment ${DEPLOYMENT_NAME}-${CURRENT_COLOR}..."
kubectl scale deployment ${DEPLOYMENT_NAME}-${CURRENT_COLOR} -n $K8S_NAMESPACE --replicas=0
fi

echo "✓ Deployment complete. ${DEPLOYMENT_NAME}-${NEW_COLOR} is now serving traffic."
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG'
- if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' # Only run this job when a semantic version tag is created
tags:
- docker
- kubernetes